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.

456 lines
12 KiB

  1. /****************************************************************************
  2. * $Header: J:\rtp\src\ppm\fact.cpv 1.3 20 Mar 1997 18:32:04 lscline $
  3. *
  4. * INTEL Corporation Proprietary Information
  5. *
  6. * This listing is supplied under the terms of a license agreement
  7. * with INTEL Corporation and may not be copied nor disclosed except
  8. * in accordance with the terms of that agreement.
  9. *
  10. * Copyright (c) 1995, 1996 Intel Corporation. All rights reserved.
  11. *
  12. * $Revision: 1.3 $
  13. * $Date: 20 Mar 1997 18:32:04 $
  14. * $Author: lscline $
  15. *
  16. * Log at end of file.
  17. *
  18. * Module Name: psfact.cpp
  19. * Abstract: common OLE 2 class factory
  20. * Environment: MSVC 4.0, OLE 2
  21. * Notes:
  22. *
  23. ***************************************************************************/
  24. //#include "_stable.h" // standard precompiled headers
  25. #include "core.h"
  26. #include <assert.h>
  27. //***************************************************************************
  28. // CClassFactory
  29. //
  30. /////////////////////////////////////////////////////////////////////////////
  31. // static data members
  32. ULONG NEAR CClassFactory::s_cLockServer = 0;
  33. ULONG NEAR CClassFactory::s_cObjects = 0;
  34. UNLOADSERVERPROC NEAR CClassFactory::s_pfnUnloadServer = NULL;
  35. UINT NEAR CClassFactory::s_nRegistry = 0;
  36. // registry defined by REGISTER_CLASS macros
  37. /////////////////////////////////////////////////////////////////////////////
  38. // ctor, dtor
  39. CClassFactory::CClassFactory( Registry* pReg )
  40. {
  41. m_cRef = 0;
  42. ++s_cObjects;
  43. assert( pReg );
  44. assert( ! pReg->pFactory );
  45. m_pReg = pReg;
  46. m_pReg->pFactory = this;
  47. }
  48. CClassFactory::~CClassFactory()
  49. {
  50. assert( m_pReg );
  51. assert( m_pReg->pFactory == this );
  52. m_pReg->pFactory = NULL;
  53. --s_cObjects;
  54. }
  55. /////////////////////////////////////////////////////////////////////////////
  56. // IUnknown implementation
  57. //
  58. STDMETHODIMP
  59. CClassFactory::QueryInterface( REFIID riid, LPVOID FAR* ppvObj )
  60. {
  61. if( riid == IID_IClassFactory || riid == IID_IUnknown )
  62. {
  63. *ppvObj = this;
  64. }
  65. else
  66. return ResultFromScode( E_NOINTERFACE );
  67. LPUNKNOWN( *ppvObj )->AddRef();
  68. return NOERROR;
  69. }
  70. STDMETHODIMP_(ULONG)
  71. CClassFactory::AddRef( void )
  72. {
  73. return ++m_cRef;
  74. }
  75. STDMETHODIMP_(ULONG)
  76. CClassFactory::Release( void )
  77. {
  78. if( ! --m_cRef )
  79. {
  80. delete this;
  81. CanUnloadNow();
  82. return 0;
  83. }
  84. return m_cRef;
  85. }
  86. /////////////////////////////////////////////////////////////////////////////
  87. // IClassFactory implementation
  88. //
  89. STDMETHODIMP
  90. CClassFactory::CreateInstance( LPUNKNOWN pUnkOuter, REFIID riid, LPVOID FAR* ppvObj )
  91. {
  92. HRESULT hr;
  93. assert( ! IsBadWritePtr( ppvObj, sizeof( LPVOID FAR* ) ) );
  94. *ppvObj = NULL;
  95. // verify that IUnknown is requested when being aggregated
  96. if( pUnkOuter && riid != IID_IUnknown )
  97. return ResultFromScode( E_INVALIDARG );
  98. assert( m_pReg );
  99. // if it's a single instance class, return an existing instance if there is one
  100. if( m_pReg->regCls == REGCLS_SINGLEUSE )
  101. {
  102. if( m_pReg->pUnkSingle )
  103. {
  104. assert( 1 == m_pReg->cObjects );
  105. return m_pReg->pUnkSingle->QueryInterface( riid, ppvObj );
  106. }
  107. }
  108. // create the object
  109. LPUNKNOWN pUnkInner;
  110. hr = m_pReg->pfnCreate( pUnkOuter, ObjectDestroyed, &pUnkInner );
  111. if( FAILED( hr ) )
  112. return hr;
  113. if( ! pUnkInner )
  114. return ResultFromScode( E_UNEXPECTED );
  115. // ref count should now be 1, by our convention
  116. // If the riid is not implemented, the object will be destroyed, at which time
  117. // these variables will be decremented (see ObjectDestroyed). If
  118. // these aren't incremented here we get ASSERTs in ObjectDestroyed.
  119. // This happens more often now that PsCreateInstance is used to
  120. // create the Settings object as it passes in IPsObject which is
  121. // not implemented by Settings.
  122. m_pReg->cObjects++;
  123. s_cObjects++;
  124. hr = pUnkInner->QueryInterface( riid, ppvObj );
  125. if( FAILED( hr ) )
  126. { // delete object; ref count should be 1 here
  127. pUnkInner->Release();
  128. return hr;
  129. }
  130. // release object to account for extra reference on creation
  131. pUnkInner->Release();
  132. if( m_pReg->regCls == REGCLS_SINGLEUSE )
  133. {
  134. m_pReg->pUnkSingle = pUnkInner;
  135. }
  136. return NOERROR;
  137. }
  138. STDMETHODIMP
  139. CClassFactory::LockServer( BOOL fLock )
  140. {
  141. if( fLock )
  142. {
  143. ++s_cLockServer;
  144. // check for overflow
  145. if( ! s_cLockServer )
  146. return ResultFromScode( E_UNEXPECTED );
  147. }
  148. else
  149. {
  150. // check for lock
  151. if( ! s_cLockServer )
  152. return ResultFromScode( E_UNEXPECTED );
  153. --s_cLockServer;
  154. // might be time to unload
  155. CanUnloadNow();
  156. }
  157. return NOERROR;
  158. }
  159. /////////////////////////////////////////////////////////////////////////////
  160. // Check if server can be unloaded (no locks and no objects serviced).
  161. // Calls s_pfnUnloadServer proc if provided
  162. //
  163. STDMETHODIMP
  164. CClassFactory::CanUnloadNow( void )
  165. {
  166. if( ! s_cLockServer && ! s_cObjects )
  167. {
  168. if( s_pfnUnloadServer )
  169. s_pfnUnloadServer();
  170. return ResultFromScode( S_OK );
  171. }
  172. return ResultFromScode( S_FALSE );
  173. }
  174. /////////////////////////////////////////////////////////////////////////////
  175. // Callback from class when an object is destroyed. Allows server to be
  176. // unloaded when no objects are being serviced
  177. //
  178. STDMETHODIMP_( void )
  179. CClassFactory::ObjectDestroyed( REFCLSID rclsid )
  180. {
  181. Registry* pReg = FindClass( &rclsid );
  182. if( pReg )
  183. {
  184. assert( pReg->cObjects );
  185. pReg->cObjects--;
  186. if( pReg->regCls == REGCLS_SINGLEUSE )
  187. {
  188. assert( ! pReg->cObjects );
  189. assert( pReg->pUnkSingle );
  190. pReg->pUnkSingle = NULL;
  191. }
  192. }
  193. assert( s_cObjects );
  194. s_cObjects--;
  195. // might be time to unload
  196. CanUnloadNow();
  197. }
  198. /////////////////////////////////////////////////////////////////////////////
  199. // Find a class in the registry
  200. //
  201. CClassFactory::Registry*
  202. CClassFactory::FindClass( const CLSID* pClsid )
  203. {
  204. return (Registry*) bsearch( (const void*) &pClsid, (const void*) s_registry,
  205. s_nRegistry, sizeof( Registry ), CompareClsids );
  206. }
  207. /////////////////////////////////////////////////////////////////////////////
  208. // qsort/bsearch comparison function - compare class ids (or Registry entries)
  209. //
  210. #ifndef _DEBUG
  211. #pragma function( memcmp ) // specifies that memcmp will be normal
  212. #endif
  213. int __cdecl
  214. CClassFactory::CompareClsids( const void* pClsid1, const void* pClsid2 )
  215. {
  216. return memcmp( *(const CLSID**)pClsid1, *(const CLSID**)pClsid2, sizeof( CLSID ) );
  217. }
  218. #ifndef _DEBUG
  219. #pragma intrinsic( memcmp ) // specifies that memcmp will be intrinsic
  220. #endif
  221. /////////////////////////////////////////////////////////////////////////////
  222. // sort the registry by clsid
  223. //
  224. void
  225. CClassFactory::SortRegistry( void )
  226. {
  227. if( ! s_nRegistry )
  228. {
  229. // count the registry
  230. for( Registry* pReg = s_registry; pReg->pClsid != &CLSID_NULL; pReg++ )
  231. {
  232. s_nRegistry++;
  233. }
  234. // sort the registry
  235. qsort( (void*) s_registry, s_nRegistry, sizeof( Registry ), CompareClsids );
  236. }
  237. }
  238. /////////////////////////////////////////////////////////////////////////////
  239. // EXE server helper functions; set unload server callback proc,
  240. // CoRegister/CoRevoke all classes registered with the class factory
  241. //
  242. void
  243. CClassFactory::SetUnloadServerProc( UNLOADSERVERPROC pfnUnloadServer )
  244. {
  245. assert( ! IsBadCodePtr( (FARPROC) pfnUnloadServer ) );
  246. s_pfnUnloadServer = pfnUnloadServer;
  247. }
  248. STDMETHODIMP
  249. CClassFactory::RegisterAllClasses( DWORD dwClsContext )
  250. {
  251. SortRegistry();
  252. Registry* pReg = s_registry;
  253. Registry* pEnd = s_registry + s_nRegistry;
  254. for( ; pReg < pEnd; pReg++ )
  255. {
  256. LPCLASSFACTORY pFactory = pReg->pFactory ? pReg->pFactory : newCClassFactory( pReg );
  257. if( ! pFactory )
  258. return ResultFromScode( E_OUTOFMEMORY );
  259. pFactory->AddRef();
  260. HRESULT hr = CoRegisterClassObject( *pReg->pClsid, pFactory, dwClsContext, pReg->regCls, &pReg->dwRegister );
  261. if( FAILED( hr ) )
  262. {
  263. pFactory->Release();
  264. return hr;
  265. }
  266. }
  267. return NOERROR;
  268. }
  269. STDMETHODIMP
  270. CClassFactory::RevokeAllClasses( void )
  271. {
  272. Registry* pReg = s_registry;
  273. Registry* pEnd = s_registry + s_nRegistry;
  274. for( ; pReg < pEnd; pReg++ )
  275. {
  276. HRESULT hr = CoRevokeClassObject( pReg->dwRegister );
  277. if( FAILED( hr ) )
  278. return hr;
  279. if( pReg->pFactory )
  280. pReg->pFactory->Release();
  281. }
  282. return NOERROR;
  283. }
  284. /////////////////////////////////////////////////////////////////////////////
  285. // DLL server helper function; call from DllGetClassObject
  286. //
  287. STDMETHODIMP
  288. CClassFactory::GetClassObject(
  289. REFCLSID rclsid,
  290. REFIID riid,
  291. LPVOID FAR* ppvObj
  292. )
  293. {
  294. assert( ! IsBadWritePtr( ppvObj, sizeof( LPVOID FAR* ) ) );
  295. SortRegistry();
  296. Registry* pReg = FindClass( &rclsid );
  297. if( ! pReg )
  298. return ResultFromScode( CLASS_E_CLASSNOTAVAILABLE );
  299. CClassFactory* pFactory = pReg->pFactory ? pReg->pFactory : newCClassFactory( pReg );
  300. if( ! pFactory )
  301. return ResultFromScode( E_OUTOFMEMORY );
  302. HRESULT hr = pFactory->QueryInterface( riid, ppvObj );
  303. if( FAILED( hr ) )
  304. {
  305. // if we just created the factory its ref count will be 0 and we
  306. // need to delete it. Otherwise it must continue to exist.
  307. pFactory->AddRef();
  308. pFactory->Release();
  309. }
  310. return hr;
  311. }
  312. /////////////////////////////////////////////////////////////////////////////
  313. // local CoCreateInstance; call when creating come objects locally
  314. // (not via CoCreateInstance)
  315. //
  316. STDMETHODIMP
  317. CClassFactory::LocalCreateInstance(
  318. REFCLSID rclsid,
  319. LPUNKNOWN pUnkOuter,
  320. DWORD dwClsContext,
  321. REFIID riid,
  322. LPVOID FAR* ppvObj
  323. )
  324. {
  325. dwClsContext; // to statisfy the compiler
  326. // get the class factory for the requested object
  327. LPCLASSFACTORY lpClassFactory;
  328. HRESULT hr = GetClassObject( rclsid, IID_IClassFactory, (LPVOID FAR*) &lpClassFactory );
  329. if( FAILED( hr ) )
  330. return hr;
  331. // create an instance of the requested object and get the requested interface
  332. hr = lpClassFactory->CreateInstance( pUnkOuter, riid, ppvObj );
  333. lpClassFactory->Release();
  334. return hr;
  335. }
  336. /////////////////////////////////////////////////////////////////////////////
  337. // Method to help with dynamic memory allocation of a CClassFactory object.
  338. //
  339. CClassFactory* CClassFactory::newCClassFactory( Registry* pReg )
  340. {
  341. CClassFactory *p = NULL;
  342. // TRY
  343. // {
  344. p = new CClassFactory( pReg );
  345. // }
  346. // CATCH( CMemoryException, e )
  347. // {
  348. // TRACE0( "Caught memory exception in CClassFactory::newCClassFactory\n" );
  349. // }
  350. // END_CATCH
  351. return p;
  352. }
  353. /*
  354. /////////////////////////////////////////////////////////////////////////////
  355. // $Log: J:\rtp\src\ppm\fact.cpv $
  356. Rev 1.3 20 Mar 1997 18:32:04 lscline
  357. Merged small change differences for MS NT 5.0 build environment.
  358. Rev 1.2 05 Apr 1996 16:46:00 LSCLINE
  359. Copyright
  360. Rev 1.1 Dec 11 1995 13:39:08 rnegrin
  361. Fixed the PVCS log at end of file
  362. Rev 1.0 Dec 08 1995 16:41:06 rnegrin
  363. Initial revision.
  364. //
  365. // Rev 1.12 20 Sep 1995 16:05:14 PCRUTCHE
  366. // OLEFHK32
  367. //
  368. // Rev 1.11 13 Jun 1995 19:36:00 DEDEN
  369. // Dynamic object allocation helper functions\macros
  370. //
  371. // Rev 1.10 06 Jan 1995 09:56:44 PCRUTCHE
  372. // Changed registry data structure
  373. //
  374. // Rev 1.9 02 Nov 1994 10:50:00 JDELLIOT
  375. // get rid of compiler warnings
  376. //
  377. // Rev 1.8 28 Oct 1994 13:51:16 JDELLIOT
  378. // added LocalCreateInstance for creating local COM objects (not via
  379. // CoCreateInstance)
  380. //
  381. // Rev 1.7 26 Oct 1994 17:52:44 JDELLIOT
  382. // in CreateInstance after calling _CreateObject the object now has a ref count
  383. // of 1. As such when we QueryInterface the ref count goes to 2 and we need
  384. // to Release it back down to one. This was added for aggregation.
  385. //
  386. // Rev 1.6 25 Oct 1994 14:42:42 KAWATTS
  387. // Removed TRACEs again
  388. //
  389. // Rev 1.5 25 Oct 1994 10:21:02 JDELLIOT
  390. // added TRACEs for s_cObjects
  391. //
  392. // Rev 1.4 19 Oct 1994 14:57:48 JDELLIOT
  393. // minor changes
  394. //
  395. // Rev 1.3 12 Oct 1994 18:11:58 JDELLIOT
  396. // changed params to CClassFactory::FindClass
  397. // fixed AddRef inside CClassFactory::QueryInterface
  398. //
  399. // Rev 1.2 07 Oct 1994 11:26:46 KAWATTS
  400. // All rights reserved
  401. //
  402. // Rev 1.1 07 Oct 1994 09:51:14 JDELLIOT
  403. // fixed PVCS keywords
  404. //
  405. */