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.

490 lines
15 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #define MAX_ICONS 500 // that is a lot 'o icons
  4. #define CX_BORDER 4
  5. #define CY_BORDER 12
  6. typedef struct {
  7. LPCTSTR pszDialogTitle; // input
  8. BOOL bShowRestoreButton; // input
  9. LPTSTR pszIconPath; // input/output
  10. int cchIconPath; // input
  11. int iIconIndex; // input/output
  12. // private state variables
  13. HWND hDlg;
  14. BOOL fFirstPass;
  15. TCHAR szPathField[MAX_PATH];
  16. TCHAR szBuffer[MAX_PATH];
  17. } PICKICON_DATA, *LPPICKICON_DATA;
  18. typedef struct
  19. {
  20. int iResult; // icon index within the resources
  21. int iResId; // resource ID to search for!
  22. } ICONENUMSTATE, *LPICONENUMSTATE;
  23. // Call back function used when trying to find the correct icon to be
  24. // highlighted, called with the name of each resource - we compare this
  25. // against the one specified in the structure and bail out if we get
  26. // a match.
  27. BOOL CALLBACK IconEnumProc( HANDLE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam )
  28. {
  29. LPICONENUMSTATE pState = (LPICONENUMSTATE)lParam;
  30. if ( (INT_PTR)lpszName == pState->iResId )
  31. return FALSE; // bail out of enum loop
  32. pState->iResult++;
  33. return TRUE;
  34. }
  35. // Checks if the file exists, if it doesn't it tries tagging on .exe and
  36. // if that fails it reports an error. The given path is environment expanded.
  37. // If it needs to put up an error box, it changes the cursor back.
  38. // Path s assumed to be MAXITEMPATHLEN long.
  39. // The main reason for moving this out of the DlgProc was because we're
  40. // running out of stack space on the call to the comm dlg.
  41. BOOL IconFileExists(LPPICKICON_DATA lppid)
  42. {
  43. TCHAR szExpBuffer[ ARRAYSIZE(lppid->szBuffer) ];
  44. if (lppid->szBuffer[0] == 0)
  45. return FALSE;
  46. if (SHExpandEnvironmentStrings(lppid->szBuffer, szExpBuffer, ARRAYSIZE(szExpBuffer)))
  47. {
  48. PathUnquoteSpaces(lppid->szBuffer);
  49. PathUnquoteSpaces(szExpBuffer);
  50. if (PathResolve(szExpBuffer, NULL, PRF_VERIFYEXISTS | PRF_TRYPROGRAMEXTENSIONS))
  51. return TRUE;
  52. ShellMessageBox(HINST_THISDLL, lppid->hDlg, MAKEINTRESOURCE(IDS_BADPATHMSG), 0, MB_OK | MB_ICONEXCLAMATION, (LPTSTR)lppid->szPathField);
  53. }
  54. return FALSE;
  55. }
  56. //
  57. // GetDefaultIconImageName:
  58. //
  59. void GetDefaultIconImageName(LPTSTR pszBuffer, int cchBuffer)
  60. {
  61. WCHAR szModName[MAX_PATH];
  62. GetModuleFileName(HINST_THISDLL, szModName, ARRAYSIZE(szModName));
  63. if (!PathUnExpandEnvStrings(szModName, pszBuffer, cchBuffer))
  64. {
  65. StringCchCopy(pszBuffer, cchBuffer, szModName);
  66. }
  67. }
  68. void PutIconsInList(LPPICKICON_DATA lppid)
  69. {
  70. HICON *rgIcons;
  71. int cIcons;
  72. HWND hDlg = lppid->hDlg;
  73. DECLAREWAITCURSOR;
  74. LONG err = LB_ERR;
  75. SendDlgItemMessage(hDlg, IDD_ICON, LB_RESETCONTENT, 0, 0L);
  76. GetDlgItemText(hDlg, IDD_PATH, lppid->szPathField, ARRAYSIZE(lppid->szPathField));
  77. StringCchCopy(lppid->szBuffer, ARRAYSIZE(lppid->szBuffer), lppid->szPathField);
  78. if (!IconFileExists(lppid)) {
  79. if (lppid->fFirstPass) {
  80. // Icon File doesn't exist, use progman
  81. lppid->fFirstPass = FALSE; // Only do this bit once.
  82. GetDefaultIconImageName(lppid->szBuffer, ARRAYSIZE(lppid->szBuffer));
  83. } else {
  84. return;
  85. }
  86. }
  87. StringCchCopy(lppid->szPathField, ARRAYSIZE(lppid->szPathField), lppid->szBuffer);
  88. SetDlgItemText(hDlg, IDD_PATH, lppid->szPathField);
  89. SetWaitCursor();
  90. rgIcons = (HICON *)LocalAlloc(LPTR, MAX_ICONS*SIZEOF(HICON));
  91. if (rgIcons != NULL)
  92. cIcons = (int)ExtractIconEx(lppid->szBuffer, 0, rgIcons, NULL, MAX_ICONS);
  93. else
  94. cIcons = 0;
  95. ResetWaitCursor();
  96. if (!cIcons) {
  97. if (lppid->fFirstPass) {
  98. lppid->fFirstPass = FALSE; // Only do this bit once.
  99. ShellMessageBox(HINST_THISDLL, hDlg, MAKEINTRESOURCE(IDS_NOICONSMSG1), 0, MB_OK | MB_ICONEXCLAMATION, (LPCTSTR)lppid->szBuffer);
  100. // No icons here - change the path do somewhere where we
  101. // know there are icons. Get the path to progman.
  102. GetDefaultIconImageName(lppid->szPathField, ARRAYSIZE(lppid->szPathField));
  103. SetDlgItemText(hDlg, IDD_PATH, lppid->szPathField);
  104. PutIconsInList(lppid);
  105. } else {
  106. ShellMessageBox(HINST_THISDLL, hDlg, MAKEINTRESOURCE(IDS_NOICONSMSG), 0, MB_OK | MB_ICONEXCLAMATION, (LPCTSTR)lppid->szBuffer);
  107. return;
  108. }
  109. }
  110. SetWaitCursor();
  111. SendDlgItemMessage(hDlg, IDD_ICON, WM_SETREDRAW, FALSE, 0L);
  112. if (rgIcons) {
  113. int i;
  114. for (i = 0; i < cIcons; i++) {
  115. SendDlgItemMessage(hDlg, IDD_ICON, LB_ADDSTRING, 0, (LPARAM)(UINT_PTR)rgIcons[i]);
  116. }
  117. LocalFree((HLOCAL)rgIcons);
  118. }
  119. // Cope with being given a resource ID, not an index into the icon array. To do this
  120. // we must enumerate the icon names checking for a match. If we have one then highlight
  121. // that, otherwise default to the first.
  122. //
  123. // A resource icon reference is indicated by being passed a -ve iIconIndex.
  124. if ( lppid->iIconIndex >= 0 )
  125. {
  126. err = (LONG) SendDlgItemMessage( hDlg, IDD_ICON, LB_SETCURSEL, lppid->iIconIndex, 0L);
  127. }
  128. else
  129. {
  130. HMODULE hModule = LoadLibrary(lppid->szBuffer);
  131. if (hModule)
  132. {
  133. ICONENUMSTATE state;
  134. state.iResult = 0;
  135. state.iResId = -(lppid->iIconIndex);
  136. EnumResourceNames( hModule, RT_GROUP_ICON, IconEnumProc, (LONG_PTR)&state );
  137. err = (LONG) SendDlgItemMessage( hDlg, IDD_ICON, LB_SETCURSEL, state.iResult, 0L );
  138. FreeLibrary( hModule );
  139. }
  140. }
  141. // Check for failure, if we did then ensure we highlight the first!
  142. if ( err == LB_ERR )
  143. SendDlgItemMessage( hDlg, IDD_ICON, LB_SETCURSEL, 0, 0L );
  144. SendDlgItemMessage(hDlg, IDD_ICON, WM_SETREDRAW, TRUE, 0L);
  145. InvalidateRect(GetDlgItem(hDlg, IDD_ICON), NULL, TRUE);
  146. ResetWaitCursor();
  147. }
  148. void InitPickIconDlg(HWND hDlg, LPPICKICON_DATA lppid)
  149. {
  150. RECT rc;
  151. UINT cy;
  152. HWND hwndIcons;
  153. // init state variables
  154. lppid->hDlg = hDlg;
  155. StringCchCopy(lppid->szPathField, ARRAYSIZE(lppid->szPathField), lppid->pszIconPath);
  156. // this first pass stuff is so that the first time something
  157. // bogus happens (file not found, no icons) we give the user
  158. // a list of icons from progman.
  159. lppid->fFirstPass = TRUE;
  160. // Override the Dialog Title if Set. Else use the default Title defined in the Dialog resource.
  161. if (lppid->pszDialogTitle && (lppid->pszDialogTitle[0] != TEXT('\0')))
  162. {
  163. SetWindowText(hDlg, lppid->pszDialogTitle);
  164. }
  165. // Enable or Disable the Restore Default button.
  166. if (lppid->bShowRestoreButton)
  167. ShowWindow(GetDlgItem(lppid->hDlg, IDD_RESTORE),SW_SHOW);
  168. else
  169. ShowWindow(GetDlgItem(lppid->hDlg, IDD_RESTORE), SW_HIDE);
  170. // init the dialog controls
  171. SetDlgItemText(hDlg, IDD_PATH, lppid->pszIconPath);
  172. // Cannot max against 0 because 0 means "no limit"
  173. SendDlgItemMessage(hDlg, IDD_PATH, EM_LIMITTEXT, max(lppid->cchIconPath-1, 1), 0L);
  174. SendDlgItemMessage(hDlg, IDD_ICON, LB_SETCOLUMNWIDTH, GetSystemMetrics(SM_CXICON) + CX_BORDER, 0L);
  175. hwndIcons = GetDlgItem(hDlg, IDD_ICON);
  176. /* compute the height of the listbox based on icon dimensions */
  177. GetClientRect(hwndIcons, &rc);
  178. cy = ((GetSystemMetrics(SM_CYICON) + CY_BORDER) * 4) +
  179. GetSystemMetrics(SM_CYHSCROLL) +
  180. GetSystemMetrics(SM_CYEDGE) * 3;
  181. SetWindowPos(hwndIcons, NULL, 0, 0, rc.right, cy, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  182. SHAutoComplete(GetDlgItem(hDlg, IDD_PATH), 0);
  183. PutIconsInList(lppid);
  184. }
  185. // call the common browse code for this
  186. BOOL BrowseForIconFile(LPPICKICON_DATA lppid)
  187. {
  188. TCHAR szTitle[80];
  189. GetWindowText(lppid->hDlg, szTitle, ARRAYSIZE(szTitle));
  190. GetDlgItemText(lppid->hDlg, IDD_PATH, lppid->szBuffer, ARRAYSIZE(lppid->szBuffer));
  191. // We will never be quoted here because IconFileExists() removes quotes (of course user could type them in)
  192. if (lppid->szBuffer[0] != '"')
  193. PathQuoteSpaces(lppid->szBuffer);
  194. if (GetFileNameFromBrowse(lppid->hDlg, lppid->szBuffer, ARRAYSIZE(lppid->szBuffer), NULL, MAKEINTRESOURCE(IDS_ICO), MAKEINTRESOURCE(IDS_ICONSFILTER), szTitle))
  195. {
  196. PathQuoteSpaces(lppid->szBuffer);
  197. SetDlgItemText(lppid->hDlg, IDD_PATH, lppid->szBuffer);
  198. // Set default button to OK.
  199. SendMessage(lppid->hDlg, DM_SETDEFID, IDOK, 0);
  200. return TRUE;
  201. } else
  202. return FALSE;
  203. }
  204. // test if the name field is different from the last file we looked at
  205. BOOL NameChange(LPPICKICON_DATA lppid)
  206. {
  207. GetDlgItemText(lppid->hDlg, IDD_PATH, lppid->szBuffer, ARRAYSIZE(lppid->szBuffer));
  208. return lstrcmpi(lppid->szBuffer, lppid->szPathField);
  209. }
  210. //
  211. // dialog procedure for picking an icon (ala progman change icon)
  212. // uses DLG_PICKICON template
  213. //
  214. // in:
  215. // pszIconFile
  216. // cbIconFile
  217. // iIndex
  218. //
  219. // out:
  220. // pszIconFile
  221. // iIndex
  222. //
  223. BOOL_PTR CALLBACK PickIconDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
  224. {
  225. LPPICKICON_DATA lppid = (LPPICKICON_DATA)GetWindowLongPtr(hDlg, DWLP_USER);
  226. DWORD dwOldLayout;
  227. // Array for context help:
  228. static const DWORD aPickIconHelpIDs[] = {
  229. IDD_PATH, IDH_FCAB_LINK_ICONNAME,
  230. IDD_ICON, IDH_FCAB_LINK_CURRENT_ICON,
  231. IDD_BROWSE, IDH_BROWSE,
  232. 0, 0
  233. };
  234. switch (wMsg) {
  235. case WM_INITDIALOG:
  236. SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  237. InitPickIconDlg(hDlg, (LPPICKICON_DATA)lParam);
  238. break;
  239. case WM_COMMAND:
  240. switch (GET_WM_COMMAND_ID(wParam, lParam)) {
  241. case IDD_BROWSE:
  242. if (BrowseForIconFile(lppid))
  243. PutIconsInList(lppid);
  244. break;
  245. case IDD_PATH:
  246. if (NameChange(lppid))
  247. SendDlgItemMessage(hDlg, IDD_ICON, LB_SETCURSEL, (WPARAM)-1, 0);
  248. break;
  249. case IDD_ICON:
  250. if (NameChange(lppid)) {
  251. PutIconsInList(lppid);
  252. break;
  253. }
  254. if (GET_WM_COMMAND_CMD(wParam, lParam) != LBN_DBLCLK)
  255. break;
  256. /*** FALL THRU on double click ***/
  257. case IDOK:
  258. if (NameChange(lppid)) {
  259. PutIconsInList(lppid);
  260. } else {
  261. int iIconIndex = (int)SendDlgItemMessage(hDlg, IDD_ICON, LB_GETCURSEL, 0, 0L);
  262. if (iIconIndex < 0)
  263. iIconIndex = 0;
  264. lppid->iIconIndex = iIconIndex;
  265. StringCchCopy(lppid->pszIconPath, lppid->cchIconPath, lppid->szPathField);
  266. EndDialog(hDlg, S_OK);
  267. }
  268. break;
  269. case IDCANCEL:
  270. EndDialog(hDlg, HRESULT_FROM_WIN32(ERROR_CANCELLED));
  271. break;
  272. case IDD_RESTORE:
  273. EndDialog(hDlg, S_FALSE);
  274. break;
  275. default:
  276. return(FALSE);
  277. }
  278. break;
  279. // owner draw messages for icon listbox
  280. case WM_DRAWITEM:
  281. #define lpdi ((DRAWITEMSTRUCT *)lParam)
  282. if (lpdi->itemState & ODS_SELECTED)
  283. SetBkColor(lpdi->hDC, GetSysColor(COLOR_HIGHLIGHT));
  284. else
  285. SetBkColor(lpdi->hDC, GetSysColor(COLOR_WINDOW));
  286. /* repaint the selection state */
  287. ExtTextOut(lpdi->hDC, 0, 0, ETO_OPAQUE, &lpdi->rcItem, NULL, 0, NULL);
  288. dwOldLayout = GET_DC_LAYOUT(lpdi->hDC);
  289. if (g_bMirroredOS && dwOldLayout)
  290. {
  291. SET_DC_LAYOUT(lpdi->hDC, dwOldLayout | LAYOUT_PRESERVEBITMAP);
  292. }
  293. /* draw the icon */
  294. if ((int)lpdi->itemID >= 0)
  295. DrawIcon(lpdi->hDC, (lpdi->rcItem.left + lpdi->rcItem.right - GetSystemMetrics(SM_CXICON)) / 2,
  296. (lpdi->rcItem.bottom + lpdi->rcItem.top - GetSystemMetrics(SM_CYICON)) / 2, (HICON)lpdi->itemData);
  297. if (dwOldLayout)
  298. {
  299. SET_DC_LAYOUT(lpdi->hDC, dwOldLayout);
  300. }
  301. // InflateRect(&lpdi->rcItem, -1, -1);
  302. /* if it has the focus, draw the focus */
  303. if (lpdi->itemState & ODS_FOCUS)
  304. DrawFocusRect(lpdi->hDC, &lpdi->rcItem);
  305. #undef lpdi
  306. break;
  307. case WM_MEASUREITEM:
  308. #define lpmi ((MEASUREITEMSTRUCT *)lParam)
  309. lpmi->itemWidth = GetSystemMetrics(SM_CXICON) + CX_BORDER;
  310. lpmi->itemHeight = GetSystemMetrics(SM_CYICON) + CY_BORDER;
  311. #undef lpmi
  312. break;
  313. case WM_DELETEITEM:
  314. #define lpdi ((DELETEITEMSTRUCT *)lParam)
  315. DestroyIcon((HICON)lpdi->itemData);
  316. #undef lpdi
  317. break;
  318. case WM_HELP:
  319. WinHelp(((LPHELPINFO) lParam)->hItemHandle, NULL,
  320. HELP_WM_HELP, (ULONG_PTR)(LPTSTR) aPickIconHelpIDs);
  321. break;
  322. case WM_CONTEXTMENU:
  323. WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU,
  324. (ULONG_PTR)(LPVOID)aPickIconHelpIDs);
  325. break;
  326. default:
  327. return FALSE;
  328. }
  329. return TRUE;
  330. }
  331. // puts up the pick icon dialog
  332. STDAPI_(int) PickIconDlg(HWND hwnd, IN OUT LPTSTR pszIconPath, UINT cchIconPath, int *piIconIndex)
  333. {
  334. return SUCCEEDED(PickIconDlgWithTitle(hwnd, NULL, FALSE, pszIconPath, cchIconPath, piIconIndex));
  335. }
  336. // puts up the pick icon dialog with a customized Title for the Dialog Window.
  337. STDAPI PickIconDlgWithTitle(HWND hwnd, LPCTSTR pszTitle, BOOL bShowRestoreButton, IN OUT LPTSTR pszIconPath, UINT cchIconPath, int *piIconIndex)
  338. {
  339. RIPMSG(pszIconPath && IS_VALID_WRITE_BUFFER(pszIconPath, TCHAR, cchIconPath), "PickIconDlgWithTitle: caller passed bad pszIconPath");
  340. RIPMSG(piIconIndex != NULL, "PickIconDlgWithTitle: caller passed bad piIconIndex");
  341. if (pszIconPath && piIconIndex)
  342. {
  343. PICKICON_DATA *pid = (PICKICON_DATA *)LocalAlloc(LPTR, sizeof(PICKICON_DATA));
  344. if (pid)
  345. {
  346. HRESULT res;
  347. pid->pszDialogTitle = pszTitle;
  348. pid->bShowRestoreButton = bShowRestoreButton;
  349. pid->pszIconPath = pszIconPath;
  350. pid->cchIconPath = cchIconPath;
  351. pid->iIconIndex = *piIconIndex;
  352. res = (HRESULT)DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_PICKICON), hwnd, PickIconDlgProc, (LPARAM)pid);
  353. *piIconIndex = pid->iIconIndex;
  354. LocalFree(pid);
  355. return res;
  356. }
  357. *piIconIndex = 0;
  358. *pszIconPath = 0;
  359. return E_OUTOFMEMORY;
  360. }
  361. return E_INVALIDARG;
  362. }