I need to determine the process ID of a Windows service (I'm using C). Seeing as I have access to the SC_HANDLE of the service, QueryServiceStatusEx
is exactly the function I need. However, when accessing the dwProcessId field in the SERVICE_STATUS_PROCESS
structure returned by QueryServiceStatusEx
, it contains 0.
Here is my code:
unsigned int get_svc_pid (SC_HANDLE svc) {
unsigned int pid = 0;
BYTE *svc_info = NULL;
DWORD buf_size = 0;
DWORD bytes_needed = 0;
//determine svc_info size
QueryServiceStatusEx(svc, SC_STATUS_PROCESS_INFO, svc_info, buf_size, &bytes_needed);
svc_info = malloc(bytes_needed);
buf_size = bytes_needed;
//get pid
if(QueryServiceStatusEx(svc, SC_STATUS_PROCESS_INFO, svc_info, buf_size, &bytes_needed) != 0){
pid = (*(SERVICE_STATUS_PROCESS *)svc_info).dwProcessId;
}else{
fprintf(msglog, "ERR: QueryServiceStatusEx failed\nGLE: %u\n", (unsigned int) GetLastError());
}
free(svc_info);
return pid;
}
Also: I've used EnumServiceStatusEx
to enumerate all running services and output their names and PIDs contained in the ENUM_SERVICE_STATUS_PROCESS
structures. The majority of the PIDs were 0. Only a few PIDs in the structures matched those listed in ProcessHacker/TaskManager.
I'm at a loss as to why the dwProcessId fields contain 0, when clearly that can't be the valid PID. Thank you in advance.
Per the QueryServiceStatusEx()
documentation:
The process identifier returned in the
SERVICE_STATUS_PROCESS
structure is valid provided that the state of the service is one ofSERVICE_RUNNING
,SERVICE_PAUSE_PENDING
,SERVICE_PAUSED
, orSERVICE_CONTINUE_PENDING
. If the service is in aSERVICE_START_PENDING
orSERVICE_STOP_PENDING
state, however, the process identifier may not be valid, and if the service is in theSERVICE_STOPPED
state, it is never valid.
Just because you can obtain an SC_SERVICE
handle to a service does not guarantee that the service is actually running. QueryServiceStatus/Ex()
tells you if the service is running or not in the dwCurrentState
field.
You are also not doing any error handling on the first QueryServiceStatusEx()
call.
Try something more like this:
unsigned int get_svc_pid (SC_HANDLE svc)
{
DWORD pid = 0;
BYTE *buf = NULL;
DWORD buf_size = 0;
SERVICE_STATUS_PROCESS *svc_info = NULL;
//determine svc_info size
QueryServiceStatusEx(svc, SC_STATUS_PROCESS_INFO, NULL, 0, &buf_size);
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
fprintf(msglog, "ERR: QueryServiceStatusEx failed\nGLE: %u\n", GetLastError());
return 0;
}
buf = malloc(buf_size);
if (!buf)
{
fprintf(msglog, "ERR: malloc failed\nsize requested: %u\n", buf_size);
return 0;
}
//get pid
if (!QueryServiceStatusEx(svc, SC_STATUS_PROCESS_INFO, buf, buf_size, &buf_size))
{
fprintf(msglog, "ERR: QueryServiceStatusEx failed\nGLE: %u\n", GetLastError());
}
else
{
svc_info = (SERVICE_STATUS_PROCESS*) buf;
switch (svc_info->dwCurrentState)
{
case SERVICE_RUNNING:
case SERVICE_PAUSE_PENDING:
case SERVICE_PAUSED:
case SERVICE_CONTINUE_PENDING:
pid = svc_info->dwProcessId;
break;
}
}
free(buf);
return pid;
}