using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Security; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace GeoSigmaViewer { public class CursorResourceLoader { #region Methods public static Cursor LoadEmbeddedCursor(byte[] cursorResource, int imageIndex = 0) { var resourceHandle = GCHandle.Alloc(cursorResource, GCHandleType.Pinned); var iconImage = IntPtr.Zero; var cursorHandle = IntPtr.Zero; try { var header = (IconHeader)Marshal.PtrToStructure(resourceHandle.AddrOfPinnedObject(), typeof(IconHeader)); if (imageIndex >= header.count) throw new ArgumentOutOfRangeException("imageIndex"); var iconInfoPtr = resourceHandle.AddrOfPinnedObject() + Marshal.SizeOf(typeof(IconHeader)) + imageIndex * Marshal.SizeOf(typeof(IconInfo)); var info = (IconInfo)Marshal.PtrToStructure(iconInfoPtr, typeof(IconInfo)); iconImage = Marshal.AllocHGlobal(info.size + 4); Marshal.WriteInt16(iconImage + 0, info.hotspot_x); Marshal.WriteInt16(iconImage + 2, info.hotspot_y); Marshal.Copy(cursorResource, info.offset, iconImage + 4, info.size); cursorHandle = NativeMethods.CreateIconFromResource(iconImage, info.size + 4, false, 0x30000); return new Cursor(cursorHandle); } finally { if (cursorHandle != IntPtr.Zero) NativeMethods.DestroyIcon(cursorHandle); if (iconImage != IntPtr.Zero) Marshal.FreeHGlobal(iconImage); if (resourceHandle.IsAllocated) resourceHandle.Free(); } } #endregion Methods #region Native Methods [SuppressUnmanagedCodeSecurity] static class NativeMethods { [DllImportAttribute("user32.dll", CharSet = CharSet.Unicode)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool DestroyIcon(IntPtr hIcon); [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr CreateIconFromResource(IntPtr pbIconBits, int dwResSize, bool fIcon, int dwVer); } #endregion Native Methods #region Native Structures [StructLayout(LayoutKind.Explicit, Pack = 1)] struct IconHeader { [FieldOffset(0)] public short reserved; [FieldOffset(2)] public short type; [FieldOffset(4)] public short count; } /// Union structure for icons and cursors. /// For icons, field offset 4 is used for planes and field offset 6 for /// bits-per-pixel, while for cursors field offset 4 is used for the x coordinate /// of the hotspot, and field offset 6 is used for the y coordinate. [StructLayout(LayoutKind.Explicit, Pack = 1)] struct IconInfo { [FieldOffset(0)] public byte width; [FieldOffset(1)] public byte height; [FieldOffset(2)] public byte colors; [FieldOffset(3)] public byte reserved; [FieldOffset(4)] public short planes; [FieldOffset(6)] public short bpp; [FieldOffset(4)] public short hotspot_x; [FieldOffset(6)] public short hotspot_y; [FieldOffset(8)] public int size; [FieldOffset(12)] public int offset; } #endregion Native Structures } }