monitor session change event in c - c

I try to build a service that monitor user sessions activity. currently focusing on logon and lock of user.
i am using http://msdn.microsoft.com/en-us/library/bb540475(v=VS.85).aspx example
my code :
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#pragma comment(lib, "advapi32.lib")
#define SVCNAME TEXT("SvcName")
#define SVC_ERROR 4
SERVICE_STATUS gSvcStatus;
SERVICE_STATUS_HANDLE gSvcStatusHandle;
HANDLE ghSvcStopEvent = NULL;
VOID SvcInstall(void);
DWORD WINAPI SvcCtrlHandler(DWORD , DWORD , LPVOID , LPVOID );
VOID WINAPI SvcMain(DWORD, LPTSTR *);
VOID ReportSvcStatus(DWORD, DWORD, DWORD);
VOID SvcInit(DWORD, LPTSTR *);
VOID SvcReportEvent(LPTSTR);
void __cdecl _tmain(int argc, TCHAR *argv[])
{
if (lstrcmpi(argv[1], TEXT("install")) == 0)
{
SvcInstall();
return;
}
SERVICE_TABLE_ENTRY DispatchTable[] =
{
{ SVCNAME, (LPSERVICE_MAIN_FUNCTION)SvcMain },
{ NULL, NULL }
};
if (!StartServiceCtrlDispatcher(DispatchTable))
{
SvcReportEvent(TEXT("StartServiceCtrlDispatcher"));
}
}
VOID SvcInstall()
{
SC_HANDLE schSCManager;
SC_HANDLE schService;
TCHAR szPath[MAX_PATH];
if (!GetModuleFileName(NULL, szPath, MAX_PATH))
{
printf("Cannot install service (%d)\n", GetLastError());
return;
}
schSCManager = OpenSCManager(
NULL, // local computer
NULL, // ServicesActive database
SC_MANAGER_ALL_ACCESS); // full access rights
if (NULL == schSCManager)
{
printf("OpenSCManager failed (%d)\n", GetLastError());
return;
}
// Create the service
schService = CreateService(
schSCManager, // SCM database
SVCNAME, // name of service
SVCNAME, // service name to display
SERVICE_ALL_ACCESS, // desired access
SERVICE_WIN32_OWN_PROCESS, // service type
SERVICE_AUTO_START, // start type
SERVICE_ERROR_NORMAL, // error control type
szPath, // path to service's binary
NULL, // no load ordering group
NULL, // no tag identifier
NULL, // no dependencies
NULL, // LocalSystem account
NULL); // no password
if (schService == NULL)
{
printf("CreateService failed (%d)\n", GetLastError());
CloseServiceHandle(schSCManager);
return;
}
else printf("Service installed successfully\n");
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
}
VOID WINAPI SvcMain(DWORD dwArgc, LPTSTR *lpszArgv)
{
gSvcStatusHandle = RegisterServiceCtrlHandler(SVCNAME,SvcCtrlHandler,NULL);
OutputDebugString(L"\n***SVCMAIN");
if (!gSvcStatusHandle)
{
SvcReportEvent(TEXT("RegisterServiceCtrlHandler"));
return;
}
gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
gSvcStatus.dwServiceSpecificExitCode = 0;
ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
SvcInit(dwArgc, lpszArgv);
}
VOID SvcInit(DWORD dwArgc, LPTSTR *lpszArgv)
{
FILE *f = fopen("c:\\test\\file.txt", "a");
OutputDebugString(L"\n***SVCINIT");
fprintf(f, "init\n");
fclose(f);
ghSvcStopEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual reset event
FALSE, // not signaled
NULL); // no name
if (ghSvcStopEvent == NULL)
{
ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
return;
}
ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0);
while (WaitForSingleObject(ghSvcStopEvent, 3000) != WAIT_OBJECT_0){
OutputDebugString(L"\n***BEEP");
f = fopen("c:\\test\\file.txt", "a");
fprintf(f, "beep\n");
fclose(f);
Beep(1000, 100);
}
ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
}
VOID ReportSvcStatus(DWORD dwCurrentState,
DWORD dwWin32ExitCode,
DWORD dwWaitHint)
{
static DWORD dwCheckPoint = 1;
DWORD my_error = 0;
// Fill in the SERVICE_STATUS structure.
gSvcStatus.dwCurrentState = dwCurrentState;
gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
gSvcStatus.dwWaitHint = dwWaitHint;
gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_SESSIONCHANGE | SERVICE_ACCEPT_STOP;
if ((dwCurrentState == SERVICE_RUNNING) ||
(dwCurrentState == SERVICE_STOPPED)){
gSvcStatus.dwCheckPoint = 0;
}
else gSvcStatus.dwCheckPoint = dwCheckPoint++;
// Report the status of the service to the SCM.
SetServiceStatus(gSvcStatusHandle, &gSvcStatus);
my_error = GetLastError();
FILE *f = fopen("c:\\test\\file.txt", "a");
fprintf(f, "last error %d \n",my_error);
fprintf(f, "\n***controls accepted %d ***\n", gSvcStatus.dwControlsAccepted);
fclose(f);
}
DWORD WINAPI SvcCtrlHandler(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)
{
DWORD dwErrorCode = NO_ERROR;
FILE *f = fopen("c:\\test\\file.txt", "a");
// Handle the requested control code.
fprintf(f, "dwCtrl is = %d \n", dwControl);
fclose(f);
switch (dwControl)
{
case SERVICE_CONTROL_TIMECHANGE:
f = fopen("c:\\test\\file.txt", "a");
fprintf(f, "time\n");
fclose(f);
OutputDebugString(L"\n****GOT time!!!\n\n");
SetEvent(ghSvcStopEvent);
ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);
break;
case SERVICE_CONTROL_SESSIONCHANGE:
f = fopen("c:\\test\\file.txt", "a");
fprintf(f, "session\n");
fclose(f);
OutputDebugString(L"\n****GOT Session!\n\n");
SetEvent(ghSvcStopEvent);
ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);
break;
case SERVICE_CONTROL_STOP:
OutputDebugString(L"\n****GOT STOP!\n\n");
f = fopen("c:\\test\\file.txt", "a");
fprintf(f, "stop\n");
fclose(f);
ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
SetEvent(ghSvcStopEvent);
ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);
return;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
break;
}
}
VOID SvcReportEvent(LPTSTR szFunction)
{
HANDLE hEventSource;
LPCTSTR lpszStrings[2];
TCHAR Buffer[80];
hEventSource = RegisterEventSource(NULL, SVCNAME);
if (NULL != hEventSource)
{
StringCchPrintf(Buffer, 80, TEXT("%s failed with %d"), szFunction, GetLastError());
lpszStrings[0] = SVCNAME;
lpszStrings[1] = Buffer;
ReportEvent(hEventSource, // event log handle
EVENTLOG_ERROR_TYPE, // event type
0, // event category
SVC_ERROR, // event identifier
NULL, // no security identifier
2, // size of lpszStrings array
0, // no binary data
lpszStrings, // array of strings
NULL); // no binary data
DeregisterEventSource(hEventSource);
}
}
any ideas why i am not getting any "case SERVICE_CONTROL_SESSIONCHANGE" and only stop?
in my log file i see the beep log and controls accepted - 129 (stop + session change)
this is my log file content :
last error 0
***controls accepted 129 ***
init
last error 0
***controls accepted 129 ***
beep
beep
beep
beep
beep

gSvcStatusHandle = RegisterServiceCtrlHandler(SVCNAME,SvcCtrlHandler,NULL);
should be :
gSvcStatusHandle = RegisterServiceCtrlHandlerEx(SVCNAME,SvcCtrlHandler,NULL);

Related

Windows C service not writing to file in PreShutdown event

I am working on a Windows Service written in C code.
In the service initialization code I have registered to a SERVICE_ACCEPT_PRESHUTDOWN event like this:
gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PRESHUTDOWN;
In the service control handler I have writen the logic to write to a file in the SERVICE_CONTROL_PRESHUTDOWN event like this:
DWORD WINAPI SvcCtrlHandler(DWORD dwCtrl, DWORD eventType, void *eventData, void *context)
{
if (dwCtrl == SERVICE_CONTROL_STOP)
{
gSvcStatus.dwWin32ExitCode = 0;
gSvcStatus.dwCurrentState = SERVICE_STOPPED;
}
else if (dwCtrl == SERVICE_CONTROL_PRESHUTDOWN)
{
char sentence[] = "Hello World";
FILE *fptr;
fptr = fopen("C:\\test\\program.txt", "w");
if (fptr == NULL) {
printf("Error!");
}
else
{
fprintf(fptr, "%s", sentence);
fclose(fptr);
}
gSvcStatus.dwWin32ExitCode = 0;
gSvcStatus.dwCurrentState = SERVICE_STOPPED;
}
SetServiceStatus(g_ServiceStatusHandle, &gSvcStatus);
return NO_ERROR;
}
But after reboot, I am not able to see the file program.txt in test folder. Need help in fixing this issue.
What else I have tried:
I also tried writing to event Viewer using the SvcReportEvent function:
//
// Purpose:
// Logs messages to the event log
//
// Parameters:
// szFunction - name of function that failed
//
// Return value:
// None
//
// Remarks:
// The service must have an entry in the Application event log.
//
VOID SvcReportEvent(LPTSTR szFunction)
{
HANDLE hEventSource;
LPCTSTR lpszStrings[2];
TCHAR Buffer[80];
hEventSource = RegisterEventSource(NULL, SVCNAME);
if( NULL != hEventSource )
{
StringCchPrintf(Buffer, 80, TEXT("%s failed with %d"), szFunction, GetLastError());
lpszStrings[0] = SVCNAME;
lpszStrings[1] = Buffer;
ReportEvent(hEventSource, // event log handle
EVENTLOG_ERROR_TYPE, // event type
0, // event category
SVC_ERROR, // event identifier
NULL, // no security identifier
2, // size of lpszStrings array
0, // no binary data
lpszStrings, // array of strings
NULL); // no binary data
DeregisterEventSource(hEventSource);
}
}
Change done to SvcCtrlHandler function:
DWORD WINAPI SvcCtrlHandler(DWORD dwCtrl, DWORD eventType, void *eventData, void *context)
{
if (dwCtrl == SERVICE_CONTROL_STOP)
{
SvcReportEvent((LPTSTR)TEXT("In function SvcCtrlHandler in condition SERVICE_CONTROL_STOP"));
gSvcStatus.dwWin32ExitCode = 0;
gSvcStatus.dwCurrentState = SERVICE_STOPPED;
}
else if (dwCtrl == SERVICE_CONTROL_PRESHUTDOWN)
{
SvcReportEvent((LPTSTR)TEXT("In function SvcCtrlHandler in condition SERVICE_CONTROL_PRESHUTDOWN"));
gSvcStatus.dwWin32ExitCode = 0;
gSvcStatus.dwCurrentState = SERVICE_STOPPED;
}
SetServiceStatus(g_ServiceStatusHandle, &gSvcStatus);
return NO_ERROR;
}
Observation:
When I restart my computer, there is no Eventviewer log written
When I manually stop the service, a log is written into event viewer:
In function SvcCtrlHandler in condition SERVICE_CONTROL_STOP
Note: Link I referred while writing the service: https://learn.microsoft.com/en-us/windows/win32/services/the-complete-service-sample?redirectedfrom=MSDN
Posting the answer that solved my problem
#include <windows.h>
#include <WinBase.h>
#include <tchar.h>
#include <strsafe.h>
#define SVC_ERROR ((DWORD)0xC0020001L)
SERVICE_STATUS gSvcStatus = { 0 };
SERVICE_STATUS_HANDLE g_ServiceStatusHandle = NULL;
HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE;
VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv);
DWORD WINAPI SvcCtrlHandler(DWORD dwCtrl, DWORD eventType, void *eventData, void *context);
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam);
#define SVCNAME _T("SampleService")
//
// Purpose:
// Logs messages to the event log
//
// Parameters:
// szFunction - name of function that failed
//
// Return value:
// None
//
// Remarks:
// The service must have an entry in the Application event log.
//
VOID SvcReportEvent(LPTSTR szFunction)
{
HANDLE hEventSource;
LPCTSTR lpszStrings[2];
TCHAR Buffer[80];
hEventSource = RegisterEventSource(NULL, SVCNAME);
if (NULL != hEventSource)
{
StringCchPrintf(Buffer, 80, TEXT("%s failed with %d"), szFunction, GetLastError());
lpszStrings[0] = SVCNAME;
lpszStrings[1] = Buffer;
ReportEvent(hEventSource, // event log handle
EVENTLOG_INFORMATION_TYPE, // event type
0, // event category
SVC_ERROR, // event identifier
NULL, // no security identifier
2, // size of lpszStrings array
0, // no binary data
lpszStrings, // array of strings
NULL); // no binary data
DeregisterEventSource(hEventSource);
}
}
int _tmain(int argc, TCHAR *argv[])
{
SvcReportEvent(_T("My Sample Service: Main: Entry"));
SERVICE_TABLE_ENTRY ServiceTable[] =
{
{SVCNAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain},
{NULL, NULL}
};
if (StartServiceCtrlDispatcher(ServiceTable) == FALSE)
{
SvcReportEvent(_T("My Sample Service: Main: StartServiceCtrlDispatcher returned error"));
return GetLastError();
}
SvcReportEvent(_T("My Sample Service: Main: Exit"));
return 0;
}
VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv)
{
DWORD Status = E_FAIL;
SvcReportEvent(_T("My Sample Service: ServiceMain: Entry"));
g_ServiceStatusHandle = RegisterServiceCtrlHandlerEx(
SVCNAME,
SvcCtrlHandler,
NULL);
if (g_ServiceStatusHandle == NULL)
{
SvcReportEvent(_T("My Sample Service: ServiceMain: RegisterServiceCtrlHandler returned error"));
goto EXIT;
}
// Tell the service controller we are starting
ZeroMemory(&gSvcStatus, sizeof(gSvcStatus));
gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
gSvcStatus.dwControlsAccepted = 0;
gSvcStatus.dwCurrentState = SERVICE_START_PENDING;
gSvcStatus.dwWin32ExitCode = 0;
gSvcStatus.dwServiceSpecificExitCode = 0;
gSvcStatus.dwCheckPoint = 0;
if (SetServiceStatus(g_ServiceStatusHandle, &gSvcStatus) == FALSE)
{
SvcReportEvent(_T("My Sample Service: ServiceMain: SetServiceStatus returned error"));
}
/*
* Perform tasks neccesary to start the service here
*/
SvcReportEvent(_T("My Sample Service: ServiceMain: Performing Service Start Operations"));
// Create stop event to wait on later.
g_ServiceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (g_ServiceStopEvent == NULL)
{
SvcReportEvent(_T("My Sample Service: ServiceMain: CreateEvent(g_ServiceStopEvent) returned error"));
gSvcStatus.dwControlsAccepted = 0;
gSvcStatus.dwCurrentState = SERVICE_STOPPED;
gSvcStatus.dwWin32ExitCode = GetLastError();
gSvcStatus.dwCheckPoint = 1;
if (SetServiceStatus(g_ServiceStatusHandle, &gSvcStatus) == FALSE)
{
SvcReportEvent(_T("My Sample Service: ServiceMain: SetServiceStatus returned error"));
}
goto EXIT;
}
// Tell the service controller we are started
gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PRESHUTDOWN;
gSvcStatus.dwCurrentState = SERVICE_RUNNING;
gSvcStatus.dwWin32ExitCode = 0;
gSvcStatus.dwCheckPoint = 0;
if (SetServiceStatus(g_ServiceStatusHandle, &gSvcStatus) == FALSE)
{
SvcReportEvent(_T("My Sample Service: 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);
SvcReportEvent(_T("My Sample Service: ServiceMain: Waiting for Worker Thread to complete"));
// Wait until our worker thread exits effectively signaling that the service needs to stop
WaitForSingleObject(hThread, INFINITE);
SvcReportEvent(_T("My Sample Service: ServiceMain: Worker Thread Stop Event signaled"));
/*
* Perform any cleanup tasks
*/
SvcReportEvent(_T("My Sample Service: ServiceMain: Performing Cleanup Operations"));
CloseHandle(g_ServiceStopEvent);
gSvcStatus.dwControlsAccepted = 0;
gSvcStatus.dwCurrentState = SERVICE_STOPPED;
gSvcStatus.dwWin32ExitCode = 0;
gSvcStatus.dwCheckPoint = 3;
if (SetServiceStatus(g_ServiceStatusHandle, &gSvcStatus) == FALSE)
{
SvcReportEvent(_T("My Sample Service: ServiceMain: SetServiceStatus returned error"));
}
EXIT:
SvcReportEvent(_T("My Sample Service: ServiceMain: Exit"));
return;
}
DWORD WINAPI SvcCtrlHandler(DWORD dwCtrl, DWORD eventType, void *eventData, void *context)
{
if (dwCtrl == SERVICE_CONTROL_STOP)
{
SvcReportEvent((LPTSTR)TEXT("In function SvcCtrlHandler in condition SERVICE_CONTROL_STOP"));
gSvcStatus.dwWin32ExitCode = 0;
gSvcStatus.dwCurrentState = SERVICE_STOPPED;
}
else if (dwCtrl == SERVICE_CONTROL_PRESHUTDOWN)
{
SvcReportEvent((LPTSTR)TEXT("In function SvcCtrlHandler in condition SERVICE_CONTROL_PRESHUTDOWN"));
gSvcStatus.dwWin32ExitCode = 0;
gSvcStatus.dwCurrentState = SERVICE_STOPPED;
}
SetServiceStatus(g_ServiceStatusHandle, &gSvcStatus);
return NO_ERROR;
}
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
{
SvcReportEvent(_T("My Sample Service: 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
for (size_t i = 0; i < 1000000; i++)
{
char sentence[] = "Hello World";
FILE *fptr;
fptr = fopen("C:\\test\\program.txt", "a");
if (fptr == NULL)
{
printf("Error!");
}
else
{
fprintf(fptr, "%s", sentence);
fclose(fptr);
}
Sleep(3000);
}
}
SvcReportEvent(_T("My Sample Service: ServiceWorkerThread: Exit"));
return ERROR_SUCCESS;
}

In C, a cURL call anywhere, even when not executed, crashes the service

I am building a small windows service which uses cURL for a small web call.
I can link cURL without issue, but if any curl_* functions are in the code - even if none are ever called - the code crashes:
Program received signal SIGSEGV, Segmentation fault.
0x00007ff8bb75f9f8 in StartServiceCtrlDispatcherW () from C:\WINDOWS\System32\sechost.dll
Here is the offending function - commenting out just the lines calling curl_* functions stops the issue:
void phone_home(identity id, char* agent_filename, char* action)
{
CURL *curl;
CURLcode res;
char service_url[MAX_PATH_LEN], username[MAX_PATH_LEN];
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
get_username(username, MAX_PATH_LEN);
sprintf(service_url, "%s/%s?identity=%lu&user=%s&agent=%s", LISTENER_HOST, action, id, username, agent_filename);
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, service_url);
#ifdef SKIP_PEER_VERIFICATION
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
#endif
#ifdef SKIP_HOSTNAME_VERIFICATION
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
#endif
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
/* always cleanup */
curl_easy_cleanup(curl);
}
curl_global_cleanup();
}
And here is the SvcInit function that never calls that function!
VOID SvcInit( DWORD dwArgc, LPTSTR *lpszArgv)
{
int id;
identity last_id = 0;
ghSvcStopEvent = CreateEvent(
NULL, /* default security attributes */
TRUE, /* manual reset event */
FALSE, /* not signaled */
NULL); /* no name */
if ( ghSvcStopEvent == NULL)
{
ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );
return;
}
ReportSvcStatus( SERVICE_RUNNING, NO_ERROR, 0 );
while(1)
{
WaitForSingleObject(ghSvcStopEvent, INFINITE);
ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );
if ((id = scan_for_devices())) {
if (id != last_id) {
last_id = id;
printf("Found marked device 0x%lX!\n", id);
//phone_home(id, "", ACTION_USBINSERT);
}
} else {
last_id = 0;
}
Sleep(5000);
}
}
And the rest of the service definition code:
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include "include/identities.h"
#include "include/identity_agent.h"
#define SVCNAME TEXT("Test")
#define SVCSHOW TEXT("Test Agent")
#define SVCDESC TEXT("Test")
SERVICE_STATUS gSvcStatus;
SERVICE_STATUS_HANDLE gSvcStatusHandle;
HANDLE ghSvcStopEvent = NULL;
VOID WINAPI SvcCtrlHandler( DWORD );
VOID WINAPI SvcMain( DWORD, LPTSTR * );
VOID ReportSvcStatus( DWORD, DWORD, DWORD );
VOID SvcInit( DWORD, LPTSTR * );
VOID SvcReportEvent( LPTSTR );
int __cdecl _tmain(int argc, TCHAR *argv[])
{
SERVICE_TABLE_ENTRY DispatchTable[] =
{
{ SVCNAME, (LPSERVICE_MAIN_FUNCTION) SvcMain },
{ NULL, NULL }
};
if (!StartServiceCtrlDispatcher( DispatchTable ))
{
SvcReportEvent(TEXT("StartServiceCtrlDispatcher"));
}
return 0;
}
VOID WINAPI SvcMain( DWORD dwArgc, LPTSTR *lpszArgv )
{
/* Register the handler function for the service */
gSvcStatusHandle = RegisterServiceCtrlHandler(
SVCNAME,
SvcCtrlHandler);
if( !gSvcStatusHandle )
{
SvcReportEvent(TEXT("RegisterServiceCtrlHandler"));
return;
}
gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
gSvcStatus.dwServiceSpecificExitCode = 0;
ReportSvcStatus( SERVICE_START_PENDING, NO_ERROR, 3000 );
SvcInit( dwArgc, lpszArgv );
}
VOID SvcInit( DWORD dwArgc, LPTSTR *lpszArgv)
{
int id;
identity last_id = 0;
ghSvcStopEvent = CreateEvent(
NULL, /* default security attributes */
TRUE, /* manual reset event */
FALSE, /* not signaled */
NULL); /* no name */
if ( ghSvcStopEvent == NULL)
{
ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );
return;
}
ReportSvcStatus( SERVICE_RUNNING, NO_ERROR, 0 );
while(1)
{
WaitForSingleObject(ghSvcStopEvent, INFINITE);
ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );
if ((id = scan_for_devices())) {
if (id != last_id) {
last_id = id;
printf("Found marked device 0x%lX!\n", id);
//phone_home(id, "", ACTION_USBINSERT);
}
} else {
last_id = 0;
}
Sleep(5000);
}
}
VOID ReportSvcStatus( DWORD dwCurrentState,
DWORD dwWin32ExitCode,
DWORD dwWaitHint)
{
static DWORD dwCheckPoint = 1;
/* Fill in the SERVICE_STATUS structure. */
gSvcStatus.dwCurrentState = dwCurrentState;
gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
gSvcStatus.dwWaitHint = dwWaitHint;
if (dwCurrentState == SERVICE_START_PENDING)
gSvcStatus.dwControlsAccepted = 0;
else gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
if ( (dwCurrentState == SERVICE_RUNNING) ||
(dwCurrentState == SERVICE_STOPPED) )
gSvcStatus.dwCheckPoint = 0;
else gSvcStatus.dwCheckPoint = dwCheckPoint++;
/* Report the status of the service to the SCM. */
SetServiceStatus( gSvcStatusHandle, &gSvcStatus );
}
VOID WINAPI SvcCtrlHandler( DWORD dwCtrl )
{
/* Handle the requested control code. */
switch(dwCtrl)
{
case SERVICE_CONTROL_STOP:
ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
/* Signal the service to stop. */
SetEvent(ghSvcStopEvent);
ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);
return;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
break;
}
}
VOID SvcReportEvent(LPTSTR szFunction)
{
HANDLE hEventSource;
LPCTSTR lpszStrings[2];
TCHAR Buffer[80];
hEventSource = RegisterEventSource(NULL, SVCNAME);
if( NULL != hEventSource )
{
StringCchPrintf(Buffer, 80, TEXT("%s failed with %d"), szFunction, GetLastError());
lpszStrings[0] = SVCNAME;
lpszStrings[1] = Buffer;
ReportEvent(hEventSource,
EVENTLOG_ERROR_TYPE, /* event type */
0, /* event category */
/*SVC_ERROR*/0, /* event identifier */
NULL, /* no security identifier */
2, /* size of lpszStrings array */
0, /* no binary data */
lpszStrings, /* array of strings */
NULL); /* no binary data */
DeregisterEventSource(hEventSource);
}
}
I am compiling with gcc -o bin/identity_service identity_agent.c identities.c -lcurl
As it turns out, I had not linked cURL statically, so it was looking for the cURL DLLs - which were in the mingw bin directory.... which was in my USER's path....... which services running under system cannot see
I linked curl statically with -DCURL_STATICLIB and all is right with the world

Serial port reading in c, using WinApi functions; WaitCommEvent fails

I tried to write a small event-based application in C for serial port reading (sources below). My program is to use the WinApi functions. The comport.c has the functions written to handle COM-port (open, read, write), the utils.c has some helper functions.
My program produces always the following output:
COM1 is selected to be listened.
GetCommMask result: 0x00000029 (EV_RXCHAR: 0x0001, EV_CTS: 0x0008, EV_RLSD: 0x0020)
Press any key to proceed...
I/O is pending (WaitCommEvent)...
I/O is pending (WaitCommEvent)...
I/O is pending (WaitCommEvent)...
I/O is pending (WaitCommEvent)...
I/O is pending (WaitCommEvent)...
It seems, that the function WaitCommEvent fails, the GetLastError() gives back error 87 (I/O pending).
Please help me to find out what the problem is, which parameter is invalid? See below the code.
The main.c:
#include "stdafx.h"
#include "comport.h"
#include "utils.h"
#include <conio.h>
#define READ_BUFF_MAX_LENGTH 1024
int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwEvtMask;
HANDLE hComPort;
OVERLAPPED oEventHandler;
int portNum;
DWORD readTotal;
BOOL bOverlappedPending = FALSE;
char readBuff[READ_BUFF_MAX_LENGTH];
if(2 > argc)
{
printf("Use the program: ZliFuerZlvbusInterface.exe XXX (where XXX is the number of com port), \r\ne.G. for COM1 -> ZliFuerZlvbusInterface.exe 1\r\n");
return 1;
}
else
{
portNum = atoi(argv[1]);
if(0 == IsValidComNumber(portNum))
{
printf("ERROR: COM port number %d is invalid (parsed from '%s').\r\n", portNum, argv[1]);
return 2;
}
else
{
printf("COM%d is selected to be listened.\r\n", portNum);
}
}
if(0 == CreateSerialConnection(&hComPort, &oEventHandler, portNum, 1200, 8, EVEN, STOP1))
{
return 3;
}
if(FALSE == GetCommMask(hComPort, &dwEvtMask))
{
printf("GetCommMask failed with error:\r\n");
PrintLastErrorText();
return 4;
}
else
{
printf("GetCommMask result: 0x%08X (EV_RXCHAR: 0x0001, EV_CTS: 0x0008, EV_RLSD: 0x0020)\r\n", dwEvtMask);
}
printf("Press any key to proceed...\r\n");
getch();
while(1)
{
if(0 != kbhit())
{
if(27 == getch()) // ESC pressed
{
printf("Key ESC pressed, exiting...\r\n");
break;
}
}
bOverlappedPending = FALSE;
readTotal = 0;
if(TRUE == WaitCommEvent(hComPort, &dwEvtMask, &oEventHandler))
{
if(dwEvtMask & EV_CTS) // Clear-to-send signal present
{
PrintCurrentDateTime();
printf("COM%d: Clear-to-send signal set\r\n", portNum);
}
if(dwEvtMask & EV_RLSD) // Data-carrier-detect signal present
{
PrintCurrentDateTime();
printf("COM%d: Data-carrier-detect signal set\r\n", portNum);
}
if(dwEvtMask & EV_RXCHAR) // Data received
{
ReadSerial(&hComPort, &oEventHandler, portNum, readBuff, READ_BUFF_MAX_LENGTH);
}
}
else
{
if(ERROR_IO_PENDING == GetLastError())
{
printf("I/O is pending (WaitCommEvent)...\r\n");
bOverlappedPending = TRUE;
}
else
{
printf("WaitCommEvent failed with error:\r\n");
PrintLastErrorText();
}
}
if(TRUE == bOverlappedPending)
{
if(FALSE == GetOverlappedResult(hComPort, &oEventHandler, &readTotal, TRUE))
{
printf("GetOverlappedResult failed with error:\r\n");
PrintLastErrorText();
}
}
}
CloseSerialConnection(&hComPort);
return 0;
}
The comport.c:
#include <stdio.h>
#include "comport.h"
#include "utils.h"
int IsValidComNumber(int com)
{
if ((com < 1) ||
(com > 256))
{
return 0;
}
return 1;
}
int IsValidBaud(int baud)
{
switch(baud)
{
case CBR_110:
case CBR_300:
case CBR_600:
case CBR_1200:
case CBR_2400:
case CBR_4800:
case CBR_9600:
case CBR_14400:
case CBR_19200:
case CBR_38400:
case CBR_56000:
case CBR_57600:
case CBR_115200:
case CBR_128000:
case CBR_256000:
{
return 1;
break;
}
default:
{
break;
}
}
return 0;
}
int IsValidBits(int bits)
{
if ((bits < 5) ||
(bits > 8))
{
return 0;
}
else
{
return 1;
}
}
int CreateSerialConnection(HANDLE* handle, OVERLAPPED* overlapped, int portNumber, int baud, int bits, enum ParType parity, enum StopType stopbits)
{
DCB dcb;
COMMTIMEOUTS timeouts;
TCHAR portVirtualFile[32];
// For serial port name this format must be used (as virtual file): "\\\\.\\COMx"
memset(portVirtualFile, 0, 32);
#ifdef _UNICODE
swprintf(portVirtualFile, 32, L"\\\\.\\COM%d", portNumber);
#else
sprintf_s(portVirtualFile, 32, "\\\\.\\COM%d", portNumber);
#endif
if(0 == IsValidBaud(baud))
{
printf("ERROR: Specified baud rate %d is invalid for serial connection to COM%d.\r\n", baud, portNumber);
return 0;
}
if(0 == IsValidBits(bits))
{
printf("ERROR: Specified number of data bits %d is invalid for serial connection to COM%d.\r\n", bits, portNumber);
return 0;
}
*handle = CreateFile(portVirtualFile, // Specify port device
GENERIC_READ | GENERIC_WRITE, // Specify mode that open device.
0, // the devide isn't shared.
NULL, // the object gets a default security.
OPEN_EXISTING, // Specify which action to take on file.
FILE_FLAG_OVERLAPPED, // Use overlapped I/O.
NULL); // default.
if(*handle == INVALID_HANDLE_VALUE)
{
printf("ERROR: Opening serial port COM%d failed\r\n", portNumber);
return 0;
}
if(FALSE == GetCommState(*handle, &dcb))
{
printf("ERROR: Getting current state of COM%d\r\n", portNumber);
PrintLastErrorText();
return 0;
}
memset(&dcb, 0, sizeof(dcb)); //zero initialize the structure
dcb.DCBlength = sizeof(dcb); //fill in length
dcb.BaudRate = baud; // baud rate
dcb.ByteSize = bits; // data size, xmit and rcv
dcb.Parity = parity; // parity bit
dcb.StopBits = stopbits; // stop bits
if(FALSE == SetCommState(*handle, &dcb))
{
printf("ERROR: Setting new state of COM%d failed.\r\n", portNumber);
PrintLastErrorText();
return 0;
}
if(FALSE == SetCommMask(*handle, EV_RXCHAR | EV_CTS | EV_RLSD))
{
printf("ERROR: Setting new COM MASK (events) for COM%d failed.\r\n", portNumber);
PrintLastErrorText();
return 0;
}
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
if(FALSE == SetCommTimeouts(*handle, &timeouts))
{
printf("ERROR: Setting timeout parameters for COM%d failed.\r\n", portNumber);
PrintLastErrorText();
return 0;
}
(*overlapped).hEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
FALSE, // not signaled
NULL // no name
);
if(NULL == overlapped->hEvent)
{
printf("ERROR: CreateEvent for COM%d failed.\r\n", portNumber);
PrintLastErrorText();
return 0;
}
// Initialize the rest of the OVERLAPPED structure to zero.
overlapped->Internal = 0;
overlapped->InternalHigh = 0;
overlapped->Offset = 0;
overlapped->OffsetHigh = 0;
return 1;
}
int CloseSerialConnection(HANDLE* handle)
{
if(FALSE == CloseHandle(*handle))
{
printf("ERROR: Cannot close handle 0x8.8%X\r\n", *handle);
PrintLastErrorText();
return 0;
}
*handle = NULL;
return 1;
}
int ReadSerial(HANDLE* handle, LPOVERLAPPED ov, int num, char* buffer, int max_len)
{
DWORD readTotal = 0;
if(FALSE == ClearCommError(*handle, NULL, NULL))
{
printf("ClearCommError failed with error:\r\n");
PrintLastErrorText();
return 0;
}
else
{
memset(buffer, 0, max_len);
if(FALSE == ReadFile(*handle, buffer, max_len, &readTotal, ov))
{
printf("ERROR: Reading from port COM%d failed\r\n", num);
if(ERROR_IO_PENDING == GetLastError())
{
printf("I/O is pending (ReadFile)...\r\n");
if(FALSE == GetOverlappedResult(*handle, ov, &readTotal, TRUE))
{
printf("GetOverlappedResult failed with error:\r\n");
PrintLastErrorText();
return 0;
}
}
else
{
PrintLastErrorText();
return 0;
}
}
else
{
PrintCurrentDateTime();
printf("Received %d characters on port COM%d: ", readTotal, num);
PrintBufferContent(buffer, readTotal);
}
}
return 1;
}
The utils.c:
#include <Windows.h>
#include <stdio.h>
#include "utils.h"
void PrintLastErrorText(void)
{
DWORD retSize;
LPTSTR pTemp = NULL;
retSize = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, GetLastError(), LANG_NEUTRAL, (LPTSTR)&pTemp, 0, NULL);
if ((retSize > 0) &&
(pTemp != NULL))
{
printf("Last error: %s (0x%08X)\r\n", pTemp, GetLastError());
LocalFree((HLOCAL)pTemp);
}
}
void PrintCurrentDateTime(void)
{
SYSTEMTIME systime;
GetLocalTime(&systime);
printf("%04d.%02d.%02d %02d:%02d:%02d:%03d ", systime.wYear, systime.wMonth, systime.wDay, systime.wHour, systime.wMinute, systime.wSecond, systime.wMilliseconds);
}
void PrintBufferContent(char* buff, int len)
{
int i;
for(i = 0; i<len; i++)
{
printf("%02X ", buff[i]);
}
}
You're using the same OVERLAPPED structure for WaitCommEvent and ReadFile. Try using separate/independent OVERLAPPED for each.
UPDATE: Ignore that previous answer.
If your call to WaitCommEvent returns ERROR_IO_PENDING, you're not waiting for it to complete. Rather than loop around and call WaitCommEvent again, you need to wait for the operation to complete (typically via GetOverlappedResult).
You cannot have multiple pending asynchronous requests share a single OVERLAPPED structure. By looping and calling WaitCommEvent again after ERROR_IO_PENDING, that's exactly what's happening.

"cannot open port!" in a DLL project

I made a C Console Application in Visual Studio in order to access one of the COM ports with the following code and all went well.
#include <windows.h>
#include <stdio.h>
#include <conio.h>
/*DWORD dwBytesWrite = 25;
WriteFile(hSerial, "LOOOOOL", n, &dwBytesWrite, NULL);*/
/*
int main(void)
{
int n = 25;
char szBuff[25 + 1] = { 0 };
HANDLE hSerial;
DCB dcbSerialParams = { 0 };
COMMTIMEOUTS timeouts = { 0 };
DWORD dwBytesRead = 25;
dcbSerialParams.DCBlength = sizeof(DCB);
hSerial = CreateFile("COM6",
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if (hSerial == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
{
puts("cannot open port!");
return;
}
puts("invalid handle value!");
return;
}
if (!GetCommState(hSerial, &dcbSerialParams))
{
puts("error getting state");
return;
}
dcbSerialParams.BaudRate = CBR_9600;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
if (!SetCommState(hSerial, &dcbSerialParams))
{
puts("error setting port state");
return;
}
timeouts.ReadIntervalTimeout = 30;
timeouts.ReadTotalTimeoutMultiplier = 100;
timeouts.ReadTotalTimeoutConstant = 100;
if (!SetCommTimeouts(hSerial, &timeouts))
{
puts("timeouts setting fail!");
}
while (1){
if (!ReadFile(hSerial, szBuff, n, &dwBytesRead, NULL)){
puts("serial read error fail!");
return;
}
else
{
printf("%s\n", szBuff);
}
}
getchar();
return 0;
}
Now I needed to make a DLL project and it gave me the following error: "cannot open port!"
Any idea why?
Thanks

How to CopyMemory to copy struct using FileMapping?

I have following code, after CopyMemory my pBuf is empty, it contains no data from newCommand, or when I want to add something in that struct it doesnt work... What am I doing wrong?
struct StCommand
{
TCHAR sourcePath[MAX_PATH];
TCHAR sourceFile[MAX_PATH];
TCHAR fileName[MAX_PATH];
bool endThread;
};
handlesInstance.mapFileHandle = CreateFileMapping(
INVALID_HANDLE_VALUE, // use paging file
NULL, // default security
PAGE_READWRITE, // read/write access
0, // maximum object size (high-order DWORD)
sizeof(StCommand), // maximum object size (low-order DWORD)
handlesInstance.valueBuffer); // name of mapping object
if (handlesInstance.mapFileHandle == NULL)
{
_tprintf(TEXT("Could not create file mapping object (%d).\n"),
GetLastError());
return 0;
}
handlesInstance.pBuf = (StCommand*) MapViewOfFile(
handlesInstance.mapFileHandle, // handle to map object
FILE_MAP_ALL_ACCESS, // read/write permission
0,
0,
sizeof(StCommand));
if (handlesInstance.pBuf == NULL)
{
_tprintf(TEXT("Could not map view of file (%d).\n"),
GetLastError());
return 0;
}
StCommand newCommand = { NULL, NULL, NULL, false };
CopyMemory(handlesInstance.pBuf, &newCommand, sizeof(StCommand));
CopyFiles(*handlesInstance.pBuf);
Here is CopyFiles function, where I send (*handlesInstance.pBuf) and I want to set values of pBuf here, to create path, to copy file later
void CopyFiles(StCommand stCommand)
{
while (!stCommand.endThread)
{
DWORD dwWaitEventResult;
dwWaitEventResult = WaitForSingleObject(handlesInstance.dataInEvent, INFINITE);
switch (dwWaitEventResult)
{
// Event object was signaled
case WAIT_OBJECT_0:
{
//Command processing
if (!stCommand.endThread)
{
GetSzSetting(pathValueName, REPOSITORY_PATH);
TCHAR newFile[MAX_PATH];
_tcscpy_s(newFile, handlesInstance.valueBuffer);
_tcscat_s(newFile, _T("/"));
TCHAR buffer[MAX_PATH];
swprintf_s(buffer, _T("%d"), GetDwordSetting(indexValueName, 0));
_tcscat_s(newFile, buffer);
_tcscat_s(newFile, _T("."));
_tcscat_s(newFile, stCommand.fileName);
TCHAR oldFile[MAX_PATH];
_tcscpy_s(oldFile, stCommand.sourcePath);
_tcscat_s(oldFile, _T("/"));
_tcscat_s(oldFile, stCommand.fileName);
if (CopyFile(oldFile, newFile, FALSE))
{
_tprintf(_T("File %s copied successfully into repository.\n"), stCommand.fileName);
SetDwordSetting(indexValueName, GetDwordSetting(indexValueName, 0) + 1);
}
else
{
_tprintf(_T("Could not copy file %s.\n"), stCommand.fileName);
_tprintf(_T("Failed with error code: %d\n"), GetLastError());
}
}
ResetEvent(handlesInstance.dataInEvent);
if (!SetEvent(handlesInstance.dataOutEvent))
{
printf("SetEvent OutEvent failed (%d)\n", GetLastError());
}
break;
}
// An error occurred
default:
printf("Wait error (%d)\n", GetLastError());
break;
}
}
}

Resources