I created a sample service using Win32 API and C++.
I have once used Mingw g++ (7.1 - C++14) and Visual Studio 2010 independently.
The service I created using g++ does not start (after installation) and gives Error 1053: "The service did not respond in a timely fashion" when attempting to start, stop or pause a service.
I created an service using Visual C++ 2010 (same code with minor modification - for Unicode support) and it run properly on development machine (after installation).
However when I run the same service (after installation) I get error Error 1053: "The service did not respond in a timely fashion" when attempting to start, stop or pause a service .
Reference Article : Simple Windows Service in C++
Visual C++ :
WindowsService.cpp
#include "stdafx.h"
#include "Common.hpp"
using namespace std;
/*
*
*/
SERVICE_STATUS serviceStatus = {0};
SERVICE_STATUS_HANDLE serviceStatusHandle = NULL;
HANDLE serviceStopEvent = INVALID_HANDLE_VALUE;
VOID WINAPI ServiceMain (DWORD, LPSTR *);
VOID WINAPI ServiceCtrlHandler(DWORD);
DWORD WINAPI ServiceWorkerThread(LPVOID);
#define SERVICE_NAME _T("My Sample Service")
int _tmain(int argc, _TCHAR* argv[])
{
SERVICE_TABLE_ENTRY serviceTable[] =
{
{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain},
{NULL, NULL}
};
if(StartServiceCtrlDispatcher(serviceTable) == FALSE)
{
DWORD errorMessageID = ::GetLastError();
FileOperations fo;
fo.printError(fo.getLastErrorAsString(errorMessageID));
return errorMessageID;
}
//cout << "Hello World";
FileOperations fo;
fo.printError("Testing Error");
fo.printLog("Ishaan Says Hello World");
return 0;
}
VOID WINAPI ServiceMain(DWORD argc, LPSTR *argv)
{
DWORD status = E_FAIL;
serviceStatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);
if(serviceStatusHandle == NULL)
{
FileOperations fo;
fo.printError(fo.getLastErrorAsString(::GetLastError()));
return;
}
//Tell The Service Controller we are starting
ZeroMemory(&serviceStatus, sizeof(serviceStatus));
serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_START_PENDING;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwServiceSpecificExitCode = 0;
serviceStatus.dwCheckPoint = 0;
if(SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE)
{
OutputDebugString(_T("My Sample Service : Service Main : SetSeviceStatus returned error. First (1) If"));
FileOperations fo;
fo.printError("My Sample Service : Service Main : SetSeviceStatus returned error");
}
//Preform task necessary to start a service here
//Create a stop event to wait on later
serviceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if(serviceStopEvent == NULL)
{
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_STOP;
serviceStatus.dwWin32ExitCode = GetLastError();
serviceStatus.dwCheckPoint = 1;
if(SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE)
{
OutputDebugString(_T("My Sample Service : ServiceMain : SetServiceStatus returned error. Second (2) If"));
FileOperations fo;
fo.printError("My Sample Service : ServiceMain : SetServiceStatus returned error. Second (2) If");
}
return;
}
//Tell Service Controller we are started
serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
serviceStatus.dwCurrentState = SERVICE_RUNNING;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCheckPoint = 0;
if(SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE)
{
OutputDebugString(_T("My Sample Service : ServiceMain : SetServiceStatus returned error. Tell Service Controller we are started"));
FileOperations fo;
fo.printError("My Sample Service : ServiceMain : SetServiceStatus returned error. Tell Service Controller we are started");
}
// Start a thread that will perform the main task of the service
HANDLE hThread = CreateThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
// Wait until our worker thread exits signaling that the service needs to stop
WaitForSingleObject(hThread, INFINITE);
//Perform Clean Up
CloseHandle(serviceStopEvent);
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_STOPPED;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCheckPoint = 3;
if(SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE)
{
OutputDebugString(_T("My Sample Service : Service Main : SetSeviceStatus returned error during exiting"));
FileOperations fo;
fo.printError("My Sample Service : Service Main : SetSeviceStatus returned error during exiting");
}
return;
}
VOID WINAPI ServiceCtrlHandler(DWORD ctrlCode)
{
switch(ctrlCode)
{
case SERVICE_CONTROL_STOP :
if(serviceStatus.dwCurrentState != SERVICE_RUNNING)
break;
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCheckPoint = 4;
if(SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE)
{
OutputDebugString(_T("My Sample Service: ServiceCtrlHandler: SetServiceStatus returned error"));
FileOperations fo;
fo.printError("My Sample Service: ServiceCtrlHandler: SetServiceStatus returned error");
}
SetEvent(serviceStopEvent);
break;
default :
break;
}
}
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
{
while(WaitForSingleObject(serviceStopEvent, 0) != WAIT_OBJECT_0)
{
FileOperations fo;
fo.printLog("Inside Service Thread");
Sleep(1000);
}
return ERROR_SUCCESS;
}
Common.hpp
#ifndef COMMON_COMMON_HPP_
#define COMMON_COMMON_HPP_
#include "stdafx.h"
using namespace std;
#define RETURN_SUCCESS true
#define RETURN_FAILURE false
class FileOperations
{
public :
void printError(string);
void printLog(string);
string getLastErrorAsString(DWORD);
private :
void getDateTime(void);
string DateTime;
};
stdafx.h
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
#include <ctime>
#include <cerrno>
#include <string>
#include <cstdio>
#include <fstream>
#include <string>
#include <cstdint>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <Windows.h>
Common.cpp
#include "stdafx.h"
#include "Common.hpp"
using namespace std;
bool GlobalVariables::startCapture = false;
void FileOperations::printLog(string str)
{
ofstream of;
of.open("C:\Log.dat", ios::out | ios::app);
this->getDateTime();
of << "[" << DateTime << "]" << "\t\t" << str << endl;
of.close();
}
void FileOperations::printError(string str)
{
ofstream of;
of.open("C:\Error.dat", ios::out | ios::app);
this->getDateTime();
of << "[" << DateTime << "]" << "\t\t" << str << endl;
of.close();
}
void FileOperations::getDateTime(void)
{
time_t now;
tm *dtStruct;
now = time(0);
dtStruct = localtime(&now);
DateTime.clear();
DateTime = to_string((long long)dtStruct->tm_mday) + ":" + to_string((long long)1 + dtStruct->tm_mon) + ":" + to_string((long long)1900 + dtStruct->tm_year) + "\t" +
to_string((long long)1 + dtStruct->tm_hour) + ":" + to_string((long long)1 + dtStruct->tm_min) + ":" + to_string((long long)1 + dtStruct->tm_sec);
}
//Returns the last Win32 error, in string format. Returns an empty string if there is no error.
string FileOperations::getLastErrorAsString(DWORD errorMessageID)
{
if(errorMessageID == 0)
return string("No error message has been recorded"); //No error message has been recorded
LPSTR messageBuffer = nullptr;
size_t size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL);
string message(messageBuffer, size);
//Free the buffer.
LocalFree(messageBuffer);
return message;
}
g++ :
main.cpp
#include "Common.hpp"
using namespace std;
/*
*
*/
SERVICE_STATUS serviceStatus = {0};
SERVICE_STATUS_HANDLE serviceStatusHandle = NULL;
HANDLE serviceStopEvent = INVALID_HANDLE_VALUE;
VOID WINAPI ServiceMain (DWORD, LPSTR *);
VOID WINAPI ServiceCtrlHandler(DWORD);
DWORD WINAPI ServiceWorkerThread(LPVOID);
#define SERVICE_NAME "My Sample Service"
int main(int argc, char** argv)
{
SERVICE_TABLE_ENTRY serviceTable[] =
{
{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain},
{NULL, NULL}
};
if(StartServiceCtrlDispatcher(serviceTable) == FALSE)
{
DWORD errorMessageID = ::GetLastError();
FileOperations fo;
fo.printError(fo.getLastErrorAsString(errorMessageID));
return errorMessageID;
}
//cout << "Hello World";
FileOperations fo;
fo.printError("Testing Error");
fo.printLog("Ishaan Says Hello World");
return 0;
}
VOID WINAPI ServiceMain(DWORD argc, LPSTR *argv)
{
DWORD status = E_FAIL;
serviceStatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);
if(serviceStatusHandle == NULL)
{
FileOperations fo;
fo.printError(fo.getLastErrorAsString(::GetLastError()));
return;
}
//Tell The Service Controller we are starting
ZeroMemory(&serviceStatus, sizeof(serviceStatus));
serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_START_PENDING;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwServiceSpecificExitCode = 0;
serviceStatus.dwCheckPoint = 0;
if(SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE)
{
OutputDebugString("My Sample Service : Service Main : SetSeviceStatus returned error. First (1) If");
FileOperations fo;
fo.printError("My Sample Service : Service Main : SetSeviceStatus returned error");
}
//Preform task necessary to start a service here
//Create a stop event to wait on later
serviceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if(serviceStopEvent == NULL)
{
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_STOP;
serviceStatus.dwWin32ExitCode = GetLastError();
serviceStatus.dwCheckPoint = 1;
if(SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE)
{
OutputDebugString("My Sample Service : ServiceMain : SetServiceStatus returned error. Second (2) If");
FileOperations fo;
fo.printError("My Sample Service : ServiceMain : SetServiceStatus returned error. Second (2) If");
}
return;
}
//Tell Service Controller we are started
serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
serviceStatus.dwCurrentState = SERVICE_RUNNING;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCheckPoint = 0;
if(SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE)
{
OutputDebugString("My Sample Service : ServiceMain : SetServiceStatus returned error. Tell Service Controller we are started");
FileOperations fo;
fo.printError("My Sample Service : ServiceMain : SetServiceStatus returned error. Tell Service Controller we are started");
}
// Start a thread that will perform the main task of the service
HANDLE hThread = CreateThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
// Wait until our worker thread exits signaling that the service needs to stop
WaitForSingleObject(hThread, INFINITE);
//Perform Clean Up
CloseHandle(serviceStopEvent);
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_STOPPED;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCheckPoint = 3;
if(SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE)
{
OutputDebugString("My Sample Service : Service Main : SetSeviceStatus returned error during exiting");
FileOperations fo;
fo.printError("My Sample Service : Service Main : SetSeviceStatus returned error during exiting");
}
return;
}
VOID WINAPI ServiceCtrlHandler(DWORD ctrlCode)
{
switch(ctrlCode)
{
case SERVICE_CONTROL_STOP :
if(serviceStatus.dwCurrentState != SERVICE_RUNNING)
break;
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCheckPoint = 4;
if(SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE)
{
OutputDebugString("My Sample Service: ServiceCtrlHandler: SetServiceStatus returned error");
FileOperations fo;
fo.printError("My Sample Service: ServiceCtrlHandler: SetServiceStatus returned error");
}
SetEvent(serviceStopEvent);
break;
default :
break;
}
}
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
{
while(WaitForSingleObject(serviceStopEvent, 0) != WAIT_OBJECT_0)
{
FileOperations fo;
fo.printLog("Inside Service Thread");
Sleep(1000);
}
}
Common.cpp
#include "Common.hpp"
using namespace std;
bool GlobalVariables::startCapture = false;
void FileOperations::printLog(string str)
{
ofstream of;
of.open("Log.dat", ios::out | ios::app);
this->getDateTime();
of << "[" << DateTime << "]" << "\t\t" << str << endl;
of.close();
}
void FileOperations::printError(string str)
{
ofstream of;
of.open("Error.dat", ios::out | ios::app);
this->getDateTime();
of << "[" << DateTime << "]" << "\t\t" << str << endl;
of.close();
}
void FileOperations::getDateTime(void)
{
time_t now;
tm *dtStruct;
now = time(0);
dtStruct = localtime(&now);
DateTime.clear();
DateTime = to_string(dtStruct->tm_mday) + ":" + to_string(1 + dtStruct->tm_mon) + ":" + to_string(1900 + dtStruct->tm_year) + "\t" +
to_string(1 + dtStruct->tm_hour) + ":" + to_string(1 + dtStruct->tm_min) + ":" + to_string(1 + dtStruct->tm_sec);
}
//Returns the last Win32 error, in string format. Returns an empty string if there is no error.
string FileOperations::getLastErrorAsString(DWORD errorMessageID)
{
if(errorMessageID == 0)
return string("No error message has been recorded"); //No error message has been recorded
LPSTR messageBuffer = nullptr;
size_t size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
string message(messageBuffer, size);
//Free the buffer.
LocalFree(messageBuffer);
return message;
}
Common.hpp
#ifndef COMMON_COMMON_HPP_
#define COMMON_COMMON_HPP_
using namespace std;
#include <ctime>
#include <cerrno>
#include <string>
#include <cstdio>
#include <thread>
#include <fstream>
#include <string>
#include <cstdint>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <cstdbool>
#include <iostream>
#include <windows.h>
//#include <pthread.h>
//#include "CommandList.hpp"
#define RETURN_SUCCESS true
#define RETURN_FAILURE false
class FileOperations
{
public :
void printError(string);
void printLog(string);
string getLastErrorAsString(DWORD);
private :
void getDateTime(void);
string DateTime;
};
class GlobalVariables
{
public :
static bool startCapture;
};
#endif /* COMMON_COMMON_HPP_ */
I used administrative account to install and run the service.
Related
I have created a simple OPC DA client for the C++ COM API in Qt5.
The client connects to the remote server, gets an OPCServer pointer, creates a new OPC group with an ItemMgt interface, and fails when I try to add items to the group.
The error message is: Incorrect function.
As far as I can see, the IUnknown:: QueryInterface works for this pItemMgt, but the ValidateItems, CreateEnumerator and AddItems calls results in the same Incorrect function error. The OPC server is a QMS220Simulator (Quadera).
Any idea what could be the problem?
This is my first attempt to write a DCOM client, so many, many thing could be wrong with this code.
The qms220.h file contains the CLSID for the QMS220Simulator.
The shortest code to reproduce the problem is this:
#include "opcda.h"
#include "qms220.h"
#include <QApplication>
#include <QDebug>
#include <comdef.h>
static void showStatus(const QString &message,HRESULT code);
IOPCServer *pOPCServer = nullptr;
IOPCItemMgt *pItemMgt = nullptr;
OPCHANDLE serverGroupHandle;
bool initializeCOM()
{
HRESULT hr = CoInitializeEx(nullptr,COINIT_APARTMENTTHREADED);
if (FAILED(hr)) {
showStatus("COM initialization failed!",hr);
return false;
}
hr = CoInitializeSecurity(
NULL, //security descriptor
-1, //COM authentication
NULL, //authentication services
NULL, //reserved
RPC_C_AUTHN_LEVEL_DEFAULT, //default authentication
RPC_C_IMP_LEVEL_IMPERSONATE, //default impersonation
NULL, //authentication info
EOAC_NONE, //additional capabilities
NULL //reserved
);
if (hr == RPC_E_TOO_LATE) {
showStatus("RPC initalization is too late, ignoring...",hr);
} else {
if (FAILED(hr)) {
showStatus("CoInitializeSecurity",hr);
return false;
}
}
return true;
}
void deinitializeCOM()
{
CoUninitialize();
}
static const int INTERFACE_COUNT = 1;
bool connectToServer(const QString &address)
{
_bstr_t serverName = address.toStdString().c_str();
COSERVERINFO cs;
memset(&cs,0,sizeof(cs));
cs.pwszName = serverName;
MULTI_QI qi[INTERFACE_COUNT];
memset(qi,0,sizeof(qi));
qi[0].pIID = &IID_IOPCServer;
HRESULT hr = CoCreateInstanceEx(
CLSID_QMG220SIMDA,
NULL,
CLSCTX_SERVER,
&cs,
INTERFACE_COUNT,
qi
);
if (FAILED(hr)) {
showStatus("CoCreateInstanceEx",hr);
return false;
}
pOPCServer = (IOPCServer*)(qi[0].pItf);
return true;
}
void disconnectFromServer()
{
if (pOPCServer != nullptr) {
pOPCServer->Release();
pOPCServer = nullptr;
}
}
void showOPCStatus(const QString &message,HRESULT hr)
{
if (pOPCServer != nullptr) {
LPWSTR buffer = nullptr;
HRESULT hr2 = pOPCServer->GetErrorString(hr,LOCALE_SYSTEM_DEFAULT,&buffer);
if (hr2 != S_OK) {
qDebug() << message << QString(": HRESULT: 0x%1").arg(hr,8,16,QChar('0'));
} else {
qDebug() << message << QString(": ") << QString::fromWCharArray(buffer);
CoTaskMemFree(buffer);
}
} else {
qDebug() << message << QString(": HRESULT: 0x%1").arg(hr,8,16,QChar('0'));
}
}
static const LPCWSTR MIDGROUPNAME = L"mid";
bool createMIDGroup()
{
if (pOPCServer == nullptr) return false;
OPCHANDLE clientGroupHandle = 1;
DWORD revisedUpdateRate;
HRESULT hr = pOPCServer->AddGroup(
MIDGROUPNAME,
FALSE, //active
0, // requestedUpdateRate
clientGroupHandle,
NULL, //timebias
NULL, //percentDeadBand,
LOCALE_SYSTEM_DEFAULT, //lcid
&serverGroupHandle,
&revisedUpdateRate,
IID_IOPCItemMgt,
(LPUNKNOWN *)(&pItemMgt)
);
showOPCStatus("OPCServer::AddGroup",hr);
if (hr != S_OK) return false;
qDebug() << "The server group handle is: " << QString("0x%1").arg(serverGroupHandle,4,16);
qDebug() << "The revised update rate is: " << revisedUpdateRate;
#define ITEM_ID L"Hardware.Modules.Analyser.SI220.SimulationMode"
QString accessPath("");
QString itemId("Hardware.Modules.Analyser.SI220.SimulationMode");
wchar_t accessPathBuffer[1024];
wchar_t itemIdBuffer[1024];
accessPath.toWCharArray(accessPathBuffer);
itemId.toWCharArray(itemIdBuffer);
static const int ITEM_COUNT = 1;
OPCITEMDEF ItemArray[ITEM_COUNT] =
{{
/*szAccessPath*/ accessPathBuffer,
/*szItemID*/ itemIdBuffer,
/*bActive*/ FALSE,
/*hClient*/ 1,
/*dwBlobSize*/ 0,
/*pBlob*/ NULL,
/*vtRequestedDataType*/ VT_UI1,
/*wReserved*/0
}};
OPCITEMRESULT *itemResults = nullptr;
HRESULT *errors = nullptr;
hr = pItemMgt->AddItems(ITEM_COUNT,ItemArray,&itemResults,&errors);
bool failed = false;
if (hr != S_OK) {
failed = true;
}
showOPCStatus("createMidGroup/AddItems ",hr);
for(DWORD k=0;k<ITEM_COUNT;k++) {
showOPCStatus(QString("createMidGroup/AddItems[%1]").arg(k),errors[k]);
if (errors[k] != S_OK) {
failed = true;
}
CoTaskMemFree(itemResults[k].pBlob);
}
CoTaskMemFree(itemResults);
CoTaskMemFree(errors);
return !failed;
}
void removeMIDGroup()
{
if (pOPCServer != nullptr) {
if (pItemMgt != nullptr) {
pItemMgt->Release();
pItemMgt = nullptr;
}
HRESULT hr = pOPCServer->RemoveGroup(serverGroupHandle,false);
if (hr != S_OK) {
showStatus("deleteMIDGroup",hr);
}
}
}
int main(int argc, char *argv[])
{
Q_UNUSED(argc)
Q_UNUSED(argv)
if (!initializeCOM()) return -1;
if (connectToServer(QString("192.168.12.106"))) {
if (createMIDGroup()) {
removeMIDGroup();
}
disconnectFromServer();
}
deinitializeCOM();
return 0;
}
static void showStatus(const QString &message,HRESULT code)
{
_com_error error(code);
qDebug() << message + QString(": " ) + QString::fromWCharArray(error.ErrorMessage());
}
So, according to the Qt documentation: https://doc.qt.io/qt-5/qstring.html#toWCharArray
The toWCharArray creates a NOT NULL CHAR TERMINATED unicode string.
So a bit better usage would be:
int size = itemId.toWCharArray(itemIdBuffer);
itemIdBuffer[size] = L'\0';
And the same for accessPathBuffer.
Probably it's not a really good idea to send an unterminated group name to the OPC server.
The good thing is, that the CreateGroupEnumerator sends back the same unterminated group names as received.
So the problem is not COM nor OPC related, it's just not reading the fine documentation.
I'm using some legacy code to enumerate ports on my machine:
#include <windows.h>
#include <devguid.h>
#include <setupapi.h>
#include <string>
#include <iostream>
#include <assert.h>
bool GetTextProperty( std::string& sProperty,
HDEVINFO dev,
_SP_DEVINFO_DATA* pDeviceInfoData,
DWORD prop )
{
char szBuf[MAX_PATH];
DWORD iPropertySize = 0;
if (SetupDiGetDeviceRegistryProperty(dev, pDeviceInfoData,
prop, 0L, (PBYTE) szBuf, MAX_PATH, &iPropertySize))
{
sProperty = szBuf;
assert( iPropertySize >= sProperty.size() + 1 );
return true;
}
return false;
}
inline bool readRegistryKeyValue( HKEY hKey, const std::string& key, std::string& value )
{
bool res = false;
CHAR szBuffer[512];
DWORD dwBufferSize = sizeof(szBuffer);
ULONG nError = RegQueryValueEx(hKey, key.c_str(), 0, NULL, (LPBYTE)szBuffer, &dwBufferSize);
if (ERROR_SUCCESS == nError)
{
value = szBuffer;
res = true;
}
return res;
}
void ListPorts()
{
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
DWORD i;
hDevInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS, 0L, 0L, DIGCF_PRESENT);
if ( hDevInfo == INVALID_HANDLE_VALUE )
{
//Medoc_ReportError(MEDOC_ERROR_HARDWARE_DRIVER_API_FAILED,
// &hDevInfo, sizeof hDevInfo);
assert( false );
}
else
{
// Enumerate through all devices in Set.
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData) != 0; i++)
{
char szBuf[MAX_PATH];
short wImageIdx = 0;
short wItem = 0;
DWORD iPropertySize;
if (SetupDiGetDeviceRegistryProperty(hDevInfo, &DeviceInfoData,
SPDRP_FRIENDLYNAME, 0L, (PBYTE) szBuf, MAX_PATH, &iPropertySize))
{
std::cout << "Smart name: " << szBuf << std::endl;
HKEY hKey = SetupDiOpenDevRegKey(
hDevInfo,
&DeviceInfoData,
DICS_FLAG_GLOBAL,
0,
DIREG_DEV,
KEY_READ );
if ( hKey )
{
std::string portName;
readRegistryKeyValue( hKey, "PortName", portName );
std::cout << "Port name: " << szBuf << std::endl;
for ( DWORD prop = 0; prop != SPDRP_MAXIMUM_PROPERTY; ++prop )
{
std::string temp;
GetTextProperty( temp, hDevInfo, &DeviceInfoData, prop );
std::cout << prop << " : " << temp << std::endl;
}
RegCloseKey(hKey);
}
}
}
}
// Cleanup
SetupDiDestroyDeviceInfoList(hDevInfo);
}
int main( int argc, char* argv[] )
{
ListPorts();
return 0;
}
Among other information, this gives me access to port name (COM*), type (FTDI for instance), VID and PID...
However, when I have many different devices based on a FTDI chip plugged, they all have the same information (SPDRP_HARDWAREID prperty reports FTDIBUS\COMPORT&VID_0403&PID_6015 or FTDIBUS\COMPORT&VID_0403&PID_6010). So I cannot discriminate who is who.
When I use a USB sniffer ("Device Monitoring Studio"), this one is able to report more relevant information withoutestablishing any connection to the ports:
Can this kind of extended information be accessed through Windows API to discriminate by name many devices using the same FTDI chip? Or must I use FTDI driver API to achieve this?
With the help of Ben Voigt and Simon Mourier, I could achieve this, here is the piece of code:
// More includes:
#include <initguid.h>
#include <devpkey.h>
#include <cfgmgr32.h>
// A new dependency:
#pragma comment (lib, "Cfgmgr32.lib")
bool GetDeviceProperty( const std::string& what,
DEVINST dev,
DEVPROPKEY prop )
{
char szDeviceBuf[MAX_PATH];
DEVPROPTYPE type;
ULONG iDevicePropertySize = MAX_PATH;
if ( CM_Get_DevNode_PropertyW(dev,
&prop,
&type,
(PBYTE) szDeviceBuf,
&iDevicePropertySize,
0) == CR_SUCCESS )
{
wchar_t* txt = (wchar_t*) szDeviceBuf;
std::wstring ws(txt);
std::cout << what << " : " << std::string(ws.begin(), ws.end()) << std::endl;
return true;
}
else
{
return false;
}
}
void ListPorts()
{
...
DEVINST devInstParent;
auto status = CM_Get_Parent(&devInstParent, DeviceInfoData.DevInst, 0);
if (status == CR_SUCCESS)
{
ShowDeviceProperty( "Bus reported device description", devInstParent, DEVPKEY_Device_BusReportedDeviceDesc );
ShowDeviceProperty( "Device description", devInstParent, DEVPKEY_Device_DeviceDesc );
}
else
{
continue;
}
...
I'm writing a program in Code::Blocks that would simply print application's process ID and base address. The PID is found correctly but I'm having difficulties with base address also I'm using GNU GCC Compiler (x64). My guess is that the error lies in HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId); because it returns INVALID_HANDLE_VALUE. But still I can't resolve this problem. The IDE doesn't show any error or warnings. GetLastError() returns 5 (Access Denied)
Console output:
Process ID = 2656
INVALID_HANDLE_VALUE returned
BaseAddr = 0
And this is full code:
#include <iostream>
#include <Windows.h>
#include <tlhelp32.h>
#include <string.h>
DWORD GetProcId(const char* procName)
{
DWORD procId = 0;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 procEntry;
procEntry.dwSize = sizeof(procEntry);
if (Process32First(hSnap, &procEntry))
{
do
{
if (lstrcmpi(procEntry.szExeFile, procName) == 0) {
procId = procEntry.th32ProcessID;
break;
}
} while (Process32Next(hSnap, &procEntry));
}
}
CloseHandle(hSnap);
return procId;
}
uintptr_t GetModuleBaseAddress(DWORD procId, const char* modName)
{
uintptr_t modBaseAddr = 0;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId);
if (hSnap != INVALID_HANDLE_VALUE)
{
MODULEENTRY32 modEntry;
modEntry.dwSize = sizeof(modEntry);
if (Module32First(hSnap, &modEntry))
{
do
{
if (!_stricmp(modEntry.szModule, modName))
{
modBaseAddr = (uintptr_t)modEntry.modBaseAddr;
break;
}
} while (Module32Next(hSnap, &modEntry));
}
} else {
std::cout << "INVALID_HANDLE_VALUE returned" << std::endl;
}
CloseHandle(hSnap);
return modBaseAddr;
}
int main()
{
DWORD procId = GetProcId("Game.exe");
std::cout << "Process ID = " << procId << std::endl;
uintptr_t baseAddr = GetModuleBaseAddress(procId, "Game.exe");
std::cout << "BaseAddr = " << baseAddr << std::endl;
std::getchar();
return 0;
}
Well after putting it to Code Blocks, i just changed the _stricmp in the GetModuleBaseAddress function to strcmp also this line
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId);
to this
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, procId);
Try this code:
#include <windows.h>
#include <tlhelp32.h>
#include <string>
#include <iostream>
using namespace std;
HANDLE _process = NULL;
DWORD pid = 0;
DWORD baseAddr = 0;
bool getID(string process)
{
HANDLE hHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
PROCESSENTRY32 entry;
entry.dwSize = sizeof(entry);
do
{
if(!strcmp(entry.szExeFile,process.c_str()))
{
pid = entry.th32ProcessID;
CloseHandle(hHandle);
_process = OpenProcess(PROCESS_ALL_ACCESS,false,pid);
return true;
}
} while(Process32Next(hHandle,&entry));
return false;
}
bool getModuleBaseAddress(string module)
{
HANDLE hHandle = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,pid);
MODULEENTRY32 mentry;
mentry.dwSize = sizeof(mentry);
do
{
if(!strcmp(mentry.szModule,module.c_str()))
{
CloseHandle(hHandle);
baseAddr = (DWORD)mentry.modBaseAddr;
return true;
}
} while(Module32Next(hHandle,&mentry));
return false;
}
int main()
{
while(!getID("popo.exe")) {Sleep(10);}
while(!getModuleBaseAddress("popo.exe")) {Sleep(10);}
cout << "PID: " << pid << endl << "Base Address: " << baseAddr;
return 0;
}
I'm trying to work with Bluetooth LE devices using Windows GATT API in Windows 10. But I never detect any devices. Running this code always returns ERROR_NO_MORE_ITEMS. I've tried with a Windows laptop with built in Bluetooth 4.0 as well as a USB bluetooth dongle. I see the Bluetooth LE Enumerator in the Device Manager, and the driver shows as installed and working.
Note: I'm trying to build a .dll so I don't want to use UWP.
#include <vector>
#include <cstdio>
#include <iostream>
#include <windows.h>
#include <SetupAPI.h>
#include <Bluetoothleapis.h>
bool enumDevices() {
HDEVINFO handle = INVALID_HANDLE_VALUE;
GUID BluetoothClassGUID = GUID_BLUETOOTHLE_DEVICE_INTERFACE;
handle = SetupDiGetClassDevs(
&BluetoothClassGUID,
NULL,
NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (handle == INVALID_HANDLE_VALUE) {
std::wcout << " No Device class" << std::endl;
return FALSE;
}
GUID BluetoothInterfaceGUID = GUID_BLUETOOTHLE_DEVICE_INTERFACE;
std::vector<SP_DEVICE_INTERFACE_DATA> ble_interfaces;
std::vector<std::wstring> ble_paths;
// Enumerate device of LE_DEVICE interface class
for (int i = 0;; i++) {
std::string error;
SP_DEVICE_INTERFACE_DATA device_interface_data = { 0 };
device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
BOOL success = SetupDiEnumDeviceInterfaces(
handle,
NULL,
(LPGUID)&BluetoothInterfaceGUID,
(DWORD)i,
&device_interface_data);
if (!success) {
DWORD last_error = GetLastError();
if (last_error == ERROR_NO_MORE_ITEMS) {
std::wcout << " No more devices found" << std::endl;
break;
}
else {
std::wcout << " Error enumerating device interfaces: " << last_error;
return FALSE;
}
}
// Retrieve required # of bytes for interface details
ULONG required_length = 0;
success = SetupDiGetDeviceInterfaceDetail(
handle,
&device_interface_data,
NULL,
0,
&required_length,
NULL);
if (!success) {
DWORD last_error = GetLastError();
return FALSE;
}
UINT8* interface_data = new UINT8[required_length];
memset(interface_data, 0, required_length);
PSP_DEVICE_INTERFACE_DETAIL_DATA device_interface_detail_data = reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(interface_data);
device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
SP_DEVINFO_DATA device_info_data = { 0 };
device_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
ULONG actual_length = required_length;
success = SetupDiGetDeviceInterfaceDetail(
handle,
&device_interface_data,
device_interface_detail_data,
actual_length,
&required_length,
&device_info_data);
//Store data
std::wstring strpath = std::wstring(device_interface_detail_data->DevicePath);
OLECHAR* bstrGuid;
StringFromCLSID(device_interface_data.InterfaceClassGuid, &bstrGuid);
std::wcout << " Path: " << strpath << " GUID:" << bstrGuid << std::endl;
ble_paths.push_back(strpath);
ble_interfaces.push_back(device_interface_data);
}
}
int main() {
enumDevices();
}
I have to read some Registry Value as soon as the program starts. The Code does works correctly and gives the Registry Value I seek, if the code is compiled and run from Command prompt. But If I create the service and attach the exe to the service using following code:
sc create someservice start=auto binpath= "PATH to EXE of Code"
and run the service I don't get the desired value. I have attached the complete code. I have logged the result of each step also.
#include <Windows.h>
#include <iostream>
#include <string>
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;
int WriteToLog(const char *);
std::string GetLPInstalledPath();
std::string GetLPInstalledPath()
{
HKEY hKey;
char buf[255];
DWORD dwType;
DWORD dwBufSize = sizeof(buf);
std::string ss="";
const char* subkey = "Software\\\\Logpoint\\\\InstalledPath";
WriteToLog(" Inside GetLPInstalledPath") ;
if( RegOpenKey(HKEY_CURRENT_USER,subkey,&hKey) == ERROR_SUCCESS)
{
WriteToLog("Opened the Registry Key");
dwType = REG_SZ;
if( RegQueryValueEx(hKey,"path",0, &dwType, (BYTE*)buf, &dwBufSize) == ERROR_SUCCESS)
{
ss = buf;
WriteToLog(ss.c_str());
}
else
{
WriteToLog(" Cound not find the value");
}
RegCloseKey(hKey);
}
else
{
WriteToLog(" Cannot Open the Installed Registry Path");
}
return ss;
}
int WriteToLog(const char* str)
{
//const char *logfile = "D:\\ubuntu_share\\lpa\\lpa_c\\build_win\\src\\lpa\\sample.txt";
FILE* log;
log = fopen("C:\\lpa\\sample.txt", "a+");
if (log == NULL)
return -1;
fprintf(log, "%s\n", str);
fclose(log);
return 0;
}
int Run()
{
WriteToLog("Run");
WriteToLog("entering infinite loop of main thread ");
while(1);
WriteToLog("end of main thread ");
return 0;
}
void ControlHandler(DWORD request)
{
//LOG4CPLUS_INFO(root, "ControlHandler: Entry";
switch(request)
{
case SERVICE_CONTROL_STOP:
//WriteToLog("Monitoring stopped.");
WriteToLog( "ControlHandler: SERVICE_CONTROL_STOP Request");
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
if(SetServiceStatus (hStatus, &ServiceStatus)==FALSE)
{
WriteToLog("ServiceCtrlHandler: SetServiceStatus returned error");
}
return;
case SERVICE_CONTROL_SHUTDOWN:
// WriteToLog("Monitoring shutdown.");
WriteToLog("ControlHandler: SERVICE_CONTROL_SHUTDOWN Request");
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
if(SetServiceStatus (hStatus, &ServiceStatus) == FALSE)
{
WriteToLog("ServiceCtrlHandler: SetServiceStatus returned error");
}
return;
case SERVICE_CONTROL_INTERROGATE:
return;
default:
WriteToLog("ServiceCtrlHandler");
break;
}
// Report current status
SetServiceStatus (hStatus, &ServiceStatus);
WriteToLog("ServiceCtrlHandler: Exit");
return;
}
void ServiceMain(int argc, char** argv)
{
//WriteToLog("at ServiceMain");
WriteToLog("ServiceMain");
int error;
ServiceStatus.dwServiceType = SERVICE_WIN32;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
hStatus = RegisterServiceCtrlHandler(
"MemoryStatus",
(LPHANDLER_FUNCTION)ControlHandler);
if (hStatus == NULL)
{
// Registering Control Handler failed
WriteToLog("ServiceMain: RegisterServiceCtrlHandler returned error");
return;
}
// We report the running status to SCM.
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
if(SetServiceStatus (hStatus, &ServiceStatus)==FALSE)
{
WriteToLog("ServiceMain: SetServiceStatus returned error");
}
WriteToLog("ServiceMain: Performing Service Start Operations");
Run();
WriteToLog("ServiceMain: Performing Cleanup Operations");
ServiceStatus.dwControlsAccepted = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCheckPoint = 3;
if (SetServiceStatus (hStatus, &ServiceStatus) == FALSE)
{
WriteToLog("ServiceMain: SetServiceStatus returned error");
}
WriteToLog("ServiceMain: Exit");
return;
}
int StartLpaService()
{
SERVICE_TABLE_ENTRY ServiceTable[2];
ServiceTable[0].lpServiceName = "MemoryStatus";
ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
ServiceTable[1].lpServiceName = NULL;
ServiceTable[1].lpServiceProc = NULL;
// Start the control dispatcher thread for our service
if(StartServiceCtrlDispatcher(ServiceTable) == FALSE)
{
WriteToLog("StartLpaService: StartServiceCtrlDispatcher returned error");
return GetLastError ();
}
WriteToLog("Main: Exit");
return 0;
}
int main(int argc, char **argv)
{
std::string pa = GetLPInstalledPath();
#ifdef SERVICE_DEBUG
WriteToLog("SERVICE_DEBUG");
Sleep(15000);
#endif
StartLpaService();
return 0;
}
The problem I am facing is that if the service of the program is started, no Registry value is written, but running directly from command prompt is giving the value. How do I solve this Issue?
You are looking in HKCU, the registry hive for the current user. So the most plausible explanation for what you describe is simply that the service is running under a different user. That is the service runs under a user account other than the interactive user.