EternalWindows
ActiveX コントロール / cabファイルの作成

インターネット上で動作させることを目的としたActiveXコントロールは、 最終的に何らかのサーバーへアップロードする必要があります。 次に、アップロードまでに必要な作業を示します。

DLL(ActiveXコントロール)の作成
↓
infファイルの作成
↓
cabファイルの作成
↓
cabファイルの署名
↓
cabファイルをインターネット上にアップロード

コントロールをアップロードするといっても、コントロールのDLLを単一でアップロードすることは稀といえるでしょう。 たとえば、コントロールが何らかのDLLに依存しているのであればそのDLLもアップロードすべきであるため、 多くの場合は必要なファイル群を1つに圧縮したcabファイルをアップロードします。 このようにすればcabファイルをダウンロードしたブラウザは、 それを展開することでコントロールの動作に必要なファイル群を取得できます。 ただし、その展開したファイルのどれがコントロールのDLLに相当するのかや、 展開したファイルをファイルシステムのどこに配置すればよいかまでは分かりませんから、 こうした情報を与えるためにinfファイルを用意しておくことになります。

infファイルでは、各情報をセクションという単位で区切って指定します。 次に、今回作成したinfファイルの中身を示します。

[version]
signature="$CHICAGO$"
AdvancedINF=2.0

[Add.Code]
sample.dll=sample.dll

[sample.dll]
file-win32-x86=thiscab
clsid={E4A5C7BC-BDE7-43e8-96DC-98FEA02F1A18}
RegisterServer=yes

versionセクションには、infファイルのバージョン情報を指定します。 signatureには$CHICAGO$という文字列を指定し、AdvancedINFには2.0という値を指定します。 どのようなファイルをインストールするにしても、これらの部分は基本的に変更する必要はありません。 Add.Codeセクションには、インストールするファイル名を指定します。 sample.dllというのは今回作成したコントロールの名前であり、これは必ず指定します。 左辺と右辺の値は同じになっていなければならず、他にもインストールするファイルが存在する場合は、 filename=filenameの形を複数行追加します。 sample.dllセクションには、sample.dllの情報を指定します。 このセクション名は、Add.Codeセクションに指定したファイル名と同一でなければなりません。 file-win32-x86にはこのファイルがどこに存在するかを示すパスを指定しますが、 cabファイル内に存在する場合はthiscabで問題ありません。 clsidは、コントロールのCLSIDを指定します。 ファイルがコントロールでない場合は、clsidは不要になります。 RegisterServerはコントロールのDllRegisterServerを呼び出すかどうかであり、yesを指定すれば呼び出されることになります。 ファイルがコントロールでない場合は、RegisterServerは不要になります。

infファイルが用意できたら、これとDLLをcabファイルに圧縮します。 cabファイルの圧縮にはcabarc.exeというファイルを使用するのが簡単ですが、 このファイルは既定でWindowsに存在していないと思われるため、 Cabinet SDKと呼ばれるファイルを別途ダウンロードします。 Cabinet SDKは、次のURLからダウンロードできます。

http://support.microsoft.com/kb/310618/ja

ダウンロードしたexeを実行すれば、Cabinet SDKのフォルダが作成されます。 cabarc.exeはBINという名前のフォルダに存在するため、 これを取り出せばCabinet SDKのフォルダは削除しても問題ありません。 取り出したcabarc.exeは、インストールすることになるファイルと共にまとめておきます。

上記のように、cabarc.exeが存在するフォルダにインストールすることになるファイルを配置します。 sample.dllはActiveXコントロール本体であり、sample.infはインストール情報を格納しているものとします。 上記のフォルダがc:\\sampleに存在するとして、コマンドプロント上で次のように入力します。

cd c:\\sample

これにより、コマンドプロントのカレントディレクトリがc:\\sampleに設定されました。 この状態で次の文字列を入力すれば、cabファイルが作成されることになります。

CABARC -s 6144 n sample.cab sample.dll sample.inf

sample.cabの部分が作成されるファイル名を表しています。 cabファイルの名前の後には、インストールすることになるファイルをスペースで区切って指定します。

cabファイルを作成したら、次はそれに対して署名を行います。 署名を行うというのは、そのファイルの作成者が自分であることを示した証明書を格納するということであり、 これによってcabファイルをダウンロードする側は、そのファイルが誰によって作成されたのかを確認できます。 証明書を取得するには、CA(証明機関)に対して証明書の申請を行う必要があるため、 まずは自分にとって適切なCAを選択することになるでしょう。 これは、コードサイニング証明書というキーワードで検索するのが一番早いと思われます。 証明書を取得したら署名を行いますが、これについてもCAのHPで説明されているため、その手順に従って行えばよいでしょう。 ちなみに、署名されていないファイルをIEでダウンロードしようとすると、次のようなダイアログが表示されます。

上図からも分かるように、身元が証明されていないファイルはダウンロードできませんから、 ファイルに署名をすることは事実上必須といえます。 ただし、自己署名入り証明書のような、自分で作成した証明書でファイルに署名しても、 それは他のコンピュータ上で正しく認識されませんから、 必ず広く信頼されたCAによって発行された証明書で署名を行うようにします。 ちなみに、IEのセキュリティゾーンの設定には「未署名のActiveXコントロールのダウンロード」というものがあり、 これが有効でない場合は署名がないファイルでもダウンロードできます。 しかし、これは既定で有効になっているため、無効になっていることを前提するわけにはいきません。

cabファイルに署名を行ったら、それを自社のサーバーなどにアップロードします。 アップロード先となるURLが記述された次のようなHTMLファイルが実行されれば、 cabファイルはクライアントのコンピュータにダウンロードされるはずです。

<html>
<title>ActiveX サンプル</title>
<body>
<p>ActiveXの表示ここから</p>

<object classid="clsid:E4A5C7BC-BDE7-43e8-96DC-98FEA02F1A18" codebase="http://samplehost.jp/sample.cab" width="320" height="240">
<param name="color" value="red">
</object>

<p>ActiveXの表示ここまで</p>
</body>
</html>

objectタグにcodebaseが指定されている場合は、ブラウザがそのURLへアクセスするようになります。 上記では架空のURLを指定していますが、 実際にはアップロード先のURLを指定する必要があります。 ちなみに、cabファイルの名前の後には#Version=1,0,0,1のようなバーショを指定することができ、 たとえ既にsample.cabがインストールされていたとしても、そのバージョンが1,0,0,1と異なる場合は新しいファイルとしてインストールさせるようなことができます。 バージョンを指定する場合は、infファイルのコントロール(今回の場合sample.dll)のセクションにFileVersion=1,0,0,1を追加し、 DLLのバージョンもリソースを通じて1,0,0,1に指定しておきます。 当然ながら、実際の開発では1,0,0,1という値にこだわらず、適切なバージョン値を指定します。

コントロールのアンインストール

インターネットからコントロールをインストールした場合は、 %windir%Downloaded Program Filesにコントロールの名前のファイルが作成され、 さらにHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Code Store Database\Distribution Units以下に、コントロールのCLSIDを基にしたキーが作成されます。 このような場合、IEの「アドオンの管理」にはコントロールの名前が表示されるようになり、 削除ボタンを押すことでコントロールをアンインストールができます。 アプリケーション内からコントロールのアンインストールを行いたい場合は、RemoveControlByNameを呼び出すようにします。

#include <windows.h>

typedef HRESULT (WINAPI *LPREMOVECONTROLBYNAME)(LPCSTR, LPCSTR, LPCSTR, BOOL, DWORD);

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	HRESULT               hr;
	HMODULE               hmod;
	LPREMOVECONTROLBYNAME lpfnRemoveControlByName;

	hmod = LoadLibrary(TEXT("occache.dll"));
	if (hmod == NULL)
		return 0;

	lpfnRemoveControlByName = (LPREMOVECONTROLBYNAME)GetProcAddress(hmod, "RemoveControlByName");
	if (lpfnRemoveControlByName == NULL) {
		FreeLibrary(hmod);
		return 0;
	}

	hr = lpfnRemoveControlByName("", "{E4A5C7BC-BDE7-43e8-96DC-98FEA02F1A18}", NULL, TRUE, TRUE);
	if (FAILED(hr)) {
		TCHAR szBuf[256];
		wsprintf(szBuf, TEXT("アンインストールに失敗しました。 %x"), hr);
		MessageBox(NULL, szBuf, NULL, MB_ICONWARNING);
		return 0;
	}
	
	MessageBox(NULL, TEXT("アンインストールに成功しました。"), TEXT("OK"), MB_OK);
	
	FreeLibrary(hmod);

	return 0;
}

RemoveControlByNameはヘッダーファイルに定義されていないため、 LoadLibraryとGetProcAddressを使用して動的に呼び出します。 第1引数はコントロールのフルパスを指定できますが、空の文字列を指定して問題ないようです。 第2引数は、コントロールのCLSIDを指定するようにします。 第3引数はタイプライブラリのCLSIDを指定しますが、タイプライブラリを作成していない場合はNULLで問題ありません。 第4引数はコントロールを強制的に削除するかどうかを指定するようですが、TRUEでもFALSEでも結果は変わらないように思えます。 第5引数は、コントロールがDistributionUnitかどうかを指定するようですが、詳しい意味はよく分かりません。 FALSEを指定した場合は失敗するようなので、TRUEを指定するようにしています。 RemoveControlByNameは管理者アカウントで呼び出すようにし、 ブラウザなどでコントロールを開いていない状態にしておきます。

「アドオンの管理」における削除やRemoveControlByNameを実行しても、 コントロールのアンインストールが正しく行われないことがあります。 それは、コントロールをsysytem32フォルダにインストールした場合です。 Downloaded Program FilesのファイルやDistribution Units以下のキーは削除されるのですが、 コントロールのDLL自体はsystem32フォルダに残ったままであり、DllUnregisterServerも呼ばれることはありません。 コントロールをsystem32フォルダにインストールする場合は、 infファイルにおけるコントロールのセクションにDestDir=11を追加すればよいでしょう。 この11がsystem32フォルダを意味し、10の場合はwindowsフォルダを意味します。 windowsフォルダの場合は、DLLは問題なく削除されるはずです。



戻る