Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

342 lines
9.4 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1993 - 1999.
  5. //
  6. // File: CIDispatchHelper.cpp
  7. //
  8. // Contents: implementation of CIDispatchHelper class
  9. //
  10. //----------------------------------------------------------------------------
  11. #include "priv.h"
  12. #include "CIDispatchHelper.h"
  13. #define TF_IDISPATCH 0
  14. //
  15. // helper function for pulling ITypeInfo out of the specified typelib
  16. //
  17. HRESULT CIDispatchHelper::_LoadTypeInfo(const GUID* rguidTypeLib, LCID lcid, UUID uuid, ITypeInfo** ppITypeInfo)
  18. {
  19. HRESULT hr;
  20. ITypeLib* pITypeLib;
  21. *ppITypeInfo = NULL;
  22. //
  23. // The type libraries are registered under 0 (neutral),
  24. // 7 (German), and 9 (English) with no specific sub-
  25. // language, which would make them 407 or 409 and such.
  26. // If you are sensitive to sub-languages, then use the
  27. // full LCID instead of just the LANGID as done here.
  28. //
  29. hr = LoadRegTypeLib(*rguidTypeLib, 1, 0, PRIMARYLANGID(lcid), &pITypeLib);
  30. //
  31. // If LoadRegTypeLib fails, try loading directly with
  32. // LoadTypeLib, which will register the library for us.
  33. // Note that there's no default case here because the
  34. // prior switch will have filtered lcid already.
  35. //
  36. // NOTE: You should prepend your DIR registry key to the
  37. // .TLB name so you don't depend on it being it the PATH.
  38. // This sample will be updated later to reflect this.
  39. //
  40. if (FAILED(hr))
  41. {
  42. OLECHAR wszPath[MAX_PATH];
  43. #ifdef UNICODE
  44. GetModuleFileName(HINST_THISDLL, wszPath, ARRAYSIZE(wszPath));
  45. #else
  46. TCHAR szPath[MAX_PATH];
  47. GetModuleFileName(HINST_THISDLL, szPath, ARRAYSIZE(szPath));
  48. MultiByteToWideChar(CP_ACP, 0, szPath, -1, wszPath, ARRAYSIZE(wszPath));
  49. #endif
  50. switch (PRIMARYLANGID(lcid))
  51. {
  52. case LANG_NEUTRAL:
  53. case LANG_ENGLISH:
  54. hr = LoadTypeLib(wszPath, &pITypeLib);
  55. break;
  56. }
  57. }
  58. if (SUCCEEDED(hr))
  59. {
  60. // got the type lib, get type info for the interface we want
  61. hr = pITypeLib->GetTypeInfoOfGuid(uuid, ppITypeInfo);
  62. pITypeLib->Release();
  63. }
  64. return hr;
  65. }
  66. //
  67. // IDispatch Interface
  68. //
  69. //
  70. // CIDispatchHelper::GetTypeInfoCount
  71. //
  72. // Purpose:
  73. // Returns the number of type information (ITypeInfo) interfaces
  74. // that the object provides (0 or 1).
  75. //
  76. // Parameters:
  77. // pctInfo UINT * to the location to receive
  78. // the count of interfaces.
  79. //
  80. // Return Value:
  81. // HRESULT NOERROR or a general error code.
  82. //
  83. STDMETHODIMP CIDispatchHelper::GetTypeInfoCount(UINT *pctInfo)
  84. {
  85. // we implement GetTypeInfo so return 1
  86. *pctInfo = 1;
  87. return NOERROR;
  88. }
  89. //
  90. // CIDispatchHelper::GetTypeInfo
  91. //
  92. // Purpose:
  93. // Retrieves type information for the automation interface. This
  94. // is used anywhere that the right ITypeInfo interface is needed
  95. // for whatever LCID is applicable. Specifically, this is used
  96. // from within GetIDsOfNames and Invoke.
  97. //
  98. // Parameters:
  99. // itInfo UINT reserved. Must be zero.
  100. // lcid LCID providing the locale for the type
  101. // information. If the object does not support
  102. // localization, this is ignored.
  103. // ppITypeInfo ITypeInfo ** in which to store the ITypeInfo
  104. // interface for the object.
  105. //
  106. // Return Value:
  107. // HRESULT NOERROR or a general error code.
  108. //
  109. STDMETHODIMP CIDispatchHelper::GetTypeInfo(UINT itInfo, LCID lcid, ITypeInfo** ppITypeInfo)
  110. {
  111. HRESULT hr = S_OK;
  112. ITypeInfo** ppITI;
  113. *ppITypeInfo = NULL;
  114. if (itInfo != 0)
  115. {
  116. return TYPE_E_ELEMENTNOTFOUND;
  117. }
  118. #if 1
  119. // docs say we can ignore lcid if we support only one LCID
  120. // we don't have to return DISP_E_UNKNOWNLCID if we're *ignoring* it
  121. ppITI = &_pITINeutral;
  122. #else
  123. //
  124. // Since we returned one from GetTypeInfoCount, this function
  125. // can be called for a specific locale. We support English
  126. // and neutral (defaults to English) locales. Anything
  127. // else is an error.
  128. //
  129. // After this switch statement, ppITI will point to the proper
  130. // member pITypeInfo. If *ppITI is NULL, we know we need to
  131. // load type information, retrieve the ITypeInfo we want, and
  132. // then store it in *ppITI.
  133. //
  134. switch (PRIMARYLANGID(lcid))
  135. {
  136. case LANG_NEUTRAL:
  137. case LANG_ENGLISH:
  138. ppITI=&_pITINeutral;
  139. break;
  140. default:
  141. hr = DISP_E_UNKNOWNLCID;
  142. }
  143. #endif
  144. if (SUCCEEDED(hr))
  145. {
  146. //Load a type lib if we don't have the information already
  147. if (*ppITI == NULL)
  148. {
  149. ITypeInfo* pITIDisp;
  150. hr = _LoadTypeInfo(_piidTypeLib, lcid, *_piid, &pITIDisp);
  151. if (SUCCEEDED(hr))
  152. {
  153. HREFTYPE hrefType;
  154. // All our IDispatch implementations are DUAL. GetTypeInfoOfGuid
  155. // returns the ITypeInfo of the IDispatch-part only. We need to
  156. // find the ITypeInfo for the dual interface-part.
  157. if (SUCCEEDED(pITIDisp->GetRefTypeOfImplType(0xffffffff, &hrefType)) &&
  158. SUCCEEDED(pITIDisp->GetRefTypeInfo(hrefType, ppITI)))
  159. {
  160. // GetRefTypeInfo should have filled in ppITI with the dual interface
  161. (*ppITI)->AddRef(); // add the ref for our caller
  162. *ppITypeInfo = *ppITI;
  163. pITIDisp->Release();
  164. }
  165. else
  166. {
  167. // I suspect GetRefTypeOfImplType may fail if someone uses
  168. // CIDispatchHelper on a non-dual interface. In this case the
  169. // ITypeInfo we got above is just fine to use.
  170. *ppITI = pITIDisp;
  171. }
  172. }
  173. }
  174. else
  175. {
  176. // we already loaded the type library and we have an ITypeInfo from it
  177. (*ppITI)->AddRef(); // add the ref for our caller
  178. *ppITypeInfo = *ppITI;
  179. }
  180. }
  181. return hr;
  182. }
  183. //
  184. // CIDispatchHelper::GetIDsOfNames
  185. //
  186. // Purpose:
  187. // Converts text names into DISPIDs to pass to Invoke
  188. //
  189. // Parameters:
  190. // riid REFIID reserved. Must be IID_NULL.
  191. // rgszNames OLECHAR ** pointing to the array of names to be
  192. // mapped.
  193. // cNames UINT number of names to be mapped.
  194. // lcid LCID of the locale.
  195. // rgDispID DISPID * caller allocated array containing IDs
  196. // corresponging to those names in rgszNames.
  197. //
  198. // Return Value:
  199. // HRESULT NOERROR or a general error code.
  200. //
  201. STDMETHODIMP CIDispatchHelper::GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgDispID)
  202. {
  203. HRESULT hr;
  204. ITypeInfo* pTI;
  205. if (riid != IID_NULL)
  206. {
  207. return DISP_E_UNKNOWNINTERFACE;
  208. }
  209. // get the right ITypeInfo for lcid.
  210. hr = GetTypeInfo(0, lcid, &pTI);
  211. if (SUCCEEDED(hr))
  212. {
  213. hr = pTI->GetIDsOfNames(rgszNames, cNames, rgDispID);
  214. pTI->Release();
  215. }
  216. return hr;
  217. }
  218. //
  219. // CIDispatchHelper::Invoke
  220. //
  221. // Purpose:
  222. // Calls a method in the dispatch interface or manipulates a
  223. // property.
  224. //
  225. // Parameters:
  226. // dispID DISPID of the method or property of interest.
  227. // riid REFIID reserved, must be IID_NULL.
  228. // lcid LCID of the locale.
  229. // wFlags USHORT describing the context of the invocation.
  230. // pDispParams DISPPARAMS * to the array of arguments.
  231. // pVarResult VARIANT * in which to store the result. Is
  232. // NULL if the caller is not interested.
  233. // pExcepInfo EXCEPINFO * to exception information.
  234. // puArgErr UINT * in which to store the index of an
  235. // invalid parameter if DISP_E_TYPEMISMATCH
  236. // is returned.
  237. //
  238. // Return Value:
  239. // HRESULT NOERROR or a general error code.
  240. //
  241. STDMETHODIMP CIDispatchHelper::Invoke(DISPID dispID, REFIID riid, LCID lcid, unsigned short wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)
  242. {
  243. HRESULT hr;
  244. ITypeInfo *pTI;
  245. //riid is supposed to be IID_NULL always
  246. if (riid != IID_NULL)
  247. {
  248. return(DISP_E_UNKNOWNINTERFACE);
  249. }
  250. // make sure we have an interface to hand off to Invoke
  251. if (_pdisp == NULL)
  252. {
  253. hr = QueryInterface(*_piid, (LPVOID*)&_pdisp);
  254. if (FAILED(hr))
  255. {
  256. return hr;
  257. }
  258. // don't hold a refcount on ourself
  259. _pdisp->Release();
  260. }
  261. // get the ITypeInfo for lcid
  262. hr = GetTypeInfo(0, lcid, &pTI);
  263. if (SUCCEEDED(hr))
  264. {
  265. // clear exceptions
  266. SetErrorInfo(0L, NULL);
  267. // this is exactly what DispInvoke does--so skip the overhead.
  268. hr = pTI->Invoke(_pdisp, dispID, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
  269. pTI->Release();
  270. }
  271. return hr;
  272. }
  273. CIDispatchHelper::CIDispatchHelper(const IID* piid, const IID* piidTypeLib)
  274. {
  275. // the constructor takes a guid that this IDispatch implementation is for
  276. _piid = piid;
  277. // and a guid that tells us which RegTypeLib to load
  278. _piidTypeLib = piidTypeLib;
  279. ASSERT(_pITINeutral == NULL);
  280. ASSERT(_pdisp == NULL);
  281. return;
  282. }
  283. CIDispatchHelper::~CIDispatchHelper(void)
  284. {
  285. if (_pITINeutral)
  286. {
  287. _pITINeutral->Release();
  288. _pITINeutral = NULL;
  289. }
  290. return;
  291. }