/* * ICON.CPP * * Implements the OleUIChangeIcon function which invokes the complete * Change Icon dialog. * * Copyright (c)1992 Microsoft Corporation, All Right Reserved */ #include "precomp.h" #include "common.h" #include "utility.h" #include "iconbox.h" OLEDBGDATA ULONG MyGetLongPathName(LPCTSTR pcsPath, LPTSTR pcsLongPath, ULONG cchLongPath); #define CXICONPAD (12) #define CYICONPAD (4) // Internally used structure typedef struct tagCHANGEICON { LPOLEUICHANGEICON lpOCI; //Original structure passed. UINT nIDD; // IDD of dialog (used for help info) /* * What we store extra in this structure besides the original caller's * pointer are those fields that we need to modify during the life of * the dialog but that we don't want to change in the original structure * until the user presses OK. */ DWORD dwFlags; HICON hCurIcon; TCHAR szLabel[OLEUI_CCHLABELMAX+1]; TCHAR szFile[MAX_PATH]; UINT iIcon; HICON hDefIcon; TCHAR szDefIconFile[MAX_PATH]; UINT iDefIcon; UINT nBrowseHelpID; // Help ID callback for Browse dlg } CHANGEICON, *PCHANGEICON, FAR *LPCHANGEICON; // Internal function prototypes // ICON.CPP INT_PTR CALLBACK ChangeIconDialogProc(HWND, UINT, WPARAM, LPARAM); BOOL FChangeIconInit(HWND, WPARAM, LPARAM); UINT UFillIconList(HWND, UINT, LPTSTR, BOOL); BOOL FDrawListIcon(LPDRAWITEMSTRUCT); void UpdateResultIcon(LPCHANGEICON, HWND, UINT); /* * OleUIChangeIcon * * Purpose: * Invokes the standard OLE Change Icon dialog box allowing the user * to select an icon from an icon file, executable, or DLL. * * Parameters: * lpCI LPOLEUIChangeIcon pointing to the in-out structure * for this dialog. * * Return Value: * UINT OLEUI_SUCCESS or OLEUI_OK if all is well, otherwise * an error value. */ STDAPI_(UINT) OleUIChangeIcon(LPOLEUICHANGEICON lpCI) { HGLOBAL hMemDlg = NULL; UINT uRet = UStandardValidation((LPOLEUISTANDARD)lpCI, sizeof(OLEUICHANGEICON), &hMemDlg); if (OLEUI_SUCCESS != uRet) return uRet; // Check for a valid hMetaPict. if (NULL == lpCI->hMetaPict && NULL == lpCI->szIconExe && CLSID_NULL == lpCI->clsid) { return(OLEUI_CIERR_MUSTHAVECURRENTMETAFILE); } if (lpCI->hMetaPict != NULL && !IsValidMetaPict(lpCI->hMetaPict)) { return(OLEUI_CIERR_MUSTHAVECURRENTMETAFILE); } // Test to be sure that the class ID matches a registered class ID // so we can return OLEUI_CIERR_MUSTHAVECLSID if necessary. HGLOBAL hTemp = OleGetIconOfClass(lpCI->clsid, NULL, TRUE); if (hTemp == NULL) { return(OLEUI_CIERR_MUSTHAVECLSID); } OleUIMetafilePictIconFree(hTemp); if (lpCI->dwFlags & CIF_USEICONEXE && (lpCI->cchIconExe < 1 || lpCI->cchIconExe > MAX_PATH)) { uRet = OLEUI_CIERR_SZICONEXEINVALID; } if (OLEUI_ERR_STANDARDMIN <= uRet) { return uRet; } // Now that we've validated everything, we can invoke the dialog. uRet = UStandardInvocation(ChangeIconDialogProc, (LPOLEUISTANDARD)lpCI, hMemDlg, MAKEINTRESOURCE(IDD_CHANGEICON)); return uRet; } /* * ChangeIconDialogProc * * Purpose: * Implements the OLE Change Icon dialog as invoked through the * OleUIChangeIcon function. * * Parameters: * Standard * * Return Value: * Standard */ INT_PTR CALLBACK ChangeIconDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) { // Declare Win16/Win32 compatible WM_COMMAND parameters. COMMANDPARAMS(wID, wCode, hWndMsg); UINT uRet = 0; LPCHANGEICON lpCI = (LPCHANGEICON)LpvStandardEntry(hDlg, iMsg, wParam, lParam, &uRet); // If the hook processed the message, we're done. if (0 != uRet) return (INT_PTR)uRet; // Process the temination message if (iMsg == uMsgEndDialog) { EndDialog(hDlg, wParam); return TRUE; } TCHAR szTemp[MAX_PATH]; HICON hIcon; HGLOBAL hMetaPict; switch (iMsg) { case WM_DESTROY: if (lpCI) { SendDlgItemMessage(hDlg, IDC_CI_ICONLIST, LB_RESETCONTENT, 0, 0L); StandardCleanup(lpCI, hDlg); } break; case WM_INITDIALOG: FChangeIconInit(hDlg, wParam, lParam); return TRUE; case WM_MEASUREITEM: { LPMEASUREITEMSTRUCT lpMI = (LPMEASUREITEMSTRUCT)lParam; // All icons are system metric+padding in width and height lpMI->itemWidth = GetSystemMetrics(SM_CXICON)+CXICONPAD; lpMI->itemHeight= GetSystemMetrics(SM_CYICON)+CYICONPAD; } break; case WM_DRAWITEM: return FDrawListIcon((LPDRAWITEMSTRUCT)lParam); case WM_DELETEITEM: DestroyIcon((HICON)(((LPDELETEITEMSTRUCT)lParam)->itemData)); break; case WM_COMMAND: switch (wID) { case IDC_CI_CURRENT: case IDC_CI_DEFAULT: case IDC_CI_FROMFILE: if (lpCI != NULL) UpdateResultIcon(lpCI, hDlg, (UINT)-1); break; case IDC_CI_LABELEDIT: if (lpCI != NULL && EN_KILLFOCUS == wCode) UpdateResultIcon(lpCI, hDlg, (UINT)-1); break; case IDC_CI_FROMFILEEDIT: GetDlgItemText(hDlg, IDC_CI_FROMFILEEDIT, szTemp, sizeof(szTemp)/sizeof(TCHAR)); if (lpCI != NULL) { if (wCode == EN_KILLFOCUS) { if (lstrcmpi(szTemp, lpCI->szFile)) { lstrcpy(lpCI->szFile, szTemp); UFillIconList(hDlg, IDC_CI_ICONLIST, lpCI->szFile, FALSE); UpdateResultIcon(lpCI, hDlg, IDC_CI_FROMFILE); } } else if (wCode == EN_SETFOCUS) { UpdateResultIcon(lpCI, hDlg, IDC_CI_FROMFILE); } } break; case IDC_CI_ICONLIST: switch (wCode) { case LBN_SETFOCUS: // If we got the focus, see about updating. GetDlgItemText(hDlg, IDC_CI_FROMFILEEDIT, szTemp, sizeof(szTemp)/sizeof(TCHAR)); // Check if file changed and update the list if so if (lpCI && 0 != lstrcmpi(szTemp, lpCI->szFile)) { lstrcpy(lpCI->szFile, szTemp); UFillIconList(hDlg, IDC_CI_ICONLIST, lpCI->szFile, FALSE); } UpdateResultIcon(lpCI, hDlg, IDC_CI_FROMFILE); break; case LBN_SELCHANGE: UpdateResultIcon(lpCI, hDlg, IDC_CI_FROMFILE); break; case LBN_DBLCLK: SendCommand(hDlg, IDOK, BN_CLICKED, hWndMsg); break; } break; case IDC_CI_BROWSE: { lstrcpyn(szTemp, lpCI->szFile, sizeof(szTemp)/sizeof(TCHAR)); uRet = UStandardHook(lpCI, hDlg, uMsgBrowse, MAX_PATH_SIZE, (LPARAM)lpCI->szFile); DWORD dwOfnFlags = OFN_FILEMUSTEXIST; if (lpCI->lpOCI->dwFlags & CIF_SHOWHELP) dwOfnFlags |= OFN_SHOWHELP; if (0 == uRet) { uRet = (BOOL)Browse(hDlg, lpCI->szFile, NULL, MAX_PATH_SIZE, IDS_ICONFILTERS, dwOfnFlags, ID_BROWSE_CHANGEICON, NULL); } if (0 != uRet && 0 != lstrcmpi(szTemp, lpCI->szFile)) { SetDlgItemText(hDlg, IDC_CI_FROMFILEEDIT, lpCI->szFile); UFillIconList(hDlg, IDC_CI_ICONLIST, lpCI->szFile, TRUE); UpdateResultIcon(lpCI, hDlg, IDC_CI_FROMFILE); } } break; case IDOK: { HWND hwndCtl = GetDlgItem(hDlg, IDOK); if (hwndCtl == GetFocus()) { GetDlgItemText(hDlg, IDC_CI_FROMFILEEDIT, szTemp, sizeof(szTemp)/sizeof(TCHAR)); // Check if the file name is valid // if SelectFromFile radio button selected if (lpCI->dwFlags & CIF_SELECTFROMFILE) { // Check if the file changed at all. if (0 != lstrcmpi(szTemp, lpCI->szFile)) { lstrcpy(lpCI->szFile, szTemp); // file changed. May need to expand the name // calling DoesFileExist will do the trick DoesFileExist(lpCI->szFile, MAX_PATH); UFillIconList(hDlg, IDC_CI_ICONLIST, lpCI->szFile, TRUE); SetDlgItemText(hDlg, IDC_CI_FROMFILEEDIT, lpCI->szFile); UpdateResultIcon(lpCI, hDlg, IDC_CI_FROMFILE); return TRUE; // eat this message to prevent focus change. } if (!DoesFileExist(lpCI->szFile, MAX_PATH)) { OpenFileError(hDlg, ERROR_FILE_NOT_FOUND, lpCI->szFile); HWND hWnd = GetDlgItem(hDlg, IDC_CI_FROMFILEEDIT); SetFocus(hWnd); SendMessage(hWnd, EM_SETSEL, 0, -1); return TRUE; // eat this message } } // Get current metafile image UpdateResultIcon(lpCI, hDlg, (UINT)-1); hMetaPict = (HGLOBAL)SendDlgItemMessage(hDlg, IDC_CI_ICONDISPLAY, IBXM_IMAGEGET, 0, 0); // Clean up the current icon that we extracted. hIcon = (HICON)SendDlgItemMessage(hDlg, IDC_CI_CURRENTICON, STM_GETICON, 0, 0L); DestroyIcon(hIcon); // Clean up the default icon DestroyIcon(lpCI->hDefIcon); // Remove the prop set on our parent RemoveProp(lpCI->lpOCI->hWndOwner, PROP_HWND_CHGICONDLG); OleUIMetafilePictIconFree(lpCI->lpOCI->hMetaPict); lpCI->lpOCI->hMetaPict = hMetaPict; lpCI->lpOCI->dwFlags = lpCI->dwFlags; SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L); } else { SetFocus(hwndCtl); SendCommand(hDlg, IDOK, BN_CLICKED, hWndMsg); } break; } case IDCANCEL: // Free current icon display image SendDlgItemMessage(hDlg, IDC_CI_ICONDISPLAY, IBXM_IMAGEFREE, 0, 0); // Clean up the current icon that we extracted. hIcon = (HICON)SendDlgItemMessage(hDlg, IDC_CI_CURRENTICON, STM_GETICON, 0, 0L); DestroyIcon(hIcon); // Clean up the default icon DestroyIcon(lpCI->hDefIcon); // Remove the prop set on our parent RemoveProp(lpCI->lpOCI->hWndOwner, PROP_HWND_CHGICONDLG); // We leave hMetaPict intact on Cancel; caller's responsibility SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L); break; case IDC_OLEUIHELP: PostMessage(lpCI->lpOCI->hWndOwner, uMsgHelp, (WPARAM)hDlg, MAKELPARAM(IDD_CHANGEICON, 0)); break; } break; default: if (lpCI && iMsg == lpCI->nBrowseHelpID) { PostMessage(lpCI->lpOCI->hWndOwner, uMsgHelp, (WPARAM)hDlg, MAKELPARAM(IDD_CHANGEICONBROWSE, 0)); } if (iMsg == uMsgBrowseOFN && lpCI && lpCI->lpOCI && lpCI->lpOCI->hWndOwner) { SendMessage(lpCI->lpOCI->hWndOwner, uMsgBrowseOFN, wParam, lParam); } break; } return FALSE; } /* * FChangeIconInit * * Purpose: * WM_INITIDIALOG handler for the Change Icon dialog box. * * Parameters: * hDlg HWND of the dialog * wParam WPARAM of the message * lParam LPARAM of the message * * Return Value: * BOOL Value to return for WM_INITDIALOG. */ BOOL FChangeIconInit(HWND hDlg, WPARAM wParam, LPARAM lParam) { // Copy the structure at lParam into our instance memory. LPCHANGEICON lpCI = (LPCHANGEICON)LpvStandardInit(hDlg, sizeof(CHANGEICON)); // LpvStandardInit send a termination to us already. if (NULL == lpCI) return FALSE; // Save the original pointer and copy necessary information. LPOLEUICHANGEICON lpOCI = (LPOLEUICHANGEICON)lParam; lpCI->lpOCI = lpOCI; lpCI->nIDD = IDD_CHANGEICON; lpCI->dwFlags = lpOCI->dwFlags; // Go extract the icon source from the metafile. TCHAR szTemp[MAX_PATH]; szTemp[0] = 0; OleUIMetafilePictExtractIconSource(lpOCI->hMetaPict, szTemp, &lpCI->iIcon); MyGetLongPathName(szTemp, lpCI->szFile, MAX_PATH); // Go extract the icon and the label from the metafile OleUIMetafilePictExtractLabel(lpOCI->hMetaPict, lpCI->szLabel, OLEUI_CCHLABELMAX_SIZE, NULL); lpCI->hCurIcon = OleUIMetafilePictExtractIcon(lpOCI->hMetaPict); // Show or hide the help button if (!(lpCI->dwFlags & CIF_SHOWHELP)) StandardShowDlgItem(hDlg, IDC_OLEUIHELP, SW_HIDE); // Set text limits and initial control contents SendDlgItemMessage(hDlg, IDC_CI_LABELEDIT, EM_LIMITTEXT, OLEUI_CCHLABELMAX, 0L); SendDlgItemMessage(hDlg, IDC_CI_FROMFILEEDIT, EM_LIMITTEXT, MAX_PATH, 0L); SetDlgItemText(hDlg, IDC_CI_FROMFILEEDIT, lpCI->szFile); // Copy the label text into the edit and static controls. SetDlgItemText(hDlg, IDC_CI_LABELEDIT, lpCI->szLabel); lpCI->hDefIcon = NULL; if (lpCI->dwFlags & CIF_USEICONEXE) { lpCI->hDefIcon = StandardExtractIcon(_g_hOleStdInst, lpCI->lpOCI->szIconExe, 0); if (NULL != lpCI->hDefIcon) { lstrcpy(lpCI->szDefIconFile, lpCI->lpOCI->szIconExe); lpCI->iDefIcon = 0; } } if (NULL == lpCI->hDefIcon) { HGLOBAL hMetaPict; hMetaPict = OleGetIconOfClass(lpCI->lpOCI->clsid, NULL, TRUE); lpCI->hDefIcon = OleUIMetafilePictExtractIcon(hMetaPict); TCHAR szTemp[MAX_PATH]; OleUIMetafilePictExtractIconSource(hMetaPict, szTemp, &lpCI->iDefIcon); MyGetLongPathName(szTemp, lpCI->szDefIconFile, MAX_PATH); OleUIMetafilePictIconFree(hMetaPict); } // Initialize all the icon displays. SendDlgItemMessage(hDlg, IDC_CI_CURRENTICON, STM_SETICON, (WPARAM)lpCI->hCurIcon, 0L); SendDlgItemMessage(hDlg, IDC_CI_DEFAULTICON, STM_SETICON, (WPARAM)lpCI->hDefIcon, 0L); /* * Since we cannot predict the size of icons on any display, * we have to resize the icon listbox to the size of an icon * (plus padding), a scrollbar, and two borders (top & bottom). */ UINT cyList = GetSystemMetrics(SM_CYICON)+GetSystemMetrics(SM_CYHSCROLL) +GetSystemMetrics(SM_CYBORDER)*2+CYICONPAD; HWND hList = GetDlgItem(hDlg, IDC_CI_ICONLIST); RECT rc; GetClientRect(hList, &rc); SetWindowPos(hList, NULL, 0, 0, rc.right, cyList, SWP_NOMOVE | SWP_NOZORDER); // Set the columns in this multi-column listbox to hold one icon SendMessage(hList, LB_SETCOLUMNWIDTH, GetSystemMetrics(SM_CXICON)+CXICONPAD,0L); /* * If the listbox expanded below the group box, then size * the groupbox down, move the label static and exit controls * down, and expand the entire dialog appropriately. */ GetWindowRect(hList, &rc); RECT rcG; GetWindowRect(GetDlgItem(hDlg, IDC_CI_GROUP), &rcG); if (rc.bottom > rcG.bottom) { // Calculate amount to move things down. cyList=(rcG.bottom-rcG.top)-(rc.bottom-rc.top-cyList); // Expand the group box. rcG.right -=rcG.left; rcG.bottom-=rcG.top; SetWindowPos(GetDlgItem(hDlg, IDC_CI_GROUP), NULL, 0, 0, rcG.right, rcG.bottom+cyList, SWP_NOMOVE | SWP_NOZORDER); // Expand the dialog box. GetClientRect(hDlg, &rc); SetWindowPos(hDlg, NULL, 0, 0, rc.right, rc.bottom+cyList, SWP_NOMOVE | SWP_NOZORDER); // Move the label and edit controls down. GetClientRect(GetDlgItem(hDlg, IDC_CI_LABEL), &rc); SetWindowPos(GetDlgItem(hDlg, IDC_CI_LABEL), NULL, 0, cyList, rc.right, rc.bottom, SWP_NOSIZE | SWP_NOZORDER); GetClientRect(GetDlgItem(hDlg, IDC_CI_LABELEDIT), &rc); SetWindowPos(GetDlgItem(hDlg, IDC_CI_LABELEDIT), NULL, 0, cyList, rc.right, rc.bottom, SWP_NOSIZE | SWP_NOZORDER); } /* * Select Current, Default, or From File radiobuttons appropriately. * The CheckRadioButton call sends WM_COMMANDs which handle * other actions. Note that if we check From File, which * takes an icon from the list, we better fill the list. * This will also fill the list even if default is selected. */ if (0 != UFillIconList(hDlg, IDC_CI_ICONLIST, lpCI->szFile, FALSE)) { // If szFile worked, then select the source icon in the listbox. SendDlgItemMessage(hDlg, IDC_CI_ICONLIST, LB_SETCURSEL, lpCI->iIcon, 0L); } if (lpCI->dwFlags & CIF_SELECTCURRENT) { CheckRadioButton(hDlg, IDC_CI_CURRENT, IDC_CI_FROMFILE, IDC_CI_CURRENT); } else { UINT uID = (lpCI->dwFlags & CIF_SELECTFROMFILE) ? IDC_CI_FROMFILE : IDC_CI_DEFAULT; CheckRadioButton(hDlg, IDC_CI_CURRENT, IDC_CI_FROMFILE, uID); } UpdateResultIcon(lpCI, hDlg, (UINT)-1); // Change the caption if (NULL!=lpOCI->lpszCaption) SetWindowText(hDlg, lpOCI->lpszCaption); /* Give our parent window access to our hDlg (via a special SetProp). * The PasteSpecial dialog may need to force our dialog down if the * clipboard contents change underneath it. if so it will send * us a IDCANCEL command. */ SetProp(lpCI->lpOCI->hWndOwner, PROP_HWND_CHGICONDLG, hDlg); lpCI->nBrowseHelpID = RegisterWindowMessage(HELPMSGSTRING); // Call the hook with lCustData in lParam UStandardHook(lpCI, hDlg, WM_INITDIALOG, wParam, lpOCI->lCustData); return TRUE; } /* * UFillIconList * * Purpose: * Given a listbox and a filename, attempts to open that file and * read all the icons that exist therein, adding them to the listbox * hList as owner-draw items. If the file does not exist or has no * icons, then you get no icons and an appropriate warning message. * * Parameters: * hDlg HWND of the dialog containing the listbox. * idList UINT identifier of the listbox to fill. * pszFile LPSTR of the file from which to extract icons. * * Return Value: * UINT Number of items added to the listbox. 0 on failure. */ UINT UFillIconList(HWND hDlg, UINT idList, LPTSTR pszFile, BOOL bError) { HWND hList = GetDlgItem(hDlg, idList); if (NULL == hList) return 0; // Clean out the listbox. SendMessage(hList, LB_RESETCONTENT, 0, 0L); // If we have an empty string, just exit leaving the listbox empty as well if (0 == lstrlen(pszFile)) return 0; // Turn on the hourglass HCURSOR hCur = HourGlassOn(); UINT nFileError = 0; // Check if the file is valid. TCHAR szPathName[MAX_PATH]; LPTSTR lpszFilePart = NULL; UINT cIcons = 0; if (SearchPath(NULL, pszFile, NULL, MAX_PATH, szPathName, &lpszFilePart) != 0) { // This hack is still necessary in Win32 because even under // Win32s this ExtractIcon bug appears. #ifdef EXTRACTICONWORKS // Get the icon count for this file. cIcons = (UINT)StandardExtractIcon(_g_hOleStdInst, szPathName, (UINT)-1); #else /* * ExtractIcon in Windows 3.1 with -1 eats a selector, leaving an * extra global memory object around for this applciation. Since * changing icons may happen very often with all OLE apps in * the system, we have to work around it. So we'll say we * have lots of icons and just call ExtractIcon until it * fails. We check if there's any around by trying to get * the first one. */ cIcons = 0xFFFF; HICON hIcon = StandardExtractIcon(_g_hOleStdInst, szPathName, 0); // Fake a failure with cIcons=0, or cleanup hIcon from this test. if (NULL == hIcon || 1 == HandleToUlong(hIcon)) cIcons = 0; else DestroyIcon(hIcon); #endif if (0 != cIcons) { SendMessage(hList, WM_SETREDRAW, FALSE, 0L); for (UINT i = 0; i < cIcons; i++) { hIcon=StandardExtractIcon(_g_hOleStdInst, szPathName, i); if (hIcon != NULL) SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)hIcon); else break; } //Force complete repaint SendMessage(hList, WM_SETREDRAW, TRUE, 0L); InvalidateRect(hList, NULL, TRUE); //Select an icon SendMessage(hList, LB_SETCURSEL, 0, 0L); } else nFileError = IDS_CINOICONSINFILE; } else nFileError = ERROR_FILE_NOT_FOUND; // show error if necessary and possible if (nFileError && bError) { ErrorWithFile(hDlg, _g_hOleStdResInst, nFileError, szPathName, MB_OK | MB_ICONEXCLAMATION); } HourGlassOff(hCur); return cIcons; } /* * FDrawListIcon * * Purpose: * Handles WM_DRAWITEM for the icon listbox. * * Parameters: * lpDI LPDRAWITEMSTRUCT from WM_DRAWITEM * * Return Value: * BOOL TRUE if we did anything, FALSE if there are no items * in the list. */ BOOL FDrawListIcon(LPDRAWITEMSTRUCT lpDI) { /* * If there are no items in the list, then itemID is negative according * to the Win3.1 SDK. Unfortunately DRAWITEMSTRUCT has an unsigned int * for this field, so we need the typecast to do a signed comparison. */ if ((int)lpDI->itemID < 0) return FALSE; /* * For selection or draw entire case we just draw the entire item all * over again. For focus cases, we only call DrawFocusRect. */ if (lpDI->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)) { COLORREF cr; // Clear background and draw the icon. if (lpDI->itemState & ODS_SELECTED) cr = SetBkColor(lpDI->hDC, GetSysColor(COLOR_HIGHLIGHT)); else cr = SetBkColor(lpDI->hDC, GetSysColor(COLOR_WINDOW)); // Draw a cheap rectangle. ExtTextOut(lpDI->hDC, 0, 0, ETO_OPAQUE, &lpDI->rcItem, NULL, 0, NULL); DrawIcon(lpDI->hDC, lpDI->rcItem.left+(CXICONPAD/2), lpDI->rcItem.top+(CYICONPAD/2), (HICON)(lpDI->itemData)); // Restore original background for DrawFocusRect SetBkColor(lpDI->hDC, cr); } // Always change focus on the focus action. if (lpDI->itemAction & ODA_FOCUS || lpDI->itemState & ODS_FOCUS) DrawFocusRect(lpDI->hDC, &lpDI->rcItem); return TRUE; } /* * UpdateResultIcon * * Purpose: * Updates the result icon using the current icon in the default display * or the icon listbox depending on fFromDefault. * * Parameters: * lpCI LPCHANGEICON containing dialog flags. * hDlg HWND of the dialog * uID UINT identifying the radiobutton selected. * * Return Value: * None */ void UpdateResultIcon(LPCHANGEICON lpCI, HWND hDlg, UINT uID) { if (uID == -1) { if (SendDlgItemMessage(hDlg, IDC_CI_CURRENT, BM_GETCHECK, 0, 0)) uID = IDC_CI_CURRENT; else if (SendDlgItemMessage(hDlg, IDC_CI_DEFAULT, BM_GETCHECK, 0, 0)) uID = IDC_CI_DEFAULT; else if (SendDlgItemMessage(hDlg, IDC_CI_FROMFILE, BM_GETCHECK, 0, 0)) uID = IDC_CI_FROMFILE; } lpCI->dwFlags &= ~(CIF_SELECTCURRENT | CIF_SELECTDEFAULT | CIF_SELECTFROMFILE); LRESULT lTemp = -1; switch (uID) { case IDC_CI_CURRENT: lTemp = SendDlgItemMessage(hDlg, IDC_CI_CURRENTICON, STM_GETICON, 0, 0L); lpCI->dwFlags |= CIF_SELECTCURRENT; break; case IDC_CI_DEFAULT: lTemp = SendDlgItemMessage(hDlg, IDC_CI_DEFAULTICON, STM_GETICON, 0, 0L); lpCI->dwFlags |= CIF_SELECTDEFAULT; break; case IDC_CI_FROMFILE: { // Get the selected icon from the list and place it in the result lpCI->dwFlags |= CIF_SELECTFROMFILE; UINT iSel = (UINT)SendDlgItemMessage(hDlg, IDC_CI_ICONLIST, LB_GETCURSEL, 0, 0L); if (LB_ERR == (int)iSel) lTemp = SendDlgItemMessage(hDlg, IDC_CI_DEFAULTICON, STM_GETICON, 0, 0L); else lTemp = SendDlgItemMessage(hDlg, IDC_CI_ICONLIST, LB_GETITEMDATA, iSel, 0); break; } default: OleDbgAssert(FALSE); break; } CheckRadioButton(hDlg, IDC_CI_CURRENT, IDC_CI_FROMFILE, uID); // set current icon display as a result of the controls LPTSTR lpszSourceFile = lpCI->szFile; if (lpCI->dwFlags & CIF_SELECTDEFAULT) { // use defaults lpszSourceFile = lpCI->szDefIconFile; lpCI->iIcon = lpCI->iDefIcon; } else if (lpCI->dwFlags & CIF_SELECTCURRENT) { TCHAR szTemp[MAX_PATH]; OleUIMetafilePictExtractIconSource(lpCI->lpOCI->hMetaPict, szTemp, &lpCI->iIcon); MyGetLongPathName(szTemp, lpszSourceFile, MAX_PATH); } else if (lpCI->dwFlags & CIF_SELECTFROMFILE) { // get from file and index GetDlgItemText(hDlg, IDC_CI_FROMFILEEDIT, lpszSourceFile, MAX_PATH); lpCI->iIcon = (UINT)SendDlgItemMessage(hDlg, IDC_CI_ICONLIST, LB_GETCURSEL, 0, 0L); } // Get new hMetaPict and set result text TCHAR szTemp[MAX_PATH]; GetDlgItemText(hDlg, IDC_CI_LABELEDIT, szTemp, MAX_PATH); TCHAR szShortFile[MAX_PATH]; GetShortPathName(lpszSourceFile, szShortFile, MAX_PATH); #if defined(WIN32) && !defined(UNICODE) OLECHAR wszTemp[MAX_PATH]; OLECHAR wszSourceFile[MAX_PATH]; ATOW(wszTemp, szTemp, MAX_PATH); ATOW(wszSourceFile, szShortFile, MAX_PATH); HGLOBAL hMetaPict = OleMetafilePictFromIconAndLabel( (HICON)lTemp, wszTemp, wszSourceFile, lpCI->iIcon); #else HGLOBAL hMetaPict = OleMetafilePictFromIconAndLabel( (HICON)lTemp, szTemp, szShortFile, lpCI->iIcon); #endif SendDlgItemMessage(hDlg, IDC_CI_ICONDISPLAY, IBXM_IMAGESET, 1, (LPARAM)hMetaPict); } //+--------------------------------------------------------------------------- // // Function: IsLongComponent, public // // Synopsis: Determines whether the current path component is a legal // 8.3 name or not. If not, it is considered to be a long // component. // // Arguments: [pwcsPath] - Path to check // [ppwcsEnd] - Return for end of component pointer // // Returns: BOOL // // Modifies: [ppwcsEnd] // // History: 28-Aug-94 DrewB Created // 5-04-95 stevebl Modified for use by oledlg // // Notes: An empty path is considered to be long // The following characters are not valid in file name domain: // * + , : ; < = > ? [ ] | // //---------------------------------------------------------------------------- BOOL IsLongComponent(LPCTSTR pwcsPath, PTSTR *ppwcsEnd) { LPTSTR pwcEnd, pwcDot; BOOL fLongNameFound; TCHAR wc; pwcEnd = (LPTSTR)pwcsPath; fLongNameFound = FALSE; pwcDot = NULL; while (TRUE) { wc = *pwcEnd; if (wc == '\\' || wc == 0) { *ppwcsEnd = pwcEnd; // We're at a component terminator, so make the // determination of whether what we've seen is a long // name or short one // If we've aready seen illegal characters or invalid // structure for a short name, don't bother to check lengths if (pwcEnd-pwcsPath > 0 && !fLongNameFound) { // If this component fits in 8.3 then it is a short name if ((!pwcDot && (ULONG)(pwcEnd - pwcsPath) <= 8) || (pwcDot && ((ULONG)(pwcEnd - pwcDot) <= 3 + 1 && (ULONG)(pwcEnd - pwcsPath) <= 8 + 3 + 1))) { return FALSE; } } return TRUE; } // Handle dots if (wc == '.') { // If two or more '.' or the base name is longer than // 8 characters or no base name at all, it is an illegal dos // file name if (pwcDot != NULL || ((ULONG)(pwcEnd - pwcsPath)) > 8 || (pwcEnd == pwcsPath && *(pwcEnd + 1) != '\\')) { fLongNameFound = TRUE; } pwcDot = pwcEnd; } // Check for characters which aren't valid in short names else if (wc <= ' ' || wc == '*' || wc == '+' || wc == ',' || wc == ':' || wc == ';' || wc == '<' || wc == '=' || wc == '>' || wc == '?' || wc == '[' || wc == ']' || wc == '|') { fLongNameFound = TRUE; } pwcEnd++; } } // // The following code was stolen from NT's RTL in curdir.c // #define IS_PATH_SEPARATOR(wch) \ ((wch) == '\\' || (wch) == '/') typedef enum { PATH_TYPE_UNKNOWN, PATH_TYPE_UNC_ABSOLUTE, PATH_TYPE_LOCAL_DEVICE, PATH_TYPE_ROOT_LOCAL_DEVICE, PATH_TYPE_DRIVE_ABSOLUTE, PATH_TYPE_DRIVE_RELATIVE, PATH_TYPE_ROOTED, PATH_TYPE_RELATIVE } PATH_TYPE; PATH_TYPE DetermineDosPathNameType( IN LPCTSTR DosFileName ) /*++ Routine Description: This function examines the Dos format file name and determines the type of file name (i.e. UNC, DriveAbsolute, Current Directory rooted, or Relative. Arguments: DosFileName - Supplies the Dos format file name whose type is to be determined. Return Value: PATH_TYPE_UNKNOWN - The path type can not be determined PATH_TYPE_UNC_ABSOLUTE - The path specifies a Unc absolute path in the format \\server-name\sharename\rest-of-path PATH_TYPE_LOCAL_DEVICE - The path specifies a local device in the format \\.\rest-of-path this can be used for any device where the nt and Win32 names are the same. For example mailslots. PATH_TYPE_ROOT_LOCAL_DEVICE - The path specifies the root of the local devices in the format \\. PATH_TYPE_DRIVE_ABSOLUTE - The path specifies a drive letter absolute path in the form drive:\rest-of-path PATH_TYPE_DRIVE_RELATIVE - The path specifies a drive letter relative path in the form drive:rest-of-path PATH_TYPE_ROOTED - The path is rooted relative to the current disk designator (either Unc disk, or drive). The form is \rest-of-path. PATH_TYPE_RELATIVE - The path is relative (i.e. not absolute or rooted). --*/ { PATH_TYPE ReturnValue; if ( IS_PATH_SEPARATOR(*DosFileName) ) { if ( IS_PATH_SEPARATOR(*(DosFileName+1)) ) { if ( DosFileName[2] == '.' ) { if ( IS_PATH_SEPARATOR(*(DosFileName+3)) ) { ReturnValue = PATH_TYPE_LOCAL_DEVICE; } else if ( (*(DosFileName+3)) == 0 ) { ReturnValue = PATH_TYPE_ROOT_LOCAL_DEVICE; } else { ReturnValue = PATH_TYPE_UNC_ABSOLUTE; } } else { ReturnValue = PATH_TYPE_UNC_ABSOLUTE; } } else { ReturnValue = PATH_TYPE_ROOTED; } } else if (*(DosFileName+1) == ':') { if (IS_PATH_SEPARATOR(*(DosFileName+2))) { ReturnValue = PATH_TYPE_DRIVE_ABSOLUTE; } else { ReturnValue = PATH_TYPE_DRIVE_RELATIVE; } } else { ReturnValue = PATH_TYPE_RELATIVE; } return ReturnValue; } //+--------------------------------------------------------------------------- // // Function: MyGetLongPathName, public // // Synopsis: Expand each component of the given path into its // long form // // Arguments: [pwcsPath] - Path // [pwcsLongPath] - Long path return buffer // [cchLongPath] - Size of return buffer in characters // // Returns: 0 for errors // Number of characters needed for buffer if buffer is too small // includes NULL terminator // Length of long path, doesn't include NULL terminator // // Modifies: [pwcsLongPath] // // History: 28-Aug-94 DrewB Created // 11-Nov-94 BruceMa Modifed to use for Chicago at // FindFirstFile // 5-04-95 stevebl Modified for use by OLEDLG // // Notes: The source and destination buffers can be the same memory // Doesn't handle paths with internal . and .., although // they are handled at the beginning // //---------------------------------------------------------------------------- ULONG MyGetLongPathName(LPCTSTR pcsPath, LPTSTR pwcsLongPath, ULONG cchLongPath) { PATH_TYPE pt; HANDLE h; LPTSTR pwcsLocalLongPath; ULONG cchReturn, cb, cch, cchOutput; LPTSTR pwcStart = NULL; LPTSTR pwcEnd; LPTSTR pwcLong; TCHAR wcSave; BOOL fLong; WIN32_FIND_DATA wfd; cchReturn = 0; pwcsLocalLongPath = NULL; __try { // // First, run down the string checking for tilde's. Any path // that has a short name section to it will have a tilde. If // there are no tilde's, then we already have the long path, // so we can return the string. // fLong = TRUE; for (pwcLong = (LPTSTR)pcsPath; *pwcLong != 0; pwcLong++) { if (*pwcLong == L'~') { fLong = FALSE; } } // // This derives the number of characters, including the NULL // cch = ((ULONG)(pwcLong - pcsPath)) + 1; // // If it isn't a long path already, then we are going to have // to parse it. // if (!fLong) { // Decide the path type, we want find out the position of // the first character of the first name pt = DetermineDosPathNameType(pcsPath); switch(pt) { // Form: "\\server_name\share_name\rest_of_the_path" case PATH_TYPE_UNC_ABSOLUTE: #if defined(UNICODE) if ((pwcStart = wcschr(pcsPath + 2, L'\\')) != NULL && (pwcStart = wcschr(pwcStart + 1, L'\\')) != NULL) #else if ((pwcStart = strchr(pcsPath + 2, '\\')) != NULL && (pwcStart = strchr(pwcStart + 1, '\\')) != NULL) #endif { pwcStart++; } else { pwcStart = NULL; } break; // Form: "\\.\rest_of_the_path" case PATH_TYPE_LOCAL_DEVICE: pwcStart = (LPTSTR)pcsPath + 4; break; // Form: "\\." case PATH_TYPE_ROOT_LOCAL_DEVICE: pwcStart = NULL; break; // Form: "D:\rest_of_the_path" case PATH_TYPE_DRIVE_ABSOLUTE: pwcStart = (LPTSTR)pcsPath + 3; break; // Form: "rest_of_the_path" case PATH_TYPE_RELATIVE: pwcStart = (LPTSTR) pcsPath; goto EatDots; // Form: "D:rest_of_the_path" case PATH_TYPE_DRIVE_RELATIVE: pwcStart = (LPTSTR)pcsPath+2; EatDots: // Handle .\ and ..\ cases while (*pwcStart != 0 && *pwcStart == L'.') { if (pwcStart[1] == L'\\') { pwcStart += 2; } else if (pwcStart[1] == L'.' && pwcStart[2] == L'\\') { pwcStart += 3; } else { break; } } break; // Form: "\rest_of_the_path" case PATH_TYPE_ROOTED: pwcStart = (LPTSTR)pcsPath + 1; break; default: pwcStart = NULL; break; } } // In the special case where we have no work to do, exit quickly // This saves a lot of instructions for trivial cases // In one case the path as given requires no processing // The middle case, we determine there were no tilde's in the path // In the other, the path only has one component and it is already // long /// if (pwcStart == NULL || (fLong == TRUE) || ((fLong = IsLongComponent(pwcStart, &pwcEnd)) && *pwcEnd == 0)) { // Nothing to convert, copy down the source string // to the buffer if necessary if (pwcStart != NULL) { cch = (ULONG)(pwcEnd - pcsPath + 1); } if (cchLongPath >= cch) { memcpy(pwcsLongPath, pcsPath, cch * sizeof(TCHAR)); cchReturn = cch - 1; goto gsnTryExit; } else { cchReturn = cch; goto gsnTryExit; } } // Make a local buffer so that we won't overlap the // source pathname in case the long name is longer than the // source name. if (cchLongPath > 0) { pwcsLocalLongPath = (PTCHAR)malloc(cchLongPath * sizeof(TCHAR)); if (pwcsLocalLongPath == NULL) { goto gsnTryExit; } } // Set up pointer to copy output to pwcLong = pwcsLocalLongPath; cchOutput = 0; // Copy the portions of the path that we skipped initially cch = (ULONG)(pwcStart-pcsPath); cchOutput += cch; if (cchOutput <= cchLongPath) { memcpy(pwcLong, pcsPath, cch*sizeof(TCHAR)); pwcLong += cch; } for (;;) { // Determine whether the current component is long or short cch = ((ULONG)(pwcEnd-pwcStart))+1; cb = cch*sizeof(TCHAR); if (fLong) { // If the component is already long, just copy it into // the output. Copy the terminating character along with it // so the output remains properly punctuated cchOutput += cch; if (cchOutput <= cchLongPath) { memcpy(pwcLong, pwcStart, cb); pwcLong += cch; } } else { TCHAR wcsTmp[MAX_PATH]; // For a short component we need to determine the // long name, if there is one. The only way to // do this reliably is to enumerate for the child wcSave = *pwcEnd; *pwcEnd = 0; h = FindFirstFile(pcsPath, &wfd); *pwcEnd = wcSave; if (h == INVALID_HANDLE_VALUE) { goto gsnTryExit; } FindClose(h); lstrcpy(wcsTmp, wfd.cFileName); // Copy the filename returned by the query into the output // Copy the terminator from the original component into // the output to maintain punctuation cch = lstrlen(wcsTmp)+1; cchOutput += cch; if (cchOutput <= cchLongPath) { memcpy(pwcLong, wcsTmp, (cch-1)*sizeof(TCHAR)); pwcLong += cch; *(pwcLong-1) = *pwcEnd; } } if (*pwcEnd == 0) { break; } // Update start pointer to next component pwcStart = pwcEnd+1; fLong = IsLongComponent(pwcStart, &pwcEnd); } // Copy local output buffer to given output buffer if necessary if (cchLongPath >= cchOutput) { memcpy(pwcsLongPath, pwcsLocalLongPath, cchOutput * sizeof(TCHAR)); cchReturn = cchOutput-1; } else { cchReturn = cchOutput; } gsnTryExit:; } __finally { if (pwcsLocalLongPath != NULL) { free(pwcsLocalLongPath); pwcsLocalLongPath = NULL; } } return cchReturn; }