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.

743 lines
17 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1997.
  5. //
  6. // File: cdispmgr.cxx
  7. //
  8. // Contents: The dispatch manager -- a class to manage
  9. // multiple IDispatch-callable interfaces.
  10. //
  11. // Classes: CAggregateeDispMgr
  12. //
  13. // Functions: None external.
  14. //
  15. // History: ??-???-?? KrishnaG created
  16. // 07-Sep-97 t-blakej Commented, cleaned up, made
  17. // independent of ADSI.
  18. //
  19. // See cdispmgr.hxx for a more thorough description of the dispatch manager.
  20. //
  21. //----------------------------------------------------------------------------
  22. //
  23. // Since this class is useful outside of ADSI, some work has been taken to
  24. // make it not depend on any ADSI-specific code. It needs two ADSI header
  25. // files (cdispmgr.hxx and iprops.hxx), but they only depend on definitions
  26. // from standard system header files.
  27. //
  28. // To accomodate the current building method in ADSI, the precompiled
  29. // header "procs.hxx" is included; this includes all the necessary ADSI
  30. // header files and definitions. But for use outside of ADSI, the few
  31. // necessary header files are explicitly included below; see the comment by
  32. // "#ifndef ADsAssert".
  33. //
  34. // So if not compiling for ADSI, comment the following two lines out.
  35. //
  36. #include "iisext.hxx"
  37. #pragma hdrstop
  38. //////////////////////////////////////////////////////////////////////////////
  39. //
  40. // General helper definitions, routines, and inclusions:
  41. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Begin Non-ADSI compile stuff
  42. //
  43. // This macro is defined by the precompiled header file, so the following
  44. // will only be included if not compiling for ADSI.
  45. //
  46. #ifndef ADsAssert
  47. //
  48. // Necessary system headers.
  49. //
  50. #define UNICODE
  51. #define _UNICODE
  52. #define _OLEAUT32_
  53. #define INC_OLE2
  54. #include <windows.h>
  55. #include <stdio.h>
  56. //
  57. // Necessary class definitions used by the dispatch manager.
  58. // Edit these paths if necessary.
  59. //
  60. #include "cdispmgr.hxx"
  61. #include "iprops.hxx"
  62. #endif // ADsAssert
  63. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- End Non-ADSI compile stuff
  64. //
  65. // A simple assert function.
  66. //
  67. #if DBG == 1
  68. //+---------------------------------------------------------------------------
  69. //
  70. // Function: AssertEx
  71. //
  72. // Synopsis: Display assertion information.
  73. //
  74. // Effects: Called when an assertion is hit.
  75. //
  76. // History: Simplified from Win4AssertEx, to make this dispatch manager
  77. // not depend on other files.
  78. //
  79. //----------------------------------------------------------------------------
  80. static void
  81. AssertEx(char const *szFile, int iLine, char const *szMessage)
  82. {
  83. static char szAssertCaption[100];
  84. sprintf(szAssertCaption, "File: %s line %u, thread id %d",
  85. szFile, iLine, GetCurrentThreadId());
  86. if (IDCANCEL == MessageBoxA(
  87. NULL,
  88. (char *) szMessage,
  89. (LPSTR) szAssertCaption,
  90. MB_SETFOREGROUND |
  91. MB_TASKMODAL | MB_ICONEXCLAMATION | MB_OKCANCEL
  92. ))
  93. {
  94. DebugBreak();
  95. }
  96. }
  97. # define DispMgrAssert(x) (void)((x) || (AssertEx(__FILE__, __LINE__, #x),0))
  98. #else
  99. # define AssertEx(f,l,m)
  100. # define DispMgrAssert(x)
  101. #endif
  102. //////////////////////////////////////////////////////////////////////////////
  103. //
  104. // Inline routines:
  105. static inline LONG
  106. getDispMgrId(DISPID InputDispId)
  107. {
  108. return (InputDispId & 0x7f000000) >> 24;
  109. }
  110. static inline LONG
  111. getTypeInfoId(DISPID InputDispId)
  112. {
  113. return (InputDispId & 0x00ff0000) >> 16;
  114. }
  115. static inline LONG
  116. getDispId(DISPID InputDispId)
  117. {
  118. return (InputDispId & 0x0000ffff);
  119. }
  120. static inline void
  121. MakeDISPID(
  122. LONG ExtensionId,
  123. LONG TypeInfoId,
  124. LONG DispId,
  125. DISPID *pResult
  126. )
  127. {
  128. if (DispId == DISPID_UNKNOWN){
  129. *pResult = DispId;
  130. }else if (TypeInfoId < 0 || TypeInfoId >= 0x100 ||
  131. DispId < 0 || DispId >= 0x10000){
  132. //
  133. // Might happen if some object has very large dispid's.
  134. // But we can't handle it if it does.
  135. //
  136. *pResult = DISPID_UNKNOWN;
  137. }
  138. else{
  139. *pResult = ((ExtensionId & 0xff) << 24) |((TypeInfoId & 0xff) << 16) | (DispId & 0xffff);
  140. }
  141. }
  142. static inline void
  143. MakeDISPIDs(
  144. LONG ExtensionId,
  145. LONG TypeInfoId,
  146. DISPID *rgdispid,
  147. unsigned int cNames
  148. )
  149. {
  150. for (unsigned int i = 0; i < cNames; i++)
  151. {
  152. MakeDISPID(ExtensionId, TypeInfoId, rgdispid[i], &rgdispid[i]);
  153. }
  154. }
  155. //////////////////////////////////////////////////////////////////////////////
  156. //
  157. // Public methods:
  158. CAggregateeDispMgr::CAggregateeDispMgr()
  159. {
  160. _pTypeInfoEntry = NULL;
  161. _pDispidNewEnum = NULL;
  162. _dwTypeInfoId = 0;
  163. _pDispidValue = NULL;
  164. _pPropertyCache = NULL;
  165. _dwPropCacheID = 0;
  166. _dwExtensionID = 0;
  167. }
  168. CAggregateeDispMgr::~CAggregateeDispMgr()
  169. {
  170. PTYPEINFOENTRY pTypeInfoEntry = NULL;
  171. PTYPEINFOENTRY pTemp = NULL;
  172. ITypeInfo *pTypeInfo = NULL;
  173. pTypeInfoEntry = _pTypeInfoEntry;
  174. while (pTypeInfoEntry) {
  175. pTemp = pTypeInfoEntry;
  176. pTypeInfo = (ITypeInfo *)pTypeInfoEntry->ptypeinfo;
  177. pTypeInfo->Release();
  178. pTypeInfoEntry = pTemp->pNext;
  179. LocalFree(pTemp);
  180. }
  181. }
  182. void
  183. CAggregateeDispMgr::RegisterPropertyCache(IPropertyCache *pPropertyCache)
  184. {
  185. _pPropertyCache = pPropertyCache;
  186. _dwPropCacheID = gentypeinfoid();
  187. }
  188. STDMETHODIMP
  189. CAggregateeDispMgr::GetTypeInfoCount(unsigned int *pctinfo)
  190. {
  191. return E_NOTIMPL;
  192. }
  193. STDMETHODIMP
  194. CAggregateeDispMgr::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo **pptinfo)
  195. {
  196. return E_NOTIMPL;
  197. }
  198. //
  199. // This works only for single names; if multiple names are
  200. // passed we die big time. This is help us get going using VB's _NewEnum
  201. //
  202. STDMETHODIMP
  203. CAggregateeDispMgr::GetIDsOfNames(REFIID iid, LPWSTR *rgszNames,
  204. unsigned int cNames, LCID lcid, DISPID *rgdispid)
  205. {
  206. PTYPEINFOENTRY pTypeInfo = NULL;
  207. HRESULT hr = DISP_E_UNKNOWNNAME;
  208. //
  209. // Try our list of TypeInfos.
  210. //
  211. pTypeInfo = _pTypeInfoEntry;
  212. while (pTypeInfo) {
  213. hr = DispGetIDsOfNames(((ITypeInfo *)pTypeInfo->ptypeinfo),
  214. rgszNames,
  215. cNames,
  216. rgdispid
  217. );
  218. if (SUCCEEDED(hr)) {
  219. //
  220. // aggregatee no longer needs to include extension id
  221. // in dispid.
  222. // TODO: change function to get rid of ext id = 0 during clean up
  223. //
  224. MakeDISPIDs(0, pTypeInfo->TypeInfoId, rgdispid, cNames);
  225. return hr;
  226. }
  227. pTypeInfo = pTypeInfo->pNext;
  228. }
  229. //
  230. // Try our property cache.
  231. //
  232. if (FAILED(hr) && _pPropertyCache) {
  233. hr = S_OK;
  234. for (DWORD dw = 0; dw < cNames; dw++) {
  235. if (FAILED(_pPropertyCache->locateproperty(rgszNames[dw],
  236. (PDWORD)(rgdispid + dw)))) {
  237. hr = DISP_E_UNKNOWNNAME;
  238. rgdispid[dw] = DISPID_UNKNOWN;
  239. }
  240. }
  241. if (SUCCEEDED(hr)) {
  242. //
  243. // aggregatee no longer needs to include extension id
  244. // in dispid.
  245. // TODO: change function to get rid of ext id = 0 during clean up
  246. //
  247. MakeDISPIDs(0, _dwPropCacheID, rgdispid, cNames);
  248. }
  249. }
  250. return hr;
  251. }
  252. STDMETHODIMP
  253. CAggregateeDispMgr::Invoke(DISPID dispidMember, REFIID iid, LCID lcid,
  254. unsigned short wFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult,
  255. EXCEPINFO *pexcepinfo, unsigned int *puArgErr)
  256. {
  257. //
  258. // Clear the error object before we call invoke.
  259. //
  260. SetErrorInfo(0, NULL);
  261. return TypeInfoInvoke(dispidMember,
  262. iid,
  263. lcid,
  264. wFlags,
  265. pdispparams,
  266. pvarResult,
  267. pexcepinfo,
  268. puArgErr
  269. );
  270. }
  271. //////////////////////////////////////////////////////////////////////////////
  272. //
  273. // Private methods and helper functions:
  274. void *
  275. CAggregateeDispMgr::getInterfacePtr(LONG TypeInfoId)
  276. {
  277. PTYPEINFOENTRY pTypeInfoEntry = FindTypeInfoEntry(TypeInfoId);
  278. return (pTypeInfoEntry ? pTypeInfoEntry->pInterfacePointer : NULL);
  279. }
  280. ITypeInfo *
  281. CAggregateeDispMgr::getTypeInfo(LONG TypeInfoId)
  282. {
  283. PTYPEINFOENTRY pTypeInfoEntry = FindTypeInfoEntry(TypeInfoId);
  284. return (ITypeInfo *)(pTypeInfoEntry ? pTypeInfoEntry->ptypeinfo : NULL);
  285. }
  286. PTYPEINFOENTRY
  287. CAggregateeDispMgr::FindTypeInfoEntry(LONG TypeInfoId)
  288. {
  289. PTYPEINFOENTRY pTypeInfoEntry;
  290. pTypeInfoEntry = _pTypeInfoEntry;
  291. while (pTypeInfoEntry) {
  292. if (pTypeInfoEntry->TypeInfoId == TypeInfoId) {
  293. return pTypeInfoEntry;
  294. }
  295. pTypeInfoEntry = pTypeInfoEntry->pNext;
  296. }
  297. return NULL;
  298. }
  299. PTYPEINFOENTRY
  300. CAggregateeDispMgr::FindTypeInfo(void *pTypeInfo)
  301. {
  302. PTYPEINFOENTRY pTypeInfoEntry;
  303. pTypeInfoEntry = _pTypeInfoEntry;
  304. while (pTypeInfoEntry) {
  305. if (pTypeInfoEntry->ptypeinfo == pTypeInfo) {
  306. return pTypeInfoEntry;
  307. }
  308. pTypeInfoEntry = pTypeInfoEntry->pNext;
  309. }
  310. return NULL;
  311. }
  312. HRESULT
  313. CAggregateeDispMgr::AddTypeInfo(void *ptypeinfo, void *pIntfptr)
  314. {
  315. PTYPEINFOENTRY pTypeInfoEntry = NULL;
  316. HRESULT hr;
  317. if (FindTypeInfo(ptypeinfo)) {
  318. return E_FAIL;
  319. }
  320. pTypeInfoEntry = (PTYPEINFOENTRY)LocalAlloc(LPTR,sizeof(TYPEINFOENTRY));
  321. if (!pTypeInfoEntry) {
  322. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  323. }
  324. pTypeInfoEntry->ptypeinfo = ptypeinfo;
  325. pTypeInfoEntry->TypeInfoId = gentypeinfoid();
  326. pTypeInfoEntry->pInterfacePointer = pIntfptr;
  327. pTypeInfoEntry->pNext = _pTypeInfoEntry;
  328. _pTypeInfoEntry = pTypeInfoEntry;
  329. return S_OK;
  330. error:
  331. return hr;
  332. }
  333. STDMETHODIMP
  334. CAggregateeDispMgr::TypeInfoInvoke(DISPID dispidMember, REFIID iid, LCID lcid,
  335. unsigned short wFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult,
  336. EXCEPINFO *pexcepinfo, unsigned int *puArgErr)
  337. {
  338. void *pInterfacePtr = NULL;
  339. DISPID dispid = 0;
  340. DISPID typeinfoid = 0;
  341. ITypeInfo *pTypeInfo = NULL;
  342. HRESULT hr = S_OK;
  343. if (dispidMember <= 0) {
  344. //
  345. // One of the special DISPIDs.
  346. //
  347. // If we have an interface pointer for it, use that.
  348. // If we don't, and we have a base IDispatch pointer,
  349. // pass it to the base pointer's Invoke() method.
  350. // If we don't, and we don't have a base IDispatch pointer,
  351. // return failure.
  352. //
  353. dispid = dispidMember;
  354. switch (dispid) {
  355. case DISPID_VALUE:
  356. if (_pDispidValue) {
  357. pTypeInfo = (ITypeInfo *)_pDispidValue->ptypeinfo;
  358. pInterfacePtr = _pDispidValue->pInterfacePointer;
  359. }
  360. break;
  361. case DISPID_NEWENUM:
  362. if (_pDispidNewEnum) {
  363. pTypeInfo = (ITypeInfo *)_pDispidNewEnum->ptypeinfo;
  364. pInterfacePtr = _pDispidNewEnum->pInterfacePointer;
  365. }
  366. break;
  367. default:
  368. break;
  369. }
  370. if (!pInterfacePtr) {
  371. BAIL_ON_FAILURE(hr = DISP_E_MEMBERNOTFOUND);
  372. }else {
  373. //
  374. // Fill in the special case scenarios here
  375. //
  376. hr = DispInvoke(
  377. pInterfacePtr,
  378. pTypeInfo,
  379. dispid,
  380. wFlags,
  381. pdispparams,
  382. pvarResult,
  383. pexcepinfo,
  384. puArgErr
  385. );
  386. return(hr);
  387. }
  388. } else {
  389. //
  390. // A regular DISPID of ours.
  391. //
  392. typeinfoid = getTypeInfoId(dispidMember);
  393. dispid = getDispId(dispidMember);
  394. if ((_pPropertyCache == NULL) || (typeinfoid != _dwPropCacheID)) {
  395. pInterfacePtr = getInterfacePtr(typeinfoid);
  396. pTypeInfo = getTypeInfo(typeinfoid);
  397. if (!pTypeInfo)
  398. //
  399. // Shouldn't happen.
  400. //
  401. BAIL_ON_FAILURE(hr = DISP_E_MEMBERNOTFOUND);
  402. }
  403. if ((_pPropertyCache == NULL) || (typeinfoid != _dwPropCacheID)) {
  404. //
  405. // A regular interface.
  406. //
  407. hr = DispInvoke(
  408. pInterfacePtr,
  409. pTypeInfo,
  410. dispid,
  411. wFlags,
  412. pdispparams,
  413. pvarResult,
  414. pexcepinfo,
  415. puArgErr
  416. );
  417. }else {
  418. //
  419. // A "dynamic DISPID", for the property cache.
  420. //
  421. hr = AggregateeDynamicDispidInvoke(
  422. _pPropertyCache,
  423. dispid,
  424. wFlags,
  425. pdispparams,
  426. pvarResult
  427. );
  428. }
  429. }
  430. error:
  431. return hr;
  432. }
  433. HRESULT
  434. AggregateeDynamicDispidInvoke(
  435. IPropertyCache * pPropertyCache,
  436. DISPID dispid,
  437. unsigned short wFlags,
  438. DISPPARAMS *pdispparams,
  439. VARIANT * pvarResult
  440. )
  441. {
  442. HRESULT hr = S_OK;
  443. if (!pPropertyCache) {
  444. return(E_INVALIDARG);
  445. }
  446. if (wFlags & DISPATCH_PROPERTYGET) {
  447. if (!pvarResult) {
  448. BAIL_ON_FAILURE(hr = E_INVALIDARG);
  449. }
  450. hr = pPropertyCache->getproperty((DWORD)dispid,pvarResult);
  451. if (FAILED(hr)) {
  452. #if 1
  453. // This lets us return S_OK and a VT_EMPTY variant if
  454. // there's no data. #if this out to disable it.
  455. V_VT(pvarResult) = VT_EMPTY;
  456. hr = S_OK;
  457. #else
  458. V_VT(pvarResult) = VT_ERROR;
  459. #endif
  460. }
  461. }else if (wFlags & DISPATCH_PROPERTYPUT) {
  462. //
  463. // only handles one argument.
  464. //
  465. if (pdispparams[0].cArgs != 1){
  466. hr = DISP_E_BADPARAMCOUNT;
  467. }
  468. else {
  469. hr = pPropertyCache->putproperty(
  470. (DWORD)dispid,
  471. pdispparams[0].rgvarg[0]
  472. );
  473. }
  474. }else {
  475. hr = E_INVALIDARG;
  476. }
  477. error:
  478. return(hr);
  479. }
  480. HRESULT
  481. CAggregateeDispMgr::MarkAsNewEnum(void *pTypeInfo)
  482. {
  483. PTYPEINFOENTRY pTypeInfoEntry;
  484. if (!pTypeInfo) {
  485. return E_FAIL;
  486. }
  487. if (!(pTypeInfoEntry = FindTypeInfo(pTypeInfo))) {
  488. return E_FAIL;
  489. }
  490. _pDispidNewEnum = pTypeInfoEntry;
  491. return S_OK;
  492. }
  493. HRESULT
  494. CAggregateeDispMgr::MarkAsItem(void *pTypeInfo)
  495. {
  496. PTYPEINFOENTRY pTypeInfoEntry;
  497. if (!pTypeInfo) {
  498. return E_FAIL;
  499. }
  500. if (!(pTypeInfoEntry = FindTypeInfo(pTypeInfo))) {
  501. return E_FAIL;
  502. }
  503. _pDispidValue = pTypeInfoEntry;
  504. return S_OK;
  505. }
  506. LONG
  507. CAggregateeDispMgr::gentypeinfoid()
  508. {
  509. //
  510. // This would mean we've registered 65536 IDispatch methods
  511. // in this object's dispatch manager. We lose.
  512. //
  513. DispMgrAssert(_dwTypeInfoId < 0xffff);
  514. return (_dwTypeInfoId++);
  515. }
  516. typedef struct _typeinfotable
  517. {
  518. GUID iid;
  519. ITypeInfo * pTypeInfo;
  520. struct _typeinfotable *pNext;
  521. }TYPEINFO_TABLE, *PTYPEINFO_TABLE;
  522. ITypeInfo *
  523. AggregateeFindTypeInfo(
  524. PTYPEINFO_TABLE pTypeInfoTable,
  525. REFIID iid
  526. )
  527. {
  528. PTYPEINFO_TABLE pTemp = NULL;
  529. pTemp = pTypeInfoTable;
  530. while (pTemp) {
  531. if (IsEqualIID(iid, pTemp->iid)) {
  532. return pTemp->pTypeInfo;
  533. }
  534. pTemp = pTemp->pNext;
  535. }
  536. return NULL;
  537. }
  538. //+------------------------------------------------------------------------
  539. //
  540. // Function: LoadTypeInfo
  541. //
  542. // Synopsis: Loads a typeinfo from a registered typelib.
  543. //
  544. // Arguments: [clsidTL] -- TypeLib GUID
  545. // [clsidTI] -- TypeInfo GUID
  546. // [ppTI] -- Resulting typeInfo
  547. //
  548. // Returns: HRESULT
  549. //
  550. //-------------------------------------------------------------------------
  551. HRESULT
  552. AggregateeLoadTypeInfo(CLSID clsidTL, CLSID clsidTI, LPTYPEINFO *ppTI)
  553. {
  554. HRESULT hr;
  555. ITypeLib * pTL;
  556. DispMgrAssert(ppTI);
  557. *ppTI = NULL;
  558. hr = LoadRegTypeLib(clsidTL, 1, 0, LOCALE_SYSTEM_DEFAULT, &pTL);
  559. if (hr)
  560. return hr;
  561. hr = pTL->GetTypeInfoOfGuid(clsidTI, ppTI);
  562. pTL->Release();
  563. return hr;
  564. }
  565. HRESULT
  566. CAggregateeDispMgr::LoadTypeInfoEntry(
  567. REFIID libid,
  568. REFIID iid,
  569. void * pIntf,
  570. DISPID SpecialId
  571. )
  572. {
  573. ITypeInfo * pTypeInfo = NULL;
  574. HRESULT hr;
  575. hr = AggregateeLoadTypeInfo(libid, iid, &pTypeInfo);
  576. BAIL_ON_FAILURE(hr);
  577. hr = AddTypeInfo(pTypeInfo, pIntf);
  578. BAIL_ON_FAILURE(hr);
  579. if (SpecialId == -4) {
  580. hr = MarkAsNewEnum(pTypeInfo);
  581. } else if (SpecialId == DISPID_VALUE) {
  582. hr = MarkAsItem(pTypeInfo);
  583. }
  584. return S_OK;
  585. error:
  586. if (pTypeInfo)
  587. pTypeInfo->Release();
  588. return hr;
  589. }
  590. //
  591. // Kept for backwards compatibility.
  592. //
  593. HRESULT
  594. LoadTypeInfoEntry(
  595. CAggregateeDispMgr *pDispMgr,
  596. REFIID libid,
  597. REFIID iid,
  598. void * pIntf,
  599. DISPID SpecialId
  600. )
  601. {
  602. return pDispMgr->LoadTypeInfoEntry(libid, iid, pIntf, SpecialId);
  603. }
  604. HRESULT
  605. CAggregateeDispMgr::InitializeDispMgr(
  606. DWORD dwExtensionID
  607. )
  608. {
  609. if (dwExtensionID > 255) {
  610. return(E_FAIL);
  611. }
  612. _dwExtensionID = dwExtensionID;
  613. return(S_OK);
  614. }