OSDN Git Service

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