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.

547 lines
13 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1996 Microsoft Corporation. All Rights Reserved.
  5. Component: IDispatch implementation
  6. File: Dispatch.h
  7. Owner: DGottner
  8. This file contains our implementation of IDispatch
  9. ===================================================================*/
  10. #include "denpre.h"
  11. #pragma hdrstop
  12. #include "dispatch.h"
  13. #include "asptlb.h"
  14. #include "memchk.h"
  15. #ifdef USE_LOCALE
  16. extern DWORD g_dwTLS;
  17. #endif
  18. /*===================================================================
  19. CDispatch::CDispatch
  20. CDispatch::~CDispatch
  21. Parameters (Constructor):
  22. pUnkObj pointer to the object we're in.
  23. pUnkOuter LPUNKNOWN to which we delegate.
  24. ===================================================================*/
  25. CDispatch::CDispatch()
  26. {
  27. m_pITINeutral = NULL;
  28. m_pITypeLib = NULL;
  29. m_pGuidDispInterface = NULL;
  30. }
  31. void CDispatch::Init
  32. (
  33. const GUID &GuidDispInterface,
  34. const ITypeLib *pITypeLib // = NULL
  35. )
  36. {
  37. m_pGuidDispInterface = &GuidDispInterface;
  38. m_pITypeLib = const_cast<ITypeLib *>(pITypeLib);
  39. }
  40. CDispatch::~CDispatch(void)
  41. {
  42. ReleaseInterface(m_pITINeutral);
  43. return;
  44. }
  45. /*===================================================================
  46. CDispatch::GetTypeInfoCount
  47. Returns the number of type information (ITypeInfo) interfaces
  48. that the object provides (0 or 1).
  49. Parameters:
  50. pcInfo UINT * to the location to receive
  51. the count of interfaces.
  52. Return Value:
  53. HRESULT S_OK or a general error code.
  54. ===================================================================*/
  55. STDMETHODIMP CDispatch::GetTypeInfoCount(UINT *pcInfo)
  56. {
  57. // We implement GetTypeInfo so return 1
  58. *pcInfo = 1;
  59. return S_OK;
  60. }
  61. /*===================================================================
  62. CDispatch::GetTypeInfo
  63. Retrieves type information for the automation interface. This
  64. is used anywhere that the right ITypeInfo interface is needed
  65. for whatever LCID is applicable. Specifically, this is used
  66. from within GetIDsOfNames and Invoke.
  67. Parameters:
  68. itInfo UINT reserved. Must be zero.
  69. lcid LCID providing the locale for the type
  70. information. If the object does not support
  71. localization, this is ignored.
  72. ppITypeInfo ITypeInfo ** in which to store the ITypeInfo
  73. interface for the object.
  74. Return Value:
  75. HRESULT S_OK or a general error code.
  76. ===================================================================*/
  77. STDMETHODIMP CDispatch::GetTypeInfo(
  78. UINT itInfo,
  79. LCID lcid,
  80. ITypeInfo **ppITypeInfo
  81. )
  82. {
  83. HRESULT hr;
  84. ITypeInfo **ppITI = NULL;
  85. if (0 != itInfo)
  86. return ResultFromScode(TYPE_E_ELEMENTNOTFOUND);
  87. if (NULL == ppITypeInfo)
  88. return ResultFromScode(E_POINTER);
  89. *ppITypeInfo = NULL;
  90. // We don't internationalize the type library, so
  91. // we always return the same one, regardless of the locale.
  92. ppITI = &m_pITINeutral;
  93. //Load a type lib if we don't have the information already.
  94. if (NULL == *ppITI)
  95. {
  96. ITypeLib *pITL;
  97. // If a specific TypeLib was given at init time use that, otherwise default to the main one
  98. if (m_pITypeLib == NULL)
  99. pITL = Glob(pITypeLibDenali);
  100. else
  101. pITL = m_pITypeLib;
  102. Assert(pITL != NULL);
  103. hr = pITL->GetTypeInfoOfGuid(*m_pGuidDispInterface, ppITI);
  104. if (FAILED(hr))
  105. return hr;
  106. // Save the type info in a class member, so we don't have
  107. // go through all this work again;
  108. m_pITINeutral = *ppITI;
  109. }
  110. /*
  111. * Note: the type library is still loaded since we have
  112. * an ITypeInfo from it.
  113. */
  114. (*ppITI)->AddRef();
  115. *ppITypeInfo = *ppITI;
  116. return S_OK;
  117. }
  118. /*===================================================================
  119. CDispatch::GetIDsOfNames
  120. Converts text names into DISPIDs to pass to Invoke
  121. Parameters:
  122. riid REFIID reserved. Must be IID_NULL.
  123. rgszNames OLECHAR ** pointing to the array of names to be mapped.
  124. cNames UINT number of names to be mapped.
  125. lcid LCID of the locale.
  126. rgDispID DISPID * caller allocated array containing IDs
  127. corresponging to those names in rgszNames.
  128. Return Value:
  129. HRESULT S_OK or a general error code.
  130. ===================================================================*/
  131. STDMETHODIMP CDispatch::GetIDsOfNames
  132. (
  133. REFIID riid,
  134. OLECHAR **rgszNames,
  135. UINT cNames,
  136. LCID lcid,
  137. DISPID *rgDispID
  138. )
  139. {
  140. HRESULT hr;
  141. ITypeInfo *pTI;
  142. if (IID_NULL != riid)
  143. return ResultFromScode(DISP_E_UNKNOWNINTERFACE);
  144. //Get the right ITypeInfo for lcid.
  145. hr = GetTypeInfo(0, lcid, &pTI);
  146. if (SUCCEEDED(hr))
  147. {
  148. hr = DispGetIDsOfNames(pTI, rgszNames, cNames, rgDispID);
  149. pTI->Release();
  150. }
  151. return hr;
  152. }
  153. /*===================================================================
  154. CDispatch::Invoke
  155. Calls a method in the dispatch interface or manipulates a property.
  156. Parameters:
  157. dispID DISPID of the method or property of interest.
  158. riid REFIID reserved, must be IID_NULL.
  159. lcid LCID of the locale.
  160. wFlags USHORT describing the context of the invocation.
  161. pDispParams DISPPARAMS * to the array of arguments.
  162. pVarResult VARIANT * in which to store the result. Is
  163. NULL if the caller is not interested.
  164. pExcepInfo EXCEPINFO * to exception information.
  165. puArgErr UINT * in which to store the index of an
  166. invalid parameter if DISP_E_TYPEMISMATCH
  167. is returned.
  168. Return Value:
  169. HRESULT S_OK or a general error code.
  170. ===================================================================*/
  171. STDMETHODIMP CDispatch::Invoke
  172. (
  173. DISPID dispID,
  174. REFIID riid,
  175. LCID lcid,
  176. unsigned short wFlags,
  177. DISPPARAMS *pDispParams,
  178. VARIANT *pVarResult,
  179. EXCEPINFO *pExcepInfo,
  180. UINT *puArgErr
  181. )
  182. {
  183. HRESULT hr;
  184. ITypeInfo *pTI;
  185. LANGID langID = PRIMARYLANGID(lcid);
  186. // riid is supposed to be IID_NULL always
  187. if (IID_NULL != riid)
  188. return ResultFromScode(DISP_E_UNKNOWNINTERFACE);
  189. // Get the ITypeInfo for lcid
  190. hr = GetTypeInfo(0, lcid, &pTI);
  191. if (FAILED(hr))
  192. return hr;
  193. #ifdef USE_LOCALE
  194. // This saves the language ID for this thread
  195. TlsSetValue(g_dwTLS, &langID);
  196. #endif
  197. // Clear exceptions
  198. SetErrorInfo(0L, NULL);
  199. // VBScript does not distinguish between a propget and a method
  200. // implement that behavior for other languages.
  201. //
  202. if (wFlags & (DISPATCH_METHOD | DISPATCH_PROPERTYGET))
  203. wFlags |= DISPATCH_METHOD | DISPATCH_PROPERTYGET;
  204. // This is exactly what DispInvoke does--so skip the overhead.
  205. // With dual interface, "this" is the address of the object AND its dispinterface
  206. //
  207. hr = pTI->Invoke(this, dispID, wFlags,
  208. pDispParams, pVarResult, pExcepInfo, puArgErr);
  209. // Exception handling is done within ITypeInfo::Invoke
  210. pTI->Release();
  211. return hr;
  212. }
  213. /*===================================================================
  214. CSupportErrorInfo::CSupportErrorInfo
  215. Default constructor so that the Init method can be used.
  216. Parameters (Constructor):
  217. pObj PCResponse of the object we're in.
  218. pUnkOuter LPUNKNOWN to which we delegate.
  219. ===================================================================*/
  220. CSupportErrorInfo::CSupportErrorInfo(void)
  221. : m_pUnkObj(NULL),
  222. m_pUnkOuter(NULL)
  223. {
  224. }
  225. /*===================================================================
  226. CSupportErrorInfo::CSupportErrorInfo
  227. Parameters (Constructor):
  228. pObj PCResponse of the object we're in.
  229. pUnkOuter LPUNKNOWN to which we delegate.
  230. GuidDispInterface GUID of dispatch interface.
  231. ===================================================================*/
  232. CSupportErrorInfo::CSupportErrorInfo(IUnknown *pUnkObj, IUnknown *pUnkOuter, const GUID &GuidDispInterface)
  233. {
  234. m_pUnkObj = pUnkObj;
  235. m_pUnkOuter = (pUnkOuter == NULL)? pUnkObj : pUnkOuter;
  236. m_pGuidDispInterface = &GuidDispInterface;
  237. }
  238. /*===================================================================
  239. void CSupportErrorInfo::Init
  240. Parameters:
  241. pObj PCResponse of the object we're in.
  242. pUnkOuter LPUNKNOWN to which we delegate.
  243. GuidDispInterface GUID of dispatch interface.
  244. Returns:
  245. Nothing
  246. ===================================================================*/
  247. void CSupportErrorInfo::Init(IUnknown *pUnkObj, IUnknown *pUnkOuter, const GUID &GuidDispInterface)
  248. {
  249. m_pUnkObj = pUnkObj;
  250. m_pUnkOuter = (pUnkOuter == NULL)? pUnkObj : pUnkOuter;
  251. m_pGuidDispInterface = &GuidDispInterface;
  252. }
  253. /*===================================================================
  254. CSupportErrorInfo::QueryInterface
  255. CSupportErrorInfo::AddRef
  256. CSupportErrorInfo::Release
  257. IUnknown members for CSupportErrorInfo object.
  258. ===================================================================*/
  259. STDMETHODIMP CSupportErrorInfo::QueryInterface(const GUID &Iid, void **ppvObj)
  260. {
  261. return m_pUnkOuter->QueryInterface(Iid, ppvObj);
  262. }
  263. STDMETHODIMP_(ULONG) CSupportErrorInfo::AddRef(void)
  264. {
  265. return m_pUnkOuter->AddRef();
  266. }
  267. STDMETHODIMP_(ULONG) CSupportErrorInfo::Release(void)
  268. {
  269. return m_pUnkOuter->Release();
  270. }
  271. /*===================================================================
  272. CSupportErrorInfo::InterfaceSupportsErrorInfo
  273. Informs a caller whether or not a specific interface
  274. supports exceptions through the Set/GetErrorInfo mechanism.
  275. Parameters:
  276. riid REFIID of the interface in question.
  277. Return Value:
  278. HRESULT S_OK if a call to GetErrorInfo will succeed
  279. for callers of riid. S_FALSE if not.
  280. ===================================================================*/
  281. STDMETHODIMP CSupportErrorInfo::InterfaceSupportsErrorInfo
  282. (
  283. REFIID riid
  284. )
  285. {
  286. if (IID_IDispatch == riid || *m_pGuidDispInterface == riid)
  287. return S_OK;
  288. return ResultFromScode(S_FALSE);
  289. }
  290. /*===================================================================
  291. Exception
  292. Raises an exception using the CreateErrorInfo API and the
  293. ICreateErrorInfo interface.
  294. Note that this method doesn't allow for deferred filling
  295. of an EXCEPINFO structure.
  296. Parameters:
  297. strSource LPOLESTR the exception source
  298. strDescr LPOLESTR the exception description
  299. Returns:
  300. Nothing
  301. ===================================================================*/
  302. void Exception
  303. (
  304. REFIID ObjID,
  305. LPOLESTR strSource,
  306. LPOLESTR strDescr
  307. )
  308. {
  309. HRESULT hr;
  310. ICreateErrorInfo *pICreateErr;
  311. IErrorInfo *pIErr;
  312. LANGID langID = LANG_NEUTRAL;
  313. #ifdef USE_LOCALE
  314. LANGID *pLangID;
  315. pLangID = (LANGID *)TlsGetValue(g_dwTLS);
  316. if (NULL != pLangID)
  317. langID = *pLangID;
  318. #endif
  319. /*
  320. * Thread-safe exception handling means that we call
  321. * CreateErrorInfo which gives us an ICreateErrorInfo pointer
  322. * that we then use to set the error information (basically
  323. * to set the fields of an EXCEPINFO structure. We then
  324. * call SetErrorInfo to attach this error to the current
  325. * thread. ITypeInfo::Invoke will look for this when it
  326. * returns from whatever function was invokes by calling
  327. * GetErrorInfo.
  328. */
  329. //Not much we can do if this fails.
  330. if (FAILED(CreateErrorInfo(&pICreateErr)))
  331. return;
  332. /*
  333. * CONSIDER: Help file and help context?
  334. */
  335. pICreateErr->SetGUID(ObjID);
  336. pICreateErr->SetHelpFile(L"");
  337. pICreateErr->SetHelpContext(0L);
  338. pICreateErr->SetSource(strSource);
  339. pICreateErr->SetDescription(strDescr);
  340. hr = pICreateErr->QueryInterface(IID_IErrorInfo, (PPVOID)&pIErr);
  341. if (SUCCEEDED(hr))
  342. {
  343. SetErrorInfo(0L, pIErr);
  344. pIErr->Release();
  345. }
  346. //SetErrorInfo holds the object's IErrorInfo
  347. pICreateErr->Release();
  348. return;
  349. }
  350. /*===================================================================
  351. ExceptionId
  352. Raises an exception using the CreateErrorInfo API and the
  353. ICreateErrorInfo interface.
  354. Note that this method doesn't allow for deferred filling
  355. of an EXCEPINFO structure.
  356. Parameters:
  357. SourceID Resource ID for the source string
  358. DescrID Resource ID for the description string
  359. Returns:
  360. Nothing
  361. ===================================================================*/
  362. void ExceptionId
  363. (
  364. REFIID ObjID,
  365. UINT SourceID,
  366. UINT DescrID,
  367. HRESULT hrCode
  368. )
  369. {
  370. HRESULT hr;
  371. ICreateErrorInfo *pICreateErr;
  372. IErrorInfo *pIErr;
  373. LANGID langID = LANG_NEUTRAL;
  374. #ifdef USE_LOCALE
  375. LANGID *pLangID;
  376. pLangID = (LANGID *)TlsGetValue(g_dwTLS);
  377. if (NULL != pLangID)
  378. langID = *pLangID;
  379. #endif
  380. /*
  381. * Thread-safe exception handling means that we call
  382. * CreateErrorInfo which gives us an ICreateErrorInfo pointer
  383. * that we then use to set the error information (basically
  384. * to set the fields of an EXCEPINFO structure. We then
  385. * call SetErrorInfo to attach this error to the current
  386. * thread. ITypeInfo::Invoke will look for this when it
  387. * returns from whatever function was invokes by calling
  388. * GetErrorInfo.
  389. */
  390. //Not much we can do if this fails.
  391. if (FAILED(CreateErrorInfo(&pICreateErr)))
  392. return;
  393. /*
  394. * CONSIDER: Help file and help context?
  395. */
  396. DWORD cch;
  397. WCHAR strSource[MAX_RESSTRINGSIZE];
  398. WCHAR strDescr[MAX_RESSTRINGSIZE];
  399. WCHAR strHRESULTDescr[256];
  400. WCHAR strDescrWithHRESULT[MAX_RESSTRINGSIZE];
  401. pICreateErr->SetGUID(ObjID);
  402. pICreateErr->SetHelpFile(L"");
  403. pICreateErr->SetHelpContext(0L);
  404. cch = CwchLoadStringOfId(SourceID, strSource, MAX_RESSTRINGSIZE);
  405. if (cch > 0)
  406. pICreateErr->SetSource(strSource);
  407. cch = CwchLoadStringOfId(DescrID, strDescr, MAX_RESSTRINGSIZE);
  408. if (cch > 0)
  409. {
  410. //Bug Fix 91847 use a FormatMessage() based description
  411. HResultToWsz(hrCode, strHRESULTDescr, 256);
  412. _snwprintf(strDescrWithHRESULT, MAX_RESSTRINGSIZE, strDescr, strHRESULTDescr);
  413. strDescrWithHRESULT[MAX_RESSTRINGSIZE - 1] = L'\0';
  414. pICreateErr->SetDescription(strDescrWithHRESULT);
  415. }
  416. hr = pICreateErr->QueryInterface(IID_IErrorInfo, (PPVOID)&pIErr);
  417. if (SUCCEEDED(hr))
  418. {
  419. SetErrorInfo(0L, pIErr);
  420. pIErr->Release();
  421. }
  422. //SetErrorInfo holds the object's IErrorInfo
  423. pICreateErr->Release();
  424. return;
  425. }