Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1323 lines
35 KiB

  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. static const SNAPCTL rgsnap[] = {
  549. { IDC_ICON1, SCF_BOTTOM | SCF_SNAPLEFT },
  550. { IDC_ANIMATE, SCF_ANCHOR },
  551. { IDC_ICON2, SCF_BOTTOM | SCF_SNAPRIGHT },
  552. };
  553. if (IsFlagSet(uFlags, UB_CHECKAVI))
  554. {
  555. ida = IDA_CHECK;
  556. ids = IDS_CAP_CHECKING;
  557. }
  558. else if (IsFlagSet(uFlags, UB_UPDATEAVI))
  559. {
  560. ida = IDA_UPDATE;
  561. ids = IDS_CAP_UPDATING;
  562. }
  563. else
  564. ASSERT(0);
  565. SetWindowText(hdlg, SzFromIDS(ids, sz, ARRAYSIZE(sz)));
  566. Animate_Open(hwndAvi, MAKEINTRESOURCE(ida));
  567. // Snap the icons on either side to the animation
  568. // control
  569. SnapControls(hdlg, rgsnap, ARRAYSIZE(rgsnap));
  570. Animate_Play(hwndAvi, 0, -1, -1);
  571. }
  572. // Don't bother setting the redraw if we're never going to show
  573. // the progress bar
  574. if (IsFlagClear(uFlags, UB_NOSHOW))
  575. {
  576. SetWindowRedraw(hdlg, TRUE);
  577. InvalidateRect(hdlg, &rc, TRUE);
  578. UpdateWindow(hdlg);
  579. }
  580. }
  581. }
  582. /*----------------------------------------------------------
  583. Purpose: Yield, and check if user aborted
  584. Returns: TRUE to abort
  585. FALSE to continue
  586. Cond: --
  587. */
  588. BOOL PUBLIC UpdBar_QueryAbort(
  589. HWND hdlg)
  590. {
  591. BOOL bAbort = FALSE;
  592. ASSERT(IsWindow(hdlg));
  593. if (IsWindow(hdlg))
  594. {
  595. MSG msg;
  596. PUPDBAR this;
  597. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  598. {
  599. TranslateMessage(&msg);
  600. DispatchMessage(&msg);
  601. }
  602. /*
  603. * Don't use SendMessage() here to ask hdlg if reconciliation has been
  604. * aborted. hdlg has typically been created in a different thread.
  605. * hdlg's creator thread may already be blocked in the sync engine. We
  606. * must avoid inter-thread SendMessage() to avoid a deadlock on the
  607. * sync engine's briefcase critical section. The sync engine is not
  608. * reentrant.
  609. */
  610. PostMessage(hdlg, WM_QUERYABORT, 0, 0);
  611. this = (PUPDBAR)GetWindowLongPtr(hdlg, DWLP_USER);
  612. if (this)
  613. {
  614. bAbort = AbortEvt_Query(this->pabortevt);
  615. }
  616. }
  617. return bAbort;
  618. }
  619. //---------------------------------------------------------------------------
  620. // Confirm Replace dialog
  621. //---------------------------------------------------------------------------
  622. // This is the private data structure for the dialog
  623. typedef struct
  624. {
  625. UINT uFlags; // CRF_*
  626. TCHAR szDesc[MAXBUFLEN+MAXPATHLEN];
  627. TCHAR szInfoExisting[MAXMEDLEN];
  628. TCHAR szInfoOther[MAXMEDLEN];
  629. HICON hicon;
  630. } CONFIRMREPLACE;
  631. /*----------------------------------------------------------
  632. Purpose: Confirm replace dialog
  633. Returns: varies
  634. Cond: --
  635. */
  636. INT_PTR CALLBACK ConfirmReplace_Proc(
  637. HWND hDlg,
  638. UINT wMsg,
  639. WPARAM wParam,
  640. LPARAM lParam)
  641. {
  642. switch (wMsg)
  643. {
  644. case WM_INITDIALOG:
  645. {
  646. CONFIRMREPLACE * pcr = (CONFIRMREPLACE *)lParam;
  647. UINT i;
  648. UINT cButtons;
  649. MB_BUTTONS const * pmbb;
  650. static UINT const rgidc[4] = { IDC_BUTTON1, IDC_BUTTON2, IDC_BUTTON3, IDC_BUTTON4 };
  651. static BTNSTYLE const btnstyleSingle =
  652. // (List buttons backwards)
  653. { 2, { { IDNO, IDS_NO },
  654. { IDYES, IDS_YES },
  655. } };
  656. static BTNSTYLE const btnstyleMulti =
  657. // (List buttons backwards)
  658. { 4, { { IDCANCEL, IDS_CANCEL },
  659. { IDNO, IDS_NO },
  660. { IDC_YESTOALL, IDS_YESTOALL },
  661. { IDYES, IDS_YES },
  662. } };
  663. Static_SetText(GetDlgItem(hDlg, IDC_DESC), pcr->szDesc);
  664. if (IsFlagClear(pcr->uFlags, CRF_FOLDER))
  665. {
  666. Static_SetText(GetDlgItem(hDlg, IDC_EXISTING), pcr->szInfoExisting);
  667. Static_SetText(GetDlgItem(hDlg, IDC_OTHER), pcr->szInfoOther);
  668. Static_SetIcon(GetDlgItem(hDlg, IDC_ICON_EXISTING), pcr->hicon);
  669. Static_SetIcon(GetDlgItem(hDlg, IDC_ICON_OTHER), pcr->hicon);
  670. }
  671. // Set the IDs and strings of used buttons
  672. if (IsFlagSet(pcr->uFlags, CRF_MULTI))
  673. {
  674. cButtons = btnstyleMulti.cButtons;
  675. pmbb = btnstyleMulti.rgmbb;
  676. }
  677. else
  678. {
  679. cButtons = btnstyleSingle.cButtons;
  680. pmbb = btnstyleSingle.rgmbb;
  681. }
  682. for (i = 0; i < cButtons; i++)
  683. {
  684. TCHAR sz[MAXMEDLEN];
  685. HWND hwnd = GetDlgItem(hDlg, rgidc[i]);
  686. LoadString(g_hinst, pmbb[i].ids, sz, ARRAYSIZE(sz));
  687. SetWindowLongPtr(hwnd, GWLP_ID, pmbb[i].id);
  688. SetWindowText(hwnd, sz);
  689. }
  690. // Disable unused buttons
  691. for (; i < ARRAYSIZE(rgidc); i++)
  692. {
  693. HWND hwnd = GetDlgItem(hDlg, rgidc[i]);
  694. EnableWindow(hwnd, FALSE);
  695. ShowWindow(hwnd, SW_HIDE);
  696. }
  697. }
  698. break;
  699. case WM_COMMAND:
  700. switch (wParam)
  701. {
  702. case IDCANCEL:
  703. case IDYES:
  704. case IDC_YESTOALL:
  705. case IDNO:
  706. EndDialog(hDlg, wParam);
  707. break;
  708. }
  709. break;
  710. default:
  711. return FALSE;
  712. }
  713. return TRUE;
  714. }
  715. /*----------------------------------------------------------
  716. Purpose: Brings up the replace confirmation dialog.
  717. Returns: IDYES, IDC_YESTOALL, IDNO or IDCANCEL
  718. Cond: --
  719. */
  720. int PUBLIC ConfirmReplace_DoModal(
  721. HWND hwndOwner,
  722. LPCTSTR pszPathExisting,
  723. LPCTSTR pszPathOther,
  724. UINT uFlags) // CRF_*
  725. {
  726. INT_PTR idRet;
  727. CONFIRMREPLACE * pcr;
  728. pcr = GAlloc(sizeof(*pcr));
  729. if (pcr)
  730. {
  731. LPTSTR pszMsg;
  732. DWORD dwAttrs = GetFileAttributes(pszPathExisting);
  733. pcr->uFlags = uFlags;
  734. // Is this replacing a folder?
  735. if (IsFlagSet(dwAttrs, FILE_ATTRIBUTE_DIRECTORY))
  736. {
  737. // Yes
  738. if (ConstructMessage(&pszMsg, g_hinst, MAKEINTRESOURCE(IDS_MSG_ConfirmFolderReplace),
  739. PathFindFileName(pszPathOther)))
  740. {
  741. lstrcpy(pcr->szDesc, pszMsg);
  742. GFree(pszMsg);
  743. }
  744. else
  745. *pcr->szDesc = 0;
  746. SetFlag(pcr->uFlags, CRF_FOLDER);
  747. idRet = DoModal(hwndOwner, ConfirmReplace_Proc, IDD_REPLACE_FOLDER, (LPARAM)pcr);
  748. }
  749. else
  750. {
  751. // No
  752. UINT ids;
  753. FileInfo * pfi;
  754. if (SUCCEEDED(FICreate(pszPathExisting, &pfi, FIF_ICON)))
  755. {
  756. pcr->hicon = pfi->hicon;
  757. FIGetInfoString(pfi, pcr->szInfoExisting, ARRAYSIZE(pcr->szInfoExisting));
  758. pfi->hicon = NULL; // (keep icon around)
  759. FIFree(pfi);
  760. }
  761. if (SUCCEEDED(FICreate(pszPathOther, &pfi, FIF_DEFAULT)))
  762. {
  763. FIGetInfoString(pfi, pcr->szInfoOther, ARRAYSIZE(pcr->szInfoOther));
  764. FIFree(pfi);
  765. }
  766. if (IsFlagSet(dwAttrs, FILE_ATTRIBUTE_READONLY))
  767. {
  768. ids = IDS_MSG_ConfirmFileReplace_RO;
  769. }
  770. else if (IsFlagSet(dwAttrs, FILE_ATTRIBUTE_SYSTEM))
  771. {
  772. ids = IDS_MSG_ConfirmFileReplace_Sys;
  773. }
  774. else
  775. {
  776. ids = IDS_MSG_ConfirmFileReplace;
  777. }
  778. if (ConstructMessage(&pszMsg, g_hinst, MAKEINTRESOURCE(ids),
  779. PathFindFileName(pszPathOther)))
  780. {
  781. lstrcpy(pcr->szDesc, pszMsg);
  782. GFree(pszMsg);
  783. }
  784. else
  785. *pcr->szDesc = 0;
  786. ClearFlag(pcr->uFlags, CRF_FOLDER);
  787. idRet = DoModal(hwndOwner, ConfirmReplace_Proc, IDD_REPLACE_FILE, (LPARAM)pcr);
  788. if (pcr->hicon)
  789. DestroyIcon(pcr->hicon);
  790. }
  791. GFree(pcr);
  792. }
  793. else
  794. {
  795. idRet = -1; // Out of memory
  796. }
  797. return (int)idRet;
  798. }
  799. //---------------------------------------------------------------------------
  800. // Introduction dialog
  801. //---------------------------------------------------------------------------
  802. /*----------------------------------------------------------
  803. Purpose: Intro dialog
  804. Returns: varies
  805. Cond: --
  806. */
  807. INT_PTR CALLBACK Intro_Proc(
  808. HWND hDlg,
  809. UINT wMsg,
  810. WPARAM wParam,
  811. LPARAM lParam)
  812. {
  813. NMHDR *lpnm;
  814. switch (wMsg)
  815. {
  816. case WM_INITDIALOG:
  817. break;
  818. case WM_NOTIFY:
  819. lpnm = (NMHDR *)lParam;
  820. switch(lpnm->code)
  821. {
  822. case PSN_SETACTIVE: {
  823. // Only allow the Finish button. The user cannot go back and
  824. // change the settings.
  825. HWND hwndCancel = GetDlgItem(GetParent(hDlg), IDCANCEL);
  826. PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_FINISH);
  827. // Hide cancel button
  828. EnableWindow(hwndCancel, FALSE);
  829. ShowWindow(hwndCancel, SW_HIDE);
  830. }
  831. break;
  832. case PSN_KILLACTIVE:
  833. case PSN_HELP:
  834. case PSN_WIZBACK:
  835. case PSN_WIZNEXT:
  836. break;
  837. default:
  838. return FALSE;
  839. }
  840. break;
  841. default:
  842. return FALSE;
  843. }
  844. return TRUE;
  845. }
  846. /*----------------------------------------------------------
  847. Purpose: Invoke the introduction wizard.
  848. Returns: ID of button that terminated dialog
  849. Cond: --
  850. */
  851. int PUBLIC Intro_DoModal(
  852. HWND hwndParent)
  853. {
  854. PROPSHEETPAGE psp = {
  855. sizeof(psp),
  856. PSP_DEFAULT | PSP_HIDEHEADER,
  857. g_hinst,
  858. MAKEINTRESOURCE(IDD_INTRO_WIZARD),
  859. NULL, // hicon
  860. NULL, // caption
  861. Intro_Proc,
  862. 0, // lParam
  863. NULL, // pfnCallback
  864. NULL // pointer to ref count
  865. };
  866. PROPSHEETHEADER psh = {
  867. sizeof(psh),
  868. PSH_WIZARD_LITE | PSH_WIZARD | PSH_PROPSHEETPAGE, // (use ppsp field)
  869. hwndParent,
  870. g_hinst,
  871. 0, // hicon
  872. 0, // caption
  873. 1, // number of pages
  874. 0, // start page
  875. &psp
  876. };
  877. return (int)PropertySheet(&psh);
  878. }
  879. //---------------------------------------------------------------------------
  880. // MsgBox dialog
  881. //---------------------------------------------------------------------------
  882. typedef struct _MSGBOX
  883. {
  884. LPCTSTR pszText;
  885. LPCTSTR pszCaption;
  886. HICON hicon;
  887. UINT uStyle;
  888. } MSGBOX, * PMSGBOX;
  889. /*----------------------------------------------------------
  890. Purpose: Determines whether to resize the dialog and reposition
  891. the buttons to fit the text.
  892. The dialog is not resized any smaller than its initial
  893. size.
  894. The dialog is only resized vertically.
  895. Returns: --
  896. Cond: --
  897. */
  898. void PRIVATE MsgBox_Resize(
  899. HWND hDlg,
  900. LPCTSTR pszText,
  901. UINT cchText)
  902. {
  903. HDC hdc;
  904. HWND hwndText = GetDlgItem(hDlg, IDC_TEXT);
  905. hdc = GetDC(hwndText);
  906. if (hdc)
  907. {
  908. HFONT hfont = GetStockObject(DEFAULT_GUI_FONT);
  909. HFONT hfontSav = SelectFont(hdc, hfont);
  910. RECT rc;
  911. RECT rcOrg;
  912. // Determine new dimensions
  913. GetClientRect(hwndText, &rcOrg);
  914. rc = rcOrg;
  915. DrawTextEx(hdc, (LPTSTR)pszText, cchText, &rc, DT_CALCRECT | DT_WORDBREAK | DT_LEFT, NULL);
  916. SelectFont(hdc, hfontSav);
  917. ReleaseDC(hwndText, hdc);
  918. // Is the required size bigger?
  919. if (rc.bottom > rcOrg.bottom)
  920. {
  921. // Yes; resize the windows
  922. int cy = rc.bottom - rcOrg.bottom;
  923. int cyFudge = GetSystemMetrics(SM_CYCAPTION) + 2*GetSystemMetrics(SM_CYFIXEDFRAME);
  924. int cxFudge = 2*GetSystemMetrics(SM_CXFIXEDFRAME);
  925. HDWP hdwp = BeginDeferWindowPos(4);
  926. if (hdwp)
  927. {
  928. // Move Buttons
  929. hdwp = SlideControlPos(hdwp, hDlg, IDC_BUTTON1, 0, cy);
  930. hdwp = SlideControlPos(hdwp, hDlg, IDC_BUTTON2, 0, cy);
  931. hdwp = SlideControlPos(hdwp, hDlg, IDC_BUTTON3, 0, cy);
  932. // Resize Static Text
  933. hdwp = DeferWindowPos(hdwp, hwndText, GetDlgItem(hDlg, IDC_BUTTON3),
  934. 0, 0,
  935. rc.right-rc.left, rc.bottom-rc.top,
  936. SWP_NOACTIVATE | SWP_NOMOVE);
  937. EndDeferWindowPos(hdwp);
  938. }
  939. // Resize Dialog
  940. GetClientRect(hDlg, &rc);
  941. SetWindowPos(hDlg, NULL, 0, 0,
  942. rc.right-rc.left + cxFudge, rc.bottom-rc.top + cy + cyFudge,
  943. SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
  944. }
  945. }
  946. }
  947. /*----------------------------------------------------------
  948. Purpose: MsgBox dialog
  949. Returns: varies
  950. Cond: --
  951. */
  952. INT_PTR CALLBACK MsgBox_Proc(
  953. HWND hDlg,
  954. UINT wMsg,
  955. WPARAM wParam,
  956. LPARAM lParam)
  957. {
  958. switch (wMsg)
  959. {
  960. case WM_INITDIALOG:
  961. {
  962. PMSGBOX pmsgbox = (PMSGBOX)lParam;
  963. UINT uStyle = pmsgbox->uStyle;
  964. UINT i;
  965. UINT imb = uStyle & MB_TYPEMASK;
  966. UINT cButtons;
  967. MB_BUTTONS const * pmbb;
  968. static UINT const rgidc[3] = { IDC_BUTTON1, IDC_BUTTON2, IDC_BUTTON3 };
  969. static BTNSTYLE const rgmbstyle[] = {
  970. // (List buttons backwards)
  971. // MB_OK
  972. { 1, { { IDOK, IDS_OK },
  973. } },
  974. // MB_OKCANCEL
  975. { 2, { { IDCANCEL, IDS_CANCEL },
  976. { IDOK, IDS_OK },
  977. } },
  978. // MB_ABORTRETRYIGNORE (not supported)
  979. { 1, { { IDOK, IDS_OK },
  980. } },
  981. // MB_YESNOCANCEL
  982. { 3, { { IDCANCEL, IDS_CANCEL },
  983. { IDNO, IDS_NO },
  984. { IDYES, IDS_YES },
  985. } },
  986. // MB_YESNO
  987. { 2, { { IDNO, IDS_NO },
  988. { IDYES, IDS_YES },
  989. } },
  990. // MB_RETRYCANCEL
  991. { 2, { { IDCANCEL, IDS_CANCEL },
  992. { IDRETRY, IDS_RETRY },
  993. } },
  994. };
  995. // Set the text
  996. if (pmsgbox->pszText)
  997. {
  998. Static_SetText(GetDlgItem(hDlg, IDC_TEXT), pmsgbox->pszText);
  999. // Resize and reposition the buttons if necessary
  1000. MsgBox_Resize(hDlg, pmsgbox->pszText, lstrlen(pmsgbox->pszText));
  1001. }
  1002. if (pmsgbox->pszCaption)
  1003. SetWindowText(hDlg, pmsgbox->pszCaption);
  1004. // Use a custom icon?
  1005. if (NULL == pmsgbox->hicon)
  1006. {
  1007. // No; use a system icon
  1008. LPCTSTR pszIcon;
  1009. if (IsFlagSet(uStyle, MB_ICONEXCLAMATION))
  1010. pszIcon = IDI_EXCLAMATION;
  1011. else if (IsFlagSet(uStyle, MB_ICONHAND))
  1012. pszIcon = IDI_HAND;
  1013. else if (IsFlagSet(uStyle, MB_ICONQUESTION))
  1014. pszIcon = IDI_QUESTION;
  1015. else
  1016. pszIcon = IDI_ASTERISK;
  1017. pmsgbox->hicon = LoadIcon(NULL, pszIcon);
  1018. }
  1019. Static_SetIcon(GetDlgItem(hDlg, IDC_MSGICON), pmsgbox->hicon);
  1020. // Set the IDs and strings of used buttons
  1021. cButtons = rgmbstyle[imb].cButtons;
  1022. pmbb = rgmbstyle[imb].rgmbb;
  1023. for (i = 0; i < cButtons; i++)
  1024. {
  1025. TCHAR sz[MAXMEDLEN];
  1026. HWND hwnd = GetDlgItem(hDlg, rgidc[i]);
  1027. LoadString(g_hinst, pmbb[i].ids, sz, ARRAYSIZE(sz));
  1028. SetWindowLongPtr(hwnd, GWLP_ID, pmbb[i].id);
  1029. SetWindowText(hwnd, sz);
  1030. }
  1031. // Disable unused buttons
  1032. for (; i < ARRAYSIZE(rgidc); i++)
  1033. {
  1034. HWND hwnd = GetDlgItem(hDlg, rgidc[i]);
  1035. EnableWindow(hwnd, FALSE);
  1036. ShowWindow(hwnd, SW_HIDE);
  1037. }
  1038. }
  1039. break;
  1040. case WM_COMMAND:
  1041. switch (wParam)
  1042. {
  1043. case IDOK:
  1044. case IDCANCEL:
  1045. case IDYES:
  1046. case IDNO:
  1047. case IDRETRY:
  1048. EndDialog(hDlg, wParam);
  1049. break;
  1050. }
  1051. break;
  1052. default:
  1053. return FALSE;
  1054. }
  1055. return TRUE;
  1056. }
  1057. /*----------------------------------------------------------
  1058. Purpose: Invoke the introduction dialog.
  1059. Returns: ID of button that terminated dialog
  1060. Cond: --
  1061. */
  1062. int PUBLIC MsgBox(
  1063. HWND hwndParent,
  1064. LPCTSTR pszText,
  1065. LPCTSTR pszCaption,
  1066. HICON hicon, // May be NULL
  1067. UINT uStyle, ...)
  1068. {
  1069. INT_PTR iRet = -1;
  1070. int ids;
  1071. TCHAR szCaption[MAXPATHLEN];
  1072. LPTSTR pszRet;
  1073. va_list ArgList;
  1074. va_start(ArgList, uStyle);
  1075. pszRet = _ConstructMessageString(g_hinst, pszText, &ArgList);
  1076. va_end(ArgList);
  1077. if (pszRet)
  1078. {
  1079. // Is pszCaption a resource ID?
  1080. if (0 == HIWORD(pszCaption))
  1081. {
  1082. // Yes; load it
  1083. ids = LOWORD(pszCaption);
  1084. SzFromIDS(ids, szCaption, ARRAYSIZE(szCaption));
  1085. pszCaption = szCaption;
  1086. }
  1087. // Invoke dialog
  1088. if (pszCaption)
  1089. {
  1090. MSGBOX msgbox = { pszRet, pszCaption, hicon, uStyle };
  1091. iRet = DoModal(hwndParent, MsgBox_Proc, IDC_MSGBOX, (LPARAM)&msgbox);
  1092. }
  1093. LocalFree(pszRet);
  1094. }
  1095. return (int)iRet;
  1096. }