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.

447 lines
16 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // File: PICKICON.CPP
  4. //
  5. // Support code for the Change Icon dialog.
  6. //
  7. //---------------------------------------------------------------------------
  8. #include <windows.h>
  9. #include <windowsx.h>
  10. #include "rc.h"
  11. #include "pickicon.h"
  12. #define MAX_ICONS 500 // that is a lot 'o icons
  13. #define ARRAYSIZE(s) (sizeof(s) / sizeof((s)[0]))
  14. typedef struct
  15. {
  16. LPSTR pszIconPath; // input/output
  17. int cbIconPath; // input
  18. int iIconIndex; // input/output
  19. // private state variables
  20. HWND hDlg;
  21. BOOL fFirstPass;
  22. char szPathField[MAX_PATH];
  23. char szBuffer[MAX_PATH];
  24. } PICKICON_DATA, FAR *LPPICKICON_DATA;
  25. extern HINSTANCE g_hInst;
  26. // Checks if the file exists, if it doesn't it tries tagging on .exe and if that
  27. // fails it reports an error. The given path is environment expanded. If it needs
  28. // to put up an error box, it changes the cursor back. Path's assumed to be
  29. // MAXITEMPATHLEN long. The main reason for moving this out of the DlgProc was
  30. // because we're running out of stack space on the call to the comm dlg.
  31. BOOL NEAR PASCAL IconFileExists( LPPICKICON_DATA lppid )
  32. {
  33. TCHAR szTitle[128];
  34. TCHAR szInvPath[ 64 ];
  35. TCHAR szText[MAX_PATH+40];
  36. TCHAR szPath[MAX_PATH];
  37. LPTSTR psz;
  38. DWORD dwRet;
  39. if( lppid->szBuffer[0] == 0 )
  40. return FALSE;
  41. // Use the Win32 version instead of the shell version. The shell version
  42. // is/was really only there for 16-bit apps. (RickTu)
  43. //
  44. // DoEnvironmentSubst( lppid->szBuffer, sizeof(lppid->szBuffer) );
  45. //
  46. dwRet = ExpandEnvironmentStrings( lppid->szBuffer, szPath, MAX_PATH );
  47. if (dwRet > 0 && dwRet <= MAX_PATH)
  48. {
  49. lstrcpy( lppid->szBuffer, szPath );
  50. }
  51. // PathUnquoteSpaces( lppid->szBuffer ); // JER
  52. // if( PathResolve( lppid->szBuffer, NULL, PRF_VERIFYEXISTS | PRF_TRYPROGRAMEXTENSIONS ) ) // JER
  53. if (SearchPath(NULL, lppid->szBuffer, NULL, ARRAYSIZE(szPath), szPath, &psz) != 0)
  54. return TRUE;
  55. LoadString( g_hInst, IDS_BADPATHMSG, szTitle, ARRAYSIZE(szTitle) );
  56. LoadString( g_hInst, IDS_INVALIDPATH, szInvPath, ARRAYSIZE(szInvPath) );
  57. wsprintf( szText, szTitle, lppid->szBuffer );
  58. GetWindowText( lppid->hDlg, szTitle, sizeof(szTitle) );
  59. lstrcat( szTitle, szInvPath );
  60. MessageBox( GetDesktopWindow(), szText, szTitle , MB_OK | MB_ICONEXCLAMATION );
  61. return FALSE;
  62. }
  63. void NEAR PASCAL PutIconsInList( LPPICKICON_DATA lppid )
  64. {
  65. HICON *rgIcons;
  66. int iTempIcon;
  67. int cIcons;
  68. HWND hDlg = lppid->hDlg;
  69. //HCURSOR hOldCursor;
  70. SendDlgItemMessage( hDlg, IDD_ICON, LB_RESETCONTENT, 0, 0L );
  71. GetDlgItemText( hDlg, IDD_PATH, lppid->szPathField, sizeof(lppid->szPathField) );
  72. lstrcpy( lppid->szBuffer, lppid->szPathField );
  73. if( !IconFileExists(lppid) )
  74. {
  75. if( lppid->fFirstPass )
  76. {
  77. // Icon File doesn't exist, use progman
  78. lppid->fFirstPass = FALSE; // Only do this bit once.
  79. GetModuleFileName( g_hInst, lppid->szBuffer, ARRAYSIZE(lppid->szBuffer) );
  80. }
  81. else
  82. {
  83. return;
  84. }
  85. }
  86. lstrcpy( lppid->szPathField, lppid->szBuffer );
  87. SetDlgItemText( hDlg, IDD_PATH, lppid->szPathField );
  88. // hOldCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) );
  89. rgIcons = (HICON *)LocalAlloc(LPTR, MAX_ICONS*sizeof(HICON));
  90. if( rgIcons != NULL )
  91. cIcons = (int)ExtractIconEx( lppid->szBuffer, 0, rgIcons, NULL, MAX_ICONS );
  92. else
  93. cIcons = 0;
  94. // SetCursor( hOldCursor );
  95. if( !cIcons )
  96. {
  97. char szText[256];
  98. char szTitle[40];
  99. GetWindowText( lppid->hDlg, szTitle, sizeof(szTitle) );
  100. if( lppid->fFirstPass )
  101. {
  102. lppid->fFirstPass = FALSE; // Only do this bit once.
  103. LoadString( g_hInst, IDS_NOICONSMSG1, szText, 256 );
  104. MessageBox( GetDesktopWindow(), szText, szTitle, MB_OK | MB_ICONEXCLAMATION );
  105. // No icons here - change the path do somewhere where we
  106. // know there are icons. Get the path to progman.
  107. // GetModuleFileName( g_hInst, lppid->szPathField, sizeof(lppid->szPathField) );
  108. GetSystemDirectory( lppid->szPathField, sizeof(lppid->szPathField) );
  109. lstrcat( lppid->szPathField, "\\shell32.dll" );
  110. SetDlgItemText( hDlg, IDD_PATH, lppid->szPathField );
  111. PutIconsInList( lppid );
  112. }
  113. else
  114. {
  115. LoadString( g_hInst, IDS_NOICONSMSG, szText, 256 );
  116. MessageBox( GetDesktopWindow(), szText, szTitle, MB_OK | MB_ICONEXCLAMATION );
  117. return;
  118. }
  119. }
  120. // hOldCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) );
  121. SendDlgItemMessage( hDlg, IDD_ICON, WM_SETREDRAW, FALSE, 0L );
  122. if( rgIcons )
  123. {
  124. for( iTempIcon = 0; iTempIcon < cIcons; iTempIcon++ )
  125. {
  126. SendDlgItemMessage( hDlg, IDD_ICON, LB_ADDSTRING, 0, (LPARAM)(UINT)rgIcons[iTempIcon] );
  127. }
  128. LocalFree((HLOCAL)rgIcons);
  129. }
  130. if( SendDlgItemMessage( hDlg, IDD_ICON, LB_SETCURSEL, lppid->iIconIndex, 0L ) == LB_ERR )
  131. {
  132. // select the first.
  133. SendDlgItemMessage( hDlg, IDD_ICON, LB_SETCURSEL, 0, 0L );
  134. }
  135. SendDlgItemMessage( hDlg, IDD_ICON, WM_SETREDRAW, TRUE, 0L );
  136. InvalidateRect( GetDlgItem(hDlg, IDD_ICON), NULL, TRUE );
  137. // SetCursor( hOldCursor );
  138. }
  139. void NEAR PASCAL InitPickIconDlg( HWND hDlg, LPPICKICON_DATA lppid )
  140. {
  141. RECT rc;
  142. UINT cy;
  143. HWND hwndIcons;
  144. // init state variables
  145. lppid->hDlg = hDlg;
  146. lstrcpyn( lppid->szPathField, lppid->pszIconPath, sizeof(lppid->szPathField) );
  147. // this first pass stuff is so that the first time something bogus happens
  148. // (file not found, no icons) we give the user a list of icons from progman.
  149. lppid->fFirstPass = TRUE;
  150. // init the dialog controls
  151. SetDlgItemText( hDlg, IDD_PATH, lppid->pszIconPath );
  152. SendDlgItemMessage( hDlg, IDD_PATH, EM_LIMITTEXT, lppid->cbIconPath, 0L );
  153. SendDlgItemMessage( hDlg, IDD_ICON, LB_SETCOLUMNWIDTH, GetSystemMetrics(SM_CXICON) + 12, 0L );
  154. hwndIcons = GetDlgItem( hDlg, IDD_ICON );
  155. // compute the height of the listbox based on icon dimensions
  156. GetClientRect( hwndIcons, &rc );
  157. cy = GetSystemMetrics( SM_CYICON ) + GetSystemMetrics( SM_CYHSCROLL ) + GetSystemMetrics( SM_CYEDGE ) * 3;
  158. SetWindowPos( hwndIcons, NULL, 0, 0, rc.right, cy, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
  159. // REVIEW, explicitly position this dialog?
  160. cy = rc.bottom - cy;
  161. GetWindowRect( hDlg, &rc );
  162. rc.bottom -= rc.top;
  163. rc.right -= rc.left;
  164. rc.bottom = rc.bottom - cy;
  165. SetWindowPos( hDlg, NULL, 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE );
  166. PutIconsInList( lppid );
  167. }
  168. // call the common browse code for this
  169. BOOL NEAR PASCAL BrowseForIconFile( LPPICKICON_DATA lppid )
  170. {
  171. OPENFILENAME ofn;
  172. CHAR szFilter[256] = TEXT("Icon Files\0*.ico;*.exe;*.dll\0Programs (*.exe)\0*.exe\0Libraries (*.dll)\0*.dll\0Icons (*.ico)\0*.ico\0All Files (*.*)\0*.*\0\0");
  173. char szTitle[40];
  174. ZeroMemory(&ofn, sizeof(ofn));
  175. if (LoadString( g_hInst, IDS_ICONFILTER, szFilter, ARRAYSIZE(szFilter) ) != 0) {
  176. LPTSTR psz;
  177. for( psz = szFilter; *psz != TEXT('\0'); psz++ ) {
  178. #ifdef DBCS
  179. if ( IsDBCSLeadByte(*psz) ) {
  180. psz = CharNext(psz) - 1;
  181. continue;
  182. }
  183. #endif
  184. if (*psz == TEXT('\1')) {
  185. *psz = TEXT('\0');
  186. }
  187. }
  188. }
  189. GetWindowText( lppid->hDlg, szTitle, sizeof(szTitle) );
  190. GetDlgItemText( lppid->hDlg, IDD_PATH, lppid->szBuffer, sizeof(lppid->szBuffer) );
  191. ofn.lStructSize = sizeof(OPENFILENAME);
  192. ofn.hwndOwner = lppid->hDlg;
  193. ofn.lpstrFilter = szFilter;
  194. // ofn.lpstrCustomFilter = (LPSTR)NULL;
  195. // ofn.nMaxCustFilter = 0L;
  196. ofn.nFilterIndex = 1L;
  197. ofn.lpstrFile = lppid->szBuffer;
  198. ofn.nMaxFile = sizeof(lppid->szBuffer);
  199. // ofn.lpstrFileTitle = (LPSTR)NULL;
  200. // ofn.lpstrInitialDir = NULL;
  201. ofn.lpstrTitle = szTitle;
  202. ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST;
  203. // ofn.nFileOffset = 0;
  204. // ofn.nFileExtension = 0;
  205. // ofn.lCustData = 0;
  206. if( GetOpenFileName( &ofn ) )
  207. {
  208. // PathQuoteSpaces( lppid->szBuffer ); // JER
  209. SetDlgItemText( lppid->hDlg, IDD_PATH, lppid->szBuffer );
  210. // Set default button to OK.
  211. SendMessage( lppid->hDlg, DM_SETDEFID, IDOK, 0 );
  212. return TRUE;
  213. }
  214. else
  215. return FALSE;
  216. }
  217. // test if the name field is different from the last file we looked at
  218. BOOL NEAR PASCAL NameChange( LPPICKICON_DATA lppid )
  219. {
  220. GetDlgItemText( lppid->hDlg, IDD_PATH, lppid->szBuffer, sizeof(lppid->szBuffer) );
  221. return lstrcmpi(lppid->szBuffer, lppid->szPathField);
  222. }
  223. //
  224. // dialog procedure for picking an icon (ala progman change icon)
  225. // uses DLG_PICKICON template
  226. //
  227. // in:
  228. // pszIconFile
  229. // cbIconFile
  230. // iIndex
  231. //
  232. // out:
  233. // pszIconFile
  234. // iIndex
  235. //
  236. INT_PTR CALLBACK PickIconDlgProc( HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam )
  237. {
  238. LPPICKICON_DATA lppid = (LPPICKICON_DATA)GetWindowLong(hDlg, DWL_USER);
  239. // Array for context help:
  240. /*static DWORD aPickIconHelpIDs[] = { // JER
  241. IDD_PATH, IDH_FCAB_LINK_ICONNAME,
  242. IDD_ICON, IDH_FCAB_LINK_CURRENT_ICON,
  243. IDD_BROWSE, IDH_BROWSE,
  244. 0, 0
  245. };
  246. */
  247. switch( wMsg )
  248. {
  249. case WM_INITDIALOG:
  250. SetWindowLong( hDlg, DWL_USER, lParam );
  251. InitPickIconDlg( hDlg, (LPPICKICON_DATA)lParam );
  252. break;
  253. case WM_COMMAND:
  254. switch( GET_WM_COMMAND_ID(wParam, lParam) )
  255. {
  256. case IDHELP: // not wired
  257. break;
  258. case IDD_BROWSE:
  259. if( BrowseForIconFile( lppid ) )
  260. PutIconsInList( lppid );
  261. break;
  262. case IDD_PATH:
  263. if( NameChange( lppid ) )
  264. SendDlgItemMessage( hDlg, IDD_ICON, LB_SETCURSEL, (WPARAM)-1, 0 );
  265. break;
  266. case IDD_ICON:
  267. if( NameChange( lppid ) )
  268. {
  269. PutIconsInList( lppid );
  270. break;
  271. }
  272. if( GET_WM_COMMAND_CMD(wParam, lParam) != LBN_DBLCLK )
  273. break;
  274. /*** FALL THRU on double click ***/
  275. case IDOK:
  276. if( NameChange( lppid ) )
  277. {
  278. PutIconsInList( lppid );
  279. }
  280. else
  281. {
  282. int iIconIndex = (int)SendDlgItemMessage( hDlg, IDD_ICON, LB_GETCURSEL, 0, 0L );
  283. if( iIconIndex < 0 )
  284. iIconIndex = 0;
  285. lppid->iIconIndex = iIconIndex;
  286. lstrcpy( lppid->pszIconPath, lppid->szPathField );
  287. EndDialog( hDlg, TRUE );
  288. }
  289. break;
  290. case IDCANCEL:
  291. EndDialog( hDlg, FALSE );
  292. break;
  293. default:
  294. return( FALSE );
  295. }
  296. break;
  297. // owner draw messages for icon listbox
  298. case WM_DRAWITEM:
  299. #define lpdi ((DRAWITEMSTRUCT FAR *)lParam)
  300. if( lpdi->itemState & ODS_SELECTED )
  301. SetBkColor( lpdi->hDC, GetSysColor( COLOR_HIGHLIGHT ) );
  302. else
  303. SetBkColor( lpdi->hDC, GetSysColor( COLOR_WINDOW ) );
  304. /* repaint the selection state */
  305. ExtTextOut( lpdi->hDC, 0, 0, ETO_OPAQUE, &lpdi->rcItem, NULL, 0, NULL );
  306. /* draw the icon */
  307. if( (int)lpdi->itemID >= 0 )
  308. DrawIcon(lpdi->hDC, (lpdi->rcItem.left + lpdi->rcItem.right - GetSystemMetrics(SM_CXICON)) / 2,
  309. (lpdi->rcItem.bottom + lpdi->rcItem.top - GetSystemMetrics(SM_CYICON)) / 2, (HICON)lpdi->itemData);
  310. // InflateRect(&lpdi->rcItem, -1, -1);
  311. /* if it has the focus, draw the focus */
  312. if( lpdi->itemState & ODS_FOCUS )
  313. DrawFocusRect( lpdi->hDC, &lpdi->rcItem );
  314. #undef lpdi
  315. break;
  316. case WM_MEASUREITEM:
  317. #define lpmi ((MEASUREITEMSTRUCT FAR *)lParam)
  318. lpmi->itemWidth = GetSystemMetrics( SM_CXICON ) + 12;
  319. lpmi->itemHeight = GetSystemMetrics( SM_CYICON ) + 4;
  320. #undef lpmi
  321. break;
  322. case WM_DELETEITEM:
  323. #define lpdi ((DELETEITEMSTRUCT FAR *)lParam)
  324. DestroyIcon( (HICON)lpdi->itemData );
  325. #undef lpdi
  326. break;
  327. case WM_HELP:
  328. // WinHelp( ((LPHELPINFO) lParam)->hItemHandle, NULL, HELP_WM_HELP, (DWORD)(LPSTR) aPickIconHelpIDs ); // JER
  329. break;
  330. case WM_CONTEXTMENU:
  331. // WinHelp( (HWND) wParam, NULL, HELP_CONTEXTMENU, (DWORD)(LPVOID)aPickIconHelpIDs ); // JER
  332. break;
  333. default:
  334. return FALSE;
  335. }
  336. return TRUE;
  337. }
  338. // puts up the pick icon dialog
  339. int WINAPI PickIconDlg( HWND hwnd, LPSTR pszIconPath, UINT cbIconPath, int FAR *piIconIndex )
  340. {
  341. PICKICON_DATA *pid;
  342. int iResult;
  343. // if we are coming up from a 16->32 thunk. it is possible that SHELL32 will
  344. // not be loaded in this context, so we will load ourself if we are not loaded.
  345. // IsDllLoaded( g_hInst, "SHELL32" ); // JER
  346. pid = (PICKICON_DATA *)LocalAlloc( LPTR, sizeof(PICKICON_DATA) );
  347. if( pid == NULL )
  348. return 0;
  349. pid->pszIconPath = pszIconPath;
  350. pid->cbIconPath = cbIconPath;
  351. pid->iIconIndex = *piIconIndex;
  352. iResult = DialogBoxParam( g_hInst, MAKEINTRESOURCE(DLG_PICKICON), hwnd, PickIconDlgProc, (LPARAM)(LPPICKICON_DATA)pid );
  353. *piIconIndex = pid->iIconIndex;
  354. LocalFree( pid );
  355. return iResult;
  356. }