OSDN Git Service

Allow NUL and \\.\NUL in paths specified as command line arguments (#2056)
[winmerge-jp/winmerge-jp.git] / Src / WinMergePluginBase.h
1 #pragma once
2
3 #include <oleauto.h>
4 #include <string>
5 #include <vector>
6 #include <map>
7
8 class WinMergePluginBase : public IDispatch, public ITypeInfo
9 {
10 public:
11         enum
12         {
13                 DISPID_PluginEvent = 1,
14                 DISPID_PluginDescription,
15                 DISPID_PluginIsAutomatic,
16                 DISPID_PluginFileFilters,
17                 DISPID_PluginUnpackedFileExtension,
18                 DISPID_PluginExtendedProperties,
19                 DISPID_PluginArguments,
20                 DISPID_PluginVariables,
21                 DISPID_PrediffFile,
22                 DISPID_UnpackFile,
23                 DISPID_PackFile,
24                 DISPID_IsFolder,
25                 DISPID_UnpackFolder,
26                 DISPID_PackFolder,
27                 DISPID_ShowSettingsDialog,
28         };
29         using ScriptFuncPtr = HRESULT(STDMETHODCALLTYPE*)(IDispatch* pDispatch, BSTR bstrText, BSTR* pbstrResult);
30
31         WinMergePluginBase(const std::wstring& sEvent, const std::wstring& sDescription = L"",
32                 const std::wstring& sFileFilters = L"", const std::wstring& sUnpackedFileExtension = L"", 
33                 const std::wstring& sExtendedProperties = L"", const std::wstring& sArguments = L"", 
34                 bool bIsAutomatic = true)
35                 : m_nRef(0)
36                 , m_sEvent(sEvent)
37                 , m_sDescription(sDescription)
38                 , m_sFileFilters(sFileFilters)
39                 , m_sUnpackedFileExtension(sUnpackedFileExtension)
40                 , m_sExtendedProperties(sExtendedProperties)
41                 , m_sArguments(sArguments)
42                 , m_bIsAutomatic(bIsAutomatic)
43         {
44                 static PARAMDATA paramData_Prediff[] =
45                 { {L"fileSrc", VT_BSTR}, {L"fileDst", VT_BSTR}, {L"pbChanged", VT_BOOL | VT_BYREF}, };
46                 static PARAMDATA paramData_UnpackFile[] =
47                 { {L"fileSrc", VT_BSTR}, {L"fileDst", VT_BSTR}, {L"pbChanged", VT_BOOL | VT_BYREF}, {L"pSubcode", VT_I4 | VT_BYREF}, };
48                 static PARAMDATA paramData_PackFile[] =
49                 { {L"fileSrc", VT_BSTR}, {L"fileDst", VT_BSTR}, {L"pbChanged", VT_BOOL | VT_BYREF}, {L"subcode", VT_I4}, };
50                 static PARAMDATA paramData_IsFolder[] =
51                 { {L"fileSrc", VT_BSTR}, };
52                 static PARAMDATA paramData_Arguments[] =
53                 { {L"args", VT_BSTR}, };
54                 static PARAMDATA paramData_Variables[] =
55                 { {L"vars", VT_BSTR}, };
56                 static PARAMDATA paramData_UnpackFolder[] =
57                 { {L"fileSrc", VT_BSTR}, {L"folderDst", VT_BSTR}, {L"pbChanged", VT_BOOL | VT_BYREF}, {L"pSubcode", VT_I4 | VT_BYREF}, };
58                 static PARAMDATA paramData_PackFolder[] =
59                 { {L"folderSrc", VT_BSTR}, {L"fileDst", VT_BSTR}, {L"pbChanged", VT_BOOL | VT_BYREF}, {L"subcode", VT_I4}, };
60                 static METHODDATA methodData_FILE_PREDIFF[] =
61                 {
62                         { L"PluginEvent",                 nullptr,                DISPID_PluginEvent,                 0, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
63                         { L"PluginDescription",           nullptr,                DISPID_PluginDescription,           1, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
64                         { L"PluginIsAutomatic",           nullptr,                DISPID_PluginIsAutomatic,           2, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BOOL },
65                         { L"PluginFileFilters",           nullptr,                DISPID_PluginFileFilters,           3, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
66                         { L"PluginExtendedProperties",    nullptr,                DISPID_PluginExtendedProperties,    4, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
67                         { L"PluginArguments",             nullptr,                DISPID_PluginArguments,             5, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
68                         { L"PluginArguments",             paramData_Arguments,    DISPID_PluginArguments,             5, CC_STDCALL, 1, DISPATCH_PROPERTYPUT, VT_VOID },
69                         { L"PluginVariables",             nullptr,                DISPID_PluginVariables,             6, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
70                         { L"PluginVariables",             paramData_Variables,    DISPID_PluginVariables,             6, CC_STDCALL, 1, DISPATCH_PROPERTYPUT, VT_VOID },
71                         { L"PrediffFile",                 paramData_Prediff,      DISPID_PrediffFile,                 7, CC_STDCALL, 3, DISPATCH_METHOD,      VT_BOOL },
72                         { L"ShowSettingsDialog",          nullptr,                DISPID_ShowSettingsDialog,          8, CC_STDCALL, 0, DISPATCH_METHOD,      VT_VOID },
73                 };
74                 static METHODDATA methodData_FILE_PACK_UNPACK[] =
75                 {
76                         { L"PluginEvent",                 nullptr,                DISPID_PluginEvent,                 0, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR  },
77                         { L"PluginDescription",           nullptr,                DISPID_PluginDescription,           1, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR  },
78                         { L"PluginIsAutomatic",           nullptr,                DISPID_PluginIsAutomatic,           2, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BOOL  },
79                         { L"PluginFileFilters",           nullptr,                DISPID_PluginFileFilters,           3, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR  },
80                         { L"PluginExtendedProperties",    nullptr,                DISPID_PluginExtendedProperties,    4, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR  },
81                         { L"PluginUnpackedFileExtension", nullptr,                DISPID_PluginUnpackedFileExtension, 5, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR  },
82                         { L"PluginArguments",             nullptr,                DISPID_PluginArguments,             6, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
83                         { L"PluginArguments",             paramData_Arguments,    DISPID_PluginArguments,             6, CC_STDCALL, 1, DISPATCH_PROPERTYPUT, VT_VOID },
84                         { L"PluginVariables",             nullptr,                DISPID_PluginVariables,             7, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
85                         { L"PluginVariables",             paramData_Variables,    DISPID_PluginVariables,             7, CC_STDCALL, 1, DISPATCH_PROPERTYPUT, VT_VOID },
86                         { L"UnpackFile",                  paramData_UnpackFile,   DISPID_UnpackFile,                  8, CC_STDCALL, 4, DISPATCH_METHOD,      VT_BOOL  },
87                         { L"PackFile",                    paramData_PackFile,     DISPID_PackFile ,                   9, CC_STDCALL, 4, DISPATCH_METHOD,      VT_BOOL  },
88                         { L"ShowSettingsDialog",          nullptr,                DISPID_ShowSettingsDialog,         10, CC_STDCALL, 0, DISPATCH_METHOD,      VT_VOID  },
89                 };
90                 static METHODDATA methodData_FILE_FOLDER_PACK_UNPACK[] =
91                 {
92                         { L"PluginEvent",                 nullptr,                DISPID_PluginEvent,                 0, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
93                         { L"PluginDescription",           nullptr,                DISPID_PluginDescription,           1, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
94                         { L"PluginIsAutomatic",           nullptr,                DISPID_PluginIsAutomatic,           2, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BOOL },
95                         { L"PluginFileFilters",           nullptr,                DISPID_PluginFileFilters,           3, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
96                         { L"PluginExtendedProperties",    nullptr,                DISPID_PluginExtendedProperties,    4, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
97                         { L"PluginUnpackedFileExtension", nullptr,                DISPID_PluginUnpackedFileExtension, 5, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
98                         { L"PluginArguments",             nullptr,                DISPID_PluginArguments,             6, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
99                         { L"PluginArguments",             paramData_Arguments,    DISPID_PluginArguments,             6, CC_STDCALL, 1, DISPATCH_PROPERTYPUT, VT_VOID },
100                         { L"PluginVariables",             nullptr,                DISPID_PluginVariables,             7, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
101                         { L"PluginVariables",             paramData_Variables,    DISPID_PluginVariables,             7, CC_STDCALL, 1, DISPATCH_PROPERTYPUT, VT_VOID },
102                         { L"UnpackFile",                  paramData_UnpackFile,   DISPID_UnpackFile,                  8, CC_STDCALL, 4, DISPATCH_METHOD,      VT_BOOL },
103                         { L"PackFile",                    paramData_PackFile,     DISPID_PackFile ,                   9, CC_STDCALL, 4, DISPATCH_METHOD,      VT_BOOL },
104                         { L"IsFolder",                    paramData_IsFolder,     DISPID_IsFolder,                   10, CC_STDCALL, 1, DISPATCH_METHOD,      VT_BOOL },
105                         { L"UnpackFolder",                paramData_UnpackFolder, DISPID_UnpackFolder,               11, CC_STDCALL, 4, DISPATCH_METHOD,      VT_BOOL },
106                         { L"PackFolder",                  paramData_PackFolder,   DISPID_PackFolder,                 12, CC_STDCALL, 4, DISPATCH_METHOD,      VT_BOOL },
107                         { L"ShowSettingsDialog",          nullptr,                DISPID_ShowSettingsDialog,         13, CC_STDCALL, 0, DISPATCH_METHOD,      VT_VOID },
108                 };
109                 static METHODDATA methodData_EDITOR_SCRIPT[] =
110                 {
111                         { L"PluginEvent",                 nullptr,                DISPID_PluginEvent,                 0, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
112                         { L"PluginDescription",           nullptr,                DISPID_PluginDescription,           1, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
113                         { L"PluginFileFilters",           nullptr,                DISPID_PluginFileFilters,           2, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
114                         { L"PluginExtendedProperties",    nullptr,                DISPID_PluginExtendedProperties,    3, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
115                         { L"PluginArguments",             nullptr,                DISPID_PluginArguments,             4, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
116                         { L"PluginArguments",             paramData_Arguments,    DISPID_PluginArguments,             4, CC_STDCALL, 1, DISPATCH_PROPERTYPUT, VT_VOID },
117                         { L"PluginVariables",             nullptr,                DISPID_PluginVariables,             5, CC_STDCALL, 0, DISPATCH_PROPERTYGET, VT_BSTR },
118                         { L"PluginVariables",             paramData_Variables,    DISPID_PluginVariables,             5, CC_STDCALL, 1, DISPATCH_PROPERTYPUT, VT_VOID },
119                 };
120                 const METHODDATA* pMethodData;
121                 size_t methodDataCount = 0;
122                 if (sEvent == L"FILE_PREDIFF")
123                 {
124                         methodDataCount = sizeof(methodData_FILE_PREDIFF) / sizeof(methodData_FILE_PREDIFF[0]);
125                         pMethodData = methodData_FILE_PREDIFF;
126                 }
127                 else if (sEvent == L"FILE_PACK_UNPACK")
128                 {
129                         methodDataCount = sizeof(methodData_FILE_PACK_UNPACK) / sizeof(methodData_FILE_PACK_UNPACK[0]);
130                         pMethodData = methodData_FILE_PACK_UNPACK;
131                 }
132                 else if (sEvent == L"FILE_FOLDER_PACK_UNPACK" || sEvent == L"URL_PACK_UNPACK")
133                 {
134                         methodDataCount = sizeof(methodData_FILE_FOLDER_PACK_UNPACK) / sizeof(methodData_FILE_FOLDER_PACK_UNPACK[0]);
135                         pMethodData = methodData_FILE_FOLDER_PACK_UNPACK;
136                 }
137                 else
138                 {
139                         methodDataCount = sizeof(methodData_EDITOR_SCRIPT) / sizeof(methodData_EDITOR_SCRIPT[0]);
140                         pMethodData = methodData_EDITOR_SCRIPT;
141                 }
142                 for (size_t i = 0; i < methodDataCount; ++i)
143                 {
144                         auto& methodData = pMethodData[i];
145                         m_mapNameToIndex.insert_or_assign(methodData.szName, static_cast<int>(m_methodData.size()));
146                         m_mapDispIdToIndex.insert_or_assign(methodData.dispid, static_cast<int>(m_methodData.size()));
147                         m_methodData.push_back(methodData);
148                 }
149         }
150
151         virtual ~WinMergePluginBase() {}
152
153         HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override
154         {
155                 return E_NOTIMPL;
156         }
157
158         ULONG STDMETHODCALLTYPE AddRef(void) override
159         {
160                 return ++m_nRef;
161         }
162
163         ULONG STDMETHODCALLTYPE Release(void) override
164         {
165                 if (--m_nRef == 0)
166                 {
167                         delete this;
168                         return 0;
169                 }
170                 return m_nRef;
171         }
172
173         HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT* pctinfo) override
174         {
175                 *pctinfo = 1;
176                 return S_OK;
177         }
178
179         HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) override
180         {
181                 *ppTInfo = this;
182                 (*ppTInfo)->AddRef();
183                 return S_OK;
184         }
185
186         HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) override
187         {
188                 for (unsigned i = 0; i < cNames; ++i)
189                 {
190                         auto it = m_mapNameToIndex.find(rgszNames[i]);
191                         if (it == m_mapNameToIndex.end())
192                                 return DISP_E_UNKNOWNNAME;
193                         rgDispId[i] = m_methodData[it->second].dispid;
194                 }
195                 return S_OK;
196         }
197
198         HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) override
199         {
200                 if (!pDispParams)
201                         return DISP_E_BADVARTYPE;
202                 HRESULT hr = E_NOTIMPL;
203                 if (wFlags & DISPATCH_METHOD)
204                 {
205                         switch (dispIdMember)
206                         {
207                         case DISPID_PrediffFile:
208                         {
209                                 BSTR fileSrc = pDispParams->rgvarg[2].bstrVal;
210                                 BSTR fileDst = pDispParams->rgvarg[1].bstrVal;
211                                 VARIANT_BOOL* pbChanged = pDispParams->rgvarg[0].pboolVal;
212                                 VARIANT_BOOL* pbSuccess = &pVarResult->boolVal;
213                                 hr = PrediffFile(fileSrc, fileDst, pbChanged, pbSuccess);
214                                 break;
215                         }
216                         case DISPID_UnpackFile:
217                         {
218                                 BSTR fileSrc = pDispParams->rgvarg[3].bstrVal;
219                                 BSTR fileDst = pDispParams->rgvarg[2].bstrVal;
220                                 VARIANT_BOOL* pbChanged = pDispParams->rgvarg[1].pboolVal;
221                                 INT* pSubcode = pDispParams->rgvarg[0].pintVal;
222                                 VARIANT_BOOL* pbSuccess = &pVarResult->boolVal;
223                                 hr = UnpackFile(fileSrc, fileDst, pbChanged, pSubcode, pbSuccess);
224                                 break;
225                         }
226                         case DISPID_PackFile:
227                         {
228                                 BSTR fileSrc = pDispParams->rgvarg[3].bstrVal;
229                                 BSTR fileDst = pDispParams->rgvarg[2].bstrVal;
230                                 VARIANT_BOOL* pbChanged = pDispParams->rgvarg[1].pboolVal;
231                                 INT subcode = pDispParams->rgvarg[0].intVal;
232                                 VARIANT_BOOL* pbSuccess = &pVarResult->boolVal;
233                                 hr = PackFile(fileSrc, fileDst, pbChanged, subcode, pbSuccess);
234                                 break;
235                         }
236                         case DISPID_IsFolder:
237                         {
238                                 BSTR file = pDispParams->rgvarg[0].bstrVal;
239                                 VARIANT_BOOL* pbSuccess = &pVarResult->boolVal;
240                                 hr = IsFolder(file, pbSuccess);
241                                 break;
242                         }
243                         case DISPID_UnpackFolder:
244                         {
245                                 BSTR fileSrc = pDispParams->rgvarg[3].bstrVal;
246                                 BSTR folderDst = pDispParams->rgvarg[2].bstrVal;
247                                 VARIANT_BOOL* pbChanged = pDispParams->rgvarg[1].pboolVal;
248                                 INT* pSubcode = pDispParams->rgvarg[0].pintVal;
249                                 VARIANT_BOOL* pbSuccess = &pVarResult->boolVal;
250                                 hr = UnpackFolder(fileSrc, folderDst, pbChanged, pSubcode, pbSuccess);
251                                 break;
252                         }
253                         case DISPID_PackFolder:
254                         {
255                                 BSTR folderSrc = pDispParams->rgvarg[3].bstrVal;
256                                 BSTR fileDst = pDispParams->rgvarg[2].bstrVal;
257                                 VARIANT_BOOL* pbChanged = pDispParams->rgvarg[1].pboolVal;
258                                 INT subcode = pDispParams->rgvarg[0].intVal;
259                                 VARIANT_BOOL* pbSuccess = &pVarResult->boolVal;
260                                 hr = PackFolder(folderSrc, fileDst, pbChanged, subcode, pbSuccess);
261                                 break;
262                         }
263                         case DISPID_ShowSettingsDialog:
264                                 hr = ShowSettingsDialog(&pVarResult->boolVal);
265                                 break;
266                         default:
267                                 if (m_mapDispIdToIndex.find(dispIdMember) != m_mapDispIdToIndex.end())
268                                 {
269                                         BSTR bstrText = pDispParams->rgvarg[0].bstrVal;
270                                         pVarResult->vt = VT_BSTR;
271                                         BSTR* pbstrResult = &pVarResult->bstrVal;
272                                         hr = m_mapScriptFuncs[dispIdMember].second(this, bstrText, pbstrResult);
273                                 }
274                                 break;
275                         }
276                 }
277                 else if (wFlags & DISPATCH_PROPERTYGET)
278                 {
279                         switch (dispIdMember)
280                         {
281                         case DISPID_PluginEvent:
282                                 pVarResult->vt = VT_BSTR;
283                                 hr = get_PluginEvent(&pVarResult->bstrVal);
284                                 break;
285                         case DISPID_PluginDescription:
286                                 pVarResult->vt = VT_BSTR;
287                                 hr = get_PluginDescription(&pVarResult->bstrVal);
288                                 break;
289                         case DISPID_PluginIsAutomatic:
290                                 pVarResult->vt = VT_BOOL;
291                                 hr = get_PluginIsAutomatic(&pVarResult->boolVal);
292                                 break;
293                         case DISPID_PluginFileFilters:
294                                 pVarResult->vt = VT_BSTR;
295                                 hr = get_PluginFileFilters(&pVarResult->bstrVal);
296                                 break;
297                         case DISPID_PluginUnpackedFileExtension:
298                                 pVarResult->vt = VT_BSTR;
299                                 hr = get_PluginUnpackedFileExtension(&pVarResult->bstrVal);
300                                 break;
301                         case DISPID_PluginExtendedProperties:
302                                 pVarResult->vt = VT_BSTR;
303                                 hr = get_PluginExtendedProperties(&pVarResult->bstrVal);
304                                 break;
305                         case DISPID_PluginArguments:
306                                 pVarResult->vt = VT_BSTR;
307                                 hr = get_PluginArguments(&pVarResult->bstrVal);
308                                 break;
309                         case DISPID_PluginVariables:
310                                 pVarResult->vt = VT_BSTR;
311                                 hr = get_PluginVariables(&pVarResult->bstrVal);
312                                 break;
313                         }
314                 }
315                 else if (wFlags & DISPATCH_PROPERTYPUT)
316                 {
317                         switch (dispIdMember)
318                         {
319                         case DISPID_PluginArguments:
320                         {
321                                 BSTR bstrArgs = pDispParams->rgvarg[0].bstrVal;
322                                 hr = put_PluginArguments(bstrArgs);
323                                 break;
324                         }
325                         case DISPID_PluginVariables:
326                         {
327                                 BSTR bstrVars = pDispParams->rgvarg[0].bstrVal;
328                                 hr = put_PluginVariables(bstrVars);
329                                 break;
330                         }
331                         }
332                 }
333                 if (hr == DISP_E_EXCEPTION && pExcepInfo)
334                 {
335                         IErrorInfo* pErrorInfo = nullptr;
336                         if (SUCCEEDED(GetErrorInfo(0, &pErrorInfo)))
337                         {
338                                 pErrorInfo->GetDescription(&pExcepInfo->bstrDescription);
339                                 pErrorInfo->GetSource(&pExcepInfo->bstrSource);
340                         }
341                 }
342                 return hr;
343         }
344
345         HRESULT STDMETHODCALLTYPE GetTypeAttr(TYPEATTR** ppTypeAttr) override
346         {
347                 auto* pTypeAttr = new TYPEATTR();
348                 pTypeAttr->cFuncs = static_cast<WORD>(m_methodData.size());
349                 pTypeAttr->typekind = TKIND_DISPATCH;
350                 pTypeAttr->cbAlignment = 8;
351                 *ppTypeAttr = pTypeAttr;
352                 return S_OK;
353         }
354         
355         HRESULT STDMETHODCALLTYPE GetTypeComp(ITypeComp** ppTComp) override
356         {
357                 return E_NOTIMPL;
358         }
359         
360         HRESULT STDMETHODCALLTYPE GetFuncDesc(UINT index, FUNCDESC** ppFuncDesc) override
361         {
362                 if (index >= m_methodData.size())
363                         return E_INVALIDARG;
364                 auto* pFuncDesc = new FUNCDESC();
365                 const METHODDATA& methodData = m_methodData[index];
366                 pFuncDesc->funckind = FUNC_DISPATCH;
367                 pFuncDesc->invkind = static_cast<INVOKEKIND>(methodData.wFlags);
368                 pFuncDesc->wFuncFlags = 0;
369                 pFuncDesc->cParams = static_cast<short>(methodData.cArgs);
370                 pFuncDesc->memid = methodData.dispid;
371                 pFuncDesc->callconv = methodData.cc;
372                 if (methodData.cArgs > 0)
373                 {
374                         pFuncDesc->lprgelemdescParam = new ELEMDESC[methodData.cArgs];
375                         for (int i = 0; i < methodData.cArgs; ++i)
376                                 pFuncDesc->lprgelemdescParam[i].tdesc.vt = methodData.ppdata[i].vt;
377                 }
378                 pFuncDesc->elemdescFunc.tdesc.vt = methodData.vtReturn;
379                 *ppFuncDesc = pFuncDesc;
380                 return S_OK;
381         }
382         
383         HRESULT STDMETHODCALLTYPE GetVarDesc(UINT index, VARDESC** ppVarDesc) override
384         {
385                 return E_NOTIMPL;
386         }
387         
388         HRESULT STDMETHODCALLTYPE GetNames(MEMBERID memid, BSTR *rgBstrNames, UINT cMaxNames, UINT *pcNames) override
389         {
390                 if (m_mapDispIdToIndex.find(memid) == m_mapDispIdToIndex.end())
391                         return E_INVALIDARG;
392                 const METHODDATA& methodData = m_methodData[m_mapDispIdToIndex[memid]];
393                 for (int i = 0; i < cMaxNames && i < methodData.cArgs + 1; i++)
394                 {
395                         if (i == 0)
396                                 rgBstrNames[i] = SysAllocString(methodData.szName);
397                         else
398                                 rgBstrNames[i] = SysAllocString(methodData.ppdata[i - 1].szName);
399                         *pcNames = i + 1;
400                 }
401                 return S_OK;
402         }
403         
404         HRESULT STDMETHODCALLTYPE GetRefTypeOfImplType(UINT index, HREFTYPE *pRefType) override
405         {
406                 return E_NOTIMPL;
407         }
408
409         HRESULT STDMETHODCALLTYPE GetImplTypeFlags(UINT index, INT *pImplTypeFlags) override
410         {
411                 return E_NOTIMPL;
412         }
413         
414         HRESULT STDMETHODCALLTYPE GetIDsOfNames(LPOLESTR* rgszNames, UINT cNames, MEMBERID* pMemId) override
415         {
416                 return GetIDsOfNames(IID_NULL, rgszNames, cNames, 0, pMemId);
417         }
418         
419         HRESULT STDMETHODCALLTYPE Invoke(PVOID pvInstance, MEMBERID memid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) override
420         {
421                 return reinterpret_cast<IDispatch*>(pvInstance)->Invoke(memid, IID_NULL, 0, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
422         }
423         
424         HRESULT STDMETHODCALLTYPE GetDocumentation(MEMBERID memid, BSTR *pBstrName, BSTR *pBstrDocString, DWORD *pdwHelpContext, BSTR *pBstrHelpFile) override
425         {
426                 return E_NOTIMPL;
427         }
428         
429         HRESULT STDMETHODCALLTYPE GetDllEntry(MEMBERID memid, INVOKEKIND invKind, BSTR *pBstrDllName, BSTR *pBstrName, WORD *pwOrdinal)
430         {
431                 return E_NOTIMPL;
432         }
433         
434         HRESULT STDMETHODCALLTYPE GetRefTypeInfo(HREFTYPE hRefType, ITypeInfo **ppTInfo) override
435         {
436                 return E_NOTIMPL;
437         }
438         
439         HRESULT STDMETHODCALLTYPE AddressOfMember(MEMBERID memid, INVOKEKIND invKind, PVOID *ppv) override
440         {
441                 return E_NOTIMPL;
442         }
443         
444         HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, REFIID riid, PVOID *ppvObj) override
445         {
446                 return E_NOTIMPL;
447         }
448         
449         HRESULT STDMETHODCALLTYPE GetMops(MEMBERID memid, BSTR *pBstrMops) override
450         {
451                 return E_NOTIMPL;
452         }
453         
454         HRESULT STDMETHODCALLTYPE GetContainingTypeLib(ITypeLib **ppTLib, UINT *pIndex) override
455         {
456                 return E_NOTIMPL;
457         }
458         
459         void STDMETHODCALLTYPE ReleaseTypeAttr(TYPEATTR *pTypeAttr) override
460         {
461                 delete pTypeAttr;
462         }
463         
464         void STDMETHODCALLTYPE ReleaseFuncDesc(FUNCDESC *pFuncDesc) override
465         {
466                 delete[] pFuncDesc->lprgelemdescParam;
467                 delete pFuncDesc;
468         }
469         
470         void STDMETHODCALLTYPE ReleaseVarDesc(VARDESC *pVarDesc) override
471         {
472         }
473         
474         virtual HRESULT STDMETHODCALLTYPE PrediffFile(BSTR fileSrc, BSTR fileDst, VARIANT_BOOL* pbChanged, VARIANT_BOOL* pbSuccess)
475         {
476                 *pbSuccess = VARIANT_FALSE;
477                 return E_NOTIMPL;
478         }
479
480         virtual HRESULT STDMETHODCALLTYPE PackFile(BSTR fileSrc, BSTR fileDst, VARIANT_BOOL* pbChanged, INT subcode, VARIANT_BOOL* pbSuccess)
481         {
482                 *pbSuccess = VARIANT_FALSE;
483                 return E_NOTIMPL;
484         }
485
486         virtual HRESULT STDMETHODCALLTYPE UnpackFile(BSTR fileSrc, BSTR fileDst, VARIANT_BOOL* pbChanged, INT* pSubcode, VARIANT_BOOL* pbSuccess)
487         {
488                 *pbSuccess = VARIANT_FALSE;
489                 return E_NOTIMPL;
490         }
491
492         virtual HRESULT STDMETHODCALLTYPE IsFolder(BSTR file, VARIANT_BOOL* pbFolder)
493         {
494                 *pbFolder = VARIANT_FALSE;
495                 return E_NOTIMPL;
496         }
497
498         virtual HRESULT STDMETHODCALLTYPE PackFolder(BSTR folderSrc, BSTR fileDst, VARIANT_BOOL* pbChanged, INT subcode, VARIANT_BOOL* pbSuccess)
499         {
500                 *pbSuccess = VARIANT_FALSE;
501                 return E_NOTIMPL;
502         }
503
504         virtual HRESULT STDMETHODCALLTYPE UnpackFolder(BSTR fileSrc, BSTR folderDst, VARIANT_BOOL* pbChanged, INT* pSubcode, VARIANT_BOOL* pbSuccess)
505         {
506                 *pbSuccess = VARIANT_FALSE;
507                 return E_NOTIMPL;
508         }
509
510         virtual HRESULT STDMETHODCALLTYPE ShowSettingsDialog(VARIANT_BOOL* pbHandled)
511         {
512                 *pbHandled = VARIANT_FALSE;
513                 return E_NOTIMPL;
514         }
515
516         virtual HRESULT STDMETHODCALLTYPE get_PluginEvent(BSTR* pVal)
517         {
518                 *pVal = SysAllocString(m_sEvent.c_str());
519                 return S_OK;
520         }
521
522         virtual HRESULT STDMETHODCALLTYPE get_PluginDescription(BSTR* pVal)
523         {
524                 *pVal = SysAllocString(m_sDescription.c_str());
525                 return S_OK;
526         }
527
528         virtual HRESULT STDMETHODCALLTYPE get_PluginIsAutomatic(VARIANT_BOOL* pVal)
529         {
530                 *pVal = m_bIsAutomatic ? -1 : 0;
531                 return S_OK;
532         }
533
534         virtual HRESULT STDMETHODCALLTYPE get_PluginFileFilters(BSTR* pVal)
535         {
536                 *pVal = SysAllocString(m_sFileFilters.c_str());
537                 return S_OK;
538         }
539
540         virtual HRESULT STDMETHODCALLTYPE get_PluginUnpackedFileExtension(BSTR* pVal)
541         {
542                 *pVal = SysAllocString(m_sUnpackedFileExtension.c_str());
543                 return S_OK;
544         }
545
546         virtual HRESULT STDMETHODCALLTYPE get_PluginExtendedProperties(BSTR* pVal)
547         {
548                 *pVal = SysAllocString(m_sExtendedProperties.c_str());
549                 return S_OK;
550         }
551
552         virtual HRESULT STDMETHODCALLTYPE get_PluginArguments(BSTR* pVal)
553         {
554                 *pVal = SysAllocString(m_sArguments.c_str());
555                 return S_OK;
556         }
557
558         virtual HRESULT STDMETHODCALLTYPE put_PluginArguments(BSTR val)
559         {
560                 m_sArguments = std::wstring{ val, SysStringLen(val) };
561                 return S_OK;
562         }
563
564         virtual HRESULT STDMETHODCALLTYPE get_PluginVariables(BSTR* pVal)
565         {
566                 *pVal = SysAllocString(m_sVariables.c_str());
567                 return S_OK;
568         }
569
570         virtual HRESULT STDMETHODCALLTYPE put_PluginVariables(BSTR val)
571         {
572                 m_sVariables = std::wstring{ val, SysStringLen(val) };
573                 return S_OK;
574         }
575
576         bool AddFunction(const std::wstring& name, ScriptFuncPtr pFunc)
577         {
578                 static PARAMDATA paramData_ScriptFunc[] =
579                 { {L"text", VT_BSTR} };
580                 unsigned index = static_cast<int>(m_methodData.size());
581                 DISPID dispid = static_cast<DISPID>(m_methodData.size()) + 100;
582                 m_mapNameToIndex.insert_or_assign(name, index);
583                 m_mapDispIdToIndex.insert_or_assign(dispid, index);
584                 m_mapScriptFuncs.insert_or_assign(dispid, std::pair{name, pFunc});
585                 METHODDATA methodData =
586                 {
587                         const_cast<OLECHAR *>(m_mapScriptFuncs[dispid].first.c_str()), paramData_ScriptFunc, dispid, index, CC_STDCALL, 1, DISPATCH_METHOD, VT_BSTR
588                 };
589                 m_methodData.emplace_back(methodData);
590                 return true;
591         }
592
593 protected:
594         int m_nRef;
595         std::map<std::wstring, int> m_mapNameToIndex;
596         std::map<DISPID, int> m_mapDispIdToIndex;
597         std::vector<METHODDATA> m_methodData;
598         std::map<DISPID, std::pair<std::wstring, ScriptFuncPtr>> m_mapScriptFuncs;
599         std::wstring m_sEvent;
600         std::wstring m_sDescription;
601         std::wstring m_sFileFilters;
602         std::wstring m_sUnpackedFileExtension;
603         std::wstring m_sExtendedProperties;
604         std::wstring m_sArguments;
605         std::wstring m_sVariables;
606         bool m_bIsAutomatic;
607 };
608