前回はビットマップファイルからアイコンを作成しました。
アイコンを作成できるのであればカーソルをつくる方法もあるはず。そこで調べてみました。
C#でカーソルを作成する コガネブログ(旧)ではAPI関数のGetIconInfo関数とCreateIconIndirect関数を使ってカーソルをつくる方法が紹介されています。
GetIconInfo関数
これはアイコンまたはマウス カーソルに関する情報を取得するための関数です。第一引数にアイコンまたはマウス カーソルのハンドルを指定、第二引数にICONINFO構造体へのポインタを指定します。するとこの構造体にアイコンやマウスカーソルに関する情報が格納されます。
CreateIconIndirect関数
CreateIconIndirect関数は指定されたICONINFO構造体に基づいて、アイコンやカーソルを作成する関数です。
ではさっそくやってみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
public partial class Form1 : Form { [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo); [DllImport("user32.dll")] public static extern IntPtr CreateIconIndirect(ref IconInfo icon); public struct IconInfo { public bool fIcon; // アイコンの場合 true, カーソルの場合 false public int xHotspot; // カーソルのホットスポットの X 座標 public int yHotspot; // カーソルのホットスポットの Y 座標 public IntPtr hbmMask; // 透過用のビットマップハンドル public IntPtr hbmColor; // 画像用のビットマップハンドル } public static Cursor CreateCursor(Bitmap bmp, int xHotSpot, int yHotSpot) { IntPtr ptr = bmp.GetHicon(); IconInfo tmp = new IconInfo(); GetIconInfo(ptr, ref tmp); tmp.xHotspot = xHotSpot; tmp.yHotspot = yHotSpot; tmp.fIcon = false; ptr = CreateIconIndirect(ref tmp); return new Cursor(ptr); } // ビットマップファイルからカーソルファイルをつくる void MakeCursorFromBmpFile(string bitmapFilePath, string cursorFilePath, int xHotSpot, int yHotSpot) { Image img = Image.FromFile(bitmapFilePath); Bitmap bitmap = new Bitmap(32, 32, System.Drawing.Imaging.PixelFormat.Format24bppRgb); Graphics g = Graphics.FromImage(bitmap); g.DrawImage(img, new Rectangle(0, 0, 32, 32)); g.Dispose(); Cursor cursor = CreateCursor(bitmap, xHotSpot, yHotSpot); Icon icon = Icon.FromHandle(cursor.Handle); Stream outStream = new FileStream(cursorFilePath, FileMode.Create, FileAccess.Write); icon.Save(outStream); //後始末 outStream.Close(); bitmap.Dispose(); icon.Dispose(); img.Dispose(); } private void button2_Click(object sender, EventArgs e) { SaveFileDialog dialog = new SaveFileDialog(); dialog.Filter = "カーソルファイル|*.cur"; if(dialog.ShowDialog() != DialogResult.OK) return; if(!File.Exists(textBoxForFilePath1.Text)) { MessageBox.Show("Bitmapファイルのバスが不正です。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } try { int x = int.Parse(textBoxHotSpotX.Text); int y = int.Parse(textBoxHotSpotY.Text); MakeCursorFromBmpFile(textBoxForFilePath1.Text, dialog.FileName, x, y); } catch { } } } |
これでカーソルファイルを作成することはできますが、ホットスポットは常に真ん中になってしまいます。ホットスポットを設定できるようにしているのですが、この場合は設定しても意味がありません。
そこでForm1_Loadのときに、もう一回設定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public partial class Form1 : Form { Cursor myCursor = null; private void Form1_Load(object sender, EventArgs e) { Cursor tempCursor = new Cursor(GetType(), "my.cur"); // もう一回設定する IconInfo tmp = new IconInfo(); GetIconInfo(tempCursor.Handle, ref tmp); tmp.xHotspot = 0; // ホットスポットは(0,0)に設定する tmp.yHotspot = 0; tmp.fIcon = false; // 必要。ないとホットスポットは中央になる。 IntPtr ptr = CreateIconIndirect(ref tmp); myCursor = new Cursor(ptr); } private void Form1_MouseDown(object sender, MouseEventArgs e) { if(e.Button == MouseButtons.Right) this.Cursor = myCursor; if(e.Button == MouseButtons.Left) this.Cursor = Cursors.Default; } } |
これだとうまくいくのですが、だったらアイコンからカーソルを読み込んでもよさそうな・・・・
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Cursor myCursor = null; private void Form1_Load(object sender, EventArgs e) { Icon tempCursor = new Icon(GetType(), "my.ico"); // もう一回設定する IconInfo tmp = new IconInfo(); GetIconInfo(tempCursor.Handle, ref tmp); tmp.xHotspot = 0; // ホットスポットは(0,0)に設定する tmp.yHotspot = 0; tmp.fIcon = false; // 必要。ないとホットスポットは中央になる。 IntPtr ptr = CreateIconIndirect(ref tmp); myCursor = new Cursor(ptr); } |