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.

809 lines
24 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1999-2002 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // DllSrc.cpp
  7. //
  8. // Description:
  9. // DLL services/entry points.
  10. //
  11. // Maintained By:
  12. // David Potter (DavidP) 19-MAR-2001
  13. // Geoffrey Pease (GPease) 18-OCT-1999
  14. //
  15. // Notes:
  16. // Switches:
  17. // - ENTRY_PREFIX
  18. // If defined, include proxy/stub code into the DLL that is
  19. // generated by the MIDL compiler.
  20. // - USE_FUSION
  21. // If defined, initialize and uninitialize Fusion on process
  22. // attach and detach respectively. The constant IDR_MANIFEST
  23. // must be defined with a value that represents the resource ID
  24. // for the manifest resource.
  25. // - NO_DLL_MAIN
  26. // If defined, don't implement DllMain.
  27. // - DEBUG_SW_TRACING_ENABLED
  28. // If defined, initialize and uninitialize software tracing on
  29. // process attach and detach respectively.
  30. // - THREAD_OPTIMIZATIONS
  31. // If defined, disable the thread notification calls when a thread
  32. // starts up or goes away.
  33. // - IMPLEMENT_COM_SERVER_DLL
  34. // If defined, defines entry points necessary for COM servers.
  35. //
  36. //////////////////////////////////////////////////////////////////////////////
  37. //
  38. // DLL Globals
  39. //
  40. HINSTANCE g_hInstance = NULL;
  41. LONG g_cObjects = 0;
  42. LONG g_cLock = 0;
  43. WCHAR g_szDllFilename[ MAX_PATH ] = { 0 };
  44. LPVOID g_GlobalMemoryList = NULL; // Global memory tracking list
  45. #if defined( ENTRY_PREFIX )
  46. extern "C"
  47. {
  48. extern HINSTANCE hProxyDll;
  49. }
  50. #endif
  51. //
  52. // Macros to generate RPC entry points
  53. //
  54. #define __rpc_macro_expand2( a, b ) a##b
  55. #define __rpc_macro_expand( a, b ) __rpc_macro_expand2( a, b )
  56. #if ! defined( NO_DLL_MAIN ) || defined( ENTRY_PREFIX ) || defined( DEBUG )
  57. //////////////////////////////////////////////////////////////////////////////
  58. //++
  59. //
  60. // DllMain
  61. //
  62. // Description:
  63. // Dll entry point.
  64. //
  65. // Arguments:
  66. // hInstIn - DLL instance handle.
  67. // ulReasonIn - DLL reason code for entrance.
  68. // lpReservedIn - Not used.
  69. //
  70. // Return Values:
  71. // TRUE
  72. //
  73. //--
  74. //////////////////////////////////////////////////////////////////////////////
  75. BOOL
  76. WINAPI
  77. DllMain(
  78. HINSTANCE hInstIn,
  79. ULONG ulReasonIn,
  80. LPVOID // lpReservedIn
  81. )
  82. {
  83. //
  84. // KB: THREAD_OPTIMIZATIONS gpease 19-OCT-1999
  85. //
  86. // By defining this you can prevent the linker
  87. // from calling your DllEntry for every new thread.
  88. // This makes creating new threads significantly
  89. // faster if every DLL in a process does it.
  90. // Unfortunately, not all DLLs do this.
  91. //
  92. // In CHKed/DEBUG, we keep this on for memory
  93. // tracking.
  94. //
  95. #if ! defined( DEBUG )
  96. #define THREAD_OPTIMIZATIONS
  97. #endif // DEBUG
  98. switch( ulReasonIn )
  99. {
  100. //////////////////////////////////////////////////////////////////////
  101. // DLL_PROCESS_ATTACH
  102. //////////////////////////////////////////////////////////////////////
  103. case DLL_PROCESS_ATTACH:
  104. {
  105. #if defined( DEBUG_SW_TRACING_ENABLED )
  106. TraceInitializeProcess( g_rgTraceControlGuidList, RTL_NUMBER_OF( g_rgTraceControlGuidList ), TRUE );
  107. #else // ! DEBUG_SW_TRACING_ENABLED
  108. TraceInitializeProcess( TRUE );
  109. #endif // DEBUG_SW_TRACING_ENABLED
  110. TraceFunc( "" );
  111. TraceMessage(
  112. TEXT(__FILE__)
  113. , __LINE__
  114. , __MODULE__
  115. , mtfDLL
  116. , L"DLL: DLL_PROCESS_ATTACH - ThreadID = %#x"
  117. , GetCurrentThreadId()
  118. );
  119. g_hInstance = hInstIn;
  120. #if defined( ENTRY_PREFIX )
  121. hProxyDll = g_hInstance;
  122. #endif // ENTRY_PREFIX
  123. {
  124. BOOL fResult = GetModuleFileName( g_hInstance, g_szDllFilename, RTL_NUMBER_OF( g_szDllFilename ) );
  125. if ( ! fResult )
  126. {
  127. TW32MSG( GetLastError(), "GetModuleFileName()" );
  128. }
  129. }
  130. //
  131. // Create a global memory list so that memory allocated by one
  132. // thread and handed to another can be tracked without causing
  133. // unnecessary trace messages.
  134. //
  135. TraceCreateMemoryList( g_GlobalMemoryList );
  136. #if defined( THREAD_OPTIMIZATIONS )
  137. {
  138. //
  139. // Disable thread library calls so that we don't get called
  140. // on thread attach and detach.
  141. //
  142. BOOL fResult = DisableThreadLibraryCalls( g_hInstance );
  143. if ( ! fResult )
  144. {
  145. TW32MSG( GetLastError(), "DisableThreadLibraryCalls()" );
  146. }
  147. }
  148. #endif // THREAD_OPTIMIZATIONS
  149. #if defined( USE_FUSION )
  150. {
  151. //
  152. // Initialize Fusion.
  153. //
  154. // The value of IDR_MANIFEST in the call to
  155. // SHFusionInitializeFromModuleID() must match the value specified in the
  156. // sources file for SXS_MANIFEST_RESOURCE_ID.
  157. //
  158. BOOL fResult = SHFusionInitializeFromModuleID( hInstIn, IDR_MANIFEST );
  159. if ( ! fResult )
  160. {
  161. TW32MSG( GetLastError(), "SHFusionInitializeFromModuleID()" );
  162. }
  163. }
  164. #endif // USE_FUSION
  165. #if defined( DO_MODULE_INIT )
  166. THR( HrLocalProcessInit() );
  167. #endif
  168. //
  169. // This is necessary here because TraceFunc() defines a variable
  170. // on the stack which isn't available outside the scope of this
  171. // block.
  172. // This function doesn't do anything but clean up after
  173. // TraceFunc().
  174. //
  175. FRETURN( TRUE );
  176. break;
  177. } // case: DLL_PROCESS_ATTACH
  178. //////////////////////////////////////////////////////////////////////
  179. // DLL_PROCESS_DETACH
  180. //////////////////////////////////////////////////////////////////////
  181. case DLL_PROCESS_DETACH:
  182. {
  183. TraceFunc( "" );
  184. TraceMessage(
  185. TEXT(__FILE__)
  186. , __LINE__
  187. , __MODULE__
  188. , mtfDLL
  189. , L"DLL: DLL_PROCESS_DETACH - ThreadID = %#x [ g_cLock=%u, g_cObjects=%u ]"
  190. , GetCurrentThreadId()
  191. , g_cLock
  192. , g_cObjects
  193. );
  194. #if defined( DO_MODULE_UNINIT )
  195. THR( HrLocalProcessUninit() );
  196. #endif
  197. //
  198. // Cleanup the global memory list used to track memory allocated
  199. // in one thread and then handed to another.
  200. //
  201. TraceTerminateMemoryList( g_GlobalMemoryList );
  202. //
  203. // This is necessary here because TraceFunc() defines a variable
  204. // on the stack which isn't available outside the scope of this
  205. // block.
  206. // This function doesn't do anything but clean up after
  207. // TraceFunc().
  208. //
  209. FRETURN( TRUE );
  210. #if defined( DEBUG_SW_TRACING_ENABLED )
  211. TraceTerminateProcess( g_rgTraceControlGuidList, RTL_NUMBER_OF( g_rgTraceControlGuidList ) );
  212. #else // ! DEBUG_SW_TRACING_ENABLED
  213. TraceTerminateProcess();
  214. #endif // DEBUG_SW_TRACING_ENABLED
  215. #if defined( USE_FUSION )
  216. SHFusionUninitialize();
  217. #endif // USE_FUSION
  218. break;
  219. } // case: DLL_PROCESS_DETACH
  220. #if ! defined( THREAD_OPTIMIZATIONS )
  221. //////////////////////////////////////////////////////////////////////
  222. // DLL_THREAD_ATTACH
  223. //////////////////////////////////////////////////////////////////////
  224. case DLL_THREAD_ATTACH:
  225. {
  226. TraceInitializeThread( NULL );
  227. TraceMessage(
  228. TEXT(__FILE__)
  229. , __LINE__
  230. , __MODULE__
  231. , mtfDLL
  232. , L"Thread %#x has started."
  233. , GetCurrentThreadId()
  234. );
  235. TraceFunc( "" );
  236. TraceMessage(
  237. TEXT(__FILE__)
  238. , __LINE__
  239. , __MODULE__
  240. , mtfDLL
  241. , L"DLL: DLL_THREAD_ATTACH - ThreadID = %#x [ g_cLock=%u, g_cObjects=%u ]"
  242. , GetCurrentThreadId()
  243. , g_cLock
  244. , g_cObjects
  245. );
  246. //
  247. // This is necessary here because TraceFunc() defines a variable
  248. // on the stack which isn't available outside the scope of this
  249. // block.
  250. // This function doesn't do anything but clean up after
  251. // TraceFunc().
  252. //
  253. FRETURN( TRUE );
  254. break;
  255. } // case: DLL_THREAD_ATTACH
  256. //////////////////////////////////////////////////////////////////////
  257. // DLL_THREAD_DETACH
  258. //////////////////////////////////////////////////////////////////////
  259. case DLL_THREAD_DETACH:
  260. {
  261. TraceFunc( "" );
  262. TraceMessage(
  263. TEXT(__FILE__)
  264. , __LINE__
  265. , __MODULE__
  266. , mtfDLL
  267. , L"DLL: DLL_THREAD_DETACH - ThreadID = %#x [ g_cLock=%u, g_cObjects=%u ]"
  268. , GetCurrentThreadId()
  269. , g_cLock
  270. , g_cObjects
  271. );
  272. //
  273. // This is necessary here because TraceFunc() defines a variable
  274. // on the stack which isn't available outside the scope of this
  275. // block.
  276. // This function doesn't do anything but clean up after
  277. // TraceFunc().
  278. //
  279. FRETURN( TRUE );
  280. TraceThreadRundown();
  281. break;
  282. } // case: DLL_THREAD_DETACH
  283. #endif // ! THREAD_OPTIMIZATIONS
  284. default:
  285. {
  286. TraceFunc( "" );
  287. TraceMessage(
  288. TEXT(__FILE__)
  289. , __LINE__
  290. , __MODULE__
  291. , mtfDLL
  292. , L"DLL: UNKNOWN ENTRANCE REASON - ThreadID = %#x [ g_cLock=%u, g_cObjects=%u ]"
  293. , GetCurrentThreadId()
  294. , g_cLock
  295. , g_cObjects
  296. );
  297. #if defined( THREAD_OPTIMIZATIONS )
  298. Assert( ( ulReasonIn != DLL_THREAD_ATTACH )
  299. && ( ulReasonIn != DLL_THREAD_DETACH ) );
  300. #endif // THREAD_OPTIMIZATIONS
  301. //
  302. // This is necessary here because TraceFunc defines a variable
  303. // on the stack which isn't available outside the scope of this
  304. // block.
  305. // This function doesn't do anything but clean up after TraceFunc.
  306. //
  307. FRETURN( TRUE );
  308. break;
  309. } // default case
  310. } // switch on reason code
  311. return TRUE;
  312. } //*** DllMain
  313. #endif // ! defined( NO_DLL_MAIN ) && ! defined( ENTRY_PREFIX ) && ! defined( DEBUG )
  314. #ifdef IMPLEMENT_COM_SERVER_DLL
  315. //
  316. // The following functions are only required by COM server DLLs.
  317. //
  318. //////////////////////////////////////////////////////////////////////////////
  319. //++
  320. //
  321. // DllGetClassObject
  322. //
  323. // Description:
  324. // OLE calls this to get the class factory from the DLL.
  325. //
  326. // Arguments:
  327. // rclsidIn
  328. // - Class ID of the object that the class factory should create.
  329. // riidIn
  330. // - Interface of the class factory
  331. // ppvOut
  332. // - The interface pointer to the class factory.
  333. //
  334. // Return Values:
  335. // S_OK - Operation completed successfully.
  336. // E_POINTER - Required output parameter was specified as NULL.
  337. // CLASS_E_CLASSNOTAVAILABLE
  338. // - Class ID not supported by this DLL.
  339. // E_OUTOFMEMORY - Error allocating memory.
  340. // Other HRESULTs to indicate failure.
  341. //
  342. //--
  343. //////////////////////////////////////////////////////////////////////////////
  344. STDAPI
  345. DllGetClassObject(
  346. REFCLSID rclsidIn,
  347. REFIID riidIn,
  348. void ** ppvOut
  349. )
  350. {
  351. TraceFunc( "rclsidIn, riidIn, ppvOut" );
  352. CFactory * pClassFactory = NULL;
  353. HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
  354. const SPublicClassInfo * pClassInfo = g_DllPublicClasses;
  355. if ( ppvOut == NULL )
  356. {
  357. hr = THR( E_POINTER );
  358. goto Cleanup;
  359. } // if: bad argument
  360. *ppvOut = NULL;
  361. //
  362. // Search the public class table for a matching CLSID.
  363. //
  364. while ( pClassInfo->pClassID != NULL )
  365. {
  366. if ( *( pClassInfo->pClassID ) == rclsidIn )
  367. {
  368. TraceMessage( TEXT(__FILE__), __LINE__, __MODULE__, mtfFUNC, L"rclsidIn = %s", pClassInfo->pcszName );
  369. hr = S_OK;
  370. break;
  371. } // if: class found
  372. ++pClassInfo;
  373. } // while: finding class
  374. // Didn't find the class ID.
  375. if ( hr == CLASS_E_CLASSNOTAVAILABLE )
  376. {
  377. TraceMsgGUID( mtfFUNC, "rclsidIn = ", rclsidIn );
  378. #if defined( ENTRY_PREFIX )
  379. //
  380. // See if the MIDL generated code can create it.
  381. //
  382. hr = STHR( __rpc_macro_expand( ENTRY_PREFIX, DllGetClassObject )( rclsidIn, riidIn, ppvOut ) );
  383. #endif // defined( ENTRY_PREFIX )
  384. goto Cleanup;
  385. } // if: class not found
  386. Assert( pClassInfo->pfnCreateInstance != NULL );
  387. hr = THR( CFactory::S_HrCreateInstance( pClassInfo->pfnCreateInstance, &pClassFactory ) );
  388. if ( FAILED( hr ) )
  389. {
  390. goto Cleanup;
  391. } // if: initialization failed
  392. // Can't safe type.
  393. hr = pClassFactory->QueryInterface( riidIn, ppvOut );
  394. Cleanup:
  395. if ( pClassFactory != NULL )
  396. {
  397. pClassFactory->Release();
  398. }
  399. HRETURN( hr );
  400. } //*** DllGetClassObject
  401. //////////////////////////////////////////////////////////////////////////////
  402. //++
  403. //
  404. // DllRegisterServer
  405. //
  406. // Description:
  407. // OLE's register entry point.
  408. //
  409. // Argument:
  410. // None.
  411. //
  412. // Return Values:
  413. // S_OK - Operation completed successfully.
  414. // Other HRESULTs to indicate failure.
  415. //
  416. //--
  417. //////////////////////////////////////////////////////////////////////////////
  418. STDAPI
  419. DllRegisterServer( void )
  420. {
  421. TraceFunc( "" );
  422. HRESULT hr;
  423. hr = THR( HrRegisterDll() );
  424. #if defined( ENTRY_PREFIX )
  425. if ( SUCCEEDED( hr ) )
  426. {
  427. hr = THR( __rpc_macro_expand( ENTRY_PREFIX, DllRegisterServer )() );
  428. } // if: register proxy/stub
  429. #endif // defined( ENTRY_PREFIX )
  430. HRETURN( hr );
  431. } //*** DllRegisterServer
  432. //////////////////////////////////////////////////////////////////////////////
  433. //++
  434. //
  435. // DllUnregisterServer
  436. //
  437. // Description:
  438. // OLE's unregister entry point.
  439. //
  440. // Arguments:
  441. // None.
  442. //
  443. // Return Values:
  444. // S_OK - Operation completed successful.
  445. // Other HRESULTs to indicate failure.
  446. //
  447. //--
  448. //////////////////////////////////////////////////////////////////////////////
  449. STDAPI
  450. DllUnregisterServer( void )
  451. {
  452. TraceFunc( "" );
  453. HRESULT hr;
  454. hr = THR( HrUnregisterDll() );
  455. #if defined( ENTRY_PREFIX )
  456. if ( SUCCEEDED( hr ) )
  457. {
  458. hr = THR( __rpc_macro_expand( ENTRY_PREFIX, DllUnregisterServer )() );
  459. } // if: unregister proxy/stub
  460. #endif // defined( ENTRY_PREFIX )
  461. if ( hr == HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) )
  462. {
  463. hr = S_OK;
  464. }
  465. HRETURN( hr );
  466. } //*** DllUnregisterServer
  467. //////////////////////////////////////////////////////////////////////////////
  468. //++
  469. //
  470. // DllCanUnloadNow
  471. //
  472. // Description:
  473. // OLE calls this entry point to see if it can unload the DLL.
  474. //
  475. // Arguments:
  476. // None.
  477. //
  478. // Return Values:
  479. // S_OK - Can unload the DLL.
  480. // S_FALSE - Can not unload the DLL.
  481. //
  482. //--
  483. //////////////////////////////////////////////////////////////////////////////
  484. STDAPI
  485. DllCanUnloadNow( void )
  486. {
  487. TraceFunc( "" );
  488. HRESULT hr = S_OK;
  489. if ( ( g_cLock != 0 ) || ( g_cObjects != 0 ) )
  490. {
  491. TraceMsg( mtfDLL, "DLL: Can't unload - g_cLock=%u, g_cObjects=%u", g_cLock, g_cObjects );
  492. hr = S_FALSE;
  493. } // if: any object or locks
  494. #if defined( ENTRY_PREFIX )
  495. else
  496. {
  497. //
  498. // Check with the MIDL generated proxy/stubs.
  499. //
  500. hr = STHR( __rpc_macro_expand( ENTRY_PREFIX, DllCanUnloadNow )() );
  501. }
  502. #endif
  503. HRETURN( hr );
  504. } //*** DllCanUnloadNow
  505. //////////////////////////////////////////////////////////////////////////////
  506. //++
  507. //
  508. // HrCoCreateInternalInstance
  509. //
  510. // Description:
  511. // Mimic CoCreateInstance() except that it looks into the DLL table
  512. // to see if we can shortcut the CoCreate with a simple CreateInstance
  513. // call.
  514. //
  515. // Arguments: (matches CoCreateInstance)
  516. // rclsidIn - Class identifier (CLSID) of the object
  517. // pUnkOuterIn - Pointer to controlling IUnknown
  518. // dwClsContext - Context for running executable code
  519. // riidIn - Reference to the identifier of the interface
  520. // ppvOut - Address of output variable that receives
  521. //
  522. // Return Values:
  523. // S_OK - Success.
  524. // E_OUTOFMEMORY - Out of memory.
  525. // other HRESULT values
  526. //
  527. //////////////////////////////////////////////////////////////////////////////
  528. HRESULT
  529. HrCoCreateInternalInstance(
  530. REFCLSID rclsidIn,
  531. LPUNKNOWN pUnkOuterIn,
  532. DWORD dwClsContextIn,
  533. REFIID riidIn,
  534. LPVOID * ppvOut
  535. )
  536. {
  537. TraceFunc( "" );
  538. Assert( ppvOut != NULL );
  539. HRESULT hr = S_OK;
  540. MULTI_QI mqi;
  541. mqi.hr = S_OK;
  542. mqi.pItf = NULL;
  543. mqi.pIID = &riidIn;
  544. hr = HrCoCreateInternalInstanceEx( rclsidIn, pUnkOuterIn, dwClsContextIn, NULL, 1, &mqi );
  545. *ppvOut = mqi.pItf;
  546. HRETURN( hr );
  547. } //*** HrCoCreateInternalInstance
  548. //////////////////////////////////////////////////////////////////////////////
  549. //++
  550. //
  551. // HrCoCreateInternalInstanceEx
  552. //
  553. // Description:
  554. // Mimic CoCreateInstanceEx() except that it looks into the DLL table
  555. // to see if we can shortcut the CoCreate with a simple CreateInstance
  556. // call.
  557. //
  558. // Arguments: (matches CoCreateInstanceEx)
  559. // rclsidIn - Class identifier (CLSID) of the object
  560. // pUnkOuterIn - Pointer to controlling IUnknown
  561. // dwClsContext - Context for running executable code
  562. // pServerInfoIn - Object location; can be NULL
  563. // cMultiQIsIn - Number of MULTI_QI structs in prgmqiInOut array
  564. // prgmqiInOut - Array to hold queried interfaces on object
  565. //
  566. // Return Values:
  567. // S_OK
  568. // Success.
  569. //
  570. // E_OUTOFMEMORY
  571. // Out of memory.
  572. //
  573. // E_NOINTERFACE
  574. // Object created, but supports no requested interfaces.
  575. //
  576. // CO_S_NOTALLINTERFACES
  577. // Object created and supports some, but not all, requested
  578. // interfaces.
  579. //
  580. // CLASS_E_CLASSNOTAVAILABLE
  581. // Unknown class ID.
  582. //
  583. // Other HRESULTs.
  584. //
  585. //////////////////////////////////////////////////////////////////////////////
  586. HRESULT
  587. HrCoCreateInternalInstanceEx(
  588. REFCLSID rclsidIn,
  589. LPUNKNOWN pUnkOuterIn,
  590. DWORD dwClsContextIn,
  591. COSERVERINFO * pServerInfoIn,
  592. ULONG cMultiQIsIn,
  593. MULTI_QI * prgmqiInOut
  594. )
  595. {
  596. TraceFunc( "" );
  597. Assert( ( prgmqiInOut != NULL ) || ( cMultiQIsIn == 0 ) );
  598. HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
  599. //
  600. // Limit simple CoCreate() only works to INPROC and non-aggregatable objects.
  601. //
  602. if ( ( dwClsContextIn & ( CLSCTX_INPROC_HANDLER | CLSCTX_INPROC_SERVER ) ) // inproc only
  603. && ( pServerInfoIn == NULL ) // local machine only
  604. && ( pUnkOuterIn == NULL ) // no aggregation
  605. )
  606. {
  607. PFN_FACTORY_METHOD pfnCreateInstance = NULL;
  608. const SPrivateClassInfo * pPrivateInfo = g_PrivateClasses;
  609. const SPublicClassInfo * pPublicInfo = g_DllPublicClasses;
  610. //
  611. // Look up the class ID in the private class table first.
  612. //
  613. while ( ( pfnCreateInstance == NULL ) && ( pPrivateInfo->pClassID != NULL ) )
  614. {
  615. if ( *( pPrivateInfo->pClassID ) == rclsidIn )
  616. {
  617. pfnCreateInstance = pPrivateInfo->pfnCreateInstance;
  618. }
  619. ++pPrivateInfo;
  620. }
  621. //
  622. // If that didn't find it, try the public table.
  623. //
  624. while ( ( pfnCreateInstance == NULL ) && ( pPublicInfo->pClassID != NULL ) )
  625. {
  626. if ( *( pPublicInfo->pClassID ) == rclsidIn )
  627. {
  628. pfnCreateInstance = pPublicInfo->pfnCreateInstance;
  629. }
  630. ++pPublicInfo;
  631. }
  632. //
  633. // If either found a match, use its factory method to create an object.
  634. //
  635. if ( pfnCreateInstance != NULL )
  636. {
  637. IUnknown * punkInstance = NULL;
  638. ULONG idxInterface = 0;
  639. BOOL fQISucceeded = FALSE;
  640. BOOL fQIFailed = FALSE;
  641. hr = THR( ( *pfnCreateInstance )( &punkInstance ) );
  642. if ( FAILED( hr ) )
  643. {
  644. goto Cleanup;
  645. }
  646. //
  647. // Query for each requested interface.
  648. //
  649. while ( idxInterface < cMultiQIsIn )
  650. {
  651. MULTI_QI * pmqi = prgmqiInOut + idxInterface;
  652. //
  653. // No THR around the following QI because client might expect some failures.
  654. //
  655. pmqi->hr = punkInstance->QueryInterface( *( pmqi->pIID ), reinterpret_cast< void** >( &( pmqi->pItf ) ) );
  656. if ( SUCCEEDED( pmqi->hr ) )
  657. {
  658. fQISucceeded = TRUE;
  659. }
  660. else
  661. {
  662. fQIFailed = TRUE;
  663. }
  664. idxInterface += 1;
  665. } // for each requested interface
  666. //
  667. // Mimic return values from CoCreateInstanceEx.
  668. //
  669. if ( fQIFailed )
  670. {
  671. if ( fQISucceeded )
  672. {
  673. // At least one QI succeeded, and at least one failed.
  674. hr = CO_S_NOTALLINTERFACES;
  675. }
  676. else
  677. {
  678. // At least one QI failed, and none succeeded.
  679. hr = E_NOINTERFACE;
  680. }
  681. }
  682. // Otherwise, leave hr as is.
  683. punkInstance->Release();
  684. } // if: creating internal class
  685. } // if: simple CoCreate()
  686. //
  687. // If not found or asking for something we do not support,
  688. // use the COM version.
  689. //
  690. if ( hr == CLASS_E_CLASSNOTAVAILABLE )
  691. {
  692. //
  693. // Try it the old fashion way...
  694. //
  695. hr = STHR( CoCreateInstanceEx( rclsidIn, pUnkOuterIn, dwClsContextIn, pServerInfoIn, cMultiQIsIn, prgmqiInOut ) );
  696. } // if: class not found
  697. Cleanup:
  698. HRETURN( hr );
  699. } //*** HrCoCreateInternalInstanceEx
  700. //
  701. // TODO: gpease 27-NOV-1999
  702. // While perusing around the MIDL SDK, I foud that
  703. // RPC creates the same type of class table we do. Maybe
  704. // we can leverage the MIDL code to create our objects(??).
  705. //
  706. #endif // IMPLEMENT_COM_SERVER_DLL