#include "OptionsDef.h"
#include "codepage_detect.h"
#include "UniFile.h"
+#include "WinMergePluginBase.h"
using std::vector;
using Poco::RegularExpression;
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)
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;
};
/**
*
* @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<IDispatch> drv(lpDispatch);
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));
{
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);
}
}
--- /dev/null
+#include <oleauto.h>
+#include <string>
+#include <map>
+
+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<UINT>(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<WORD>(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<INVOKEKIND>(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<IDispatch*>(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<std::wstring, int> m_mapNameToIndex;
+ std::vector<MemberInfo> m_memberInfo;
+ std::wstring m_sEvent;
+ std::wstring m_sDescription;
+ std::wstring m_sFileFilters;
+ bool m_bIsAutomatic;
+};
+