/* * NativeMethods - All the Windows SDK structures and imports * * Author: Phillip Piper * Date: 10/10/2006 * * Change log: * v2.8.0 * 2014-05-21 JPP - Added DeselectOneItem * - Added new imagelist drawing * v2.3 * 2006-10-10 JPP - Initial version * * To do: * * Copyright (C) 2006-2014 Phillip Piper * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * If you wish to use this code in a closed source application, please contact phillip_piper@bigfoot.com. */ using System; using System.Drawing; using System.Runtime.InteropServices; using System.Windows.Forms; namespace BrightIdeasSoftware { /// /// Wrapper for all native method calls on ListView controls /// internal static class NativeMethods { #region Constants private const int LVM_FIRST = 0x1000; private const int LVM_GETCOLUMN = LVM_FIRST + 95; private const int LVM_GETCOUNTPERPAGE = LVM_FIRST + 40; private const int LVM_GETGROUPINFO = LVM_FIRST + 149; private const int LVM_GETGROUPSTATE = LVM_FIRST + 92; private const int LVM_GETHEADER = LVM_FIRST + 31; private const int LVM_GETTOOLTIPS = LVM_FIRST + 78; private const int LVM_GETTOPINDEX = LVM_FIRST + 39; private const int LVM_HITTEST = LVM_FIRST + 18; private const int LVM_INSERTGROUP = LVM_FIRST + 145; private const int LVM_REMOVEALLGROUPS = LVM_FIRST + 160; private const int LVM_SCROLL = LVM_FIRST + 20; private const int LVM_SETBKIMAGE = LVM_FIRST + 0x8A; private const int LVM_SETCOLUMN = LVM_FIRST + 96; private const int LVM_SETEXTENDEDLISTVIEWSTYLE = LVM_FIRST + 54; private const int LVM_SETGROUPINFO = LVM_FIRST + 147; private const int LVM_SETGROUPMETRICS = LVM_FIRST + 155; private const int LVM_SETIMAGELIST = LVM_FIRST + 3; private const int LVM_SETITEM = LVM_FIRST + 76; private const int LVM_SETITEMCOUNT = LVM_FIRST + 47; private const int LVM_SETITEMSTATE = LVM_FIRST + 43; private const int LVM_SETSELECTEDCOLUMN = LVM_FIRST + 140; private const int LVM_SETTOOLTIPS = LVM_FIRST + 74; private const int LVM_SUBITEMHITTEST = LVM_FIRST + 57; private const int LVS_EX_SUBITEMIMAGES = 0x0002; private const int LVIF_TEXT = 0x0001; private const int LVIF_IMAGE = 0x0002; private const int LVIF_PARAM = 0x0004; private const int LVIF_STATE = 0x0008; private const int LVIF_INDENT = 0x0010; private const int LVIF_NORECOMPUTE = 0x0800; private const int LVIS_SELECTED = 2; private const int LVCF_FMT = 0x0001; private const int LVCF_WIDTH = 0x0002; private const int LVCF_TEXT = 0x0004; private const int LVCF_SUBITEM = 0x0008; private const int LVCF_IMAGE = 0x0010; private const int LVCF_ORDER = 0x0020; private const int LVCFMT_LEFT = 0x0000; private const int LVCFMT_RIGHT = 0x0001; private const int LVCFMT_CENTER = 0x0002; private const int LVCFMT_JUSTIFYMASK = 0x0003; private const int LVCFMT_IMAGE = 0x0800; private const int LVCFMT_BITMAP_ON_RIGHT = 0x1000; private const int LVCFMT_COL_HAS_IMAGES = 0x8000; private const int LVBKIF_SOURCE_NONE = 0x0; private const int LVBKIF_SOURCE_HBITMAP = 0x1; private const int LVBKIF_SOURCE_URL = 0x2; private const int LVBKIF_SOURCE_MASK = 0x3; private const int LVBKIF_STYLE_NORMAL = 0x0; private const int LVBKIF_STYLE_TILE = 0x10; private const int LVBKIF_STYLE_MASK = 0x10; private const int LVBKIF_FLAG_TILEOFFSET = 0x100; private const int LVBKIF_TYPE_WATERMARK = 0x10000000; private const int LVBKIF_FLAG_ALPHABLEND = 0x20000000; private const int LVSICF_NOINVALIDATEALL = 1; private const int LVSICF_NOSCROLL = 2; private const int HDM_FIRST = 0x1200; private const int HDM_HITTEST = HDM_FIRST + 6; private const int HDM_GETITEMRECT = HDM_FIRST + 7; private const int HDM_GETITEM = HDM_FIRST + 11; private const int HDM_SETITEM = HDM_FIRST + 12; private const int HDI_WIDTH = 0x0001; private const int HDI_TEXT = 0x0002; private const int HDI_FORMAT = 0x0004; private const int HDI_BITMAP = 0x0010; private const int HDI_IMAGE = 0x0020; private const int HDF_LEFT = 0x0000; private const int HDF_RIGHT = 0x0001; private const int HDF_CENTER = 0x0002; private const int HDF_JUSTIFYMASK = 0x0003; private const int HDF_RTLREADING = 0x0004; private const int HDF_STRING = 0x4000; private const int HDF_BITMAP = 0x2000; private const int HDF_BITMAP_ON_RIGHT = 0x1000; private const int HDF_IMAGE = 0x0800; private const int HDF_SORTUP = 0x0400; private const int HDF_SORTDOWN = 0x0200; private const int SB_HORZ = 0; private const int SB_VERT = 1; private const int SB_CTL = 2; private const int SB_BOTH = 3; private const int SIF_RANGE = 0x0001; private const int SIF_PAGE = 0x0002; private const int SIF_POS = 0x0004; private const int SIF_DISABLENOSCROLL = 0x0008; private const int SIF_TRACKPOS = 0x0010; private const int SIF_ALL = (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS); private const int ILD_NORMAL = 0x0; private const int ILD_TRANSPARENT = 0x1; private const int ILD_MASK = 0x10; private const int ILD_IMAGE = 0x20; private const int ILD_BLEND25 = 0x2; private const int ILD_BLEND50 = 0x4; const int SWP_NOSIZE = 1; const int SWP_NOMOVE = 2; const int SWP_NOZORDER = 4; const int SWP_NOREDRAW = 8; const int SWP_NOACTIVATE = 16; public const int SWP_FRAMECHANGED = 32; const int SWP_ZORDERONLY = SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOACTIVATE; const int SWP_SIZEONLY = SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER | SWP_NOACTIVATE; const int SWP_UPDATE_FRAME = SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED; #endregion #region Structures [StructLayout(LayoutKind.Sequential)] public struct HDITEM { public int mask; public int cxy; public IntPtr pszText; public IntPtr hbm; public int cchTextMax; public int fmt; public IntPtr lParam; public int iImage; public int iOrder; //if (_WIN32_IE >= 0x0500) public int type; public IntPtr pvFilter; } [StructLayout(LayoutKind.Sequential)] public class HDHITTESTINFO { public int pt_x; public int pt_y; public int flags; public int iItem; } [StructLayout(LayoutKind.Sequential)] public class HDLAYOUT { public IntPtr prc; public IntPtr pwpos; } [StructLayout(LayoutKind.Sequential)] public struct IMAGELISTDRAWPARAMS { public int cbSize; public IntPtr himl; public int i; public IntPtr hdcDst; public int x; public int y; public int cx; public int cy; public int xBitmap; public int yBitmap; public uint rgbBk; public uint rgbFg; public uint fStyle; public uint dwRop; public uint fState; public uint Frame; public uint crEffect; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct LVBKIMAGE { public int ulFlags; public IntPtr hBmp; [MarshalAs(UnmanagedType.LPTStr)] public string pszImage; public int cchImageMax; public int xOffset; public int yOffset; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct LVCOLUMN { public int mask; public int fmt; public int cx; [MarshalAs(UnmanagedType.LPTStr)] public string pszText; public int cchTextMax; public int iSubItem; // These are available in Common Controls >= 0x0300 public int iImage; public int iOrder; }; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct LVFINDINFO { public int flags; public string psz; public IntPtr lParam; public int ptX; public int ptY; public int vkDirection; } [StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)] public struct LVGROUP { public uint cbSize; public uint mask; [MarshalAs(UnmanagedType.LPTStr)] public string pszHeader; public int cchHeader; [MarshalAs(UnmanagedType.LPTStr)] public string pszFooter; public int cchFooter; public int iGroupId; public uint stateMask; public uint state; public uint uAlign; } [StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)] public struct LVGROUP2 { public uint cbSize; public uint mask; [MarshalAs(UnmanagedType.LPTStr)] public string pszHeader; public uint cchHeader; [MarshalAs(UnmanagedType.LPTStr)] public string pszFooter; public int cchFooter; public int iGroupId; public uint stateMask; public uint state; public uint uAlign; [MarshalAs(UnmanagedType.LPTStr)] public string pszSubtitle; public uint cchSubtitle; [MarshalAs(UnmanagedType.LPTStr)] public string pszTask; public uint cchTask; [MarshalAs(UnmanagedType.LPTStr)] public string pszDescriptionTop; public uint cchDescriptionTop; [MarshalAs(UnmanagedType.LPTStr)] public string pszDescriptionBottom; public uint cchDescriptionBottom; public int iTitleImage; public int iExtendedImage; public int iFirstItem; // Read only public int cItems; // Read only [MarshalAs(UnmanagedType.LPTStr)] public string pszSubsetTitle; // NULL if group is not subset public uint cchSubsetTitle; } [StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)] public struct LVGROUPMETRICS { public uint cbSize; public uint mask; public uint Left; public uint Top; public uint Right; public uint Bottom; public int crLeft; public int crTop; public int crRight; public int crBottom; public int crHeader; public int crFooter; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct LVHITTESTINFO { public int pt_x; public int pt_y; public int flags; public int iItem; public int iSubItem; public int iGroup; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct LVITEM { public int mask; public int iItem; public int iSubItem; public int state; public int stateMask; [MarshalAs(UnmanagedType.LPTStr)] public string pszText; public int cchTextMax; public int iImage; public IntPtr lParam; // These are available in Common Controls >= 0x0300 public int iIndent; // These are available in Common Controls >= 0x056 public int iGroupId; public int cColumns; public IntPtr puColumns; }; [StructLayout(LayoutKind.Sequential)] public struct NMHDR { public IntPtr hwndFrom; public IntPtr idFrom; public int code; } [StructLayout(LayoutKind.Sequential)] public struct NMCUSTOMDRAW { public NativeMethods.NMHDR nmcd; public int dwDrawStage; public IntPtr hdc; public NativeMethods.RECT rc; public IntPtr dwItemSpec; public int uItemState; public IntPtr lItemlParam; } [StructLayout(LayoutKind.Sequential)] public struct NMHEADER { public NMHDR nhdr; public int iItem; public int iButton; public IntPtr pHDITEM; } const int MAX_LINKID_TEXT = 48; const int L_MAX_URL_LENGTH = 2048 + 32 + 4; //#define L_MAX_URL_LENGTH (2048 + 32 + sizeof("://")) [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct LITEM { public uint mask; public int iLink; public uint state; public uint stateMask; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_LINKID_TEXT)] public string szID; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = L_MAX_URL_LENGTH)] public string szUrl; } [StructLayout(LayoutKind.Sequential)] public struct NMLISTVIEW { public NativeMethods.NMHDR hdr; public int iItem; public int iSubItem; public int uNewState; public int uOldState; public int uChanged; public IntPtr lParam; } [StructLayout(LayoutKind.Sequential)] public struct NMLVCUSTOMDRAW { public NativeMethods.NMCUSTOMDRAW nmcd; public int clrText; public int clrTextBk; public int iSubItem; public int dwItemType; public int clrFace; public int iIconEffect; public int iIconPhase; public int iPartId; public int iStateId; public NativeMethods.RECT rcText; public uint uAlign; } [StructLayout(LayoutKind.Sequential)] public struct NMLVFINDITEM { public NativeMethods.NMHDR hdr; public int iStart; public NativeMethods.LVFINDINFO lvfi; } [StructLayout(LayoutKind.Sequential)] public struct NMLVGETINFOTIP { public NativeMethods.NMHDR hdr; public int dwFlags; public string pszText; public int cchTextMax; public int iItem; public int iSubItem; public IntPtr lParam; } [StructLayout(LayoutKind.Sequential)] public struct NMLVGROUP { public NMHDR hdr; public int iGroupId; // which group is changing public uint uNewState; // LVGS_xxx flags public uint uOldState; } [StructLayout(LayoutKind.Sequential)] public struct NMLVLINK { public NMHDR hdr; public LITEM link; public int iItem; public int iSubItem; } [StructLayout(LayoutKind.Sequential)] public struct NMLVSCROLL { public NativeMethods.NMHDR hdr; public int dx; public int dy; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct NMTTDISPINFO { public NativeMethods.NMHDR hdr; [MarshalAs(UnmanagedType.LPTStr)] public string lpszText; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] public string szText; public IntPtr hinst; public int uFlags; public IntPtr lParam; //public int hbmp; This is documented but doesn't work } [StructLayout(LayoutKind.Sequential)] public struct RECT { public int left; public int top; public int right; public int bottom; } [StructLayout(LayoutKind.Sequential)] public class SCROLLINFO { public int cbSize = Marshal.SizeOf(typeof(NativeMethods.SCROLLINFO)); public int fMask; public int nMin; public int nMax; public int nPage; public int nPos; public int nTrackPos; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public class TOOLINFO { public int cbSize = Marshal.SizeOf(typeof(NativeMethods.TOOLINFO)); public int uFlags; public IntPtr hwnd; public IntPtr uId; public NativeMethods.RECT rect; public IntPtr hinst = IntPtr.Zero; public IntPtr lpszText; public IntPtr lParam = IntPtr.Zero; } [StructLayout(LayoutKind.Sequential)] public struct WINDOWPOS { public IntPtr hwnd; public IntPtr hwndInsertAfter; public int x; public int y; public int cx; public int cy; public int flags; } #endregion #region Entry points // Various flavours of SendMessage: plain vanilla, and passing references to various structures [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, int lParam); [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, int lParam); [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam); [DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)] public static extern IntPtr SendMessageLVItem(IntPtr hWnd, int msg, int wParam, ref LVITEM lvi); [DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)] public static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, ref LVHITTESTINFO ht); [DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)] public static extern IntPtr SendMessageRECT(IntPtr hWnd, int msg, int wParam, ref RECT r); //[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)] //private static extern IntPtr SendMessageLVColumn(IntPtr hWnd, int m, int wParam, ref LVCOLUMN lvc); [DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)] private static extern IntPtr SendMessageHDItem(IntPtr hWnd, int msg, int wParam, ref HDITEM hdi); [DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)] public static extern IntPtr SendMessageHDHITTESTINFO(IntPtr hWnd, int Msg, IntPtr wParam, [In, Out] HDHITTESTINFO lParam); [DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)] public static extern IntPtr SendMessageTOOLINFO(IntPtr hWnd, int Msg, int wParam, NativeMethods.TOOLINFO lParam); [DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)] public static extern IntPtr SendMessageLVBKIMAGE(IntPtr hWnd, int Msg, int wParam, ref NativeMethods.LVBKIMAGE lParam); [DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)] public static extern IntPtr SendMessageString(IntPtr hWnd, int Msg, int wParam, string lParam); [DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)] public static extern IntPtr SendMessageIUnknown(IntPtr hWnd, int msg, [MarshalAs(UnmanagedType.IUnknown)] object wParam, int lParam); [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, ref LVGROUP lParam); [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, ref LVGROUP2 lParam); [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, ref LVGROUPMETRICS lParam); [DllImport("gdi32.dll")] public static extern bool DeleteObject(IntPtr objectHandle); [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] public static extern bool GetClientRect(IntPtr hWnd, ref Rectangle r); [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] public static extern bool GetScrollInfo(IntPtr hWnd, int fnBar, SCROLLINFO scrollInfo); [DllImport("user32.dll", EntryPoint = "GetUpdateRect", CharSet = CharSet.Auto)] private static extern bool GetUpdateRectInternal(IntPtr hWnd, ref Rectangle r, bool eraseBackground); [DllImport("comctl32.dll", CharSet = CharSet.Auto)] private static extern bool ImageList_Draw(IntPtr himl, int i, IntPtr hdcDst, int x, int y, int fStyle); [DllImport("comctl32.dll", CharSet = CharSet.Auto)] private static extern bool ImageList_DrawIndirect(ref IMAGELISTDRAWPARAMS parms); [DllImport("user32.dll")] public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern bool GetWindowRect(IntPtr hWnd, ref Rectangle r); [DllImport("user32.dll", EntryPoint = "GetWindowLong", CharSet = CharSet.Auto)] public static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex); [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr", CharSet = CharSet.Auto)] public static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex); [DllImport("user32.dll", EntryPoint = "SetWindowLong", CharSet = CharSet.Auto)] public static extern IntPtr SetWindowLongPtr32(IntPtr hWnd, int nIndex, int dwNewLong); [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", CharSet = CharSet.Auto)] public static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, int nIndex, int dwNewLong); [DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); [DllImport("user32.dll", EntryPoint = "ValidateRect", CharSet = CharSet.Auto)] private static extern IntPtr ValidatedRectInternal(IntPtr hWnd, ref Rectangle r); #endregion //[DllImport("user32.dll", EntryPoint = "LockWindowUpdate", CharSet = CharSet.Auto)] //private static extern int LockWindowUpdateInternal(IntPtr hWnd); //public static void LockWindowUpdate(IWin32Window window) { // if (window == null) // NativeMethods.LockWindowUpdateInternal(IntPtr.Zero); // else // NativeMethods.LockWindowUpdateInternal(window.Handle); //} /// /// Put an image under the ListView. /// /// /// /// The ListView must have its handle created before calling this. /// /// /// This doesn't work very well. Specifically, it doesn't play well with owner drawn, /// and grid lines are drawn over it. /// /// /// /// The image to be used as the background. If this is null, any existing background image will be cleared. /// If this is true, the image is pinned to the bottom right and does not scroll. The other parameters are ignored /// If this is true, the image will be tiled to fill the whole control background. The offset parameters will be ignored. /// If both watermark and tiled are false, this indicates the horizontal percentage where the image will be placed. 0 is absolute left, 100 is absolute right. /// If both watermark and tiled are false, this indicates the vertical percentage where the image will be placed. /// public static bool SetBackgroundImage(ListView lv, Image image, bool isWatermark, bool isTiled, int xOffset, int yOffset) { LVBKIMAGE lvbkimage = new LVBKIMAGE(); // We have to clear any pre-existing background image, otherwise the attempt to set the image will fail. // We don't know which type may already have been set, so we just clear both the watermark and the image. lvbkimage.ulFlags = LVBKIF_TYPE_WATERMARK; IntPtr result = NativeMethods.SendMessageLVBKIMAGE(lv.Handle, LVM_SETBKIMAGE, 0, ref lvbkimage); lvbkimage.ulFlags = LVBKIF_SOURCE_HBITMAP; result = NativeMethods.SendMessageLVBKIMAGE(lv.Handle, LVM_SETBKIMAGE, 0, ref lvbkimage); Bitmap bm = image as Bitmap; if (bm != null) { lvbkimage.hBmp = bm.GetHbitmap(); lvbkimage.ulFlags = isWatermark ? LVBKIF_TYPE_WATERMARK : (isTiled ? LVBKIF_SOURCE_HBITMAP | LVBKIF_STYLE_TILE : LVBKIF_SOURCE_HBITMAP); lvbkimage.xOffset = xOffset; lvbkimage.yOffset = yOffset; result = NativeMethods.SendMessageLVBKIMAGE(lv.Handle, LVM_SETBKIMAGE, 0, ref lvbkimage); } return (result != IntPtr.Zero); } public static bool DrawImageList(Graphics g, ImageList il, int index, int x, int y, bool isSelected, bool isDisabled) { ImageListDrawItemConstants flags = (isSelected ? ImageListDrawItemConstants.ILD_SELECTED : ImageListDrawItemConstants.ILD_NORMAL) | ImageListDrawItemConstants.ILD_TRANSPARENT; ImageListDrawStateConstants state = isDisabled ? ImageListDrawStateConstants.ILS_SATURATE : ImageListDrawStateConstants.ILS_NORMAL; try { IntPtr hdc = g.GetHdc(); return DrawImage(il, hdc, index, x, y, flags, 0, 0, state); } finally { g.ReleaseHdc(); } } /// /// Flags controlling how the Image List item is /// drawn /// [Flags] public enum ImageListDrawItemConstants { /// /// Draw item normally. /// ILD_NORMAL = 0x0, /// /// Draw item transparently. /// ILD_TRANSPARENT = 0x1, /// /// Draw item blended with 25% of the specified foreground colour /// or the Highlight colour if no foreground colour specified. /// ILD_BLEND25 = 0x2, /// /// Draw item blended with 50% of the specified foreground colour /// or the Highlight colour if no foreground colour specified. /// ILD_SELECTED = 0x4, /// /// Draw the icon's mask /// ILD_MASK = 0x10, /// /// Draw the icon image without using the mask /// ILD_IMAGE = 0x20, /// /// Draw the icon using the ROP specified. /// ILD_ROP = 0x40, /// /// Preserves the alpha channel in dest. XP only. /// ILD_PRESERVEALPHA = 0x1000, /// /// Scale the image to cx, cy instead of clipping it. XP only. /// ILD_SCALE = 0x2000, /// /// Scale the image to the current DPI of the display. XP only. /// ILD_DPISCALE = 0x4000 } /// /// Enumeration containing XP ImageList Draw State options /// [Flags] public enum ImageListDrawStateConstants { /// /// The image state is not modified. /// ILS_NORMAL = (0x00000000), /// /// Adds a glow effect to the icon, which causes the icon to appear to glow /// with a given color around the edges. (Note: does not appear to be implemented) /// ILS_GLOW = (0x00000001), //The color for the glow effect is passed to the IImageList::Draw method in the crEffect member of IMAGELISTDRAWPARAMS. /// /// Adds a drop shadow effect to the icon. (Note: does not appear to be implemented) /// ILS_SHADOW = (0x00000002), //The color for the drop shadow effect is passed to the IImageList::Draw method in the crEffect member of IMAGELISTDRAWPARAMS. /// /// Saturates the icon by increasing each color component /// of the RGB triplet for each pixel in the icon. (Note: only ever appears to result in a completely unsaturated icon) /// ILS_SATURATE = (0x00000004), // The amount to increase is indicated by the frame member in the IMAGELISTDRAWPARAMS method. /// /// Alpha blends the icon. Alpha blending controls the transparency /// level of an icon, according to the value of its alpha channel. /// (Note: does not appear to be implemented). /// ILS_ALPHA = (0x00000008) //The value of the alpha channel is indicated by the frame member in the IMAGELISTDRAWPARAMS method. The alpha channel can be from 0 to 255, with 0 being completely transparent, and 255 being completely opaque. } private const uint CLR_DEFAULT = 0xFF000000; /// /// Draws an image using the specified flags and state on XP systems. /// /// The image list from which an item will be drawn /// Device context to draw to /// Index of image to draw /// X Position to draw at /// Y Position to draw at /// Drawing flags /// Width to draw /// Height to draw /// State flags public static bool DrawImage(ImageList il, IntPtr hdc, int index, int x, int y, ImageListDrawItemConstants flags, int cx, int cy, ImageListDrawStateConstants stateFlags) { IMAGELISTDRAWPARAMS pimldp = new IMAGELISTDRAWPARAMS(); pimldp.hdcDst = hdc; pimldp.cbSize = Marshal.SizeOf(pimldp.GetType()); pimldp.i = index; pimldp.x = x; pimldp.y = y; pimldp.cx = cx; pimldp.cy = cy; pimldp.rgbFg = CLR_DEFAULT; pimldp.fStyle = (uint) flags; pimldp.fState = (uint) stateFlags; pimldp.himl = il.Handle; return ImageList_DrawIndirect(ref pimldp); } /// /// Make sure the ListView has the extended style that says to display subitem images. /// /// This method must be called after any .NET call that update the extended styles /// since they seem to erase this setting. /// The listview to send a m to public static void ForceSubItemImagesExStyle(ListView list) { SendMessage(list.Handle, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_SUBITEMIMAGES, LVS_EX_SUBITEMIMAGES); } /// /// Change the virtual list size of the given ListView (which must be in virtual mode) /// /// This will not change the scroll position /// The listview to send a message to /// How many rows should the list have? public static void SetItemCount(ListView list, int count) { SendMessage(list.Handle, LVM_SETITEMCOUNT, count, LVSICF_NOSCROLL); } /// /// Make sure the ListView has the extended style that says to display subitem images. /// /// This method must be called after any .NET call that update the extended styles /// since they seem to erase this setting. /// The listview to send a m to /// /// public static void SetExtendedStyle(ListView list, int style, int styleMask) { SendMessage(list.Handle, LVM_SETEXTENDEDLISTVIEWSTYLE, styleMask, style); } /// /// Calculates the number of items that can fit vertically in the visible area of a list-view (which /// must be in details or list view. /// /// The listView /// Number of visible items per page public static int GetCountPerPage(ListView list) { return (int)SendMessage(list.Handle, LVM_GETCOUNTPERPAGE, 0, 0); } /// /// For the given item and subitem, make it display the given image /// /// The listview to send a m to /// row number (0 based) /// subitem (0 is the item itself) /// index into the image list public static void SetSubItemImage(ListView list, int itemIndex, int subItemIndex, int imageIndex) { LVITEM lvItem = new LVITEM(); lvItem.mask = LVIF_IMAGE; lvItem.iItem = itemIndex; lvItem.iSubItem = subItemIndex; lvItem.iImage = imageIndex; SendMessageLVItem(list.Handle, LVM_SETITEM, 0, ref lvItem); } /// /// Setup the given column of the listview to show the given image to the right of the text. /// If the image index is -1, any previous image is cleared /// /// The listview to send a m to /// Index of the column to modifiy /// /// Index into the small image list public static void SetColumnImage(ListView list, int columnIndex, SortOrder order, int imageIndex) { IntPtr hdrCntl = NativeMethods.GetHeaderControl(list); if (hdrCntl.ToInt32() == 0) return; HDITEM item = new HDITEM(); item.mask = HDI_FORMAT; IntPtr result = SendMessageHDItem(hdrCntl, HDM_GETITEM, columnIndex, ref item); item.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN | HDF_IMAGE | HDF_BITMAP_ON_RIGHT); if (NativeMethods.HasBuiltinSortIndicators()) { if (order == SortOrder.Ascending) item.fmt |= HDF_SORTUP; if (order == SortOrder.Descending) item.fmt |= HDF_SORTDOWN; } else { item.mask |= HDI_IMAGE; item.fmt |= (HDF_IMAGE | HDF_BITMAP_ON_RIGHT); item.iImage = imageIndex; } result = SendMessageHDItem(hdrCntl, HDM_SETITEM, columnIndex, ref item); } /// /// Does this version of the operating system have builtin sort indicators? /// /// Are there builtin sort indicators /// XP and later have these public static bool HasBuiltinSortIndicators() { return OSFeature.Feature.GetVersionPresent(OSFeature.Themes) != null; } /// /// Return the bounds of the update region on the given control. /// /// The BeginPaint() system call validates the update region, effectively wiping out this information. /// So this call has to be made before the BeginPaint() call. /// The control whose update region is be calculated /// A rectangle public static Rectangle GetUpdateRect(Control cntl) { Rectangle r = new Rectangle(); GetUpdateRectInternal(cntl.Handle, ref r, false); return r; } /// /// Validate an area of the given control. A validated area will not be repainted at the next redraw. /// /// The control to be validated /// The area of the control to be validated public static void ValidateRect(Control cntl, Rectangle r) { ValidatedRectInternal(cntl.Handle, ref r); } /// /// Select all rows on the given listview /// /// The listview whose items are to be selected public static void SelectAllItems(ListView list) { NativeMethods.SetItemState(list, -1, LVIS_SELECTED, LVIS_SELECTED); } /// /// Deselect all rows on the given listview /// /// The listview whose items are to be deselected public static void DeselectAllItems(ListView list) { NativeMethods.SetItemState(list, -1, LVIS_SELECTED, 0); } /// /// Deselect a single row /// /// /// public static void DeselectOneItem(ListView list, int index) { NativeMethods.SetItemState(list, index, LVIS_SELECTED, 0); } /// /// Set the item state on the given item /// /// The listview whose item's state is to be changed /// The index of the item to be changed /// Which bits of the value are to be set? /// The value to be set public static void SetItemState(ListView list, int itemIndex, int mask, int value) { LVITEM lvItem = new LVITEM(); lvItem.stateMask = mask; lvItem.state = value; SendMessageLVItem(list.Handle, LVM_SETITEMSTATE, itemIndex, ref lvItem); } /// /// Scroll the given listview by the given deltas /// /// /// /// /// true if the scroll succeeded public static bool Scroll(ListView list, int dx, int dy) { return SendMessage(list.Handle, LVM_SCROLL, dx, dy) != IntPtr.Zero; } /// /// Return the handle to the header control on the given list /// /// The listview whose header control is to be returned /// The handle to the header control public static IntPtr GetHeaderControl(ListView list) { return SendMessage(list.Handle, LVM_GETHEADER, 0, 0); } /// /// Return the edges of the given column. /// /// /// /// A Point holding the left and right co-ords of the column. /// -1 means that the sides could not be retrieved. public static Point GetColumnSides(ObjectListView lv, int columnIndex) { Point sides = new Point(-1, -1); IntPtr hdr = NativeMethods.GetHeaderControl(lv); if (hdr == IntPtr.Zero) return new Point(-1, -1); RECT r = new RECT(); NativeMethods.SendMessageRECT(hdr, HDM_GETITEMRECT, columnIndex, ref r); return new Point(r.left, r.right); } /// /// Return the edges of the given column. /// /// /// /// A Point holding the left and right co-ords of the column. /// -1 means that the sides could not be retrieved. public static Point GetScrolledColumnSides(ListView lv, int columnIndex) { IntPtr hdr = NativeMethods.GetHeaderControl(lv); if (hdr == IntPtr.Zero) return new Point(-1, -1); RECT r = new RECT(); IntPtr result = NativeMethods.SendMessageRECT(hdr, HDM_GETITEMRECT, columnIndex, ref r); int scrollH = NativeMethods.GetScrollPosition(lv, true); return new Point(r.left - scrollH, r.right - scrollH); } /// /// Return the index of the column of the header that is under the given point. /// Return -1 if no column is under the pt /// /// The list we are interested in /// The client co-ords /// The index of the column under the point, or -1 if no column header is under that point public static int GetColumnUnderPoint(IntPtr handle, Point pt) { const int HHT_ONHEADER = 2; const int HHT_ONDIVIDER = 4; return NativeMethods.HeaderControlHitTest(handle, pt, HHT_ONHEADER | HHT_ONDIVIDER); } private static int HeaderControlHitTest(IntPtr handle, Point pt, int flag) { HDHITTESTINFO testInfo = new HDHITTESTINFO(); testInfo.pt_x = pt.X; testInfo.pt_y = pt.Y; IntPtr result = NativeMethods.SendMessageHDHITTESTINFO(handle, HDM_HITTEST, IntPtr.Zero, testInfo); if ((testInfo.flags & flag) != 0) return testInfo.iItem; else return -1; } /// /// Return the index of the divider under the given point. Return -1 if no divider is under the pt /// /// The list we are interested in /// The client co-ords /// The index of the divider under the point, or -1 if no divider is under that point public static int GetDividerUnderPoint(IntPtr handle, Point pt) { const int HHT_ONDIVIDER = 4; return NativeMethods.HeaderControlHitTest(handle, pt, HHT_ONDIVIDER); } /// /// Get the scroll position of the given scroll bar /// /// /// /// public static int GetScrollPosition(ListView lv, bool horizontalBar) { int fnBar = (horizontalBar ? SB_HORZ : SB_VERT); SCROLLINFO scrollInfo = new SCROLLINFO(); scrollInfo.fMask = SIF_POS; if (GetScrollInfo(lv.Handle, fnBar, scrollInfo)) return scrollInfo.nPos; else return -1; } /// /// Change the z-order to the window 'toBeMoved' so it appear directly on top of 'reference' /// /// /// /// public static bool ChangeZOrder(IWin32Window toBeMoved, IWin32Window reference) { return NativeMethods.SetWindowPos(toBeMoved.Handle, reference.Handle, 0, 0, 0, 0, SWP_ZORDERONLY); } /// /// Make the given control/window a topmost window /// /// /// public static bool MakeTopMost(IWin32Window toBeMoved) { IntPtr HWND_TOPMOST = (IntPtr)(-1); return NativeMethods.SetWindowPos(toBeMoved.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_ZORDERONLY); } /// /// Change the size of the window without affecting any other attributes /// /// /// /// /// public static bool ChangeSize(IWin32Window toBeMoved, int width, int height) { return NativeMethods.SetWindowPos(toBeMoved.Handle, IntPtr.Zero, 0, 0, width, height, SWP_SIZEONLY); } /// /// Show the given window without activating it /// /// The window to show static public void ShowWithoutActivate(IWin32Window win) { const int SW_SHOWNA = 8; NativeMethods.ShowWindow(win.Handle, SW_SHOWNA); } /// /// Mark the given column as being selected. /// /// /// The OLVColumn or null to clear /// /// This method works, but it prevents subitems in the given column from having /// back colors. /// static public void SetSelectedColumn(ListView objectListView, ColumnHeader value) { NativeMethods.SendMessage(objectListView.Handle, LVM_SETSELECTEDCOLUMN, (value == null) ? -1 : value.Index, 0); } static public int GetTopIndex(ListView lv) { return (int)SendMessage(lv.Handle, LVM_GETTOPINDEX, 0, 0); } static public IntPtr GetTooltipControl(ListView lv) { return SendMessage(lv.Handle, LVM_GETTOOLTIPS, 0, 0); } static public IntPtr SetTooltipControl(ListView lv, ToolTipControl tooltip) { return SendMessage(lv.Handle, LVM_SETTOOLTIPS, 0, tooltip.Handle); } static public bool HasHorizontalScrollBar(ListView lv) { const int GWL_STYLE = -16; const int WS_HSCROLL = 0x00100000; return (NativeMethods.GetWindowLong(lv.Handle, GWL_STYLE) & WS_HSCROLL) != 0; } public static int GetWindowLong(IntPtr hWnd, int nIndex) { if (IntPtr.Size == 4) return (int)GetWindowLong32(hWnd, nIndex); else return (int)(long)GetWindowLongPtr64(hWnd, nIndex); } public static int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong) { if (IntPtr.Size == 4) return (int)SetWindowLongPtr32(hWnd, nIndex, dwNewLong); else return (int)(long)SetWindowLongPtr64(hWnd, nIndex, dwNewLong); } [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] public static extern IntPtr SetBkColor(IntPtr hDC, int clr); [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] public static extern IntPtr SetTextColor(IntPtr hDC, int crColor); [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] public static extern IntPtr SelectObject(IntPtr hdc, IntPtr obj); [DllImport("uxtheme.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] public static extern IntPtr SetWindowTheme(IntPtr hWnd, string subApp, string subIdList); [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] public static extern bool InvalidateRect(IntPtr hWnd, int ignored, bool erase); [StructLayout(LayoutKind.Sequential)] public struct LVITEMINDEX { public int iItem; public int iGroup; } [StructLayout(LayoutKind.Sequential)] public struct POINT { public int x; public int y; } public static int GetGroupInfo(ObjectListView olv, int groupId, ref LVGROUP2 group) { return (int)NativeMethods.SendMessage(olv.Handle, LVM_GETGROUPINFO, groupId, ref group); } public static GroupState GetGroupState(ObjectListView olv, int groupId, GroupState mask) { return (GroupState)NativeMethods.SendMessage(olv.Handle, LVM_GETGROUPSTATE, groupId, (int)mask); } public static int InsertGroup(ObjectListView olv, LVGROUP2 group) { return (int)NativeMethods.SendMessage(olv.Handle, LVM_INSERTGROUP, -1, ref group); } public static int SetGroupInfo(ObjectListView olv, int groupId, LVGROUP2 group) { return (int)NativeMethods.SendMessage(olv.Handle, LVM_SETGROUPINFO, groupId, ref group); } public static int SetGroupMetrics(ObjectListView olv, LVGROUPMETRICS metrics) { return (int)NativeMethods.SendMessage(olv.Handle, LVM_SETGROUPMETRICS, 0, ref metrics); } public static void ClearGroups(VirtualObjectListView virtualObjectListView) { NativeMethods.SendMessage(virtualObjectListView.Handle, LVM_REMOVEALLGROUPS, 0, 0); } public static void SetGroupImageList(ObjectListView olv, ImageList il) { const int LVSIL_GROUPHEADER = 3; IntPtr handle = IntPtr.Zero; if (il != null) handle = il.Handle; NativeMethods.SendMessage(olv.Handle, LVM_SETIMAGELIST, LVSIL_GROUPHEADER, handle); } public static int HitTest(ObjectListView olv, ref LVHITTESTINFO hittest) { return (int)NativeMethods.SendMessage(olv.Handle, olv.View == View.Details ? LVM_SUBITEMHITTEST : LVM_HITTEST, -1, ref hittest); } } }