Leaked source code of windows server 2003
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.

494 lines
15 KiB

  1. /*
  2. * pickicon - Icon picker
  3. */
  4. #include "stdafx.h"
  5. #include "pickicon.h"
  6. #include "windowsx.h"
  7. #include "commdlg.h"
  8. #include "resource.h"
  9. #include "util.h"
  10. typedef TCHAR TCH;
  11. typedef struct COFN { /* common open file name */
  12. OPENFILENAME ofn; /* The thing COMMDLG wants */
  13. TCH tsz[MAX_PATH]; /* Where we build the name */
  14. TCH tszFilter[100]; /* File open/save filter */
  15. } COFN, *PCOFN;
  16. /*****************************************************************************
  17. *
  18. * InitOpenFileName
  19. *
  20. * Initialize a COFN structure.
  21. *
  22. *****************************************************************************/
  23. void PASCAL
  24. InitOpenFileName(HWND hwnd, PCOFN pcofn, UINT ids, LPCTSTR pszInit)
  25. {
  26. DECLARE_SC(sc, TEXT("InitOpenFileName"));
  27. int itchMax;
  28. TCH tch;
  29. ZeroMemory(&pcofn->ofn, sizeof(pcofn->ofn));
  30. pcofn->ofn.lStructSize |= sizeof(pcofn->ofn);
  31. pcofn->ofn.hwndOwner = hwnd;
  32. pcofn->ofn.lpstrFilter = pcofn->tszFilter;
  33. pcofn->ofn.lpstrFile = pcofn->tsz;
  34. pcofn->ofn.nMaxFile = MAX_PATH;
  35. pcofn->ofn.Flags |= (OFN_HIDEREADONLY | OFN_NOCHANGEDIR);
  36. /* Get the filter string */
  37. itchMax = LoadString(SC::GetHinst(), ids, pcofn->tszFilter, countof(pcofn->tszFilter));
  38. if (itchMax) {
  39. /* Marker character must not be DBCS */
  40. tch = pcofn->tszFilter[itchMax-1];
  41. LPTSTR ptsz = pcofn->tszFilter;
  42. while (ptsz < &pcofn->tszFilter[itchMax]) {
  43. if (*ptsz == tch) *ptsz++ = '\0';
  44. else ptsz = CharNext(ptsz);
  45. }
  46. }
  47. /* Set the initial value */
  48. sc = StringCchCopy(pcofn->tsz, countof(pcofn->tsz), pszInit);
  49. // Let the sc trace on destruction
  50. }
  51. /*
  52. * Instance info for the dialog.
  53. */
  54. typedef struct PIDI { /* PickIcon dialog instance */
  55. LPTSTR ptszIconPath; /* Which file? */
  56. UINT ctchIconPath;
  57. int iIconIndex; /* Which icon number? */
  58. int *piIconIndex;
  59. TCH tszCurFile[MAX_PATH]; /* The path in the list box */
  60. } PIDI, *PPIDI;
  61. #define cxIcon GetSystemMetrics(SM_CXICON)
  62. #define cyIcon GetSystemMetrics(SM_CYICON)
  63. /*****************************************************************************
  64. *
  65. * PickIcon_ppidiHdlg
  66. *
  67. * Extract the PPIDI from an hdlg.
  68. *
  69. *****************************************************************************/
  70. #define PickIcon_ppidiHdlg(hdlg) ((PPIDI)GetWindowLongPtr(hdlg, DWLP_USER))
  71. /*****************************************************************************
  72. *
  73. * PickIcon_OnMeasureItem
  74. *
  75. * Tell USER the size of each item.
  76. *
  77. *****************************************************************************/
  78. void PASCAL
  79. PickIcon_OnMeasureItem(HWND hdlg, LPMEASUREITEMSTRUCT lpmi, PPIDI ppidi)
  80. {
  81. lpmi->itemWidth = cxIcon + 12;
  82. lpmi->itemHeight = cyIcon + 4;
  83. }
  84. /*****************************************************************************
  85. *
  86. * PickIcon_OnDrawItem
  87. *
  88. * Draw an icon.
  89. *
  90. *****************************************************************************/
  91. void PASCAL
  92. PickIcon_OnDrawItem(HWND hdlg, LPDRAWITEMSTRUCT lpdi, PPIDI ppidi)
  93. {
  94. SetBkColor(lpdi->hDC, GetSysColor((lpdi->itemState & ODS_SELECTED) ?
  95. COLOR_HIGHLIGHT : COLOR_WINDOW));
  96. /* repaint the selection state */
  97. ExtTextOut(lpdi->hDC, 0, 0, ETO_OPAQUE, &lpdi->rcItem, NULL, 0, NULL);
  98. /*
  99. * Preserve icon shape when BitBlitting it to a
  100. * mirrored DC.
  101. */
  102. DWORD dwLayout=0L;
  103. if ((dwLayout=GetLayout(lpdi->hDC)) & LAYOUT_RTL)
  104. {
  105. SetLayout(lpdi->hDC, dwLayout|LAYOUT_BITMAPORIENTATIONPRESERVED);
  106. }
  107. /* draw the icon centered in the rectangle */
  108. if ((int)lpdi->itemID >= 0) {
  109. DrawIcon(lpdi->hDC,
  110. (lpdi->rcItem.left + lpdi->rcItem.right - cxIcon) / 2,
  111. (lpdi->rcItem.bottom + lpdi->rcItem.top - cyIcon) / 2,
  112. (HICON)lpdi->itemData);
  113. }
  114. /*
  115. * Restore the DC to its previous layout state.
  116. */
  117. if (dwLayout & LAYOUT_RTL)
  118. {
  119. SetLayout(lpdi->hDC, dwLayout);
  120. }
  121. /* if it has the focus, draw the focus */
  122. if (lpdi->itemState & ODS_FOCUS) {
  123. DrawFocusRect(lpdi->hDC, &lpdi->rcItem);
  124. }
  125. }
  126. /*****************************************************************************
  127. *
  128. * PickIcon_OnDeleteItem
  129. *
  130. * USER is nuking an item. Clean it up.
  131. *
  132. *****************************************************************************/
  133. #define PickIcon_OnDeleteItem(hdlg, lpdi, ppidi) \
  134. DestroyIcon((HICON)(lpdi)->itemData)
  135. /*****************************************************************************
  136. *
  137. * PickIcon_FillIconList
  138. *
  139. * Fill in all the icons. If the user picks a bad place, we leave
  140. * garbage in the path (so he can edit the name) and leave the list
  141. * box blank.
  142. *
  143. *****************************************************************************/
  144. void PickIcon_FillIconList(HWND hdlg, PPIDI ppidi)
  145. {
  146. DECLARE_SC(sc, TEXT("PickIcon_FillIconList"));
  147. sc = ScCheckPointers(ppidi);
  148. if (sc)
  149. return;
  150. HCURSOR hcurOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
  151. HWND hwnd = GetDlgItem(hdlg, IDC_PICKICON);
  152. if (!IsWindow (hwnd))
  153. return;
  154. ListBox_SetColumnWidth(hwnd, cxIcon + 12);
  155. ListBox_ResetContent(hwnd);
  156. TCHAR szFile[countof(ppidi->tszCurFile)];
  157. GetDlgItemText(hdlg, IDC_PICKPATH, szFile, countof(szFile));
  158. // support indirect paths (e.g. %SystemRoot%\...")
  159. TCHAR szExpandedFile[countof(ppidi->tszCurFile)];
  160. ExpandEnvironmentStrings (szFile, szExpandedFile, countof(szExpandedFile));
  161. if (SearchPath(0, szExpandedFile, 0, countof(ppidi->tszCurFile),
  162. ppidi->tszCurFile, 0)) {
  163. ExtractIcons:
  164. int cIcons;
  165. cIcons = ExtractIconEx(ppidi->tszCurFile, 0, 0, 0, 0);
  166. if (cIcons) {
  167. HICON *rgIcons = (HICON *)LocalAlloc(LPTR, cIcons * sizeof(HICON));
  168. if (rgIcons) {
  169. cIcons = (int)ExtractIconEx(ppidi->tszCurFile, 0,
  170. rgIcons, NULL, cIcons);
  171. if (cIcons) {
  172. int iicon;
  173. SendMessage(hwnd, WM_SETREDRAW, 0, 0);
  174. for (iicon = 0; iicon < cIcons; iicon++) {
  175. ListBox_AddString(hwnd, rgIcons[iicon]);
  176. }
  177. if (ListBox_SetCurSel(hwnd, ppidi->iIconIndex) == LB_ERR) {
  178. ListBox_SetCurSel(hwnd, 0);
  179. }
  180. SendMessage(hwnd, WM_SETREDRAW, 1, 0);
  181. } else { /* Mysteriously unable to extract */
  182. }
  183. LocalFree((HLOCAL)rgIcons);
  184. } else { /* Not enough memory to load icons */
  185. }
  186. } else { /* No icons in the file */
  187. }
  188. // compare the indirect path (e.g., %SystemRoot%\...) against
  189. // the expanded version (szFile - c:\windows)
  190. int nCmpFile = CompareString(LOCALE_USER_DEFAULT,
  191. 0,
  192. szExpandedFile,
  193. countof(szExpandedFile),
  194. szFile,
  195. countof(szFile));
  196. // If the comparision failed, then no need to do the next comparsion
  197. // so trace the failure and move on
  198. if(ERROR_INVALID_FLAGS == nCmpFile || ERROR_INVALID_PARAMETER == nCmpFile)
  199. {
  200. sc = E_UNEXPECTED ;
  201. sc.TraceAndClear();
  202. }
  203. else
  204. {
  205. // Compare the expanded file against the file chosen from the dialog
  206. int nCmpCurFile = CompareString(LOCALE_USER_DEFAULT,
  207. 0,
  208. szExpandedFile,
  209. countof(szExpandedFile),
  210. ppidi->tszCurFile,
  211. countof(ppidi->tszCurFile));
  212. // If the comparison failed, then no need to continue so trace the error
  213. // and move on
  214. if(ERROR_INVALID_FLAGS == nCmpCurFile || ERROR_INVALID_PARAMETER == nCmpCurFile)
  215. {
  216. sc = E_UNEXPECTED ;
  217. sc.TraceAndClear();
  218. }
  219. else
  220. {
  221. // if szExpandedFile != szFile and szExpandFile == ppidi->tszCurFile
  222. // then copy szFile into ppidi->tszCurFile to update the path for
  223. // the open file dialog
  224. if((CSTR_EQUAL != nCmpFile) && (CSTR_EQUAL == nCmpCurFile))
  225. {
  226. sc = StringCchCopy(ppidi->tszCurFile, countof(ppidi->tszCurFile), szFile);
  227. if (sc)
  228. sc.TraceAndClear();
  229. }
  230. }
  231. }
  232. SetDlgItemText(hdlg, IDC_PICKPATH, ppidi->tszCurFile);
  233. } else { /* File not found */
  234. SC sc;
  235. MMCErrorBox (sc.FromWin32(ERROR_FILE_NOT_FOUND));
  236. goto ExtractIcons;
  237. }
  238. InvalidateRect(hwnd, 0, 1);
  239. SetCursor(hcurOld);
  240. }
  241. /*****************************************************************************
  242. *
  243. * PickIcon_OnInitDialog
  244. *
  245. * Dialog init. Populate the list box with what we came in with.
  246. *
  247. *****************************************************************************/
  248. void PASCAL
  249. PickIcon_OnInitDialog(HWND hdlg, PPIDI ppidi)
  250. {
  251. DECLARE_SC(sc, _T("PickIcon_OnInitDialog"));
  252. SetWindowLongPtr(hdlg, DWLP_USER, (LPARAM)ppidi);
  253. sc = StringCchCopy(ppidi->tszCurFile, countof(ppidi->tszCurFile), ppidi->ptszIconPath);
  254. if(sc)
  255. sc.TraceAndClear();
  256. else
  257. SetDlgItemText(hdlg, IDC_PICKPATH, ppidi->tszCurFile);
  258. SendDlgItemMessage(hdlg, IDC_PICKPATH, EM_LIMITTEXT,
  259. ppidi->ctchIconPath, 0);
  260. PickIcon_FillIconList(hdlg, ppidi);
  261. }
  262. /*****************************************************************************
  263. *
  264. * PickIcon_OnBrowse
  265. *
  266. *****************************************************************************/
  267. void PASCAL
  268. PickIcon_OnBrowse(HWND hdlg, PPIDI ppidi)
  269. {
  270. DWORD dw;
  271. COFN cofn;
  272. InitOpenFileName(hdlg, &cofn, IDS_ICONFILES, ppidi->tszCurFile);
  273. dw = GetFileAttributes(ppidi->tszCurFile);
  274. if (dw == 0xFFFFFFFF || (dw & FILE_ATTRIBUTE_DIRECTORY)) {
  275. cofn.tsz[0] = '\0';
  276. }
  277. if (GetOpenFileName(&cofn.ofn)) {
  278. SetDlgItemText(hdlg, IDC_PICKPATH, cofn.tsz);
  279. SendMessage(hdlg, DM_SETDEFID, IDOK, 0);
  280. PickIcon_FillIconList(hdlg, ppidi);
  281. }
  282. }
  283. /*****************************************************************************
  284. *
  285. * PickIcon_NameChange
  286. *
  287. * Determine whether the thing in the edit control doesn't match the
  288. * thing whose icons we are showing.
  289. *
  290. *****************************************************************************/
  291. BOOL PASCAL
  292. PickIcon_NameChange(HWND hdlg, PPIDI ppidi)
  293. {
  294. TCH tszBuffer[MAX_PATH];
  295. GetDlgItemText(hdlg, IDC_PICKPATH, tszBuffer, countof(tszBuffer));
  296. int nCmpFile = CompareString(LOCALE_USER_DEFAULT, 0,
  297. tszBuffer, -1,
  298. ppidi->tszCurFile, -1);
  299. // If the name change can't be confirmed, then assume that something
  300. // changed and return TRUE (which will force the selection to be cleared)
  301. if(ERROR_INVALID_FLAGS == nCmpFile || ERROR_INVALID_PARAMETER == nCmpFile)
  302. return TRUE;
  303. // NOTE: From the SDK: To maintain the C run-time convention of
  304. // comparing strings, the value 2 can be subtracted from a nonzero
  305. // return value. The meaning of < 0, ==0 and > 0 is then consistent
  306. // with the C run times.
  307. return nCmpFile - 2; // If nCmpFile == 0, then nothing changed so return FALSE else TRUE
  308. }
  309. /*****************************************************************************
  310. *
  311. * PickIcon_OnOk
  312. *
  313. * If the name has changed, treat this as a "Okay, now reload
  314. * the icons" rather than "Okay, I'm finished".
  315. *
  316. *****************************************************************************/
  317. void PASCAL
  318. PickIcon_OnOk(HWND hdlg, PPIDI ppidi)
  319. {
  320. DECLARE_SC(sc, _T("PickIcon_OnOk"));
  321. if (PickIcon_NameChange(hdlg, ppidi)) {
  322. PickIcon_FillIconList(hdlg, ppidi);
  323. } else {
  324. int iIconIndex = (int)SendDlgItemMessage(hdlg, IDC_PICKICON,
  325. LB_GETCURSEL, 0, 0L);
  326. if (iIconIndex >= 0) { /* We have an icon */
  327. *ppidi->piIconIndex = iIconIndex;
  328. sc = StringCchCopy(ppidi->ptszIconPath, ppidi->ctchIconPath, ppidi->tszCurFile);
  329. // if error trace on destruction, but don't clear
  330. EndDialog(hdlg, 1);
  331. } else { /* No icon, act like cancel */
  332. EndDialog(hdlg, 0);
  333. }
  334. }
  335. }
  336. /*****************************************************************************
  337. *
  338. * PickIcon_OnCommand
  339. *
  340. *****************************************************************************/
  341. void PASCAL
  342. PickIcon_OnCommand(HWND hdlg, int id, UINT codeNotify, PPIDI ppidi)
  343. {
  344. switch (id) {
  345. case IDOK: PickIcon_OnOk(hdlg, ppidi); break;
  346. case IDCANCEL: EndDialog(hdlg, 0); break;
  347. case IDC_PICKBROWSE: PickIcon_OnBrowse(hdlg, ppidi); break;
  348. /*
  349. * When the name changes, remove the selection highlight.
  350. */
  351. case IDC_PICKPATH:
  352. if (PickIcon_NameChange(hdlg, ppidi)) {
  353. SendDlgItemMessage(hdlg, IDC_PICKICON, LB_SETCURSEL, (WPARAM)-1, 0);
  354. }
  355. break;
  356. case IDC_PICKICON:
  357. if (codeNotify == LBN_DBLCLK) {
  358. PickIcon_OnOk(hdlg, ppidi);
  359. }
  360. break;
  361. }
  362. }
  363. /*****************************************************************************
  364. *
  365. * PickIcon_DlgProc
  366. *
  367. * Dialog procedure.
  368. *
  369. *****************************************************************************/
  370. /*
  371. * The HANDLE_WM_* macros weren't designed to be used from a dialog
  372. * proc, so we need to handle the messages manually. (But carefully.)
  373. */
  374. INT_PTR EXPORT
  375. PickIcon_DlgProc(HWND hdlg, UINT wm, WPARAM wParam, LPARAM lParam)
  376. {
  377. PPIDI ppidi = PickIcon_ppidiHdlg(hdlg);
  378. switch (wm) {
  379. case WM_INITDIALOG: PickIcon_OnInitDialog(hdlg, (PPIDI)lParam); break;
  380. case WM_COMMAND:
  381. PickIcon_OnCommand(hdlg, (int)GET_WM_COMMAND_ID(wParam, lParam),
  382. (UINT)GET_WM_COMMAND_CMD(wParam, lParam),
  383. ppidi);
  384. break;
  385. case WM_DRAWITEM:
  386. PickIcon_OnDrawItem(hdlg, (LPDRAWITEMSTRUCT)lParam, ppidi);
  387. break;
  388. case WM_MEASUREITEM:
  389. PickIcon_OnMeasureItem(hdlg, (LPMEASUREITEMSTRUCT)lParam, ppidi);
  390. break;
  391. case WM_DELETEITEM:
  392. PickIcon_OnDeleteItem(hdlg, (LPDELETEITEMSTRUCT)lParam, ppidi);
  393. break;
  394. default: return 0; /* Unhandled */
  395. }
  396. return 1; /* Handled */
  397. }
  398. /*****************************************************************************
  399. *
  400. * MMC_PickIconDlg
  401. *
  402. * Ask the user to pick an icon.
  403. *
  404. * hwnd - owner window
  405. * ptszIconPath - (in) default icon file
  406. * (out) chosen icon file
  407. * ctchIconPath - size of ptszIconPath buffer
  408. * piIconIndex - (in) default icon index
  409. * (out) index of chosen icon
  410. *
  411. * If the dialog box is cancelled, then no values are changed.
  412. *
  413. *****************************************************************************/
  414. MMCBASE_API INT_PTR PASCAL
  415. MMC_PickIconDlg(HWND hwnd, LPTSTR ptszIconPath, UINT ctchIconPath, int *piIconIndex)
  416. {
  417. PIDI pidi;
  418. pidi.ptszIconPath = ptszIconPath;
  419. pidi.ctchIconPath = ctchIconPath;
  420. pidi.piIconIndex = piIconIndex;
  421. pidi.iIconIndex = *piIconIndex;
  422. return DialogBoxParam(SC::GetHinst(), MAKEINTRESOURCE(IDD_PICKICON), hwnd,
  423. PickIcon_DlgProc, (LPARAM)&pidi);
  424. }