PROWAREtech
Windows API: "Helper" Service Program
An example Windows service program that executes another program; written in C/C++.
This is a good example of a Windows Service written in C. A better example would use C++ and the "Event Viewer".
This Windows Service installs itself and uninstalls itself. Run "HelperService.exe /help" for install instructions.
This service executes an executable at a time everyday specified in its INI file. Hence the name "Helper". This is useful because the programmer can write the executable in higher generation languages like C# or VB.NET where productivity is high.
Download the 32-bit/x86 executable w/INI file and README text file: HELPERSERVICE.zip.
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <winsvc.h>
#define ALLOC(siz) HeapAlloc(GetProcessHeap(), 0, siz)
#define FREE(mem) HeapFree(GetProcessHeap(), 0, mem)
char* ini, * szServiceName = NULL, * szProcessToCreate = NULL, * szProcessArguments = NULL, * szTimeToExecute = NULL;
HANDLE hLog;
void printf(const char* s)
{
unsigned long i;
for (i = 0; s[i]; i++);
WriteFile(CreateFileA("CONOUT$", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL), s, i, &i, NULL);
}
SERVICE_STATUS ServStatus;
SERVICE_STATUS_HANDLE ServStatusHandle;
const char szDefaultINI[] = "ServiceName=\r\nExeToRun=\r\nArguments=\r\nTimeToExecute=1:00\r\nLogFile=";
void WriteLog(const char* szText)
{
if (hLog != INVALID_HANDLE_VALUE)
{
DWORD dw;
WriteFile(hLog, szText, strlen(szText), &dw, NULL);
}
}
void PrintLastErrorToLog(const char* szAddOn)
{
LPSTR lpMsgBuf;
int i = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&lpMsgBuf, 0, NULL);
while (lpMsgBuf[i - 1] == '\r' || lpMsgBuf[i - 1] == '\n')i--;
lpMsgBuf[i] = 0;
WriteLog(lpMsgBuf);
LocalFree(lpMsgBuf);
if (szAddOn)
WriteLog(szAddOn);
}
void WaitForInput()
{
DWORD dw;
ReadFile(CreateFileA("CONIN$", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL), &dw, 1, &dw, NULL);
}
void PrintLastErrorToScreen(int lastError)
{
LPSTR lpMsgBuf;
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, lastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&lpMsgBuf, 0, NULL);
printf("Error ");
char sz[10];
_itoa(lastError, sz, 10);
printf(sz);
printf(": ");
printf(lpMsgBuf);
LocalFree(lpMsgBuf);
WaitForInput();
}
void __stdcall ServCtrlHandler(DWORD Opcode)
{
switch (Opcode)
{
case SERVICE_CONTROL_STOP:
ServStatus.dwWin32ExitCode = 0;
ServStatus.dwCurrentState = SERVICE_STOP_PENDING;
ServStatus.dwCheckPoint = 0;
ServStatus.dwWaitHint = 3000;
if (!SetServiceStatus(ServStatusHandle, &ServStatus))
PrintLastErrorToLog(" : SetServiceStatus()\r\n");
Sleep(ServStatus.dwWaitHint);
if (INVALID_HANDLE_VALUE != hLog)
CloseHandle(hLog);
FREE(ini);
ServStatus.dwWaitHint = 0;
ServStatus.dwCurrentState = SERVICE_STOPPED;
break;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
WriteLog("Unrecognized Control Handler Code\r\n");
}
// Send current status.
if (!SetServiceStatus(ServStatusHandle, &ServStatus))
PrintLastErrorToLog(" : SetServiceStatus()\r\n");
return;
}
void MakeTime(SYSTEMTIME* st, char* output)
{
GetLocalTime(st);
int i = 0;
_itoa(st->wYear, &output[i], 10);
while (output[++i]);
output[i++] = '\\';
if (st->wMonth < 10)
output[i++] = '0';
_itoa(st->wMonth, &output[i], 10);
while (output[++i]);
output[i++] = '\\';
if (st->wDay < 10)
output[i++] = '0';
_itoa(st->wDay, &output[i], 10);
while (output[++i]);
output[i++] = ' ';
if (st->wHour < 10)
output[i++] = '0';
_itoa(st->wHour, &output[i], 10);
while (output[++i]);
output[i++] = ':';
if (st->wMinute < 10)
output[i++] = '0';
_itoa(st->wMinute, &output[i], 10);
while (output[++i]);
output[i++] = ':';
if (st->wSecond < 10)
output[i++] = '0';
_itoa(st->wSecond, &output[i], 10);
}
BOOL ExecuteProcess()
{
STARTUPINFOA* si = (STARTUPINFOA*)ALLOC(sizeof(STARTUPINFOA));
PROCESS_INFORMATION* pi = (PROCESS_INFORMATION*)ALLOC(sizeof(PROCESS_INFORMATION));
ZeroMemory(si, sizeof(STARTUPINFOA));
si->cb = sizeof(STARTUPINFOA);
ZeroMemory(pi, sizeof(PROCESS_INFORMATION));
if (!CreateProcessA(szProcessToCreate, szProcessArguments, NULL, NULL, FALSE, 0, NULL, NULL, si, pi))
{
PrintLastErrorToLog(" : CreateProcess()");
FREE(si);
FREE(pi);
return FALSE;
}
WaitForSingleObject(pi->hProcess, INFINITE);
CloseHandle(pi->hProcess);
CloseHandle(pi->hThread);
FREE(pi);
FREE(si);
return TRUE;
}
void __stdcall StartServ(DWORD argc, LPSTR* argv)
{
int i;
SYSTEMTIME st;
char tim[20];
long hr, min;
ServStatus.dwServiceType = SERVICE_WIN32;
ServStatus.dwCurrentState = SERVICE_START_PENDING;
ServStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
ServStatus.dwWin32ExitCode = 0;
ServStatus.dwServiceSpecificExitCode = 0;
ServStatus.dwCheckPoint = 0;
ServStatus.dwWaitHint = 0;
ServStatusHandle = RegisterServiceCtrlHandlerA(szServiceName, ServCtrlHandler);
if (ServStatusHandle == (SERVICE_STATUS_HANDLE)0)
{
PrintLastErrorToLog(" : RegisterServiceCtrlHandler()\r\n");
goto exit;
}
WriteLog("Service started at ");
MakeTime(&st, tim);
WriteLog(tim);
WriteLog("\r\n");
// Initialization complete - report running status.
ServStatus.dwCurrentState = SERVICE_RUNNING;
ServStatus.dwCheckPoint = 0;
ServStatus.dwWaitHint = 0;
if (!SetServiceStatus(ServStatusHandle, &ServStatus))
PrintLastErrorToLog(" : SetServiceStatus()\r\n");
for (i = 0; szTimeToExecute[i] && szTimeToExecute[i] != ':' && szTimeToExecute[i] >= '0' && szTimeToExecute[i] <= '9'; i++);
if (':' == szTimeToExecute[i])
{
szTimeToExecute[i++] = 0;
hr = atol(szTimeToExecute);
szTimeToExecute = &szTimeToExecute[i];
min = atol(szTimeToExecute);
}
else
hr = min = 0;
while (SERVICE_RUNNING == ServStatus.dwCurrentState)
{
GetLocalTime(&st);
if (st.wHour == hr && st.wMinute == min && st.wSecond == 0)
{
MakeTime(&st, tim);
WriteLog(tim);
WriteLog(" Execute process initiated.\r\n");
ExecuteProcess();
}
Sleep(500); // MUST SLEEP FOR ONE-HALF SECOND
}
exit:
return;
}
#define INSTALL_FOUND 1
#define UNINSTALL_FOUND 2
#define HELP_FOUND 4
#define SERVICE_NAME 1
#define PROCESS_TO_CREATE 2
#define LOG_FILE 3
#define TIME_TO_EXECUTE 4
#define PROCESS_ARGUMENTS 5
int FindINIParam(char* nam)
{
if (0 == _stricmp(nam, "ServiceName"))
return SERVICE_NAME;
else if (0 == _stricmp(nam, "ExeToRun"))
return PROCESS_TO_CREATE;
else if (0 == _stricmp(nam, "LogFile"))
return LOG_FILE;
else if (0 == _stricmp(nam, "TimeToExecute"))
return TIME_TO_EXECUTE;
else if (0 == _stricmp(nam, "Arguments"))
return PROCESS_ARGUMENTS;
return 0;
}
void ParseINI()
{
char* sz, * szLog = NULL;
int i = 0;
for (i = 0; ini[i];)
{
while ('\r' == ini[i] || '\n' == ini[i] || ' ' == ini[i])
{
if (0 == ini[i++])
goto exit;
}
sz = &ini[i];
while ('=' != ini[i])
{
if (0 == ini[i++])
goto exit;
}
ini[i++] = 0;
switch (FindINIParam(sz))
{
case SERVICE_NAME:
szServiceName = &ini[i];
break;
case PROCESS_TO_CREATE:
szProcessToCreate = &ini[i];
break;
case LOG_FILE:
szLog = &ini[i];
break;
case TIME_TO_EXECUTE:
szTimeToExecute = &ini[i];
break;
case PROCESS_ARGUMENTS:
szProcessArguments = &ini[i];
break;
}
while ('\r' != ini[i] && '\n' != ini[i])
{
if (0 == ini[i++])
goto exit;
}
ini[i++] = 0;
}
exit:
if (szLog)
{
hLog = CreateFileA(szLog, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE != hLog)
SetFilePointer(hLog, 0, NULL, FILE_END);
}
}
const char* HELP_PART_1 = "\r\nService Name: ";
const char* HELP_PART_2 = "\r\n\r\nUSAGE\r\n\r\nInstall Service: HelperService.exe /install domain\\user-name user-password\r\nNOTE: The user should have the \"Log on as a service\" right\r\n\r\nInstall Service: HelperService.exe /install null null\r\n\r\nUninstall Service: HelperService.exe /uninstall\r\n\r\n";
int main(int argc, char* argv[])
{
int action;
int i;
HANDLE hTmp;
char* sz = (char*)ALLOC(strlen(argv[0]) + 2);
strcpy(sz, argv[0]);
for (i = strlen(sz) - 1; sz[i] && sz[i] != '\\'; i--);
if (sz[i])
{
sz[i] = 0;
SetCurrentDirectoryA(sz);
sz[i] = '\\';
}
for (i = strlen(sz) - 1; sz[i] && sz[i] != '.'; i--);
if (sz[i])
strcpy(&(sz[i + 1]), "ini");
else
strcat(sz, ".ini");
hTmp = CreateFileA(sz, GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE != hTmp)
{
FREE(sz);
DWORD dw = GetFileSize(hTmp, NULL);
if (dw <= strlen(szDefaultINI))
{
printf("INI file not setup");
if (dw < strlen(szDefaultINI))
WriteFile(hTmp, szDefaultINI, strlen(szDefaultINI), &dw, NULL);
CloseHandle(hTmp);
return 0;
}
ini = (char*)ALLOC(dw + 1);
if (!ReadFile(hTmp, ini, dw, &dw, NULL))
{
CloseHandle(hTmp);
printf("INI file read error");
FREE(ini);
return 0;
}
CloseHandle(hTmp);
if (0 == dw)
{
printf("INI file not read");
FREE(ini);
return 0;
}
ini[dw] = 0;
ParseINI();
if (NULL == szServiceName || 0 == szServiceName[0] || NULL == szProcessToCreate || 0 == szProcessToCreate[0] || NULL == szTimeToExecute || 0 == szTimeToExecute[0])
{
printf("INI file incomplete");
FREE(ini);
return 0;
}
}
else
{
FREE(sz);
printf("Error opening INI file");
return 0;
}
SERVICE_TABLE_ENTRYA DispatchTable[] =
{
{ (char*)szServiceName, StartServ },
{ NULL, NULL }
};
for (action = i = 0; i < argc; i++)
{
if (0 == _stricmp(argv[i], "/install"))
action |= INSTALL_FOUND;
else if (0 == _stricmp(argv[i], "/uninstall"))
action |= UNINSTALL_FOUND;
else if (0 == _stricmp(argv[i], "/help"))
action |= HELP_FOUND;
else if (0 == _stricmp(argv[i], "/?"))
action |= HELP_FOUND;
else if (0 == _stricmp(argv[i], "help"))
action |= HELP_FOUND;
else if (0 == _stricmp(argv[i], "?"))
action |= HELP_FOUND;
}
if ((action & INSTALL_FOUND) && !(action & HELP_FOUND))
{
if (4 == argc)
{
int len = 0;
for (i = 1; i < argc; i++)
len += strlen(argv[i]) + 1;
sz = (char*)ALLOC(len);
sz[0] = 0;
for (i = 1; i < argc; i++)
{
strcpy(&sz[strlen(sz)], argv[i]);
strcpy(&sz[strlen(sz)], " ");
}
strcpy(&sz[strlen(sz)], " /admin");
ShellExecuteA(NULL, "runas", argv[0], sz, NULL, SW_SHOWNORMAL);
FREE(sz);
}
else if(5 == argc)
{
SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);
if (scm != NULL)
{
SC_HANDLE serv = CreateServiceA(scm, szServiceName, szServiceName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS | (0 == _stricmp(argv[2], "null") ? SERVICE_INTERACTIVE_PROCESS : 0), SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, argv[0], NULL, NULL, NULL, (0 == _stricmp(argv[2], "null") ? NULL : argv[2]), (0 == _stricmp(argv[3], "null") ? NULL : argv[3]));
if (NULL != serv)
{
if (!StartService(serv, 0, NULL))
{
int le = GetLastError();
if (_stricmp(argv[2], "null") != 0 && ERROR_SERVICE_LOGON_FAILED == le)
{
printf("Service is installed but there was a log on failure using: ");
printf(argv[2]);
printf(" ");
printf(argv[3]);
printf("\r\nThe service is not running...");
printf(HELP_PART_2);
WaitForInput();
}
else
PrintLastErrorToScreen(le);
}
else
{
printf(szServiceName);
printf(": installed and running\r\n\r\n");
WaitForInput();
}
CloseServiceHandle(serv);
}
else
PrintLastErrorToScreen(GetLastError());
CloseServiceHandle(scm);
}
else
PrintLastErrorToScreen(GetLastError());
}
else
{
printf(HELP_PART_1);
printf(szServiceName);
printf(HELP_PART_2);
WaitForInput();
}
}
else if ((action & UNINSTALL_FOUND) && !(action & HELP_FOUND))
{
if(2 == argc)
ShellExecuteA(NULL, "runas", argv[0], "/uninstall /admin", NULL, SW_SHOWNORMAL);
else if(3 == argc)
{
SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
if (scm != NULL)
{
SC_HANDLE serv = OpenServiceA(scm, szServiceName, SERVICE_ALL_ACCESS);
if (NULL != serv)
{
SERVICE_STATUS stat;
if (QueryServiceStatus(serv, &stat))
{
if (stat.dwCurrentState != SERVICE_STOPPED)
{
if (ControlService(serv, SERVICE_CONTROL_STOP, &stat))
{
while (stat.dwCurrentState != SERVICE_STOP_PENDING && stat.dwCurrentState != SERVICE_STOPPED)
{
Sleep(1000);
if (!QueryServiceStatus(serv, &stat))
{
PrintLastErrorToLog("\r\n");
break;
}
}
while (stat.dwCurrentState != SERVICE_STOPPED)
{
Sleep(1000);
if (!QueryServiceStatus(serv, &stat))
{
PrintLastErrorToLog("\r\n");
break;
}
}
}
}
}
if (!DeleteService(serv))
PrintLastErrorToScreen(GetLastError());
else
printf("Service uninstalled\r\n\r\n");
CloseServiceHandle(serv);
WaitForInput();
}
else
PrintLastErrorToScreen(GetLastError());
CloseServiceHandle(scm);
}
else
PrintLastErrorToScreen(GetLastError());
}
else
{
printf(HELP_PART_1);
printf(szServiceName);
printf(HELP_PART_2);
WaitForInput();
}
}
else if (action & HELP_FOUND)
{
printf(HELP_PART_1);
printf(szServiceName);
printf(HELP_PART_2);
WaitForInput();
}
else
{
SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
if (scm != NULL)
{
SC_HANDLE serv = OpenServiceA(scm, szServiceName, SERVICE_ALL_ACCESS);
if (NULL != serv)
{
CloseServiceHandle(serv);
CloseServiceHandle(scm);
printf("\r\nAttempting to start service.");
StartServiceCtrlDispatcherA(DispatchTable);
}
else
{
switch (GetLastError())
{
case ERROR_ACCESS_DENIED:
printf("\r\nAccess denied.");
break;
case ERROR_INVALID_NAME:
printf("\r\nInvalid Service Name.");
break;
case ERROR_SERVICE_DOES_NOT_EXIST:
printf("\r\nService not installed.\r\n");
printf(HELP_PART_1);
printf(szServiceName);
printf(HELP_PART_2);
break;
}
}
CloseServiceHandle(scm);
}
WaitForInput();
}
return 0;
}
Comment