OSDN Git Service

Add WinMergePluginBase.h (7)
[winmerge-jp/winmerge-jp.git] / Src / WinMergePluginBase.h
1 #include <oleauto.h>
2 #include <string>
3 #include <map>
4
5 class WinMergePluginBase : public IDispatch, public ITypeInfo
6 {
7 public:
8         enum
9         {
10                 DISPID_PluginEvent = 1,
11                 DISPID_PluginDescription,
12                 DISPID_PluginIsAutomatic,
13                 DISPID_PluginFileFilters,
14                 DISPID_PluginUnpackedFileExtension,
15                 DISPID_PrediffFile,
16                 DISPID_UnpackFile,
17                 DISPID_PackFile,
18                 DISPID_IsFolder,
19                 DISPID_UnpackFolder,
20                 DISPID_PackFolder,
21                 DISPID_ShowSettingsDialog,
22         };
23         using ScriptFuncPtr = HRESULT(STDMETHODCALLTYPE*)(IDispatch* pDispatch, BSTR bstrText, BSTR* pbstrResult);
24
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)
28                 : m_nRef(0)
29                 , m_sEvent(sEvent)
30                 , m_sDescription(sDescription)
31                 , m_sFileFilters(sFileFilters)
32                 , m_sUnpackedFileExtension(sUnpackedFileExtension)
33                 , m_bIsAutomatic(bIsAutomatic)
34         {
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[] =
48                 { {L"", VT_EMPTY} };
49                 static METHODDATA methodData_FILE_PREDIFF[] =
50                 {
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 },
57                 };
58                 static METHODDATA methodData_FILE_PACK_UNPACK[] =
59                 {
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 },
68                 };
69                 static METHODDATA methodData_FILE_FOLDER_PACK_UNPACK[] =
70                 {
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 },
82                 };
83                 static METHODDATA methodData_EDITOR_SCRIPT[] =
84                 {
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 },
87                 };
88                 const METHODDATA* pMethodData;
89                 size_t methodDataCount = 0;
90                 if (sEvent == L"FILE_PREDIFF")
91                 {
92                         methodDataCount = sizeof(methodData_FILE_PREDIFF) / sizeof(methodData_FILE_PREDIFF[0]);
93                         pMethodData = methodData_FILE_PREDIFF;
94                 }
95                 else if (sEvent == L"FILE_PACK_UNPACK")
96                 {
97                         methodDataCount = sizeof(methodData_FILE_PACK_UNPACK) / sizeof(methodData_FILE_PACK_UNPACK[0]);
98                         pMethodData = methodData_FILE_PACK_UNPACK;
99                 }
100                 else if (sEvent == L"FILE_FOLDER_PACK_UNPACK")
101                 {
102                         methodDataCount = sizeof(methodData_FILE_FOLDER_PACK_UNPACK) / sizeof(methodData_FILE_FOLDER_PACK_UNPACK[0]);
103                         pMethodData = methodData_FILE_FOLDER_PACK_UNPACK;
104                 }
105                 else
106                 {
107                         methodDataCount = sizeof(methodData_EDITOR_SCRIPT) / sizeof(methodData_EDITOR_SCRIPT[0]);
108                         pMethodData = methodData_EDITOR_SCRIPT;
109                 }
110                 for (size_t i = 0; i < methodDataCount; ++i)
111                 {
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);
116                 }
117         }
118
119         virtual ~WinMergePluginBase() {}
120
121         HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override
122         {
123                 return E_NOTIMPL;
124         }
125
126         ULONG STDMETHODCALLTYPE AddRef(void) override
127         {
128                 return ++m_nRef;
129         }
130
131         ULONG STDMETHODCALLTYPE Release(void) override
132         {
133                 if (--m_nRef == 0)
134                 {
135                         delete this;
136                         return 0;
137                 }
138                 return m_nRef;
139         }
140
141         HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT* pctinfo) override
142         {
143                 *pctinfo = static_cast<UINT>(m_methodData.size());
144                 return S_OK;
145         }
146
147         HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) override
148         {
149                 *ppTInfo = this;
150                 (*ppTInfo)->AddRef();
151                 return S_OK;
152         }
153
154         HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) override
155         {
156                 for (unsigned i = 0; i < cNames; ++i)
157                 {
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;
162                 }
163                 return S_OK;
164         }
165
166         HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) override
167         {
168                 if (!pDispParams)
169                         return DISP_E_BADVARTYPE;
170                 HRESULT hr = E_NOTIMPL;
171                 if (wFlags == DISPATCH_METHOD)
172                 {
173                         switch (dispIdMember)
174                         {
175                         case DISPID_PrediffFile:
176                         {
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);
182                                 break;
183                         }
184                         case DISPID_UnpackFile:
185                         {
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].pintVal;
190                                 VARIANT_BOOL* pbSuccess = &pVarResult->boolVal;
191                                 hr = UnpackFile(fileSrc, fileDst, pbChanged, pSubcode, pbSuccess);
192                                 break;
193                         }
194                         case DISPID_PackFile:
195                         {
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);
202                                 break;
203                         }
204                         case DISPID_IsFolder:
205                         {
206                                 BSTR file = pDispParams->rgvarg[0].bstrVal;
207                                 VARIANT_BOOL* pbSuccess = &pVarResult->boolVal;
208                                 hr = IsFolder(file, pbSuccess);
209                                 break;
210                         }
211                         case DISPID_UnpackFolder:
212                         {
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].pintVal;
217                                 VARIANT_BOOL* pbSuccess = &pVarResult->boolVal;
218                                 hr = UnpackFolder(fileSrc, folderDst, pbChanged, pSubcode, pbSuccess);
219                                 break;
220                         }
221                         case DISPID_PackFolder:
222                         {
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);
229                                 break;
230                         }
231                         case DISPID_ShowSettingsDialog:
232                                 hr = ShowSettingsDialog(&pVarResult->boolVal);
233                                 break;
234                         default:
235                                 if (m_mapDispIdToIndex.find(dispIdMember) != m_mapDispIdToIndex.end())
236                                 {
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);
241                                 }
242                                 break;
243                         }
244                 }
245                 else if (wFlags == DISPATCH_PROPERTYGET)
246                 {
247                         switch (dispIdMember)
248                         {
249                         case DISPID_PluginEvent:
250                                 pVarResult->vt = VT_BSTR;
251                                 hr = get_PluginEvent(&pVarResult->bstrVal);
252                                 break;
253                         case DISPID_PluginDescription:
254                                 pVarResult->vt = VT_BSTR;
255                                 hr = get_PluginDescription(&pVarResult->bstrVal);
256                                 break;
257                         case DISPID_PluginIsAutomatic:
258                                 pVarResult->vt = VT_BOOL;
259                                 hr = get_PluginIsAutomatic(&pVarResult->boolVal);
260                                 break;
261                         case DISPID_PluginFileFilters:
262                                 pVarResult->vt = VT_BSTR;
263                                 hr = get_PluginFileFilters(&pVarResult->bstrVal);
264                                 break;
265                         case DISPID_PluginUnpackedFileExtension:
266                                 pVarResult->vt = VT_BSTR;
267                                 hr = get_PluginUnpackedFileExtension(&pVarResult->bstrVal);
268                                 break;
269                         }
270                 }
271                 if (hr == DISP_E_EXCEPTION && pExcepInfo)
272                 {
273                         IErrorInfo* pErrorInfo = nullptr;
274                         GetErrorInfo(0, &pErrorInfo);
275                         pErrorInfo->GetDescription(&pExcepInfo->bstrDescription);
276                         pErrorInfo->GetSource(&pExcepInfo->bstrSource);
277                 }
278                 return hr;
279         }
280
281         HRESULT STDMETHODCALLTYPE GetTypeAttr(TYPEATTR** ppTypeAttr) override
282         {
283                 auto* pTypeAttr = new TYPEATTR();
284                 pTypeAttr->cFuncs = static_cast<WORD>(m_methodData.size());
285                 pTypeAttr->typekind = TKIND_DISPATCH;
286                 pTypeAttr->cbAlignment = 8;
287                 *ppTypeAttr = pTypeAttr;
288                 return S_OK;
289         }
290         
291         HRESULT STDMETHODCALLTYPE GetTypeComp(ITypeComp** ppTComp) override
292         {
293                 return E_NOTIMPL;
294         }
295         
296         HRESULT STDMETHODCALLTYPE GetFuncDesc(UINT index, FUNCDESC** ppFuncDesc) override
297         {
298                 if (index >= m_methodData.size())
299                         return E_INVALIDARG;
300                 auto* pFuncDesc = new FUNCDESC();
301                 const METHODDATA& methodData = m_methodData[index];
302                 pFuncDesc->funckind = FUNC_DISPATCH;
303                 pFuncDesc->invkind = static_cast<INVOKEKIND>(methodData.wFlags);
304                 pFuncDesc->wFuncFlags = 0;
305                 pFuncDesc->cParams = static_cast<short>(methodData.cArgs);
306                 pFuncDesc->memid = methodData.dispid;
307                 pFuncDesc->callconv = methodData.cc;
308                 if (methodData.cArgs > 0)
309                 {
310                         pFuncDesc->lprgelemdescParam = new ELEMDESC[methodData.cArgs];
311                         for (int i = 0; i < methodData.cArgs; ++i)
312                                 pFuncDesc->lprgelemdescParam[i].tdesc.vt = methodData.ppdata[i].vt;
313                 }
314                 pFuncDesc->elemdescFunc.tdesc.vt = methodData.vtReturn;
315                 *ppFuncDesc = pFuncDesc;
316                 return S_OK;
317         }
318         
319         HRESULT STDMETHODCALLTYPE GetVarDesc(UINT index, VARDESC** ppVarDesc) override
320         {
321                 return E_NOTIMPL;
322         }
323         
324         HRESULT STDMETHODCALLTYPE GetNames(MEMBERID memid, BSTR *rgBstrNames, UINT cMaxNames, UINT *pcNames) override
325         {
326                 if (m_mapDispIdToIndex.find(memid) == m_mapDispIdToIndex.end())
327                         return E_INVALIDARG;
328                 const METHODDATA& methodData = m_methodData[m_mapDispIdToIndex[memid]];
329                 for (int i = 0; i < cMaxNames && i < methodData.cArgs + 1; i++)
330                 {
331                         if (i == 0)
332                                 rgBstrNames[i] = SysAllocString(methodData.szName);
333                         else
334                                 rgBstrNames[i] = SysAllocString(methodData.ppdata[i - 1].szName);
335                         *pcNames = i + 1;
336                 }
337                 return S_OK;
338         }
339         
340         HRESULT STDMETHODCALLTYPE GetRefTypeOfImplType(UINT index, HREFTYPE *pRefType) override
341         {
342                 return E_NOTIMPL;
343         }
344
345         HRESULT STDMETHODCALLTYPE GetImplTypeFlags(UINT index, INT *pImplTypeFlags) override
346         {
347                 return E_NOTIMPL;
348         }
349         
350         HRESULT STDMETHODCALLTYPE GetIDsOfNames(LPOLESTR* rgszNames, UINT cNames, MEMBERID* pMemId) override
351         {
352                 return GetIDsOfNames(IID_NULL, rgszNames, cNames, 0, pMemId);
353         }
354         
355         HRESULT STDMETHODCALLTYPE Invoke(PVOID pvInstance, MEMBERID memid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) override
356         {
357                 return reinterpret_cast<IDispatch*>(pvInstance)->Invoke(memid, IID_NULL, 0, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
358         }
359         
360         HRESULT STDMETHODCALLTYPE GetDocumentation(MEMBERID memid, BSTR *pBstrName, BSTR *pBstrDocString, DWORD *pdwHelpContext, BSTR *pBstrHelpFile) override
361         {
362                 return E_NOTIMPL;
363         }
364         
365         HRESULT STDMETHODCALLTYPE GetDllEntry(MEMBERID memid, INVOKEKIND invKind, BSTR *pBstrDllName, BSTR *pBstrName, WORD *pwOrdinal)
366         {
367                 return E_NOTIMPL;
368         }
369         
370         HRESULT STDMETHODCALLTYPE GetRefTypeInfo(HREFTYPE hRefType, ITypeInfo **ppTInfo) override
371         {
372                 return E_NOTIMPL;
373         }
374         
375         HRESULT STDMETHODCALLTYPE AddressOfMember(MEMBERID memid, INVOKEKIND invKind, PVOID *ppv) override
376         {
377                 return E_NOTIMPL;
378         }
379         
380         HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, REFIID riid, PVOID *ppvObj) override
381         {
382                 return E_NOTIMPL;
383         }
384         
385         HRESULT STDMETHODCALLTYPE GetMops(MEMBERID memid, BSTR *pBstrMops) override
386         {
387                 return E_NOTIMPL;
388         }
389         
390         HRESULT STDMETHODCALLTYPE GetContainingTypeLib(ITypeLib **ppTLib, UINT *pIndex) override
391         {
392                 return E_NOTIMPL;
393         }
394         
395         void STDMETHODCALLTYPE ReleaseTypeAttr(TYPEATTR *pTypeAttr) override
396         {
397                 delete pTypeAttr;
398         }
399         
400         void STDMETHODCALLTYPE ReleaseFuncDesc(FUNCDESC *pFuncDesc) override
401         {
402                 delete pFuncDesc->lprgelemdescParam;
403                 delete pFuncDesc;
404         }
405         
406         void STDMETHODCALLTYPE ReleaseVarDesc(VARDESC *pVarDesc) override
407         {
408         }
409         
410         virtual HRESULT STDMETHODCALLTYPE PrediffFile(BSTR fileSrc, BSTR fileDst, VARIANT_BOOL* pbChanged, VARIANT_BOOL* pbSuccess)
411         {
412                 *pbSuccess = VARIANT_FALSE;
413                 return E_NOTIMPL;
414         }
415
416         virtual HRESULT STDMETHODCALLTYPE PackFile(BSTR fileSrc, BSTR fileDst, VARIANT_BOOL* pbChanged, INT subcode, VARIANT_BOOL* pbSuccess)
417         {
418                 *pbSuccess = VARIANT_FALSE;
419                 return E_NOTIMPL;
420         }
421
422         virtual HRESULT STDMETHODCALLTYPE UnpackFile(BSTR fileSrc, BSTR fileDst, VARIANT_BOOL* pbChanged, INT* pSubcode, VARIANT_BOOL* pbSuccess)
423         {
424                 *pbSuccess = VARIANT_FALSE;
425                 return E_NOTIMPL;
426         }
427
428         virtual HRESULT STDMETHODCALLTYPE IsFolder(BSTR file, VARIANT_BOOL* pbFolder)
429         {
430                 *pbFolder = VARIANT_FALSE;
431                 return E_NOTIMPL;
432         }
433
434         virtual HRESULT STDMETHODCALLTYPE PackFolder(BSTR folderSrc, BSTR fileDst, VARIANT_BOOL* pbChanged, INT subcode, VARIANT_BOOL* pbSuccess)
435         {
436                 *pbSuccess = VARIANT_FALSE;
437                 return E_NOTIMPL;
438         }
439
440         virtual HRESULT STDMETHODCALLTYPE UnpackFolder(BSTR fileSrc, BSTR folderDst, VARIANT_BOOL* pbChanged, INT* pSubcode, VARIANT_BOOL* pbSuccess)
441         {
442                 *pbSuccess = VARIANT_FALSE;
443                 return E_NOTIMPL;
444         }
445
446         virtual HRESULT STDMETHODCALLTYPE ShowSettingsDialog(VARIANT_BOOL* pbHandled)
447         {
448                 *pbHandled = VARIANT_FALSE;
449                 return E_NOTIMPL;
450         }
451
452         virtual HRESULT STDMETHODCALLTYPE get_PluginEvent(BSTR* pVal)
453         {
454                 *pVal = SysAllocString(m_sEvent.c_str());
455                 return S_OK;
456         }
457
458         virtual HRESULT STDMETHODCALLTYPE get_PluginDescription(BSTR* pVal)
459         {
460                 *pVal = SysAllocString(m_sDescription.c_str());
461                 return S_OK;
462         }
463
464         virtual HRESULT STDMETHODCALLTYPE get_PluginIsAutomatic(VARIANT_BOOL* pVal)
465         {
466                 *pVal = m_bIsAutomatic ? -1 : 0;
467                 return S_OK;
468         }
469
470         virtual HRESULT STDMETHODCALLTYPE get_PluginFileFilters(BSTR* pVal)
471         {
472                 *pVal = SysAllocString(m_sFileFilters.c_str());
473                 return S_OK;
474         }
475
476         virtual HRESULT STDMETHODCALLTYPE get_PluginUnpackedFileExtension(BSTR* pVal)
477         {
478                 *pVal = SysAllocString(m_sUnpackedFileExtension.c_str());
479                 return S_OK;
480         }
481
482         bool AddFunction(const std::wstring& name, ScriptFuncPtr pFunc)
483         {
484                 static PARAMDATA paramData_ScriptFunc[] =
485                 { {L"text", VT_BSTR} };
486                 unsigned index = static_cast<int>(m_methodData.size());
487                 DISPID dispid = static_cast<DISPID>(m_methodData.size()) + 100;
488                 m_mapNameToIndex.insert_or_assign(name, index);
489                 m_mapDispIdToIndex.insert_or_assign(dispid, index);
490                 m_mapScriptFuncs.insert_or_assign(dispid, std::pair{name, pFunc});
491                 METHODDATA methodData =
492                 {
493                         const_cast<OLECHAR *>(m_mapScriptFuncs[dispid].first.c_str()), paramData_ScriptFunc, dispid, index, CC_STDCALL, 1, DISPATCH_METHOD, VT_BSTR
494                 };
495                 m_methodData.emplace_back(methodData);
496                 return true;
497         }
498
499 protected:
500         int m_nRef;
501         std::map<std::wstring, int> m_mapNameToIndex;
502         std::map<DISPID, int> m_mapDispIdToIndex;
503         std::vector<METHODDATA> m_methodData;
504         std::map<DISPID, std::pair<std::wstring, ScriptFuncPtr>> m_mapScriptFuncs;
505         std::wstring m_sEvent;
506         std::wstring m_sDescription;
507         std::wstring m_sFileFilters;
508         std::wstring m_sUnpackedFileExtension;
509         bool m_bIsAutomatic;
510 };
511