I think I've found a solution.
While I don't know how to emit an event through an existing provider in realtime, Windows 8 exposes an interface which allows to modify ETL trace logs, so it's possible to alter the ProviderId
of an event to a different value. The interface in question is ITraceRelogger
. You need these guids:
EXTERN_GUID(CLSID_TraceRelogger, 0x7b40792d, 0x05ff, 0x44c4, 0x90, 0x58, 0xf4, 0x40, 0xc7, 0x1f, 0x17, 0xd4);
DEFINE_GUID(IID_ITraceRelogger, 0xF754AD43, 0x3BCC, 0x4286, 0x80, 0x09,0x9C, 0x5D, 0xA2, 0x14, 0xE8, 0x4E); // {F754AD43-3BCC-4286-8009-9C5DA214E84E}
DEFINE_GUID(IID_ITraceEventCallback, 0x3ED25501, 0x593F, 0x43E9, 0x8F, 0x38,0x3A, 0xB4, 0x6F, 0x5A, 0x4A, 0x52); // {3ED25501-593F-43E9-8F38-3AB46F5A4A52}
and relogger.h
file from Windows 8 SDK (c:\Program Files (x86)\Windows Kits\8.0\Include\um\relogger.h
). Original relogger.h
seems to be broken somehow, because it references some external symbols, but it seems there's no LIB file to supplement it. I'm sure you will manage to resolve this though!
To use it, simply create an instance by:
ITraceRelogger *relog = NULL;
hres = CoCreateInstance(CLSID_TraceRelogger, 0, CLSCTX_INPROC_SERVER, IID_ITraceRelogger2, (LPVOID *)& relog);
add you input.etl
and output.etl
files:
#include <windows.h>
#include <cguid.h>
#include <atlbase.h>
#include <comdef.h>
...
CComBSTR input = "input.etl";
CComBSTR output = "output.etl";
...
hres = relog->AddLogfileTraceStream(input, NULL, & trace);
...
hres = relog->SetOutputFilename(output);
Then, you need to register a callback, which will handle event modification. Event callback's implementation example is placed at the end of this answer. Here's the code on how to use it with current ITraceRelogger:
EventCallback *ec = new EventCallback();
hres = relog->RegisterCallback(ec);
...
hres = relog->ProcessTrace();
Warning:ProcessTrace()
will return an error if you haven't register any callbacks.
Here's an example of a working callback:
class EventCallback: public ITraceEventCallback {
private:
DWORD ref_count;
DWORD64 evno;
public:
EventCallback() {
ref_count = 0;
evno = 0;
}
STDMETHODIMP QueryInterface(const IID& iid, void **obj) {
if(iid == IID_IUnknown) {
*obj = dynamic_cast<IUnknown *>(this);
} else if(iid == IID_ITraceEventCallback) {
*obj = dynamic_cast<ITraceEventCallback *>(this);
} else {
*obj = NULL;
return E_NOINTERFACE;
}
return S_OK;
}
STDMETHODIMP_ (ULONG) AddRef(void) {
return InterlockedIncrement(& ref_count);
}
STDMETHODIMP_ (ULONG) Release() {
ULONG ucount = InterlockedDecrement(& ref_count);
if(ucount == 0) {
delete this;
}
return ucount;
}
HRESULT STDMETHODCALLTYPE OnBeginProcessTrace(ITraceEvent *HeaderEvent, ITraceRelogger *Relogger) {
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnEvent(ITraceEvent *Event, ITraceRelogger *Relogger) {
// Your main method.
evno++;
Relogger->Inject(Event);
}
HRESULT STDMETHODCALLTYPE OnFinalizeProcessTrace(ITraceRelogger *Relogger) {
return S_OK;
}
};
Relogger->Inject
will copy current Event
to the output file. You can use MSDN for ITraceRelogger
to check for the available methods which will allow you to change desired event properties. The method that I was interested in was SetProviderId()
.
Also, have in mind that MSDN states, that ITraceRelogger
is available in Windows 7. That's not what I experienced -- I can't instantiate this class in Windows 7, so MSDN can have wrong information about this subject.