CefSharpでポップアップウィンドウのアイコンを変更する。LifeSpanHandlerとWin32APIを使ってFormをコントロールする

2020年3月20日

前回、ILifeSpanHandlerを使ってポップアップを自前のフォームで制御できることを書きました。

上記の場合だと、親子のwindowオブジェクトの連携が取れなくなり、公式でも非推奨なので、親子連携がないパターンくらいでしか使えないかなと思ったのが正直なところでした。

今回は、CefSharpで自動的に生成されるポップアップのFormをどうやって制御するかという内容を取り上げます。
今回やっていくのは
①ポップアップで開かれるWindowのアイコンを変更すること
②ポップアップで開かれるwindowを最大化して開く
です。

本来自分でFormを実装しているのであれば、上記した内容は簡単に実現できます。
Formのプロパティに必要なパラメータを設定すればOKなので。
例えばFormのアイコンを変えたい場合は、以下のプロパティを変更すればいいですよね。

ポップアップのアイコンを制御するためにはWin32APIを使う必要がある。

CefSharpが自動的に生成するFormに対してアイコンを設定したり、画面を最大化したりするためにはWin32APIを使用する必要があります。

いつもは.NETが各種イベントを制御してくれているので、私もこういう機会がないとWin32APIを触ることがないので、あまり理解していなかったので、まずはざっくり理解していくために、いくつかググりました。

今回は、私自身がWin32APIを解説できるまで詳しくないということがあるので、内容についてはノータッチです。

ちなみに、理解の助けになったのが以下サイトです。
https://tech.sanwasystem.com/entry/2015/11/25/171004

そもそも今回業務で必要だったのは
①ポップアップで開かれるWindowのアイコンを変更すること
でした。
色々とググって検索していると、CefSharpのポップアップでアイコンを変更するためにはWin32APIを使う必要があるということがわかりました。

参考にしたサイト
https://www.magpcss.org/ceforum/viewtopic.php?f=6&t=11814
こちらでは、CefSharpで立ち上がるポップアップの画像を変更するにはWin32APIを使用する必要があることが書かれています。

そのあと、どうやってFormのアイコンを変えるか探した結果行きついたサイトがこちら。
https://stackoverflow.com/questions/9199523/is-there-a-way-to-have-my-app-push-its-icon-to-other-apps
こちらはCefSharpとは関係なく、他アプリのFormのアイコンを変更する方法が書かれています。

CefSharpで上がってくるPopupも捉え方を変えれば、他アプリのFormのIconを変えることと同じことをすればよいということになります。

ソース

上記を元に実装してみた結果、うまく動いたのでソースを公開します。
以下がそのソース。

using System;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using CefSharp;

namespace WinFormsCefSharpSample.ChangePopupIconSample
{
    class LifespanHandler : ILifeSpanHandler
    {
        public bool OnBeforePopup(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl,
            string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures,
            IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser)
        {
            newBrowser = null;
            return false;
        }

        /// <summary>
        /// Win32APIのSendMessage(Formのアイコンを変更するために使用する)
        /// </summary>
        /// <param name="hwnd">送信先ウィンドウのハンドル</param>
        /// <param name="message">メッセージ</param>
        /// <param name="wParam">メッセージの最初のパラメータ</param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        private static extern int SendMessage(IntPtr hwnd, int message, int wParam, IntPtr lParam);
        /// <summary>
        /// Win32APIのShowWindowAsync(画面サイズを最大化させるために使用)
        /// </summary>
        /// <param name="hwnd"></param>
        /// <param name="nCmdShow"></param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        public static extern int ShowWindowAsync(IntPtr hwnd, int nCmdShow);

        private const int WM_SETICON = 0x80;
        private const int ICON_BIG = 1;
        private const int SIZE_MAXIMIZED = 3;


        public void OnAfterCreated(IWebBrowser chromiumWebBrowser, IBrowser browser)
        {
            try
            {
                var windHandler = browser.GetHost().GetWindowHandle();
                // winformのアイコンを変更する
                using (var icon = new Icon(Directory.GetCurrentDirectory() + @"\ChangePopupIconSample\myIcon.ico"))
                {
                    SendMessage(windHandler, WM_SETICON, ICON_BIG, icon.Handle);
                }
                // 画面サイズを最大化する
                ShowWindowAsync(windHandler, SIZE_MAXIMIZED);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }

        public bool DoClose(IWebBrowser chromiumWebBrowser, IBrowser browser)
        {
            return false;
        }

        public void OnBeforeClose(IWebBrowser chromiumWebBrowser, IBrowser browser)
        {
        }
    }
}