/* Copyright (c) 1995, Microsoft Corporation, all rights reserved ** ** lvx.c ** Listview extension routines ** Listed alphabetically ** ** 11/25/95 Steve Cobb ** Some adapted from \\ftp\data\softlib\mslfiles\odlistvw.exe sample code. */ #include // Win32 root #include // Win32 macro extensions #include // Win32 common controls #include // Trace and assert #include // Our public header #include // Our resource constants /* List view of check boxes state indices. */ #define SI_Unchecked 1 #define SI_Checked 2 #define SI_DisabledUnchecked 3 #define SI_DisabledChecked 4 /* Text indents within a column in pixels. If you mess with the dx, you're ** asking for misalignment problems with the header labels. BTW, the first ** column doesn't line up with it's header if there are no icons. Regular ** list view has this problem, too. If you try to fix this you'll wind up ** duplicating the AUTOSIZE_USEHEADER option of ListView_SetColumnWidth. ** Should be able to change the dy without causing problems. */ #define LVX_dxColText 4 #define LVX_dyColText 1 /* Guaranteed vertical space between icons. Should be able to mess with this ** without causing problems. */ #define LVX_dyIconSpacing 1 /* The atom identifying our context property suitable for use by the Windows ** XxxProp APIs. A Prop is used to associate context information (the address ** of the WNDPROC we subclassed) with a "list view of check boxes" window. */ static LPCWSTR g_lvxcbContextId = NULL; /*---------------------------------------------------------------------------- ** Local prototypes **---------------------------------------------------------------------------- */ LRESULT APIENTRY LvxcbProc( IN HWND hwnd, IN UINT unMsg, IN WPARAM wparam, IN LPARAM lparam ); BOOL LvxDrawItem( IN DRAWITEMSTRUCT* pdis, IN PLVXCALLBACK pLvxCallback ); BOOL LvxMeasureItem( IN HWND hwnd, IN OUT MEASUREITEMSTRUCT* pmis ); /*---------------------------------------------------------------------------- ** ListView of check boxes **---------------------------------------------------------------------------- */ BOOL ListView_GetCheck( IN HWND hwndLv, IN INT iItem ) /* Returns true if the check box of item 'iItem' of listview of checkboxes ** 'hwndLv' is checked, false otherwise. This function works on disabled ** check boxes as well as enabled ones. */ { UINT unState; unState = ListView_GetItemState( hwndLv, iItem, LVIS_STATEIMAGEMASK ); return !!((unState == INDEXTOSTATEIMAGEMASK( SI_Checked )) || (unState == INDEXTOSTATEIMAGEMASK( SI_DisabledChecked ))); } BOOL ListView_IsCheckDisabled ( IN HWND hwndLv, IN INT iItem) /* Returns true if the check box of item 'iItem' of listview of checkboxes ** 'hwndLv' is disabled, false otherwise. */ { UINT unState; unState = ListView_GetItemState( hwndLv, iItem, LVIS_STATEIMAGEMASK ); if ((unState == INDEXTOSTATEIMAGEMASK( SI_DisabledChecked )) || (unState == INDEXTOSTATEIMAGEMASK( SI_DisabledUnchecked ))) return TRUE; return FALSE; } VOID ListView_DisableCheck ( IN HWND hwndLv, IN INT iItem) /* Disables a check box of item 'iItem' of listview of checkboxes. Once ** disabled, ListView_SetCheck will have no effect on the item until ** ListView_EnableCheck(...) is called for this item. Likewise, there is no ** way through the UI to change the check of this item until it is enabled. ** Calling this function on a disabled check has no effect. */ { BOOL fCheck; fCheck = ListView_GetCheck(hwndLv, iItem); ListView_SetItemState( hwndLv, iItem, INDEXTOSTATEIMAGEMASK( (fCheck) ? SI_DisabledChecked : SI_DisabledUnchecked), LVIS_STATEIMAGEMASK ); } VOID ListView_EnableCheck ( IN HWND hwndLv, IN INT iItem) /* Reverses the effect of ListView_DisableCheck. */ { BOOL fCheck; fCheck = ListView_GetCheck(hwndLv, iItem); ListView_SetItemState( hwndLv, iItem, INDEXTOSTATEIMAGEMASK( (fCheck) ? SI_Checked : SI_Unchecked ), LVIS_STATEIMAGEMASK ); } UINT ListView_GetCheckedCount( IN HWND hwndLv ) /* Returns the number of checked items in 'hwndLv' regardless of whether ** they are disabled. */ { UINT c = 0; INT i = -1; while ((i = ListView_GetNextItem( hwndLv, i, LVNI_ALL )) >= 0) { if (ListView_GetCheck( hwndLv, i )) ++c; } return c; } BOOL ListView_InstallChecks( IN HWND hwndLv, IN HINSTANCE hinst ) /* Initialize "list of checkbox" handling for listview 'hwndLv'. 'Hinst' ** is the module instance containing the two checkbox icons. See LVX.RC. ** ** Returns true if successful, false otherwise. Caller must eventually ** call 'ListView_UninstallChecks', typically in WM_DESTROY processing. */ { HICON hIcon; HIMAGELIST himl; WNDPROC pOldProc; //Add this for RTL(right to left, mirrored windows version) //whistler bug 41349 gangz // BOOL fMirrored=FALSE; DWORD dwLayout; // pmay: 397395 // // Prevent endless loops resulting from accidentally calling this // api twice. // pOldProc = (WNDPROC)GetWindowLongPtr(hwndLv, GWLP_WNDPROC); if (pOldProc == LvxcbProc) { return TRUE; } //get current application's layout (RTL or normal) gangz // for whistler bug 41349 //There are two ways: //(1) use GetWindowLong() with GWL_EXSTYLE for WS_EX_LAYOUTRTL style if // you have a window handler available //(2) use GetProcessDefaultLayout() to get the layout for the current // process, and compare that against LAYOUT_RTL // dwLayout = GetWindowLong(hwndLv, GWL_EXSTYLE); if ( WS_EX_LAYOUTRTL & dwLayout ) { fMirrored = TRUE; } /* Build checkbox image lists. */ himl = ImageList_Create( GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), ILC_MASK, 2, 2 ); /* The order these are added is significant since it implicitly ** establishes the state indices matching SI_Unchecked and SI_Checked. */ hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Unchecked ) ); if ( NULL != hIcon ) { ImageList_AddIcon( himl, hIcon ); DeleteObject( hIcon ); } hIcon = LoadIcon( hinst, MAKEINTRESOURCE( fMirrored?IID_CheckedRTL : IID_Checked ) ); if ( NULL != hIcon ) { ImageList_AddIcon( himl, hIcon ); DeleteObject( hIcon ); } hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_DisabledUnchecked ) ); if ( NULL != hIcon ) { ImageList_AddIcon( himl, hIcon ); DeleteObject( hIcon ); } hIcon = LoadIcon( hinst, MAKEINTRESOURCE( fMirrored?IID_DisabledCheckedRTL : IID_DisabledChecked ) ); if ( NULL != hIcon ) { ImageList_AddIcon( himl, hIcon ); DeleteObject( hIcon ); } ListView_SetImageList( hwndLv, himl, LVSIL_STATE ); /* Register atom for use in the Windows XxxProp calls which are used to ** associate the old WNDPROC with the listview window handle. */ if (!g_lvxcbContextId) g_lvxcbContextId = (LPCWSTR )GlobalAddAtom( L"RASLVXCB" ); if (!g_lvxcbContextId) return FALSE; /* Subclass the current window procedure. */ pOldProc = (WNDPROC)SetWindowLongPtr( hwndLv, GWLP_WNDPROC, (ULONG_PTR)LvxcbProc ); return SetProp( hwndLv, g_lvxcbContextId, (HANDLE )pOldProc ); } VOID ListView_SetCheck( IN HWND hwndLv, IN INT iItem, IN BOOL fCheck ) /* Sets the check mark on item 'iItem' of listview of checkboxes 'hwndLv' ** to checked if 'fCheck' is true or unchecked if false. */ { NM_LISTVIEW nmlv; if (ListView_IsCheckDisabled(hwndLv, iItem)) return; ListView_SetItemState( hwndLv, iItem, INDEXTOSTATEIMAGEMASK( (fCheck) ? SI_Checked : SI_Unchecked ), LVIS_STATEIMAGEMASK ); nmlv.hdr.code = LVXN_SETCHECK; nmlv.hdr.hwndFrom = hwndLv; nmlv.iItem = iItem; FORWARD_WM_NOTIFY( GetParent(hwndLv), GetDlgCtrlID(hwndLv), &nmlv, SendMessage ); } VOID ListView_UninstallChecks( IN HWND hwndLv ) /* Uninstalls "listview of check boxes" handling from list view 'hwndLv'. */ { WNDPROC pOldProc; pOldProc = (WNDPROC)GetProp( hwndLv, g_lvxcbContextId ); if (pOldProc) { /* Un-subclass so it can terminate without access to the context. */ SetWindowLongPtr( hwndLv, GWLP_WNDPROC, (ULONG_PTR)pOldProc ); } RemoveProp( hwndLv, g_lvxcbContextId ); } LRESULT APIENTRY LvxcbProc( IN HWND hwnd, IN UINT unMsg, IN WPARAM wparam, IN LPARAM lparam ) /* List view subclass window procedure to trap toggle-check events. */ { WNDPROC pOldProc; INT iItem; BOOL fSet; BOOL fClear; BOOL fToggle; iItem = -1; fSet = fClear = fToggle = FALSE; if (unMsg == WM_LBUTTONDOWN) { LV_HITTESTINFO info; /* Left mouse button pressed over checkbox icon toggles state. ** Normally, we'd use LVHT_ONITEMSTATEICON and be done with it, but we ** want to work with our cool owner-drawn list view extensions in ** which case the control doesn't know where the icon is on the item, ** so it returns a hit anywhere on the item anyway. */ ZeroMemory( &info, sizeof(info) ); info.pt.x = LOWORD( lparam ); info.pt.y = HIWORD( lparam ); info.flags = LVHT_ONITEM; iItem = ListView_HitTest( hwnd, &info ); if (iItem >= 0) { /* OK, it's over item 'iItem'. Now figure out if it's over the ** checkbox. Note this currently doesn't account for use of the ** "indent" feature on an owner-drawn item. */ if ((INT )(LOWORD( lparam )) >= GetSystemMetrics( SM_CXSMICON )) iItem = -1; else fToggle = TRUE; } } else if (unMsg == WM_LBUTTONDBLCLK) { LV_HITTESTINFO info; /* Left mouse button double clicked over any area toggles state. ** Normally, we'd use LVHT_ONITEMSTATEICON and be done with it, but we ** want to work with our cool owner-drawn list view extensions in ** which case the control doesn't know where the icon is on the item, ** so it returns a hit anywhere on the item anyway. */ ZeroMemory( &info, sizeof(info) ); info.pt.x = LOWORD( lparam ); info.pt.y = HIWORD( lparam ); info.flags = LVHT_ONITEM; iItem = ListView_HitTest( hwnd, &info ); if (iItem >= 0) { /* OK, it's over item 'iItem'. If the click does not occur * over a checkbox, inform the parent of the double click. */ if ((INT )(LOWORD( lparam )) >= GetSystemMetrics( SM_CXSMICON )) { NM_LISTVIEW nmlv; nmlv.hdr.code = LVXN_DBLCLK; nmlv.hdr.hwndFrom = hwnd; nmlv.iItem = iItem; FORWARD_WM_NOTIFY( GetParent(hwnd), GetDlgCtrlID(hwnd), &nmlv, SendMessage); iItem = -1; } /* * Otherwise, toggle the state. */ else fToggle = TRUE; } } else if (unMsg == WM_CHAR) { /* Space bar pressed with item selected toggles check. ** Plus or Equals keys set check. ** Minus key clears check. */ switch (wparam) { case TEXT(' '): fToggle = TRUE; break; case TEXT('+'): case TEXT('='): fSet = TRUE; break; case TEXT('-'): fClear = TRUE; break; } if (fToggle || fSet || fClear) iItem = ListView_GetNextItem( hwnd, -1, LVNI_SELECTED ); } else if (unMsg == WM_KEYDOWN) { /* Left arrow becomes up arrow and right arrow becomes down arrow so ** the list of checkboxes behaves just like a static group of ** checkboxes. */ if (wparam == VK_LEFT) wparam = VK_UP; else if (wparam == VK_RIGHT) wparam = VK_DOWN; } if (iItem >= 0) { /* If we are handling the spacebar, plus, minus, or equals, ** the change we make applies to all the selected items; ** hence the do {} while(WM_CHAR). */ do { if (fToggle) { UINT unOldState; BOOL fCheck; fCheck = ListView_GetCheck( hwnd, iItem ); ListView_SetCheck( hwnd, iItem, !fCheck ); } else if (fSet) { if (!ListView_GetCheck( hwnd, iItem )) ListView_SetCheck( hwnd, iItem, TRUE ); } else if (fClear) { if (ListView_GetCheck( hwnd, iItem )) ListView_SetCheck( hwnd, iItem, FALSE ); } iItem = ListView_GetNextItem(hwnd, iItem, LVNI_SELECTED); } while(iItem >= 0 && unMsg == WM_CHAR); if (fSet || fClear) { /* Don't pass to listview to avoid beep. */ return 0; } } pOldProc = (WNDPROC )GetProp( hwnd, g_lvxcbContextId ); if (pOldProc) return CallWindowProc( pOldProc, hwnd, unMsg, wparam, lparam ); return 0; } /*---------------------------------------------------------------------------- ** Enhanced ListView **---------------------------------------------------------------------------- */ BOOL ListView_OwnerHandler( IN HWND hwnd, IN UINT unMsg, IN WPARAM wparam, IN LPARAM lparam, IN PLVXCALLBACK pLvxCallback ) /* Handler that, when installed, turns a regular report-view-only list ** view (but with style LVS_OWNERDRAWFIXED) into an enhanced list view ** with full width selection bar and other custom column display options. ** It should appear in list view owner's dialog proc as follows: ** ** BOOL ** MyDlgProc( ** IN HWND hwnd, ** IN UINT unMsg, ** IN WPARAM wparam, ** IN LPARAM lparam ) ** { ** if (ListView_OwnerHandler( ** hwnd, unMsg, wParam, lParam, MyLvxCallback )) ** return TRUE; ** ** ** } ** ** 'PLvxCallback' is caller's callback routine that provides information ** about drawing columns and other options. ** ** Returns true if processed message, false otherwise. */ { /* This routine executes on EVERY message thru the dialog so keep it ** efficient, please. */ switch (unMsg) { case WM_DRAWITEM: return LvxDrawItem( (DRAWITEMSTRUCT* )lparam, pLvxCallback ); case WM_MEASUREITEM: return LvxMeasureItem( hwnd, (MEASUREITEMSTRUCT* )lparam ); } return FALSE; } BOOL LvxDrawItem( IN DRAWITEMSTRUCT* pdis, IN PLVXCALLBACK pLvxCallback ) /* Respond to WM_DRAWITEM by drawing the list view item. 'Pdis' is the ** information sent by the system. 'PLvxCallback' is caller's callback to ** get information about drawing the control. ** ** Returns true is processed the message, false otherwise. */ { LV_ITEM item; INT i; INT dxState; INT dyState; INT dxSmall; INT dySmall; INT dxIndent; UINT uiStyleState; UINT uiStyleSmall; HIMAGELIST himlState; HIMAGELIST himlSmall; LVXDRAWINFO* pDrawInfo; RECT rc; RECT rcClient; BOOL fEnabled; BOOL fSelected; HDC hdc; HFONT hfont; TRACE3("LvxDrawItem,i=%d,a=$%X,s=$%X", pdis->itemID,pdis->itemAction,pdis->itemState); /* Make sure this is something we want to handle. */ if (pdis->CtlType != ODT_LISTVIEW) return FALSE; if (pdis->itemAction != ODA_DRAWENTIRE && pdis->itemAction != ODA_SELECT && pdis->itemAction != ODA_FOCUS) { return TRUE; } /* Get item information from the list view. */ ZeroMemory( &item, sizeof(item) ); item.mask = LVIF_IMAGE + LVIF_STATE; item.iItem = pdis->itemID; item.stateMask = LVIS_STATEIMAGEMASK; if (!ListView_GetItem( pdis->hwndItem, &item )) { TRACE("LvxDrawItem GetItem failed"); return TRUE; } /* Stash some useful stuff for reference later. */ fEnabled = IsWindowEnabled( pdis->hwndItem ) && !(pdis->itemState & ODS_DISABLED); fSelected = (pdis->itemState & ODS_SELECTED); GetClientRect( pdis->hwndItem, &rcClient ); /* Callback owner to get drawing information. */ ASSERT(pLvxCallback); pDrawInfo = pLvxCallback( pdis->hwndItem, pdis->itemID ); ASSERT(pDrawInfo); /* Get image list icon sizes now, though we draw them last because their ** background is set up during first column text output. */ dxState = dyState = 0; himlState = ListView_GetImageList( pdis->hwndItem, LVSIL_STATE ); if (himlState) ImageList_GetIconSize( himlState, &dxState, &dyState ); dxSmall = dySmall = 0; himlSmall = ListView_GetImageList( pdis->hwndItem, LVSIL_SMALL ); if (himlSmall) ImageList_GetIconSize( himlSmall, &dxSmall, &dySmall ); uiStyleState = uiStyleSmall = ILD_TRANSPARENT; /* Figure out the number of pixels to indent the item, if any. */ if (pDrawInfo->dxIndent >= 0) dxIndent = pDrawInfo->dxIndent; else { if (dxSmall > 0) dxIndent = dxSmall; else dxIndent = GetSystemMetrics( SM_CXSMICON ); } /* Get a device context for the window and set it up with the font the ** control says it's using. (Can't use the one that comes in the ** DRAWITEMSTRUCT because sometimes it has the wrong rectangle, see bug ** 13106) */ hdc = GetDC( pdis->hwndItem ); if(NULL == hdc) { return FALSE; } hfont = (HFONT )SendMessage( pdis->hwndItem, WM_GETFONT, 0, 0 ); if (hfont) SelectObject( hdc, hfont ); /* Set things up as if we'd just got done processing a column that ends ** after the icons, then loop thru each column from left to right. */ rc.right = pdis->rcItem.left + dxIndent + dxState + dxSmall; rc.top = pdis->rcItem.top; rc.bottom = pdis->rcItem.bottom; for (i = 0; i < pDrawInfo->cCols; ++i) { TCHAR szText[ LVX_MaxColTchars + 1 ]; TCHAR* pszText; INT dxCol; /* Get the column width, adding any index and icon width to the first ** column. */ // For whistler bug 458513 39081 // ZeroMemory(szText,sizeof(szText)); dxCol = ListView_GetColumnWidth( pdis->hwndItem, i ); if (i == 0) dxCol -= dxIndent + dxState + dxSmall; szText[ 0 ] = TEXT('\0'); ListView_GetItemText( pdis->hwndItem, pdis->itemID, i, szText, LVX_MaxColTchars + 1 ); /* Update rectangle to enclose just this one item's column 'i'. */ rc.left = rc.right; rc.right = rc.left + dxCol; if ((pDrawInfo->dwFlags & LVXDI_DxFill) && i == pDrawInfo->cCols - 1) { INT dxWnd = pdis->rcItem.left + rcClient.right; if (rc.right < dxWnd) { /* When the last column does not fill out a full controls ** width of space, extend it to the right so it does. Note ** this does not mean the user can't scroll off to the right ** if they want. ** (Abolade-Gbadegesin 03-27-96) ** Don't subtrace rc.left when there is only one column; ** this accounts for the space needed for icons. */ rc.right = pdis->rcItem.right = dxWnd; if (i == 0) { ListView_SetColumnWidth(pdis->hwndItem, i, rc.right); } else { ListView_SetColumnWidth( pdis->hwndItem, i, rc.right - rc.left ); } } } /* Lop the text and append "..." if it won't fit in the column. */ pszText = Ellipsisize( hdc, szText, rc.right - rc.left, LVX_dxColText ); if (!pszText) continue; /* Figure out the appropriate text and background colors for the ** current item state. */ if (fEnabled) { if (fSelected) { SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) ); SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) ); if (pDrawInfo->dwFlags & LVXDI_Blend50Sel) uiStyleSmall |= ILD_BLEND50; } else { if (pDrawInfo->adwFlags[ i ] & LVXDIA_3dFace) { SetTextColor( hdc, GetSysColor( COLOR_WINDOWTEXT ) ); SetBkColor( hdc, GetSysColor( COLOR_3DFACE ) ); } else { SetTextColor( hdc, GetSysColor( COLOR_WINDOWTEXT ) ); SetBkColor( hdc, GetSysColor( COLOR_WINDOW ) ); } } } else { if (pDrawInfo->adwFlags[ i ] & LVXDIA_Static) { SetTextColor( hdc, GetSysColor( COLOR_WINDOWTEXT ) ); SetBkColor( hdc, GetSysColor( COLOR_3DFACE ) ); } else { SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) ); SetBkColor( hdc, GetSysColor( COLOR_3DFACE ) ); } if (pDrawInfo->dwFlags & LVXDI_Blend50Dis) uiStyleSmall |= ILD_BLEND50; } /* Draw the column text. In the first column the background of any ** indent and icons is erased to the text background color. */ { RECT rcBg = rc; if (i == 0) rcBg.left -= dxIndent + dxState + dxSmall; ExtTextOut( hdc, rc.left + LVX_dxColText, rc.top + LVX_dyColText, ETO_CLIPPED + ETO_OPAQUE, &rcBg, pszText, lstrlen( pszText ), NULL ); } Free( pszText ); } /* Finally, draw the icons, if caller specified any. */ if (himlState) { ImageList_Draw( himlState, (item.state >> 12) - 1, hdc, pdis->rcItem.left + dxIndent, pdis->rcItem.top, uiStyleState ); } if (himlSmall) { ImageList_Draw( himlSmall, item.iImage, hdc, pdis->rcItem.left + dxIndent + dxState, pdis->rcItem.top, uiStyleSmall ); } /* Draw the dotted focus rectangle around the whole item, if indicated. */ //comment for bug 52688 whistler // if ((pdis->itemState & ODS_FOCUS) && GetFocus() == pdis->hwndItem) // DrawFocusRect( hdc, &pdis->rcItem ); // ReleaseDC( pdis->hwndItem, hdc ); return TRUE; } BOOL LvxMeasureItem( IN HWND hwnd, IN OUT MEASUREITEMSTRUCT* pmis ) /* Respond to WM_MEASUREITEM message, i.e. fill in the height of an item ** in the ListView. 'Hwnd' is the owner window. 'Pmis' is the structure ** provided from Windows. ** ** Returns true is processed the message, false otherwise. */ { HDC hdc; HWND hwndLv; HFONT hfont; TEXTMETRIC tm; UINT dySmIcon; RECT rc; TRACE("LvxMeasureItem"); if (pmis->CtlType != ODT_LISTVIEW) return FALSE; hwndLv = GetDlgItem( hwnd, pmis->CtlID ); ASSERT(hwndLv); /* Get a device context for the list view control and set up the font the ** control says it's using. MSDN claims the final font may not be ** available at this point, but it sure seems to be. */ hdc = GetDC( hwndLv ); hfont = (HFONT )SendMessage( hwndLv, WM_GETFONT, 0, 0 ); if (hfont) SelectObject( hdc, hfont ); if (GetTextMetrics( hdc, &tm )) pmis->itemHeight = tm.tmHeight + 1; else pmis->itemHeight = 0; /* Make sure it's tall enough for a standard small icon. */ dySmIcon = (UINT )GetSystemMetrics( SM_CYSMICON ); if (pmis->itemHeight < dySmIcon + LVX_dyIconSpacing) pmis->itemHeight = dySmIcon + LVX_dyIconSpacing; /* Set the width since the docs say to, though I don't think it's used by ** list view. */ GetClientRect( hwndLv, &rc ); pmis->itemWidth = rc.right - rc.left - 1; ReleaseDC( hwndLv, hdc ); return TRUE; } /*---------------------------------------------------------------------------- ** ListView utilities **---------------------------------------------------------------------------- */ VOID ListView_SetDeviceImageList( IN HWND hwndLv, IN HINSTANCE hinst ) /* Set the "small icon" image list view 'hwndLv' to be a list of DI_* ** images. 'Hinst' is the module instance containing the icons IID_Modem ** and IID_Adapter. For example, see RASDLG.DLL. */ { HICON hIcon; HIMAGELIST himl; himl = ImageList_Create( GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), ILC_MASK, 2, 2 ); /* The order these are added is significant since it implicitly ** establishes the state indices matching SI_Unchecked and SI_Checked. */ hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Modem ) ); if ( NULL != hIcon ) { ImageList_ReplaceIcon( himl, -1, hIcon ); DeleteObject( hIcon ); } hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Adapter ) ); if ( NULL != hIcon ) { ImageList_ReplaceIcon( himl, -1, hIcon ); DeleteObject( hIcon ); } hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Direct_Connect ) ); if ( NULL != hIcon ) { ImageList_ReplaceIcon( himl, -1, hIcon ); DeleteObject( hIcon ); } hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Connections_Modem ) ); if ( NULL != hIcon ) { ImageList_ReplaceIcon( himl, -1, hIcon ); DeleteObject( hIcon ); } ListView_SetImageList( hwndLv, himl, LVSIL_SMALL ); } VOID ListView_SetUserImageList( IN HWND hwndLv, IN HINSTANCE hinst ) /* Set the "small icon" image list view 'hwndLv' to be a list of DI_* ** images. 'Hinst' is the module instance containing the icons IID_Modem ** and IID_Adapter. For example, see RASDLG.DLL. */ { HICON hIcon; HIMAGELIST himl; himl = ImageList_Create( GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), ILC_MASK, 2, 2 ); /* The order these are added is significant since it implicitly ** establishes the state indices matching SI_Unchecked and SI_Checked. */ hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Connections_User ) ); if(NULL != hIcon) { ImageList_ReplaceIcon( himl, -1, hIcon ); DeleteObject( hIcon ); } ListView_SetImageList( hwndLv, himl, LVSIL_SMALL ); } VOID ListView_SetNetworkComponentImageList( IN HWND hwndLv, IN HINSTANCE hinst ) /* Set the "small icon" image list view 'hwndLv' to be a list of DI_* ** images. 'Hinst' is the module instance containing the icons IID_Modem ** and IID_Adapter. For example, see RASDLG.DLL. */ { HICON hIcon; HIMAGELIST himl; himl = ImageList_Create( GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), ILC_MASK, 2, 2 ); /* The order these are added is significant since it implicitly ** establishes the state indices matching SI_Unchecked and SI_Checked. */ hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Protocol ) ); if(NULL != hIcon) { ImageList_ReplaceIcon( himl, -1, hIcon ); DeleteObject( hIcon ); } hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Service ) ); if(NULL != hIcon) { ImageList_ReplaceIcon( himl, -1, hIcon ); DeleteObject( hIcon ); } hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Client ) ); if(NULL != hIcon) { ImageList_ReplaceIcon( himl, -1, hIcon ); DeleteObject( hIcon ); } ListView_SetImageList( hwndLv, himl, LVSIL_SMALL ); }