//-------------------------------------------------------------------- // 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""); } //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; };