windows-nt/Source/XPSP1/NT/ds/security/services/w32time/w32tm/servicehost.cpp
2020-09-26 16:20:57 +08:00

781 lines
28 KiB
C++

//--------------------------------------------------------------------
// ServiceHost - implementation
// Copyright (C) Microsoft Corporation, 1999
//
// Created by: Louis Thomas (louisth), 9-9-99
//
// Stuff for hosting a service dll
//
#include "pch.h" // precompiled headers
#include "wchar.h"
//####################################################################
// module private
//--------------------------------------------------------------------
// module globals
MODULEPRIVATE HANDLE g_hServiceThread=NULL;
MODULEPRIVATE HANDLE g_hCtrlHandlerAvailEvent=NULL;
MODULEPRIVATE void * g_pvServiceContext=NULL;
MODULEPRIVATE LPHANDLER_FUNCTION_EX g_fnServiceCtrlHandler=NULL;
MODULEPRIVATE HWND g_hwServiceCtrlDlg=NULL;
MODULEPRIVATE SERVICE_STATUS g_ssLastStatus;
#define MYSERVICESTATUSHANDLE ((SERVICE_STATUS_HANDLE)3)
//--------------------------------------------------------------------
MODULEPRIVATE SERVICE_STATUS_HANDLE WINAPI W32TmRegisterServiceCtrlHandlerEx(const WCHAR * wszServiceName, LPHANDLER_FUNCTION_EX fnServiceCtrlHandler, void * pvContext) {
DWORD dwWaitResult;
DebugWPrintf3(L"RegisterServiceCtrlHandlerEx(0x%p, 0x%p, 0x%p) called.\n",wszServiceName, fnServiceCtrlHandler, pvContext);
// make sure we haven't set this already
_MyAssert(NULL!=g_hCtrlHandlerAvailEvent);
dwWaitResult=WaitForSingleObject(g_hCtrlHandlerAvailEvent, 0);
if (WAIT_FAILED==dwWaitResult) {
_IgnoreLastError("WaitForSingleObject");
}
_MyAssert(WAIT_TIMEOUT==dwWaitResult);
// check the service name, just for kicks
_MyAssert(NULL!=wszServiceName);
_MyAssert(NULL==wszServiceName || 0==wcscmp(wszServiceName, wszSERVICENAME));
// save the context
g_pvServiceContext=pvContext;
// save the handler
_MyAssert(NULL!=fnServiceCtrlHandler);
g_fnServiceCtrlHandler=fnServiceCtrlHandler;
if (!SetEvent(g_hCtrlHandlerAvailEvent)) {
_IgnoreLastError("SetEvent");
}
return MYSERVICESTATUSHANDLE;
}
//--------------------------------------------------------------------
MODULEPRIVATE void MyAppendString(WCHAR ** pwszString, const WCHAR * wszAdd) {
// calculate the length
DWORD dwLen=1;
if (NULL!=*pwszString) {
dwLen+=wcslen(*pwszString);
}
dwLen+=wcslen(wszAdd);
// allocate space
WCHAR * wszResult;
wszResult=(WCHAR *)LocalAlloc(LPTR, dwLen*sizeof(WCHAR));
if (NULL==wszResult) {
DebugWPrintf0(L"Out Of Memory in MyAppendString\n");
return;
}
// build the new string
if (NULL==*pwszString) {
wszResult[0]=L'\0';
} else {
wcscpy(wszResult, *pwszString);
}
wcscat(wszResult, wszAdd);
// replace the old one
if (NULL!=*pwszString) {
LocalFree(*pwszString);
}
*pwszString=wszResult;
}
//--------------------------------------------------------------------
MODULEPRIVATE void UpdateServiceCtrlDlg(void) {
if (NULL!=g_hwServiceCtrlDlg) {
WCHAR * wszDesc=NULL;
//SERVICE_STATUS::dwServiceType
MyAppendString(&wszDesc, L"Type: ");
switch (g_ssLastStatus.dwServiceType&(~SERVICE_INTERACTIVE_PROCESS)) {
case SERVICE_WIN32_OWN_PROCESS:
MyAppendString(&wszDesc, L"SERVICE_WIN32_OWN_PROCESS");
break;
case SERVICE_WIN32_SHARE_PROCESS:
MyAppendString(&wszDesc, L"SERVICE_WIN32_SHARE_PROCESS");
break;
case SERVICE_KERNEL_DRIVER:
MyAppendString(&wszDesc, L"SERVICE_KERNEL_DRIVER");
break;
case SERVICE_FILE_SYSTEM_DRIVER:
MyAppendString(&wszDesc, L"SERVICE_FILE_SYSTEM_DRIVER");
break;
default:
MyAppendString(&wszDesc, L"(unknown)");
break;
}
if (g_ssLastStatus.dwServiceType&SERVICE_INTERACTIVE_PROCESS) {
MyAppendString(&wszDesc, L" | SERVICE_INTERACTIVE_PROCESS");
}
//SERVICE_STATUS::dwCurrentState,
MyAppendString(&wszDesc, L"\r\nState: ");
switch (g_ssLastStatus.dwCurrentState) {
case SERVICE_STOPPED:
MyAppendString(&wszDesc, L"SERVICE_STOPPED");
break;
case SERVICE_START_PENDING:
MyAppendString(&wszDesc, L"SERVICE_START_PENDING");
break;
case SERVICE_STOP_PENDING:
MyAppendString(&wszDesc, L"SERVICE_STOP_PENDING");
break;
case SERVICE_RUNNING:
MyAppendString(&wszDesc, L"SERVICE_RUNNING");
break;
case SERVICE_CONTINUE_PENDING:
MyAppendString(&wszDesc, L"SERVICE_CONTINUE_PENDING");
break;
case SERVICE_PAUSE_PENDING:
MyAppendString(&wszDesc, L"SERVICE_PAUSE_PENDING");
break;
case SERVICE_PAUSED:
MyAppendString(&wszDesc, L"SERVICE_PAUSED");
break;
default:
MyAppendString(&wszDesc, L"(unknown)");
break;
}
//SERVICE_STATUS::dwControlsAccepted,
MyAppendString(&wszDesc, L"\r\nControls Accepted: ");
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_DEVICEEVENT), false);
bool bFirst=true;
//-----
if (g_ssLastStatus.dwControlsAccepted&SERVICE_ACCEPT_STOP) {
bFirst=false;
MyAppendString(&wszDesc, L"SERVICE_ACCEPT_STOP");
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_STOP), true);
} else {
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_STOP), false);
}
//-----
if (g_ssLastStatus.dwControlsAccepted&SERVICE_ACCEPT_PAUSE_CONTINUE) {
if (bFirst) {
bFirst=false;
} else {
MyAppendString(&wszDesc, L" | ");
}
MyAppendString(&wszDesc, L"SERVICE_ACCEPT_PAUSE_CONTINUE");
if (SERVICE_PAUSE_PENDING==g_ssLastStatus.dwCurrentState || SERVICE_PAUSED==g_ssLastStatus.dwCurrentState) {
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_PAUSE), false);
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_CONTINUE), true);
} else {
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_PAUSE), true);
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_CONTINUE), false);
}
} else {
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_PAUSE), false);
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_CONTINUE), false);
}
//-----
if (g_ssLastStatus.dwControlsAccepted&SERVICE_ACCEPT_SHUTDOWN) {
if (bFirst) {
bFirst=false;
} else {
MyAppendString(&wszDesc, L" | ");
}
MyAppendString(&wszDesc, L"SERVICE_ACCEPT_SHUTDOWN");
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_SHUTDOWN), true);
} else {
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_SHUTDOWN), false);
}
//-----
if (g_ssLastStatus.dwControlsAccepted&SERVICE_ACCEPT_PARAMCHANGE) {
if (bFirst) {
bFirst=false;
} else {
MyAppendString(&wszDesc, L" | ");
}
MyAppendString(&wszDesc, L"SERVICE_ACCEPT_PARAMCHANGE");
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_PARAMCHANGE), true);
} else {
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_PARAMCHANGE), false);
}
//-----
if (g_ssLastStatus.dwControlsAccepted&SERVICE_ACCEPT_NETBINDCHANGE) {
if (bFirst) {
bFirst=false;
} else {
MyAppendString(&wszDesc, L" | ");
}
MyAppendString(&wszDesc, L"SERVICE_ACCEPT_NETBINDCHANGE");
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_NETBINDADD), true);
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_NETBINDREMOVE), true);
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_NETBINDENABLE), true);
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_NETBINDDISABLE), true);
} else {
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_NETBINDADD), false);
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_NETBINDREMOVE), false);
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_NETBINDENABLE), false);
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_NETBINDDISABLE), false);
}
//-----
if (g_ssLastStatus.dwControlsAccepted&SERVICE_ACCEPT_HARDWAREPROFILECHANGE) {
if (bFirst) {
bFirst=false;
} else {
MyAppendString(&wszDesc, L" | ");
}
MyAppendString(&wszDesc, L"SERVICE_ACCEPT_HARDWAREPROFILECHANGE");
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_HARDWAREPROFILECHANGE), true);
} else {
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_HARDWAREPROFILECHANGE), false);
}
//-----
if (g_ssLastStatus.dwControlsAccepted&SERVICE_ACCEPT_POWEREVENT) {
if (bFirst) {
bFirst=false;
} else {
MyAppendString(&wszDesc, L" | ");
}
MyAppendString(&wszDesc, L"SERVICE_ACCEPT_POWEREVENT");
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_POWEREVENT), true);
} else {
EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_POWEREVENT), false);
}
//-----
if (bFirst) {
MyAppendString(&wszDesc, L"<none>");
}
//SERVICE_STATUS::dwWin32ExitCode,
//SERVICE_STATUS::dwServiceSpecificExitCode,
//SERVICE_STATUS::dwCheckPoint,
//SERVICE_STATUS::dwWaitHint
WCHAR wszBuf[256];
_snwprintf(wszBuf, 256, L"\r\nWin32 Exit Code: 0x%08X\r\nService Specific Exit Code: 0x%08X\r\nCheckpoint: 0x%08X\r\nWait Hint: 0x%08X",
g_ssLastStatus.dwWin32ExitCode,
g_ssLastStatus.dwServiceSpecificExitCode,
g_ssLastStatus.dwCheckPoint,
g_ssLastStatus.dwWaitHint);
MyAppendString(&wszDesc, wszBuf);
SendDlgItemMessage(g_hwServiceCtrlDlg, IDC_STATUS, WM_SETTEXT, 0, (LPARAM) wszDesc);
LocalFree(wszDesc);
}
}
//--------------------------------------------------------------------
MODULEPRIVATE BOOL WINAPI W32TmSetServiceStatus(SERVICE_STATUS_HANDLE ssh, SERVICE_STATUS * pss) {
const WCHAR * wszState;
switch (pss->dwCurrentState) {
case SERVICE_STOPPED:
wszState=L"SERVICE_STOPPED";
break;
case SERVICE_START_PENDING:
wszState=L"SERVICE_START_PENDING";
break;
case SERVICE_STOP_PENDING:
wszState=L"SERVICE_STOP_PENDING";
break;
case SERVICE_RUNNING:
wszState=L"SERVICE_RUNNING";
break;
case SERVICE_CONTINUE_PENDING:
wszState=L"SERVICE_CONTINUE_PENDING";
break;
case SERVICE_PAUSE_PENDING:
wszState=L"SERVICE_PAUSE_PENDING";
break;
case SERVICE_PAUSED:
wszState=L"SERVICE_PAUSED";
break;
default:
wszState=L"(unknown)";
break;
}
switch (pss->dwCurrentState) {
case SERVICE_STOPPED:
DebugWPrintf4(L"SetServiceStatus called; %s Accept:0x%08X Ret:0x%08X(0x%08X)\n",
wszState,
pss->dwControlsAccepted,
pss->dwWin32ExitCode,
pss->dwServiceSpecificExitCode,
);
break;
case SERVICE_START_PENDING:
case SERVICE_STOP_PENDING:
case SERVICE_PAUSE_PENDING:
case SERVICE_CONTINUE_PENDING:
DebugWPrintf4(L"SetServiceStatus called; %s Accept:0x%08X ChkPt:0x%08X Wait:0x%08X\n",
wszState,
pss->dwControlsAccepted,
pss->dwCheckPoint,
pss->dwWaitHint
);
break;
case SERVICE_RUNNING:
case SERVICE_PAUSED:
default:
DebugWPrintf2(L"SetServiceStatus called; %s Accept:0x%08X\n",
wszState,
pss->dwControlsAccepted
);
break;
}
_MyAssert(MYSERVICESTATUSHANDLE==ssh);
memcpy(&g_ssLastStatus, pss, sizeof(SERVICE_STATUS));
UpdateServiceCtrlDlg();
return true;
}
//--------------------------------------------------------------------
MODULEPRIVATE DWORD WINAPI MyServiceThread(void * pvServiceMain) {
DebugWPrintf0(L"Starting service thread.\n");
((LPSERVICE_MAIN_FUNCTION)pvServiceMain)(0, NULL);
DebugWPrintf0(L"Service thread exited.\n"); // service may still be running!
return S_OK;
}
//--------------------------------------------------------------------
MODULEPRIVATE INT_PTR CALLBACK ServiceCtrlDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
DWORD dwError;
HRESULT hrExit;
if (NULL==g_hwServiceCtrlDlg) {
g_hwServiceCtrlDlg=hwndDlg;
}
switch (uMsg) {
case WM_INITDIALOG:
UpdateServiceCtrlDlg();
return true;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDCANCEL:
if (g_ssLastStatus.dwCurrentState!=SERVICE_STOPPED) {
hrExit=HRESULT_FROM_WIN32(ERROR_CANCELLED);
DebugWPrintf1(L"Aborting with error 0x%08X\n", hrExit);
} else {
hrExit=g_ssLastStatus.dwServiceSpecificExitCode;
DebugWPrintf1(L"Exiting with service return value 0x%08X\n", hrExit);
}
EndDialog(hwndDlg, hrExit);
return true;
case IDC_SC_STOP:
DebugWPrintf0(L"Passing SERVICE_CONTROL_STOP to service's control handler.\n");
dwError=g_fnServiceCtrlHandler(SERVICE_CONTROL_STOP, NULL, NULL, g_pvServiceContext);
DebugWPrintf1(L"Service's control handler returns 0x%08X.\n", dwError);
return false;
case IDC_SC_PAUSE:
DebugWPrintf0(L"Passing SERVICE_CONTROL_PAUSE to service's control handler.\n");
dwError=g_fnServiceCtrlHandler(SERVICE_CONTROL_PAUSE, NULL, NULL, g_pvServiceContext);
DebugWPrintf1(L"Service's control handler returns 0x%08X.\n", dwError);
return false;
case IDC_SC_CONTINUE:
DebugWPrintf0(L"Passing SERVICE_CONTROL_CONTINUE to service's control handler.\n");
dwError=g_fnServiceCtrlHandler(SERVICE_CONTROL_CONTINUE, NULL, NULL, g_pvServiceContext);
DebugWPrintf1(L"Service's control handler returns 0x%08X.\n", dwError);
return false;
case IDC_SC_INTERROGATE:
DebugWPrintf0(L"Passing SERVICE_CONTROL_INTERROGATE to service's control handler.\n");
dwError=g_fnServiceCtrlHandler(SERVICE_CONTROL_INTERROGATE, NULL, NULL, g_pvServiceContext);
DebugWPrintf1(L"Service's control handler returns 0x%08X.\n", dwError);
return false;
case IDC_SC_SHUTDOWN:
DebugWPrintf0(L"IDC_SC_SHUTDOWN\n");
return false;
case IDC_SC_PARAMCHANGE:
DebugWPrintf0(L"Passing SERVICE_CONTROL_PARAMCHANGE to service's control handler.\n");
dwError=g_fnServiceCtrlHandler(SERVICE_CONTROL_PARAMCHANGE, NULL, NULL, g_pvServiceContext);
DebugWPrintf1(L"Service's control handler returns 0x%08X.\n", dwError);
return false;
case IDC_SC_NETBINDADD:
DebugWPrintf0(L"Passing SERVICE_CONTROL_NETBINDADD to service's control handler.\n");
dwError=g_fnServiceCtrlHandler(SERVICE_CONTROL_NETBINDADD, NULL, NULL, g_pvServiceContext);
DebugWPrintf1(L"Service's control handler returns 0x%08X.\n", dwError);
return false;
case IDC_SC_NETBINDREMOVE:
DebugWPrintf0(L"Passing SERVICE_CONTROL_NETBINDREMOVE to service's control handler.\n");
dwError=g_fnServiceCtrlHandler(SERVICE_CONTROL_NETBINDREMOVE, NULL, NULL, g_pvServiceContext);
DebugWPrintf1(L"Service's control handler returns 0x%08X.\n", dwError);
return false;
case IDC_SC_NETBINDENABLE:
DebugWPrintf0(L"Passing SERVICE_CONTROL_NETBINDENABLE to service's control handler.\n");
dwError=g_fnServiceCtrlHandler(SERVICE_CONTROL_NETBINDENABLE, NULL, NULL, g_pvServiceContext);
DebugWPrintf1(L"Service's control handler returns 0x%08X.\n", dwError);
return false;
case IDC_SC_NETBINDDISABLE:
DebugWPrintf0(L"Passing SERVICE_CONTROL_NETBINDDISABLE to service's control handler.\n");
dwError=g_fnServiceCtrlHandler(SERVICE_CONTROL_NETBINDDISABLE, NULL, NULL, g_pvServiceContext);
DebugWPrintf1(L"Service's control handler returns 0x%08X.\n", dwError);
return false;
case IDC_SC_DEVICEEVENT:
DebugWPrintf0(L"IDC_SC_DEVICEEVENT NYI\n");
return false;
case IDC_SC_HARDWAREPROFILECHANGE:
DebugWPrintf0(L"IDC_SC_HARDWAREPROFILECHANGE NYI\n");
return false;
case IDC_SC_POWEREVENT:
DebugWPrintf0(L"IDC_SC_POWEREVENT NYI\n");
return false;
default:
//DebugWPrintf2(L"Unknown WM_COMMAND: wParam:0x%08X lParam:0x%08X\n", wParam, lParam);
return false; // unhandled
}
return false; // unhandled
// end case WM_COMMAND
default:
return false; // unhandled
}
return false; // unhandled
}
//--------------------------------------------------------------------
MODULEPRIVATE HRESULT MyServiceCtrlDispatcher(LPSERVICE_MAIN_FUNCTION fnW32TmServiceMain) {
HRESULT hr;
DWORD dwThreadID;
DWORD dwWaitResult;
INT_PTR nDialogError;
g_hCtrlHandlerAvailEvent=CreateEvent(NULL, TRUE, FALSE, NULL);
if (NULL==g_hCtrlHandlerAvailEvent) {
_JumpLastError(hr, error, "CreateEvent");
}
// 'start' the service
g_hServiceThread=CreateThread(NULL, 0, MyServiceThread, (void *)fnW32TmServiceMain, 0, &dwThreadID);
if (NULL==g_hServiceThread) {
_JumpLastError(hr, error, "CreateThread");
}
DebugWPrintf0(L"Waiting for service to register ctrl handler.\n");
_Verify(WAIT_FAILED!=WaitForSingleObject(g_hCtrlHandlerAvailEvent, INFINITE), hr, error);
// do dialog box
nDialogError=DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_SERVICECTRL), NULL, ServiceCtrlDialogProc);
if (-1==nDialogError) {
_JumpLastError(hr, error, "DialogBox");
}
hr=(HRESULT)nDialogError;
_JumpIfError(hr, error, "DialogBox");
// confirm that the thread exited
dwWaitResult=WaitForSingleObject(g_hServiceThread, 0);
if (WAIT_FAILED==dwWaitResult) {
_IgnoreLastError("WaitForSingleObject");
}
_Verify(WAIT_TIMEOUT!=dwWaitResult, hr, error);
// When this exits, everything ends.
hr=S_OK;
error:
if (NULL!=g_hServiceThread) {
CloseHandle(g_hServiceThread);
g_hServiceThread=NULL;
}
if (NULL!=g_hCtrlHandlerAvailEvent) {
CloseHandle(g_hCtrlHandlerAvailEvent);
g_hCtrlHandlerAvailEvent=NULL;
}
return hr;
}
//--------------------------------------------------------------------
MODULEPRIVATE HRESULT GetDllName(WCHAR ** pwszDllName) {
HRESULT hr;
DWORD dwError;
DWORD dwSize;
DWORD dwType;
// must be cleaned up
HKEY hkParams=NULL;
WCHAR * wszDllName=NULL;
WCHAR * wszDllExpandedName=NULL;
// get our config key
dwError=RegOpenKeyEx(HKEY_LOCAL_MACHINE, wszW32TimeRegKeyParameters, 0, KEY_READ, &hkParams);
if (ERROR_SUCCESS!=dwError) {
hr=HRESULT_FROM_WIN32(dwError);
_JumpErrorStr(hr, error, "RegOpenKeyEx", wszW32TimeRegKeyParameters);
}
// read the value containing the DLL name
dwSize=0;
dwError=RegQueryValueEx(hkParams, wszW32TimeRegValueServiceDll, NULL, &dwType, NULL, &dwSize);
if (ERROR_SUCCESS!=dwError) {
hr=HRESULT_FROM_WIN32(dwError);
_JumpErrorStr(hr, error, "RegQueryValueEx", wszW32TimeRegValueServiceDll);
}
_Verify(REG_EXPAND_SZ==dwType, hr, error);
wszDllName=(WCHAR *)LocalAlloc(LPTR, dwSize);
_JumpIfOutOfMemory(hr, error, wszDllName);
dwError=RegQueryValueEx(hkParams, wszW32TimeRegValueServiceDll, NULL, &dwType, (BYTE *)wszDllName, &dwSize);
if (ERROR_SUCCESS!=dwError) {
hr=HRESULT_FROM_WIN32(dwError);
_JumpErrorStr(hr, error, "RegQueryValueEx", wszW32TimeRegValueServiceDll);
}
// expand environment string
dwSize=ExpandEnvironmentStrings(wszDllName, NULL, 0);
if (0==dwSize) {
_JumpLastError(hr, error, "ExpandEnvironmentStrings");
}
wszDllExpandedName=(WCHAR *)LocalAlloc(LPTR, dwSize*sizeof(WCHAR));
_JumpIfOutOfMemory(hr, error, wszDllExpandedName);
dwSize=ExpandEnvironmentStrings(wszDllName, wszDllExpandedName, dwSize);
if (0==dwSize) {
_JumpLastError(hr, error, "ExpandEnvironmentStrings");
}
// success
*pwszDllName=wszDllExpandedName;
wszDllExpandedName=NULL;
error:
if (NULL!=wszDllExpandedName) {
LocalFree(wszDllExpandedName);
}
if (NULL!=wszDllName) {
LocalFree(wszDllName);
}
if (NULL!=hkParams) {
RegCloseKey(hkParams);
}
return hr;
}
//####################################################################
// module public
//--------------------------------------------------------------------
// run W32Time as a real service under the SCM
HRESULT RunAsService(void) {
HRESULT hr;
SERVICE_STATUS_HANDLE (WINAPI ** pfnW32TmRegisterServiceCtrlHandlerEx)(LPCWSTR, LPHANDLER_FUNCTION_EX, LPVOID);
BOOL (WINAPI ** pfnW32TmSetServiceStatus)(SERVICE_STATUS_HANDLE, LPSERVICE_STATUS);
SERVICE_TABLE_ENTRY rgsteDispatchTable[]= {
{ wszSERVICENAME, NULL},
{NULL, NULL}
};
// must be cleaned up
HINSTANCE hW32Time=NULL;
WCHAR * wszDllName=NULL;
// load the library
hr=GetDllName(&wszDllName);
_JumpIfError(hr, error, "GetDllName");
hW32Time=LoadLibrary(wszDllName);
if (NULL==hW32Time) {
_JumpLastError(hr, error, "LoadLibrary");
}
// get the entry point
rgsteDispatchTable[0].lpServiceProc=(LPSERVICE_MAIN_FUNCTION)GetProcAddress(hW32Time, "W32TmServiceMain");
if (NULL==rgsteDispatchTable[0].lpServiceProc) {
_JumpLastErrorStr(hr, error, "GetProcAddress", L"W32TmServiceMain");
}
// adjust the function pointers
pfnW32TmRegisterServiceCtrlHandlerEx=(SERVICE_STATUS_HANDLE (WINAPI **)(LPCWSTR, LPHANDLER_FUNCTION_EX, LPVOID))GetProcAddress(hW32Time, "fnW32TmRegisterServiceCtrlHandlerEx");
if (NULL==pfnW32TmRegisterServiceCtrlHandlerEx) {
_JumpLastErrorStr(hr, error, "GetProcAddress", L"fnW32TmRegisterServiceCtrlHandlerEx");
}
*pfnW32TmRegisterServiceCtrlHandlerEx=RegisterServiceCtrlHandlerExW;
pfnW32TmSetServiceStatus=(BOOL (WINAPI **)(SERVICE_STATUS_HANDLE, LPSERVICE_STATUS))GetProcAddress(hW32Time, "fnW32TmSetServiceStatus");
if (NULL==pfnW32TmSetServiceStatus) {
_JumpLastErrorStr(hr, error, "GetProcAddress", L"fnW32TmSetServiceStatus");
}
*pfnW32TmSetServiceStatus=SetServiceStatus;
// This thread becomes the service control dispatcher.
if (!StartServiceCtrlDispatcher(rgsteDispatchTable)) {
_JumpLastError(hr, error, "StartServiceCtrlDispatcher");
}
// service is stopped.
hr=S_OK;
error:
if (NULL!=wszDllName) {
LocalFree(wszDllName);
}
if (NULL!=hW32Time) {
FreeLibrary(hW32Time);
}
if (FAILED(hr)) {
WCHAR * wszError;
HRESULT hr2=GetSystemErrorString(hr, &wszError);
if (FAILED(hr2)) {
_IgnoreError(hr2, "GetSystemErrorString");
} else {
LocalizedWPrintf2(IDS_W32TM_ERRORGENERAL_ERROR_OCCURED, L" %s\n", wszError);
LocalFree(wszError);
}
}
return hr;
}
//--------------------------------------------------------------------
// pretend to run as a service for easier debugging
HRESULT RunAsTestService(void) {
HRESULT hr;
LPSERVICE_MAIN_FUNCTION fnW32TmServiceMain;
SERVICE_STATUS_HANDLE (WINAPI ** pfnW32TmRegisterServiceCtrlHandlerEx)(LPCWSTR, LPHANDLER_FUNCTION_EX, LPVOID);
BOOL (WINAPI ** pfnW32TmSetServiceStatus)(SERVICE_STATUS_HANDLE, LPSERVICE_STATUS);
// must be cleaned up
HINSTANCE hW32Time=NULL;
WCHAR * wszDllName=NULL;
// load the library
hr=GetDllName(&wszDllName);
_JumpIfError(hr, error, "GetDllName");
hW32Time=LoadLibrary(wszDllName);
if (NULL==hW32Time) {
_JumpLastError(hr, error, "LoadLibrary");
}
// get the entry point
fnW32TmServiceMain=(LPSERVICE_MAIN_FUNCTION)GetProcAddress(hW32Time, "W32TmServiceMain");
if (NULL==fnW32TmServiceMain) {
_JumpLastErrorStr(hr, error, "GetProcAddress", L"W32TmServiceMain");
}
// adjust the function pointers
pfnW32TmRegisterServiceCtrlHandlerEx=(SERVICE_STATUS_HANDLE (WINAPI **)(LPCWSTR, LPHANDLER_FUNCTION_EX, LPVOID))GetProcAddress(hW32Time, "fnW32TmRegisterServiceCtrlHandlerEx");
if (NULL==pfnW32TmRegisterServiceCtrlHandlerEx) {
_JumpLastErrorStr(hr, error, "GetProcAddress", L"fnW32TmRegisterServiceCtrlHandlerEx");
}
*pfnW32TmRegisterServiceCtrlHandlerEx=W32TmRegisterServiceCtrlHandlerEx;
// adjust the function pointers
pfnW32TmSetServiceStatus=(BOOL (WINAPI **)(SERVICE_STATUS_HANDLE, LPSERVICE_STATUS))GetProcAddress(hW32Time, "fnW32TmSetServiceStatus");
if (NULL==pfnW32TmSetServiceStatus) {
_JumpLastErrorStr(hr, error, "GetProcAddress", L"fnW32TmSetServiceStatus");
}
*pfnW32TmSetServiceStatus=W32TmSetServiceStatus;
// This thread becomes the service control dispatcher.
hr=MyServiceCtrlDispatcher(fnW32TmServiceMain);
_JumpIfError(hr, error, "MyServiceCtrlDispatcher");
// service is stopped.
hr=S_OK;
error:
if (NULL!=wszDllName) {
LocalFree(wszDllName);
}
if (NULL!=hW32Time) {
FreeLibrary(hW32Time);
}
if (FAILED(hr)) {
WCHAR * wszError;
HRESULT hr2=GetSystemErrorString(hr, &wszError);
if (FAILED(hr2)) {
_IgnoreError(hr2, "GetSystemErrorString");
} else {
LocalizedWPrintf2(IDS_W32TM_ERRORGENERAL_ERROR_OCCURED, L" %s\n", wszError);
LocalFree(wszError);
}
}
return hr;
}
//--------------------------------------------------------------------
HRESULT RegisterDll(void) {
HRESULT hr;
HRESULT (__stdcall * pfnDllRegisterServer)(void);
// must be cleaned up
HINSTANCE hW32Time=NULL;
// load the library
hW32Time=LoadLibrary(wszDLLNAME);
if (NULL==hW32Time) {
_JumpLastError(hr, error, "LoadLibrary");
}
// get the entry point
pfnDllRegisterServer=(HRESULT (__stdcall *) (void))GetProcAddress(hW32Time, "DllRegisterServer");
if (NULL==pfnDllRegisterServer) {
_JumpLastErrorStr(hr, error, "GetProcAddress", L"DllRegisterServer");
}
hr=pfnDllRegisterServer();
_JumpIfError(hr, error, "DllRegisterServer");
LocalizedWPrintfCR(IDS_W32TM_STATUS_REGISTER_SUCCESSFUL);
hr=S_OK;
error:
if (NULL!=hW32Time) {
FreeLibrary(hW32Time);
}
if (FAILED(hr)) {
WCHAR * wszError;
HRESULT hr2=GetSystemErrorString(hr, &wszError);
if (FAILED(hr2)) {
_IgnoreError(hr2, "GetSystemErrorString");
} else {
LocalizedWPrintf2(IDS_W32TM_ERRORGENERAL_ERROR_OCCURED, L" %s\n", wszError);
LocalFree(wszError);
}
}
return hr;
};
//--------------------------------------------------------------------
HRESULT UnregisterDll(void) {
HRESULT hr;
HRESULT (__stdcall * pfnDllUnregisterServer)(void);
// must be cleaned up
HINSTANCE hW32Time=NULL;
// load the library
hW32Time=LoadLibrary(wszDLLNAME);
if (NULL==hW32Time) {
_JumpLastError(hr, error, "LoadLibrary");
}
// get the entry point
pfnDllUnregisterServer=(HRESULT (__stdcall *) (void))GetProcAddress(hW32Time, "DllUnregisterServer");
if (NULL==pfnDllUnregisterServer) {
_JumpLastErrorStr(hr, error, "GetProcAddress", L"DllUnregisterServer");
}
hr=pfnDllUnregisterServer();
_JumpIfError(hr, error, "DllUnregisterServer");
LocalizedWPrintfCR(IDS_W32TM_STATUS_REGISTER_SUCCESSFUL);
hr=S_OK;
error:
if (NULL!=hW32Time) {
FreeLibrary(hW32Time);
}
if (FAILED(hr)) {
WCHAR * wszError;
HRESULT hr2=GetSystemErrorString(hr, &wszError);
if (FAILED(hr2)) {
_IgnoreError(hr2, "GetSystemErrorString");
} else {
LocalizedWPrintf2(IDS_W32TM_ERRORGENERAL_ERROR_OCCURED, L" %s\n", wszError);
LocalFree(wszError);
}
}
return hr;
};