├── install_xp.cmd ├── ntdll.lib ├── Release └── SetTimerService.exe ├── ServiceControl.h ├── Registry.h ├── resource.h ├── NtTimer.h ├── SetTimerService.sln ├── LICENSE.txt ├── README.md ├── ServiceControl.cpp ├── Registry.cpp ├── SetTimerService.rc ├── SetTimerService.vcproj └── SetTimerService.cpp /install_xp.cmd: -------------------------------------------------------------------------------- 1 | sc config AudioSrv depend= "PlugPlay/RpcSs/SetTimer" -------------------------------------------------------------------------------- /ntdll.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/temerkhanov/SetTimerService/HEAD/ntdll.lib -------------------------------------------------------------------------------- /Release/SetTimerService.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/temerkhanov/SetTimerService/HEAD/Release/SetTimerService.exe -------------------------------------------------------------------------------- /ServiceControl.h: -------------------------------------------------------------------------------- 1 | #ifndef __SERVICE_CONTROL_H__ 2 | #define __SERVICE_CONTROL_H__ 3 | 4 | #include 5 | #include 6 | 7 | DWORD ServiceInstall(LPCTSTR ServiceName, 8 | LPCTSTR DisplayName, 9 | LPCTSTR ExecPath); 10 | 11 | DWORD ServiceUninstall(LPCTSTR ServiceName); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /Registry.h: -------------------------------------------------------------------------------- 1 | #ifndef __REGISTRY_H__ 2 | #define __REGISTRY_H__ 3 | 4 | #include 5 | 6 | LONG RegistryGetServiceParameter( 7 | LPCTSTR ServiceName, 8 | LPCTSTR ParameterName, 9 | LPDWORD ParameterValue 10 | ); 11 | 12 | LONG RegistrySetServiceParameter( 13 | LPCTSTR ServiceName, 14 | LPCTSTR ParameterName, 15 | DWORD ParameterValue 16 | ); 17 | 18 | #endif -------------------------------------------------------------------------------- /resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by SetTimerService.rc 4 | // 5 | 6 | // Next default values for new objects 7 | // 8 | #ifdef APSTUDIO_INVOKED 9 | #ifndef APSTUDIO_READONLY_SYMBOLS 10 | #define _APS_NEXT_RESOURCE_VALUE 101 11 | #define _APS_NEXT_COMMAND_VALUE 40001 12 | #define _APS_NEXT_CONTROL_VALUE 1001 13 | #define _APS_NEXT_SYMED_VALUE 101 14 | #endif 15 | #endif 16 | -------------------------------------------------------------------------------- /NtTimer.h: -------------------------------------------------------------------------------- 1 | #ifndef __NT_TIMER_H__ 2 | #define __NT_TIMER_H__ 3 | 4 | #include 5 | 6 | #define STATUS_SUCCESS 0 7 | #define STATUS_TIMER_RESOLUTION_NOT_SET 0xC0000245 8 | 9 | #ifndef NTSTATUS 10 | typedef LONG NTSTATUS, *PNTSTATUS; 11 | #endif 12 | 13 | EXTERN_C NTSYSAPI 14 | NTSTATUS 15 | NTAPI 16 | NtSetTimerResolution( 17 | IN ULONG DesiredResolution, 18 | IN BOOLEAN SetResolution, 19 | OUT PULONG CurrentResolution); 20 | 21 | #endif -------------------------------------------------------------------------------- /SetTimerService.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 8.00 2 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SetTimerService", "SetTimerService.vcproj", "{1B5AA71F-1680-49BF-91D4-FF99313699A5}" 3 | ProjectSection(ProjectDependencies) = postProject 4 | EndProjectSection 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfiguration) = preSolution 8 | Debug = Debug 9 | Release = Release 10 | EndGlobalSection 11 | GlobalSection(ProjectDependencies) = postSolution 12 | EndGlobalSection 13 | GlobalSection(ProjectConfiguration) = postSolution 14 | {1B5AA71F-1680-49BF-91D4-FF99313699A5}.Debug.ActiveCfg = Debug|Win32 15 | {1B5AA71F-1680-49BF-91D4-FF99313699A5}.Debug.Build.0 = Debug|Win32 16 | {1B5AA71F-1680-49BF-91D4-FF99313699A5}.Release.ActiveCfg = Release|Win32 17 | {1B5AA71F-1680-49BF-91D4-FF99313699A5}.Release.Build.0 = Release|Win32 18 | EndGlobalSection 19 | GlobalSection(ExtensibilityGlobals) = postSolution 20 | EndGlobalSection 21 | GlobalSection(ExtensibilityAddIns) = postSolution 22 | EndGlobalSection 23 | EndGlobal 24 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2020 Sergey Temerkhanov 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software 4 | and associated documentation files (the "Software"), to deal in the Software without restriction, 5 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 6 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to 7 | do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial 10 | portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 14 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 15 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 16 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SetTimerService 2 | SetTimerService is a tiny Windows NT4/2000/XP compatible service intended to fix distorted sound in VMWare guests. This is done by setting the kernel timer resolution early during the bootup process. 3 | 4 | Installation: 5 | 6 | Copy the SetTimerService.exe binary to a permanent location (e.g. C:\Windows\System32) 7 | 8 | In Windows command prompt change directory to the location where the binary is located. 9 | 10 | "SetTimerService /install" - install SetTimerService 11 | 12 | Uninstall: 13 | 14 | "SetTimerService /uninstall" - uninstall SetTimerService 15 | 16 | install_xp.cmd - adds SetTimerService as a dependency for Windows sound system, should prevent possible races at startup. 17 | 18 | Tuning: 19 | Registry values are located at HKLM:SYSTEM\CurrentControlSet\Services\SetTimerService\Parameters 20 | 21 | TimerResolution: Dword - Desired timer resolution in 100 ns quanta. 22 | 23 | Note: 24 | Timer setting only works with native VMWare virtualization interface as opposed to Hyper-V based one enabled by default in the latest Windows versions. Virtualization-based security and Hyper-V effectively inhibit the 25 | underlying API this program uses. 26 | 27 | -------------------------------------------------------------------------------- /ServiceControl.cpp: -------------------------------------------------------------------------------- 1 | #include "ServiceControl.h" 2 | #include 3 | 4 | DWORD ServiceInstall(LPCTSTR ServiceName, 5 | LPCTSTR DisplayName, 6 | LPCTSTR ExecPath) 7 | { 8 | SC_HANDLE SCManagerHandle; 9 | SC_HANDLE ServiceHandle; 10 | TCHAR Path[MAX_PATH]; 11 | DWORD Result; 12 | 13 | if (ExecPath == NULL) 14 | { 15 | if (!GetModuleFileName(NULL, Path, MAX_PATH)) 16 | { 17 | return GetLastError(); 18 | } 19 | } 20 | 21 | SCManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); 22 | 23 | if (NULL == SCManagerHandle) 24 | { 25 | return GetLastError(); 26 | } 27 | 28 | ServiceHandle = CreateService( 29 | SCManagerHandle, 30 | ServiceName, 31 | DisplayName, 32 | SERVICE_ALL_ACCESS, 33 | SERVICE_WIN32_OWN_PROCESS, 34 | SERVICE_AUTO_START, 35 | SERVICE_ERROR_NORMAL, 36 | Path, 37 | NULL, 38 | NULL, 39 | NULL, 40 | NULL, 41 | NULL); 42 | 43 | Result = GetLastError(); 44 | 45 | if (NULL == ServiceHandle) 46 | { 47 | goto Exit; 48 | } 49 | 50 | CloseServiceHandle(ServiceHandle); 51 | 52 | Exit: 53 | CloseServiceHandle(SCManagerHandle); 54 | 55 | return Result; 56 | } 57 | 58 | DWORD ServiceUninstall(LPCTSTR ServiceName) 59 | { 60 | SC_HANDLE SCManagerHandle; 61 | SC_HANDLE ServiceHandle; 62 | DWORD Result; 63 | 64 | SCManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); 65 | 66 | if (NULL == SCManagerHandle) 67 | { 68 | return GetLastError(); 69 | } 70 | 71 | ServiceHandle = OpenService( 72 | SCManagerHandle, 73 | ServiceName, 74 | SERVICE_ALL_ACCESS); 75 | 76 | if (NULL == ServiceHandle) 77 | { 78 | Result = GetLastError(); 79 | goto Exit; 80 | } 81 | 82 | DeleteService(ServiceHandle); 83 | 84 | Result = GetLastError(); 85 | 86 | CloseServiceHandle(ServiceHandle); 87 | 88 | Exit: 89 | CloseServiceHandle(SCManagerHandle); 90 | 91 | return Result; 92 | } 93 | -------------------------------------------------------------------------------- /Registry.cpp: -------------------------------------------------------------------------------- 1 | #include "Registry.h" 2 | #include 3 | #include 4 | 5 | #define MAX_KEY_NAME_LENGTH 255 6 | #define REG_PATH_TEMPLATE _T("SYSTEM\\CurrentControlSet\\Services\\%s\\Parameters") 7 | 8 | LONG RegistryGetServiceParameter( 9 | LPCTSTR ServiceName, 10 | LPCTSTR ParameterName, 11 | LPDWORD ParameterValue 12 | ) 13 | { 14 | LONG Result; 15 | LPTSTR KeyName; 16 | HKEY KeyHandle; 17 | HANDLE Heap = GetProcessHeap(); 18 | DWORD Disposition; 19 | DWORD Type; 20 | DWORD Size = sizeof(ULONG); 21 | 22 | if (Heap == NULL) 23 | return GetLastError(); 24 | 25 | KeyName = (LPTSTR)HeapAlloc(Heap, HEAP_ZERO_MEMORY, MAX_KEY_NAME_LENGTH * sizeof(TCHAR)); 26 | 27 | if (KeyName == NULL) 28 | return GetLastError(); 29 | 30 | _sntprintf(KeyName, MAX_KEY_NAME_LENGTH, REG_PATH_TEMPLATE, ServiceName); 31 | 32 | Result = RegCreateKeyEx(HKEY_LOCAL_MACHINE, KeyName, 0, NULL, REG_OPTION_NON_VOLATILE, 33 | KEY_ALL_ACCESS, NULL, &KeyHandle, &Disposition); 34 | 35 | if (Result != ERROR_SUCCESS) 36 | { 37 | goto Exit; 38 | } 39 | 40 | Result = RegQueryValueEx(KeyHandle, ParameterName, NULL, &Type, (LPBYTE)ParameterValue, &Size); 41 | 42 | if (Result != ERROR_SUCCESS) 43 | { 44 | goto Close; 45 | } 46 | 47 | Close: 48 | RegCloseKey(KeyHandle); 49 | Exit: 50 | HeapFree(Heap, 0, KeyName); 51 | 52 | return Result; 53 | } 54 | 55 | LONG RegistrySetServiceParameter( 56 | LPCTSTR ServiceName, 57 | LPCTSTR ParameterName, 58 | DWORD ParameterValue 59 | ) 60 | { 61 | LONG Result; 62 | LPTSTR KeyName; 63 | HKEY KeyHandle; 64 | HANDLE Heap = GetProcessHeap(); 65 | DWORD Disposition; 66 | 67 | if (Heap == NULL) 68 | return GetLastError(); 69 | 70 | KeyName = (LPTSTR)HeapAlloc(Heap, HEAP_ZERO_MEMORY, MAX_KEY_NAME_LENGTH * sizeof(TCHAR)); 71 | 72 | if (KeyName == NULL) 73 | return GetLastError(); 74 | 75 | _sntprintf(KeyName, MAX_KEY_NAME_LENGTH, REG_PATH_TEMPLATE, ServiceName); 76 | 77 | Result = RegCreateKeyEx(HKEY_LOCAL_MACHINE, KeyName, 0, NULL, REG_OPTION_NON_VOLATILE, 78 | KEY_ALL_ACCESS, NULL, &KeyHandle, &Disposition); 79 | 80 | if (Result != ERROR_SUCCESS) 81 | { 82 | goto Exit; 83 | } 84 | 85 | Result = RegSetValueEx(KeyHandle, ParameterName, NULL, REG_DWORD, (const LPBYTE)&ParameterValue, sizeof(ULONG)); 86 | 87 | if (Result != ERROR_SUCCESS) 88 | { 89 | goto Close; 90 | } 91 | 92 | Close: 93 | RegCloseKey(KeyHandle); 94 | Exit: 95 | HeapFree(Heap, 0, KeyName); 96 | 97 | return Result; 98 | } 99 | -------------------------------------------------------------------------------- /SetTimerService.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #include "resource.h" 4 | 5 | #define APSTUDIO_READONLY_SYMBOLS 6 | ///////////////////////////////////////////////////////////////////////////// 7 | // 8 | // Generated from the TEXTINCLUDE 2 resource. 9 | // 10 | #include "windows.h" 11 | 12 | ///////////////////////////////////////////////////////////////////////////// 13 | #undef APSTUDIO_READONLY_SYMBOLS 14 | 15 | ///////////////////////////////////////////////////////////////////////////// 16 | // English (U.S.) resources 17 | 18 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 19 | #ifdef _WIN32 20 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 21 | #pragma code_page(1252) 22 | #endif //_WIN32 23 | 24 | #ifdef APSTUDIO_INVOKED 25 | ///////////////////////////////////////////////////////////////////////////// 26 | // 27 | // TEXTINCLUDE 28 | // 29 | 30 | 1 TEXTINCLUDE 31 | BEGIN 32 | "resource.h\0" 33 | END 34 | 35 | 2 TEXTINCLUDE 36 | BEGIN 37 | "#include ""windows.h""\r\n" 38 | "\0" 39 | END 40 | 41 | 3 TEXTINCLUDE 42 | BEGIN 43 | "\r\n" 44 | "\0" 45 | END 46 | 47 | #endif // APSTUDIO_INVOKED 48 | 49 | 50 | ///////////////////////////////////////////////////////////////////////////// 51 | // 52 | // Version 53 | // 54 | 55 | VS_VERSION_INFO VERSIONINFO 56 | FILEVERSION 1,0,0,1 57 | PRODUCTVERSION 1,0,0,1 58 | FILEFLAGSMASK 0x17L 59 | #ifdef _DEBUG 60 | FILEFLAGS 0x1L 61 | #else 62 | FILEFLAGS 0x0L 63 | #endif 64 | FILEOS 0x4L 65 | FILETYPE 0x1L 66 | FILESUBTYPE 0x0L 67 | BEGIN 68 | BLOCK "StringFileInfo" 69 | BEGIN 70 | BLOCK "040904b0" 71 | BEGIN 72 | VALUE "CompanyName", "Sergey Temerkhanov" 73 | VALUE "FileDescription", "SetTimer Service" 74 | VALUE "FileVersion", "1, 0, 0, 1" 75 | VALUE "InternalName", "SetTimer" 76 | VALUE "LegalCopyright", "Copyright (C) 2020" 77 | VALUE "OriginalFilename", "SetTimer.exe" 78 | VALUE "ProductName", " SetTimer Service" 79 | VALUE "ProductVersion", "1, 0, 0, 1" 80 | END 81 | END 82 | BLOCK "VarFileInfo" 83 | BEGIN 84 | VALUE "Translation", 0x409, 1200 85 | END 86 | END 87 | 88 | #endif // English (U.S.) resources 89 | ///////////////////////////////////////////////////////////////////////////// 90 | 91 | 92 | 93 | #ifndef APSTUDIO_INVOKED 94 | ///////////////////////////////////////////////////////////////////////////// 95 | // 96 | // Generated from the TEXTINCLUDE 3 resource. 97 | // 98 | 99 | 100 | ///////////////////////////////////////////////////////////////////////////// 101 | #endif // not APSTUDIO_INVOKED 102 | 103 | -------------------------------------------------------------------------------- /SetTimerService.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 11 | 12 | 13 | 21 | 36 | 38 | 48 | 52 | 54 | 56 | 58 | 62 | 64 | 66 | 68 | 70 | 72 | 73 | 81 | 97 | 99 | 108 | 112 | 114 | 116 | 118 | 122 | 124 | 126 | 128 | 130 | 132 | 133 | 134 | 135 | 136 | 137 | 140 | 142 | 143 | 145 | 146 | 148 | 150 | 155 | 156 | 158 | 162 | 163 | 164 | 165 | 168 | 170 | 171 | 173 | 174 | 176 | 177 | 178 | 181 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | -------------------------------------------------------------------------------- /SetTimerService.cpp: -------------------------------------------------------------------------------- 1 | // SetTimerService.cpp : Defines the entry point for the console application. 2 | // 3 | 4 | #include 5 | #include 6 | 7 | #include "NtTimer.h" 8 | #include "Registry.h" 9 | #include "ServiceControl.h" 10 | 11 | SERVICE_STATUS gServiceStatus = { 0 }; 12 | SERVICE_STATUS_HANDLE gStatusHandle = NULL; 13 | 14 | ULONG gOriginalTimerResolution; 15 | 16 | VOID WINAPI ServiceMain(DWORD Argc, LPTSTR Argv[]); 17 | VOID WINAPI ServiceCtrlHandler(DWORD); 18 | 19 | #define SERVICE_NAME _T("SetTimer") 20 | #define DISPLAY_NAME _T("Set Kernel Timer") 21 | #define PARAMETER_NAME _T("TimerResolution") 22 | #define MAX_TIMER_PERIOD (100000) 23 | #define MIN_TIMER_PERIOD (5000) 24 | #define DEFAULT_TIMER_PERIOD (20000) /* 2 ms */ 25 | 26 | LONG SetupTimerResolution(VOID) 27 | { 28 | LONG Result; 29 | DWORD TimerResolution; 30 | 31 | Result = RegistryGetServiceParameter(SERVICE_NAME, PARAMETER_NAME, &TimerResolution); 32 | 33 | if ((Result != ERROR_SUCCESS) || 34 | (TimerResolution > MAX_TIMER_PERIOD) || 35 | (TimerResolution < MIN_TIMER_PERIOD)) 36 | { 37 | TimerResolution = DEFAULT_TIMER_PERIOD; 38 | } 39 | 40 | if (Result == ERROR_FILE_NOT_FOUND) { 41 | Result = RegistrySetServiceParameter(SERVICE_NAME, PARAMETER_NAME, TimerResolution); 42 | } 43 | 44 | return TimerResolution; 45 | } 46 | 47 | VOID WINAPI ServiceMain(DWORD Argc, LPTSTR Argv[]) 48 | { 49 | NTSTATUS Status; 50 | LONG TimerResolution; 51 | 52 | UNREFERENCED_PARAMETER(Argc); 53 | UNREFERENCED_PARAMETER(Argv); 54 | 55 | gStatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler); 56 | 57 | if (gStatusHandle == NULL) 58 | { 59 | goto Exit; 60 | } 61 | 62 | // Prepare to start 63 | ZeroMemory(&gServiceStatus, sizeof(gServiceStatus)); 64 | 65 | gServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; 66 | gServiceStatus.dwControlsAccepted = 0; 67 | gServiceStatus.dwCurrentState = SERVICE_START_PENDING; 68 | gServiceStatus.dwWin32ExitCode = 0; 69 | gServiceStatus.dwServiceSpecificExitCode = 0; 70 | gServiceStatus.dwCheckPoint = 0; 71 | 72 | if (SetServiceStatus(gStatusHandle, &gServiceStatus) == FALSE) 73 | { 74 | goto Exit; 75 | } 76 | 77 | TimerResolution = SetupTimerResolution(); 78 | 79 | Status = NtSetTimerResolution(TimerResolution, TRUE, &gOriginalTimerResolution); 80 | 81 | if (Status == STATUS_TIMER_RESOLUTION_NOT_SET) { 82 | gServiceStatus.dwControlsAccepted = 0; 83 | gServiceStatus.dwCurrentState = SERVICE_STOPPED; 84 | gServiceStatus.dwWin32ExitCode = Status; 85 | } else { 86 | // Set the running status 87 | gServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; 88 | gServiceStatus.dwCurrentState = SERVICE_RUNNING; 89 | gServiceStatus.dwWin32ExitCode = 0; 90 | } 91 | 92 | gServiceStatus.dwCheckPoint = 1; 93 | 94 | if (SetServiceStatus(gStatusHandle, &gServiceStatus) == FALSE) 95 | { 96 | goto Exit; 97 | } 98 | 99 | Exit: 100 | return; 101 | } 102 | 103 | VOID WINAPI ServiceCtrlHandler(DWORD CtrlCode) 104 | { 105 | NTSTATUS Status; 106 | ULONG TimerResolution; 107 | 108 | switch (CtrlCode) 109 | { 110 | case SERVICE_CONTROL_STOP: 111 | if (gServiceStatus.dwCurrentState != SERVICE_RUNNING) 112 | break; 113 | 114 | /* 115 | * Stop the service and cleanup here 116 | */ 117 | 118 | gServiceStatus.dwControlsAccepted = 0; 119 | gServiceStatus.dwCurrentState = SERVICE_STOPPED; 120 | gServiceStatus.dwWin32ExitCode = 0; 121 | gServiceStatus.dwCheckPoint = 4; 122 | 123 | Status = NtSetTimerResolution(gOriginalTimerResolution, FALSE, &TimerResolution); 124 | 125 | if (SetServiceStatus(gStatusHandle, &gServiceStatus) == FALSE) 126 | { 127 | return; 128 | } 129 | 130 | break; 131 | 132 | default: 133 | break; 134 | } 135 | 136 | } 137 | 138 | #define PARAM_USAGE \ 139 | _T("Command line parameters:\r\n") \ 140 | _T("/INSTALL install service\r\n") \ 141 | _T("/UNINSTALL uninstall service\r\n") 142 | 143 | #define PARAM_HELP \ 144 | _T("/? for a list of supported parameters\r\n") 145 | 146 | #define PARAM_TOO_MANY \ 147 | _T("Too many command line parameters\r\n") 148 | 149 | #define PARAM_UNKNOWN \ 150 | _T("Unknown command line parameter\r\n") 151 | 152 | #define PARAM_INSTALL \ 153 | _T("/INSTALL") 154 | 155 | #define PARAM_UNINSTALL \ 156 | _T("/UNINSTALL") 157 | 158 | #define PARAM_QUESTION \ 159 | _T("/?") 160 | 161 | int _tmain(int Argc, LPTSTR Argv[]) 162 | { 163 | UNREFERENCED_PARAMETER(Argc); 164 | UNREFERENCED_PARAMETER(Argv); 165 | 166 | SERVICE_TABLE_ENTRY ServiceTable[] = 167 | { 168 | {SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain}, 169 | {NULL, NULL} 170 | }; 171 | 172 | if (Argc > 2) { 173 | _tcprintf(PARAM_TOO_MANY); 174 | _tcprintf(PARAM_HELP); 175 | return ERROR_INVALID_PARAMETER; 176 | } else if (Argc == 2) { 177 | if (_tcsicmp(Argv[1], PARAM_QUESTION) == 0) 178 | { 179 | _tcprintf(PARAM_USAGE); 180 | return ERROR_SUCCESS; 181 | } 182 | else if (_tcsicmp(Argv[1], PARAM_INSTALL) == 0) 183 | { 184 | return ServiceInstall(SERVICE_NAME, DISPLAY_NAME, NULL); 185 | } 186 | else if (_tcsicmp(Argv[1], PARAM_UNINSTALL) == 0) 187 | { 188 | return ServiceUninstall(SERVICE_NAME); 189 | } 190 | else 191 | { 192 | _tcprintf(PARAM_UNKNOWN); 193 | _tcprintf(PARAM_HELP); 194 | return ERROR_INVALID_PARAMETER; 195 | } 196 | } 197 | 198 | if (StartServiceCtrlDispatcher(ServiceTable) == FALSE) 199 | { 200 | return GetLastError(); 201 | } 202 | 203 | return 0; 204 | } 205 | --------------------------------------------------------------------------------