Chromiumをアプリケーションに組み込むためのフレームワークで、C#実装がCefSharpとなります。
CefはChromium Embedded Frameworkの略で、Chromiumをアプリケーションに組み込むためのフレームワークです。
https://bitbucket.org/chromiumembedded/cef
Cefには各言語向けのラッパーがあり、その中のC#実装がCefSharpです。
https://github.com/cefsharp/CefSharp
CefSharpはNuGetでインストールできるようになっている。
WPF対応版とWinForms対応のコンポーネントに分かれている。
.NET Framework 4.5.2以上が必要となる。
Any CPUには対応していないが、プラットフォームをx86かx64を自動で判別する方法がある。
Any CPUで32bit優先にした場合(32bit優先とはARMのWindows環境でも動作可能となる)
How to use CefSharp (chromium embedded framework c#) in a Winforms application
ひらがなと漢字が混在していた場合、ひらがなのみ太いなどのフォント表示(中国語っぽい)がされてしまう。
原因はロケールが違うため、言語を日本語に変更する。
CefSharp.Wpfのlocaleを変更する - stackoverflow
CefSettings settings = new CefSettings(); settings.Locale = "ja" settings.AcceptLanguageList = "ja-JP" Cef.Initialize(settings);
または、OSのカルチャーを取得してセットする。
CefSettings settings = new CefSettings(); settings.Locale = System.Globalization.CultureInfo.CurrentCulture.Parent.ToString(); settings.AcceptLanguageList = System.Globalization.CultureInfo.CurrentCulture.Name; Cef.Initialize(settings);
LogSeverity プロパティを無効にする。
CefSettings settings = new CefSettings(); settings.LogSeverity = LogSeverity.Disable; Cef.Initialize(settings);
CefSharpを使用したアプリケーションをデスクトップのショートカットから実行した場合
ショートカットの作業フォルダが空だった場合、GPUCacheがblob_storageフォルダがデスクトップに作成されてしまう。
対応として作業フォルダを指定することで、作業フォルダ側に作成される。
ショートカットの作業フォルダ対応ではなくプログラムで対応する場合
カレントフォルダを設定しただけでは、GPUCacheフォルダはカレントフォルダに作成されるが、blob_storageフォルダはデスクトップに作成されてしまう。
対応として、CefSettings.UserDataPath にカレントフォルダを指定する必要がある。
// カレントディレクトリをアプリケーション起動パスに設定する string appPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); Directory.SetCurrentDirectory(appPath); CefSettings settings = new CefSettings(); settings.UserDataPath = appPath; Cef.Initialize(settings);
Cef.Initializeの設定は1回のみで、new ChromiumWebBrowser する前に設定する。
Cef.Initialize したかどうかは、Cef.IsInitialized で判断(false:未設定、true:設定済)する。
C# (CSharp) CefSettings Code Examples
フォームにToolboxを配置したあったので、パネルを用意して配下にブラウザをセットした。
browser = new ChromiumWebBrowser("https://www.google.co.jp/"); this.pnlWebBrowser.Controls.Add(browser); browser.Dock = DockStyle.Fill;
Addressプロパティが見当たらないため、アドレス変更イベントで変数にセットする。
this.browser= new ChromiumWebBrowser(); this.browser.AddressChanged += browser_AddressChanged; private void browser_AddressChanged(object sender, AddressChangedEventArgs e) { this.CurrentAddress = e.Address; }
Addressプロパティで取得できる。
var browser = new CefSharp.Wpf.ChromiumWebBrowser(); this.CurrentAddress = browser.Address
Addressプロパティが見当たらないため、Loadメソッドで変更する。
How to change the URL using CefSharp WinForms - stackoverflow
this.Browser = new ChromiumWebBrowser(); this.Browser.Load("https://www.google.co.jp/")
Addressプロパティ または、Loadメソッドで変更する。
WPFでCefSharp(Chromiumの.NET向け実装)を使う - 1
var browser = new ChromiumWebBrowser(); browser.Address = "https://www.google.co.jp/";
AddressプロパティとLoadメソッドでは、基本的な挙動に変わりはありませんが、ブラウザが初期化されていないときに実行すると挙動が変わる。
ブラウザの初期化後にそのURLに遷移する
初期化されていないので何も起こらない
IEのWebブラウザコンポーネントにあった DocumentCompleted イベントの代わり。
CefSharp documentcompleted - stackoverflow
var browser = new ChromiumWebBrowser(); browser.LoadingStateChanged += OnLoadingStateChanged; private void OnLoadingStateChanged(object sender, LoadingStateChangedEventArgs e) { if (!e.IsLoading) { // 読込完了処理を記述 } }
Javascriptで操作させてボタンをClickさせる。
ExecuteScriptAsyncメソッドで、Javascriptを実行する。
var browser = new ChromiumWebBrowser(); // Enterボタンクリック用スクリプト string clickScript = "var inputs = document.getElementsByTagName('input');" + "for(var i = 0; i < inputs.length; i++){ " + " if(inputs[i].getAttribute('value') == 'Enter') inputs[i].click(); " + "}"; string jsScript = string.Format("document.getElementById('c03').value = '{0}';", txtInput.Text); browser.ExecuteScriptAsync(jsScript + clickScript);
Javascriptで操作させて取得する。
ExecuteScriptAsyncメソッドで、Javascriptを実行する。
CefSharp - HTML要素の値を取得する
var browser = new ChromiumWebBrowser(); browser.EvaluateScriptAsync(jsScript).ContinueWith(x => { var response = x.Result; if (response.Success && response.Result != null) { userCodeData = response.Result.ToString(); } });
IEのWebブラウザコンポーネントにあった previewkeydown イベントの代わり
KeyboardHandleクラスを定義する。
public class KeyboardHandler : IKeyboardHandler { private frmMain _frm; public KeyboardHandler(frmMain frm) { _frm = frm; } public bool OnKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey) { return false; } public bool OnPreKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut) { _frm.OnPreviewKeyDown(windowsKeyCode, modifiers); return false; } }
今回は、Enterキー押下時のみ処理を行う。
var browser = new ChromiumWebBrowser(); // キーイベント処理登録 browser.KeyboardHandler = new KeyboardHandler(this); public void OnPreviewKeyDown(int windowsKeyCode, CefEventFlags modifiers) { if (windowsKeyCode != (int)Keys.Return) return; // Enterキー押下時の処理を記述する。 }
何故か、browser.Focus() ではフォーカスがセットされなかったため、Win32APIのSetFocusを使用した。
読み込み完了時のイベントで処理している。
// フォーカスセット用 [DllImport("user32.dll", SetLastError = true)] static extern IntPtr SetFocus(IntPtr hWnd); var browser = new ChromiumWebBrowser(); browser.LoadingStateChanged += OnLoadingStateChanged; private void OnLoadingStateChanged(object sender, LoadingStateChangedEventArgs e) { if (String.IsNullOrEmpty(this.CurrentAddress)) return; if (e.IsLoading) return; // 読込完了時にWebブラウザにフォーカスをセット this.Invoke((MethodInvoker)delegate { SetFocus(browser.Handle); }); }
最初は、ブラウザにマウスクリックするとフォーカスがセットされたのでマウスクリックするプログラムを組んだが、SetFocusで出来たのでやめた。
[DllImport("USER32.dll", CallingConvention = CallingConvention.StdCall)] static extern void SetCursorPos(int X, int Y); [DllImport("USER32.dll", CallingConvention = CallingConvention.StdCall)] static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo); private void SetFocusWebBrowser() { // マウス位置を移動してクリックして元に戻す this.Invoke((MethodInvoker)delegate { int curX = Cursor.Position.X; int curY = Cursor.Position.Y; var point = this.pnlWebBrowser.PointToScreen(this.pnlWebBrowser.Location); SetCursorPos(point.X, point.Y); mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); SetCursorPos(curX, curY); }); }
参照:ブルネイ工廠電気実験部
一部のHigh-DPI 環境のPCでクリックする位置が10ドット上くらいでないと反応しない現象があった。
EXEファイルから直接起動すると現象が発生しないが、デスクトップのショートカットやスタートアップから起動するとこの現象が発生する。
ショートカットのプロパティの互換性タブにある「高DPIスケール設定の上書き」の「高いDPIスケールの動作を上書きします。」にチェックを付ける。
Windows 7では互換性タブにある「設定」の「高DPI設定では画面のスケーリングを無効にする」にチェックを付ける。
高DPI対応するために、app.manifest ファイルを追加して、dpiAwareをtrueに設定する。
manifest ファイルの配布は不要。
アプリの高DPI(High DPI)対応について 第3回 ~ マニフェストでアプリのDPI対応レベルを変更する ~
「dpiAware」の設定を「true」または「true/PM」または「per monitor」に設定する。
違いは下記参照
[C#][VB.NET]Windows Formアプリケーションで表示がぼやけるのを防ぐ
<?xml version="1.0" encoding="utf-8"?> <assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"> <application xmlns="urn:schemas-microsoft-com:asm.v3"> <windowsSettings> <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware> </windowsSettings> </application> </assembly>
Cef.EnableHighDPISupport()メソッドを追加する。
Cef.EnableHighDPISupport(); Cef.Initialize(setting);