5 class WinMergePluginBase : public IDispatch, public ITypeInfo
10 DISPID_PluginEvent = 1,
11 DISPID_PluginDescription,
12 DISPID_PluginIsAutomatic,
13 DISPID_PluginFileFilters,
14 DISPID_PluginUnpackedFileExtension,
21 DISPID_ShowSettingsDialog,
23 using ScriptFuncPtr = HRESULT(STDMETHODCALLTYPE*)(IDispatch* pDispatch, BSTR bstrText, BSTR* pbstrResult);
25 WinMergePluginBase(const std::wstring& sEvent, const std::wstring& sDescription = L"",
26 const std::wstring& sFileFilters = L"", const std::wstring& sUnpackedFileExtension = L"",
27 bool bIsAutomatic = true)
30 , m_sDescription(sDescription)
31 , m_sFileFilters(sFileFilters)
32 , m_sUnpackedFileExtension(sUnpackedFileExtension)
33 , m_bIsAutomatic(bIsAutomatic)
35 static PARAMDATA paramData_Prediff[] =
36 { {L"fileSrc", VT_BSTR}, {L"fileDst", VT_BSTR}, {L"pbChanged", VT_BOOL | VT_BYREF}, };
37 static PARAMDATA paramData_UnpackFile[] =
38 { {L"fileSrc", VT_BSTR}, {L"fileDst", VT_BSTR}, {L"pbChanged", VT_BOOL | VT_BYREF}, {L"pSubcode", VT_I4 | VT_BYREF}, };
39 static PARAMDATA paramData_PackFile[] =
40 { {L"fileSrc", VT_BSTR}, {L"fileDst", VT_BSTR}, {L"pbChanged", VT_BOOL | VT_BYREF}, {L"subcode", VT_I4}, };
41 static PARAMDATA paramData_IsFolder[] =
42 { {L"fileSrc", VT_BSTR}, };
43 static PARAMDATA paramData_UnpackFolder[] =
44 { {L"fileSrc", VT_BSTR}, {L"folderDst", VT_BSTR}, {L"pbChanged", VT_BOOL | VT_BYREF}, {L"pSubcode", VT_I4 | VT_BYREF}, };
45 static PARAMDATA paramData_PackFolder[] =
46 { {L"folderSrc", VT_BSTR}, {L"fileDst", VT_BSTR}, {L"pbChanged", VT_BOOL | VT_BYREF}, {L"subcode", VT_I4}, };
47 static PARAMDATA paramData_Empty[] =
49 static METHODDATA methodData_FILE_PREDIFF[] =
51 { L"PluginEvent", nullptr, DISPID_PluginEvent, 0, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
52 { L"PluginDescription", nullptr, DISPID_PluginDescription, 1, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
53 { L"PluginIsAutomatic", nullptr, DISPID_PluginIsAutomatic, 2, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BOOL },
54 { L"PluginFileFilters", nullptr, DISPID_PluginFileFilters, 3, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
55 { L"PrediffFile", paramData_Prediff, DISPID_PrediffFile, 4, CC_STDCALL, 3, DISPATCH_METHOD, VT_BOOL },
56 { L"ShowSettingsDialog", nullptr, DISPID_ShowSettingsDialog, 5, CC_STDCALL, 0, DISPATCH_METHOD, VT_EMPTY },
58 static METHODDATA methodData_FILE_PACK_UNPACK[] =
60 { L"PluginEvent", nullptr, DISPID_PluginEvent, 0, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
61 { L"PluginDescription", nullptr, DISPID_PluginDescription, 1, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
62 { L"PluginIsAutomatic", nullptr, DISPID_PluginIsAutomatic, 2, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BOOL },
63 { L"PluginFileFilters", nullptr, DISPID_PluginFileFilters, 3, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
64 { L"PluginUnpackedFileExtension", nullptr, DISPID_PluginUnpackedFileExtension, 4, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
65 { L"UnpackFile", paramData_UnpackFile, DISPID_UnpackFile, 5, CC_STDCALL, 4, DISPATCH_METHOD, VT_BOOL },
66 { L"PackFile", paramData_PackFile, DISPID_PackFile , 6, CC_STDCALL, 4, DISPATCH_METHOD, VT_BOOL },
67 { L"ShowSettingsDialog", nullptr, DISPID_ShowSettingsDialog, 7, CC_STDCALL, 0, DISPATCH_METHOD, VT_EMPTY },
69 static METHODDATA methodData_FILE_FOLDER_PACK_UNPACK[] =
71 { L"PluginEvent", nullptr, DISPID_PluginEvent, 0, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
72 { L"PluginDescription", nullptr, DISPID_PluginDescription, 1, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
73 { L"PluginIsAutomatic", nullptr, DISPID_PluginIsAutomatic, 2, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BOOL },
74 { L"PluginFileFilters", nullptr, DISPID_PluginFileFilters, 3, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
75 { L"PluginUnpackedFileExtension", nullptr, DISPID_PluginUnpackedFileExtension, 4, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
76 { L"UnpackFile", paramData_UnpackFile, DISPID_UnpackFile, 5, CC_STDCALL, 4, DISPATCH_METHOD, VT_BOOL },
77 { L"PackFile", paramData_PackFile, DISPID_PackFile , 6, CC_STDCALL, 4, DISPATCH_METHOD, VT_BOOL },
78 { L"IsFolder", paramData_IsFolder, DISPID_IsFolder, 7, CC_STDCALL, 1, DISPATCH_METHOD, VT_BOOL },
79 { L"UnpackFolder", paramData_UnpackFolder, DISPID_UnpackFolder, 8, CC_STDCALL, 4, DISPATCH_METHOD, VT_BOOL },
80 { L"PackFolder", paramData_PackFolder, DISPID_PackFolder, 9, CC_STDCALL, 4, DISPATCH_METHOD, VT_BOOL },
81 { L"ShowSettingsDialog", nullptr, DISPID_ShowSettingsDialog, 10, CC_STDCALL, 0, DISPATCH_METHOD, VT_EMPTY },
83 static METHODDATA methodData_EDITOR_SCRIPT[] =
85 { L"PluginEvent", nullptr, DISPID_PluginEvent, 0, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
86 { L"PluginDescription", nullptr, DISPID_PluginDescription, 1, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
88 const METHODDATA* pMethodData;
89 size_t methodDataCount = 0;
90 if (sEvent == L"FILE_PREDIFF")
92 methodDataCount = sizeof(methodData_FILE_PREDIFF) / sizeof(methodData_FILE_PREDIFF[0]);
93 pMethodData = methodData_FILE_PREDIFF;
95 else if (sEvent == L"FILE_PACK_UNPACK")
97 methodDataCount = sizeof(methodData_FILE_PACK_UNPACK) / sizeof(methodData_FILE_PACK_UNPACK[0]);
98 pMethodData = methodData_FILE_PACK_UNPACK;
100 else if (sEvent == L"FILE_FOLDER_PACK_UNPACK")
102 methodDataCount = sizeof(methodData_FILE_FOLDER_PACK_UNPACK) / sizeof(methodData_FILE_FOLDER_PACK_UNPACK[0]);
103 pMethodData = methodData_FILE_FOLDER_PACK_UNPACK;
107 methodDataCount = sizeof(methodData_EDITOR_SCRIPT) / sizeof(methodData_EDITOR_SCRIPT[0]);
108 pMethodData = methodData_EDITOR_SCRIPT;
110 for (size_t i = 0; i < methodDataCount; ++i)
112 auto& methodData = pMethodData[i];
113 m_mapNameToIndex.insert_or_assign(methodData.szName, static_cast<int>(m_methodData.size()));
114 m_mapDispIdToIndex.insert_or_assign(methodData.dispid, static_cast<int>(m_methodData.size()));
115 m_methodData.push_back(methodData);
119 virtual ~WinMergePluginBase() {}
121 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override
126 ULONG STDMETHODCALLTYPE AddRef(void) override
131 ULONG STDMETHODCALLTYPE Release(void) override
141 HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT* pctinfo) override
143 *pctinfo = static_cast<UINT>(m_methodData.size());
147 HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) override
150 (*ppTInfo)->AddRef();
154 HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) override
156 for (unsigned i = 0; i < cNames; ++i)
158 auto it = m_mapNameToIndex.find(rgszNames[i]);
159 if (it == m_mapNameToIndex.end())
160 return DISP_E_UNKNOWNNAME;
161 rgDispId[i] = m_methodData[it->second].dispid;
166 HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) override
169 return DISP_E_BADVARTYPE;
170 HRESULT hr = E_NOTIMPL;
171 if (wFlags == DISPATCH_METHOD)
173 switch (dispIdMember)
175 case DISPID_PrediffFile:
177 BSTR fileSrc = pDispParams->rgvarg[2].bstrVal;
178 BSTR fileDst = pDispParams->rgvarg[1].bstrVal;
179 VARIANT_BOOL* pbChanged = pDispParams->rgvarg[0].pboolVal;
180 VARIANT_BOOL* pbSuccess = &pVarResult->boolVal;
181 hr = PrediffFile(fileSrc, fileDst, pbChanged, pbSuccess);
184 case DISPID_UnpackFile:
186 BSTR fileSrc = pDispParams->rgvarg[3].bstrVal;
187 BSTR fileDst = pDispParams->rgvarg[2].bstrVal;
188 VARIANT_BOOL* pbChanged = pDispParams->rgvarg[1].pboolVal;
189 INT* pSubcode = &pDispParams->rgvarg[0].intVal;
190 VARIANT_BOOL* pbSuccess = &pVarResult->boolVal;
191 hr = UnpackFile(fileSrc, fileDst, pbChanged, pSubcode, pbSuccess);
194 case DISPID_PackFile:
196 BSTR fileSrc = pDispParams->rgvarg[3].bstrVal;
197 BSTR fileDst = pDispParams->rgvarg[2].bstrVal;
198 VARIANT_BOOL* pbChanged = pDispParams->rgvarg[1].pboolVal;
199 INT subcode = pDispParams->rgvarg[0].intVal;
200 VARIANT_BOOL* pbSuccess = &pVarResult->boolVal;
201 hr = PackFile(fileSrc, fileDst, pbChanged, subcode, pbSuccess);
204 case DISPID_IsFolder:
206 BSTR file = pDispParams->rgvarg[0].bstrVal;
207 VARIANT_BOOL* pbSuccess = &pVarResult->boolVal;
208 hr = IsFolder(file, pbSuccess);
211 case DISPID_UnpackFolder:
213 BSTR fileSrc = pDispParams->rgvarg[3].bstrVal;
214 BSTR folderDst = pDispParams->rgvarg[2].bstrVal;
215 VARIANT_BOOL* pbChanged = pDispParams->rgvarg[1].pboolVal;
216 INT* pSubcode = &pDispParams->rgvarg[0].intVal;
217 VARIANT_BOOL* pbSuccess = &pVarResult->boolVal;
218 hr = UnpackFolder(fileSrc, folderDst, pbChanged, pSubcode, pbSuccess);
221 case DISPID_PackFolder:
223 BSTR folderSrc = pDispParams->rgvarg[3].bstrVal;
224 BSTR fileDst = pDispParams->rgvarg[2].bstrVal;
225 VARIANT_BOOL* pbChanged = pDispParams->rgvarg[1].pboolVal;
226 INT subcode = pDispParams->rgvarg[0].intVal;
227 VARIANT_BOOL* pbSuccess = &pVarResult->boolVal;
228 hr = PackFolder(folderSrc, fileDst, pbChanged, subcode, pbSuccess);
231 case DISPID_ShowSettingsDialog:
232 hr = ShowSettingsDialog(&pVarResult->boolVal);
235 if (m_mapDispIdToIndex.find(dispIdMember) != m_mapDispIdToIndex.end())
237 BSTR bstrText = pDispParams->rgvarg[0].bstrVal;
238 pVarResult->vt = VT_BSTR;
239 BSTR* pbstrResult = &pVarResult->bstrVal;
240 hr = m_mapScriptFuncs[dispIdMember].second(this, bstrText, pbstrResult);
245 else if (wFlags == DISPATCH_PROPERTYGET)
247 switch (dispIdMember)
249 case DISPID_PluginEvent:
250 pVarResult->vt = VT_BSTR;
251 hr = get_PluginEvent(&pVarResult->bstrVal);
253 case DISPID_PluginDescription:
254 pVarResult->vt = VT_BSTR;
255 hr = get_PluginDescription(&pVarResult->bstrVal);
257 case DISPID_PluginIsAutomatic:
258 pVarResult->vt = VT_BOOL;
259 hr = get_PluginIsAutomatic(&pVarResult->boolVal);
261 case DISPID_PluginFileFilters:
262 pVarResult->vt = VT_BSTR;
263 hr = get_PluginFileFilters(&pVarResult->bstrVal);
265 case DISPID_PluginUnpackedFileExtension:
266 pVarResult->vt = VT_BSTR;
267 hr = get_PluginUnpackedFileExtension(&pVarResult->bstrVal);
274 HRESULT STDMETHODCALLTYPE GetTypeAttr(TYPEATTR** ppTypeAttr) override
276 auto* pTypeAttr = new TYPEATTR();
277 pTypeAttr->cFuncs = static_cast<WORD>(m_methodData.size());
278 pTypeAttr->typekind = TKIND_DISPATCH;
279 pTypeAttr->cbAlignment = 8;
280 *ppTypeAttr = pTypeAttr;
284 HRESULT STDMETHODCALLTYPE GetTypeComp(ITypeComp** ppTComp) override
289 HRESULT STDMETHODCALLTYPE GetFuncDesc(UINT index, FUNCDESC** ppFuncDesc) override
291 if (index >= m_methodData.size())
293 auto* pFuncDesc = new FUNCDESC();
294 const METHODDATA& methodData = m_methodData[index];
295 pFuncDesc->funckind = FUNC_DISPATCH;
296 pFuncDesc->invkind = static_cast<INVOKEKIND>(methodData.wFlags);
297 pFuncDesc->wFuncFlags = 0;
298 pFuncDesc->cParams = static_cast<short>(methodData.cArgs);
299 pFuncDesc->memid = methodData.dispid;
300 pFuncDesc->callconv = methodData.cc;
301 if (methodData.cArgs > 0)
303 pFuncDesc->lprgelemdescParam = new ELEMDESC[methodData.cArgs];
304 for (int i = 0; i < methodData.cArgs; ++i)
305 pFuncDesc->lprgelemdescParam[i].tdesc.vt = methodData.ppdata[i].vt;
307 pFuncDesc->elemdescFunc.tdesc.vt = methodData.vtReturn;
308 *ppFuncDesc = pFuncDesc;
312 HRESULT STDMETHODCALLTYPE GetVarDesc(UINT index, VARDESC** ppVarDesc) override
317 HRESULT STDMETHODCALLTYPE GetNames(MEMBERID memid, BSTR *rgBstrNames, UINT cMaxNames, UINT *pcNames) override
319 if (m_mapDispIdToIndex.find(memid) == m_mapDispIdToIndex.end())
321 const METHODDATA& methodData = m_methodData[m_mapDispIdToIndex[memid]];
322 for (int i = 0; i < cMaxNames && i < methodData.cArgs + 1; i++)
325 rgBstrNames[i] = SysAllocString(methodData.szName);
327 rgBstrNames[i] = SysAllocString(methodData.ppdata[i - 1].szName);
333 HRESULT STDMETHODCALLTYPE GetRefTypeOfImplType(UINT index, HREFTYPE *pRefType) override
338 HRESULT STDMETHODCALLTYPE GetImplTypeFlags(UINT index, INT *pImplTypeFlags) override
343 HRESULT STDMETHODCALLTYPE GetIDsOfNames(LPOLESTR* rgszNames, UINT cNames, MEMBERID* pMemId) override
345 return GetIDsOfNames(IID_NULL, rgszNames, cNames, 0, pMemId);
348 HRESULT STDMETHODCALLTYPE Invoke(PVOID pvInstance, MEMBERID memid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) override
350 return reinterpret_cast<IDispatch*>(pvInstance)->Invoke(memid, IID_NULL, 0, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
353 HRESULT STDMETHODCALLTYPE GetDocumentation(MEMBERID memid, BSTR *pBstrName, BSTR *pBstrDocString, DWORD *pdwHelpContext, BSTR *pBstrHelpFile) override
358 HRESULT STDMETHODCALLTYPE GetDllEntry(MEMBERID memid, INVOKEKIND invKind, BSTR *pBstrDllName, BSTR *pBstrName, WORD *pwOrdinal)
363 HRESULT STDMETHODCALLTYPE GetRefTypeInfo(HREFTYPE hRefType, ITypeInfo **ppTInfo) override
368 HRESULT STDMETHODCALLTYPE AddressOfMember(MEMBERID memid, INVOKEKIND invKind, PVOID *ppv) override
373 HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, REFIID riid, PVOID *ppvObj) override
378 HRESULT STDMETHODCALLTYPE GetMops(MEMBERID memid, BSTR *pBstrMops) override
383 HRESULT STDMETHODCALLTYPE GetContainingTypeLib(ITypeLib **ppTLib, UINT *pIndex) override
388 void STDMETHODCALLTYPE ReleaseTypeAttr(TYPEATTR *pTypeAttr) override
393 void STDMETHODCALLTYPE ReleaseFuncDesc(FUNCDESC *pFuncDesc) override
395 delete pFuncDesc->lprgelemdescParam;
399 void STDMETHODCALLTYPE ReleaseVarDesc(VARDESC *pVarDesc) override
403 virtual HRESULT STDMETHODCALLTYPE PrediffFile(BSTR fileSrc, BSTR fileDst, VARIANT_BOOL* pbChanged, VARIANT_BOOL* pbSuccess)
405 *pbSuccess = VARIANT_FALSE;
409 virtual HRESULT STDMETHODCALLTYPE PackFile(BSTR fileSrc, BSTR fileDst, VARIANT_BOOL* pbChanged, INT subcode, VARIANT_BOOL* pbSuccess)
411 *pbSuccess = VARIANT_FALSE;
415 virtual HRESULT STDMETHODCALLTYPE UnpackFile(BSTR fileSrc, BSTR fileDst, VARIANT_BOOL* pbChanged, INT* pSubcode, VARIANT_BOOL* pbSuccess)
417 *pbSuccess = VARIANT_FALSE;
421 virtual HRESULT STDMETHODCALLTYPE IsFolder(BSTR file, VARIANT_BOOL* pbFolder)
423 *pbFolder = VARIANT_FALSE;
427 virtual HRESULT STDMETHODCALLTYPE PackFolder(BSTR folderSrc, BSTR fileDst, VARIANT_BOOL* pbChanged, INT subcode, VARIANT_BOOL* pbSuccess)
429 *pbSuccess = VARIANT_FALSE;
433 virtual HRESULT STDMETHODCALLTYPE UnpackFolder(BSTR fileSrc, BSTR folderDst, VARIANT_BOOL* pbChanged, INT* pSubcode, VARIANT_BOOL* pbSuccess)
435 *pbSuccess = VARIANT_FALSE;
439 virtual HRESULT STDMETHODCALLTYPE ShowSettingsDialog(VARIANT_BOOL* pbHandled)
441 *pbHandled = VARIANT_FALSE;
445 virtual HRESULT STDMETHODCALLTYPE get_PluginEvent(BSTR* pVal)
447 *pVal = SysAllocString(m_sEvent.c_str());
451 virtual HRESULT STDMETHODCALLTYPE get_PluginDescription(BSTR* pVal)
453 *pVal = SysAllocString(m_sDescription.c_str());
457 virtual HRESULT STDMETHODCALLTYPE get_PluginIsAutomatic(VARIANT_BOOL* pVal)
459 *pVal = m_bIsAutomatic ? -1 : 0;
463 virtual HRESULT STDMETHODCALLTYPE get_PluginFileFilters(BSTR* pVal)
465 *pVal = SysAllocString(m_sFileFilters.c_str());
469 virtual HRESULT STDMETHODCALLTYPE get_PluginUnpackedFileExtension(BSTR* pVal)
471 *pVal = SysAllocString(m_sUnpackedFileExtension.c_str());
475 bool AddFunction(const std::wstring& name, ScriptFuncPtr pFunc)
477 static PARAMDATA paramData_ScriptFunc[] =
478 { {L"text", VT_BSTR} };
479 unsigned index = static_cast<int>(m_methodData.size());
480 DISPID dispid = static_cast<DISPID>(m_methodData.size()) + 100;
481 m_mapNameToIndex.insert_or_assign(name, index);
482 m_mapDispIdToIndex.insert_or_assign(dispid, index);
483 m_mapScriptFuncs.insert_or_assign(dispid, std::pair{name, pFunc});
484 METHODDATA methodData =
486 const_cast<OLECHAR *>(m_mapScriptFuncs[dispid].first.c_str()), paramData_ScriptFunc, dispid, index, CC_STDCALL, 1, DISPATCH_METHOD, VT_BSTR
488 m_methodData.emplace_back(methodData);
494 std::map<std::wstring, int> m_mapNameToIndex;
495 std::map<DISPID, int> m_mapDispIdToIndex;
496 std::vector<METHODDATA> m_methodData;
497 std::map<DISPID, std::pair<std::wstring, ScriptFuncPtr>> m_mapScriptFuncs;
498 std::wstring m_sEvent;
499 std::wstring m_sDescription;
500 std::wstring m_sFileFilters;
501 std::wstring m_sUnpackedFileExtension;