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.

200 lines
5.9 KiB

  1. #include "stock.h"
  2. #pragma hdrstop
  3. #include "dspsprt.h"
  4. #define TF_IDISPATCH 0
  5. EXTERN_C HINSTANCE g_hinst;
  6. CImpIDispatch::CImpIDispatch(REFGUID libid, USHORT wVerMajor, USHORT wVerMinor, REFIID riid) :
  7. m_libid(libid), m_wVerMajor(wVerMajor), m_wVerMinor(wVerMinor), m_riid(riid), m_pITINeutral(NULL)
  8. {
  9. ASSERT(NULL == m_pITINeutral);
  10. }
  11. CImpIDispatch::~CImpIDispatch(void)
  12. {
  13. ATOMICRELEASE(m_pITINeutral);
  14. }
  15. STDMETHODIMP CImpIDispatch::GetTypeInfoCount(UINT *pctInfo)
  16. {
  17. *pctInfo = 1;
  18. return S_OK;
  19. }
  20. // helper function for pulling ITypeInfo out of our typelib
  21. // Uncomment to force loading libid from the calling module: #define FORCE_LOCAL_LOAD
  22. STDAPI GetTypeInfoFromLibId(LCID lcid, REFGUID libid, USHORT wVerMajor, USHORT wVerMinor,
  23. REFGUID uuid, ITypeInfo **ppITypeInfo)
  24. {
  25. *ppITypeInfo = NULL; // assume failure
  26. ITypeLib *pITypeLib;
  27. HRESULT hr;
  28. USHORT wResID;
  29. if (!IsEqualGUID(libid, GUID_NULL))
  30. {
  31. // The type libraries are registered under 0 (neutral),
  32. // 7 (German), and 9 (English) with no specific sub-
  33. // language, which would make them 407 or 409 and such.
  34. // If you are sensitive to sub-languages, then use the
  35. // full LCID instead of just the LANGID as done here.
  36. #ifdef FORCE_LOCAL_LOAD
  37. hr = E_FAIL; // force load through GetModuleFileName(), to get fusion 1.0 support
  38. #else
  39. hr = LoadRegTypeLib(libid, wVerMajor, wVerMinor, PRIMARYLANGID(lcid), &pITypeLib);
  40. #endif
  41. wResID = 0;
  42. }
  43. else
  44. {
  45. // If libid is GUID_NULL, then get type lib from module and use wVerMajor as
  46. // the resource ID (0 means use first type lib resource).
  47. pITypeLib = NULL;
  48. hr = E_FAIL;
  49. wResID = wVerMajor;
  50. }
  51. // If LoadRegTypeLib fails, try loading directly with LoadTypeLib.
  52. if (FAILED(hr) && g_hinst)
  53. {
  54. WCHAR wszPath[MAX_PATH];
  55. GetModuleFileNameWrapW(g_hinst, wszPath, ARRAYSIZE(wszPath));
  56. // Append resource ID to path, if specified.
  57. if (wResID)
  58. {
  59. WCHAR wszResStr[10];
  60. wnsprintfW(wszResStr, ARRAYSIZE(wszResStr), L"\\%d", wResID);
  61. StrCatBuffW(wszPath, wszResStr, ARRAYSIZE(wszPath));
  62. }
  63. switch (PRIMARYLANGID(lcid))
  64. {
  65. case LANG_NEUTRAL:
  66. case LANG_ENGLISH:
  67. hr = LoadTypeLib(wszPath, &pITypeLib);
  68. break;
  69. }
  70. }
  71. if (SUCCEEDED(hr))
  72. {
  73. // Got the type lib, get type info for the interface we want.
  74. hr = pITypeLib->GetTypeInfoOfGuid(uuid, ppITypeInfo);
  75. pITypeLib->Release();
  76. }
  77. return hr;
  78. }
  79. STDMETHODIMP CImpIDispatch::GetTypeInfo(UINT itInfo, LCID lcid, ITypeInfo **ppITypeInfo)
  80. {
  81. *ppITypeInfo = NULL;
  82. if (0 != itInfo)
  83. return TYPE_E_ELEMENTNOTFOUND;
  84. // docs say we can ignore lcid if we support only one LCID
  85. // we don't have to return DISP_E_UNKNOWNLCID if we're *ignoring* it
  86. ITypeInfo **ppITI = &m_pITINeutral; // our cached typeinfo
  87. // Load a type lib if we don't have the information already.
  88. if (NULL == *ppITI)
  89. {
  90. ITypeInfo *pITIDisp;
  91. HRESULT hr = GetTypeInfoFromLibId(lcid, m_libid, m_wVerMajor, m_wVerMinor, m_riid, &pITIDisp);
  92. if (SUCCEEDED(hr))
  93. {
  94. // All our IDispatch implementations are DUAL. GetTypeInfoOfGuid
  95. // returns the ITypeInfo of the IDispatch-part only. We need to
  96. // find the ITypeInfo for the dual interface-part.
  97. //
  98. HREFTYPE hrefType;
  99. HRESULT hrT = pITIDisp->GetRefTypeOfImplType(0xffffffff, &hrefType);
  100. if (SUCCEEDED(hrT))
  101. {
  102. hrT = pITIDisp->GetRefTypeInfo(hrefType, ppITI);
  103. }
  104. if (FAILED(hrT))
  105. {
  106. // I suspect GetRefTypeOfImplType may fail if someone uses
  107. // CImpIDispatch on a non-dual interface. In this case the
  108. // ITypeInfo we got above is just fine to use.
  109. *ppITI = pITIDisp;
  110. }
  111. else
  112. {
  113. pITIDisp->Release();
  114. }
  115. }
  116. if (FAILED(hr))
  117. return hr;
  118. }
  119. (*ppITI)->AddRef();
  120. *ppITypeInfo = *ppITI;
  121. return S_OK;
  122. }
  123. STDMETHODIMP CImpIDispatch::GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgDispID)
  124. {
  125. if (IID_NULL != riid)
  126. return DISP_E_UNKNOWNINTERFACE;
  127. //Get the right ITypeInfo for lcid.
  128. ITypeInfo *pTI;
  129. HRESULT hr = GetTypeInfo(0, lcid, &pTI);
  130. if (SUCCEEDED(hr))
  131. {
  132. hr = pTI->GetIDsOfNames(rgszNames, cNames, rgDispID);
  133. pTI->Release();
  134. }
  135. #ifdef DEBUG
  136. TCHAR szParam[MAX_PATH] = TEXT("");
  137. if (cNames >= 1)
  138. SHUnicodeToTChar(*rgszNames, szParam, ARRAYSIZE(szParam));
  139. TraceMsg(TF_IDISPATCH, "CImpIDispatch::GetIDsOfNames(%s = %x) called hres(%x)",
  140. szParam, *rgDispID, hr);
  141. #endif
  142. return hr;
  143. }
  144. STDMETHODIMP CImpIDispatch::Invoke(DISPID dispID, REFIID riid,
  145. LCID lcid, unsigned short wFlags, DISPPARAMS *pDispParams,
  146. VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
  147. {
  148. if (IID_NULL != riid)
  149. return DISP_E_UNKNOWNINTERFACE; // riid is supposed to be IID_NULL always
  150. IDispatch *pdisp;
  151. HRESULT hr = QueryInterface(m_riid, (void **)&pdisp);
  152. if (SUCCEEDED(hr))
  153. {
  154. //Get the ITypeInfo for lcid
  155. ITypeInfo *pTI;
  156. hr = GetTypeInfo(0, lcid, &pTI);
  157. if (SUCCEEDED(hr))
  158. {
  159. SetErrorInfo(0, NULL); //Clear exceptions
  160. // This is exactly what DispInvoke does--so skip the overhead.
  161. hr = pTI->Invoke(pdisp, dispID, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
  162. pTI->Release();
  163. }
  164. pdisp->Release();
  165. }
  166. return hr;
  167. }
  168. void CImpIDispatch::Exception(WORD wException)
  169. {
  170. ASSERT(FALSE); // No one should call this yet
  171. }