はじめに
Firefox(Mozilla)などの機能をC++によって拡張することができるXPCOMの作り方を紹介する。 ここでは具体的なDLLの作成方法についてを記す。前段階で準備を行っていない場合は「その1」 を参考にすること。プロジェクトの作成
Win32プロジェクトとして空のDLLプロジェクトを作成する。Visual C++を起動し、「ファイル」メニューの「新規作成」から「プロジェクト」を選択する。 「テンプレート」は「Win32プロジェクト」を使う。ここでは「プロジェクト名」は「xxx」とし た。
プロジェクトの作成で「OK」ボタンを押すと「Win32アプリケーションウイザード」の画面が開く。 ここで「アプリケーションの設定」を開き、「アプリケーションの種類」で「DLL」を選択する。 さらに「空のプロジェクト」にチェックを入れる。
XPCOM用IDLの作成
VC++の「プロジェクト」メニューの「新しい項目の追加」を選択する。そして「テンプレート」から 「MIDLファイル(.idl)」を選択してファイル名を「Ixxx.idl」としてファイルを作成する。新しく作成したIDLファイルには初めから2行あるが、それを削除してファイル内容を以下のようにす る。
#include "nsISupports.idl"
[scriptable, uuid(2E02A2B5-AD6F-4688-A75B-F642838BCCA2)]
interface Ixxx : nsISupports
{
long Add(in long nData1, in long nData2);
AString AddString(in AString strData,in long nData);
};
※太字で強調している部分はVC++に含まれるGuidGen.exeを使って新しいGUIDを生成して利用 する。同じ値を使いまわしてはいけない!
IDLファイルビルド設定
Visual C++標準のIDLビルドをキャンセルして、XPCOM用のIDLビルドコマンドを登録する。VC++の「ソリューションエクスプローラー」に新しく追加された「Ixxx.idl」を右クリックし、 現れたメニューから「プロパティ」を選択する。そして開いたダイアログの「構成」から「すべて の構成」を選択し、左側のツリーの「全般」にある「ビルドから除外」を「はい」に変更する。そし て「OK」ボタンを押して設定を保存する。
VC++の「プロジェクト」メニューから「プロパティ」を選択する。そして「構成」から「すべての構成」 を選択する。左側のツリーから「ビルドイベント」の「ビルド前のイベント」を選択する。ここで右側の 「コマンドライン」に「makexpidl.bat $(ProjectDir)Ixxx.idl」を入力して「OK」ボタンを押して保存す る。
※「クラスビュー」を開いた状態でないと「プロジェクト」メニューに「プロパティ」が見つからない。
main.cppファイルの作成
VC++の「プロジェクト」メニューの「新しい項目の追加」を選択する。そして「テンプレート」から 「C++ファイル(.cpp)」を選択してファイル名を「main.cpp」としてファイルを作成する。ここでは暫定的にファイル内容を以下のようにする。
#include "mozilla-config.h"
#include "windows.h"
#include "wchar.h"
#include "nsEmbedString.h"
#include "Ixxx.h"
#pragma comment(lib,"odbc32.lib")
#pragma comment(lib,"odbccp32.lib")
#pragma comment(lib,"nspr4.lib")
#pragma comment(lib,"plds4.lib")
#pragma comment(lib,"plc4.lib")
#pragma comment(lib,"xpcomglue.lib")
#define MY_COMPONENT_CONTRACTID "@mydomain.com/xxxxxxx/Ixxx;1"
#define MY_COMPONENT_CLASSNAME "Ixxx XPCOM"
#define MY_COMPONENT_CID { 0x5506ca73, 0x8f02, 0x40b9, { 0x87, 0xeb, 0xfa, 0x53, 0xc9, 0x58, 0x70, 0xfc } }
※太字で強調している部分はVC++に含まれるGuidGen.exeを使って新しいGUIDを生成して利用 する。同じ値を使いまわしてはいけない!
main.cppファイル内容の作成
cppファイル内容の作成には「Ixxx.h」が必要だが、まだこのファイルはどこにもない。「Ixxx.h」を 作成するために一度ビルドをする。「ビルド」メニューから「ソリューションのビルド」しビルドする。 これで自動的に「Ixxx.h」が作成される。「main.cpp」に書かれている「#include "Ixxx.h"」の上で右クリックをして現れたメニューから 「ドキュメント "Ixxx.h"を開く」を選択し、ヘッダーファイルを開く。
自動的に作成された「Ixxx.h」の中には以下のように「#if 0」と「#endif」で囲まれた部分がある。 この部分を選択してmain.cppに追加する。
(...省略...)
#if 0 (この行を含まず下の部分を追加)
/* Use the code below as a template for the implementation class for this interface. */
/* Header file */
class _MYCLASS_ : public Ixxx
{
public:
NS_DECL_ISUPPORTS
NS_DECL_IXXX
_MYCLASS_();
private:
~_MYCLASS_();
protected:
/* additional members */
};
/* Implementation file */
NS_IMPL_ISUPPORTS1(_MYCLASS_, Ixxx)
_MYCLASS_::_MYCLASS_()
{
/* member initializers and constructor code */
}
_MYCLASS_::~_MYCLASS_()
{
/* destructor code */
}
/* long Add (in long nData1, in long nData2); */
NS_IMETHODIMP _MYCLASS_::Add(PRInt32 nData1, PRInt32 nData2, PRInt32 *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* AString AddString (in AString strData, in long nData); */
NS_IMETHODIMP _MYCLASS_::AddString(const nsAString & strData, PRInt32 nData, nsAString & _retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* End of implementation class template. */
#endif (この行を含まず上の部分までを追加)
(...省略...)
ただし追加したときに以下の太字の部分を変更しておく
/* long Add (in long nData1, in long nData2); */
NS_IMETHODIMP _MYCLASS_::Add(PRInt32 nData1, PRInt32 nData2, PRInt32 *_retval)
{
*_retval = nData1 + nData2;
return NS_OK;
}
/* AString AddString (in AString strData, in long nData); */
NS_IMETHODIMP _MYCLASS_::AddString(const nsAString & strData, PRInt32 nData, nsAString & _retval)
{
PRUnichar uchText[128];
swprintf(uchText,L"%d",nData);
_retval = uchText;
_retval += strData;
return NS_OK;
}
さらに以下の内容もmain.cppに追加する。
#include "nsIGenericFactory.h"
NS_GENERIC_FACTORY_CONSTRUCTOR(_MYCLASS_)
static nsModuleComponentInfo components[] =
{
{
MY_COMPONENT_CLASSNAME,
MY_COMPONENT_CID,
MY_COMPONENT_CONTRACTID,
_MYCLASS_Constructor,
}
};
NS_IMPL_NSGETMODULE("_MYCLASS_Module", components)
※ここまでの処理で完成したmain.cppの内容はこのページ下部に表示してあります。
プロジェクトの設定
VC++の「プロジェクト」メニューから「プロパティ」を選択する。そして「構成」から「Debug」 を選択する。左側のツリーから「C/C++」の「プリプロセッサ」を選択する。ここで右側の 「プロセッサの定義」に「;XPCOM_GLUE」を追加する(既存の文字列は消さないこと!)。同じように「構成」が「Release」のときの「プロセッサの定義」にも追加しておく。
次に「構成」を「すべての構成」にして「リンカ」の「入力」にある「特定のライブラリの無視」 に「libcmtd.lib」を追加する。
※「クラスビュー」を開いた状態でないと「プロジェクト」メニューに「プロパティ」が見つからない。
※「libcmtd.lib」を除外するという方法はかなり強引で、本来なら避けるべきものだが...今回は簡 便化のためにこうした。除外しない方法は次回以降に紹介する。
XPCOMの生成
これで「ビルド」メニューから「ソリューションのビルド」を選択してびるどをする。すると以下のファイル を得ることができる。・xxx.dll
・Ixxx.idl
・Ixxx.xpt
これら3つのファイルがFirefoxなどで利用するためのXPCOMコンポーネントとなる。
main.cppの内容
上の説明が分かりずらいのでここまででできたmain.cppの全内容を以下に示す。
#include "mozilla-config.h"
#include "windows.h"
#include "wchar.h"
#include "nsEmbedString.h"
#include "Ixxx.h"
#pragma comment(lib,"odbc32.lib")
#pragma comment(lib,"odbccp32.lib")
#pragma comment(lib,"nspr4.lib")
#pragma comment(lib,"plds4.lib")
#pragma comment(lib,"plc4.lib")
#pragma comment(lib,"xpcomglue.lib")
#define MY_COMPONENT_CONTRACTID "@mydomain.com/xxxxxxx/Ixxx;1"
#define MY_COMPONENT_CLASSNAME "Ixxx XPCOM"
#define MY_COMPONENT_CID { 0x5506ca73, 0x8f02, 0x40b9, { 0x87, 0xeb, 0xfa, 0x53, 0xc9, 0x58, 0x70, 0xfc } }
/* Header file */
class _MYCLASS_ : public Ixxx
{
public:
NS_DECL_ISUPPORTS
NS_DECL_IXXX
_MYCLASS_();
private:
~_MYCLASS_();
protected:
/* additional members */
};
/* Implementation file */
NS_IMPL_ISUPPORTS1(_MYCLASS_, Ixxx)
_MYCLASS_::_MYCLASS_()
{
/* member initializers and constructor code */
}
_MYCLASS_::~_MYCLASS_()
{
/* destructor code */
}
/* long Add (in long nData1, in long nData2); */
NS_IMETHODIMP _MYCLASS_::Add(PRInt32 nData1, PRInt32 nData2, PRInt32 *_retval)
{
*_retval = nData1 + nData2;
return NS_OK;
}
/* AString AddString (in AString strData, in long nData); */
NS_IMETHODIMP _MYCLASS_::AddString(const nsAString & strData, PRInt32 nData, nsAString & _retval)
{
PRUnichar uchText[128];
swprintf(uchText,L"%d",nData);
_retval = uchText;
_retval += strData;
return NS_OK;
}
#include "nsIGenericFactory.h"
NS_GENERIC_FACTORY_CONSTRUCTOR(_MYCLASS_)
static nsModuleComponentInfo components[] =
{
{
MY_COMPONENT_CLASSNAME,
MY_COMPONENT_CID,
MY_COMPONENT_CONTRACTID,
_MYCLASS_Constructor,
}
};
NS_IMPL_NSGETMODULE("_MYCLASS_Module", components)







