[SOLVED] Crash when setting a hardware mouse cursor from a sprite... any ideas?

{“Failed to set surface for mouse cursor: CreateIconIndirect(): The parameter is incorrect.\r\n”} System.InvalidOperationException

Stack Trace:
StackTrace " at Microsoft.Xna.Framework.Input.MouseCursor.PlatformFromTexture2D(Texture2D texture, Int32 originx, Int32 originy)\r\n" string

So I was messing around with Mouse.SetCursor(MouseCursor.FromTexture2D(sprite, 0, 0));

And by messing around I mean setting it several times per second (i.e. every frame). Windows 10, VS 2017.

This crash pops out after maybe half a minute of incessant clicking, but is 100% reproducible under those conditions.

Has anyone seen this before? Google has failed me.

I’d appreciate any pointers on how to prevent this crash.

It seems that I can avoid it by setting mouse cursor sprite less frequently, but that means I can’t have an animated mouse cursor. Even then, that’s not a guarantee if there’s a bug somewhere in the pipeline.

Should I just put this inside a giant try{} block and forget about it?

Thanks for reading!

MouseCursor.FromTexture2D generates a new texture each time. It’s possible you’re generating too many textures that aren’t being disposed based on how often you’re calling it and using the textures.

Instead, call FromTexture2D on each sprite you need in your animation and cache the MouseCursors you get back. Then, call Mouse.SetCursor and pass in the cached MouseCursor object when it’s time to switch. Here’s a quick, untested example:

public class MouseCursorAnim
{
    private MouseCursor[] Cursors = null;

    public void CacheCursors(Texture2D[] mouseAnim)
    {
        Cursors = new MouseCursor[mouseAnim.Length];
        
        for (int i = 0; i < Cursors.Length; i++)
        {
            Cursors[i] = MouseCursor.FromTexture2D(mouseAnim[i], 0, 0);
        }
    }
    
    public void SetCursor(int frame)
    {
        Mouse.SetCursor(Cursors[frame]);
    }
}
2 Likes

Hey, awesome. Going to stress test the hell out of this and report back.

I tested it, and your solution worked great. Memory is holding steady and as of 5 minutes running, there are no crashes while I’m pumping a new cursor in at every frame. Thank you!

I am missing something about Texture2D. I understand that generating new textures every frame is a bad idea, but I’m curious exactly what’s happening under the hood. Is it creating a texture in video card memory or RAM? What should I read to avoid such snafus in the future?

Awesome; I’m glad to hear that did the trick!

To my understanding, creating a Texture2D (and many other graphics resources) via the constructor requires you to dispose the Texture2D when you’re finished with it because it’s a native resource, so the GC doesn’t see it and won’t free the memory associated with it. Failing to do so will result in memory leaks.

To help with your issue, I looked at the source for one of the MouseCursor platform implementations. If you’d like to delve more into how it all works, I’d recommend checking out the MonoGame source code since documentation is scarce on this subject. There’s quite a lot to digest, but it’s nice to know how some of this is working under the hood.

1 Like

Texture data is stored in video memory only.

1 Like

I remember shawn hargraves saying that he didn’t like from file which is what this is basically because of just the scenario you gave. However FromFile is sort of requisite at times and you need to know a little bit about the dangers of it when using it.

Consider the following scenario you create a texture as you did or using from file or set data.

Texture2D t;

// first
t = MouseCursor.FromTexture2D(mouseAnim[i], 0, 0);

lets say you do this later on again but load in a different texture without calling dispose.

// second
t = MouseCursor.FromTexture2D(mouseAnimB[i], 0, 0);

.
then you call dispose.
.

t.Dispose();

What allocated memory does t now refer to ?
t refers to the second texture only now.
So.
How does the first texture get disposed now ? …

Answer is … it doesn’t and you can’t the reference is now dangling in limbo.

So what and were is the reference to the first texture now ?

This may not be spot on technically but practically this is how it is.

The reference is pinned memory basically and the gc can’t reclaim it.
The video card thinks you are using it so its not unloaded there either.
Worse yet its got the reference to t for first and second memory areas.
You no longer have acess to it.
The gc does but it wont touch it.

It’s essentially a semi dangling reference but since its not accessible and can’t be called even by the gc it may not even crash the app or just might do so at a unexpected time or variable time depending on other things going on in the os (Like maybe a Alt Enter or Tab).

Video cards do their own thing the driver has more control over it then the os and (when the card starts to fill up say in the case were you have multiple apps running at once) they can if need be grab the reference they have and clear out memory temporarily then sort of reload it using that reference. Which also means if the second texture you loaded has a different size then the first this could be a app or card crashing event when the reference for the first and the second are the same when they shouldn’t be and there could even be a buffer overflow or underflow into a protected memory area which would probably now days just be a app crashing event too.

All this applys to set data as well. It’s not so bad if you just load a small texture and forget to dispose it before exit but if you did this a crap load then exit the app and reload it over and over it can add up and you can actually tax the card with no way to clear that memory till you restart your computer.

That’s terrifying.

So what’s the proper way of disposing of a texture that was created with a “new .FromTexture2D” call as opposed to Content.Load, and if there isn’t, why is that in the codebase?

Call Dispose() on the Texture2D when you’re finished with it. An example can be found here.