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.

1107 lines
30 KiB

  1. /*++
  2. Copyright (c) 1990-1998, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. dlgs.c
  5. Abstract:
  6. This module contains the common functions for the Win32 common dialogs.
  7. Revision History:
  8. --*/
  9. // precompiled headers
  10. #include "precomp.h"
  11. #pragma hdrstop
  12. #include "util.h"
  13. //
  14. // Global Variables.
  15. //
  16. extern BOOL bInitializing;
  17. extern DWORD g_tlsiExtError;
  18. //
  19. // Function Prototypes.
  20. //
  21. LONG
  22. RgbInvertRgb(
  23. LONG rgbOld);
  24. const struct _ERRORMAP
  25. {
  26. DWORD dwCommDlgError;
  27. DWORD dwWin32Error;
  28. } ERRORMAP[] =
  29. {
  30. { CDERR_INITIALIZATION , ERROR_INVALID_PARAMETER},
  31. { PDERR_INITFAILURE , ERROR_INVALID_PARAMETER},
  32. { CDERR_STRUCTSIZE , ERROR_INVALID_PARAMETER},
  33. { CDERR_NOTEMPLATE , ERROR_INVALID_PARAMETER},
  34. { CDERR_NOHINSTANCE , ERROR_INVALID_PARAMETER},
  35. { CDERR_NOHOOK , ERROR_INVALID_PARAMETER},
  36. { CDERR_MEMALLOCFAILURE , ERROR_OUTOFMEMORY},
  37. { CDERR_LOCKRESFAILURE , ERROR_INVALID_HANDLE},
  38. { CDERR_DIALOGFAILURE , E_FAIL},
  39. { PDERR_SETUPFAILURE , ERROR_INVALID_PARAMETER},
  40. { PDERR_RETDEFFAILURE , ERROR_INVALID_PARAMETER},
  41. { FNERR_BUFFERTOOSMALL , ERROR_INSUFFICIENT_BUFFER},
  42. { FRERR_BUFFERLENGTHZERO, ERROR_INSUFFICIENT_BUFFER},
  43. { FNERR_INVALIDFILENAME , ERROR_INVALID_NAME},
  44. { PDERR_NODEFAULTPRN , E_FAIL},
  45. { CFERR_NOFONTS , E_FAIL},
  46. { CFERR_MAXLESSTHANMIN , ERROR_INVALID_PARAMETER},
  47. };
  48. ////////////////////////////////////////////////////////////////////////////
  49. //
  50. // StoreExtendedError
  51. //
  52. // Stores an extended error code for the next call to
  53. // CommDlgExtendedError.
  54. //
  55. ////////////////////////////////////////////////////////////////////////////
  56. void StoreExtendedError(
  57. DWORD dwError)
  58. {
  59. int i;
  60. for (i=0; i < ARRAYSIZE(ERRORMAP); i++)
  61. {
  62. if (ERRORMAP[i].dwCommDlgError == dwError)
  63. {
  64. SetLastError(ERRORMAP[i].dwWin32Error);
  65. break;
  66. }
  67. }
  68. TlsSetValue(g_tlsiExtError, UlongToPtr(dwError));
  69. }
  70. ////////////////////////////////////////////////////////////////////////////
  71. //
  72. // GetStoredExtendedError
  73. //
  74. // Retieves the stored extended error code.
  75. //
  76. ////////////////////////////////////////////////////////////////////////////
  77. DWORD GetStoredExtendedError(void)
  78. {
  79. DWORD dwError;
  80. dwError = PtrToUlong(TlsGetValue(g_tlsiExtError));
  81. return (dwError);
  82. }
  83. ////////////////////////////////////////////////////////////////////////////
  84. //
  85. // CommDlgExtendedError
  86. //
  87. // Provides additional information about dialog failure.
  88. // This should be called immediately after failure.
  89. //
  90. // Returns: LO word - error code
  91. // HI word - error specific info
  92. //
  93. ////////////////////////////////////////////////////////////////////////////
  94. DWORD WINAPI CommDlgExtendedError()
  95. {
  96. return (GetStoredExtendedError());
  97. }
  98. ////////////////////////////////////////////////////////////////////////////
  99. //
  100. // HourGlass
  101. //
  102. // Turn hourglass on or off.
  103. //
  104. // bOn - specifies ON or OFF
  105. //
  106. ////////////////////////////////////////////////////////////////////////////
  107. VOID HourGlass(
  108. BOOL bOn)
  109. {
  110. //
  111. // Change cursor to hourglass.
  112. //
  113. if (!bInitializing)
  114. {
  115. if (!bMouse)
  116. {
  117. ShowCursor(bCursorLock = bOn);
  118. }
  119. SetCursor(LoadCursor(NULL, bOn ? IDC_WAIT : IDC_ARROW));
  120. }
  121. }
  122. ////////////////////////////////////////////////////////////////////////////
  123. //
  124. // LoadAlterBitmap
  125. //
  126. // Loads a bitmap given its name and gives all the pixels that are
  127. // a certain color a new color.
  128. //
  129. // Returns: NULL - failed
  130. // handle to the bitmap loaded - success
  131. //
  132. ////////////////////////////////////////////////////////////////////////////
  133. HBITMAP WINAPI LoadAlterBitmap(
  134. int id,
  135. DWORD rgbReplace,
  136. DWORD rgbInstead)
  137. {
  138. LPBITMAPINFOHEADER qbihInfo;
  139. HDC hdcScreen;
  140. BOOL fFound;
  141. HANDLE hresLoad;
  142. HANDLE hres;
  143. LPLONG qlng;
  144. DWORD *qlngReplace; // points to bits that are replaced
  145. LPBYTE qbBits;
  146. HANDLE hbmp;
  147. LPBITMAPINFOHEADER lpBitmapInfo;
  148. UINT cbBitmapSize;
  149. hresLoad = FindResource(g_hinst, MAKEINTRESOURCE(id), RT_BITMAP);
  150. if (hresLoad == HNULL)
  151. {
  152. return (HNULL);
  153. }
  154. hres = LoadResource(g_hinst, hresLoad);
  155. if (hres == HNULL)
  156. {
  157. return (HNULL);
  158. }
  159. //
  160. // Lock the bitmap data and make a copy of it for the mask and the
  161. // bitmap.
  162. //
  163. cbBitmapSize = SizeofResource(g_hinst, hresLoad);
  164. lpBitmapInfo = (LPBITMAPINFOHEADER)LockResource(hres);
  165. qbihInfo = (LPBITMAPINFOHEADER)LocalAlloc(LPTR, cbBitmapSize);
  166. if ((lpBitmapInfo == NULL) || (qbihInfo == NULL))
  167. {
  168. return (NULL);
  169. }
  170. memcpy((TCHAR *)qbihInfo, (TCHAR *)lpBitmapInfo, cbBitmapSize);
  171. //
  172. // Get a pointer into the color table of the bitmaps, cache the
  173. // number of bits per pixel.
  174. //
  175. rgbReplace = RgbInvertRgb(rgbReplace);
  176. rgbInstead = RgbInvertRgb(rgbInstead);
  177. qlng = (LPLONG)((LPSTR)(qbihInfo) + qbihInfo->biSize);
  178. fFound = FALSE;
  179. while (!fFound)
  180. {
  181. if (*qlng == (LONG)rgbReplace)
  182. {
  183. fFound = TRUE;
  184. qlngReplace = (DWORD *)qlng;
  185. *qlng = (LONG)rgbInstead;
  186. }
  187. qlng++;
  188. }
  189. //
  190. // First skip over the header structure.
  191. //
  192. qbBits = (LPBYTE)(qbihInfo + 1);
  193. //
  194. // Skip the color table entries, if any.
  195. //
  196. qbBits += (1 << (qbihInfo->biBitCount)) * sizeof(RGBQUAD);
  197. //
  198. // Create a color bitmap compatible with the display device.
  199. //
  200. hdcScreen = GetDC(HNULL);
  201. if (hdcScreen != HNULL)
  202. {
  203. hbmp = CreateDIBitmap( hdcScreen,
  204. qbihInfo,
  205. (LONG)CBM_INIT,
  206. qbBits,
  207. (LPBITMAPINFO)qbihInfo,
  208. DIB_RGB_COLORS );
  209. ReleaseDC(HNULL, hdcScreen);
  210. }
  211. //
  212. // Reset color bits to original value.
  213. //
  214. *qlngReplace = (LONG)rgbReplace;
  215. LocalFree(qbihInfo);
  216. return (hbmp);
  217. }
  218. ////////////////////////////////////////////////////////////////////////////
  219. //
  220. // RgbInvertRgb
  221. //
  222. // Reverses the byte order of the RGB value (for file format).
  223. //
  224. // Returns the new color value (RGB to BGR).
  225. //
  226. ////////////////////////////////////////////////////////////////////////////
  227. LONG RgbInvertRgb(
  228. LONG rgbOld)
  229. {
  230. LONG lRet;
  231. BYTE R, G, B;
  232. R = GetRValue(rgbOld);
  233. G = GetGValue(rgbOld);
  234. B = GetBValue(rgbOld);
  235. lRet = (LONG)RGB(B, G, R);
  236. return (lRet);
  237. }
  238. ////////////////////////////////////////////////////////////////////////////
  239. //
  240. // HbmpLoadBmp
  241. //
  242. // Loads in a bitmap.
  243. //
  244. // Returns: Bitmap handle - success
  245. // HNULL - failure
  246. //
  247. ////////////////////////////////////////////////////////////////////////////
  248. #if 0
  249. HBITMAP HbmpLoadBmp(
  250. WORD bmp)
  251. {
  252. HBITMAP hbmp;
  253. CHAR szBitmap[cbResNameMax];
  254. hbmp = HNULL;
  255. if (LoadString(g_hinst, bmp, (LPTSTR)szBitmap, cbResNameMax - 1))
  256. {
  257. hbmp = LoadBitmap(g_hinst, (LPCTSTR)szBitmap);
  258. }
  259. return (hbmp);
  260. }
  261. #endif
  262. ////////////////////////////////////////////////////////////////////////////
  263. //
  264. // AddNetButton
  265. //
  266. // Attempts to add a network button to the open, save, or print dialogs.
  267. //
  268. // hDlg - dialog to add button to
  269. // hInstance - instance handle for dlg
  270. // dyBottomMargin - DUs to bottom edge
  271. //
  272. ////////////////////////////////////////////////////////////////////////////
  273. #define xDUsToPels(DUs, lDlgBaseUnits) \
  274. (int)(((DUs) * (int)LOWORD((lDlgBaseUnits))) / 4)
  275. #define yDUsToPels(DUs, lDlgBaseUnits) \
  276. (int)(((DUs) * (int)HIWORD((lDlgBaseUnits))) / 8)
  277. VOID AddNetButton(
  278. HWND hDlg,
  279. HANDLE hInstance,
  280. int dyBottomMargin,
  281. BOOL bAddAccel,
  282. BOOL bTryLowerRight,
  283. BOOL bTryLowerLeft)
  284. {
  285. LONG lDlgBaseUnits;
  286. RECT rcDlg, rcCtrl, rcTmp;
  287. LONG xButton, yButton;
  288. LONG dxButton, dyButton;
  289. LONG dxDlgFrame, dyDlgFrame;
  290. LONG yDlgHeight, xDlgWidth;
  291. HWND hwndButton, hCtrl, hLastCtrl, hTmp, hSave;
  292. HFONT hFont;
  293. POINT ptTopLeft, ptTopRight, ptCenter, ptBtmLeft, ptBtmRight, ptTopLeftTmp;
  294. TCHAR szNetwork[MAX_PATH];
  295. //
  296. // Make sure a network button (psh14) doesn't already exist in
  297. // the dialog.
  298. //
  299. if (GetDlgItem(hDlg, psh14))
  300. {
  301. return;
  302. }
  303. //
  304. // Get dialog coordinate info.
  305. //
  306. lDlgBaseUnits = GetDialogBaseUnits();
  307. dxDlgFrame = GetSystemMetrics(SM_CXDLGFRAME);
  308. dyDlgFrame = GetSystemMetrics(SM_CYDLGFRAME);
  309. GetWindowRect(hDlg, &rcDlg);
  310. rcDlg.left += dxDlgFrame;
  311. rcDlg.right -= dxDlgFrame;
  312. rcDlg.top += dyDlgFrame + GetSystemMetrics(SM_CYCAPTION);
  313. rcDlg.bottom -= dyDlgFrame;
  314. //
  315. // Get the OK button.
  316. //
  317. if (!(hCtrl = GetDlgItem(hDlg, IDOK)))
  318. {
  319. return;
  320. }
  321. GetWindowRect(hCtrl, &rcCtrl);
  322. ptTopLeft.x = rcCtrl.left;
  323. ptTopLeft.y = rcCtrl.top;
  324. //
  325. // Make sure the OK button isn't outside the dialog.
  326. //
  327. if (!PtInRect(&rcDlg, ptTopLeft))
  328. {
  329. //
  330. // Try the CANCEL button.
  331. //
  332. if (!(hCtrl = GetDlgItem(hDlg, IDCANCEL)))
  333. {
  334. //
  335. // Both OK and CANCEL do not exist, so return.
  336. //
  337. return;
  338. }
  339. //
  340. // The check for the Cancel button outside the dialog is handled
  341. // below.
  342. //
  343. GetWindowRect(hCtrl, &rcCtrl);
  344. }
  345. hSave = hCtrl;
  346. #ifdef UNICODE
  347. //
  348. // Get the full hDlg value if coming from WOW.
  349. //
  350. if (IS_INTRESOURCE(hDlg))
  351. {
  352. HWND hNewDlg = GetParent(hCtrl);
  353. if (hDlg == (HWND)LOWORD(hNewDlg))
  354. {
  355. hDlg = hNewDlg;
  356. }
  357. }
  358. #endif
  359. //
  360. // Save the coordinate info of the button.
  361. //
  362. dxButton = rcCtrl.right - rcCtrl.left;
  363. dyButton = rcCtrl.bottom - rcCtrl.top;
  364. xButton = rcCtrl.left;
  365. yButton = rcCtrl.bottom + yDUsToPels(4, lDlgBaseUnits);
  366. yDlgHeight = rcDlg.bottom - yDUsToPels(dyBottomMargin, lDlgBaseUnits);
  367. //
  368. // Try to insert the network button in the lower right corner
  369. // of dialog box.
  370. //
  371. if (bTryLowerRight && (hTmp = GetDlgItem(hDlg, cmb2)))
  372. {
  373. //
  374. // See if the network button can be inserted in the
  375. // lower right corner of the dialog box.
  376. //
  377. hLastCtrl = hCtrl;
  378. GetWindowRect(hTmp, &rcTmp);
  379. yButton = rcTmp.top;
  380. //
  381. // Set the coordinates of the new button.
  382. //
  383. ptTopLeft.x = ptBtmLeft.x = xButton;
  384. ptTopLeft.y = ptTopRight.y = yButton;
  385. ptTopRight.x = ptBtmRight.x = xButton + dxButton;
  386. ptBtmLeft.y = ptBtmRight.y = yButton + dyButton;
  387. ptCenter.x = xButton + dxButton / 2;
  388. ptCenter.y = yButton + dyButton / 2;
  389. ScreenToClient(hDlg, (LPPOINT)&ptTopLeft);
  390. ScreenToClient(hDlg, (LPPOINT)&ptBtmLeft);
  391. ScreenToClient(hDlg, (LPPOINT)&ptTopRight);
  392. ScreenToClient(hDlg, (LPPOINT)&ptBtmRight);
  393. ScreenToClient(hDlg, (LPPOINT)&ptCenter);
  394. //
  395. // See if the new button is over any other buttons.
  396. //
  397. if (((yButton + dyButton) < yDlgHeight) &&
  398. ((ChildWindowFromPoint(hDlg, ptTopLeft) == hDlg) &&
  399. (ChildWindowFromPoint(hDlg, ptTopRight) == hDlg) &&
  400. (ChildWindowFromPoint(hDlg, ptCenter) == hDlg) &&
  401. (ChildWindowFromPoint(hDlg, ptBtmLeft) == hDlg) &&
  402. (ChildWindowFromPoint(hDlg, ptBtmRight) == hDlg)))
  403. {
  404. //
  405. // If the last control is the OK button and there is a
  406. // HELP button, then the last control should be the
  407. // HELP button.
  408. //
  409. if ((hLastCtrl == GetDlgItem(hDlg, IDOK)) &&
  410. (hCtrl = GetDlgItem(hDlg, pshHelp)))
  411. {
  412. GetWindowRect(hCtrl, &rcCtrl);
  413. ptTopLeftTmp.x = rcCtrl.left;
  414. ptTopLeftTmp.y = rcCtrl.top;
  415. //
  416. // Make sure the HELP button isn't outside the dialog
  417. // and then set the last control to be the HELP button.
  418. //
  419. if (PtInRect(&rcDlg, ptTopLeftTmp))
  420. {
  421. hLastCtrl = hCtrl;
  422. }
  423. }
  424. //
  425. // If the last control is still the OK button and there is a
  426. // CANCEL button, then the last control should be the
  427. // CANCEL button.
  428. //
  429. if ((hLastCtrl == GetDlgItem(hDlg, IDOK)) &&
  430. (hCtrl = GetDlgItem(hDlg, IDCANCEL)))
  431. {
  432. GetWindowRect(hCtrl, &rcCtrl);
  433. ptTopLeftTmp.x = rcCtrl.left;
  434. ptTopLeftTmp.y = rcCtrl.top;
  435. //
  436. // Make sure the CANCEL button isn't outside the dialog
  437. // and then set the last control to be the CANCEL button.
  438. //
  439. if (PtInRect(&rcDlg, ptTopLeftTmp))
  440. {
  441. hLastCtrl = hCtrl;
  442. }
  443. }
  444. goto FoundPlace;
  445. }
  446. //
  447. // Reset yButton.
  448. //
  449. yButton = rcCtrl.bottom + yDUsToPels(4, lDlgBaseUnits);
  450. }
  451. //
  452. // Try to insert the network button vertically below the other
  453. // control buttons.
  454. //
  455. while (hCtrl != NULL)
  456. {
  457. //
  458. // Move vertically down and see if there is space.
  459. //
  460. hLastCtrl = hCtrl;
  461. GetWindowRect(hCtrl, &rcCtrl);
  462. yButton = rcCtrl.bottom + yDUsToPels(4, lDlgBaseUnits);
  463. //
  464. // Make sure there is still room in the dialog.
  465. //
  466. if ((yButton + dyButton) > yDlgHeight)
  467. {
  468. //
  469. // No space.
  470. //
  471. break;
  472. }
  473. //
  474. // Set the coordinates of the new button.
  475. //
  476. ptTopLeft.x = ptBtmLeft.x = xButton;
  477. ptTopLeft.y = ptTopRight.y = yButton;
  478. ptTopRight.x = ptBtmRight.x = xButton + dxButton;
  479. ptBtmLeft.y = ptBtmRight.y = yButton + dyButton;
  480. ptCenter.x = xButton + dxButton / 2;
  481. ptCenter.y = yButton + dyButton / 2;
  482. ScreenToClient(hDlg, (LPPOINT)&ptTopLeft);
  483. ScreenToClient(hDlg, (LPPOINT)&ptBtmLeft);
  484. ScreenToClient(hDlg, (LPPOINT)&ptTopRight);
  485. ScreenToClient(hDlg, (LPPOINT)&ptBtmRight);
  486. ScreenToClient(hDlg, (LPPOINT)&ptCenter);
  487. //
  488. // See if the new button is over any other buttons.
  489. //
  490. if (((hCtrl = ChildWindowFromPoint(hDlg, ptTopLeft)) == hDlg) &&
  491. ((hCtrl = ChildWindowFromPoint(hDlg, ptTopRight)) == hDlg) &&
  492. ((hCtrl = ChildWindowFromPoint(hDlg, ptCenter)) == hDlg) &&
  493. ((hCtrl = ChildWindowFromPoint(hDlg, ptBtmLeft)) == hDlg) &&
  494. ((hCtrl = ChildWindowFromPoint(hDlg, ptBtmRight)) == hDlg))
  495. {
  496. goto FoundPlace;
  497. }
  498. }
  499. //
  500. // Try to insert the network button in the lower left corner of
  501. // the dialog box.
  502. //
  503. if (bTryLowerLeft)
  504. {
  505. //
  506. // Get the width of the dialog to make sure the button doesn't
  507. // go off the side of the dialog.
  508. //
  509. xDlgWidth = rcDlg.right - xDUsToPels(FILE_RIGHT_MARGIN, lDlgBaseUnits);
  510. //
  511. // Use the OK or CANCEL button saved earlier to get the size of
  512. // the buttons.
  513. //
  514. hCtrl = hSave;
  515. //
  516. // Start at the far left of the dialog.
  517. //
  518. // NOTE: We know that hCtrl is not NULL at this point because
  519. // otherwise we would have returned earlier.
  520. //
  521. // The print dialogs have a left margin of 8.
  522. //
  523. GetWindowRect(hCtrl, &rcCtrl);
  524. xButton = rcDlg.left + xDUsToPels(FILE_LEFT_MARGIN + 3, lDlgBaseUnits);
  525. yButton = rcCtrl.top;
  526. while (1)
  527. {
  528. hLastCtrl = hCtrl;
  529. //
  530. // Make sure there is still room in the dialog.
  531. //
  532. if ((xButton + dxButton) > xDlgWidth)
  533. {
  534. //
  535. // No space.
  536. //
  537. break;
  538. }
  539. //
  540. // Set the coordinates of the new button.
  541. //
  542. ptTopLeft.x = ptBtmLeft.x = xButton;
  543. ptTopLeft.y = ptTopRight.y = yButton;
  544. ptTopRight.x = ptBtmRight.x = xButton + dxButton;
  545. ptBtmLeft.y = ptBtmRight.y = yButton + dyButton;
  546. ptCenter.x = xButton + dxButton / 2;
  547. ptCenter.y = yButton + dyButton / 2;
  548. ScreenToClient(hDlg, (LPPOINT)&ptTopLeft);
  549. ScreenToClient(hDlg, (LPPOINT)&ptBtmLeft);
  550. ScreenToClient(hDlg, (LPPOINT)&ptTopRight);
  551. ScreenToClient(hDlg, (LPPOINT)&ptBtmRight);
  552. ScreenToClient(hDlg, (LPPOINT)&ptCenter);
  553. //
  554. // See if the new button is over any other buttons.
  555. //
  556. if ( ( ((hCtrl = ChildWindowFromPoint(hDlg, ptTopLeft)) == hDlg) &&
  557. ((hCtrl = ChildWindowFromPoint(hDlg, ptTopRight)) == hDlg) &&
  558. ((hCtrl = ChildWindowFromPoint(hDlg, ptCenter)) == hDlg) &&
  559. ((hCtrl = ChildWindowFromPoint(hDlg, ptBtmLeft)) == hDlg) &&
  560. ((hCtrl = ChildWindowFromPoint(hDlg, ptBtmRight)) == hDlg) ) )
  561. {
  562. //
  563. // If the last control is the OK button and there is a
  564. // HELP button, then the last control should be the
  565. // HELP button.
  566. //
  567. if ((hLastCtrl == GetDlgItem(hDlg, IDOK)) &&
  568. (hCtrl = GetDlgItem(hDlg, pshHelp)))
  569. {
  570. GetWindowRect(hCtrl, &rcCtrl);
  571. ptTopLeftTmp.x = rcCtrl.left;
  572. ptTopLeftTmp.y = rcCtrl.top;
  573. //
  574. // Make sure the HELP button isn't outside the dialog
  575. // and then set the last control to be the HELP button.
  576. //
  577. if (PtInRect(&rcDlg, ptTopLeftTmp))
  578. {
  579. hLastCtrl = hCtrl;
  580. }
  581. }
  582. //
  583. // If the last control is still the OK button and there is a
  584. // CANCEL button, then the last control should be the
  585. // CANCEL button.
  586. //
  587. if ((hLastCtrl == GetDlgItem(hDlg, IDOK)) &&
  588. (hCtrl = GetDlgItem(hDlg, IDCANCEL)))
  589. {
  590. GetWindowRect(hCtrl, &rcCtrl);
  591. ptTopLeftTmp.x = rcCtrl.left;
  592. ptTopLeftTmp.y = rcCtrl.top;
  593. //
  594. // Make sure the CANCEL button isn't outside the dialog
  595. // and then set the last control to be the CANCEL button.
  596. //
  597. if (PtInRect(&rcDlg, ptTopLeftTmp))
  598. {
  599. hLastCtrl = hCtrl;
  600. }
  601. }
  602. goto FoundPlace;
  603. }
  604. //
  605. // Make sure we encountered another control and that we
  606. // didn't go off the end of the dialog.
  607. //
  608. if (!hCtrl)
  609. {
  610. break;
  611. }
  612. //
  613. // Move over to the right and see if there is space.
  614. //
  615. GetWindowRect(hCtrl, &rcCtrl);
  616. xButton = rcCtrl.right + xDUsToPels(4, lDlgBaseUnits);
  617. }
  618. }
  619. return;
  620. FoundPlace:
  621. xButton = ptTopLeft.x;
  622. yButton = ptTopLeft.y;
  623. //If it a mirrored Dlg then the direction will be to the right.
  624. if (IS_WINDOW_RTL_MIRRORED(hDlg))
  625. xButton -= dxButton;
  626. #ifndef UNICODE
  627. //
  628. // For non-localized apps that don't include the network button as part
  629. // of their template, don't add a Far East one because the characters
  630. // will not be displayed correctly.
  631. //
  632. {
  633. #define NetworkButtonText TEXT("Network...")
  634. #define NetworkButtonTextAccel TEXT("Net&work...")
  635. CPINFO cpinfo;
  636. if ((GetCPInfo(CP_ACP, &cpinfo)) && (cpinfo.MaxCharSize > 1))
  637. {
  638. TEXTMETRIC tm;
  639. HFONT hPrevFont;
  640. HWND hIDOK = GetDlgItem(hDlg, IDOK);
  641. HDC hDC = GetDC(hIDOK);
  642. hFont = (HFONT)SendMessage(hIDOK, WM_GETFONT, 0, 0L);
  643. if (hFont != NULL)
  644. {
  645. hPrevFont = SelectObject(hDC, hFont);
  646. GetTextMetrics(hDC, &tm);
  647. SelectObject(hDC, hPrevFont);
  648. ReleaseDC(hIDOK, hDC);
  649. if (tm.tmCharSet == ANSI_CHARSET)
  650. {
  651. lstrcpy( szNetwork,
  652. bAddAccel ? NetworkButtonTextAccel : NetworkButtonText );
  653. goto CreateNetworkButton;
  654. }
  655. }
  656. }
  657. }
  658. #endif
  659. if (CDLoadString( g_hinst,
  660. (bAddAccel ? iszNetworkButtonTextAccel : iszNetworkButtonText),
  661. (LPTSTR)szNetwork,
  662. MAX_PATH ))
  663. {
  664. #ifndef UNICODE
  665. CreateNetworkButton:
  666. #endif
  667. hwndButton = CreateWindow( TEXT("button"),
  668. szNetwork,
  669. WS_VISIBLE | WS_CHILD | WS_GROUP |
  670. WS_TABSTOP | BS_PUSHBUTTON,
  671. xButton,
  672. yButton,
  673. dxButton,
  674. dyButton,
  675. hDlg,
  676. NULL,
  677. hInstance,
  678. NULL );
  679. if (hwndButton != NULL)
  680. {
  681. SetWindowLong(hwndButton, GWL_ID, psh14);
  682. SetWindowPos( hwndButton,
  683. hLastCtrl,
  684. 0, 0, 0, 0,
  685. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
  686. hFont = (HFONT)SendDlgItemMessage(hDlg, IDOK, WM_GETFONT, 0, 0L);
  687. SendMessage(hwndButton, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE,0));
  688. }
  689. }
  690. }
  691. ////////////////////////////////////////////////////////////////////////////
  692. //
  693. // IsNetworkInstalled
  694. //
  695. ////////////////////////////////////////////////////////////////////////////
  696. BOOL IsNetworkInstalled()
  697. {
  698. if (GetSystemMetrics(SM_NETWORK) & RNC_NETWORKS)
  699. {
  700. return (TRUE);
  701. }
  702. else
  703. {
  704. return (FALSE);
  705. }
  706. }
  707. #ifdef WINNT
  708. ////////////////////////////////////////////////////////////////////////////
  709. //
  710. // Ssync_ANSI_UNICODE_Struct_For_WOW (This is exported for WOW)
  711. //
  712. // For WOW support on NT only.
  713. //
  714. // When a 16-bit app calls one of the comdlg API's, WOW thunks the 16-bit
  715. // comdlg struct passed by the app to a 32-bit ANSI struct. Comdlg32 code
  716. // then thunks the 32-bit ANSI struct into a UNICODE struct. This scheme
  717. // creates a problem for WOW apps because on Win3.1, the app and comdlg16
  718. // share the same structure. When either updates the struct, the other is
  719. // aware of the change.
  720. //
  721. // This function allows us to sychronize the UNICODE struct with the app's
  722. // 16-bit struct & vice versa from WOW.
  723. //
  724. ////////////////////////////////////////////////////////////////////////////
  725. VOID Ssync_ANSI_UNICODE_Struct_For_WOW(
  726. HWND hDlg,
  727. BOOL fDirection,
  728. DWORD dwID)
  729. {
  730. switch (dwID)
  731. {
  732. case ( WOW_CHOOSECOLOR ) :
  733. {
  734. Ssync_ANSI_UNICODE_CC_For_WOW(hDlg, fDirection);
  735. break;
  736. }
  737. case ( WOW_CHOOSEFONT ) :
  738. {
  739. Ssync_ANSI_UNICODE_CF_For_WOW(hDlg, fDirection);
  740. break;
  741. }
  742. case ( WOW_OPENFILENAME ) :
  743. {
  744. Ssync_ANSI_UNICODE_OFN_For_WOW(hDlg, fDirection);
  745. break;
  746. }
  747. case ( WOW_PRINTDLG ) :
  748. {
  749. Ssync_ANSI_UNICODE_PD_For_WOW(hDlg, fDirection);
  750. break;
  751. }
  752. // case not needed for FINDREPLACE
  753. }
  754. }
  755. #endif
  756. #ifdef WX86
  757. ////////////////////////////////////////////////////////////////////////////
  758. //
  759. // Wx86GetX86Callback
  760. //
  761. // Creates a RISC-callable alias for a x86 hook function pointer.
  762. //
  763. // lpfnHook - x86 address of hook
  764. //
  765. // Returns a function pointer which can be called from RISC.
  766. //
  767. ////////////////////////////////////////////////////////////////////////////
  768. PVOID Wx86GetX86Callback(
  769. PVOID lpfnHook)
  770. {
  771. if (!lpfnHook)
  772. {
  773. return (NULL);
  774. }
  775. if (!pfnAllocCallBx86)
  776. {
  777. HMODULE hMod;
  778. if (!Wx86CurrentTib())
  779. {
  780. //
  781. // Wx86 is not running in this thread. Assume a RISC app has
  782. // passed a bad flag value and that lpfnHook is already a RISC
  783. // function pointer.
  784. //
  785. return (lpfnHook);
  786. }
  787. hMod = GetModuleHandle(TEXT("wx86.dll"));
  788. if (hMod == NULL)
  789. {
  790. //
  791. // Wx86 is running, but wx86.dll is not loaded! This should
  792. // never happen, but if it does, assume lpfnHook is already a
  793. // RISC pointer.
  794. //
  795. return (lpfnHook);
  796. }
  797. pfnAllocCallBx86 = (PALLOCCALLBX86)GetProcAddress( hMod,
  798. "AllocCallBx86" );
  799. if (!pfnAllocCallBx86)
  800. {
  801. //
  802. // Something has gone terribly wrong!
  803. //
  804. return (lpfnHook);
  805. }
  806. }
  807. //
  808. // Call into Wx86.dll to create a RISC-to-x86 callback which takes
  809. // 4 parameters and has no logging.
  810. //
  811. return (*pfnAllocCallBx86)(lpfnHook, 4, NULL, NULL);
  812. }
  813. #endif
  814. ////////////////////////////////////////////////////////////////////////////
  815. //
  816. // CDLoadString
  817. //
  818. ////////////////////////////////////////////////////////////////////////////
  819. int CDLoadString(HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax)
  820. {
  821. return CDLoadStringEx(CP_ACP, hInstance, uID, lpBuffer, nBufferMax);
  822. }
  823. // CDLoadStringEx takes a codepage, so we can store unicode strings in the resource file
  824. int CDLoadStringEx(UINT cp, HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax)
  825. {
  826. HRSRC hResInfo;
  827. int cch = 0;
  828. LPWSTR lpwsz;
  829. LANGID LangID;
  830. if (!GET_BIDI_LOCALIZED_SYSTEM_LANGID(NULL)) {
  831. #ifdef WINNT
  832. return LoadString(hInstance, uID, lpBuffer, nBufferMax);
  833. #else
  834. lpwsz = (LPWSTR) LocalAlloc(NONZEROLPTR, nBufferMax * sizeof(WCHAR));
  835. if (lpwsz)
  836. {
  837. int iRet;
  838. LoadStringWrapW(hInstance, uID, lpwsz, nBufferMax);
  839. iRet = WideCharToMultiByte(cp, 0, lpwsz, -1, lpBuffer, nBufferMax, NULL, NULL);
  840. LocalFree(lpwsz);
  841. return iRet;
  842. }
  843. return 0;
  844. #endif
  845. }
  846. LangID = (LANGID)TlsGetValue(g_tlsLangID);
  847. if (!LangID || MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) == LangID) {
  848. return LoadString(hInstance, uID, lpBuffer, nBufferMax);
  849. }
  850. if (!lpBuffer || (nBufferMax-- == 0))
  851. return 0;
  852. // String Tables are broken up into 16 string resources. Find the resource
  853. // containing the string we are interested in.
  854. if (hResInfo = FindResourceExFallback(hInstance, RT_STRING, MAKEINTRESOURCE((uID>>4)+1), LangID)) {
  855. // Load the resource. Note LoadResource returns an address.
  856. if (lpwsz = (LPWSTR)LoadResource(hInstance, hResInfo)) {
  857. // Move past the other strings in this resource.
  858. // (16 strings in a segment -> & 0x0F)
  859. for (uID %= 16; uID; uID--) {
  860. lpwsz += *lpwsz + 1;
  861. }
  862. cch = min(*lpwsz, nBufferMax - 1);
  863. #ifdef UNICODE
  864. // Copy the string into the buffer;
  865. memcpy(lpBuffer, lpwsz+1, cch*sizeof(WCHAR));
  866. #else
  867. // Copy the string into the buffer, converting to Ansi.
  868. cch= WideCharToMultiByte( CP_ACP, 0, lpwsz+1, cch, lpBuffer, cch, NULL, NULL);
  869. #endif
  870. }
  871. }
  872. lpBuffer[cch] = 0;
  873. return cch;
  874. }
  875. #define ENGLISH_APP 0
  876. #define MIRRORED_APP 1
  877. #define BIDI_APP 2
  878. DWORD GetAppType(HWND hWnd) {
  879. DWORD dwExStyle = 0;
  880. HWND hWndT = hWnd;
  881. DWORD dwAppType = ENGLISH_APP;
  882. #ifdef CHECK_OWNER
  883. //Check the window and its owners.
  884. while (!dwExStyle && hWndT) {
  885. dwExStyle = GetWindowLongA(hWndT, GWL_EXSTYLE) & (WS_EX_RIGHT | WS_EX_RTLREADING | RTL_MIRRORED_WINDOW);
  886. hWndT = GetWindow(hWndT, GW_OWNER);
  887. }
  888. if (!dwExStyle) {
  889. #endif
  890. //If we still did not find then check the parents.
  891. hWndT = hWnd;
  892. while (!dwExStyle && hWndT) {
  893. dwExStyle = GetWindowLongA(hWndT, GWL_EXSTYLE) & (WS_EX_RIGHT | WS_EX_RTLREADING | RTL_MIRRORED_WINDOW);
  894. hWndT = GetParent(hWndT);
  895. }
  896. #ifdef CHECK_OWNER
  897. }
  898. #endif
  899. if (dwExStyle & RTL_MIRRORED_WINDOW) {
  900. dwAppType = MIRRORED_APP;
  901. } else if (dwExStyle & (WS_EX_RIGHT | WS_EX_RTLREADING)) {
  902. dwAppType = BIDI_APP;
  903. }
  904. return dwAppType;
  905. }
  906. DWORD GetTemplateType(HANDLE hDlgTemplate)
  907. {
  908. DWORD dwExStyle = 0;
  909. DWORD dwAppType = ENGLISH_APP;
  910. LPDLGTEMPLATE pDlgTemplate;
  911. pDlgTemplate = (LPDLGTEMPLATE)LockResource(hDlgTemplate);
  912. if (pDlgTemplate) {
  913. if (((LPDLGTEMPLATEEX) pDlgTemplate)->wSignature == 0xFFFF) {
  914. dwExStyle = ((LPDLGTEMPLATEEX) pDlgTemplate)->dwExStyle;
  915. } else {
  916. dwExStyle = pDlgTemplate->dwExtendedStyle;
  917. }
  918. }
  919. if (dwExStyle & RTL_MIRRORED_WINDOW) {
  920. dwAppType = MIRRORED_APP;
  921. } else if (dwExStyle & (WS_EX_RIGHT | WS_EX_RTLREADING)) {
  922. dwAppType = BIDI_APP;
  923. }
  924. return dwAppType;
  925. }
  926. LANGID GetDialogLanguage(HWND hwndOwner, HANDLE hDlgTemplate)
  927. {
  928. LANGID LangID = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
  929. DWORD dwType;
  930. if (GET_BIDI_LOCALIZED_SYSTEM_LANGID(&LangID)) {
  931. if (hDlgTemplate == NULL) {
  932. dwType = GetAppType(hwndOwner);
  933. } else {
  934. dwType = GetTemplateType(hDlgTemplate);
  935. }
  936. switch (dwType) {
  937. case ENGLISH_APP :
  938. LangID = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
  939. break;
  940. case MIRRORED_APP:
  941. LangID = MAKELANGID(PRIMARYLANGID(LangID), SUBLANG_DEFAULT);
  942. break;
  943. case BIDI_APP :
  944. LangID = MAKELANGID(PRIMARYLANGID(LangID), SUBLANG_SYS_DEFAULT);
  945. break;
  946. }
  947. }
  948. return LangID;
  949. }