1. 記事一覧 >
  2. ブログ記事
category logo

C++ Visual Studio 2019でActiveXを作成

(更新) (公開)

はじめに

以前書いたブログ記事「C++,C# WebBrowser コントロールで IE11 の ActiveX を延命」にて、「Hello world.」 とだけ表示する ActiveX を紹介しました。
今回、その ActiveX について、Visual Studio 2019 で実装、ビルドするところまで紹介したいと思います。


ActiveXは、IE11の拡張機能です。「C++,C# WebBrowserコントロールでIE11のActiveXを延命」または、Edge の IE11 モードで使い続けることはできると思います。正直、今更、ActiveX?という気がしないでもないですが、何かのお役に立てればと思います。


概要

ただ単に 「Hello world.」 と表示する ActiveX です。 (赤枠内が ActiveX です。)

ActiveX表示


この ActiveX がインストールされた状態です。
ActiveXがインストールされた状態


以下の HTML で表示します。

<HTML>
<HEAD>
</HEAD>
<BODY>
<OBJECT CLASSID="CLSID:11b7ddbf-412b-45f5-accc-ab6d01ceb53e" WIDTH="200" HEIGHT="100">
<PARAM NAME="Caption" VALUE="Hello world.">
<EMBED TYPE="application/x-test-activex" WIDTH="200" HEIGHT="100" Caption="Hello world.">
</OBJECT>
</BODY>
</HTML>

IE11 モードではない Edge の場合は、以下のように起動しません。 IE11 モードではない Edge の場合


ソースコード(C++)

ウィザードで生成されたソースコードを少し変更するのみです。ここでは、差分のみ示します。


SafeComp.cpp
SafeComp.h
の2つを追加し、


TestActiveX.cpp
の1つを変更します。


ここで、TestActiveX.cpp について、

const GUID CDECL BASED_CODE _ctlid =
{ 0x11b7ddbf,0x412b,0x45f5,{0xac,0xcc,0xab,0x6d,0x01,0xce,0xb5,0x3e } };

0x11b7ddbf...0x3e 部分は、


TestActiveXCtrl.cpp

IMPLEMENT_OLECREATE_EX(CTestActiveXCtrl, "MFCACTIVEXCONTRO.TestActiveXCtrl.1",
	0x11b7ddbf,0x412b,0x45f5,0xac,0xcc,0xab,0x6d,0x01,0xce,0xb5,0x3e)

に合わせる必要があります。


SafeComp.cpp CHANGED
@@ -0,0 +1,64 @@
1
+ #include "pch.h"
2
+ #include "SafeComp.h"
3
+ // Helper function to create a component category and associated
4
+ // description
5
+ HRESULT CreateComponentCategory(CATID catid, WCHAR* catDescription)
6
+ {
7
+ ICatRegister* pcr = NULL ;
8
+ HRESULT hr = S_OK ;
9
+
10
+ hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,
11
+ NULL,
12
+ CLSCTX_INPROC_SERVER,
13
+ IID_ICatRegister,
14
+ (void**)&pcr);
15
+ if (FAILED(hr)) {
16
+ return hr;
17
+ }
18
+
19
+ // Make sure the HKCR\Component Categories\{..catid...}
20
+ // key is registered
21
+ CATEGORYINFO catinfo;
22
+ catinfo.catid = catid;
23
+ catinfo.lcid = 0x0409 ; // english
24
+
25
+ // Make sure the provided description is not too long.
26
+ // Only copy the first 127 characters if it is
27
+ int len = wcslen(catDescription);
28
+ if (len>127)
29
+ len = 127;
30
+ wcsncpy_s(catinfo.szDescription, sizeof(catinfo.szDescription), catDescription, len);
31
+ // Make sure the description is null terminated
32
+ catinfo.szDescription[len] = '\0';
33
+
34
+ hr = pcr->RegisterCategories(1, &catinfo);
35
+ pcr->Release();
36
+
37
+ return hr;
38
+ }
39
+ // Helper function to register a CLSID as belonging to a component
40
+ // category
41
+ HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid)
42
+ {
43
+ // Register your component categories information.
44
+ ICatRegister* pcr = NULL ;
45
+ HRESULT hr = S_OK ;
46
+ hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,
47
+ NULL,
48
+ CLSCTX_INPROC_SERVER,
49
+ IID_ICatRegister,
50
+ (void**)&pcr);
51
+ if (SUCCEEDED(hr)) {
52
+ // Register this category as being "implemented" by
53
+ // the class.
54
+ CATID rgcatid[1] ;
55
+ rgcatid[0] = catid;
56
+ hr = pcr->RegisterClassImplCategories(clsid, 1, rgcatid);
57
+ }
58
+
59
+ if (pcr != NULL) {
60
+ pcr->Release();
61
+ }
62
+
63
+ return hr;
64
+ }
SafeComp.h CHANGED
@@ -0,0 +1,12 @@
1
+ #ifndef INC_SAFEMOD_H
2
+ #define INC_SAFEMOD_H
3
+ #include <COMCAT.H>
4
+ #include <SHLGUID.H>
5
+
6
+ // Helper function to create a component category and associated
7
+ // description
8
+ HRESULT CreateComponentCategory(CATID catid, WCHAR* catDescription);
9
+ // Helper function to register a CLSID as belonging to a component
10
+ // category
11
+ HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid);
12
+ #endif
TestActiveX.cpp CHANGED
@@ -3,6 +3,7 @@
3
3
  #include "pch.h"
4
4
  #include "framework.h"
5
5
  #include "TestActiveX.h"
6
+ #include "SafeComp.h"
6
7
 
7
8
  #ifdef _DEBUG
8
9
  #define new DEBUG_NEW
@@ -15,7 +16,13 @@
15
16
  const WORD _wVerMajor = 1;
16
17
  const WORD _wVerMinor = 0;
17
18
 
19
+ const CATID CATID_SafeForScripting =
20
+ { 0x7dd95801,0x9882,0x11cf,{0x9f,0xa9,0x00,0xaa,0x00,0x6c,0x42,0xc4 } };
21
+ const CATID CATID_SafeForInitializing =
22
+ { 0x7dd95802,0x9882,0x11cf,{0x9f,0xa9,0x00,0xaa,0x00,0x6c,0x42,0xc4 } };
18
23
 
24
+ const GUID CDECL BASED_CODE _ctlid =
25
+ { 0x11b7ddbf,0x412b,0x45f5,{0xac,0xcc,0xab,0x6d,0x01,0xce,0xb5,0x3e } };
19
26
 
20
27
  // CTestActiveXApp::InitInstance - DLL 初期化
21
28
 
@@ -56,6 +63,24 @@
56
63
  if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
57
64
  return ResultFromScode(SELFREG_E_CLASS);
58
65
 
66
+ if (FAILED(CreateComponentCategory(
67
+ CATID_SafeForScripting,
68
+ L"Controls that are safely scriptable")))
69
+ return ResultFromScode(SELFREG_E_CLASS);
70
+
71
+ if (FAILED(CreateComponentCategory(
72
+ CATID_SafeForInitializing,
73
+ L"Controls safely initializable from persistent data")))
74
+ return ResultFromScode(SELFREG_E_CLASS);
75
+
76
+ if (FAILED(RegisterCLSIDInCategory(
77
+ _ctlid, CATID_SafeForScripting)))
78
+ return ResultFromScode(SELFREG_E_CLASS);
79
+
80
+ if (FAILED(RegisterCLSIDInCategory(
81
+ _ctlid, CATID_SafeForInitializing)))
82
+ return ResultFromScode(SELFREG_E_CLASS);
83
+
59
84
  return NOERROR;
60
85
  }
61
86
 

セーフとしてマーク

マイクロソフトの
スクリプトと初期化 ActiveX MFC コントロールセーフとしてマークする

こちらのサイトに、
既定では、MFC ActiveXコントロールは、スクリプトおよび初期化セーフのセーフマークされません。
という記述があります。


これは、どういうことかと言うと、"セーフとしてマーク" しないと、ActiveX が起動しません。


これを回避するためには、
インターネットオプション - 信頼済みサイト(信頼済みサイト追加済み の場合) - このゾーンのセキュリティのレベル : 低


とするか、


インターネットオプション - セキュリティ - レベルのカスタマイズ で
スクリプトを実行しても安全だとマークされていない ActiveX コントロールの初期化とスクリプトの実行 : ダイアログを表示する(有効にする)

ActiveX コントロールの初期化とスクリプトの実行

と設定しないといけません。


"セーフとしてマーク" しておけば、設定は必要無いため、今回、"セーフとしてマーク" したプログラム作成になります。
内容は、上記マイクロソフトのサイトに書いてある通り実装された SafeComp.cppSafeComp.h 追加 + TestActiveX.cpp に上記マイクロソフトのサイトに書いてある通りのプログラム追加です。
実は、Hello world 表示だけの場合、ソースコードの変更箇所は有りません。diff は、全てそのためです。


C++ 版ビルド手順

exe ビルド

Visual Studio 2019 は、インストールしたての状態が前提です。

プロジェクト作成準備

Visual Studio Installer を起動します。
「変更」をクリックします。
Visual Studio Installerを起動 「変更」をクリック


「C++ によるデスクトップ開発」→ 右側の詳細部分の「最新の v142 ビルドツール C++ MFC (x86...」にチェックを入れ、「変更」をクリックします。 「最新のv142ビルドツール C++ MFC (x86...」にチェック


プロジェクト作成

Visual Studio Installer を閉じて、Visual Studio 2019 を起動します。
「新しいプロジェクトの作成」をクリックします。
「新しいプロジェクトの作成」をクリック


「MFC ActiveX コントロール」を選択して、「次へ」をクリックします。 「MFC ActiveX コントロール」を選択して、「次へ」をクリック


プロジェクト名:TestActiveX
ソリューション名:TestActiveX
とし、(入力内容は任意です。)「作成」をクリックします。 「作成」をクリックし


「次へ」をクリックします。 MFC ActiveX コントロール「次へ」をクリック


次に基づいてコントールを作成:「STATIC」を選択し、「完了」をクリックします。 「ユーザーインターフェース機能」


ソースコード編集

この時点で、リポジトリパスにある程度のプログラムが作成されていますので、
(リポジトリパス例:C:\Users\admin\source\repos\TestActiveX\TestActiveX
github リポジトリ(itc-lab/TestActiveX)


SafeComp.cpp
SafeComp.h
の2つを追加し、


TestActiveX.cpp
の1つを上書きします。
3ファイル反映


ここで、TestActiveX.cpp について、

const GUID CDECL BASED_CODE _ctlid =
{ 0x11b7ddbf,0x412b,0x45f5,{0xac,0xcc,0xab,0x6d,0x01,0xce,0xb5,0x3e } };

0x11b7ddbf...0x3e 部分は、

TestActiveXCtrl.cpp

IMPLEMENT_OLECREATE_EX(CTestActiveXCtrl, "MFCACTIVEXCONTRO.TestActiveXCtrl.1",
	0x11b7ddbf,0x412b,0x45f5,0xac,0xcc,0xab,0x6d,0x01,0xce,0xb5,0x3e)

に合わせる必要があります。


SafeComp.cpp
SafeComp.h


については、


ソリューションエクスプローラー

ソース ファイル

追加

既存の項目


で追加の必要があります。

ソリューションエクスプローラー 追加


表示 - クラスビュー

TestActiveX / TestActiveXLib / _DTestActiveX を右クリック

追加

プロパティの追加

クラスビュー プロパティの追加


プロパティー名 : Caption(リストボックスで選択) とし、「OK」をクリックします。

プロパティー名:Caption


ビルド実行

ビルドモードを Release x86に変更します。 Release x86


「ビルド」→「TestActiveX のビルド」をクリックします。 TestActiveX のビルド


ここで、管理者権限が無い場合、以下のようなエラーになります。
その場合は、Visual Studio 2019 を "管理者として実行" で起動して、ビルドします。

1> ライブラリ C:\Users\admin\source\repos\TestActiveX\Debug\TestActiveX.lib とオブジェクト C:\Users\admin\source\repos\TestActiveX\Debug\TestActiveX.exp を作成中
1>TestActiveX.vcxproj -> C:\Users\admin\source\repos\TestActiveX\Debug\TestActiveX.ocx
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VC\v160\Microsoft.CppCommon.targets(2288,5): warning MSB3075: コマンド "regsvr32 /s "C:\Users\admin\source\repos\TestActiveX\Debug\TestActiveX.ocx"" はコード 5 で終了しました。このコマンドを実行するための十分な権限があるか確認してください。
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VC\v160\Microsoft.CppCommon.targets(2288,5): warning MSB4181: "Exec" タスクから false が返されましたが、エラーがログに記録されませんでした。
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VC\v160\Microsoft.CppCommon.targets(2300,5): error MSB8011: 出力の登録に失敗しました。ユーザーごとのリダイレクトを有効にするか、引き上げられたアクセス許可を使用して、コマンド プロンプトからコンポーネントを登録してください。
1>プロジェクト "TestActiveX.vcxproj" のビルドが終了しました -- 失敗。
========== ビルド: 0 正常終了、1 失敗、0 更新不要、0 スキップ ==========

⇒ Visual Studio 2019 を管理者として実行


ビルドに成功すると、
C:\Users\admin\source\repos\TestActiveX\Release\TestActiveX.ocx
が作成されます。


msi ビルド

本ブログ別記事「カスタム URL スキームでエクスプローラーを起動してフォルダを開く msi ビルド全手順」「拡張機能インストール」の手順とほぼ同じですので、詳細は省略します。
概ね以下の手順になります。


拡張機能の Microsoft Visual Studio Installer Projects をインストールします。

TestActiveX.sln ソリューションを開きます。

ファイル → 追加 → 新しいプロジェクト → 「Setup Project」選択し、「次へ」をクリックします。

プロジェクト名:TestActiveXInstaller とし、「作成」をクリックします。

「Application Folder」をクリックして、DefaultLocation の値を [LocalAppDataFolder]TestActiveX とします。

「Application Folder」選択状態で、右ペインを右クリック →「Add」→「ファイル」をクリックします。

ビルド済みの TestActiveX.ocx
例:C:\Users\admin\source\repos\TestActiveX\Release\TestActiveX.ocx
を追加します。

「ビルド」→「TestActiveXInstaller のビルド」をクリックして、TestActiveXIntaller.msi ができます。
(例:C:\Users\admin\source\repos\TestActiveX\TestActiveXInstaller\Release\TestActiveXIntaller.msi


動作例

「Hello world.」 と表示されれば、OKです。真っ白になっている場合、正常に動作していません。

動作例1

動作例2


ヨシ!


loading...