・2020/09/28
Visual Studio 2017の C# .NETで CefSharpを使って自動運転の独自ブラウザを作成する
(C#で CefSharpを使って自前のブラウザを作り、自動巡回ブラウザを作成する方法)
Tags: [Windows], [無人インストール]
● Visual Studio 2017の C# .NETで CefSharpを使って自動運転の独自ブラウザを作成する
C#で CefSharpを使って自前のブラウザを作り、自動巡回ブラウザを作成する方法。
Visual Studio 2017を使用して自前のブラウザを作ります。
某クラウドサービスを使用していますが、セキュリティの為に SSH接続を禁止していて、ブラウザの「セッションマネージャ」を使ってターミナルにアクセスする必要があります。
また、「アクセス権限」を取得するために IAMの「スイッチロール」で切り替える必要があります。
1日に100回以上、似た様な操作をマウスとキーボードで行なうので気が狂いそうです。
と言う訳で、自前のブラウザを使ってボタン操作で「定型操作」を行なう様にして、作業の効率を上げるのが目的となります。
また、某ショッピングサイトで、大人気の商品の入荷を一定間隔でリロードして監視して、入荷したら「アラームを鳴らす」と言う用途も考えられます。
※ 大昔に、DVDレンタルのサイトを対象として、一定間隔でリロードして、DVDが返却されて状態が「レンタル可能」になったらアラームすると言う似た様なアプリを作っていました。
● CefSharp C#で使える Chromiumベースのブラウザライブラリ
ここではブラウザのライブラリとして無料で使用できる CefSharpライブラリを使用します。
アマゾンの AWSを使う場合、Chromeブラウザが一番安定するので Chromiumベースの CefSharpを選択しました。
● CefSharp.WinFormsライブラリのインストール方法
cefsharp/CefSharp
CefSharp.WinForms 84.4.10
The CefSharp Chromium-based browser component (WinForms control) .
It is compatible with .NETFramework 4.5.2
パッケージマネージャのコンソールで下記を実行します
PM> Install-Package CefSharp.WinForms -Version 84.4.10
パッケージ 'CefSharp.WinForms.84.4.10' をインストールするアクションを解決しています
パッケージ 'CefSharp.WinForms.84.4.10' をインストールするアクションが解決されました
'nuget.org' からパッケージ 'cef.redist.x64 84.4.1' を取得しています。
'nuget.org' からパッケージ 'cef.redist.x86 84.4.1' を取得しています。
'nuget.org' からパッケージ 'CefSharp.Common 84.4.10' を取得しています。
'nuget.org' からパッケージ 'CefSharp.WinForms 84.4.10' を取得しています。
● CefSharp AnyCPU
ビルド時に出る下記は無視する。気になる場合は CefSharp x86 x64 AnyCPUでググる。
https://github.com/cefsharp/CefSharp/issues/1714
重大度レベル 警告
CefSharp.Common is unable to proceeed as your current Platform is 'AnyCPU'.
To target AnyCPU please read
https://github.com/cefsharp/CefSharp/issues/1714
Alternatively change your Platform to x86 or x64 and the relevant files will be copied automatically.
For details on changing your projects Platform see
https://docs.microsoft.com/en-gb/visualstudio/ide/how-to-configure-projects-to-target-platforms?view=vs-2017
● C#で CefSharpライブラリを使用してブラウザの実装のサンプル
CefSharp.MinimalExample.WinForms/BrowserForm.cs
● C#で CefSharpライブラリを使用してブラウザを作成する方法
とりあえず C#で CefSharpライブラリを使用してブラウザを作成する方法。
using System;
using System.Globalization;
using System.IO;
using System.Windows.Forms;
using CefSharp;
using CefSharp.WinForms;
namespace TestCefSharp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// Start the browser after initialize global component
InitializeChromium();
}
public ChromiumWebBrowser chromeBrowser;
public void InitializeChromium()
{
CefSettings settings = new CefSettings();
// Initialize cef with the provided settings
// CefSharp 2重に初期設定するとクラッシュする
if (Cef.IsInitialized == false)
Cef.Initialize(settings);
// Create a browser component
chromeBrowser = new ChromiumWebBrowser("https://google.com/")
{
Dock = DockStyle.Fill,
};
// Add it to the form and fill it to the form window.
this.Controls.Add(chromeBrowser);
// panel1.Controls.Add(chromeBrowser);
// chromeBrowser.Load("https://google.com/");
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
Cef.Shutdown();
}
}
}
● CefSharp ブラウザの言語を設定する
CefSettings settings = new CefSettings();
// Initialize cef with the provided settings
// CefSharp 言語設定
var ci = CultureInfo.CurrentCulture;
settings.Locale = ci.TwoLetterISOLanguageName; // "ja";
settings.AcceptLanguageList = ci.Name; // "ja-JP"
Cef.Initialize(settings);
● CefSharp デバグログを無効にする
CefSettings settings = new CefSettings();
// Initialize cef with the provided settings
// CefSharp デバグログを無効
settings.LogSeverity = LogSeverity.Disable;
Cef.Initialize(settings);
● CefSharp ダウンロードの保存先を設定する
CefSettings settings = new CefSettings();
// Initialize cef with the provided settings
// CefSharp ダウンロードの保存先
string appPath = Directory.GetParent(Assembly.GetExecutingAssembly().Location).ToString();
settings.UserDataPath = appPath;
Cef.Initialize(settings);
● CefSharp キャッシュ設定
CefExample.cs
CefSettings settings = new CefSettings();
// Initialize cef with the provided settings
// CefSharp キャッシュ設定
settings.CachePath = "cache";
// settings.CachePath = AppDomain.CurrentDomain.BaseDirectory + "cache";
Cef.Initialize(settings);
CefSharp CefSharpSettings CachePath
var settings = new CefSettings()
{
//By default CefSharp will use an in-memory cache, you need to specify a Cache Folder to persist data
CachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CefSharp\\Cache")
};
● CefSharp Cookie設定
CefSharp GetGlobalCookieManager
CefSettings settings = new CefSettings();
// Initialize cef with the provided settings
// CefSharp Cookie設定
settings.CefCommandLineArgs.Add("disable-application-cache", "1");
settings.CefCommandLineArgs.Add("disable-session-storage", "1");
if (Cef.IsInitialized == false)
Cef.Initialize(settings);
// The Global CookieManager has been initialized, you can now set cookies
var cookieManager = Cef.GetGlobalCookieManager();
cookieManager.SetStoragePath(new string[] { "cookies" }, true);
// CefSharp Cookieの削除
Cef.GetGlobalCookieManager().DeleteCookies("", "")
// The Global CookieManager has been initialized, you can now set cookies
var cookieManager = Cef.GetGlobalCookieManager();
cookieManager.SetSupportedSchemes(new string[] { "custom" }, true);
if (cookieManager.SetCookie("custom://cefsharp/home.html", new Cookie
{
Name = "CefSharpTestCookie",
Value = "ILikeCookies",
Expires = DateTime.Now.AddDays(1)
}))
● CefSharp URLの変化のイベント
Detecting an URL change with CefSharp
CefSharp AddressChangedEventArgs Properties
...
// URLの変化のイベント
chromeBrowser.AddressChanged += OnBrowserAddressChanged;
...
// Detecting an URL change with CefSharp
// https://stackoverflow.com/questions/56816678/detecting-an-url-change-with-cefsharp
private void OnBrowserAddressChanged(object sender, AddressChangedEventArgs e)
{
// this.InvokeOnUiThreadIfRequired(() => Text = e.Address);
this.Invoke(new Action(() => {
textBox1.Text = e.Address;
}));
}
● CefSharp ページの読み込みのステータス変化のイベント、ページの読み込み完了の通知
CefSharp documentcompleted
CefSharp ChromiumWebBrowser.LoadingStateChanged Event
CefSharp LoadingStateChangedEventArgs
...
// ページの読み込みのステータス変化のイベント
chromeBrowser.LoadingStateChanged += OnLoadingStateChanged;
...
// CefSharp documentcompleted
// https://stackoverflow.com/questions/41985380/cefsharp-documentcompleted
private void OnLoadingStateChanged(object sender, LoadingStateChangedEventArgs args)
{
if (!args.IsLoading)
{
// Page has finished loading, do whatever you want here
Console.Beep(800, 50);
}
}
...
private async void OnLoadingStateChanged(object sender, LoadingStateChangedEventArgs args)
{
if (!args.IsLoading)
{
// Page has finished loading, do whatever you want here
async string HTML = await chromeBrowser.GetSourceAsync();
}
}
● CefSharp その他の各種イベント
CefSharp BrowserForm.cs
browser.IsBrowserInitializedChanged += OnIsBrowserInitializedChanged;
browser.LoadingStateChanged += OnLoadingStateChanged;
browser.ConsoleMessage += OnBrowserConsoleMessage;
browser.StatusMessage += OnBrowserStatusMessage;
browser.TitleChanged += OnBrowserTitleChanged;
browser.AddressChanged += OnBrowserAddressChanged;
private void OnIsBrowserInitializedChanged(object sender, EventArgs e)
{
var b = ((ChromiumWebBrowser)sender);
this.InvokeOnUiThreadIfRequired(() => b.Focus());
}
private void OnBrowserConsoleMessage(object sender, ConsoleMessageEventArgs args)
{
DisplayOutput(string.Format("Line: {0}, Source: {1}, Message: {2}", args.Line, args.Source, args.Message));
}
private void OnBrowserStatusMessage(object sender, StatusMessageEventArgs args)
{
this.InvokeOnUiThreadIfRequired(() => statusLabel.Text = args.Value);
}
private void OnLoadingStateChanged(object sender, LoadingStateChangedEventArgs args)
{
SetCanGoBack(args.CanGoBack);
SetCanGoForward(args.CanGoForward);
this.InvokeOnUiThreadIfRequired(() => SetIsLoading(!args.CanReload));
}
private void OnBrowserTitleChanged(object sender, TitleChangedEventArgs args)
{
this.InvokeOnUiThreadIfRequired(() => Text = args.Title);
}
private void OnBrowserAddressChanged(object sender, AddressChangedEventArgs args)
{
this.InvokeOnUiThreadIfRequired(() => urlTextBox.Text = args.Address);
}
private void SetCanGoBack(bool canGoBack)
{
this.InvokeOnUiThreadIfRequired(() => backButton.Enabled = canGoBack);
}
private void SetCanGoForward(bool canGoForward)
{
this.InvokeOnUiThreadIfRequired(() => forwardButton.Enabled = canGoForward);
}
private void SetIsLoading(bool isLoading)
{
goButton.Text = isLoading ?
"Stop" :
"Go";
goButton.Image = isLoading ?
Properties.Resources.nav_plain_red :
Properties.Resources.nav_plain_green;
HandleToolStripLayout();
}
public void DisplayOutput(string output)
{
this.InvokeOnUiThreadIfRequired(() => outputLabel.Text = output);
}
private void HandleToolStripLayout(object sender, LayoutEventArgs e)
{
HandleToolStripLayout();
}
private void HandleToolStripLayout()
{
var width = toolStrip1.Width;
foreach (ToolStripItem item in toolStrip1.Items)
{
if (item != urlTextBox)
{
width -= item.Width - item.Margin.Horizontal;
}
}
urlTextBox.Width = Math.Max(0, width - urlTextBox.Margin.Horizontal - 18);
}
● CefSharp その他の各種操作
// CefSharp 戻る
browser.Back();
// CefSharp 進む
browser.Forward();
// CefSharp 開発者画面を表示
browser.ShowDevTools();
● CefSharp URLを指定して開く
chromeBrowser.Load("https://google.com/");
● CefSharp キャッシュを無効で再読み込み、リロード、リフレッシュ
WebBrowserExtensions.Reload Method (IWebBrowser, Boolean)
// bool ignoreCache
// trueでキャッシュを無効で再読み込み
chromeBrowser.Reload(true);
● CefSharp Webページのアクティブな Elementの情報を取得する
private async void button1_Click(object sender, EventArgs e)
{
var response = await chromeBrowser.EvaluateScriptAsync("(() => { var element = document.activeElement; return element.localName; })();");
if (response.Success && response.Result != null)
{
textBox1.Text = response.Result.ToString();
}
else
{
textBox1.Text = "Err";
}
}
● CefSharpでダウンロード機能を追加する
C# CefSharp Add Download function
DownloadHandler.cs
DownloadHandler.cs
using System;
namespace CefSharp.Example.Handlers
{
public class DownloadHandler : IDownloadHandler
{
public event EventHandler<DownloadItem> OnBeforeDownloadFired;
public event EventHandler<DownloadItem> OnDownloadUpdatedFired;
public void OnBeforeDownload(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, IBeforeDownloadCallback callback)
{
OnBeforeDownloadFired?.Invoke(this, downloadItem);
if (!callback.IsDisposed)
{
using (callback)
{
callback.Continue(downloadItem.SuggestedFileName, showDialog: true);
}
}
}
public void OnDownloadUpdated(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback)
{
OnDownloadUpdatedFired?.Invoke(this, downloadItem);
}
}
}
using CefSharp.Example.Handlers;
chromeBrowser.DownloadHandler = new DownloadHandler();
● CefSharpの右クリックのコンテキストメニューの拡張
C# CefSharp Right Click Context Menu
この辺の記事を参考にする。
How to prevent the native Context Menu from appearing on a CefSharp control in WinForms
How to add new items to the native Context Menu on a CefSharp control in WinForms
using System;
using CefSharp;
using System.Windows.Forms;
public class MyCustomMenuHandler : IContextMenuHandler
{
public void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model)
{
// Add a new item to the list using the AddItem method of the model
model.AddItem((CefMenuCommand)26501, "Show DevTools");
// Add a separator
model.AddSeparator();
}
public bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags)
{
// React to the first ID (show dev tools method)
if (commandId == (CefMenuCommand)26501)
{
browser.GetHost().ShowDevTools();
return true;
}
return false;
}
public void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame)
{
}
public bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback)
{
return false;
}
}
// Register your Custom Menu Handler as default
chromeBrowser.MenuHandler = new MyCustomMenuHandler();
● CefSharp Webページの Elementの内容を id指定で取得する
ヨドハ”シカメラの商品ページの「価格」情報を取得する例
private async void button2_Click(object sender, EventArgs e)
{
string script = string.Format("document.getElementById('js_scl_unitPrice').innerHTML;");
JavascriptResponse response = await chromeBrowser.EvaluateScriptAsync(script);
if (response.Success && response.Result != null)
{
textBox1.Text = response.Result.ToString();
}
else
{
textBox1.Text = "Err";
}
chromeBrowser.Focus();
}
● CefSharp Webページの Elementの内容を id指定で画面内に移動する、フォーカスする、クリックする
ヨドハ”シカメラの商品ページの「ショッピングカートに入れる」ボタンをクリックする例
private async void button3_Click(object sender, EventArgs e)
{
// JavascriptResponse
var response = await chromeBrowser.EvaluateScriptAsync("(() => { " +
"var target = document.getElementById('js_m_submitRelated'); " +
// 見える様に画面内に移動する
"target.scrollIntoView(); " +
// フォーカスする
"target.focus(); " +
// クリックする
"target.click(); " +
"})();");
if (response.Success)
{
// 成功
}
else
{
// 失敗
}
}
● CefSharp キー入力(文字列を入力する)
Thread.Sleep(10);
Thread.Sleep(5);
は私が心配性なので入れている。
...
sendKeyString("hogehoge");
...
private void sendKeyString(string str)
{
foreach (char c in str)
{
sendKeyEventChar((int)c);
}
Thread.Sleep(10);
}
private void sendKeyEventChar(int keyCode)
{
KeyEvent k = new KeyEvent();
k.WindowsKeyCode = keyCode;
k.FocusOnEditableField = true;
k.IsSystemKey = false;
k.Type = KeyEventType.Char;
chromeBrowser.GetBrowser().GetHost().SendKeyEvent(k);
Thread.Sleep(5);
}
● CefSharp 特殊キー入力
Thread.Sleep(50);
は私が心配性なので入れている。
private void sendKeyEventTab()
{
sendKeyEventCode(0x09); // VK_TAB
}
private void sendKeyEventSpace()
{
sendKeyEventCode(0x20); // VK_SPACE
}
private void sendKeyEventRight()
{
sendKeyEventCode(0x27); // VK_RIGHT
}
private void sendKeyEventEnter()
{
sendKeyEventCode(0x0D); // VK_RETURN
}
private void sendKeyEventCode(int keyCode)
{
KeyEvent k = new KeyEvent();
k.WindowsKeyCode = keyCode;
k.FocusOnEditableField = true;
k.IsSystemKey = false;
k.Type = KeyEventType.KeyDown;
chromeBrowser.GetBrowser().GetHost().SendKeyEvent(k);
Thread.Sleep(50);
k = new KeyEvent();
k.WindowsKeyCode = keyCode;
k.FocusOnEditableField = true;
k.IsSystemKey = false;
k.Type = KeyEventType.KeyUp;
chromeBrowser.GetBrowser().GetHost().SendKeyEvent(k);
Thread.Sleep(50);
}
● CefSharp 座標を指定してクリック
MouseButtonType.Left クリック、左クリック
MouseButtonType.Middle 真ん中クリック
MouseButtonType.Right 右クリック
await Task.Delay(50);
は私が心配性なので入れている。
private async void clickCef(int x = 0, int y = 0)
{
chromeBrowser.GetBrowser().GetHost().SendMouseClickEvent(x, y, MouseButtonType.Left, false, 1, CefEventFlags.None);
await Task.Delay(50);
chromeBrowser.GetBrowser().GetHost().SendMouseClickEvent(x, y, MouseButtonType.Left, true, 1, CefEventFlags.None);
await Task.Delay(50);
}
● CefSharp フォーカスを設定する
...
chromeBrowser.Focus();
...
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetFocus(IntPtr hWnd);
...
SetFocus(chromeBrowser.Handle);
...
● CefSharp Enable WebRTC
// Enable WebRTC
settings.CefCommandLineArgs.Add("enable-media-stream", "1");
● CefSharp フォントがボケる時の対策
// Disables the DirectWrite font rendering system on windows.
// Possibly useful when experiencing blury fonts.
settings.CefCommandLineArgs.Add("disable-direct-write", "1");
● CefSharp その他の初期設定
var settings = new CefSettings();
settings.RemoteDebuggingPort = 8088;
// The location where cache data will be stored on disk. If empty an in-memory cache will be used for some features and a temporary disk cache for others.
// HTML5 databases such as localStorage will only persist across sessions if a cache path is specified.
settings.CachePath = "cache";
// Example User Agent
settings.UserAgent = "CefSharp Browser" + Cef.CefSharpVersion;
// renderer
settings.CefCommandLineArgs.Add("renderer-process-limit", "1");
settings.CefCommandLineArgs.Add("renderer-startup-dialog", "renderer-startup-dialog");
// disable GPU
settings.CefCommandLineArgs.Add("disable-gpu", "1");
settings.CefCommandLineArgs.Add("disable-gpu-vsync", "1");
// Enable WebRTC
settings.CefCommandLineArgs.Add("enable-media-stream", "1");
// Don't use a proxy server, always make direct connections. Overrides any other proxy server flags that are passed.
settings.CefCommandLineArgs.Add("no-proxy-server", "1");
// Dumps extra logging about plugin loading to the log file.
settings.CefCommandLineArgs.Add("debug-plugin-loading", "1");
// Disable discovering third-party plugins. Effectively loading only ones shipped with the browser plus third-party ones as specified by --extra-plugin-dir and --load-plugin switches
settings.CefCommandLineArgs.Add("disable-plugins-discovery", "1");
// Disables the DirectWrite font rendering system on windows.
// Possibly useful when experiencing blury fonts.
settings.CefCommandLineArgs.Add("disable-direct-write", "1");
settings.LogSeverity = LogSeverity.Verbose;
Tags: [Windows], [無人インストール]
●関連するコンテンツ(この記事を読んだ人は、次の記事も読んでいます)
OpenSSLコマンドを使って RSA暗号処理する方法
OpenSSLコマンドで公開鍵暗号方式の RSA暗号処理する方法を解説
Java言語で RSA暗号処理する方法、OpenSSLとの連携方法、Androidにも対応
Java言語で公開鍵暗号方式の RSA暗号処理と OpenSSLと連携する方法を解説
Visual Studio 2013の .NET C#で RSA暗号処理する方法、OpenSSLとの連携方法
C# .NETで公開鍵暗号方式の RSA暗号処理と OpenSSLと連携する方法を解説
PHP言語で RSA暗号処理する方法、OpenSSLとの連携方法
PHP言語で 公開鍵暗号方式の RSA暗号処理と OpenSSLと連携する方法を解説
GO言語で RSA暗号処理する方法、OpenSSLとの連携方法
GO言語で 公開鍵暗号方式の RSA暗号処理と OpenSSLと連携する方法を解説
Visual Studio 2013の C# .NETで Hash計算処理をする方法のサンプルプログラム
HashAlgorithm.TransformBlockを使用すると巨大ファイル等でハッシュ計算の進行状況の進捗を取得できます
Visual Studio 2013の .NET C#で UTF-8対応 QRコード生成・読取アプリを作成する方法、ZXing.Net QR Codeライブラリを使用
.NETで UTF-8対応 QRコード作成・解読アプリを作成、ILMergeで dllを exeに合体する方法
C# .NETで ZIPファイル解凍ツール UnZipをソースリスト 1行で自作する方法、Windows .NET専用
Visual Studio 2013の C# .NET 4.5で ZipFile.ExtractToDirectoryを使い、UnZip解凍ツールを作成
Visual Studio 2013に Windows 10 SDK + UwpDesktopで UWPの機能を素の Windowsアプリから使用
VS2013に Win 10 SDKをインストールして Uwp Desktopで UWPの機能を従来の Windowsアプリで動かす
Visual Studio 2013の C# .NETで 日本語対応の OCR文字認識アプリを自作する方法
オフライン環境で動作可能な 世界各国語対応の OCR文字認識アプリを C# .NETで作成、MS製 OCRライブラリを使用
Visual Studio 2013の C#で日本語対応の手書き文字認識アプリを自作する方法
オフライン環境で動作する世界各国語対応の手書き文字認識アプリを作成、MS製 手書き認識ライブラリを使用
Open XML SDKを使用して Officeのファイルを C#で自在に操る方法
Microsoft Officeのファイルをプログラムで生成したり直接中身の読み取りができます
Visual Studioの各バージョンと開発できる .NET Frameworkの各バージョンのまとめ
.Microsoft.NET Framework Developer Packの各バージョンのダウンロードまとめ。言語パック等
Windows 10対応 Microsoft Speech使用の音声認識アプリ
SpeechRecognizeApp 音声認識エンジンを使用してマイク入力の音声を認識します
Windows 10の音声合成エンジンを使用して入力した文字列を喋る & Waveファイル書き出し
SpeechApp Windows 10用 Speech 音声合成 Text-to-Speech TTSのアプリ
Visual Studioの C#や MFC C++用のサンプルアプリのリンク集
Visual Studioの C#や MFC C++でアプリを作る時の参考資料として
Windowsの Input Method Manager IMEや TSF Text Services Frameworkの公式情報源のまとめ
Windowsで IME Input Method Manager関連のアプリを作成する時の情報 ImeTrayもこの辺を必死に読んだ
Visual Studioの C#で開発した .Netアプリの難読化をする方法
C#で開発した .Netアプリの難読化は必須事項です、素の状態では簡単に内部を解析されます
Visual Studioの C#で開発した .Netアプリを逆コンパイルして、中身の実装を覗き見る方法
C#で開発した .Netアプリは比較的簡単に元のソースコードに戻せます
Visual Studio 2019 Professional v16.4を無人インストールする方法、完全自動でインストール
VS2019 v16.4を完全オフラインインストール&コンポーネント選択の事前設定で自動インストールする
Visual Studio 2013 Professionalを無人インストールする方法、完全自動でインストール
VS2013を Update 5適用済みとコンポーネント選択の事前設定でインストール時の手間を省く
[HOME]
|
[BACK]
リンクフリー(連絡不要、ただしトップページ以外は Web構成の変更で移動する場合があります)
Copyright (c)
2020 FREE WING,Y.Sakamoto
Powered by 猫屋敷工房 & HTML Generator
http://www.neko.ne.jp/~freewing/software/visual_c_sharp_cefsharp_browser/