home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / except1.zip / Xcept.C < prev   
C/C++ Source or Header  |  1994-09-26  |  29KB  |  814 lines

  1. #pragma    title("Example Exception Handler  --  Version 1.0  --  (Xcept.C)")
  2. #pragma    subtitle("   Exception Handler - Interface Definitions")
  3.  
  4. #define    INCL_DOS           /* Include OS/2 DOS Kernal        */
  5. #define    INCL_WIN           /* Include OS/2 PM Windows Interface    */
  6.  
  7. #pragma    info(nopar, noext)
  8.  
  9. #include <os2.h>
  10. #include <setjmp.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14.  
  15. #include "appdefs.h"
  16. #include "except.h"
  17.  
  18.  
  19. /* This    module contains    the example exception handler and dialogue    */
  20. /* display.                                */
  21.  
  22. /* Filename:   XCept.C                            */
  23.  
  24. /*  Version:   3.0                            */
  25. /*  Created:   1994-08-22                        */
  26. /*  Revised:   1994-08-22                        */
  27.  
  28. /* Routines:   VOID XEndAddress(VOID);                    */
  29. /*           static VOID SortAddresses(INTERNALADDRESSLIST *aial,    */
  30. /*                     INT sLeft, INT    sRight);    */
  31. /*           static BOOL fLookupAddress(PVOID    pvExceptAddress,    */
  32. /*                      PEXCEPT pex,            */
  33. /*                      BOOL fStackTrace,        */
  34. /*                      INT cFunctions);        */
  35. /*           APIRET APIENTRY ExceptionHandler(            */
  36. /*                   PEXCEPTIONREPORTRECORD pxcptrepr,    */
  37. /*                   PEXCEPTIONREGISTRATIONRECORD pxcptregr,    */
  38. /*                   PCONTEXTRECORD pcr, PVOID sysinfo);    */
  39. /*           static PSZ pszHexShort(ULONG ul,    PSZ pszBuffer);        */
  40. /*           static PSZ pszHex(ULONG ul, PSZ pszBuffer);        */
  41. /*           static PSZ pszFormAddress(PSZ pszBuffer,    ULONG ulSeg,*/
  42. /*                         ULONG ulBase);        */
  43. /*           MRESULT EXPENTRY    ExceptionDlgProc(HWND hWnd, ULONG msg,    */
  44. /*                         MPARAM    mp1,        */
  45. /*                         MPARAM    mp2);        */
  46.  
  47.  
  48. /* Copyright ╕ 1994, 1995  Prominare Inc.  All Rights Reserved.        */
  49.  
  50. /* --------------------------------------------------------------------    */
  51.  
  52. INT  main(INT, CHAR *[ ]);
  53. VOID XEndAddress(VOID);
  54.  
  55. /* --- External    Definitions -------------------------------------------    */
  56.  
  57. /************************************************************************/
  58. /*                                    */
  59. /*     DEBUGGING SUPPORT     DEBUGGING SUPPORT       DEBUGGING SUPPORT    */
  60. /*                                    */
  61. /************************************************************************/
  62.  
  63. static INTERNALADDRESSLIST aial[ ] = { { (PFNINTADD)XEndAddress, "XEndAddress" },
  64.                        { NULL, NULL } };
  65.  
  66. static INTERNALADDRESSLIST *pial;  /* Constructed Address List        */
  67. static PINT piModules;           /* Constructed Modules Array        */
  68.  
  69. INTERNALADDRESS    intaddXceptionHandler =     { __FILE__, 0,    aial };
  70.  
  71. extern INTERNALADDRESS intadd3DLine;
  72. extern INTERNALADDRESS intadd3DText;
  73. extern INTERNALADDRESS intaddDialog1;
  74. extern INTERNALADDRESS intaddDialog2;
  75. extern INTERNALADDRESS intaddExcept;
  76. extern INTERNALADDRESS intaddSupport;
  77. extern INTERNALADDRESS intaddWndProc;
  78.  
  79. #define    CMODULES 7
  80.  
  81. INTERNALADDRESS    *aintadd[ ] = {    &intaddExcept,       /* Always place first module    here */
  82.                 &intadd3DLine,
  83.                 &intadd3DText,
  84.                 &intaddDialog1,
  85.                 &intaddDialog2,
  86.                 &intaddSupport,
  87.                 &intaddWndProc,
  88.                 &intaddXceptionHandler };
  89.  
  90. /************************************************************************/
  91. /*                                    */
  92. /*     DEBUGGING SUPPORT     DEBUGGING SUPPORT       DEBUGGING SUPPORT    */
  93. /*                                    */
  94. /************************************************************************/
  95.  
  96. BOOL   (* EXPENTRY pfnDllExceptionLookup)(PVOID    ExceptionAddress, PSZ pszName,
  97.                       PSZ pszModule, PSZ pszFunction,
  98.                       PVOID    *pfnStart, PVOID *pfnEnd);
  99.  
  100. typedef    struct _EXCEPT
  101.    {
  102.    PEXCEPTIONREPORTRECORD pxcptrepr;
  103.    PCONTEXTRECORD      pcr;
  104.    INT              iIntAdd;
  105.    CHAR              szComponent[CCHMAXPATH];
  106.    CHAR              szModule[CCHMAXPATH];
  107.    CHAR              szFunction[64];
  108.    BOOL              fStackTraced;
  109.    PVOID          pfnStart;
  110.    PVOID          pfnEnd;
  111.    PID              pid;
  112.    TID              tid;
  113.    } EXCEPT, *PEXCEPT;
  114.  
  115. static VOID SortAddresses(INTERNALADDRESSLIST *aial, INT sLeft,    INT sRight);
  116. static BOOL fLookupAddress(PVOID pvExceptAddress, PEXCEPT pex, BOOL fStackTrace, INT cFunctions);
  117.  
  118. static PSZ pszRegisters    =
  119. "\r\n\r\nRegister dump:\r\nEAX = 0x%08X    EBX = 0x%08X    ECX = 0x%08X    EDX = 0x%08X\r\n"
  120. "EBP = 0x%08X    EDI = 0x%08X    ESI = 0x%08X    ESP = 0x%08X\r\n"
  121. " CS = 0x%04X         DS = 0x%04X         ES = 0x%04X         FS = 0x%04X\r\n"
  122. " GS = 0x%04X         SS = 0x%04X\r\n\r\n"
  123. "%s-%02d-%02d %02d:%02d:%02d.%02d\r\nPID: %u  TID: %u\r\n\r\n";
  124.  
  125. static PSZ pszAddresses    =
  126. "main( )             : 0x%08X\r\n"
  127. "ExceptionHandler( ) : 0x%08X\r\n"
  128. "-----\r\n\r\n";
  129.  
  130. static PSZ apszMonth[12] = { "Jan", "Feb", "Mar", "Apr", "May",    "Jun",
  131.                  "Jul", "Aug", "Sep", "Oct", "Nov",    "Dec" };
  132.  
  133. static PSZ pszFormAddress(PSZ pszBuffer, ULONG ulSeg, ULONG ulBase);
  134. static PSZ pszHexShort(ULONG ul, PSZ pszBuffer);
  135. static PSZ pszHex(ULONG    ul, PSZ    pszBuffer);
  136.  
  137. typedef    struct _EXCEPTINFO
  138.    {
  139.    PEXCEPT  pex;           /* Exception    Data            */
  140.    PSZ        pszTitle;           /* Dialogue Title            */
  141.    PSZ        pszXCP;           /* XCP Filename            */
  142.    BOOL        fFatal;           /* Fatal Error Flag            */
  143.    } EXCEPTINFO, *PEXCEPTINFO;
  144.  
  145. #pragma    subtitle("   Exception Handler - End Address Function")
  146. #pragma    page( )
  147.  
  148. /* --- XEndAddress ------------------------------------    [ Private ] ---    */
  149. /*                                    */
  150. /*     This function is    used as    the end    address    marker for the        */
  151. /*     main-line code of Prominare Designer.                */
  152. /*                                    */
  153. /*     Upon Entry:                            */
  154. /*                                    */
  155. /*     Nothing                                */
  156. /*                                    */
  157. /*     Upon Exit:                            */
  158. /*                                    */
  159. /*     Nothing                                */
  160. /*                                    */
  161. /* --------------------------------------------------------------------    */
  162.  
  163. VOID XEndAddress(VOID)
  164.  
  165. {
  166. }
  167. #pragma    subtitle("   Storage Support - Dialogue ID Sort Routine")
  168. #pragma    page( )
  169.  
  170. /* --- SortAddresses ----------------------------------    [ Private ] ---    */
  171. /*                                    */
  172. /*     This function is    used to    sort a source modules function        */
  173. /*     addresses in ascending order.  The routine implemented is the    */
  174. /*     "Quick Sort" algorithm.    The function uses recursion to        */
  175. /*     perform the sort.                        */
  176. /*                                    */
  177. /*     Upon Entry:                            */
  178. /*                                    */
  179. /*     INTERNALADDRESSLIST *aial;  = Internal Address List Pointer    */
  180. /*     INT           sLeft;  = Low Index Value            */
  181. /*     INT           sRight; = High Index    Value            */
  182. /*                                    */
  183. /*     Upon Exit:                            */
  184. /*                                    */
  185. /*     Nothing                                */
  186. /*                                    */
  187. /* --------------------------------------------------------------------    */
  188.  
  189. static VOID SortAddresses(INTERNALADDRESSLIST *aial, INT sLeft,    INT sRight)
  190.  
  191. {
  192. PFNINTADD        pfn;       /* Function Address            */
  193. INTERNALADDRESSLIST ial;       /* Internal Address List Entry    */
  194. register INT i;               /* Low Index    Counter            */
  195. register INT n;               /* High Index Counter        */
  196.  
  197.                /* Determine target pointer and retrieve    string    */
  198.                /* address                    */
  199.  
  200. pfn = aial[((i = sLeft)    + (n = sRight))    / 2].pfn;
  201.  
  202. do
  203.    {
  204.    while ( ((PVOID)aial[i].pfn < (PVOID)pfn) &&    (i < sRight) )
  205.        ++i;
  206.    while ( ((PVOID)aial[n].pfn > (PVOID)pfn) &&    (n > sLeft) )
  207.        --n;
  208.  
  209.    if (    i <= n )
  210.        {
  211.        ial = aial[i];
  212.        aial[i++] = aial[n];
  213.        aial[n--] = ial;
  214.        }
  215.    } while ( i <= n );
  216.  
  217. if ( sLeft < n )
  218.    SortAddresses(aial, sLeft, n);
  219.  
  220. if ( i < sRight    )
  221.    SortAddresses(aial, i, sRight);
  222. }
  223. #pragma    subtitle("   Exception Handler - Exception Handler Routine")
  224. #pragma    page( )
  225.  
  226. /* --- fLookupAddress ---------------------------------    [ Private ] ---    */
  227. /*                                    */
  228. /*     This function is    used lookup the    locate the area    where the    */
  229. /*     acception occurred when the stack is backtraced.            */
  230. /*                                    */
  231. /*     Upon Entry:                            */
  232. /*                                    */
  233. /*     PVOID   pvExceptAddress;    = Address to Check            */
  234. /*     PEXCEPT pex;        = Exception Information            */
  235. /*     BOOL    fStackTrace;    = Stack    Traced Flag            */
  236. /*     INT     cFunctions;    = Function Count            */
  237. /*                                    */
  238. /*     Upon Exit:                            */
  239. /*                                    */
  240. /*     fLookupAddress =     TRUE :    Address    Located                */
  241. /*              =    FALSE :    Address    Not Located            */
  242. /*                                    */
  243. /* --------------------------------------------------------------------    */
  244.  
  245. static BOOL fLookupAddress(PVOID pvExceptAddress, PEXCEPT pex,
  246.                BOOL    fStackTrace, INT cFunctions)
  247.  
  248. {
  249. register INT n;               /* Loop Counters            */
  250.  
  251.                /* Check    to see if dynamic link library loaded    */
  252.                /* in which case    check with the DLL to see if    */
  253.                /* the exception    occurred within    it        */
  254.  
  255. if ( pfnDllExceptionLookup )
  256.    {
  257.    pex->iIntAdd    = 0;
  258.    pex->fStackTraced = fStackTrace;
  259.    if (    pfnDllExceptionLookup(pvExceptAddress, pex->szComponent, pex->szModule,    pex->szFunction,
  260.                   &pex->pfnStart, &pex->pfnEnd) )
  261.       return(TRUE);
  262.    }
  263.                /* Exception didn't occur within a DLL, check    */
  264.                /* the function address array for the exception    */
  265.                /* address                    */
  266.  
  267. for ( n    = 0; n < cFunctions; n++ )
  268.    if (    (pvExceptAddress > (PVOID)pial[n].pfn) &&
  269.     (pvExceptAddress < (PVOID)pial[n + 1].pfn) )
  270.        {
  271.                /* Exception address within the application    */
  272.                /* address space, save the necessary information    */
  273.                /* before returning                */
  274.  
  275.        pex->fStackTraced = fStackTrace;
  276.        memcpy(pex->szComponent,    "Except.Exe", 11);
  277.        strcpy(pex->szModule,    aintadd[pex->iIntAdd = piModules[n]]->pszModule);
  278.        strcpy(pex->szFunction,    pial[n].pszFunction);
  279.        pex->pfnStart = (PVOID)pial[n].pfn;
  280.        pex->pfnEnd   = (PVOID)pial[n + 1].pfn;
  281.        return(TRUE);
  282.        }
  283. return(FALSE);
  284. }
  285. #pragma    subtitle("   Exception Handler - Exception Handler Routine")
  286. #pragma    page( )
  287.  
  288. /* --- ExceptionHandler    -------------------------------- [ Public ] ---    */
  289. /*                                    */
  290. /*     This function is    used process exceptions    under 2.x and to,    */
  291. /*     depending on the    exception, terminate the application after    */
  292. /*     saving relevant information to a    trap file.            */
  293. /*                                    */
  294. /*     Upon Entry:                            */
  295. /*                                    */
  296. /*     PEXCEPTIONREPORTRECORD        pxcptrepr; = Report    Record        */
  297. /*     PEXCEPTIONREGISTRATIONRECORD pxcptregr; = Registration Record    */
  298. /*     PCONTEXTRECORD            pcr;       = Context Record        */
  299. /*     PVOID                sysinfo;   = System    Reserved    */
  300. /*                                    */
  301. /*     Upon Exit:                            */
  302. /*                                    */
  303. /*     ExceptionHandler    = Exception Return Status            */
  304. /*                                    */
  305. /* --------------------------------------------------------------------    */
  306.  
  307. APIRET APIENTRY    ExceptionHandler(PEXCEPTIONREPORTRECORD    pxcptrepr,
  308.                  PEXCEPTIONREGISTRATIONRECORD pxcptregr,
  309.                  PCONTEXTRECORD    pcr, PVOID sysinfo)
  310.  
  311. {
  312. DATETIME   dt;               /* Date Time    Holder            */
  313. EXCEPT       ex;               /* Exception    Info            */
  314. EXCEPT       exTrace;           /* Exception    Info            */
  315. EXCEPTINFO exi;               /* Exception    Information        */
  316. HFILE       hf;               /* Trap File    Handle            */
  317. PPIB       ppib;           /* Process Information Block    Pointer    */
  318. PSZ       pszBuffer;           /* Scratch Buffer            */
  319. PSZ       pszXCP;           /* XCP Filename Pointer        */
  320. PTIB       ptib;           /* Thread Information Block Pointer    */
  321. PULONG       pulEBP;           /* BP Stack Frame            */
  322. ULONG       cb;               /* Bytes Written            */
  323. ULONG       ulAction;           /* Action                */
  324. register INT i,    n, k;           /* Loop Counter            */
  325.  
  326. if ( EH_EXIT_UNWIND & pxcptrepr->fHandlerFlags )
  327.    return(XCPT_CONTINUE_SEARCH);
  328.  
  329. if ( EH_UNWINDING & pxcptrepr->fHandlerFlags )
  330.    return(XCPT_CONTINUE_SEARCH);
  331.  
  332. if ( EH_NESTED_CALL & pxcptrepr->fHandlerFlags )
  333.    return(XCPT_CONTINUE_SEARCH);
  334.  
  335.                /* Only handle access violation and divide by    */
  336.                /* zero exceptions                */
  337.  
  338. if ( (pxcptrepr->ExceptionNum == XCPT_ACCESS_VIOLATION)    ||
  339.      (pxcptrepr->ExceptionNum == XCPT_INTEGER_DIVIDE_BY_ZERO) )
  340.    {
  341.                /* Allocate space for the formatting buffer    */
  342.  
  343.    DosAllocMem((PPVOID)(PVOID)&pszBuffer, 4096UL,
  344.            PAG_READ    | PAG_WRITE | PAG_COMMIT);
  345.    memset(&ex, 0, sizeof(EXCEPT));
  346.  
  347.                /* Open the logging file                */
  348.  
  349.    DosOpen(memcpy(pszBuffer, pszXCP = "Except.Log", 11), &hf, &ulAction, 0UL, FILE_NORMAL,
  350.        OPEN_ACTION_OPEN_IF_EXISTS |    OPEN_ACTION_CREATE_IF_NEW,
  351.        OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE, NULL);
  352.  
  353.                /* Set the file pointer to the end of the    */
  354.                /* logging file                    */
  355.  
  356.    DosSetFilePtr(hf, 0L, FILE_END, &cb);
  357.  
  358.                /* Write    out the    start of the exception dump    */
  359.  
  360.    DosWrite(hf,    (PVOID)pszBuffer,
  361.         (ULONG)sprintf(pszBuffer, "Except.Log :\r\nAccess violation occurred at CS:EIP = 0x%04X:%08X\r\n",
  362.                pcr->ctx_SegCs, pxcptrepr->ExceptionAddress), &cb);
  363.  
  364.                /* Write    out the    type of    exception        */
  365.  
  366.    if (    pxcptrepr->ExceptionNum    == XCPT_INTEGER_DIVIDE_BY_ZERO )
  367.        DosWrite(hf, (PVOID)"Integer divide by zero\r\n", 24UL, &cb);
  368.    else
  369.        if ( pxcptrepr->ExceptionInfo[0]    & XCPT_READ_ACCESS )
  370.        DosWrite(hf,    (PVOID)pszBuffer,
  371.             (ULONG)sprintf(pszBuffer, "Invalid Read Access occurred at 0x%04X:%08X",
  372.                    pcr->ctx_SegDs, pxcptrepr->ExceptionInfo[1]), &cb);
  373.        else
  374.        if (    pxcptrepr->ExceptionInfo[0] & XCPT_WRITE_ACCESS    )
  375.            DosWrite(hf, (PVOID)pszBuffer,
  376.             (ULONG)sprintf(pszBuffer, "Invalid Write Access occurred at 0x%04X:%08X",
  377.                        pcr->ctx_SegDs, pxcptrepr->ExceptionInfo[1]), &cb);
  378.        else
  379.            if ( pxcptrepr->ExceptionInfo[0]    & XCPT_SPACE_ACCESS )
  380.            DosWrite(hf,    (PVOID)pszBuffer,
  381.                 (ULONG)sprintf(pszBuffer, "Invalid Space Access occurred with 0x%04X",
  382.                        pxcptrepr->ExceptionInfo[1]), &cb);
  383.            else
  384.            if (    pxcptrepr->ExceptionInfo[0] & XCPT_LIMIT_ACCESS    )
  385.                DosWrite(hf, (PVOID)pszBuffer,
  386.                 (ULONG)sprintf(pszBuffer, "Invalid Limit Access occurred"), &cb);
  387.            else
  388.                if ( pxcptrepr->ExceptionInfo[0]    == XCPT_UNKNOWN_ACCESS )
  389.                DosWrite(hf,    (PVOID)pszBuffer,
  390.                     (ULONG)sprintf(pszBuffer, "Invalid Unknown occurred at 0x%04X:%08X\r\n",
  391.                            pcr->ctx_SegDs, pxcptrepr->ExceptionInfo[1]), &cb);
  392.  
  393.                /* Get the current date and time    along with the    */
  394.                /* thread information                */
  395.    DosGetDateTime(&dt);
  396.    DosGetInfoBlocks(&ptib, &ppib);
  397.  
  398.                /* Write    out the    register information along with    */
  399.                /* the current date, time and thread/process    */
  400.                /* information                    */
  401.  
  402.    DosWrite(hf,    (PVOID)pszBuffer,
  403.         (ULONG)sprintf(pszBuffer, pszRegisters,
  404.                pcr->ctx_RegEax, pcr->ctx_RegEbx, pcr->ctx_RegEcx, pcr->ctx_RegEdx,
  405.                pcr->ctx_RegEbp, pcr->ctx_RegEdi, pcr->ctx_RegEsi, pcr->ctx_RegEsp,
  406.                pcr->ctx_SegCs, pcr->ctx_SegDs, pcr->ctx_SegEs, pcr->ctx_SegFs,
  407.                pcr->ctx_SegGs, pcr->ctx_SegSs,
  408.                apszMonth[dt.month -    1], dt.day, dt.year,
  409.                dt.hours, dt.minutes, dt.seconds, dt.hundredths,
  410.                ex.pid = ppib->pib_ulpid, ex.tid = ptib->tib_ptib2->tib2_ultid), &cb);
  411.  
  412.                /* Walk the list    of module addresses to find    */
  413.                /* out total number of functions    for the        */
  414.                /* final    function address array            */
  415.  
  416.    for ( i = k = 0; i <    CMODULES; i++ )
  417.        {
  418.        n = 0;
  419.        while ( aintadd[i]->aial[n].pfn )
  420.        {
  421.        ++n;
  422.        ++k;
  423.        }
  424.        }
  425.                /* Allocate memory for the master address list    */
  426.                /* array    along with memory for the module index    */
  427.                /* array                        */
  428.  
  429.    DosAllocMem((PPVOID)(PVOID)&pial, (ULONG)(sizeof(INTERNALADDRESSLIST) * k),
  430.            PAG_READ    | PAG_WRITE | PAG_COMMIT);
  431.  
  432.    DosAllocMem((PPVOID)(PVOID)&piModules, (ULONG)(sizeof(INT) *    k),
  433.            PAG_READ    | PAG_WRITE | PAG_COMMIT);
  434.  
  435.                /* Re-walk the module address lists transferring    */
  436.                /* the functions    to the master array.  Also save    */
  437.                /* the index to the module.            */
  438.  
  439.    for ( i = k = 0; i <    CMODULES; i++ )
  440.        {
  441.        n = 0;
  442.        while ( aintadd[i]->aial[n].pfn )
  443.        {
  444.        piModules[k]    = i;
  445.        pial[k++] = aintadd[i]->aial[n++];
  446.        }
  447.        }
  448.                /* Sort the list    in ascending order        */
  449.    if (    k )
  450.        SortAddresses(pial, 0, k    - 1);
  451.  
  452.                /* Try looking up the exception address        */
  453.  
  454.    if (    fLookupAddress((PVOID)pxcptrepr->ExceptionAddress, &ex,    FALSE, k) )
  455.        {
  456.                /* Have found the exception location, write out    */
  457.                /* the names of the module and function where    */
  458.                /* the exception    occurred            */
  459.  
  460.        DosWrite(hf, (PVOID)pszBuffer,
  461.         (ULONG)sprintf(pszBuffer, "Component: %s Module: %s Function: %s\r\nFunction start: 0x%08X\r\nFunction end:   0x%08X\r\n\r\n",
  462.                    ex.szComponent, ex.szModule, ex.szFunction, ex.pfnStart,    ex.pfnEnd), &cb);
  463.  
  464.                /* Try walking the stack    to give    a full chain    */
  465.                /* of function calls since this may actually be    */
  466.                /* of use                    */
  467.        cb = 1UL;
  468.        if ( !DosQueryMem((PVOID)(pulEBP    = (PULONG)pcr->ctx_RegEbp), &cb, &cb) )
  469.        while ( pulEBP && ((PVOID)*(pulEBP +    1) > (PVOID)(PFNINTADD)main) )
  470.            if ( (PVOID)*pulEBP > ptib->tib_pstacklimit )
  471.            break;
  472.            else
  473.            {
  474.            if (    fLookupAddress((PVOID)(*(pulEBP    + 1)), &exTrace, TRUE, k) )
  475.                DosWrite(hf, (PVOID)pszBuffer,
  476.                 (ULONG)sprintf(pszBuffer, "Tracing back through stack\r\nModule: %s Function: %s\r\nFunction start: 0x%08X\r\nFunction end:   0x%08X\r\n\r\n",
  477.                            exTrace.szModule, exTrace.szFunction, exTrace.pfnStart, exTrace.pfnEnd),    &cb);
  478.            pulEBP = (PULONG)*pulEBP;
  479.            }
  480.        }
  481.    else
  482.                /* Could    not find the address within any    program    */
  483.                /* or DLL address space,    now try    walking    the    */
  484.                /* stack    back to    the address space to at    least    */
  485.                /* try to give some information about where the    */
  486.                /* mess started                    */
  487.  
  488.        if ( (PVOID)pxcptrepr->ExceptionAddress > (PVOID)(PFNINTADD)XEndAddress )
  489.        {
  490.        cb =    1UL;
  491.        if (    !DosQueryMem((PVOID)(pulEBP = (PULONG)pcr->ctx_RegEbp),    &cb, &cb) )
  492.            {
  493.            while ( (PVOID)*(pulEBP + 1) > (PVOID)(PFNINTADD)XEndAddress )
  494.            if (    (PVOID)*pulEBP > ptib->tib_pstacklimit )
  495.                break;
  496.            else
  497.                pulEBP =    (PULONG)*pulEBP;
  498.            if ( fLookupAddress((PVOID)(*(pulEBP + 1)), &ex,    TRUE, k) )
  499.            DosWrite(hf,    (PVOID)pszBuffer,
  500.                 (ULONG)sprintf(pszBuffer, "Back traced through stack\r\nModule: %s Function: %s\r\nFunction start: 0x%08X\r\nFunction end:   0x%08X\r\n\r\n",
  501.                        ex.szModule,    ex.szFunction, ex.pfnStart, ex.pfnEnd),    &cb);
  502.            ex.fStackTraced = TRUE;
  503.            }
  504.        }
  505.                /* Write    out the    addresses for the bottom and    */
  506.                /* top of the program address space        */
  507.  
  508.    DosWrite(hf,    (PVOID)pszBuffer,
  509.         (ULONG)sprintf(pszBuffer, pszAddresses, &main, &ExceptionHandler), &cb);
  510.    DosFreeMem((PVOID)pszBuffer);
  511.    DosClose(hf);
  512.                /* Release the array memory            */
  513.    DosFreeMem((PVOID)pial);
  514.    DosFreeMem((PVOID)piModules);
  515.  
  516.                /* Initialize the dialogue information and    */
  517.                /* display the dialogue                */
  518.  
  519.    ex.pxcptrepr    = pxcptrepr;
  520.    ex.pcr    = pcr;
  521.  
  522.    exi.pex    = &ex;
  523.    exi.pszTitle    = "Exception Example FATAL ERROR";
  524.    exi.pszXCP    = pszXCP;
  525.    exi.fFatal    = TRUE;
  526.  
  527.    WinDlgBox(HWND_DESKTOP, HWND_DESKTOP, (PFNWP)XceptionDlgProc,
  528.           (HMODULE)NULL, DLG_EXCEPTION, (PVOID)&exi);
  529.  
  530.    DosExit(EXIT_PROCESS, 128UL);
  531.    }
  532.  
  533. return(XCPT_CONTINUE_SEARCH);
  534. }
  535. #pragma    subtitle("   Exception Support - Exception Dialogue Box Function")
  536. #pragma    page( )
  537.  
  538. /* --- pszHexShort ------------------------------------    [ Private ] ---    */
  539. /*                                    */
  540. /*     This function is    used to    process    the Directory Rename dialogue    */
  541. /*     box.                                */
  542. /*                                    */
  543. /*     Upon Entry:                            */
  544. /*                                    */
  545. /*     PSZ   pszBuffer;    = Buffer                    */
  546. /*     ULONG ul;    = Numeric Value                    */
  547. /*                                    */
  548. /*     Upon Exit:                            */
  549. /*                                    */
  550. /*     pszHex =    pszBuffer Address                    */
  551. /*                                    */
  552. /* --------------------------------------------------------------------    */
  553.  
  554. static PSZ pszHexShort(ULONG ul, PSZ pszBuffer)
  555.  
  556. {
  557. CHAR szNumber[16];           /* Segment Address Holder        */
  558. register INT i,    n;           /* Loop Counter            */
  559.  
  560. memcpy(pszBuffer, "0x0000", 7);
  561.  
  562. if ( ul    )
  563.    for ( i = 5,    n = (INT)strlen(_ultoa(ul, szNumber, 16)) - 1; n >= 0; i--, n--    )
  564.        pszBuffer[i] = szNumber[n];
  565.  
  566. return(pszBuffer);
  567. }
  568. #pragma    subtitle("   Exception Support - Exception Dialogue Box Function")
  569. #pragma    page( )
  570.  
  571. /* --- pszHex -----------------------------------------    [ Private ] ---    */
  572. /*                                    */
  573. /*     This function is    used to    process    the Directory Rename dialogue    */
  574. /*     box.                                */
  575. /*                                    */
  576. /*     Upon Entry:                            */
  577. /*                                    */
  578. /*     PSZ   pszBuffer;    = Buffer                    */
  579. /*     ULONG ul;    = Numeric Value                    */
  580. /*                                    */
  581. /*     Upon Exit:                            */
  582. /*                                    */
  583. /*     pszHex =    pszBuffer Address                    */
  584. /*                                    */
  585. /* --------------------------------------------------------------------    */
  586.  
  587. static PSZ pszHex(ULONG    ul, PSZ    pszBuffer)
  588.  
  589. {
  590. CHAR szNumber[16];           /* Segment Address Holder        */
  591. register INT i,    n;           /* Loop Counter            */
  592.  
  593. memcpy(pszBuffer, "0x00000000",    11);
  594.  
  595. if ( ul    )
  596.    for ( i = 9,    n = (INT)strlen(_ultoa(ul, szNumber, 16)) - 1; n >= 0; i--, n--    )
  597.        pszBuffer[i] = szNumber[n];
  598.  
  599. return(pszBuffer);
  600. }
  601. #pragma    subtitle("   Exception Support - Exception Dialogue Box Function")
  602. #pragma    page( )
  603.  
  604. /* --- pszFormAddress ---------------------------------    [ Private ] ---    */
  605. /*                                    */
  606. /*     This function is    used to    process    the Directory Rename dialogue    */
  607. /*     box.                                */
  608. /*                                    */
  609. /*     Upon Entry:                            */
  610. /*                                    */
  611. /*     HWND   hWnd; = Window Handle                    */
  612. /*     ULONG  msg;  = PM Message                    */
  613. /*     MPARAM mp1;  = Message Parameter    1                */
  614. /*     MPARAM mp2;  = Message Parameter    2                */
  615. /*                                    */
  616. /*     Upon Exit:                            */
  617. /*                                    */
  618. /*     ExceptionDlgProc    = Message Handling Result            */
  619. /*                                    */
  620. /* --------------------------------------------------------------------    */
  621.  
  622. static PSZ pszFormAddress(PSZ pszBuffer, ULONG ulSeg, ULONG ulBase)
  623.  
  624. {
  625. CHAR szSegment[16];           /* Segment Address Holder        */
  626. CHAR szBase[32];           /* Base Address Holder        */
  627.  
  628. return(strcat(strcat(strcpy(pszBuffer, pszHexShort(ulSeg, szSegment)),
  629.           ":"),
  630.        pszHex(ulBase, szBase)));
  631. }
  632. #pragma    subtitle("   Exception Support - Exception Dialogue Box Function")
  633. #pragma    page( )
  634.  
  635. /* --- XceptionDlgProc --------------------------------    [ Private ] ---    */
  636. /*                                    */
  637. /*     This function is    used to    process    the Directory Rename dialogue    */
  638. /*     box.                                */
  639. /*                                    */
  640. /*     Upon Entry:                            */
  641. /*                                    */
  642. /*     HWND   hWnd; = Window Handle                    */
  643. /*     ULONG  msg;  = PM Message                    */
  644. /*     MPARAM mp1;  = Message Parameter    1                */
  645. /*     MPARAM mp2;  = Message Parameter    2                */
  646. /*                                    */
  647. /*     Upon Exit:                            */
  648. /*                                    */
  649. /*     XceptionDlgProc = Message Handling Result            */
  650. /*                                    */
  651. /* --------------------------------------------------------------------    */
  652.  
  653. MRESULT    EXPENTRY XceptionDlgProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  654.  
  655. {
  656. CHAR        szBuffer[CCHMAXPATH];  /* File Name    Holder            */
  657. CHAR        szAddress[32];       /* File Name    Holder            */
  658. HMODULE        hmodSnd;           /* Sound DLL    Module Handle        */
  659. PEXCEPTINFO pexi;           /* Directory    Entry Pointer        */
  660. SWP        swp;           /* Screen Window Position Holder    */
  661.  
  662. switch ( msg )
  663.    {
  664.    case WM_CONTROL :
  665.     switch ( SHORT2FROMMP(mp1) )
  666.         {
  667.             /* Process control selections            */
  668.         }
  669.     break;
  670.                /* Perform dialog initialization            */
  671.    case    WM_INITDLG :
  672.        WinSetWindowULong(hWnd, QWL_USER, (ULONG)(pexi =    (PEXCEPTINFO)PVOIDFROMMP(mp2)));
  673.        WinSetWindowText(hWnd, pexi->pszTitle);
  674.  
  675.        strcat(memcpy(szBuffer, "Further detail contained in ", 29), pexi->pszXCP);
  676.        WinSetDlgItemText(hWnd, IT_DETAIL,
  677.              strcat(szBuffer, " within sub-directory."));
  678.        if ( pexi->fFatal )
  679.        WinSetDlgItemText(hWnd, IT_STATUS, "Fatal error: NON-RECOVERABLE (application terminating)");
  680.        else
  681.        {
  682.        WinSetDlgItemText(hWnd, IT_STATUS, "Recoverable error: last operation non-completed, proceeding to next");
  683.        WinSetDlgItemText(hWnd, DID_OK, "Resume");
  684.        }
  685.                /* Place    file entry selected in first edit field    */
  686.  
  687.        WinSetDlgItemText(hWnd, IT_CSEIP,
  688.              strcat(memcpy(szBuffer,
  689.                        "Access violation occurred at CS:EIP = ", 39),
  690.                 pszFormAddress(szAddress, pexi->pex->pcr->ctx_SegCs,
  691.                            (ULONG)pexi->pex->pxcptrepr->ExceptionAddress)));
  692.  
  693.        if ( pexi->pex->pxcptrepr->ExceptionNum == XCPT_INTEGER_DIVIDE_BY_ZERO )
  694.        memcpy(szBuffer, "Integer divide by zero.", 24);
  695.        else
  696.        if (    pexi->pex->pxcptrepr->ExceptionInfo[0] & XCPT_READ_ACCESS )
  697.            strcat(memcpy(szBuffer,
  698.                  "Invalid Read Access occurred at ", 33),
  699.               pszFormAddress(szAddress,    pexi->pex->pcr->ctx_SegDs,
  700.                      pexi->pex->pxcptrepr->ExceptionInfo[1]));
  701.        else
  702.            if ( pexi->pex->pxcptrepr->ExceptionInfo[0] & XCPT_WRITE_ACCESS )
  703.            strcat(memcpy(szBuffer,
  704.                  "Invalid Write Access occurred at ", 34),
  705.               pszFormAddress(szAddress, pexi->pex->pcr->ctx_SegDs,
  706.                      pexi->pex->pxcptrepr->ExceptionInfo[1]));
  707.            else
  708.            if (    pexi->pex->pxcptrepr->ExceptionInfo[0] & XCPT_SPACE_ACCESS )
  709.                strcat(memcpy(szBuffer,
  710.                      "Invalid Space Access occurred with ", 36),
  711.                   _ultoa(pexi->pex->pxcptrepr->ExceptionInfo[1], szAddress,    16));
  712.            else
  713.                if ( pexi->pex->pxcptrepr->ExceptionInfo[0] & XCPT_LIMIT_ACCESS )
  714.                memcpy(szBuffer, "Invalid Limit Access occurred", 30);
  715.                else
  716.                strcat(memcpy(szBuffer,
  717.                      "Invalid Unknown occurred at ", 29),
  718.                   pszFormAddress(szAddress, pexi->pex->pcr->ctx_SegDs,
  719.                          pexi->pex->pxcptrepr->ExceptionInfo[1]));
  720.        WinSetDlgItemText(hWnd, IT_EXCEPTTYPE, szBuffer);
  721.  
  722.        if ( pexi->pex->iIntAdd != -1 )
  723.        {
  724.        if (    pexi->pex->fStackTraced    )
  725.            memcpy(szBuffer,    "Stack backtraced\nComponent: ", 29);
  726.        else
  727.            memcpy(szBuffer,    "Component: ", 12);
  728.  
  729.        WinSetDlgItemText(hWnd, IT_DEBUGINFO,
  730.                  strcat(strcat(strcat(strcat(strcat(szBuffer, pexi->pex->szComponent),
  731.                              "\nModule:   "),
  732.                           pexi->pex->szModule),
  733.                        "\nFunction: "),
  734.                     pexi->pex->szFunction));
  735.        }
  736.  
  737.        WinSetDlgItemText(hWnd, IT_PID, _ultoa(pexi->pex->pid, szBuffer,    10));
  738.        WinSetDlgItemText(hWnd, IT_TID, _ultoa(pexi->pex->tid, szBuffer,    10));
  739.  
  740.        WinSetDlgItemText(hWnd, IT_PFNSTART, pszHex((ULONG)pexi->pex->pfnStart, szBuffer));
  741.        WinSetDlgItemText(hWnd, IT_PFNEND,   pszHex((ULONG)pexi->pex->pfnEnd,   szBuffer));
  742.  
  743.        WinSetDlgItemText(hWnd, IT_EAX, pszHex(pexi->pex->pcr->ctx_RegEax, szBuffer));
  744.        WinSetDlgItemText(hWnd, IT_EBX, pszHex(pexi->pex->pcr->ctx_RegEbx, szBuffer));
  745.        WinSetDlgItemText(hWnd, IT_ECX, pszHex(pexi->pex->pcr->ctx_RegEcx, szBuffer));
  746.        WinSetDlgItemText(hWnd, IT_EDX, pszHex(pexi->pex->pcr->ctx_RegEdx, szBuffer));
  747.  
  748.        WinSetDlgItemText(hWnd, IT_EBP, pszHex(pexi->pex->pcr->ctx_RegEbp, szBuffer));
  749.        WinSetDlgItemText(hWnd, IT_ESP, pszHex(pexi->pex->pcr->ctx_RegEsp, szBuffer));
  750.  
  751.        WinSetDlgItemText(hWnd, IT_EDI, pszHex(pexi->pex->pcr->ctx_RegEdi, szBuffer));
  752.        WinSetDlgItemText(hWnd, IT_ESI, pszHex(pexi->pex->pcr->ctx_RegEsi, szBuffer));
  753.  
  754.        WinSetDlgItemText(hWnd, IT_CS, pszHexShort(pexi->pex->pcr->ctx_SegCs, szBuffer));
  755.        WinSetDlgItemText(hWnd, IT_SS, pszHexShort(pexi->pex->pcr->ctx_SegSs, szBuffer));
  756.        WinSetDlgItemText(hWnd, IT_DS, pszHexShort(pexi->pex->pcr->ctx_SegDs, szBuffer));
  757.        WinSetDlgItemText(hWnd, IT_ES, pszHexShort(pexi->pex->pcr->ctx_SegEs, szBuffer));
  758.        WinSetDlgItemText(hWnd, IT_FS, pszHexShort(pexi->pex->pcr->ctx_SegFs, szBuffer));
  759.        WinSetDlgItemText(hWnd, IT_GS, pszHexShort(pexi->pex->pcr->ctx_SegGs, szBuffer));
  760.  
  761.        WinSetDlgItemText(hWnd, IT_FLAGS, pszHex(pexi->pex->pcr->ctx_EFlags, szBuffer));
  762.  
  763.        WinPostMsg(hWnd,    WM_PLAYSOUND, 0L, 0L);
  764.  
  765.                /* Centre dialog    on the screen            */
  766.  
  767.                /* Centre dialog    on the screen            */
  768.  
  769.        WinQueryWindowPos(hWnd, (PSWP)&swp);
  770.        WinSetWindowPos(hWnd, HWND_TOP,
  771.                (WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN) - swp.cx) /    2L,
  772.                (WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN) - swp.cy) /    2L,
  773.                0L, 0L, SWP_MOVE);
  774.        break;
  775.  
  776.    case    WM_PLAYSOUND :
  777.        if ( !DosLoadModule(szBuffer, CCHMAXPATHCOMP, "PDSSnd", &hmodSnd) )
  778.        {
  779.        VOID    (* EXPENTRY pfnPlaySound)(HWND hWnd, PSZ pszWaveFile);
  780.  
  781.        pexi    = (PEXCEPTINFO)WinQueryWindowULong(hWnd, QWL_USER);
  782.  
  783.        if (    !DosQueryProcAddr(hmodSnd, ORD_PLAYSOUND, NULL,
  784.                   (PFN *)(PVOID)&pfnPlaySound) )
  785.            pfnPlaySound(hWnd, "flush.wav");
  786.        else
  787.            WinAlarm(HWND_DESKTOP, WA_ERROR);
  788.        DosFreeModule(hmodSnd);
  789.        }
  790.        else
  791.        WinAlarm(HWND_DESKTOP, WA_ERROR);
  792.        break;
  793.                /* Process push button selections        */
  794.    case    WM_COMMAND :
  795.        switch (    SHORT1FROMMP(mp1) )
  796.        {
  797.                /* OK button selected, get text from edit fields    */
  798.                /* and rename the file                */
  799.        case    DID_OK :
  800.            WinDismissDlg(hWnd, FALSE);
  801.            break;
  802.        }
  803.        break;
  804.                /* Close    received, exit dialog            */
  805.    case    WM_CLOSE :
  806.        WinDismissDlg(hWnd, FALSE);
  807.        break;
  808.                /* Pass through unhandled messages        */
  809.    default :
  810.        return(WinDefDlgProc(hWnd, msg, mp1, mp2));
  811.    }
  812. return(0L);
  813. }
  814.