misc.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 34k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. //---------------------------------------------------------------------------
  2. //
  3. // Copyright (c) Microsoft Corporation 1993-1994
  4. //
  5. // File: misc.c
  6. //
  7. //  This file contains miscellaneous dialog code
  8. //
  9. // History:
  10. //  08-06-93 ScottH     Transferred from twin code
  11. //
  12. //---------------------------------------------------------------------------
  13. #include "brfprv.h"     // common headers
  14. #include "res.h"
  15. typedef struct _MB_BUTTONS
  16.     {
  17.     UINT id;        // id
  18.     UINT ids;       // string ID
  19.     } MB_BUTTONS, * PMB_BUTTONS;
  20. typedef struct _BTNSTYLE
  21.     {
  22.     UINT cButtons;
  23.     MB_BUTTONS rgmbb[4];
  24.     } BTNSTYLE;
  25. //---------------------------------------------------------------------------
  26. // Control manipulation stuff
  27. //---------------------------------------------------------------------------
  28. // Flags for SNAPCTL
  29. #define SCF_ANCHOR      0x0001
  30. #define SCF_VCENTER     0x0002
  31. #define SCF_BOTTOM      0x0004
  32. #define SCF_TOP         0x0008
  33. #define SCF_SNAPLEFT    0x0010
  34. #define SCF_SNAPRIGHT   0x0020
  35. typedef struct tagSNAPCTL
  36.     {
  37.     UINT    idc;
  38.     UINT    uFlags;
  39.     } SNAPCTL, * PSNAPCTL;
  40. /*----------------------------------------------------------
  41. Purpose: Moves a control
  42. Returns: HDWP
  43. Cond:    --
  44. */
  45. HDWP PRIVATE SlideControlPos(
  46.     HDWP hdwp,
  47.     HWND hDlg,
  48.     UINT idc,
  49.     int cx,
  50.     int cy)
  51.     {
  52.     HWND hwndPos = GetDlgItem(hDlg, idc);
  53.     RECT rcPos;
  54.     GetWindowRect(hwndPos, &rcPos);
  55.     MapWindowRect(HWND_DESKTOP, hDlg, &rcPos);
  56.     return DeferWindowPos(hdwp, hwndPos, NULL,
  57.                           rcPos.left + cx, rcPos.top + cy,
  58.                           0, 0,
  59.                           SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
  60.     }
  61. /*----------------------------------------------------------
  62. Purpose: Aligns a list of controls, relative to an "anchor"
  63.          control.
  64.          Only one anchor control is supported; the first control
  65.          designated as anchor in the list is selected.
  66. Returns: --
  67. Cond:    --
  68. */
  69. void PRIVATE SnapControls(
  70.     HWND hwnd,
  71.     SNAPCTL const * psnap,
  72.     UINT csnap)
  73.     {
  74.     HWND hwndAnchor;
  75.     UINT i;
  76.     SNAPCTL const * psnapStart = psnap;
  77.     HDWP hdwp;
  78.     RECT rcAnchor;
  79.     int yCenter;
  80.     ASSERT(psnap);
  81.     // Find the anchor control
  82.     for (i = 0; i < csnap; i++, psnap++)
  83.         {
  84.         if (IsFlagSet(psnap->uFlags, SCF_ANCHOR))
  85.             {
  86.             hwndAnchor = GetDlgItem(hwnd, psnap->idc);
  87.             break;
  88.             }
  89.         }
  90.     if (i == csnap)
  91.         return;     // No anchor control!
  92.     GetWindowRect(hwndAnchor, &rcAnchor);
  93.     yCenter = rcAnchor.top + (rcAnchor.bottom - rcAnchor.top)/2;
  94.     hdwp = BeginDeferWindowPos(csnap-1);
  95.     if (hdwp)
  96.         {
  97.         RECT rc;
  98.         UINT uFlags;
  99.         HWND hwndPos;
  100.         for (i = 0, psnap = psnapStart; i < csnap; i++, psnap++)
  101.             {
  102.             uFlags = psnap->uFlags;
  103.             if (IsFlagSet(uFlags, SCF_ANCHOR))
  104.                 continue;       // skip anchor
  105.             hwndPos = GetDlgItem(hwnd, psnap->idc);
  106.             GetWindowRect(hwndPos, &rc);
  107.             if (IsFlagSet(uFlags, SCF_VCENTER))
  108.                 {
  109.                 // Vertically match the center of this control with
  110.                 // the center of the anchor
  111.                 rc.top += yCenter - (rc.top + (rc.bottom - rc.top)/2);
  112.                 }
  113.             else if (IsFlagSet(uFlags, SCF_TOP))
  114.                 {
  115.                 // Vertically match the top of this control with
  116.                 // the top of the anchor
  117.                 rc.top += rcAnchor.top - rc.top;
  118.                 }
  119.             else if (IsFlagSet(uFlags, SCF_BOTTOM))
  120.                 {
  121.                 // Vertically match the bottom of this control with
  122.                 // the bottom of the anchor
  123.                 rc.top += rcAnchor.bottom - rc.bottom;
  124.                 }
  125.             if (IsFlagSet(uFlags, SCF_SNAPLEFT))
  126.                 {
  127.                 // Snap the control so it is abut to the left side
  128.                 // of the anchor control
  129.                 rc.left += rcAnchor.left - rc.right;
  130.                 }
  131.             else if (IsFlagSet(uFlags, SCF_SNAPRIGHT))
  132.                 {
  133.                 // Snap the control so it is abut to the right side
  134.                 // of the anchor control
  135.                 rc.left += rcAnchor.right - rc.left;
  136.                 }
  137.             // Move control
  138.             MapWindowRect(HWND_DESKTOP, hwnd, &rc);
  139.             hdwp = DeferWindowPos(hdwp, hwndPos, NULL,
  140.                                   rc.left, rc.top, 0, 0,
  141.                                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
  142.             }
  143.         EndDeferWindowPos(hdwp);
  144.         }
  145.     }
  146. //---------------------------------------------------------------------------
  147. // Abort event stuff
  148. //---------------------------------------------------------------------------
  149. /*----------------------------------------------------------
  150. Purpose: Creates an abort event.
  151. Returns: TRUE on success
  152. Cond:    --
  153. */
  154. BOOL PUBLIC AbortEvt_Create(
  155.     PABORTEVT * ppabortevt,
  156.     UINT uFlags)
  157.     {
  158.     PABORTEVT this;
  159.     ASSERT(ppabortevt);
  160.     if (IsFlagSet(uFlags, AEF_SHARED))
  161.         this = SharedAllocType(ABORTEVT);
  162.     else
  163.         this = GAllocType(ABORTEVT);
  164.     if (this)
  165.         {
  166.         this->uFlags = uFlags;
  167.         }
  168.     *ppabortevt = this;
  169.     return NULL != this;
  170.     }
  171. /*----------------------------------------------------------
  172. Purpose: Destroys an abort event.
  173. Returns: --
  174. Cond:    --
  175. */
  176. void PUBLIC AbortEvt_Free(
  177.     PABORTEVT this)
  178.     {
  179.     if (this)
  180.         {
  181.         if (IsFlagSet(this->uFlags, AEF_SHARED))
  182.             SharedFree(&this);
  183.         else
  184.             GFree(this);
  185.         }
  186.     }
  187. /*----------------------------------------------------------
  188. Purpose: Sets the abort event.
  189. Returns: Returns the previous abort event.
  190. Cond:    --
  191. */
  192. BOOL PUBLIC AbortEvt_Set(
  193.     PABORTEVT this,
  194.     BOOL bAbort)
  195.     {
  196.     BOOL bRet;
  197.     if (this)
  198.         {
  199.         bRet = IsFlagSet(this->uFlags, AEF_ABORT);
  200.         if (bAbort)
  201.             {
  202.             TRACE_MSG(TF_GENERAL, TEXT("Setting abort event"));
  203.             SetFlag(this->uFlags, AEF_ABORT);
  204.             }
  205.         else
  206.             {
  207.             TRACE_MSG(TF_GENERAL, TEXT("Clearing abort event"));
  208.             ClearFlag(this->uFlags, AEF_ABORT);
  209.             }
  210.         }
  211.     else
  212.         bRet = FALSE;
  213.     return bRet;
  214.     }
  215. /*----------------------------------------------------------
  216. Purpose: Queries the abort event
  217. Returns: the current abort event (TRUE or FALSE)
  218. Cond:    --
  219. */
  220. BOOL PUBLIC AbortEvt_Query(
  221.     PABORTEVT this)
  222.     {
  223.     BOOL bRet;
  224.     if (this)
  225.         {
  226.         bRet = IsFlagSet(this->uFlags, AEF_ABORT);
  227. #ifdef DEBUG
  228.         if (bRet)
  229.             TRACE_MSG(TF_GENERAL, TEXT("Abort is set!"));
  230. #endif
  231.         }
  232.     else
  233.         bRet = FALSE;
  234.     return bRet;
  235.     }
  236. //---------------------------------------------------------------------------
  237. // Progress bar stuff
  238. //---------------------------------------------------------------------------
  239. #define MSECS_PER_SEC   1000
  240. #define WM_QUERYABORT   (WM_APP + 1)
  241. /*----------------------------------------------------------
  242. Purpose: Progress dialog during reconciliations
  243. Returns: varies
  244. Cond:    --
  245. */
  246. INT_PTR CALLBACK UpdateProgressProc(
  247.     HWND hDlg,
  248.     UINT wMsg,
  249.     WPARAM wParam,
  250.     LPARAM lParam)
  251.     {
  252.     PUPDBAR this = (PUPDBAR)GetWindowLongPtr(hDlg, DWLP_USER);
  253.     switch (wMsg)
  254.         {
  255.     case WM_INITDIALOG:
  256.         SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  257.         this = (PUPDBAR)lParam;
  258.         if (IsFlagSet(this->uFlags, UB_NOCANCEL))
  259.             {
  260.             ShowWindow(GetDlgItem(hDlg, IDCANCEL), SW_HIDE);
  261.             EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE);
  262.             }
  263.         break;
  264.     case WM_COMMAND:
  265.         switch (wParam)
  266.             {
  267.         case IDCANCEL:
  268.             AbortEvt_Set(this->pabortevt, TRUE);
  269.             break;
  270.             }
  271.         break;
  272.     case WM_QUERYABORT:
  273.         if (GetTickCount() >= this->dwTickShow &&
  274.             0 != this->dwTickShow)
  275.             {
  276.             if (this->hcurSav)
  277.                 {
  278.                 SetCursor(this->hcurSav);
  279.                 this->hcurSav = NULL;
  280.                 }
  281.             ShowWindow(hDlg, SW_SHOW);
  282.             UpdateWindow(hDlg);
  283.             this->dwTickShow = 0;
  284.             }
  285.         break;
  286.     default:
  287.         return FALSE;
  288.         }
  289.     return TRUE;
  290.     }
  291. /*----------------------------------------------------------
  292. Purpose: Displays the update progress bar dialog
  293. Returns: dialog handle to a modeless dialog
  294.          NULL if dialog couldn't be created
  295. Cond:    Call UpdBar_Kill when finished
  296. */
  297. HWND PUBLIC UpdBar_Show(
  298.     HWND hwndParent,
  299.     UINT uFlags,        // UB_*
  300.     UINT nSecs)         // Valid only if UB_TIMER set
  301.     {
  302.     HWND hdlg = NULL;
  303.     PUPDBAR this;
  304.     // Create and show the progress dialog
  305.     //
  306.     this = GAlloc(sizeof(*this));
  307.     if (this)
  308.         {
  309.         // (It is okay if this fails--it just means we ignore the Cancel button)
  310.         AbortEvt_Create(&this->pabortevt, AEF_DEFAULT);
  311.         this->hwndParent = hwndParent;
  312.         this->uFlags = uFlags;
  313.         hdlg = CreateDialogParam(g_hinst, MAKEINTRESOURCE(IDD_PROGRESS),
  314.             hwndParent, UpdateProgressProc, (LPARAM)(PUPDBAR)this);
  315.         if (!hdlg)
  316.             {
  317.             GFree(this);
  318.             }
  319.         else
  320.             {
  321.             UpdBar_SetAvi(hdlg, uFlags);
  322.             if (IsFlagClear(uFlags, UB_NOSHOW))
  323.                 EnableWindow(hwndParent, FALSE);
  324.             if (IsFlagSet(uFlags, UB_TIMER))
  325.                 {
  326.                 this->dwTickShow = GetTickCount() + (nSecs * MSECS_PER_SEC);
  327.                 this->hcurSav = SetCursorRemoveWigglies(LoadCursor(NULL, IDC_WAIT));
  328.                 }
  329.             else
  330.                 {
  331.                 this->dwTickShow = 0;
  332.                 this->hcurSav = NULL;
  333.                 if (IsFlagClear(uFlags, UB_NOSHOW))
  334.                     {
  335.                     ShowWindow(hdlg, SW_SHOW);
  336.                     UpdateWindow(hdlg);
  337.                     }
  338.                 }
  339.             }
  340.         }
  341.     return hdlg;
  342.     }
  343. /*----------------------------------------------------------
  344. Purpose: Destroy the update progress bar
  345. Returns: --
  346. Cond:    --
  347. */
  348. void PUBLIC UpdBar_Kill(
  349.     HWND hdlg)
  350.     {
  351.     ASSERT(IsWindow(hdlg));
  352.     if (IsWindow(hdlg))
  353.         {
  354.         PUPDBAR this = (PUPDBAR)GetWindowLongPtr(hdlg, DWLP_USER);
  355.         ASSERT(this);
  356.         if (this)
  357.             {
  358.             if (this->hcurSav)
  359.                 SetCursor(this->hcurSav);
  360.             if (IsWindow(this->hwndParent))
  361.                 EnableWindow(this->hwndParent, TRUE);
  362.             GFree(this);
  363.             }
  364.         DestroyWindow(hdlg);
  365.         }
  366.     }
  367. /*----------------------------------------------------------
  368. Purpose: Set the progress bar range.  Reset the position to 0
  369. Returns: --
  370. Cond:    --
  371. */
  372. void PUBLIC UpdBar_SetRange(
  373.     HWND hdlg,
  374.     WORD wRangeMax)
  375.     {
  376.     ASSERT(IsWindow(hdlg));
  377.     if (IsWindow(hdlg))
  378.         {
  379.         SendDlgItemMessage(hdlg, IDC_PROGRESS, PBM_SETPOS, 0, 0);
  380.         SendDlgItemMessage(hdlg, IDC_PROGRESS, PBM_SETRANGE, 0, MAKELONG(0, wRangeMax));
  381.         }
  382.     }
  383. /*----------------------------------------------------------
  384. Purpose: Increment the position of progress bar
  385. Returns: --
  386. Cond:    --
  387. */
  388. void PUBLIC UpdBar_DeltaPos(
  389.     HWND hdlg,
  390.     WORD wdelta)
  391.     {
  392.     ASSERT(IsWindow(hdlg));
  393.     if (IsWindow(hdlg))
  394.         {
  395.         SendDlgItemMessage(hdlg, IDC_PROGRESS, PBM_DELTAPOS, wdelta, 0);
  396.         }
  397.     }
  398. /*----------------------------------------------------------
  399. Purpose: Set the position of progress bar
  400. Returns: --
  401. Cond:    --
  402. */
  403. void PUBLIC UpdBar_SetPos(
  404.     HWND hdlg,
  405.     WORD wPos)
  406.     {
  407.     ASSERT(IsWindow(hdlg));
  408.     if (IsWindow(hdlg))
  409.         {
  410.         SendDlgItemMessage(hdlg, IDC_PROGRESS, PBM_SETPOS, wPos, 0);
  411.         }
  412.     }
  413. /*----------------------------------------------------------
  414. Purpose: Set the current name we're updating in the progress
  415.          bar.
  416. Returns: --
  417. Cond:    --
  418. */
  419. void PUBLIC UpdBar_SetName(
  420.     HWND hdlg,
  421.     LPCTSTR pszName)
  422.     {
  423.     ASSERT(IsWindow(hdlg));
  424.     if (IsWindow(hdlg))
  425.         {
  426.         HWND hwndName = GetDlgItem(hdlg, IDC_NAME);
  427.         Static_SetText(hwndName, pszName);
  428.         }
  429.     }
  430. /*----------------------------------------------------------
  431. Purpose: Set the current name we're updating in the progress
  432.          bar.
  433. Returns: --
  434. Cond:    --
  435. */
  436. void PUBLIC UpdBar_SetDescription(
  437.     HWND hdlg,
  438.     LPCTSTR psz)
  439.     {
  440.     ASSERT(IsWindow(hdlg));
  441.     if (IsWindow(hdlg))
  442.         {
  443.         HWND hwndName = GetDlgItem(hdlg, IDC_TONAME);
  444.         Static_SetText(hwndName, psz);
  445.         }
  446.     }
  447. /*----------------------------------------------------------
  448. Purpose: Get the window handle of the progress status text.
  449. Returns: --
  450. Cond:    --
  451. */
  452. HWND PUBLIC UpdBar_GetStatusWindow(
  453.     HWND hdlg)
  454.     {
  455.     HWND hwnd;
  456.     ASSERT(IsWindow(hdlg));
  457.     if (IsWindow(hdlg))
  458.         hwnd = GetDlgItem(hdlg, IDC_TEXT);
  459.     else
  460.         hwnd = NULL;
  461.     return hwnd;
  462.     }
  463. /*----------------------------------------------------------
  464. Purpose: Returns a pointer to the abort event owned by this
  465.          progress window.
  466. Returns: pointer to abort event or NULL
  467. Cond:    --
  468. */
  469. PABORTEVT PUBLIC UpdBar_GetAbortEvt(
  470.     HWND hdlg)
  471.     {
  472.     PABORTEVT pabortevt = NULL;
  473.     ASSERT(IsWindow(hdlg));
  474.     if (IsWindow(hdlg))
  475.         {
  476.         PUPDBAR this;
  477.         this = (PUPDBAR)GetWindowLongPtr(hdlg, DWLP_USER);
  478.         if (this)
  479.             {
  480.             pabortevt = this->pabortevt;
  481.             }
  482.         }
  483.     return pabortevt;
  484.     }
  485. /*----------------------------------------------------------
  486. Purpose: Sets the animate control to play the avi file designated
  487.          by the UB_ flags
  488. Returns: --
  489. Cond:    --
  490. */
  491. void PUBLIC UpdBar_SetAvi(
  492.     HWND hdlg,
  493.     UINT uFlags)    // UB_*
  494.     {
  495.     ASSERT(IsWindow(hdlg));
  496.     if (IsWindow(hdlg))
  497.         {
  498.         UINT ida;
  499.         UINT ids;
  500.         HWND hwndAvi = GetDlgItem(hdlg, IDC_ANIMATE);
  501.         TCHAR sz[MAXBUFLEN];
  502.         RECT rc;
  503.         if (IsFlagClear(uFlags, UB_NOSHOW))
  504.             {
  505.             SetWindowRedraw(hdlg, FALSE);
  506.             // Is the window visible yet?
  507.             if (IsFlagSet(GetWindowLong(hdlg, GWL_STYLE), WS_VISIBLE))
  508.                 {
  509.                 // Yes; select just the upper area of the progress bar to
  510.                 // repaint
  511.                 int cy;
  512.                 GetWindowRect(GetDlgItem(hdlg, IDC_NAME), &rc);
  513.                 MapWindowPoints(HWND_DESKTOP, hdlg, (LPPOINT)&rc, 1);
  514.                 cy = rc.top;
  515.                 GetClientRect(hdlg, &rc);
  516.                 rc.bottom = cy;
  517.                 }
  518.             else
  519.                 {
  520.                 // No
  521.                 GetWindowRect(hdlg, &rc);
  522.                 MapWindowPoints(HWND_DESKTOP, hdlg, (LPPOINT)&rc, 2);
  523.                 }
  524.             }
  525.         if (IsFlagSet(uFlags, UB_NOPROGRESS))
  526.             {
  527.             ShowWindow(GetDlgItem(hdlg, IDC_PROGRESS), SW_HIDE);
  528.             }
  529.         else
  530.             {
  531.             ShowWindow(GetDlgItem(hdlg, IDC_PROGRESS), SW_SHOW);
  532.             }
  533.         // Special text when checking?
  534.         if (IsFlagSet(uFlags, UB_CHECKAVI))
  535.             {
  536.             // Yes
  537.             SetDlgItemText(hdlg, IDC_TONAME, SzFromIDS(IDS_MSG_CHECKING, sz, ARRAYSIZE(sz)));
  538.             }
  539.         else
  540.             {
  541.             // No
  542.             SetDlgItemText(hdlg, IDC_TONAME, TEXT(""));
  543.             }
  544.         // Run AVI?
  545.         if (uFlags & (UB_CHECKAVI | UB_UPDATEAVI))
  546.             {
  547.             // Yes
  548. #pragma data_seg(DATASEG_READONLY)
  549.             static const SNAPCTL rgsnap[] = {
  550.                 { IDC_ICON1, SCF_BOTTOM | SCF_SNAPLEFT },
  551.                 { IDC_ANIMATE, SCF_ANCHOR },
  552.                 { IDC_ICON2, SCF_BOTTOM | SCF_SNAPRIGHT },
  553.                 };
  554. #pragma data_seg()
  555.             if (IsFlagSet(uFlags, UB_CHECKAVI))
  556.                 {
  557.                 ida = IDA_CHECK;
  558.                 ids = IDS_CAP_CHECKING;
  559.                 }
  560.             else if (IsFlagSet(uFlags, UB_UPDATEAVI))
  561.                 {
  562.                 ida = IDA_UPDATE;
  563.                 ids = IDS_CAP_UPDATING;
  564.                 }
  565.             else
  566.                 ASSERT(0);
  567.             SetWindowText(hdlg, SzFromIDS(ids, sz, ARRAYSIZE(sz)));
  568.             Animate_Open(hwndAvi, MAKEINTRESOURCE(ida));
  569.             // Snap the icons on either side to the animation
  570.             // control
  571.             SnapControls(hdlg, rgsnap, ARRAYSIZE(rgsnap));
  572.             Animate_Play(hwndAvi, 0, -1, -1);
  573.             }
  574.         // Don't bother setting the redraw if we're never going to show
  575.         // the progress bar
  576.         if (IsFlagClear(uFlags, UB_NOSHOW))
  577.             {
  578.             SetWindowRedraw(hdlg, TRUE);
  579.             InvalidateRect(hdlg, &rc, TRUE);
  580.             UpdateWindow(hdlg);
  581.             }
  582.         }
  583.     }
  584. /*----------------------------------------------------------
  585. Purpose: Yield, and check if user aborted
  586. Returns: TRUE to abort
  587.          FALSE to continue
  588. Cond:    --
  589. */
  590. BOOL PUBLIC UpdBar_QueryAbort(
  591.     HWND hdlg)
  592.     {
  593.     BOOL bAbort = FALSE;
  594.     ASSERT(IsWindow(hdlg));
  595.     if (IsWindow(hdlg))
  596.         {
  597.         MSG msg;
  598.         PUPDBAR this;
  599.         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  600.             {
  601.             TranslateMessage(&msg);
  602.             DispatchMessage(&msg);
  603.             }
  604.         /*
  605.          * Don't use SendMessage() here to ask hdlg if reconciliation has been
  606.          * aborted.  hdlg has typically been created in a different thread.
  607.          * hdlg's creator thread may already be blocked in the sync engine.  We
  608.          * must avoid inter-thread SendMessage() to avoid a deadlock on the
  609.          * sync engine's briefcase critical section.  The sync engine is not
  610.          * reentrant.
  611.          */
  612.         PostMessage(hdlg, WM_QUERYABORT, 0, 0);
  613.         this = (PUPDBAR)GetWindowLongPtr(hdlg, DWLP_USER);
  614.         if (this)
  615.             {
  616.             bAbort = AbortEvt_Query(this->pabortevt);
  617.             }
  618.         }
  619.     return bAbort;
  620.     }
  621. //---------------------------------------------------------------------------
  622. // Confirm Replace dialog
  623. //---------------------------------------------------------------------------
  624. // This is the private data structure for the dialog
  625. typedef struct
  626.     {
  627.     UINT uFlags;        // CRF_*
  628.     TCHAR szDesc[MAXBUFLEN+MAXPATHLEN];
  629.     TCHAR szInfoExisting[MAXMEDLEN];
  630.     TCHAR szInfoOther[MAXMEDLEN];
  631.     HICON hicon;
  632.     } CONFIRMREPLACE;
  633. /*----------------------------------------------------------
  634. Purpose: Confirm replace dialog
  635. Returns: varies
  636. Cond:    --
  637. */
  638. INT_PTR CALLBACK ConfirmReplace_Proc(
  639.     HWND hDlg,
  640.     UINT wMsg,
  641.     WPARAM wParam,
  642.     LPARAM lParam)
  643.     {
  644.     switch (wMsg)
  645.         {
  646.     case WM_INITDIALOG:
  647.         {
  648.         CONFIRMREPLACE * pcr = (CONFIRMREPLACE *)lParam;
  649.         UINT i;
  650.         UINT cButtons;
  651.         MB_BUTTONS const * pmbb;
  652. #pragma data_seg(DATASEG_READONLY)
  653.         static UINT const rgidc[4] = { IDC_BUTTON1, IDC_BUTTON2, IDC_BUTTON3, IDC_BUTTON4 };
  654.         static BTNSTYLE const btnstyleSingle =
  655.                 // (List buttons backwards)
  656.                 { 2, { { IDNO,  IDS_NO },
  657.                        { IDYES, IDS_YES },
  658.                      } };
  659.         static BTNSTYLE const btnstyleMulti =
  660.                 // (List buttons backwards)
  661.                 { 4, { { IDCANCEL,      IDS_CANCEL },
  662.                        { IDNO,          IDS_NO },
  663.                        { IDC_YESTOALL,  IDS_YESTOALL },
  664.                        { IDYES,         IDS_YES },
  665.                      } };
  666. #pragma data_seg()
  667.         Static_SetText(GetDlgItem(hDlg, IDC_DESC), pcr->szDesc);
  668.         if (IsFlagClear(pcr->uFlags, CRF_FOLDER))
  669.             {
  670.             Static_SetText(GetDlgItem(hDlg, IDC_EXISTING), pcr->szInfoExisting);
  671.             Static_SetText(GetDlgItem(hDlg, IDC_OTHER), pcr->szInfoOther);
  672.             Static_SetIcon(GetDlgItem(hDlg, IDC_ICON_EXISTING), pcr->hicon);
  673.             Static_SetIcon(GetDlgItem(hDlg, IDC_ICON_OTHER), pcr->hicon);
  674.             }
  675.         // Set the IDs and strings of used buttons
  676.         if (IsFlagSet(pcr->uFlags, CRF_MULTI))
  677.             {
  678.             cButtons = btnstyleMulti.cButtons;
  679.             pmbb = btnstyleMulti.rgmbb;
  680.             }
  681.         else
  682.             {
  683.             cButtons = btnstyleSingle.cButtons;
  684.             pmbb = btnstyleSingle.rgmbb;
  685.             }
  686.         for (i = 0; i < cButtons; i++)
  687.             {
  688.             TCHAR sz[MAXMEDLEN];
  689.             HWND hwnd = GetDlgItem(hDlg, rgidc[i]);
  690.             LoadString(g_hinst, pmbb[i].ids, sz, ARRAYSIZE(sz));
  691.             SetWindowLongPtr(hwnd, GWLP_ID, pmbb[i].id);
  692.             SetWindowText(hwnd, sz);
  693.             }
  694.         // Disable unused buttons
  695.         for (; i < ARRAYSIZE(rgidc); i++)
  696.             {
  697.             HWND hwnd = GetDlgItem(hDlg, rgidc[i]);
  698.             EnableWindow(hwnd, FALSE);
  699.             ShowWindow(hwnd, SW_HIDE);
  700.             }
  701.         }
  702.         break;
  703.     case WM_COMMAND:
  704.         switch (wParam)
  705.             {
  706.         case IDCANCEL:
  707.         case IDYES:
  708.         case IDC_YESTOALL:
  709.         case IDNO:
  710.             EndDialog(hDlg, wParam);
  711.             break;
  712.             }
  713.         break;
  714.     default:
  715.         return FALSE;
  716.         }
  717.     return TRUE;
  718.     }
  719. /*----------------------------------------------------------
  720. Purpose: Brings up the replace confirmation dialog.
  721. Returns: IDYES, IDC_YESTOALL, IDNO or IDCANCEL
  722. Cond:    --
  723. */
  724. int PUBLIC ConfirmReplace_DoModal(
  725.     HWND hwndOwner,
  726.     LPCTSTR pszPathExisting,
  727.     LPCTSTR pszPathOther,
  728.     UINT uFlags)                // CRF_*
  729.     {
  730.     INT_PTR idRet;
  731.     CONFIRMREPLACE * pcr;
  732.     pcr = GAlloc(sizeof(*pcr));
  733.     if (pcr)
  734.         {
  735.         LPTSTR pszMsg;
  736.         DWORD dwAttrs = GetFileAttributes(pszPathExisting);
  737.         pcr->uFlags = uFlags;
  738.         // Is this replacing a folder?
  739.         if (IsFlagSet(dwAttrs, FILE_ATTRIBUTE_DIRECTORY))
  740.             {
  741.             // Yes
  742.             if (ConstructMessage(&pszMsg, g_hinst, MAKEINTRESOURCE(IDS_MSG_ConfirmFolderReplace),
  743.                 PathFindFileName(pszPathOther)))
  744.                 {
  745.                 lstrcpy(pcr->szDesc, pszMsg);
  746.                 GFree(pszMsg);
  747.                 }
  748.             else
  749.                 *pcr->szDesc = 0;
  750.             SetFlag(pcr->uFlags, CRF_FOLDER);
  751.             idRet = DoModal(hwndOwner, ConfirmReplace_Proc, IDD_REPLACE_FOLDER, (LPARAM)pcr);
  752.             }
  753.         else
  754.             {
  755.             // No
  756.             UINT ids;
  757.             FileInfo * pfi;
  758.             if (SUCCEEDED(FICreate(pszPathExisting, &pfi, FIF_ICON)))
  759.                 {
  760.                 pcr->hicon = pfi->hicon;
  761.                 FIGetInfoString(pfi, pcr->szInfoExisting, ARRAYSIZE(pcr->szInfoExisting));
  762.                 pfi->hicon = NULL;      // (keep icon around)
  763.                 FIFree(pfi);
  764.                 }
  765.             if (SUCCEEDED(FICreate(pszPathOther, &pfi, FIF_DEFAULT)))
  766.                 {
  767.                 FIGetInfoString(pfi, pcr->szInfoOther, ARRAYSIZE(pcr->szInfoOther));
  768.                 FIFree(pfi);
  769.                 }
  770.             if (IsFlagSet(dwAttrs, FILE_ATTRIBUTE_READONLY))
  771.                 {
  772.                 ids = IDS_MSG_ConfirmFileReplace_RO;
  773.                 }
  774.             else if (IsFlagSet(dwAttrs, FILE_ATTRIBUTE_SYSTEM))
  775.                 {
  776.                 ids = IDS_MSG_ConfirmFileReplace_Sys;
  777.                 }
  778.             else
  779.                 {
  780.                 ids = IDS_MSG_ConfirmFileReplace;
  781.                 }
  782.             if (ConstructMessage(&pszMsg, g_hinst, MAKEINTRESOURCE(ids),
  783.                 PathFindFileName(pszPathOther)))
  784.                 {
  785.                 lstrcpy(pcr->szDesc, pszMsg);
  786.                 GFree(pszMsg);
  787.                 }
  788.             else
  789.                 *pcr->szDesc = 0;
  790.             ClearFlag(pcr->uFlags, CRF_FOLDER);
  791.             idRet = DoModal(hwndOwner, ConfirmReplace_Proc, IDD_REPLACE_FILE, (LPARAM)pcr);
  792.             if (pcr->hicon)
  793.                 DestroyIcon(pcr->hicon);
  794.             }
  795.         GFree(pcr);
  796.         }
  797.     else
  798.         {
  799.         idRet = -1;     // Out of memory
  800.         }
  801.     return (int)idRet;
  802.     }
  803. //---------------------------------------------------------------------------
  804. // Introduction dialog
  805. //---------------------------------------------------------------------------
  806. /*----------------------------------------------------------
  807. Purpose: Intro dialog
  808. Returns: varies
  809. Cond:    --
  810. */
  811. INT_PTR CALLBACK Intro_Proc(
  812.     HWND hDlg,
  813.     UINT wMsg,
  814.     WPARAM wParam,
  815.     LPARAM lParam)
  816.     {
  817.     NMHDR  *lpnm;
  818.     switch (wMsg)
  819.         {
  820.     case WM_INITDIALOG:
  821.         break;
  822.     case WM_NOTIFY:
  823.         lpnm = (NMHDR  *)lParam;
  824.         switch(lpnm->code)
  825.             {
  826.         case PSN_SETACTIVE: {
  827.             // Only allow the Finish button.  The user cannot go back and
  828.             // change the settings.
  829.             HWND hwndCancel = GetDlgItem(GetParent(hDlg), IDCANCEL);
  830.             PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_FINISH);
  831.             // Hide cancel button
  832.             EnableWindow(hwndCancel, FALSE);
  833.             ShowWindow(hwndCancel, SW_HIDE);
  834.             }
  835.             break;
  836.         case PSN_KILLACTIVE:
  837.         case PSN_HELP:
  838.         case PSN_WIZBACK:
  839.         case PSN_WIZNEXT:
  840.             break;
  841.         default:
  842.             return FALSE;
  843.             }
  844.         break;
  845.     default:
  846.         return FALSE;
  847.         }
  848.     return TRUE;
  849.     }
  850. /*----------------------------------------------------------
  851. Purpose: Invoke the introduction wizard.
  852. Returns: ID of button that terminated dialog
  853. Cond:    --
  854. */
  855. int PUBLIC Intro_DoModal(
  856.     HWND hwndParent)
  857.     {
  858.     PROPSHEETPAGE psp = {
  859.         sizeof(psp),
  860.         PSP_DEFAULT | PSP_HIDEHEADER,
  861.         g_hinst,
  862.         MAKEINTRESOURCE(IDD_INTRO_WIZARD),
  863.         NULL,           // hicon
  864.         NULL,           // caption
  865.         Intro_Proc,
  866.         0,              // lParam
  867.         NULL,           // pfnCallback
  868.         NULL            // pointer to ref count
  869.         };
  870.     PROPSHEETHEADER psh = {
  871.         sizeof(psh),
  872.         PSH_WIZARD_LITE | PSH_WIZARD | PSH_PROPSHEETPAGE,     // (use ppsp field)
  873.         hwndParent,
  874.         g_hinst,
  875.         0,              // hicon
  876.         0,              // caption
  877.         1,              // number of pages
  878.         0,              // start page
  879.         &psp
  880.         };
  881.     return (int)PropertySheet(&psh);
  882.     }
  883. //---------------------------------------------------------------------------
  884. // MsgBox dialog
  885. //---------------------------------------------------------------------------
  886. typedef struct _MSGBOX
  887.     {
  888.     LPCTSTR pszText;
  889.     LPCTSTR pszCaption;
  890.     HICON  hicon;
  891.     UINT   uStyle;
  892.     } MSGBOX, * PMSGBOX;
  893. /*----------------------------------------------------------
  894. Purpose: Determines whether to resize the dialog and reposition
  895.          the buttons to fit the text.
  896.          The dialog is not resized any smaller than its initial
  897.          size.
  898.          The dialog is only resized vertically.
  899. Returns: --
  900. Cond:    --
  901. */
  902. void PRIVATE MsgBox_Resize(
  903.     HWND hDlg,
  904.     LPCTSTR pszText,
  905.     UINT cchText)
  906.     {
  907.     HDC hdc;
  908.     HWND hwndText = GetDlgItem(hDlg, IDC_TEXT);
  909.     hdc = GetDC(hwndText);
  910.     if (hdc)
  911.         {
  912.         HFONT hfont = GetStockObject(DEFAULT_GUI_FONT);
  913.         HFONT hfontSav = SelectFont(hdc, hfont);
  914.         RECT rc;
  915.         RECT rcOrg;
  916.         // Determine new dimensions
  917.         GetClientRect(hwndText, &rcOrg);
  918.         rc = rcOrg;
  919.         DrawTextEx(hdc, (LPTSTR)pszText, cchText, &rc, DT_CALCRECT | DT_WORDBREAK | DT_LEFT, NULL);
  920.         SelectFont(hdc, hfontSav);
  921.         ReleaseDC(hwndText, hdc);
  922.         // Is the required size bigger?
  923.         if (rc.bottom > rcOrg.bottom)
  924.             {
  925.             // Yes; resize the windows
  926.             int cy = rc.bottom - rcOrg.bottom;
  927.             int cyFudge = GetSystemMetrics(SM_CYCAPTION) + 2*GetSystemMetrics(SM_CYFIXEDFRAME);
  928.             int cxFudge = 2*GetSystemMetrics(SM_CXFIXEDFRAME);
  929.             HDWP hdwp = BeginDeferWindowPos(4);
  930.             if (hdwp)
  931.                 {
  932.                 // Move Buttons
  933.                 hdwp = SlideControlPos(hdwp, hDlg, IDC_BUTTON1, 0, cy);
  934.                 hdwp = SlideControlPos(hdwp, hDlg, IDC_BUTTON2, 0, cy);
  935.                 hdwp = SlideControlPos(hdwp, hDlg, IDC_BUTTON3, 0, cy);
  936.                 // Resize Static Text
  937.                 hdwp = DeferWindowPos(hdwp, hwndText, GetDlgItem(hDlg, IDC_BUTTON3),
  938.                                       0, 0,
  939.                                       rc.right-rc.left, rc.bottom-rc.top,
  940.                                       SWP_NOACTIVATE | SWP_NOMOVE);
  941.                 EndDeferWindowPos(hdwp);
  942.                 }
  943.             // Resize Dialog
  944.             GetClientRect(hDlg, &rc);
  945.             SetWindowPos(hDlg, NULL, 0, 0,
  946.                          rc.right-rc.left + cxFudge, rc.bottom-rc.top + cy + cyFudge,
  947.                          SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
  948.             }
  949.         }
  950.     }
  951. /*----------------------------------------------------------
  952. Purpose: MsgBox dialog
  953. Returns: varies
  954. Cond:    --
  955. */
  956. INT_PTR CALLBACK MsgBox_Proc(
  957.     HWND hDlg,
  958.     UINT wMsg,
  959.     WPARAM wParam,
  960.     LPARAM lParam)
  961.     {
  962.     switch (wMsg)
  963.         {
  964.     case WM_INITDIALOG:
  965.         {
  966.         PMSGBOX pmsgbox = (PMSGBOX)lParam;
  967.         UINT uStyle = pmsgbox->uStyle;
  968.         UINT i;
  969.         UINT imb = uStyle & MB_TYPEMASK;
  970.         UINT cButtons;
  971.         MB_BUTTONS const * pmbb;
  972. #pragma data_seg(DATASEG_READONLY)
  973.         static UINT const rgidc[3] = { IDC_BUTTON1, IDC_BUTTON2, IDC_BUTTON3 };
  974.         static BTNSTYLE const rgmbstyle[] = {
  975.                 // (List buttons backwards)
  976.                 // MB_OK
  977.                 { 1, { { IDOK,      IDS_OK },
  978.                      } },
  979.                 // MB_OKCANCEL
  980.                 { 2, { { IDCANCEL,  IDS_CANCEL },
  981.                        { IDOK,      IDS_OK },
  982.                      } },
  983.                 // MB_ABORTRETRYIGNORE (not supported)
  984.                 { 1, { { IDOK,      IDS_OK },
  985.                      } },
  986.                 // MB_YESNOCANCEL
  987.                 { 3, { { IDCANCEL,  IDS_CANCEL },
  988.                        { IDNO,      IDS_NO },
  989.                        { IDYES,     IDS_YES },
  990.                      } },
  991.                 // MB_YESNO
  992.                 { 2, { { IDNO,      IDS_NO },
  993.                        { IDYES,     IDS_YES },
  994.                      } },
  995.                 // MB_RETRYCANCEL
  996.                 { 2, { { IDCANCEL,  IDS_CANCEL },
  997.                        { IDRETRY,   IDS_RETRY },
  998.                      } },
  999.                 };
  1000. #pragma data_seg()
  1001.         // Set the text
  1002.         if (pmsgbox->pszText)
  1003.             {
  1004.             Static_SetText(GetDlgItem(hDlg, IDC_TEXT), pmsgbox->pszText);
  1005.             // Resize and reposition the buttons if necessary
  1006.             MsgBox_Resize(hDlg, pmsgbox->pszText, lstrlen(pmsgbox->pszText));
  1007.             }
  1008.         if (pmsgbox->pszCaption)
  1009.             SetWindowText(hDlg, pmsgbox->pszCaption);
  1010.         // Use a custom icon?
  1011.         if (NULL == pmsgbox->hicon)
  1012.             {
  1013.             // No; use a system icon
  1014.             LPCTSTR pszIcon;
  1015.             if (IsFlagSet(uStyle, MB_ICONEXCLAMATION))
  1016.                 pszIcon = IDI_EXCLAMATION;
  1017.             else if (IsFlagSet(uStyle, MB_ICONHAND))
  1018.                 pszIcon = IDI_HAND;
  1019.             else if (IsFlagSet(uStyle, MB_ICONQUESTION))
  1020.                 pszIcon = IDI_QUESTION;
  1021.             else
  1022.                 pszIcon = IDI_ASTERISK;
  1023.             pmsgbox->hicon = LoadIcon(NULL, pszIcon);
  1024.             }
  1025.         Static_SetIcon(GetDlgItem(hDlg, IDC_MSGICON), pmsgbox->hicon);
  1026.         // Set the IDs and strings of used buttons
  1027.         cButtons = rgmbstyle[imb].cButtons;
  1028.         pmbb = rgmbstyle[imb].rgmbb;
  1029.         for (i = 0; i < cButtons; i++)
  1030.             {
  1031.             TCHAR sz[MAXMEDLEN];
  1032.             HWND hwnd = GetDlgItem(hDlg, rgidc[i]);
  1033.             LoadString(g_hinst, pmbb[i].ids, sz, ARRAYSIZE(sz));
  1034.             SetWindowLongPtr(hwnd, GWLP_ID, pmbb[i].id);
  1035.             SetWindowText(hwnd, sz);
  1036.             }
  1037.         // Disable unused buttons
  1038.         for (; i < ARRAYSIZE(rgidc); i++)
  1039.             {
  1040.             HWND hwnd = GetDlgItem(hDlg, rgidc[i]);
  1041.             EnableWindow(hwnd, FALSE);
  1042.             ShowWindow(hwnd, SW_HIDE);
  1043.             }
  1044.         }
  1045.         break;
  1046.     case WM_COMMAND:
  1047.         switch (wParam)
  1048.             {
  1049.         case IDOK:
  1050.         case IDCANCEL:
  1051.         case IDYES:
  1052.         case IDNO:
  1053.         case IDRETRY:
  1054.             EndDialog(hDlg, wParam);
  1055.             break;
  1056.             }
  1057.         break;
  1058.     default:
  1059.         return FALSE;
  1060.         }
  1061.     return TRUE;
  1062.     }
  1063. /*----------------------------------------------------------
  1064. Purpose: Invoke the introduction dialog.
  1065. Returns: ID of button that terminated dialog
  1066. Cond:    --
  1067. */
  1068. int PUBLIC MsgBox(
  1069.     HWND hwndParent,
  1070.     LPCTSTR pszText,
  1071.     LPCTSTR pszCaption,
  1072.     HICON hicon,            // May be NULL
  1073.     UINT uStyle, ...)
  1074.     {
  1075.     INT_PTR iRet = -1;
  1076.     int ids;
  1077.     TCHAR szCaption[MAXPATHLEN];
  1078.     LPTSTR pszRet;
  1079.     va_list ArgList;
  1080.     va_start(ArgList, uStyle);
  1081.     pszRet = _ConstructMessageString(g_hinst, pszText, &ArgList);
  1082.     va_end(ArgList);
  1083.     if (pszRet)
  1084.         {
  1085.         // Is pszCaption a resource ID?
  1086.         if (0 == HIWORD(pszCaption))
  1087.             {
  1088.             // Yes; load it
  1089.             ids = LOWORD(pszCaption);
  1090.             SzFromIDS(ids, szCaption, ARRAYSIZE(szCaption));
  1091.             pszCaption = szCaption;
  1092.             }
  1093.         // Invoke dialog
  1094.         if (pszCaption)
  1095.             {
  1096.             MSGBOX msgbox = { pszRet, pszCaption, hicon, uStyle };
  1097.             iRet = DoModal(hwndParent, MsgBox_Proc, IDC_MSGBOX, (LPARAM)&msgbox);
  1098.             }
  1099.         LocalFree(pszRet);
  1100.         }
  1101.     return (int)iRet;
  1102.     }