swythan

swythan


  • Name: [not set]
  • Favorite Languages: [not set]
  • Website: [not set]
  • Location: [not set]
  • About Me: [not set]

Recent Comments

  • WPF Tutorial - How To Use Custom Cursors
    05/12/2009 - 08:29

    Fantastic! Just what I needed.

    I think your use of SafeHandle is a bit out, though. SafeFileHandle calls CloseHandle(handle) in it's ReleaseHandle implementation, but CloseHandle doesn't deal with icons. For icons you should call DestroyIcon.

    Here's my version. I've also reorganised a bit.

    using System;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Security.Permissions;
    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Interop;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using Microsoft.Win32.SafeHandles;

    namespace Controls.Utilities
    {
      public class CursorHelper
      {
        private static class NativeMethods
        {
          public struct IconInfo
          {
            public bool fIcon;
            public int xHotspot;
            public int yHotspot;
            public IntPtr hbmMask;
            public IntPtr hbmColor;
          }

          [DllImport("user32.dll")]
          public static extern SafeIconHandle CreateIconIndirect(ref IconInfo icon);

          [DllImport("user32.dll")]
          public static extern bool DestroyIcon(IntPtr hIcon);

          [DllImport("user32.dll")]
          [return: MarshalAs(UnmanagedType.Bool)]
          public static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo);
        }

        [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
        private class SafeIconHandle : SafeHandleZeroOrMinusOneIsInvalid
        {
          public SafeIconHandle()
            : base(true)
          {
          }

          override protected bool ReleaseHandle()
          {
            return NativeMethods.DestroyIcon(handle);
          }
        }

        private static Cursor InternalCreateCursor(System.Drawing.Bitmap bmp, int xHotSpot, int yHotSpot)
        {
          var iconInfo = new NativeMethods.IconInfo();
          NativeMethods.GetIconInfo(bmp.GetHicon(), ref iconInfo);

          iconInfo.xHotspot = xHotSpot;
          iconInfo.yHotspot = yHotSpot;
          iconInfo.fIcon = false;

          SafeIconHandle cursorHandle = NativeMethods.CreateIconIndirect(ref iconInfo);
          return CursorInteropHelper.Create(cursorHandle);
        }

        public static Cursor CreateCursor(UIElement element, int xHotSpot, int yHotSpot)
        {
          element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
          element.Arrange(new Rect(new Point(), element.DesiredSize));

          RenderTargetBitmap rtb =
            new RenderTargetBitmap(
              (int)element.DesiredSize.Width,
              (int)element.DesiredSize.Height,
              96, 96, PixelFormats.Pbgra32);

          rtb.Render(element);

          var encoder = new PngBitmapEncoder();
          encoder.Frames.Add(BitmapFrame.Create(rtb));

          using (var ms = new MemoryStream())
          {
            encoder.Save(ms);
            using (var bmp = new System.Drawing.Bitmap(ms))
            {
              return InternalCreateCursor(bmp, xHotSpot, yHotSpot);
            }
          }
        }
      }
    }