画面キャプチャ
サンプルコード - 修正版
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
class IconMakeTest:Form
{
class NativeMethods
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public extern static bool DestroyIcon(IntPtr handle);
}
IconMakeTest()
{
HandleCreated+=(sender,e)=>{GetHiconExample();};
}
static string[] iconDot = new string[]{
"................",
".###...##...##..",
"..#...#..#.#..#.",
"..#...#....#..#.",
"..#...#....#..#.",
"..#...#....#..#.",
"..#...#....#..#.",
"..#...#....#..#.",
"..#...#....#..#.",
"..#...#....#..#.",
"..#...#....#..#.",
"..#...#....#..#.",
"..#...#....#..#.",
"..#...#..#.#..#.",
".###...##...##..",
"................",
};
void GetHiconExample()
{
Bitmap bmp = new Bitmap(16,16);
using ( Graphics g = Graphics.FromImage(bmp) ) {
g.Clear(Color.White);
}
for(int y=0;y<16;y++){
for(int x=0;x<16;x++){
if (iconDot[y][x]=='#') {
bmp.SetPixel(x,y,Color.Black);
}
}
}
IntPtr Hicon = bmp.GetHicon();
Icon newIcon;
newIcon = Icon.FromHandle(Hicon);
this.Icon = newIcon;
NativeMethods.DestroyIcon(newIcon.Handle);
}
[STAThread]
static void Main(string[] args)
{
Application.Run(new IconMakeTest());
}
}
説明
string配列でドット絵を表現していて、BitmapへSetPixelで描画し、GetHiconメソッドでIconへのポインタを取得し、Icon.FromHandleメソッドで取得したハンドルをFormのIconプロパティにセットしている。
HandleCreated
イベントで呼び出している理由
HandleCreated
イベントが発生したときにGetHiconExample
を呼んでいるのは、以下の理由のため。
最初は、Form
のコンストラクタでGetHiconExample
を呼ぶコードを書いていた。それで実行すると、下記の例外が発生した。
System.ObjectDisposedException: 破棄されたオブジェクトにアクセスできません。
オブジェクト名 'Icon' です。
どうやらDestroyIcon
したあとにIcon
が生成されているようである。
ILSpyで色々調べてみたところ、Form
のIcon
プロパティに代入(setアクセス)したときに、内部でUpdateWindowIcon
が呼ばれるのだが、IsHandleCreated
がtrue
でないと、このときにIcon
が生成(WM_SETICON
)されないようになっている。
private void UpdateWindowIcon(bool redrawFrame)
{
if (!base.IsHandleCreated)
{
return;
}
:
SendMessage(128, 1, icon.Handle); // 128 = WM_SETICON
なので、以下の順になっていないといけない。
-
HandleCreated
イベント発生 -
Form.Icon
へのハンドルのset -
DestroyIcon
の実行
参考サイト
- https://docs.microsoft.com/en-us/dotnet/api/system.drawing.icon.fromhandle?view=netframework-4.8
- https://dobon.net/vb/dotnet/graphics/saveimage.html
おまけ - 参考サイト 1 のサンプルコードの完全版
参考サイト 1 のサンプルコードは一部しかかかれておらず、そのままでは実行できないため、
GetHicon_Example
メソッドとDestroyIcon
以外を付け足した。
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
class IconTest : Form
{
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = CharSet.Auto)]
extern static bool DestroyIcon(IntPtr handle);
IconTest()
{
Paint += (sender,e)=>{GetHicon_Example(e);};
}
private void GetHicon_Example(PaintEventArgs e)
{
// Create a Bitmap object from an image file.
Bitmap myBitmap = new Bitmap(@"c:\FakePhoto.jpg");
// Draw myBitmap to the screen.
e.Graphics.DrawImage(myBitmap, 0, 0);
// Get an Hicon for myBitmap.
IntPtr Hicon = myBitmap.GetHicon();
// Create a new icon from the handle.
Icon newIcon = Icon.FromHandle(Hicon);
// Set the form Icon attribute to the new icon.
this.Icon = newIcon;
// You can now destroy the icon, since the form creates
// its own copy of the icon accessible through the Form.Icon property.
DestroyIcon(newIcon.Handle);
}
[STAThread]
static void Main(string[] args)
{
Application.Run(new IconTest());
}
}
DestroyIcon
のWindowsAPIの説明を見ても.Netでの使用を考慮していない説明になっており、このコードのDestroyIcon
を呼び出しているとこのコメントが参考になった。