前回:COM講座第1回

C++からC#のクラスを呼び出したいと思います
C#側で使える.Netの膨大なライブラリと簡単に作成できるGUIモジュールを
C++側で使う場合等に有効な手段だと思います

開発環境は
Visual C++ 2010 Express
Visual C# 2010 Express
です

MFCやATLは使いません
(VC++の有償版でないと使えないうえに、利用すると中身が不透明になりがちなので・・・)

サンプル:
VC#側 fileComponent.zip
VC++側 fileComTest.zip

手順としては
1.C#のクラスを、COMコンポーネント化します。
2.COMコンポーネントを登録します
3.C++側からCOMコンポーネントをインスタンス化し、クラスのメソッドを呼び出します

まず、管理者権限でVC#を起動します
uac.jpg

クラスライブラリでプロジェクトを作成します

vcsproj.jpg

以下のコードに変更します

   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)]
       [ProgId("Component.Vector3")]
       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)]
       [ProgId("Component.TestCom")]
       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);
           }
       }
   }

System.Runtime.InteropServices名前空間を省略します
参照設定は不要です

公開するクラスはインタフェースを継承し
[ClassInterface(ClassInterfaceType.None)]
を先頭に付けます

さらにProgIDの指定をします
[ProgId("Component.TestCom")]
これは実はしなくても自動的に割り振られて
C++側からは呼び出しのときには使わないのですが
第4回で説明するWSHからの呼び出しの時に使います

プロジェクトのプロパティを開きます
まず、アセンブリ情報を開きます

vcsprop.jpg

アセンブリをCOM参照可にチェックを入れて、OKを押して閉じます

asm.jpg

次にビルドのタブ欄の下にある
COM相互運用機能の登録の欄にチェックをいれます

comreg.jpg

ビルドをしてください。

ビルド時につぎのようなエラーが出た場合は管理者権限でVC#を起動してないので
管理者権限で起動してからビルドしてください

error.jpg

ビルドするとCOMコンポーネントが登録され
DLLとタイプライブラリファイル(拡張子.tlb)がReleaseフォルダ以下に作成されます
tlb.jpg


ここからはVC++でのCOMコンポーネントの利用になります
まず、VC++を起動し、コンソールアプリケーションで適当なプロジェクトを作成します
(COMコンポーネントを利用するVC++側は管理者権限で起動する必要はありません)
タイプライブラリファイルが必要になるのでこれをプロジェクトフォルダにコピーします

copytlb.jpg

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;
	}

まず、タイプライブラリをインポートします

// インポート
#import "Component.tlb" no_namespace named_guids raw_interfaces_only

COMを使用するにはCoInitialize関数で準備して
使い終わったらCoUnInitialize関数で終了処理をします

// COMの初期化
CoInitialize(NULL);
// COMの終了処理
CoUninitialize();

インスタンスを生成するにはCoCreateInstance関数を使います
クラスIDとインタフェースID
CLSID_** (**はクラス名)
IID_** (**はインタフェース名)
を指定することでそのクラスのインスタンスを生成でき、
インタフェースを中継して、そのクラスのメソッドを呼ぶことができます
インスタンスを使い終わったらRelease関数でメモリを破棄しなければなりません

実行結果は次のようになります

result.jpg

ちゃんとCOMコンポーネント化したC#のクラスがC++側から呼べています

選択肢 投票
合体はロマン 9  
ktkr 0  
Windowsでしか動かないのはMicrosoftの仕様です 3  

添付ファイル: fileComTest.zip 262件 [詳細] fileComponent.zip 266件 [詳細] fileerror.jpg 400件 [詳細] fileresult.jpg 365件 [詳細] filecopytlb.jpg 14件 [詳細] filetlb.jpg 387件 [詳細] filevcsprop.jpg 407件 [詳細] filecomreg.jpg 397件 [詳細] fileuac.jpg 455件 [詳細] fileasm.jpg 452件 [詳細] filevcsproj.jpg 464件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2017-12-26 (火) 13:10:43