はじめに
Microsoft社は.NETの最初のバージョンを開発する際に、それまで8年以上もの間アプリケーション開発に使われてきた既存のWindowsテクノロジ――つまりCOM――との連携機能を組み込む必要があると考えました。このような考えからMicrosoft社が.NETランタイムに追加したのが「COM相互運用機能」です。この機能は両方向に対応しており、.NETコードからCOMコンポーネントを呼び出すことも、COMコードから.NETコンポーネントを呼び出すこともできます。
この記事は、COMコンポーネント開発やインターフェイスの概念に精通しているVB6プログラマを対象としています。ここではCOMの背景を復習してVB6でのCOM処理を解説したうえで、COMとスムーズにやり取りできる.NETコンポーネントの設計方法を示します。別の記事で、.NETアプリケーション内で既存のCOMコンポーネントを使う方法も説明する予定です。
COMに精通しているエキスパートから見れば単純化しすぎの部分もあると思いますが、ここではCOMコードの不足部分を.NETコンポーネントで補おうとする開発者にとって重要なポイントを中心に説明します。
COMとVB6の背景
COMで重要な点の1つは、すべてがインターフェイスから呼び出されるということです。COM
オブジェクトを作成すればメソッドを呼び出せるという単純なものではありません。インターフェイスを使う必要があります。
ここでこう思うかもしれません。「ちょっと待ってくれ、VB6で何百ものクラスをコーディングしてきたけど、インターフェイスなんて一度も必要なかったぞ」。そのとおりです。VB6ではバックグラウンドでインターフェイスが提供されていたので、開発者が直接操作する必要はありませんでした。開発者がクラスのパブリックメソッドを定義するだけで、VB6がそのメソッドをCOMインターフェイスに含め、そのインターフェイスをクラスに実装してくれました。
例えば、ActiveX DLLプロジェクトに次のようなVB6
クラスがあるとします。クラス名はRobotです。
Option Strict Public Sub MoveForward() ... End Sub Public Sub FindCar() ... End Sub
このクラスをDLLにコンパイルすると、VB6によって_Robot
というインターフェイス(先頭にアンダースコアが付きます)とRobot
というコクラスが作成され、このコクラスにインターフェイス_Robot
が実装されます(コクラスは実際のCOM作成可能オブジェクトです)。
OLE View(OLE/COMオブジェクトビューア)というMicrosoftユーティリティは、COMコンポーネントで定義されている型を調べるツールです。OLE Viewは、[スタート]-[すべてのプログラム]-[Microsoft Visual Studio 6.0]-[Microsoft Visual Studio 6.0 Tools]-[OLE View]にインストールされています。OLE Viewを起動し、[File]メニューの[View TypeLib...]を選択して、上記の例でコンパイルしたActiveX DLLを選択します。この場合の出力のうち、重要な部分の抜粋を以下に示します。
interface _Robot : IDispatch { ... HRESULT MoveForward(); ... HRESULT FindCar(); }; coclass Robot { [default] interface _Robot; };
まず見てほしいのは、_Robot
というインターフェイスです。これはVB6が開発者の代わりに作成したインターフェイスです。このインターフェイスには、このクラスに追加した2つのメソッド(MoveForward
とFindCar
)が定義されています。次に、Robot
というコクラスがあります。これは、実際の作成可能クラスです。COMのすべてはインターフェイスを介して呼び出されるので、コクラスにはこのオブジェクトでサポートされるすべてのインターフェイスが列挙されます。今このコクラスにあるのは_Robot
というインターフェイスのみで、default
修飾子が付いています。
COMとデフォルトインターフェイスについての詳しい説明は省きますが、ここでVB6コンポーネントの観点から見て重要な点は、クラスに実装可能な全インターフェイスのうち、遅延バインディングをサポートしているのはデフォルトインターフェイスのみであるということです。従って、遅延バインディングのみに対応しているVBScriptなどのスクリプティングクライアントからは、デフォルトインターフェイスのメソッドしか見えません。
複数のインターフェイス
COMでは、複数のインターフェイスを実装できます。上記のActiveX DLLの例に、IMaid
という新しいクラスモジュールを追加します(VB6ではCOMインターフェイスを直接作成する方法は用意されていません。詳細は後述します)。IMaid
のコードを次のように記述します。
Option Explicit Public Sub CleanKitchen() ... End Sub Public Sub WashCar() ... End Sub
次に、Robot
クラスにImplements IMaid
を追加します。
Option Explicit Implements IMaid Public Sub MoveForward() End Sub Public Sub FindCar() End Sub Private Sub IMaid_CleanKitchen() End Sub Private Sub IMaid_WashCar() End Sub
このDLLをコンパイルしてからOLE Viewで見てみると、次のように出力されます(ここでも重要な部分以外は省略します)。
interface _Robot : IDispatch { ... HRESULT MoveForward(); ... HRESULT FindCar(); }; coclass Robot { [default] interface _Robot; interface _IMaid; }; interface _IMaid : IDispatch { .. HRESULT CleanKitchen(); .. HRESULT WashCar(); }; coclass IMaid { [default] interface _IMaid; };
前にも述べたとおり、VB6では開発者がCOMインターフェイスを直接作成することはできません。ただし、VB6によってすべてのクラスに(先頭にアンダースコアの付いた)COMインターフェイスが作成されるので、VB6でクラスにImplements
キーワードを指定すると、このコードをコンパイルするとき、VB6コンパイラでは自動生成されたインターフェイスが使用されます。従って、上記のRobot
コクラスには_Robot
インターフェイス(VB6で自動的に生成)と_IMaid
インターフェイス(IMaid
クラスから自動的に生成)が実装されます。
VB6で自動的に作成された_Robot
インターフェイスがデフォルトインターフェイスとなっている点にも注意してください。このオブジェクトをスクリプティング環境(ASPページなど)で使う場合には、MoveForward
メソッドとFindCar
メソッドしか使えません。IMaid
インターフェイスで実装されるメソッドは、デフォルトインターフェイスのメソッドではないので使用できません。