A few days ago, I reported about the 
peculiarities of the ReportFault API,
particularly on Windows Vista, and how those peculiarities drove me to
give in to Microsoft's sound advice and use the new and shiny 
Windows Error Reporting (WER) APIs
on Vista.
ReportFault() is a great 
one-stop shopping API: A one-liner will display
all required dialogs, ask the user if he wants to contact Microsoft,
create report data (including 
minidumps) 
if required, and send the whole report off to Microsoft.
The new 
WER APIs
in Vista are slightly more complex, but also provide more control for
the details of error reporting. Well, if you know how to handle the APIs,
that is. Apparently, I do 
not know how to handle them since I still
haven't solved all the problems around them.
More on this in a moment. Let's first take a look at the core of a test application I wrote:
static bool report_crash(_EXCEPTION_POINTERS *inExceptionPointer)
{
  // Set up parameters for WerReportCreate()
  WER_REPORT_INFORMATION werReportInfo;
  memset(&werReportInfo, 0, sizeof(werReportInfo));
  werReportInfo.dwSize = sizeof(werReportInfo);
  wcscpy_s(werReportInfo.wzFriendlyEventName,
    _countof(werReportInfo.wzFriendlyEventName),
        L"werapitest (friendly event name)");
  wcscpy_s(werReportInfo.wzApplicationName,
    _countof(werReportInfo.wzApplicationName), L"");
  wcscpy_s(werReportInfo.wzDescription,
    _countof(werReportInfo.wzDescription), L"Critical runtime problem");
  PCWSTR eventType = L"werapitest (eventType)"; // APPCRASH
  HREPORT hReportHandle;
  if (FAILED(pWerReportCreate(eventType, WerReportCritical,
    &werReportInfo, &hReportHandle)) || !hReportHandle) {
      return false;
  }
  bool ret = false;
  WER_EXCEPTION_INFORMATION werExceptionInformation;
  werExceptionInformation.bClientPointers = FALSE;
  werExceptionInformation.pExceptionPointers = inExceptionPointer;
  bool dumpAdded = SUCCEEDED(pWerReportAddDump(hReportHandle, ::GetCurrentProcess(),
    ::GetCurrentThread(), WerDumpTypeMiniDump, &werExceptionInformation, NULL, 0));
  if (!dumpAdded) {
    FATAL_ERROR("Minidump generation failed.\n");
  }
  DWORD submitOptions = WER_SUBMIT_OUTOFPROCESS | WER_SUBMIT_NO_CLOSE_UI;
  WER_SUBMIT_RESULT submitResult;
  if (SUCCEEDED(pWerReportSubmit(hReportHandle, WerConsentNotAsked,
    submitOptions, &submitResult))) {
      switch(submitResult)
      {
        // ... decode result ...
      }
  }
  pWerReportCloseHandle(hReportHandle);
  return ret;
}
static int filter_exception(EXCEPTION_POINTERS *exc_ptr)
{
  report_crash(exc_ptr);
  return EXCEPTION_EXECUTE_HANDLER;
}
static void wedding_crasher(void)
{
  __try {
    int *foo = (int *)0;
    *foo = 42;
  } __except(filter_exception(GetExceptionInformation())) {
    printf("Now in exception handler, process is still alive!\n");
  }
  Sleep(5000);
}
int main()
{
  HMODULE hWer = LoadLibrary("Wer.dll");
  if (hWer) {
    pWerReportCreate =
      (pfn_WERREPORTCREATE)GetProcAddress(hWer, "WerReportCreate");
    pWerReportSubmit =
      (pfn_WERREPORTSUBMIT)GetProcAddress(hWer, "WerReportSubmit");
    pWerReportCloseHandle =
      (pfn_WERREPORTCLOSEHANDLE)GetProcAddress(hWer, "WerReportCloseHandle");
    pWerReportAddDump =
      (pfn_WERREPORTADDDUMP)GetProcAddress(hWer, "WerReportAddDump");
  }
  if (!pWerReportCreate || !pWerReportSubmit ||
    !pWerReportCloseHandle || !pWerReportAddDump) {
      printf("Cannot initialize WER API.\n");
      return 1;
  }
  wedding_crasher();
  return 0;
}
The fundamental approach is still the same as for the 
ReportFault
test program 
presented recently:
-  A structured exception block is established using __tryand__except.
-  Code provokes an access violation.
-  The exception filter filter_exceptionis consulted by the 
     exception handling infrastructure to find out how to proceed 
     with the exception.
-  The filter calls the WER APIs to display the crash dialog(s), 
     and to give the user options to debug the problem, ignore it, 
     or report it to Microsoft.
-  The exception filter returns EXCEPTION_EXECUTE_HANDLERto indicate that its associated exception handler should 
     be called.
The following WER APIs are used to create and send a crash report:
The WER APIs do indeed solve a problem that I found with 
ReportFault
on Vista: They don't force the calling process to be terminated, and 
allow me to proceed as I see fit. That's really good news.
The problem I haven't resolved yet is this: Even though I call
WerReportAddDump, I have no idea whether minidump data are
actually generated and sent. In fact, from the feedback
provided by the system, it seems likely that those data are 
not
generated.
To illustrate my uncertainties, I wrote a test program called 
werapitest.
The code is attached as a ZIP file; unpack it into a directory, open
a Visual Studio command prompt window, and build the code as follows:
  cl werapitest.cpp
Run the resulting executable, then open up the "Problem Reports and Solutions"
control panel and click on "View problem history". On my system, I get
something like this:
 
Double-clicking on the report entry leads to this:
 
The problem history entry does not mention any attached files, such as 
minidump data!
When a crash occurs, the system also writes entries into the event log;
those log entries claim there 
are additional data in paths such as
C:\Users\clausb\AppData\Local\Microsoft\Windows\WER\ReportArchive\Report0f8918ad,
and indeed, such directories exist and each contain a file called 
Report.wer,
which holds data such as:
Version=1
EventType=werapitest (eventType)
EventTime=128266502225896608
ReportType=1
Consent=1
UploadTime=128266502257542112
Response.BucketId=8
Response.BucketTable=5
Response.type=4
DynamicSig[1].Name=OS Version
DynamicSig[1].Value=6.0.6000.2.0.0.256.16
DynamicSig[2].Name=Locale ID
DynamicSig[2].Value=1033
UI[3]=werapitest.exe has stopped working
UI[4]=Windows can check online for a solution to the problem.
UI[5]=Check online for a solution and close the program
UI[6]=Check online for a solution later and close the program
UI[7]=Close the program
State[0].Key=Transport.DoneStage1
State[0].Value=1
State[1].Key=DataRequest
State[1].Value=Bucket=8/nBucketTable=5/nResponse=1/n
FriendlyEventName=werapitest (friendly event name)
ConsentKey=werapitest (eventType)
AppName=werapitest.exe
AppPath=C:\tmp\werapitest.exe
ReportDescription=Critical runtime problem
So again, the minidump is not mentioned anywhere.
Now let's try some minimal code which uses neither 
ReportFault nor
the new WER API:
  int main(void)
  {
    int *p = (int *)0;
    *p = 42;
    return 0;
  }
After running this code and letting it crash and report to Microsoft, I get the following
problem history entry:
 
This problem report contains a 
lot more data than the one for 
werapitest,
and it even refers to a minidump file which was apparently generated by the system
and probably also sent to Microsoft.
So the lazy code which doesn't do anything about crashes gets full and proper
service from the OS, while the application which tries to deal with a crash in 
an orderly manner and elaborately goes through all the trouble of using the 
proper APIs doesn't get its message across to Microsoft. I call this unfair 
 
Oh, and in case you're wondering: Yes, we've registered with Microsoft's Winqual site 
where the crash reports are supposed to be sent to, and we established 
"product mappings" there, and the whole process seems to work for XP clients 
just fine.
I'm pretty sure that I'm just missing a couple of details with the new
APIs, or maybe I'm misinterpreting the feedback from the system.
I ran numerous experiments and umpteen variations, I've searched the web
high and low, read the docs, consulted newsgroups 
here
and 
there - 
and now I'm running out of ideas. Any hints most welcome...
to top