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.

388 lines
12 KiB

  1. // Copyright 1995-1997 Microsoft Corporation. All Rights Reserved.
  2. // all of our objects will inherit from this class to share as much of the same
  3. // code as possible. this super-class contains the unknown, dispatch and
  4. // error info implementations for them.
  5. #include "header.h"
  6. #include "AutoObj.H"
  7. #ifndef _DEBUG
  8. #undef THIS_FILE
  9. static const char THIS_FILE[] = __FILE__;
  10. #endif
  11. //=--------------------------------------------------------------------------=
  12. // CAutomationObject::CAutomationObject
  13. //=--------------------------------------------------------------------------=
  14. // create the object and initialize the refcount
  15. //
  16. // Parameters:
  17. // IUnknown * - [in] controlling Unknown
  18. // int - [in] the object type that we are
  19. // void * - [in] the VTable of of the object we really are.
  20. CAutomationObject::CAutomationObject(IUnknown *pUnkOuter, int ObjType, void *pVTable)
  21. : CUnknownObject(pUnkOuter, pVTable), m_ObjectType (ObjType)
  22. {
  23. m_fLoadedTypeInfo = FALSE;
  24. }
  25. //=--------------------------------------------------------------------------=
  26. // CAutomationObject::~CAutomationObject
  27. //=--------------------------------------------------------------------------=
  28. CAutomationObject::~CAutomationObject ()
  29. {
  30. // if we loaded up a type info, release our count on the globally stashed
  31. // type infos, and release if it becomes zero.
  32. if (m_fLoadedTypeInfo) {
  33. // we have to crit sect this since it's possible to have more than
  34. // one thread partying with this object.
  35. // EnterCriticalSection(&g_CriticalSection);
  36. ASSERT_COMMENT(CTYPEINFOOFOBJECT(m_ObjectType), "Bogus ref counting on the Type Infos");
  37. CTYPEINFOOFOBJECT(m_ObjectType)--;
  38. // if we're the last one, free that sucker!
  39. if (!CTYPEINFOOFOBJECT(m_ObjectType)) {
  40. PTYPEINFOOFOBJECT(m_ObjectType)->Release();
  41. PTYPEINFOOFOBJECT(m_ObjectType) = NULL;
  42. }
  43. // LeaveCriticalSection(&g_CriticalSection);
  44. }
  45. return;
  46. }
  47. //=--------------------------------------------------------------------------=
  48. // CAutomationObject::InternalQueryInterface
  49. //=--------------------------------------------------------------------------=
  50. // the controlling unknown will call this for us in the case where they're
  51. // looking for a specific interface.
  52. //
  53. // Parameters:
  54. // REFIID - [in] interface they want
  55. // void ** - [out] where they want to put the resulting object ptr.
  56. //
  57. // Output:
  58. // HRESULT - S_OK, E_NOINTERFACE
  59. HRESULT CAutomationObject::InternalQueryInterface(REFIID riid, void **ppvObjOut)
  60. {
  61. #if 0
  62. ASSERT_COMMENT(ppvObjOut, "controlling Unknown should be checking this!");
  63. return E_NOTIMPL;
  64. #endif
  65. // start looking for the guids we support, namely IDispatch, and the
  66. if (DO_GUIDS_MATCH(riid, IID_IDispatch)) {
  67. *ppvObjOut = (void *)(IDispatch *)m_pvInterface;
  68. ((IUnknown *)(*ppvObjOut))->AddRef();
  69. return S_OK;
  70. }
  71. // just get our parent class to process it from here on out.
  72. return CUnknownObject::InternalQueryInterface(riid, ppvObjOut);
  73. }
  74. //=--------------------------------------------------------------------------=
  75. // CAutomationObject::GetTypeInfoCount
  76. //=--------------------------------------------------------------------------=
  77. // returns the number of type information interfaces that the object provides
  78. //
  79. // Parameters:
  80. // UINT * - [out] the number of interfaces supported.
  81. //
  82. // Output:
  83. // HRESULT - S_OK, E_NOTIMPL, E_INVALIDARG
  84. STDMETHODIMP CAutomationObject::GetTypeInfoCount(UINT *pctinfo)
  85. {
  86. if (!pctinfo)
  87. return E_INVALIDARG;
  88. *pctinfo = 1;
  89. return S_OK;
  90. }
  91. //=--------------------------------------------------------------------------=
  92. // CAutomationObject::GetTypeInfo
  93. //=--------------------------------------------------------------------------=
  94. // Retrieves a type information object, which can be used to get the type
  95. // information for an interface.
  96. //
  97. // Parameters:
  98. // UINT - [in] the type information they'll want returned
  99. // LCID - [in] the LCID of the type info we want
  100. // ITypeInfo ** - [out] the new type info object.
  101. //
  102. // Output:
  103. // HRESULT - S_OK, E_INVALIDARG, etc.
  104. //
  105. // Notes:
  106. //
  107. STDMETHODIMP CAutomationObject::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **ppTypeInfoOut)
  108. {
  109. DWORD dwPathLen;
  110. char szDllPath[MAX_PATH];
  111. HRESULT hr;
  112. ITypeLib *pTypeLib;
  113. ITypeInfo **ppTypeInfo =NULL;
  114. // arg checking
  115. if (itinfo != 0)
  116. return DISP_E_BADINDEX;
  117. if (!ppTypeInfoOut)
  118. return E_POINTER;
  119. *ppTypeInfoOut = NULL;
  120. // ppTypeInfo will point to our global holder for this particular
  121. // type info. if it's null, then we have to load it up. if it's not
  122. // NULL, then it's already loaded, and we're happy.
  123. // crit sect this entire nightmare so we're okay with multiple
  124. // threads trying to use this object.
  125. // EnterCriticalSection(&g_CriticalSection);
  126. ppTypeInfo = PPTYPEINFOOFOBJECT(m_ObjectType);
  127. if (*ppTypeInfo == NULL) {
  128. ITypeInfo *pTypeInfoTmp;
  129. HREFTYPE hrefType;
  130. // we don't have the type info around, so go load the sucker.
  131. //
  132. hr = LoadRegTypeLib(*g_pLibid, (USHORT)VERSIONOFOBJECT(m_ObjectType), 0,
  133. LANG_NEUTRAL, &pTypeLib);
  134. // if, for some reason, we failed to load the type library this
  135. // way, we're going to try and load the type library directly out of
  136. // our resources. this has the advantage of going and re-setting all
  137. // the registry information again for us.
  138. if (FAILED(hr)) {
  139. dwPathLen = GetModuleFileName(_Module.GetModuleInstance(), szDllPath, MAX_PATH);
  140. if (!dwPathLen) {
  141. hr = E_FAIL;
  142. goto CleanUp;
  143. }
  144. MAKE_WIDEPTR_FROMANSI(pwsz, szDllPath);
  145. hr = LoadTypeLib(pwsz, &pTypeLib);
  146. CLEANUP_ON_FAILURE(hr);
  147. }
  148. // we've got the Type Library now, so get the type info for the interface
  149. // we're interested in.
  150. //
  151. hr = pTypeLib->GetTypeInfoOfGuid((REFIID)INTERFACEOFOBJECT(m_ObjectType), &pTypeInfoTmp);
  152. pTypeLib->Release();
  153. CLEANUP_ON_FAILURE(hr);
  154. // the following couple of lines of code are to dereference the dual
  155. // interface stuff and take us right to the dispatch portion of the
  156. // interfaces.
  157. //
  158. hr = pTypeInfoTmp->GetRefTypeOfImplType(0xffffffff, &hrefType);
  159. if (FAILED(hr)) {
  160. pTypeInfoTmp->Release();
  161. goto CleanUp;
  162. }
  163. hr = pTypeInfoTmp->GetRefTypeInfo(hrefType, ppTypeInfo);
  164. pTypeInfoTmp->Release();
  165. CLEANUP_ON_FAILURE(hr);
  166. // add an extra reference to this object. if it ever becomes zero, then
  167. // we need to release it ourselves. crit sect this since more than
  168. // one thread can party on this object.
  169. //
  170. CTYPEINFOOFOBJECT(m_ObjectType)++;
  171. m_fLoadedTypeInfo = TRUE;
  172. }
  173. // we still have to go and addref the Type info object, however, so that
  174. // the people using it can release it.
  175. //
  176. (*ppTypeInfo)->AddRef();
  177. *ppTypeInfoOut = *ppTypeInfo;
  178. hr = S_OK;
  179. CleanUp:
  180. // LeaveCriticalSection(&g_CriticalSection);
  181. return hr;
  182. }
  183. //=--------------------------------------------------------------------------=
  184. // CAutomationObject::GetIDsOfNames
  185. //=--------------------------------------------------------------------------=
  186. // Maps a single member and an optional set of argument names to a
  187. // corresponding set of integer DISPIDs
  188. //
  189. // Parameters:
  190. // REFIID - [in] must be IID_NULL
  191. // OLECHAR ** - [in] array of names to map.
  192. // UINT - [in] count of names in the array.
  193. // LCID - [in] LCID on which to operate
  194. // DISPID * - [in] place to put the corresponding DISPIDs.
  195. //
  196. // Output:
  197. // HRESULT - S_OK, E_OUTOFMEMORY, DISP_E_UNKNOWNNAME,
  198. // DISP_E_UNKNOWNLCID
  199. //
  200. // Notes:
  201. // - we're just going to use DispGetIDsOfNames to save us a lot of hassle,
  202. // and to let this superclass handle it.
  203. //
  204. STDMETHODIMP CAutomationObject::GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgdispid)
  205. {
  206. HRESULT hr;
  207. ITypeInfo *pTypeInfo;
  208. if (!DO_GUIDS_MATCH(riid, IID_NULL))
  209. return E_INVALIDARG;
  210. hr = GetTypeInfo(0, lcid, &pTypeInfo);
  211. RETURN_ON_FAILURE(hr);
  212. // use the standard provided routines to do all the work for us.
  213. hr = pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
  214. pTypeInfo->Release();
  215. return hr;
  216. }
  217. //=--------------------------------------------------------------------------=
  218. // CAutomationObject::Invoke
  219. //=--------------------------------------------------------------------------=
  220. // provides access to the properties and methods on this object.
  221. //
  222. // Parameters:
  223. // DISPID - [in] identifies the member we're working with.
  224. // REFIID - [in] must be IID_NULL.
  225. // LCID - [in] language we're working under
  226. // USHORT - [in] flags, propput, get, method, etc ...
  227. // DISPPARAMS * - [in] array of arguments.
  228. // VARIANT * - [out] where to put result, or NULL if they don't care.
  229. // EXCEPINFO * - [out] filled in in case of exception
  230. // UINT * - [out] where the first argument with an error is.
  231. //
  232. // Output:
  233. // HRESULT - tonnes of them.
  234. STDMETHODIMP CAutomationObject::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, EXCEPINFO *pexcepinfo, UINT *puArgErr)
  235. {
  236. HRESULT hr;
  237. ITypeInfo *pTypeInfo;
  238. if (!DO_GUIDS_MATCH(riid, IID_NULL))
  239. return E_INVALIDARG;
  240. // get our typeinfo first!
  241. //
  242. hr = GetTypeInfo(0, lcid, &pTypeInfo);
  243. RETURN_ON_FAILURE(hr);
  244. // Clear exceptions
  245. SetErrorInfo(0L, NULL);
  246. // This is exactly what DispInvoke does--so skip the overhead.
  247. hr = pTypeInfo->Invoke(m_pvInterface, dispid, wFlags,
  248. pdispparams, pvarResult,
  249. pexcepinfo, puArgErr);
  250. pTypeInfo->Release();
  251. return hr;
  252. }
  253. //=--------------------------------------------------------------------------=
  254. // CAutomationObject::Exception
  255. //=--------------------------------------------------------------------------=
  256. // fills in the rich error info object so that both our vtable bound interfaces
  257. // and calls through ITypeInfo::Invoke get the right error informaiton.
  258. //
  259. // Parameters:
  260. // HRESULT - [in] the SCODE that should be associated with this err
  261. // WORD - [in] the RESOURCE ID of the error message.
  262. // DWORD - [in] helpcontextid for the error
  263. //
  264. // Output:
  265. // HRESULT - the HRESULT that was passed in.
  266. HRESULT CAutomationObject::Exception(HRESULT hrExcep, WORD idException, DWORD dwHelpContextID)
  267. {
  268. ICreateErrorInfo *pCreateErrorInfo;
  269. IErrorInfo *pErrorInfo;
  270. HRESULT hr;
  271. // first get the createerrorinfo object.
  272. hr = CreateErrorInfo(&pCreateErrorInfo);
  273. if (FAILED(hr)) return hrExcep;
  274. MAKE_WIDEPTR_FROMANSI(wszHelpFile, HELPFILEOFOBJECT(m_ObjectType));
  275. // set up some default information on it.
  276. //
  277. pCreateErrorInfo->SetGUID((REFIID)INTERFACEOFOBJECT(m_ObjectType));
  278. pCreateErrorInfo->SetHelpFile(wszHelpFile);
  279. pCreateErrorInfo->SetHelpContext(dwHelpContextID);
  280. // load in the actual error string value. max of 256.
  281. CWStr cwzError(GetStringResource(idException));
  282. pCreateErrorInfo->SetDescription(cwzError);
  283. // load in the source
  284. cwzError = NAMEOFOBJECT(m_ObjectType);
  285. pCreateErrorInfo->SetSource(cwzError);
  286. // now set the Error info up with the system
  287. hr = pCreateErrorInfo->QueryInterface(IID_IErrorInfo, (void **)&pErrorInfo);
  288. CLEANUP_ON_FAILURE(hr);
  289. SetErrorInfo(0, pErrorInfo);
  290. pErrorInfo->Release();
  291. CleanUp:
  292. pCreateErrorInfo->Release();
  293. return hrExcep;
  294. }
  295. //=--------------------------------------------------------------------------=
  296. // CAutomationObject::InterfaceSupportsErrorInfo
  297. //=--------------------------------------------------------------------------=
  298. // indicates whether or not the given interface supports rich error information
  299. //
  300. // Parameters:
  301. // REFIID - [in] the interface we want the answer for.
  302. //
  303. // Output:
  304. // HRESULT - S_OK = Yes, S_FALSE = No.
  305. HRESULT CAutomationObject::InterfaceSupportsErrorInfo(REFIID riid)
  306. {
  307. // see if it's the interface for the type of object that we are.
  308. if (riid == (REFIID)INTERFACEOFOBJECT(m_ObjectType))
  309. return S_OK;
  310. return S_FALSE;
  311. }