前回:COM講座第1回
C++からC#のクラスを呼び出したいと思います
C#側で使える.Netの膨大なライブラリと簡単に作成できるGUIモジュールを
C++側で使う場合等に有効な手段だと思います
開発環境は
Visual C++ 2010 Express
Visual C# 2010 Express
です
MFCやATLは使いません
(VC++の有償版でないと使えないうえに、利用すると中身が不透明になりがちなので・・・)
サンプル:
VC#側
・Component.zip
VC++側
・ComTest.zip
手順としては
1.C#のクラスを、COMコンポーネント化します。
2.COMコンポーネントを登録します
3.C++側からCOMコンポーネントをインスタンス化し、クラスのメソッドを呼び出します
クラスライブラリでプロジェクトを作成します
以下のコードに変更します
using System; using System.Runtime.InteropServices; namespace Component { public interface IVector3 { void SetVector3(float x, float y, float z); void GetVector3(out float x, out float y, out float z); } [ClassInterface(ClassInterfaceType.None)] public class Vector3 : IVector3 { public float x, y, z; public Vector3() { } public Vector3(float x, float y, float z) { this.x = x; this.y = y; this.z = z; } public void SetVector3(float x, float y, float z) { this.x = x; this.y = y; this.z = z; } public void GetVector3(out float x, out float y, out float z) { x = this.x; y = this.y; z = this.z; } } public interface ITestCom { int Add(int a, int b); Vector3 AddVec(Vector3 a, Vector3 b); } [ClassInterface(ClassInterfaceType.None)] public class TestCom : ITestCom { public int Add(int a, int b) { return a + b; } public Vector3 AddVec(Vector3 a, Vector3 b) { return new Vector3(a.x + b.x, a.y + b.y, a.z + b.z); } } }
プロジェクトのプロパティを開きます
まず、アセンブリ情報を開きます
アセンブリをCOM参照可にチェックを入れて、OKを押して閉じます
次にビルドのタブ欄の下にある
COM相互運用機能の登録の欄にチェックをいれます
ビルドをしてください。
ビルド時につぎのようなエラーが出た場合は管理者権限でVC#を起動してないので
管理者権限で起動してからビルドしてください
ビルドするとCOMコンポーネントが登録され
DLLとタイプライブラリファイル(拡張子.tlb)がReleaseフォルダ以下に作成されます
ここからはVC++でのCOMコンポーネントの利用になります
まず、VC++を起動し、コンソールアプリケーションで適当なプロジェクトを作成します
(COMコンポーネントを利用するVC++側は管理者権限で起動する必要はありません)
タイプライブラリファイルが必要になるのでこれをプロジェクトフォルダにコピーします
main.cppに以下のコードを書きます
#include <tchar.h> #include <Windows.h> #include <Objbase.h> // インポート #import "Component.tlb" no_namespace named_guids raw_interfaces_only // メイン処理 int main(int argc, char* argv[]) { IVector3 *a,*b,*c; ITestCom* pTestCom; // COMインターフェイスポインタ // COMの初期化 ::CoInitialize(NULL); // インスタンスの作成(CLSIDとIIDを指定して、インスタンスを取得) CoCreateInstance((REFCLSID) CLSID_TestCom, 0, CLSCTX_ALL, (REFIID) IID_ITestCom, (LPVOID*)&pTestCom); // インスタンスの作成(CLSIDとIIDを指定して、インスタンスを取得) CoCreateInstance((REFCLSID) CLSID_Vector3, 0, CLSCTX_ALL, (REFIID) IID_IVector3, (LPVOID*)&a); // インスタンスの作成(CLSIDとIIDを指定して、インスタンスを取得) CoCreateInstance((REFCLSID) CLSID_Vector3, 0, CLSCTX_ALL, (REFIID) IID_IVector3, (LPVOID*)&b); // インスタンスの作成(CLSIDとIIDを指定して、インスタンスを取得) CoCreateInstance((REFCLSID) CLSID_Vector3, 0, CLSCTX_ALL, (REFIID) IID_IVector3, (LPVOID*)&c); long out; pTestCom->Add(10,15,&out); printf("%d\n",out); a->SetVector3(1.0f,2.0f,3.0f); b->SetVector3(3.0f,4.0f,5.0f); pTestCom->AddVec(a,b,&c); float x,y,z; c->GetVector3(&x,&y,&z); printf("%f,%f,%f\n",x,y,z); c->Release(); b->Release(); a->Release(); pTestCom->Release(); // COMの終了処理 ::CoUninitialize(); return 0; }
実行結果は次のようになります
ちゃんとCOMコンポーネント化したC#のクラスがC++側から呼べています