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