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.

531 lines
16 KiB

  1. //=--------------------------------------------------------------------------=
  2. // AutoObj.Cpp
  3. //=--------------------------------------------------------------------------=
  4. // Copyright 1995-1996 Microsoft Corporation. All Rights Reserved.
  5. //
  6. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  7. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  8. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  9. // PARTICULAR PURPOSE.
  10. //=--------------------------------------------------------------------------=
  11. //
  12. // all of our objects will inherit from this class to share as much of the same
  13. // code as possible. this super-class contains the unknown, dispatch and
  14. // error info implementations for them.
  15. //
  16. #include "IPServer.H"
  17. #include "LocalSrv.H"
  18. #include "AutoObj.H"
  19. #include "Globals.H"
  20. #include "Util.H"
  21. // for ASSERT and FAIL
  22. //
  23. SZTHISFILE
  24. //=--------------------------------------------------------------------------=
  25. // CAutomationObject::CAutomationObject
  26. //=--------------------------------------------------------------------------=
  27. // create the object and initialize the refcount
  28. //
  29. // Parameters:
  30. // IUnknown * - [in] controlling Unknown
  31. // int - [in] the object type that we are
  32. // void * - [in] the VTable of of the object we really are.
  33. //
  34. // Notes:
  35. //
  36. CAutomationObject::CAutomationObject
  37. (
  38. IUnknown *pUnkOuter,
  39. int ObjType,
  40. void *pVTable,
  41. BOOL fExpandoEnabled
  42. )
  43. : CUnknownObject(pUnkOuter, pVTable), m_ObjectType (ObjType)
  44. {
  45. m_fLoadedTypeInfo = FALSE;
  46. m_fExpandoEnabled = (BYTE)fExpandoEnabled;
  47. m_pexpando = NULL;
  48. }
  49. //=--------------------------------------------------------------------------=
  50. // CAutomationObject::~CAutomationObject
  51. //=--------------------------------------------------------------------------=
  52. // "I have a rendezvous with Death, At some disputed barricade"
  53. // - Alan Seeger (1888-1916)
  54. //
  55. // Notes:
  56. //
  57. CAutomationObject::~CAutomationObject ()
  58. {
  59. // if we loaded up a type info, release our count on the globally stashed
  60. // type infos, and release if it becomes zero.
  61. //
  62. if (m_fLoadedTypeInfo) {
  63. // we have to crit sect this since it's possible to have more than
  64. // one thread partying with this object.
  65. //
  66. EnterCriticalSection(&g_CriticalSection);
  67. ASSERT(CTYPEINFOOFOBJECT(m_ObjectType), "Bogus ref counting on the Type Infos");
  68. CTYPEINFOOFOBJECT(m_ObjectType)--;
  69. // if we're the last one, free it!
  70. //
  71. if (!CTYPEINFOOFOBJECT(m_ObjectType)) {
  72. PTYPEINFOOFOBJECT(m_ObjectType)->Release();
  73. PTYPEINFOOFOBJECT(m_ObjectType) = NULL;
  74. }
  75. LeaveCriticalSection(&g_CriticalSection);
  76. }
  77. if (m_pexpando)
  78. {
  79. delete m_pexpando;
  80. }
  81. return;
  82. }
  83. //=--------------------------------------------------------------------------=
  84. // CAutomationObject::InternalQueryInterface
  85. //=--------------------------------------------------------------------------=
  86. // the controlling unknown will call this for us in the case where they're
  87. // looking for a specific interface.
  88. //
  89. // Parameters:
  90. // REFIID - [in] interface they want
  91. // void ** - [out] where they want to put the resulting object ptr.
  92. //
  93. // Output:
  94. // HRESULT - S_OK, E_NOINTERFACE
  95. //
  96. // Notes:
  97. //
  98. HRESULT CAutomationObject::InternalQueryInterface
  99. (
  100. REFIID riid,
  101. void **ppvObjOut
  102. )
  103. {
  104. ASSERT(ppvObjOut, "controlling Unknown should be checking this!");
  105. // start looking for the guids we support, namely IDispatch, and
  106. // IDispatchEx
  107. if (DO_GUIDS_MATCH(riid, IID_IDispatch)) {
  108. // If expando functionality is enabled, attempt to allocate an
  109. // expando object and return that for the IDispatch interface.
  110. // If the allocation fails, we will fall back on using the regular
  111. // IDispatch from m_pvInterface;
  112. if (m_fExpandoEnabled)
  113. {
  114. if (!m_pexpando)
  115. m_pexpando = new CExpandoObject(m_pUnkOuter, (IDispatch*) m_pvInterface);
  116. if (m_pexpando)
  117. {
  118. *ppvObjOut = (void*)(IDispatch*) m_pexpando;
  119. ((IUnknown *)(*ppvObjOut))->AddRef();
  120. return S_OK;
  121. }
  122. }
  123. *ppvObjOut = (void*) (IDispatch*) m_pvInterface;
  124. ((IUnknown *)(*ppvObjOut))->AddRef();
  125. return S_OK;
  126. }
  127. else if (DO_GUIDS_MATCH(riid, IID_IDispatchEx) && m_fExpandoEnabled) {
  128. // Allocate the expando object if it hasn't been allocated already
  129. if (!m_pexpando)
  130. m_pexpando = new CExpandoObject(m_pUnkOuter, (IDispatch*) m_pvInterface);
  131. // If the allocation succeeded, return the IDispatchEx interface from
  132. // the expando. Otherwise fall through to CUnknownObject::InternalQueryInterface,
  133. // (which will most likely fail)
  134. if (m_pexpando)
  135. {
  136. *ppvObjOut = (void *)(IDispatchEx *) m_pexpando;
  137. ((IUnknown *)(*ppvObjOut))->AddRef();
  138. return S_OK;
  139. }
  140. }
  141. // just get our parent class to process it from here on out.
  142. //
  143. return CUnknownObject::InternalQueryInterface(riid, ppvObjOut);
  144. }
  145. //=--------------------------------------------------------------------------=
  146. // CAutomationObject::GetTypeInfoCount
  147. //=--------------------------------------------------------------------------=
  148. // returns the number of type information interfaces that the object provides
  149. //
  150. // Parameters:
  151. // UINT * - [out] the number of interfaces supported.
  152. //
  153. // Output:
  154. // HRESULT - S_OK, E_NOTIMPL, E_INVALIDARG
  155. //
  156. // Notes:
  157. //
  158. STDMETHODIMP CAutomationObject::GetTypeInfoCount
  159. (
  160. UINT *pctinfo
  161. )
  162. {
  163. // arg checking
  164. //
  165. if (!pctinfo)
  166. return E_INVALIDARG;
  167. // we support GetTypeInfo, so we need to return the count here.
  168. //
  169. *pctinfo = 1;
  170. return S_OK;
  171. }
  172. //=--------------------------------------------------------------------------=
  173. // CAutomationObject::GetTypeInfo
  174. //=--------------------------------------------------------------------------=
  175. // Retrieves a type information object, which can be used to get the type
  176. // information for an interface.
  177. //
  178. // Parameters:
  179. // UINT - [in] the type information they'll want returned
  180. // LCID - [in] the LCID of the type info we want
  181. // ITypeInfo ** - [out] the new type info object.
  182. //
  183. // Output:
  184. // HRESULT - S_OK, E_INVALIDARG, etc.
  185. //
  186. // Notes:
  187. //
  188. STDMETHODIMP CAutomationObject::GetTypeInfo
  189. (
  190. UINT itinfo,
  191. LCID lcid,
  192. ITypeInfo **ppTypeInfoOut
  193. )
  194. {
  195. DWORD dwPathLen;
  196. char szDllPath[MAX_PATH];
  197. HRESULT hr;
  198. ITypeLib *pTypeLib;
  199. ITypeInfo **ppTypeInfo =NULL;
  200. // arg checking
  201. //
  202. if (itinfo != 0)
  203. return DISP_E_BADINDEX;
  204. if (!ppTypeInfoOut)
  205. return E_POINTER;
  206. *ppTypeInfoOut = NULL;
  207. // ppTypeInfo will point to our global holder for this particular
  208. // type info. if it's null, then we have to load it up. if it's not
  209. // NULL, then it's already loaded, and we're happy.
  210. // crit sect this entire nightmare so we're okay with multiple
  211. // threads trying to use this object.
  212. //
  213. EnterCriticalSection(&g_CriticalSection);
  214. ppTypeInfo = PPTYPEINFOOFOBJECT(m_ObjectType);
  215. if (*ppTypeInfo == NULL) {
  216. ITypeInfo *pTypeInfoTmp;
  217. HREFTYPE hrefType;
  218. // we don't have the type info around, so go load it.
  219. //
  220. hr = LoadRegTypeLib(*g_pLibid, (USHORT)VERSIONOFOBJECT(m_ObjectType), 0,
  221. LANG_NEUTRAL, &pTypeLib);
  222. // if, for some reason, we failed to load the type library this
  223. // way, we're going to try and load the type library directly out of
  224. // our resources. this has the advantage of going and re-setting all
  225. // the registry information again for us.
  226. //
  227. if (FAILED(hr)) {
  228. dwPathLen = GetModuleFileName(g_hInstance, szDllPath, MAX_PATH);
  229. if (!dwPathLen) {
  230. hr = E_FAIL;
  231. goto CleanUp;
  232. }
  233. MAKE_WIDEPTR_FROMANSI(pwsz, szDllPath);
  234. hr = LoadTypeLib(pwsz, &pTypeLib);
  235. CLEANUP_ON_FAILURE(hr);
  236. }
  237. // we've got the Type Library now, so get the type info for the interface
  238. // we're interested in.
  239. //
  240. hr = pTypeLib->GetTypeInfoOfGuid((REFIID)INTERFACEOFOBJECT(m_ObjectType), &pTypeInfoTmp);
  241. pTypeLib->Release();
  242. CLEANUP_ON_FAILURE(hr);
  243. // the following couple of lines of code are to dereference the dual
  244. // interface stuff and take us right to the dispatch portion of the
  245. // interfaces.
  246. //
  247. hr = pTypeInfoTmp->GetRefTypeOfImplType(0xffffffff, &hrefType);
  248. if (FAILED(hr)) {
  249. pTypeInfoTmp->Release();
  250. goto CleanUp;
  251. }
  252. hr = pTypeInfoTmp->GetRefTypeInfo(hrefType, ppTypeInfo);
  253. pTypeInfoTmp->Release();
  254. CLEANUP_ON_FAILURE(hr);
  255. // add an extra reference to this object. if it ever becomes zero, then
  256. // we need to release it ourselves. crit sect this since more than
  257. // one thread can party on this object.
  258. //
  259. CTYPEINFOOFOBJECT(m_ObjectType)++;
  260. m_fLoadedTypeInfo = TRUE;
  261. }
  262. // we still have to go and addref the Type info object, however, so that
  263. // the people using it can release it.
  264. //
  265. (*ppTypeInfo)->AddRef();
  266. *ppTypeInfoOut = *ppTypeInfo;
  267. hr = S_OK;
  268. CleanUp:
  269. LeaveCriticalSection(&g_CriticalSection);
  270. return hr;
  271. }
  272. //=--------------------------------------------------------------------------=
  273. // CAutomationObject::GetIDsOfNames
  274. //=--------------------------------------------------------------------------=
  275. // Maps a single member and an optional set of argument names to a
  276. // corresponding set of integer DISPIDs
  277. //
  278. // Parameters:
  279. // REFIID - [in] must be IID_NULL
  280. // OLECHAR ** - [in] array of names to map.
  281. // UINT - [in] count of names in the array.
  282. // LCID - [in] LCID on which to operate
  283. // DISPID * - [in] place to put the corresponding DISPIDs.
  284. //
  285. // Output:
  286. // HRESULT - S_OK, E_OUTOFMEMORY, DISP_E_UNKNOWNNAME,
  287. // DISP_E_UNKNOWNLCID
  288. //
  289. // Notes:
  290. // - we're just going to use DispGetIDsOfNames to save us a lot of hassle,
  291. // and to let this superclass handle it.
  292. //
  293. STDMETHODIMP CAutomationObject::GetIDsOfNames
  294. (
  295. REFIID riid,
  296. OLECHAR **rgszNames,
  297. UINT cNames,
  298. LCID lcid,
  299. DISPID *rgdispid
  300. )
  301. {
  302. HRESULT hr;
  303. ITypeInfo *pTypeInfo;
  304. if (!DO_GUIDS_MATCH(riid, IID_NULL))
  305. return E_INVALIDARG;
  306. // get the type info for this dude!
  307. //
  308. hr = GetTypeInfo(0, lcid, &pTypeInfo);
  309. RETURN_ON_FAILURE(hr);
  310. // use the standard provided routines to do all the work for us.
  311. //
  312. hr = pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
  313. pTypeInfo->Release();
  314. return hr;
  315. }
  316. //=--------------------------------------------------------------------------=
  317. // CAutomationObject::Invoke
  318. //=--------------------------------------------------------------------------=
  319. // provides access to the properties and methods on this object.
  320. //
  321. // Parameters:
  322. // DISPID - [in] identifies the member we're working with.
  323. // REFIID - [in] must be IID_NULL.
  324. // LCID - [in] language we're working under
  325. // USHORT - [in] flags, propput, get, method, etc ...
  326. // DISPPARAMS * - [in] array of arguments.
  327. // VARIANT * - [out] where to put result, or NULL if they don't care.
  328. // EXCEPINFO * - [out] filled in in case of exception
  329. // UINT * - [out] where the first argument with an error is.
  330. //
  331. // Output:
  332. // HRESULT - tonnes of them.
  333. //
  334. // Notes:
  335. //
  336. STDMETHODIMP CAutomationObject::Invoke
  337. (
  338. DISPID dispid,
  339. REFIID riid,
  340. LCID lcid,
  341. WORD wFlags,
  342. DISPPARAMS *pdispparams,
  343. VARIANT *pvarResult,
  344. EXCEPINFO *pexcepinfo,
  345. UINT *puArgErr
  346. )
  347. {
  348. HRESULT hr;
  349. ITypeInfo *pTypeInfo;
  350. if (!DO_GUIDS_MATCH(riid, IID_NULL))
  351. return E_INVALIDARG;
  352. // get our typeinfo first!
  353. //
  354. hr = GetTypeInfo(0, lcid, &pTypeInfo);
  355. RETURN_ON_FAILURE(hr);
  356. // Clear exceptions
  357. //
  358. SetErrorInfo(0L, NULL);
  359. // This is exactly what DispInvoke does--so skip the overhead.
  360. //
  361. hr = pTypeInfo->Invoke(m_pvInterface, dispid, wFlags,
  362. pdispparams, pvarResult,
  363. pexcepinfo, puArgErr);
  364. pTypeInfo->Release();
  365. return hr;
  366. }
  367. //=--------------------------------------------------------------------------=
  368. // CAutomationObject::Exception
  369. //=--------------------------------------------------------------------------=
  370. // fills in the rich error info object so that both our vtable bound interfaces
  371. // and calls through ITypeInfo::Invoke get the right error informaiton.
  372. //
  373. // Parameters:
  374. // HRESULT - [in] the SCODE that should be associated with this err
  375. // WORD - [in] the RESOURCE ID of the error message.
  376. // DWORD - [in] helpcontextid for the error
  377. //
  378. // Output:
  379. // HRESULT - the HRESULT that was passed in.
  380. //
  381. // Notes:
  382. //
  383. HRESULT CAutomationObject::Exception
  384. (
  385. HRESULT hrExcep,
  386. WORD idException,
  387. DWORD dwHelpContextID
  388. )
  389. {
  390. ICreateErrorInfo *pCreateErrorInfo;
  391. IErrorInfo *pErrorInfo;
  392. WCHAR wszTmp[256];
  393. char szTmp[256];
  394. HRESULT hr;
  395. // first get the createerrorinfo object.
  396. //
  397. hr = CreateErrorInfo(&pCreateErrorInfo);
  398. if (FAILED(hr)) return hrExcep;
  399. MAKE_WIDEPTR_FROMANSI(wszHelpFile, HELPFILEOFOBJECT(m_ObjectType));
  400. // set up some default information on it.
  401. //
  402. pCreateErrorInfo->SetGUID((REFIID)INTERFACEOFOBJECT(m_ObjectType));
  403. pCreateErrorInfo->SetHelpFile(wszHelpFile);
  404. pCreateErrorInfo->SetHelpContext(dwHelpContextID);
  405. // load in the actual error string value. max of 256.
  406. //
  407. LoadString(GetResourceHandle(), idException, szTmp, 256);
  408. MultiByteToWideChar(CP_ACP, 0, szTmp, -1, wszTmp, 256);
  409. pCreateErrorInfo->SetDescription(wszTmp);
  410. // load in the source
  411. //
  412. MultiByteToWideChar(CP_ACP, 0, NAMEOFOBJECT(m_ObjectType), -1, wszTmp, 256);
  413. pCreateErrorInfo->SetSource(wszTmp);
  414. // now set the Error info up with the system
  415. //
  416. hr = pCreateErrorInfo->QueryInterface(IID_IErrorInfo, (void **)&pErrorInfo);
  417. CLEANUP_ON_FAILURE(hr);
  418. SetErrorInfo(0, pErrorInfo);
  419. pErrorInfo->Release();
  420. CleanUp:
  421. pCreateErrorInfo->Release();
  422. return hrExcep;
  423. }
  424. //=--------------------------------------------------------------------------=
  425. // CAutomationObject::InterfaceSupportsErrorInfo
  426. //=--------------------------------------------------------------------------=
  427. // indicates whether or not the given interface supports rich error information
  428. //
  429. // Parameters:
  430. // REFIID - [in] the interface we want the answer for.
  431. //
  432. // Output:
  433. // HRESULT - S_OK = Yes, S_FALSE = No.
  434. //
  435. // Notes:
  436. //
  437. HRESULT CAutomationObject::InterfaceSupportsErrorInfo
  438. (
  439. REFIID riid
  440. )
  441. {
  442. // see if it's the interface for the type of object that we are.
  443. //
  444. if (riid == (REFIID)INTERFACEOFOBJECT(m_ObjectType))
  445. return S_OK;
  446. return S_FALSE;
  447. }
  448. //=--------------------------------------------------------------------------=
  449. // CAutomationObject::GetResourceHandle [helper]
  450. //=--------------------------------------------------------------------------=
  451. // virtual routine to get the resource handle. virtual, so that inheriting
  452. // objects, such as COleControl can use theirs instead, which goes and gets
  453. // the Host's version ...
  454. //
  455. // Output:
  456. // HINSTANCE
  457. //
  458. // Notes:
  459. //
  460. HINSTANCE CAutomationObject::GetResourceHandle
  461. (
  462. void
  463. )
  464. {
  465. return ::GetResourceHandle();
  466. }