C++ Make service do something - c++

I made a service using a tutorial. How can I make it actually do something? Here's the code:
#include <windows.h>
SERVICE_STATUS serviceStatus = { 0 };
SERVICE_STATUS_HANDLE statusHandle;
HANDLE serviceStopEvent = INVALID_HANDLE_VALUE;
void WINAPI ServiceMain(DWORD argc, LPTSTR *argv);
void WINAPI ServiceCtrlHandler(DWORD);
DWORD WINAPI ServiceWorkerThread(LPVOID lParam);
#define SERVICE_NAME "Cool Service"
int main(int argc, char **argv)
{
SERVICE_TABLE_ENTRY serviceTable[] =
{
{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain},
{NULL, NULL}
};
if (!StartServiceCtrlDispatcher(serviceTable))
return GetLastError();
return 0;
}
void WINAPI ServiceMain(DWORD argc, LPTSTR *argv)
{
DWORD status = E_FAIL;
statusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);
if (statusHandle == NULL)
goto EXIT;
ZeroMemory(&serviceStatus, sizeof(serviceStatus));
serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_START_PENDING;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwServiceSpecificExitCode = 0;
serviceStatus.dwCheckPoint = 0;
if (!SetServiceStatus(statusHandle, &serviceStatus))
OutputDebugString("Cool Service: Service Main: SetServiceStatus returned error!");
serviceStopEvent = CreateEvent(NULL, true, false, NULL);
if (serviceStopEvent == NULL)
{
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_STOPPED;
serviceStatus.dwWin32ExitCode = GetLastError();
serviceStatus.dwCheckPoint = 1;
if (!SetServiceStatus(statusHandle, &serviceStatus))
OutputDebugString("Cool Service: Service Main: SetServiceStatus returned error!");
goto EXIT;
}
serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
serviceStatus.dwCurrentState = SERVICE_RUNNING;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCheckPoint = 0;
if (!SetServiceStatus(statusHandle, &serviceStatus))
OutputDebugString("Cool Service: Service Main: SetServiceStatus returned error!");
HANDLE thread = CreateThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
WaitForSingleObject(thread, INFINITE);
CloseHandle(serviceStopEvent);
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_STOPPED;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCheckPoint = 3;
if (!SetServiceStatus(statusHandle, &serviceStatus))
OutputDebugString("Cool Service: Service Main: SetServiceStatus returned error!");
EXIT:
return;
}
void WINAPI ServiceCtrlHandler(DWORD ctrlCode)
{
switch (ctrlCode)
{
case SERVICE_CONTROL_STOP:
{
if (serviceStatus.dwCurrentState != SERVICE_RUNNING)
break;
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCheckPoint = 4;
if (!SetServiceStatus(statusHandle, &serviceStatus))
OutputDebugString("Cool Service: Service Handler: SetServiceStatus returned error!");
SetEvent(serviceStopEvent);
break;
}
default: break;
}
}
void Function()
{
Beep(7000, 1000);
}
DWORD WINAPI ServiceWorkerThread(LPVOID lParam)
{
while (WaitForSingleObject(serviceStopEvent, 0) != WAIT_OBJECT_0)
{
Function();
Sleep(3000);
}
return ERROR_SUCCESS;
}
The service does nothing after I install and start it in "services.msc", it should beep, right? Or my thinking is off the way here. Thanks for help :)

Related

Windows service does not capture shutdown event C/C++

I created a small windows service to capture some events, including the system shutdown. Every time I turn off the computer, the service event is not called. But when I restart the computer the event works normally.
I already tried to use: SERVICE_ACCEPT_PRESHUTDOWN + SERVICE_CONTROL_PRESHUTDOWN and was not successful.
How could I catch the computer shutdown event?
Ps: After compiling I register the service with the following command: sc.exe create "ZSimpleService" binPath = "C:\path\ZSimpleService.exe"
Edit 1: I'm using windows 10
Code:
SERVICE_STATUS g_ServiceStatus = { 0 };
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE;
VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv);
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam);
DWORD WINAPI CtrlHandlerEx(DWORD CtrlCode, DWORD eventType, LPVOID eventData, LPVOID context);
#define SERVICE_NAME _T("ZSimpleService")
VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv) {
g_StatusHandle = RegisterServiceCtrlHandlerEx(SERVICE_NAME, CtrlHandlerEx,
NULL);
if (g_StatusHandle == NULL) {
goto EXIT;
}
// Tell the service controller we are starting
ZeroMemory( & g_ServiceStatus, sizeof(g_ServiceStatus));
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_SESSIONCHANGE
| SERVICE_ACCEPT_SHUTDOWN;
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwServiceSpecificExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE) {
//...
}
g_ServiceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (g_ServiceStopEvent == NULL) {
//...
goto EXIT;
}
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE) {
//...
}
HANDLE hThread = CreateThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(g_ServiceStopEvent);
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 3;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE) {
}
EXIT: return;
}
void suspending() {
FILE *file = fopen("C:\\test\\suspending.txt", "w+");
if (file)
fprintf(file, "...");
}
void logoff() {
FILE *file = fopen("C:\\test\\logoff.txt", "w+");
if (file)
fprintf(file, "...");
}
void lock_session() {
FILE *file = fopen("C:\\test\\lock_session.txt", "w+");
if (file)
fprintf(file, "...");
}
void poweroff() {
FILE *file = fopen("C:\\test\\poweroff.txt", "w+");
if (file)
fprintf(file, "...");
}
DWORD WINAPI CtrlHandlerEx(DWORD CtrlCode, DWORD eventType, LPVOID eventData,
LPVOID context) {
switch (CtrlCode) {
case SERVICE_CONTROL_STOP: {
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
g_ServiceStatus.dwWaitHint = 0;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE) {
//...
}
SetEvent(g_ServiceStopEvent);
return NO_ERROR;
}
case SERVICE_CONTROL_POWEREVENT: {
if (eventType == PBT_APMQUERYSUSPEND) {
//Computer is suspending
suspending();
}
return NO_ERROR;
}
case SERVICE_CONTROL_SESSIONCHANGE: {
switch (eventType) {
case WTS_SESSION_LOGOFF:
//User is logging off
logoff();
break;
case WTS_SESSION_LOCK:
//User locks the session
lock_session();
break;
}
return NO_ERROR;
}
case SERVICE_CONTROL_SHUTDOWN: {
//Computer is shutting down
poweroff();
return NO_ERROR;
}
default:
return ERROR_CALL_NOT_IMPLEMENTED;
}
}
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam) {
while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0) {
//many cool code....
Sleep(3000);
}
return 0;
}
DWORD RunService() {
SERVICE_TABLE_ENTRY serviceTable[] = { { SERVICE_NAME, ServiceMain },
{ 0, 0 } };
if (StartServiceCtrlDispatcher(serviceTable)) {
return 0;
} else {
DWORD erro = GetLastError();
//handler erro...
return 1;
}
}
int _tmain(int argc, TCHAR *argv[]) {
RunService();
return 0;
}
When the fast startup option enabled, click start menu -> shutdown will put the machine into sleep mode/hibernation instead of shutdown. But restart menu isn't affected. (And shuting down from command line isn't affected too as we already found.)
So you can disable fast startup to solve this issue.

Troubles when using named pipes in Windows service

I'm creating service for Windows 10. I've followed this tutorial. https://www.codeproject.com/Articles/499465/Simple-Windows-Service-in-Cplusplus
But when I've added my code to this example, something happened and I can't stop service from Services list. I can stop it only from task manager. But if I comment my code, service stopping properly.
I would be grateful for any advice. Code listed below.
#include <Windows.h>
#include <tchar.h>
#include <string>
#include <fstream>
SERVICE_STATUS g_ServiceStatus = { 0 };
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE;
std::wofstream output(L"C:\\Users\\0x0\\source\\Service\\output.txt");
VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv);
VOID WINAPI ServiceCtrlHandler(DWORD);
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam);
#define SERVICE_NAME _T("TestService")
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
{
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
auto dwFlags = FILE_ATTRIBUTE_NORMAL;
STARTUPINFOW si;
GetStartupInfoW(&si);
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
ZeroMemory(&pi, sizeof(pi));
HANDLE service_pipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\ServicePipe"),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
128,
16 * 1024,
16 * 1024,
0,
nullptr);
if (service_pipe == INVALID_HANDLE_VALUE)
{
return 1;
}
TCHAR inbox_buffer[1024];
DWORD read, write;
while (1)
{
if (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0)
{
//If I comment this 'if block', service stopping properly. But I don't see any errors in this part of code.
if (ConnectNamedPipe(service_pipe, nullptr))
{
if (ReadFile(service_pipe, inbox_buffer, 1024 * sizeof(TCHAR), &read, nullptr))
{
std::wstring args = inbox_buffer;
std::wstring command = L"\"C:\\Program Files (x86)\\Unility\\utility.exe\" " + args;
if (!CreateProcessW(NULL, (LPWSTR)command.c_str(), NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
{
output << "CreateProcessW Error = " << GetLastError() << std::endl;
}
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
bool success = false;
do
{
success = WriteFile(service_pipe, L"executed", sizeof(L"executed"), &write, nullptr);
} while (!success);
}
DisconnectNamedPipe(service_pipe);
}
}
else
{
output << "WaitForSingleObject(g_ServiceStopEvent, 0)" << std::endl;
break;
}
}
output << "CloseHandle(service_pipe)_1" << std::endl;
CloseHandle(service_pipe);
output << "CloseHandle(service_pipe)_2" << std::endl;
return ERROR_SUCCESS;
}
VOID WINAPI ServiceCtrlHandler(DWORD CtrlCode)
{
switch (CtrlCode)
{
case SERVICE_CONTROL_STOP:
if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
break;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 4;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
output << "TestService: ServiceCtrlHandler: SetServiceStatus returned error" << std::endl;
}
SetEvent(g_ServiceStopEvent);
output << "SetEvent(g_ServiceStopEvent)_1" << std::endl;
break;
default:
break;
}
output << "SetEvent(g_ServiceStopEvent)_2" << std::endl;
}
VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv)
{
DWORD Status = E_FAIL;
g_StatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);
if (g_StatusHandle == NULL)
{
return;
}
ZeroMemory(&g_ServiceStatus, sizeof(g_ServiceStatus));
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwServiceSpecificExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
output << "TestService: ServiceMain: SetServiceStatus returned error" << std::endl;
}
g_ServiceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (g_ServiceStopEvent == NULL)
{
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = GetLastError();
g_ServiceStatus.dwCheckPoint = 1;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
output << "TestService: ServiceMain: SetServiceStatus returned error" << std::endl;
}
return;
}
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
output << "TestService: ServiceMain: SetServiceStatus returned error" << std::endl;
}
HANDLE hThread = CreateThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
output << "CloseHandle(g_ServiceStopEvent)_1" << std::endl;
CloseHandle(g_ServiceStopEvent);
output << "CloseHandle(g_ServiceStopEvent)_2" << std::endl;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 3;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
output << "TestService: ServiceMain: SetServiceStatus returned error" << std::endl;
}
return;
}
int _tmain(int argc, TCHAR *argv[])
{
SERVICE_TABLE_ENTRY ServiceTable[] =
{
{(LPWSTR)"TestService", (LPSERVICE_MAIN_FUNCTION)ServiceMain},
{NULL, NULL}
};
if (StartServiceCtrlDispatcher(ServiceTable) == FALSE)
{
return GetLastError();
}
return 0;
}
Dirty way, but it's working. I've created function which handles all job related to pipes. I've runned this function in new thread. When the service receives a stop signal, I send a stop message to the pipe and it stops the loop.
#include <Windows.h>
#include <tchar.h>
#include <string>
#include <thread>
#include <fstream>
SERVICE_STATUS g_ServiceStatus = { 0 };
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE;
VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv);
VOID WINAPI ServiceCtrlHandler(DWORD);
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam);
#define SERVICE_NAME _T("TestService")
void pipe_server_function() {
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
auto dwFlags = FILE_ATTRIBUTE_NORMAL;
STARTUPINFOW si;
GetStartupInfoW(&si);
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
ZeroMemory(&pi, sizeof(pi));
HANDLE service_pipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\ServicePipe"),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
128,
16 * 1024,
16 * 1024,
0,
nullptr);
if (service_pipe == INVALID_HANDLE_VALUE)
{
return;
}
TCHAR inbox_buffer[1024];
std::fill(inbox_buffer, inbox_buffer + 1024, '\0');
DWORD read, write;
while (true)
{
if (ConnectNamedPipe(service_pipe, nullptr))
{
if (ReadFile(service_pipe, inbox_buffer, 1024 * sizeof(TCHAR), &read, nullptr))
{
std::wstring args = inbox_buffer;
if (args.find("stop_signal") != std::wstring::npos)
{
DisconnectNamedPipe(service_pipe);
break;
}
std::wstring command = L"\"C:\\Program Files (x86)\\Unility\\utility.exe\" " + args;
if (!CreateProcessW(NULL, (LPWSTR)command.c_str(), NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
{
//CreateProcessW failed. You should log this!
}
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
bool success = false;
do
{
success = WriteFile(service_pipe, L"executed", sizeof(L"executed"), &write, nullptr);
} while (!success);
}
DisconnectNamedPipe(service_pipe);
std::fill(inbox_buffer, inbox_buffer + 1024, '\0');
}
}
CloseHandle(service_pipe);
}
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
{
if (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0) {
Sleep(1000);
}
service::handle gsprint_pipe = CreateFile(TEXT("\\\\.\\pipe\\ServicePipe"),
GENERIC_READ | GENERIC_WRITE,
0,
nullptr,
OPEN_EXISTING,
0,
nullptr);
bool succeess = false;
DWORD read;
do
{
succeess = WriteFile(gsprint_pipe, L"stop_signal", sizeof(L"stop_signal"), &read, nullptr);
} while (!succeess);
return ERROR_SUCCESS;
}
VOID WINAPI ServiceCtrlHandler(DWORD CtrlCode)
{
switch (CtrlCode)
{
case SERVICE_CONTROL_STOP:
if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
break;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 4;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
//SetServiceStatus failed. You should log this!
}
SetEvent(g_ServiceStopEvent);
break;
default:
break;
}
}
VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv)
{
DWORD Status = E_FAIL;
g_StatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);
if (g_StatusHandle == NULL)
{
return;
}
ZeroMemory(&g_ServiceStatus, sizeof(g_ServiceStatus));
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwServiceSpecificExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
//SetServiceStatus failed. You should log this!
}
g_ServiceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (g_ServiceStopEvent == NULL)
{
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = GetLastError();
g_ServiceStatus.dwCheckPoint = 1;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
//SetServiceStatus failed. You should log this!
}
return;
}
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
//SetServiceStatus failed. You should log this!
}
std::thread pipe_server(pipe_server_function);
HANDLE hThread = CreateThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
pipe_server.join();
CloseHandle(g_ServiceStopEvent);
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 3;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
//SetServiceStatus failed. You should log this!
}
return;
}
int _tmain(int argc, TCHAR *argv[])
{
SERVICE_TABLE_ENTRY ServiceTable[] =
{
{(LPWSTR)"TestService", (LPSERVICE_MAIN_FUNCTION)ServiceMain},
{NULL, NULL}
};
if (StartServiceCtrlDispatcher(ServiceTable) == FALSE)
{
return GetLastError();
}
return 0;
}

get the default string using EvtFormatMessage

I am trying to get the base string in the DLL using EvtFormatMessage but no matter what I do its not working. The windows help page made it sound like you can use the values and valuecount parameters to change the default behavior but when I change them nothing is printed.
Another attempt I made was to go through the publishers metadata and match it with the correct eventId and version but the EvtOpenEventMetadatEnum has no items for it to iterate through for all events publishers. It works for time change events but not for other events.
This is the code I have to return the message string. hMetadata is the publisher metadata and hEvent is the event metadata
LPWSTR GetMessageString(EVT_HANDLE hMetadata, EVT_HANDLE hEvent, EVT_FORMAT_MESSAGE_FLAGS FormatId, DWORD MsgID)
{
LPWSTR pBuffer = NULL;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
DWORD status = ERROR_SUCCESS;
if (!fpEvtFormatMessage(hMetadata, hEvent, MsgID, 0, NULL, FormatId, dwBufferSize, pBuffer, &dwBufferUsed))
{
status = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER == status)
{
// An event can contain one or more keywords. The function returns keywords
// as a list of keyword strings. To process the list, you need to know the
// size of the buffer, so you know when you have read the last string, or you
// can terminate the list of strings with a second null terminator character
// as this example does.
if ((EvtFormatMessageKeyword == FormatId))
pBuffer[dwBufferSize - 1] = L'\0';
else
dwBufferSize = dwBufferUsed;
pBuffer = (LPWSTR)malloc(dwBufferSize * sizeof(WCHAR));
if (pBuffer)
{
fpEvtFormatMessage(hMetadata, hEvent, MsgID, 0, NULL, FormatId, dwBufferSize, pBuffer, &dwBufferUsed);
// Add the second null terminator character.
if ((EvtFormatMessageKeyword == FormatId))
pBuffer[dwBufferUsed - 1] = L'\0';
}
else
{
TRACE5(_T("malloc failed\n"));
}
}
else if (ERROR_EVT_MESSAGE_NOT_FOUND == status || ERROR_EVT_MESSAGE_ID_NOT_FOUND == status)
;
else
{
TRACE5(_T("EvtFormatMessage failed with %u\n"), status);
}
}
This is the code that is supposed to match the event I have with the template event in the dll
hEvents = fpEvtOpenEventMetadataEnum(g_hMetadata, 0);
if (NULL == hEvents)
{
TRACE5(_T("EvtOpenEventMetadataEnum failed with %lu\n"), GetLastError());
goto cleanup;
}
// Enumerate the events and print each event's metadata.
while (run)
{
hEvent = fpEvtNextEventMetadata(hEvents, 0);
if (NULL == hEvent)
{
if (ERROR_NO_MORE_ITEMS != (status = GetLastError()))
{
TRACE5(_T("EvtNextEventMetadata failed with %lu\n"), status);
}
break;
}
msgId = getEventID(g_hMetadata, hEvent, &tempVersion);
if (dwMsgID == msgId && tempVersion == version) {
PEVT_VARIANT pProperty = NULL; // Contains a metadata value
PEVT_VARIANT pTemp = NULL;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
DWORD status2 = ERROR_SUCCESS;
if (!fpEvtGetEventMetadataProperty(hEvent, EventMetadataEventMessageID, 0, dwBufferSize, pProperty, &dwBufferUsed))
{
status2 = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER == status2)
{
dwBufferSize = dwBufferUsed;
pTemp = (PEVT_VARIANT)realloc(pProperty, dwBufferSize);
if (pTemp)
{
pProperty = pTemp;
pTemp = NULL;
fpEvtGetEventMetadataProperty(hEvent, EventMetadataEventMessageID, 0, dwBufferSize, pProperty, &dwBufferUsed);
}
else
{
TRACE5(_T("realloc failed\n"));
status2 = ERROR_OUTOFMEMORY;
goto cleanup;
}
}
if (ERROR_SUCCESS != (status2 = GetLastError()))
{
TRACE5(_T("EvtGetEventMetadataProperty failed with %d\n"), GetLastError());
goto cleanup;
}
}
if (-1 == pProperty->UInt32Val)
{
*pStrNonExpLibMsg = "Message string: \n";
}
else
{
*pStrNonExpLibMsg = GetMessageString(g_hMetadata, NULL, EvtFormatMessageId, pProperty->UInt32Val);
if (pMessage)
{
free(pMessage);
}
}
run = false;
break;
}
fpEvtClose(hEvent);
hEvent = NULL;
}
cleanup:
if (hEvents)
fpEvtClose(hEvents);
if (hEvent)
fpEvtClose(hEvent);
return status;
}
DWORD getEventID(EVT_HANDLE g_hMetadata, EVT_HANDLE hEvent, DWORD *evtVersion)
{
PEVT_VARIANT pProperty = NULL; // Contains a metadata value
PEVT_VARIANT pTemp = NULL;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
DWORD status = ERROR_SUCCESS;
DWORD retValue = NULL;
// Get the specified metadata property. If the pProperty buffer is not big enough, reallocate the buffer.
for (int i = 0; i < 2; i++)
{
if (!fpEvtGetEventMetadataProperty(hEvent, (EVT_EVENT_METADATA_PROPERTY_ID)i, 0, dwBufferSize, pProperty, &dwBufferUsed))
{
status = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER == status)
{
dwBufferSize = dwBufferUsed;
pTemp = (PEVT_VARIANT)realloc(pProperty, dwBufferSize);
if (pTemp)
{
pProperty = pTemp;
pTemp = NULL;
fpEvtGetEventMetadataProperty(hEvent, (EVT_EVENT_METADATA_PROPERTY_ID)i, 0, dwBufferSize, pProperty, &dwBufferUsed);
}
else
{
TRACE5(_T("realloc failed\n"));
status = ERROR_OUTOFMEMORY;
goto cleanup;
}
}
if (ERROR_SUCCESS != (status = GetLastError()))
{
TRACE5(_T("EvtGetEventMetadataProperty failed with %d\n"), GetLastError());
goto cleanup;
}
}
if (i == 0)
{
retValue = pProperty->UInt32Val;
}
else
{
*evtVersion = pProperty->UInt32Val;
}
RtlZeroMemory(pProperty, dwBufferUsed);
}

How do I write to a log file from a Windows Service

I have a windows service. All I want to do right now is see what it is doing and ensure it is working. Unfortunately, I can't write to the file system and OutputDebugString does not work.
#include "stdafx.h"
SERVICE_STATUS g_ServiceStatus = {0};
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE;
void Log(char * text)
{
FILE * f = fopen("TestSocketServiceLog.txt", "a+");
fprintf(f, "%s\n", text);
fclose(f);
}
VOID WINAPI ServiceMain (DWORD argc, LPTSTR *argv);
VOID WINAPI ServiceCtrlHandler (DWORD);
DWORD WINAPI ServiceWorkerThread (LPVOID lpParam);
#define SERVICE_NAME _T("TestSocketService")
int _tmain (int argc, TCHAR *argv[])
{
OutputDebugString(_T("TestSocketService: Main: Entry"));
SERVICE_TABLE_ENTRY ServiceTable[] =
{
{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
{NULL, NULL}
};
if (StartServiceCtrlDispatcher (ServiceTable) == FALSE)
{
OutputDebugString(_T("TestSocketService: Main: StartServiceCtrlDispatcher returned error\n"));
return GetLastError ();
}
OutputDebugString(_T("TestSocketService: Main: Exit"));
return 0;
}
VOID WINAPI ServiceMain (DWORD argc, LPTSTR *argv)
{
DWORD Status = E_FAIL;
OutputDebugString(_T("TestSocketService: ServiceMain: Entry"));
g_StatusHandle = RegisterServiceCtrlHandler (SERVICE_NAME, ServiceCtrlHandler);
if (g_StatusHandle == NULL)
{
OutputDebugString(_T("TestSocketService: ServiceMain: RegisterServiceCtrlHandler returned error"));
goto EXIT;
}
// Tell the service controller we are starting
ZeroMemory (&g_ServiceStatus, sizeof (g_ServiceStatus));
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwServiceSpecificExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE)
{
OutputDebugString(_T("TestSocketService: ServiceMain: SetServiceStatus returned error"));
}
/*
* Perform tasks neccesary to start the service here
*/
OutputDebugString(_T("TestSocketService: ServiceMain: Performing Service Start Operations"));
// Create stop event to wait on later.
g_ServiceStopEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
if (g_ServiceStopEvent == NULL)
{
OutputDebugString(_T("TestSocketService: ServiceMain: CreateEvent(g_ServiceStopEvent) returned error"));
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = GetLastError();
g_ServiceStatus.dwCheckPoint = 1;
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE)
{
OutputDebugString(_T("TestSocketService: ServiceMain: SetServiceStatus returned error"));
}
goto EXIT;
}
// Tell the service controller we are started
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE)
{
OutputDebugString(_T("TestSocketService: ServiceMain: SetServiceStatus returned error"));
}
// Start the thread that will perform the main task of the service
HANDLE hThread = CreateThread (NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
OutputDebugString(_T("TestSocketService: ServiceMain: Waiting for Worker Thread to complete"));
// Wait until our worker thread exits effectively signaling that the service needs to stop
WaitForSingleObject (hThread, INFINITE);
OutputDebugString(_T("TestSocketService: ServiceMain: Worker Thread Stop Event signaled"));
/*
* Perform any cleanup tasks
*/
OutputDebugString(_T("TestSocketService: ServiceMain: Performing Cleanup Operations"));
CloseHandle (g_ServiceStopEvent);
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 3;
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE)
{
OutputDebugString(_T("TestSocketService: ServiceMain: SetServiceStatus returned error"));
}
EXIT:
OutputDebugString(_T("TestSocketService: ServiceMain: Exit"));
return;
}
VOID WINAPI ServiceCtrlHandler (DWORD CtrlCode)
{
OutputDebugString(_T("TestSocketService: ServiceCtrlHandler: Entry"));
switch (CtrlCode)
{
case SERVICE_CONTROL_STOP :
OutputDebugString(_T("TestSocketService: ServiceCtrlHandler: SERVICE_CONTROL_STOP Request"));
if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
break;
/*
* Perform tasks neccesary to stop the service here
*/
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 4;
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE)
{
OutputDebugString(_T("TestSocketService: ServiceCtrlHandler: SetServiceStatus returned error"));
}
// This will signal the worker thread to start shutting down
SetEvent (g_ServiceStopEvent);
break;
default:
break;
}
OutputDebugString(_T("TestSocketService: ServiceCtrlHandler: Exit"));
}
DWORD WINAPI ServiceWorkerThread (LPVOID lpParam)
{
OutputDebugString(_T("TestSocketService: ServiceWorkerThread: Entry"));
// Periodically check if the service has been requested to stop
while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0)
{
/*
* Perform main service function here
*/
// Simulate some work by sleeping
Sleep(3000);
}
OutputDebugString(_T("TestSocketService: ServiceWorkerThread: Exit"));
return ERROR_SUCCESS;
}
I tried using the function Log() located near the top of the program. The file "TestSocketServiceLog.txt" never showed up. And I tried using OutputDebugString(). None of the lines showed up in Debug View. I just want to see what the service is doing! What do I have to do to be able to get some kind of logging?

C++ Reading Registry When using Service fails but the same succeds in Console

I have to read some Registry Value as soon as the program starts. The Code does works correctly and gives the Registry Value I seek, if the code is compiled and run from Command prompt. But If I create the service and attach the exe to the service using following code:
sc create someservice start=auto binpath= "PATH to EXE of Code"
and run the service I don't get the desired value. I have attached the complete code. I have logged the result of each step also.
#include <Windows.h>
#include <iostream>
#include <string>
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;
int WriteToLog(const char *);
std::string GetLPInstalledPath();
std::string GetLPInstalledPath()
{
HKEY hKey;
char buf[255];
DWORD dwType;
DWORD dwBufSize = sizeof(buf);
std::string ss="";
const char* subkey = "Software\\\\Logpoint\\\\InstalledPath";
WriteToLog(" Inside GetLPInstalledPath") ;
if( RegOpenKey(HKEY_CURRENT_USER,subkey,&hKey) == ERROR_SUCCESS)
{
WriteToLog("Opened the Registry Key");
dwType = REG_SZ;
if( RegQueryValueEx(hKey,"path",0, &dwType, (BYTE*)buf, &dwBufSize) == ERROR_SUCCESS)
{
ss = buf;
WriteToLog(ss.c_str());
}
else
{
WriteToLog(" Cound not find the value");
}
RegCloseKey(hKey);
}
else
{
WriteToLog(" Cannot Open the Installed Registry Path");
}
return ss;
}
int WriteToLog(const char* str)
{
//const char *logfile = "D:\\ubuntu_share\\lpa\\lpa_c\\build_win\\src\\lpa\\sample.txt";
FILE* log;
log = fopen("C:\\lpa\\sample.txt", "a+");
if (log == NULL)
return -1;
fprintf(log, "%s\n", str);
fclose(log);
return 0;
}
int Run()
{
WriteToLog("Run");
WriteToLog("entering infinite loop of main thread ");
while(1);
WriteToLog("end of main thread ");
return 0;
}
void ControlHandler(DWORD request)
{
//LOG4CPLUS_INFO(root, "ControlHandler: Entry";
switch(request)
{
case SERVICE_CONTROL_STOP:
//WriteToLog("Monitoring stopped.");
WriteToLog( "ControlHandler: SERVICE_CONTROL_STOP Request");
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
if(SetServiceStatus (hStatus, &ServiceStatus)==FALSE)
{
WriteToLog("ServiceCtrlHandler: SetServiceStatus returned error");
}
return;
case SERVICE_CONTROL_SHUTDOWN:
// WriteToLog("Monitoring shutdown.");
WriteToLog("ControlHandler: SERVICE_CONTROL_SHUTDOWN Request");
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
if(SetServiceStatus (hStatus, &ServiceStatus) == FALSE)
{
WriteToLog("ServiceCtrlHandler: SetServiceStatus returned error");
}
return;
case SERVICE_CONTROL_INTERROGATE:
return;
default:
WriteToLog("ServiceCtrlHandler");
break;
}
// Report current status
SetServiceStatus (hStatus, &ServiceStatus);
WriteToLog("ServiceCtrlHandler: Exit");
return;
}
void ServiceMain(int argc, char** argv)
{
//WriteToLog("at ServiceMain");
WriteToLog("ServiceMain");
int error;
ServiceStatus.dwServiceType = SERVICE_WIN32;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
hStatus = RegisterServiceCtrlHandler(
"MemoryStatus",
(LPHANDLER_FUNCTION)ControlHandler);
if (hStatus == NULL)
{
// Registering Control Handler failed
WriteToLog("ServiceMain: RegisterServiceCtrlHandler returned error");
return;
}
// We report the running status to SCM.
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
if(SetServiceStatus (hStatus, &ServiceStatus)==FALSE)
{
WriteToLog("ServiceMain: SetServiceStatus returned error");
}
WriteToLog("ServiceMain: Performing Service Start Operations");
Run();
WriteToLog("ServiceMain: Performing Cleanup Operations");
ServiceStatus.dwControlsAccepted = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCheckPoint = 3;
if (SetServiceStatus (hStatus, &ServiceStatus) == FALSE)
{
WriteToLog("ServiceMain: SetServiceStatus returned error");
}
WriteToLog("ServiceMain: Exit");
return;
}
int StartLpaService()
{
SERVICE_TABLE_ENTRY ServiceTable[2];
ServiceTable[0].lpServiceName = "MemoryStatus";
ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
ServiceTable[1].lpServiceName = NULL;
ServiceTable[1].lpServiceProc = NULL;
// Start the control dispatcher thread for our service
if(StartServiceCtrlDispatcher(ServiceTable) == FALSE)
{
WriteToLog("StartLpaService: StartServiceCtrlDispatcher returned error");
return GetLastError ();
}
WriteToLog("Main: Exit");
return 0;
}
int main(int argc, char **argv)
{
std::string pa = GetLPInstalledPath();
#ifdef SERVICE_DEBUG
WriteToLog("SERVICE_DEBUG");
Sleep(15000);
#endif
StartLpaService();
return 0;
}
The problem I am facing is that if the service of the program is started, no Registry value is written, but running directly from command prompt is giving the value. How do I solve this Issue?
You are looking in HKCU, the registry hive for the current user. So the most plausible explanation for what you describe is simply that the service is running under a different user. That is the service runs under a user account other than the interactive user.