I was running the sample provided by MS.
Starting a Service
I use Windows 10 21H2.
I did it in the order below
First, I disable 'control panel' > 'date and time' > 'Synchronization with internet time' and click 'OK'
disable Synchronization with internet time
Second, I execute My code (My full code is below)
Then, error 1058
(The service cannot be started, either because it is disabled or because it has no enabled devices associated with it.. )
result error 1058
If I enable 'Synchronization with internet time' again, the code works fine...
I don't know why this 1058 error occurs.
I've been searching for days, but I can't figure out the cause.
However, it is thought that the startservice api does not operate when the service is stopped.
I wonder if this is correct?
Thank you.
Add 21:30 minutes.
I found that startservice throws 1058 error if start type is disabled in services.msc.
I would like to know additionally whether the user program cannot automatically or manually change the disabled service.
My full code is below.
// servicetest.cpp : 이 파일에는 'main' 함수가 포함됩니다. 거기서 프로그램 실행이 시작되고 종료됩니다.
//
#include <iostream>
#include <Windows.h>
VOID __stdcall DoStartSvc(LPCWSTR szSvcName);
int main()
{
std::cout << "Hello World!\n";
const WCHAR *name = L"w32Time";
DoStartSvc(name);
}
VOID __stdcall DoStartSvc(LPCWSTR szSvcName)
{
SERVICE_STATUS_PROCESS ssStatus;
DWORD dwOldCheckPoint;
DWORD dwStartTickCount;
DWORD dwWaitTime;
DWORD dwBytesNeeded;
// Get a handle to the SCM database.
SC_HANDLE 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;
}
// Get a handle to the service.
SC_HANDLE schService = OpenService(
schSCManager, // SCM database
szSvcName, // name of service
SERVICE_ALL_ACCESS); // full access
if (schService == NULL)
{
printf("OpenService failed (%d)\n", GetLastError());
CloseServiceHandle(schSCManager);
return;
}
// Check the status in case the service is not stopped.
if (!QueryServiceStatusEx(
schService, // handle to service
SC_STATUS_PROCESS_INFO, // information level
(LPBYTE)&ssStatus, // address of structure
sizeof(SERVICE_STATUS_PROCESS), // size of structure
&dwBytesNeeded)) // size needed if buffer is too small
{
printf("QueryServiceStatusEx failed (%d)\n", GetLastError());
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return;
}
// Check if the service is already running. It would be possible
// to stop the service here, but for simplicity this example just returns.
if (ssStatus.dwCurrentState != SERVICE_STOPPED && ssStatus.dwCurrentState != SERVICE_STOP_PENDING)
{
printf("Cannot start the service because it is already running\n");
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return;
}
// Save the tick count and initial checkpoint.
dwStartTickCount = GetTickCount();
dwOldCheckPoint = ssStatus.dwCheckPoint;
// Wait for the service to stop before attempting to start it.
while (ssStatus.dwCurrentState == SERVICE_STOP_PENDING)
{
// Do not wait longer than the wait hint. A good interval is
// one-tenth of the wait hint but not less than 1 second
// and not more than 10 seconds.
dwWaitTime = ssStatus.dwWaitHint / 10;
if (dwWaitTime < 1000)
dwWaitTime = 1000;
else if (dwWaitTime > 10000)
dwWaitTime = 10000;
Sleep(dwWaitTime);
// Check the status until the service is no longer stop pending.
if (!QueryServiceStatusEx(
schService, // handle to service
SC_STATUS_PROCESS_INFO, // information level
(LPBYTE)&ssStatus, // address of structure
sizeof(SERVICE_STATUS_PROCESS), // size of structure
&dwBytesNeeded)) // size needed if buffer is too small
{
printf("QueryServiceStatusEx failed (%d)\n", GetLastError());
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return;
}
if (ssStatus.dwCheckPoint > dwOldCheckPoint)
{
// Continue to wait and check.
dwStartTickCount = GetTickCount();
dwOldCheckPoint = ssStatus.dwCheckPoint;
}
else
{
if (GetTickCount() - dwStartTickCount > ssStatus.dwWaitHint)
{
printf("Timeout waiting for service to stop\n");
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return;
}
}
}
// Attempt to start the service.
if (!StartService(
schService, // handle to service
0, // number of arguments
NULL)) // no arguments
{
printf("StartService failed (%d)\n", GetLastError());
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return;
}
else printf("Service start pending...\n");
// Check the status until the service is no longer start pending.
if (!QueryServiceStatusEx(
schService, // handle to service
SC_STATUS_PROCESS_INFO, // info level
(LPBYTE)&ssStatus, // address of structure
sizeof(SERVICE_STATUS_PROCESS), // size of structure
&dwBytesNeeded)) // if buffer too small
{
printf("QueryServiceStatusEx failed (%d)\n", GetLastError());
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return;
}
// Save the tick count and initial checkpoint.
dwStartTickCount = GetTickCount();
dwOldCheckPoint = ssStatus.dwCheckPoint;
while (ssStatus.dwCurrentState == SERVICE_START_PENDING)
{
// Do not wait longer than the wait hint. A good interval is
// one-tenth the wait hint, but no less than 1 second and no
// more than 10 seconds.
dwWaitTime = ssStatus.dwWaitHint / 10;
if (dwWaitTime < 1000)
dwWaitTime = 1000;
else if (dwWaitTime > 10000)
dwWaitTime = 10000;
Sleep(dwWaitTime);
// Check the status again.
if (!QueryServiceStatusEx(
schService, // handle to service
SC_STATUS_PROCESS_INFO, // info level
(LPBYTE)&ssStatus, // address of structure
sizeof(SERVICE_STATUS_PROCESS), // size of structure
&dwBytesNeeded)) // if buffer too small
{
printf("QueryServiceStatusEx failed (%d)\n", GetLastError());
break;
}
if (ssStatus.dwCheckPoint > dwOldCheckPoint)
{
// Continue to wait and check.
dwStartTickCount = GetTickCount();
dwOldCheckPoint = ssStatus.dwCheckPoint;
}
else
{
if (GetTickCount() - dwStartTickCount > ssStatus.dwWaitHint)
{
// No progress made within the wait hint.
break;
}
}
}
// Determine whether the service is running.
if (ssStatus.dwCurrentState == SERVICE_RUNNING)
{
printf("Service started successfully.\n");
}
else
{
printf("Service not started. \n");
printf(" Current State: %d\n", ssStatus.dwCurrentState);
printf(" Exit Code: %d\n", ssStatus.dwWin32ExitCode);
printf(" Check Point: %d\n", ssStatus.dwCheckPoint);
printf(" Wait Hint: %d\n", ssStatus.dwWaitHint);
}
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
}
I found this
changing-a-service-configuration
I don't know why I haven't seen it until now.
If error 1058 occurs, change the startup type by calling ChangeServiceConfig and calling startservice again, it works properly.
Thank you.
Related
I am working on a simple process filtering minifilter driver.
Managed to make it work in test mode, also managed to get it signed by Microsoft.
Problem is: built it in release mode with the linker's /INTEGRITYCHECK option, signed it, works perfect on my machine, and on the virtual machines that i have hosted on my local machine for testing (hyper-V).
As soon as I asked my colleague to run it, he gets a BSOD with "UNEXPECTED KERNEL MODE TRAP" after just opening some processes.
I am attaching myself to PsSetCreateProcessNotifyRoutineEx, code below. Not sure where to look at this point, I fail to understand why can't I reproduce the issue.
Registering with this:
KdPrint((DRIVER_PREFIX "Registering process callback\n"));
//PROCESS CALLBACKS
status = PsSetCreateProcessNotifyRoutineEx(OnProcessNotify, FALSE);
if (!NT_SUCCESS(status)) {
KdPrint((DRIVER_PREFIX "failed to register process callback (0x%08X)\n", status));
KdPrint((DRIVER_PREFIX "Unregistering OnProcessNotify... \r\n"));
PsSetCreateProcessNotifyRoutineEx(OnProcessNotify, TRUE);
KdPrint((DRIVER_PREFIX "Unregistered OnProcessNotify \r\n"));
return status;
}
The structure that I'm sending to the clients:
typedef struct _ACCESS_DATA
{
UINT32 ProcessID;
UINT32 EventType;
WCHAR Path[MAX_PATH]; // [260 bytes] Max size of a full path in windows.
WCHAR CommandLine[MAX_CMDLINE]; // [8191 bytes] Max size of a commandline
} ACCESS_DATA, * PACCESS_DATA;
The reply structure that I'm waiting from the clients:
typedef struct _REPLY_DATA
{
BOOLEAN Allow; // TRUE if request is permitted, FALSE if not permitted.
UINT32 Reserved; // Alignment. Must be NULL.
} REPLY_DATA, * PREPLY_DATA;
The main method that I'm using. Basically upon any process interception, I am asking the client apps whether I should allow it or not.
I have two separate communication channel to ask two separate applications.
Again, this works perfectly on my computer and on any virtual machine I create on my computer. Not on two of my colleagues machines, nor on some other virtual machines hosted on a different on-prem server. Can't figure out why. All of them are Windows 10 x64, the driver was built for Windows 10 x64.
void OnProcessNotify(_Inout_ PEPROCESS Process, _In_ HANDLE ProcessId, _Inout_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo) {
UNREFERENCED_PARAMETER(Process);
KdPrint((DRIVER_PREFIX "Started something \r\n"));
if (CreateInfo) {
if (CreateInfo->FileOpenNameAvailable && CreateInfo->ImageFileName)
{
//KdPrint(("Pid: %p\n", ProcessId));
KdPrint((DRIVER_PREFIX "ImageFilePath: %wZ\r\n", CreateInfo->ImageFileName));
KdPrint((DRIVER_PREFIX "CmdLine: %wZ\r\n", CreateInfo->CommandLine));
PREPLY_DATA pReplyData = NULL;
PREPLY_DATA ac_pReplyData = NULL;
PAGED_CODE();
pReplyData = ExAllocatePoolWithTag(NonPagedPool, sizeof(REPLY_DATA), REPLY_DATA_TAG);
ac_pReplyData = ExAllocatePoolWithTag(NonPagedPool, sizeof(REPLY_DATA), REPLY_DATA_TAG);
if (pReplyData != NULL && ac_pReplyData != NULL) {
PPROCESS_ACCESS_DATA pAccessData;
pAccessData = ExAllocatePoolWithTag(NonPagedPool, sizeof(PROCESS_ACCESS_DATA), ACCESS_DATA_TAG);
if (pAccessData != NULL) {
//do work
pAccessData->ProcessID = (UINT32)HandleToPid(ProcessId);
//(UINT32)(((ULONG_PTR)ProcessId) & 0xFFFFFFFF);
pAccessData->EventType = 8;
pAccessData->ParentProcessID = (UINT32)HandleToPid(CreateInfo->ParentProcessId);
WCHAR ProcessPath[MAX_PATH] = { 0 };
RtlCopyMemory(ProcessPath, CreateInfo->ImageFileName->Buffer, CreateInfo->ImageFileName->MaximumLength);
RtlZeroMemory(pAccessData->Path, MAX_PATH * sizeof(wchar_t));
//RtlCopyMemory(pAccessData->Path, FileNameInfo->Name.Buffer, FileNameInfo->Name.Length);
RtlCopyMemory(pAccessData->Path, ProcessPath, MAX_PATH * sizeof(wchar_t));
WCHAR CommandLine[MAX_CMDLINE] = { 0 };
RtlCopyMemory(CommandLine, CreateInfo->CommandLine->Buffer, CreateInfo->CommandLine->MaximumLength);
RtlZeroMemory(pAccessData->CommandLine, MAX_CMDLINE * sizeof(wchar_t));
//RtlCopyMemory(pAccessData->CommandLine, FileNameInfo->Name.Buffer, FileNameInfo->Name.Length);
RtlCopyMemory(pAccessData->CommandLine, CommandLine, MAX_CMDLINE * sizeof(wchar_t));
KdPrint((DRIVER_PREFIX "File trying to Execute: %ws\r\n", CreateInfo->ImageFileName->Buffer));
//begin send the request to the first client app, if connected
LARGE_INTEGER Timeout;
Timeout.QuadPart = -((LONGLONG)1 * 1 * 1000 * 1000); // 1000 milliseconds
NTSTATUS status;
ULONG ReplyDataSize = sizeof(REPLY_DATA);
status = FltSendMessage(FilterHandle, &IN_ProcessPort, pAccessData, sizeof(PROCESS_ACCESS_DATA), pReplyData, &ReplyDataSize, &Timeout);
if (Timeout.QuadPart != 0 && NT_SUCCESS(status))
{
//block or not block
if (pReplyData->Allow == TRUE)
{
KdPrint((DRIVER_PREFIX "File Allowed to Execute: %ws\r\n", CreateInfo->ImageFileName->Buffer));
}
else
{
CreateInfo->CreationStatus = STATUS_ACCESS_DENIED;
KdPrint((DRIVER_PREFIX "Process DENIED to Execute: %ws\r\n", CreateInfo->ImageFileName->Buffer));
}
}
//end send the request to the first client app, if connected
//begin send the request to the second client app, if connected
LARGE_INTEGER AC_Timeout;
AC_Timeout.QuadPart = -((LONGLONG)10 * 1000 * (1000 * 10) /*nanoseconds*/); // 10 seconds
NTSTATUS ac_status;
ULONG AC_ReplyDataSize = sizeof(REPLY_DATA);
ac_status = FltSendMessage(FilterHandle, &AC_ProcessPort, pAccessData, sizeof(PROCESS_ACCESS_DATA), ac_pReplyData, &AC_ReplyDataSize, &AC_Timeout);
if (AC_Timeout.QuadPart != 0 && NT_SUCCESS(ac_status))
{
//block or not block
if (ac_pReplyData->Allow == FALSE)
{
CreateInfo->CreationStatus = STATUS_ACCESS_DENIED;
KdPrint((DRIVER_PREFIX "Process DENIED to Execute: %ws\r\n", CreateInfo->ImageFileName->Buffer));
}
else
{
KdPrint((DRIVER_PREFIX "File Allowed to Execute: %ws\r\n", CreateInfo->ImageFileName->Buffer));
}
}
//end send the request to the first client app, if connected
ExFreePoolWithTag(pAccessData, ACCESS_DATA_TAG);
}
ExFreePoolWithTag(pReplyData, REPLY_DATA_TAG);
ExFreePoolWithTag(ac_pReplyData, REPLY_DATA_TAG);
}
}
}
I've got a child thread that calls WaitForMultipleObjects() and blocks waiting for, among other things, an incoming message over COM4. Attached to the other side of COM4 is a board sending a message once every five seconds.
The problem is, WaitForMultipleObjects() is only notified that a message was received when the read buffer I allocated for it is full, rather than becoming notified whenever a single message is transmitted.
The weird part is that this behavior changes if I connect to the board with putty, close putty, and then reopen my application - WaitForMultipleObjects() will thereafter return whenever a message is received, buffer filled or not. This behavior is preferable, and I would like to know what putty is doing so that I may have it enabled all the time.
I checked the DCB object returned from GetCommState() both with and without using Putty, and it doesn't appear that Putty is changing the structure in a way that I am not already doing.
Here is the code initializing the HANDLE object for the com port (referred to as "hCom"):
bool init(struct ReadComArg readComArg) {
BOOL fSuccess;
log(comPort);
// Open a handle to the specified com port.
hCom = CreateFile(comPort,
GENERIC_READ | GENERIC_WRITE,
0, // must be opened with exclusive-access
NULL, // default security attributes
OPEN_EXISTING, // must use OPEN_EXISTING
FILE_FLAG_OVERLAPPED, // can't write in one thread while blocked for a read in another unless port is declared overlapped
NULL); // hTemplate must be NULL for comm devices
if (hCom == INVALID_HANDLE_VALUE) {
// Handle the error.
log("Failed to create hCom handle");
return false;
}
DWORD lptEvtMask;
fSuccess = GetCommMask(hCom, &lptEvtMask);
if (!fSuccess) {
log("GetCommMask failed");
CloseHandle(hCom);
return false;
}
fSuccess = SetCommMask(hCom, lptEvtMask);
printAll(&lptEvtMask);
// Initialize the DCB structure.
DCB dcb;
SecureZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
// Build on the current configuration by first retrieving all current
// settings.
/*fSuccess = GetCommState(hCom, &dcb);
if (!fSuccess) {
log("GetCommState failed");
CloseHandle(hCom);
return false;
}
*/
dcb.BaudRate = readComArg.baudRate; // 115200 baud rate
dcb.ByteSize = readComArg.dataBits; // 8 data size, xmit and rcv
/*
dcb.Parity = readComArg.parity; // parity bit
dcb.StopBits = readComArg.stopBits; // stop bit
dcb.fRtsControl = RTS_CONTROL_ENABLE;
dcb.fDtrControl = DTR_CONTROL_ENABLE;
*/
fSuccess = SetCommState(hCom, &dcb);
if (!fSuccess) {
log("SetCommState failed");
CloseHandle(hCom);
return false;
}
// Get the comm config again.
fSuccess = GetCommState(hCom, &dcb);
if (!fSuccess) {
log("GetCommState failed");
CloseHandle(hCom);
return false;
}
log("Serial Port successfully reconfigured");
hFile = CreateFileW(fileName, // name of the write
FILE_APPEND_DATA, // open for appending
0, // no sharing
NULL, // default security
OPEN_ALWAYS, // open existing file or create new file
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no attr. template
if (hFile == NULL) {
log("Failed to create hFile handle");
CloseHandle(hCom);
return false;
}
PostMessage(readComArg.MainWindow, WM_THREAD_UP, 0, 0);
return true;
}
Putty doesn't touch any of the DCB fields except DCBlength, BaudRate, ByteSize, Parity, and StopBits, and setting the fields that aren't these five to arbitrary values doesn't seem to affect the code's behavior, so I left the rest at zero.
Here is the main loop code:
void loop(struct ReadComArg readComArg) {
//TODO: close all handles when function returns
const unsigned long BUFFSIZE = 256;
BYTE buffer[BUFFSIZE];
DWORD bytesRead, bytesWritten, result;
OVERLAPPED osReader;
OVERLAPPED osWriter;
HANDLE eventArray[4];
eventArray[0] = readComArg.killEvent;
eventArray[2] = readComArg.writeRequestEvent;
BOOL continueLooping = true;
BOOL fWaitingOnRead = FALSE;
BOOL fWaitingOnWrite = FALSE;
while (continueLooping) {
//There is no outstanding read request and we must create a new one:
if (!fWaitingOnRead) {
//First, check to make sure we haven't received a killEvent.
result = WaitForSingleObject(readComArg.killEvent, 0); //returns immediately
if (result == WAIT_OBJECT_0) {
//received killEvent, exiting
log("killEvent was signaled. Exiting loop");
if (!ResetEvent(readComArg.killEvent))
log("failed to reset killEvent");
break;
}
else if (result != WAIT_TIMEOUT) {
//some error occured
log("WaitForSingleObject returned an error");
break;
}
//Otherwise, there was no kill request, continue as normal.
//Attempt to create new read request
osReader = { 0 };
osReader.hEvent = CreateEvent(NULL, true, false, NULL);
//read event failed to allocate, return:
if (osReader.hEvent == NULL) {
log("failed to create readEvent");
break;
}
eventArray[1] = osReader.hEvent;
//Execute the asynchronous read:
if (!ReadFile(hCom, buffer, BUFFSIZE, &bytesRead, &osReader)) {
//The asynchronous read request succeeded and will be completed later:
if (GetLastError() == ERROR_IO_PENDING) {
log("Read request queued and pending");
fWaitingOnRead = TRUE;
}
//The asynchronous read request failed:
else {
log("ReadFile returned an error");
CloseHandle(osReader.hEvent);
break;
}
}
//The asynchronous read request succeeded and completed immediately:
else {
log("Read request queued and returned immediately");
CloseHandle(osReader.hEvent);
handleRead(readComArg, buffer, bytesRead);
}
}
//We are waiting on an outstanding read request:
else {
//block until a signal arrives
//if we are waiting on a write, then there is an additional signal we must block for
if (fWaitingOnWrite) {
log("blocking for kills, reads, writeRequests, and writeResponses.");
result = WaitForMultipleObjects(4, eventArray, FALSE, INFINITE);
}
else {
log("blocking for kills, reads, and writeRequests. No outstanding write Request.");
result = WaitForMultipleObjects(3, eventArray, FALSE, INFINITE);
}
continueLooping = false;
switch (result) {
//The killEvent handle received a signal. This has priority over every other signal.
case WAIT_OBJECT_0:
log("Received killEvent. Exiting loop");
if (!ResetEvent(readComArg.killEvent))
log("failed to reset killEvent");
break;
//The com port handle received a signal
case WAIT_OBJECT_0+1:
log("received signal");
//Unsuccessful read
if (!GetOverlappedResult(hCom, &osReader, &bytesRead, FALSE)) {
log("GetOverlappedResult returned an error");
break;
}
//Successful read, continue looping
log("Outstanding read request fulfilled");
handleRead(readComArg, buffer, bytesRead);
fWaitingOnRead = FALSE;
CloseHandle(osReader.hEvent);
continueLooping = true;
break;
//The writeRequestEvent handle received a signal. Create an asynchronous write request:
case WAIT_OBJECT_0 + 2:
//reset writeRequestEvent signal.
if (!ResetEvent(readComArg.writeRequestEvent)) {
log("failed to reset writeRequestEvent");
break;
}
//attempt to create writeResponseEvent:
osWriter = { 0 };
osWriter.hEvent = CreateEvent(NULL, true, false, NULL);
if (osWriter.hEvent == NULL) {
log("failed to create writeResponseEvent");
break;
}
eventArray[3] = osWriter.hEvent;
//execute the asynchronous write:
if (!WriteFile(hCom, readComArg.writeBuffer, readComArg.numCharsToWrite, &bytesWritten, &osWriter)) {
//The asynchronous write request succeeded and will be completed later:
if (GetLastError() == ERROR_IO_PENDING) {
log("Write request queued and pending");
fWaitingOnWrite = true;
continueLooping = true;
break;
}
//The asynchronous write request failed:
else {
log("WriteFile returned an error");
CloseHandle(osWriter.hEvent);
break;
}
}
//The asynchronous write request succeeded and completed immediately
else {
log("Write request queued and returned immediately");
CloseHandle(osWriter.hEvent);
continueLooping = true;
PostMessage(readComArg.MainWindow, WM_THREAD_SENT, 0, 0);
break;
}
break;
//The writeResponseEvent handle received a signal
case WAIT_OBJECT_0+3:
//Unsuccessful write
if (!GetOverlappedResult(hCom, &osWriter, &bytesWritten, FALSE)) {
log("GetOverlappedResult returned an error");
break;
}
//Successful write, continue looping
PostMessage(readComArg.MainWindow, WM_THREAD_SENT, 0, 0);
log("Outstanding write request fulfilled");
fWaitingOnWrite = FALSE;
CloseHandle(osWriter.hEvent);
continueLooping = true;
break;
// Error in WaitForMultipleObjects()
default:
log("WaitForMultipleObjects returned an error");
break;
}
}
}
CancelIo(hCom);
if(fWaitingOnRead)
CloseHandle(osReader.hEvent);
if (fWaitingOnWrite)
CloseHandle(osWriter.hEvent);
}
I am not very familiar with StackOverflow ettiquette, so if there is something incorrect with how I am asking my question, I apologize in advance and will correct it as soon as I am able. Thank you.
I am creating an application which track the System startup time.
I tried GetTickcount() method and WMI query.In both cases I got the same solution.
But the time that I obtained is different from actual startup time.
By researching I found that because of fast startup option enabled in power option the system is not going for boot when we shutdown it.
Thing that I needed is time actual startup time.How can we get the actual startup time using C++?
I shut downed the system and turned ON it on 24-Jun-20, 8:22:05 AM but boot time that I got is 22-Jun-20, 5:11:05 PM
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 shutting down from command line isn't affected too as my test). So, boot time will not be reset.
You could try the following methods:
Turn off the "fast startup" option.
Add a task to the task schedule to log the time when the system start.
Read the Windows Event Log:
Event ID 27 records the kernel boot events. As you can see in the picture, boot type 0x1 means it was a fast startup. You could just read the newest one and get the create time.
Sample(Refer to this sample document: Querying for Events):
#include <windows.h>
#include <sddl.h>
#include <stdio.h>
#include <winevt.h>
#pragma comment(lib, "wevtapi.lib")
#define ARRAY_SIZE 1
#define TIMEOUT 1000 // 1 second; Set and use in place of INFINITE in EvtNext call
DWORD PrintResults(EVT_HANDLE hResults);
DWORD PrintEvent(EVT_HANDLE hEvent); // Shown in the Rendering Events topic
void main(void)
{
DWORD status = ERROR_SUCCESS;
EVT_HANDLE hResults = NULL;
LPCWSTR pwsPath = L"System";
LPCWSTR pwsQuery = L"Event/System[EventID=27]";
hResults = EvtQuery(NULL, pwsPath, pwsQuery, EvtQueryChannelPath | EvtQueryReverseDirection);
if (NULL == hResults)
{
status = GetLastError();
if (ERROR_EVT_CHANNEL_NOT_FOUND == status)
wprintf(L"The channel was not found.\n");
else if (ERROR_EVT_INVALID_QUERY == status)
// You can call the EvtGetExtendedStatus function to try to get
// additional information as to what is wrong with the query.
wprintf(L"The query is not valid.\n");
else
wprintf(L"EvtQuery failed with %lu.\n", status);
goto cleanup;
}
PrintResults(hResults);
cleanup:
if (hResults)
EvtClose(hResults);
}
// Enumerate all the events in the result set.
DWORD PrintResults(EVT_HANDLE hResults)
{
DWORD status = ERROR_SUCCESS;
EVT_HANDLE hEvents[ARRAY_SIZE];
DWORD dwReturned = 0;
// Get a block of events from the result set.
if (!EvtNext(hResults, ARRAY_SIZE, hEvents, INFINITE, 0, &dwReturned))
{
if (ERROR_NO_MORE_ITEMS != (status = GetLastError()))
{
wprintf(L"EvtNext failed with %lu\n", status);
}
goto cleanup;
}
// For each event, call the PrintEvent function which renders the
// event for display. PrintEvent is shown in RenderingEvents.
/*for (DWORD i = 0; i < dwReturned; i++)
{
if (ERROR_SUCCESS == (status = PrintEvent(hEvents[i])))
{
EvtClose(hEvents[i]);
hEvents[i] = NULL;
}
else
{
goto cleanup;
}
}*/
if (ERROR_SUCCESS == (status = PrintEvent(hEvents[0])))
{
EvtClose(hEvents[0]);
hEvents[0] = NULL;
}
else
{
goto cleanup;
}
cleanup:
for (DWORD i = 0; i < dwReturned; i++)
{
if (NULL != hEvents[i])
EvtClose(hEvents[i]);
}
return status;
}
DWORD PrintEvent(EVT_HANDLE hEvent)
{
DWORD status = ERROR_SUCCESS;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
DWORD dwPropertyCount = 0;
LPWSTR pRenderedContent = NULL;
if (!EvtRender(NULL, hEvent, EvtRenderEventXml, dwBufferSize, pRenderedContent, &dwBufferUsed, &dwPropertyCount))
{
if (ERROR_INSUFFICIENT_BUFFER == (status = GetLastError()))
{
dwBufferSize = dwBufferUsed;
pRenderedContent = (LPWSTR)malloc(dwBufferSize);
if (pRenderedContent)
{
EvtRender(NULL, hEvent, EvtRenderEventXml, dwBufferSize, pRenderedContent, &dwBufferUsed, &dwPropertyCount);
}
else
{
wprintf(L"malloc failed\n");
status = ERROR_OUTOFMEMORY;
goto cleanup;
}
}
if (ERROR_SUCCESS != (status = GetLastError()))
{
wprintf(L"EvtRender failed with %d\n", status);
goto cleanup;
}
}
wprintf(L"%s\n\n", pRenderedContent);
cleanup:
if (pRenderedContent)
free(pRenderedContent);
return status;
}
Result:
I am writing a service based on the tutorial at the following page:
https://www.codeproject.com/Articles/499465/Simple-Windows-Service-in-Cplusplus
I can successfully create the service using:
sc create service_name binPath=<path_name>
When I attempt to start the service, I get the following error:
sc start service_name
[SC] StartService FAILED 1053:
The service did not respond to the start or control request in a timely fashion.
Here is my main():
int main (int argc, char *argv[])
{
OutputDebugString("service_name: entered main");
SERVICE_TABLE_ENTRY ServiceTable[] =
{
{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
{NULL, NULL}
};
if (StartServiceCtrlDispatcher (ServiceTable) == FALSE)
{
return GetLastError();
}
return 0;
}
EDIT: I switched from log files to OutputDebugString()/DebugView
I ran DebugView, and I never receive "entered main". However, if I replace the contents of my worker thread with a return statement, I do start up successfully, and I receive the debug message, so I know that DebugView is working correctly.
Here is where I create my worker thread:
// Start a thread that will perform the main task of the service
HANDLE hThread = CreateThread (NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
if (hThread) {
// Wait until our worker thread exits, so we can set state to SERVICE_STOPPED and return needs to stop
WaitForSingleObject (hThread, INFINITE);
} else {
OutputDebugString("service_name: ServiceMain: CreateThread returned NULL");
}
It seems like my worker thread is responsible for the startup error, but why wouldn't I get debug messages at the top of main()?
If your service was created successfully, you should see it in the list of Windows Services ( Computer Management -> Services and Applications->Services). If it is not present, then it was not registered properly. If it is present, you could try to start it from Windows Service console. Your's _tmain is just not called by the service, no log will be produced.
You need to update the SCM states using SetServiceStatus function.
If initializing your service takes a long time, you should update the state periodically with the SERVICE_START_PENDING state.
When the initialization is finished, you must update the SCM state to SERVICE_RUNNING.
Other states are:
-SERVICE_STOP_PENDING.
-SERVICE_PAUSE_PENDING.
-SERVICE_CONTINUE_PENDING.
-SERVICE_STOPPED.
My function that sends the state to the SCM is as follows:
BOOL SendStatusToSCM
(
DWORD dwCurrentState,
DWORD dwWin32ExitCode,
DWORD dwServiceSpecificExitCode,
DWORD dwCheckPoint,
DWORD dwWaitHint
)
{
BOOL success;
SERVICE_STATUS serviceStatus;
// Preenche os campos do service status
serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwCurrentState = dwCurrentState;
if (dwCurrentState == SERVICE_START_PENDING)
serviceStatus.dwControlsAccepted = 0;
else
serviceStatus.dwControlsAccepted =
SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE |
SERVICE_ACCEPT_SHUTDOWN;
if (dwServiceSpecificExitCode == 0)
serviceStatus.dwWin32ExitCode =
dwWin32ExitCode;
else
serviceStatus.dwWin32ExitCode =
ERROR_SERVICE_SPECIFIC_ERROR;
serviceStatus.dwServiceSpecificExitCode =
dwServiceSpecificExitCode;
serviceStatus.dwCheckPoint = dwCheckPoint;
serviceStatus.dwWaitHint = dwWaitHint;
// Passa o status para o SCM
success = SetServiceStatus
(
serviceStatusHandle,
&serviceStatus
);
if (!success)
exit( 99 );
return success;
}
With this create below the start service works perfectly and always activates the main():
serv=CreateService (
sc,
noServ, // service name
noDisp, // display name
SERVICE_ALL_ACCESS, // desired access
SERVICE_WIN32_OWN_PROCESS, // service type
SERVICE_AUTO_START, // modo de iniciar o serviço
SERVICE_ERROR_NORMAL, // gravidade da falha do serviço
noExec, // nome do executável
NULL, // nome do grupo ao qual pertence
NULL, // tag id
NULL, // tabela de dependências
NULL, // account name
NULL // account password
);
I am working on a very confused issue all this afternoon, I want to check the windows service status by QueryServiceStatusEx, but always get 0. MSDN says
"If the function fails, the return value is zero. To get extended
error information, call GetLastError."
To get more error information, I call GetLastError, the error code is 1.
ERROR_INVALID_HANDLE : The handle is invalid.
Here is my code, e.g. I check the window service :"Spooler", where is wrong in my code? Why I can't get the service SC_HANDLE by using OpenService()?
bool isServiceStart()
{
SERVICE_STATUS_PROCESS status;
SC_HANDLE schSCManager;
SC_HANDLE schService;
//get hadnle to the scm database
schSCManager = OpenSCManager(
NULL, //local machine
NULL, //services acitive database
SC_MANAGER_ALL_ACCESS
);
if(NULL == schSCManager){
qDebug() << "Open SCManager failed: " << (GetLastError() == ERROR_ACCESS_DENIED);
CloseServiceHandle(schSCManager);
return false;
}
//Get a hadle to the service
QString serviceName = "Spooler";
schService = OpenService(
schSCManager, //database
(LPCTSTR)serviceName.data(),
SERVICE_ALL_ACCESS
);
if(schService == NULL){
qDebug() << "service doesn't exist: " << GetLastError();
CloseServiceHandle(schSCManager);
return false;
}
DWORD dwBytesNeeded;
if(!QueryServiceStatusEx(
schService,
SC_STATUS_PROCESS_INFO, // information level
(LPBYTE) &status, // address of structure
sizeof(SERVICE_STATUS_PROCESS),
&dwBytesNeeded // size needed if buffer is too small
))
{
qInfo() << "service status" << status.dwCurrentState;
}else{
qInfo() << "hahaha alway is 0" <<GetLastError();
}
return false;
}
Your condition is wrong, you write "hahaha alway is 0" when QueryServiceStatusEx returns non-zero.
Either remove the ! operator in the condition, or switch places of the outputs.