-
Notifications
You must be signed in to change notification settings - Fork 0
/
typeinfoex.h
216 lines (203 loc) · 5.62 KB
/
typeinfoex.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#ifndef _NEWOBJECTS_ATL_TYPEINFOEX_H_
#define _NEWOBJECTS_ATL_TYPEINFOEX_H_
// This class is a little changed version of the
// CComTypeInfoHolder class found in the MS ATL
// It supports different ways to obtain type info
// depending on the CComTypeInfoHolder parameter:
//
// 0 - Acts as the Normal CComTypeInfoHolder i.e. loading from the registry only
// 1 - Loads only from the module resource
// 2 - Try registry and if not found load from the module
// 3 - Try from the module and if not found then from the registry
//
// Use this class in the IDispatchImpl templates passed as parent
// classes to your components if you want to create components
// capable of working with scripts without registration in the
// system registry
//
// Michael Elfial, newObjects 2001
// http://www.newobjects.com
#ifndef COM_NO_WINDOWS_H
#include "windows.h"
#include "ole2.h"
#endif /*COM_NO_WINDOWS_H*/
template <int nObtainMethod = 1>
class CComTypeInfoHolderModule {
public:
const GUID* m_pguid;
const GUID* m_plibid;
WORD m_wMajor;
WORD m_wMinor;
ITypeInfo* m_pInfo;
long m_dwRef;
struct stringdispid
{
ATL::CComBSTR bstr;
int nLen{};
DISPID id{};
};
stringdispid* m_pMap;
int m_nCount;
public:
HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo)
{
HRESULT hr = S_OK;
if (m_pInfo == NULL)
hr = GetTI(lcid);
*ppInfo = m_pInfo;
if (m_pInfo != NULL)
{
m_pInfo->AddRef();
hr = S_OK;
}
return hr;
}
HRESULT GetTI(LCID lcid);
HRESULT EnsureTI(LCID lcid)
{
HRESULT hr = S_OK;
if (m_pInfo == NULL)
hr = GetTI(lcid);
return hr;
}
// This function is called by the module on exit
// It is registered through _Module.AddTermFunc()
static void __stdcall Cleanup(DWORD_PTR dw)
{
CComTypeInfoHolder* p = (CComTypeInfoHolder*) dw;
if (p->m_pInfo != NULL)
p->m_pInfo->Release();
p->m_pInfo = NULL;
delete [] p->m_pMap;
p->m_pMap = NULL;
}
HRESULT GetTypeInfo(UINT /* itinfo */, LCID lcid, ITypeInfo** pptinfo)
{
HRESULT hRes = E_POINTER;
if (pptinfo != NULL)
hRes = GetTI(lcid, pptinfo);
return hRes;
}
HRESULT GetIDsOfNames(REFIID /* riid */, LPOLESTR* rgszNames, UINT cNames,
LCID lcid, DISPID* rgdispid)
{
HRESULT hRes = EnsureTI(lcid);
if (m_pInfo != NULL)
{
for (int i=0; i<(int)cNames; i++)
{
int n = ocslen(rgszNames[i]);
int j;
for (j=m_nCount-1; j>=0; j--)
{
if ((n == m_pMap[j].nLen) &&
(memcmp(m_pMap[j].bstr, rgszNames[i], m_pMap[j].nLen * sizeof(OLECHAR)) == 0))
{
rgdispid[i] = m_pMap[j].id;
break;
}
}
if (j < 0)
{
hRes = m_pInfo->GetIDsOfNames(rgszNames + i, 1, &rgdispid[i]);
if (FAILED(hRes))
break;
}
}
}
return hRes;
}
HRESULT Invoke(IDispatch* p, DISPID dispidMember, REFIID /* riid */,
LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
HRESULT hRes = EnsureTI(lcid);
if (m_pInfo != NULL)
hRes = m_pInfo->Invoke(p, dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
return hRes;
}
HRESULT LoadNameCache(ITypeInfo* pTypeInfo)
{
TYPEATTR* pta;
HRESULT hr = pTypeInfo->GetTypeAttr(&pta);
if (SUCCEEDED(hr))
{
m_nCount = pta->cFuncs;
m_pMap = m_nCount == 0 ? 0 : new stringdispid[m_nCount];
for (int i=0; i<m_nCount; i++)
{
FUNCDESC* pfd;
if (SUCCEEDED(pTypeInfo->GetFuncDesc(i, &pfd)))
{
CComBSTR bstrName;
if (SUCCEEDED(pTypeInfo->GetDocumentation(pfd->memid, &bstrName, NULL, NULL, NULL)))
{
m_pMap[i].bstr.Attach(bstrName.Detach());
m_pMap[i].nLen = SysStringLen(m_pMap[i].bstr);
m_pMap[i].id = pfd->memid;
}
pTypeInfo->ReleaseFuncDesc(pfd);
}
}
pTypeInfo->ReleaseTypeAttr(pta);
}
return S_OK;
}
};
template <int nObtainMethod>
inline HRESULT CComTypeInfoHolderModule<nObtainMethod>::GetTI(LCID lcid)
{
USES_CONVERSION;
//If this assert occurs then most likely didn't initialize properly
ATLASSERT(m_plibid != NULL && m_pguid != NULL);
ATLASSERT(!::InlineIsEqualGUID(*m_plibid, GUID_NULL) && "Did you forget to pass the LIBID to CComModule::Init?");
if (m_pInfo != NULL)
return S_OK;
HRESULT hRes = E_FAIL;
EnterCriticalSection(&_Module.m_csTypeInfoHolder);
if (m_pInfo == NULL)
{
ITypeLib* pTypeLib{};
hRes = E_FAIL;
TCHAR szModule[_MAX_PATH+10];
LPOLESTR lpszModule;
// Select the way
switch (nObtainMethod) {
case 2: // registry, module
hRes = LoadRegTypeLib(*m_plibid, m_wMajor, m_wMinor, lcid, &pTypeLib);
[[fallthrough]];
case 1: // module
if (SUCCEEDED(hRes)) break;
[[fallthrough]];
case 3: // module, registry
GetModuleFileName(_Module.m_hInstTypeLib, szModule, _MAX_PATH);
lpszModule = T2OLE(szModule);
hRes = LoadTypeLib(lpszModule, &pTypeLib);
if (nObtainMethod == 1) break;
[[fallthrough]];
default:
if (FAILED(hRes)) {
hRes = LoadRegTypeLib(*m_plibid, m_wMajor, m_wMinor, lcid, &pTypeLib);
}
}
if (SUCCEEDED(hRes))
{
CComPtr<ITypeInfo> spTypeInfo;
hRes = pTypeLib->GetTypeInfoOfGuid(*m_pguid, &spTypeInfo);
if (SUCCEEDED(hRes))
{
CComPtr<ITypeInfo> spInfo(spTypeInfo);
CComPtr<ITypeInfo2> spTypeInfo2;
if (SUCCEEDED(spTypeInfo->QueryInterface(&spTypeInfo2)))
spInfo = spTypeInfo2;
LoadNameCache(spInfo);
m_pInfo = spInfo.Detach();
}
pTypeLib->Release();
}
}
LeaveCriticalSection(&_Module.m_csTypeInfoHolder);
_Module.AddTermFunc(Cleanup, (DWORD_PTR)this);
return hRes;
}
#endif // _NEWOBJECTS_ATL_TYPEINFOEX_H_