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.

480 lines
11 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. // CCOMBaseFactory
  3. // Base class for reusing a single class factory for all components in a DLL
  4. #include "fact.h"
  5. #include "unk.h"
  6. #include "regsvr.h"
  7. #include "dbg.h"
  8. struct OUTPROCINFO
  9. {
  10. // Reserved (used only for COM Exe server)
  11. IClassFactory* _pfact;
  12. DWORD _dwRegister;
  13. };
  14. LONG CCOMBaseFactory::_cServerLocks = 0;
  15. LONG CCOMBaseFactory::_cComponents = 0;
  16. HMODULE CCOMBaseFactory::_hModule = NULL;
  17. CRITICAL_SECTION CCOMBaseFactory::_cs = {0};
  18. OUTPROCINFO* CCOMBaseFactory::_popinfo = NULL;
  19. DWORD CCOMBaseFactory::_dwThreadID = 0;
  20. BOOL CCOMBaseFactory::_fCritSectInit = FALSE;
  21. ///////////////////////////////////////////////////////////////////////////////
  22. // IUnknown implementation
  23. STDMETHODIMP CCOMBaseFactory::QueryInterface(REFIID iid, void** ppv)
  24. {
  25. IUnknown* punk = NULL;
  26. HRESULT hres = S_OK;
  27. if ((iid == IID_IUnknown) || (iid == IID_IClassFactory))
  28. {
  29. punk = this;
  30. punk->AddRef();
  31. }
  32. else
  33. {
  34. hres = E_NOINTERFACE;
  35. }
  36. *ppv = punk;
  37. return hres;
  38. }
  39. STDMETHODIMP_(ULONG) CCOMBaseFactory::AddRef()
  40. {
  41. return ::InterlockedIncrement(&_cRef);
  42. }
  43. STDMETHODIMP_(ULONG) CCOMBaseFactory::Release()
  44. {
  45. ASSERT( 0 != _cRef );
  46. ULONG cRef = ::InterlockedDecrement(&_cRef);
  47. if (!cRef)
  48. {
  49. delete this;
  50. }
  51. return cRef;
  52. }
  53. ///////////////////////////////////////////////////////////////////////////////
  54. // IFactory implementation
  55. STDMETHODIMP CCOMBaseFactory::CreateInstance(IUnknown* pUnknownOuter,
  56. REFIID riid, void** ppv)
  57. {
  58. HRESULT hres = CLASS_E_NOAGGREGATION;
  59. // We don't support aggregation at all for now
  60. if (!pUnknownOuter)
  61. {
  62. // Aggregate only if the requested IID is IID_IUnknown.
  63. if ((pUnknownOuter != NULL) && (riid != IID_IUnknown))
  64. {
  65. hres = CLASS_E_NOAGGREGATION;
  66. }
  67. else
  68. {
  69. // Create the component.
  70. IUnknown* punkNew;
  71. hres = _pFactoryData->CreateInstance(
  72. CCOMBaseFactory::_COMFactoryCB, pUnknownOuter, &punkNew);
  73. if (SUCCEEDED(hres))
  74. {
  75. _COMFactoryCB(TRUE);
  76. // Get the requested interface.
  77. // hres = pNewComponent->NondelegatingQueryInterface(iid, ppv);
  78. hres = punkNew->QueryInterface(riid, ppv);
  79. // Release the reference held by the class factory.
  80. // pNewComponent->NondelegatingRelease();
  81. punkNew->Release();
  82. }
  83. }
  84. }
  85. return hres;
  86. }
  87. STDMETHODIMP CCOMBaseFactory::LockServer(BOOL fLock)
  88. {
  89. return _LockServer(fLock);
  90. }
  91. //static
  92. HRESULT CCOMBaseFactory::DllAttach(HINSTANCE hinst)
  93. {
  94. HRESULT hr;
  95. _hModule = (HMODULE)hinst;
  96. if (InitializeCriticalSectionAndSpinCount(&_cs, 0))
  97. {
  98. _fCritSectInit = TRUE;
  99. hr = S_OK;
  100. }
  101. else
  102. {
  103. hr = E_OUTOFMEMORY;
  104. }
  105. return hr;
  106. }
  107. //static
  108. HRESULT CCOMBaseFactory::DllDetach()
  109. {
  110. if (_fCritSectInit)
  111. {
  112. DeleteCriticalSection(&_cs);
  113. _fCritSectInit = FALSE;
  114. }
  115. return S_OK;
  116. }
  117. ///////////////////////////////////////////////////////////////////////////////
  118. // Install/Unintall
  119. //static
  120. HRESULT CCOMBaseFactory::_RegisterAll()
  121. {
  122. for (DWORD dw = 0; dw < _cDLLFactoryData; ++dw)
  123. {
  124. RegisterServer(_hModule,
  125. *(_pDLLFactoryData[dw]._pCLSID),
  126. _pDLLFactoryData[dw]._pszRegistryName,
  127. _pDLLFactoryData[dw]._pszVerIndProgID,
  128. _pDLLFactoryData[dw]._pszProgID,
  129. _pDLLFactoryData[dw]._dwThreadingModel,
  130. _pDLLFactoryData[dw].IsInprocServer(),
  131. _pDLLFactoryData[dw].IsLocalServer(),
  132. _pDLLFactoryData[dw].IsLocalService(),
  133. _pDLLFactoryData[dw]._pszLocalService,
  134. _pDLLFactoryData[dw]._pAppID);
  135. }
  136. return S_OK;
  137. }
  138. //static
  139. HRESULT CCOMBaseFactory::_UnregisterAll()
  140. {
  141. for (DWORD dw = 0; dw < _cDLLFactoryData; ++dw)
  142. {
  143. UnregisterServer(*(_pDLLFactoryData[dw]._pCLSID),
  144. _pDLLFactoryData[dw]._pszVerIndProgID,
  145. _pDLLFactoryData[dw]._pszProgID);
  146. }
  147. return S_OK;
  148. }
  149. ///////////////////////////////////////////////////////////////////////////////
  150. // CCOMBaseFactory implementation
  151. CCOMBaseFactory::CCOMBaseFactory(const CFactoryData* pFactoryData) : _cRef(1),
  152. _pFactoryData(pFactoryData)
  153. {}
  154. //static
  155. BOOL CCOMBaseFactory::_IsLocked()
  156. {
  157. // Always need to be called from within Critical Section
  158. return (_cServerLocks > 0);
  159. }
  160. //static
  161. HRESULT CCOMBaseFactory::_CanUnloadNow()
  162. {
  163. HRESULT hres = S_OK;
  164. // Always need to be called from within Critical Section
  165. if (_IsLocked())
  166. {
  167. hres = S_FALSE;
  168. }
  169. else
  170. {
  171. if (_cComponents)
  172. {
  173. hres = S_FALSE;
  174. }
  175. }
  176. return hres;
  177. }
  178. //static
  179. HRESULT CCOMBaseFactory::_CheckForUnload()
  180. {
  181. // Always need to be called from within Critical Section
  182. if (S_OK == _CanUnloadNow())
  183. {
  184. ::PostThreadMessage(_dwThreadID, WM_QUIT, 0, 0);
  185. }
  186. return S_OK;
  187. }
  188. //static
  189. HRESULT CCOMBaseFactory::_LockServer(BOOL fLock)
  190. {
  191. HRESULT hres = S_OK;
  192. EnterCriticalSection(&_cs);
  193. if (fLock)
  194. {
  195. ++_cServerLocks;
  196. }
  197. else
  198. {
  199. --_cServerLocks;
  200. hres = _CheckForUnload();
  201. }
  202. LeaveCriticalSection(&_cs);
  203. return hres;
  204. }
  205. //static
  206. void CCOMBaseFactory::_COMFactoryCB(BOOL fIncrement)
  207. {
  208. EnterCriticalSection(&_cs);
  209. if (fIncrement)
  210. {
  211. ++_cComponents;
  212. }
  213. else
  214. {
  215. --_cComponents;
  216. _CheckForUnload();
  217. }
  218. LeaveCriticalSection(&_cs);
  219. }
  220. ///////////////////////////////////////////////////////////////////////////////
  221. //
  222. // static
  223. HRESULT CCOMBaseFactory::_GetClassObject(REFCLSID rclsid, REFIID riid,
  224. void** ppv)
  225. {
  226. HRESULT hres = S_OK;
  227. ASSERT(_fCritSectInit);
  228. if ((riid != IID_IUnknown) && (riid != IID_IClassFactory))
  229. {
  230. hres = E_NOINTERFACE;
  231. }
  232. else
  233. {
  234. hres = CLASS_E_CLASSNOTAVAILABLE;
  235. // Traverse the array of data looking for this class ID.
  236. for (DWORD dw = 0; dw < _cDLLFactoryData; ++dw)
  237. {
  238. const CFactoryData* pData = &_pDLLFactoryData[dw];
  239. if (pData->IsClassID(rclsid) && pData->IsInprocServer())
  240. {
  241. // Found the ClassID in the array of components we can
  242. // create. So create a class factory for this component.
  243. // Pass the CDLLFactoryData structure to the class factory
  244. // so that it knows what kind of components to create.
  245. *ppv = (IUnknown*) new CCOMBaseFactory(pData);
  246. if (*ppv == NULL)
  247. {
  248. hres = E_OUTOFMEMORY;
  249. }
  250. else
  251. {
  252. hres = S_OK;
  253. }
  254. break;
  255. }
  256. }
  257. }
  258. return hres;
  259. }
  260. //static
  261. BOOL CCOMBaseFactory::_ProcessConsoleCmdLineParams(int argc, wchar_t* argv[],
  262. BOOL* pfRun, BOOL* pfEmbedded)
  263. {
  264. _dwThreadID = GetCurrentThreadId();
  265. if (argc > 1)
  266. {
  267. if (!lstrcmpi(argv[1], TEXT("-i")) ||
  268. !lstrcmpi(argv[1], TEXT("/i")))
  269. {
  270. CCOMBaseFactory::_RegisterAll();
  271. *pfRun = FALSE;
  272. }
  273. else
  274. {
  275. if (!lstrcmpi(argv[1], TEXT("-u")) ||
  276. !lstrcmpi(argv[1], TEXT("/u")))
  277. {
  278. CCOMBaseFactory::_UnregisterAll();
  279. *pfRun = FALSE;
  280. }
  281. else
  282. {
  283. if (!lstrcmpi(argv[1], TEXT("-Embedding")) ||
  284. !lstrcmpi(argv[1], TEXT("/Embedding")))
  285. {
  286. *pfRun = TRUE;
  287. *pfEmbedded = TRUE;
  288. }
  289. }
  290. }
  291. }
  292. else
  293. {
  294. *pfEmbedded = FALSE;
  295. *pfRun = TRUE;
  296. }
  297. return TRUE;
  298. }
  299. //static
  300. BOOL CCOMBaseFactory::_RegisterFactories(BOOL fEmbedded)
  301. {
  302. HRESULT hres = S_OK;
  303. if (!fEmbedded)
  304. {
  305. hres = _LockServer(TRUE);
  306. }
  307. _popinfo = (OUTPROCINFO*)LocalAlloc(LPTR, sizeof(OUTPROCINFO) * _cDLLFactoryData);
  308. if (_popinfo)
  309. {
  310. for (DWORD dw = 0; SUCCEEDED(hres) && (dw < _cDLLFactoryData); ++dw)
  311. {
  312. const CFactoryData* pData = &_pDLLFactoryData[dw];
  313. if (pData->IsLocalServer() || pData->IsLocalService())
  314. {
  315. _popinfo[dw]._pfact = NULL;
  316. _popinfo[dw]._dwRegister = NULL;
  317. IClassFactory* pfact = new CCOMBaseFactory(pData);
  318. if (pfact)
  319. {
  320. DWORD dwRegister;
  321. hres = ::CoRegisterClassObject(*pData->_pCLSID,
  322. static_cast<IUnknown*>(pfact), pData->_dwClsContext,
  323. pData->_dwFlags, &dwRegister);
  324. if (SUCCEEDED(hres))
  325. {
  326. _popinfo[dw]._pfact = pfact;
  327. _popinfo[dw]._dwRegister = dwRegister;
  328. }
  329. else
  330. {
  331. pfact->Release();
  332. }
  333. }
  334. else
  335. {
  336. hres = E_OUTOFMEMORY;
  337. }
  338. }
  339. }
  340. }
  341. else
  342. {
  343. hres = E_OUTOFMEMORY;
  344. }
  345. return SUCCEEDED(hres);
  346. }
  347. //static
  348. BOOL CCOMBaseFactory::_SuspendFactories()
  349. {
  350. return SUCCEEDED(::CoSuspendClassObjects());
  351. }
  352. //static
  353. BOOL CCOMBaseFactory::_ResumeFactories()
  354. {
  355. return SUCCEEDED(::CoResumeClassObjects());
  356. }
  357. //static
  358. BOOL CCOMBaseFactory::_UnregisterFactories(BOOL fEmbedded)
  359. {
  360. HRESULT hres = S_OK;
  361. ASSERT(_popinfo);
  362. for (DWORD dw = 0; dw < _cDLLFactoryData; ++dw)
  363. {
  364. if (_popinfo[dw]._pfact)
  365. {
  366. _popinfo[dw]._pfact->Release();
  367. HRESULT hresTmp = ::CoRevokeClassObject(_popinfo[dw]._dwRegister);
  368. if (FAILED(hresTmp) && (S_OK == hres))
  369. {
  370. hres = hresTmp;
  371. }
  372. }
  373. }
  374. LocalFree(_popinfo);
  375. _popinfo = NULL;
  376. if (!fEmbedded)
  377. {
  378. HRESULT hresTmp = _LockServer(FALSE);
  379. if (FAILED(hresTmp) && (S_OK == hres))
  380. {
  381. hres = hresTmp;
  382. }
  383. }
  384. return SUCCEEDED(hres);
  385. }
  386. //static
  387. void CCOMBaseFactory::_WaitForAllClientsToGo()
  388. {
  389. MSG msg;
  390. while (::GetMessage(&msg, 0, 0, 0))
  391. {
  392. ::DispatchMessage(&msg);
  393. }
  394. }