C++BuilderでChromiumブラウザを作る

<img width="531" alt="スクリーンショット 2019-01-05 22.55.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/76058/53384090-75e7-d98c-c346-dfc592666945.png">

C++BuilderでChromiumを使うための方法。
Chromium Embedded Framework と、DEF4DelphiというライブラリをC++Builderで使う方法を記載。
iOSやMacなんかはTWebBrowserを使っても十分だが、WindowsだけIEがベースになっているのでCSSが崩れたりJavascriptがうまく動作しなかったりするためこの方法を探した。
なお、DelphiがなくてもC++Builderだけで可能だが、VCLの32bitのみでしか成功していない。
だれか64bitのFireMonkeyで成功した人は居ないかな？

## 環境

Windows10
C++Builder 10.3 Rio

## ダウンロード

下記URLのGitHubからクローンしてきたりダウンロードする。

[GitHub - salvadordf/CEF4Delphi: CEF4Delphi is an open source project to embed Chromium-based browsers in applications made with Delphi or Lazarus/FPC.](https://github.com/salvadordf/CEF4Delphi)

### 移動

適当な場所に移動。
今回はパブリックのドキュメント内に保存。
C:\Users\Public\Documents\CEF4Delphi-master

### CEF

GitHubのreadme内に記載されている「32bit」のファイルをダウンロードして解凍し、

![4f2434bc.png](https://qiita-image-store.s3.amazonaws.com/0/76058/90c8dfa2-ed12-5cef-dcd1-58d02062e692.png)

ReleaseとResourcesというフォルダの中身を全て

C:\Users\Public\Documents\Embarcadero\Studio\20.0\BPL\

に「cef」というフォルダを作成して
その中にコピーもしくは移動させる。
（これはデバッグ時と、コンパイル時後に使うため。）

![スクリーンショット 2019-01-05 18.20.47.png](https://qiita-image-store.s3.amazonaws.com/0/76058/467145f7-afa2-54ba-0afd-4402d1842357.png)

## C++Builderで作業

C++Builderを起動。

### ツールオプション

**ツール->オプション**
**言語->Delphiオプション->ライブラリ**
内の、
**ライブラリパス**の横の「…」をクリックしてディレクトリ一覧を表示させたら、そこに先程移動させたフォルダ内の**CEF4Delphi-master/source**フォルダを追加します。

![3cb40f4f.png](https://qiita-image-store.s3.amazonaws.com/0/76058/f16d8ad9-af49-8c5d-914e-33c8e2a7ad2a.png)

### コンポーネントのインストール

コンポーネントのインストールを選択

![3c9284ea.png](https://qiita-image-store.s3.amazonaws.com/0/76058/124386e9-f560-c4cd-1e6b-8ac2785f2e0b.png)

ユニットファイル名項目の右にある「...」をクリックして**CEF4Delphi-master/packages**フォルダ内の**CEF4Delphi_Register.pas**を選択。（CEF4Delphi_FMX_Register.pasを選択するとFiremonkeyで使用可能になるそうですが、エラー回避が出来なかった）
新規パッケージにインストールにチェックを入れて次へ

![fb95d126.png](https://qiita-image-store.s3.amazonaws.com/0/76058/e3823c96-4ffd-31a3-428f-8aba80949c3a.png)

パッケージ名の右の「...」をクリックしてCEF4Delphi-master/packages/CEF4Delphi.dpkを選択、

「C++Builderパッケージ」にチェックを入れて完了。
完了すると、エラーが表示されるが、気にせず次へ

### 保存する

**ファイル**->**全てを保存**で適当に保存。

### インストール

プロジェクトウィンドウのプロジェクト名の部分を右クリックして**インストール**を選択。
インストールを完了させる。

![12bed3c8.png](https://qiita-image-store.s3.amazonaws.com/0/76058/d0f04fc8-4a81-ae28-b972-ec92d44903ea.png)

## フォームを作る

C++Builderを開き直して、Windows VCLアプリケーションを作成する。

### TChromiumを貼り付け

TChromiumとTCEFWindowParentを貼り付ける。
保存しようとすると、ヘッダが見つからない旨が表示されるので、sourceフォルダ内の同名のファイルを指定する。
TCEFWindowParentは表示場所なので、目一杯に広げておく。

さらに、TEditとTButtonを配置しておく。

![f38e0ed1.png](https://qiita-image-store.s3.amazonaws.com/0/76058/41db84f5-ae73-e4ca-efdc-8f12fe024f3a.png)

### コード

#### Project1.cpp

**Project1.cpp**のコードを下記URLのように記述していく。ただし、TCefApplicationのコンストラクタの仕様が変わっているらしいので、trueと記述しているところを消す。

[TChromium vs C++ Builder - BriskBard and CEF4Delphi](https://www.briskbard.com/forum/viewtopic.php?f=8&t=178)

```c++:Project1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop
#include <tchar.h>
//---------------------------------------------------------------------------
USEFORM("Unit1.cpp", Form1);
#include "uCEFApplication.hpp"
#define SetPEFlags IMAGE_FILE_LARGE_ADDRESS_AWARE //In mine I didn't used it and works fine, i recompiled with it and it works fine for me as well

//---------------------------------------------------------------------------
int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
{
	try
	{
		GlobalCEFApp = new TCefApplication();//<-- here you had false;
		GlobalCEFApp->CheckCEFFiles =true; //<- like this you are sure that all files are good
		GlobalCEFApp->FrameworkDirPath = "cef";
		GlobalCEFApp->ResourcesDirPath = "cef";
		GlobalCEFApp->LocalesDirPath = "cef\\locales";
		GlobalCEFApp->Cache = "cef\\cache";
		GlobalCEFApp->Cookies = "cef\\cookies";
		GlobalCEFApp->UserDataPath = "cef\\User Data";
		// Added some Misc info to disable possible "can broke things" extensions
		GlobalCEFApp->FlashEnabled=false;
		GlobalCEFApp->FastUnload=true;
		GlobalCEFApp->NoSandbox=false;
		GlobalCEFApp->SingleProcess=true; //<-C++ builder seems a little bit akward using multiprocess.

		if(GlobalCEFApp->StartMainProcess())
		  {
			Application->Initialize();
			Application->MainFormOnTaskBar = true;
			Application->CreateForm(__classid(TForm1), &Form1);
			Application->Run();
		  }
		// GlobalCEFApp->~TCefApplication(); // Here "GlobalCEFApp->Free();" crash the app at shutdown
	}
	catch (Exception &exception)
	{
		Application->ShowException(&exception);
	}
	catch (...)
	{
		try
		{
			throw Exception("");
		}
		catch (Exception &exception)
		{
			Application->ShowException(&exception);
		}
	}
	return 0;
}
//---------------------------------------------------------------------------

```

一度実行させると、エラーが表示されるので、該当する箇所（多分下記のような記述で41行目と42行目）をコメントアウトさせる。

```
extern "C" System::LongBool __fastcall ProcessUnderWow64(NativeUInt hProcess, System::LongBool &Wow64Process);
extern "C" System::LongBool __stdcall TzSpecificLocalTimeToSystemTime(Winapi::Windows::PTimeZoneInformation lpTimeZoneInformation, Winapi::Windows::PSystemTime lpLocalTime, Winapi::Windows::PSystemTime lpUniversalTime);

```

#### TFromのイベント

TFormの各イベントにコードを記述

##### TFromのコンストラクタ

コンストラクタ内でLoadURL()を実行しようとしても上手くいかない。

```c++
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) {
	Chromium1->CreateBrowser(CEFWindowParent1);
}
```

##### TFromを閉じるときのイベント（念の為）

```c++
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action) {
	// クローズ
	Chromium1->CloseBrowser(true);
}
```

##### ボタンのイベント

ボタンを押したときにEditのURLを開くようにする。

```c++
void __fastcall TForm1::Button1Click(TObject *Sender) {
	Chromium1->LoadURL(Edit1->Text);
}
```

### ビルド後イベント

DLL等をコンパイルした先にコピーするようにしておく。

```
xcopy /y /d /S /E "C:\Users\Public\Documents\Embarcadero\Studio\20.0\BPL\*" "$(OUTPUTDIR)"
```

以上。