Send command to service from C++ - c++

how can I send command to a Windows service from C++? Equivalent .NET code is:
ServiceController sc = new ServiceController("MyService");
sc.ExecuteCommand(255);

From native C++, you will need to:
Open a handle to the service control manager,
Use the service control manager to obtain a service handle for the service you want to control,
Send a control code or codes to the service, and
Close the handles opened in steps 1 and 2.
For example, this code restarts the time synchronization service. First, I create a wrapper class for the service handles, to close them automatically when leaving the block.
class CSC_HANDLE
{
public:
CSC_HANDLE(SC_HANDLE h) : m_h(h) { }
~CSC_HANDLE() { ::CloseServiceHandle(m_h); }
operator SC_HANDLE () { return m_h; }
private:
SC_HANDLE m_h;
};
Then, I open the service control manager (using OpenSCManager()) and the service I want to control. Note that the dwDesiredAccess parameter to OpenService() must include permissions for each control I want to send, or the relevant control functions will fail.
BOOL RestartTimeService()
{
CSC_HANDLE hSCM(::OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, GENERIC_READ));
if (NULL == hSCM) return FALSE;
CSC_HANDLE hW32Time(::OpenService(hSCM, L"W32Time", SERVICE_START | SERVICE_STOP | SERVICE_QUERY_STATUS));
if (NULL == hW32Time) return FALSE;
To stop the service, I use ControlService() to send the SERVICE_CONTROL_STOP code, and then check the return value to make sure the command succeeded. If any error other than ERROR_SERVICE_NOT_ACTIVE is reported, I assume that starting the service is not going to succeed.
SERVICE_STATUS ss = { 0 };
::SetLastError(0);
BOOL success = ::ControlService(hW32Time, SERVICE_CONTROL_STOP, &ss);
if (!success)
{
DWORD le = ::GetLastError();
switch (le)
{
case ERROR_ACCESS_DENIED:
case ERROR_DEPENDENT_SERVICES_RUNNING:
case ERROR_INVALID_HANDLE:
case ERROR_INVALID_PARAMETER:
case ERROR_INVALID_SERVICE_CONTROL:
case ERROR_SERVICE_CANNOT_ACCEPT_CTRL:
case ERROR_SERVICE_REQUEST_TIMEOUT:
case ERROR_SHUTDOWN_IN_PROGRESS:
return FALSE;
case ERROR_SERVICE_NOT_ACTIVE:
default:
break;
}
}
After instructing the service to stop, I wait for the service manager to report that the service is in fact stopped. This code has two potential bugs, which you may wish to correct for production code:
Sleep(1000) will suspend the message loop on this thread, so you should use another method to delay execution if this function will run on a UI thread. You can construct a suitable sleep-with-message-loop using MsgWaitForMultipleObjectsEx().
The DWORD returned from GetTickCount() will wrap around to zero eventually; if it wraps around while this function is waiting, the wait may give up sooner than I intended.
DWORD waitstart(::GetTickCount());
while (true)
{
ZeroMemory(&ss, sizeof(ss));
::QueryServiceStatus(hW32Time, &ss);
if (SERVICE_STOPPED == ss.dwCurrentState) break;
::Sleep(1000);
DWORD tick(::GetTickCount());
if ((tick < waitstart) || (tick > (waitstart + 30000))) return FALSE;
}
Finally, knowing that the service is in a stopped state, I call StartService() run it again.
success = ::StartService(hW32Time, 0, NULL);
if (!success) return FALSE;
return TRUE;
}

You use ControlService, see Service Control Requests.

Here is a little program which will connect to a service called "MYSERVICE" then send a command 141 (which is defined by the service)
// ServiceCommunicator.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
using namespace std;
int main()
{
SC_HANDLE managerHandle;
SC_HANDLE serviceHandle;
SERVICE_STATUS controlParms;
DWORD retStatus;
managerHandle = OpenSCManager(NULL, NULL, GENERIC_READ);
if (NULL != managerHandle)
{
serviceHandle = OpenService(managerHandle, L"MYSERVICE", SERVICE_USER_DEFINED_CONTROL | SERVICE_QUERY_STATUS);
if (NULL != serviceHandle)
{
cout << "connected to Service" << endl;
retStatus = ControlService(serviceHandle, 141, &controlParms);
if (retStatus)
{
//Get the return code from the service
cout << "For command 141, return code from service was " << controlParms.dwWin32ExitCode << endl;
}
else
cout << "Sending command 141 failed" << endl;
CloseServiceHandle(serviceHandle);
}
else
{
cout << "could not connect to Service" << endl;
}
CloseServiceHandle(managerHandle);
}
else
{
cout << "could not open service manager" << endl;
}
return 0;
}

Related

Libmosquitto publish doesn't deliver all messages to Azure IoT Hub

I'm trying to publish more than 100 messages per second to Azure Iot Hub built-in event hub. I'm using libmosquitto 1.6.8 library. I'm using the Free tier package for Azure Iot Hub, I know that there is throttle limit of 100 messages per second. But this is not related to that issue. I have not been able to publish even half of the messages to AZ Iot Hub.
Basically, I have a list of multiple values in multimap that needs to be sent. The metric list:
std::multimap< const std::string, std::tuple< const std::string, const std::string, float> > calculatedMetricList;
I'll be iterating through the multimap and constructing each value into a object payload and will be sending it through. What this means is that the mosquitto_publish method will be called multiple times.
Following is the code for publishing the messages:
void MosquittoClient::sendDataToUpstreamSystem(){
StatisticalMethod statisticalMethod;
int rc;
MosquittoClient pub_mosq(
"<IoT Hub Name>.azure-devices.net",
"<deviceID>",
"<username>",
"<Password>",
"devices/<deviceID>/messages/events/");
printf("Using MQTT to get data payload from host: %s and on port: %d.\r\n", pub_mosq.get_host(), pub_mosq.get_port());
// init the mosquitto lib
mosquitto_lib_init();
// create the mosquito object
struct mosquitto* mosq = mosquitto_new(pub_mosq.get_deviceID(), false, NULL);
// add callback functions
mosquitto_connect_callback_set(mosq, MosquittoClient::connect_callback);
mosquitto_publish_callback_set(mosq, MosquittoClient::publish_callback);
mosquitto_message_callback_set(mosq, MosquittoClient::on_message);
mosquitto_disconnect_callback_set(mosq, MosquittoClient::on_disconnect_callback);
// set mosquitto username, password and options
mosquitto_username_pw_set(mosq, pub_mosq.get_userName(), pub_mosq.get_password());
// specify the certificate to use
std::ifstream infile(pub_mosq.get_certificate());
bool certExists = infile.good();
infile.close();
if (!certExists)
{
printf("Warning: Could not find file '%s'! The mosquitto loop may fail.\r\n", pub_mosq.get_certificate());
}
printf("Using certificate: %s\r\n", pub_mosq.get_certificate());
mosquitto_tls_set(mosq, pub_mosq.get_certificate(), NULL, NULL, NULL, NULL);
// specify the mqtt version to use
int* option = new int(MQTT_PROTOCOL_V311);
rc = mosquitto_opts_set(mosq, MOSQ_OPT_PROTOCOL_VERSION, option);
if (rc != MOSQ_ERR_SUCCESS)
{
rc = pub_mosq.mosquitto_error(rc, "Error: opts_set protocol version");
}
else
{
printf("Setting up options OK\r\n");
}
// connect
printf("Connecting...\r\n");
rc = mosquitto_connect_async(mosq, pub_mosq.get_host(), pub_mosq.get_port(), 4);
if (rc != MOSQ_ERR_SUCCESS)
{
rc = pub_mosq.mosquitto_error(rc, NULL);
}
else
{
printf("Connect returned OK\r\n");
rc = mosquitto_loop_start(mosq);
if (rc != MOSQ_ERR_SUCCESS)
{
rc = pub_mosq.mosquitto_error(rc, NULL);
}
else
{
do
{
for (auto itr = Metrics::calculatedMetricList.begin(); itr != Metrics::calculatedMetricList.end(); itr++) {
int msgId = rand();
std::string test1= itr->first;
std::string test2 = std::get<0>(itr->second);
std::string test3= std::get<1>(itr->second); // metric type
float value = std::get<2>(itr->second); // value
DataPayload objectPayload(
75162345,
496523,
test3,
value,
"test",
test1,
"test",
"test",
123,
213,
23
);
objectPayload.setPayload();
std::string dataPayload = objectPayload.getPayload();
//DEBUG
std::cout << "dataPayload: " << dataPayload << std::endl;
//DEBUG
std::cout << "dataPayload Size: " << dataPayload.size() << std::endl;
// once connected, we can publish (send) a Telemetry message
printf("Publishing to topic: %s\r\n", pub_mosq.get_topic());
rc = pub_mosq.publishToTopic(mosq, &msgId, dataPayload.size(), (char *)dataPayload.c_str());
if (rc == MOSQ_ERR_SUCCESS)
{
printf("Publish returned OK\r\n");
}
else
{
rc = pub_mosq.mosquitto_error(rc, NULL);
}
}
} while (rc != MOSQ_ERR_SUCCESS);
}
}
mosquitto_loop_stop(mosq, true);
mosquitto_destroy(mosq);
mosquitto_lib_cleanup();}
Publish method:
int MosquittoClient::publishToTopic(struct mosquitto *mosq, int *msgId, int sizeOfData, char *data)
{
return mosquitto_publish(mosq, msgId, p_topic, sizeOfData, data, 1, true);
}
When running the program all the messages published return ok, according to the console. But only one or two messages are appearing on the Azure IoT Hub side.
The following image shows the monitoring of IoT Hub, at that time only one message got through.
Device Explorer Twin Monitoring
I have tried so many different solutions, but the program was unable to publish all the messages. It looks like the publish method is waiting to complete the first message but the iteration is moving onto the next message, causing it to be dropped. If that is the cause of the dropped messages, what is the best way to sequence the message sending? Otherwise, what else could be causing messages to be dropped?
Update
The problem was the program didn't waiting until the messages were successfully published to the broker (Azure IoT Hub). You will know if the message is successfully published to the broker if the publish_callback is returned.
void MosquittoClient::publish_callback(struct mosquitto* mosq, void* userdata, int mid)
{
printf("Publish OK.\r\n");
}
Solution was to sleep thread before destroy, cleanup calls and start Mosquitto loop before connection is established.
sleep(30);
mosquitto_loop_stop(mosq, true);
mosquitto_destroy(mosq);
mosquitto_lib_cleanup();
mosquitto_publish() is asynchronous: having it return MOSQ_ERR_SUCCESS simply means that the publication of the message has properly been passed to the Mosquitto thread. So at the moment you are enqueuing lots of messages, and then have your program terminate before it had a chance to actually send the packets.
You can use your MosquittoClient::publish_callback callback to check that all the messages have effectively been sent before stopping the loop and terminating your program.

Execute a command line process with C++ and gracefully close on Windows 10

As part of my automated test suite, I have a C++ Program (A) that executes a command line Process (B) using CreateProcess().
The process only terminates when it receives a SIGINT signal (for reasons outside of my control).
I can terminate the process (B) from (A) using CloseHandle() and/or TerminateProcess(), however, this does not call the destructor of (B), preventing it from closing gracefully (writing stuff to disk and closing DB connections) and causing the tests to fail.
What is the best approach to gracefully close (B), allowing it clean up after itself? Should I be using a helper executable with IPC, a remote thread...?
I have tried the solutions in these SA questions:
Can I send a ctrl-C (SIGINT) to an application on Windows? (If I detach my console the test suite fails)
How do I send ctrl+c to a process in c#? (Modified for C+)
How to get GenerateConsoleCtrlEvent to work with cmd.exe
Edit: #Remy Lebeau is right I should have posted some code:
Current Approach:
Close the process handle. This kills the process immediately.
PROCESS_INFORMATION process_info;
... // CreateProcess()
CloseHandle(process.hProcess);
CloseHandle(process.hThread);
Approach 2:
Detach the current console and then re-attach. This causes the initial test suite to fail.
PROCESS_INFORMATION process_info;
... // CreateProcess
DWORD thisConsoleId = GetCurrentProcessId();
bool consoleDetached = (FreeConsole() != FALSE);
if (AttachConsole(process_info.dwProcessId)) {
std::cout << "Attached process to console" << std::endl;
SetConsoleCtrlHandler(NULL, true);
if (GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0)) {
std::cout << "Ctrl-c sent to process" << std::endl;
} else {
std::cout << "Could not send ctrl-c (" << GetLastError() << ")" << std::endl;
}
FreeConsole();
} else {
std::cout << "Unable to attach process to console (" << GetLastError() << ")" << std::endl;
}
if (consoleDetached) {
// Create a new console if previous was deleted by OS
if (AttachConsole(thisConsoleId)) {
int errorCode = GetLastError();
// 31=ERROR_GEN_FAILURE
if (errorCode == 31) {
AllocConsole();
}
}
}
Approach 3:
Attach to console without freeing. This kills everything including the test suite.
PROCESS_INFORMATION process_info;
... // CreateProcess
AttachConsole(process_info.dwProcessId);
SetConsoleCtrlHandler(NULL, TRUE);
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);

How to check whether a Tibco EMS exclusive queue has an active consumer?

I am developing an application which consumes from a Tibco EMS Queue which has exclusive property set. I shall be able to run multiple instances of my application in Active and Standby mode.
When the application is in standby mode it should not create a consumer to the exclusive queue.
I have implemented the below solution but am looking for a better way to do this?
Currently am using tibemsQueueInfo_GetReceiverCount() to get the receiver count. But this API gives all the consumers created for the queue and I have to call 2 more APIs before this.
Is there a single API that would just return that the queue has an active consumer?
status = tibemsAdmin_Create(&admin, server, userName, password, sslParams);
if (status != TIBEMS_OK)
{
baseUtils_print("tibemsAdmin_Create create failed: %s\n", tibemsStatus_GetText(status));
exit(1);
}
baseUtils_print("Amin creation successful\n");
status = tibemsAdmin_GetQueue(admin, &queueInfo, name);
if (status != TIBEMS_OK)
{
baseUtils_print("tibemsAdmin_GetQueue create failed: %s\n", tibemsStatus_GetText(status));
exit(1);
}
baseUtils_print("Admin GetQueue successful \n");
status = tibemsQueueInfo_GetReceiverCount(queueInfo, &receiverCount);
if (status != TIBEMS_OK)
{
baseUtils_print("tibemsQueueInfo_GetReceiverCount create failed: %s\n", tibemsStatus_GetText(status));
exit(1);
}
baseUtils_print("Queue: '%s', Active Consumers = '%d'\n",name, receiverCount);
bool flag = true;
int prevCount = 0;
while(receiverCount)
{
prevCount = receiverCount;
if(flag)
{
cout << "Consumer in Standby mode..."<<endl;
flag = false;;
}
std::this_thread::sleep_for(std::chrono::seconds(3));
status = tibemsAdmin_GetQueue(admin, &queueInfo, name);
if (status != TIBEMS_OK)
{
baseUtils_print("tibemsAdmin_GetQueue create failed: %s\n", tibemsStatus_GetText(status));
exit(1);
}
status = tibemsQueueInfo_GetReceiverCount(queueInfo, &receiverCount);
if (status != TIBEMS_OK)
{
baseUtils_print("tibemsQueueInfo_GetReceiverCount create failed: %s\n", tibemsStatus_GetText(status));
exit(1);
}
if(receiverCount != prevCount)
cout << "current receiver count = "<<receiverCount<<endl;
}
cout << "Consumer mode is Active"<<endl;
status = tibemsSession_CreateConsumer(session,
&msgConsumer,destination,NULL,TIBEMS_FALSE);
if (status != TIBEMS_OK)
{
fail("Error creating tibemsMsgConsumer", errorContext);
}
No, unfortunately there isn't an easier API. If there would be a 'direct-access' method it would be on tibemsAdmin, but there isn't.
And structurally the API kind of makes sense: you have an Admin Object, then get to the Queue Object and then ask for properties of that Queue Object.
Also the code below will not work, so the fact if a consumer is 'the second in line' is only established after the consumer is created and silently waits for its turn.
while(true) // or better: while( !isStopped() ) ...
{
status = tibemsSession_CreateConsumer(session, &msgConsumer,destination,NULL,TIBEMS_FALSE);
if (status != TIBEMS_OK)
{
std::this_thread::sleep_for(std::chrono::seconds(3));
cout << "Consumer in Standby mode ??"<<endl;
}
else
{
cout << "Consumer mode is Active ??"<<endl;
break;
}
}

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 );
}

Using a Waitable Timer from within a Windows Service

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.