OSDN Git Service

Add WinMergePluginBase.h (6)
[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].intVal;
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].intVal;
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                 return hr;
272         }
273
274         HRESULT STDMETHODCALLTYPE GetTypeAttr(TYPEATTR** ppTypeAttr) override
275         {
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;
281                 return S_OK;
282         }
283         
284         HRESULT STDMETHODCALLTYPE GetTypeComp(ITypeComp** ppTComp) override
285         {
286                 return E_NOTIMPL;
287         }
288         
289         HRESULT STDMETHODCALLTYPE GetFuncDesc(UINT index, FUNCDESC** ppFuncDesc) override
290         {
291                 if (index >= m_methodData.size())
292                         return E_INVALIDARG;
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)
302                 {
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;
306                 }
307                 pFuncDesc->elemdescFunc.tdesc.vt = methodData.vtReturn;
308                 *ppFuncDesc = pFuncDesc;
309                 return S_OK;
310         }
311         
312         HRESULT STDMETHODCALLTYPE GetVarDesc(UINT index, VARDESC** ppVarDesc) override
313         {
314                 return E_NOTIMPL;
315         }
316         
317         HRESULT STDMETHODCALLTYPE GetNames(MEMBERID memid, BSTR *rgBstrNames, UINT cMaxNames, UINT *pcNames) override
318         {
319                 if (m_mapDispIdToIndex.find(memid) == m_mapDispIdToIndex.end())
320                         return E_INVALIDARG;
321                 const METHODDATA& methodData = m_methodData[m_mapDispIdToIndex[memid]];
322                 for (int i = 0; i < cMaxNames && i < methodData.cArgs + 1; i++)
323                 {
324                         if (i == 0)
325                                 rgBstrNames[i] = SysAllocString(methodData.szName);
326                         else
327                                 rgBstrNames[i] = SysAllocString(methodData.ppdata[i - 1].szName);
328                         *pcNames = i + 1;
329                 }
330                 return S_OK;
331         }
332         
333         HRESULT STDMETHODCALLTYPE GetRefTypeOfImplType(UINT index, HREFTYPE *pRefType) override
334         {
335                 return E_NOTIMPL;
336         }
337
338         HRESULT STDMETHODCALLTYPE GetImplTypeFlags(UINT index, INT *pImplTypeFlags) override
339         {
340                 return E_NOTIMPL;
341         }
342         
343         HRESULT STDMETHODCALLTYPE GetIDsOfNames(LPOLESTR* rgszNames, UINT cNames, MEMBERID* pMemId) override
344         {
345                 return GetIDsOfNames(IID_NULL, rgszNames, cNames, 0, pMemId);
346         }
347         
348         HRESULT STDMETHODCALLTYPE Invoke(PVOID pvInstance, MEMBERID memid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) override
349         {
350                 return reinterpret_cast<IDispatch*>(pvInstance)->Invoke(memid, IID_NULL, 0, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
351         }
352         
353         HRESULT STDMETHODCALLTYPE GetDocumentation(MEMBERID memid, BSTR *pBstrName, BSTR *pBstrDocString, DWORD *pdwHelpContext, BSTR *pBstrHelpFile) override
354         {
355                 return E_NOTIMPL;
356         }
357         
358         HRESULT STDMETHODCALLTYPE GetDllEntry(MEMBERID memid, INVOKEKIND invKind, BSTR *pBstrDllName, BSTR *pBstrName, WORD *pwOrdinal)
359         {
360                 return E_NOTIMPL;
361         }
362         
363         HRESULT STDMETHODCALLTYPE GetRefTypeInfo(HREFTYPE hRefType, ITypeInfo **ppTInfo) override
364         {
365                 return E_NOTIMPL;
366         }
367         
368         HRESULT STDMETHODCALLTYPE AddressOfMember(MEMBERID memid, INVOKEKIND invKind, PVOID *ppv) override
369         {
370                 return E_NOTIMPL;
371         }
372         
373         HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, REFIID riid, PVOID *ppvObj) override
374         {
375                 return E_NOTIMPL;
376         }
377         
378         HRESULT STDMETHODCALLTYPE GetMops(MEMBERID memid, BSTR *pBstrMops) override
379         {
380                 return E_NOTIMPL;
381         }
382         
383         HRESULT STDMETHODCALLTYPE GetContainingTypeLib(ITypeLib **ppTLib, UINT *pIndex) override
384         {
385                 return E_NOTIMPL;
386         }
387         
388         void STDMETHODCALLTYPE ReleaseTypeAttr(TYPEATTR *pTypeAttr) override
389         {
390                 delete pTypeAttr;
391         }
392         
393         void STDMETHODCALLTYPE ReleaseFuncDesc(FUNCDESC *pFuncDesc) override
394         {
395                 delete pFuncDesc->lprgelemdescParam;
396                 delete pFuncDesc;
397         }
398         
399         void STDMETHODCALLTYPE ReleaseVarDesc(VARDESC *pVarDesc) override
400         {
401         }
402         
403         virtual HRESULT STDMETHODCALLTYPE PrediffFile(BSTR fileSrc, BSTR fileDst, VARIANT_BOOL* pbChanged, VARIANT_BOOL* pbSuccess)
404         {
405                 *pbSuccess = VARIANT_FALSE;
406                 return E_NOTIMPL;
407         }
408
409         virtual HRESULT STDMETHODCALLTYPE PackFile(BSTR fileSrc, BSTR fileDst, VARIANT_BOOL* pbChanged, INT subcode, VARIANT_BOOL* pbSuccess)
410         {
411                 *pbSuccess = VARIANT_FALSE;
412                 return E_NOTIMPL;
413         }
414
415         virtual HRESULT STDMETHODCALLTYPE UnpackFile(BSTR fileSrc, BSTR fileDst, VARIANT_BOOL* pbChanged, INT* pSubcode, VARIANT_BOOL* pbSuccess)
416         {
417                 *pbSuccess = VARIANT_FALSE;
418                 return E_NOTIMPL;
419         }
420
421         virtual HRESULT STDMETHODCALLTYPE IsFolder(BSTR file, VARIANT_BOOL* pbFolder)
422         {
423                 *pbFolder = VARIANT_FALSE;
424                 return E_NOTIMPL;
425         }
426
427         virtual HRESULT STDMETHODCALLTYPE PackFolder(BSTR folderSrc, BSTR fileDst, VARIANT_BOOL* pbChanged, INT subcode, VARIANT_BOOL* pbSuccess)
428         {
429                 *pbSuccess = VARIANT_FALSE;
430                 return E_NOTIMPL;
431         }
432
433         virtual HRESULT STDMETHODCALLTYPE UnpackFolder(BSTR fileSrc, BSTR folderDst, VARIANT_BOOL* pbChanged, INT* pSubcode, VARIANT_BOOL* pbSuccess)
434         {
435                 *pbSuccess = VARIANT_FALSE;
436                 return E_NOTIMPL;
437         }
438
439         virtual HRESULT STDMETHODCALLTYPE ShowSettingsDialog(VARIANT_BOOL* pbHandled)
440         {
441                 *pbHandled = VARIANT_FALSE;
442                 return E_NOTIMPL;
443         }
444
445         virtual HRESULT STDMETHODCALLTYPE get_PluginEvent(BSTR* pVal)
446         {
447                 *pVal = SysAllocString(m_sEvent.c_str());
448                 return S_OK;
449         }
450
451         virtual HRESULT STDMETHODCALLTYPE get_PluginDescription(BSTR* pVal)
452         {
453                 *pVal = SysAllocString(m_sDescription.c_str());
454                 return S_OK;
455         }
456
457         virtual HRESULT STDMETHODCALLTYPE get_PluginIsAutomatic(VARIANT_BOOL* pVal)
458         {
459                 *pVal = m_bIsAutomatic ? -1 : 0;
460                 return S_OK;
461         }
462
463         virtual HRESULT STDMETHODCALLTYPE get_PluginFileFilters(BSTR* pVal)
464         {
465                 *pVal = SysAllocString(m_sFileFilters.c_str());
466                 return S_OK;
467         }
468
469         virtual HRESULT STDMETHODCALLTYPE get_PluginUnpackedFileExtension(BSTR* pVal)
470         {
471                 *pVal = SysAllocString(m_sUnpackedFileExtension.c_str());
472                 return S_OK;
473         }
474
475         bool AddFunction(const std::wstring& name, ScriptFuncPtr pFunc)
476         {
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 =
485                 {
486                         const_cast<OLECHAR *>(m_mapScriptFuncs[dispid].first.c_str()), paramData_ScriptFunc, dispid, index, CC_STDCALL, 1, DISPATCH_METHOD, VT_BSTR
487                 };
488                 m_methodData.emplace_back(methodData);
489                 return true;
490         }
491
492 protected:
493         int m_nRef;
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;
502         bool m_bIsAutomatic;
503 };
504