1584 lines
46 KiB
C++
1584 lines
46 KiB
C++
/*===================================================================
|
|
Microsoft Denali
|
|
|
|
Microsoft Confidential.
|
|
Copyright 1996-1999 Microsoft Corporation. All Rights Reserved.
|
|
|
|
Component: Main
|
|
|
|
File: denali.cpp
|
|
|
|
Owner: AndyMorr
|
|
|
|
This file contains the I S A P I C A L L B A C K A P I S
|
|
===================================================================*/
|
|
#include "denpre.h"
|
|
#pragma hdrstop
|
|
|
|
#undef DEFAULT_TRACE_FLAGS
|
|
#define DEFAULT_TRACE_FLAGS (DEBUG_ERROR)
|
|
|
|
#include "gip.h"
|
|
#include "mtacb.h"
|
|
#include "perfdata.h"
|
|
#include "activdbg.h"
|
|
#include "dlldatax.h"
|
|
#include "debugger.h"
|
|
#include "dbgutil.h"
|
|
#include "randgen.h"
|
|
#include "aspdmon.h"
|
|
#include "tlbcache.h"
|
|
#include "thrdgate.h"
|
|
#include "ie449.h"
|
|
|
|
#include "memcls.h"
|
|
#include "memchk.h"
|
|
|
|
// Globals
|
|
|
|
BOOL g_fShutDownInProgress = FALSE;
|
|
BOOL g_fInitStarted = FALSE;
|
|
|
|
char g_szExtensionDesc[] = "Microsoft Active Server Pages 2.0";
|
|
GLOB gGlob;
|
|
BOOL g_fFirstHit = TRUE;
|
|
char g_pszASPModuleName[] = "ASP";
|
|
|
|
DECLARE_DEBUG_PRINTS_OBJECT();
|
|
#ifdef _NO_TRACING_
|
|
DECLARE_DEBUG_VARIABLE();
|
|
#else
|
|
#include <initguid.h>
|
|
DEFINE_GUID(IisAspGuid,
|
|
0x784d8902, 0xaa8c, 0x11d2, 0x92, 0x5e, 0x00, 0xc0, 0x4f, 0x72, 0xd9, 0x0e);
|
|
#endif
|
|
DECLARE_PLATFORM_TYPE();
|
|
|
|
// Out of process flag
|
|
BOOL g_fOOP = FALSE;
|
|
|
|
// session id cookie
|
|
char g_szSessionIDCookieName[CCH_SESSION_ID_COOKIE+1];
|
|
|
|
CRITICAL_SECTION g_csEventlogLock;
|
|
CRITICAL_SECTION g_csFirstHitLock;
|
|
HINSTANCE g_hODBC32Lib;
|
|
|
|
// Added to support CacheExtensions
|
|
HINSTANCE g_hDenali = (HINSTANCE)0;
|
|
HINSTANCE g_hinstDLL = (HINSTANCE)0;
|
|
|
|
extern LONG g_nSessionObjectsActive;
|
|
|
|
// Cached BSTRs
|
|
BSTR g_bstrApplication = NULL;
|
|
BSTR g_bstrRequest = NULL;
|
|
BSTR g_bstrResponse = NULL;
|
|
BSTR g_bstrServer = NULL;
|
|
BSTR g_bstrCertificate = NULL;
|
|
BSTR g_bstrSession = NULL;
|
|
BSTR g_bstrScriptingNamespace = NULL;
|
|
BSTR g_bstrObjectContext = NULL;
|
|
|
|
|
|
// Forward references
|
|
HRESULT GlobInit();
|
|
HRESULT GlobUnInit();
|
|
HRESULT CacheStdTypeInfos();
|
|
HRESULT UnCacheStdTypeInfos();
|
|
HRESULT InitCachedBSTRs();
|
|
HRESULT UnInitCachedBSTRs();
|
|
HRESULT ShutDown();
|
|
HRESULT SendHtmlSubstitute(CIsapiReqInfo *pIReq);
|
|
|
|
void MakeAspCookieName(char *);
|
|
BOOL FirstHitInit(CIsapiReqInfo *pIReq);
|
|
|
|
|
|
// ATL support
|
|
#if _IIS_5_1
|
|
CWamModule _Module;
|
|
#elif _IIS_6_0
|
|
CComModule _Module;
|
|
#else
|
|
#error "Neither _IIS_6_0 nor _IIS_5_1 is defined"
|
|
#endif
|
|
|
|
BEGIN_OBJECT_MAP(ObjectMap)
|
|
END_OBJECT_MAP()
|
|
|
|
|
|
/*===================================================================
|
|
DllMain - Moved from clsfctry.cpp
|
|
|
|
Main entry point into the DLL. Called by system on DLL load
|
|
and unload.
|
|
|
|
Returns:
|
|
TRUE on success
|
|
|
|
Side effects:
|
|
None.
|
|
===================================================================*/
|
|
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
|
|
{
|
|
/* Obsolete
|
|
// Let the Proxy code get a crack at it
|
|
if (!PrxDllMain(hinstDLL, dwReason, lpvReserved))
|
|
return FALSE;
|
|
*/
|
|
|
|
switch(dwReason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
// hang onto the hinstance so we can use it to get to our string resources
|
|
//
|
|
g_hinstDLL = hinstDLL;
|
|
|
|
// Here's an interesting optimization:
|
|
// The following tells the system NOT to call us for Thread attach/detach
|
|
// since we dont handle those calls anyway, this will speed things up a bit.
|
|
// If this turns out to be a problem for some reason (cant imagine why),
|
|
// just remove this again.
|
|
DisableThreadLibraryCalls(hinstDLL);
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
break;
|
|
|
|
case DLL_THREAD_ATTACH:
|
|
break;
|
|
|
|
case DLL_THREAD_DETACH:
|
|
break;
|
|
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/*===================================================================
|
|
DWORD HandleHit
|
|
|
|
Given the CIsapiReqInfo construct a hit object to be queued
|
|
for execution
|
|
|
|
Parameters:
|
|
pIReq - CIsapiReqInfo
|
|
|
|
Returns:
|
|
HSE_STATUS_PENDING if function is successful in queuing request
|
|
HSE_STATUS_ERROR if not successful
|
|
===================================================================*/
|
|
|
|
DWORD HandleHit(CIsapiReqInfo *pIReq)
|
|
{
|
|
int errorId = 0;
|
|
BOOL fRejected = FALSE;
|
|
BOOL fCompleted = FALSE;
|
|
HRESULT hr = S_OK;
|
|
|
|
/*
|
|
* We cant read the metabase until we have the WAM_EXEC_INFO, which
|
|
* we dont have at DllInit time. Therefore, we postpone reading the
|
|
* metabase until now, but we do it only on the first hit.
|
|
*/
|
|
if (g_fFirstHit)
|
|
{
|
|
EnterCriticalSection(&g_csFirstHitLock);
|
|
|
|
// If someone initied while we were waiting for the CS,
|
|
// then noop
|
|
if (g_fFirstHit)
|
|
{
|
|
BOOL fT;
|
|
|
|
fT = FirstHitInit(pIReq);
|
|
Assert(fT);
|
|
|
|
g_fFirstHit = FALSE;
|
|
}
|
|
|
|
LeaveCriticalSection(&g_csFirstHitLock);
|
|
}
|
|
|
|
#ifndef PERF_DISABLE
|
|
if (!g_fPerfInited) // Init PERFMON data on first request
|
|
{
|
|
// FYI: leverage same CS as first hit lock
|
|
EnterCriticalSection(&g_csFirstHitLock);
|
|
|
|
// If someone initied while we were waiting for the CS,
|
|
// then noop
|
|
if (!g_fPerfInited)
|
|
{
|
|
if (SUCCEEDED(InitPerfDataOnFirstRequest(pIReq)))
|
|
{
|
|
g_fPerfInited = TRUE;
|
|
}
|
|
else
|
|
{
|
|
g_fPerfInited = FALSE;
|
|
// call this again since InitPerfDataOnFirstRequest will uninit
|
|
// and erase the criticalsection which will then AV when we try to increment counters
|
|
PreInitPerfData();
|
|
}
|
|
}
|
|
LeaveCriticalSection(&g_csFirstHitLock);
|
|
}
|
|
g_PerfData.Incr_REQTOTAL();
|
|
#endif
|
|
|
|
if (Glob(fNeedUpdate))
|
|
{
|
|
if (SUCCEEDED(StartISAThreadBracket(pIReq)))
|
|
{
|
|
// Update uses pIReq - need to bracket
|
|
gGlob.Update(pIReq);
|
|
|
|
EndISAThreadBracket(pIReq);
|
|
}
|
|
}
|
|
|
|
if (IsShutDownInProgress())
|
|
hr = E_FAIL;
|
|
|
|
// Enforce the limit of concurrent browser requests
|
|
if (SUCCEEDED(hr) && Glob(dwRequestQueueMax) &&
|
|
(*g_PerfData.PDWCounter(ID_REQCURRENT) >= Glob(dwRequestQueueMax)))
|
|
{
|
|
hr = E_FAIL;
|
|
fRejected = TRUE;
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = CHitObj::NewBrowserRequest(pIReq, &fRejected, &fCompleted, &errorId);
|
|
|
|
if (SUCCEEDED(hr))
|
|
return fCompleted ? HSE_STATUS_SUCCESS_AND_KEEP_CONN : HSE_STATUS_PENDING;
|
|
|
|
if (fRejected)
|
|
{
|
|
if (Glob(fEnableAspHtmlFallBack))
|
|
{
|
|
// Instead of rejecting the request try to find
|
|
// XXX_ASP.HTM file in the same directory and dump its contents
|
|
hr = SendHtmlSubstitute(pIReq);
|
|
|
|
if (hr == S_OK)
|
|
return HSE_STATUS_SUCCESS_AND_KEEP_CONN; // HTML substitute sent
|
|
else if (FAILED(hr))
|
|
return HSE_STATUS_ERROR; // error sending
|
|
// HTML substitute not found
|
|
}
|
|
|
|
errorId = IDE_SERVER_TOO_BUSY;
|
|
|
|
#ifndef PERF_DISABLE
|
|
g_PerfData.Incr_REQREJECTED();
|
|
#endif
|
|
}
|
|
|
|
if (SUCCEEDED(StartISAThreadBracket(pIReq)))
|
|
{
|
|
// Uses pIReq -- need to bracket
|
|
Handle500Error(errorId, pIReq);
|
|
|
|
EndISAThreadBracket(pIReq);
|
|
}
|
|
|
|
return HSE_STATUS_ERROR;
|
|
}
|
|
|
|
/*===================================================================
|
|
BOOL DllInit
|
|
|
|
Initialize Denali if not invoked by RegSvr32. Only do inits here
|
|
that dont require Glob values loaded from the metabase. For any
|
|
inits that require values loaded into Glob from the metabase, use
|
|
FirstHitInit.
|
|
|
|
Returns:
|
|
TRUE on successful initialization
|
|
===================================================================*/
|
|
BOOL DllInit()
|
|
{
|
|
HRESULT hr;
|
|
const CHAR szASPDebugRegLocation[] =
|
|
"System\\CurrentControlSet\\Services\\W3Svc\\ASP";
|
|
|
|
#if _IIS_5_1
|
|
InitializeIISRTL();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- IISRTL\n"));
|
|
#endif
|
|
|
|
#ifndef _NO_TRACING_
|
|
CREATE_DEBUG_PRINT_OBJECT( g_pszASPModuleName, IisAspGuid);
|
|
#else
|
|
CREATE_DEBUG_PRINT_OBJECT( g_pszASPModuleName);
|
|
#endif
|
|
|
|
if ( !VALID_DEBUG_PRINT_OBJECT())
|
|
{
|
|
return ( FALSE);
|
|
}
|
|
|
|
#ifdef _NO_TRACING_
|
|
LOAD_DEBUG_FLAGS_FROM_REG_STR(szASPDebugRegLocation, (DEBUG_ERROR));
|
|
#endif
|
|
|
|
#ifdef SCRIPT_STATS
|
|
ReadRegistrySettings();
|
|
#endif // SCRIPT_STATS
|
|
|
|
// Create ASP RefTrace Logs
|
|
IF_DEBUG(TEMPLATE) CTemplate::gm_pTraceLog = CreateRefTraceLog(5000, 0);
|
|
IF_DEBUG(SESSION) CSession::gm_pTraceLog = CreateRefTraceLog(5000, 0);
|
|
IF_DEBUG(APPLICATION) CAppln::gm_pTraceLog = CreateRefTraceLog(5000, 0);
|
|
IF_DEBUG(FCN) CASPDirMonitorEntry::gm_pTraceLog = CreateRefTraceLog(500, 0);
|
|
CAppln::gm_pTraceLog = CreateRefTraceLog(5000, 0);
|
|
|
|
if (FAILED(PreInitPerfData()))
|
|
return FALSE;
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- PerfMon Data PreInit\n"));
|
|
|
|
ErrInitCriticalSection( &g_csEventlogLock, hr );
|
|
if (FAILED(hr))
|
|
return FALSE;
|
|
|
|
ErrInitCriticalSection( &g_csFirstHitLock, hr );
|
|
if (FAILED(hr))
|
|
return FALSE;
|
|
|
|
#ifdef DENALI_MEMCHK
|
|
if (FAILED(DenaliMemoryInit()))
|
|
return FALSE;
|
|
#else
|
|
if (FAILED(AspMemInit()))
|
|
return FALSE;
|
|
#endif
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- Denali Memory Init\n"));
|
|
|
|
g_pDirMonitor = new CDirMonitor;
|
|
|
|
if (g_pDirMonitor == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
#if _IIS_5_1
|
|
if (AtqInitialize(0) == FALSE)
|
|
return FALSE;
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- ATQ Initialized\n"));
|
|
#endif
|
|
|
|
if (FAILED(GlobInit()))
|
|
return FALSE;
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- Glob Init\n"));
|
|
|
|
if (FAILED(InitMemCls()))
|
|
return FALSE;
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- Per-Class Cache Init\n"));
|
|
|
|
if (FAILED(InitCachedBSTRs()))
|
|
return FALSE;
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- Cached BSTRs Init\n"));
|
|
|
|
if (FAILED(TxnSupportInit()))
|
|
return FALSE;
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- Txn Support Init\n"));
|
|
|
|
if (FAILED(CacheStdTypeInfos()))
|
|
return FALSE;
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- Cache Std TypeInfos\n"));
|
|
|
|
if (FAILED(g_TypelibCache.Init()))
|
|
return FALSE;
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- Typelib Cache Init\n"));
|
|
|
|
if (FAILED(ErrHandleInit()))
|
|
return FALSE;
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- Err Handler Init\n"));
|
|
|
|
srand( (unsigned int) time(NULL) );
|
|
if (FAILED(g_SessionIdGenerator.Init())) // seed session id
|
|
return FALSE;
|
|
// Init new Exposed Session Id variable
|
|
if (FAILED(g_ExposedSessionIdGenerator.Init(g_SessionIdGenerator))) // seed exposed session id
|
|
return FALSE;
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- SessionID Generator Init\n"));
|
|
|
|
MakeAspCookieName(g_szSessionIDCookieName);
|
|
|
|
if (FAILED(InitRandGenerator()))
|
|
return FALSE;
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- RandGen Init\n"));
|
|
|
|
if (FAILED(g_ApplnMgr.Init()))
|
|
return FALSE;
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- Appln Mgr Init\n"));
|
|
|
|
if (FAILED(Init449()))
|
|
return FALSE;
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- 449 Mgr Init\n"));
|
|
|
|
// Note: Template cache manager is inited in two phases. Do first here.
|
|
if (FAILED(g_TemplateCache.Init()))
|
|
return FALSE;
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- Template Cache Init\n"));
|
|
|
|
if (FAILED(g_IncFileMap.Init()))
|
|
return FALSE;
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- Inc File Users Init\n"));
|
|
|
|
if (FIsWinNT()) // No Change notification on Windows 95
|
|
{
|
|
if (FAILED(g_FileAppMap.Init()))
|
|
return FALSE;
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- File-Application Map Init\n"));
|
|
}
|
|
|
|
if (FAILED(g_ScriptManager.Init()))
|
|
return FALSE;
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- Script Manager Init\n"));
|
|
|
|
if (FAILED(CTemplate::InitClass()))
|
|
return FALSE;
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- CTemplate Init Class\n"));
|
|
|
|
if (FIsWinNT()) // No GIPs on Win95
|
|
{
|
|
if (FAILED(g_GIPAPI.Init()))
|
|
return FALSE;
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- Global Interface API Init\n"));
|
|
}
|
|
|
|
if (FAILED(InitMTACallbacks()))
|
|
return FALSE;
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- MTA Callbacks Init\n"));
|
|
|
|
if (!RequestSupportInit())
|
|
return FALSE;
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- Request Support Init\n"));
|
|
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Init -- Denali DLL Initialized\n"));
|
|
|
|
#ifdef LOG_FCNOTIFICATIONS
|
|
LfcnCreateLogFile();
|
|
#endif //LOG_FCNOTIFICATIONS
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*===================================================================
|
|
BOOL FirstHitInit
|
|
|
|
Initialize any ASP values that can not be inited at DllInit time.
|
|
|
|
Returns:
|
|
TRUE on successful initialization
|
|
===================================================================*/
|
|
BOOL FirstHitInit
|
|
(
|
|
CIsapiReqInfo *pIReq
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
/*
|
|
* In the out of proc case, being able to call the metabase relies on having
|
|
* told WAM that we are a "smart" client
|
|
*/
|
|
|
|
if (SUCCEEDED(StartISAThreadBracket(pIReq)))
|
|
{
|
|
// ReadConfigFromMD uses pIReq - need to bracket
|
|
hr = ReadConfigFromMD(pIReq, NULL, TRUE);
|
|
|
|
// Initialize Debugging
|
|
if (FIsWinNT() && RevertToSelf()) // No Debugging on Win95
|
|
{
|
|
// Don't care whether debugging initializaiton succeeds or not. The most likely
|
|
// falure is debugger not installed on the machine.
|
|
//
|
|
if (SUCCEEDED(InitDebuggingAndCreateActivity(pIReq)))
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT, "FirstHitInit: Debugging Initialized\n"));
|
|
}
|
|
else
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT, "FirstHitInit: Debugger Initialization Failed\n"));
|
|
}
|
|
|
|
DBG_REQUIRE( SetThreadToken(NULL, pIReq->QueryImpersonationToken()) );
|
|
}
|
|
|
|
EndISAThreadBracket(pIReq);
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
goto LExit;
|
|
DBGPRINTF((DBG_CONTEXT, "FirstHitInit: Metadata loaded successfully\n"));
|
|
|
|
// Do FirstHitInit for the Template Cache Manager. Primarily initializes
|
|
// the Persisted Template Cache
|
|
if (FAILED(hr = g_TemplateCache.FirstHitInit()))
|
|
goto LExit;
|
|
DBGPRINTF((DBG_CONTEXT, "FirstHitInit: Template Cache Initialized\n"));
|
|
|
|
// Configure MTS
|
|
if (FAILED(hr = ViperConfigure(Glob(dwProcessorThreadMax), Glob(fAllowOutOfProcCmpnts))))
|
|
goto LExit;
|
|
DBGPRINTF((DBG_CONTEXT, "FirstHitInit: MTS configured\n"));
|
|
|
|
// Configure Thread Gate
|
|
THREADGATE_CONFIG tgc;
|
|
tgc.fEnabled = Glob(fThreadGateEnabled);
|
|
tgc.msTimeSlice = Glob(dwThreadGateTimeSlice);
|
|
tgc.msSleepDelay = Glob(dwThreadGateSleepDelay);
|
|
tgc.nSleepMax = Glob(dwThreadGateSleepMax);
|
|
tgc.nLoadLow = Glob(dwThreadGateLoadLow);
|
|
tgc.nLoadHigh = Glob(dwThreadGateLoadHigh);
|
|
tgc.nMinProcessorThreads = 1;
|
|
tgc.nMaxProcessorThreads = Glob(dwProcessorThreadMax);
|
|
if (FAILED(hr = InitThreadGate(&tgc)))
|
|
goto LExit;
|
|
DBGPRINTF((DBG_CONTEXT, "Thread Gate Init\n"));
|
|
|
|
DBGPRINTF((DBG_CONTEXT, "ASP First Hit Initialization complete\n"));
|
|
|
|
LExit:
|
|
Assert(SUCCEEDED(hr));
|
|
return SUCCEEDED(hr);
|
|
}
|
|
|
|
/*===================================================================
|
|
void DllUnInit
|
|
|
|
UnInitialize Denali DLL if not invoked by RegSvr32
|
|
|
|
Returns:
|
|
NONE
|
|
|
|
Side effects:
|
|
NONE
|
|
===================================================================*/
|
|
void DllUnInit( void )
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- %d Apps %d Sessions %d Requests\n",
|
|
g_nApplications, g_nSessions, g_nBrowserRequests));
|
|
|
|
g_fShutDownInProgress = TRUE;
|
|
|
|
ShutDown();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- ShutDown Processing\n" ));
|
|
|
|
UnInitMTACallbacks();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- MTA Callbacks\n" ));
|
|
|
|
UnInitRandGenerator();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- RandGen\n"));
|
|
|
|
UnInitThreadGate();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- Thread Gate\n"));
|
|
|
|
UnInit449();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- 449 Mgr\n"));
|
|
|
|
g_ApplnMgr.UnInit();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- Application Manager\n" ));
|
|
|
|
g_ScriptManager.UnInit();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- Script Manager\n" ));
|
|
|
|
g_TemplateCache.UnInit();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- Template Cache\n" ));
|
|
|
|
g_IncFileMap.UnInit();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- IncFileMap\n" ));
|
|
|
|
if (FIsWinNT()) {
|
|
// No change notification on windows 95
|
|
g_FileAppMap.UnInit();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- File-Application Map\n" ));
|
|
|
|
if (g_pDirMonitor) {
|
|
g_pDirMonitor->Cleanup();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UNInit -- Directory Monitor\n" ));
|
|
}
|
|
}
|
|
|
|
CTemplate::UnInitClass();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- CTemplate\n" ));
|
|
|
|
g_TypelibCache.UnInit();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- Typelib Cache\n"));
|
|
|
|
UnCacheStdTypeInfos();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- TypeInfos\n" ));
|
|
|
|
TxnSupportUnInit();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- Txn Support\n" ));
|
|
|
|
if (FIsWinNT())
|
|
{
|
|
// No GIPs on Win95
|
|
g_GIPAPI.UnInit();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- GIP\n" ));
|
|
}
|
|
|
|
ErrHandleUnInit();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- ErrHandler\n" ));
|
|
|
|
GlobUnInit();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- Glob\n" ));
|
|
|
|
UnInitCachedBSTRs();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- Cached BSTRs\n" ));
|
|
|
|
//////////////////////////////////////////////////////////
|
|
// Wait for the actual session objects to be destroyed.
|
|
// The g_nSessions global tracks the init/uninit of session
|
|
// objects but not the memory itself. This presents a
|
|
// problem when something outside of ASP holds a reference
|
|
// to a session object or one of the contained intrinsics.
|
|
// One case of this is the revoking of a git'd transaction
|
|
// object. Turns out the revoke can happen asynchronously.
|
|
//
|
|
// NOTE!!! - This needs to be done BEFORE uniniting the
|
|
// mem classes since these objects are in the acache.
|
|
|
|
LONG lastCount = g_nSessionObjectsActive;
|
|
DWORD loopCount = 50;
|
|
|
|
while( (g_nSessionObjectsActive > 0) && (loopCount--) )
|
|
{
|
|
if (lastCount != g_nSessionObjectsActive) {
|
|
lastCount = g_nSessionObjectsActive;
|
|
loopCount = 50;
|
|
}
|
|
Sleep( 100 );
|
|
}
|
|
|
|
UnInitMemCls();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- Per-Class Cache\n" ));
|
|
|
|
#if _IIS_5_1
|
|
AtqTerminate();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- ATQ\n" ));
|
|
#endif
|
|
|
|
// Destroy ASP RefTrace Logs
|
|
IF_DEBUG(TEMPLATE) DestroyRefTraceLog(CTemplate::gm_pTraceLog);
|
|
IF_DEBUG(SESSION) DestroyRefTraceLog(CSession::gm_pTraceLog);
|
|
IF_DEBUG(APPLICATION) DestroyRefTraceLog(CAppln::gm_pTraceLog);
|
|
IF_DEBUG(FCN) DestroyRefTraceLog(CASPDirMonitorEntry::gm_pTraceLog);
|
|
|
|
_Module.Term();
|
|
|
|
delete g_pDirMonitor;
|
|
g_pDirMonitor = NULL;
|
|
|
|
// UnInitODBC();
|
|
// Note: the memmgr uses perf counters, so must be uninited before the perf counters are uninited
|
|
#ifdef DENALI_MEMCHK
|
|
DenaliMemoryUnInit();
|
|
#else
|
|
AspMemUnInit();
|
|
#endif
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- Memory Manager\n" ));
|
|
|
|
UnInitPerfData();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- Perf Counters\n" ));
|
|
|
|
#if _IIS_5_1
|
|
TerminateIISRTL();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP UnInit -- IISRTL\n" ));
|
|
#endif
|
|
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Uninitialized\n" ));
|
|
|
|
#ifdef LOG_FCNOTIFICATIONS
|
|
LfcnUnmapLogFile();
|
|
#endif //LOG_FCNOTIFICATIONS
|
|
|
|
// Deleting the following CS's must be last. Dont put anything after this
|
|
DeleteCriticalSection( &g_csFirstHitLock );
|
|
DeleteCriticalSection( &g_csEventlogLock );
|
|
|
|
DELETE_DEBUG_PRINT_OBJECT();
|
|
}
|
|
|
|
/*===================================================================
|
|
GetExtensionVersion
|
|
|
|
Mandatory server extension call which returns the version number of
|
|
the ISAPI spec that we were built with.
|
|
|
|
Returns:
|
|
TRUE on success
|
|
|
|
Side effects:
|
|
None.
|
|
===================================================================*/
|
|
BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pextver)
|
|
{
|
|
// This DLL can be inited only once
|
|
if (g_fShutDownInProgress ||
|
|
InterlockedExchange((LPLONG)&g_fInitStarted, TRUE))
|
|
{
|
|
SetLastError(ERROR_BUSY);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!DllInit())
|
|
{
|
|
SetLastError(ERROR_BUSY);
|
|
return FALSE;
|
|
}
|
|
|
|
pextver->dwExtensionVersion =
|
|
MAKELONG(HSE_VERSION_MAJOR, HSE_VERSION_MINOR);
|
|
strcpy(pextver->lpszExtensionDesc, g_szExtensionDesc);
|
|
return TRUE;
|
|
}
|
|
|
|
/*===================================================================
|
|
HttpExtensionProc
|
|
|
|
Main entry point into the DLL for the (ActiveX) Internet Information Server.
|
|
|
|
Returns:
|
|
DWord indicating status of request.
|
|
HSE_STATUS_PENDING for normal return
|
|
(This indicates that we will process the request, but havent yet.)
|
|
|
|
Side effects:
|
|
None.
|
|
===================================================================*/
|
|
DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB)
|
|
{
|
|
#ifdef SCRIPT_STATS
|
|
InterlockedIncrement(&g_cHttpExtensionsExecuting);
|
|
#endif // SCRIPT_STATS
|
|
|
|
CIsapiReqInfo *pIReq = new CIsapiReqInfo(pECB);
|
|
|
|
if (pIReq == NULL) {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return HSE_STATUS_ERROR;
|
|
}
|
|
|
|
#ifndef PERF_DISABLE
|
|
g_PerfData.Add_REQTOTALBYTEIN
|
|
(
|
|
pIReq->QueryCchQueryString()
|
|
#if _IIS_5_1
|
|
+ pIReq->QueryCchPathTranslated()
|
|
#elif _IIS_6_0
|
|
+ strlen( pIReq->ECB()->lpszPathTranslated )
|
|
#endif
|
|
+ pIReq->QueryCbTotalBytes()
|
|
);
|
|
#endif
|
|
|
|
DWORD dw = HandleHit(pIReq);
|
|
|
|
#ifdef SCRIPT_STATS
|
|
InterlockedDecrement(&g_cHttpExtensionsExecuting);
|
|
#endif // SCRIPT_STATS
|
|
|
|
pIReq->Release();
|
|
|
|
return dw;
|
|
}
|
|
|
|
/*===================================================================
|
|
TerminateExtension
|
|
|
|
IIS is supposed to call this entry point to unload ISAPI DLLs.
|
|
|
|
Returns:
|
|
NONE
|
|
|
|
Side effects:
|
|
Uninitializes the Denali ISAPI DLL if asked to.
|
|
===================================================================*/
|
|
BOOL WINAPI TerminateExtension( DWORD dwFlag )
|
|
{
|
|
if ( dwFlag == HSE_TERM_ADVISORY_UNLOAD )
|
|
return TRUE;
|
|
|
|
if ( dwFlag == HSE_TERM_MUST_UNLOAD )
|
|
{
|
|
// If already shutdown don't uninit twice.
|
|
if (g_fShutDownInProgress)
|
|
return TRUE;
|
|
|
|
// make sure this is a CoInitialize()'d thread
|
|
HRESULT hr = CoInitialize(NULL);
|
|
|
|
if (hr == RPC_E_CHANGED_MODE)
|
|
{
|
|
// already coinitialized MUTLITREADED - OK
|
|
DllUnInit();
|
|
}
|
|
else if (SUCCEEDED(hr))
|
|
{
|
|
DllUnInit();
|
|
|
|
// need to CoUninit() because CoInit() Succeeded
|
|
CoUninitialize();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*===================================================================
|
|
HRESULT ShutDown
|
|
|
|
ASP Processing ShutDown logic. (Moved from ThreadManager::UnInit())
|
|
|
|
Returns:
|
|
HRESULT - S_OK on success
|
|
|
|
Side effects:
|
|
May be slow. Kills all requests/sessions/applications
|
|
===================================================================*/
|
|
HRESULT ShutDown()
|
|
{
|
|
long iT;
|
|
const DWORD dwtLongWait = 1000; // 1 sec
|
|
const DWORD dwtShortWait = 100; // 1/10 sec
|
|
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Shutdown: %d apps (%d restarting), %d sessions\n",
|
|
g_nApplications, g_nApplicationsRestarting, g_nSessions ));
|
|
|
|
//////////////////////////////////////////////////////////
|
|
// Stop change notification on files in template cache
|
|
|
|
if (FIsWinNT())
|
|
{
|
|
g_TemplateCache.ShutdownCacheChangeNotification();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////
|
|
// Shut down debugging, which will have the effect of
|
|
// resuming scripts stopped at a breakpoint.
|
|
//
|
|
// (otherwise stopping running scripts will hang later)
|
|
|
|
if (g_pPDM)
|
|
{
|
|
g_TemplateCache.RemoveApplicationFromDebuggerUI(NULL); // remove all document nodes
|
|
UnInitDebugging(); // kill PDM
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Shutdown: PDM Closed\n" ));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////
|
|
// Drain down all pending browser requests
|
|
|
|
if (g_nBrowserRequests > 0)
|
|
{
|
|
// Give them a little time each
|
|
for (iT = 2*g_nBrowserRequests; g_nBrowserRequests > 0 && iT > 0; iT--)
|
|
Sleep(dwtShortWait);
|
|
|
|
if (g_nBrowserRequests > 0)
|
|
{
|
|
// Still there - kill scripts and wait again
|
|
g_ScriptManager.EmptyRunningScriptList();
|
|
|
|
for (iT = 2*g_nBrowserRequests; g_nBrowserRequests > 0 && iT > 0; iT--)
|
|
Sleep(dwtShortWait);
|
|
}
|
|
}
|
|
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Shutdown: Requests drained: %d remaining\n",
|
|
g_nBrowserRequests));
|
|
|
|
//////////////////////////////////////////////////////////
|
|
// Kill any remaining engines running scripts
|
|
|
|
g_ScriptManager.EmptyRunningScriptList();
|
|
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Shutdown: Scripts killed\n"));
|
|
|
|
//////////////////////////////////////////////////////////
|
|
// Wait till there are no appications restarting
|
|
|
|
g_ApplnMgr.Lock();
|
|
while (g_nApplicationsRestarting > 0)
|
|
{
|
|
g_ApplnMgr.UnLock();
|
|
Sleep(dwtShortWait);
|
|
g_ApplnMgr.Lock();
|
|
}
|
|
g_ApplnMgr.UnLock();
|
|
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Shutdown: 0 applications restarting\n"));
|
|
|
|
//////////////////////////////////////////////////////////
|
|
// Make this thread's priority higher than that of worker threads
|
|
|
|
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
|
|
|
|
//////////////////////////////////////////////////////////
|
|
// For each application queue up all its sessions for deletion
|
|
|
|
CApplnIterator ApplnIterator;
|
|
ApplnIterator.Start();
|
|
CAppln *pAppln;
|
|
while (pAppln = ApplnIterator.Next())
|
|
{
|
|
// remove link to ATQ scheduler (even if killing of sessions fails)
|
|
pAppln->PSessionMgr()->UnScheduleSessionKiller();
|
|
|
|
for (iT = pAppln->GetNumSessions(); iT > 0; iT--)
|
|
{
|
|
pAppln->PSessionMgr()->DeleteAllSessions(TRUE);
|
|
|
|
if (pAppln->GetNumSessions() == 0) // all gone?
|
|
break;
|
|
|
|
Sleep(dwtShortWait);
|
|
}
|
|
}
|
|
ApplnIterator.Stop();
|
|
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Shutdown: All sessions queued up for deletion. nSessions=%d\n",
|
|
g_nSessions));
|
|
|
|
//////////////////////////////////////////////////////////
|
|
// Wait till all sessions are gone (UnInited)
|
|
|
|
while (g_nSessions > 0)
|
|
{
|
|
// Wait for a maximum of 0.1 sec x # of sessions
|
|
for (iT = g_nSessions; g_nSessions > 0 && iT > 0; iT--)
|
|
Sleep(dwtShortWait);
|
|
|
|
if (g_nSessions > 0)
|
|
g_ScriptManager.EmptyRunningScriptList(); // Kill runaway Session_OnEnd scripts
|
|
}
|
|
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Shutdown: Finished waiting for sessions to go away. nSessions=%d\n",
|
|
g_nSessions));
|
|
|
|
//////////////////////////////////////////////////////////
|
|
// Queue up all application objects for deletion
|
|
|
|
g_ApplnMgr.DeleteAllApplications();
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Shutdown: All applications queued up for deletion. nApplications=%d\n",
|
|
g_nApplications));
|
|
|
|
//////////////////////////////////////////////////////////
|
|
// Wait till all applications are gone (UnInited)
|
|
|
|
while (g_nApplications > 0)
|
|
{
|
|
// Wait for a maximum of 1 sec x # of applications
|
|
for (iT = g_nApplications; g_nApplications > 0 && iT > 0; iT--)
|
|
Sleep(dwtLongWait);
|
|
|
|
if (g_nApplications > 0)
|
|
g_ScriptManager.EmptyRunningScriptList(); // Kill runaway Applications_OnEnd scripts
|
|
}
|
|
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Shutdown: Finished waiting for applications to go away. nApplications=%d\n",
|
|
g_nApplications));
|
|
|
|
/////////////////////////////////////////////////////////
|
|
// Wait on the CViperAsyncRequest objects. COM holds the
|
|
// final reference to these so we need to let the activity
|
|
// threads release any outstanding references before we
|
|
// exit.
|
|
|
|
while( g_nViperRequests > 0 )
|
|
{
|
|
Sleep( dwtShortWait );
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////
|
|
// Free up libraries to force call of DllCanUnloadNow()
|
|
// Component writers should put cleanup code in the DllCanUnloadNow() entry point.
|
|
|
|
CoFreeUnusedLibraries();
|
|
|
|
//////////////////////////////////////////////////////////
|
|
// Kill Debug Activity if any
|
|
|
|
if (g_pDebugActivity)
|
|
delete g_pDebugActivity;
|
|
|
|
DBGPRINTF((DBG_CONTEXT, "ASP Shutdown: Debug Activity destroyed\n"));
|
|
|
|
//////////////////////////////////////////////////////////
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
HRESULT GlobInit
|
|
|
|
Get all interesting global values (mostly from registry)
|
|
|
|
Returns:
|
|
HRESULT - S_OK on success
|
|
|
|
Side effects:
|
|
fills in glob. May be slow
|
|
===================================================================*/
|
|
HRESULT GlobInit()
|
|
{
|
|
//
|
|
// BUGBUG - This really needs to be provided either through
|
|
// a server support function or via the wamexec
|
|
//
|
|
|
|
char szModule[MAX_PATH+1];
|
|
if (GetModuleFileNameA(NULL, szModule, MAX_PATH) > 0)
|
|
{
|
|
int cch = strlen(szModule);
|
|
if (cch > 12 && stricmp(szModule+cch-12, "inetinfo.exe") == 0)
|
|
{
|
|
g_fOOP = FALSE;
|
|
}
|
|
else if ( cch > 8 && stricmp( szModule+cch-8, "w3wp.exe" ) == 0 )
|
|
{
|
|
g_fOOP = FALSE;
|
|
}
|
|
else
|
|
{
|
|
g_fOOP = TRUE;
|
|
}
|
|
}
|
|
|
|
// Init gGlob
|
|
return gGlob.GlobInit();
|
|
}
|
|
|
|
/*===================================================================
|
|
GlobUnInit
|
|
|
|
It is a macro now. see glob.h
|
|
|
|
Returns:
|
|
HRESULT - S_OK on success
|
|
|
|
Side effects:
|
|
memory freed.
|
|
===================================================================*/
|
|
HRESULT GlobUnInit()
|
|
{
|
|
return gGlob.GlobUnInit();
|
|
}
|
|
|
|
/*===================================================================
|
|
InitCachedBSTRs
|
|
|
|
Pre-create frequently used BSTRs
|
|
===================================================================*/
|
|
HRESULT InitCachedBSTRs()
|
|
{
|
|
g_bstrApplication = SysAllocString(WSZ_OBJ_APPLICATION);
|
|
g_bstrRequest = SysAllocString(WSZ_OBJ_REQUEST);
|
|
g_bstrResponse = SysAllocString(WSZ_OBJ_RESPONSE);
|
|
g_bstrServer = SysAllocString(WSZ_OBJ_SERVER);
|
|
g_bstrCertificate = SysAllocString(WSZ_OBJ_CERTIFICATE);
|
|
g_bstrSession = SysAllocString(WSZ_OBJ_SESSION);
|
|
g_bstrScriptingNamespace = SysAllocString(WSZ_OBJ_SCRIPTINGNAMESPACE);
|
|
g_bstrObjectContext = SysAllocString(WSZ_OBJ_OBJECTCONTEXT);
|
|
|
|
return
|
|
(
|
|
g_bstrApplication &&
|
|
g_bstrRequest &&
|
|
g_bstrResponse &&
|
|
g_bstrServer &&
|
|
g_bstrCertificate &&
|
|
g_bstrSession &&
|
|
g_bstrScriptingNamespace &&
|
|
g_bstrObjectContext
|
|
)
|
|
? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
/*===================================================================
|
|
UnInitCachedBSTRs
|
|
|
|
Delete frequently used BSTRs
|
|
===================================================================*/
|
|
HRESULT UnInitCachedBSTRs()
|
|
{
|
|
if (g_bstrApplication)
|
|
{
|
|
SysFreeString(g_bstrApplication);
|
|
g_bstrApplication = NULL;
|
|
}
|
|
if (g_bstrRequest)
|
|
{
|
|
SysFreeString(g_bstrRequest);
|
|
g_bstrRequest = NULL;
|
|
}
|
|
if (g_bstrResponse)
|
|
{
|
|
SysFreeString(g_bstrResponse);
|
|
g_bstrResponse = NULL;
|
|
}
|
|
if (g_bstrServer)
|
|
{
|
|
SysFreeString(g_bstrServer);
|
|
g_bstrServer = NULL;
|
|
}
|
|
if (g_bstrCertificate)
|
|
{
|
|
SysFreeString(g_bstrCertificate);
|
|
g_bstrCertificate = NULL;
|
|
}
|
|
if (g_bstrSession)
|
|
{
|
|
SysFreeString(g_bstrSession);
|
|
g_bstrSession = NULL;
|
|
}
|
|
if (g_bstrScriptingNamespace)
|
|
{
|
|
SysFreeString(g_bstrScriptingNamespace);
|
|
g_bstrScriptingNamespace = NULL;
|
|
}
|
|
if (g_bstrObjectContext)
|
|
{
|
|
SysFreeString(g_bstrObjectContext);
|
|
g_bstrObjectContext = NULL;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
// Cached typeinfo's
|
|
ITypeInfo *g_ptinfoIDispatch = NULL; // Cache IDispatch typeinfo
|
|
ITypeInfo *g_ptinfoIUnknown = NULL; // Cache IUnknown typeinfo
|
|
ITypeInfo *g_ptinfoIStringList = NULL; // Cache IStringList typeinfo
|
|
ITypeInfo *g_ptinfoIRequestDictionary = NULL; // Cache IRequestDictionary typeinfo
|
|
ITypeInfo *g_ptinfoIReadCookie = NULL; // Cache IReadCookie typeinfo
|
|
ITypeInfo *g_ptinfoIWriteCookie = NULL; // Cache IWriteCookie typeinfo
|
|
|
|
/*===================================================================
|
|
CacheStdTypeInfos
|
|
|
|
This is kindofa funny OA-threading bug workaround and perf improvement.
|
|
Because we know that they typinfo's for IUnknown and IDispatch are
|
|
going to be used like mad, we will load them on startup and keep
|
|
them addref'ed. Without this, OA would be loading and unloading
|
|
their typeinfos on almost every Invoke.
|
|
|
|
Also, cache denali's typelib so everyone can get at it, and
|
|
cache tye typeinfo's of all our non-top-level intrinsics.
|
|
|
|
Returns:
|
|
HRESULT - S_OK on success
|
|
|
|
Side effects:
|
|
===================================================================*/
|
|
HRESULT CacheStdTypeInfos()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ITypeLib *pITypeLib = NULL;
|
|
CMBCSToWChar convStr;
|
|
|
|
/*
|
|
* Load the typeinfos for IUnk and IDisp
|
|
*/
|
|
hr = LoadRegTypeLib(IID_StdOle,
|
|
STDOLE2_MAJORVERNUM,
|
|
STDOLE2_MINORVERNUM,
|
|
STDOLE2_LCID,
|
|
&pITypeLib);
|
|
if (hr != S_OK)
|
|
{
|
|
hr = LoadTypeLibEx(OLESTR("stdole2.tlb"), REGKIND_DEFAULT, &pITypeLib);
|
|
}
|
|
|
|
hr = pITypeLib->GetTypeInfoOfGuid(IID_IDispatch, &g_ptinfoIDispatch);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pITypeLib->GetTypeInfoOfGuid(IID_IUnknown, &g_ptinfoIUnknown);
|
|
}
|
|
|
|
pITypeLib->Release();
|
|
pITypeLib = NULL;
|
|
|
|
if (FAILED(hr))
|
|
goto LFail;
|
|
|
|
/*
|
|
* Load denali's typelibs. Save them in Glob.
|
|
*/
|
|
|
|
/*
|
|
* The type libraries are registered under 0 (neutral),
|
|
* and 9 (English) with no specific sub-language, which
|
|
* would make them 407 or 409 and such.
|
|
* If we become sensitive to sub-languages, then use the
|
|
* full LCID instead of just the LANGID as done here.
|
|
*/
|
|
|
|
char szPath[MAX_PATH];
|
|
|
|
// Get the path for denali so we can look for the TLB there.
|
|
if (!GetModuleFileNameA(g_hinstDLL, szPath, sizeof(szPath)/sizeof(char)))
|
|
return E_FAIL;
|
|
|
|
if (FAILED(hr = convStr.Init(szPath)))
|
|
goto LFail;
|
|
|
|
hr = LoadTypeLibEx(convStr.GetString(), REGKIND_DEFAULT, &pITypeLib);
|
|
|
|
// Since it's presumably in our DLL, make sure that we loaded it.
|
|
Assert (SUCCEEDED(hr));
|
|
if (FAILED(hr))
|
|
goto LFail;
|
|
|
|
// Save it in Glob
|
|
gGlob.m_pITypeLibDenali = pITypeLib;
|
|
|
|
/*
|
|
* Now cache the typeinfo's of all non-top-level intrinsics
|
|
* This is for the OA workaround and for performance.
|
|
*/
|
|
hr = pITypeLib->GetTypeInfoOfGuid(IID_IStringList, &g_ptinfoIStringList);
|
|
if (FAILED(hr))
|
|
goto LFail;
|
|
hr = pITypeLib->GetTypeInfoOfGuid(IID_IRequestDictionary, &g_ptinfoIRequestDictionary);
|
|
if (FAILED(hr))
|
|
goto LFail;
|
|
hr = pITypeLib->GetTypeInfoOfGuid(IID_IReadCookie, &g_ptinfoIReadCookie);
|
|
if (FAILED(hr))
|
|
goto LFail;
|
|
hr = pITypeLib->GetTypeInfoOfGuid(IID_IWriteCookie, &g_ptinfoIWriteCookie);
|
|
if (FAILED(hr))
|
|
goto LFail;
|
|
|
|
LFail:
|
|
return(hr);
|
|
}
|
|
|
|
/*===================================================================
|
|
UnCacheStdTypeInfos
|
|
|
|
Release the typeinfo's we have cached for IUnknown and IDispatch
|
|
and the denali typelib and the other cached stuff.
|
|
|
|
Returns:
|
|
HRESULT - S_OK on success
|
|
|
|
Side effects:
|
|
===================================================================*/
|
|
HRESULT UnCacheStdTypeInfos()
|
|
{
|
|
ITypeInfo **ppTypeInfo;
|
|
|
|
// Release the typeinfos for IUnk and IDisp
|
|
if (g_ptinfoIDispatch)
|
|
{
|
|
g_ptinfoIDispatch->Release();
|
|
g_ptinfoIDispatch = NULL;
|
|
}
|
|
if (g_ptinfoIUnknown)
|
|
{
|
|
g_ptinfoIUnknown->Release();
|
|
g_ptinfoIDispatch = NULL;
|
|
}
|
|
|
|
// Let go of the cached Denali typelibs
|
|
Glob(pITypeLibDenali)->Release();
|
|
|
|
// Let go of other cached typeinfos
|
|
g_ptinfoIStringList->Release();
|
|
g_ptinfoIRequestDictionary->Release();
|
|
g_ptinfoIReadCookie->Release();
|
|
g_ptinfoIWriteCookie->Release();
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
/*===================================================================
|
|
InitODBC
|
|
|
|
Based on the registry Entry value for StartConnectionPool
|
|
we will initialize the ODBC Connection Pool.
|
|
This initialization requires no un-init call
|
|
|
|
StartConnectionPool = TRUE - turn on connection pooling
|
|
StartConnectionPool = FALSE
|
|
|
|
Returns:
|
|
Void - no return value
|
|
===================================================================*/
|
|
/*void InitODBC(void)
|
|
{
|
|
|
|
if (!Glob(fStartConnectionPool))
|
|
return;
|
|
|
|
signed short rc;
|
|
|
|
// define the function pointer type
|
|
typedef signed short(CALLBACK *PFNSQLSetEnvAttr)
|
|
(
|
|
DWORD, DWORD, void*, DWORD
|
|
);
|
|
|
|
// declare the function pointer
|
|
PFNSQLSetEnvAttr pfnSQLSetEnvAttr;
|
|
g_hODBC32Lib = LoadLibrary("odbc32.dll");
|
|
if(g_hODBC32Lib)
|
|
{
|
|
pfnSQLSetEnvAttr = (PFNSQLSetEnvAttr) GetProcAddress(g_hODBC32Lib, "SQLSetEnvAttr");
|
|
|
|
if (pfnSQLSetEnvAttr)
|
|
rc = (*pfnSQLSetEnvAttr)(0UL, 201UL, (void*)2UL, 0UL);
|
|
// rc = SQLSetEnvAttr(SQL_NULL_HENV, SQL_ATTR_CONNECTION_POOLING, (void*)SQL_CP_ONE_PER_HENV,0)
|
|
// I did not want to include all of the SQL h files so I hard-coded the values
|
|
// for the constants
|
|
|
|
}
|
|
}
|
|
*/
|
|
/*===================================================================
|
|
UnInitODBC
|
|
|
|
Based on the registry Entry value for StartConnectionPool
|
|
we will free the odbc32.dll that was loaded with InitODBC
|
|
|
|
StartConnectionPool = TRUE - turn on connection pooling
|
|
StartConnectionPool = FALSE
|
|
|
|
|
|
Returns:
|
|
Void - no return value
|
|
===================================================================*/
|
|
/*
|
|
void UnInitODBC(void)
|
|
{
|
|
if (!Glob(fStartConnectionPool))
|
|
return;
|
|
|
|
if (g_hODBC32Lib)
|
|
FreeLibrary(g_hODBC32Lib);
|
|
}
|
|
*/
|
|
/*===================================================================
|
|
MakeAspCookieName
|
|
|
|
Creates the asp cookie name as concatination of standard prefix and
|
|
current process id.
|
|
|
|
This function is called once per ASP.DLL (oon DllInit())
|
|
|
|
Parameters:
|
|
szCookie [out] Put cookie name here
|
|
|
|
Returns:
|
|
NOTHING
|
|
===================================================================*/
|
|
static void MakeAspCookieName(char *szCookie)
|
|
{
|
|
// Standard prefix
|
|
strcpy(szCookie, SZ_SESSION_ID_COOKIE_PREFIX);
|
|
szCookie += CCH_SESSION_ID_COOKIE_PREFIX;
|
|
|
|
// Process ID
|
|
sprintf(szCookie, "%08x", GetCurrentProcessId());
|
|
|
|
// Uppercase
|
|
strupr(szCookie);
|
|
|
|
// Change digits to letters
|
|
static const char *pszDigitsToLetters[2] = {"GHIJKLMNOP","QRSTUVWXYZ"};
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
int ch = szCookie[i];
|
|
if (ch >= '0' && ch <= '9')
|
|
szCookie[i] = pszDigitsToLetters[rand() % 2][ch - '0'];
|
|
}
|
|
}
|
|
|
|
/*===================================================================
|
|
SendHtmlSubstitute
|
|
|
|
Send the html file named XXX_ASP.HTM instead of rejecting the
|
|
request.
|
|
|
|
Parameters:
|
|
pIReq CIsapiReqInfo
|
|
|
|
Returns:
|
|
HRESULT (S_FALSE = no html substitute found)
|
|
===================================================================*/
|
|
HRESULT SendHtmlSubstitute(CIsapiReqInfo *pIReq)
|
|
{
|
|
TCHAR *szAspPath = pIReq->QueryPszPathTranslated();
|
|
DWORD cchAspPath = pIReq->QueryCchPathTranslated();
|
|
|
|
// verify file name
|
|
if (cchAspPath < 4 || cchAspPath > MAX_PATH ||
|
|
_tcsicmp(szAspPath + cchAspPath - 4, _T(".asp")) != 0)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
// construct path of the html file
|
|
TCHAR szHtmPath[MAX_PATH+5];
|
|
DWORD cchHtmPath = cchAspPath + 4;
|
|
_tcscpy(szHtmPath, szAspPath);
|
|
szHtmPath[cchAspPath - 4] = _T('_');
|
|
_tcscpy(szHtmPath + cchAspPath, _T(".htm"));
|
|
|
|
// check if the html file exists
|
|
if (FAILED(AspGetFileAttributes(szHtmPath)))
|
|
return S_FALSE;
|
|
|
|
return CResponse::SyncWriteFile(pIReq, szHtmPath);
|
|
}
|
|
|
|
|
|
|
|
#ifdef LOG_FCNOTIFICATIONS
|
|
// UNDONE get this from registry
|
|
LPSTR g_szNotifyLogFile = "C:\\Temp\\AspNotify.Log";
|
|
HANDLE g_hfileNotifyLog;
|
|
HANDLE g_hmapNotifyLog;
|
|
char* g_pchNotifyLogStart;
|
|
char* g_pchNotifyLogCurrent;
|
|
LPSTR g_szNotifyPrefix = "File change notification: ";
|
|
LPSTR g_szCreateHandlePrefix = "Create handle: ";
|
|
|
|
void LfcnCreateLogFile()
|
|
{
|
|
DWORD dwErrCode;
|
|
|
|
if(INVALID_HANDLE_VALUE != (g_hfileNotifyLog =
|
|
CreateFile(
|
|
g_szNotifyLogFile, // file name
|
|
GENERIC_READ | GENERIC_WRITE, // access (read-write) mode
|
|
FILE_SHARE_READ, // share mode
|
|
NULL, // pointer to security descriptor
|
|
CREATE_ALWAYS, // how to create
|
|
FILE_ATTRIBUTE_NORMAL, // file attributes
|
|
NULL // handle to file with attributes to copy
|
|
)))
|
|
{
|
|
BYTE rgb[0x10000];
|
|
DWORD cb = sizeof( rgb );
|
|
DWORD cbWritten = 0;
|
|
// FillMemory( rgb, cb, 0xAB );
|
|
|
|
WriteFile(
|
|
g_hfileNotifyLog, // handle to file to write to
|
|
rgb, // pointer to data to write to file
|
|
cb, // number of bytes to write
|
|
&cbWritten, // pointer to number of bytes written
|
|
NULL // pointer to structure needed for overlapped I/O
|
|
);
|
|
|
|
if(NULL != (g_hmapNotifyLog =
|
|
CreateFileMapping(
|
|
g_hfileNotifyLog, // handle to file to map
|
|
NULL, // optional security attributes
|
|
PAGE_READWRITE, // protection for mapping object
|
|
0, // high-order 32 bits of object size
|
|
100, // low-order 32 bits of object size
|
|
NULL // name of file-mapping object
|
|
)))
|
|
{
|
|
if(NULL != (g_pchNotifyLogStart =
|
|
(char*) MapViewOfFile(
|
|
g_hmapNotifyLog, // file-mapping object to map into address space
|
|
FILE_MAP_WRITE, // access mode
|
|
0, // high-order 32 bits of file offset
|
|
0, // low-order 32 bits of file offset
|
|
0 // number of bytes to map
|
|
)))
|
|
{
|
|
*g_pchNotifyLogStart = '\0';
|
|
g_pchNotifyLogCurrent = g_pchNotifyLogStart;
|
|
LfcnAppendLog( "ASP change-notifications log file \r\n" );
|
|
LfcnAppendLog( "================================= \r\n" );
|
|
DBGPRINTF((DBG_CONTEXT, "Notifications log file created and mapped.\r\n" ));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
dwErrCode = GetLastError();
|
|
DBGERROR((DBG_CONTEXT, "Failed to create notifications log file; last error was %d\r\n", szErrCode));
|
|
}
|
|
|
|
void LfcnCopyAdvance(char** ppchDest, const char* sz)
|
|
{
|
|
// UNDONE make this robust (WriteFile to extend file?)
|
|
strcpy( *ppchDest, sz );
|
|
*ppchDest += strlen( sz );
|
|
}
|
|
|
|
void LfcnAppendLog(const char* sz)
|
|
{
|
|
LfcnCopyAdvance( &g_pchNotifyLogCurrent, sz );
|
|
DBGPRINTF((DBG_CONTEXT, "%s", sz));
|
|
}
|
|
|
|
void LfcnLogNotification(char* szFile)
|
|
{
|
|
LfcnAppendLog( g_szNotifyPrefix );
|
|
LfcnAppendLog( szFile );
|
|
LfcnAppendLog( "\r\n" );
|
|
}
|
|
|
|
void LfcnLogHandleCreation(int i, char* szApp)
|
|
{
|
|
char szIndex[5];
|
|
_itoa( i, szIndex, 10);
|
|
|
|
LfcnAppendLog( g_szCreateHandlePrefix );
|
|
LfcnAppendLog( szIndex );
|
|
LfcnAppendLog( "\t" );
|
|
LfcnAppendLog( szApp );
|
|
LfcnAppendLog( "\r\n" );
|
|
}
|
|
|
|
void LfcnUnmapLogFile()
|
|
{
|
|
if(g_pchNotifyLogStart != NULL)
|
|
UnmapViewOfFile(g_pchNotifyLogStart);
|
|
|
|
if(g_hmapNotifyLog!= NULL)
|
|
CloseHandle(g_hmapNotifyLog);
|
|
|
|
if(g_hfileNotifyLog != NULL && g_hfileNotifyLog != INVALID_HANDLE_VALUE)
|
|
CloseHandle( g_hfileNotifyLog );
|
|
|
|
g_pchNotifyLogStart = NULL;
|
|
g_hmapNotifyLog = NULL;
|
|
g_hfileNotifyLog = NULL;
|
|
}
|
|
|
|
#endif //LOG_FCNOTIFICATIONS
|
|
|
|
#if _IIS_5_1
|
|
LONG CWamModule::Lock()
|
|
{
|
|
return CComModule::Lock();
|
|
}
|
|
|
|
LONG CWamModule::Unlock()
|
|
{
|
|
return CComModule::Unlock();
|
|
}
|
|
#endif
|