Using a Waitable Timer from within a Windows Service - c++

I am attempting to use a WaitableTimer in a Windows Service written in C++ to bring a Windows XP machine out of sleep/stand-by mode but I cannot seem to get it to work. I copy/pasted the code I am using in the service into a standalone app and that works fine. Is there a step I am missing to get this to work within a service?
The code I am using to set up the waitable timer is as follows (the call to UpdateWaitableTimer() happens within a thread that loops indefinitely):
void UpdateWaitableTimer(job_definition *jobdef)
{
HANDLE existingHandle;
try
{
if (jobdef->JobType == JOB_TYPE_SCAN)
{
char szTimerName[MAX_PATH];
sprintf_s(szTimerName, MAX_PATH, "Timer_%I64d", jobdef->JobID);
existingHandle = OpenWaitableTimer(TIMER_ALL_ACCESS, TRUE, szTimerName);
if (existingHandle != NULL)
{
// A timer handle already exists for this job, so cancel it
CancelWaitableTimer(existingHandle);
}
else
{
// No timer handle exists, create one
existingHandle = CreateWaitableTimer(NULL, TRUE, szTimerName);
}
if (jobdef->JobStatus != JOB_STATUS_SCHEDULED)
{
// This job was cancelled, so close the handle
CloseHandle(existingHandle);
}
else
{
time_t now = time(NULL);
time_t dt = jobdef->JobScheduleTime;
while(dt < now)
{
dt += 86400;
}
// Get a FILETIME one minute before
FILETIME utcFileTime = GetTimestamp(dt - 60);
// Convert to LARGE_INTEGER
LARGE_INTEGER dueTime;
dueTime.HighPart = utcFileTime.dwHighDateTime;
dueTime.LowPart = utcFileTime.dwLowDateTime;
SYSTEMTIME st;
FILETIME *ft = &utcFileTime;
FileTimeToSystemTime(ft, &st);
LogRelease(false, "Setting Timer for scheduled job: %02d/%02d/%d %02d:%02d:%02d", st.wMonth, st.wDay, st.wYear, st.wHour, st.wMinute, st.wSecond);
if(SetWaitableTimer(existingHandle, &dueTime, 0, NULL, NULL, TRUE))
{
if(GetLastError() == ERROR_NOT_SUPPORTED)
{
LogRelease(false, "Resume from sleep/stand-by feature not supported on this operating system.");
}
}
else
{
LogError(false, "Could not create timer. Error: %d", GetLastError());
}
}
}
}
catch(...)
{
LogError(false, "An exception occured while updating waitable timer for job %I64d", jobdef->JobID);
}
LogRelease(false, "Finished Updating Waitable Timer [Job:%I64d]", jobdef->JobID);
}

If it works outside a service then your code is probably fine. There are really only two things I can think of that might cause it to behave differently:
Resuming might require the service to be able to "interact with the desktop." Try setting that option in the service manager under the log on tab, and restart your service.
Services running as LOCAL_SYSTEM might not have rights to resume from sleep. Try running the service as yourself, or create a service account specifically for the service to run from.
If you're already running the service as a specific user, then perhaps that user account has insufficient permissions.

Related

WNetOpenEnum returns ERROR_NETWORK_UNREACHABLE for the "Microsoft Windows Network" node

Our program has a piece of code that calculates the list of computers on our local network. It uses the Windows Networking API (WNetOpenEnum/WNetEnumResource) to unwind the network. For many years, the resulting list was identical to the one that can be seen in Windows Explorer under the "Network" entry. However, recently we have noticed that the same code returns an empty list. During debugging I found that WNetOpenEnum returns error 1231 (ERROR_NETWORK_UNREACHABLE) when it is called for the "Microsoft Windows Network" under the root node.
I have to mention, though I'm pretty sure it has nothing to do with the matter, that the network unwinding is done multithreaded, to avoid possible delays in the main GUI thread. Each time a node of type RESOURCEUSAGE_CONTAINER is encountered, a new worker thread is launched. The thread function calls the following procedure:
DWORD WINAPI EnumNetwork(NETRESOURCE_M* lpNR)
{
const int BUF_SIZE = 16384; // 16K is a good size.
HANDLE hEnum;
DWORD Result;
// Call the WNetOpenEnum function to begin the enumeration.
Result = ::WNetOpenEnum(RESOURCE_GLOBALNET, // all network
RESOURCETYPE_ANY, // all resource types
0, // enumerate all
(LPNETRESOURCE)lpNR,// parent resource
&hEnum); // enumeration handle
if (Result != NO_ERROR) // -> for "Microsoft Windows Network" Result = 1231
return Result;
std::vector<std::wstring> SrvList;
// Allocate buffer for enumeration.
LPNETRESOURCE lpEnumNR = (LPNETRESOURCE)new char[BUF_SIZE];
if (lpEnumNR == 0)
Result = ERROR_OUTOFMEMORY;
else
{
while (1)
{
::ZeroMemory(lpEnumNR, BUF_SIZE); // Initialize the buffer.
DWORD NumEntries = -1; // Enumerate all entries.
DWORD BufSize = BUF_SIZE;
// Call WNetEnumResource to continue the enumeration.
Result = ::WNetEnumResource(hEnum, // enumeration handle
&NumEntries,// number of entries to enumerate
lpEnumNR, // array of resources to return
&BufSize); // buffer size
if (Result == NO_ERROR)
{
// If the call succeeds, loop through the array.
for (unsigned i = 0; i < NumEntries; ++i)
{
if (lpEnumNR[i].dwDisplayType == RESOURCEDISPLAYTYPE_SERVER)
{
// Collect servers.
LPCWSTR SrvName = lpEnumNR[i].lpRemoteName;
if (PathHelpers::IsFullPath(SrvName))
SrvList.push_back(SrvName);
}
else if ((lpEnumNR[i].dwUsage & RESOURCEUSAGE_CONTAINER) &&
lpEnumNR[i].lpRemoteName != 0)
{
TCHAR PathBuf[1024] = {0};
if (lpNR && lpNR->Path)
{
_tcscpy(PathBuf, lpNR->Path);
::PathAddBackslash(PathBuf);
}
_tcscat(PathBuf, lpEnumNR[i].lpRemoteName);
if (RegisterServer(PathBuf))
{
// Start new thread for recursive enumeration.
NETRESOURCE_M* lpChildNR = DeepCopyNR(&lpEnumNR[i], PathBuf);
ExploreNetwork(lpChildNR); // -> this starts a worker thread
}
else
{
GetLogger().LogMessage(
_T("Cycles found while unwinding network: %s"), PathBuf);
}
}
}
}
else
{
if (Result == ERROR_NO_MORE_ITEMS)
Result = NO_ERROR;
break;
}
} // end while
delete [] (char*)lpEnumNR;
} // end if
::WNetCloseEnum(hEnum);
if (!SrvList.empty())
NotifyServerAdded(SrvList);
return Result;
}
where NETRESOURCE_M is the structure
struct NETRESOURCE_M
{
NETRESOURCE NR;
LPTSTR Path;
};
Trying to figure out what could have caused such a sudden change in behavior, I found in Google that a few years ago Microsoft disabled the SMB1 protocol, which could affect Network Discovery. However, I can't believe they could have damaged their own API without saying a word in the documentation.
EDIT: At the same time, Windows Explorer has a bunch of computers under its "Network" node. In the network settings, the network type is "Domain", and the network discovery is ON. Services "Function Discovery Provider Host" and "Function Discovery Resources Publication" are running. Windows OS build is 19042.685.
Edit 2: The Sysinternals' "ShareEnum" tool also fails with the error: "No domains or workgroups where found on your network". Because of this, and also because some time ago our company moved all of its computers to a different network, I got the feeling that the problem is in the network configuration. Such as though the network is declared as "Domain", the computers were not enrolled to this domain. I do not understand much in that, but something like this.

OPCUA C++ Monitored item doest'n callback the function

I'm quite new in the opcua's world and I'm trying to monitor a server variable with a client in C++.
I'm on the 1.2.2 version of opcua
I have a boolean variable in the server at the node (1,6070) and when I run the following code I receive the LOG :
[2021-08-03 15:27:47.442 (UTC+0200)] info/session Connection 5 | SecureChannel 2 | Session ns=1;g=913a21de-f467-5bc9-ed9e-29b27b470490 | Subscription 2 | Created the Subscription with a publishing interval of 500.00 ms
But I've never reach the function 'handler_events_datachange' in which I only put an output for now. (I'm sure that the value in the node 6070 changed btw)
Thanks for helping!
int main(void) {
signal(SIGINT, stopHandler); /* catches ctrl-c */
UA_Client *client = UA_Client_new();
UA_ClientConfig *cc = UA_Client_getConfig(client);
UA_ClientConfig_setDefault(cc);
UA_Client_connect(client, "opc.tcp://localhost");
UA_MonitoredItemCreateResult result;
UA_CreateSubscriptionResponse response; // warning memory leak
UA_CreateSubscriptionRequest request = UA_CreateSubscriptionRequest_default();
UA_Client_Subscriptions_create(client, request, NULL, NULL, NULL);
UA_Int32 subId = response.subscriptionId;
if(response.responseHeader.serviceResult == UA_STATUSCODE_GOOD)
{
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND , "subscription succed");
} else {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND , "subscription UNsucced");
}
UA_MonitoredItemCreateRequest monRequest = UA_MonitoredItemCreateRequest_default(UA_NODEID_NUMERIC(1, 6070));
result = UA_Client_MonitoredItems_createDataChange(client, subId, UA_TIMESTAMPSTORETURN_BOTH, monRequest, NULL, handler_events_datachange, NULL);
while(running) {
}
}
I finally found the error !
The problem comme from the fact no means of handling asynchronous
events automatically is provided. However, some synchronous function
calls will trigger handling, but to ensure this happens a client
should periodically call UA_Client_run_iterate explicitly.
So the solution is to add UA_Client_run_iterate(client,100) in the while().
I didn't fully understand what the timeout was about but I'll complete this answer if I can

How can I write a simple application using Openthread library

Even to develop a simple application, the existing examples in Openthread are complex to refer. Can anybody provide a list of steps to use Openthread "mdt/fdt library" and develop a simple application, from where a CoAP message can be sent or received ? Following is what I have written, but it is not running properly and crashing at times. I have linked "fdt, posix, mbedtls, libcrypto" etc libraries and able to build the application successfully.
instance = otInstanceInitSingle();
otError err = otIp6SetEnabled(instance, true);
if(err == OT_ERROR_NONE)
{
err = otCoapStart(instance, OT_DEFAULT_COAP_PORT);
pthread_t thread_id;
pthread_create(&thread_id, NULL, OTProcessThread, NULL); // To call otTaskletsProcess(instance);
return OK;
}
else{
std::cout << "Init Status: " << err << "\n";
}
The thread looks like the following. I this is a sample code, so I have not given any sleep/signal in the thread at present.
void *OTProcessThread(void *vargp)
{
printf("\nOTProcessThread started..");
while (true)
{
otTaskletsProcess(instance);
//otSysProcessDrivers(instance);
}
}
With this initialization process, I am trying to send a message as follows. But after that the application is crashing somewhere inside the Openthread code.
message = otCoapNewMessage(instance, NULL);
otCoapMessageInit(message, coapType, coapCode);
otCoapMessageGenerateToken(message, 8);
otCoapMessageAppendUriPathOptions(message, uri.c_str());
//otMessageAppend(message, NULL, 0);
otError status = otCoapSendRequest(instance, message, &messageInfo, &HandleResponse, this);
Can somebody please let me know, what exactly I am missing ?
While I can't speak to your specific issue without greater visibility, here are some resources you may find helpful:
https://github.com/openthread/ot-rtos
https://codelabs.developers.google.com/codelabs/openthread-apis/
https://www.nordicsemi.com/Software-and-tools/Software/nRF5-SDK-for-Thread-and-Zigbee

How can I wait for an application launched by another application launched by my application Qt/C++

I'm creating a Windows Add/Remove Programs application in Qt 5.4 and I'm becaming crazy to solve a little "puzzle":
My application (APP_0) runs another application (APP_1) and waits for this APP_1 until it terminates.
APP_1 is an uninstaller (i.e. uninstall.exe) and I've not the source code of the APP_1, just of my Qt APP_0.
APP_1, instead of doing the uninstall job, it simply copies itself somewhere in the filesystem (I saw as Au_.exe but other apps could use different names and locations), runs this copy of itself (APP_2) and terminates.
The APP_2 has a GUI and the job I'm waiting for (uninstall) is demanded to the final user of the running APP_2.
In this situation my application (APP_0) stops waiting for APP_1 pratically immediately (because it launches APP_1 and waits for APP_1). But to work properly, obviously, I need to know instead when APP_2 is terminated...
So the question is:
is there a way (using some techniques (hooking?)) to know if and when APP_2 terminates?
Note: Consider that the standard Windows Add/Remove Programs utility does the job successfully (it seems it waits for APP_2). You can test this, for example, installing Adobe Digital Edition. Its uninstaller (uninstall.exe) copies itself into a new folder in the User_Local_Temp folder as Au_.exe, runs it and terminates. But the OS utility successfully waits for Au_.exe and only after it terminates refreshes the list of installed programs.
If this kind of technique (uninstall.exe copies itself somewhere ALWAYS with THE SAME name (Au_.exe) ) the problem could be resolved, obviously, very simply. But I don't think that the name of the copied uninstaller is always the same and also I don't like to assume things I'm not sure are real.
Many thanks in advance
Thanks to IInspectable's suggestion (see his comment... and many thanks guy!) I created a function which solves my problems! I'll share here this function which could be useful to other people with the same (or similar) problem.
For my needs, the function receives as parameter the index of the item to be uninstalled (from a QList) and gets the uninstall string (for example: C:\ProgramFiles\MyApp\uninstall.exe).
Then with this uninstall string, I'll create a process (CreateProcess) and put its handle into a Job Object, so that my function will wait for all the processes ran by this process.
The function itself is pretty simple and can be improved.
Notice that the process MUST be created with the CREATE_BREAKAWAY_FROM_JOB option, otherwise the AssignProcessToJobObject will fail with a "Access Denied" error.
void MainWindow::uniButtonClick(int idx)
{
QMessageBox::StandardButton reply;
QMessageBox::StandardButton err;
reply = QMessageBox::question(this, "Uninstall/Change", "Uninstall " +
ip[idx].displayName +"?\r\n\r\n" + ip[idx].uninstallString,
QMessageBox::Yes|QMessageBox::No);
if (reply == QMessageBox::Yes)
{
//QString s = "C:\\windows\\notepad.exe"; // Just to test Job assignment and createprocess
QString s = ip[idx].uninstallString; // the real uninstaller string
QString jobName = "MyJobObject";
try
{
PROCESS_INFORMATION ProcessInfo; //This is what we get as an [out] parameter
STARTUPINFO StartupInfo; //This is an [in] parameter
PJOBOBJECT_BASIC_PROCESS_ID_LIST pList;
HANDLE hProcess;
BOOL bJobAllEnd;
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
StartupInfo.cb = sizeof StartupInfo ; //Only compulsory field
wchar_t* path;
path = (wchar_t*) malloc (sizeof(wchar_t)*s.length()+1);
s.toWCharArray(path);
path[s.length()]=0; // Null terminate the string
// Create the process with CREATE_BREAKAWAY_FROM_JOB to overcome the AccessDenied issue on AssignProcessToJobObject.
if(CreateProcess(NULL, path, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB|CREATE_SUSPENDED, NULL, NULL,&StartupInfo, &ProcessInfo))
{
pList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST)GlobalAlloc(GMEM_FIXED, 10000);
HANDLE jobObj = CreateJobObject(NULL, (const wchar_t*)jobName.utf16());
if (AssignProcessToJobObject(jobObj, ProcessInfo.hProcess) != 0)
{
ResumeThread(ProcessInfo.hThread); // Process assigned to JobObjext, resume it now
do
{
QueryInformationJobObject(jobObj, JobObjectBasicProcessIdList, pList, 10000, NULL);
bJobAllEnd = TRUE;
for(DWORD i=0; i<pList->NumberOfProcessIdsInList; i++)
{
hProcess = OpenProcess(SYNCHRONIZE, FALSE, pList->ProcessIdList[i]);
if(hProcess != NULL)
{
CloseHandle(hProcess);
bJobAllEnd = FALSE;
}
}
Sleep(500);
} while(!bJobAllEnd);
}
else
qDebug() << "AssignProcess to Job failed: error = " << QString::number(GetLastError());
GlobalFree(pList);
CloseHandle(jobObj);
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
}
}
catch(QString error)
{
QMessageBox::critical(this, "File not found!", "The requested uninstaller doesn't exists", QMessageBox::Ok);
}
// refresh list
handleButton();
}
}

Windows service installation returns error 1053

I have created a Http Server(C++ Win 32 console application ) and I wanted to run it is service.
This server has main thread and Listener thread which will listen to the incoming traffic.main thread will block forever.
I have created a NSIS Installer which uses SimpleSC plugin to install and the run the server
SimpleSC::InstallService "HttpServer" "HttpServer" "16" "2" "$INSTDIR\Server.exe" "" "" ""
SimpleSC::StartService "HttpServer" "" 30
I am able to install service but its not starting and return 1053 error.Is this because of main thread block ? Please help me on this.
The problem must be in your service code. In the service control handler that you declared in the call to RegisterServiceCtrlHandler() you need to handle several request types and return according feedback to the system service manager. It let the system kow that your service is working correctly and what is its current state.
If you do not answer to all request types (esp. SERVICE_CONTROL_INTERROGATE), or if you do not answer in a limited time, the system will deduce that your service has failed / is stalled.
This is an example of control handler that I use in a code of mine:
//Feedback() is a custom function to put log into the system events and / or OutputDebugString()
//mSrvStatus is a global SERVICE_STATUS
void WINAPI SrvControlHandler(DWORD Opcode) {
DWORD state;
switch (Opcode) {
case SERVICE_CONTROL_PAUSE:
Feedback(FEED_EVENTS|FEED_ODS, "Pausing %s", SRVNAME);
bActive = false;
state = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
//refresh our settings from registry before continuing
GetRegistrySettings();
Feedback(FEED_EVENTS|FEED_ODS, "Continuing %s with refresh=%d", SRVNAME, dwRefresh);
bActive = true;
state = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
Feedback(FEED_EVENTS|FEED_ODS, "Stopping %s", SRVNAME);
ReportSrvStatus(SERVICE_STOP_PENDING, NO_ERROR, 0); //ok, we begin to stop
//The final ReportSrvStatus(SERVICE_STOPPED, NO_ERROR, 0);
//is sent from the function that started the service
//that is waiting forever on the hSrvStopEvt event
bActive = false; //we tell the thread to stop fetching
SetEvent(hSrvStopEvt); //and we signal the final event
return;
break;
case SERVICE_CONTROL_INTERROGATE:
state = mSrvStatus.dwCurrentState;
Feedback(FEED_ODS, "%s interrogated by SCM, returned %d", SRVNAME, state);
break;
default:
Feedback(FEED_ODS, "other control resquest ?? - %d", Opcode);
state = mSrvStatus.dwCurrentState;
}
ReportSrvStatus(state, NO_ERROR, 0);
}
/* Sets the current service status and reports it to the SCM.
Parameters:
dwCurrentState - The current state (see SERVICE_STATUS)
dwWin32ExitCode - The system error code
dwWaitHint - Estimated time for pending operation, in milliseconds
*/
void ReportSrvStatus( DWORD dwCurrentState,
DWORD dwWin32ExitCode,
DWORD dwWaitHint) {
static DWORD dwCheckPoint = 1;
mSrvStatus.dwCurrentState = dwCurrentState;
mSrvStatus.dwWin32ExitCode = dwWin32ExitCode;
mSrvStatus.dwWaitHint = dwWaitHint;
if (dwCurrentState == SERVICE_START_PENDING)
mSrvStatus.dwControlsAccepted = 0;
else mSrvStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_PAUSE_CONTINUE|SERVICE_ACCEPT_SHUTDOWN;
if ( (dwCurrentState == SERVICE_RUNNING) ||
(dwCurrentState == SERVICE_STOPPED) )
mSrvStatus.dwCheckPoint = 0;
else mSrvStatus.dwCheckPoint = dwCheckPoint++;
SetServiceStatus( hSrvStatus, &mSrvStatus );
}