レイヤードウィンドウを使用するのでウィンドウとして表示する画像ファイルを別途用意する。
WIN32APIを使うのでAPI宣言。
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CreateCompatibleDC(IntPtr hdc);
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int DeleteObject(IntPtr hobject);
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int DeleteDC(IntPtr hdc);
[DllImport("user32")]
public static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("user32")]
public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
public const int AC_SRC_OVER = 0;
public const int AC_SRC_ALPHA = 1;
public const int ULW_ALPHA = 2;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BLENDFUNCTION
{
public byte BlendOp;
public byte BlendFlags;
public byte SourceConstantAlpha;
public byte AlphaFormat;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int UpdateLayeredWindow(
IntPtr hwnd,
IntPtr hdcDst,
[System.Runtime.InteropServices.In()]
ref Point pptDst,
[System.Runtime.InteropServices.In()]
ref Size psize,
IntPtr hdcSrc,
[System.Runtime.InteropServices.In()]
ref Point pptSrc,
int crKey,
[System.Runtime.InteropServices.In()]
ref BLENDFUNCTION pblend,
int dwFlags
);フォームの CreateParams プロパティを override してレイヤードウィンドウにする。
フォームを突き抜けるには下記のWS_EX_TRANSPARENTをスタイルに設定するのがポイント。
protected override CreateParams CreateParams
{
get
{
const int WS_EX_LAYERED = 0x00080000;
const int WS_EX_TRANSPARENT = 0x00000020;
const int WS_BORDER = 0x00800000;
const int WS_THICKFRAME = 0x00040000;
System.Windows.Forms.CreateParams cp = base.CreateParams;
cp.ExStyle = cp.ExStyle | WS_EX_LAYERED;
cp.ExStyle = cp.ExStyle | WS_EX_TRANSPARENT;
if (this.FormBorderStyle != FormBorderStyle.None) {
cp.Style = cp.Style & (~WS_BORDER);
cp.Style = cp.Style & (~WS_THICKFRAME);
}
return cp;
}
}
レイヤードウィンドウを設定するメソッドを定義。
BLENDFUNCTION構造体のSourceConstantAlphaの値で透明度を指定できるのでお好みで設定する。
private void SetLayeredWindow(Bitmap bmp)
{
IntPtr screenDc = IntPtr.Zero;
IntPtr memDc = IntPtr.Zero;
IntPtr hbmp = IntPtr.Zero;
IntPtr oldbmp = IntPtr.Zero;
try {
screenDc = GetDC(IntPtr.Zero);
memDc = CreateCompatibleDC(screenDc);
hbmp = bmp.GetHbitmap(Color.FromArgb(0));
oldbmp = SelectObject(memDc, hbmp);
// イメージの透過情報を設定
BLENDFUNCTION bf = new BLENDFUNCTION();
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = 128; // 50%の透過度でイメージを表示する!
bf.AlphaFormat = AC_SRC_ALPHA;
// ウィンドウ更新
this.Size = new Size(bmp.Width, bmp.Height);
Point pptDst = new Point(this.Left, this.Top);
Size psize = new Size(this.Width, this.Height);
Point pptSrc = new Point(0, 0);
User32.UpdateLayeredWindow(this.Handle, screenDc, ref pptDst, ref psize, memDc, ref pptSrc, 0, ref bf, ULW_ALPHA);
} finally {
if (screenDc != IntPtr.Zero) {
ReleaseDC(IntPtr.Zero, screenDc);
}
if (hbmp != IntPtr.Zero) {
SelectObject(memDc, oldbmp);
DeleteObject(hbmp);
}
if (memDc != IntPtr.Zero) {
DeleteDC(memDc);
}
}
}
あとはフォームのコンストラクタあたりでイメージファイルを読み込んで上記のメソッドを呼んであげる。
public Form1()
{
Bitmap bmp = new Bitmap(@"C:\test.png");
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData bd = bmp.LockBits(rect, ImageLockMode.ReadOnly, bmp.PixelFormat);
Bitmap ret = new Bitmap(bd.Width, bd.Height, bd.Stride, PixelFormat.Format32bppArgb, bd.Scan0);
bmp.UnlockBits(bd);
SetLayeredWindow(bmp);
}
申し訳ないがここにのせたソース、動いてるソースを切って貼ったものではあるけれども、貼った後の検証をしてないのでコピペして動かなかった場合、各自アドリブでの対応をお願いしたい。