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.
 
 
 
 
 
 

1318 lines
46 KiB

/*
* 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;
}