potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。

C# 9&Win API ウィンドウのクライアント領域のボタン降下でウィンドウを移動させる

ウィンドウのクライアント領域のボタン降下でウィンドウを移動させるサンプルコードです。ウィンドウはシステムに対してカーソルの位置を自身のWM_NCHITTESTメッセージで指定できることを利用します。

#nullable enable

using System;
using System.Drawing;
using System.Windows.Forms;

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.SetHighDpiMode(HighDpiMode.SystemAware);
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
}

sealed class Form1 : Form
{
    protected override void WndProc(ref Message m)
    {
        switch (m.Msg)
        {
            case WindowMessages.WM_NCHITTEST:
                OnNCHitTest(
                    ref m,
                    new Point(GetXLParam(m.LParam), GetYLParam(m.LParam)));
                break;
            default:
                base.WndProc(ref m);
                break;
        }
    }

    #region ウィンドウメッセージ用のユーティリティー
    private static short GetXLParam(nint LParam) => (short)LParam;
    private static short GetYLParam(nint LParam) => (short)(((int)LParam) >> 16);
    #endregion

    /// <summary>
    /// WM_NCHITTESTウィンドウメッセージを処理します。
    /// </summary>
    /// <param name="m">ウィンドウメッセージ。</param>
    /// <param name="location">画面左上からの位置。</param>
    private void OnNCHitTest(ref Message m, Point location)
    {
        // var existsInWindow = DesktopBounds.Contains(location);
        var existsInClient = RectangleToScreen(ClientRectangle).Contains(location);

        if (existsInClient)
        {
            m.Result = NCMousePositionCodes.HTCAPTION;
        }
        else
        {
            DefWndProc(ref m);
        }
    }

    private static class WindowMessages
    {
        public const int WM_NCHITTEST = 0x0084;
    }

    private static class NCMousePositionCodes
    {
        public const nint HTCAPTION = 2;
    }
}

HT~には他にも次のような定数があります。

private static class NCMousePositionCodes
{
    public const nint HTERROR = -2;
    public const nint HTTRANSPARENT = -1;
    public const nint HTNOWHERE = 0;
    public const nint HTCLIENT = 1;
    public const nint HTCAPTION = 2;
    public const nint HTSYSMENU = 3;
    public const nint HTGROWBOX = 4;
    public const nint HTSIZE = HTGROWBOX;
    public const nint HTMENU = 5;
    public const nint HTHSCROLL = 6;
    public const nint HTVSCROLL = 7;
    public const nint HTMINBUTTON = 8;
    public const nint HTMAXBUTTON = 9;
    public const nint HTLEFT = 10;
    public const nint HTRIGHT = 11;
    public const nint HTTOP = 12;
    public const nint HTTOPLEFT = 13;
    public const nint HTTOPRIGHT = 14;
    public const nint HTBOTTOM = 15;
    public const nint HTBOTTOMLEFT = 16;
    public const nint HTBOTTOMRIGHT = 17;
    public const nint HTBORDER = 18;
    public const nint HTREDUCE = HTMINBUTTON;
    public const nint HTZOOM = HTMAXBUTTON;
    public const nint HTSIZEFIRST = HTLEFT;
    public const nint HTSIZELAST = HTBOTTOMRIGHT;
    public const nint HTOBJECT = 19;
    public const nint HTCLOSE = 20;
    public const nint HTHELP = 21;
}