デュアルインターフェース - proxyとstubの利用

いちごパック > COM/ActiveXの解説 > デュアルインターフェース - proxyとstubの利用

独自インターフェースと通信

すでに説明したように、COMサーバとCOMクライアントが別のプロセスで動いている場合はproxyとstubが動作しています。 EXEサーバの説明で用いたサンプルコードでは、 IClassFactoryやISequentialStreamといったシステム定義のインターフェースを用いてきました。 COMシステムはこれらのインターフェースに対するproxyやstubを持っているため、 COMサーバがDLLであってもEXEであっても同じように動作します。
しかし、COMシステムは独自インターフェースの内容を知りません。 したがって、独自インターフェースを定義する際には、 proxyやstubを提供する方法を考えておく必要があります。
MIDLには、タイプライブラリを生成する機能と、proxyとstubのソースコードを生成する機能が備わっています。 デュアルインターフェースの場合は、タイプライブラリをCOMシステムに登録することで、 タイプライブラリの内容に基づくproxyとstubをCOMシステムが自動的に生成してくれるようになります。 タイプライブラリは、32bitのインターフェースと64bitのインターフェースを区別していません。 タイプライブラリをCOMシステムに登録しておけば、32bit OSからでも64bit OSからでも独自インターフェースを呼び出せるようになります。
MIDLで生成されたソースコードを利用すると、proxyとstubを準備することも可能です。 あるいは、独自にproxyとstubを実装することも可能です。 これらの方法を用いる場合は、32bit OSと64bit OSのそれぞれに対しproxyとstubを用意する必要があります。 こちらの方法はタイプライブラリと比べ複雑になりますので、 可能な限りタイプライブラリを用いると良いでしょう。

タイプライブラリを用いたproxyとstubの利用

タイプライブラリに保存されたインターフェースがオートメーション互換である場合、 タイプライブラリが登録されるときに、そのproxyとstubもCOMシステムが登録してくれます。
オートメーション互換のインターフェースとは、 引数がVARIANTで表現可能で、戻り値がHRESULTであるインターフェースのことです。 デュアルインターフェースであればオートメーション互換になります。
いいかえれば、次の手順を踏めば、 独自インターフェースを備えたCOMサーバを、proxyとstubを介して呼び出せるようになります。
  • .idlでdual指定したinterfaceを作成する。
  • 生成されたタイプライブラリをCOMシステムに登録する。
  • coclassでそのinterfaceを使用する。

  • デュアルインターフェースのEXEサーバとして実装されたサンプルCOMサーバは、 独自インターフェースIIchigo4を備えたcoclassで、 そのCLSIDはCLSID_Ichigo4、ProgIDはIchigo4.Logwriterです。
    EXEサーバは別のプロセスとして起動されますが、 タイプライブラリを利用してシステムが提供するproxyとstubのおかげで、 C++言語からでも、Javascriptなどのスクリプト言語からでも、 proxyとstubを介してこのcoclassを呼び出すことができます。
    C++言語から呼び出すコードは次の通りです。
    //
    // Copyright (c) 2016 The Ichigopack Project (http://ichigopack.net/).
    //
    
    #include <windows.h>
    #include <ole2.h>
    #include <iostream>
    #include <string>
    #include <iomanip>
    #include "ichigocom4_if.h"
    
    
    // {287AF1C7-7618-4C81-952C-B70238A474CB}
    static const GUID CLSID_Ichigo4 =
    { 0x287af1c7, 0x7618, 0x4c81, { 0x95, 0x2c, 0xb7, 0x2, 0x38, 0xa4, 0x74, 0xcb } };
    
    
    
    int main(int argc, char** argv)
    {
        HRESULT hr;
        hr = CoInitialize(NULL);
        if ( FAILED(hr) ) {
            std::cout << "CoInitialize() error: " << hr << std::endl;
            return 1;
        }
        IIchigo4* pObj = NULL;
        hr = CoCreateInstance(
                 CLSID_Ichigo4, NULL,
                 CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER |
                 CLSCTX_LOCAL_SERVER,
                 IID_IIchigo4, (LPVOID*)&pObj);
        if ( SUCCEEDED(hr) ) {
            BSTR bstr = SysAllocString(L"ichigopack COM sample 4 (exe)\n");
            if ( bstr != NULL ) {
                pObj->Write( bstr );
                SysFreeString( bstr );
            } else {
                std::cout << "SysAllocString() error" << std::endl;
            }
            pObj->Release();
        } else {
            std::cout << "CoCreateInstance() error: "
                      << std::hex << std::setfill('0')
                      << std::setw(8) << hr << std::endl;
        }
        CoUninitialize();
        return 0;
    }
    
    

    Javascript言語から呼び出すコードは次の通りです。 COMサーバを呼び出すJavascriptは、.wsfの拡張子を持つWindows Scriptファイルとして保存する必要があります。
    <job id="ichigocom4">
      <script language="JScript">
        var obj = new ActiveXObject("Ichigo4.Logwriter")
        obj.Write("ichigopack COM sample 4 (javascript)\n");
      </script>
    </job>
    

    関連ページ

  • COM/ActiveXの解説ページ 目次
  • 前の項目: タイプライブラリの登録とその利用