さて、手順は次のようになります。
- C#でDLLを作成する
- 上で作成したDLLをレジストリへ登録する
- Cでプログラムを作成する
Cから呼び出されるライブラリをC#で作成します。
DLLをレジストリへ登録する
警告が出ますが気にしない。だってサンプルですもの。
Cでプログラムを作成する
さあ、ここからが本番です。先ほど登録したDLLからクラス名とメソッド名を指定してオブジェクトに働いてもらいましょう。大まかなイメージはJavaやC#のリフレクションに近いです。
- 初期化
- クラス名からCLSIDを取得
- インスタンス作成
- IDispatchへキャスト
- メソッド名からDISPIDを取得
- パラメータの設定
- メソッドの呼び出し
- 終了処理
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// cl callCOM.c ole32.lib oleaut32.lib | |
#include <Objbase.h> | |
int main() { | |
HRESULT hr; | |
CLSID clsid; | |
DISPID dispid; | |
VARIANTARG rgvArg[2]; | |
int result = 0; | |
DISPPARAMS dispParams = {NULL, NULL, 0, 0}; | |
VARIANT varResult; | |
EXCEPINFO excepInfo; | |
UINT uArgErr; | |
OLECHAR *lpszProgID = L"NamespaceSample.ClassSample"; | |
OLECHAR *rgszNames = {L"MethodSample"}; | |
IUnknown *pUnknown = NULL; | |
IDispatch *pDispatch = NULL; | |
// 1. 初期化 | |
hr = CoInitialize(NULL); | |
if (FAILED(hr)) { | |
return -10; | |
} | |
// 2. クラス名からCLSIDを取得 | |
hr = CLSIDFromProgID(lpszProgID, &clsid); | |
if (FAILED(hr)) { | |
CoUninitialize(); | |
return -20; | |
} | |
// 3. インスタンス作成 | |
hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnknown); | |
if (FAILED(hr)) { | |
CoUninitialize(); | |
return -30; | |
} | |
// 4. IDispatchへキャスト | |
hr = pUnknown->lpVtbl->QueryInterface(pUnknown, &IID_IDispatch, (void **)&pDispatch); | |
if (FAILED(hr)) { | |
pUnknown->lpVtbl->Release(pUnknown); | |
CoUninitialize(); | |
return -40; | |
} | |
// 5. メソッド名からDISPIDを取得 | |
hr = pDispatch->lpVtbl->GetIDsOfNames(pDispatch, &IID_NULL, &rgszNames, 1, LOCALE_SYSTEM_DEFAULT, &dispid); | |
if (FAILED(hr)) { | |
pUnknown->lpVtbl->Release(pUnknown); | |
CoUninitialize(); | |
return -50; | |
} | |
// 6. パラメータの設定 | |
VariantInit(&rgvArg[0]); | |
rgvArg[0].vt = VT_I4; | |
rgvArg[0].lVal = 99; | |
VariantInit(&rgvArg[1]); | |
rgvArg[1].vt = VT_BSTR; | |
rgvArg[1].bstrVal = SysAllocString(L"HOGE"); | |
dispParams.rgvarg = rgvArg; | |
dispParams.cArgs = 2; | |
VariantInit(&varResult); | |
// 7. メソッドの呼び出し | |
hr = pDispatch->lpVtbl->Invoke(pDispatch, dispid, &IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispParams, &varResult, &excepInfo, &uArgErr); | |
if (FAILED(hr)) { | |
pUnknown->lpVtbl->Release(pUnknown); | |
CoUninitialize(); | |
return -60; | |
} | |
// 8. 終了処理 | |
printf("%S\n", varResult.bstrVal); | |
pUnknown->lpVtbl->Release(pUnknown); | |
CoUninitialize(); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// csc /target:library ClassSample.cs | |
// regasm /codebase ClassSample.dll | |
// regasm /u ClassSample.dll | |
namespace NamespaceSample { | |
using System.Runtime.InteropServices; | |
// ComVisibleAttributeをCOM経由で呼び出したいクラスへ設定する | |
[ComVisible(true)] | |
public class ClassSample { | |
public string MethodSample(string arg1, int arg2) { | |
return string.Format("arg1={0} arg2={1}", arg1, arg2); | |
} | |
} | |
} |