How to enable ImageId provider when using ETW programmatically?

Jingzhou Zhang 20 Reputation points
2025-12-02T08:44:35.12+00:00

Hi, I have a C++ program that uses ETW API and its code is as follows:

#define INITGUID  // Include this #define to use SystemTraceControlGuid in Evntrace.h.
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <strsafe.h>
#include <wmistr.h>
#include <evntrace.h>
#include <evntprov.h>
#include <vector>
#define LOGFILE_PATH L"mytrace.etl"
static bool EnableAdminPrivilege()
{
    HANDLE token = NULL;
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) return false;
    LUID luid;
    if (!LookupPrivilegeValueW(NULL, SE_SYSTEM_PROFILE_NAME, &luid)) { CloseHandle(token); return false; }
    TOKEN_PRIVILEGES tp;
    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    BOOL ok = AdjustTokenPrivileges(token, FALSE, &tp, sizeof(tp), NULL, NULL);
    DWORD err = GetLastError();
    CloseHandle(token);
    return ok && (err == ERROR_SUCCESS);
}
static void foo()
{
    for (int j = 0; j < 10; j++)
    {
        std::vector<int> v;
        for (int i = 0; i < 10000000; i++)
        {
            v.push_back(i);
        }
    }
}
void wmain(void)
{
    if (!EnableAdminPrivilege())
    {
        wprintf(L"Failed to enable admin privilege.\n");
        return;
    }
    ULONG status = ERROR_SUCCESS;
    TRACEHANDLE SessionHandle = 0;
    EVENT_TRACE_PROPERTIES* pSessionProperties = NULL;
    ULONG BufferSize = 0;
    static const GUID ETW_PerfInfoGuid = { 0xce1dbfb4, 0x137e, 0x4da6, { 0x87, 0xb0, 0x3f, 0x59, 0xaa, 0x10, 0x2c, 0xbc } };
    CLASSIC_EVENT_ID Events[] = { { ETW_PerfInfoGuid, 0x2e } };
    // Allocate memory for the session properties. The memory must
    // be large enough to include the log file name and session name,
    // which get appended to the end of the session properties structure.
    BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGFILE_PATH) + sizeof(KERNEL_LOGGER_NAME) + 1024*1024*16;
    pSessionProperties = (EVENT_TRACE_PROPERTIES*)malloc(BufferSize);
    if (NULL == pSessionProperties)
    {
        wprintf(L"Unable to allocate %d bytes for properties structure.\n", BufferSize);
        goto cleanup;
    }
    // Set the session properties. You only append the log file name
    // to the properties structure; the StartTrace function appends
    // the session name for you.
    ZeroMemory(pSessionProperties, BufferSize);
    pSessionProperties->Wnode.BufferSize = BufferSize;
    pSessionProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
    pSessionProperties->Wnode.ClientContext = 1; //QPC clock resolution
    pSessionProperties->Wnode.Guid = SystemTraceControlGuid;
    pSessionProperties->EnableFlags = EVENT_TRACE_FLAG_CSWITCH | EVENT_TRACE_FLAG_PROFILE | EVENT_TRACE_FLAG_PROCESS | EVENT_TRACE_FLAG_THREAD | EVENT_TRACE_FLAG_IMAGE_LOAD | EVENT_TRACE_TYPE_LOAD | EVENT_TRACE_FLAG_INTERRUPT | EVENT_TRACE_FLAG_SYSTEMCALL;
    pSessionProperties->LogFileMode = EVENT_TRACE_FILE_MODE_CIRCULAR | EVENT_TRACE_SYSTEM_LOGGER_MODE;
    pSessionProperties->MaximumFileSize = 1024;  // 1024 MB
    pSessionProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
    pSessionProperties->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(KERNEL_LOGGER_NAME);
    StringCbCopy((LPWSTR)((char*)pSessionProperties + pSessionProperties->LoggerNameOffset), sizeof(KERNEL_LOGGER_NAME), KERNEL_LOGGER_NAME);
    StringCbCopy((LPWSTR)((char*)pSessionProperties + pSessionProperties->LogFileNameOffset), sizeof(LOGFILE_PATH), LOGFILE_PATH);
    // Create the trace session.
    status = StartTrace((PTRACEHANDLE)&SessionHandle, KERNEL_LOGGER_NAME, pSessionProperties);
    if (ERROR_SUCCESS != status)
    {
        wprintf(L"StartTrace failed.\n");
        goto cleanup;
    }
    status = TraceSetInformation(SessionHandle, TraceStackTracingInfo, Events, sizeof(Events));
    if (ERROR_SUCCESS != status)
    {
        wprintf(L"TraceSetInformation failed.\n");
        goto cleanup;
    }
    foo();
    wprintf(L"Press any key to end trace session ");
    _getch();
cleanup:
    if (SessionHandle)
    {
        status = ControlTrace(SessionHandle, KERNEL_LOGGER_NAME, pSessionProperties, EVENT_TRACE_CONTROL_STOP);
        if (ERROR_SUCCESS != status)
        {
            wprintf(L"ControlTrace(stop) failed with %lu\n", status);
        }
    }
    if (pSessionProperties)
        free(pSessionProperties);
}



However when analyzing the etl file this program generated, Stack column shows "Missing ImageId event".

User's image

I noticed there is a provider named "ImageId" in the etl file recorded by WPR.

User's image

The problem is how can I enable this provider programmatically?

Windows development | Windows Performance Toolkit
0 comments No comments
{count} votes

Answer accepted by question author
  1. Gary Nebbett 6,411 Reputation points
    2025-12-02T14:49:30.6733333+00:00

    Hello Jingzhou Zhang,

    That "provider" is not actually a provider and can therefore not be enabled. The "events" of that provider are fabricated and injected by WPR at the send of a trace (if the CustomEvents element of the TraceMergeProperties element in the WPR profile includes the CustomEvent ImageId).

    If your .etl file contains Image Start/DCStart/DCEnd events, you can use WPR to inject the additional image events into the file. Issue the command "wpr -help stop" and read about the command "wpr -merge" and the "-injectonly" option.

    Gary

    1 person found this answer helpful.

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.