|
|
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1999-2002 Microsoft Corporation
//
// Module Name:
// DllSrc.cpp
//
// Description:
// DLL services/entry points.
//
// Maintained By:
// David Potter (DavidP) 19-MAR-2001
// Geoffrey Pease (GPease) 18-OCT-1999
//
// Notes:
// Switches:
// - ENTRY_PREFIX
// If defined, include proxy/stub code into the DLL that is
// generated by the MIDL compiler.
// - USE_FUSION
// If defined, initialize and uninitialize Fusion on process
// attach and detach respectively. The constant IDR_MANIFEST
// must be defined with a value that represents the resource ID
// for the manifest resource.
// - NO_DLL_MAIN
// If defined, don't implement DllMain.
// - DEBUG_SW_TRACING_ENABLED
// If defined, initialize and uninitialize software tracing on
// process attach and detach respectively.
// - THREAD_OPTIMIZATIONS
// If defined, disable the thread notification calls when a thread
// starts up or goes away.
// - IMPLEMENT_COM_SERVER_DLL
// If defined, defines entry points necessary for COM servers.
//
//////////////////////////////////////////////////////////////////////////////
//
// DLL Globals
//
HINSTANCE g_hInstance = NULL; LONG g_cObjects = 0; LONG g_cLock = 0; WCHAR g_szDllFilename[ MAX_PATH ] = { 0 };
LPVOID g_GlobalMemoryList = NULL; // Global memory tracking list
#if defined( ENTRY_PREFIX )
extern "C" { extern HINSTANCE hProxyDll; } #endif
//
// Macros to generate RPC entry points
//
#define __rpc_macro_expand2( a, b ) a##b
#define __rpc_macro_expand( a, b ) __rpc_macro_expand2( a, b )
#if ! defined( NO_DLL_MAIN ) || defined( ENTRY_PREFIX ) || defined( DEBUG )
//////////////////////////////////////////////////////////////////////////////
//++
//
// DllMain
//
// Description:
// Dll entry point.
//
// Arguments:
// hInstIn - DLL instance handle.
// ulReasonIn - DLL reason code for entrance.
// lpReservedIn - Not used.
//
// Return Values:
// TRUE
//
//--
//////////////////////////////////////////////////////////////////////////////
BOOL WINAPI DllMain( HINSTANCE hInstIn, ULONG ulReasonIn, LPVOID // lpReservedIn
) { //
// KB: THREAD_OPTIMIZATIONS gpease 19-OCT-1999
//
// By defining this you can prevent the linker
// from calling your DllEntry for every new thread.
// This makes creating new threads significantly
// faster if every DLL in a process does it.
// Unfortunately, not all DLLs do this.
//
// In CHKed/DEBUG, we keep this on for memory
// tracking.
//
#if ! defined( DEBUG )
#define THREAD_OPTIMIZATIONS
#endif // DEBUG
switch( ulReasonIn ) { //////////////////////////////////////////////////////////////////////
// DLL_PROCESS_ATTACH
//////////////////////////////////////////////////////////////////////
case DLL_PROCESS_ATTACH: { #if defined( DEBUG_SW_TRACING_ENABLED )
TraceInitializeProcess( g_rgTraceControlGuidList, RTL_NUMBER_OF( g_rgTraceControlGuidList ), TRUE ); #else // ! DEBUG_SW_TRACING_ENABLED
TraceInitializeProcess( TRUE ); #endif // DEBUG_SW_TRACING_ENABLED
TraceFunc( "" ); TraceMessage( TEXT(__FILE__) , __LINE__ , __MODULE__ , mtfDLL , L"DLL: DLL_PROCESS_ATTACH - ThreadID = %#x" , GetCurrentThreadId() );
g_hInstance = hInstIn;
#if defined( ENTRY_PREFIX )
hProxyDll = g_hInstance; #endif // ENTRY_PREFIX
{ BOOL fResult = GetModuleFileName( g_hInstance, g_szDllFilename, RTL_NUMBER_OF( g_szDllFilename ) ); if ( ! fResult ) { TW32MSG( GetLastError(), "GetModuleFileName()" ); } }
//
// Create a global memory list so that memory allocated by one
// thread and handed to another can be tracked without causing
// unnecessary trace messages.
//
TraceCreateMemoryList( g_GlobalMemoryList );
#if defined( THREAD_OPTIMIZATIONS )
{ //
// Disable thread library calls so that we don't get called
// on thread attach and detach.
//
BOOL fResult = DisableThreadLibraryCalls( g_hInstance ); if ( ! fResult ) { TW32MSG( GetLastError(), "DisableThreadLibraryCalls()" ); } } #endif // THREAD_OPTIMIZATIONS
#if defined( USE_FUSION )
{ //
// Initialize Fusion.
//
// The value of IDR_MANIFEST in the call to
// SHFusionInitializeFromModuleID() must match the value specified in the
// sources file for SXS_MANIFEST_RESOURCE_ID.
//
BOOL fResult = SHFusionInitializeFromModuleID( hInstIn, IDR_MANIFEST ); if ( ! fResult ) { TW32MSG( GetLastError(), "SHFusionInitializeFromModuleID()" ); } } #endif // USE_FUSION
#if defined( DO_MODULE_INIT )
THR( HrLocalProcessInit() ); #endif
//
// This is necessary here because TraceFunc() defines a variable
// on the stack which isn't available outside the scope of this
// block.
// This function doesn't do anything but clean up after
// TraceFunc().
//
FRETURN( TRUE );
break; } // case: DLL_PROCESS_ATTACH
//////////////////////////////////////////////////////////////////////
// DLL_PROCESS_DETACH
//////////////////////////////////////////////////////////////////////
case DLL_PROCESS_DETACH: { TraceFunc( "" ); TraceMessage( TEXT(__FILE__) , __LINE__ , __MODULE__ , mtfDLL , L"DLL: DLL_PROCESS_DETACH - ThreadID = %#x [ g_cLock=%u, g_cObjects=%u ]" , GetCurrentThreadId() , g_cLock , g_cObjects );
#if defined( DO_MODULE_UNINIT )
THR( HrLocalProcessUninit() ); #endif
//
// Cleanup the global memory list used to track memory allocated
// in one thread and then handed to another.
//
TraceTerminateMemoryList( g_GlobalMemoryList );
//
// This is necessary here because TraceFunc() defines a variable
// on the stack which isn't available outside the scope of this
// block.
// This function doesn't do anything but clean up after
// TraceFunc().
//
FRETURN( TRUE );
#if defined( DEBUG_SW_TRACING_ENABLED )
TraceTerminateProcess( g_rgTraceControlGuidList, RTL_NUMBER_OF( g_rgTraceControlGuidList ) ); #else // ! DEBUG_SW_TRACING_ENABLED
TraceTerminateProcess(); #endif // DEBUG_SW_TRACING_ENABLED
#if defined( USE_FUSION )
SHFusionUninitialize(); #endif // USE_FUSION
break; } // case: DLL_PROCESS_DETACH
#if ! defined( THREAD_OPTIMIZATIONS )
//////////////////////////////////////////////////////////////////////
// DLL_THREAD_ATTACH
//////////////////////////////////////////////////////////////////////
case DLL_THREAD_ATTACH: { TraceInitializeThread( NULL ); TraceMessage( TEXT(__FILE__) , __LINE__ , __MODULE__ , mtfDLL , L"Thread %#x has started." , GetCurrentThreadId() ); TraceFunc( "" ); TraceMessage( TEXT(__FILE__) , __LINE__ , __MODULE__ , mtfDLL , L"DLL: DLL_THREAD_ATTACH - ThreadID = %#x [ g_cLock=%u, g_cObjects=%u ]" , GetCurrentThreadId() , g_cLock , g_cObjects );
//
// This is necessary here because TraceFunc() defines a variable
// on the stack which isn't available outside the scope of this
// block.
// This function doesn't do anything but clean up after
// TraceFunc().
//
FRETURN( TRUE );
break; } // case: DLL_THREAD_ATTACH
//////////////////////////////////////////////////////////////////////
// DLL_THREAD_DETACH
//////////////////////////////////////////////////////////////////////
case DLL_THREAD_DETACH: { TraceFunc( "" ); TraceMessage( TEXT(__FILE__) , __LINE__ , __MODULE__ , mtfDLL , L"DLL: DLL_THREAD_DETACH - ThreadID = %#x [ g_cLock=%u, g_cObjects=%u ]" , GetCurrentThreadId() , g_cLock , g_cObjects );
//
// This is necessary here because TraceFunc() defines a variable
// on the stack which isn't available outside the scope of this
// block.
// This function doesn't do anything but clean up after
// TraceFunc().
//
FRETURN( TRUE );
TraceThreadRundown();
break; } // case: DLL_THREAD_DETACH
#endif // ! THREAD_OPTIMIZATIONS
default: { TraceFunc( "" ); TraceMessage( TEXT(__FILE__) , __LINE__ , __MODULE__ , mtfDLL , L"DLL: UNKNOWN ENTRANCE REASON - ThreadID = %#x [ g_cLock=%u, g_cObjects=%u ]" , GetCurrentThreadId() , g_cLock , g_cObjects );
#if defined( THREAD_OPTIMIZATIONS )
Assert( ( ulReasonIn != DLL_THREAD_ATTACH ) && ( ulReasonIn != DLL_THREAD_DETACH ) ); #endif // THREAD_OPTIMIZATIONS
//
// This is necessary here because TraceFunc defines a variable
// on the stack which isn't available outside the scope of this
// block.
// This function doesn't do anything but clean up after TraceFunc.
//
FRETURN( TRUE );
break; } // default case
} // switch on reason code
return TRUE;
} //*** DllMain
#endif // ! defined( NO_DLL_MAIN ) && ! defined( ENTRY_PREFIX ) && ! defined( DEBUG )
#ifdef IMPLEMENT_COM_SERVER_DLL
//
// The following functions are only required by COM server DLLs.
//
//////////////////////////////////////////////////////////////////////////////
//++
//
// DllGetClassObject
//
// Description:
// OLE calls this to get the class factory from the DLL.
//
// Arguments:
// rclsidIn
// - Class ID of the object that the class factory should create.
// riidIn
// - Interface of the class factory
// ppvOut
// - The interface pointer to the class factory.
//
// Return Values:
// S_OK - Operation completed successfully.
// E_POINTER - Required output parameter was specified as NULL.
// CLASS_E_CLASSNOTAVAILABLE
// - Class ID not supported by this DLL.
// E_OUTOFMEMORY - Error allocating memory.
// Other HRESULTs to indicate failure.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDAPI DllGetClassObject( REFCLSID rclsidIn, REFIID riidIn, void ** ppvOut ) { TraceFunc( "rclsidIn, riidIn, ppvOut" );
CFactory * pClassFactory = NULL; HRESULT hr = CLASS_E_CLASSNOTAVAILABLE; const SPublicClassInfo * pClassInfo = g_DllPublicClasses;
if ( ppvOut == NULL ) { hr = THR( E_POINTER ); goto Cleanup; } // if: bad argument
*ppvOut = NULL;
//
// Search the public class table for a matching CLSID.
//
while ( pClassInfo->pClassID != NULL ) { if ( *( pClassInfo->pClassID ) == rclsidIn ) { TraceMessage( TEXT(__FILE__), __LINE__, __MODULE__, mtfFUNC, L"rclsidIn = %s", pClassInfo->pcszName ); hr = S_OK; break;
} // if: class found
++pClassInfo; } // while: finding class
// Didn't find the class ID.
if ( hr == CLASS_E_CLASSNOTAVAILABLE ) { TraceMsgGUID( mtfFUNC, "rclsidIn = ", rclsidIn ); #if defined( ENTRY_PREFIX )
//
// See if the MIDL generated code can create it.
//
hr = STHR( __rpc_macro_expand( ENTRY_PREFIX, DllGetClassObject )( rclsidIn, riidIn, ppvOut ) ); #endif // defined( ENTRY_PREFIX )
goto Cleanup; } // if: class not found
Assert( pClassInfo->pfnCreateInstance != NULL );
hr = THR( CFactory::S_HrCreateInstance( pClassInfo->pfnCreateInstance, &pClassFactory ) ); if ( FAILED( hr ) ) { goto Cleanup;
} // if: initialization failed
// Can't safe type.
hr = pClassFactory->QueryInterface( riidIn, ppvOut );
Cleanup:
if ( pClassFactory != NULL ) { pClassFactory->Release(); }
HRETURN( hr );
} //*** DllGetClassObject
//////////////////////////////////////////////////////////////////////////////
//++
//
// DllRegisterServer
//
// Description:
// OLE's register entry point.
//
// Argument:
// None.
//
// Return Values:
// S_OK - Operation completed successfully.
// Other HRESULTs to indicate failure.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDAPI DllRegisterServer( void ) { TraceFunc( "" );
HRESULT hr;
hr = THR( HrRegisterDll() );
#if defined( ENTRY_PREFIX )
if ( SUCCEEDED( hr ) ) { hr = THR( __rpc_macro_expand( ENTRY_PREFIX, DllRegisterServer )() ); } // if: register proxy/stub
#endif // defined( ENTRY_PREFIX )
HRETURN( hr );
} //*** DllRegisterServer
//////////////////////////////////////////////////////////////////////////////
//++
//
// DllUnregisterServer
//
// Description:
// OLE's unregister entry point.
//
// Arguments:
// None.
//
// Return Values:
// S_OK - Operation completed successful.
// Other HRESULTs to indicate failure.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDAPI DllUnregisterServer( void ) { TraceFunc( "" );
HRESULT hr;
hr = THR( HrUnregisterDll() );
#if defined( ENTRY_PREFIX )
if ( SUCCEEDED( hr ) ) { hr = THR( __rpc_macro_expand( ENTRY_PREFIX, DllUnregisterServer )() ); } // if: unregister proxy/stub
#endif // defined( ENTRY_PREFIX )
if ( hr == HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) ) { hr = S_OK; } HRETURN( hr );
} //*** DllUnregisterServer
//////////////////////////////////////////////////////////////////////////////
//++
//
// DllCanUnloadNow
//
// Description:
// OLE calls this entry point to see if it can unload the DLL.
//
// Arguments:
// None.
//
// Return Values:
// S_OK - Can unload the DLL.
// S_FALSE - Can not unload the DLL.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDAPI DllCanUnloadNow( void ) { TraceFunc( "" );
HRESULT hr = S_OK;
if ( ( g_cLock != 0 ) || ( g_cObjects != 0 ) ) { TraceMsg( mtfDLL, "DLL: Can't unload - g_cLock=%u, g_cObjects=%u", g_cLock, g_cObjects ); hr = S_FALSE;
} // if: any object or locks
#if defined( ENTRY_PREFIX )
else { //
// Check with the MIDL generated proxy/stubs.
//
hr = STHR( __rpc_macro_expand( ENTRY_PREFIX, DllCanUnloadNow )() ); } #endif
HRETURN( hr );
} //*** DllCanUnloadNow
//////////////////////////////////////////////////////////////////////////////
//++
//
// HrCoCreateInternalInstance
//
// Description:
// Mimic CoCreateInstance() except that it looks into the DLL table
// to see if we can shortcut the CoCreate with a simple CreateInstance
// call.
//
// Arguments: (matches CoCreateInstance)
// rclsidIn - Class identifier (CLSID) of the object
// pUnkOuterIn - Pointer to controlling IUnknown
// dwClsContext - Context for running executable code
// riidIn - Reference to the identifier of the interface
// ppvOut - Address of output variable that receives
//
// Return Values:
// S_OK - Success.
// E_OUTOFMEMORY - Out of memory.
// other HRESULT values
//
//////////////////////////////////////////////////////////////////////////////
HRESULT HrCoCreateInternalInstance( REFCLSID rclsidIn, LPUNKNOWN pUnkOuterIn, DWORD dwClsContextIn, REFIID riidIn, LPVOID * ppvOut ) { TraceFunc( "" );
Assert( ppvOut != NULL );
HRESULT hr = S_OK; MULTI_QI mqi;
mqi.hr = S_OK; mqi.pItf = NULL; mqi.pIID = &riidIn;
hr = HrCoCreateInternalInstanceEx( rclsidIn, pUnkOuterIn, dwClsContextIn, NULL, 1, &mqi ); *ppvOut = mqi.pItf; HRETURN( hr );
} //*** HrCoCreateInternalInstance
//////////////////////////////////////////////////////////////////////////////
//++
//
// HrCoCreateInternalInstanceEx
//
// Description:
// Mimic CoCreateInstanceEx() except that it looks into the DLL table
// to see if we can shortcut the CoCreate with a simple CreateInstance
// call.
//
// Arguments: (matches CoCreateInstanceEx)
// rclsidIn - Class identifier (CLSID) of the object
// pUnkOuterIn - Pointer to controlling IUnknown
// dwClsContext - Context for running executable code
// pServerInfoIn - Object location; can be NULL
// cMultiQIsIn - Number of MULTI_QI structs in prgmqiInOut array
// prgmqiInOut - Array to hold queried interfaces on object
//
// Return Values:
// S_OK
// Success.
//
// E_OUTOFMEMORY
// Out of memory.
//
// E_NOINTERFACE
// Object created, but supports no requested interfaces.
//
// CO_S_NOTALLINTERFACES
// Object created and supports some, but not all, requested
// interfaces.
//
// CLASS_E_CLASSNOTAVAILABLE
// Unknown class ID.
//
// Other HRESULTs.
//
//////////////////////////////////////////////////////////////////////////////
HRESULT HrCoCreateInternalInstanceEx( REFCLSID rclsidIn, LPUNKNOWN pUnkOuterIn, DWORD dwClsContextIn, COSERVERINFO * pServerInfoIn, ULONG cMultiQIsIn, MULTI_QI * prgmqiInOut ) { TraceFunc( "" );
Assert( ( prgmqiInOut != NULL ) || ( cMultiQIsIn == 0 ) );
HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
//
// Limit simple CoCreate() only works to INPROC and non-aggregatable objects.
//
if ( ( dwClsContextIn & ( CLSCTX_INPROC_HANDLER | CLSCTX_INPROC_SERVER ) ) // inproc only
&& ( pServerInfoIn == NULL ) // local machine only
&& ( pUnkOuterIn == NULL ) // no aggregation
) { PFN_FACTORY_METHOD pfnCreateInstance = NULL; const SPrivateClassInfo * pPrivateInfo = g_PrivateClasses; const SPublicClassInfo * pPublicInfo = g_DllPublicClasses; //
// Look up the class ID in the private class table first.
//
while ( ( pfnCreateInstance == NULL ) && ( pPrivateInfo->pClassID != NULL ) ) { if ( *( pPrivateInfo->pClassID ) == rclsidIn ) { pfnCreateInstance = pPrivateInfo->pfnCreateInstance; } ++pPrivateInfo; } //
// If that didn't find it, try the public table.
//
while ( ( pfnCreateInstance == NULL ) && ( pPublicInfo->pClassID != NULL ) ) { if ( *( pPublicInfo->pClassID ) == rclsidIn ) { pfnCreateInstance = pPublicInfo->pfnCreateInstance; } ++pPublicInfo; }
//
// If either found a match, use its factory method to create an object.
//
if ( pfnCreateInstance != NULL ) { IUnknown * punkInstance = NULL; ULONG idxInterface = 0; BOOL fQISucceeded = FALSE; BOOL fQIFailed = FALSE;
hr = THR( ( *pfnCreateInstance )( &punkInstance ) ); if ( FAILED( hr ) ) { goto Cleanup; } //
// Query for each requested interface.
//
while ( idxInterface < cMultiQIsIn ) { MULTI_QI * pmqi = prgmqiInOut + idxInterface;
//
// No THR around the following QI because client might expect some failures.
//
pmqi->hr = punkInstance->QueryInterface( *( pmqi->pIID ), reinterpret_cast< void** >( &( pmqi->pItf ) ) ); if ( SUCCEEDED( pmqi->hr ) ) { fQISucceeded = TRUE; } else { fQIFailed = TRUE; } idxInterface += 1; } // for each requested interface
//
// Mimic return values from CoCreateInstanceEx.
//
if ( fQIFailed ) { if ( fQISucceeded ) { // At least one QI succeeded, and at least one failed.
hr = CO_S_NOTALLINTERFACES; } else { // At least one QI failed, and none succeeded.
hr = E_NOINTERFACE; } } // Otherwise, leave hr as is.
punkInstance->Release(); } // if: creating internal class
} // if: simple CoCreate()
//
// If not found or asking for something we do not support,
// use the COM version.
//
if ( hr == CLASS_E_CLASSNOTAVAILABLE ) { //
// Try it the old fashion way...
//
hr = STHR( CoCreateInstanceEx( rclsidIn, pUnkOuterIn, dwClsContextIn, pServerInfoIn, cMultiQIsIn, prgmqiInOut ) );
} // if: class not found
Cleanup:
HRETURN( hr );
} //*** HrCoCreateInternalInstanceEx
//
// TODO: gpease 27-NOV-1999
// While perusing around the MIDL SDK, I foud that
// RPC creates the same type of class table we do. Maybe
// we can leverage the MIDL code to create our objects(??).
//
#endif // IMPLEMENT_COM_SERVER_DLL
|