windows-nt/Source/XPSP1/NT/base/fs/hsm/hsmservr/hsmservr.cpp
2020-09-26 16:20:57 +08:00

1009 lines
31 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.

/*++
Module Name:
hsmservr.cpp
Abstract:
Provides the Service and main executable implementation.
Author:
Ran Kalach [rankala]
Revision History:
--*/
// Note: Proxy/Stub Information
// To build a separate proxy/stub DLL,
// run nmake -f hsmservrps.mk in the project directory.
#include "stdafx.h"
#include "resource.h"
#include "engcommn.h"
// This include is here due to a MIDL bug - it should have been in the created file hsmservr.h
#include "fsalib.h"
#include "hsmservr.h"
#include <stdio.h>
#include "hsmconpt.h"
// Service dependencies for the HSM server service
#define ENG_DEPENDENCIES L"EventLog\0RpcSs\0Schedule\0NtmsSvc\0\0"
// Service name
#define SERVICE_LOGICAL_NAME _T("Remote_Storage_Server")
#define SERVICE_DISPLAY_NAME L"Remote Storage Server"
CServiceModule _Module;
BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRY(CLSID_HsmConnPoint, CHsmConnPoint)
END_OBJECT_MAP()
// The global server objects
IHsmServer *g_pEngServer;
IFsaServer *g_pFsaServer;
BOOL g_bEngCreated = FALSE;
BOOL g_bEngInitialized = FALSE;
BOOL g_bFsaCreated = FALSE;
BOOL g_bFsaInitialized = FALSE;
CRITICAL_SECTION g_FsaCriticalSection;
CRITICAL_SECTION g_EngCriticalSection;
#define HSM_SERVER_TRACE_FILE_NAME OLESTR("rsserv.trc")
CComPtr<IWsbTrace> g_pTrace;
// Global functions for console handling
static void ConsoleApp(void);
BOOL WINAPI ConsoleHandler(DWORD dwCtrlType);
static void DebugRelease (void);
// Although some of these functions are big they are declared inline since they are only used once
inline HRESULT CServiceModule::RegisterServer(BOOL bRegTypeLib)
{
WsbTraceIn ( L"CServiceModule::RegisterServer", L"bRegTypeLib = %ls", WsbBoolAsString ( bRegTypeLib ) );
HRESULT hr = S_OK;
try {
WsbAssertHr ( CoInitialize ( NULL ) );
//
// Do not try to remove any previous service since this can cause a delay
// in the registration to happen when another process is trying to get
// this program to self register
//
//
// Add service entries
//
WsbAssertHr( UpdateRegistryFromResource( IDR_Hsmservr, TRUE ) );
//
// Create service
//
WsbAssert( Install(), E_FAIL ) ;
//
// Add object entries
//
WsbAssertHr ( CComModule::RegisterServer( bRegTypeLib ) );
CoUninitialize();
}WsbCatch ( hr )
WsbTraceOut ( L"CServiceModule::RegisterServer", L"HRESULT = %ls", WsbHrAsString ( hr ) );
return( hr );
}
inline HRESULT CServiceModule::UnregisterServer()
{
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
return hr;
// Remove service entries
UpdateRegistryFromResource(IDR_Hsmservr, FALSE);
// Remove service
Uninstall();
// Remove object entries
CComModule::UnregisterServer();
CoUninitialize();
return S_OK;
}
inline void CServiceModule::Init(_ATL_OBJMAP_ENTRY* p, HINSTANCE h)
{
WsbTraceIn ( L"CServiceModule::Init", L"" );
CComModule::Init(p, h);
m_bService = TRUE;
_tcscpy(m_szServiceName, SERVICE_LOGICAL_NAME);
// set up the initial service status
m_hServiceStatus = NULL;
m_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
m_status.dwCurrentState = SERVICE_STOPPED;
m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN |
SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PAUSE_CONTINUE;
m_status.dwWin32ExitCode = 0;
m_status.dwServiceSpecificExitCode = 0;
m_status.dwCheckPoint = 0;
m_status.dwWaitHint = 0;
WsbTraceOut ( L"CServiceModule::Init", L"" );
}
LONG CServiceModule::Unlock()
{
LONG l = CComModule::Unlock();
/* This line put in comment since it causes the process to immediately exit
if (l == 0 && !m_bService)
PostThreadMessage(dwThreadID, WM_QUIT, 0, 0); */
return l;
}
BOOL CServiceModule::IsInstalled()
{
BOOL bResult = FALSE;
SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCM != NULL) {
SC_HANDLE hService = ::OpenService(hSCM, m_szServiceName, SERVICE_QUERY_CONFIG);
if (hService != NULL) {
bResult = TRUE;
::CloseServiceHandle(hService);
}
::CloseServiceHandle(hSCM);
}
return bResult;
}
inline BOOL CServiceModule::Install()
/*++
Routine Description:
Install service module.
Arguments:
None.
Return Value:
TRUE - Service installed successfully
FALSE - Service install failed
--*/
{
BOOL bResult = FALSE;
CWsbStringPtr errorMessage;
CWsbStringPtr displayName;
CWsbStringPtr description;
if (!IsInstalled()) {
displayName = SERVICE_DISPLAY_NAME;
description.LoadFromRsc(_Module.m_hInst, IDS_SERVICE_DESCRIPTION );
SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCM) {
// Get the executable file path
TCHAR szFilePath[_MAX_PATH];
::GetModuleFileName(NULL, szFilePath, _MAX_PATH);
SC_HANDLE hService = ::CreateService(
hSCM, m_szServiceName, (OLECHAR *) displayName,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
szFilePath, NULL, NULL, ENG_DEPENDENCIES, NULL, NULL);
if (hService) {
// the service was successfully installed.
bResult = TRUE;
SERVICE_DESCRIPTION svcDesc;
svcDesc.lpDescription = description;
::ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &svcDesc);
::CloseServiceHandle(hService);
::CloseServiceHandle(hSCM);
} else {
errorMessage = WsbHrAsString(HRESULT_FROM_WIN32( GetLastError() ) );
::CloseServiceHandle(hSCM);
MessageBox(NULL, errorMessage, (OLECHAR *) displayName, MB_OK);
}
} else {
MessageBox(NULL, WsbHrAsString(HRESULT_FROM_WIN32( GetLastError() ) ), (OLECHAR *) displayName, MB_OK);
}
} else {
// service already install, just return TRUE.
bResult = TRUE;
}
return bResult;
}
inline BOOL CServiceModule::Uninstall()
/*++
Routine Description:
Uninstall service module.
Arguments:
None.
Return Value:
TRUE - Service successfully uninstalled.
FALSE - Unable to uninstall service.
--*/
{
BOOL bResult = FALSE;
CWsbStringPtr errorMessage;
CWsbStringPtr displayName;
if (IsInstalled()) {
displayName = SERVICE_DISPLAY_NAME;
SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCM) {
SC_HANDLE hService = ::OpenService(hSCM, m_szServiceName, DELETE);
if (hService) {
BOOL bDelete = ::DeleteService(hService);
// if it did not delete then get the error message
if (!bDelete)
errorMessage = WsbHrAsString(HRESULT_FROM_WIN32( GetLastError() ) );
::CloseServiceHandle(hService);
::CloseServiceHandle(hSCM);
if (bDelete) {
// the service was deleted.
bResult = TRUE;
} else {
MessageBox(NULL, errorMessage, (OLECHAR *) displayName, MB_OK);
}
} else {
errorMessage = WsbHrAsString(HRESULT_FROM_WIN32( GetLastError() ) );
::CloseServiceHandle(hSCM);
MessageBox(NULL, errorMessage, (OLECHAR *) displayName, MB_OK);
}
} else {
MessageBox(NULL, WsbHrAsString(HRESULT_FROM_WIN32( GetLastError() ) ), (OLECHAR *) displayName, MB_OK);
}
} else {
// service not installed, just return TRUE.
bResult = TRUE;
}
return bResult;
}
///////////////////////////////////////////////////////////////////////////////////////
// Logging functions
//
void
CServiceModule::LogEvent(
DWORD eventId,
...
)
/*++
Routine Description:
Log data to event log.
Arguments:
eventId - The message Id to log.
Inserts - Message inserts that are merged with the message description specified by
eventId. The number of inserts must match the number specified by the
message description. The last insert must be NULL to indicate the
end of the insert list.
Return Value:
None.
--*/
{
if (m_bService) {
// Report the event.
va_list vaList;
va_start(vaList, eventId);
WsbLogEventV( eventId, 0, NULL, &vaList );
va_end(vaList);
} else {
// Just write the error to the console, if we're not running as a service.
va_list vaList;
const OLECHAR * facilityName = 0;
OLECHAR * messageText = 0;
switch ( HRESULT_FACILITY( eventId ) ) {
case WSB_FACILITY_PLATFORM:
case WSB_FACILITY_RMS:
case WSB_FACILITY_HSMENG:
case WSB_FACILITY_JOB:
case WSB_FACILITY_HSMTSKMGR:
case WSB_FACILITY_FSA:
case WSB_FACILITY_GUI:
case WSB_FACILITY_MOVER:
case WSB_FACILITY_LAUNCH:
facilityName = WSB_FACILITY_PLATFORM_NAME;
break;
}
if ( facilityName ) {
// Print out the variable arguments
// NOTE: Positional parameters in the inserts are not processed. These
// are done by ReportEvent() only.
HMODULE hLib = LoadLibraryEx( facilityName, NULL, LOAD_LIBRARY_AS_DATAFILE );
if (hLib != NULL) {
va_start(vaList, eventId);
FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER,
hLib,
eventId,
MAKELANGID ( LANG_NEUTRAL, SUBLANG_DEFAULT ),
(LPTSTR) &messageText,
0,
&vaList );
va_end(vaList);
FreeLibrary(hLib);
}
if ( messageText ) {
_putts(messageText);
LocalFree( messageText );
} else {
_tprintf( OLESTR("!!!!! ERROR !!!!! - Message <0x%08x> could not be translated.\n"), eventId );
}
} else {
_tprintf( OLESTR("!!!!! ERROR !!!!! - Message File for <0x%08x> could not be found.\n"), eventId );
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////
// Service startup and registration
inline void CServiceModule::Start()
{
SERVICE_TABLE_ENTRY st[] =
{
{ m_szServiceName, _ServiceMain},
{ NULL, NULL}
};
if (!::StartServiceCtrlDispatcher(st)) {
m_bService = FALSE;
if (GetLastError()==ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
Run();
}
}
inline void CServiceModule::ServiceMain(DWORD /* dwArgc */, LPTSTR* /* lpszArgv */)
{
SetServiceStatus(SERVICE_START_PENDING);
// Register the control request handler
m_status.dwCurrentState = SERVICE_START_PENDING;
m_hServiceStatus = RegisterServiceCtrlHandlerEx(m_szServiceName, _HandlerEx,
NULL);
if (m_hServiceStatus == NULL) {
LogEvent( HSM_MESSAGE_SERVICE_HANDLER_NOT_INSTALLED, NULL );
return;
}
m_status.dwWin32ExitCode = S_OK;
m_status.dwCheckPoint = 0;
m_status.dwWaitHint = 0;
// When the Run function returns, the service has stopped.
Run();
SetServiceStatus(SERVICE_STOPPED);
LogEvent( HSM_MESSAGE_SERVICE_STOPPED, NULL );
}
inline DWORD CServiceModule::HandlerEx(DWORD dwOpcode, DWORD fdwEventType,
LPVOID /* lpEventData */, LPVOID /* lpContext */)
{
DWORD dwRetCode = 0;
HRESULT hr = S_OK;
HRESULT hr1 = S_OK;
HSM_SYSTEM_STATE SysState;
WsbTraceIn(OLESTR("CServiceModule::HandlerEx"), OLESTR("opCode=%lx"),
dwOpcode );
switch (dwOpcode) {
case SERVICE_CONTROL_STOP: {
SetServiceStatus(SERVICE_STOP_PENDING);
PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
}
break;
case SERVICE_CONTROL_PAUSE:
SetServiceStatus(SERVICE_PAUSE_PENDING);
SysState.State = HSM_STATE_SUSPEND;
if (g_pEngServer && g_bEngInitialized) {
g_pEngServer->ChangeSysState(&SysState);
}
if (g_pFsaServer && g_bFsaInitialized) {
g_pFsaServer->ChangeSysState(&SysState);
}
SetServiceStatus(SERVICE_PAUSED);
break;
case SERVICE_CONTROL_CONTINUE:
SetServiceStatus(SERVICE_CONTINUE_PENDING);
SysState.State = HSM_STATE_RESUME;
if (g_pFsaServer && g_bFsaInitialized) {
g_pFsaServer->ChangeSysState(&SysState);
}
if (g_pEngServer && g_bEngInitialized) {
g_pEngServer->ChangeSysState(&SysState);
}
SetServiceStatus(SERVICE_RUNNING);
break;
case SERVICE_CONTROL_INTERROGATE:
break;
case SERVICE_CONTROL_SHUTDOWN:
// Prepare Eng server for releasing
if (g_pEngServer && g_bEngInitialized) {
SysState.State = HSM_STATE_SHUTDOWN;
if (!SUCCEEDED(hr = g_pEngServer->ChangeSysState(&SysState))) {
LogEvent( HSM_MESSAGE_SERVICE_FAILED_TO_SHUTDOWN, WsbHrAsString(hr), NULL );
}
}
// Prepare Fsa server for releasing
if (g_pFsaServer && g_bFsaInitialized) {
CComPtr<IWsbServer> pWsbServer;
SysState.State = HSM_STATE_SHUTDOWN;
// If it was initialized, then we should try to save the current state.
hr = g_pFsaServer->QueryInterface(IID_IWsbServer, (void**) &pWsbServer);
if (hr == S_OK) {
hr = pWsbServer->SaveAll();
}
if (FAILED(hr)) {
LogEvent(FSA_MESSAGE_SERVICE_FAILED_TO_SAVE_DATABASE, WsbHrAsString(hr), NULL );
}
hr = g_pFsaServer->ChangeSysState(&SysState);
if (FAILED(hr)) {
LogEvent( FSA_MESSAGE_SERVICE_FAILED_TO_SHUTDOWN, WsbHrAsString(hr), NULL );
}
}
// Release Eng server
if (g_bEngCreated && (g_pEngServer != 0)) {
// Free server inside a crit. section thus avoid conflicts with accessing clients
EnterCriticalSection(&g_EngCriticalSection);
g_bEngInitialized = FALSE;
g_bEngCreated = FALSE;
// Disconnect all remote clients
(void)CoDisconnectObject(g_pEngServer, 0);
// Forse object destroy, ignore reference count here
IWsbServer *pWsbServer;
hr = g_pEngServer->QueryInterface(IID_IWsbServer, (void**) &pWsbServer);
if (hr == S_OK) {
pWsbServer->Release();
pWsbServer->DestroyObject();
}
g_pEngServer = 0;
LeaveCriticalSection (&g_EngCriticalSection);
}
// Release Fsa server
if (g_bFsaCreated && (g_pFsaServer != 0)) {
// Free server inside a crit. section thus avoid conflicts with accessing clients
EnterCriticalSection(&g_FsaCriticalSection);
g_bFsaInitialized = FALSE;
g_bFsaCreated = FALSE;
// Disconnect all remote clients
(void)CoDisconnectObject(g_pFsaServer, 0);
// Forse object destroy, ignore reference count here
IWsbServer *pWsbServer;
hr = g_pFsaServer->QueryInterface(IID_IWsbServer, (void**) &pWsbServer);
if (hr == S_OK) {
pWsbServer->Release();
pWsbServer->DestroyObject();
}
g_pFsaServer = 0;
LeaveCriticalSection(&g_FsaCriticalSection);
}
break;
case SERVICE_CONTROL_POWEREVENT:
if (S_OK == WsbPowerEventNtToHsm(fdwEventType, &SysState.State)) {
WsbTrace(OLESTR("CServiceModule::HandlerEx: power event, fdwEventType = %lx\n"),
fdwEventType);
if (g_pEngServer && g_bEngInitialized) {
hr = g_pEngServer->ChangeSysState(&SysState);
}
if (g_pFsaServer && g_bFsaInitialized) {
hr1 = g_pFsaServer->ChangeSysState(&SysState);
}
if ((S_FALSE == hr) || (S_FALSE == hr1)) {
dwRetCode = BROADCAST_QUERY_DENY;
}
}
break;
default:
LogEvent( HSM_MESSAGE_SERVICE_RECEIVED_BAD_REQUEST, NULL );
}
WsbTraceOut(OLESTR("CServiceModule::HandlerEx"), OLESTR("dwRetCode = %lx"),
dwRetCode );
return(dwRetCode);
}
void WINAPI CServiceModule::_ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv)
{
_Module.ServiceMain(dwArgc, lpszArgv);
}
DWORD WINAPI CServiceModule::_HandlerEx(DWORD dwOpcode, DWORD fdwEventType,
LPVOID lpEventData, LPVOID lpContext)
{
return(_Module.HandlerEx(dwOpcode, fdwEventType, lpEventData, lpContext));
}
void CServiceModule::SetServiceStatus(DWORD dwState)
{
m_status.dwCurrentState = dwState;
::SetServiceStatus(m_hServiceStatus, &m_status);
}
void CServiceModule::Run()
{
HRESULT hr = S_OK;
try {
// Initialize both servers critical section.
try {
InitializeCriticalSectionAndSpinCount (&g_FsaCriticalSection, 1000);
InitializeCriticalSectionAndSpinCount (&g_EngCriticalSection, 1000);
} catch (DWORD status) {
WsbLogEvent(status, 0, NULL, NULL);
switch (status) {
case STATUS_NO_MEMORY:
WsbThrow(E_OUTOFMEMORY);
break;
default:
WsbThrow(E_UNEXPECTED);
}
}
_Module.dwThreadID = GetCurrentThreadId();
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
_ASSERTE(SUCCEEDED(hr));
if (hr != S_OK) {
m_status.dwWin32ExitCode = HRESULT_CODE(hr) ;
LogEvent( HSM_MESSAGE_SERVICE_FAILED_COM_INIT, OLESTR("CoInitializeEx"),
WsbHrAsString(hr), NULL );
DeleteCriticalSection(&g_EngCriticalSection);
DeleteCriticalSection(&g_FsaCriticalSection);
return;
}
// This provides Admin only access.
CWsbSecurityDescriptor sd;
sd.InitializeFromThreadToken();
sd.AllowRid( SECURITY_LOCAL_SYSTEM_RID, COM_RIGHTS_EXECUTE );
sd.AllowRid( DOMAIN_ALIAS_RID_ADMINS, COM_RIGHTS_EXECUTE );
hr = CoInitializeSecurity(sd, -1, NULL, NULL,
RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
_ASSERTE(SUCCEEDED(hr));
if (hr != S_OK) {
m_status.dwWin32ExitCode = HRESULT_CODE(hr) ;
LogEvent( HSM_MESSAGE_SERVICE_FAILED_COM_INIT, OLESTR("CoInitializeSecurity"),
WsbHrAsString(hr), NULL );
CoUninitialize();
DeleteCriticalSection(&g_EngCriticalSection);
DeleteCriticalSection(&g_FsaCriticalSection);
return;
}
// Create the trace object and initialize it
hr = CoCreateInstance(CLSID_CWsbTrace, 0, CLSCTX_SERVER, IID_IWsbTrace, (void **) &g_pTrace);
_ASSERTE(SUCCEEDED(hr));
if (hr != S_OK) {
m_status.dwWin32ExitCode = HRESULT_CODE(hr) ;
LogEvent( HSM_MESSAGE_SERVICE_INITIALIZATION_FAILED, WsbHrAsString(hr), NULL );
CoUninitialize();
DeleteCriticalSection(&g_EngCriticalSection);
DeleteCriticalSection(&g_FsaCriticalSection);
return;
}
// Figure out where to store information and initialize trace.
// Currently, Engine & Fsa share the same trace file
WsbGetServiceTraceDefaults(m_szServiceName, HSM_SERVER_TRACE_FILE_NAME, g_pTrace);
WsbTraceIn(OLESTR("CServiceModule::Run"), OLESTR(""));
hr = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, REGCLS_MULTIPLEUSE);
if (hr != S_OK) {
m_status.dwWin32ExitCode = HRESULT_CODE(hr) ;
LogEvent( HSM_MESSAGE_SERVICE_FAILED_COM_INIT, OLESTR("CoRegisterClassObjects"),
WsbHrAsString(hr), NULL );
g_pTrace = 0;
CoUninitialize();
DeleteCriticalSection(&g_EngCriticalSection);
DeleteCriticalSection(&g_FsaCriticalSection);
return;
}
// Now we need to get the HSM Server initialized
// First Fsa server is initialized, ONLY if it succeeds, Engine
// server is initialized as well
m_status.dwCheckPoint = 1;
m_status.dwWaitHint = 60000;
SetServiceStatus(SERVICE_START_PENDING);
// initialize Fsa server
if (! g_pFsaServer) {
try {
//
// Create and initialize the server.
//
WsbAffirmHr( CoCreateInstance(CLSID_CFsaServerNTFS, 0, CLSCTX_SERVER, IID_IFsaServer, (void**) &g_pFsaServer) );
// Created the server, now initialize it
g_bFsaCreated = TRUE;
CComPtr<IWsbServer> pWsbServer;
WsbAffirmHr(g_pFsaServer->QueryInterface(IID_IWsbServer, (void**) &pWsbServer));
WsbAffirmHrOk(pWsbServer->SetTrace(g_pTrace));
hr = g_pFsaServer->Init();
WsbAffirmHrOk(hr);
g_bFsaInitialized = TRUE;
}WsbCatchAndDo( hr,
// If the error is a Win32 make it back to a Win32 error else send
// the HR in the service specific exit code
if ( FACILITY_WIN32 == HRESULT_FACILITY(hr) ){
m_status.dwWin32ExitCode = HRESULT_CODE(hr) ;}else{
m_status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
m_status.dwServiceSpecificExitCode = hr ;}
LogEvent( FSA_MESSAGE_SERVICE_INITIALIZATION_FAILED , WsbHrAsString(hr), NULL );
);
}
WsbTrace (OLESTR("Fsa: Created=%ls , Initialized=%ls\n"),
WsbBoolAsString(g_bFsaCreated), WsbBoolAsString(g_bFsaInitialized));
// initialize Engine server
if ((! g_pEngServer) && (hr == S_OK)) {
try {
//
// Create and initialize the server.
//
WsbAffirmHr( CoCreateInstance( CLSID_HsmServer, 0, CLSCTX_SERVER, IID_IHsmServer, (void **)&g_pEngServer ) );
g_bEngCreated = TRUE;
CComPtr<IWsbServer> pWsbServer;
WsbAffirmHr(g_pEngServer->QueryInterface(IID_IWsbServer, (void**) &pWsbServer));
WsbAffirmHrOk(pWsbServer->SetTrace(g_pTrace));
WsbAffirmHr(g_pEngServer->Init());
g_bEngInitialized = TRUE;
}WsbCatchAndDo(hr,
// If the error is a Win32 make it back to a Win32 error else send
// the HR in the service specific exit code
if ( FACILITY_WIN32 == HRESULT_FACILITY(hr) ){
m_status.dwWin32ExitCode = HRESULT_CODE(hr) ;}else{
m_status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
m_status.dwServiceSpecificExitCode = hr ;}
LogEvent( HSM_MESSAGE_SERVICE_CREATE_FAILED, WsbHrAsString(hr), NULL );
);
}
WsbTrace (OLESTR("Engine: Created=%ls , Initialized=%ls\n"),
WsbBoolAsString(g_bEngCreated), WsbBoolAsString(g_bEngInitialized));
if (hr == S_OK) {
SetServiceStatus(SERVICE_RUNNING);
LogEvent( HSM_MESSAGE_SERVICE_STARTED, NULL );
MSG msg;
while (GetMessage(&msg, 0, 0, 0)) {
// If something has changed with the devices, then rescan. At somepoint we
// may want to do a more limited scan (i.e. just update what changed), but this
// should cover it for now.
//
// Since something has changed, we will also force a rewrite of the persistant data.
if (WM_DEVICECHANGE == msg.message) {
CComPtr<IWsbServer> pWsbServer;
try {
WsbAffirmHr(g_pFsaServer->ScanForResources());
WsbAffirmHr(g_pFsaServer->QueryInterface(IID_IWsbServer, (void**) &pWsbServer));
WsbAffirmHr(pWsbServer->SaveAll());
}WsbCatchAndDo(hr,
// If we had a problem then log a message and exit the service. We don't
// want to leave the service running, since we might have invalid drive
// mappings.
LogEvent(FSA_MESSAGE_RESCANFAILED, WsbHrAsString(hr), NULL);
PostMessage(NULL, WM_QUIT, 0, 0);
);
pWsbServer = 0;
}
DispatchMessage(&msg);
}
}
LogEvent( HSM_MESSAGE_SERVICE_EXITING, NULL );
// TEMPORARY - call a function so we can break before release.
DebugRelease ();
// prepare for releasing Eng server
if ((g_pEngServer != 0) && g_bEngCreated && g_bEngInitialized) {
// Save out server data
HSM_SYSTEM_STATE SysState;
SysState.State = HSM_STATE_SHUTDOWN;
hr = g_pEngServer->ChangeSysState(&SysState);
if (FAILED(hr)) {
LogEvent( HSM_MESSAGE_SERVICE_FAILED_TO_SHUTDOWN, WsbHrAsString(hr), NULL );
}
}
// Prepare for releasing Fsa server
if ((g_pFsaServer != 0) && g_bFsaCreated && g_bFsaInitialized) {
CComPtr<IWsbServer> pWsbServer;
HSM_SYSTEM_STATE SysState;
hr = g_pFsaServer->QueryInterface(IID_IWsbServer, (void**) &pWsbServer);
if (hr == S_OK) {
hr = pWsbServer->SaveAll();
}
if (FAILED(hr)) {
LogEvent( FSA_MESSAGE_SERVICE_FAILED_TO_SAVE_DATABASE, WsbHrAsString(hr), NULL );
}
pWsbServer = 0;
// Persist the databases and release everything
SysState.State = HSM_STATE_SHUTDOWN;
hr = g_pFsaServer->ChangeSysState(&SysState);
if (FAILED(hr)) {
LogEvent( FSA_MESSAGE_SERVICE_FAILED_TO_SHUTDOWN, WsbHrAsString(hr), NULL );
}
}
// Release Eng server
if (g_bEngCreated && (g_pEngServer != 0)) {
// Free server inside a crit. section thus avoid conflicts with accessing clients
EnterCriticalSection(&g_EngCriticalSection);
g_bEngInitialized = FALSE;
g_bEngCreated = FALSE;
// Disconnect all remote clients
(void)CoDisconnectObject(g_pEngServer, 0);
// Forse object destroy, ignore reference count here
IWsbServer *pWsbServer;
hr = g_pEngServer->QueryInterface(IID_IWsbServer, (void**) &pWsbServer);
if (hr == S_OK) {
pWsbServer->Release();
pWsbServer->DestroyObject();
}
g_pEngServer = 0;
LeaveCriticalSection (&g_EngCriticalSection);
}
// Release Fsa server
if (g_bFsaCreated && (g_pFsaServer != 0)) {
// Free server inside a crit. section thus avoid conflicts with accessing clients
EnterCriticalSection(&g_FsaCriticalSection);
g_bFsaInitialized = FALSE;
g_bFsaCreated = FALSE;
// Disconnect all remote clients
(void)CoDisconnectObject(g_pFsaServer, 0);
// Forse object destroy, ignore reference count here
IWsbServer *pWsbServer;
hr = g_pFsaServer->QueryInterface(IID_IWsbServer, (void**) &pWsbServer);
if (hr == S_OK) {
pWsbServer->Release();
pWsbServer->DestroyObject();
}
g_pFsaServer = 0;
LeaveCriticalSection(&g_FsaCriticalSection);
}
_Module.RevokeClassObjects();
WsbTraceOut(OLESTR("CServiceModule::Run"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
g_pTrace = 0;
CoUninitialize();
// Delete the server critical section
DeleteCriticalSection(&g_EngCriticalSection);
DeleteCriticalSection(&g_FsaCriticalSection);
}WsbCatch(hr);
}
//
// Tries to start the service as a console application
// (not through SCM calls)
//
static void ConsoleApp()
{
HRESULT hr;
::SetConsoleCtrlHandler(ConsoleHandler, TRUE) ;
// set Registry for process
hr = CoInitialize (NULL);
if (SUCCEEDED(hr)) {
hr = _Module.UpdateRegistryFromResourceD(IDR_Serv2Proc, TRUE);
CoUninitialize();
_Module.Run();
//
// set Registry back for service
hr = CoInitialize (NULL);
if (SUCCEEDED(hr)) {
hr = _Module.UpdateRegistryFromResourceD(IDR_Proc2Serv, TRUE);
CoUninitialize();
}
}
}
//
// Callback function for handling console events
//
BOOL WINAPI ConsoleHandler(DWORD dwCtrlType)
{
switch (dwCtrlType) {
case CTRL_BREAK_EVENT:
case CTRL_C_EVENT:
case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
PostThreadMessage(_Module.dwThreadID, WM_QUIT, 0, 0);
return TRUE;
}
return FALSE ;
}
/////////////////////////////////////////////////////////////////////////////
//
extern "C" int WINAPI _tWinMain(HINSTANCE hInstance,
HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/)
{
_Module.Init(ObjectMap, hInstance);
TCHAR szTokens[] = _T("-/");
LPTSTR lpszToken = _tcstok(lpCmdLine, szTokens);
while (lpszToken != NULL) {
if (_tcsicmp(lpszToken, _T("UnregServer"))==0) {
return _Module.UnregisterServer();
}
if (_tcsicmp(lpszToken, _T("RegServer"))==0) {
return _Module.RegisterServer(FALSE);
}
#ifdef DBG
if (_tcsicmp(lpszToken, _T("D"))==0) {
_Module.m_bService = FALSE;
}
#endif
lpszToken = _tcstok(NULL, szTokens);
}
//
// Cheap hack to force the ESE.DLL to be loaded before any other threads are started
//
LoadLibrary( L"RsIdb.dll" );
if (_Module.m_bService) {
_Module.Start();
} else {
ConsoleApp ();
}
// When we get here, the service has been stopped
return _Module.m_status.dwWin32ExitCode;
}
void DebugRelease ()
{
WsbTrace(OLESTR("DebugRelease in"));
WsbTrace(OLESTR("DebugRelease out"));
}