mirror of https://github.com/tongzx/nt5src
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
649 lines
18 KiB
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) 1999-2001 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.
|
|
// -- NO_THREAD_OPTIMIZATIONS
|
|
// If defined, disable the thread notification calls when a thread
|
|
// starts up or goes away.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// DLL Globals
|
|
//
|
|
HINSTANCE g_hInstance = NULL;
|
|
LONG g_cObjects = 0;
|
|
LONG g_cLock = 0;
|
|
TCHAR 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, ARRAYSIZE( g_rgTraceControlGuidList ), TRUE );
|
|
#else // ! DEBUG_SW_TRACING_ENABLED
|
|
TraceInitializeProcess( TRUE );
|
|
#endif // DEBUG_SW_TRACING_ENABLED
|
|
|
|
TraceFunc( "" );
|
|
TraceMessage( TEXT(__FILE__),
|
|
__LINE__,
|
|
__MODULE__,
|
|
mtfDLL,
|
|
TEXT("DLL: DLL_PROCESS_ATTACH - ThreadID = %#x"),
|
|
GetCurrentThreadId()
|
|
);
|
|
|
|
g_hInstance = hInstIn;
|
|
|
|
#if defined( ENTRY_PREFIX )
|
|
hProxyDll = g_hInstance;
|
|
#endif // ENTRY_PREFIX
|
|
|
|
GetModuleFileName( g_hInstance, g_szDllFilename, ARRAYSIZE( g_szDllFilename ) );
|
|
|
|
//
|
|
// 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
|
|
|
|
//
|
|
// 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,
|
|
TEXT("DLL: DLL_PROCESS_DETACH - ThreadID = %#x [ g_cLock=%u, g_cObjects=%u ]"),
|
|
GetCurrentThreadId(),
|
|
g_cLock,
|
|
g_cObjects
|
|
);
|
|
|
|
//
|
|
// 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, ARRAYSIZE( 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,
|
|
TEXT("Thread %#x has started."),
|
|
GetCurrentThreadId()
|
|
);
|
|
TraceFunc( "" );
|
|
TraceMessage( TEXT(__FILE__),
|
|
__LINE__,
|
|
__MODULE__,
|
|
mtfDLL,
|
|
TEXT("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,
|
|
TEXT("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,
|
|
TEXT("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 )
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// 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" );
|
|
|
|
LPCFACTORY lpClassFactory;
|
|
HRESULT hr;
|
|
int idx;
|
|
|
|
if ( ppvOut == NULL )
|
|
{
|
|
hr = E_POINTER;
|
|
goto Cleanup;
|
|
} // if: bad argument
|
|
|
|
hr = CLASS_E_CLASSNOTAVAILABLE;
|
|
idx = 0;
|
|
while( g_DllClasses[ idx ].rclsid )
|
|
{
|
|
if ( *g_DllClasses[ idx ].rclsid == rclsidIn )
|
|
{
|
|
TraceMessage( TEXT(__FILE__), __LINE__, __MODULE__, mtfFUNC, L"rclsidIn = %s", g_DllClasses[ idx ].pszName );
|
|
hr = S_OK;
|
|
break;
|
|
|
|
} // if: class found
|
|
|
|
idx++;
|
|
|
|
} // 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( g_DllClasses[ idx ].pfnCreateInstance != NULL );
|
|
|
|
lpClassFactory = new CFactory;
|
|
if ( lpClassFactory == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
|
|
} // if: memory failure
|
|
|
|
hr = THR( lpClassFactory->HrInit( g_DllClasses[ idx ].pfnCreateInstance ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
TraceDo( lpClassFactory->Release() );
|
|
goto Cleanup;
|
|
|
|
} // if: initialization failed
|
|
|
|
// Can't safe type.
|
|
hr = lpClassFactory->QueryInterface( riidIn, ppvOut );
|
|
//
|
|
// Release the created instance to counter the AddRef() in Init().
|
|
//
|
|
((IUnknown *) lpClassFactory )->Release();
|
|
|
|
Cleanup:
|
|
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 )
|
|
{
|
|
HRESULT hr;
|
|
|
|
TraceFunc( "" );
|
|
|
|
hr = THR( HrRegisterDll( TRUE ) );
|
|
|
|
#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( HrRegisterDll( FALSE ) );
|
|
|
|
#if defined( ENTRY_PREFIX )
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
hr = THR( __rpc_macro_expand( ENTRY_PREFIX, DllUnregisterServer )() );
|
|
} // if: unregister proxy/stub
|
|
#endif // defined( ENTRY_PREFIX )
|
|
|
|
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 || g_cObjects )
|
|
{
|
|
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 = CLASS_E_CLASSNOTAVAILABLE;
|
|
|
|
//
|
|
// Limit simple CoCreate() only works to INPROC and non-aggregatable objects.
|
|
//
|
|
|
|
if ( ( dwClsContextIn & CLSCTX_INPROC_HANDLER ) // inproc only
|
|
&& ( pUnkOuterIn == NULL ) // no aggregation
|
|
)
|
|
{
|
|
int idx;
|
|
|
|
//
|
|
// Try to find the class in our DLL table.
|
|
//
|
|
for( idx = 0; g_DllClasses[ idx ].rclsid != NULL; idx++ )
|
|
{
|
|
if ( *g_DllClasses[ idx ].rclsid == rclsidIn )
|
|
{
|
|
LPUNKNOWN punk;
|
|
Assert( g_DllClasses[ idx ].pfnCreateInstance != NULL );
|
|
|
|
hr = THR( g_DllClasses[ idx ].pfnCreateInstance( &punk ) );
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
// Can't safe type.
|
|
hr = THR( punk->QueryInterface( riidIn, ppvOut ) );
|
|
punk->Release();
|
|
} // if: got object
|
|
|
|
break; // bail loop
|
|
|
|
} // if: class found
|
|
|
|
} // for: finding 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 = THR( CoCreateInstance( rclsidIn, pUnkOuterIn, dwClsContextIn, riidIn, ppvOut ) );
|
|
|
|
} // if: class not found
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** HrClusCoCreateInstance()
|
|
|
|
|
|
//
|
|
// 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(??).
|
|
//
|