internal static void GetIconInfo(HandleRef hIcon, out NativeMethods.ICONINFO piconinfo) { bool success = false; int error = 0; piconinfo = new NativeMethods.ICONINFO(); ICONINFO_IMPL iconInfoImpl = new ICONINFO_IMPL(); SRCS.RuntimeHelpers.PrepareConstrainedRegions(); // Mark the following as special try { // Intentionally empty } finally { // This block won't be interrupted by certain runtime induced failures or thread abort success = GetIconInfoImpl(hIcon, iconInfoImpl); error = Marshal.GetLastWin32Error(); if (success) { piconinfo.hbmMask = NativeMethods.BitmapHandle.CreateFromHandle(iconInfoImpl.hbmMask); piconinfo.hbmColor = NativeMethods.BitmapHandle.CreateFromHandle(iconInfoImpl.hbmColor); piconinfo.fIcon = iconInfoImpl.fIcon; piconinfo.xHotspot = iconInfoImpl.xHotspot; piconinfo.yHotspot = iconInfoImpl.yHotspot; } } if(!success) { Debug.WriteLine("GetIconInfo failed. Error = " + error); throw new Win32Exception(); } }
internal static NativeMethods.IconHandle CreateIconCursor( byte[] colorArray, int width, int height, int xHotspot, int yHotspot, bool isIcon) { // 1. We are going to generate a WIN32 color bitmap which represents the color cursor. // 2. Then we need to create a monochrome bitmap which is used as the cursor mask. // 3. At last we create a WIN32 HICON from the above two bitmaps NativeMethods.BitmapHandle colorBitmap = null; NativeMethods.BitmapHandle maskBitmap = null; try { // 1) Create the color bitmap using colorArray // Fill in the header information NativeMethods.BITMAPINFO bi = new NativeMethods.BITMAPINFO( width, // width -height, // A negative value indicates the bitmap is top-down DIB 32 // biBitCount ); bi.bmiHeader_biCompression = NativeMethods.BI_RGB; IntPtr bits = IntPtr.Zero; colorBitmap = MS.Win32.UnsafeNativeMethods.CreateDIBSection( new HandleRef(null, IntPtr.Zero), // A device context. Pass null in if no DIB_PAL_COLORS is used. ref bi, // A BITMAPINFO structure which specifies the dimensions and colors. NativeMethods.DIB_RGB_COLORS, // Specifies the type of data contained in the bmiColors array member of the BITMAPINFO structure ref bits, // An out Pointer to a variable that receives a pointer to the location of the DIB bit values null, // Handle to a file-mapping object that the function will use to create the DIB. This parameter can be null. 0 // dwOffset. This value is ignored if hSection is NULL ); if ( colorBitmap.IsInvalid || bits == IntPtr.Zero) { // Note we will release the GDI resources in the finally block. return NativeMethods.IconHandle.GetInvalidIcon(); } // Copy the color bits to the win32 bitmap Marshal.Copy(colorArray, 0, bits, colorArray.Length); // 2) Now create the mask bitmap which is monochrome byte[] maskArray = GenerateMaskArray(width, height, colorArray); Invariant.Assert(maskArray != null); maskBitmap = UnsafeNativeMethods.CreateBitmap(width, height, 1, 1, maskArray); if ( maskBitmap.IsInvalid ) { // Note we will release the GDI resources in the finally block. return NativeMethods.IconHandle.GetInvalidIcon(); } // Now create HICON from two bitmaps. NativeMethods.ICONINFO iconInfo = new NativeMethods.ICONINFO(); iconInfo.fIcon = isIcon; // fIcon == ture means creating an Icon, otherwise Cursor iconInfo.xHotspot = xHotspot; iconInfo.yHotspot = yHotspot; iconInfo.hbmMask = maskBitmap; iconInfo.hbmColor = colorBitmap; return UnsafeNativeMethods.CreateIconIndirect(iconInfo); } finally { if (colorBitmap != null) { colorBitmap.Dispose(); colorBitmap = null; } if (maskBitmap != null) { maskBitmap.Dispose(); maskBitmap = null; } } }
private static void GetMouseCursorSize(out int width, out int height, out int hotX, out int hotY) { /* The code for this function is based upon shell\comctl32\v6\tooltips.cpp _GetHcursorPdy3 ------------------------------------------------------------------------- With the current mouse drivers that allow you to customize the mouse pointer size, GetSystemMetrics returns useless values regarding that pointer size. Assumption: 1. The pointer's width is equal to its height. We compute its height and infer its width. This function looks at the mouse pointer bitmap to find out the dimensions of the mouse pointer and the hot spot location. ------------------------------------------------------------------------- */ // If there is no mouse cursor, these should be 0 width = height = hotX = hotY = 0; // First, retrieve the mouse cursor IntPtr hCursor = SafeNativeMethods.GetCursor(); if (hCursor != IntPtr.Zero) { // In case we can't figure out the dimensions, this is a best guess width = height = 16; // Get the cursor information NativeMethods.ICONINFO iconInfo = new NativeMethods.ICONINFO(); bool gotIconInfo = true; try { UnsafeNativeMethods.GetIconInfo(new HandleRef(null, hCursor), out iconInfo); } catch(Win32Exception) { gotIconInfo = false; } if(gotIconInfo) { // Get a handle to the bitmap NativeMethods.BITMAP bm = new NativeMethods.BITMAP(); int resultOfGetObject=0; new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert(); //Blessed Assert try { resultOfGetObject = UnsafeNativeMethods.GetObject(iconInfo.hbmMask.MakeHandleRef(null), Marshal.SizeOf(typeof(NativeMethods.BITMAP)), bm); } finally { SecurityPermission.RevertAssert(); } if (resultOfGetObject != 0) { // Extract the bitmap bits int max = (bm.bmWidth * bm.bmHeight / 8); byte[] curMask = new byte[max * 2]; // Enough space for the mask and the xor mask if (UnsafeNativeMethods.GetBitmapBits(iconInfo.hbmMask.MakeHandleRef(null), curMask.Length, curMask) != 0) { bool hasXORMask = false; if (iconInfo.hbmColor.IsInvalid) { // if no color bitmap, then the hbmMask is a double height bitmap // with the cursor and the mask stacked. hasXORMask = true; max /= 2; } // Go through the bitmap looking for the bottom of the image and/or mask bool empty = true; int bottom = max; for (bottom--; bottom >= 0; bottom--) { if (curMask[bottom] != 0xFF || (hasXORMask && (curMask[bottom + max] != 0))) { empty = false; break; } } if (!empty) { // Go through the bitmap looking for the top of the image and/or mask int top; for (top = 0; top < max; top++) { if (curMask[top] != 0xFF || (hasXORMask && (curMask[top + max] != 0))) break; } // Calculate the left, right, top, bottom points // byteWidth = bytes per row AND bytes per vertical pixel int byteWidth = bm.bmWidth / 8; int right /*px*/ = (bottom /*bytes*/ % byteWidth) * 8 /*px/byte*/; bottom /*px*/ = bottom /*bytes*/ / byteWidth /*bytes/px*/; int left /*px*/ = top /*bytes*/ % byteWidth * 8 /*px/byte*/; top /*px*/ = top /*bytes*/ / byteWidth /*bytes/px*/; // (Final value) Convert LRTB to Width and Height width = right - left + 1; height = bottom - top + 1; // (Final value) Calculate the hotspot relative to top/left hotX = iconInfo.xHotspot - left; hotY = iconInfo.yHotspot - top; } else { // (Final value) We didn't find anything in the bitmap. // So, we'll make a guess with the information that we have. // Note: This seems to happen on I-Beams and Cross-hairs -- cursors that // are all inverted. Strangely, their hbmColor is non-null. width = bm.bmWidth; height = bm.bmHeight; hotX = iconInfo.xHotspot; hotY = iconInfo.yHotspot; } } } iconInfo.hbmColor.Dispose(); iconInfo.hbmMask.Dispose(); } } }