Custom Cursor in Resource will not Load

P

Paul Cheetham

Hi,

I have some custom colour cursors which I have added to my c# project,
and set them to be compiled as "Embedded Resource"
It seems impossible to load a colour cursor using the standard Cursor
class, so I have had to resort to loading it using the Win32 API, and
creating the cursor with - new Cursor(HCURSOR)

The code I am using is shown at the bottom of this post.

I have confirmed that the cursors I am trying to load are embedded in
the exe file, by listing them to the output window as follows:
foreach(string s in
this.GetType().Assembly.GetManifestResourceNames())
System.Diagnostics.Trace.WriteLine(s);


However, whenever I try to load one of these using the Win32 LoadImage
function (I have also tried LoadCursor) it fails, with the following error:

1813 - The specified resource type cannot be found in the image file.

As far as I can tell the resource is there, but it is either in a
different format to what the Win32 functions expect it, or it's not
really there at all.

I have spent a great deal of time on this, and it is something I need to
solve for several projects.

Has anybody managed to solve this problem, and actually use cursors
properly in .Net as is possible in Win32?


Thankyou.

Paul Cheetham

(Using Visual Studio 2003, .Net Framework 1.1)



Code:

public static Cursor LoadCursor (string CursorName)
{
Cursor myCursor = null;
String Name;
IntPtr HCursor=IntPtr.Zero, HInst=IntPtr.Zero;
uint ErrCode;

//Name = "ProLogic.Cursors." + CursorName + ".CUR";
Name = "ProLogic.Cursor1.CUR";

HInst = Win32.GetModuleHandleW(null);

HCursor = Win32.LoadImage(HInst, Name, Win32.IMAGE_CURSOR, 0, 0,
Win32.LR_DEFAULTCOLOR | Win32.LR_DEFAULTSIZE | Win32.LR_SHARED);
//HCursor = Win32.LoadCursor (HInst, Name);
if (HCursor.ToInt32() == 0)
{ ErrCode = Win32.GetLastError();
} else
myCursor = new Cursor (HCursor);

return (myCursor);
}


#region <<< Class Win32 >>>

/// <author>Shrijeet Nair</author>
public class Win32
{
public const uint IMAGE_BITMAP = 0;
public const uint IMAGE_ICON = 1;
public const uint IMAGE_CURSOR = 2;

public const uint LR_DEFAULTCOLOR = 0x0000;
public const uint LR_MONOCHROME = 0x0001;
public const uint LR_COLOR = 0x0002;
public const uint LR_COPYRETURNORG = 0x0004;
public const uint LR_COPYDELETEORG = 0x0008;
public const uint LR_LOADFROMFILE = 0x0010;
public const uint LR_LOADTRANSPARENT = 0x0020;
public const uint LR_DEFAULTSIZE = 0x0040;
public const uint LR_VGACOLOR = 0x0080;
public const uint LR_LOADMAP3DCOLORS = 0x1000;
public const uint LR_CREATEDIBSECTION = 0x2000;
public const uint LR_COPYFROMRESOURCE = 0x4000;
public const uint LR_SHARED = 0x8000;


[DllImport("User32.dll")]
public static extern IntPtr LoadImage(IntPtr hinst,

[MarshalAs(UnmanagedType.LPTStr)] string lpszName,
uint uType,
int cxDesired,
int cyDesired,
uint fuLoad);

[DllImport("User32.dll")]
public static extern IntPtr LoadCursor(IntPtr hinst,
[MarshalAs(UnmanagedType.LPTStr)] string lpszName);

[DllImport( "kernel32.dll" )]
public extern static IntPtr
GetModuleHandleW([MarshalAs(UnmanagedType.LPStr)] string lpModuleName );

[DllImport( "kernel32.dll" )]
public extern static uint GetLastError();
}

#endregion
 
N

Nicholas Paldino [.NET/C# MVP]

Paul,

Why are you using LoadImage? If you are storing a cursor as an embedded
resource, you can just call the GetManifestResourceStream (on the Assembly
class, passing the name of the resource, in this case, a cursor, to get).
That will return a Stream to you. You can then take that Stream and pass
that to the constructor of the Cursor class. At that point, you have your
cursor, and if you need the handle of it, you can call the Handle property
of the Cursor instance.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Paul Cheetham said:
Hi,

I have some custom colour cursors which I have added to my c# project, and
set them to be compiled as "Embedded Resource"
It seems impossible to load a colour cursor using the standard Cursor
class, so I have had to resort to loading it using the Win32 API, and
creating the cursor with - new Cursor(HCURSOR)

The code I am using is shown at the bottom of this post.

I have confirmed that the cursors I am trying to load are embedded in the
exe file, by listing them to the output window as follows:
foreach(string s in
this.GetType().Assembly.GetManifestResourceNames())
System.Diagnostics.Trace.WriteLine(s);


However, whenever I try to load one of these using the Win32 LoadImage
function (I have also tried LoadCursor) it fails, with the following
error:

1813 - The specified resource type cannot be found in the image file.

As far as I can tell the resource is there, but it is either in a
different format to what the Win32 functions expect it, or it's not really
there at all.

I have spent a great deal of time on this, and it is something I need to
solve for several projects.

Has anybody managed to solve this problem, and actually use cursors
properly in .Net as is possible in Win32?


Thankyou.

Paul Cheetham

(Using Visual Studio 2003, .Net Framework 1.1)



Code:

public static Cursor LoadCursor (string CursorName)
{
Cursor myCursor = null;
String Name;
IntPtr HCursor=IntPtr.Zero, HInst=IntPtr.Zero;
uint ErrCode;

//Name = "ProLogic.Cursors." + CursorName + ".CUR";
Name = "ProLogic.Cursor1.CUR";

HInst = Win32.GetModuleHandleW(null);

HCursor = Win32.LoadImage(HInst, Name, Win32.IMAGE_CURSOR, 0, 0,
Win32.LR_DEFAULTCOLOR | Win32.LR_DEFAULTSIZE | Win32.LR_SHARED);
//HCursor = Win32.LoadCursor (HInst, Name);
if (HCursor.ToInt32() == 0)
{ ErrCode = Win32.GetLastError();
} else
myCursor = new Cursor (HCursor);

return (myCursor);
}


#region <<< Class Win32 >>>

/// <author>Shrijeet Nair</author>
public class Win32
{
public const uint IMAGE_BITMAP = 0;
public const uint IMAGE_ICON = 1;
public const uint IMAGE_CURSOR = 2;

public const uint LR_DEFAULTCOLOR = 0x0000;
public const uint LR_MONOCHROME = 0x0001;
public const uint LR_COLOR = 0x0002;
public const uint LR_COPYRETURNORG = 0x0004;
public const uint LR_COPYDELETEORG = 0x0008;
public const uint LR_LOADFROMFILE = 0x0010;
public const uint LR_LOADTRANSPARENT = 0x0020;
public const uint LR_DEFAULTSIZE = 0x0040;
public const uint LR_VGACOLOR = 0x0080;
public const uint LR_LOADMAP3DCOLORS = 0x1000;
public const uint LR_CREATEDIBSECTION = 0x2000;
public const uint LR_COPYFROMRESOURCE = 0x4000;
public const uint LR_SHARED = 0x8000;


[DllImport("User32.dll")]
public static extern IntPtr LoadImage(IntPtr hinst,

[MarshalAs(UnmanagedType.LPTStr)] string lpszName,
uint uType,
int cxDesired,
int cyDesired,
uint fuLoad);

[DllImport("User32.dll")]
public static extern IntPtr LoadCursor(IntPtr hinst,
[MarshalAs(UnmanagedType.LPTStr)] string lpszName);

[DllImport( "kernel32.dll" )]
public extern static IntPtr
GetModuleHandleW([MarshalAs(UnmanagedType.LPStr)] string lpModuleName );

[DllImport( "kernel32.dll" )]
public extern static uint GetLastError();
}

#endregion
 
P

Paul Cheetham

Hi Nicholas,

I have tried that method, but I end up with a monochrome version of the
cursor instead of the colour version as it should be.
Since none of the .Net Cursor constructors seem able to load a colour
cursor correctly I was forced to try and load it using the Win32 API and
then try to assign it to the cursor class.


Any other ideas greatly appreciated.

Thanks.


Paul Cheetham
 
N

Nicholas Paldino [.NET/C# MVP]

Paul,

Looking into this, it seems that ultimately, it uses some of the Ole
methods to load it as a picture first, and then load it as a cursor. I
think that along the way, this is where the colors get skewed.

In order to get a cursor that you would load through LoadCursor, you
will have to compile through the command line (or adjust the tasks in your
project file if you are using .NET 2.0 with MSBUILD). You can use the
/win32res flag to embed a Win32 resource.

This means you will have to create a .rc file, run it through the
Resource Compiler (used in Visual C++ typically) and then point to the
resulting .res file with the /win32res flag.

Once you do that, in your code, you can call LoadCursor through the
P/Invoke layer. You to get the handle, you would pass the Module (in most
assemblies, there is only one Module, but you can create multi-module
assemblies) to the static GetHINSTANCE method on the Marshal class. You
would then pass this handle as the first parameter in the LoadCursor method.
Then, you should have your cursor handle, and you can pass that to the
Cursor object.
 
P

Paul Cheetham

Nicholas,

Thankyou for your help.
I will try your suggestion - I will create a Win32 .rc file and compile
it into my project (I am assuming there will be a way to do this in VS 2003)

Hopefully it should be reasonably straight forward from there.

Thankyou again.

Paul
 
N

Nicholas Paldino [.NET/C# MVP]

Paul,

In VS.NET 2003 (rather, .NET 1.1 and before) there is no way to do this.
You have to use the command-line compiler (csc) with the options I
mentioned.

Hope this helps.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top