Subversion Repositories AndroidProjects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
244 chris 1
#include "SEHCatcher.h"
2
#include "SexyAppBase.h"
3
#include <fstream>
4
#include <process.h>
5
 
6
#ifdef ZYLOM
7
#include "zylomso.h"
8
using namespace zylom::zylomso;
9
#endif
10
 
11
using namespace Sexy;
12
 
13
LPTOP_LEVEL_EXCEPTION_FILTER SEHCatcher::mPreviousFilter;
14
SexyAppBase*                            SEHCatcher::mApp = NULL;
15
HFONT                                           SEHCatcher::mDialogFont = NULL;
16
HFONT                                           SEHCatcher::mBoldFont = NULL;
17
bool                                            SEHCatcher::mHasDemoFile = false;
18
bool                                            SEHCatcher::mDebugError = false;
19
std::string                                     SEHCatcher::mErrorTitle;
20
std::string                                     SEHCatcher::mErrorText;
21
std::string                                     SEHCatcher::mUserText;
22
std::string                                     SEHCatcher::mUploadFileName;
23
HWND                                            SEHCatcher::mYesButtonWindow = NULL;
24
HWND                                            SEHCatcher::mNoButtonWindow = NULL;
25
HWND                                            SEHCatcher::mDebugButtonWindow = NULL;
26
HWND                                            SEHCatcher::mEditWindow = NULL;
27
HMODULE                                         SEHCatcher::mImageHelpLib = NULL;
28
SYMINITIALIZEPROC                       SEHCatcher::mSymInitialize = NULL;
29
SYMSETOPTIONSPROC                       SEHCatcher::mSymSetOptions = NULL;
30
UNDECORATESYMBOLNAMEPROC        SEHCatcher::mUnDecorateSymbolName = NULL;
31
SYMCLEANUPPROC                          SEHCatcher::mSymCleanup = NULL;
32
STACKWALKPROC                           SEHCatcher::mStackWalk = NULL;
33
SYMFUNCTIONTABLEACCESSPROC      SEHCatcher::mSymFunctionTableAccess = NULL;
34
SYMGETMODULEBASEPROC            SEHCatcher::mSymGetModuleBase = NULL;
35
SYMGETSYMFROMADDRPROC           SEHCatcher::mSymGetSymFromAddr = NULL;
36
HTTPTransfer                            SEHCatcher::mSubmitReportTransfer;
37
bool                                            SEHCatcher::mExiting = false;
38
bool                                            SEHCatcher::mShowUI = true;
39
bool                                            SEHCatcher::mAllowSubmit = true;
40
 
41
std::wstring                                    SEHCatcher::mCrashMessage = L"An unexpected error has occured!";
42
std::string                                             SEHCatcher::mSubmitHost;
43
std::wstring                                    SEHCatcher::mSubmitMessage = L"Please help out by providing as much information as you can about this crash.";
44
std::wstring                                    SEHCatcher::mSubmitErrorMessage = L"Failed to connect to server.";
45
 
46
static bool gUseDefaultFonts = true;
47
 
48
struct
49
{
50
    DWORD   dwExceptionCode;
51
    char    *szMessage;
52
} gMsgTable[] = {
53
   { STATUS_SEGMENT_NOTIFICATION,     "Segment Notification" },
54
   { STATUS_BREAKPOINT,               "Breakpoint" },
55
   { STATUS_SINGLE_STEP,              "Single step" },
56
   { STATUS_WAIT_0,                   "Wait 0" },
57
   { STATUS_ABANDONED_WAIT_0,         "Abandoned Wait 0" },
58
   { STATUS_USER_APC,                 "User APC" },
59
   { STATUS_TIMEOUT,                  "Timeout" },
60
   { STATUS_PENDING,                  "Pending" },
61
   { STATUS_GUARD_PAGE_VIOLATION,     "Guard Page Violation" },
62
   { STATUS_DATATYPE_MISALIGNMENT,    "Data Type Misalignment" },
63
   { STATUS_ACCESS_VIOLATION,         "Access Violation" },
64
   { STATUS_IN_PAGE_ERROR,            "In Page Error" },
65
   { STATUS_NO_MEMORY,                "No Memory" },
66
   { STATUS_ILLEGAL_INSTRUCTION,      "Illegal Instruction" },
67
   { STATUS_NONCONTINUABLE_EXCEPTION, "Noncontinuable Exception" },
68
   { STATUS_INVALID_DISPOSITION,      "Invalid Disposition" },
69
   { STATUS_ARRAY_BOUNDS_EXCEEDED,    "Array Bounds Exceeded" },
70
   { STATUS_FLOAT_DENORMAL_OPERAND,   "Float Denormal Operand" },
71
   { STATUS_FLOAT_DIVIDE_BY_ZERO,     "Divide by Zero" },
72
   { STATUS_FLOAT_INEXACT_RESULT,     "Float Inexact Result" },
73
   { STATUS_FLOAT_INVALID_OPERATION,  "Float Invalid Operation" },
74
   { STATUS_FLOAT_OVERFLOW,           "Float Overflow" },
75
   { STATUS_FLOAT_STACK_CHECK,        "Float Stack Check" },
76
   { STATUS_FLOAT_UNDERFLOW,          "Float Underflow" },
77
   { STATUS_INTEGER_DIVIDE_BY_ZERO,   "Integer Divide by Zero" },
78
   { STATUS_INTEGER_OVERFLOW,         "Integer Overflow" },
79
   { STATUS_PRIVILEGED_INSTRUCTION,   "Privileged Instruction" },
80
   { STATUS_STACK_OVERFLOW,           "Stack Overflow" },
81
   { STATUS_CONTROL_C_EXIT,           "Ctrl+C Exit" },
82
   { 0xFFFFFFFF,                      "" }
83
};
84
 
85
 
86
SEHCatcher::SEHCatcher()
87
{      
88
        mPreviousFilter = SetUnhandledExceptionFilter(UnhandledExceptionFilter);        
89
}
90
 
91
SEHCatcher::~SEHCatcher()
92
{
93
        SetUnhandledExceptionFilter(mPreviousFilter);
94
}
95
 
96
long __stdcall SEHCatcher::UnhandledExceptionFilter(LPEXCEPTION_POINTERS lpExceptPtr)
97
{
98
        if (mApp != NULL)
99
                mApp->SEHOccured();    
100
 
101
        DoHandleDebugEvent(lpExceptPtr);
102
 
103
        if (!mDebugError)
104
                SetErrorMode(SEM_NOGPFAULTERRORBOX);
105
 
106
        return EXCEPTION_CONTINUE_SEARCH;      
107
}
108
 
109
bool SEHCatcher::LoadImageHelp()
110
{
111
        mImageHelpLib = LoadLibraryA("IMAGEHLP.DLL");
112
    if (!mImageHelpLib)
113
        return false;
114
 
115
    mSymInitialize = (SYMINITIALIZEPROC) GetProcAddress(mImageHelpLib, "SymInitialize");
116
    if (!mSymInitialize)
117
        return false;
118
 
119
        mSymSetOptions = (SYMSETOPTIONSPROC) GetProcAddress(mImageHelpLib, "SymSetOptions");
120
    if (!mSymSetOptions)
121
        return false;
122
 
123
    mSymCleanup = (SYMCLEANUPPROC) GetProcAddress(mImageHelpLib, "SymCleanup");
124
    if (!mSymCleanup)
125
        return false;
126
 
127
        mUnDecorateSymbolName = (UNDECORATESYMBOLNAMEPROC) GetProcAddress(mImageHelpLib, "UnDecorateSymbolName");
128
    if (!mUnDecorateSymbolName)
129
        return false;
130
 
131
    mStackWalk = (STACKWALKPROC) GetProcAddress(mImageHelpLib, "StackWalk");
132
    if (!mStackWalk)
133
        return false;
134
 
135
    mSymFunctionTableAccess = (SYMFUNCTIONTABLEACCESSPROC) GetProcAddress(mImageHelpLib, "SymFunctionTableAccess");
136
    if (!mSymFunctionTableAccess)
137
        return false;
138
 
139
    mSymGetModuleBase = (SYMGETMODULEBASEPROC) GetProcAddress(mImageHelpLib, "SymGetModuleBase");
140
    if (!mSymGetModuleBase)
141
        return false;
142
 
143
    mSymGetSymFromAddr = (SYMGETSYMFROMADDRPROC) GetProcAddress(mImageHelpLib, "SymGetSymFromAddr" );
144
    if (!mSymGetSymFromAddr)
145
        return false;    
146
 
147
        mSymSetOptions(SYMOPT_DEFERRED_LOADS);
148
 
149
        // Get image filename of the main executable
150
        char filepath[MAX_PATH], *lastdir, *pPath;
151
        DWORD filepathlen = GetModuleFileNameA ( NULL, filepath, sizeof(filepath));
152
 
153
    lastdir = strrchr (filepath, '/');
154
    if (lastdir == NULL) lastdir = strrchr (filepath, '\\');
155
    if (lastdir != NULL) lastdir[0] = '\0';
156
 
157
    // Initialize the symbol table routines, supplying a pointer to the path
158
    pPath = filepath;
159
    if (strlen (filepath) == 0) pPath = NULL;
160
 
161
     if (!mSymInitialize (GetCurrentProcess(), pPath, TRUE))
162
                return false;
163
 
164
    return true;
165
}
166
 
167
void SEHCatcher::UnloadImageHelp()
168
{
169
        if (mImageHelpLib != NULL)
170
                FreeLibrary(mImageHelpLib);
171
}
172
 
173
static bool StrToLongHex(const std::string& aString, DWORD* theValue)
174
{      
175
        *theValue = 0;
176
 
177
        for (int i = 0; i < (int)aString.length(); i++)
178
        {
179
                char aChar = aString[i];
180
 
181
                int aValue;
182
                if ((aChar >= '0') && (aChar <= '9'))
183
                        aValue = aChar - '0';
184
                else if ((aChar >= 'A') && (aChar <= 'F'))
185
                        aValue = (aChar - 'A') + 10;
186
                else if ((aChar >= 'a') && (aChar <= 'f'))
187
                        aValue = (aChar - 'a') + 10;
188
                else
189
                        return false;
190
 
191
                *theValue += aValue << ((aString.length()-i-1)*4);
192
        }
193
 
194
        return true;
195
}
196
 
197
void SEHCatcher::GetSymbolsFromMapFile(std::string &theDebugDump)
198
{
199
        DWORD aTick = GetTickCount();
200
        WIN32_FIND_DATAA aFindData;
201
        HANDLE aFindHandle = FindFirstFileA("*.map",&aFindData);
202
        if (aFindHandle==INVALID_HANDLE_VALUE)
203
                return;
204
 
205
        FindClose(aFindHandle);
206
 
207
        typedef std::pair<DWORD,DWORD> SymbolPair;
208
        typedef std::map<SymbolPair,std::string> SymbolMap;
209
        typedef std::pair<std::string,int> LineNumPair;
210
        typedef std::map<SymbolPair,LineNumPair> LineNumMap;
211
 
212
/**/
213
        SymbolMap aSymbolMap;
214
        LineNumMap aLineNumMap;
215
        std::fstream aFile(aFindData.cFileName, std::ios::in);
216
 
217
        if (!aFile.is_open())
218
                return;
219
 
220
        // Parse map file
221
        std::string aCurLinesFile;
222
        while (!aFile.eof())
223
        {
224
                char aStr[4096];
225
                aFile.getline(aStr, 4096);
226
 
227
                std::string aString = aStr;
228
 
229
                if ((aString.length() > 22) && (aString[5] == ':'))
230
                {
231
                        std::string aFoundPreStr = aString.substr(1, 4);
232
                        std::string aFoundPostStr = aString.substr(6, 8);
233
 
234
                        DWORD aFoundPreVal;
235
                        DWORD aFoundPostVal;
236
 
237
                        if (StrToLongHex(aFoundPreStr, &aFoundPreVal) && StrToLongHex(aFoundPostStr, &aFoundPostVal))
238
                        {
239
                                int aSpacePos = aString.find(' ', 21);
240
 
241
                                if ((aString[20] == ' ') && (aSpacePos >= 0))
242
                                        aSymbolMap[SymbolPair(aFoundPreVal,aFoundPostVal)] =  aString.substr(21, aSpacePos-21);
243
                        }
244
                }
245
                else if (strcmp(aString.substr(0, strlen("Line numbers")).c_str(), "Line numbers") == 0)
246
                {
247
                        int aSegmentPos = aString.rfind(')');
248
                        if (aSegmentPos == -1)
249
                                aSegmentPos = aString.length();
250
 
251
                        int aPreLen = strlen("Line numbers for ");
252
 
253
                        int aStartPos = aString.find('(');
254
 
255
                        aCurLinesFile = aString.substr(aStartPos + 1, aSegmentPos - aStartPos - 1);
256
                }
257
                else if ((aCurLinesFile.length() > 0) && (aString.length() == 80))
258
                {      
259
                        // Line number stuff
260
 
261
                        for (int i = 0; i < 4; i++)
262
                        {
263
                                int aStartLoc = 20 * i;
264
 
265
                                int aLine = atoi(aString.substr(aStartLoc, 6).c_str());
266
 
267
                                std::string aFoundPreStr = aString.substr(aStartLoc + 7, 4);
268
                                std::string aFoundPostStr = aString.substr(aStartLoc + 12, 8);
269
 
270
                                DWORD aFoundPreVal;
271
                                DWORD aFoundPostVal;
272
 
273
                                if (StrToLongHex(aFoundPreStr, &aFoundPreVal) && StrToLongHex(aFoundPostStr, &aFoundPostVal))
274
                                {
275
                                        aLineNumMap[SymbolPair(aFoundPreVal,aFoundPostVal)] = LineNumPair(aCurLinesFile,aLine);
276
                                }
277
                        }
278
                }
279
        }
280
 
281
        // Parse stack trace
282
        for (int i = 0; i < (int)theDebugDump.length(); i++)
283
        {
284
                if (theDebugDump.at(i) == ':')
285
                {
286
                        std::string aFindPreStr = theDebugDump.substr(i-4, 4);
287
                        std::string aFindPostStr = theDebugDump.substr(i+1, 8);
288
 
289
                        DWORD aFindPreVal;
290
                        DWORD aFindPostVal;
291
 
292
                        if (StrToLongHex(aFindPreStr, &aFindPreVal) && StrToLongHex(aFindPostStr, &aFindPostVal))
293
                        {
294
 
295
                                int aBestDist = -1;
296
                                SymbolMap::iterator aSymbolItr  = aSymbolMap.lower_bound(SymbolPair(aFindPreVal,aFindPostVal));
297
                                if (aSymbolItr!=aSymbolMap.end() && aSymbolItr!=aSymbolMap.begin() && aSymbolItr->first.second!=aFindPostVal)
298
                                        --aSymbolItr;
299
 
300
                                if (aSymbolItr!=aSymbolMap.end() && aSymbolItr->first.first==aFindPreVal)
301
                                        aBestDist = aFindPostVal - aSymbolItr->first.second;
302
 
303
                                if (aBestDist != -1)
304
                                {
305
                                        std::string &aBestName = aSymbolItr->second;
306
 
307
                                        char aSymbolName[4096];
308
 
309
                                        if (mUnDecorateSymbolName(aBestName.c_str(), aSymbolName, 4096,
310
                                                UNDNAME_NO_ALLOCATION_MODEL | UNDNAME_NO_ACCESS_SPECIFIERS |
311
                                                UNDNAME_NO_THROW_SIGNATURES | UNDNAME_NO_MEMBER_TYPE) == 0)
312
                                                strcpy(aSymbolName, aBestName.c_str());
313
 
314
                                        if (aBestDist != 0)
315
                                        {
316
                                                sprintf(aSymbolName+strlen(aSymbolName), "+0x%X", aBestDist);
317
                                        }
318
 
319
                                        std::string aNewText = aSymbolName;
320
 
321
                                        LineNumMap::iterator aLineNumItr = aLineNumMap.lower_bound(SymbolPair(aFindPreVal,aFindPostVal));
322
                                        if (aLineNumItr!=aLineNumMap.end() && aLineNumItr!=aLineNumMap.begin() && aLineNumItr->first.second!=aFindPostVal)
323
                                                --aLineNumItr;
324
 
325
                                        if (aLineNumItr!=aLineNumMap.end() && aLineNumItr->first.first==aFindPreVal)
326
                                        {                                                      
327
                                                std::string &aBestFile = aLineNumItr->second.first;
328
                                                int aBestLine = aLineNumItr->second.second;
329
                                                int aBestLineDist =  aFindPostVal - aLineNumItr->first.second;
330
 
331
                                                char aDistStr[4096];
332
                                                sprintf(aDistStr, "\r\n    %s line %d +0x%X", aBestFile.c_str(), aBestLine, aBestLineDist);
333
                                                aNewText += aDistStr;
334
                                        }
335
 
336
                                        theDebugDump.erase(i-4, 13);
337
                                        theDebugDump.insert(i-4, aNewText.c_str());
338
                                }
339
                        }
340
                }
341
        }
342
 
343
//      MessageBox(NULL,StrFormat("%d",GetTickCount()-aTick).c_str(),"Time",MB_OK);
344
}
345
 
346
void SEHCatcher::DoHandleDebugEvent(LPEXCEPTION_POINTERS lpEP)
347
{
348
        bool hasImageHelp = LoadImageHelp();
349
 
350
        std::string anErrorTitle;
351
        std::string aDebugDump;
352
 
353
        char aBuffer[2048];
354
 
355
                ///////////////////////////
356
        // first name the exception     
357
        char  *szName = NULL;
358
    for (int i=0; gMsgTable[i].dwExceptionCode != 0xFFFFFFFF; i++)
359
        {
360
        if (gMsgTable[i].dwExceptionCode == lpEP->ExceptionRecord->ExceptionCode)
361
                {
362
            szName = gMsgTable[i].szMessage;
363
            break;
364
        }
365
    }  
366
 
367
    if (szName != NULL)
368
        {              
369
                sprintf(aBuffer,"Exception: %s (code 0x%x) at address %08X in thread %X\r\n",
370
                                szName, lpEP->ExceptionRecord->ExceptionCode,
371
                                lpEP->ExceptionRecord->ExceptionAddress, GetCurrentThreadId());
372
        }
373
        else
374
        {
375
                sprintf(aBuffer,"Unknown exception: (code 0x%x) at address %08X in thread %X\r\n",
376
                                lpEP->ExceptionRecord->ExceptionCode,
377
                                lpEP->ExceptionRecord->ExceptionAddress, GetCurrentThreadId());
378
        }
379
 
380
        aDebugDump += aBuffer; 
381
 
382
        ///////////////////////////////////////////////////////////
383
        // Get logical address of the module where exception occurs
384
        DWORD section, offset;
385
        GetLogicalAddress(lpEP->ExceptionRecord->ExceptionAddress, aBuffer, sizeof(aBuffer), section, offset);
386
        aDebugDump += "Module: " + GetFilename(aBuffer) + "\r\n";              
387
        sprintf(aBuffer, "Logical Address: %04X:%08X\r\n", section, offset);
388
        aDebugDump += aBuffer; 
389
 
390
        aDebugDump += "\r\n";  
391
 
392
        anErrorTitle = StrFormat("Exception at %04X:%08X", section, offset);
393
 
394
        std::string aWalkString;       
395
 
396
        if (hasImageHelp)
397
                aWalkString = ImageHelpWalk(lpEP->ContextRecord, 0);
398
 
399
        if (aWalkString.length() == 0)
400
                aWalkString = IntelWalk(lpEP->ContextRecord, 0);
401
 
402
        aDebugDump += aWalkString;
403
 
404
        aDebugDump += "\r\n";
405
        sprintf(aBuffer, ("EAX:%08X EBX:%08X ECX:%08X EDX:%08X ESI:%08X EDI:%08X\r\n"),
406
            lpEP->ContextRecord->Eax, lpEP->ContextRecord->Ebx, lpEP->ContextRecord->Ecx, lpEP->ContextRecord->Edx, lpEP->ContextRecord->Esi, lpEP->ContextRecord->Edi);
407
        aDebugDump += aBuffer;
408
    sprintf(aBuffer, "EIP:%08X ESP:%08X  EBP:%08X\r\n", lpEP->ContextRecord->Eip, lpEP->ContextRecord->Esp, lpEP->ContextRecord->Ebp); 
409
        aDebugDump += aBuffer;
410
    sprintf(aBuffer, "CS:%04X SS:%04X DS:%04X ES:%04X FS:%04X GS:%04X\r\n", lpEP->ContextRecord->SegCs, lpEP->ContextRecord->SegSs, lpEP->ContextRecord->SegDs, lpEP->ContextRecord->SegEs, lpEP->ContextRecord->SegFs, lpEP->ContextRecord->SegGs );
411
        aDebugDump += aBuffer;
412
    sprintf(aBuffer, "Flags:%08X\r\n", lpEP->ContextRecord->EFlags );
413
        aDebugDump += aBuffer;
414
 
415
        aDebugDump += "\r\n";
416
        aDebugDump += GetSysInfo();    
417
 
418
        if (mApp != NULL)
419
        {
420
                std::string aGameSEHInfo = mApp->GetGameSEHInfo();
421
                if (aGameSEHInfo.length() > 0)
422
                {
423
                        aDebugDump += "\r\n";
424
                        aDebugDump += aGameSEHInfo;
425
                }
426
 
427
                mApp->CopyToClipboard(aDebugDump);
428
        }              
429
 
430
        if (hasImageHelp)
431
                GetSymbolsFromMapFile(aDebugDump);
432
 
433
        WriteToFile(aDebugDump);
434
 
435
#ifdef ZYLOM
436
        ZylomGS_StandAlone_SendBugReport((char*) aDebugDump.c_str());
437
#else
438
        if (mApp != NULL)
439
        {
440
                if (mApp->mRecordingDemoBuffer)
441
                {
442
                        // Make sure we have enough update block things in there to
443
                        //  get to the final crashing update
444
                        mApp->WriteDemoTimingBlock();
445
                        mApp->mDemoBuffer.WriteNumBits(0, 1);
446
                        mApp->mDemoBuffer.WriteNumBits(DEMO_IDLE, 5);
447
                        mApp->WriteDemoBuffer();               
448
                        mUploadFileName = mApp->mDemoFileName;
449
                }      
450
 
451
                mHasDemoFile = mApp->mRecordingDemoBuffer;
452
                std::string anUploadFile = mApp->NotifyCrashHook();
453
                if (!anUploadFile.empty())
454
                {
455
                        mUploadFileName = anUploadFile;
456
                        mHasDemoFile = true;
457
                }
458
 
459
                mApp->mRecordingDemoBuffer = false;
460
                mApp->mPlayingDemoBuffer = false;
461
        }
462
 
463
        if (mShowUI)
464
                ShowErrorDialog(anErrorTitle, aDebugDump);
465
#endif
466
 
467
        //::MessageBox(NULL, aDebugDump.c_str(), "ERROR", MB_ICONERROR);        
468
 
469
        UnloadImageHelp();     
470
}
471
 
472
std::string SEHCatcher::IntelWalk(PCONTEXT theContext, int theSkipCount)
473
{
474
        std::string aDebugDump;
475
        char aBuffer[2048];
476
 
477
        DWORD pc = theContext->Eip;
478
    PDWORD pFrame, pPrevFrame;
479
 
480
    pFrame = (PDWORD)theContext->Ebp;
481
 
482
    for (;;)
483
    {
484
        char szModule[MAX_PATH] = "";
485
        DWORD section = 0, offset = 0;
486
 
487
        GetLogicalAddress((PVOID)pc, szModule, sizeof(szModule), section, offset);
488
 
489
        sprintf(aBuffer, "%08X  %08X  %04X:%08X %s\r\n",
490
                  pc, pFrame, section, offset, GetFilename(szModule).c_str());
491
                aDebugDump += aBuffer;
492
 
493
        pc = pFrame[1];
494
 
495
        pPrevFrame = pFrame;
496
 
497
        pFrame = (PDWORD)pFrame[0]; // proceed to next higher frame on stack
498
 
499
        if ((DWORD)pFrame & 3)    // Frame pointer must be aligned on a
500
            break;                  // DWORD boundary.  Bail if not so.
501
 
502
        if (pFrame <= pPrevFrame)
503
            break;
504
 
505
        // Can two DWORDs be read from the supposed frame address?          
506
        if (IsBadWritePtr(pFrame, sizeof(PVOID)*2))
507
            break;
508
    };
509
 
510
        return aDebugDump;
511
}
512
 
513
std::string SEHCatcher::ImageHelpWalk(PCONTEXT theContext, int theSkipCount)
514
{
515
        char aBuffer[2048];
516
        std::string aDebugDump;
517
 
518
        STACKFRAME sf;
519
        memset( &sf, 0, sizeof(sf) );  
520
 
521
        // Initialize the STACKFRAME structure for the first call.  This is only
522
        // necessary for Intel CPUs, and isn't mentioned in the documentation.
523
        sf.AddrPC.Offset       = theContext->Eip;
524
        sf.AddrPC.Mode         = AddrModeFlat;
525
        sf.AddrStack.Offset    = theContext->Esp;
526
        sf.AddrStack.Mode      = AddrModeFlat;
527
        sf.AddrFrame.Offset    = theContext->Ebp;
528
        sf.AddrFrame.Mode      = AddrModeFlat;
529
 
530
        int aLevelCount = 0;
531
 
532
        for (;;)
533
        {
534
                if (!mStackWalk(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), GetCurrentThread(),
535
                                                &sf, NULL  /*theContext*/, NULL, mSymFunctionTableAccess, mSymGetModuleBase, 0))
536
                {
537
                        DWORD lastErr = GetLastError();
538
                        sprintf(aBuffer, "StackWalk failed (error %d)\r\n", lastErr);
539
                        aDebugDump += aBuffer;
540
                        break;
541
                }
542
 
543
                if ((sf.AddrFrame.Offset == 0) || (sf.AddrPC.Offset == 0))
544
                        break;
545
 
546
                if (theSkipCount > 0)
547
                {
548
                        theSkipCount--;
549
                        continue;
550
                }
551
 
552
                BYTE symbolBuffer[sizeof(IMAGEHLP_SYMBOL) + 512];
553
                PIMAGEHLP_SYMBOL pSymbol = (PIMAGEHLP_SYMBOL)symbolBuffer;
554
                pSymbol->SizeOfStruct = sizeof(symbolBuffer);
555
                pSymbol->MaxNameLength = 512;
556
 
557
                DWORD symDisplacement = 0;  // Displacement of the input address,
558
                                                                        // relative to the start of the symbol
559
 
560
                if (mSymGetSymFromAddr(GetCurrentProcess(), sf.AddrPC.Offset, &symDisplacement, pSymbol))
561
                {
562
                        char aUDName[256];
563
                        mUnDecorateSymbolName(pSymbol->Name, aUDName, 256,
564
                                                                 UNDNAME_NO_ALLOCATION_MODEL | UNDNAME_NO_ALLOCATION_LANGUAGE |
565
                                                                 UNDNAME_NO_MS_THISTYPE | UNDNAME_NO_ACCESS_SPECIFIERS |
566
                                                                 UNDNAME_NO_THISTYPE | UNDNAME_NO_MEMBER_TYPE |
567
                                                                 UNDNAME_NO_RETURN_UDT_MODEL | UNDNAME_NO_THROW_SIGNATURES |
568
                                                                 UNDNAME_NO_SPECIAL_SYMS);
569
 
570
                        sprintf(aBuffer, "%08X %08X %hs+%X\r\n",
571
                                        sf.AddrFrame.Offset, sf.AddrPC.Offset, aUDName, symDisplacement);
572
                }
573
                else // No symbol found.  Print out the logical address instead.
574
                {
575
                        char szModule[MAX_PATH];            
576
                        DWORD section = 0, offset = 0;
577
 
578
                        GetLogicalAddress((PVOID)sf.AddrPC.Offset, szModule, sizeof(szModule), section, offset);                               
579
                        sprintf(aBuffer, "%08X %08X %04X:%08X %s\r\n", sf.AddrFrame.Offset, sf.AddrPC.Offset, section, offset, GetFilename(szModule).c_str());
580
                }
581
                aDebugDump += aBuffer;
582
 
583
                sprintf(aBuffer, "Params: %08X %08X %08X %08X\r\n", sf.Params[0], sf.Params[1], sf.Params[2], sf.Params[3]);
584
                aDebugDump += aBuffer;         
585
                aDebugDump += "\r\n";
586
 
587
                aLevelCount++;
588
        }
589
 
590
        return aDebugDump;
591
}
592
 
593
bool SEHCatcher::GetLogicalAddress(void* addr, char* szModule, DWORD len, DWORD& section, DWORD& offset)
594
{
595
    MEMORY_BASIC_INFORMATION mbi;
596
 
597
    if (!VirtualQuery(addr, &mbi, sizeof(mbi)))
598
        return false;
599
 
600
    DWORD hMod = (DWORD)mbi.AllocationBase;
601
 
602
    if (!GetModuleFileNameA((HMODULE) hMod, szModule, len))
603
        return false;
604
 
605
    // Point to the DOS header in memory
606
    PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER) hMod;
607
 
608
    // From the DOS header, find the NT (PE) header
609
    PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS) (hMod + pDosHdr->e_lfanew);
610
 
611
    PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNtHdr);
612
 
613
    DWORD rva = (DWORD) addr - hMod; // RVA is offset from module load address
614
 
615
    // Iterate through the section table, looking for the one that encompasses
616
    // the linear address.
617
    for (unsigned i = 0; i < pNtHdr->FileHeader.NumberOfSections; i++, pSection++)
618
    {
619
        DWORD sectionStart = pSection->VirtualAddress;
620
        DWORD sectionEnd = sectionStart + max(pSection->SizeOfRawData, pSection->Misc.VirtualSize);
621
 
622
        // Is the address in this section???
623
        if ((rva >= sectionStart) && (rva <= sectionEnd))
624
        {
625
            // Yes, address is in the section.  Calculate section and offset,
626
            // and store in the "section" & "offset" params, which were
627
            // passed by reference.
628
            section = i+1;
629
            offset = rva - sectionStart;
630
            return true;
631
        }
632
    }
633
 
634
    return false; // Should never get here!
635
}
636
 
637
std::string SEHCatcher::GetFilename(const std::string& thePath)
638
{
639
        int aLastSlash = max((int) thePath.rfind('\\'), (int) thePath.rfind('/'));     
640
 
641
        if (aLastSlash >= 0)
642
        {
643
                return thePath.substr(aLastSlash+1);
644
        }
645
        else
646
                return thePath;
647
}
648
 
649
HWND gEditWindow = NULL;
650
int aCount = 0;
651
 
652
static LRESULT CALLBACK SEHProgressWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
653
{
654
        switch (uMsg)
655
        {              
656
        case WM_COMMAND:
657
                {
658
                        HWND hwndCtl = (HWND) lParam;
659
                        if (hwndCtl == SEHCatcher::mNoButtonWindow)
660
                        {
661
                                // Cancel it, man!
662
                                SEHCatcher::mSubmitReportTransfer.Abort();
663
                        }
664
                }
665
                break;
666
        case WM_CLOSE:
667
                SEHCatcher::mSubmitReportTransfer.Abort();
668
                return 0;
669
        case WM_TIMER:
670
                {
671
                        if (wParam == 0)
672
                        {
673
                                int aResult = SEHCatcher::mSubmitReportTransfer.GetResultCode();
674
 
675
                                if ((aResult != HTTPTransfer::RESULT_NOT_COMPLETED) &&
676
                                        (aResult != HTTPTransfer::RESULT_NOT_STARTED))
677
                                {
678
                                        if ((aResult != HTTPTransfer::RESULT_DONE) &&
679
                                                (aResult != HTTPTransfer::RESULT_ABORTED))
680
                                        {
681
                                                SEHCatcher::mSubmitReportTransfer.Reset();
682
 
683
                                                if (::MessageBoxW(hWnd, SEHCatcher::mSubmitErrorMessage.c_str(),
684
                                                        L"Connection Failed", MB_RETRYCANCEL | MB_APPLMODAL) == IDRETRY)
685
                                                {
686
                                                        _beginthread(SEHCatcher::SubmitReportThread, 0, 0);
687
                                                        return 0;
688
                                                }
689
                                        }
690
 
691
                                        SEHCatcher::mExiting = true;
692
                                }
693
                        }
694
                        else if (wParam == 1)
695
                        {
696
                                ++aCount;
697
 
698
                                std::string aNewString = "Please Wait";
699
 
700
                                for (int i = 0; i < (aCount % 10); i++)
701
                                        aNewString += " .";
702
 
703
                                SetWindowTextA(gEditWindow, aNewString.c_str());
704
                        }
705
                }
706
                break;
707
        }
708
 
709
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
710
}
711
 
712
static void CreateProgressWindow()
713
{
714
        WNDCLASSA wc;
715
        wc.style = 0;
716
        wc.cbClsExtra = 0;
717
        wc.cbWndExtra = 0;
718
        wc.hbrBackground = ::GetSysColorBrush(COLOR_BTNFACE);
719
        wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
720
        wc.hIcon = ::LoadIcon(NULL, IDI_ERROR);
721
        wc.hInstance = gHInstance;
722
        wc.lpfnWndProc = SEHProgressWindowProc;
723
        wc.lpszClassName = "SEHProgressWindow";
724
        wc.lpszMenuName = NULL;
725
        RegisterClassA(&wc);
726
 
727
        RECT aRect;
728
                aRect.left = 0;
729
                aRect.top = 0;
730
                aRect.right = 240;
731
                aRect.bottom = 64;
732
 
733
        DWORD aWindowStyle = WS_CLIPCHILDREN | WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
734
 
735
        BOOL worked = AdjustWindowRect(&aRect, aWindowStyle, FALSE);
736
 
737
        HWND aHWnd = CreateWindowA("SEHProgressWindow", "Submitting Report",
738
                aWindowStyle,
739
                64, 64,
740
                aRect.right - aRect.left,
741
                aRect.bottom - aRect.top,
742
                NULL,
743
                NULL,
744
                gHInstance,
745
                0);
746
 
747
        // Check every 20ms to see if the transfer has completed
748
        SetTimer(aHWnd, 0, 20, NULL);
749
 
750
        // Every second we should change the edit text
751
        SetTimer(aHWnd, 1, 1000, NULL);
752
 
753
        gEditWindow = CreateWindowA("EDIT",
754
                "Please Wait",
755
 
756
                WS_VISIBLE | WS_CHILD | ES_READONLY,
757
                24, 10,
758
                240-8-8,
759
                24,
760
                aHWnd,
761
                NULL,
762
                gHInstance,
763
                0);    
764
        if (!gUseDefaultFonts)
765
                SendMessage(gEditWindow, WM_SETFONT, (WPARAM) SEHCatcher::mBoldFont, 0);
766
 
767
        SEHCatcher::mNoButtonWindow = CreateWindowA("BUTTON", "Abort",
768
                WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON | BS_PUSHBUTTON,
769
                (240 - 96)/2, 64 - 22 - 6,
770
                96,
771
                22,
772
                aHWnd,
773
                NULL,
774
                gHInstance,
775
                0);
776
        if (!gUseDefaultFonts)
777
                SendMessage(SEHCatcher::mNoButtonWindow, WM_SETFONT, (WPARAM) SEHCatcher::mDialogFont, 0);
778
 
779
        ShowWindow(aHWnd, SW_NORMAL);
780
}
781
 
782
LRESULT CALLBACK SEHCatcher::SEHWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
783
{
784
        switch (uMsg)
785
        {
786
        case WM_COMMAND:
787
                {
788
                        HWND hwndCtl = (HWND) lParam;
789
                        if (hwndCtl == mYesButtonWindow)
790
                        {
791
                                // Hide current window and bring up score submitting stuff
792
                                ShowWindow(hWnd, SW_HIDE);
793
 
794
                                ShowSubmitInfoDialog();
795
                        }                      
796
                        else if (hwndCtl == mNoButtonWindow)
797
                        {
798
                                mExiting = true;
799
                        }
800
                        else if (hwndCtl == mDebugButtonWindow)
801
                        {
802
                                mDebugError = true;
803
                                mExiting = true;
804
                        }
805
                }
806
                break;
807
        case WM_CLOSE:
808
                mExiting = true;
809
                return 0;
810
        }
811
 
812
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
813
}
814
 
815
LRESULT CALLBACK SEHCatcher::SubmitInfoWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
816
{
817
        switch (uMsg)
818
        {              
819
        case WM_COMMAND:
820
                {
821
                        HWND hwndCtl = (HWND) lParam;
822
                        if (hwndCtl == mYesButtonWindow)
823
                        {
824
                                // Hide current window and bring up score submitting stuff
825
                                ShowWindow(hWnd, SW_HIDE);
826
 
827
                                char aStr[8192];
828
                                GetWindowTextA(mEditWindow, aStr, 8192);
829
                                mUserText = aStr;
830
 
831
                                CreateProgressWindow();
832
                                _beginthread(SubmitReportThread, 0, 0);
833
                        }
834
                        else if (hwndCtl == mNoButtonWindow)
835
                        {
836
                                mExiting = true;
837
                        }
838
                }
839
                break;
840
        case WM_CLOSE:
841
                mExiting = true;
842
                return 0;
843
        }
844
 
845
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
846
}
847
 
848
void SEHCatcher::WriteToFile(const std::string& theErrorText)
849
{
850
        std::fstream aStream("crash.txt", std::ios::out);
851
        aStream << theErrorText.c_str() << std::endl;
852
}
853
 
854
void SEHCatcher::SubmitReportThread(void *theArg)
855
{
856
        std::string aSeperator = "---------------------------7d3e1f30eec";
857
 
858
        DefinesMap aSEHWebParams;
859
 
860
        mApp->GetSEHWebParams(&aSEHWebParams);
861
 
862
        std::string aContent;
863
 
864
        DefinesMap::iterator anItr = aSEHWebParams.begin();
865
        while (anItr != aSEHWebParams.end())
866
        {
867
                aContent += "--" + aSeperator + "\r\n"
868
                "Content-Disposition: form-data; name=\"" + anItr->first + "\"\r\n" +          
869
                "\r\n" +
870
                anItr->second + "\r\n";
871
 
872
                ++anItr;
873
        }
874
 
875
        aContent +=
876
 
877
                /*"--" + aSeperator + "\r\n"
878
                "Content-Disposition: form-data; name=\"username\"\r\n" +              
879
                "\r\n" +
880
                mApp->mUserName + "\r\n" +      */
881
 
882
                "--" + aSeperator + "\r\n"
883
                "Content-Disposition: form-data; name=\"prod\"\r\n" +          
884
                "\r\n" +
885
                mApp->mProdName + "\r\n" +     
886
 
887
                "--" + aSeperator + "\r\n"
888
                "Content-Disposition: form-data; name=\"version\"\r\n" +               
889
                "\r\n" +
890
                mApp->mProductVersion + "\r\n" +
891
 
892
                /*"--" + aSeperator + "\r\n"
893
                "Content-Disposition: form-data; name=\"buildnum\"\r\n" +              
894
                "\r\n" +
895
                StrFormat("%d", mApp->mBuildNum) + "\r\n" +
896
 
897
                "--" + aSeperator + "\r\n"
898
                "Content-Disposition: form-data; name=\"builddate\"\r\n" +             
899
                "\r\n" +
900
                mApp->mBuildDate + "\r\n" +
901
 
902
                "--" + aSeperator + "\r\n"
903
                "Content-Disposition: form-data; name=\"referid\"\r\n" +               
904
                "\r\n" +
905
                mApp->mReferId + "\r\n" +*/
906
 
907
                "--" + aSeperator + "\r\n"
908
                "Content-Disposition: form-data; name=\"usertext\"\r\n" +
909
                "\r\n" +
910
                mUserText + "\r\n" +
911
 
912
                "--" + aSeperator + "\r\n"
913
                "Content-Disposition: form-data; name=\"errortitle\"\r\n" +            
914
                "\r\n" +
915
                mErrorTitle + "\r\n" +
916
 
917
                "--" + aSeperator + "\r\n"
918
                "Content-Disposition: form-data; name=\"errortext\"\r\n" +             
919
                "\r\n" +
920
                mErrorText + "\r\n";
921
 
922
        if (mHasDemoFile)
923
        {
924
                Buffer aBuffer;
925
                mApp->ReadBufferFromFile(mUploadFileName, &aBuffer, true);
926
 
927
                aContent +=
928
                        "--" + aSeperator + "\r\n"
929
                        "Content-Disposition: form-data; name=\"demofile\"; filename=\"popcap.dmo\"\r\n" +
930
                        "Content-Type: application/octet-stream\r\n" +
931
                        "\r\n";        
932
 
933
                aContent.insert(aContent.end(), (char*) aBuffer.GetDataPtr(), (char*) aBuffer.GetDataPtr() + aBuffer.GetDataLen());                    
934
 
935
                aContent += "\r\n";
936
        }
937
 
938
        aContent +=
939
                "--" + aSeperator + "--\r\n";
940
 
941
        std::string aSendString =
942
                "POST /deluxe_error.php HTTP/1.1\r\n"
943
                "Content-Type: multipart/form-data; boundary=" + aSeperator + "\r\n"
944
                "User-Agent: Mozilla/4.0 (compatible; popcap)\r\n" +
945
                "Host: " + mSubmitHost + "\r\n" +
946
                "Content-Length: " + StrFormat("%d", aContent.length()) + "\r\n" +
947
                "Connection: close\r\n" +
948
                "\r\n" + aContent;
949
 
950
        mSubmitReportTransfer.SendRequestString(mSubmitHost, aSendString);
951
}
952
 
953
void SEHCatcher::ShowSubmitInfoDialog()
954
{
955
        WNDCLASSA wc;
956
        wc.style = 0;
957
        wc.cbClsExtra = 0;
958
        wc.cbWndExtra = 0;
959
        wc.hbrBackground = ::GetSysColorBrush(COLOR_BTNFACE);
960
        wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
961
        wc.hIcon = ::LoadIcon(NULL, IDI_ERROR);
962
        wc.hInstance = gHInstance;
963
        wc.lpfnWndProc = SubmitInfoWindowProc;
964
        wc.lpszClassName = "SubmitInfoWindow";
965
        wc.lpszMenuName = NULL;
966
        RegisterClassA(&wc);
967
 
968
        RECT aRect;
969
                aRect.left = 0;
970
                aRect.top = 0;
971
                aRect.right = 400;
972
                aRect.bottom = 300;
973
 
974
        DWORD aWindowStyle = WS_CLIPCHILDREN | WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
975
 
976
        BOOL worked = AdjustWindowRect(&aRect, aWindowStyle, FALSE);
977
 
978
        HWND aHWnd = CreateWindowA("SubmitInfoWindow", "Error Details",
979
                aWindowStyle,
980
                64+16, 64+16,
981
                aRect.right - aRect.left,
982
                aRect.bottom - aRect.top,
983
                NULL,
984
                NULL,
985
                gHInstance,
986
                0);
987
 
988
        HWND aLabelWindow = CreateWindowW(L"EDIT", mSubmitMessage.c_str(),
989
 
990
                WS_VISIBLE | WS_CHILD | ES_MULTILINE | ES_READONLY,
991
                8, 8,
992
                400-8-8,
993
                84,
994
                aHWnd,
995
                NULL,
996
                gHInstance,
997
                0);
998
 
999
        HDC aDC = ::GetDC(aLabelWindow);
1000
        int aFontHeight = -MulDiv(9, 96, 72);
1001
        ::ReleaseDC(aLabelWindow, aDC);
1002
        HFONT aBoldArialFont = CreateFontA(aFontHeight, 0, 0, 0, FW_BOLD, 0, 0,
1003
                        false, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
1004
                        DEFAULT_PITCH | FF_DONTCARE, "Arial");
1005
 
1006
        if (!gUseDefaultFonts)
1007
                SendMessage(aLabelWindow, WM_SETFONT, (WPARAM) aBoldArialFont, 0);
1008
 
1009
        mEditWindow = CreateWindowA("EDIT", "",
1010
                WS_VISIBLE | WS_CHILD | ES_MULTILINE | WS_BORDER | WS_VSCROLL,
1011
                8, 300-168-24-8-8,
1012
                400-8-8,
1013
                168,
1014
                aHWnd,
1015
                NULL,
1016
                gHInstance,
1017
                0);    
1018
 
1019
        aDC = ::GetDC(mEditWindow);
1020
        aFontHeight = -MulDiv(8, 96, 72);
1021
        ::ReleaseDC(mEditWindow, aDC);
1022
        HFONT aCourierNewFont = CreateFontA(aFontHeight, 0, 0, 0, FW_NORMAL, 0, 0,
1023
                        false, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
1024
                        DEFAULT_PITCH | FF_DONTCARE, "Courier New");
1025
        if (!gUseDefaultFonts)
1026
                SendMessage(mEditWindow, WM_SETFONT, (WPARAM) mDialogFont, 0);
1027
        SetFocus(mEditWindow);
1028
 
1029
        int aButtonWidth = (400 - 8 - 8 - 8) / 2;
1030
        int aCurX = 8;
1031
 
1032
        aWindowStyle = WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON | BS_PUSHBUTTON;
1033
 
1034
        if (mApp == NULL)
1035
                aWindowStyle |= WS_DISABLED;
1036
 
1037
        mYesButtonWindow = CreateWindowA("BUTTON", "Continue",
1038
                aWindowStyle,
1039
                aCurX, 300-24-8,
1040
                aButtonWidth,
1041
                24,
1042
                aHWnd,
1043
                NULL,
1044
                gHInstance,
1045
                0);
1046
        if (!gUseDefaultFonts)
1047
                SendMessage(mYesButtonWindow, WM_SETFONT, (WPARAM) aBoldArialFont, 0);
1048
 
1049
        aCurX += aButtonWidth+8;
1050
 
1051
        mNoButtonWindow = CreateWindowA("BUTTON", "Abort",
1052
                WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON | BS_PUSHBUTTON,
1053
                aCurX, 300-24-8,
1054
                aButtonWidth,
1055
                24,
1056
                aHWnd,
1057
                NULL,
1058
                gHInstance,
1059
                0);
1060
        if (!gUseDefaultFonts)
1061
                SendMessage(mNoButtonWindow, WM_SETFONT, (WPARAM) aBoldArialFont, 0);
1062
 
1063
        ShowWindow(aHWnd, SW_NORMAL);
1064
}
1065
 
1066
void SEHCatcher::ShowErrorDialog(const std::string& theErrorTitle, const std::string& theErrorText)
1067
{
1068
        OSVERSIONINFO aVersionInfo;
1069
        aVersionInfo.dwOSVersionInfoSize = sizeof(aVersionInfo);
1070
        GetVersionEx(&aVersionInfo);
1071
 
1072
        // Setting fonts on 98 causes weirdo crash things in GDI upon the second crash.
1073
        //  That's no good.     
1074
        gUseDefaultFonts = aVersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT;
1075
 
1076
        int aHeight = -MulDiv(8, 96, 72);
1077
        mDialogFont = ::CreateFontA(aHeight, 0, 0, 0, FW_NORMAL, FALSE, FALSE,
1078
                        false, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
1079
                        DEFAULT_PITCH | FF_DONTCARE, "Tahoma");
1080
 
1081
        aHeight = -MulDiv(10, 96, 72);
1082
        mBoldFont = ::CreateFontA(aHeight, 0, 0, 0, FW_BOLD, FALSE, FALSE,
1083
                        false, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
1084
                        DEFAULT_PITCH | FF_DONTCARE, "Tahoma");
1085
 
1086
        ::SetCursor(::LoadCursor(NULL, IDC_ARROW));
1087
 
1088
        mErrorTitle = theErrorTitle;
1089
        mErrorText = theErrorText;     
1090
 
1091
 
1092
        WNDCLASSA wc;
1093
        wc.style = 0;
1094
        wc.cbClsExtra = 0;
1095
        wc.cbWndExtra = 0;
1096
        wc.hbrBackground = ::GetSysColorBrush(COLOR_BTNFACE);
1097
        wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
1098
        wc.hIcon = ::LoadIcon(NULL, IDI_ERROR);
1099
        wc.hInstance = gHInstance;
1100
        wc.lpfnWndProc = SEHWindowProc;
1101
        wc.lpszClassName = "SEHWindow";
1102
        wc.lpszMenuName = NULL;
1103
        RegisterClassA(&wc);
1104
 
1105
        RECT aRect;
1106
                aRect.left = 0;
1107
                aRect.top = 0;
1108
                aRect.right = 400;
1109
                aRect.bottom = 300;
1110
 
1111
        DWORD aWindowStyle = WS_CLIPCHILDREN | WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
1112
 
1113
        BOOL worked = AdjustWindowRect(&aRect, aWindowStyle, FALSE);
1114
 
1115
        HWND aHWnd = CreateWindowW(L"SEHWindow", L"Fatal Error!",
1116
                aWindowStyle,
1117
                64, 64,
1118
                aRect.right - aRect.left,
1119
                aRect.bottom - aRect.top,
1120
                NULL,
1121
                NULL,
1122
                gHInstance,
1123
                0);
1124
 
1125
        HWND aLabelWindow = CreateWindowW(L"EDIT",
1126
                mCrashMessage.c_str(),
1127
                WS_VISIBLE | WS_CHILD | ES_MULTILINE | ES_READONLY,
1128
                8, 8,
1129
                400-8-8,
1130
                84,
1131
                aHWnd,
1132
                NULL,
1133
                gHInstance,
1134
                0);
1135
 
1136
        int aFontHeight = -MulDiv(9, 96, 72);  
1137
        HFONT aBoldArialFont = CreateFontA(aFontHeight, 0, 0, 0, FW_BOLD, 0, 0,
1138
                        false, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
1139
                        DEFAULT_PITCH | FF_DONTCARE, "Arial");
1140
 
1141
        if (!gUseDefaultFonts)
1142
                SendMessage(aLabelWindow, WM_SETFONT, (WPARAM) aBoldArialFont, 0);             
1143
 
1144
        HWND anEditWindow = CreateWindowA("EDIT", theErrorText.c_str(),
1145
                WS_VISIBLE | WS_CHILD | ES_MULTILINE | WS_BORDER | WS_VSCROLL | ES_READONLY,
1146
                8, 300-168-24-8-8,
1147
                400-8-8,
1148
                168,
1149
                aHWnd,
1150
                NULL,
1151
                gHInstance,
1152
                0);    
1153
 
1154
        aFontHeight = -MulDiv(8, 96, 72);      
1155
        HFONT aCourierNewFont = CreateFontA(aFontHeight, 0, 0, 0, FW_NORMAL, 0, 0,
1156
                        false, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
1157
                        DEFAULT_PITCH | FF_DONTCARE, "Courier New");
1158
        if (!gUseDefaultFonts)
1159
                SendMessage(anEditWindow, WM_SETFONT, (WPARAM) aCourierNewFont, 0);
1160
 
1161
        aWindowStyle = WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON | BS_PUSHBUTTON;
1162
 
1163
        if (mApp == NULL)
1164
                aWindowStyle |= WS_DISABLED;
1165
 
1166
#ifdef _DEBUG
1167
        bool doDebugButton = true;
1168
#else
1169
        bool doDebugButton = false;
1170
#endif
1171
 
1172
        bool canSubmit = mAllowSubmit && !mSubmitHost.empty(); 
1173
        int aNumButtons = 1 + (doDebugButton ? 1 : 0) + (canSubmit ? 1 : 0);
1174
 
1175
        int aButtonWidth = (400 - 8 - 8 - (aNumButtons - 1)*8) / aNumButtons;          
1176
 
1177
        int aCurX = 8;
1178
 
1179
        if (canSubmit)
1180
        {
1181
                mYesButtonWindow = CreateWindowA("BUTTON", "Send Report",
1182
                        aWindowStyle,
1183
                        aCurX, 300-24-8,
1184
                        aButtonWidth,
1185
                        24,
1186
                        aHWnd,
1187
                        NULL,
1188
                        gHInstance,
1189
                        0);
1190
                if (!gUseDefaultFonts)
1191
                        SendMessage(mYesButtonWindow, WM_SETFONT, (WPARAM) aBoldArialFont, 0);
1192
 
1193
                aCurX += aButtonWidth + 8;     
1194
        }
1195
 
1196
        if (doDebugButton)
1197
        {
1198
                mDebugButtonWindow = CreateWindowA("BUTTON", "Debug",
1199
                        aWindowStyle,
1200
                        aCurX, 300-24-8,
1201
                        aButtonWidth,
1202
                        24,
1203
                        aHWnd,
1204
                        NULL,
1205
                        gHInstance,
1206
                        0);            
1207
                if (!gUseDefaultFonts)
1208
                        SendMessage(mDebugButtonWindow, WM_SETFONT, (WPARAM) aBoldArialFont, 0);               
1209
 
1210
                aCurX += aButtonWidth + 8;
1211
        }
1212
 
1213
        mNoButtonWindow = CreateWindowA("BUTTON", "Close Now",
1214
                WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON | BS_PUSHBUTTON,
1215
                aCurX, 300-24-8,
1216
                aButtonWidth,
1217
                24,
1218
                aHWnd,
1219
                NULL,
1220
                gHInstance,
1221
                0);
1222
 
1223
        if (!gUseDefaultFonts)
1224
                SendMessage(mNoButtonWindow, WM_SETFONT, (WPARAM) aBoldArialFont, 0);
1225
 
1226
        ShowWindow(aHWnd, SW_NORMAL);
1227
 
1228
        MSG msg;
1229
        while ((GetMessage(&msg, NULL, 0, 0) > 0) && (!mExiting))
1230
        {
1231
                TranslateMessage(&msg);
1232
                DispatchMessage(&msg);
1233
        }      
1234
 
1235
        DestroyWindow(aHWnd);
1236
 
1237
        DeleteObject(mDialogFont);
1238
        DeleteObject(mBoldFont);
1239
        DeleteObject(aBoldArialFont);
1240
        DeleteObject(aCourierNewFont);
1241
}
1242
 
1243
std::string SEHCatcher::GetSysInfo()
1244
{
1245
        std::string aDebugDump;
1246
 
1247
        OSVERSIONINFOA aVersionInfo;
1248
        aVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1249
        GetVersionExA(&aVersionInfo);
1250
 
1251
        aDebugDump += "Windows Ver: ";
1252
        if (aVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
1253
                aDebugDump += "NT ";
1254
        else
1255
                aDebugDump += "9x ";
1256
 
1257
        char aVersionStr[20];
1258
        sprintf(aVersionStr, "%d.%d", aVersionInfo.dwMajorVersion, aVersionInfo.dwMinorVersion);
1259
        aDebugDump += aVersionStr;
1260
        aDebugDump += " ";
1261
        aDebugDump += aVersionInfo.szCSDVersion;
1262
        aDebugDump += " ";
1263
        sprintf(aVersionStr, "%d", aVersionInfo.dwBuildNumber);
1264
        aDebugDump += "Build ";
1265
        aDebugDump += aVersionStr;
1266
        aDebugDump += "\r\n";
1267
 
1268
        HMODULE aMod;
1269
        char aPath[256];
1270
 
1271
        if (mApp != NULL)
1272
        {
1273
                aMod = LoadLibraryA("ddraw.dll");
1274
                if (aMod != NULL)
1275
                {
1276
                        GetModuleFileNameA(aMod, aPath, 256);                  
1277
                        aDebugDump += "DDraw Ver: " + mApp->GetProductVersion(aPath) + "\r\n";
1278
                        FreeLibrary(aMod);
1279
                }
1280
 
1281
                aMod = LoadLibraryA("dsound.dll");
1282
                if (aMod != NULL)
1283
                {
1284
                        GetModuleFileNameA(aMod, aPath, 256);                  
1285
                        aDebugDump += "DSound Ver: " + mApp->GetProductVersion(aPath) + "\r\n";
1286
                        FreeLibrary(aMod);
1287
                }
1288
        }      
1289
 
1290
        return aDebugDump;
1291
}      
1292