Leaked source code of windows server 2003
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.

336 lines
9.5 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. GetModuleFileName(HINST_THISDLL, wszPath, ARRAYSIZE(wszPath));
  44. switch (PRIMARYLANGID(lcid))
  45. {
  46. case LANG_NEUTRAL:
  47. case LANG_ENGLISH:
  48. hr = LoadTypeLib(wszPath, &pITypeLib);
  49. break;
  50. }
  51. }
  52. if (SUCCEEDED(hr))
  53. {
  54. // got the type lib, get type info for the interface we want
  55. hr = pITypeLib->GetTypeInfoOfGuid(uuid, ppITypeInfo);
  56. pITypeLib->Release();
  57. }
  58. return hr;
  59. }
  60. //
  61. // IDispatch Interface
  62. //
  63. //
  64. // CIDispatchHelper::GetTypeInfoCount
  65. //
  66. // Purpose:
  67. // Returns the number of type information (ITypeInfo) interfaces
  68. // that the object provides (0 or 1).
  69. //
  70. // Parameters:
  71. // pctInfo UINT * to the location to receive
  72. // the count of interfaces.
  73. //
  74. // Return Value:
  75. // HRESULT NOERROR or a general error code.
  76. //
  77. STDMETHODIMP CIDispatchHelper::GetTypeInfoCount(UINT *pctInfo)
  78. {
  79. // we implement GetTypeInfo so return 1
  80. *pctInfo = 1;
  81. return NOERROR;
  82. }
  83. //
  84. // CIDispatchHelper::GetTypeInfo
  85. //
  86. // Purpose:
  87. // Retrieves type information for the automation interface. This
  88. // is used anywhere that the right ITypeInfo interface is needed
  89. // for whatever LCID is applicable. Specifically, this is used
  90. // from within GetIDsOfNames and Invoke.
  91. //
  92. // Parameters:
  93. // itInfo UINT reserved. Must be zero.
  94. // lcid LCID providing the locale for the type
  95. // information. If the object does not support
  96. // localization, this is ignored.
  97. // ppITypeInfo ITypeInfo ** in which to store the ITypeInfo
  98. // interface for the object.
  99. //
  100. // Return Value:
  101. // HRESULT NOERROR or a general error code.
  102. //
  103. STDMETHODIMP CIDispatchHelper::GetTypeInfo(UINT itInfo, LCID lcid, ITypeInfo** ppITypeInfo)
  104. {
  105. HRESULT hr = S_OK;
  106. ITypeInfo** ppITI;
  107. *ppITypeInfo = NULL;
  108. if (itInfo != 0)
  109. {
  110. return TYPE_E_ELEMENTNOTFOUND;
  111. }
  112. #if 1
  113. // docs say we can ignore lcid if we support only one LCID
  114. // we don't have to return DISP_E_UNKNOWNLCID if we're *ignoring* it
  115. ppITI = &_pITINeutral;
  116. #else
  117. //
  118. // Since we returned one from GetTypeInfoCount, this function
  119. // can be called for a specific locale. We support English
  120. // and neutral (defaults to English) locales. Anything
  121. // else is an error.
  122. //
  123. // After this switch statement, ppITI will point to the proper
  124. // member pITypeInfo. If *ppITI is NULL, we know we need to
  125. // load type information, retrieve the ITypeInfo we want, and
  126. // then store it in *ppITI.
  127. //
  128. switch (PRIMARYLANGID(lcid))
  129. {
  130. case LANG_NEUTRAL:
  131. case LANG_ENGLISH:
  132. ppITI=&_pITINeutral;
  133. break;
  134. default:
  135. hr = DISP_E_UNKNOWNLCID;
  136. }
  137. #endif
  138. if (SUCCEEDED(hr))
  139. {
  140. //Load a type lib if we don't have the information already
  141. if (*ppITI == NULL)
  142. {
  143. ITypeInfo* pITIDisp;
  144. hr = _LoadTypeInfo(_piidTypeLib, lcid, *_piid, &pITIDisp);
  145. if (SUCCEEDED(hr))
  146. {
  147. HREFTYPE hrefType;
  148. // All our IDispatch implementations are DUAL. GetTypeInfoOfGuid
  149. // returns the ITypeInfo of the IDispatch-part only. We need to
  150. // find the ITypeInfo for the dual interface-part.
  151. if (SUCCEEDED(pITIDisp->GetRefTypeOfImplType(0xffffffff, &hrefType)) &&
  152. SUCCEEDED(pITIDisp->GetRefTypeInfo(hrefType, ppITI)))
  153. {
  154. // GetRefTypeInfo should have filled in ppITI with the dual interface
  155. (*ppITI)->AddRef(); // add the ref for our caller
  156. *ppITypeInfo = *ppITI;
  157. pITIDisp->Release();
  158. }
  159. else
  160. {
  161. // I suspect GetRefTypeOfImplType may fail if someone uses
  162. // CIDispatchHelper on a non-dual interface. In this case the
  163. // ITypeInfo we got above is just fine to use.
  164. *ppITI = pITIDisp;
  165. }
  166. }
  167. }
  168. else
  169. {
  170. // we already loaded the type library and we have an ITypeInfo from it
  171. (*ppITI)->AddRef(); // add the ref for our caller
  172. *ppITypeInfo = *ppITI;
  173. }
  174. }
  175. return hr;
  176. }
  177. //
  178. // CIDispatchHelper::GetIDsOfNames
  179. //
  180. // Purpose:
  181. // Converts text names into DISPIDs to pass to Invoke
  182. //
  183. // Parameters:
  184. // riid REFIID reserved. Must be IID_NULL.
  185. // rgszNames OLECHAR ** pointing to the array of names to be
  186. // mapped.
  187. // cNames UINT number of names to be mapped.
  188. // lcid LCID of the locale.
  189. // rgDispID DISPID * caller allocated array containing IDs
  190. // corresponging to those names in rgszNames.
  191. //
  192. // Return Value:
  193. // HRESULT NOERROR or a general error code.
  194. //
  195. STDMETHODIMP CIDispatchHelper::GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgDispID)
  196. {
  197. HRESULT hr;
  198. ITypeInfo* pTI;
  199. if (riid != IID_NULL)
  200. {
  201. return DISP_E_UNKNOWNINTERFACE;
  202. }
  203. // get the right ITypeInfo for lcid.
  204. hr = GetTypeInfo(0, lcid, &pTI);
  205. if (SUCCEEDED(hr))
  206. {
  207. hr = pTI->GetIDsOfNames(rgszNames, cNames, rgDispID);
  208. pTI->Release();
  209. }
  210. return hr;
  211. }
  212. //
  213. // CIDispatchHelper::Invoke
  214. //
  215. // Purpose:
  216. // Calls a method in the dispatch interface or manipulates a
  217. // property.
  218. //
  219. // Parameters:
  220. // dispID DISPID of the method or property of interest.
  221. // riid REFIID reserved, must be IID_NULL.
  222. // lcid LCID of the locale.
  223. // wFlags USHORT describing the context of the invocation.
  224. // pDispParams DISPPARAMS * to the array of arguments.
  225. // pVarResult VARIANT * in which to store the result. Is
  226. // NULL if the caller is not interested.
  227. // pExcepInfo EXCEPINFO * to exception information.
  228. // puArgErr UINT * in which to store the index of an
  229. // invalid parameter if DISP_E_TYPEMISMATCH
  230. // is returned.
  231. //
  232. // Return Value:
  233. // HRESULT NOERROR or a general error code.
  234. //
  235. STDMETHODIMP CIDispatchHelper::Invoke(DISPID dispID, REFIID riid, LCID lcid, unsigned short wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)
  236. {
  237. HRESULT hr;
  238. ITypeInfo *pTI;
  239. //riid is supposed to be IID_NULL always
  240. if (riid != IID_NULL)
  241. {
  242. return(DISP_E_UNKNOWNINTERFACE);
  243. }
  244. // make sure we have an interface to hand off to Invoke
  245. if (_pdisp == NULL)
  246. {
  247. hr = QueryInterface(*_piid, (LPVOID*)&_pdisp);
  248. if (FAILED(hr))
  249. {
  250. return hr;
  251. }
  252. // don't hold a refcount on ourself
  253. _pdisp->Release();
  254. }
  255. // get the ITypeInfo for lcid
  256. hr = GetTypeInfo(0, lcid, &pTI);
  257. if (SUCCEEDED(hr))
  258. {
  259. // clear exceptions
  260. SetErrorInfo(0L, NULL);
  261. // this is exactly what DispInvoke does--so skip the overhead.
  262. hr = pTI->Invoke(_pdisp, dispID, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
  263. pTI->Release();
  264. }
  265. return hr;
  266. }
  267. CIDispatchHelper::CIDispatchHelper(const IID* piid, const IID* piidTypeLib)
  268. {
  269. // the constructor takes a guid that this IDispatch implementation is for
  270. _piid = piid;
  271. // and a guid that tells us which RegTypeLib to load
  272. _piidTypeLib = piidTypeLib;
  273. ASSERT(_pITINeutral == NULL);
  274. ASSERT(_pdisp == NULL);
  275. return;
  276. }
  277. CIDispatchHelper::~CIDispatchHelper(void)
  278. {
  279. if (_pITINeutral)
  280. {
  281. _pITINeutral->Release();
  282. _pITINeutral = NULL;
  283. }
  284. return;
  285. }