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.

649 lines
18 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1999-2001 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. // -- NO_THREAD_OPTIMIZATIONS
  31. // If defined, disable the thread notification calls when a thread
  32. // starts up or goes away.
  33. //
  34. //////////////////////////////////////////////////////////////////////////////
  35. //
  36. // DLL Globals
  37. //
  38. HINSTANCE g_hInstance = NULL;
  39. LONG g_cObjects = 0;
  40. LONG g_cLock = 0;
  41. TCHAR g_szDllFilename[ MAX_PATH ] = { 0 };
  42. LPVOID g_GlobalMemoryList = NULL; // Global memory tracking list
  43. #if defined( ENTRY_PREFIX )
  44. extern "C"
  45. {
  46. extern HINSTANCE hProxyDll;
  47. }
  48. #endif
  49. //
  50. // Macros to generate RPC entry points
  51. //
  52. #define __rpc_macro_expand2( a, b ) a##b
  53. #define __rpc_macro_expand( a, b ) __rpc_macro_expand2( a, b )
  54. #if ! defined( NO_DLL_MAIN ) || defined( ENTRY_PREFIX ) || defined( DEBUG )
  55. //////////////////////////////////////////////////////////////////////////////
  56. //++
  57. //
  58. // DllMain
  59. //
  60. // Description:
  61. // Dll entry point.
  62. //
  63. // Arguments:
  64. // hInstIn - DLL instance handle.
  65. // ulReasonIn - DLL reason code for entrance.
  66. // lpReservedIn - Not used.
  67. //
  68. // Return Values:
  69. // TRUE
  70. //
  71. //--
  72. //////////////////////////////////////////////////////////////////////////////
  73. BOOL
  74. WINAPI
  75. DllMain(
  76. HINSTANCE hInstIn,
  77. ULONG ulReasonIn,
  78. LPVOID // lpReservedIn
  79. )
  80. {
  81. //
  82. // KB: THREAD_OPTIMIZATIONS gpease 19-OCT-1999
  83. //
  84. // By defining this you can prevent the linker
  85. // from calling your DllEntry for every new thread.
  86. // This makes creating new threads significantly
  87. // faster if every DLL in a process does it.
  88. // Unfortunately, not all DLLs do this.
  89. //
  90. // In CHKed/DEBUG, we keep this on for memory
  91. // tracking.
  92. //
  93. #if ! defined( DEBUG )
  94. #define THREAD_OPTIMIZATIONS
  95. #endif // DEBUG
  96. switch( ulReasonIn )
  97. {
  98. //////////////////////////////////////////////////////////////////////
  99. // DLL_PROCESS_ATTACH
  100. //////////////////////////////////////////////////////////////////////
  101. case DLL_PROCESS_ATTACH:
  102. {
  103. #if defined( DEBUG_SW_TRACING_ENABLED )
  104. TraceInitializeProcess( g_rgTraceControlGuidList, ARRAYSIZE( g_rgTraceControlGuidList ), TRUE );
  105. #else // ! DEBUG_SW_TRACING_ENABLED
  106. TraceInitializeProcess( TRUE );
  107. #endif // DEBUG_SW_TRACING_ENABLED
  108. TraceFunc( "" );
  109. TraceMessage( TEXT(__FILE__),
  110. __LINE__,
  111. __MODULE__,
  112. mtfDLL,
  113. TEXT("DLL: DLL_PROCESS_ATTACH - ThreadID = %#x"),
  114. GetCurrentThreadId()
  115. );
  116. g_hInstance = hInstIn;
  117. #if defined( ENTRY_PREFIX )
  118. hProxyDll = g_hInstance;
  119. #endif // ENTRY_PREFIX
  120. GetModuleFileName( g_hInstance, g_szDllFilename, ARRAYSIZE( g_szDllFilename ) );
  121. //
  122. // Create a global memory list so that memory allocated by one
  123. // thread and handed to another can be tracked without causing
  124. // unnecessary trace messages.
  125. //
  126. TraceCreateMemoryList( g_GlobalMemoryList );
  127. #if defined( THREAD_OPTIMIZATIONS )
  128. {
  129. //
  130. // Disable thread library calls so that we don't get called
  131. // on thread attach and detach.
  132. //
  133. BOOL fResult = DisableThreadLibraryCalls( g_hInstance );
  134. if ( ! fResult )
  135. {
  136. TW32MSG( GetLastError(), "DisableThreadLibraryCalls()" );
  137. }
  138. }
  139. #endif // THREAD_OPTIMIZATIONS
  140. #if defined( USE_FUSION )
  141. //
  142. // Initialize Fusion.
  143. //
  144. // The value of IDR_MANIFEST in the call to
  145. // SHFusionInitializeFromModuleID() must match the value specified in the
  146. // sources file for SXS_MANIFEST_RESOURCE_ID.
  147. //
  148. BOOL fResult = SHFusionInitializeFromModuleID( hInstIn, IDR_MANIFEST );
  149. if ( ! fResult )
  150. {
  151. TW32MSG( GetLastError(), "SHFusionInitializeFromModuleID()" );
  152. }
  153. #endif // USE_FUSION
  154. //
  155. // This is necessary here because TraceFunc() defines a variable
  156. // on the stack which isn't available outside the scope of this
  157. // block.
  158. // This function doesn't do anything but clean up after
  159. // TraceFunc().
  160. //
  161. FRETURN( TRUE );
  162. break;
  163. } // case: DLL_PROCESS_ATTACH
  164. //////////////////////////////////////////////////////////////////////
  165. // DLL_PROCESS_DETACH
  166. //////////////////////////////////////////////////////////////////////
  167. case DLL_PROCESS_DETACH:
  168. {
  169. TraceFunc( "" );
  170. TraceMessage( TEXT(__FILE__),
  171. __LINE__,
  172. __MODULE__,
  173. mtfDLL,
  174. TEXT("DLL: DLL_PROCESS_DETACH - ThreadID = %#x [ g_cLock=%u, g_cObjects=%u ]"),
  175. GetCurrentThreadId(),
  176. g_cLock,
  177. g_cObjects
  178. );
  179. //
  180. // Cleanup the global memory list used to track memory allocated
  181. // in one thread and then handed to another.
  182. //
  183. TraceTerminateMemoryList( g_GlobalMemoryList );
  184. //
  185. // This is necessary here because TraceFunc() defines a variable
  186. // on the stack which isn't available outside the scope of this
  187. // block.
  188. // This function doesn't do anything but clean up after
  189. // TraceFunc().
  190. //
  191. FRETURN( TRUE );
  192. #if defined( DEBUG_SW_TRACING_ENABLED )
  193. TraceTerminateProcess( g_rgTraceControlGuidList, ARRAYSIZE( g_rgTraceControlGuidList )
  194. );
  195. #else // ! DEBUG_SW_TRACING_ENABLED
  196. TraceTerminateProcess();
  197. #endif // DEBUG_SW_TRACING_ENABLED
  198. #if defined( USE_FUSION )
  199. SHFusionUninitialize();
  200. #endif // USE_FUSION
  201. break;
  202. } // case: DLL_PROCESS_DETACH
  203. #if ! defined( THREAD_OPTIMIZATIONS )
  204. //////////////////////////////////////////////////////////////////////
  205. // DLL_THREAD_ATTACH
  206. //////////////////////////////////////////////////////////////////////
  207. case DLL_THREAD_ATTACH:
  208. {
  209. TraceInitializeThread( NULL );
  210. TraceMessage( TEXT(__FILE__),
  211. __LINE__,
  212. __MODULE__,
  213. mtfDLL,
  214. TEXT("Thread %#x has started."),
  215. GetCurrentThreadId()
  216. );
  217. TraceFunc( "" );
  218. TraceMessage( TEXT(__FILE__),
  219. __LINE__,
  220. __MODULE__,
  221. mtfDLL,
  222. TEXT("DLL: DLL_THREAD_ATTACH - ThreadID = %#x [ g_cLock=%u, g_cObjects=%u ]"),
  223. GetCurrentThreadId(),
  224. g_cLock,
  225. g_cObjects
  226. );
  227. //
  228. // This is necessary here because TraceFunc() defines a variable
  229. // on the stack which isn't available outside the scope of this
  230. // block.
  231. // This function doesn't do anything but clean up after
  232. // TraceFunc().
  233. //
  234. FRETURN( TRUE );
  235. break;
  236. } // case: DLL_THREAD_ATTACH
  237. //////////////////////////////////////////////////////////////////////
  238. // DLL_THREAD_DETACH
  239. //////////////////////////////////////////////////////////////////////
  240. case DLL_THREAD_DETACH:
  241. {
  242. TraceFunc( "" );
  243. TraceMessage( TEXT(__FILE__),
  244. __LINE__,
  245. __MODULE__,
  246. mtfDLL,
  247. TEXT("DLL: DLL_THREAD_DETACH - ThreadID = %#x [ g_cLock=%u, g_cObjects=%u ]"),
  248. GetCurrentThreadId(),
  249. g_cLock,
  250. g_cObjects
  251. );
  252. //
  253. // This is necessary here because TraceFunc() defines a variable
  254. // on the stack which isn't available outside the scope of this
  255. // block.
  256. // This function doesn't do anything but clean up after
  257. // TraceFunc().
  258. //
  259. FRETURN( TRUE );
  260. TraceThreadRundown();
  261. break;
  262. } // case: DLL_THREAD_DETACH
  263. #endif // ! THREAD_OPTIMIZATIONS
  264. default:
  265. {
  266. TraceFunc( "" );
  267. TraceMessage( TEXT(__FILE__),
  268. __LINE__,
  269. __MODULE__,
  270. mtfDLL,
  271. TEXT("DLL: UNKNOWN ENTRANCE REASON - ThreadID = %#x [ g_cLock=%u, g_cObjects=%u ]"),
  272. GetCurrentThreadId(),
  273. g_cLock,
  274. g_cObjects
  275. );
  276. #if defined( THREAD_OPTIMIZATIONS )
  277. Assert( ( ulReasonIn != DLL_THREAD_ATTACH )
  278. && ( ulReasonIn != DLL_THREAD_DETACH ) );
  279. #endif // THREAD_OPTIMIZATIONS
  280. //
  281. // This is necessary here because TraceFunc defines a variable
  282. // on the stack which isn't available outside the scope of this
  283. // block.
  284. // This function doesn't do anything but clean up after TraceFunc.
  285. //
  286. FRETURN( TRUE );
  287. break;
  288. } // default case
  289. } // switch on reason code
  290. return TRUE;
  291. } //*** DllMain()
  292. #endif // ! defined( NO_DLL_MAIN ) && ! defined( ENTRY_PREFIX ) && ! defined( DEBUG )
  293. //////////////////////////////////////////////////////////////////////////////
  294. //++
  295. //
  296. // DllGetClassObject
  297. //
  298. // Description:
  299. // OLE calls this to get the class factory from the DLL.
  300. //
  301. // Arguments:
  302. // rclsidIn
  303. // - Class ID of the object that the class factory should create.
  304. // riidIn
  305. // - Interface of the class factory
  306. // ppvOut
  307. // - The interface pointer to the class factory.
  308. //
  309. // Return Values:
  310. // S_OK - Operation completed successfully.
  311. // E_POINTER - Required output parameter was specified as NULL.
  312. // CLASS_E_CLASSNOTAVAILABLE
  313. // - Class ID not supported by this DLL.
  314. // E_OUTOFMEMORY - Error allocating memory.
  315. // Other HRESULTs to indicate failure.
  316. //
  317. //--
  318. //////////////////////////////////////////////////////////////////////////////
  319. STDAPI
  320. DllGetClassObject(
  321. REFCLSID rclsidIn,
  322. REFIID riidIn,
  323. void ** ppvOut
  324. )
  325. {
  326. TraceFunc( "rclsidIn, riidIn, ppvOut" );
  327. LPCFACTORY lpClassFactory;
  328. HRESULT hr;
  329. int idx;
  330. if ( ppvOut == NULL )
  331. {
  332. hr = E_POINTER;
  333. goto Cleanup;
  334. } // if: bad argument
  335. hr = CLASS_E_CLASSNOTAVAILABLE;
  336. idx = 0;
  337. while( g_DllClasses[ idx ].rclsid )
  338. {
  339. if ( *g_DllClasses[ idx ].rclsid == rclsidIn )
  340. {
  341. TraceMessage( TEXT(__FILE__), __LINE__, __MODULE__, mtfFUNC, L"rclsidIn = %s", g_DllClasses[ idx ].pszName );
  342. hr = S_OK;
  343. break;
  344. } // if: class found
  345. idx++;
  346. } // while: finding class
  347. // Didn't find the class ID.
  348. if ( hr == CLASS_E_CLASSNOTAVAILABLE )
  349. {
  350. TraceMsgGUID( mtfFUNC, "rclsidIn = ", rclsidIn );
  351. #if defined( ENTRY_PREFIX )
  352. //
  353. // See if the MIDL generated code can create it.
  354. //
  355. hr = STHR( __rpc_macro_expand( ENTRY_PREFIX, DllGetClassObject )( rclsidIn, riidIn, ppvOut ) );
  356. #endif // defined( ENTRY_PREFIX )
  357. goto Cleanup;
  358. } // if: class not found
  359. Assert( g_DllClasses[ idx ].pfnCreateInstance != NULL );
  360. lpClassFactory = new CFactory;
  361. if ( lpClassFactory == NULL )
  362. {
  363. hr = E_OUTOFMEMORY;
  364. goto Cleanup;
  365. } // if: memory failure
  366. hr = THR( lpClassFactory->HrInit( g_DllClasses[ idx ].pfnCreateInstance ) );
  367. if ( FAILED( hr ) )
  368. {
  369. TraceDo( lpClassFactory->Release() );
  370. goto Cleanup;
  371. } // if: initialization failed
  372. // Can't safe type.
  373. hr = lpClassFactory->QueryInterface( riidIn, ppvOut );
  374. //
  375. // Release the created instance to counter the AddRef() in Init().
  376. //
  377. ((IUnknown *) lpClassFactory )->Release();
  378. Cleanup:
  379. HRETURN( hr );
  380. } //*** DllGetClassObject()
  381. //////////////////////////////////////////////////////////////////////////////
  382. //++
  383. //
  384. // DllRegisterServer
  385. //
  386. // Description:
  387. // OLE's register entry point.
  388. //
  389. // Argument:
  390. // None.
  391. //
  392. // Return Values:
  393. // S_OK - Operation completed successfully.
  394. // Other HRESULTs to indicate failure.
  395. //
  396. //--
  397. //////////////////////////////////////////////////////////////////////////////
  398. STDAPI
  399. DllRegisterServer( void )
  400. {
  401. HRESULT hr;
  402. TraceFunc( "" );
  403. hr = THR( HrRegisterDll( TRUE ) );
  404. #if defined( ENTRY_PREFIX )
  405. if ( SUCCEEDED( hr ) )
  406. {
  407. hr = THR( __rpc_macro_expand( ENTRY_PREFIX, DllRegisterServer )() );
  408. } // if: register proxy/stub
  409. #endif // defined( ENTRY_PREFIX )
  410. HRETURN( hr );
  411. } //*** DllRegisterServer()
  412. //////////////////////////////////////////////////////////////////////////////
  413. //++
  414. //
  415. // DllUnregisterServer
  416. //
  417. // Description:
  418. // OLE's unregister entry point.
  419. //
  420. // Arguments:
  421. // None.
  422. //
  423. // Return Values:
  424. // S_OK - Operation completed successful.
  425. // Other HRESULTs to indicate failure.
  426. //
  427. //--
  428. //////////////////////////////////////////////////////////////////////////////
  429. STDAPI
  430. DllUnregisterServer( void )
  431. {
  432. TraceFunc( "" );
  433. HRESULT hr;
  434. hr = THR( HrRegisterDll( FALSE ) );
  435. #if defined( ENTRY_PREFIX )
  436. if ( SUCCEEDED( hr ) )
  437. {
  438. hr = THR( __rpc_macro_expand( ENTRY_PREFIX, DllUnregisterServer )() );
  439. } // if: unregister proxy/stub
  440. #endif // defined( ENTRY_PREFIX )
  441. HRETURN( hr );
  442. } //*** DllUnregisterServer()
  443. //////////////////////////////////////////////////////////////////////////////
  444. //++
  445. //
  446. // DllCanUnloadNow
  447. //
  448. // Description:
  449. // OLE calls this entry point to see if it can unload the DLL.
  450. //
  451. // Arguments:
  452. // None.
  453. //
  454. // Return Values:
  455. // S_OK - Can unload the DLL.
  456. // S_FALSE - Can not unload the DLL.
  457. //
  458. //--
  459. //////////////////////////////////////////////////////////////////////////////
  460. STDAPI
  461. DllCanUnloadNow( void )
  462. {
  463. TraceFunc( "" );
  464. HRESULT hr = S_OK;
  465. if ( g_cLock || g_cObjects )
  466. {
  467. TraceMsg( mtfDLL, "DLL: Can't unload - g_cLock=%u, g_cObjects=%u", g_cLock, g_cObjects );
  468. hr = S_FALSE;
  469. } // if: any object or locks
  470. #if defined( ENTRY_PREFIX )
  471. else
  472. {
  473. //
  474. // Check with the MIDL generated proxy/stubs.
  475. //
  476. hr = STHR( __rpc_macro_expand( ENTRY_PREFIX, DllCanUnloadNow )() );
  477. }
  478. #endif
  479. HRETURN( hr );
  480. } //*** DLlCanUnloadNow()
  481. //////////////////////////////////////////////////////////////////////////////
  482. //++
  483. //
  484. // HrCoCreateInternalInstance
  485. //
  486. // Description:
  487. // Mimic CoCreateInstance() except that it looks into the DLL table
  488. // to see if we can shortcut the CoCreate with a simple CreateInstance
  489. // call.
  490. //
  491. // Arguments: (matches CoCreateInstance)
  492. // rclsidIn - Class identifier (CLSID) of the object
  493. // pUnkOuterIn - Pointer to controlling IUnknown
  494. // dwClsContext - Context for running executable code
  495. // riidIn - Reference to the identifier of the interface
  496. // ppvOut - Address of output variable that receives
  497. //
  498. // Return Values:
  499. // S_OK - Success.
  500. // E_OUTOFMEMORY - Out of memory.
  501. // other HRESULT values
  502. //
  503. //////////////////////////////////////////////////////////////////////////////
  504. HRESULT
  505. HrCoCreateInternalInstance(
  506. REFCLSID rclsidIn,
  507. LPUNKNOWN pUnkOuterIn,
  508. DWORD dwClsContextIn,
  509. REFIID riidIn,
  510. LPVOID * ppvOut
  511. )
  512. {
  513. TraceFunc( "" );
  514. Assert( ppvOut != NULL );
  515. HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
  516. //
  517. // Limit simple CoCreate() only works to INPROC and non-aggregatable objects.
  518. //
  519. if ( ( dwClsContextIn & CLSCTX_INPROC_HANDLER ) // inproc only
  520. && ( pUnkOuterIn == NULL ) // no aggregation
  521. )
  522. {
  523. int idx;
  524. //
  525. // Try to find the class in our DLL table.
  526. //
  527. for( idx = 0; g_DllClasses[ idx ].rclsid != NULL; idx++ )
  528. {
  529. if ( *g_DllClasses[ idx ].rclsid == rclsidIn )
  530. {
  531. LPUNKNOWN punk;
  532. Assert( g_DllClasses[ idx ].pfnCreateInstance != NULL );
  533. hr = THR( g_DllClasses[ idx ].pfnCreateInstance( &punk ) );
  534. if ( SUCCEEDED( hr ) )
  535. {
  536. // Can't safe type.
  537. hr = THR( punk->QueryInterface( riidIn, ppvOut ) );
  538. punk->Release();
  539. } // if: got object
  540. break; // bail loop
  541. } // if: class found
  542. } // for: finding class
  543. } // if: simple CoCreate()
  544. //
  545. // If not found or asking for something we do not support,
  546. // use the COM version.
  547. //
  548. if ( hr == CLASS_E_CLASSNOTAVAILABLE )
  549. {
  550. //
  551. // Try it the old fashion way...
  552. //
  553. hr = THR( CoCreateInstance( rclsidIn, pUnkOuterIn, dwClsContextIn, riidIn, ppvOut ) );
  554. } // if: class not found
  555. HRETURN( hr );
  556. } //*** HrClusCoCreateInstance()
  557. //
  558. // TODO: gpease 27-NOV-1999
  559. // While perusing around the MIDL SDK, I foud that
  560. // RPC creates the same type of class table we do. Maybe
  561. // we can leverage the MIDL code to create our objects(??).
  562. //