Alpha testers
Есть самец, есть альфа-самец. Есть тестеры, есть альфа-тестеры. Разница понятна?
А тем временем тихонько обновили Casablanca. Предыдущий refresh
не работал с Visual Studion 2012 RTM.
I have 2 DOTA 2 gifts. Probably you can ask me by email, probably someone will definitely get it. Go, gentlemen.
Short howto for real time Event Tracing for Windows.
#pragma once
struct ITraceConsumer;
class TraceSession
{
public:
TraceSession(LPCTSTR szSessionName);
~TraceSession();
public:
bool Start();
bool EnableProvider(const GUID& providerId, UCHAR level, ULONGLONG anyKeyword = 0, ULONGLONG allKeyword = 0);
bool OpenTrace(ITraceConsumer *pConsumer);
bool Process();
bool CloseTrace();
bool DisableProvider(const GUID& providerId);
bool Stop();
ULONG Status() const;
LONGLONG PerfFreq() const;
private:
LPTSTR _szSessionName;
ULONG _status;
EVENT_TRACE_PROPERTIES* _pSessionProperties;
TRACEHANDLE hSession;
EVENT_TRACE_LOGFILE _logFile;
TRACEHANDLE _hTrace;
};
Initialization and cleanup:
TraceSession::TraceSession(LPCTSTR szSessionName) : _szSessionName(_tcsdup(szSessionName))
{
}
TraceSession::~TraceSession(void)
{
delete []_szSessionName;
delete _pSessionProperties;
}
First step - lets start trace session:
bool TraceSession::Start()
{
if (!_pSessionProperties) {
const size_t buffSize = sizeof(EVENT_TRACE_PROPERTIES) + (_tcslen(_szSessionName) + 1) * sizeof(TCHAR);
_pSessionProperties = reinterpret_cast<EVENT_TRACE_PROPERTIES *>(malloc(buffSize));
ZeroMemory(_pSessionProperties, buffSize);
_pSessionProperties->Wnode.BufferSize = buffSize;
_pSessionProperties->Wnode.ClientContext = 1;
_pSessionProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
_pSessionProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
}
// Create the trace session.
_status = StartTrace(&hSession, _szSessionName, _pSessionProperties);
return (_status == ERROR_SUCCESS);
}
Then lets enable a provider with some filters:
bool TraceSession::EnableProvider(const GUID& providerId, UCHAR level, ULONGLONG anyKeyword, ULONGLONG allKeyword)
{
_status = EnableTraceEx2(hSession, &providerId, EVENT_CONTROL_CODE_ENABLE_PROVIDER, level, anyKeyword, allKeyword, 0, NULL);
return (_status == ERROR_SUCCESS);
}
BTW, you can have useful ETW metadata generated by mc.exe utility,
just find your specific man manifest file for your ETW provider.
Now we open the trace:
bool TraceSession::OpenTrace(ITraceConsumer *pConsumer)
{
if (!pConsumer)
return false;
ZeroMemory(&_logFile, sizeof(EVENT_TRACE_LOGFILE));
_logFile.LoggerName = _szSessionName;
_logFile.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD;
_logFile.EventRecordCallback = &EventRecordCallback;
_logFile.Context = pConsumer;
_hTrace = ::OpenTrace(&_logFile);
return (_hTrace != 0);
}
EventRecordCallback looks like this:
namespace
{
VOID WINAPI EventRecordCallback(_In_ PEVENT_RECORD pEventRecord)
{
reinterpret_cast<ITraceConsumer *>(pEventRecord->UserContext)->OnEventRecord(pEventRecord);
}
}
But this is just for convenience and OOP, you can have just static function. Up to you.
Finally, call the following method:
bool TraceSession::Process()
{
_status = ProcessTrace(&_hTrace, 1, NULL, NULL);
return (_status == ERROR_SUCCESS);
}
Ensure you are running under elevated privileges.
When you decide its over - close the trace, disable any providers and stop the session:
bool TraceSession::CloseTrace()
{
_status = ::CloseTrace(_hTrace);
return (_status == ERROR_SUCCESS);
}
bool TraceSession::DisableProvider(const GUID& providerId)
{
_status = EnableTraceEx2(hSession, &providerId, EVENT_CONTROL_CODE_DISABLE_PROVIDER, 0, 0, 0, 0, NULL);
return (_status == ERROR_SUCCESS);
}
bool TraceSession::Stop()
{
_status = ControlTrace(hSession, _szSessionName, _pSessionProperties, EVENT_TRACE_CONTROL_STOP);
delete _pSessionProperties;
_pSessionProperties = NULL;
return (_status == ERROR_SUCCESS);
}
Some useful stuff:
ULONG TraceSession::Status() const
{
return _status;
}
LONGLONG TraceSession::PerfFreq() const
{
return _logFile.LogfileHeader.PerfFreq.QuadPart;
}
Remember: sessions are global, not tied to your executable. So be sure to write something like this:
if (!traceSession.Start()) {
if (traceSession.Status() == ERROR_ALREADY_EXISTS) {
if (!traceSession.Stop() || !traceSession.Start()) {
// Handle an error
}
}
}
Well, thats it.
Short tutorial on how to make cross apartment (cross thread) COM call without interfaces, proxies, stubs and tlbs.
Each apartment (thread) has its own accesible context object. It can be obtained
via
CoGetObjectContext API function:
CComPtr<IContext> pContext; CComPtr<IContextCallback> pContextCallback; hr = CoGetObjectContext(IID_PPV_ARGS(&pContext)); hr = CoGetObjectContext(IID_PPV_ARGS(&pContextCallback));
One of interfaces you can get is IContextCallback with only one
method - ContextCallback. As you might already guessed, we just need
to get IContextCallback in target execution context and invoke
ContextCallback method in any other context:
pContextCallback.p->AddRef();
_beginthread(&myThread, 65536, pContextCallback.p);
HANDLE h[] = { CreateEvent(NULL, TRUE, FALSE, NULL) };
DWORD dwIndex;
CoWaitForMultipleHandles(0, INFINITE, _countof(h), h, &dwIndex);
[...]
HRESULT _stdcall contextCall(ComCallData *pParam)
{
OutputDebugString(_T("contextCall\n"));
return S_OK;
}
void __cdecl myThread(LPVOID p)
{
CoInitialize(NULL);
CComPtr<IContextCallback> pContextCallback;
pContextCallback.Attach(reinterpret_cast<IContextCallback *>(p));
ComCallData cd = { 0, 0, NULL };
pContextCallback->ContextCallback(&contextCall, &cd, IID_NULL, 0, NULL);
CoUninitialize();
}
Here I'm starting a separate thread to make cross context call and using
CoWaitForMultipleHandles OLE32 function to trigger message loop to
accept cross thread COM calls (regular message loop is surely enough, I'm just reluctant
to write one). Here are resulting call stacks:
Main thread: > Win32ConsoleApplication.exe!contextCall(tagComCallData * pParam) Line 227 C++ ole32.dll!CRemoteUnknown::DoCallback(struct tagXAptCallback *) Unknown rpcrt4.dll!_Invoke@12 () Unknown rpcrt4.dll!_NdrStubCall2@16 () Unknown ole32.dll!_CStdStubBuffer_Invoke@12 () Unknown ole32.dll!SyncStubInvoke(struct tagRPCOLEMESSAGE *,struct _GUID const &,class CIDObject *,void *,struct IRpcChannelBuffer *,struct IRpcStubBuffer *,unsigned long *) Unknown ole32.dll!StubInvoke(struct tagRPCOLEMESSAGE *,class CStdIdentity *,struct IRpcStubBuffer *,struct IRpcChannelBuffer *,struct tagIPIDEntry *,unsigned long *) Unknown ole32.dll!CCtxComChnl::ContextInvoke(struct tagRPCOLEMESSAGE *,struct IRpcStubBuffer *,struct tagIPIDEntry *,unsigned long *) Unknown ole32.dll!MTAInvoke(struct tagRPCOLEMESSAGE *,unsigned long,struct IRpcStubBuffer *,class IInternalChannelBuffer *,struct tagIPIDEntry *,unsigned long *) Unknown ole32.dll!STAInvoke(struct tagRPCOLEMESSAGE *,unsigned long,struct IRpcStubBuffer *,class IInternalChannelBuffer *,void *,struct tagIPIDEntry *,unsigned long *) Unknown ole32.dll!AppInvoke(class CMessageCall *,class CRpcChannelBuffer *,struct IRpcStubBuffer *,void *,void *,struct tagIPIDEntry *,struct LocalThis *) Unknown ole32.dll!ComInvokeWithLockAndIPID(class CMessageCall *,struct tagIPIDEntry *) Unknown ole32.dll!ComInvoke(class CMessageCall *) Unknown ole32.dll!ThreadDispatch(void *) Unknown ole32.dll!ThreadWndProc(struct HWND__ *,unsigned int,unsigned int,long) Unknown user32.dll!_InternalCallWinProc@20 () Unknown user32.dll!_UserCallWinProcCheckWow@32 () Unknown user32.dll!_DispatchMessageWorker@8 () Unknown user32.dll!_DispatchMessageW@4 () Unknown ole32.dll!CCliModalLoop::PeekRPCAndDDEMessage(void) Unknown ole32.dll!CCliModalLoop::FindMessage(unsigned long) Unknown ole32.dll!CCliModalLoop::HandleWakeForMsg(void) Unknown ole32.dll!CCliModalLoop::BlockFn(void * *,unsigned long,unsigned long *) Unknown ole32.dll!_CoWaitForMultipleHandles@20 () Unknown Win32ConsoleApplication.exe!wmain(int argc, wchar_t * * argv) Line 284 C++ Win32ConsoleApplication.exe!__tmainCRTStartup() Line 533 C Win32ConsoleApplication.exe!wmainCRTStartup() Line 377 C kernel32.dll!@BaseThreadInitThunk@12 () Unknown ntdll.dll!___RtlUserThreadStart@8 () Unknown ntdll.dll!__RtlUserThreadStart@8 () Unknown Worker thread: ntdll.dll!_NtWaitForMultipleObjects@20 () Unknown ntdll.dll!_NtWaitForMultipleObjects@20 () Unknown KernelBase.dll!_WaitForMultipleObjectsEx@20 () Unknown kernel32.dll!_WaitForMultipleObjectsExImplementation@20 () Unknown user32.dll!_RealMsgWaitForMultipleObjectsEx@20 () Unknown ole32.dll!CCliModalLoop::BlockFn(void * *,unsigned long,unsigned long *) Unknown ole32.dll!ModalLoop(class CMessageCall *) Unknown ole32.dll!SwitchSTA(class OXIDEntry *,class CMessageCall * *) Unknown ole32.dll!CRpcChannelBuffer::SwitchAptAndDispatchCall(class CMessageCall * *) Unknown ole32.dll!CRpcChannelBuffer::SendReceive2(struct tagRPCOLEMESSAGE *,unsigned long *) Unknown ole32.dll!CCliModalLoop::SendReceive(struct tagRPCOLEMESSAGE *,unsigned long *,class IInternalChannelBuffer *) Unknown ole32.dll!CAptRpcChnl::SendReceive(struct tagRPCOLEMESSAGE *,unsigned long *) Unknown ole32.dll!CCtxComChnl::SendReceive(struct tagRPCOLEMESSAGE *,unsigned long *) Unknown ole32.dll!NdrExtpProxySendReceive(void *,struct _MIDL_STUB_MESSAGE *) Unknown rpcrt4.dll!@NdrpProxySendReceive@4 () Unknown rpcrt4.dll!_NdrClientCall2 () Unknown ole32.dll!_ObjectStublessClient@8 () Unknown ole32.dll!_ObjectStubless@0 () Unknown ole32.dll!CObjectContext::InternalContextCallback(long (*)(void *),void *,struct _GUID const &,int,struct IUnknown *) Unknown ole32.dll!CObjectContext::ContextCallback(long (*)(struct tagComCallData *),struct tagComCallData *,struct _GUID const &,int,struct IUnknown *) Unknown > Win32ConsoleApplication.exe!myThread(void * p) Line 239 C++ msvcr110d.dll!_callthreadstart() Line 255 C msvcr110d.dll!_threadstart(void * ptd) Line 239 C kernel32.dll!@BaseThreadInitThunk@12 () Unknown ntdll.dll!___RtlUserThreadStart@8 () Unknown ntdll.dll!__RtlUserThreadStart@8 () Unknown
Windows OS has many hidden features, used by Microsoft products. Are we any worse?