チュートリアル : テキスト エディタを使った COM サーバーの作成
属性は、面倒で複雑な従来の COM プログラミングを簡単にするために開発されました。属性を使ってアプリケーションを開発することで、COM の一般的な手順の多くを自動化したり簡略化したりできます。このチュートリアルでは、テキスト エディタとコマンド ライン ツールを使って、簡単な COM サーバーを開発します。
アプリケーションで属性を使用するには、関連するマクロ (_ATL_ATTRIBUTES など) を定義し、関連するヘッダー ファイルをインクルードして、属性のサポートを追加する必要があります。
ヘッダー ファイルを作成するには
メモ帳または任意のテキスト エディタを開きます。
MyIncludes.h という名前の新しいファイルを作成します。
次のコードを追加します。
#pragma once #define STRICT #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0400 #endif #define _ATL_ATTRIBUTES #define _ATL_APARTMENT_THREADED #define _ATL_NO_AUTOMATIC_NAMESPACE #include <atlbase.h> #include <atlcom.h> #include <atlwin.h> #include <atltypes.h> #include <atlctl.h> #include <atlhost.h> using namespace ATL;
ファイルを保存します。
"atl" で始まるインクルード ファイルは、アプリケーションに ATL のサポートを加えます。_ATL_ATTRIBUTES の定義により、属性付き ATL プログラミングのサポートも追加されます。
インプロセス サーバーを実装するソース ファイルを作成する必要があります。
ソース ファイルを作成するには
メモ帳で、MyServer.cpp という名前の新しいファイルを作成します。
次のコードを追加します。
#include "MyIncludes.h" // The module attribute is specified in order to implement DllMain, // DllRegisterServer and DllUnregisterServer [ module(dll, name = "MyServer", helpstring = "MyServer 1.0 Type Library") ]; [ emitidl ];
ファイルを保存します。
module 属性を使うと、COM インプロセス サーバーに必要な機能を実装する手間が省かれます。また、.idl ファイルまたは .def ファイル (サーバーの関数をエクスポートするファイル) を記述する必要もありません。これらの作業はすべて、module 属性によって自動的に行われます。
プロジェクトをビルドするには
コマンド ラインに次のコマンドを入力します。
cl /LD MyServer.cpp regsvr32 MyServer.dll
エラーが発生した場合は、Visual Studio が正しくインストールされ、環境変数が定義されていることを確認してください。Visual Studio 環境変数は、[Visual Studio 2005 コマンド プロンプト] を実行して自動的に定義することも、<Visual Studio インストール ディレクトリ>\Common7\Tools\vsvars32.bat にある vsvars32.bat を実行して手動で設定することもできます。
プロジェクトが正常にビルドされると、オペレーティング システムにサーバーが登録されます。
この時点では、COM サーバーはクライアントに対してどの機能も公開していません。これは、COM サーバーにサーバー オブジェクトが実装されていないためです。次の手順として、このサーバーにサーバー オブジェクトを追加します。
サーバーにサーバー オブジェクトを追加するには
MyServer.cpp を開き、次のコードを追加します。
///////////////////////////////////////////////////////////////////////////// // IObject1 [ object, uuid("103FF9D9-8BC9-4ea8-8CD4-C1E627D04358"), dual, helpstring("IObject1 Interface"), pointer_default(unique) ] __interface IObject1 : IDispatch { HRESULT GetANum([out, retval]int* pInt); }; ///////////////////////////////////////////////////////////////////////////// // CObject1 [ coclass, threading(apartment), vi_progid("MyServer.Object1"), progid("MyServer.Object1.1"), version(1.0), uuid("15615078-523C-43A0-BE6F-651E78A89213"), helpstring("Object1 Class") ] class ATL_NO_VTABLE CObject1 : public IObject1 { public: CObject1() { } HRESULT GetANum(int* pInt){ *pInt = 101; return S_OK; } DECLARE_PROTECT_FINAL_CONSTRUCT() HRESULT FinalConstruct() { return S_OK; } void FinalRelease() { } };
変更を保存し、新しいコードをチェックします。
このコードにより、メソッドを 1 つ持つカスタム インターフェイス (IObject1) を実装する、簡単な COM オブジェクト (CObject1) が作成されます。このメソッド (GetANum) は、データ メンバの値 (int 型) を返します。
変更を保存し、前の手順と同じコマンドを使って、アプリケーションを再ビルドします。
cl /LD MyServer.cpp
regsvr32 MyServer.dll
サーバーが動作するかどうかを調べるには、テスト用のクライアント アプリケーションを作成する必要があります。
テスト用クライアント アプリケーションを作成するには
メモ帳を開き、Comtest.cpp という名前の新しいファイルを作成します。
Comtest.cpp は、MyServer.cpp と同じフォルダにある必要があります。
Comtest.cpp に次のコードを追加します。
#include <iostream> #include "atlbase.h" #import "vc90.tlb" no_namespace using namespace std; int main() { CoInitialize(NULL); { CComPtr<IUnknown> spUnknown; spUnknown.CoCreateInstance(__uuidof(CObject1)); CComPtr<IObject1> pI; spUnknown.QueryInterface(&pI); int res = 0; res = pI->GetANum(); cout << res << endl; } CoUninitialize(); }
クライアント側でサーバーの正しい動作を認識するには、#import キーワードを使って、サーバーのタイプ ライブラリをインポートする必要があります。サーバーを作成するときに名前を指定していないため、コンパイラによって生成されたタイプ ライブラリは、既定の名前 (vc90.tlb) になっています。前掲のコードの中にある次の行で、ライブラリがインポートされます。
#import "vc90.tlb" no_namespace
このファイルがテスト用アプリケーションにインポートされると、クライアントは COM サーバーの型情報にアクセスできます。型情報にアクセスできると、テスト用アプリケーションは、その中で定義されている任意の型 (CObject1 や IObject1 など) を参照できます。
テスト アプリケーションをビルドおよび実行するには
コマンド ラインに次のコマンドを入力します。
cl /EHsc comtest.cpp
次のコマンドを入力して、アプリケーションを実行します。
comtest
整数値が出力されます。