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.
505 lines
12 KiB
505 lines
12 KiB
/*
|
|
* E N T R Y . C P P
|
|
*
|
|
* Entrypoints for Caligula DLLs
|
|
*
|
|
* Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
|
|
*/
|
|
|
|
#include "_davfs.h"
|
|
#include "_shlkmgr.h"
|
|
#include <langtocpid.h>
|
|
#include <ex\idlethrd.h>
|
|
#include <ntverp.h>
|
|
#include <iisver.h>
|
|
|
|
// Global items --------------------------------------------------------------
|
|
//
|
|
EXTERN_C const CHAR gc_szSignature[] = "HTTPEXT";
|
|
EXTERN_C const WCHAR gc_wszSignature[] = L"HTTPEXT";
|
|
HINSTANCE g_hinst = NULL;
|
|
WCHAR gc_wszDllPath[MAX_PATH+1];
|
|
|
|
CHAR gc_szVersion[] = VER_PRODUCTVERSION_STR;
|
|
|
|
// Per process instance data -------------------------------------------------
|
|
//
|
|
class CImplInst : private RefCountedGlobal<CImplInst, HSE_VERSION_INFO *>
|
|
{
|
|
//
|
|
// Friend declarations required by RefCountedGlobal template
|
|
//
|
|
friend class Singleton<CImplInst>;
|
|
friend class RefCountedGlobal<CImplInst, HSE_VERSION_INFO *>;
|
|
|
|
//
|
|
// Flags to track initialization progress so we know
|
|
// how much to uninitialize if initialization fails overall
|
|
//
|
|
BOOL m_fInitializedHeap;
|
|
|
|
// CREATORS
|
|
//
|
|
// Declared private to ensure that arbitrary instances
|
|
// of this class cannot be created. The Singleton
|
|
// template (declared as a friend above) controls
|
|
// the sole instance of this class.
|
|
//
|
|
CImplInst() :
|
|
m_fInitializedHeap(FALSE)
|
|
{
|
|
}
|
|
BOOL FInit( HSE_VERSION_INFO * pver );
|
|
~CImplInst();
|
|
|
|
//
|
|
// Array of strings used in service state change
|
|
// event log messages.
|
|
//
|
|
static LPCSTR mc_rgszLogServiceStateChange[];
|
|
|
|
// NOT IMPLEMENTED
|
|
//
|
|
CImplInst( const CImplInst& );
|
|
CImplInst& operator=( const CImplInst& );
|
|
|
|
public:
|
|
using RefCountedGlobal<CImplInst, HSE_VERSION_INFO *>::DwInitRef;
|
|
using RefCountedGlobal<CImplInst, HSE_VERSION_INFO *>::DeinitRef;
|
|
};
|
|
|
|
LPCSTR CImplInst::mc_rgszLogServiceStateChange[] = { gc_szSignature, gc_szVersion };
|
|
|
|
STGOPENSTORAGEONHANDLE g_pfnStgOpenStorageOnHandle = NULL;
|
|
|
|
#ifdef DBG
|
|
BOOL g_fDavTrace = FALSE;
|
|
DEC_CONST CHAR gc_szDbgIni[] = "HTTPEXT.INI";
|
|
DEC_CONST INT gc_cchDbgIni = CchConstString(gc_szDbgIni);
|
|
#endif
|
|
|
|
// ------------------------------------------------------------------------
|
|
//
|
|
// CImplInst::FInit()
|
|
//
|
|
// Second-phase (failable) CImplInst constructor. Code that instantiates
|
|
// the CImplInst should call this function after instantiation. If the
|
|
// call returns FALSE, calling code should immediately destroy the
|
|
// CImplInst.
|
|
//
|
|
BOOL
|
|
CImplInst::FInit( HSE_VERSION_INFO * pver )
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
//
|
|
// Handle exceptions locally. If anything below throws
|
|
// an exception then fail the initialization.
|
|
//
|
|
try
|
|
{
|
|
HINSTANCE hLib;
|
|
|
|
// First and foremost, check to ensure that
|
|
// our resources are well attached and accessible
|
|
// if this fails, then we want to fail our loading.
|
|
//
|
|
if (!LoadStringA (g_hinst,
|
|
IDS_ExtensionName,
|
|
pver->lpszExtensionDesc,
|
|
sizeof(pver->lpszExtensionDesc)))
|
|
goto Exit;
|
|
|
|
// Setup the HSE version numbering
|
|
//
|
|
pver->dwExtensionVersion = MAKELONG (HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
|
|
|
|
#ifdef DBG
|
|
// Do the DBG tracing initialization
|
|
//
|
|
g_fDavTrace = GetPrivateProfileIntA (gc_szDbgTraces,
|
|
gc_szSignature,
|
|
FALSE,
|
|
gc_szDbgIni);
|
|
#endif // DBG
|
|
|
|
// Init the heap allocators
|
|
//
|
|
if ( !g_heap.FInit() )
|
|
goto Exit;
|
|
m_fInitializedHeap = TRUE;
|
|
|
|
// Initialize the resource string cache
|
|
//
|
|
if ( !FInitResourceStringCache() )
|
|
goto Exit;
|
|
|
|
// Init the volume type cache
|
|
//
|
|
if ( !FInitVolumeTypeCache() )
|
|
goto Exit;
|
|
|
|
// Init the parser
|
|
//
|
|
if ( !CDAVExt::FVersion (pver) )
|
|
goto Exit;
|
|
|
|
// Create shared lock mgr
|
|
//
|
|
if (FAILED(CSharedLockMgr::CreateInstance().HrInitialize()))
|
|
goto Exit;
|
|
|
|
// Create the thread pool
|
|
//
|
|
if (!CPoolManager::FInit())
|
|
goto Exit;
|
|
|
|
// Start the idle thread
|
|
//
|
|
if ( !FInitIdleThread() )
|
|
goto Exit;
|
|
|
|
// Init the cache mapping accept language string to cpid
|
|
// cache used to decode non-UTF8 characters in URLs
|
|
//
|
|
if (!CLangToCpidCache::FCreateInstance())
|
|
goto Exit;
|
|
|
|
// If this API is not available on ole32.dll. we'll not be able
|
|
// to operate properties, but we should still work to some extent
|
|
// so we'll take care of the NULL function pointer in our code.
|
|
// don't fail now
|
|
//
|
|
// Don't use relative paths for dlls, It is easy to put suspect dlls
|
|
// somewhere in an application's path. Always use absolute paths.
|
|
//
|
|
CHAR szOle32Path[MAX_PATH+1];
|
|
UINT cSystemDir;
|
|
|
|
// Get the system directory
|
|
//
|
|
cSystemDir = GetSystemDirectory (szOle32Path, CElems(szOle32Path));
|
|
|
|
// GetSystemDirectory will return
|
|
// 1. the number of characters copied if it succeeds (excluding the
|
|
// terminating NULL)
|
|
// 2. 0 if it fails
|
|
// 3. the number of characters required if the supplied buffer is
|
|
// too smallto hold the path.
|
|
// Since we gave enough space for the system
|
|
// directory, we will treat "buffer not enough" errors as failures.
|
|
//
|
|
if ((0 < cSystemDir) && (CElems(szOle32Path) > cSystemDir))
|
|
{
|
|
// GetSystemDirectory path does not end with a backslash
|
|
//
|
|
if (CElems("\\ole32.dll") + cSystemDir <= CElems(szOle32Path))
|
|
{
|
|
strcat(szOle32Path, "\\ole32.dll");
|
|
hLib = LoadLibraryA (szOle32Path);
|
|
if (hLib)
|
|
{
|
|
g_pfnStgOpenStorageOnHandle = (STGOPENSTORAGEONHANDLE)
|
|
GetProcAddress (hLib, "StgOpenStorageOnHandle");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Start up event log message takes two parameters
|
|
// the signature and the version
|
|
//
|
|
#undef LOG_STARTUP_EVENT
|
|
#ifdef LOG_STARTUP_EVENT
|
|
LogEvent (DAVPRS_SERVICE_STARTUP,
|
|
EVENTLOG_INFORMATION_TYPE,
|
|
sizeof(mc_rgszLogServiceStateChange) / sizeof(LPCSTR),
|
|
mc_rgszLogServiceStateChange,
|
|
0,
|
|
NULL);
|
|
#endif // LOG_STARTUP_EVENT
|
|
}
|
|
catch ( CDAVException& )
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
//
|
|
// CImplInst::~CImplInst()
|
|
//
|
|
CImplInst::~CImplInst()
|
|
{
|
|
//
|
|
// DO NOT allow exceptions to propagate out of this call.
|
|
// This is intended as a safety valve only. In order to
|
|
// avoid leaking instance data, individual instance data
|
|
// components should handle any exceptions themselves.
|
|
//
|
|
try
|
|
{
|
|
//
|
|
// If we logged a startup message, then log a shutdown message
|
|
//
|
|
#undef LOG_STARTUP_EVENT
|
|
#ifdef LOG_STARTUP_EVENT
|
|
LogEvent (DAVPRS_SERVICE_SHUTDOWN,
|
|
EVENTLOG_INFORMATION_TYPE,
|
|
sizeof(mc_rgszLogServiceStateChange) / sizeof(LPCSTR),
|
|
mc_rgszLogServiceStateChange,
|
|
0,
|
|
NULL);
|
|
#endif // LOG_STARTUP_EVENT
|
|
|
|
//
|
|
// Deinit the idle thread. Do this before taking down the
|
|
// thread pool there may be delayed thread pool work items
|
|
// pending on the idle thread.
|
|
//
|
|
DeleteIdleThread();
|
|
|
|
//
|
|
// Deinit the thread pool
|
|
//
|
|
CPoolManager::Deinit();
|
|
|
|
// Deinit the language string to cpid cache
|
|
//
|
|
CLangToCpidCache::DestroyInstance();
|
|
|
|
//
|
|
// remove the IDBCreateCommand if exist
|
|
//
|
|
ReleaseDBCreateCommandObject();
|
|
|
|
// Destroy shared lock mgr
|
|
//
|
|
CSharedLockMgr::DestroyInstance();
|
|
|
|
// Shutdown the parser
|
|
//
|
|
(void) CDAVExt::FTerminate ();
|
|
|
|
// Deinit the volume type cache
|
|
//
|
|
DeinitVolumeTypeCache();
|
|
|
|
// Clean out the security-thread-token cache.
|
|
//
|
|
CleanupSecurityToken();
|
|
|
|
// Deinit the resource string cache
|
|
//
|
|
DeinitResourceStringCache();
|
|
|
|
// Destroy allocators
|
|
//
|
|
if ( m_fInitializedHeap )
|
|
g_heap.Deinit();
|
|
}
|
|
catch ( CDAVException& )
|
|
{
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
//
|
|
// Instance refcounting callouts from _davprs
|
|
//
|
|
VOID AddRefImplInst()
|
|
{
|
|
HSE_VERSION_INFO lVer;
|
|
DWORD cRef;
|
|
|
|
cRef = CImplInst::DwInitRef(&lVer);
|
|
|
|
//
|
|
// We should already have at least one ref on the instance
|
|
// before we called DwInitRef(), so we should more than one
|
|
// ref after the call.
|
|
//
|
|
Assert( cRef > 1 );
|
|
}
|
|
|
|
VOID ReleaseImplInst()
|
|
{
|
|
CImplInst::DeinitRef();
|
|
}
|
|
|
|
// IIS Entrypoints -----------------------------------------------------------
|
|
//
|
|
EXTERN_C BOOL WINAPI
|
|
FGetExtensionVersion (HSE_VERSION_INFO * pver)
|
|
{
|
|
CWin32ExceptionHandler win32ExceptionHandler;
|
|
|
|
//
|
|
// Initialize one instance reference and return whether it succeeded.
|
|
//
|
|
return !!CImplInst::DwInitRef( pver );
|
|
}
|
|
|
|
EXTERN_C BOOL WINAPI
|
|
FTerminateDavFS (DWORD)
|
|
{
|
|
CWin32ExceptionHandler win32ExceptionHandler;
|
|
|
|
//
|
|
// Deinitialize one instance reference
|
|
//
|
|
CImplInst::DeinitRef();
|
|
|
|
//
|
|
// After the instance data has been released, we are ready to terminate.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
EXTERN_C DWORD WINAPI
|
|
DwDavFSExtensionProc (LPEXTENSION_CONTROL_BLOCK pecb)
|
|
{
|
|
HSE_VERSION_INFO lVer;
|
|
|
|
DWORD dwHSEStatusRet = HSE_STATUS_ERROR;
|
|
|
|
if ( CImplInst::DwInitRef(&lVer) )
|
|
{
|
|
dwHSEStatusRet = CDAVExt::DwMain(pecb);
|
|
|
|
CImplInst::DeinitRef();
|
|
}
|
|
|
|
return dwHSEStatusRet;
|
|
}
|
|
|
|
// Win32 DLL Entrypoints -----------------------------------------------------
|
|
//
|
|
EXTERN_C BOOL WINAPI
|
|
DllMain (HINSTANCE hinst, DWORD dwReason, LPVOID lpvReserved)
|
|
{
|
|
switch (dwReason)
|
|
{
|
|
default:
|
|
{
|
|
DebugTrace ("FInitHttpExtDll(), unknown reason\n");
|
|
return FALSE;
|
|
}
|
|
|
|
case DLL_THREAD_ATTACH:
|
|
case DLL_THREAD_DETACH:
|
|
{
|
|
//
|
|
// We disable thread library calls (see below),
|
|
// so we should never see DLL_THREAD_ATTACH or
|
|
// DLL_THREAD_DETACH.
|
|
//
|
|
Assert (FALSE);
|
|
|
|
//
|
|
// But if we do, it doesn't harm anything.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
case DLL_PROCESS_ATTACH:
|
|
{
|
|
//
|
|
// Init .INI file tagged debug traces
|
|
//
|
|
InitTraces();
|
|
|
|
// Cache the inst
|
|
//
|
|
g_hinst = hinst;
|
|
|
|
// And the full path to the DLL
|
|
//
|
|
if ( !GetModuleFileNameW( hinst, gc_wszDllPath, sizeof(gc_wszDllPath)/sizeof(WCHAR) ) )
|
|
{
|
|
DebugTrace( "FInitHttpExtDll() - GetModuleFileName() failed in DLL_PROCESS_ATTACH\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
// Call the parser's initialization for every call into our
|
|
// DLL initialization proc. The order of operations here is
|
|
// fairly important. The parser should be called after we do
|
|
// our processing in the non-DETACH case.
|
|
//
|
|
if ( !CDAVExt::FInitializeDll (hinst, dwReason) )
|
|
return FALSE;
|
|
|
|
// We are going to disable thread library calls. If the parser
|
|
// really ever needs these then the this needs to change.
|
|
//
|
|
DisableThreadLibraryCalls (hinst);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
{
|
|
// And in the detach case, the impl. gets the last word.
|
|
// Ignore any failures -- the DLL is being unloaded and
|
|
// the process is going away whether we like it or not.
|
|
//
|
|
(void) CDAVExt::FInitializeDll (hinst, dwReason);
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// OLE Entrypoints -----------------------------------------------------------
|
|
//
|
|
STDAPI
|
|
HrDllCanUnloadNowDavFS (VOID)
|
|
{
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDAPI
|
|
HrDllGetClassObjectDavFS (REFCLSID rclsid, REFIID riid, LPVOID * ppv)
|
|
{
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
STDAPI
|
|
HrDllRegisterServerDavFS (VOID)
|
|
{
|
|
HRESULT hr;
|
|
|
|
// This is a "first line" entrypoint into our dll. Need to init some stuff.
|
|
// Right now, the heap is the only important piece.
|
|
//
|
|
g_heap.FInit();
|
|
|
|
// Everybody gets to register regardless of failures
|
|
//
|
|
hr = EventLogDllRegisterServer( gc_wszDllPath );
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDAPI
|
|
HrDllUnregisterServerDavFS (VOID)
|
|
{
|
|
HRESULT hr;
|
|
|
|
// This is a "first line" entrypoint into our dll. Need to init some stuff.
|
|
// Right now, the heap is the only important piece.
|
|
//
|
|
g_heap.FInit();
|
|
|
|
// Everybody gets to unregister regardless of failures
|
|
//
|
|
hr = EventLogDllUnregisterServer();
|
|
|
|
return hr;
|
|
}
|