From 8267621f227c5b743a97287f63c61ea9dee877aa Mon Sep 17 00:00:00 2001 From: Takashi Sawanaka Date: Mon, 10 May 2021 09:24:32 +0900 Subject: [PATCH] Add WinMergePluginBase.h --- Src/Merge.vcxproj | 1 + Src/Merge.vcxproj.filters | 3 + Src/Plugins.cpp | 123 +++++++------------ Src/Plugins.h | 1 + Src/WinMergePluginBase.h | 304 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 351 insertions(+), 81 deletions(-) create mode 100644 Src/WinMergePluginBase.h diff --git a/Src/Merge.vcxproj b/Src/Merge.vcxproj index 022e6444e..6187a3711 100644 --- a/Src/Merge.vcxproj +++ b/Src/Merge.vcxproj @@ -1337,6 +1337,7 @@ + diff --git a/Src/Merge.vcxproj.filters b/Src/Merge.vcxproj.filters index 215c17e05..08e755651 100644 --- a/Src/Merge.vcxproj.filters +++ b/Src/Merge.vcxproj.filters @@ -1218,6 +1218,9 @@ Common\Header Files + + Header Files + diff --git a/Src/Plugins.cpp b/Src/Plugins.cpp index 940a156a5..90c617ff8 100644 --- a/Src/Plugins.cpp +++ b/Src/Plugins.cpp @@ -39,6 +39,7 @@ #include "OptionsDef.h" #include "codepage_detect.h" #include "UniFile.h" +#include "WinMergePluginBase.h" using std::vector; using Poco::RegularExpression; @@ -375,50 +376,21 @@ static String GetCustomFilters(const String& name, const String& filtersTextDefa return filtersTextDefault; } -class UnpackerGeneratedFromEditorScript: public IDispatch +class UnpackerGeneratedFromEditorScript: public WinMergePluginBase { public: - UnpackerGeneratedFromEditorScript(IDispatch *pDispatch, int id) : m_pDispatch(pDispatch), m_funcid(id), m_nRef(0) + UnpackerGeneratedFromEditorScript(IDispatch *pDispatch, const std::wstring funcname, int id) : m_pDispatch(pDispatch), m_funcid(id) { + m_sDescription = + strutils::format_string1(_T("Unpacker to execute %1 script (automatically generated)") , funcname); + m_sFileFilters = _T("."); + m_bIsAutomatic = true; + m_sEvent = L"FILE_PACK_UNPACK"; m_pDispatch->AddRef(); } - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override + virtual ~UnpackerGeneratedFromEditorScript() { - return E_NOTIMPL; - } - - ULONG STDMETHODCALLTYPE AddRef(void) override - { - return ++m_nRef; - } - - ULONG STDMETHODCALLTYPE Release(void) override - { - if (--m_nRef == 0) - { - m_pDispatch->Release(); - delete this; - return 0; - } - return m_nRef; - } - - HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT* pctinfo) override - { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) override - { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) override - { - for (unsigned i = 0; i < cNames; ++i) - rgDispId[i] = (wcscmp(L"UnpackFile", rgszNames[i]) == 0) ? 1 : -1; - return S_OK; } static HRESULT ReadFile(const String& path, String& text) @@ -454,53 +426,27 @@ public: return S_OK; } - HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) override + HRESULT STDMETHODCALLTYPE UnpackFile(BSTR fileSrc, BSTR fileDst, VARIANT_BOOL* pbChanged, INT* pSubcode, VARIANT_BOOL* pbSuccess) override { - if (!pDispParams) - return DISP_E_BADVARTYPE; - if (dispIdMember != 1) - return E_NOTIMPL; - - BSTR dstPath = pDispParams->rgvarg[2].bstrVal; - BSTR srcPath = pDispParams->rgvarg[3].bstrVal; - - int changed = 0; String text; - HRESULT hr = ReadFile(srcPath, text); + HRESULT hr = ReadFile(fileSrc, text); if (FAILED(hr)) return hr; + int changed = 0; if (!plugin::InvokeTransformText(text, changed, m_pDispatch, m_funcid)) return E_FAIL; - hr = WriteFile(dstPath, text); + hr = WriteFile(fileDst, text); if (FAILED(hr)) return hr; - - *pDispParams->rgvarg[1].pboolVal = VARIANT_TRUE; - pVarResult->boolVal = VARIANT_TRUE; + *pSubcode = 0; + *pbChanged = VARIANT_TRUE; + *pbSuccess = VARIANT_TRUE; return S_OK; } - static PluginInfoPtr MakePluginInfo(PluginInfo *pPluginBase, const String& funcname, int fncid) - { - PluginInfoPtr plugin(new PluginInfo); - plugin->m_lpDispatch = new UnpackerGeneratedFromEditorScript(pPluginBase->m_lpDispatch, fncid); - plugin->m_lpDispatch->AddRef(); - plugin->m_name = pPluginBase->m_name + _T(":") + funcname; - plugin->m_description = - strutils::format_string2(_T("Unpacker to execute %1 script (automatically generated from %2)") - , funcname, pPluginBase->m_name); - plugin->m_disabled = false; - plugin->m_filtersTextDefault = _T("."); - plugin->m_filtersText = GetCustomFilters(plugin->m_name, plugin->m_filtersTextDefault); - plugin->m_bAutomatic = true; - plugin->m_event = L"FILE_PACK_UNPACK"; - return plugin; - } - private: IDispatch *m_pDispatch; int m_funcid; - int m_nRef; }; /** @@ -524,19 +470,11 @@ struct ScriptInfo * * @return 1 if loaded plugin successfully, negatives for errors */ -int PluginInfo::LoadPlugin(const String & scriptletFilepath) +int PluginInfo::MakeInfo(const String & scriptletFilepath, IDispatch *lpDispatch) { // set up object in case we need to log info ScriptInfo scinfo(scriptletFilepath); - // Search for the class "WinMergeScript" - LPDISPATCH lpDispatch = CreateDispatchBySource(scriptletFilepath.c_str(), L"WinMergeScript"); - if (lpDispatch == nullptr) - { - scinfo.Log(_T("WinMergeScript entry point not found")); - return -10; // error - } - // Ensure that interface is released if any bad exit or exception AutoReleaser drv(lpDispatch); @@ -702,6 +640,27 @@ int PluginInfo::LoadPlugin(const String & scriptletFilepath) return 1; } +/** + * @brief Try to load a plugin + * + * @return 1 if loaded plugin successfully, negatives for errors + */ +int PluginInfo::LoadPlugin(const String & scriptletFilepath) +{ + // set up object in case we need to log info + ScriptInfo scinfo(scriptletFilepath); + + // Search for the class "WinMergeScript" + LPDISPATCH lpDispatch = CreateDispatchBySource(scriptletFilepath.c_str(), L"WinMergeScript"); + if (lpDispatch == nullptr) + { + scinfo.Log(_T("WinMergeScript entry point not found")); + return -10; // error + } + + return MakeInfo(scriptletFilepath, lpDispatch); +} + static void ReportPluginLoadFailure(const String & scriptletFilepath) { AppErrorMessageBox(strutils::format(_T("Exception loading plugin\r\n%s"), scriptletFilepath)); @@ -862,8 +821,10 @@ static std::map GetAvailableScripts() { if (plugins.find(L"FILE_PACK_UNPACK") == plugins.end()) plugins[L"FILE_PACK_UNPACK"].reset(new PluginArray); - PluginInfoPtr pluginNew = UnpackerGeneratedFromEditorScript::MakePluginInfo(plugin.get(), namesArray[i], idArray[i]); - pluginNew->m_disabled = (disabled_plugin_list.find(pluginNew->m_name) != disabled_plugin_list.end()); + PluginInfoPtr pluginNew(new PluginInfo()); + IDispatch *pDispatch = new UnpackerGeneratedFromEditorScript(plugin->m_lpDispatch, namesArray[i], idArray[i]); + pDispatch->AddRef(); + pluginNew->MakeInfo(plugin->m_filepath + _T(":") + namesArray[i], pDispatch); plugins[L"FILE_PACK_UNPACK"]->push_back(pluginNew); } } diff --git a/Src/Plugins.h b/Src/Plugins.h index fbe3ee0eb..eb3fd7407 100644 --- a/Src/Plugins.h +++ b/Src/Plugins.h @@ -47,6 +47,7 @@ public: } int LoadPlugin(const String & scriptletFilepath); + int MakeInfo(const String & scriptletFilepath, IDispatch *pDispatch); /// Parse the filter string (only for files), and create the filters void LoadFilterString(); diff --git a/Src/WinMergePluginBase.h b/Src/WinMergePluginBase.h new file mode 100644 index 000000000..6f03b1be8 --- /dev/null +++ b/Src/WinMergePluginBase.h @@ -0,0 +1,304 @@ +#include +#include +#include + +class WinMergePluginBase : public IDispatch, public ITypeInfo +{ +public: + enum + { + DISPID_UnpackFile, + DISPID_PackFile, + DISPID_ShowSettingsDialog, + DISPID_PluginFileFilters, + DISPID_PluginIsAutomatic, + DISPID_PluginDescription, + DISPID_PluginEvent, + }; + struct MemberInfo { std::wstring name; DISPID id; int flags; }; + + WinMergePluginBase() : m_nRef(0) + { + static const MemberInfo memberInfo[] = + { + { L"UnpackFile", DISPID_UnpackFile, DISPATCH_METHOD }, + { L"PackFile", DISPID_PackFile , DISPATCH_METHOD }, + { L"ShowSettingsDialog", DISPID_ShowSettingsDialog, DISPATCH_METHOD }, + { L"PluginFileFilters", DISPID_PluginFileFilters, DISPATCH_PROPERTYGET }, + { L"PluginIsAutomatic", DISPID_PluginIsAutomatic, DISPATCH_PROPERTYGET }, + { L"PluginDescription", DISPID_PluginDescription, DISPATCH_PROPERTYGET }, + { L"PluginEvent", DISPID_PluginEvent, DISPATCH_PROPERTYGET }, + }; + for (auto item : memberInfo) + { + m_memberInfo.push_back(item); + m_mapNameToIndex.emplace(item.name, item.id); + } + } + + virtual ~WinMergePluginBase() {} + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override + { + return E_NOTIMPL; + } + + ULONG STDMETHODCALLTYPE AddRef(void) override + { + return ++m_nRef; + } + + ULONG STDMETHODCALLTYPE Release(void) override + { + if (--m_nRef == 0) + { + delete this; + return 0; + } + return m_nRef; + } + + HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT* pctinfo) override + { + *pctinfo = static_cast(m_memberInfo.size()); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) override + { + *ppTInfo = this; + (*ppTInfo)->AddRef(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) override + { + for (unsigned i = 0; i < cNames; ++i) + { + auto it = m_mapNameToIndex.find(rgszNames[i]); + if (it == m_mapNameToIndex.end()) + return DISP_E_UNKNOWNNAME; + rgDispId[i] = it->second; + } + return S_OK; + } + + HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) override + { + if (!pDispParams) + return DISP_E_BADVARTYPE; + HRESULT hr = E_NOTIMPL; + if (wFlags == DISPATCH_METHOD) + { + switch (dispIdMember) + { + case DISPID_UnpackFile: + { + BSTR fileSrc = pDispParams->rgvarg[3].bstrVal; + BSTR fileDst = pDispParams->rgvarg[2].bstrVal; + VARIANT_BOOL* pbChanged = pDispParams->rgvarg[1].pboolVal; + INT* pSubcode = &pDispParams->rgvarg[0].intVal; + VARIANT_BOOL* pbSuccess = &pVarResult->boolVal; + hr = UnpackFile(fileSrc, fileDst, pbChanged, pSubcode, pbSuccess); + break; + } + case DISPID_PackFile: + { + BSTR fileSrc = pDispParams->rgvarg[3].bstrVal; + BSTR fileDst = pDispParams->rgvarg[2].bstrVal; + VARIANT_BOOL* pbChanged = pDispParams->rgvarg[1].pboolVal; + INT subcode = pDispParams->rgvarg[0].intVal; + VARIANT_BOOL* pbSuccess = &pVarResult->boolVal; + hr = PackFile(fileSrc, fileDst, pbChanged, subcode, pbSuccess); + break; + } + case DISPID_ShowSettingsDialog: + hr = ShowSettingsDialog(&pVarResult->boolVal); + break; + } + } + else if (wFlags == DISPATCH_PROPERTYGET) + { + switch (dispIdMember) + { + case DISPID_PluginFileFilters: + pVarResult->vt = VT_BSTR; + hr = get_PluginFileFilters(&pVarResult->bstrVal); + break; + case DISPID_PluginIsAutomatic: + pVarResult->vt = VT_BOOL; + hr = get_PluginIsAutomatic(&pVarResult->boolVal); + break; + case DISPID_PluginDescription: + pVarResult->vt = VT_BSTR; + hr = get_PluginDescription(&pVarResult->bstrVal); + break; + case DISPID_PluginEvent: + pVarResult->vt = VT_BSTR; + hr = get_PluginEvent(&pVarResult->bstrVal); + break; + } + } + return hr; + } + + HRESULT STDMETHODCALLTYPE GetTypeAttr(TYPEATTR** ppTypeAttr) override + { + auto* pTypeAttr = new TYPEATTR(); + pTypeAttr->cFuncs = static_cast(m_memberInfo.size()); + *ppTypeAttr = pTypeAttr; + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetTypeComp(ITypeComp** ppTComp) override + { + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE GetFuncDesc(UINT index, FUNCDESC** ppFuncDesc) override + { + if (index >= m_memberInfo.size()) + return E_INVALIDARG; + auto* pFuncDesc = new FUNCDESC(); + pFuncDesc->invkind = static_cast(m_memberInfo[index].flags); + pFuncDesc->wFuncFlags = 0; + pFuncDesc->memid = index; + *ppFuncDesc = pFuncDesc; + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetVarDesc(UINT index, VARDESC** ppVarDesc) override + { + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE GetNames(MEMBERID memid, BSTR *rgBstrNames, UINT cMaxNames, UINT *pcNames) override + { + if (memid >= m_memberInfo.size()) + return E_INVALIDARG; + *rgBstrNames = SysAllocString(m_memberInfo[memid].name.c_str()); + *pcNames = 1; + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetRefTypeOfImplType(UINT index, HREFTYPE *pRefType) override + { + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE GetImplTypeFlags(UINT index, INT *pImplTypeFlags) override + { + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE GetIDsOfNames(LPOLESTR* rgszNames, UINT cNames, MEMBERID* pMemId) override + { + return GetIDsOfNames(IID_NULL, rgszNames, cNames, 0, pMemId); + } + + HRESULT STDMETHODCALLTYPE Invoke(PVOID pvInstance, MEMBERID memid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) override + { + return reinterpret_cast(pvInstance)->Invoke(memid, IID_NULL, 0, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); + } + + HRESULT STDMETHODCALLTYPE GetDocumentation(MEMBERID memid, BSTR *pBstrName, BSTR *pBstrDocString, DWORD *pdwHelpContext, BSTR *pBstrHelpFile) override + { + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE GetDllEntry(MEMBERID memid, INVOKEKIND invKind, BSTR *pBstrDllName, BSTR *pBstrName, WORD *pwOrdinal) + { + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE GetRefTypeInfo(HREFTYPE hRefType, ITypeInfo **ppTInfo) override + { + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE AddressOfMember(MEMBERID memid, INVOKEKIND invKind, PVOID *ppv) override + { + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, REFIID riid, PVOID *ppvObj) override + { + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE GetMops(MEMBERID memid, BSTR *pBstrMops) override + { + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE GetContainingTypeLib(ITypeLib **ppTLib, UINT *pIndex) override + { + return E_NOTIMPL; + } + + void STDMETHODCALLTYPE ReleaseTypeAttr(TYPEATTR *pTypeAttr) override + { + delete pTypeAttr; + } + + void STDMETHODCALLTYPE ReleaseFuncDesc(FUNCDESC *pFuncDesc) override + { + delete pFuncDesc; + } + + void STDMETHODCALLTYPE ReleaseVarDesc(VARDESC *pVarDesc) override + { + } + + virtual HRESULT STDMETHODCALLTYPE PackFile(BSTR fileSrc, BSTR fileDst, VARIANT_BOOL* pbChanged, INT subcode, VARIANT_BOOL* pbSuccess) + { + *pbSuccess = VARIANT_FALSE; + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE UnpackFile(BSTR fileSrc, BSTR fileDst, VARIANT_BOOL* pbChanged, INT* pSubcode, VARIANT_BOOL* pbSuccess) + { + *pbSuccess = VARIANT_FALSE; + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE ShowSettingsDialog(VARIANT_BOOL* pbHandled) + { + *pbHandled = VARIANT_FALSE; + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE get_PluginIsAutomatic(VARIANT_BOOL* pVal) + { + *pVal = m_bIsAutomatic ? -1 : 0; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE get_PluginFileFilters(BSTR* pVal) + { + *pVal = SysAllocString(m_sFileFilters.c_str()); + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE get_PluginDescription(BSTR* pVal) + { + *pVal = SysAllocString(m_sDescription.c_str()); + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE get_PluginEvent(BSTR* pVal) + { + *pVal = SysAllocString(m_sEvent.c_str()); + return S_OK; + } + +protected: + int m_nRef; + std::map m_mapNameToIndex; + std::vector m_memberInfo; + std::wstring m_sEvent; + std::wstring m_sDescription; + std::wstring m_sFileFilters; + bool m_bIsAutomatic; +}; + -- 2.11.0