Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom cursor anomaly?

I've come across some weird behavior while playing with custom cursors in c# using Windows Forms. I've reduced the problem to a new project with 1 form, 2 panels added to the form, 1 icon added to project's properties/resources.resx, and 3 images added to the same place.

The only code the project will have is this

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace TestProject
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            panel1.Cursor = new Cursor(Properties.Resources.randomIcon.Handle);
            panel2.Cursor = new Cursor(Properties.Resources.randomIcon.Handle);
        }
    }
}

Now, the weird behaviour starts when I modify the backgroundimage property of the Form. I've downloaded multiple random images from various sources and set them as form's background image.

  • When I set some of them and run the program, both of the panels have their custom cursor.

  • When I set other images, only the second panel has its cursor.

  • I've even found an image with which panel1 has its cursor for the first few seconds, but if I happen to get out and back in the panel after those few seconds, the cursor gets permanently removed.

If I change the backgroundimagelayout property of the form to None instead of Tile, the cursor works no matter what the image is.

There is nothing else that's being modified in the entire project. 1 Form, 2 Panels, 1 icon as the cursor, 3 images and a totally senseless (or maybe not, maybe i'm missing something) behavior.

I just want to find out what causes this behavior as I encountered it while working on bigger project, and it took me a while to track the core of the problem. Maybe i shouldn't be using the cursors this way, but the question remains, what makes c# behave in such a way when nothing but the background image is being modified.

I've made a sample project here - https://www.dropbox.com/s/bl4iomzyz1bv7kb/Sample.rar?dl=0

like image 500
Gabriel Em Avatar asked Jul 15 '26 19:07

Gabriel Em


1 Answers

From the MSDN article for the Icon.Handle property that you use:

This is not a copy of the handle; do not free it.

This a bit more cryptic than it could be, to put it mildly. What it does mean is that Handle is only valid as long as the Icon object is not destroyed. That is a problem in your code, you are not making sure that the new object returned by Properties.Resources.randomIcon is referenced anywhere.

So as soon as the garbage collector runs, the icon object is history. And the handle is no longer valid. Which in turn makes the cursor invalid. The only relevance of the images is what impact they have on the GC.

You have to write it like this instead:

    private Icon customCursor;

    public Form1()
    {
        InitializeComponent();
        customCursor = Properties.Resources.Cat;
        panel1.Cursor = panel2.Cursor = new Cursor(customCursor.Handle);
    }

Now the garbage collector always sees a reference to the Icon object as long as the form object stays alive. So its Handle property stays valid.

This also has another side to the medal. The Icon class implements IDisposable. So be a good .NET citizen:

    protected override void OnFormClosed(FormClosedEventArgs e) {
        customCursor.Dispose();
        base.OnFormClosed(e);
    }

Fwiw, pretty safe to assume that if Microsoft could designed the .NET 1.0 Icon and Cursor classes all over again, and the Properties.Resources facility, they probably would have done it differently :)

like image 193
Hans Passant Avatar answered Jul 18 '26 07:07

Hans Passant