windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/wam/object/wam.cpp
2020-09-26 16:20:57 +08:00

558 lines
14 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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 <isapip.hxx>
#include "pudebug.h"
#include "resource.h"
#include "initguid.h"
#include "wamobj.hxx"
#include "Wam_i.c"
// BEGIN mods
#include <irtldbg.h>
#include "setable.hxx"
#include "wamccf.hxx"
#include <ooptoken.h>
#ifdef _ATL_STATIC_REGISTRY
#include <statreg.h>
#include <statreg.cpp>
#endif
#include <atlimpl.cpp>
// 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 <initguid.h>
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()