pickicon.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 14k
Category:

Windows Kernel

Development Platform:

Visual C++

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