Aeroなウィンドウを作る
VistaやWindows7で実装されているAero、キャプションバーが半透明になるやつです。Internet ExplorerやGoogle Chromeでは、タブの部分まで半透明になっていますよね。どうやってやるのか調べた結果の備忘録です。
Aeroを実現するには、デスクトップウィンドウマネージャ(DWM)というインターフェースを使います。詳細はMSDNマガジンにある記事に書かれていますが、多くを文章で説明していて、コードの実例があまりないです。
では実例を紹介します。まず、DllImportするために、次の一行を加えます。
using System.Runtime.InteropServices;
Imports System.Runtime.InteropServices
そして、クラス内に次のコードを書きます。
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern void DwmExtendFrameIntoClientArea(IntPtr hWnd, MARGINS pMargins);
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern bool DwmIsCompositionEnabled();
[StructLayout(LayoutKind.Sequential)]
public struct MARGINS
{
    public int leftWidth;
    public int rightWidth;
    public int topHeight;
    public int bottomHeight;
}
<dllimport("dwmapi.dll", preservesig="" :="False)"> _
Public Shared Sub DwmExtendFrameIntoClientArea(hWnd As IntPtr, pMargins As MARGINS)
End Sub
<dllimport("dwmapi.dll", preservesig="" :="False)"> _
Public Shared Function DwmIsCompositionEnabled() As Boolean
End Function
<structlayout(layoutkind.sequential)> _
Public Structure MARGINS
    Public leftWidth As Integer
    Public rightWidth As Integer
    Public topHeight As Integer
    Public bottomHeight As Integer
End Structure
これでDWMを呼び出す準備ができました。続いてコンストラクタでDWMを呼び出します。
public Form1()
{
    InitializeComponent();
    BackColor = Color.Black;
    if (DwmIsCompositionEnabled() == true)
    {
        MARGINS margin;
        margin.leftWidth = 0;
        margin.rightWidth = 0;
        margin.topHeight = -1;
        margin.bottomHeight = 0;
        DwmExtendFrameIntoClientArea(this.Handle, margin);
    }
}
Public Sub New()
    InitializeComponent()
    BackColor = Color.Black
    If DwmIsCompositionEnabled() = True Then
        Dim margin As MARGINS
        margin.leftWidth = 0
        margin.rightWidth = 0
        margin.topHeight = -1
        margin.bottomHeight = 0
        DwmExtendFrameIntoClientArea(Me.Handle, margin)
    End If
End Sub
BackColorをBlackにしているのは、DWMでは黒い部分が半透明になるからです。また、marginのいずれかを-1にすると、ウィンドウ全体にAero効果が現れます。
ちゃんと半透明になりました。しかし、よく見ると、ボタンやテキストボックスの文字の色まで半透明になってしまいました。これを回避するには、UseCompatibleTextRenderingをtrueにすればいいという記事を見つけたのですが、ボタンのUseCompatibleTextRenderingをtrueにしても結果は同じでした。まだ調べる必要がありますね。
次のコードを加えて、フォーム上に直接文字列を書いてみましたが、これは半透明になりませんでした。これが半透明になった場合は、SetCompatibleTextRenderingDefaultをtrueにしてやれば黒で描画されるようになる、という記事を見つけたのですが、再現できないので保留です。
private void Form1_Paint(object sender, PaintEventArgs e)
{
    // GDI+で描画
    e.Graphics.DrawString("Hello World!", Font, Brushes.Black, 100, 100);
    // GDIで描画
    TextRenderer.DrawText(e.Graphics, "Hello World!", Font, new Point(100, 120), BackColor);
}
Private Sub Form1_Paint(sender As Object, e As PaintEventArgs)
    ' GDI+で描画
    e.Graphics.DrawString("Hello World!", Font, Brushes.Black, 100, 100)
    ' GDIで描画
    TextRenderer.DrawText(e.Graphics, "Hello World!", Font, New Point(100, 120), BackColor)
End Sub
もっとも、ウィンドウ全体を半透明にしたい場合は少ないでしょう。次のようなコードが現実的ではないでしょうか。(tabControl1.ItemSize.Heightを参照したいので、Form_Loadに書いています)
private void Form1_Load(object sender, EventArgs e)
{
    BackColor = Color.Black;
    if (DwmIsCompositionEnabled() == true)
    {
        MARGINS margin;
        margin.leftWidth = 0;
        margin.rightWidth = 0;
        margin.topHeight = tabControl1.ItemSize.Height + 2;
        margin.bottomHeight = 0;
        DwmExtendFrameIntoClientArea(this.Handle, margin);
    }
}
Private Sub Form1_Load(sender As Object, e As EventArgs)
    BackColor = Color.Black
    If DwmIsCompositionEnabled() = True Then
        Dim margin As MARGINS
        margin.leftWidth = 0
        margin.rightWidth = 0
        margin.topHeight = tabControl1.ItemSize.Height + 2
        margin.bottomHeight = 0
        DwmExtendFrameIntoClientArea(Me.Handle, margin)
    End If
End Sub
まだまだ不完全な記事です。情報をお持ちの方はお知らせください。
2014年1月3日


