123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- //===========================================================================//
- // Copyright (C) Microsoft Corporation. All rights reserved. //
- //===========================================================================//
- #include <windows.h>
- #include <stdio.h>
- #include "msodw.h"
- #include "utilities.h"
- #include "..\resource.h"
- #include <gameos.hpp>
- long _stdcall ProcessException( EXCEPTION_POINTERS* ep );
- extern HWND hWindow;
- void EnterWindowMode();
- #define EXTERNAL
- //--------------------------------------------------------------------------------------------
- //DW Exception Code for MC2.
- //
- // Simple, really. Setup the exception filter by calling InitDW.
- // After DW is inited, ANY exception which occurs in ANY thread will be handed
- // to DW first. Any problem with running DW OR when DW ends, the GameOS exception handler
- // will triggered to give even more data to the user.
- //
- //--------------------------------------------------------------------------------------------
- char WatsonCrashMessage[4096];
- //Will be allocated below.
- WCHAR *WatsonCrashMessageUnicode = NULL;
- /*
- * AnsiToUnicode converts the ANSI string pszA to a Unicode string
- * and returns the Unicode string through ppszW. Space for the
- * the converted string is allocated by AnsiToUnicode.
- */
- HRESULT __fastcall AnsiToUnicode(LPCSTR pszA, LPOLESTR* ppszW)
- {
- ULONG cCharacters;
- DWORD dwError;
- // If input is null then just return the same.
- if (NULL == pszA)
- {
- *ppszW = NULL;
- return NOERROR;
- }
- // Determine number of wide characters to be allocated for the
- // Unicode string.
- cCharacters = strlen(pszA)+1;
- // Use of the OLE allocator is required if the resultant Unicode
- // string will be passed to another COM component and if that
- // component will free it. Otherwise you can use your own allocator.
- *ppszW = (LPOLESTR)malloc(cCharacters*2);
- if (NULL == *ppszW)
- return E_OUTOFMEMORY;
- // Covert to Unicode.
- if (0 == MultiByteToWideChar(CP_ACP, 0, pszA, cCharacters,
- *ppszW, cCharacters))
- {
- dwError = GetLastError();
- free(*ppszW);
- *ppszW = NULL;
- return HRESULT_FROM_WIN32(dwError);
- }
- return NOERROR;
- }
- //----------------------------------------------------------------------------
- // ORIGINAL source from testCrash.cpp.
- // %%Function: DwHandleException
- // %%Contact: MRuhlen
- // Calls DW in the event of an exception
- // Calls GameOS exception handler AFTER DW has had a crack at it.
- //----------------------------------------------------------------------------
- LONG WINAPI DwExceptionFilter(LPEXCEPTION_POINTERS pep)
- {
- EXCEPTION_RECORD *per;
- HANDLE hFileMap;
- DWSharedMem *pdwsm;
- SECURITY_ATTRIBUTES sa;
-
- //------------------------------------------------------------------------------------------------------------
- // we keep local copies of these in case another thread is trashing memory
- // it much more likely to trash the heap than our stack
- HANDLE hEventDone; // event DW signals when done
- HANDLE hEventAlive; // heartbeat event DW signals per EVENT_TIMEOUT
- HANDLE hMutex; // to protect the signaling of EventDone
-
- char szCommandLine[MAX_PATH * 2];
-
- DWORD dw;
- BOOL fDwRunning;
-
- STARTUPINFO si;
- PROCESS_INFORMATION pi;
-
- //------------------------------------------------------------------------------------------------------------
- // init - Check if we just hit a breakpoint. If so, continue execution. Debugger will take care of itself.
- per = pep->ExceptionRecord;
- if (EXCEPTION_BREAKPOINT == per->ExceptionCode)
- return 0;
- //------------------------------------------------------------------------------------------------------------
- // create shared memory
- memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
- sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- sa.bInheritHandle = TRUE;
-
- hFileMap = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, sizeof(DWSharedMem), NULL);
- if (hFileMap == NULL)
- {
- //At this point, call the GameOS exception handler and convert the pep to the data they need!
- ProcessException(pep);
- return 1;
- }
-
- pdwsm = (DWSharedMem *) MapViewOfFile(hFileMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
- if (pdwsm == NULL)
- {
- //At this point, call the GameOS exception handler and convert the pep to the data they need!
- ProcessException(pep);
- return 1;
- }
- memset(pdwsm, 0, sizeof(DWSharedMem));
- hEventAlive = CreateEvent(&sa, FALSE, FALSE, NULL);
- hEventDone = CreateEvent(&sa, FALSE, FALSE, NULL);
- hMutex = CreateMutex(&sa, FALSE, NULL);
- if (!DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &pdwsm->hProc, PROCESS_ALL_ACCESS, TRUE, 0))
- {
- //At this point, call the GameOS exception handler and convert the pep to the data they need!
- ProcessException(pep);
- return 1;
- }
- if (hEventAlive == NULL || hEventDone == NULL || hMutex == NULL || pdwsm->hProc == NULL)
- {
- //At this point, call the GameOS exception handler and convert the pep to the data they need!
- ProcessException(pep);
- return 1;
- }
- //------------------------------------------------------------------------------------------------------------
- // setup interface structure
- pdwsm->pid = GetCurrentProcessId();
- pdwsm->tid = GetCurrentThreadId();
- pdwsm->hEventAlive = hEventAlive;
- pdwsm->hEventDone = hEventDone;
- pdwsm->hMutex = hMutex;
- pdwsm->dwSize = sizeof(DWSharedMem);
- pdwsm->pep = pep;
- pdwsm->eip = (DWORD) pep->ExceptionRecord->ExceptionAddress;
- pdwsm->bfmsoctdsOffer = msoctdsQuit;
- pdwsm->bfmsoctdsLetRun = msoctdsQuit;
- pdwsm->bfDWBehaviorFlags = fDwCheckSig;
- strcpy(pdwsm->szFormalAppName, Environment.applicationName);
- strcpy(pdwsm->szInformalAppName, "MechCommander 2");
- strcpy(pdwsm->szRegSubPath, "Software\\Microsoft\\Microsoft Games\\");
- strcat(pdwsm->szRegSubPath, Environment.applicationName);
- // strcpy(pdwsm->szLCIDKeyValue, "");
- // strcpy(pdwsm->szPIDRegKey, "HKLM\\Software\\Microsoft\\Internet Explorer\\Registration\\DigitalProductID");
- #if defined(FINAL) || defined(EXTERNAL)
- strcpy(pdwsm->szServer, "watson.microsoft.com");
- #else
- strcpy(pdwsm->szServer, "officewatson");
- #endif
- wcscpy(pdwsm->wzErrorMessage, WatsonCrashMessageUnicode);
- //Leave this alone? No idea what it does. Not in Docs.
- // OK, I kinda know now. These are DLLs that Watson can check for goodness at crash time.
- // COOL, because the end user might have mucked with the EXE or data and this allows us to
- // report that information back to the server.
- memcpy(pdwsm->wzDotDataDlls, L"mc2res.dll\0editores.dll\0", 24 * sizeof(WCHAR));
- GetModuleFileNameA(NULL, pdwsm->szModuleFileName, DW_MAX_PATH);
- //Additional Files for MechCommander? Should there be any? Log files, etc.
- // ok, now we don't want to accidently change this
- memset(&si, 0, sizeof(STARTUPINFO));
- si.cb = sizeof(STARTUPINFO);
- memset(&pi, 0, sizeof(PROCESS_INFORMATION));
-
- wsprintfA(szCommandLine, "dw -x -s %u", (DWORD) hFileMap);
- //Check if we are in fullScreen mode. If so, switch back to WindowMode to insure DW screen comes up.
- if(Environment.fullScreen && hWindow )
- EnterWindowMode();
- if (CreateProcessA(NULL, szCommandLine, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi))
- {
- fDwRunning = TRUE;
- while (fDwRunning)
- {
- if (WaitForSingleObject(hEventAlive, DW_TIMEOUT_VALUE * 100) == WAIT_OBJECT_0)
- {
- if (WaitForSingleObject(hEventDone, 1) == WAIT_OBJECT_0)
- {
- fDwRunning = FALSE;
- }
- continue;
- }
-
- // we timed-out waiting for DW to respond, try to quit
- dw = WaitForSingleObject(hMutex, DW_TIMEOUT_VALUE);
- if (dw == WAIT_TIMEOUT)
- {
- fDwRunning = FALSE; // either DW's hung or crashed, we must carry on
- }
- else if (dw == WAIT_ABANDONED)
- {
- fDwRunning = FALSE;
- ReleaseMutex(hMutex);
- }
- else
- {
- // DW has not woken up?
- if (WaitForSingleObject(hEventAlive, 1) != WAIT_OBJECT_0)
- // tell DW we're through waiting for it's sorry self
- {
- SetEvent(hEventDone);
- fDwRunning = FALSE;
- }
- else
- {
- // are we done
- if (WaitForSingleObject(hEventDone, 1) == WAIT_OBJECT_0)
- fDwRunning = FALSE;
- }
- ReleaseMutex(hMutex);
- }
- }
- #if 0
- // did we get attached?
- // Again, do NOT term the current APP. Late GameOS have its shot at the exception.
- if (WaitForSingleObject(hEventDBAttach, 1) == WAIT_OBJECT_0)
- {
- // yes, die
- MessageBox(NULL, "DB Attach ", "out", MB_OK);
- CloseHandle(hEventAlive);
- CloseHandle(hEventDone);
- CloseHandle(hMutex);
- TerminateProcess(GetCurrentProcess(), 0);
- }
- #endif
- // no, clean up
- CloseHandle(hEventAlive);
- CloseHandle(hEventDone);
- CloseHandle(hMutex);
- } // end if CreateProcess succeeded
-
- UnmapViewOfFile(pdwsm);
- CloseHandle(hFileMap);
- //At this point, call the GameOS exception handler and convert the pep to the data they need!
- ProcessException(pep);
- return 1;
- }
- //----------------------------------------------------------------------------
- void InitDW (void)
- {
- cLoadString(IDS_WATSON_CRASH_MSG,WatsonCrashMessage,4095);
- AnsiToUnicode(WatsonCrashMessage,&WatsonCrashMessageUnicode);
- SetUnhandledExceptionFilter(DwExceptionFilter);
- }
- //----------------------------------------------------------------------------
|