CFILER.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:41k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /******************************************************************************
  2. *       This is a part of the Microsoft Source Code Samples. 
  3. *       Copyright 1996-1997 Microsoft Corporation.
  4. *       All rights reserved. 
  5. *       This source code is only intended as a supplement to 
  6. *       Microsoft Development Tools and/or WinHelp documentation.
  7. *       See these sources for detailed information regarding the 
  8. *       Microsoft samples programs.
  9. ******************************************************************************/
  10. // CFILER.C
  11. #include "cfiler.h"
  12. #include "time.h"
  13. HANDLE    ghModule;                                    
  14. HANDLE   ghDrvThread = NULL;
  15. HWND     ghwndMain = NULL;                      
  16. HWND     ghwndDrives;              
  17. HWND     ghwndDrv;
  18. HWND     ghFocusWnd;                   
  19. HFONT    ghFont;
  20. HMENU ghMenu;                        
  21. BOOL                gfDrvWndOrient = SIDE_BY_SIDE,
  22.                     gfKeepCommandWin = FALSE;
  23. DRVCHILDINFO        gDrvChildInfo;
  24. LPDINFO             glpDrives = (LPDINFO)0;    
  25. CRITICAL_SECTION    gDrvCS;                    
  26.                                              
  27. extern LPTSTR  lpDriveStrings;
  28. extern ALG_ID AlgidEncrypt;
  29. extern ALG_ID AlgidSign;
  30. extern CHAR sPass[BUF_SIZE];
  31. extern TCHAR szPassName[BUF_SIZE];
  32. int WINAPI WinMain(HINSTANCE hInstance, 
  33.    HINSTANCE hPrevInstance, 
  34.    LPSTR lpCmdLine, 
  35.    INT nCmdShow) {
  36.     MSG    msg;
  37.     HANDLE hAccel;
  38.     ghModule = hInstance;
  39.     if (!InitializeApp()) {
  40.         ErrorMsg(TEXT("WinMain: InitializeApp failed."));
  41.         return 0;
  42.     }
  43.     ShowWindow(ghwndMain, nCmdShow);
  44.     if (!(hAccel = LoadAccelerators (ghModule, MAKEINTRESOURCE(ACCEL_ID))))
  45.         ErrorMsg(TEXT("WinMain: LoadAccelerators failed."));
  46.     while (GetMessage(&msg, NULL, 0, 0)) {
  47.         if( !TranslateAccelerator(ghwndMain, hAccel, &msg) ) {
  48.             TranslateMessage(&msg);
  49.             DispatchMessage(&msg);
  50.         }
  51.     }
  52.     return 1;
  53.     UNREFERENCED_PARAMETER(lpCmdLine);
  54.     UNREFERENCED_PARAMETER(hPrevInstance);
  55. }
  56. BOOL InitializeApp(void)
  57. {
  58.     WNDCLASS wc;
  59. HWND FirsthWnd, FirstChildhWnd;
  60. if (FirsthWnd = FindWindow("CRYPTFILERClass", NULL))
  61. {
  62.    // Found another running application with the same class name.
  63.    // Therefore, one instance is already running.
  64.    FirstChildhWnd = GetLastActivePopup(FirsthWnd);
  65.    BringWindowToTop(FirsthWnd);         // bring main window to top
  66.    if (FirsthWnd != FirstChildhWnd)
  67.       BringWindowToTop(FirstChildhWnd); // a pop-up window is active
  68.                                         // bring it to the top too
  69.    return FALSE;                        // do not run second instance
  70. }
  71.     srand(time(0));
  72.        
  73.     lstrcpy(szPassName, TEXT(""));
  74.     
  75.     wc.style            = 0;
  76.     wc.lpfnWndProc      = (WNDPROC)MainWndProc;
  77.     wc.cbClsExtra       = 0;
  78.     wc.cbWndExtra    = 0;
  79.     wc.hInstance        = ghModule;
  80.     wc.hIcon            = LoadIcon(ghModule, MAKEINTRESOURCE(UI_CRYPTFILERICON));
  81.     wc.hCursor          = 0;
  82.     wc.hbrBackground    = (HBRUSH)(COLOR_APPWORKSPACE);
  83.     wc.lpszMenuName     = TEXT("CRYPTFILERMenu");
  84.     wc.lpszClassName    = TEXT("CRYPTFILERClass");
  85.     if (!RegisterClass(&wc)) {
  86. ErrorMsg(TEXT("InitializeApp: RegisterClass failed."));
  87.      return FALSE;
  88. }
  89.     wc.lpfnWndProc  = DrvWndProc;
  90.     wc.hIcon        = NULL;
  91.     wc.lpszMenuName = NULL;
  92.     wc.lpszClassName    = TEXT("DrvClass");
  93.     if (!RegisterClass(&wc)) {
  94.         ErrorMsg(TEXT("InitializeApp: RegisterClass failed."));
  95.         return FALSE;
  96.     }
  97.     
  98.     wc.style        = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
  99.     wc.lpfnWndProc  = DriveBarProc;
  100.     wc.hbrBackground    = (HBRUSH)(COLOR_BTNSHADOW);
  101.     wc.lpszClassName    = TEXT("DriveBarClass");
  102.     if (!RegisterClass(&wc)) {
  103.         ErrorMsg(TEXT("InitializeApp: RegisterClass failed."));
  104.         return FALSE;
  105. }
  106.     wc.style        = CS_HREDRAW | CS_VREDRAW;
  107.     wc.lpfnWndProc  = TextWndProc;
  108.     wc.hbrBackground    = (HBRUSH)(COLOR_INACTIVECAPTION);
  109.     wc.lpszClassName    = TEXT("TextClass");
  110.     if (!RegisterClass(&wc)) {
  111.         ErrorMsg(TEXT("InitializeApp: RegisterClass failed."));
  112.         return FALSE;
  113. }
  114.     ghMenu = LoadMenu(ghModule, TEXT("CRYPTFILERMenu"));
  115.     if (!ghMenu)
  116. return FALSE;    
  117.     
  118.     AlgidEncrypt = CALG_RC2;
  119. AlgidSign = CALG_MD4;
  120. ghwndMain = CreateWindow(TEXT("CRYPTFILERClass"),
  121.                              TEXT("CRYPTFILER"),
  122.                              WS_OVERLAPPEDWINDOW,
  123.                              CW_USEDEFAULT,
  124.                              CW_USEDEFAULT,
  125.                              MAIN_WIDTH,
  126.                              MAIN_HEIGHT,
  127.                              HWND_DESKTOP,
  128.                              ghMenu,
  129.                              ghModule,
  130.                              NULL);
  131.     if (!ghwndMain) {
  132. ErrorMsg(TEXT("InitializeApp: CreateWindow failed."));
  133. return FALSE;
  134. }
  135. if (!MakeHashDirectory()) {
  136. ErrorMsg(TEXT("InitializeApp: MakeHashDirectory failed."));
  137. return FALSE;
  138. }
  139. return TRUE;
  140. }
  141. LRESULT WINAPI MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  142. {
  143.     INT bRet;
  144.     
  145.     switch (message) {
  146.      case WM_CREATE: { 
  147.         LOGFONT    lf;
  148.         HDC        hDC;
  149.         HGDIOBJ    hOldFont;
  150. HGDIOBJ    hFont;
  151.         TEXTMETRIC tm;
  152.         DWORD dwThreadID;
  153. DWORD dwLastError = GetLastError();
  154.         LPCINFO lpCInfo;
  155.         
  156.         //
  157.         // Initialize drive list and Set Directory critical sections.
  158.         //
  159.         InitializeCriticalSection(&gDrvCS);
  160.        
  161.         ghDrvThread = CreateThread(NULL, 0,
  162.                                    (LPTHREAD_START_ROUTINE)EnumDrives,
  163.                                    (LPVOID)&glpDrives,
  164.                                    0, &dwThreadID);
  165. if (!ghDrvThread) {
  166. ErrorMsg(TEXT("MainWndProc: CreateThread failed."));
  167. return 0;
  168. }       
  169.         
  170.         //
  171.         // Compute default application font by creating a bold version
  172.         //   of the system default icon font.
  173.         //
  174.         if (!SystemParametersInfo(SPI_GETICONTITLELOGFONT, 
  175.            sizeof(lf), 
  176.            (PVOID) &lf, 
  177.            FALSE)) {
  178. ErrorMsg(TEXT("MainWndProc: SystemParametersInfo failed."));
  179. return 0;
  180. }
  181.         hDC = GetDC(hwnd);
  182.         if (!hDC) {
  183. ErrorMsg(TEXT("MainWndProc: GetDC failed."));
  184. return 0;
  185. }
  186.         
  187.         //
  188.         // this is the height for 8 point size font in pixels.
  189.         //  (1 point = 1/72 in.)
  190.         //
  191.         lf.lfHeight = 8 * GetDeviceCaps(hDC, LOGPIXELSY) / 72;
  192.         lf.lfWeight = BOLD_FONT;
  193.         ghFont = CreateFontIndirect(&lf);
  194. if (!ghFont) {
  195. ErrorMsg(TEXT("MainWndProc: CreateFontIndirect failed."));
  196. return 0;
  197. }
  198.         hOldFont = SelectObject(hDC, ghFont);
  199.         if (!hOldFont || (HGDIOBJ)hOldFont == (HGDIOBJ)GDI_ERROR) {
  200. ErrorMsg(TEXT("MainWndProc: SelectObject failed."));
  201. return 0;
  202. }
  203.         if (!GetTextMetrics(hDC, &tm)) {
  204. ErrorMsg(TEXT("MainWndProc: GetTextMetrics failed."));
  205. return 0;
  206. }
  207.         if (hOldFont) {
  208. hFont = SelectObject(hDC, hOldFont);
  209.   if (!hFont || (HGDIOBJ)hFont == (HGDIOBJ)GDI_ERROR) {
  210.   ErrorMsg(TEXT("MainWndProc: SelectObject failed."));
  211.   return 0;
  212.   }
  213.   } 
  214.         
  215.         if (!ReleaseDC(hwnd, hDC)) {
  216. ErrorMsg(TEXT("MainWndProc: ReleaseDC failed.rn"));
  217. return 0;
  218. }
  219.         //
  220.         // Create Drive windows
  221.         //
  222.         gDrvChildInfo.hParent = hwnd;
  223.       
  224.    ghwndDrv = CreateWindow(TEXT("DrvClass"), NULL,
  225.                                  WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,
  226.                                  0, 0, 0, 0,
  227.                                  hwnd, (HMENU) 1, ghModule,
  228.                                  (LPVOID)&gDrvChildInfo);
  229. if (!ghwndDrv) {
  230. ErrorMsg(TEXT("MainWndProc: CreateWindow failed."));
  231. dwLastError = GetLastError();
  232. return 0;
  233. }
  234.         ghwndDrv = ghwndDrv;
  235.         //
  236.         // Set initial focus to Drive Child 1's Directory listbox.
  237.         //
  238.         lpCInfo = (LPCINFO)GetWindowLong(ghwndDrv, GWL_USERDATA);
  239.         if (!lpCInfo) {
  240.          ErrorMsg(TEXT("MainWndProc: WM_CREATE: lpCInfo is NULL."));
  241.          return 0;
  242.         }
  243.         
  244.         ghFocusWnd = lpCInfo->hDirLB;
  245.         if (!ghFocusWnd) {
  246.          ErrorMsg(TEXT("MainWndProc: GetWindowLong failed."));
  247. return 0;
  248. }
  249.         
  250.         // Create DriveBar, FunctionBar and Command windows
  251.         
  252.         ghwndDrives = CreateWindow(TEXT("DriveBarClass"), NULL,
  253.                                     WS_CHILD | WS_VISIBLE | WS_BORDER,
  254.                                    0, 0, 0, 0,
  255.                                    hwnd, (HMENU) 3, ghModule,
  256.                                    (LPVOID)NULL);
  257.         if (!ghwndDrives) {
  258.          ErrorMsg(TEXT("MainWndProc: CreateWindow failed."));
  259.          return 0;
  260.         }
  261.         UpdateDrivesMenu(ghMenu, ghDrvThread);
  262.              
  263.        return 1;
  264.       }
  265.       case WM_COMMAND:{
  266.         //
  267.         // The menu Identifiers for the drives are (potentially)
  268.         // MM_DRIVE_NUM + 0 thru MM_DRIVE_NUM + 25. They all go to the
  269.         // same case, so we will put the Menu ID in lParam, and
  270.         // MM_DRIVE_NUM in LOWORD(wParam).
  271.         //
  272.         if( (LOWORD(wParam) - MM_DRIVE_NUM) <= 25 &&
  273.             (LOWORD(wParam) - MM_DRIVE_NUM) >= 0 ){
  274.             lParam = LOWORD(wParam);
  275.             wParam = MM_DRIVE_NUM;
  276.         }
  277.         switch (LOWORD(wParam)) {
  278.             //
  279.             // If a drive is selected from the Drives menu, or clicked
  280.             //  on the drives toolbar, the currently active child will
  281.             //  switch to this drive. Message 'unconverted' (see top of
  282.             //  WM_COMMAND case), and sent to DriveBarProc
  283.             //
  284.             case MM_DRIVE_NUM:{
  285.                 SendMessage(ghwndDrives, WM_COMMAND,
  286.                             (WPARAM)lParam, (LPARAM)NULL);
  287.                 return 1;
  288.             }
  289.             //
  290.             // Passes these WM_COMMAND messages to the appropriate active child
  291.             //  window proc for processing
  292.             //
  293.             case MM_TAB:
  294.             case MM_ESCAPE:
  295.             case MM_ENCRYPT_DECRYPT:
  296. case MM_SIGN:
  297. case MM_VERIFY:
  298.             case MM_EXPAND:{
  299.                 SendMessage(ghwndDrv, WM_COMMAND, wParam, lParam);
  300.                 return 1;
  301.             }
  302.             case MM_EXIT:{
  303.                 SendMessage(ghwndMain, WM_CLOSE, wParam, lParam);
  304.                 return 1;
  305.             }
  306.             //
  307.             // Creates the drive enumeration thread to re-enumerate the
  308.             //   available drives in the main menu.  Also sends a refresh
  309.             //   to the active drive child, and repaints the window.
  310.             //
  311.             case MM_REFRESH: {
  312.                 DWORD   dwThreadID;
  313.                 //
  314.                 // Initialize/Refresh Drives linked list
  315.                 //
  316.                 if( WaitForSingleObject(ghDrvThread, 0) != WAIT_TIMEOUT ){
  317.                     //
  318.                     // Close previous Drive Thread handle before creating new handle.
  319.                     //
  320.                     CloseHandle( ghDrvThread );
  321.                     ghDrvThread = CreateThread(NULL, 0,
  322.                                            (LPTHREAD_START_ROUTINE)EnumDrives,
  323.                                            (LPVOID)&glpDrives,
  324.                                            0, &dwThreadID);
  325.                     //
  326.                     // Refresh active child, drive toolbar, and drives menu
  327.                     //
  328.                     SendMessage(ghwndDrv, WM_COMMAND, wParam, lParam);
  329.                     SendMessage(ghwndDrives, WM_COMMAND, wParam, lParam);
  330.                     UpdateDrivesMenu(ghMenu, ghDrvThread);
  331.                     //
  332.                     // Mark all for repaint
  333.                     //
  334.                     InvalidateRect(hwnd,NULL,TRUE);
  335.                 }
  336.                 else
  337.                     MessageBeep(MB_ICONASTERISK);
  338.                 return 1;
  339.             }
  340.             //
  341.             // Swaps the directory and file list boxes of the active drv child.
  342.             //
  343.             case MM_SWAP:{
  344.                 LPCINFO lpCInfo;
  345.                 RECT    rect;
  346.                 lpCInfo = (LPCINFO)GetWindowLong(ghwndDrv, GWL_USERDATA);
  347.                 if (!lpCInfo) {
  348.                  ErrorMsg(TEXT("MainWndProc: MM_SWAP: lpCInfo is NULL."));
  349.                  return FALSE;
  350.                 }
  351.                 
  352.                 //
  353.                 // Switch the flag which indicates which side the Directory
  354.                 //  LB is on.  This is used by the WM_SIZE case of DrvWndProc.
  355.                 //
  356.                 lpCInfo->fDirLeft = !lpCInfo->fDirLeft;
  357.                 //
  358.                 // Send size message with current size to active child,
  359.                 //   in order to redraw the listboxes.
  360.                 //
  361.                 if( !GetClientRect( ghwndDrv, &rect ) )
  362.                     return 0;
  363.                 SendMessage( ghwndDrv, WM_SIZE, SIZENORMAL,
  364.                              MAKELONG( rect.right - rect.left,
  365.                                        rect.bottom - rect.top) );
  366.                 return 1;
  367.             }
  368.             case MM_KEEPCMD:{
  369.                 gfKeepCommandWin = !gfKeepCommandWin;
  370.                 if( gfKeepCommandWin )
  371.                     CheckMenuItem( ghMenu, MM_KEEPCMD,
  372.                                     MF_BYCOMMAND | MF_CHECKED);
  373.                 else
  374.                     CheckMenuItem( ghMenu, MM_KEEPCMD,
  375.                                 MF_BYCOMMAND | MF_UNCHECKED);
  376.             }
  377.             break;
  378.             //
  379.             // Toggles the relative Drive Child orientaion between
  380.             // Over/under and side/side.  gfDrvWndOrient is a flag checked
  381.             // by WM_SIZE to size Drv children
  382.             //
  383.             case MM_ORIENT:{
  384.                 RECT    rect;
  385.                 if( gfDrvWndOrient == OVER_UNDER )
  386.                     gfDrvWndOrient = SIDE_BY_SIDE;
  387.                 else
  388.                     gfDrvWndOrient = OVER_UNDER;
  389.                 //
  390.                 // Send size message with current size to self (main window),
  391.                 //   in order to redraw the Drv children.
  392.                 //
  393.                 if( !GetClientRect( hwnd, &rect ) )
  394.                     return 0;
  395.                 SendMessage( hwnd, WM_SIZE, SIZENORMAL,
  396.                              MAKELONG( rect.right - rect.left,
  397.                                        rect.bottom - rect.top) );
  398.                 InvalidateRect(ghwndDrv,NULL,TRUE);
  399.            
  400.                 return 1;
  401.             }
  402.             //
  403.             // Launches the About DialogBox.
  404.             //
  405.             case MM_ABOUT:{
  406.                 if (DialogBox(ghModule, 
  407.                    TEXT("AboutBox"), 
  408.                    ghwndMain, 
  409.                    (DLGPROC)AboutProc) == -1)
  410.                         
  411.                  ErrorMsg(TEXT("Main: About Dialog Creation Error!"));
  412.                 return 1;
  413.             }
  414.             case ID_HELP:
  415.          if (!WinHelp(hwnd, TEXT("cf.hlp"), HELP_CONTENTS, 0L)) {
  416. ErrorMsg(TEXT("MainWndProc: WinHelp failed."));
  417. return 0;
  418. }
  419.          return 1;
  420. case ID_ENCRYPTION_ALGORITHM:
  421. bRet = DialogBox(ghModule, 
  422.      TEXT("ENCRYPTION_ALGORITHM"), 
  423.      ghwndMain, 
  424.      EncryptDlgProc);
  425. if (bRet == TRUE)
  426. InvalidateRect(ghwndMain, NULL, TRUE);
  427. else if (bRet == FALSE)
  428. return FALSE;
  429. return 1; 
  430. case ID_SIGNATURE_ALGORITHM:
  431. bRet = DialogBox(ghModule, TEXT("HASH_ALGORITHM"), ghwndMain, HashDlgProc);
  432. if (bRet == TRUE)
  433. InvalidateRect(ghwndMain, NULL, TRUE);
  434. else if (bRet == FALSE)
  435. return FALSE;
  436. return 1;
  437. case MM_PASS:
  438. AlgidEncrypt = 0;
  439. if (!GetPass(ghwndMain) || strlen(sPass) == 0) {
  440. AlgidEncrypt = CALG_RC2;
  441. return FALSE;
  442. }
  443. return 1;
  444. case ID_HIDE: {
  445. DWORD cm;
  446. cm = CheckMenuItem(ghMenu, ID_HIDE, MF_CHECKED);
  447. if (cm == MF_CHECKED) {
  448. if (ShowSignatures())
  449. CheckMenuItem(ghMenu, ID_HIDE, MF_UNCHECKED);
  450. }
  451. else if (cm == MF_UNCHECKED) {
  452. if (HideSignatures())
  453. CheckMenuItem(ghMenu, ID_HIDE, MF_CHECKED);
  454. }
  455. else {
  456. ErrorMsg(TEXT("ID_HIDE: CheckMenuItem failed."));
  457. return 0;
  458. }
  459. return 1;
  460. }
  461. default:
  462.                 return(DefWindowProc(hwnd, message, wParam, lParam));
  463.         }
  464.         return 1;
  465.       }
  466.       //
  467.       // Whenever the window is resized, its children have to be
  468.       //  resized accordingly.  The GetWindowLong values are the height
  469.       //  of the windows queried by this function, and are set in the
  470.       //  WM_CREATE cases of their respective WNDPROCs.
  471.       //
  472.       case WM_SIZE:{
  473.         int DrvWndHeight;
  474.         //
  475.         // Always put the drives toolbar at the top of the frame window
  476.         //
  477.         MoveWindow(ghwndDrives,
  478.            0,
  479.            0,
  480.            LOWORD(lParam),
  481.            GetWindowLong(ghwndDrives, GWL_USERDATA),
  482.            TRUE);
  483.         //
  484.         // Always size the Drive Children between the Drives and Command
  485.         // windows. The width is set so that borders overlap.
  486.         //
  487.         if( gfDrvWndOrient == OVER_UNDER ){
  488.             DrvWndHeight = ( HIWORD(lParam) -
  489.                            GetWindowLong(ghwndDrives, GWL_USERDATA));
  490.             MoveWindow(ghwndDrv,
  491.                        -1,
  492.                        GetWindowLong(ghwndDrives, GWL_USERDATA),
  493.                        (LOWORD(lParam) + 2),
  494.                        DrvWndHeight,
  495.                        TRUE);
  496.         }
  497.         else{
  498.             DrvWndHeight = HIWORD(lParam) -
  499.                            GetWindowLong(ghwndDrives, GWL_USERDATA);
  500.             MoveWindow(ghwndDrv,
  501.                         -1,
  502.                         GetWindowLong(ghwndDrives, GWL_USERDATA),
  503.                         (LOWORD(lParam)/2 + 1)*2,
  504.                         DrvWndHeight,
  505.                         TRUE);
  506.         }
  507.         return 1;
  508.       }
  509.       case WM_DESTROY: {
  510.         Logoff(hwnd);
  511.        
  512.     DeleteHashDirectory();
  513.         free(lpDriveStrings);
  514. DestroyMenu(ghMenu);
  515.         
  516.         SendMessage(ghwndDrv, WM_CLOSE, 0, 0);
  517.         
  518.         //
  519.         // Close last drive thread handle,
  520.         //  the created font, and the Drive list critical section.
  521.         //
  522.         CloseHandle( ghDrvThread );
  523.         DeleteObject(ghFont);
  524.         DeleteCriticalSection(&gDrvCS);
  525.         PostQuitMessage(0);
  526.     return 1;
  527.       }
  528.       default:
  529.         return DefWindowProc(hwnd, message, wParam, lParam);
  530.     }
  531. }
  532. LRESULT WINAPI AboutProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  533. {
  534.     switch (message) {
  535.       case WM_INITDIALOG:{
  536.         return TRUE;
  537.       }
  538.       case WM_COMMAND:{
  539.         if (wParam == IDOK)
  540.             EndDialog(hDlg, wParam);
  541.         break;
  542.       }
  543.     }
  544.     return FALSE;
  545.     UNREFERENCED_PARAMETER(lParam);
  546.     UNREFERENCED_PARAMETER(hDlg);
  547. }
  548. /************************************************************************
  549. * DriveBarProc()
  550. *
  551. * Drive Toolbar procedure for displaying available drive Icons.
  552. *  A bitmap button is displayed corresponding to the drive type of the
  553. *  given drive, with the drive letter alongside.
  554. *  ghwndDrives is the global handle assoc. w/ this window procedure.
  555. ***********************************************************************/
  556. LRESULT WINAPI DriveBarProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  557. {
  558.     static HBITMAP  hDrvBmp[NUM_BITMAPS];
  559.     static HBRUSH   hBrush;         // background brush
  560.     static int      nDrvEntryWidth; // width of button/letter entry
  561.     static int      yVal;           // y value in toolbar for top left of bmp
  562.     static LPBINFO  lpDrvButtonRoot;
  563.     static int      nActiveDrvIndex;
  564.     switch (message)
  565.     {
  566.         case WM_CREATE:{
  567.             HDC        hDC;
  568.             HGDIOBJ    hOldFont;
  569.             TEXTMETRIC tm;
  570.             LONG       lHeight;
  571.             lpDrvButtonRoot = NULL;
  572.             //
  573.             // Load drive button bitmaps.
  574.             //
  575.             for(yVal = 0; yVal < NUM_BITMAPS; yVal++)
  576.                 hDrvBmp[yVal] = LoadBitmap( ghModule,
  577.                                       MAKEINTRESOURCE(UB_BMP_MARKER + yVal) );
  578.             //
  579.             // Sets background color of Toolbar non-modal dialog children.
  580.             //
  581.             hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
  582.             hDC = GetDC(hwnd);
  583.             hOldFont = SelectObject(hDC, ghFont);
  584.             GetTextMetrics(hDC, &tm);
  585.             //
  586.             // base the height of the window on size of text
  587.             //
  588.             lHeight = tm.tmHeight + GetSystemMetrics(SM_CYBORDER) + 6;
  589.             //
  590.             // saved the window height, drive button entry width
  591.             //   and button y starting value for later reference
  592.             //
  593.             SetWindowLong(hwnd, GWL_USERDATA, lHeight);
  594.             //
  595.             // Width of one button entry = spacing, button, sm. space,
  596.             //   drive letter, spacing.
  597.             //
  598.             nDrvEntryWidth = DRIVE_BITMAP_SPACING + DRIVE_BITMAP_WIDTH +
  599.                              DRIVE_LETTER_SPACING + tm.tmAveCharWidth +
  600.                              DRIVE_BITMAP_SPACING;
  601.             //
  602.             // Center bitmaps (by height) in drive toolbar.
  603.             //
  604.             yVal = (lHeight - DRIVE_BITMAP_HEIGHT)/2;
  605.             SelectObject(hDC, hOldFont);
  606.             ReleaseDC(hwnd, hDC);
  607.             SendMessage(hwnd, WM_COMMAND, (WPARAM)MM_REFRESH, (LPARAM)NULL);
  608.             break;
  609.         }
  610.         case WM_COMMAND:{
  611.             //
  612.             // The button Identifiers for the drives are (potentially)
  613.             // MM_DRIVE_NUM + 0 thru MM_DRIVE_NUM + 25. They all go to the
  614.             // same case, so we will put the Menu ID in lParam, and
  615.             // MM_DRIVE_NUM in LOWORD(wParam).
  616.             //
  617.             if( (LOWORD(wParam) - MM_DRIVE_NUM) <= 25 &&
  618.                 (LOWORD(wParam) - MM_DRIVE_NUM) >= 0 ){
  619.                 lParam = LOWORD(wParam);
  620.                 wParam = MM_DRIVE_NUM;
  621.             }
  622.             switch( LOWORD(wParam) ){
  623.               case MM_REFRESH:{
  624.                 LPDINFO lpWalk;
  625.                 LPBINFO lpBWalk, lpBHold;
  626.                 LPCINFO lpCInfo;
  627.                 int     xVal = 0;
  628. int nCount = MM_DRIVE_NUM;
  629.                
  630.                 lpCInfo = (LPCINFO)GetWindowLong(ghwndDrv, GWL_USERDATA);
  631.                 if (!lpCInfo) {
  632.                  ErrorMsg(TEXT("DriveBarProc: MM_REFRESH: lpCInfo is NULL."));
  633.                  return FALSE;
  634.                 }
  635.                 
  636.                 //
  637.                 // Wait for Drive Thread to complete, if necessary.
  638.                 //
  639.                 WaitForSingleObject(ghDrvThread, INFINITE);
  640.                 EnterCriticalSection(&gDrvCS);
  641.                 //
  642.                 // Traverse DRVINFO linked list, creating drive buttons and
  643.                 //   allocating corresp. structures as necessary.
  644.                 //
  645.                 lpWalk = glpDrives;
  646.                 lpBWalk = lpDrvButtonRoot;
  647.                 while( lpWalk != NULL ){
  648.                  if( lpBWalk == NULL ){ //If at the end of the button list
  649.                         // Allocate a LPBINFO (button) structure
  650.                         lpBWalk = (LPBINFO)malloc((DWORD)sizeof(BINFO));
  651.                         
  652.                         if (!lpBWalk) {
  653. ErrorMsg(TEXT("DriveBarProc: MM_REFRESH: malloc failed."));
  654. return 0;
  655. }
  656.                         lpBWalk->next = NULL;
  657.                         // Create a button window
  658.                         lpBWalk->hButton = (HANDLE)CreateWindow(TEXT("BUTTON"),
  659.                                                  lpWalk->DriveName,
  660.                                                  WS_CHILD | WS_VISIBLE |
  661.                                                  BS_OWNERDRAW ,
  662.                                                  xVal + DRIVE_BITMAP_SPACING,
  663.                                                  yVal,
  664.                                                  DRIVE_BITMAP_WIDTH,
  665.                                                  DRIVE_BITMAP_HEIGHT,
  666.                                                  hwnd,
  667.                                                  (HMENU)nCount,
  668.                                                  ghModule,
  669.                                                  NULL);
  670.                         // Insert structure into list
  671.                         if( lpDrvButtonRoot == NULL)
  672.                             lpDrvButtonRoot = lpBHold = lpBWalk;
  673.                         else{
  674.                             lpBHold->next = lpBWalk;
  675.                             lpBWalk->next = NULL;
  676.                         }
  677.                     }
  678.                     // An LPBINFO (button) structure exists: now initialize
  679.                     // Set Title of Button (Drive Letter)
  680.                     SetWindowText(lpBWalk->hButton, lpWalk->DriveName);
  681.                     // Set Child Window ID for Button
  682.                     // SetMenu(lpBWalk->hButton, (HMENU)nCount);
  683.                     // Determine button up/down status
  684.                     if( lpCInfo->lpDriveInfo == lpWalk ){
  685.                         nActiveDrvIndex = nCount;
  686.                         lpBWalk->fButtonDown = TRUE;
  687.                     }
  688.                     else
  689.                         lpBWalk->fButtonDown = FALSE;
  690.                     // Set a pointer to the corresponding drive in Drive list
  691.                     lpBWalk->lpDrive = lpWalk;
  692.                     nCount++;
  693.                     xVal += nDrvEntryWidth;
  694.                     lpBHold = lpBWalk;
  695.                     lpBWalk = lpBWalk->next;
  696.                     lpWalk = lpWalk->next;
  697.                 
  698.                 }
  699.                 LeaveCriticalSection(&gDrvCS);
  700.                 //
  701.                 // Free any remaining button windows.
  702.                 //
  703.                 while( lpBWalk != NULL ){
  704.                     // NULL out new end of list
  705.                     lpBHold->next = NULL;
  706.                     // Assign pointer to doomed node
  707.                     lpBHold = lpBWalk;
  708.                     lpBWalk = lpBWalk->next;
  709.                     // Free doomed node resources
  710.                     if( !DestroyWindow(lpBHold->hButton) )
  711.                         ErrorMsg(TEXT("DriveBarProc: Drive Button Destroy Error"));
  712.                     free(lpBHold);
  713.                 }
  714.                 SendMessage(hwnd, WM_PAINT, (WPARAM)NULL, (LPARAM)NULL);
  715.                 
  716. break;
  717.               }
  718.               //
  719.               // switches the drive button to the newly active drv child's
  720.               //   current drive.  Called by WM_MOUSEACTIVATE in DrvWndProc,
  721.               //   as well as ChangeDrive.
  722.               //   lParam contains the drive linked list pointer of the active
  723.               //   drv child's LPCINFO struct.
  724.               //
  725.               case MM_ACTIVEDRV:{
  726.                 LPBINFO lpBWalk = lpDrvButtonRoot;
  727.                 int     nCount = 0;
  728.                 //
  729.                 // 'unpush' old active button
  730.                 //
  731.                 for( nCount = MM_DRIVE_NUM; nCount < nActiveDrvIndex; nCount++)
  732.                     lpBWalk = lpBWalk->next;
  733.                 lpBWalk->fButtonDown = FALSE;
  734.                 InvalidateRect(lpBWalk->hButton, NULL, FALSE);
  735.                 //
  736.                 // change active drive to new before redrawing old.
  737.                 //  'push' new active button
  738.                 //
  739.                 lpBWalk = lpDrvButtonRoot;
  740.                 nCount = MM_DRIVE_NUM;
  741.                 while( lpBWalk->lpDrive != (LPDINFO)lParam){
  742.                     lpBWalk = lpBWalk->next;
  743.                     nCount++;
  744.                 }
  745.                 nActiveDrvIndex = nCount;
  746.                 lpBWalk->fButtonDown = TRUE;
  747.                 InvalidateRect(lpBWalk->hButton, NULL, FALSE);
  748.                 break;
  749.               }
  750.               //
  751.               // Changes drive of active child.  ButtonID in lParam.
  752.               //
  753.               case MM_DRIVE_NUM:{
  754.                 LPBINFO lpBWalk = lpDrvButtonRoot;
  755.                 int     nCount = 0;
  756.                 TCHAR    szDrvBuff[DIRECTORY_STRING_SIZE];
  757.                 //
  758.                 // if drive chosen is already current drive, leave.
  759.                 //
  760.                 if( nActiveDrvIndex == (int)lParam )
  761.                     break;
  762.                 //
  763.                 // unpush' old active button
  764.                 //
  765.                 for( nCount = MM_DRIVE_NUM; nCount < nActiveDrvIndex; nCount++)
  766.                     lpBWalk = lpBWalk->next;
  767.                 lpBWalk->fButtonDown = FALSE;
  768.                 //
  769.                 // change active drive to new before redrawing old.
  770.                 //
  771.                 nActiveDrvIndex = (int)lParam;
  772.                 InvalidateRect(lpBWalk->hButton, NULL, FALSE);
  773.                 //
  774.                 // 'push' new active button
  775.                 //
  776.                 lpBWalk = lpDrvButtonRoot;
  777.                 for( nCount = MM_DRIVE_NUM; nCount < nActiveDrvIndex; nCount++)
  778.                     lpBWalk = lpBWalk->next;
  779.                 lpBWalk->fButtonDown = TRUE;
  780.                 InvalidateRect(lpBWalk->hButton, NULL, FALSE);
  781.                 GetWindowText(lpBWalk->hButton, szDrvBuff,
  782.                               DIRECTORY_STRING_SIZE);
  783.                 if( !ChangeDrive(szDrvBuff, (DWORD)nActiveDrvIndex) ){
  784.                     ErrorMsg(TEXT("Error changing Drives.rn"));
  785.                     return 0;
  786.                 }
  787.                 break;
  788.               }
  789.             }
  790.             return 1;
  791.         }
  792.         //
  793.         // Sent by all created buttons for initialization purposes.
  794.         //
  795.         case WM_MEASUREITEM:{
  796.             LPMEASUREITEMSTRUCT lpMIS;
  797.             lpMIS = (LPMEASUREITEMSTRUCT)lParam;
  798.             lpMIS->CtlType = ODT_BUTTON;
  799.             lpMIS->CtlID = (UINT)wParam;
  800.             lpMIS->itemWidth = DRIVE_BITMAP_WIDTH;
  801.             lpMIS->itemHeight = DRIVE_BITMAP_HEIGHT;
  802.             return 1;
  803.         }
  804.         //
  805.         // Sent by owner draw drive buttons when needing redrawing.
  806.         //
  807.         case WM_DRAWITEM:{
  808.             LPBINFO lpBWalk = lpDrvButtonRoot;
  809.             int     nCount;
  810.             int     nBmpIndex;
  811.             HDC     hDC;
  812.             HDC     hCompatDC;
  813.             HGDIOBJ hOldBitmap;
  814.             TCHAR    szDrvBuff[DIRECTORY_STRING_SIZE];
  815.             LPDRAWITEMSTRUCT    lpDIS;
  816.             lpDIS = (LPDRAWITEMSTRUCT)lParam;
  817.             for( nCount = MM_DRIVE_NUM; nCount < (int)wParam; nCount++)
  818.                 lpBWalk = lpBWalk->next;
  819.             //
  820.             // If not the current selected button, handle button stuff.
  821.             //
  822.             if( (int)wParam != nActiveDrvIndex ){
  823.                 //
  824.                 // mousebutton is down...
  825.                 //
  826.                 if( lpDIS->itemAction & ODA_SELECT ){
  827.                     //
  828.                     // left button region, 'unpush' button
  829.                     //
  830.                     if( lpDIS->itemState == (UINT)ODS_FOCUS )
  831.                         lpBWalk->fButtonDown = FALSE;
  832.                     //
  833.                     // clicked on a button, draw 'pushed' button
  834.                     //
  835.                     if( lpDIS->itemState == (UINT)(ODS_SELECTED | ODS_FOCUS))
  836.                         lpBWalk->fButtonDown = TRUE;
  837.                 }
  838.             }
  839.             //
  840.             // draw current state of button.
  841.             //
  842.             GetWindowText(lpDIS->hwndItem, szDrvBuff,
  843.                           DIRECTORY_STRING_SIZE);
  844.             szDrvBuff[1] = TEXT('');
  845.             hCompatDC = CreateCompatibleDC(lpDIS->hDC);
  846.             hOldBitmap = CreateCompatibleBitmap(hCompatDC,
  847.                                                 DRIVE_BITMAP_WIDTH,
  848.                                                 DRIVE_BITMAP_HEIGHT);
  849.             nBmpIndex = GetDriveBitmap(lpBWalk);
  850.             SelectObject( hCompatDC, hDrvBmp[nBmpIndex] );
  851.             if( !hOldBitmap )
  852.                 ErrorMsg(TEXT("WM_DRAWITEM: SelectObject failure."));
  853.             if( !BitBlt(lpDIS->hDC, lpDIS->rcItem.left, lpDIS->rcItem.top,
  854.                    DRIVE_BITMAP_WIDTH,
  855.                    DRIVE_BITMAP_HEIGHT,
  856.                    hCompatDC, 0, 0, SRCCOPY) )
  857.                 ErrorMsg(TEXT("WM_DRAWITEM: BitBlt failure."));
  858.             SelectObject( hCompatDC, hOldBitmap);
  859.             DeleteDC(hCompatDC);
  860.             hDC = GetDC(hwnd);
  861.             SetBkMode(hDC, OPAQUE);
  862.             SetTextColor(hDC, GetSysColor(COLOR_MENUTEXT) );
  863.             SetBkColor(hDC, GetSysColor(COLOR_MENU) );
  864.             TextOut(hDC,
  865.                     ((int)(wParam - MM_DRIVE_NUM) * nDrvEntryWidth) +
  866.                         DRIVE_BITMAP_SPACING + DRIVE_BITMAP_WIDTH +
  867.                         DRIVE_LETTER_SPACING,
  868.                     (GetSystemMetrics(SM_CYBORDER) + 6)/2,
  869.                     szDrvBuff, 1);
  870.             SetBkMode(hDC, OPAQUE);
  871.             ReleaseDC(hwnd, hDC);
  872. DeleteObject(hOldBitmap);
  873.             break;
  874.         }
  875.         case WM_PAINT:{
  876.             HDC     hCompatDC;
  877.             RECT     rc;
  878.             PAINTSTRUCT ps;
  879.             //
  880.             // Paint btnshadow background.
  881.             //
  882.             GetClientRect(hwnd, &rc);
  883.             BeginPaint(hwnd, &ps);
  884.             hCompatDC = CreateCompatibleDC(ps.hdc);
  885.             FillRect(ps.hdc, &rc, hBrush);
  886.             EndPaint(hwnd, &ps);
  887.             DeleteDC(hCompatDC);
  888.             
  889.             return(TRUE);
  890.         }
  891.         case WM_DESTROY:{
  892.             LPBINFO p, q;
  893.             LPDINFO p1, q1;
  894.             DeleteObject(hBrush);
  895.             for (p = lpDrvButtonRoot; p; p = q) {
  896. q = p->next;
  897. free(p);
  898. }
  899.             
  900.             for (p1 = glpDrives; p1; p1 = q1) {
  901.              q1 = p1->next;
  902.              free(p1);
  903.              p1 = NULL;
  904.             }
  905.             
  906.             for(yVal = 0; yVal < NUM_BITMAPS; yVal++)
  907.                 DeleteObject(hDrvBmp[yVal]);
  908.             break;
  909.         }
  910.     }
  911.     return DefWindowProc(hwnd, message, wParam, lParam);
  912. }
  913. /************************************************************************
  914. * GetDriveBitmap()
  915. *
  916. * Determines the appropriate index into the drive button bitmap array
  917. * (hDrvBmp[]), given a pointer to a drive info structure (LPDINFO)
  918. *
  919. * lpWalk          -   pointer to LPDINFO structure.
  920. * lpCurrentDrv    -   pointer to current drive of active child.
  921. ***********************************************************************/
  922. int GetDriveBitmap(LPBINFO lpBWalk)
  923. {
  924.     int nBmpIndex;
  925.     EnterCriticalSection(&gDrvCS);
  926.     switch( lpBWalk->lpDrive->DriveType ){
  927.         case DRIVE_REMOVABLE:{
  928.           nBmpIndex = UB_FLOPPY1 - UB_BMP_MARKER;
  929.           break;
  930.         }
  931.         case DRIVE_REMOTE:{
  932.           nBmpIndex = UB_REMOTE1 - UB_BMP_MARKER;
  933.             break;
  934.         }
  935.         case DRIVE_CDROM:{
  936.           nBmpIndex = UB_CD1 - UB_BMP_MARKER;
  937.             break;
  938.         }
  939.         case DRIVE_FIXED:
  940.         default:{
  941.           nBmpIndex = UB_FIXED1 - UB_BMP_MARKER;
  942.             break;
  943.         }
  944.     }
  945.     LeaveCriticalSection(&gDrvCS);
  946.     if( lpBWalk->fButtonDown == TRUE )
  947.         nBmpIndex++;
  948.     return(nBmpIndex);
  949. }
  950. /********************************************************************************
  951. * ChangeDrive()
  952. *
  953. *   Changes the current drive of the child.  Called by the MM_DRIVE_NUM
  954. *   cases in MainWndProc and DriveBarProc.  This is caused by choosing a
  955. *   Drive menu item or selecting a drive button from the drive toolbar.
  956. *
  957. *   lpszDriveName -   points to a buffer containing the name of the drive
  958. *   DriveID       -   points to the ID of the Menu item or button, which
  959. *                         corresponds to the index into the drives linked list
  960. *                         of the new drive.
  961. ********************************************************************************/
  962. BOOL ChangeDrive(LPTSTR lpszDriveName, DWORD DriveIndex)
  963. {
  964.     LPCINFO     lpCInfo;
  965.     LPDINFO     lpWalk;
  966.     DWORD       dwLoop;
  967.     UINT        nDriveType;
  968.     //
  969.     // Retrieve active child handle.
  970.     //
  971.     if( (ghwndDrv != ghwndDrv) ){
  972.         ErrorMsg(TEXT("A Drive Window Must be Active."));
  973.         return 0;
  974.     }
  975.     //
  976.     // Retrieving the child window's DRVCHILDINFO data
  977.     //
  978.     lpCInfo = (LPCINFO)GetWindowLong(ghwndDrv, GWL_USERDATA);
  979.     if (!lpCInfo) {
  980.      ErrorMsg(TEXT("ChangeDrive: lpCInfo is NULL."));
  981.      return FALSE;
  982.     }
  983.     
  984.     //
  985.     // Enter Drive list critical section
  986.     //
  987.     EnterCriticalSection(&gDrvCS);
  988.     //
  989.     // if removable drive, check for existing media.
  990.     //
  991.     nDriveType = GetDriveType(lpszDriveName);
  992.     if( nDriveType == DRIVE_REMOVABLE ||
  993.         nDriveType == DRIVE_CDROM ){
  994.         dwLoop = (DWORD)IDOK;
  995.         while( !CheckRM(lpszDriveName) && (dwLoop == (DWORD)IDOK) ){
  996.            dwLoop = (DWORD)MessageBox(ghwndMain,
  997.                            TEXT("CRYPTFILER: Insert some media in drive"),
  998.                            lpszDriveName, MB_OKCANCEL);
  999.         }
  1000.         if( dwLoop == (DWORD)IDCANCEL ){
  1001.             SendMessage(ghwndDrives, WM_COMMAND, MM_ACTIVEDRV,
  1002.                         (LPARAM)lpCInfo->lpDriveInfo);
  1003.         LeaveCriticalSection(&gDrvCS);
  1004.             return 0;
  1005.         }
  1006.     }
  1007.     //
  1008.     // set lpDriveInfo member to associated drive struct.
  1009.     //
  1010.     lpWalk = glpDrives;
  1011.     for( dwLoop = 0; dwLoop < DriveIndex - MM_DRIVE_NUM;
  1012.          dwLoop++)
  1013.          lpWalk = lpWalk->next;
  1014.     lpCInfo->lpDriveInfo = lpWalk;
  1015.     lstrcpy(lpCInfo->CaptionBarText, lpWalk->DriveName);
  1016.     LeaveCriticalSection(&gDrvCS);
  1017.     //
  1018.     // This will terminate any currently running drive thread.
  1019.     //
  1020.     SendMessage(ghwndDrv, WM_COMMAND, MM_ESCAPE, (LPARAM)0);
  1021.     lpCInfo->fEscape = FALSE;
  1022.     //
  1023.     // enact the drive change.
  1024.     //
  1025.     PostMessage(ghwndDrv, WM_COMMAND, MM_REFRESH, (LPARAM)0);
  1026.     return 1;
  1027. }
  1028. /********************************************************************************
  1029. * UpdateDrivesMenu()
  1030. *
  1031. * Adds current drives from the glpDrives linked list to the TEXT('Drives') menu
  1032. *
  1033. * Input: hDrivesMenu - handle to TEXT('Drives') Menu
  1034. *        hThread    - used to wait for drives thread to terminate
  1035. ********************************************************************************/
  1036. BOOL UpdateDrivesMenu(HMENU hMenu, HANDLE hThread)
  1037. {
  1038.     HMENU   hDrivesMenu;
  1039.     int     NumMenuItems;
  1040.     DWORD   dwLoop;
  1041.     LPDINFO lpWalk;
  1042.     //
  1043.     // Remove list of drive menu items from Drive menu, if any.
  1044.     //
  1045.     hDrivesMenu = GetSubMenu( hMenu, DRIVE_MENU_NUM);
  1046.     if(!hDrivesMenu){
  1047.         ErrorMsg(TEXT("UpdateDrivesMenu: GetSubMenu error."));
  1048.         return FALSE;
  1049.     }
  1050.     if((NumMenuItems = GetMenuItemCount(hDrivesMenu)) == -1) {
  1051.         ErrorMsg(TEXT("Main Refresh: Menu Item Count Error."));
  1052. return FALSE;
  1053. }
  1054.     //
  1055.     // Delete previous menu items.
  1056.     //
  1057.     for( dwLoop = 0; dwLoop < (DWORD)NumMenuItems; dwLoop++)
  1058.         if(!DeleteMenu(hDrivesMenu, 0, MF_BYPOSITION)){
  1059.             ErrorMsg(TEXT("Main Refresh: Menu Item Delete Error."));
  1060.             return FALSE;
  1061.         }
  1062.     //
  1063.     // Wait for Enumdrv Thread to terminate, and
  1064.     //   enter drive list critical section
  1065.     //
  1066.     if (WaitForSingleObject(hThread, INFINITE) == WAIT_FAILED) {
  1067. ErrorMsg(TEXT("UpdateDrivesMenu: WaitForSingleObject failed."));
  1068. return FALSE;
  1069. }
  1070.     EnterCriticalSection(&gDrvCS);
  1071.     //
  1072.     // Fill drive menu from glpDrives linked list
  1073.     //
  1074.     NumMenuItems = 0;
  1075.     lpWalk = glpDrives;
  1076.     while(lpWalk != NULL){
  1077.         if(!InsertMenu(hDrivesMenu, NumMenuItems, MF_STRING | MF_BYPOSITION 
  1078.          | MF_ENABLED, MM_DRIVE_NUM + NumMenuItems, lpWalk->DriveName)) {
  1079.             ErrorMsg(TEXT("Main Refresh: Menu Item Insert Error."));
  1080. return FALSE;
  1081. }
  1082.         NumMenuItems++;
  1083.         lpWalk = lpWalk->next;
  1084.     }
  1085.     LeaveCriticalSection(&gDrvCS);
  1086.     return TRUE;
  1087. }
  1088. /***************************************************************
  1089. * ErrorMsg()
  1090. *
  1091. *   Displays a Message Box with a given error message.
  1092. *
  1093. ***************************************************************/
  1094. void ErrorMsg(LPTSTR szMsg)
  1095. {
  1096.     TCHAR szHold[DIRECTORY_STRING_SIZE + 1];
  1097.     lstrcpy( szHold, szMsg );
  1098.     lstrcat( szHold, TEXT("n") );
  1099.     OutputDebugString(szHold);
  1100. }