home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / com / freethrd / server / apputil.cpp next >
Encoding:
C/C++ Source or Header  |  1998-04-03  |  61.6 KB  |  2,140 lines

  1. /*+==========================================================================
  2.   File:      APPUTIL.CPP
  3.  
  4.   Summary:   Implementation file for the general application utility
  5.              classes and functions offered by the APPUTIL library.
  6.  
  7.              For a comprehensive tutorial code tour of APPUTIL's
  8.              contents and offerings see the accompanying APPUTIL.TXT file.
  9.              For more specific details see the comments dispersed
  10.              throughout the APPUTIL source code.
  11.  
  12.   Classes:   CVirWindow, CVirDialog, CAboutBox, CMsgBox, CMsgLog
  13.  
  14.   Functions: WindowProc, DialogProc, FileExist, MakeFamilyPath, CmdExec,
  15.              ReadMe, ReadMeFile, ReadSource, OutputDebugFmt, lRandom,
  16.              UcToAnsi, A_StringFromGUID2, A_WriteFmtUserTypeStg,
  17.              A_StgIsStorageFile, A_StgCreateDocfile, A_StgOpenStorage,
  18.              CreateColorScalePalette, PaintWindow.
  19.  
  20.   Origin:    7-27-95: atrent - Created based on WINHLPRS by stevebl.
  21.  
  22. ----------------------------------------------------------------------------
  23.   This file is part of the Microsoft OLE Tutorial Code Samples.
  24.  
  25.   Copyright (C) Microsoft Corporation, 1996.  All rights reserved.
  26.  
  27.   This source code is intended only as a supplement to Microsoft
  28.   Development Tools and/or on-line documentation.  See these other
  29.   materials for detailed information regarding Microsoft code samples.
  30.  
  31.   THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  32.   KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  33.   IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  34.   PARTICULAR PURPOSE.
  35. ==========================================================================+*/
  36.  
  37. /*---------------------------------------------------------------------------
  38.   We include WINDOWS.H for all Win32 applications.
  39.   We include TCHAR.H for general Unicode/Ansi prototype of utility
  40.     functions like _tsplitpath, etc.
  41.   We include APPUTIL.H for the defines of this APPUTIL library.  We use
  42.     the _NOANSIMACROS_ to turn off the ANSI macro undefines so that
  43.     function calls to certain OLE APIs inside this module get to the
  44.     original OLE functions instead of the ANSI surrogates.
  45. ---------------------------------------------------------------------------*/
  46.  
  47. #include <windows.h>
  48. #include <tchar.h>
  49. #define _NOANSIMACROS_
  50. #include "apputil.h"
  51.  
  52. #if !defined(UNICODE)
  53.  
  54. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  55.   Function: UcToAnsi
  56.  
  57.   Summary:  Convert a UNICODE input string to an output ANSI string.
  58.  
  59.   Args:     LPWSTR pszUc
  60.               Pointer to a caller's input UNICODE wide string.
  61.             LPSTR pszAnsi
  62.               Pointer to a caller's output ANSI string.
  63.             int cch
  64.               Character count. If 0 then use length of pszUc.
  65.  
  66.   Returns:  HRESULT
  67.               Standard OLE result code. NOERROR for success.
  68. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  69. HRESULT UcToAnsi(
  70.           LPWSTR pszUc,
  71.           LPSTR pszAnsi,
  72.           int cch)
  73. {
  74.   HRESULT hr = E_FAIL;
  75.   int cSize;
  76.   int cOut;
  77.  
  78.   if (0 == cch)
  79.     cSize = WideCharToMultiByte(CP_ACP,0,pszUc,-1,NULL,0,NULL,NULL);
  80.   else
  81.     cSize = cch;
  82.  
  83.   if (0 != cSize)
  84.   {
  85.     cOut = WideCharToMultiByte(CP_ACP,0,pszUc,-1,pszAnsi,cSize,NULL,NULL);
  86.     if (0 != cOut)
  87.       hr = NOERROR;
  88.   }
  89.  
  90.   return hr;
  91. }
  92.  
  93.  
  94. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  95.   Function: A_StringFromGUID2
  96.  
  97.   Summary:  ANSI Surrogate for the OLE Unicode API call.
  98. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  99. STDAPI A_StringFromGUID2(REFGUID guid, LPSTR pszGUID, int cch)
  100. {
  101.   HRESULT hr = E_INVALIDARG;
  102.   LPWSTR  pszUc;
  103.   IMalloc* pIMalloc;
  104.  
  105.   if (NULL != pszGUID && 0 < cch)
  106.   {
  107.     hr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);
  108.     if (SUCCEEDED(hr))
  109.     {
  110.       pszUc = (LPWSTR)pIMalloc->Alloc((cch+1)*sizeof(TCHAR));
  111.       pIMalloc->Release();
  112.       if (NULL != pszUc)
  113.       {
  114.         hr = StringFromGUID2(guid, pszUc, cch);
  115.         if (SUCCEEDED(hr))
  116.           hr = UcToAnsi(pszUc, pszGUID, cch);
  117.         CoTaskMemFree((void *)pszUc);
  118.       }
  119.       else
  120.         hr = E_OUTOFMEMORY;
  121.     }
  122.   }
  123.  
  124.   return hr;
  125. }
  126.  
  127.  
  128. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  129.   Function: A_WriteFmtUserTypeStg
  130.  
  131.   Summary:  ANSI Surrogate for the OLE Unicode API call.
  132. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  133. STDAPI A_WriteFmtUserTypeStg(
  134.          IStorage* pIStorage,
  135.          CLIPFORMAT ClipFmt,
  136.          LPSTR pszUserType)
  137. {
  138.   HRESULT hr = E_INVALIDARG;
  139.   WCHAR szUc[MAX_PATH];
  140.  
  141.   if (NULL != pszUserType)
  142.   {
  143.     MultiByteToWideChar(CP_ACP, 0, pszUserType, -1, szUc, MAX_PATH);
  144.     hr = WriteFmtUserTypeStg(pIStorage, ClipFmt, szUc);
  145.   }
  146.  
  147.   return hr;
  148. }
  149.  
  150.  
  151. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  152.   Function: A_StgIsStorageFile
  153.  
  154.   Summary:  ANSI Surrogate for the OLE Unicode API call.
  155. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  156. STDAPI A_StgIsStorageFile(
  157.          LPSTR pszFileName)
  158. {
  159.   HRESULT hr = E_INVALIDARG;
  160.   WCHAR szUc[MAX_PATH];
  161.  
  162.   if (NULL != pszFileName)
  163.   {
  164.     MultiByteToWideChar(CP_ACP, 0, pszFileName, -1, szUc, MAX_PATH);
  165.     hr = StgIsStorageFile(szUc);
  166.   }
  167.  
  168.   return hr;
  169. }
  170.  
  171.  
  172. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  173.   Function: A_StgCreateDocfile
  174.  
  175.   Summary:  ANSI Surrogate for the OLE Unicode API call.
  176. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  177. STDAPI A_StgCreateDocfile(
  178.          LPSTR pszFileName,
  179.          DWORD dwAccessMode,
  180.          DWORD reserved,
  181.          IStorage** ppIStorage)
  182. {
  183.   HRESULT hr = E_INVALIDARG;
  184.   WCHAR szUc[MAX_PATH];
  185.   LPWSTR pszUc = NULL;
  186.  
  187.   // Null the caller's output variable.
  188.   *ppIStorage = NULL;
  189.  
  190.   if (NULL != pszFileName)
  191.   {
  192.     MultiByteToWideChar(CP_ACP, 0, pszFileName, -1, szUc, MAX_PATH);
  193.     pszUc = szUc;
  194.   }
  195.  
  196.   hr = StgCreateDocfile(pszUc, dwAccessMode, reserved, ppIStorage);
  197.  
  198.   return hr;
  199. }
  200.  
  201.  
  202. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  203.   Function: A_StgOpenStorage
  204.  
  205.   Summary:  ANSI Surrogate for the OLE Unicode API call.
  206. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  207. STDAPI A_StgOpenStorage(
  208.          LPSTR pszFileName,
  209.          IStorage* pIStorage,
  210.          DWORD dwAccessMode,
  211.          SNB snbExclude,
  212.          DWORD reserved,
  213.          IStorage** ppIStorage)
  214. {
  215.   HRESULT hr = E_INVALIDARG;
  216.   WCHAR szUc[MAX_PATH];
  217.   LPWSTR pszUc = NULL;
  218.  
  219.   // Null the caller's output variable.
  220.   *ppIStorage = NULL;
  221.  
  222.   if (NULL != pszFileName)
  223.   {
  224.     MultiByteToWideChar(CP_ACP, 0, pszFileName, -1, szUc, MAX_PATH);
  225.     pszUc = szUc;
  226.   }
  227.  
  228.   hr = StgOpenStorage(
  229.          pszUc,
  230.          pIStorage,
  231.          dwAccessMode,
  232.          snbExclude,
  233.          reserved,
  234.          ppIStorage);
  235.  
  236.   return hr;
  237. }
  238.  
  239.  
  240. #endif  // !UNICODE
  241.  
  242.  
  243. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  244.   Function: lRandom
  245.  
  246.   Summary:  Simple random number generator. Returns a random DWORD.
  247.  
  248.   Args:     void
  249.  
  250.   Returns:  DWORD
  251.               Random number.
  252. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  253. DWORD lRandom(void)
  254. {
  255.   static DWORD glSeed = (DWORD)-365387184;
  256.  
  257.   glSeed *= 69069;
  258.  
  259.   return(++glSeed);
  260. }
  261.  
  262.  
  263. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  264.   Function: CreateColorScalePalette
  265.  
  266.   Summary:  This routine creates a palette representing the scale values
  267.             of a particular RGB color.  A gray-scale palette can also be
  268.             created. Borrowed from GDIDEMO in the Win32 samples of the
  269.             Win32 SDK.
  270.  
  271.   Args:     HDC hDC,
  272.               Handle to device context.
  273.             int nColor
  274.               New color.
  275.  
  276.   Returns:  HPALETTE
  277.               Handle to new pallete.
  278. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  279. HPALETTE CreateColorScalePalette(HDC hDC, int nColor)
  280. {
  281.   HPALETTE     hPalette;
  282.   GLOBALHANDLE hMem;
  283.   LPLOGPALETTE lpMem;
  284.   int          idx,nReserved,nSize;
  285.  
  286.   hPalette = NULL;
  287.   if(GetDeviceCaps(hDC,RASTERCAPS) & RC_PALETTE)
  288.   {
  289.     nReserved = GetDeviceCaps(hDC,NUMRESERVED);
  290.     nSize     = GetDeviceCaps(hDC,SIZEPALETTE) - nReserved;
  291.  
  292.     hMem = GlobalAlloc(
  293.              GHND,
  294.              (DWORD)sizeof(LOGPALETTE)+(sizeof(PALETTEENTRY)*nSize));
  295.     if(hMem)
  296.     {
  297.       if(lpMem = (LPLOGPALETTE)GlobalLock(hMem))
  298.       {
  299.         lpMem->palNumEntries = (WORD)nSize;
  300.         lpMem->palVersion    = (WORD)0x0300;
  301.         switch(nColor)
  302.         {
  303.           case COLOR_SCALE_RED:
  304.             for(idx=0; idx < nSize; idx++)
  305.             {
  306.               lpMem->palPalEntry[idx].peRed   = (BYTE)idx;
  307.               lpMem->palPalEntry[idx].peGreen = 0;
  308.               lpMem->palPalEntry[idx].peBlue  = 0;
  309.               lpMem->palPalEntry[idx].peFlags = PC_RESERVED;
  310.             }
  311.             break;
  312.  
  313.           case COLOR_SCALE_GREEN:
  314.             for(idx=0; idx < nSize; idx++)
  315.             {
  316.               lpMem->palPalEntry[idx].peRed   = 0;
  317.               lpMem->palPalEntry[idx].peGreen = (BYTE)idx;
  318.               lpMem->palPalEntry[idx].peBlue  = 0;
  319.               lpMem->palPalEntry[idx].peFlags = PC_RESERVED;
  320.             }
  321.             break;
  322.  
  323.           case COLOR_SCALE_BLUE:
  324.             for(idx=0; idx < nSize; idx++)
  325.             {
  326.               lpMem->palPalEntry[idx].peRed   = 0;
  327.               lpMem->palPalEntry[idx].peGreen = 0;
  328.               lpMem->palPalEntry[idx].peBlue  = (BYTE)idx;
  329.               lpMem->palPalEntry[idx].peFlags = PC_RESERVED;
  330.             }
  331.             break;
  332.  
  333.           default:
  334.           case COLOR_SCALE_GRAY:
  335.             for(idx=0; idx < nSize; idx++)
  336.             {
  337.               lpMem->palPalEntry[idx].peRed   = (BYTE)idx;
  338.               lpMem->palPalEntry[idx].peGreen = (BYTE)idx;
  339.               lpMem->palPalEntry[idx].peBlue  = (BYTE)idx;
  340.               lpMem->palPalEntry[idx].peFlags = PC_RESERVED;
  341.             }
  342.             break;
  343.         }
  344.  
  345.         hPalette = CreatePalette(lpMem);
  346.  
  347.         GlobalUnlock(hMem);
  348.       }
  349.       GlobalFree(hMem);
  350.     }
  351.   }
  352.  
  353.   return(hPalette);
  354. }
  355.  
  356.  
  357. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  358.   Function: PaintWindow
  359.  
  360.   Summary:  This routine is used to paint the background of a window.
  361.             Borrowed from GDIDEMO in the Win32 samples of the Win32 SDK.
  362.  
  363.   Args:     HWND hWnd,
  364.               Window handle.
  365.             int nColor
  366.               New window color.
  367.  
  368.   Returns:  void.
  369. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  370. VOID PaintWindow(HWND hWnd, int nColor)
  371. {
  372.   HDC         hDC;
  373.   int         nMapMode,idx,nSize,nReserved,nLoop;
  374.   RECT        rect;
  375.   HBRUSH      hBrush;
  376.   PAINTSTRUCT ps;
  377.   HPALETTE    hPal;
  378.  
  379.   if(hDC = BeginPaint(hWnd,&ps))
  380.   {
  381.     GetClientRect(hWnd,&rect);
  382.     nMapMode = SetMapMode(hDC,MM_ANISOTROPIC);
  383.  
  384.     if(GetDeviceCaps(hDC,RASTERCAPS) & RC_PALETTE)
  385.     {
  386.       nReserved = GetDeviceCaps(hDC,NUMRESERVED);
  387.       nSize     = GetDeviceCaps(hDC,SIZEPALETTE) - nReserved;
  388.  
  389.       if(hPal = CreateColorScalePalette(hDC,nColor))
  390.       {
  391.         hPal = SelectPalette(hDC,hPal,FALSE);
  392.         RealizePalette(hDC);
  393.  
  394.         SetWindowExtEx(hDC,nSize,nSize,NULL);
  395.         SetViewportExtEx(hDC,rect.right,-rect.bottom,NULL);
  396.         SetViewportOrgEx(hDC,0,rect.bottom,NULL);
  397.  
  398.         nLoop = nSize >> 1;
  399.         for(idx=0; idx < nLoop; idx++)
  400.         {
  401.           hBrush = CreateSolidBrush(PALETTEINDEX(idx+nLoop));
  402.           SetRect(&rect,idx,idx,nSize-idx,nSize-idx);
  403.           FillRect(hDC,&rect,hBrush);
  404.           DeleteObject(hBrush);
  405.         }
  406.         DeleteObject(SelectPalette(hDC,hPal,FALSE));
  407.         RealizePalette(hDC);
  408.       }
  409.     }
  410.     else
  411.     {
  412.       SetWindowExtEx(hDC,512,512,NULL);
  413.       SetViewportExtEx(hDC,rect.right,-rect.bottom,NULL);
  414.       SetViewportOrgEx(hDC,0,rect.bottom,NULL);
  415.  
  416.       for(idx=0; idx < 256; idx++)
  417.       {
  418.         hBrush = CreateSolidBrush(RGB(0,0,idx));
  419.         SetRect(&rect,idx,idx,512-idx,512-idx);
  420.         FillRect(hDC,&rect,hBrush);
  421.         DeleteObject(hBrush);
  422.       }
  423.     }
  424.  
  425.     SetMapMode(hDC,nMapMode);
  426.  
  427.     EndPaint(hWnd,&ps);
  428.   }
  429.  
  430.   return;
  431. }
  432.  
  433.  
  434. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  435.   Function: FileExist
  436.  
  437.   Summary:  Function to test for the existance of a file.
  438.  
  439.   Args:     TCHAR* pszFileName
  440.               String pointer to file's path/name.
  441.  
  442.   Returns:  BOOL.  TRUE if file exists; FALSE if not.
  443. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  444. BOOL FileExist(TCHAR* pszFileName)
  445. {
  446.   BOOL bExist = FALSE;
  447.   HANDLE hFile;
  448.  
  449.   if (NULL != pszFileName)
  450.   {
  451.     // Use the preferred Win32 API call and not the older OpenFile.
  452.     hFile = CreateFile(
  453.               pszFileName,
  454.               GENERIC_READ,
  455.               FILE_SHARE_READ | FILE_SHARE_WRITE,
  456.               NULL,
  457.               OPEN_EXISTING,
  458.               0,
  459.               0);
  460.  
  461.     if (hFile != INVALID_HANDLE_VALUE)
  462.     {
  463.       // If the handle is valid then the file exists.
  464.       CloseHandle(hFile);
  465.       bExist = TRUE;
  466.     }
  467.   }
  468.  
  469.   return (bExist);
  470. }
  471.  
  472.  
  473. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  474.   Function: MakeFamilyPath
  475.  
  476.   Summary:  Function to make a family file/path/name string using the
  477.             detetected pathname of the current executable module.
  478.             Makes paths like d:\dir1\dir2\mymodule.hlp,
  479.             d:\dir1\dir2\mymodule.lic, etc.
  480.  
  481.   Args:     HINSTANCE hInst
  482.               Handle to the module intstance.
  483.             TCHAR* pszNewPath
  484.               String pointer to the new path/name.
  485.             TCHAR* pszFileExt
  486.               String pointer to the filename extension for the new path.
  487.  
  488.   Returns:  BOOL.  TRUE if success; FALSE if not.
  489. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  490. BOOL MakeFamilyPath(
  491.        HINSTANCE hInst,
  492.        TCHAR* pszNewPath,
  493.        TCHAR* pszFileExt)
  494. {
  495.   BOOL bOk = FALSE;
  496.   TCHAR  szPath[MAX_PATH];
  497.   TCHAR  szDrive[64];
  498.   TCHAR  szDir[MAX_PATH];
  499.   TCHAR  szName[64];
  500.  
  501.   if (NULL != pszNewPath)
  502.   {
  503.     pszNewPath[0] = 0;
  504.  
  505.     bOk = (0 != GetModuleFileName(hInst, szPath, MAX_PATH));
  506.     if (bOk)
  507.     {
  508.       _tsplitpath(szPath, szDrive, szDir, szName, NULL);
  509.       lstrcpy(pszNewPath, szDrive);
  510.       lstrcat(pszNewPath, szDir);
  511.       lstrcat(pszNewPath, szName);
  512.       lstrcat(pszNewPath, pszFileExt);
  513.     }
  514.   }
  515.  
  516.   return bOk;
  517. }
  518.  
  519.  
  520. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  521.   Function: CmdExec
  522.  
  523.   Summary:  Execute an EXE Win32 program by creating a process and
  524.             running the specified EXE in it.
  525.  
  526.   Args:     LPTSTR szCmd,
  527.               Entire command line (eg, "notepad.exe mytext.txt")
  528.  
  529.   Returns:  BOOL
  530.               TRUE if succeed; FALSE if fail.
  531. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  532. BOOL CmdExec(
  533.        LPTSTR szCmd)
  534. {
  535.   BOOL bOk;
  536.   STARTUPINFO si;
  537.   PROCESS_INFORMATION pi;
  538.  
  539.   // Execute the command with a call to the CreateProcess API call.
  540.   memset(&si,0,sizeof(STARTUPINFO));
  541.   si.cb = sizeof(STARTUPINFO);
  542.   si.wShowWindow = SW_SHOW;
  543.   bOk = CreateProcess(NULL,szCmd,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
  544.   CloseHandle(pi.hThread);
  545.   CloseHandle(pi.hProcess);
  546.  
  547.   return bOk;
  548. }
  549.  
  550.  
  551. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  552.   Function: ReadMe
  553.  
  554.   Summary:  For use by code sample applications that study themselves as
  555.             it were.  This function assumes a "family" named <sample>.TXT
  556.             "readme" text file is located next to the main .EXE file for
  557.             the code sample.  This function launches a reader/editor on
  558.             that text file.  The default editor\reader is NOTEPAD.EXE.
  559.             You can change that editor by changing EDITOR_FILE_STR in
  560.             APPUTIL.H above.
  561.  
  562.   Args:     HINSTANCE hInst,
  563.               Handle of the executable module instance.
  564.             HWND hWndOwner,
  565.               Handle to owner parent window.
  566.  
  567.   Returns:  void
  568. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  569. void ReadMe(
  570.        HINSTANCE hInst,
  571.        HWND hWndOwner)
  572. {
  573.   TCHAR szReadCmd[MAX_PATH+12];
  574.   TCHAR szFileName[MAX_PATH];
  575.   BOOL bOk;
  576.   int iResult;
  577.  
  578.   // Build a path to where the .TXT file should be (it should be in
  579.   // the same directory as the .EXE but with the .TXT extension.
  580.   MakeFamilyPath(hInst, szFileName, TEXT(README_FILE_EXT));
  581.  
  582.   // First check if the readme .TXT file is there at all.
  583.   if (FileExist(szFileName))
  584.   {
  585.     // If the text file is there then assemble a command string.
  586.     lstrcpy(szReadCmd, TEXT(EDITOR_FILE_STR));
  587.     lstrcat(szReadCmd, szFileName);
  588.     // And execute it.
  589.     bOk = CmdExec(szReadCmd);
  590.     if (!bOk)
  591.     {
  592.       // If create procees failed then put up an error box.
  593.       iResult = MessageBox(
  594.                   hWndOwner,
  595.                   TEXT(NOEDITOR_ERROR_STR),
  596.                   TEXT(ERROR_TITLE_STR),
  597.                   MB_OK | MB_ICONEXCLAMATION);
  598.     }
  599.   }
  600.   else
  601.   {
  602.     // If the .TXT file doesn't exist the put up an error box.
  603.     iResult = MessageBox(
  604.                 hWndOwner,
  605.                 TEXT(NOREADME_ERROR_STR),
  606.                 TEXT(ERROR_TITLE_STR),
  607.                 MB_OK | MB_ICONEXCLAMATION);
  608.   }
  609.  
  610.   return;
  611. }
  612.  
  613.  
  614. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  615.   Function: ReadMeFile
  616.  
  617.   Summary:  For use by code sample applications that study themselves
  618.             as it were.  This function allows you to pass a filename for
  619.             the <sample>.TXT "readme" file associated with the code sample
  620.             and to launch a reader/editor on that file.  The default
  621.             editor\reader is NOTEPAD.EXE.  You can change that editor by
  622.             changing EDITOR_FILE_STR in APPUTIL.H.
  623.  
  624.   Args:     HWND hWndOwner,
  625.               Handle to owner parent window.
  626.             LPTSTR szFileName,
  627.               Filename string.
  628.  
  629.   Returns:  void
  630. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  631. void ReadMeFile(
  632.        HWND hWndOwner,
  633.        LPTSTR szFileName)
  634. {
  635.   TCHAR szReadCmd[MAX_PATH+12];
  636.   BOOL bOk;
  637.   int iResult;
  638.  
  639.   // First check if the readme .TXT file is there at all.
  640.   if (FileExist(szFileName))
  641.   {
  642.     // If the text file is there then assemble a command string.
  643.     lstrcpy(szReadCmd, TEXT(EDITOR_FILE_STR));
  644.     lstrcat(szReadCmd, szFileName);
  645.     // And execute it.
  646.     bOk = CmdExec(szReadCmd);
  647.     if (!bOk)
  648.     {
  649.       // If create procees failed then put up an error box.
  650.       iResult = MessageBox(
  651.                   hWndOwner,
  652.                   TEXT(NOEDITOR_ERROR_STR),
  653.                   TEXT(ERROR_TITLE_STR),
  654.                   MB_OK | MB_ICONEXCLAMATION);
  655.     }
  656.   }
  657.   else
  658.   {
  659.     // If the .TXT file doesn't exist the put up an error box.
  660.     iResult = MessageBox(
  661.                 hWndOwner,
  662.                 TEXT(NOREADME_ERROR_STR),
  663.                 TEXT(ERROR_TITLE_STR),
  664.                 MB_OK | MB_ICONEXCLAMATION);
  665.   }
  666.  
  667.   return;
  668. }
  669.  
  670.  
  671. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  672.   Function: ReadSource
  673.  
  674.   Summary:  For use by code sample applications that study themselves
  675.             as it were.  This function allows you to select one of the
  676.             source files of this code sample and launch a reader to
  677.             edit/read it.  NOTEPAD.EXE is the default editor/reader.
  678.             You can change this by changing EDITOR_FILE_STR in APPUTIL.H.
  679.  
  680.   Args:     HWND hWndOwner
  681.               Handle of parent window.
  682.             OPENFILENAME* pofn,
  683.               Pointer to the Open File Name Common Dialog structure.
  684.  
  685.   Returns:  void
  686. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  687. void ReadSource(
  688.        HWND hWndOwner,
  689.        OPENFILENAME* pOfn)
  690. {
  691.   TCHAR szReadCmd[MAX_PATH+12];
  692.   TCHAR szFileName[MAX_PATH];
  693.   BOOL bOk;
  694.   int iResult;
  695.  
  696.   // We'll use the OpenFileName Common Dialog (defined in main app).
  697.   // Set the dialog's file filter and title.
  698.   szFileName[0] = 0;
  699.   pOfn->lpstrFilter = TEXT(OFN_SOURCEFILES_STR);
  700.   pOfn->lpstrTitle = TEXT(OFN_SOURCETITLE_STR);
  701.   pOfn->lpstrFile = szFileName;
  702.  
  703.   // Call up the dialog to get a file name from the user.
  704.   if (GetOpenFileName(pOfn))
  705.   {
  706.     // If the user provided a file name then assemble a command string
  707.     lstrcpy(szReadCmd, TEXT(EDITOR_FILE_STR));
  708.     lstrcat(szReadCmd, szFileName);
  709.     // And execute it.
  710.     bOk = CmdExec(szReadCmd);
  711.     if (!bOk)
  712.     {
  713.       // If create procees failed then put up an error box.
  714.       iResult = MessageBox(
  715.                   hWndOwner,
  716.                   TEXT(NOEDITOR_ERROR_STR),
  717.                   TEXT(ERROR_TITLE_STR),
  718.                   MB_OK | MB_ICONEXCLAMATION);
  719.     }
  720.   }
  721.  
  722.   return;
  723. }
  724.  
  725.  
  726. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  727.   Function: OutputDebugFmt
  728.  
  729.   Summary:  Wraps the Win32 OutputDebugString API call to provide
  730.             printf-style formatted (and variable argument) output.
  731.  
  732.   Args:     LPTSTR pszFmt,
  733.               Format string.
  734.             [...]
  735.               Arguments to match those specified in the format string.
  736.  
  737.   Returns:  void
  738. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  739. void OutputDebugFmt(
  740.        LPTSTR pszFmt,
  741.        ...)
  742. {
  743.   va_list arglist;
  744.   va_start(arglist, pszFmt);
  745.   TCHAR szMsg[MAX_STRING_LENGTH];
  746.  
  747.   // Use the format string and arguments to format the content text.
  748.   wvsprintf(szMsg, pszFmt, arglist);
  749.   // Output the newly formated message string to the debugger display.
  750.   OutputDebugString(szMsg);
  751.  
  752.   return;
  753. }
  754.  
  755.  
  756. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  757.   Function: GetErrorMsg
  758.  
  759.   Summary:  Accepts a Win32 error code and retrieves a human readable
  760.             system message for it.
  761.  
  762.   Args:     HRESULT hr
  763.               SCODE error code.
  764.             LPTSTR pszMsg
  765.               Pointer string where message will be placed.
  766.             UINT uiSize
  767.               Max size of the msg string.
  768.  
  769.   Returns:  BOOL
  770.               TRUE if hr was error; FALSE if not.
  771. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  772. BOOL GetErrorMsg(
  773.        HRESULT hr,
  774.        LPTSTR pszMsg,
  775.        UINT uiSize)
  776. {
  777.   BOOL bErr = FAILED(hr);
  778.   DWORD dwSize;
  779.  
  780.   if (bErr)
  781.   {
  782.     memset(pszMsg, 0, uiSize * sizeof(TCHAR));
  783.  
  784.     if (HRESULT_FACILITY(hr) == FACILITY_WINDOWS)
  785.       hr = HRESULT_CODE(hr);
  786.  
  787.     dwSize = FormatMessage(
  788.       FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
  789.       NULL,
  790.       hr,
  791.       MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
  792.       pszMsg,
  793.       uiSize,
  794.       NULL);
  795.     if (dwSize>2)
  796.     {
  797.       // Take out the trailing CRLF.
  798.       pszMsg[--dwSize] = 0;
  799.       pszMsg[--dwSize] = 0;
  800.     }
  801.   }
  802.  
  803.   return bErr;
  804. }
  805.  
  806.  
  807. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  808.   Function: WindowProc
  809.  
  810.   Summary:  Standard WindowProc callback function that forwards Windows
  811.             messages on to the CVirWindow::WindowProc method.  This
  812.             Window procedure expects that it will receive a "this"
  813.             pointer as the lpCreateParams member passed as part of the
  814.             WM_NCCREATE message.  It saves the "this" pointer in the
  815.             GWL_USERDATA field of the window structure.
  816.  
  817.   Args:     HWND hWnd,
  818.               Window handle.
  819.             UINT uMsg,
  820.               Windows message.
  821.             WPARAM wParam,
  822.               First message parameter (word sized).
  823.             LPARAM lParam);
  824.               Second message parameter (long sized).
  825.  
  826.   Returns:  LRESULT.  Windows window procedure callback return value.
  827. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  828. LRESULT CALLBACK WindowProc(
  829.                    HWND hWnd,
  830.                    UINT uMsg,
  831.                    WPARAM wParam,
  832.                    LPARAM lParam)
  833. {
  834.   // Get a pointer to the window class object.
  835.   CVirWindow* pWin = (CVirWindow*) GetWindowLong(hWnd, GWL_USERDATA);
  836.  
  837.   switch (uMsg)
  838.   {
  839.     case WM_NCCREATE:
  840.       // Since this is the first time that we can get ahold of
  841.       // a pointer to the window class object, all messages that might
  842.       // have been sent before this are never seen by the Windows object
  843.       // and only get passed on to the DefWindowProc
  844.  
  845.       // Get the initial creation pointer to the window object
  846.       pWin = (CVirWindow *) ((CREATESTRUCT *)lParam)->lpCreateParams;
  847.  
  848.       // Set it's protected m_hWnd member variable to ensure that
  849.       // member functions have access to the correct window handle.
  850.       pWin->m_hWnd = hWnd;
  851.  
  852.       // Set its USERDATA DWORD to point to the window object
  853.       SetWindowLong(hWnd, GWL_USERDATA, (long) pWin);
  854.       break;
  855.  
  856.     case WM_DESTROY:
  857.       // This is our signal to destroy the window object.
  858.       SetWindowLong(hWnd, GWL_USERDATA, 0);
  859.       delete pWin;
  860.       pWin = (CVirWindow *) 0;
  861.       break;
  862.  
  863.     default:
  864.       break;
  865.   }
  866.  
  867.   // Call its message proc method.
  868.   if (pWin != (CVirWindow *) 0)
  869.     return (pWin->WindowProc(uMsg, wParam, lParam));
  870.   else
  871.     return (DefWindowProc(hWnd, uMsg, wParam, lParam));
  872. }
  873.  
  874.  
  875. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  876.   Method:   CVirWindow::Create
  877.  
  878.   Summary:  Envelopes the Windows' CreateWindow call.  Uses its
  879.             window-creation data pointer to pass the 'this' pointer.
  880.  
  881.   Args:     LPTSTR lpszClassName,
  882.               Address of registered class name.
  883.             LPTSTR lpszWindowName,
  884.               Address of window name/title.
  885.             DWORD dwStyle,
  886.               Window style.
  887.             int x,
  888.               Horizontal position of window.
  889.             int y,
  890.               Vertical position of window.
  891.             int nWidth,
  892.               Window width.
  893.             int nHeight,
  894.               Window height.
  895.             HWND hwndParent,
  896.               Handle of parent or owner window.
  897.             HMENU hmenu,
  898.               Handle of menu, or child window identifier.
  899.             HINSTANCE hinst)
  900.               Handle of application instance.
  901.  
  902.   Modifies: m_hWnd, m_hInst.
  903.  
  904.   Returns:  HWND (Window handle) of the created window.
  905. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  906. HWND CVirWindow::Create(
  907.        LPTSTR lpszClassName,
  908.        LPTSTR lpszWindowName,
  909.        DWORD dwStyle,
  910.        int x,
  911.        int y,
  912.        int nWidth,
  913.        int nHeight,
  914.        HWND hWndParent,
  915.        HMENU hMenu,
  916.        HINSTANCE hInst)
  917. {
  918.   // Remember the passed instance handle in a member variable of the
  919.   //   C++ Window object.
  920.   m_hInst = hInst;
  921.  
  922.   // Call the Win32 API to create the window.
  923.   m_hWnd = ::CreateWindow(
  924.                lpszClassName,
  925.                lpszWindowName,
  926.                dwStyle,
  927.                x,
  928.                y,
  929.                nWidth,
  930.                nHeight,
  931.                hWndParent,
  932.                hMenu,
  933.                hInst,
  934.                this);
  935.  
  936.   return (m_hWnd);
  937. }
  938.  
  939.  
  940. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  941.   Function: DialogProc
  942.  
  943.   Summary:  The general dialog procedure callback function.  Used by all
  944.             CVirDialog class objects.  This procedure is the DialogProc
  945.             registered for all dialogs created with the CVirDialog class.
  946.             It uses the parameter passed with the WM_INITDIALOG message
  947.             to identify the dialog classes' "this" pointer which it then
  948.             stores in the window structure's GWL_USERDATA field.
  949.             All subsequent messages can then be forwarded on to the
  950.             correct dialog class's DialogProc method by using the pointer
  951.             stored in the GWL_USERDATA field.
  952.  
  953.   Args:     HWND hWndDlg,
  954.               Handle of dialog box.
  955.             UINT uMsg,
  956.               Message.
  957.             WPARAM wParam,
  958.               First message parameter (word sized).
  959.             LPARAM lParam);
  960.               Second message parameter (long sized).
  961.  
  962.   Returns:  BOOL.  Return of the CVirDialog::DialogProc method.
  963. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  964. BOOL CALLBACK DialogProc(
  965.                 HWND hWndDlg,
  966.                 UINT uMsg,
  967.                 WPARAM wParam,
  968.                 LPARAM lParam)
  969. {
  970.   // Get a pointer to the window class object.
  971.   CVirDialog* pdlg = (CVirDialog*) GetWindowLong(hWndDlg, GWL_USERDATA);
  972.  
  973.   switch (uMsg)
  974.   {
  975.     case WM_INITDIALOG:
  976.       // Get a pointer to the window class object.
  977.       pdlg = (CVirDialog*) lParam;
  978.  
  979.       // Assign the m_hWnd member variable.
  980.       pdlg->m_hWnd = hWndDlg;
  981.  
  982.       // Set the USERDATA word to point to the class object.
  983.       SetWindowLong(hWndDlg, GWL_USERDATA, (long) pdlg);
  984.       break;
  985.  
  986.     default:
  987.       break;
  988.   }
  989.  
  990.   // Call its message proc method.
  991.   if (pdlg != (CVirDialog *) 0)
  992.     return (pdlg->DialogProc(hWndDlg, uMsg, wParam, lParam));
  993.   else
  994.     return (FALSE);
  995. }
  996.  
  997.  
  998. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  999.   Method:   CVirDialog::ShowDialog
  1000.  
  1001.   Summary:  Creates the dialog so that it's DialogProc member function can
  1002.             be invoked.  The dialog box object exists until deleted by the
  1003.             caller.  It can be shown any number of times.  This function is
  1004.             analgous to Windows' DialogBox function.  The main difference
  1005.             being that you don't specify a DialogProc; you override the
  1006.             pure virtal function CVirDialog::DialogProc.
  1007.  
  1008.   Args:     HINSTANCE hInst,
  1009.               Handle of the module instance.  Needed to specify the
  1010.               module instance for fetching the dialog template resource
  1011.               (ie, from either a host EXE or DLL).
  1012.             LPTSTR lpszTemplate,
  1013.               Identifies the dialog box template.
  1014.             HWND hwndOwner)
  1015.               Handle of the owner window.
  1016.  
  1017.   Modifies: m_hInst.
  1018.  
  1019.   Returns:  Return value from the DialogBoxParam Windows API function.
  1020. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1021. int CVirDialog::ShowDialog(
  1022.       HINSTANCE hInst,
  1023.       LPTSTR lpszTemplate,
  1024.       HWND hWndOwner)
  1025. {
  1026.   int iResult;
  1027.  
  1028.   // Assign the module instance handle in the Dialog object.
  1029.   m_hInst = hInst;
  1030.  
  1031.   // Create and show the dialog on screen.  Load the dialog resource
  1032.   // from the specified module instance (could be a module other than
  1033.   // that of the EXE that is running--the resources could be in a DLL
  1034.   // that is calling this ShowDialog).  Pass the 'this' pointer to the
  1035.   // dialog object so that it can be assigned inside the dialog object
  1036.   // during WM_INITDIALOG and later available to the dailog procedure
  1037.   // via the GWL_USERDATA associated with the dialog window.
  1038.   iResult = ::DialogBoxParam(
  1039.                 hInst,
  1040.                 lpszTemplate,
  1041.                 hWndOwner,
  1042.                 (DLGPROC)::DialogProc,
  1043.                 (long)this);
  1044.  
  1045.   return (iResult);
  1046. }
  1047.  
  1048.  
  1049. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1050.   Method:   CAboutBox::DialogProc
  1051.  
  1052.   Summary:  Dialog proc for the About dialog box.  This DialogProc
  1053.             method definition overrides the same-named pure virtual
  1054.             function in abstract base class CVirDialog thus giving
  1055.             AboutBox-unique message dispatching behavior to this
  1056.             derivation of CVirDialog.  The remaining behavior of
  1057.             CAboutBox is inherited from CVirDialog and is common to
  1058.             all CVirDialogs.
  1059.  
  1060.   Args:     HWND hWndDlg,
  1061.               Handle to the dialog.
  1062.             UINT uMsg,
  1063.               Windows message to dialog.
  1064.             WPARAM wParam,
  1065.               First message parameter (word sized).
  1066.             LPARAM lParam)
  1067.               Second message parameter (long sized).
  1068.  
  1069.   Modifies: .
  1070.  
  1071.   Returns:  BOOL.  TRUE if message was handled; FALSE otherwise.
  1072. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1073. BOOL CAboutBox::DialogProc(
  1074.        HWND hWndDlg,
  1075.        UINT uMsg,
  1076.        WPARAM wParam,
  1077.        LPARAM lParam)
  1078. {
  1079.   BOOL bResult = TRUE;
  1080.  
  1081.   switch (uMsg)
  1082.   {
  1083.     case WM_INITDIALOG:
  1084.       SetFocus(GetDlgItem(hWndDlg,IDOK));
  1085.       break;
  1086.  
  1087.     case WM_COMMAND:
  1088.       if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
  1089.         ::EndDialog(hWndDlg, TRUE);
  1090.       break;
  1091.  
  1092.     case WM_PAINT:
  1093.       // Wash the background of the aboutbox to give it a nice
  1094.       // blue-scaling effect.  Invalidate the OK button to force it to the
  1095.       // top.  This seems to be necessary since the OK button gets
  1096.       // overwritten during the washing.
  1097.       PaintWindow(hWndDlg,COLOR_SCALE_BLUE);
  1098.       InvalidateRect(GetDlgItem(hWndDlg,IDOK),NULL,TRUE);
  1099.       break;
  1100.  
  1101.     default:
  1102.       bResult = FALSE;
  1103.       break;
  1104.   }
  1105.  
  1106.   return(bResult);
  1107. }
  1108.  
  1109.  
  1110. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1111.   Method:   CMsgBox::Init
  1112.  
  1113.   Summary:  CMsgBox constructor.  Initializes private member data handles
  1114.             for both the eventual Parent window of any MsgBox and the
  1115.             application instance.
  1116.  
  1117.   Args:     HINSTANCE hInst,
  1118.               Handle of app instance.
  1119.             HWND hWndParent)
  1120.               Handle of parent window.
  1121.  
  1122.   Returns:  BOOL
  1123.               TRUE.
  1124. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1125. BOOL CMsgBox::Init(
  1126.       HINSTANCE hInst,
  1127.       HWND hWndOwner)
  1128. {
  1129.   m_hInst = hInst;
  1130.   m_hWndOwner = hWndOwner;
  1131.  
  1132.   return (TRUE);
  1133. }
  1134.  
  1135.  
  1136. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1137.   Method:   CMsgBox::Error
  1138.  
  1139.   Summary:  Shows a specified message string in an Error MessageBox Dialog.
  1140.  
  1141.   Args:     LPTSTR szMsg
  1142.               The message string to display.
  1143.  
  1144.   Returns:  int
  1145.               Result of the MessageBox call.
  1146. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1147. int CMsgBox::Error(
  1148.       LPTSTR szMsg)
  1149. {
  1150.   int iResult;
  1151.  
  1152.   iResult = MessageBox(
  1153.               m_hWndOwner,
  1154.               szMsg,
  1155.               TEXT(ERROR_TITLE_STR),
  1156.               MB_OK | MB_ICONEXCLAMATION);
  1157.  
  1158.   return (iResult);
  1159. }
  1160.  
  1161.  
  1162. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1163.   Method:   CMsgBox::ErrorID
  1164.  
  1165.   Summary:  Shows a resource ID specified message string in an Error
  1166.             MessageBox Dialog.
  1167.  
  1168.   Args:     UINT uMsgID
  1169.               The resource ID of the message string to display.
  1170.  
  1171.   Returns:  int
  1172.               Result of the MessageBox call.
  1173. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1174. int CMsgBox::ErrorID(
  1175.       UINT uMsgID)
  1176. {
  1177.   int iResult = FALSE;
  1178.   TCHAR szMsg[MAX_STRING_LENGTH];
  1179.  
  1180.   if (LoadString(m_hInst, uMsgID, szMsg, MAX_STRING_LENGTH))
  1181.   {
  1182.     iResult = MessageBox(
  1183.                 m_hWndOwner,
  1184.                 szMsg,
  1185.                 TEXT(ERROR_TITLE_STR),
  1186.                 MB_OK | MB_ICONEXCLAMATION);
  1187.   }
  1188.  
  1189.   return (iResult);
  1190. }
  1191.  
  1192.  
  1193. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1194.   Method:   CMsgBox::Note
  1195.  
  1196.   Summary:  Shows a specified message string in a Notice MessageBox Dialog.
  1197.  
  1198.   Args:     LPTSTR szMsg
  1199.               The message string to display.
  1200.  
  1201.   Returns:  int
  1202.               Result of the MessageBox call.
  1203. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1204. int CMsgBox::Note(
  1205.       LPTSTR szMsg)
  1206. {
  1207.   int iResult;
  1208.  
  1209.   iResult = MessageBox(
  1210.               m_hWndOwner,
  1211.               szMsg,
  1212.               TEXT(NOTICE_TITLE_STR),
  1213.               MB_OK | MB_ICONINFORMATION);
  1214.  
  1215.   return (iResult);
  1216. }
  1217.  
  1218.  
  1219. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1220.   Method:   CMsgBox::NoteID
  1221.  
  1222.   Summary:  Shows a resource ID specified message string in a Notice
  1223.             MessageBox Dialog.
  1224.  
  1225.   Args:     UINT uMsgID
  1226.               The resource ID of the message string to display.
  1227.  
  1228.   Returns:  int
  1229.               Result of the MessageBox call.
  1230. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1231. int CMsgBox::NoteID(
  1232.       UINT uMsgID)
  1233. {
  1234.   int iResult = FALSE;
  1235.   TCHAR szMsg[MAX_STRING_LENGTH];
  1236.  
  1237.   if (LoadString(m_hInst, uMsgID, szMsg, MAX_STRING_LENGTH))
  1238.   {
  1239.     iResult = MessageBox(
  1240.                 m_hWndOwner,
  1241.                 szMsg,
  1242.                 TEXT(NOTICE_TITLE_STR),
  1243.                 MB_OK | MB_ICONINFORMATION);
  1244.   }
  1245.  
  1246.   return (iResult);
  1247. }
  1248.  
  1249.  
  1250. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1251.   Method:   CMsgBox::NoteFmt
  1252.  
  1253.   Summary:  Shows a printf-style formatted message string in a Notice
  1254.             MessageBox Dialog.
  1255.  
  1256.   Args:     LPTSTR szFmtMsg
  1257.               The format/message string to display.
  1258.             [...]
  1259.               Arguments to match those specified in the format string.
  1260.  
  1261.   Returns:  int
  1262.               Result of the MessageBox call.
  1263. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1264. int CMsgBox::NoteFmt(
  1265.       LPTSTR szFmtMsg
  1266.            ...)
  1267. {
  1268.   int iResult = 0;
  1269.   va_list arglist;
  1270.   va_start(arglist, szFmtMsg);
  1271.   TCHAR szMsg[MAX_STRING_LENGTH];
  1272.  
  1273.   // Use the format string to format the messagebox's content text.
  1274.   wvsprintf(szMsg, szFmtMsg, arglist);
  1275.   iResult = MessageBox(
  1276.               m_hWndOwner,
  1277.               szMsg,
  1278.               TEXT(NOTICE_TITLE_STR),
  1279.               MB_OK | MB_ICONINFORMATION);
  1280.  
  1281.   return (iResult);
  1282. }
  1283.  
  1284.  
  1285. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1286.   Method:   CMsgBox::NoteFmtID
  1287.  
  1288.   Summary:  Shows a resource ID specified printf-style formatted message
  1289.             string in a Notice MessageBox Dialog.
  1290.  
  1291.   Args:     UINT uFmtMsgID
  1292.               The resource ID of the format message string to display.
  1293.             [...]
  1294.               Arguments to match those specified in the format string.
  1295.  
  1296.   Returns:  int
  1297.               Result of the MessageBox call.
  1298. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1299. int CMsgBox::NoteFmtID(
  1300.       UINT uFmtMsgID,
  1301.       ...)
  1302. {
  1303.   int iResult = 0;
  1304.   va_list arglist;
  1305.   va_start(arglist, uFmtMsgID);
  1306.   TCHAR szFmtMsg[MAX_STRING_LENGTH];
  1307.   TCHAR szMsg[MAX_STRING_LENGTH];
  1308.  
  1309.   if (LoadString(m_hInst, uFmtMsgID, szFmtMsg, MAX_STRING_LENGTH))
  1310.   {
  1311.     // Use the format string to format the messagebox's content text.
  1312.     wvsprintf(szMsg, szFmtMsg, arglist);
  1313.     iResult = MessageBox(
  1314.                 m_hWndOwner,
  1315.                 szMsg,
  1316.                 TEXT(NOTICE_TITLE_STR),
  1317.                 MB_OK | MB_ICONINFORMATION);
  1318.   }
  1319.  
  1320.   return (iResult);
  1321. }
  1322.  
  1323.  
  1324. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1325.   Method:   CMsgLog::Create
  1326.  
  1327.   Summary:  Creates the ListBox as a child window to fill the client area
  1328.             of the specified parent window or to exist as a separate
  1329.             window owned by the parent window.
  1330.  
  1331.   Args:     HINSTANCE hInst,
  1332.               Instance handle of the application.
  1333.             HWND hWndparent,
  1334.               Window handle for the parent window of the listbox.
  1335.             BOOL bChild)
  1336.               Flag to create the listbox as a child window.  TRUE means fit
  1337.               the child window to fill the client area of the parent window.
  1338.               FALSE means the window is a separate (but owned) window.
  1339.  
  1340.   Returns:  BOOL
  1341.               TRUE if successful; FALSE if not.
  1342. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1343. BOOL CMsgLog::Create(
  1344.        HINSTANCE hInst,
  1345.        HWND hWndParent,
  1346.        BOOL bChild)
  1347. {
  1348.   BOOL bResult = FALSE;
  1349.   HWND hWnd;
  1350.   RECT rect;
  1351.   DWORD dwStyle = WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | LBS_NOSEL |
  1352.                     LBS_NOINTEGRALHEIGHT;
  1353.   TCHAR* pszTitle = bChild ? NULL : TEXT("Trace Log");
  1354.  
  1355.   dwStyle |= bChild ? WS_CHILD : WS_OVERLAPPEDWINDOW;
  1356.  
  1357.   // Logging will be flagged as on when creation is successful.
  1358.   m_bLogging = FALSE;
  1359.  
  1360.   if (IsWindow(hWndParent))
  1361.   {
  1362.     GetClientRect(hWndParent, &rect);
  1363.  
  1364.     // Create the child ListBox window and fill the parent window with it.
  1365.     hWnd = ::CreateWindowEx(
  1366.                0,                // Extended Window Style
  1367.                TEXT("LISTBOX"),  // Class Name
  1368.                pszTitle,         // Window Title
  1369.                dwStyle,          // The window style
  1370.                0,                // (x,y)=Upper left of Parent window
  1371.                0,
  1372.                rect.right,       // Width; Fill Client Window
  1373.                rect.bottom,      // Height
  1374.                hWndParent,       // Parent Window Handle
  1375.                0,                // No menu
  1376.                hInst,            // App Instance Handle
  1377.                NULL);            // Window Creation Data
  1378.  
  1379.     if (NULL != hWnd)
  1380.     {
  1381.       // Remember the window handle of this listbox window.
  1382.       m_hWndLog = hWnd;
  1383.       // Remember the instance of this application.
  1384.       m_hInstLog = hInst;
  1385.       // Remember if this is a child window (bChild==TRUE).
  1386.       m_bChild = bChild;
  1387.       // Turn on message logging by default after create.
  1388.       m_bLogging = TRUE;
  1389.       // Return success.
  1390.       bResult = TRUE;
  1391.     }
  1392.   }
  1393.  
  1394.   return (bResult);
  1395. }
  1396.  
  1397.  
  1398. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1399.   Method:   CMsgLog::Logging
  1400.  
  1401.   Summary:  Turns logging of or off.
  1402.  
  1403.   Args:     BOOL bLogging
  1404.               TRUE to turn on; FALSE to turn off.
  1405.  
  1406.   Returns:  BOOL
  1407.               New logging status.
  1408. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1409. BOOL CMsgLog::Logging(
  1410.        BOOL bLogging)
  1411. {
  1412.   BOOL bResult = bLogging;
  1413.  
  1414.   m_bLogging = bLogging;
  1415.  
  1416.   return (bResult);
  1417. }
  1418.  
  1419.  
  1420. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1421.   Method:   CMsgLog::Msg
  1422.  
  1423.   Summary:  Logs a message string as a separate line in the listbox.
  1424.  
  1425.   Args:     LPTSTR szMsg
  1426.               Pointer to String of the message to display/log.
  1427.  
  1428.   Returns:  BOOL
  1429.               TRUE if successful; FALSE if not.
  1430. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1431. BOOL CMsgLog::Msg(
  1432.        LPTSTR szMsg)
  1433. {
  1434.   BOOL bResult = FALSE;
  1435.   int iIndex;
  1436.  
  1437.   if (m_bLogging)
  1438.   {
  1439.     ::SendMessage(
  1440.         m_hWndLog,
  1441.         LB_ADDSTRING,
  1442.         0,
  1443.         (LPARAM)szMsg);
  1444.     iIndex = ::SendMessage(
  1445.                  m_hWndLog,
  1446.                  LB_GETCOUNT,
  1447.                  0,
  1448.                  0);
  1449.     if (LB_ERR != iIndex && iIndex > 0)
  1450.     {
  1451.       --iIndex;
  1452.       ::SendMessage(
  1453.           m_hWndLog,
  1454.           LB_SETCURSEL,
  1455.           (WPARAM)iIndex,
  1456.           0);
  1457.     }
  1458.     bResult = TRUE;
  1459.   }
  1460.  
  1461. #if defined(_DEBUG)
  1462.   ::OutputDebugString(szMsg);
  1463. #endif
  1464.  
  1465.   return (bResult);
  1466. }
  1467.  
  1468.  
  1469. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1470.   Method:   CMsgLog::MsgFmt
  1471.  
  1472.   Summary:  Logs a printf-style formated message as a separate line in the
  1473.             Message log listbox.
  1474.  
  1475.   Args:     LPTSTR szFmtMsg
  1476.               The format/message string to display/log.
  1477.             [...]
  1478.               Arguments to match those specified in the format string.
  1479.  
  1480.   Returns:  BOOL
  1481.               TRUE if successful; FALSE if not.
  1482. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1483. BOOL CMsgLog::MsgFmt(
  1484.        LPTSTR szFmtMsg,
  1485.        ...)
  1486. {
  1487.   BOOL bResult = FALSE;
  1488.   va_list arglist;
  1489.   va_start(arglist, szFmtMsg);
  1490.   TCHAR szMsg[MAX_STRING_LENGTH];
  1491.   int iIndex;
  1492.  
  1493.   // Use the format string and arguments to format the content text.
  1494.   wvsprintf(szMsg, szFmtMsg, arglist);
  1495.  
  1496.   // Send the newly formated message string to the Log Listbox.
  1497.   if (m_bLogging)
  1498.   {
  1499.     ::SendMessage(
  1500.         m_hWndLog,
  1501.         LB_ADDSTRING,
  1502.         0,
  1503.         (LPARAM)szMsg);
  1504.     iIndex = ::SendMessage(
  1505.                  m_hWndLog,
  1506.                  LB_GETCOUNT,
  1507.                  0,
  1508.                  0);
  1509.     if (LB_ERR != iIndex && iIndex > 0)
  1510.     {
  1511.       --iIndex;
  1512.       ::SendMessage(
  1513.           m_hWndLog,
  1514.           LB_SETCURSEL,
  1515.           (WPARAM)iIndex,
  1516.           0);
  1517.     }
  1518.     bResult = TRUE;
  1519.   }
  1520.  
  1521. #if defined(_DEBUG)
  1522.   ::OutputDebugString(szMsg);
  1523. #endif
  1524.  
  1525.   return (bResult);
  1526. }
  1527.  
  1528.  
  1529. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1530.   Method:   CMsgLog::MsgID
  1531.  
  1532.   Summary:  Logs a message string as a separate line in the listbox.
  1533.  
  1534.   Args:     int iMsgID
  1535.               String Resource ID for the message to display/log.
  1536.  
  1537.   Returns:  BOOL
  1538.               TRUE if successful; FALSE if not.
  1539. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1540. BOOL CMsgLog::MsgID(
  1541.        int iMsgID)
  1542. {
  1543.   BOOL bResult = FALSE;
  1544.   TCHAR szMsg[MAX_STRING_LENGTH];
  1545.  
  1546.   if (LoadString(m_hInstLog, iMsgID, szMsg, MAX_STRING_LENGTH))
  1547.     bResult = Msg(szMsg);
  1548.  
  1549.   return (bResult);
  1550. }
  1551.  
  1552.  
  1553. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1554.   Method:   CMsgLog::MsgFmtID
  1555.  
  1556.   Summary:  Logs a printf-style formated message as a separate line in the
  1557.             Message log listbox.
  1558.  
  1559.   Args:     int iFmtID
  1560.               The resource ID for the format/message string to display/log.
  1561.             [...]
  1562.               Arguments to match those specified in the format string.
  1563.  
  1564.   Returns:  BOOL
  1565.               TRUE if successful; FALSE if not.
  1566. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1567. BOOL CMsgLog::MsgFmtID(
  1568.        int iFmtID,
  1569.        ...)
  1570. {
  1571.   BOOL bResult = FALSE;
  1572.   va_list arglist;
  1573.   va_start(arglist, iFmtID);
  1574.   TCHAR szFormat[MAX_STRING_LENGTH];
  1575.   TCHAR szMsg[MAX_STRING_LENGTH];
  1576.  
  1577.   // Load the format string from the app's string resources.
  1578.   if (LoadString(m_hInstLog, iFmtID, szFormat, MAX_STRING_LENGTH))
  1579.   {
  1580.     // Use the format string and arguments to format the content text.
  1581.     wvsprintf(szMsg, szFormat, arglist);
  1582.  
  1583.     // Send the newly formated message string to the Log Listbox.
  1584.     bResult = Msg(szMsg);
  1585.   }
  1586.  
  1587.   return (bResult);
  1588. }
  1589.  
  1590.  
  1591. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1592.   Method:   CMsgLog::Resize
  1593.  
  1594.   Summary:  Resizes the listbox to a new width and height.  Called during
  1595.             the parent window's WM_SIZE to fit the listbox to the client
  1596.             area of the parent window.  It only honors this request if it
  1597.             is an integral child window.
  1598.  
  1599.   Args:     int nWidth
  1600.               New width in pixels of the listbox.
  1601.             int nHeight
  1602.               New height in pixels of the listbox.
  1603.  
  1604.   Returns:  BOOL
  1605.               TRUE if successful; FALSE if not.
  1606. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1607. BOOL CMsgLog::Resize(
  1608.        int nWidth,
  1609.        int nHeight)
  1610. {
  1611.   BOOL bResult = FALSE;
  1612.  
  1613.   if (m_bChild)
  1614.     bResult = ::MoveWindow(m_hWndLog, 0, 0, nWidth, nHeight, TRUE);
  1615.  
  1616.   return (bResult);
  1617. }
  1618.  
  1619.  
  1620. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1621.   Method:   CMsgLog::Clear
  1622.  
  1623.   Summary:  Clears all logged messages from the message log listbox.
  1624.  
  1625.   Args:     void
  1626.  
  1627.   Returns:  BOOL
  1628.               TRUE.
  1629. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1630. BOOL CMsgLog::Clear(
  1631.        void)
  1632. {
  1633.   ::SendMessage(
  1634.       m_hWndLog,
  1635.       LB_RESETCONTENT,
  1636.       0,
  1637.       0);
  1638.  
  1639.   return (TRUE);
  1640. }
  1641.  
  1642.  
  1643. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1644.   Method:   CMsgLog::Copy
  1645.  
  1646.   Summary:  Copies the current content of the trace message log to the
  1647.             Windows clipboard.
  1648.  
  1649.   Args:     void
  1650.  
  1651.   Returns:  BOOL
  1652.               TRUE if success; FALSE if failure.
  1653. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1654. BOOL CMsgLog::Copy(void)
  1655. {
  1656.   BOOL bResult = FALSE;
  1657.   DWORD iIndex;
  1658.   DWORD cbLen;
  1659.   HANDLE hClip;
  1660.   LPTSTR pLogData;
  1661.   TCHAR szLine[MAX_STRING_LENGTH];
  1662.   DWORD cItems = ::SendMessage(m_hWndLog,LB_GETCOUNT,0,0);
  1663.  
  1664.   if (LB_ERR != cItems
  1665.       && 0 < cItems
  1666.       && MAX_LOG_LINES > cItems
  1667.       && OpenClipboard(m_hWndLog))
  1668.   {
  1669.     if (EmptyClipboard())
  1670.     {
  1671.       m_hLogData = GlobalAlloc(GHND, cItems * MAX_STRING_LENGTH);
  1672.       if (m_hLogData)
  1673.       {
  1674.         // Lock the global memory while we write to it.
  1675.         pLogData = (LPTSTR) GlobalLock(m_hLogData);
  1676.         // Loop thru the log text lines and concat them to one big string.
  1677.         for (iIndex = 0; iIndex < cItems; iIndex++)
  1678.         {
  1679.           // Get each log text line.
  1680.           cbLen = ::SendMessage(
  1681.                       m_hWndLog,
  1682.                       LB_GETTEXT,
  1683.                       (WPARAM)iIndex,
  1684.                       (LPARAM) (LPSTR)szLine);
  1685.           if (LB_ERR != cbLen && (MAX_STRING_LENGTH-3) > cbLen)
  1686.           {
  1687.             // Put CRLF at end.  Fix this for Unicode!
  1688.             szLine[cbLen]   = '\r';
  1689.             szLine[cbLen+1] = '\n';
  1690.             szLine[cbLen+2] = '\0';
  1691.             if (0 == iIndex)
  1692.               lstrcpy((LPTSTR)pLogData, szLine);
  1693.             else
  1694.               lstrcat((LPTSTR)pLogData, szLine);
  1695.           }
  1696.         }
  1697.         // We're done with writing so unlock the memory block.
  1698.         GlobalUnlock(m_hLogData);
  1699.         // If there were any lines at all then copy them to clipboard.
  1700.         if (0 < iIndex)
  1701.           hClip = SetClipboardData(CF_TEXT, m_hLogData);
  1702.         if (!hClip)
  1703.         {
  1704.           // If we couldn't clip the data then free the global handle.
  1705.           GlobalFree(m_hLogData);
  1706.           m_hLogData = 0;
  1707.         }
  1708.         // We're done with the clipboard so close it.
  1709.         bResult = CloseClipboard();
  1710.       }
  1711.     }
  1712.   }
  1713.  
  1714.   return (bResult);
  1715. }
  1716.  
  1717.  
  1718. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1719.   Method:   CSendLog::CreateServerLog
  1720.  
  1721.   Summary:  Creates the ListBox as a child window to fill the client area
  1722.             of the specified local server's parent window.
  1723.  
  1724.   Args:     HINSTANCE hInst,
  1725.               Instance handle of the application.
  1726.             HWND hWndparent,
  1727.               Window handle for the parent window of the listbox.
  1728.             BOOL bChild)
  1729.               Flag to create the listbox as a child window.  TRUE means fit
  1730.               the child window to fill the client area of the parent window.
  1731.               FALSE means the window is a separate (but owned) window.
  1732.  
  1733.   Returns:  BOOL
  1734.               TRUE if successful; FALSE if not.
  1735. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1736. BOOL CSendLog::CreateServerLog(
  1737.        HINSTANCE hInst,
  1738.        HWND hWndParent,
  1739.        BOOL bChild)
  1740. {
  1741.   BOOL bResult = FALSE;
  1742.   HWND hWnd;
  1743.   RECT rect;
  1744.   DWORD dwStyle = WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | LBS_NOSEL |
  1745.                     LBS_NOINTEGRALHEIGHT;
  1746.  
  1747.   if (bChild)
  1748.     dwStyle |= WS_CHILD;
  1749.   else
  1750.     dwStyle |= WS_OVERLAPPEDWINDOW;
  1751.  
  1752.   if (IsWindow(hWndParent))
  1753.   {
  1754.     GetClientRect(hWndParent, &rect);
  1755.  
  1756.     // Create the child ListBox window and fill the parent window with it.
  1757.     hWnd = ::CreateWindowEx(
  1758.                0,                // Extended Window Style
  1759.                TEXT("LISTBOX"),  // Class Name
  1760.                NULL,             // No Window Title
  1761.                dwStyle,          // The window style
  1762.                0,                // (x,y)=Upper left of Parent window
  1763.                0,
  1764.                rect.right,       // Width; Fill Client Window
  1765.                rect.bottom,      // Hight
  1766.                hWndParent,       // Parent Window Handle
  1767.                0,                // No menu
  1768.                hInst,            // App Instance Handle
  1769.                NULL);            // Window Creation Data
  1770.  
  1771.     if (NULL != hWnd)
  1772.     {
  1773.       // Remember the instance of this application.
  1774.       m_hInstSender = hInst;
  1775.       // Remember the window handle of this Sending application.
  1776.       m_hWndSender = hWndParent;
  1777.       // Remember the window handle of the new listbox window.
  1778.       m_hWndListBox = hWnd;
  1779.       // Remember if this is a child window (bChild==TRUE).
  1780.       m_bChild = bChild;
  1781.       // Return success.
  1782.       bResult = TRUE;
  1783.     }
  1784.   }
  1785.  
  1786.   return (bResult);
  1787. }
  1788.  
  1789.  
  1790. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1791.   Method:   CSendLog::SetClient
  1792.  
  1793.   Summary:  Initialize the SendLog facility for logging to the client.
  1794.  
  1795.   Args:     HINSTANCE hInstSender,
  1796.               Instance handle of the sending server application.
  1797.             HWND hWndSender,
  1798.               Window handle for the sending server's main window.
  1799.             HWND hWndReceiver,
  1800.               Window handle for the destination receiving client window.
  1801.  
  1802.   Returns:  BOOL
  1803.               Returns TRUE.
  1804. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1805. BOOL CSendLog::SetClient(
  1806.        HINSTANCE hInstSender,
  1807.        HWND hWndSender,
  1808.        HWND hWndReceiver)
  1809. {
  1810.   BOOL bOk;
  1811.  
  1812.   bOk = (NULL != hWndReceiver);
  1813.  
  1814.   if (bOk)
  1815.   {
  1816.     // Remember the instance of this sending application.
  1817.     m_hInstSender = hInstSender;
  1818.     // Remember the main window of this sending application.
  1819.     m_hWndSender = hWndSender;
  1820.     // Remember the window handle of the receiving window.
  1821.     m_hWndReceiver = hWndReceiver;
  1822.   }
  1823.  
  1824.   return bOk;
  1825. }
  1826.  
  1827.  
  1828. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1829.   Method:   CSendLog::LogToServer
  1830.  
  1831.   Summary:  Switches logging to either server or client display.
  1832.  
  1833.   Args:     BOOL bLogToServer
  1834.               TRUE for logging to server; FALSE for logging to client.
  1835.  
  1836.   Returns:  BOOL
  1837.               New logging status.
  1838. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1839. BOOL CSendLog::LogToServer(
  1840.        BOOL bLogToServer)
  1841. {
  1842.   BOOL bResult = bLogToServer;
  1843.  
  1844.   m_bLogToServer = bLogToServer;
  1845.  
  1846.   return (bResult);
  1847. }
  1848.  
  1849.  
  1850. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1851.   Method:   CSendLog::Msg
  1852.  
  1853.   Summary:  Logs a message string as a separate line in the receiving
  1854.             CMsgLog facility.
  1855.  
  1856.   Args:     LPTSTR szMsg
  1857.               Pointer to String of the message to display/log.
  1858.  
  1859.   Returns:  BOOL bResult
  1860.               TRUE if successful; FALSE if not.
  1861. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1862. BOOL CSendLog::Msg(
  1863.        LPTSTR szMsg)
  1864. {
  1865.   BOOL bResult = FALSE;
  1866.   COPYDATASTRUCT cds;
  1867.  
  1868.   if (NULL != szMsg)
  1869.   {
  1870.     if (m_bLogToServer)
  1871.     {
  1872.       int iIndex;
  1873.  
  1874.       bResult = TRUE;
  1875.       ::SendMessage(
  1876.           m_hWndListBox,
  1877.           LB_ADDSTRING,
  1878.           0,
  1879.           (LPARAM)szMsg);
  1880.       iIndex = ::SendMessage(
  1881.                    m_hWndListBox,
  1882.                    LB_GETCOUNT,
  1883.                    0,
  1884.                    0);
  1885.       if (LB_ERR != iIndex && iIndex > 0)
  1886.       {
  1887.         --iIndex;
  1888.         ::SendMessage(
  1889.             m_hWndListBox,
  1890.             LB_SETCURSEL,
  1891.             (WPARAM)iIndex,
  1892.             0);
  1893.       }
  1894.     }
  1895.     else
  1896.     {
  1897.       cds.dwData = 0;
  1898.       cds.cbData = sizeof(TCHAR) * (lstrlen(szMsg)+1);
  1899.       cds.lpData = szMsg;
  1900.  
  1901.       bResult = SendMessage(
  1902.                   m_hWndReceiver,
  1903.                   WM_COPYDATA,
  1904.                   (WPARAM) m_hWndSender,
  1905.                   (LPARAM) &cds);
  1906.     }
  1907.  
  1908.     #if defined(_DEBUG)
  1909.       ::OutputDebugString(szMsg);
  1910.     #endif
  1911.   }
  1912.  
  1913.   return (bResult);
  1914. }
  1915.  
  1916.  
  1917. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1918.   Method:   CSendLog::MsgFmt
  1919.  
  1920.   Summary:  Logs a printf-style formated message as a separate line in the
  1921.             receiving CMsgLog facility.
  1922.  
  1923.   Args:     LPTSTR szFmtMsg
  1924.               The format/message string to display/log.
  1925.             [...]
  1926.               Arguments to match those specified in the format string.
  1927.  
  1928.   Returns:  BOOL
  1929.               TRUE if successful; FALSE if not.
  1930. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1931. BOOL CSendLog::MsgFmt(
  1932.        LPTSTR szFmtMsg,
  1933.        ...)
  1934. {
  1935.   BOOL bResult = FALSE;
  1936.   va_list arglist;
  1937.   va_start(arglist, szFmtMsg);
  1938.   TCHAR szMsg[MAX_STRING_LENGTH];
  1939.  
  1940.   if (NULL != szFmtMsg)
  1941.   {
  1942.     // Use the format string and arguments to format the content text.
  1943.     wvsprintf(szMsg, szFmtMsg, arglist);
  1944.     // Send the newly formated message string to the trace Log Listbox.
  1945.     bResult = Msg(szMsg);
  1946.   }
  1947.  
  1948.   return (bResult);
  1949. }
  1950.  
  1951.  
  1952. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1953.   Method:   CSendLog::MsgID
  1954.  
  1955.   Summary:  Logs a message string as a separate line in the receiving
  1956.             CMsgLog facility.
  1957.  
  1958.   Args:     int iMsgID
  1959.               String Resource ID for the message to display/log.
  1960.  
  1961.   Returns:  BOOL
  1962.               TRUE if successful; FALSE if not.
  1963. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1964. BOOL CSendLog::MsgID(
  1965.        int iMsgID)
  1966. {
  1967.   BOOL bResult = FALSE;
  1968.   TCHAR szMsg[MAX_STRING_LENGTH];
  1969.  
  1970.   // Load the message string from the sender's resources and log/send it.
  1971.   if (LoadString(m_hInstSender, iMsgID, szMsg, MAX_STRING_LENGTH))
  1972.     bResult = Msg(szMsg);
  1973.  
  1974.   return (bResult);
  1975. }
  1976.  
  1977.  
  1978. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1979.   Method:   CSendLog::MsgFmtID
  1980.  
  1981.   Summary:  Logs a printf-style formated message as a separate line in the
  1982.             receiving CMsgLog facility.
  1983.  
  1984.   Args:     int iFmtID
  1985.               The resource ID for the format/message string to display/log.
  1986.             [...]
  1987.               Arguments to match those specified in the format string.
  1988.  
  1989.   Returns:  BOOL
  1990.               TRUE if successful; FALSE if not.
  1991. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1992. BOOL CSendLog::MsgFmtID(
  1993.        int iFmtID,
  1994.        ...)
  1995. {
  1996.   BOOL bResult = FALSE;
  1997.   va_list arglist;
  1998.   va_start(arglist, iFmtID);
  1999.   TCHAR szFormat[MAX_STRING_LENGTH];
  2000.   TCHAR szMsg[MAX_STRING_LENGTH];
  2001.  
  2002.   // Load the format string from the app's string resources.
  2003.   if (LoadString(m_hInstSender, iFmtID, szFormat, MAX_STRING_LENGTH))
  2004.   {
  2005.     // Use the format string and arguments to format the content text.
  2006.     wvsprintf(szMsg, szFormat, arglist);
  2007.     // Send the newly formated message string to the trace Log Listbox.
  2008.     bResult = Msg(szMsg);
  2009.   }
  2010.  
  2011.   return (bResult);
  2012. }
  2013.  
  2014.  
  2015. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  2016.   Method:   CSendLog::Resize
  2017.  
  2018.   Summary:  Resizes the listbox to a new width and height.  Called during
  2019.             the parent window's WM_SIZE to fit the listbox to the client
  2020.             area of the parent window.  It only honors this request if it
  2021.             is an integral child window.
  2022.  
  2023.   Args:     int nWidth
  2024.               New width in pixels of the listbox.
  2025.             int nHeight
  2026.               New height in pixels of the listbox.
  2027.  
  2028.   Returns:  BOOL
  2029.               TRUE if successful; FALSE if not.
  2030. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  2031. BOOL CSendLog::Resize(
  2032.        int nWidth,
  2033.        int nHeight)
  2034. {
  2035.   BOOL bResult = FALSE;
  2036.  
  2037.   if (m_bChild)
  2038.     bResult = ::MoveWindow(m_hWndListBox, 0, 0, nWidth, nHeight, TRUE);
  2039.  
  2040.   return (bResult);
  2041. }
  2042.  
  2043.  
  2044. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  2045.   Method:   CSendLog::Clear
  2046.  
  2047.   Summary:  Clears all logged messages from the message log listbox.
  2048.  
  2049.   Args:     void
  2050.  
  2051.   Returns:  BOOL
  2052.               TRUE.
  2053. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  2054. BOOL CSendLog::Clear(
  2055.        void)
  2056. {
  2057.   ::SendMessage(
  2058.       m_hWndListBox,
  2059.       LB_RESETCONTENT,
  2060.       0,
  2061.       0);
  2062.  
  2063.   return (TRUE);
  2064. }
  2065.  
  2066.  
  2067. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  2068.   Method:   CSendLog::Copy
  2069.  
  2070.   Summary:  Copies the current content of the trace message log to the
  2071.             Windows clipboard.
  2072.  
  2073.   Args:     void
  2074.  
  2075.   Returns:  BOOL
  2076.               TRUE if success; FALSE if failure.
  2077. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  2078. BOOL CSendLog::Copy(void)
  2079. {
  2080.   BOOL bResult = FALSE;
  2081.   DWORD iIndex;
  2082.   DWORD cbLen;
  2083.   HANDLE hClip;
  2084.   LPTSTR pLogData;
  2085.   TCHAR szLine[MAX_STRING_LENGTH];
  2086.   DWORD cItems = ::SendMessage(m_hWndListBox,LB_GETCOUNT,0,0);
  2087.  
  2088.   if (LB_ERR != cItems
  2089.       && 0 < cItems
  2090.       && MAX_LOG_LINES > cItems
  2091.       && OpenClipboard(m_hWndListBox))
  2092.   {
  2093.     if (EmptyClipboard())
  2094.     {
  2095.       m_hLogData = GlobalAlloc(GHND, cItems * MAX_STRING_LENGTH);
  2096.       if (m_hLogData)
  2097.       {
  2098.         // Lock the global memory while we write to it.
  2099.         pLogData = (LPTSTR) GlobalLock(m_hLogData);
  2100.         // Loop thru the log text lines and concat them to one big string.
  2101.         for (iIndex = 0; iIndex < cItems; iIndex++)
  2102.         {
  2103.           // Get each log text line.
  2104.           cbLen = ::SendMessage(
  2105.                       m_hWndListBox,
  2106.                       LB_GETTEXT,
  2107.                       (WPARAM)iIndex,
  2108.                       (LPARAM) (LPSTR)szLine);
  2109.           if (LB_ERR != cbLen && (MAX_STRING_LENGTH-3) > cbLen)
  2110.           {
  2111.             // Put CRLF at end.  Fix this for Unicode!
  2112.             szLine[cbLen]   = '\r';
  2113.             szLine[cbLen+1] = '\n';
  2114.             szLine[cbLen+2] = '\0';
  2115.             if (0 == iIndex)
  2116.               lstrcpy((LPTSTR)pLogData, szLine);
  2117.             else
  2118.               lstrcat((LPTSTR)pLogData, szLine);
  2119.           }
  2120.         }
  2121.         // We're done with writing so unlock the memory block.
  2122.         GlobalUnlock(m_hLogData);
  2123.         // If there were any lines at all then copy them to clipboard.
  2124.         if (0 < iIndex)
  2125.           hClip = SetClipboardData(CF_TEXT, m_hLogData);
  2126.         if (!hClip)
  2127.         {
  2128.           // If we couldn't clip the data then free the global handle.
  2129.           GlobalFree(m_hLogData);
  2130.           m_hLogData = 0;
  2131.         }
  2132.         // We're done with the clipboard so close it.
  2133.         bResult = CloseClipboard();
  2134.       }
  2135.     }
  2136.   }
  2137.  
  2138.   return (bResult);
  2139. }
  2140.