home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / netds / winsock / dt_dll / dt_dll.cpp < prev    next >
Text File  |  1997-09-21  |  33KB  |  1,124 lines

  1. /*++
  2.  
  3.   Copyright (c) 1995 Intel Corp
  4.  
  5.   File Name:
  6.  
  7.     dt_dll.cpp
  8.  
  9.   Abstract:
  10.  
  11.     Contains main and supporting functions for a Debug/Trace
  12.     DLL for the WinSock2 DLL.  See the design spec
  13.     for more information.
  14.  
  15. --*/
  16.  
  17. //
  18. // Include Files
  19. //
  20.  
  21. #include "nowarn.h"  /* turn off benign warnings */
  22. #ifndef _WINSOCKAPI_
  23. #define _WINSOCKAPI_   /* Prevent inclusion of winsock.h in windows.h */
  24. #endif
  25.  
  26. #include "nowarn.h"  /* some warnings may have been turned back on */
  27. #include <winsock2.h>
  28. #include <stdarg.h>
  29. #include <ws2spi.h>
  30. #include <commdlg.h>
  31.  
  32. #include "dt_dll.h"
  33. #include "cstack.h"
  34. #include "dt.h"
  35. #include "handlers.h"
  36.  
  37. //
  38. // Forward References for Functions
  39. //
  40.  
  41. LRESULT APIENTRY
  42. DTMainWndProc(
  43.     IN HWND   WindowHandle,
  44.     IN UINT   Message,
  45.     IN WPARAM WParam,
  46.     IN LPARAM LParam);
  47.  
  48. LRESULT APIENTRY
  49. DTEditWndProc(
  50.     IN HWND   WindowHandle,
  51.     IN UINT   Message,
  52.     IN WPARAM WParam,
  53.     IN LPARAM LParam);
  54.  
  55. BOOL WINAPI
  56. DllMain(
  57.     HINSTANCE DllInstHandle,
  58.     DWORD     Reason,
  59.     LPVOID    Reserved);
  60.  
  61. DWORD
  62. WindowThreadFunc(LPDWORD TheParam);
  63.  
  64. BOOL APIENTRY
  65. DebugDlgProc(
  66.     IN HWND hwndDlg,
  67.     IN UINT message,
  68.     IN WPARAM wParam,
  69.     IN LPARAM lParam);
  70.  
  71. BOOL
  72. GetFile(
  73.     IN  HWND   OwnerWindow,
  74.     OUT  LPSTR Buffer,
  75.     IN  DWORD  BufSize);
  76.  
  77. void
  78. AbortAndClose(
  79.     IN HANDLE FileHandle,
  80.     IN HWND WindowHandle);
  81.  
  82.  
  83.  
  84.  
  85. //
  86. // Externally Visible Global Variables
  87. //
  88.  
  89. HWND   DebugWindow;               // handle to the child edit control
  90. HANDLE LogFileHandle;             // handle to the log file
  91. DWORD  OutputStyle = WINDOW_ONLY; // where to put output
  92. char   Buffer[TEXT_LEN];          // buffer for building output strings
  93.  
  94.  
  95.  
  96. //
  97. // Static Global Variables
  98. //
  99.  
  100. // name for my window class
  101. static char             DTWndClass[] = "DTWindow";
  102.  
  103. static HWND             FrameWindow;   // handle to frame of debug window
  104. static WNDPROC          EditWndProc;   // the edit control's window proc
  105. static HINSTANCE        DllInstHandle; // handle to the dll instance
  106. static DWORD            TlsIndex;      // tls index for this module
  107. static CRITICAL_SECTION CrSec;         // critical section for text output
  108. static HANDLE           TextOutEvent;  // set when debug window is ready
  109.  
  110. static char             LogFileName[256]; // name of the log file
  111.  
  112. // handle to and id of the main thread of the DLL which initializes
  113. // and creates windows, etc
  114. static HANDLE           WindowThread;
  115. static DWORD            WindowThreadId;
  116.  
  117. // function pointer tables for handler functions.
  118. static LPFNDTHANDLER  HdlFuncTable[MAX_DTCODE + 1];
  119.  
  120. // static strings
  121. static char ErrStr1[] = "Couldn't open file.  Debug output will go to \
  122. debug window.";
  123. static char  ErrStr2[] = "An error occurred while trying to get a log \
  124. filename.  Debug output will go to the window only.";
  125. static char ErrStr3[] = "Had problems writing to file.  Aborting file \
  126. ouput -- all debug output will now go to the debugging window";
  127.  
  128.  
  129.  
  130.  
  131. //
  132. // Function Definitions
  133. //
  134.  
  135.  
  136. BOOL WINAPI
  137. DllMain(
  138.     HINSTANCE InstanceHandle,
  139.     DWORD     Reason,
  140.     LPVOID    Reserved)
  141. /*++
  142.  
  143.   DllMain()
  144.  
  145.   Function Description:
  146.  
  147.       Please see Windows documentation for DllEntryPoint.
  148.  
  149.   Arguments:
  150.  
  151.       Please see windows documentation.
  152.  
  153.   Return Value:
  154.  
  155.       Please see windows documentation.
  156.  
  157. --*/
  158. {
  159.  
  160.     Cstack_c   *ThreadCstack;  // points to Cstack objects in tls
  161.     PINITDATA  InitDataPtr;    // to pass to the window creation thread
  162.  
  163.     switch(Reason) {
  164.  
  165.     // Determine the reason for the call and act accordingly.
  166.  
  167.     case DLL_PROCESS_ATTACH:
  168.  
  169.         DllInstHandle = InstanceHandle;
  170.         InitializeCriticalSection(&CrSec);
  171.         TextOutEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  172.  
  173.         // Fill in the handler function table.
  174.         DTHandlerInit(HdlFuncTable, MAX_DTCODE);
  175.  
  176.         // Allocate a TLS index.
  177.         TlsIndex = TlsAlloc();
  178.  
  179.         // Pop up a dialog box for the user to choose output method.
  180.         DialogBox(DllInstHandle,
  181.                   MAKEINTRESOURCE(IDD_DIALOG1),
  182.                   NULL,
  183.                   (DLGPROC)DebugDlgProc);
  184.  
  185.         if ((OutputStyle == FILE_ONLY) || (OutputStyle == FILE_AND_WINDOW)) {
  186.  
  187.             LogFileHandle = CreateFile(LogFileName,
  188.                                        GENERIC_WRITE,
  189.                                        FILE_SHARE_READ | FILE_SHARE_WRITE,
  190.                                        NULL,
  191.                                        CREATE_ALWAYS,
  192.                                        FILE_ATTRIBUTE_NORMAL,
  193.                                        NULL);
  194.             if (LogFileHandle == INVALID_HANDLE_VALUE) {
  195.                 OutputStyle = WINDOW_ONLY;
  196.                 MessageBox(NULL, ErrStr1, "Error", MB_OK | MB_ICONSTOP);
  197.             }
  198.         }
  199.  
  200.         // Get some information for later output to the debug window
  201.         // or file -- get the time, PID, and TID of the calling
  202.         // process and put into a INITDATA struct.  This memory will
  203.         // be freed by the thread it is passed to.
  204.         InitDataPtr = (PINITDATA) LocalAlloc(0, sizeof(INITDATA));
  205.         GetLocalTime(&(InitDataPtr->LocalTime));
  206.         InitDataPtr->TID = GetCurrentThreadId();
  207.         InitDataPtr->PID = GetCurrentProcessId();
  208.  
  209.         // Create the initialization/window handling thread.
  210.         if ((OutputStyle == WINDOW_ONLY) || (OutputStyle == FILE_AND_WINDOW)) {
  211.             WindowThread =
  212.               CreateThread(NULL,
  213.                            0,
  214.                            (LPTHREAD_START_ROUTINE)WindowThreadFunc,
  215.                            (LPVOID)InitDataPtr,
  216.                            0,
  217.                            &WindowThreadId);
  218.         } else {
  219.  
  220.             // Normally the window thread does a DTTextOut of the time
  221.             // and process info that we saved just above.  But in this
  222.             // case,  there is no window thread so spit it out to the
  223.             // file.
  224.  
  225.             wsprintf(Buffer, "Log initiated: %d-%d-%d, %d:%d:%d\r\n",
  226.                      InitDataPtr->LocalTime.wMonth,
  227.                      InitDataPtr->LocalTime.wDay,
  228.                      InitDataPtr->LocalTime.wYear,
  229.                      InitDataPtr->LocalTime.wHour,
  230.                      InitDataPtr->LocalTime.wMinute,
  231.                      InitDataPtr->LocalTime.wSecond);
  232.             DTTextOut(DebugWindow, LogFileHandle, Buffer, OutputStyle);
  233.             wsprintf(Buffer, "Process ID: 0x%X   Thread ID: 0x%X\r\n",
  234.                      InitDataPtr->PID,
  235.                      InitDataPtr->TID);
  236.             DTTextOut(DebugWindow, LogFileHandle, Buffer, OutputStyle);
  237.  
  238.             // Setting this event allows {Pre|Post}ApiNotify to
  239.             // proceed.  This event isn't really needed in this case
  240.             // (because there is only one thread, and we know the code
  241.             // above has been executed before WSAPre|PostApiNotify).
  242.             SetEvent(TextOutEvent);
  243.         }
  244.  
  245.         // flow through...
  246.  
  247.     case DLL_THREAD_ATTACH:
  248.  
  249.         // Store a pointer to a new Cstack_c in the slot for this
  250.         // thread.
  251.         ThreadCstack = new Cstack_c();
  252.         TlsSetValue(TlsIndex, (LPVOID)ThreadCstack);
  253.  
  254.         break;
  255.  
  256.     case DLL_PROCESS_DETACH:
  257.  
  258.         // Free up some resources.  This is like cleaning up your room
  259.         // before the tornado strikes, but hey, it's good practice.
  260.         TlsFree(TlsIndex);
  261.         DeleteCriticalSection(&CrSec);
  262.  
  263.         if ((OutputStyle == FILE_ONLY) || (OutputStyle == FILE_AND_WINDOW)) {
  264.             CloseHandle(LogFileHandle);
  265.         }
  266.         CloseHandle(WindowThread);
  267.  
  268.         break;
  269.  
  270.     case DLL_THREAD_DETACH:
  271.  
  272.         // Get the pointer to this thread's Cstack, and delete the
  273.         // object.
  274.         ThreadCstack = (Cstack_c *)TlsGetValue(TlsIndex);
  275.         delete ThreadCstack;
  276.  
  277.         break;
  278.  
  279.     default:
  280.  
  281.         break;
  282.     } // switch (Reason)
  283.  
  284.     return TRUE;
  285. } // DllMain()
  286.  
  287.  
  288.  
  289.  
  290.  
  291. BOOL WINAPIV
  292. WSAPreApiNotify(
  293.     IN  INT    NotificationCode,
  294.     OUT LPVOID ReturnCode,
  295.     IN  LPSTR  LibraryName,
  296.     ...)
  297. /*++
  298.  
  299.   Function Description:
  300.  
  301.       Builds a string for output and passes it, along with information
  302.       about the call, to a handler function.
  303.  
  304.   Arguments:
  305.  
  306.       NotificationCode -- specifies which API function called us.
  307.  
  308.       ReturnCode -- a generic pointer to the return value of the API
  309.       function.  Can be used to change the return value in the
  310.       case of a short-circuit (see how the return value from
  311.       PreApiNotify works for more information on short-circuiting
  312.       the API function).
  313.  
  314.       LibraryName -- a string pointing to the name of the library that
  315.       called us.
  316.  
  317.       ...    -- variable number argument list.  These are pointers
  318.       to the actual parameters of the API functions.
  319.  
  320.   Return Value:
  321.  
  322.       Returns TRUE if we want to short-circuit the API function;
  323.       in other words, returning non-zero here forces the API function
  324.       to return immediately before any other actions take place.
  325.  
  326.       Returns FALSE if we want to proceed with the API function.
  327.  
  328. --*/
  329. {
  330.     va_list          vl;            // used for variable arg-list parsing
  331.     Cstack_c         *ThreadCstack; // the Cstack_c object for this thread
  332.     int              Index = 0;     // index into string we are creating
  333.     BOOL             ReturnValue;   // value to return
  334.     LPFNDTHANDLER    HdlFunc;       // pointer to handler function
  335.     int              Counter;       // counter popped off the cstack
  336.     int              OriginalError; // any pending error is saved
  337.     int              HandlerError;  // the error after handler returns
  338.  
  339.     EnterCriticalSection(&CrSec);
  340.     OriginalError = GetLastError();
  341.  
  342.     // Wait until the debug window is ready to receive text for output.
  343.     WaitForSingleObject(TextOutEvent, INFINITE);
  344.     va_start(vl, LibraryName);
  345.  
  346.     // Get the Cstack_c object for this thread.
  347.     ThreadCstack = (Cstack_c *)TlsGetValue(TlsIndex);
  348.     if (!ThreadCstack){
  349.         ThreadCstack = new Cstack_c();
  350.         TlsSetValue(TlsIndex, (LPVOID)ThreadCstack);
  351.         wsprintf(Buffer, "0x%X Foriegn thread\n",
  352.                  GetCurrentThreadId());
  353.         DTTextOut(DebugWindow, LogFileHandle, Buffer, OutputStyle);
  354.     } //if
  355.  
  356.     // Start building an output string with some info that's
  357.     // independent of which API function called us.
  358.     Index += wsprintf(Buffer, "TID: 0x%X   ", GetCurrentThreadId());
  359.     Index += wsprintf(Buffer + Index, "Function call: %d   ",
  360.                       ThreadCstack->CGetCounter());
  361.  
  362.     // Push the counter & increment.
  363.     ThreadCstack->CPush();
  364.  
  365.     // Reset the error to what it was when the function started.
  366.     SetLastError(OriginalError);
  367.  
  368.     // Call the appropriate handling function, output the buffer.
  369.     if ((NotificationCode < MAX_DTCODE) && HdlFuncTable[NotificationCode]) {
  370.         HdlFunc = HdlFuncTable[NotificationCode];
  371.         ReturnValue = (*HdlFunc)(vl, ReturnCode,
  372.                                  LibraryName,
  373.                                  Buffer,
  374.                                  Index,
  375.                                  TEXT_LEN,
  376.                                  TRUE);
  377.         HandlerError = GetLastError();
  378.  
  379.     } else {
  380.  
  381.         wsprintf(Buffer + Index, "Unknown function called!\r\n");
  382.         DTTextOut(DebugWindow, LogFileHandle, Buffer, OutputStyle);
  383.         ReturnValue = FALSE;
  384.     }
  385.  
  386.     // If we are returning TRUE, then the API/SPI function will be
  387.     // short-circuited.  We must pop the thread stack, since no
  388.     // corresponding WSAPostApiNotify will be called.
  389.     if (ReturnValue) {
  390.         ThreadCstack->CPop(Counter);
  391.     }
  392.  
  393.     // In case the error has changed since the handler returned, we
  394.     // want to set it back to that.  So if the handler set the error,
  395.     // the function exits with that value; if not, it exits with the
  396.     // original error.
  397.     SetLastError(HandlerError);
  398.     LeaveCriticalSection(&CrSec);
  399.     return(ReturnValue);
  400.  
  401. } // WSAPreApiNotify()
  402.  
  403.  
  404.  
  405.  
  406.  
  407.  
  408. BOOL WINAPIV
  409. WSAPostApiNotify(
  410.     IN  INT    NotificationCode,
  411.     OUT LPVOID ReturnCode,
  412.     IN  LPSTR  LibraryName,
  413.     ...)
  414. /*++
  415.  
  416.   PostApiNotify()
  417.  
  418.   Function Description:
  419.  
  420.       Like PreApiNotify, builds a string and passes it, along with
  421.       information about the call, to a handler function.
  422.  
  423.   Arguments:
  424.  
  425.       NotificationCode  -- specifies which API function called us.
  426.  
  427.       ReturnCode -- a generic pointer to the return value of the API
  428.       function.
  429.  
  430.       ...    -- variable number argument list.  These are pointers
  431.       to the actual parameters of the API functions.
  432.  
  433.   Return Value:
  434.  
  435.       Returns value is currently meaningless.
  436.  
  437. --*/
  438. {
  439.     va_list          vl;            // used for variable arg-list parsing
  440.     Cstack_c         *ThreadCstack; // the Cstack_c object for this thread
  441.     int              Index = 0;     // index into string we are creating
  442.     int              Counter;       // counter we pop off the cstack
  443.     LPFNDTHANDLER    HdlFunc;       // pointer to handler function
  444.     int              OriginalError; // any pending error is saved
  445.     int              HandlerError;  // error after the handler returns
  446.  
  447.     // Lets hope EnterCriticalSection() doesn't change the error...
  448.     EnterCriticalSection(&CrSec);
  449.     OriginalError = GetLastError();
  450.  
  451.     // Wait until it's ok to send output.
  452.     WaitForSingleObject(TextOutEvent, INFINITE);
  453.     
  454.     va_start(vl, LibraryName);
  455.  
  456.     // Get the cstack object from TLS, pop the Counter.
  457.     ThreadCstack = (Cstack_c *) TlsGetValue(TlsIndex);
  458.  
  459.     if (!ThreadCstack){
  460.         ThreadCstack = new Cstack_c();
  461.         TlsSetValue(TlsIndex, (LPVOID)ThreadCstack);
  462.         wsprintf(Buffer, "0x%X Foriegn thread\n",
  463.                  GetCurrentThreadId());
  464.         DTTextOut(DebugWindow, LogFileHandle, Buffer, OutputStyle);
  465.     } //if
  466.  
  467.     ThreadCstack->CPop(Counter);
  468.  
  469.     // Output some info that's independent of which API called us.
  470.     Index += wsprintf(Buffer, "TID: 0x%X   ", GetCurrentThreadId());
  471.     Index += wsprintf(Buffer + Index, "Function Call: %d   ", Counter);
  472.  
  473.     // Set the error to what it originally was.
  474.     SetLastError(OriginalError);
  475.  
  476.     // Call the appropriate handling function, output the buffer.
  477.     if ((NotificationCode < MAX_DTCODE) && HdlFuncTable[NotificationCode]) {
  478.         HdlFunc = HdlFuncTable[NotificationCode];
  479.         (*HdlFunc)(vl, ReturnCode,
  480.                    LibraryName,
  481.                    Buffer,
  482.                    Index,
  483.                    TEXT_LEN,
  484.                    FALSE);
  485.         HandlerError = GetLastError();
  486.  
  487.     } else {
  488.  
  489.         wsprintf(Buffer + Index, "Unknown function returned!\r\n");
  490.         DTTextOut(DebugWindow, LogFileHandle, Buffer, OutputStyle);
  491.     }
  492.  
  493.     // In case the error has changed since the handler returned, we
  494.     // want to set it back to that.  So if the handler set the error,
  495.     // the function exits with that value; if not, it exits with the
  496.     // original error.
  497.     SetLastError(HandlerError);
  498.     LeaveCriticalSection(&CrSec);
  499.     return(FALSE);
  500.  
  501. } // WSAPostApiNotify()
  502.  
  503.  
  504.  
  505.  
  506.  
  507. LRESULT APIENTRY
  508. DTMainWndProc(
  509.     IN HWND   WindowHandle,
  510.     IN UINT   Message,
  511.     IN WPARAM WParam,
  512.     IN LPARAM LParam)
  513. /*++
  514.  
  515.   DTMainWndProc()
  516.  
  517.   Function Description:
  518.  
  519.       Window procedure for the main window of the Dll.  This function
  520.       processes WM_CREATE messages in order to create a child
  521.       edit control, which does most of the dirty work.  Also processes
  522.       WM_COMMAND to trap notification messages from the edit control,
  523.       as well as WM_SIZE and WM_DESTROY messages.
  524.  
  525.   Arguments:
  526.  
  527.       WindowHandle -- the window.
  528.  
  529.       Message -- the message.
  530.  
  531.       WParam -- first parameter.
  532.  
  533.       LParam -- second parameter.
  534.  
  535.   Return Value:
  536.  
  537.       Message dependent.
  538.  
  539. --*/
  540. {
  541.  
  542.     HFONT      FixedFontHandle;   // self-explanatory
  543.     RECT       Rect;              // specifies client area of frame window
  544.     DWORD      CharIndex1;
  545.     DWORD      CharIndex2;
  546.     DWORD      LineIndex;         // indices into edit control text
  547.     char       NullString[] = ""; // self-explanatory
  548.     DWORD      OldOutputStyle;    // temporary storage for OutputStyle
  549.  
  550.     switch (Message) {
  551.  
  552.     case WM_CREATE:
  553.  
  554.         // Create the debug window as a multiline edit control.
  555.         GetClientRect(WindowHandle, &Rect);
  556.         DebugWindow = CreateWindow("EDIT",
  557.                                    NULL,
  558.                                    WS_CHILD | WS_VISIBLE |
  559.                                    WS_VSCROLL | ES_LEFT  |
  560.                                    ES_MULTILINE | ES_AUTOVSCROLL,
  561.                                    0,
  562.                                    0,
  563.                                    Rect.right,
  564.                                    Rect.bottom,
  565.                                    WindowHandle,
  566.                                    (HMENU)EC_CHILD,
  567.                                    DllInstHandle,
  568.                                    NULL);
  569.  
  570.         // Subclass the edit control's window procedure to be
  571.         // DTEditWndProc.
  572.         EditWndProc = (WNDPROC) SetWindowLong(DebugWindow,
  573.                                               GWL_WNDPROC,
  574.                                               (DWORD)DTEditWndProc);
  575.  
  576.         // Set the edit control's text size to the maximum.
  577.         SendMessage(DebugWindow, EM_LIMITTEXT, 0, 0);
  578.  
  579.         // Set the edit control's font
  580.         FixedFontHandle = (HFONT)GetStockObject(ANSI_FIXED_FONT);
  581.         SendMessage(DebugWindow, WM_SETFONT, (WPARAM)FixedFontHandle,
  582.                     MAKELPARAM(TRUE, 0));
  583.  
  584.         return(0);
  585.  
  586.     case WM_COMMAND:
  587.  
  588.         if (LOWORD(WParam) == EC_CHILD) {
  589.  
  590.             // The notification is coming from the edit-control child.
  591.             // Determine which notification it is and act appropriately.
  592.  
  593.             switch (HIWORD(WParam)) {
  594.  
  595.             case EN_ERRSPACE:
  596.  
  597.                 // Flow through
  598.  
  599.             case EN_MAXTEXT:
  600.  
  601.                 // There's too much text in the edit control.  This is
  602.                 // a hack to eliminate approximately the first half of
  603.                 // the text, so we can then add more...
  604.                 CharIndex1 = GetWindowTextLength(DebugWindow) / 2;
  605.                 LineIndex = SendMessage(DebugWindow, EM_LINEFROMCHAR,
  606.                                         (WPARAM)CharIndex1, 0);
  607.                 CharIndex2 = SendMessage(DebugWindow, EM_LINEINDEX,
  608.                                          (WPARAM)LineIndex, 0);
  609.  
  610.                 SendMessage(DebugWindow, EM_SETSEL, 0, CharIndex2);
  611.                 SendMessage(DebugWindow, EM_REPLACESEL, 0,
  612.                             (LPARAM)NullString);
  613.  
  614.                 // send this text to the window only...
  615.                 OldOutputStyle = OutputStyle;
  616.                 OutputStyle = WINDOW_ONLY;
  617.                 DTTextOut(DebugWindow, LogFileHandle,
  618.                           "----Buffer Overflow...Resetting----\r\n",
  619.                           OutputStyle);
  620.                 OutputStyle = OldOutputStyle;
  621.                 break;
  622.  
  623.             case EN_CHANGE:
  624.             case EN_UPDATE:
  625.  
  626.                 // Ignore these notification codes
  627.                 return 0;
  628.                 break;
  629.  
  630.             default:
  631.  
  632.                 // Let the default window procedure handle it.
  633.                 return DefWindowProc(WindowHandle, Message, WParam,
  634.                                  LParam);
  635.             } // switch (HIWORD(WParam))
  636.  
  637.         } // if (LOWORD(WParam) == EC_CHILD)
  638.         else {
  639.  
  640.             // The notification is coming from somewhere else!!!
  641.             return DefWindowProc(WindowHandle, Message, WParam,
  642.                                  LParam);
  643.         }
  644.  
  645.         return(0);
  646.         break;
  647.  
  648.     case WM_DESTROY:
  649.  
  650.         PostQuitMessage(0);
  651.         return(0);
  652.  
  653.     case WM_SIZE:
  654.  
  655.  
  656.         // Make the edit control the size of the window's client area.
  657.         MoveWindow(DebugWindow, 0, 0, LOWORD(LParam), HIWORD(LParam), TRUE);
  658.         return(0);
  659.  
  660.     default:
  661.  
  662.         // All other messages are taken care of by the default.
  663.         return(DefWindowProc(WindowHandle, Message, WParam, LParam));
  664.  
  665.     } // switch
  666.  
  667. } // DTMainWndProc()
  668.  
  669.  
  670.  
  671.  
  672.  
  673. LRESULT APIENTRY
  674. DTEditWndProc(
  675.     IN HWND   WindowHandle,
  676.     IN UINT   Message,
  677.     IN WPARAM WParam,
  678.     IN LPARAM LParam)
  679. /*++
  680.  
  681.   DTEditWndProc()
  682.  
  683.   Function Description:
  684.  
  685.       Subclassed window procedure for the debug window.  This function
  686.       disables some edit control functionality, and also responds to a
  687.       user-defined message to print out text in the window.
  688.  
  689.   Arguments:
  690.  
  691.       WindowHandle -- the window.
  692.  
  693.       Message -- the message.
  694.  
  695.       WParam -- first parameter.
  696.  
  697.       LParam -- second parameter.
  698.  
  699.   Return Value:
  700.  
  701.       Message dependent.
  702.  
  703. --*/
  704. {
  705.     switch (Message) {
  706.  
  707.     case WM_CHAR:
  708.  
  709.         // Handle control-c so that copy works.  Sorry about the magic
  710.         // number!
  711.         if (WParam == 3) {
  712.             return (CallWindowProc((WNDPROC)EditWndProc, WindowHandle, Message,
  713.                                    WParam, LParam));
  714.         } // else flows through
  715.  
  716.     case WM_KEYDOWN:    // Flow through
  717.     case WM_UNDO:       // Flow through
  718.     case WM_PASTE:      // Flow through
  719.     case WM_CUT:
  720.  
  721.         return (0);     // Effectively disables the above messages
  722.  
  723.     default:
  724.  
  725.         return (CallWindowProc(EditWndProc, WindowHandle, Message,
  726.                                WParam, LParam));
  727.     } // switch
  728.  
  729. } // DTEditWndProc()
  730.  
  731.  
  732.  
  733.  
  734.  
  735. DWORD
  736. WindowThreadFunc(
  737.     LPDWORD TheParam)
  738. /*++
  739.  
  740.   WindowThreadFunc()
  741.  
  742.   Function Description:
  743.  
  744.       Thread function for WindowThread created in DllMain during
  745.       process attachment.  Registers a window class, creates an
  746.       instance of that class, and goes into a message loop to retrieve
  747.       messages for that window or it's child edit control.
  748.  
  749.   Arguments:
  750.  
  751.       TheParam -- Pointer to the parameter passed in by the function
  752.       that called CreateThread.
  753.  
  754.   Return Value:
  755.  
  756.       Returns the wParam of the quit message that forced us out of the
  757.       message loop.
  758.  
  759. --*/
  760. {
  761.  
  762.     WNDCLASS  wnd_class;    // window class structure to register
  763.     MSG       msg;          // retrieved message
  764.     PINITDATA InitDataPtr;  // casts TheParam into a INITDATA pointer
  765.  
  766.     // Register a window class for the frame window.
  767.     wnd_class.style         = CS_HREDRAW | CS_VREDRAW;
  768.     wnd_class.lpfnWndProc   = DTMainWndProc;
  769.     wnd_class.cbClsExtra    = 0;
  770.     wnd_class.cbWndExtra    = 0;
  771.     wnd_class.hInstance     = DllInstHandle;
  772.     wnd_class.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
  773.     wnd_class.hCursor       = LoadCursor(NULL, IDC_ARROW);
  774.     wnd_class.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
  775.     wnd_class.lpszMenuName  = NULL;
  776.     wnd_class.lpszClassName = DTWndClass;
  777.     RegisterClass(&wnd_class);
  778.  
  779.     // Create a frame window
  780.     FrameWindow = CreateWindow(DTWndClass,
  781.                                "Debug Window",
  782.                                WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN |
  783.                                WS_VISIBLE,
  784.                                CW_USEDEFAULT,
  785.                                CW_USEDEFAULT,
  786.                                CW_USEDEFAULT,
  787.                                CW_USEDEFAULT,
  788.                                NULL,
  789.                                NULL,
  790.                                DllInstHandle,
  791.                                NULL);
  792.  
  793.     // Send the initialization data to the debug window and/or file.
  794.     InitDataPtr = (PINITDATA)TheParam;
  795.     wsprintf(Buffer, "Log initiated: %d-%d-%d, %d:%d:%d\r\n",
  796.              InitDataPtr->LocalTime.wMonth,
  797.              InitDataPtr->LocalTime.wDay,
  798.              InitDataPtr->LocalTime.wYear,
  799.              InitDataPtr->LocalTime.wHour,
  800.              InitDataPtr->LocalTime.wMinute,
  801.              InitDataPtr->LocalTime.wSecond);
  802.     DTTextOut(DebugWindow, LogFileHandle, Buffer, OutputStyle);
  803.     wsprintf(Buffer, "Process ID: 0x%X   Thread ID: 0x%X\r\n",
  804.              InitDataPtr->PID,
  805.              InitDataPtr->TID);
  806.     DTTextOut(DebugWindow, LogFileHandle, Buffer, OutputStyle);
  807.     LocalFree(InitDataPtr);
  808.  
  809.     // Setting this event allows {Pre|Post}ApiNotify to proceed.  This
  810.     // insures (ensures?  what's the difference) that any debugging
  811.     // output by other threads is held up until after this statement.
  812.     SetEvent(TextOutEvent);
  813.  
  814.     // Go into a message loop.
  815.     while (GetMessage(&msg, NULL, 0 , 0)) {
  816.         TranslateMessage(&msg);
  817.         DispatchMessage(&msg);
  818.     }
  819.  
  820.     return(msg.wParam);
  821.  
  822. } // WindowThreadFunc()
  823.  
  824.  
  825.  
  826.  
  827.  
  828. BOOL APIENTRY
  829. DebugDlgProc(
  830.     HWND DialogWindow,
  831.     UINT Message,
  832.     WPARAM WParam,
  833.     LPARAM LParam)
  834. /*++
  835.  
  836.   DebugDlgProc()
  837.  
  838.   Function Description:
  839.  
  840.       Window function for the dialog box IDC_DIALOG1, the dialog box
  841.       that pops up when the dll is loaded and prompts the user for the
  842.       output style of his/her choice.
  843.  
  844.   Arguments:
  845.  
  846.       DialogWindow -- handle to the dialog box window.
  847.  
  848.       Message -- the message being received.
  849.  
  850.       WParam -- first parameter.
  851.  
  852.       LParam -- second parameter.
  853.  
  854.   Return Value:
  855.  
  856.       Returns TRUE to indicate message was handled, FALSE otherwise.
  857.  
  858. --*/
  859. {
  860.  
  861.     DWORD LogFNSize = sizeof(LogFileName); // size of the file name buffer
  862.  
  863.     switch (Message) {
  864.  
  865.     case WM_COMMAND:
  866.  
  867.         switch (LOWORD(WParam)) {
  868.  
  869.         case IDOK:
  870.  
  871.             // The user clicked the OK button...figure out his choice
  872.             // and act appropriately.
  873.             if (IsDlgButtonChecked(DialogWindow, IDC_RADIO5)) {
  874.  
  875.                 // Radio Button 1 was clicked.
  876.                 if (!GetFile(DialogWindow, LogFileName, LogFNSize)) {
  877.  
  878.                     // Error -- OutputStyle stays WINDOW_ONLY.
  879.                     MessageBox(DialogWindow, ErrStr2, "Error.",
  880.                                MB_OK | MB_ICONSTOP);
  881.                 } else {
  882.                     OutputStyle = FILE_ONLY;
  883.                 }
  884.  
  885.             } else if (IsDlgButtonChecked(DialogWindow, IDC_RADIO6)) {
  886.  
  887.                 // Radio Button 2 was clicked.
  888.                 OutputStyle = WINDOW_ONLY;
  889.  
  890.             } else if (IsDlgButtonChecked(DialogWindow, IDC_RADIO7)) {
  891.  
  892.                 // Radio Button 3 was clicked.
  893.                 if (!GetFile(DialogWindow, LogFileName, LogFNSize)) {
  894.  
  895.                     // Error -- OutputStyle stays WINDOW_ONLY.
  896.                     MessageBox(DialogWindow, ErrStr2, "Error",
  897.                                MB_OK | MB_ICONSTOP);
  898.                 } else {
  899.                     OutputStyle = FILE_AND_WINDOW;
  900.                 }
  901.  
  902.             } else if (IsDlgButtonChecked(DialogWindow, IDC_RADIO8)) {
  903.  
  904.                 // Radio Button 4 was clicked.
  905.                 OutputStyle = DEBUGGER;
  906.  
  907.             } else {
  908.  
  909.                 // No radio buttons were clicked -- pop up a Message
  910.                 // box.
  911.                 MessageBox(DialogWindow, "You must choose one output method.",
  912.                            "Choose or Die.", MB_OK | MB_ICONSTOP);
  913.                 break;
  914.  
  915.             }
  916.  
  917.             // flow through
  918.  
  919.         case IDCANCEL:
  920.  
  921.             EndDialog(DialogWindow, WParam);
  922.             return TRUE;
  923.  
  924.         }
  925.  
  926.     case WM_INITDIALOG:
  927.  
  928.         return TRUE;
  929.  
  930.     }
  931.     return FALSE;
  932.  
  933. } // DebugDlgProc()
  934.  
  935.  
  936.  
  937.  
  938.  
  939. BOOL
  940. DTTextOut(
  941.     IN HWND   WindowHandle,
  942.     IN HANDLE FileHandle,
  943.     IN char   *String,
  944.     DWORD     Style)
  945. /*++
  946.  
  947.   DTTextOut()
  948.  
  949.   Function Description:
  950.  
  951.       This function outputs a string to a debug window and/or file.
  952.  
  953.   Arguments:
  954.  
  955.       WindowHandle -- handle to an edit control for debug output.
  956.  
  957.       FileHandle -- handle to an open file for debug output.
  958.  
  959.       String -- the string to output.
  960.  
  961.       Style -- specifies whether the output should go to the window,
  962.       the file, or both.
  963.  
  964.   Return Value:
  965.  
  966.       Returns TRUE if the output succeeds, FALSE otherwise.
  967.  
  968. --*/
  969. {
  970.  
  971.     DWORD NumWritten;           // WriteFile takes an address to this
  972.     DWORD Index;                // index of end of edit control text
  973.     BOOL  Result;               // result of WriteFile
  974.     char  Output[TEXT_LEN];     // scratch buffer
  975.  
  976.     static DWORD LineCount = 0; // text output line number
  977.     DWORD  BufIndex = 0;        // index into output string
  978.  
  979.     // Build a new string with the line-number in front.
  980.     BufIndex += wsprintf(Output, "(%d) ", LineCount++);
  981.     strcpy(Output + BufIndex, String);
  982.  
  983.     switch (Style) {
  984.  
  985.     case WINDOW_ONLY:
  986.  
  987.         Index = GetWindowTextLength(WindowHandle);
  988.         SendMessage(WindowHandle, EM_SETSEL, Index, Index);
  989.         SendMessage(WindowHandle, EM_REPLACESEL, 0, (LPARAM)Output);
  990.  
  991.         break;
  992.  
  993.     case FILE_ONLY:
  994.  
  995.         Result = WriteFile(FileHandle, (LPCVOID)Output, strlen(Output),
  996.                            &NumWritten, NULL);
  997.         if (!Result) {
  998.  
  999.             AbortAndClose(FileHandle, WindowHandle);
  1000.             return FALSE;
  1001.         }
  1002.         break;
  1003.  
  1004.     case FILE_AND_WINDOW:
  1005.  
  1006.         Index = GetWindowTextLength(WindowHandle);
  1007.         SendMessage(WindowHandle, EM_SETSEL, Index, Index);
  1008.         SendMessage(WindowHandle, EM_REPLACESEL, 0, (LPARAM)Output);
  1009.         Result = WriteFile(FileHandle, (LPCVOID)Output, strlen(Output),
  1010.                            &NumWritten, NULL);
  1011.         if (!Result) {
  1012.  
  1013.             AbortAndClose(FileHandle, WindowHandle);
  1014.             return FALSE;
  1015.         }
  1016.         break;
  1017.  
  1018.     case DEBUGGER:
  1019.  
  1020.         OutputDebugString(Output);
  1021.     }
  1022.     return TRUE;
  1023.  
  1024. } // DTTextOut()
  1025.  
  1026.  
  1027.  
  1028.  
  1029.  
  1030. void
  1031. AbortAndClose(
  1032.     IN HANDLE FileHandle,
  1033.     IN HWND WindowHandle)
  1034. /*++
  1035.  
  1036.   AbortAndClose()
  1037.  
  1038.   Function Description:
  1039.  
  1040.       Closes a file handle, informs the user via a message box, and
  1041.       changes the global variable OutputStyle to WINDOW_ONLY
  1042.  
  1043.   Arguments:
  1044.  
  1045.       FileHandle -- handle to a file that caused the error.
  1046.  
  1047.       WindowHandle -- handle to a window to be the parent of the
  1048.       Message Box.
  1049.  
  1050.   Return Value:
  1051.  
  1052.       Void.
  1053.  
  1054. --*/
  1055. {
  1056.     CloseHandle(FileHandle);
  1057.     MessageBox(WindowHandle, ErrStr3, "Error", MB_OK | MB_ICONSTOP);
  1058.     OutputStyle = WINDOW_ONLY;
  1059.  
  1060. } // AbortAndClose()
  1061.  
  1062.  
  1063.  
  1064.  
  1065.  
  1066. BOOL
  1067. GetFile(
  1068.     IN  HWND   OwnerWindow,
  1069.     OUT LPSTR  FileName,
  1070.     IN  DWORD  FileNameSize)
  1071. /*++
  1072.  
  1073.   GetFile()
  1074.  
  1075.   Function Description:
  1076.  
  1077.       Uses the predefined "Save As" dialog box style to retrieve a
  1078.       file name from the user.  The file name the user selects is
  1079.       stored in LogFileName.
  1080.  
  1081.   Arguments:
  1082.  
  1083.       OwnerWindow -- window which will own the dialog box.
  1084.  
  1085.       FileName -- address of a buffer in which to store the string.
  1086.  
  1087.       FileNameSize -- size of the FileName buffer.
  1088.  
  1089.   Return Value:
  1090.  
  1091.       Returns whatever GetSaveFileName returns; see documentation for
  1092.       that function.
  1093.  
  1094. --*/
  1095. {
  1096.  
  1097.     OPENFILENAME OpenFileName;  // common dialog box structure
  1098.     char DirName[256];          // directory string
  1099.     char FileTitle[256];        // file-title string
  1100.  
  1101.     FileName[0] = '\0';
  1102.  
  1103.     FillMemory((PVOID)&OpenFileName, sizeof(OPENFILENAME), 0);
  1104.  
  1105.     // Retrieve the system directory name and store it in DirName.
  1106.     GetCurrentDirectory(sizeof(DirName), DirName);
  1107.  
  1108.     // Set the members of the OPENFILENAME structure.
  1109.     OpenFileName.lStructSize = sizeof(OPENFILENAME);
  1110.     OpenFileName.hwndOwner = OwnerWindow;
  1111.     OpenFileName.lpstrFilter = OpenFileName.lpstrCustomFilter = NULL;
  1112.     OpenFileName.nFilterIndex = 0;
  1113.     OpenFileName.lpstrFile = FileName;
  1114.     OpenFileName.nMaxFile = FileNameSize;
  1115.     OpenFileName.lpstrFileTitle = FileTitle;
  1116.     OpenFileName.nMaxFileTitle = sizeof(FileTitle);
  1117.     OpenFileName.lpstrInitialDir = DirName;
  1118.     OpenFileName.Flags = OFN_SHOWHELP | OFN_OVERWRITEPROMPT;
  1119.  
  1120.     // Pop up the dialog box to get the file name.
  1121.     return GetSaveFileName(&OpenFileName);
  1122.  
  1123. } // GetFile()
  1124.