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

//////////////////////////////////////////////////////////////////////////////
//
// 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