Edit
Attach
Printable
topic end
<!-- * Set TOPICTITLE = #define private public Crashing with style on Vista, part II (25 Jun 2007) --> <style type="text/css"> pre {background-color:#ffeecc;} </style> %STARTINCLUDE% <a name="25"></a> ---+++ [[DefinePrivatePublic20070625][Crashing with style on Vista, part II]] (25 Jun 2007) <summary> In the first part of this mini-series, I [[Blog.DefinePrivatePublic20070616][demonstrated the <nop>ReportFault API]] and why it didn't fit my needs on Vista. Last time around, I discussed my [[Blog.DefinePrivatePublic20070618][first attempt]] to use the new Windows Error Reporting (WER) APIs instead, which failed to produce any crash reports on Microsoft's Winqual site. </summary> When the curtain fell last time, I had a WER test application which, on the surface, _appeared_ to work, but didn't manage to get any crash reports through to Winqual. Also, entries for crash reports produced by this application looked a little funny in Vista's Problem History window: <img src="%PUBURL%/Blog/DefinePrivatePublic20070618/werapitest_entry.png" border="1" /> <br clear="all" /> In particular, the _Bucket ID_ value stands out. What are [[https://winqual.microsoft.com/help/bucket_details.htm][bucket IDs]]? Essentially, the Winqual site combines various attributes of the crash report (application, signatures, crash address etc.) and creates a unique integer value from them, which then becomes an identifier for this particular type of crash. All my WER-induced crash reports submitted from Vista clients always had a bucket ID of 8, regardless of which test application I used and how exactly I provoked the crash. Also, I knew from earlier, successful attempts to talk to the Winqual servers how _real_ bucket IDs usually look like (much larger integers). Something fishy was going on here. The application I tested was properly registered, signed and mapped at the Winqual site, and crash reports submitted from XP systems made it to the Winqual servers just fine. Hence, registration issues could be ruled out. I posted to the [[http://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=1429&SiteID=1][Windows Error Reporting forum]] and asked for help and clarification. Saar Picker responded: "We filter out unknown event types. Since your report is not of a recognized event type, it is being rejected. The Bucket ID 8 event is reporting the rejection to us." So my crash reports were _not of a recognized event type_. What's a poor crash report supposed to do to be recognized? The first parameter for [[http://msdn2.microsoft.com/en-us/library/bb513625.aspx][<nop>WerReportCreate]] is an event type. The documentations says: "<tt>wzEventType</tt> - A pointer to a Unicode string that specifies the name of the event." Hmmm, so maybe this is the event type that Saar mentioned. If so, what kind of event are we talking about? Win32 events? Events like the ones captured in the Windows event log? None of those, as it turns out. Instead, error reporting servers can define types of error events that they want to capture. Microsoft's Winqual servers, for example, are configured to accept event types which represent application or operating system crashes. So what is the magic event type which represents an application crash? Hint 1: The =werapi.h= header file defines an undocumented macro constant called =APPCRASH_EVENT=. <pre> #define APPCRASH_EVENT L"APPCRASH" </pre> Hint 2: When a crash report is submitted using =WerReportSubmit=, this API tries to contact the error reporting server. In Vista, the protocol is based on XML snippets which the client sends to the server via HTTP. One of the attributes in the initial XML that is transmitted is called =eventtype=, and for applications which do not try to handle fatal crashes themselves, the value of that attribute is indeed "APPCRASH". So I modified my WER code to use "APPCRASH" instead of some arbitrary string. And indeed, this made a difference, although not the one I had hoped for: With the new event type, =WerReportSubmit()= now returned an error (=E_FAIL=), where it previously succeeded... To debug the problem, I intercepted the XML exchange between the client and the server, and looked at the differences between a non-WER client and my own test code. (If you're interested in the interception details, drop me a line.) The non-WER client transmitted additional data (so-called "signature parameters"), and it also specified a "report type" of 2 instead of 1. So my strategy was to eliminate the differences one by one by working the WER APIs. The extra parameters sent by the non-WER client were things like the application's name, version and timestamp; the faulting module's name, version and typestamp; and the exception code and address offset. And now, finally, I understood the purpose of the underdocumented [[http://msdn2.microsoft.com/en-us/library/ms681641.aspx][<nop>WerReportSetParameter]] API - depending on the server's setup, it expects certain extra parameters to safely identify an event, and those can be set using =WerReportSetParameter=: <pre> <font color="#2e8b57"><b>static</b></font> <font color="#2e8b57"><b>void</b></font> wer_report_set_parameters(HREPORT hReportHandle, EXCEPTION_POINTERS *exc_ptr) { TCHAR moduleName[<font color="#ff00ff">1024</font>]; get_module_name(<font color="#ff00ff">NULL</font>, moduleName, _countof(moduleName)); pWerReportSetParameter(hReportHandle, <font color="#ff00ff">0</font>, <font color="#ff00ff">L"Application Name"</font>, moduleName); TCHAR buffer[<font color="#ff00ff">1024</font>]; get_module_file_version(moduleName, buffer, _countof(buffer)); pWerReportSetParameter(hReportHandle, <font color="#ff00ff">1</font>, <font color="#ff00ff">L"Application Version"</font>, buffer); HMODULE hModule = GetModuleHandle(<font color="#ff00ff">0</font>); DWORD timeStamp = GetTimestampForLoadedLibrary(hModule); _sntprintf_s(buffer, _countof(buffer), _TRUNCATE, __T(<font color="#ff00ff">"</font><font color="#6a5acd">%x</font><font color="#ff00ff">"</font>), timeStamp); pWerReportSetParameter(hReportHandle, <font color="#ff00ff">2</font>, <font color="#ff00ff">L"Application Timestamp"</font>, buffer); <font color="#0000ff">// determine module name from crash address</font> moduleName[<font color="#ff00ff">0</font>] = <font color="#ff00ff">0</font>; <font color="#2e8b57"><b>void</b></font> *exceptionAddress = exc_ptr->ExceptionRecord->ExceptionAddress; <font color="#804040"><b>if</b></font> (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR)exceptionAddress, &hModule)) { get_module_name(hModule, moduleName, _countof(moduleName)); } pWerReportSetParameter(hReportHandle, <font color="#ff00ff">3</font>, <font color="#ff00ff">L"Fault Module Name"</font>, moduleName); get_module_file_version(moduleName, buffer, _countof(buffer)); pWerReportSetParameter(hReportHandle, <font color="#ff00ff">4</font>, <font color="#ff00ff">L"Fault Module Version"</font>, buffer); timeStamp = GetTimestampForLoadedLibrary(hModule); _sntprintf_s(buffer, _countof(buffer), _TRUNCATE,__T(<font color="#ff00ff">"</font><font color="#6a5acd">%x</font><font color="#ff00ff">"</font>), timeStamp); pWerReportSetParameter(hReportHandle, <font color="#ff00ff">5</font>, <font color="#ff00ff">L"Fault Module Timestamp"</font>, buffer); _sntprintf_s(buffer, _countof(buffer), _TRUNCATE, __T(<font color="#ff00ff">"</font><font color="#6a5acd">%08x</font><font color="#ff00ff">"</font>), exc_ptr->ExceptionRecord->ExceptionCode); pWerReportSetParameter(hReportHandle, <font color="#ff00ff">6</font>, <font color="#ff00ff">L"Exception Code"</font>, buffer); INT_PTR offset = (<font color="#2e8b57"><b>char</b></font> *)exceptionAddress - (<font color="#2e8b57"><b>char</b></font> *)hModule; _sntprintf_s(buffer, _countof(buffer), _TRUNCATE, __T(<font color="#ff00ff">"</font><font color="#6a5acd">%p</font><font color="#ff00ff">"</font>), offset); pWerReportSetParameter(hReportHandle, <font color="#ff00ff">7</font>, <font color="#ff00ff">L"Exception Offset"</font>, buffer); } </pre> The other significant change was to use the undocumented =WerReportApplicationCrash= constant as the "report type" parameter for =WerReportCreate=. After these changes, the Winqual servers finally started talking to me: I received bucket IDs, sometimes also requests to transmit minidump data - and after a few days, the crash reports appeared on the Winqual site! Whoopee! The full demo code is [[%ATTACHURL%/werapitest2.zip][attached]]. To build, open a Visual Studio command prompt and run the compiler: <pre> cl werapitest.cpp </pre> My special thanks to Saar Picker and Jason Hardester at Microsoft for their help! Now that I've achieved my original goal (reporting crashes using the WER APIs under Vista), let me spoil the fun by warning you to ever use this approach. Why? Because this is clearly not the way Microsoft recommends to handle application crashes. Now, while I'm not sure whether Microsoft as a whole has an official recommendation, the documentation or the postings in newsgroups in blogs clearly suggest that an application shouldn't actually even try to handle a crash explicitly - instead, it should just crash and let the OS do the reporting. The basic rationale behind this is that an application is probably already deeply confused when a crash occurs, and some of its data may already have been damaged. This makes crash recovery a difficult and unreliable endeavor. There are circumstances where an application needs to keep control of the reporting process, but Microsoft expects such cases to be very rare. Which explains a lot of the initial communication disconnects that I experienced while discussing my case with Saar and Jason. There's a reason why it's called "WER" (<i>W</i>indows <i>E</i>rror <i>Reporting</i>) and not "WCR" (<i>W</i>indows <i>C</i>rash <i>R</i>eporting). Apparently, Microsoft doesn't expect us to use those APIs for crash reporting, but rather for more generic "error" or "event" reporting. For example, [[http://www.freepatentsonline.com/20060285749.html][this U.S. patent claim]] discusses how the WER APIs can be used to report failures in handwriting recognition. (By the way, there's also a patent for WER itself, see http://www.freepatentsonline.com/20060271591.html.) --- %STOPINCLUDE% %COMMENT{type="below" nonotify="on"}% ---
to top
End of topic
Skip to action links
|
Back to top
Edit
|
Attach image or document
|
Printable version
|
Raw text
|
Refresh
|
More topic actions
Revisions: | r1.9 |
>
|
r1.8
|
>
|
r1.7
|
Total page history
|
Backlinks
You are here:
Blog
>
DefinePrivatePublic20070625
r1.9 - 19 Sep 2007 - 22:01 -
ClausBrod
to top
Blog
This site
2017
:
12
-
11
-
10
2016
:
10
-
7
-
3
2015
:
11
-
10
-
9
-
4
-
1
2014
:
5
2013
:
9
-
8
-
7
-
6
-
5
2012
:
2
-
10
2011
:
1
-
8
-
9
-
10
-
12
2010
:
11
-
10
-
9
-
4
2009
:
11
-
9
-
8
-
7
-
6
-
5
-
4
-
3
2008
:
5
-
4
-
3
-
1
2007:
12
-
8
-
7
-
6
-
5
-
4
-
3
-
1
2006:
4
-
3
-
2
-
1
2005:
12
-
6
-
5
-
4
2004:
12
-
11
-
10
C++
CoCreate Modeling
COM & .NET
Java
Mac
Lisp
OpenSource
Scripting
Windows
Stuff
Changes
Index
Search
Maintenance
Impressum
Datenschutzerklärung
Home
Webs
Atari
Blog
Claus
CoCreateModeling
Klassentreffen
Main
Sandbox
Sommelier
TWiki
Xplm
Jump:
Copyright © 1999-2024 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki?
Send feedback