OSDN Git Service

8990d6cf29c3072d939b0dec8267aca7f1a1d7b5
[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_UnpackFile,
15                 DISPID_PackFile,
16                 DISPID_ShowSettingsDialog,
17         };
18         struct MemberInfo
19         {
20                 std::wstring name;
21                 DISPID id;
22                 short params;
23                 short flags;
24                 HRESULT (STDMETHODCALLTYPE *pFunc)(IDispatch *pDispatch, BSTR bstrText, BSTR* pbstrResult);
25         };
26
27         WinMergePluginBase(const std::wstring& sEvent, const std::wstring& sDescription = L"",
28                 const std::wstring& sFileFilters = L"", bool bIsAutomatic = true)
29                 : m_nRef(0)
30                 , m_sEvent(sEvent)
31                 , m_sDescription(sDescription)
32                 , m_sFileFilters(sFileFilters)
33                 , m_bIsAutomatic(bIsAutomatic)
34         {
35                 static const MemberInfo memberInfo[] =
36                 {
37                         { L"PluginEvent",        DISPID_PluginEvent,        0, DISPATCH_PROPERTYGET },
38                         { L"PluginDescription",  DISPID_PluginDescription,  0, DISPATCH_PROPERTYGET },
39                         { L"PluginIsAutomatic",  DISPID_PluginIsAutomatic,  0, DISPATCH_PROPERTYGET },
40                         { L"PluginFileFilters",  DISPID_PluginFileFilters,  0, DISPATCH_PROPERTYGET },
41                         { L"UnpackFile",         DISPID_UnpackFile,         4, DISPATCH_METHOD },
42                         { L"PackFile",           DISPID_PackFile ,          4, DISPATCH_METHOD },
43                         { L"ShowSettingsDialog", DISPID_ShowSettingsDialog, 0, DISPATCH_METHOD },
44                 };
45                 for (auto item : memberInfo)
46                 {
47                         if (item.id == DISPID_PluginIsAutomatic && sEvent == _T("EDITOR_SCRIPT"))
48                                 break;
49                         m_mapNameToIndex.insert_or_assign(item.name, static_cast<int>(m_memberInfo.size()));
50                         m_mapDispIdToIndex.insert_or_assign(item.id, static_cast<int>(m_memberInfo.size()));
51                         m_memberInfo.push_back(item);
52                 }
53         }
54
55         virtual ~WinMergePluginBase() {}
56
57         HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override
58         {
59                 return E_NOTIMPL;
60         }
61
62         ULONG STDMETHODCALLTYPE AddRef(void) override
63         {
64                 return ++m_nRef;
65         }
66
67         ULONG STDMETHODCALLTYPE Release(void) override
68         {
69                 if (--m_nRef == 0)
70                 {
71                         delete this;
72                         return 0;
73                 }
74                 return m_nRef;
75         }
76
77         HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT* pctinfo) override
78         {
79                 *pctinfo = static_cast<UINT>(m_memberInfo.size());
80                 return S_OK;
81         }
82
83         HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) override
84         {
85                 *ppTInfo = this;
86                 (*ppTInfo)->AddRef();
87                 return S_OK;
88         }
89
90         HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) override
91         {
92                 for (unsigned i = 0; i < cNames; ++i)
93                 {
94                         auto it = m_mapNameToIndex.find(rgszNames[i]);
95                         if (it == m_mapNameToIndex.end())
96                                 return DISP_E_UNKNOWNNAME;
97                         rgDispId[i] = m_memberInfo[it->second].id;
98                 }
99                 return S_OK;
100         }
101
102         HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) override
103         {
104                 if (!pDispParams)
105                         return DISP_E_BADVARTYPE;
106                 HRESULT hr = E_NOTIMPL;
107                 if (wFlags == DISPATCH_METHOD)
108                 {
109                         switch (dispIdMember)
110                         {
111                         case DISPID_UnpackFile:
112                         {
113                                 BSTR fileSrc = pDispParams->rgvarg[3].bstrVal;
114                                 BSTR fileDst = pDispParams->rgvarg[2].bstrVal;
115                                 VARIANT_BOOL* pbChanged = pDispParams->rgvarg[1].pboolVal;
116                                 INT* pSubcode = &pDispParams->rgvarg[0].intVal;
117                                 VARIANT_BOOL* pbSuccess = &pVarResult->boolVal;
118                                 hr = UnpackFile(fileSrc, fileDst, pbChanged, pSubcode, pbSuccess);
119                                 break;
120                         }
121                         case DISPID_PackFile:
122                         {
123                                 BSTR fileSrc = pDispParams->rgvarg[3].bstrVal;
124                                 BSTR fileDst = pDispParams->rgvarg[2].bstrVal;
125                                 VARIANT_BOOL* pbChanged = pDispParams->rgvarg[1].pboolVal;
126                                 INT subcode = pDispParams->rgvarg[0].intVal;
127                                 VARIANT_BOOL* pbSuccess = &pVarResult->boolVal;
128                                 hr = PackFile(fileSrc, fileDst, pbChanged, subcode, pbSuccess);
129                                 break;
130                         }
131                         case DISPID_ShowSettingsDialog:
132                                 hr = ShowSettingsDialog(&pVarResult->boolVal);
133                                 break;
134                         default:
135                                 if (m_mapDispIdToIndex.find(dispIdMember) != m_mapDispIdToIndex.end())
136                                 {
137                                         BSTR bstrText = pDispParams->rgvarg[0].bstrVal;
138                                         pVarResult->vt = VT_BSTR;
139                                         BSTR* pbstrResult = &pVarResult->bstrVal;
140                                         hr = m_memberInfo[m_mapDispIdToIndex[dispIdMember]].pFunc(this, bstrText, pbstrResult);
141                                 }
142                                 break;
143                         }
144                 }
145                 else if (wFlags == DISPATCH_PROPERTYGET)
146                 {
147                         switch (dispIdMember)
148                         {
149                         case DISPID_PluginFileFilters:
150                                 pVarResult->vt = VT_BSTR;
151                                 hr = get_PluginFileFilters(&pVarResult->bstrVal);
152                                 break;
153                         case DISPID_PluginIsAutomatic:
154                                 pVarResult->vt = VT_BOOL;
155                                 hr = get_PluginIsAutomatic(&pVarResult->boolVal);
156                                 break;
157                         case DISPID_PluginDescription:
158                                 pVarResult->vt = VT_BSTR;
159                                 hr = get_PluginDescription(&pVarResult->bstrVal);
160                                 break;
161                         case DISPID_PluginEvent:
162                                 pVarResult->vt = VT_BSTR;
163                                 hr = get_PluginEvent(&pVarResult->bstrVal);
164                                 break;
165                         }
166                 }
167                 return hr;
168         }
169
170         HRESULT STDMETHODCALLTYPE GetTypeAttr(TYPEATTR** ppTypeAttr) override
171         {
172                 auto* pTypeAttr = new TYPEATTR();
173                 pTypeAttr->cFuncs = static_cast<WORD>(m_memberInfo.size());
174                 *ppTypeAttr = pTypeAttr;
175                 return S_OK;
176         }
177         
178         HRESULT STDMETHODCALLTYPE GetTypeComp(ITypeComp** ppTComp) override
179         {
180                 return E_NOTIMPL;
181         }
182         
183         HRESULT STDMETHODCALLTYPE GetFuncDesc(UINT index, FUNCDESC** ppFuncDesc) override
184         {
185                 if (index >= m_memberInfo.size())
186                         return E_INVALIDARG;
187                 auto* pFuncDesc = new FUNCDESC();
188                 pFuncDesc->funckind = FUNC_DISPATCH;
189                 pFuncDesc->invkind = static_cast<INVOKEKIND>(m_memberInfo[index].flags);
190                 pFuncDesc->wFuncFlags = 0;
191                 pFuncDesc->cParams = m_memberInfo[index].params;
192                 pFuncDesc->memid = m_memberInfo[index].id;
193                 pFuncDesc->callconv = CC_STDCALL;
194                 *ppFuncDesc = pFuncDesc;
195                 return S_OK;
196         }
197         
198         HRESULT STDMETHODCALLTYPE GetVarDesc(UINT index, VARDESC** ppVarDesc) override
199         {
200                 return E_NOTIMPL;
201         }
202         
203         HRESULT STDMETHODCALLTYPE GetNames(MEMBERID memid, BSTR *rgBstrNames, UINT cMaxNames, UINT *pcNames) override
204         {
205                 if (m_mapDispIdToIndex.find(memid) == m_mapDispIdToIndex.end())
206                         return E_INVALIDARG;
207                 *rgBstrNames = SysAllocString(m_memberInfo[m_mapDispIdToIndex[memid]].name.c_str());
208                 *pcNames = 1;
209                 return S_OK;
210         }
211         
212         HRESULT STDMETHODCALLTYPE GetRefTypeOfImplType(UINT index, HREFTYPE *pRefType) override
213         {
214                 return E_NOTIMPL;
215         }
216
217         HRESULT STDMETHODCALLTYPE GetImplTypeFlags(UINT index, INT *pImplTypeFlags) override
218         {
219                 return E_NOTIMPL;
220         }
221         
222         HRESULT STDMETHODCALLTYPE GetIDsOfNames(LPOLESTR* rgszNames, UINT cNames, MEMBERID* pMemId) override
223         {
224                 return GetIDsOfNames(IID_NULL, rgszNames, cNames, 0, pMemId);
225         }
226         
227         HRESULT STDMETHODCALLTYPE Invoke(PVOID pvInstance, MEMBERID memid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) override
228         {
229                 return reinterpret_cast<IDispatch*>(pvInstance)->Invoke(memid, IID_NULL, 0, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
230         }
231         
232         HRESULT STDMETHODCALLTYPE GetDocumentation(MEMBERID memid, BSTR *pBstrName, BSTR *pBstrDocString, DWORD *pdwHelpContext, BSTR *pBstrHelpFile) override
233         {
234                 return E_NOTIMPL;
235         }
236         
237         HRESULT STDMETHODCALLTYPE GetDllEntry(MEMBERID memid, INVOKEKIND invKind, BSTR *pBstrDllName, BSTR *pBstrName, WORD *pwOrdinal)
238         {
239                 return E_NOTIMPL;
240         }
241         
242         HRESULT STDMETHODCALLTYPE GetRefTypeInfo(HREFTYPE hRefType, ITypeInfo **ppTInfo) override
243         {
244                 return E_NOTIMPL;
245         }
246         
247         HRESULT STDMETHODCALLTYPE AddressOfMember(MEMBERID memid, INVOKEKIND invKind, PVOID *ppv) override
248         {
249                 return E_NOTIMPL;
250         }
251         
252         HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, REFIID riid, PVOID *ppvObj) override
253         {
254                 return E_NOTIMPL;
255         }
256         
257         HRESULT STDMETHODCALLTYPE GetMops(MEMBERID memid, BSTR *pBstrMops) override
258         {
259                 return E_NOTIMPL;
260         }
261         
262         HRESULT STDMETHODCALLTYPE GetContainingTypeLib(ITypeLib **ppTLib, UINT *pIndex) override
263         {
264                 return E_NOTIMPL;
265         }
266         
267         void STDMETHODCALLTYPE ReleaseTypeAttr(TYPEATTR *pTypeAttr) override
268         {
269                 delete pTypeAttr;
270         }
271         
272         void STDMETHODCALLTYPE ReleaseFuncDesc(FUNCDESC *pFuncDesc) override
273         {
274                 delete pFuncDesc;
275         }
276         
277         void STDMETHODCALLTYPE ReleaseVarDesc(VARDESC *pVarDesc) override
278         {
279         }
280         
281         virtual HRESULT STDMETHODCALLTYPE PackFile(BSTR fileSrc, BSTR fileDst, VARIANT_BOOL* pbChanged, INT subcode, VARIANT_BOOL* pbSuccess)
282         {
283                 *pbSuccess = VARIANT_FALSE;
284                 return E_NOTIMPL;
285         }
286
287         virtual HRESULT STDMETHODCALLTYPE UnpackFile(BSTR fileSrc, BSTR fileDst, VARIANT_BOOL* pbChanged, INT* pSubcode, VARIANT_BOOL* pbSuccess)
288         {
289                 *pbSuccess = VARIANT_FALSE;
290                 return E_NOTIMPL;
291         }
292
293         virtual HRESULT STDMETHODCALLTYPE ShowSettingsDialog(VARIANT_BOOL* pbHandled)
294         {
295                 *pbHandled = VARIANT_FALSE;
296                 return E_NOTIMPL;
297         }
298
299         virtual HRESULT STDMETHODCALLTYPE get_PluginIsAutomatic(VARIANT_BOOL* pVal)
300         {
301                 *pVal = m_bIsAutomatic ? -1 : 0;
302                 return S_OK;
303         }
304
305         virtual HRESULT STDMETHODCALLTYPE get_PluginFileFilters(BSTR* pVal)
306         {
307                 *pVal = SysAllocString(m_sFileFilters.c_str());
308                 return S_OK;
309         }
310
311         virtual HRESULT STDMETHODCALLTYPE get_PluginDescription(BSTR* pVal)
312         {
313                 *pVal = SysAllocString(m_sDescription.c_str());
314                 return S_OK;
315         }
316
317         virtual HRESULT STDMETHODCALLTYPE get_PluginEvent(BSTR* pVal)
318         {
319                 *pVal = SysAllocString(m_sEvent.c_str());
320                 return S_OK;
321         }
322
323         bool AddFunction(const std::wstring& name, HRESULT(STDMETHODCALLTYPE* pFunc)(IDispatch *pDispatch, BSTR bstrText, BSTR* pbstrResult))
324         {
325                 DISPID dispid = static_cast<DISPID>(m_memberInfo.size()) + 100;
326                 m_mapNameToIndex.insert_or_assign(name, static_cast<int>(m_memberInfo.size()));
327                 m_mapDispIdToIndex.insert_or_assign(dispid, static_cast<int>(m_memberInfo.size()));
328                 m_memberInfo.emplace_back(MemberInfo{ name, dispid, 1, DISPATCH_METHOD, pFunc });
329                 return true;
330         }
331
332 protected:
333         int m_nRef;
334         std::map<std::wstring, int> m_mapNameToIndex;
335         std::map<DISPID, int> m_mapDispIdToIndex;
336         std::vector<MemberInfo> m_memberInfo;
337         std::wstring m_sEvent;
338         std::wstring m_sDescription;
339         std::wstring m_sFileFilters;
340         bool m_bIsAutomatic;
341 };
342