Access user data associated with event provided using TraceLoggingWrite - c++

I am able to generate tracelogging events from my application(able to view them in Windows Performance Analyzer) using this method.
The event emitted is as follows
HRESULT CTracelogger::PublishEvent(void *pData)
{
if (pData)
{
EVENT_H sHEvent = *(static_cast<EVENT_H *>(pData));
TraceLoggingWrite(g_hEventProvider,
"HEvent",
TraceLoggingStruct(5, "HEventData"),
TraceLoggingUInt32(sHEvent.m_eEventType, "eEventType"),
TraceLoggingUInt32(sHEvent.m_uiVersion, "Version"),
TraceLoggingUInt32(sHEvent.m_uiPid, "Pid"),
TraceLoggingUInt32(sHEvent.m_uiSize, "Size"),
TraceLoggingWideString(sHEvent.m_wszHName, "HName")
);
}
return S_OK;
}
I am trying to consume the same events in a different application by writing a custom consumer, the consumer is receiving the events(as the corresponding provider GUID events are being received). I am trying to access the user data associated with the event using TdhGetProperty() as shown in documentation here but the function TdhGetEventInformation() is failing with ERROR_NOT_FOUND if the variable buffersize is initialized to 0 and fails with error ERROR_INVALID_PARAMETER if buffersize is initialized to a non-zero value.
Is the above approach taken correct to retrieve the data associated with the tracelogging event?
If yes, then why TdhGetEventInformation() is failing?
VOID WINAPI CEventLogger::EventRecordCallback(PEVENT_RECORD pEvent)
{
DWORD status = ERROR_SUCCESS;
PTRACE_EVENT_INFO pInfo = NULL;
char msgbuf[4096];
DWORD BufferSize = 0;
status = TdhGetEventInformation(pEvent, 0, nullptr, pInfo, &BufferSize);
if (ERROR_INSUFFICIENT_BUFFER == status)
{
pInfo = (TRACE_EVENT_INFO*)malloc(BufferSize);
if (pInfo == NULL)
{
OutputDebugString("Failed to allocate memory for event info");
status = ERROR_OUTOFMEMORY;
return;
}
else
{
OutputDebugString("successful memory allocation");
}
// Retrieve the event metadata.
status = TdhGetEventInformation(pEvent, 0, nullptr, pInfo, &BufferSize);
}
if (ERROR_SUCCESS != status)
{
sprintf_s(msgbuf, "TdhGetEventInformation failed status[%d], buffersize[%d]", status, BufferSize);
OutputDebugString(msgbuf);
}
else
{
sprintf_s(msgbuf, "TdhGetEventInformation successful, buffersize[%d]", BufferSize);
OutputDebugString(msgbuf);
}
}

The code above looks reasonable. My guess is that the problem is with your call to OpenTrace. By default (for backwards-compatibility with very old code), OpenTrace assumes that your callback wants to receive an EVENT_TRACE structure. However, your callback wants to receive an EVENT_RECORD. To tell OpenTrace to use the newer EVENT_RECORD format, you have to set ProcessTraceMode to PROCESS_TRACE_MODE_EVENT_RECORD.

Related

How Do I Use NotifyServiceStatusChange to Get Notified When a Service Is Deleted?

How can I use NotifyServiceStatusChange properly so I can get notified when the service specified is deleted? My current code successfully stops the service and marks it for deletion. However, I want to be notified when the service is fully deleted.
Here are the main points of my code:
SC_HANDLE SCManager = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE,
SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);
HANDLE EventHandle = CreateEventW(NULL, TRUE, FALSE, NULL);
SERVICE_NOTIFY ServiceNotify;
ServiceNotify.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;
ServiceNotify.pszServiceNames = ServiceName;
ServiceNotify.pContext = &EventHandle;
ServiceNotify.pfnNotifyCallback = (PFN_SC_NOTIFY_CALLBACK)CallbackFunction;
DWORD status = NotifyServiceStatusChangeW(SCManager, SERVICE_NOTIFY_DELETED, &ServiceNotify);
WaitForSingleObject(EventHandle, INFINITE);
CloseServiceHandle(SCManager);
CloseHandle(EventHandle);
(ServiceName is WCHAR*)
CallbackFunction code:
VOID CALLBACK CallbackFunction(IN PVOID pParameter) {
SERVICE_NOTIFY* ServiceNotify = pParameter;
HANDLE EventHandle = *(HANDLE*)ServiceNotify->pContext;
SetEvent(EventHandle);
}
NotifyServiceStatusChange is returning ERROR_SUCCESS (0). However, my callback function is not being called at all. How can I fix this?
Edit:
Here is minimal reproducible code:
void ErrorExit(char* FunctionName, unsigned long ErrorCode) {
char* ErrorMessage;
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, ErrorCode, LANG_USER_DEFAULT, (LPTSTR)&ErrorMessage, 0, NULL);
int MessageSize = (strlen(ErrorMessage) + strlen(FunctionName) + 50) * sizeof(char);
char* FullMessage = malloc(MessageSize);
sprintf_s(FullMessage, MessageSize, "%s failed with error %d: %s", FunctionName, ErrorCode, ErrorMessage);
MessageBoxA(NULL, FullMessage, "Error", MB_OK);
ExitProcess(ErrorCode);
}
PFN_SC_NOTIFY_CALLBACK CallbackFunction(PVOID pParameter) {
printf("CallbackFunction has been called.\r\n");
SERVICE_NOTIFY* ServiceNotify = pParameter;
HANDLE EventHandle = ServiceNotify->pContext;
if (!SetEvent(EventHandle)) {
ErrorExit("SetEvent", GetLastError());
}
}
int main()
{
WCHAR* ServiceName = L"SERVICE NAME"; // Input service name here
SC_HANDLE SCManager = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
if (!SCManager) {
ErrorExit("OpenSCManagerW", GetLastError());
}
SC_HANDLE ServiceHandle = OpenServiceW(SCManager, ServiceName,
SERVICE_ENUMERATE_DEPENDENTS | SERVICE_STOP | DELETE);
if (!ServiceHandle) {
ErrorExit("ServiceHandle", GetLastError());
}
if (!DeleteService(ServiceHandle)) {
ErrorExit("DeleteService", GetLastError());
}
if (!CloseServiceHandle(ServiceHandle)) {
ErrorExit("CloseServiceHandle", GetLastError());
}
HANDLE EventHandle = CreateEventW(NULL, TRUE, FALSE, NULL);
if (!EventHandle) {
ErrorExit("CreateEventW", GetLastError());
}
SERVICE_NOTIFY ServiceNotify;
ServiceNotify.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;
ServiceNotify.pszServiceNames = ServiceName;
ServiceNotify.pContext = EventHandle;
ServiceNotify.pfnNotifyCallback = CallbackFunction;
DWORD status = NotifyServiceStatusChangeW(SCManager, SERVICE_NOTIFY_DELETED, &ServiceNotify);
if (status != ERROR_SUCCESS) {
ErrorExit("NotifyServiceStatusChangeW", GetLastError());
}
status = WaitForSingleObjectEx(EventHandle, INFINITE, TRUE);
if (status == WAIT_FAILED) {
ErrorExit("WaitForSingleObjectEx", GetLastError());
}
printf("WaitForSingleObjectEx Result: %lu\r\n", status);
system("pause");
return 0;
}
When I run this, no other service depends on the service being deleted, and the service being deleted is already stopped. My error handling function "ErrorExit" is never called. Nothing is printed on the screen. My program simply pauses, which I assume is from WaitForSingleObjectEx.
I know the service is being deleted because I have ProcessHacker open, and it is giving me notifications that the service is being deleted.
NotifyServiceStatusChange is returning ERROR_SUCCESS (0). However, my callback function is not being called at all.
The NotifyServiceStatusChangeW documentation says:
When the service status changes, the system invokes the specified callback function as an asynchronous procedure call (APC) queued to the calling thread. The calling thread must enter an alertable wait (for example, by calling the SleepEx function) to receive notification. For more information, see Asynchronous Procedure Calls.
So, make sure you are actually processing APC notifications while you wait. WaitForSingleObject() will not do that for you.
Use WaitForSingleObjectEx() instead. It has a bAlertable parameter you can set to TRUE. You will have to call it in a loop, since it will return when any APC call is processed by the calling thread, which may not be the one you are expecting.
You also need to call NotifyServiceStatusChangeW() in a loop, too. The documentation does not mention this, but the callback will be called only 1 time per use. Once the callback is called, you need to call NotifyServiceStatusChangeW() again to receive another notification if the current one is not the event you are expecting.
With that said, try something more like this:
struct MyCallbackInfo {
HANDLE EventHandle;
LPCWSTR pszServiceName;
bool bDeleted;
};
...
VOID CALLBACK CallbackFunction(PVOID pParameter) {
SERVICE_NOTIFYW* ServiceNotify = (SERVICE_NOTIFYW*) pParameter;
MyCallbackInfo *ci = (MyCallbackInfo*) ServiceNotify->pContext;
if (ServiceNotify->dwNotificationStatus == ERROR_SUCCESS) {
LPWSTR pServiceName = ServiceNotify->pszServiceNames;
while (*pServiceName != L'\0') {
if (lstrcmpW(pServiceName, ci->pszServiceName) == 0) {
ci.bDeleted = true;
break;
}
pServiceName += (lstrlenW(pServiceName) + 1);
}
LocalFree(ServiceNotify->pszServiceNames);
}
SetEvent(ci->EventHandle);
}
...
MyCallbackInfo ci;
ci.EventHandle = CreateEventW(NULL, TRUE, FALSE, NULL);
ci.pszServiceName = ServiceName;
ci.bDeleted = false;
if (!ci.EventHandle) {
// error handling...
}
SC_HANDLE SCManager = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE,
SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);
if (!SCManager) {
// error handling...
}
SERVICE_NOTIFYW ServiceNotify = {};
ServiceNotify.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;
ServiceNotify.pContext = &ci;
ServiceNotify.pfnNotifyCallback = CallbackFunction;
DWORD status;
do {
status = NotifyServiceStatusChangeW(SCManager, SERVICE_NOTIFY_DELETED, &ServiceNotify);
if (status != ERROR_SUCCESS) {
// error handling...
}
while ((status = WaitForSingleObjectEx(ci.EventHandle, INFINITE, TRUE)) == WAIT_IO_COMPLETION);
if (status == WAIT_FAILED) {
// error handling...
}
if (ci.bDeleted) {
// service has been deleted ...
break;
}
ResetEvent(ci.EventHandle);
}
while (true);
CloseServiceHandle(SCManager);
CloseHandle(ci.EventHandle);

TdhGetEventInformation return 1168 (NOT FOUND) - How PerfView can get the info?

I have a ETL file and I am trying to parse it with OpenTrace and get the information with TdhGetEventInformation when I get the callback EventRecordCallback.
However, for the provider that I need, it always return 1168 (NOT FOUND). The only way it works is by loading the manifest with TdhLoadManifest, this way I get all the information. But I don't understand how WPA and PerfView can get all the events for my provider even when I am not providing the manifest...
I found that the TDH.dll has some undocumented functions that PerfView uses like TdhGetAllEventsInformation, I tried to use this function by loading the DLL with LoadLibraryEx, the function again return 1168..
Following code is mostly by Microsoft samples:
DWORD status = ERROR_SUCCESS;
DWORD BufferSize = 0;
status = TdhGetEventInformation(pEvent, 0, nullptr, pInfo, &BufferSize);
if (1168 == status)
return status; // THIS
if (ERROR_INSUFFICIENT_BUFFER == status)
{
pInfo = (TRACE_EVENT_INFO*)malloc(BufferSize);
ZeroMemory(pInfo, BufferSize);
if (pInfo == NULL)
{
LogPrintError(L"Failed to allocate memory for event info (size=%lu).\n", BufferSize);
status = ERROR_OUTOFMEMORY;
goto cleanup;
}
// Retrieve the event metadata.
status = TdhGetEventInformation(pEvent, 0, NULL, pInfo, &BufferSize);
}
I really want to know how PerfView get this information without the manifest. So far I see they use TdhGetAllEventsInformation but I keep receiving 1168, I am missing something?
Thanks.

Retrieving info from multiple sensors using Windows Sensor API

I am using the Windows Sensor API to get info from various sensors including accelerometer and gyroscope. (https://learn.microsoft.com/en-us/windows/desktop/sensorsapi/sensor-api-programming-guide)
My initial implementation of sensor driver for accelerometer worked - I asynchronously can get the values for that sensor.
The working initialization code for a single sensor (accelerometer) looks like the following:
void initialize1(AccelerometerCallBack callBack) {
HRESULT hr = S_OK;
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
ISensorManager* pSensorManager = NULL;
ISensorCollection* pSensorColl = NULL;
ISensor* accelerometer = NULL;
hr = CoCreateInstance(CLSID_SensorManager,
NULL, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&pSensorManager));
if (SUCCEEDED(hr))
{
printf("Succeeded getting Sensor...\n");
ULONG ulCount = 0;
// Verify that the collection contains
// at least one sensor.
hr = pSensorColl->GetCount(&ulCount);
if (SUCCEEDED(hr))
{
if (ulCount < 1)
{
wprintf_s(L"\nNo sensors of the requested category.\n");
hr = E_UNEXPECTED;
}
}
}
else {
printf("Failed to get Sensor...\n");
}
if (SUCCEEDED(hr))
{
// Get the first available sensor.
hr = pSensorColl->GetAt(0, &accelerometer);
BSTR name = 0;
hr = accelerometer->GetFriendlyName(&name);
wprintf(L"%s\n", name);
}
AccelerometerEvent* pEventClass = NULL;
ISensorEvents* pMyEvents = NULL;
if (SUCCEEDED(hr))
{
// Create an instance of the event class.
pEventClass = new(std::nothrow) AccelerometerEvent();
pEventClass->globalCallBack = callBack;
}
if (SUCCEEDED(hr))
{
// Retrieve the pointer to the callback interface.
hr = pEventClass->QueryInterface(IID_PPV_ARGS(&pMyEvents));
}
if (SUCCEEDED(hr))
{
// Start receiving events.
hr = accelerometer->SetEventSink(pMyEvents);
}
MSG msg;
BOOL bRet;
while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
Now I wanted to simultaneously get the gyroscope, so I add a similar initialization code:
void initialize2(GyroscopeCallBack callBack);, which does similar thing as above.
Now my C# layer triggers those code like this:
internal void Start()
{
AccelerometerCallBack myCallBack1 = new AccelerometerCallBack(onAccelerometerDataChanged);
initialize1(myCallBack1);
GyroscopeCallBack myCallBack2 = new GyroscopeCallBack(onGyroscopeDataChanged);
initialize2(myCallBack2);
}
However, only the accelerometer info is received through the callback, not the gyroscope's.
I have confirmed that my device has both sensors of the correct type
I have confirmed that my callback functions and C# to C++ interface all works properly
What is the correct way to "fetch" multiple sensors (instead of one) using the Windows Sensor API?
There are no examples on the official website about doing this, and the only related SO post (Exposing multiple sensors on a single device to Windows Sensor API) does not help. Thanks!
It worked! Solution was to remove the message pump and use COINIT_MULTITHREADED option for Coinitializine(). Thanks for all the help.

Not able to set audit object access in Local Security Policy using c++

I'm using the following code to enable audit object access for success, failure in Local security policy.
bool EnableObjectAccessPolicy()
{
NTSTATUS ntsResult;
LSA_HANDLE PolicyHandle = GetPolicyHandle();
DebugLogMessage("\n%x",PolicyHandle);
PPOLICY_AUDIT_EVENTS_INFO ppPAUDInfo = NULL;
ntsResult = LsaQueryInformationPolicy(PolicyHandle,PolicyAuditEventsInformation,(PVOID *)&ppPAUDInfo);
DebugLogMessage("\n-----%x",ntsResult);
if(ntsResult != STATUS_SUCCESS)
{
DebugLogMessage("LsaSetInformationPolicy returned %lu\n ntstatus %04x",LsaNtStatusToWinError(ntsResult),ntsResult);
LsaFreeMemory(PolicyHandle);
return FALSE;
}
DebugLogMessage("\nMaxCount is %d",ppPAUDInfo->MaximumAuditEventCount);
DebugLogMessage("\nEventAuditingOptions at 0 is %d",ppPAUDInfo->EventAuditingOptions[0]);
if(ppPAUDInfo->EventAuditingOptions[2] != 3)
{
DebugLogMessage("\nNot equal to 3");
ppPAUDInfo->EventAuditingOptions[2] = 3;
ntsResult = LsaSetInformationPolicy(PolicyHandle,PolicyAuditEventsInformation,ppPAUDInfo);
printf("ntstatus is %04x",ntsResult);
if(ntsResult != STATUS_SUCCESS)
{
DebugLogMessage("LsaSetInformationPolicy returned %lu\n ntstatus %04x",LsaNtStatusToWinError(ntsResult),ntsResult);
LsaFreeMemory(PolicyHandle);
return FALSE;
}
}
LsaClose(PolicyHandle);
return TRUE;
}
LSA_HANDLE GetPolicyHandle()
{
LSA_OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS ntsResult;
LSA_HANDLE lsahPolicyHandle;
// Object attributes are reserved, so initialize to zeros.
ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
// Get a handle to the Policy object.
ntsResult = LsaOpenPolicy(
NULL, //Name of the target system. &lusSystemName,
&ObjectAttributes, //Object attributes.
POLICY_VIEW_LOCAL_INFORMATION | GENERIC_READ | GENERIC_EXECUTE | POLICY_ALL_ACCESS, //Desired access permissions.
&lsahPolicyHandle //Receives the policy handle.
);
DebugLogMessage("\nOpenPolicy returned %x\n",LsaNtStatusToWinError(ntsResult));
if (ntsResult != STATUS_SUCCESS)
{
// An error occurred. Display it as a win32 error code.
DebugLogMessage("\nOpenPolicy returned %lu\n",LsaNtStatusToWinError(ntsResult));
return NULL;
}
DebugLogMessage("Policy Handle is \n%x",lsahPolicyHandle);
return lsahPolicyHandle;
}
the above code works perfectly when i make standalone exe and test. But as soon as i integrate the above code with my main project ppPAUDInfo->MaximumAuditEventCount gives a six digit count which should be 9. And my main project process quits as soon as i try to access ppPAUDInfo->EventAuditingOptions[index].

ReadDirectoryChangesW issues

I'am using ReadDirectoryChangesW to watch a directory changes asynchronously, based on this question I implement a function that watch a given directory, but I still get the error message GetQueuedCompletionStatus(): Timeout
void Filewatcher::OpenWatchDir(QString PathToOpen)
{
QString path=QDir::fromNativeSeparators(PathToOpen);
LPCTSTR Dirname=(LPCTSTR)path.utf16();//.toStdWString().c_str();
dirinfo_t* d =(dirinfo_t*) malloc(1*sizeof(dirinfo_t));
d->CompletionKey = (ULONG_PTR)&somekey;
dirinfo_init(d);
/* set up */
runthread = TRUE;
d->hDirFH = CreateFile(Dirname,
FILE_LIST_DIRECTORY,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
NULL);
d->hDirOPPort = CreateIoCompletionPort(d->hDirFH, NULL,
(ULONG_PTR)d->CompletionKey, 1);
DWORD errorcode = 0; // an error code
BOOL bResultQ = FALSE; // obvios=us
BOOL bResultR = FALSE;
DWORD NumBytes = 0;
FILE_NOTIFY_INFORMATION* pInfo = NULL; // the data incoming is a pointer
// to this struct.
int i = 0;
while ( runthread )
{
bResultR = ReadDirectoryChangesW(d->hDirFH, (void*)d->buffer,
16777216, TRUE,
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION ,
NULL,
&d->o->overlapped,
NULL );
bResultQ = GetQueuedCompletionStatus(d->hDirOPPort,
&NumBytes, &(d->CompletionKey),
(LPOVERLAPPED*)(d->o), 1000);
if ( bResultQ && bResultR )
{
wprintf(L"\n");
pInfo = (FILE_NOTIFY_INFORMATION*) d->buffer;
wprintf(L"File %s", pInfo->FileName);
wprintf(L" changes %d\n", pInfo->Action);
qDebug()<<"file "<<pInfo->FileName<<" was"<<pInfo->Action;
memset(d->buffer, 0, 16777216);
}
else
{
errorcode = GetLastError();
if ( errorcode == WAIT_TIMEOUT )
{
qDebug()<<"GetQueuedCompletionStatus(): Timeout\n";
}
else
{
qDebug()<<"GetQueuedCompletionStatus(): Failed\n";
qDebug()<<"Error Code "<<errorcode;
}
Sleep(500);
}
}
}
I need to know how use ReadDirectoryChangesW asynchronously with IoCompletionPort.
Any help please.
There's no reason to use a completion port here, simple overlapped I/O with an event will work fabulously.
The key is to wait for this operation (whether event or completion port) at the same time as all other events (possibly including GUI messages), and only check the status when the event becomes signaled. For that, use (Msg)WaitForMultipleObjects(Ex).
In Qt, you can add Win32 events (used by OVERLAPPED structure for async I/O) using QWinEventNotifier as described here:
http://www.downtowndougbrown.com/2010/07/adding-windows-event-objects-to-a-qt-event-loop/
thank you guys for your answers, after a deep research and retesting code I solve my problem based on this , I really appreciate your help.