/*++ Copyright (c) 1995-1997 Microsoft Corporation Module Name : wam.cpp Abstract: This module implements the exported routines for WAM object Author: David Kaplan ( DaveK ) 26-Feb-1997 Environment: User Mode - Win32 Project: Wam DLL --*/ // // Following are the notes from the original MSDEV generated file // Note: Proxy/Stub Information // To merge the proxy/stub code into the object DLL, add the file // dlldatax.c to the project. Make sure precompiled headers // are turned off for this file, and add _MERGE_PROXYSTUB to the // defines for the project. // // If you are not running WinNT4.0 or Win95 with DCOM, then you // need to remove the following define from dlldatax.c // #define _WIN32_WINNT 0x0400 // // Further, if you are running MIDL without /Oicf switch, you also // need to remove the following define from dlldatax.c. // #define USE_STUBLESS_PROXY // // Modify the custom build rule for Wam.idl by adding the following // files to the Outputs. // Wam_p.c // dlldata.c // To build a separate proxy/stub DLL, // run nmake -f Wamps.mk in the project directory. // BEGIN mods // Post-wizard mods appear within BEGIN mods ... END mods // END mods #include #include "pudebug.h" #include "resource.h" #include "initguid.h" #include "wamobj.hxx" #include "Wam_i.c" // BEGIN mods #include #include "setable.hxx" #include "wamccf.hxx" #include #ifdef _ATL_STATIC_REGISTRY #include #include #endif #include // END mods /************************************************************ * Global Variables ************************************************************/ const CHAR g_pszModuleName[] = "WAM"; const CHAR g_pszWamRegLocation[] = "System\\CurrentControlSet\\Services\\W3Svc\\WAM"; #ifdef _MERGE_PROXYSTUB extern "C" HINSTANCE hProxyDll; #endif CWamModule _Module; BEGIN_OBJECT_MAP(ObjectMap) OBJECT_ENTRY(CLSID_Wam, WAM) END_OBJECT_MAP() // BEGIN mods WAM_CCF_MODULE _WAMCCFModule; // Custom Class Factory Module DECLARE_PLATFORM_TYPE(); #ifndef _NO_TRACING_ #include DEFINE_GUID(IisWamObjectGuid, 0x784d8909, 0xaa8c, 0x11d2, 0x92, 0x5e, 0x00, 0xc0, 0x4f, 0x72, 0xd9, 0x0e); #else DECLARE_DEBUG_VARIABLE(); #endif DECLARE_DEBUG_PRINTS_OBJECT(); BOOL g_fGlobalInitDone = FALSE; CRITICAL_SECTION g_csGlobalLock; BOOL g_fEnableTryExcept = TRUE; // WAM needs to ensure that IISRTL is fully initialized. This happens // automatically in infocomm when running in-process, but the following // hack is needed for OOP apps. InitializeIISRTL and TerminateIISRTL // use an internal refcount, so tying the initialization/termination to // _Module.GetLockCount works. LONG CWamModule::Lock() { IF_DEBUG( WAM_REFCOUNTS) DBGPRINTF((DBG_CONTEXT, "WamModule::Lock(%d)\n", GetLockCount())); InitializeIISRTL(); AtqInitialize(0); return CComModule::Lock(); } LONG CWamModule::Unlock() { IF_DEBUG( WAM_REFCOUNTS) DBGPRINTF((DBG_CONTEXT, "WamModule::Unlock(%d)\n", GetLockCount())); AtqTerminate(); TerminateIISRTL(); return CComModule::Unlock(); } /************************************************************ * Local Functions ************************************************************/ static void WAMLoadNTApis(VOID); static void WAMUnloadNTApis(VOID); PFN_INTERLOCKED_COMPARE_EXCHANGE g_pfnInterlockedCompareExchange = NULL; // END mods ///////////////////////////////////////////////////////////////////////////// // DLL Entry Point extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { DWORD dwErr = NO_ERROR; #ifdef _MERGE_PROXYSTUB if (!PrxDllMain(hInstance, dwReason, lpReserved)) return FALSE; #endif if (dwReason == DLL_PROCESS_ATTACH) { // // BEGIN mods // #ifdef _NO_TRACING_ CREATE_DEBUG_PRINT_OBJECT( g_pszModuleName); #else CREATE_DEBUG_PRINT_OBJECT( g_pszModuleName, IisWamObjectGuid); #endif if ( !VALID_DEBUG_PRINT_OBJECT()) { return ( FALSE); } (VOID)IISGetPlatformType(); #ifdef _NO_TRACING_ LOAD_DEBUG_FLAGS_FROM_REG_STR( g_pszWamRegLocation, (DEBUG_ERROR | DEBUG_IID) ); #endif INITIALIZE_PLATFORM_TYPE(); DBG_ASSERT( IISIsValidPlatform()); INITIALIZE_CRITICAL_SECTION( &g_csGlobalLock); WAMLoadNTApis(); DBG_REQUIRE( WAM_EXEC_INFO::InitClass()); dwErr = InitializeHseExtensions(); if ( NOERROR == dwErr ) { IF_DEBUG( INIT_CLEAN) { DBGPRINTF((DBG_CONTEXT, " InitializeHseExtensions succeeded.\n" ) ); } // From ATL generated _Module.Init(ObjectMap, hInstance); DisableThreadLibraryCalls(hInstance); // End of ATL generated _WAMCCFModule.Init(); // must be after _Module.Init() } else { dwErr = GetLastError(); IF_DEBUG( ERROR ) { DBGPRINTF((DBG_CONTEXT, " InitializeHseExtensions failed. Error=%d.\n", dwErr) ); } } // END mods } else if (dwReason == DLL_PROCESS_DETACH) { DBGPRINTF( (DBG_CONTEXT, " Termination of WAM.dll called with lpvReserved=%08x\n", lpReserved) ); if ( NULL != lpReserved ) { // // Only cleanup if there is a FreeLibrary() call // return ( TRUE); } // BEGIN mods _WAMCCFModule.Term(); // must be before _Module.Term() // END mods _Module.Term(); // BEGIN mods CleanupHseExtensions(); WAM_EXEC_INFO::CleanupClass(); DoGlobalCleanup(); DeleteCriticalSection( &g_csGlobalLock); WAMUnloadNTApis(); DELETE_DEBUG_PRINT_OBJECT(); // END mods } return (dwErr == NO_ERROR); } // DllMain() ///////////////////////////////////////////////////////////////////////////// // Used to determine whether the DLL can be unloaded by OLE STDAPI DllCanUnloadNow(void) { #ifdef _MERGE_PROXYSTUB if (PrxDllCanUnloadNow() != S_OK) return S_FALSE; #endif return (_Module.GetLockCount()==0) ? S_OK : S_FALSE; } ///////////////////////////////////////////////////////////////////////////// // Returns a class factory to create an object of the requested type STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) { HRESULT hr; if (ppv == NULL) { return ( NULL); } *ppv = NULL; // reset the value before getting inside. IF_DEBUG( IID) { DBGPRINTF(( DBG_CONTEXT, "GetClassObject( " GUID_FORMAT "," GUID_FORMAT ", %08x)\n", GUID_EXPAND( &rclsid), GUID_EXPAND( &riid), ppv)); } if (ppv == NULL) { return ( E_POINTER); } *ppv = NULL; // set the incoming value to be invalid entry #ifdef _MERGE_PROXYSTUB if (PrxDllGetClassObject(rclsid, riid, ppv) == S_OK) return S_OK; #endif hr = _Module.GetClassObject(rclsid, riid, ppv); // BEGIN mods if (hr == CLASS_E_CLASSNOTAVAILABLE) { // If request for standard CF failed -> try custom IF_DEBUG( IID){ DBGPRINTF(( DBG_CONTEXT, "Trying Custom CF GetClassObject()\n")); } #ifdef USE_DEFAULT_CF hr = _Module.GetClassObject(CLSID_Wam, riid, ppv); #else hr = _WAMCCFModule.GetClassObject(rclsid, riid, ppv); #endif } IF_DEBUG( IID) { DBGPRINTF(( DBG_CONTEXT, "GetClassObject() returns %08x. (*ppv=%08x)\n", hr, *ppv)); } // END mods return ( hr); } // DllGetClassObject() ///////////////////////////////////////////////////////////////////////////// // DllRegisterServer - Adds entries to the system registry STDAPI DllRegisterServer(void) { #ifdef _MERGE_PROXYSTUB HRESULT hRes = PrxDllRegisterServer(); if (FAILED(hRes)) return hRes; #endif // registers object, typelib and all interfaces in typelib return _Module.RegisterServer(TRUE); } ///////////////////////////////////////////////////////////////////////////// // DllUnregisterServer - Removes entries from the system registry STDAPI DllUnregisterServer(void) { #ifdef _MERGE_PROXYSTUB PrxDllUnregisterServer(); #endif _Module.UnregisterServer(); return S_OK; } /************************************************************ * Global Init/Cleanup functions ************************************************************/ HRESULT DoGlobalInitializations(IN BOOL fInProc, IN BOOL fEnableTryExcept) /*++ Description: This function is used to initialize the global state of various variable in use. RPC runtime runs into deadlocks with respect to the NT DLL loader lock. Eventlog for one uses RPC to establish the connections. Hence, we use this separate global initialize function to setup state outside the NT DLL loader lock boundary (outside the DllMain()) Arguments: fInProc - Is this WAM instance running InProc? fEnableTryExcept - Catch exceptions in ISAPIs? Returns: HRESULT - NOERROR means success; otherwise returns custom error. --*/ { HRESULT hr = NOERROR; // // Use Locks to ensure that only one guy is initializing the data // EnterCriticalSection( &g_csGlobalLock); if ( !g_fGlobalInitDone) { // remember fEnableTryExcept flag g_fEnableTryExcept = fEnableTryExcept; if( !fInProc ) { hr = CWamOopTokenInfo::Create(); DBG_ASSERT( SUCCEEDED(hr) ); if( WAM_EXEC_INFO::sm_pSVCacheMap == NULL ) { WAM_EXEC_INFO::sm_pSVCacheMap = new SV_CACHE_MAP(); DBG_ASSERT( WAM_EXEC_INFO::sm_pSVCacheMap != NULL ); if( WAM_EXEC_INFO::sm_pSVCacheMap != NULL ) { DBG_REQUIRE( WAM_EXEC_INFO::sm_pSVCacheMap->Initialize() ); } } } #ifndef _NO_TRACING_ CREATE_INITIALIZE_DEBUG(); #endif g_fGlobalInitDone = TRUE; } LeaveCriticalSection( &g_csGlobalLock); IF_DEBUG( INIT_CLEAN) { DBGPRINTF(( DBG_CONTEXT, " DoGlobalInitializations() returns hr = %08x\n", hr)); } return ( hr); } // DoGlobalInitializations() HRESULT DoGlobalCleanup(VOID) { HRESULT hr = NOERROR; if ( !g_fGlobalInitDone) { return ( hr); } EnterCriticalSection( &g_csGlobalLock); if( CWamOopTokenInfo::HasInstance() ) { CWamOopTokenInfo::Destroy(); } delete WAM_EXEC_INFO::sm_pSVCacheMap; WAM_EXEC_INFO::sm_pSVCacheMap = NULL; g_fGlobalInitDone = FALSE; LeaveCriticalSection( &g_csGlobalLock); return ( hr); } // DoGlobalCleanup() /************************************************************ * Thunks for Fake NT APIs ************************************************************/ CRITICAL_SECTION g_csNonNTAPIs; LONG FakeInterlockedCompareExchange( LONG *Destination, LONG Exchange, LONG Comperand ) /*++ Description: This function fakes the interlocked compare exchange operation for non NT platforms See WAMLoadNTApis() for details Returns: returns the old value at Destination --*/ { LONG oldValue; EnterCriticalSection( &g_csNonNTAPIs); oldValue = *Destination; if ( oldValue == Comperand ) { *Destination = Exchange; } LeaveCriticalSection( &g_csNonNTAPIs); return( oldValue); } // FakeInterlockedCompareExchange() static VOID WAMLoadNTApis(VOID) /*++ Description: This function loads the entry point for functions from Kernel32.dll. If the entry point is missing, the function pointer will point to a fake routine which does nothing. Otherwise, it will point to the real function. It dynamically loads the kernel32.dll to find the entry ponit and then unloads it after getting the address. For the resulting function pointer to work correctly one has to ensure that the kernel32.dll is linked with the dll/exe which links to this file. --*/ { // Initialize the critical section for non NT API support, in case if we need this INITIALIZE_CRITICAL_SECTION( &g_csNonNTAPIs); if ( g_pfnInterlockedCompareExchange == NULL ) { HINSTANCE tmpInstance; // // load kernel32 and get NT specific entry points // tmpInstance = LoadLibrary("kernel32.dll"); if ( tmpInstance != NULL ) { // For some reason the original function is _InterlockedCompareExchange! g_pfnInterlockedCompareExchange = (PFN_INTERLOCKED_COMPARE_EXCHANGE ) GetProcAddress( tmpInstance, "InterlockedCompareExchange"); if ( g_pfnInterlockedCompareExchange == NULL ) { // the function is not available // Just thunk it. g_pfnInterlockedCompareExchange = FakeInterlockedCompareExchange; } // // We can free this because we are statically linked to it // FreeLibrary(tmpInstance); } } return; } // WAMLoadNTApis() static void WAMUnloadNTApis(VOID) { DeleteCriticalSection( &g_csNonNTAPIs); return; } // WAMUnloadNTApis()