Leaked source code of windows server 2003
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.

551 lines
14 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. router.cpp
  5. Abstract:
  6. This module contains the implementation for the Server
  7. Extension Object Router class.
  8. Author:
  9. Don Dumitru (dondu@microsoft.com)
  10. Revision History:
  11. dondu 03/04/97 created
  12. --*/
  13. // router.cpp : Implementation of CSEORouter
  14. #include "stdafx.h"
  15. #define SEODLLDEF // identifiers get exported through the .DEF file
  16. #include "seodefs.h"
  17. #include "fhash.h"
  18. #include "router.h"
  19. #define LOCK_TIMEOUT INFINITE
  20. static DWORD HashGuidToDword(const GUID& guid) {
  21. DWORD dwRes = 0;
  22. DWORD *pdwTmp = (DWORD *) &guid;
  23. DWORD dwRemain = sizeof(guid);
  24. while (dwRemain > sizeof(*pdwTmp)) {
  25. dwRes += *pdwTmp;
  26. *pdwTmp++;
  27. dwRemain -= sizeof(*pdwTmp);
  28. }
  29. return (dwRes);
  30. }
  31. static HRESULT VariantQI(VARIANT *pvar, REFIID iid, IUnknown **ppunkResult) {
  32. HRESULT hrRes;
  33. if (!pvar || !ppunkResult) {
  34. return (E_POINTER);
  35. }
  36. hrRes = VariantChangeType(pvar,pvar,0,VT_UNKNOWN);
  37. if (!SUCCEEDED(hrRes)) {
  38. VariantClear(pvar);
  39. return (hrRes);
  40. }
  41. hrRes = pvar->punkVal->QueryInterface(iid,(void **) ppunkResult);
  42. VariantClear(pvar);
  43. return (hrRes);
  44. }
  45. static HRESULT GetNextSubDict(ISEODictionary *pdictBase, IEnumVARIANT *pevEnum, VARIANT *pvarName, ISEODictionary **ppdictSub) {
  46. HRESULT hrRes;
  47. VARIANT varSub;
  48. if (!pdictBase || !pevEnum || !pvarName || !ppdictSub) {
  49. return (E_POINTER);
  50. }
  51. VariantInit(pvarName);
  52. *ppdictSub = NULL;
  53. hrRes = pevEnum->Next(1,pvarName,NULL);
  54. if (!SUCCEEDED(hrRes)) {
  55. return (hrRes);
  56. }
  57. if (hrRes == S_FALSE) {
  58. return (SEO_E_NOTPRESENT);
  59. }
  60. VariantInit(&varSub);
  61. hrRes = pdictBase->get_Item(pvarName,&varSub);
  62. if (!SUCCEEDED(hrRes) || (varSub.vt == VT_EMPTY)) {
  63. VariantClear(pvarName);
  64. return (hrRes);
  65. }
  66. hrRes = VariantQI(&varSub,IID_ISEODictionary,(IUnknown **) ppdictSub);
  67. VariantClear(&varSub);
  68. if (!SUCCEEDED(hrRes)) {
  69. VariantClear(pvarName);
  70. }
  71. return (hrRes);
  72. }
  73. /////////////////////////////////////////////////////////////////////////////
  74. // CBP
  75. class CBP {
  76. public:
  77. CBP();
  78. CBP(CBP& bpFrom);
  79. ~CBP();
  80. const CBP& operator =(const CBP& cbpFrom);
  81. CLSID& GetKey();
  82. int MatchKey(CLSID& clsid);
  83. HRESULT Init(REFCLSID clsidBP, ISEODictionary *pdictIn);
  84. CLSID m_clsidBP;
  85. CLSID m_clsidDispatcher;
  86. CComPtr<ISEODictionary> m_pdictBP;
  87. CComPtr<IUnknown> m_punkDispatcher;
  88. };
  89. inline const CBP& CBP::operator =(const CBP& cbpFrom) {
  90. m_clsidBP = cbpFrom.m_clsidBP;
  91. m_clsidDispatcher = cbpFrom.m_clsidDispatcher;
  92. m_pdictBP = cbpFrom.m_pdictBP;
  93. m_punkDispatcher = cbpFrom.m_punkDispatcher;
  94. return (*this);
  95. }
  96. /////////////////////////////////////////////////////////////////////////////
  97. // CSEORouterInternal
  98. class ATL_NO_VTABLE CSEORouterInternal :
  99. public CComObjectRootEx<CComMultiThreadModelNoCS>,
  100. // public CComCoClass<CSEORouter, &CLSID_CSEORouter>,
  101. public ISEORouter
  102. {
  103. public:
  104. HRESULT FinalConstruct();
  105. void FinalRelease();
  106. DECLARE_PROTECT_FINAL_CONSTRUCT();
  107. DECLARE_AGGREGATABLE(CSEORouterInternal);
  108. // DECLARE_REGISTRY_RESOURCEID_EX(IDR_StdAfx,
  109. // L"SEORouter Class",
  110. // L"SEO.SEORouter.1",
  111. // L"SEO.SEORouter");
  112. DECLARE_GET_CONTROLLING_UNKNOWN();
  113. BEGIN_COM_MAP(CSEORouterInternal)
  114. COM_INTERFACE_ENTRY(ISEORouter)
  115. COM_INTERFACE_ENTRY_AGGREGATE(IID_IEventLock, m_pUnkLock.p)
  116. COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_pUnkMarshaler.p)
  117. END_COM_MAP()
  118. // ISEORouter
  119. public:
  120. HRESULT STDMETHODCALLTYPE get_Database(ISEODictionary **ppdictResult);
  121. HRESULT STDMETHODCALLTYPE put_Database(ISEODictionary *pdictDatabase);
  122. HRESULT STDMETHODCALLTYPE get_Server(ISEODictionary **ppdictResult);
  123. HRESULT STDMETHODCALLTYPE put_Server(ISEODictionary *pdictServer);
  124. HRESULT STDMETHODCALLTYPE get_Applications(ISEODictionary **ppdictResult);
  125. HRESULT STDMETHODCALLTYPE GetDispatcher(REFIID iidEvent, REFIID iidDesired, IUnknown **ppUnkResult);
  126. HRESULT STDMETHODCALLTYPE GetDispatcherByCLSID(REFCLSID clsidDispatcher, REFIID iidEvent, REFIID iidDesired, IUnknown **ppUnkResult);
  127. private:
  128. typedef TFHash<CBP,CLSID> CBPHash;
  129. CBPHash m_hashBP;
  130. CComPtr<ISEODictionary> m_pdictDatabase;
  131. CComPtr<ISEODictionary> m_pdictServer;
  132. CComPtr<ISEODictionary> m_pdictApplications;
  133. CComPtr<IUnknown> m_pUnkLock;
  134. CComPtr<IUnknown> m_pUnkMarshaler;
  135. IEventLock *m_pLock;
  136. };
  137. CBP::CBP() {
  138. m_clsidBP = GUID_NULL;
  139. m_clsidDispatcher = GUID_NULL;
  140. }
  141. CBP::CBP(CBP& cbpFrom) {
  142. m_clsidBP = cbpFrom.m_clsidBP;
  143. m_clsidDispatcher = cbpFrom.m_clsidDispatcher;
  144. m_pdictBP = cbpFrom.m_pdictBP;
  145. m_punkDispatcher = cbpFrom.m_punkDispatcher;
  146. }
  147. CBP::~CBP() {
  148. m_clsidBP = GUID_NULL;
  149. m_clsidDispatcher = GUID_NULL;
  150. m_pdictBP.Release();
  151. m_punkDispatcher.Release();
  152. }
  153. CLSID& CBP::GetKey() {
  154. return (m_clsidBP);
  155. }
  156. int CBP::MatchKey(CLSID& clsid) {
  157. return (memcmp(&m_clsidBP,&clsid,sizeof(clsid))==0);
  158. }
  159. HRESULT CBP::Init(REFCLSID clsidBP, ISEODictionary *pdictIn) {
  160. HRESULT hrRes;
  161. VARIANT varTmp;
  162. CComPtr<ISEODictionary> pdictTmp;
  163. if (!pdictIn) {
  164. return (E_POINTER);
  165. }
  166. m_clsidBP = clsidBP;
  167. VariantInit(&varTmp);
  168. hrRes = pdictIn->GetVariantA(BD_DISPATCHER,&varTmp);
  169. if (SUCCEEDED(hrRes)) {
  170. hrRes = VariantChangeType(&varTmp,&varTmp,0,VT_BSTR);
  171. }
  172. if (SUCCEEDED(hrRes)) {
  173. hrRes = CLSIDFromString(varTmp.bstrVal,&m_clsidDispatcher);
  174. }
  175. if (!SUCCEEDED(hrRes)) {
  176. m_clsidDispatcher = GUID_NULL;
  177. }
  178. VariantClear(&varTmp);
  179. hrRes = SEOCopyDictionary(pdictIn,&m_pdictBP);
  180. if (!SUCCEEDED(hrRes)) {
  181. return (hrRes);
  182. }
  183. return (S_OK);
  184. }
  185. HRESULT CSEORouterInternal::FinalConstruct() {
  186. TraceFunctEnter("CSEORouterInternal::FinalConstruct");
  187. HRESULT hrRes;
  188. if (!m_hashBP.Init(4,4,HashGuidToDword)) {
  189. return (E_OUTOFMEMORY);
  190. }
  191. hrRes = CoCreateInstance(CLSID_CSEOMemDictionary,
  192. NULL,
  193. CLSCTX_ALL,
  194. IID_ISEODictionary,
  195. (LPVOID *) &m_pdictApplications);
  196. if (!SUCCEEDED(hrRes)) {
  197. TraceFunctLeave();
  198. return (hrRes);
  199. }
  200. hrRes = CoCreateInstance(CLSID_CEventLock,
  201. GetControllingUnknown(),
  202. CLSCTX_ALL,
  203. IID_IUnknown,
  204. (LPVOID *) &m_pUnkLock);
  205. if (!SUCCEEDED(hrRes)) {
  206. TraceFunctLeave();
  207. return (hrRes);
  208. }
  209. hrRes = m_pUnkLock->QueryInterface(IID_IEventLock,(LPVOID *) &m_pLock);
  210. if (!SUCCEEDED(hrRes)) {
  211. TraceFunctLeave();
  212. return (hrRes);
  213. }
  214. GetControllingUnknown()->Release(); // decrement reference count to prevent circular reference
  215. hrRes = CoCreateFreeThreadedMarshaler(GetControllingUnknown(),&m_pUnkMarshaler.p);
  216. _ASSERTE(!SUCCEEDED(hrRes)||m_pUnkMarshaler);
  217. return (SUCCEEDED(hrRes)?S_OK:hrRes);
  218. }
  219. void CSEORouterInternal::FinalRelease() {
  220. TraceFunctEnter("CSEORouterInternal::FinalRelease");
  221. GetControllingUnknown()->AddRef();
  222. m_pdictDatabase.Release();
  223. m_pdictServer.Release();
  224. m_pdictApplications.Release();
  225. m_pLock->Release();
  226. m_pUnkLock.Release();
  227. m_pUnkMarshaler.Release();
  228. TraceFunctLeave();
  229. }
  230. HRESULT CSEORouterInternal::get_Database(ISEODictionary **ppdictResult) {
  231. HRESULT hrRes;
  232. if (!ppdictResult) {
  233. return (E_POINTER);
  234. }
  235. *ppdictResult = NULL;
  236. hrRes = m_pLock->LockRead(LOCK_TIMEOUT);
  237. if (!SUCCEEDED(hrRes)) {
  238. return (hrRes);
  239. }
  240. *ppdictResult = m_pdictDatabase;
  241. if (*ppdictResult) {
  242. (*ppdictResult)->AddRef();
  243. }
  244. m_pLock->UnlockRead();
  245. return (S_OK);
  246. }
  247. HRESULT CSEORouterInternal::put_Database(ISEODictionary *pdictDatabase) {
  248. HRESULT hrRes;
  249. hrRes = m_pLock->LockWrite(LOCK_TIMEOUT);
  250. if (!SUCCEEDED(hrRes)) {
  251. return (hrRes);
  252. }
  253. m_pdictDatabase = pdictDatabase;
  254. m_hashBP.Clear();
  255. if (!m_hashBP.Init(4,4,HashGuidToDword)) {
  256. return (E_OUTOFMEMORY);
  257. }
  258. if (m_pdictDatabase) {
  259. CComPtr<ISEODictionary> pdictBindingPoints;
  260. hrRes = m_pdictDatabase->GetInterfaceA(BD_BINDINGPOINTS,
  261. IID_ISEODictionary,
  262. (IUnknown **) &pdictBindingPoints);
  263. if (SUCCEEDED(hrRes)) {
  264. CComPtr<IUnknown> pUnkEnum;
  265. hrRes = pdictBindingPoints->get__NewEnum(&pUnkEnum);
  266. if (SUCCEEDED(hrRes)) {
  267. CComQIPtr<IEnumVARIANT,&IID_IEnumVARIANT> pevEnum(pUnkEnum);
  268. if (pevEnum) {
  269. while (1) {
  270. VARIANT varBP;
  271. CComPtr<ISEODictionary> pdictBP;
  272. CLSID clsidBP;
  273. CBP cbpBP;
  274. VariantInit(&varBP);
  275. pdictBP = NULL;
  276. hrRes = GetNextSubDict(pdictBindingPoints,pevEnum,&varBP,&pdictBP);
  277. if (!SUCCEEDED(hrRes)) {
  278. break;
  279. }
  280. if (hrRes == S_FALSE) {
  281. continue;
  282. }
  283. hrRes = CLSIDFromString(varBP.bstrVal,&clsidBP);
  284. VariantClear(&varBP);
  285. if (!SUCCEEDED(hrRes)) {
  286. continue;
  287. }
  288. hrRes = cbpBP.Init(clsidBP,pdictBP);
  289. if (!SUCCEEDED(hrRes)) {
  290. continue;
  291. }
  292. m_hashBP.Insert(cbpBP);
  293. }
  294. }
  295. }
  296. }
  297. }
  298. m_pLock->UnlockWrite();
  299. return (S_OK);
  300. }
  301. HRESULT CSEORouterInternal::get_Server(ISEODictionary **ppdictResult) {
  302. HRESULT hrRes;
  303. if (!ppdictResult) {
  304. return (E_POINTER);
  305. }
  306. *ppdictResult = NULL;
  307. hrRes = m_pLock->LockRead(LOCK_TIMEOUT);
  308. if (!SUCCEEDED(hrRes)) {
  309. return (hrRes);
  310. }
  311. *ppdictResult = m_pdictServer;
  312. if (*ppdictResult) {
  313. (*ppdictResult)->AddRef();
  314. }
  315. m_pLock->UnlockRead();
  316. return (S_OK);
  317. }
  318. HRESULT CSEORouterInternal::put_Server(ISEODictionary *pdictServer) {
  319. HRESULT hrRes;
  320. hrRes = m_pLock->LockWrite(LOCK_TIMEOUT);
  321. if (!SUCCEEDED(hrRes)) {
  322. return (hrRes);
  323. }
  324. m_pdictServer = pdictServer;
  325. m_pLock->UnlockWrite();
  326. return (S_OK);
  327. }
  328. HRESULT CSEORouterInternal::get_Applications(ISEODictionary **ppdictResult) {
  329. HRESULT hrRes;
  330. if (!ppdictResult) {
  331. return (E_POINTER);
  332. }
  333. *ppdictResult = NULL;
  334. hrRes = m_pLock->LockRead(LOCK_TIMEOUT);
  335. if (!SUCCEEDED(hrRes)) {
  336. return (hrRes);
  337. }
  338. *ppdictResult = m_pdictApplications;
  339. if (*ppdictResult) {
  340. (*ppdictResult)->AddRef();
  341. }
  342. m_pLock->UnlockRead();
  343. return (S_OK);
  344. }
  345. HRESULT STDMETHODCALLTYPE CSEORouterInternal::GetDispatcher(REFIID iidEvent, REFIID iidDesired, IUnknown **ppUnkResult) {
  346. return (GetDispatcherByCLSID(iidEvent,iidEvent,iidDesired,ppUnkResult));
  347. }
  348. HRESULT STDMETHODCALLTYPE CSEORouterInternal::GetDispatcherByCLSID(REFCLSID clsidDispatcher, REFIID iidEvent, REFIID iidDesired, IUnknown **ppUnkResult) {
  349. HRESULT hrRes;
  350. CBP *pcbpBP;
  351. CComPtr<IUnknown> punkDispatcher;
  352. if (!ppUnkResult) {
  353. return (E_POINTER);
  354. }
  355. *ppUnkResult = NULL;
  356. // First, get a read-lock across the entire set of binding points.
  357. hrRes = m_pLock->LockRead(LOCK_TIMEOUT);
  358. if (!SUCCEEDED(hrRes)) {
  359. return (hrRes);
  360. }
  361. // Next, look for this particular binding point in the hash table.
  362. if (!(pcbpBP=m_hashBP.SearchKey((GUID&) iidEvent))) {
  363. // If it's not there - that's fine. It means we don't have to dispatch to anyone.
  364. m_pLock->UnlockRead();
  365. return (S_FALSE);
  366. }
  367. // Next, look to see if we have already loaded the dispatcher for this binding point.
  368. if (!pcbpBP->m_punkDispatcher) {
  369. // Make copies of the data we'll need from the hash table entry.
  370. CLSID clsidTmpDispatcher = pcbpBP->m_clsidDispatcher;
  371. CComQIPtr<ISEODispatcher,&IID_ISEODispatcher> pdispDispatcher;
  372. CComQIPtr<ISEORouter,&IID_ISEORouter> prouterThis(GetControllingUnknown());
  373. CComPtr<ISEODictionary> pdictBP = pcbpBP->m_pdictBP;
  374. // If the CLSID for the dispatcher specified in the binding point is GUID_NULL, then use the
  375. // CLSID from the clsidDispatcher parameter.
  376. if (clsidTmpDispatcher == GUID_NULL) {
  377. clsidTmpDispatcher = clsidDispatcher;
  378. }
  379. // If we haven't already loaded the dispatcher, we need to release the read-lock, and create
  380. // the dispatcher object.
  381. m_pLock->UnlockRead();
  382. hrRes = CoCreateInstance(clsidTmpDispatcher,
  383. NULL,
  384. CLSCTX_ALL,
  385. IID_IUnknown,
  386. (LPVOID *) &punkDispatcher);
  387. if (!SUCCEEDED(hrRes)) {
  388. return (hrRes);
  389. }
  390. // If the dispatcher supports ISEODispatcher, we want to initialize it through that interface.
  391. pdispDispatcher = punkDispatcher;
  392. if (pdispDispatcher) {
  393. hrRes = pdispDispatcher->SetContext(prouterThis,pdictBP);
  394. if (!SUCCEEDED(hrRes)) {
  395. return (hrRes);
  396. }
  397. }
  398. // Now get a write-lock across the entire set of binding points.
  399. hrRes = m_pLock->LockWrite(LOCK_TIMEOUT);
  400. if (!SUCCEEDED(hrRes)) {
  401. return (hrRes);
  402. }
  403. // While we were creating the dispatcher, someone else may have updated the binding database
  404. // and removed this binding point entirely - so search for it again.
  405. if (!(pcbpBP=m_hashBP.SearchKey((GUID&) iidEvent))) {
  406. // The binding point went away while we were unlocked - which is not a problem, since it
  407. // means that someone changed the binding database during that window. So just assume
  408. // everything is cool.
  409. m_pLock->UnlockWrite();
  410. return (S_FALSE);
  411. }
  412. // Also while we were creating the dispatcher, someone else may have been doing the exact same
  413. // thing - so check to make sure that there still isn't a dispatcher in the hash table.
  414. if (!pcbpBP->m_punkDispatcher) {
  415. // There isn't, so store the one we created there.
  416. pcbpBP->m_punkDispatcher = punkDispatcher;
  417. } else {
  418. // Make copy of the interface we need from the hash table entry.
  419. punkDispatcher = pcbpBP->m_punkDispatcher;
  420. }
  421. m_pLock->UnlockWrite();
  422. } else {
  423. // Make copies of the interface we need from the hash table entry.
  424. punkDispatcher = pcbpBP->m_punkDispatcher;
  425. m_pLock->UnlockRead();
  426. }
  427. // Get the interface which the client actually wants.
  428. hrRes = punkDispatcher->QueryInterface(iidDesired,(LPVOID *) ppUnkResult);
  429. return (hrRes);
  430. }
  431. /////////////////////////////////////////////////////////////////////////////
  432. // CSEORouter
  433. HRESULT CSEORouter::FinalConstruct() {
  434. HRESULT hrRes;
  435. hrRes = CComObject<CSEORouterInternal>::_CreatorClass::CreateInstance(NULL,
  436. IID_ISEORouter,
  437. (LPVOID *) &m_pRouter);
  438. if (!SUCCEEDED(hrRes)) {
  439. return (hrRes);
  440. }
  441. m_pLock = m_pRouter;
  442. m_pMarshal = m_pRouter;
  443. if (!m_pLock || !m_pMarshal) {
  444. return (E_NOINTERFACE);
  445. }
  446. return (S_OK);
  447. }
  448. void CSEORouter::FinalRelease() {
  449. if (m_pRouter) {
  450. m_pRouter->put_Database(NULL);
  451. }
  452. m_pRouter.Release();
  453. m_pLock.Release();
  454. m_pMarshal.Release();
  455. }