• 1999/09/05 [COM] COMの呼び方

    COMを呼ぶためのライブラリです。
    IDispatchインターフェースを使っています。
    callCom.cpp
    /*
    COMを呼び出すライブラリ
    多少、簡単なI/Fにしました。
    IDispatchインターフェースを使用しています。
    createInstance()した後は、IDispatch::Release()を行うこと。
    末尾にサンプルプログラムあり    "VbProject.VbClass"が登録されていること。
    
    尚、MFCにはこれとは別のアプローチにより、容易に扱えるクラスがある。
    COleDispatchDriver::InvokeHelper()などがそうです。
    特に支障なければそちらを使う方がよいだろう。
    
    */
    #include "atlbase.h"
    #include "atlconv.h"
    #include "atlconv.cpp"
    #include <stdio.h>
    
    /**
    *   指定されたCOMのインスタンスを生成します。
    *   文字列はShiftJISで指定すること。
    *   @param progid       ProgID
    *   @param ppIDispatch  IDispatchを返します。
    *   @result             エラーコード 正常終了のときは(S_OK)を返します。
    */
    HRESULT createInstance(const char* progid, IDispatch** ppIDispatch)
    {
        USES_CONVERSION;
        HRESULT hr = CoInitialize(NULL);
        if(FAILED(hr)) return hr;
    
        CLSID clsid;
        hr = CLSIDFromProgID(T2OLE(progid), &clsid);
        if(FAILED(hr)) return hr;
    
        *ppIDispatch = NULL;    // 念のため
        hr = CoCreateInstance(clsid, NULL, CLSCTX_SERVER,
                            IID_IDispatch, (void**)ppIDispatch);
        return hr;
    }
    
    
    /**
    *   指定されたメソッドを呼び出します。
    *   文字列はShiftJISで指定すること。
    *   @param pIDispatch   I IDispatchのポインタ
    *   @param mame         I メソッドの名前(Shift-JIS)
    *   @param varg         U 引数。
    *   @param args         I 引数の数
    *   @param result       O COMの関数の戻り値
    *   @result             エラーコード 正常終了のときは(S_OK)を返します。
    */
    HRESULT invokeMethod(IDispatch* pIDispatch, const char* name, VARIANTARG* varg, int args, VARIANT* result)
    {
        USES_CONVERSION;
    
        DISPID dispid;
        OLECHAR* olename = A2OLE(name);
        HRESULT hr = pIDispatch->GetIDsOfNames(IID_NULL, &olename, 1, GetUserDefaultLCID(), &dispid);
        if(FAILED(hr)) return hr;
    
        DISPPARAMS param = {varg, NULL, args, 0};
    
        if(result) VariantInit(result);
        hr = pIDispatch->Invoke(dispid, IID_NULL, GetUserDefaultLCID(), DISPATCH_METHOD,
                            &param, result,
                            NULL, NULL);
        return hr;
    }
    
    
    
    /**
    *   指定したプロパティの値を取得する
    *   文字列はShiftJISで指定すること。
    *   @param pIDispatch   I IDispatchのポインタ
    *   @param mame         I プロパティの名前(Shift-JIS)
    *   @param pVarResult   O 取得するプロパティの値
    *   @param result       O COMの関数の戻り値
    *   @result             エラーコード 正常終了のときは(S_OK)を返します。
    */
    HRESULT getProperty(IDispatch* pIDispatch, const char* name, VARIANT* pVarResult)
    {
        USES_CONVERSION;
    
        DISPID dispid;
        OLECHAR* ole_name = T2OLE(name);
        HRESULT hr = pIDispatch->GetIDsOfNames(IID_NULL, &ole_name, 1, GetUserDefaultLCID(), &dispid);
        if(FAILED(hr)) return hr;
    
        DISPPARAMS dispparams = {NULL, NULL, 0, 0};
        VariantInit(pVarResult);    // 必要
        hr = pIDispatch->Invoke(dispid, IID_NULL, GetUserDefaultLCID(), DISPATCH_PROPERTYGET,
                            &dispparams,
                            pVarResult,
                            NULL, NULL);
        return hr;
    }
    
    
    
    /**
    *   指定したプロパティに値を設定する
    *   文字列はShiftJISで指定すること。
    *   @param pIDispatch   I IDispatchのポインタ
    *   @param mame         I プロパティの名前(Shift-JIS)
    *   @param pVar         I 設定するプロパティの値
    *   @param result       O COMの関数の戻り値
    *   @result             エラーコード 正常終了のときは(S_OK)を返します。
    */
    HRESULT putProperty(IDispatch* pIDispatch, const char* name, VARIANT* pVar)
    {
        USES_CONVERSION;
    
        DISPID dispid;
        OLECHAR* ole_name = T2OLE(name);
        HRESULT hr = pIDispatch->GetIDsOfNames(IID_NULL, &ole_name, 1, GetUserDefaultLCID(), &dispid);
        if(FAILED(hr)) return hr;
    
        DISPID dispidPut = DISPID_PROPERTYPUT;
        DISPPARAMS dispparams = { pVar, &dispidPut, 1,1 };
        if (pVar->vt == VT_UNKNOWN || pVar->vt == VT_DISPATCH || 
            (pVar->vt & VT_ARRAY) || (pVar->vt & VT_BYREF))
        {
            hr = pIDispatch->Invoke(dispid, IID_NULL, GetUserDefaultLCID(), DISPATCH_PROPERTYPUTREF,
                            &dispparams,
                            NULL, NULL, NULL);
            if (SUCCEEDED(hr))
                return hr;
        }
    
        hr = pIDispatch->Invoke(dispid, IID_NULL, GetUserDefaultLCID(), DISPATCH_PROPERTYPUT,
                            &dispparams,
                            NULL, NULL, NULL);
        return hr;
    }
    
    
    /**
    *   指定したプロパティの値を取得する
    *   信じられないことに、プロパティを取得するのに引数が必要な場合がある。
    *   文字列はShiftJISで指定すること。
    *   @param pIDispatch   I IDispatchのポインタ
    *   @param mame         I プロパティの名前(Shift-JIS)
    *   @param varg         U 引数。
    *   @param args         I 引数の数
    *   @param pVarResult   O 取得するプロパティの値
    *   @param result       O COMの関数の戻り値
    *   @result             エラーコード 正常終了のときは(S_OK)を返します。
    */
    HRESULT getPropertyArg(IDispatch* pIDispatch, const char* name, VARIANTARG* varg, int args, VARIANT* pVarResult)
    {
        USES_CONVERSION;
        printf("getProperty2(%p,'%s',varg,%d,result)\n",pIDispatch, name, args);
        DISPID dispid;
        OLECHAR* ole_name = T2OLE(name);
        HRESULT hr = pIDispatch->GetIDsOfNames(IID_NULL, &ole_name, 1, GetUserDefaultLCID(), &dispid);
        if(FAILED(hr)) return hr;
    
        DISPPARAMS param = {varg, NULL, args, 0};
        if(pVarResult!=NULL) VariantInit(pVarResult);
        hr = pIDispatch->Invoke(dispid, IID_NULL, GetUserDefaultLCID(), DISPATCH_PROPERTYGET,
                            &param,
                            pVarResult,
                            NULL, NULL);
        return hr;
    }
    
    
    
    #ifdef TEST
    #include <stdio.h>
    
    // サンプルプログラム
    // cl /DTEST callCom.cpp で作成します。
    // あらかじめ、VB等で下記のCOMを作成し、そのCOMを呼びます。
    int main()
    {
        USES_CONVERSION;
        VARIANT var, result;
        BSTR    bstr;
    
        IDispatch* pIDispatch=NULL;
        HRESULT hr = createInstance("VbProject.VbClass", &pIDispatch);
        printf("hr=%xh\n", hr);
    
        printf("'** num = 55\n");
        VariantInit(&var);  var.vt = VT_I4;     var.lVal = 55;
        hr = putProperty(pIDispatch, "num", &var);
        printf("hr=%xh\n", hr);
    
        printf("'** Print num\n");
        hr = getProperty(pIDispatch, "num", &result);
        printf("hr=%xh num=%d\n", hr, result.lVal);
    
        printf("'** Call funcType0()\n");
        hr = invokeMethod(pIDispatch, "funcType0", NULL, 0, NULL);
        printf("hr = %xh \n", hr);
    
        printf("'** Print num\n");
        hr = getProperty(pIDispatch, "num", &result);
        printf("hr=%xh num=%d\n", hr, result.lVal);
    
        printf("'** str = \"モジモジもじれつ\"\n");
        bstr = SysAllocString(T2OLE("モジモジもじれつ"));
        VariantInit(&var);  var.vt = VT_BSTR;   var.bstrVal = bstr;
        hr = putProperty(pIDispatch, "str", &var);
        printf("hr=%xh\n", hr);
        SysFreeString(bstr);
    
        printf("'** str = \"今年\" : Print funcType1(1999, str), str\n");
        bstr = SysAllocString(T2OLE("今年"));
        VARIANTARG varg[2];
        VariantInit(&varg[0]);  varg[0].vt = VT_BSTR|VT_BYREF;  varg[0].pbstrVal = &bstr;
        VariantInit(&varg[1]);  varg[1].vt = VT_I4;             varg[1].lVal = 1999;
        hr = invokeMethod(pIDispatch, "funcType1", varg, 2, &result);
        printf("hr = %xh return=%d str=%s\n", hr, result.lVal, OLE2A(*varg[0].pbstrVal));
        SysFreeString(*varg[0].pbstrVal);
    
        pIDispatch->Release();      // 使い終わったらリリースを
        return 0;
    }
    /*
    VB5で VbProject プロジェクト  VbClass クラスモジュール として作成。
    ここのサブルーチンの中は何でもよい。
    --------------------------------------------------------------------
    Public str As String
    Public num As Long
    
    '*** タイプ0:引数なし、戻り値なし
    Public Sub funcType0()
        num = 0
        str = ""
    End Sub
    
    '*** タイプ1:引数 Long(ByVal)とString(ByRef) 戻り値Long
    Public Function funcType1(ByVal n As Long, ByRef s As String) As Long
        num = n
        s = str + s
        funcType1 = Len(s)
    End Function
    --------------------------------------------------------------------
    OLE−COMオブジェクトビューアでは以下のように見える。
    dispinterface _VbClass {
        properties:
        methods:
            [id(0x40030000), propget]
            BSTR str();
            [id(0x40030000), propput]
            void str([in] BSTR rhs);
            [id(0x40030001), propget]
            long num();
            [id(0x40030001), propput]
            void num([in] long rhs);
            [id(0x60030000)]
            void funcType0();
            [id(0x60030001)]
            long funcType1(
                            [in] long n, 
                            [in, out] BSTR* s);
    };
    */
    #endif
    

    戻る