Introduction
The .NET System.Windows.Forms.Cursor
class doesn't natively support animated or color cursors. (And, if the constructor doesn't throw an exception when passed a color cursor, the colors vanish). But, one can use the LoadCursorFromFileW
function of "user32.dll" to get around this constraint.
The 'TdhCursorFactory' Class
The TdhCursorFactory
class is built on a basis primarily of code published in this MSDN article: Using Colored and Animated Cursors; and secondarily Bingzhe Quan's Code Project article: A scrollable, zoomable, and scalable picture box. But, then it takes off into parts unknown.
The class is static
; its primary purpose is to create .NET usable color and animated cursors. As an added bonus, it can maintain an array of Cursors for easy access by the program making use of the library. The Cursors stored in this array may be used to "override" the standard Cursors of the System.Windows.Forms.Cursors
class.
A Note On The LoadCursorFromFileW Function
The LoadCursorFromFileW
function of "user32.dll" requires its argument to be the name of an actual file on disk (I was unable to find if there is a similar function which can take a memory stream). Thus, when the methods of TdhCursorFactory
must make use of the LoadCursorFromFileW
function as part of the process of extracting a Cursor object from the embedded resources (i.e. for animated cursors or color non-animated cursors), the resource is first extracted into a memory stream, which is written to a temporary file. This temporary file is then passed as the argument to the LoadCursorFromFileW
function (and deleted afterward).
On the other hand, a black-and-white non-animated cursor may be passed as a memory stream directly to the [new System.Windows.Forms.Cursor(stream)] constructor. By default, the TdhCursorFactory
class attempts this with cursors having the ".CUR" extension.
So, effectively, the only real advantage to making animated cursors or color non-animated cursors embedded resources of your project is that since they are "inside" the assembly, they won't get lost.
Using The Class
To use TdhCursorFactory
as is, add a reference in your project to the class library 'TDHCursorFactory.dll.' The namespace used in this library is:
using TDHControls.TDHCursorFactory;
{
TdhCursorFactory.SetCursor(TdhCursorFactory.Cursors._Busy,
@"C:\SomePath\SomeCursor.ani");
TdhCursorFactory.SetCursor(TdhCursorFactory.Cursors.WaitCursor, true,
"Cursors.Cow_chewing.ani", true);
this.Cursor = TdhCursorFactory.GetCursor(TdhCursorFactory.Cursors._Busy);
this.Cursor = TdhCursorFactory.GetCursor(
TdhCursorFactory.Cursors.WaitCursor);
TdhCursorFactory.UnsetCursor(TdhCursorFactory.Cursors.WaitCursor);
this.Cursor = TdhCursorFactory.GetCursor(
TdhCursorFactory.Cursors.WaitCursor);
TdhCursorFactory.SetCursor(TdhCursorFactory.Cursors._Busy, true,
"Demo_Cursors.EarlyBird.ani", true);
TdhCursorFactory.SetCursor(TdhCursorFactory.Cursors._Busy, true,
"Drum.ani", true);
TdhCursorFactory.SetCursor(TdhCursorFactory.Cursors._Busy, true,
"Drum.ani", false);
this.Cursor = TdhCursorFactory.FromFile(@"C:\SomePath\SomeCursor.cur",
false);
this.Cursor = TdhCursorFactory.FromResource(false,
"Demo_Cursors.SomeCursor.cur", true, false);
}
The TdhCursorFactory
class was written (and compiled) using VS2002 (.NET 1.0) with the intention that the source code be readily available to other developers regardless of the .NET version they are using.
The members of TdhCursorFactory
's interface are:
Cursors
� The items in the array of Cursors managed by the class are accessed via the TdhCursorFactory.Cursors
enum (see below for a list of members).
public static System.Windows.Forms.Cursor GetCursor(TdhCursorFactory.Cursors whichCursor)
This method returns a System.Windows.Forms.Cursor
object from the array of cursors managed by the class, as named by the 'whichCursor
' value. If that particular cursor has not been set, the method returns the standard System.Windows.Forms.Cursors.Default
object.
public static void InitCursor_X(TdhCursorFactory.Cursors whichCursor)
This method initializes the "sub-array" of Cursors referenced by the 'whichCursor
' enum value (at this time, only the TdhCursorFactory.Cursors._X_Random_Busy
enum member is so defined) to a set of pre-defined Cursor objects obtained from the class's resources manifest. The method is not executed automatically by the class's constructor, but rather if it is desired that these cursors be loaded, the method must be explicitly called by the main program.
public static void SetCursor(TdhCursorFactory.Cursors whichCursor, bool forceAsColor, string cursorName, bool caseSensitive)
This method sets the managed Cursor named by 'whichCursor
' to a System.Windows.Forms.Cursor
object obtained from the embedded Resources of either: 1) the calling assembly, or 2) the TdhCursorFactory
class' assembly. If the 'cursorName
' value cannot be found in either assembly (or if it is not a valid Cursor), the method will leave the managed Cursor as is. The 'caseSensitive
' value determines whether the 'cursorName
' value must be given exactly. When this value is false, the class will examine all the object names contained in the assembly's resources manifest. The value of 'forceAsColor
' allows the developer using the class to force ".CUR" files to be loaded via the LoadCursorFromFileW
function of "user32.dll." (Cursors with the ".ANI" extension are always loaded via this function).
public static void SetCursor(TdhCursorFactory.Cursors whichCursor, string fileName)
This method sets the managed Cursor named by 'whichCursor
' to the System.Windows.Forms.Cursor
object read from the file with the path given in 'fileName
.' If the given path does not resolve to a valid Cursor, the method will leave the managed Cursor as is.
public static void SetCursor(TdhCursorFactory.Cursors whichCursor, System.Windows.Forms.Cursor theCursor)
This method sets the managed Cursor named by 'whichCursor
' to the System.Windows.Forms.Cursor
object passed as 'theCursor
.'
public static void UnsetCursor(TdhCursorFactory.Cursors whichCursor)
This method releases the managed Cursor named by 'whichCursor
.'
public static System.Windows.Forms.Cursor FromFile(string fileName, bool allowNull)
This method returns a System.Windows.Forms.Cursor
object read from the file with the path given in 'fileName
.' If the given path does not resolve to a valid Cursor, the method will return either a null object or the System.Windows.Forms.Cursors.Default
object, depending on the value of 'allowNull
.'
public static System.Windows.Forms.Cursor FromResource(bool forceAsColor, string cursorName, bool caseSensitive, bool allowNull)
This method returns a System.Windows.Forms.Cursor
object obtained from the embedded Resources of either: 1) the calling assembly, or 2) the TdhCursorFactory
class' assembly. If the 'cursorName
' value cannot be found in either assembly (or if it is not a valid Cursor), the method will return either a null object or the System.Windows.Forms.Cursors.Default
object, depending on the value of 'allowNull
.' The 'caseSensitive
' value determines whether the 'cursorName
' value must be given exactly. When this value is false, the class will examine all the object names contained in the assembly's resources manifest. The value of 'forceAsColor
' allows the developer using the class to force ".CUR" files to be loaded via the LoadCursorFromFileW
function of "user32.dll." (Cursors with the ".ANI" extension are always loaded via this function).
public static System.Collections.ArrayList ResourcesManifest(bool forCallingAssembly)
This method returns an ArrayList (of string objects) containing the fully qualified names of the ".ANI" and ".CUR" items in the resources manifest of either the calling assembly or the 'TDHCursorFactory.dll' assembly.
As written/assembled, the 'TDHCursorFactory.dll' assembly contains a number of cursors as embedded resources. Since the class as written is geared towards my overall project, you may well want to eliminate many (or all) of these; and you may want to add your own cursors as resources ... aren't you glad you have the source code?
- Cursors.arrow_l.cur
- Cursors.arrow_l_blue.cur
- Cursors.arrow_l_red-outline.cur
- Cursors.BlindMouse.ani
- Cursors.busy_l.cur
- Cursors.counter.ani
- Cursors.Cow_chewing.ani
- Cursors.EarlyBird.ani
- Cursors.FlyingPig.ani
- Cursors.HamsterWheel.ani
- Cursors.HamtonJPig3.cur
- Cursors.HorseRider.ani
- Cursors.PanToolCursor.cur
- Cursors.PanToolCursorMouseDown.cur
- Cursors.PorkyPig.cur
The TdhCursorFactory.Cursors
enum is the means by which the array of Cursors internally managed by the TdhCursorFactory
class are accessed. This has both advantages and disadvantages. The main disadvantage is that the only way to add items to the enum is to recompile the class. The advantages are legion, including: the TdhCursorFactory
class manages the set of cursors your program is using for you, all you need do is initially set them; you may "override" (or not, as you wish) the standard cursors of the System.Windows.Forms.Cursors
class -- your main program's code will be given a valid cursor object in either case; once you are satisfied with *your* version of the TdhCursorFactory.Cursors
enum, your version of the TdhCursorFactory
class will be both flexible enough to be useful for any program needing color and/or animated cursors and simultaneously specific to your own needs.
The members of the TdhCursorFactory.Cursors
enum are :
- There are a number of members for custom-defined Cursors. By default, the class constructor extracts embedded resources from its assembly for these items, though the main program can replace (or release) any of them at any time. These custom definitions are, of course, geared towards my overall project; you may want to add or remove custom definitions.
Cursors._Busy
Cursors._Grab
Cursors._GrabRelease
Cursors._Normal
Cursors._X_Random_Busy
- a special member; it (randomly) accesses the elements of a "sub-array" of Cursors
- The remainder of members may be used to "override" the standard Cursors of the
System.Windows.Forms.Cursors
class. Any to which a Cursor has not been explicitly set (via the [ SetCursor()
] methods) will return (via the [ GetCursor()
] method) the corresponding standard Cursor:
Cursors.AppStarting
Cursors.Arrow
Cursors.Cross
Cursors.Default
Cursors.Hand
Cursors.Help
Cursors.HSplit
Cursors.IBeam
Cursors.No
Cursors.NoMove2D
Cursors.NoMoveHoriz
Cursors.NoMoveVert
Cursors.PanEast
Cursors.PanNE
Cursors.PanNorth
Cursors.PanNW
Cursors.PanSE
Cursors.PanSouth
Cursors.PanSW
Cursors.PanWest
Cursors.SizeAll
Cursors.SizeNESW
Cursors.SizeNS
Cursors.SizeNWSE
Cursors.SizeWE
Cursors.UpArrow
Cursors.VSplit
Cursors.WaitCursor
History
- 2007 October 26: Submission of
TdhCursorFactory
ver 1.0.001 to The Code Project.
- 2007 October 27: ver 1.0.002
- Modified the
SetCursor(TdhCursorFactory.Cursors whichCursor, string cursorName, bool caseSensitive)
method.
Previously, if the string cursorName
value could not be found in the resources manifest (or did not resolve to a valid Cursor), the method would set the array item referenced by the TdhCursorFactory.Cursors whichCursor
value to a null object. Now, there will be no effect.
- Created the
public static System.Collections.ArrayList ResourcesManifest(bool forCallingAssembly)
method.
- 2007 October 29: ver 1.0.003
- Modified the methods:
FromResource()
and (one signature of) SetCursor()
(sorry about that!)
- Added the argument "bool forceAsColor
" to allow the developer using the class to force ".CUR" files to be loaded via the LoadCursorFromFileW
function of "user32.dll." The value of this argument is relevant only for Cursors with the ".CUR" extension; Cursors with the ".ANI" extension are always loaded via the LoadCursorFromFileW
function of "user32.dll."
- 2007 October 29: ver 1.1.000
- Added the special '
_X_Random_Busy
' member to the TdhCursorFactory.Cursors
enum.
The '_X_Random_Busy
' member may be used to access a "sub-array" of Cursors -- It randomly points to one of the Cursors which have been loaded into the "sub-array." Individual Cursors may be loaded into this "sub-array" via the existing [ SetCursor()
] methods; the [ GetCursor()
] method will randomly return one of the Cursors loaded into the "sub-array."
- Created the [
InitCursor_X()
] method.
This method initializes the "sub-array" of Cursors referenced by the enum value TdhCursorFactory.Cursors._X_Random_Busy
to a set of pre-defined Cursor objects obtained from the class' resources manifest.