2012-03-29 8 views
5

私はcppプロジェクト、cpp cliプロジェクト、c#winフォームプロジェクトを持っています。私は自分のネイティブのcppコードからメソッドを起動し、C#プロジェクトでそれをキャッチしたい。これどうやってするの?Cpp/Cliイベントを起動する

+0

これは相互運用性の問題ですので、このようにタグ付けすることをお勧めします。[ここ](http://msdn.microsoft.com/en-us/library/2x8kf7zx(v = vs80).aspx)forピンボケの情報 – ldgorman

答えて

7

これらのプロジェクト間の依存関係の要件が重要なので、この質問には複数のアプローチがあります。私は、あなたが既にネイティブのC++ライブラリを持っていて、そのライブラリをC#アプリケーションで使用したいという、最も一般的な(私は推測の)ケースに答えるように試みます。このシナリオでは、C#プロジェクトはネイティブライブラリプロジェクトに依存します。このような場合、ゲートウェイcli/C++ライブラリを使用して、ネイティブC++イベントを.NETイベントに変換できます。

ここでは、完全なコードサンプルですが、その前に、注意してください。

  • をそれは最短の解決策ではないかもしれないが、それは正常に動作します。また、ネイティブデータを.net型に変換する際に、より多くの制御を提供することができます。
  • 私はVS 2005でこのアプローチを使用しました。その特定の相互運用性の目的のために、新しいバージョンのVSに優れた手段があるかどうかはわかりません。
  • ネイティブイベントがGUIスレッド以外のスレッドからトリガーされる場合は、thatに注意してください。


ネイティブライブラリ:

#ifndef _NATIVE_CODE_H_ 
#define _NATIVE_CODE_H_ 

//NativeCode.h 
//A simple native library which emits only one event. 

#include <stdlib.h> 
#include <iostream> 
using namespace std; 

#define NATIVELIBRARY_API __declspec(dllexport) 

//An argument class to wrap event parameters 
class NativeEventArgs{ 
public: 
    //a 32bit integer argument 
    //any other primitives can be here, just be careful about the byte size 
    int argInt32; 

    //null terminated ascii string 
    const char* argString; 

    //null terminated wide/unicode string 
    const wchar_t* argWString; 
}; 

//A simple mechanism to fire an event from native code. 
//Your library may have a DIFFERENT triggering mechanism (e.g. function pointers) 
class INativeListener 
{ 
public: 
    virtual void OnEvent(const NativeEventArgs& args)=0; 
}; 

//The actual native library code, source of native events 
class NATIVELIBRARY_API NativeCode 
{ 
public: 
    NativeCode() 
     :theListener_(NULL) 
    {} 

    //Listener registration method 
    void registerListener(INativeListener* listener) { 
     theListener_ = listener; 
    } 

    //this is the very first source of the event 
    //native code emits the event via the listener mechanism 
    void eventSourceMethod() { 
     //... other stuff 

     //fire the native event to be catched 
     if(theListener_){ 
      //prepare event parameters 
      NativeEventArgs args; 
      wstring wstr(L"A wide string"); 
      string str("A regular string"); 

      //build-up the argument object 
      args.argInt32 = 15; 
      args.argString = str.c_str(); 
      args.argWString = wstr.c_str(); 

      //fire the event using argument 
      theListener_->OnEvent(args); 
     } 
    } 

private: 

    //native code uses a listener object to emit events 
    INativeListener* theListener_; 
}; 

#endif 


ゲートウェイライブラリサンプル:

//GatewayCode.h 
//GatewayLibrary is the tricky part, 
//Here we listen events from the native library 
//and propagate them to .net/clr world 

#ifndef _GATEWAY_CODE_H_ 
#define _GATEWAY_CODE_H_ 

#include "../NativeLibrary/NativeCode.h" //include native library 
#include <vcclr.h> //required for gcroot 
using namespace System; 
using namespace System::Runtime::InteropServices; 

namespace GatewayLibrary{ 

    //.net equvelant of the argument class 
    public ref class DotNetEventArg{ 
    internal: 

     //contructor takes native version of argument to transform 
     DotNetEventArg(const NativeEventArgs& args) { 

      //assign primitives naturally 
      argInt32 = args.argInt32; 

      //convert wide string to CLR string 
      argWString = Marshal::PtrToStringUni(IntPtr((void*)args.argWString)); 

      //convert 8-bit native string to CLR string 
      argString = Marshal::PtrToStringAnsi(IntPtr((void*)args.argString)); 

      //see Marshal class for rich set of conversion methods (e.g. buffers) 
     } 
    private: 
     String^ argString; 
     String^ argWString; 
     Int32 argInt32; 

    public: 
     //define properties 
     property String^ ArgString { 
      String^ get() { 
       return argString; 
      } 
     } 

     property String^ ArgWString { 
      String^ get() { 
       return argWString; 
      } 
     } 

     property Int32 ArgInt32 { 
      Int32 get() { 
       return argInt32; 
      } 
     } 
    }; 

    //EventGateway fires .net event when a native event happens. 
    //It is the actual gateway class between Native C++ and .NET world. 
    //In other words, It RECEIVES NATIVE events, TRANSFORMS/SENDS them into CLR. 
    public ref class EventGateway { 
    public: 

     //ctor, its implementation placed below 
     EventGateway(); 

     //required to clean native objects 
     ~EventGateway(); 
     !EventGateway(); 

     //the SENDER part 
     //.net event stuff defined here 
     delegate void DotNetEventHandler(DotNetEventArg^ arg); 
     event DotNetEventHandler^ OnEvent; 

    private: 
     //our native library code 
     //notice you can have pointers to native objects in ref classes. 
     NativeCode* nativeCode_; 

     //the required device to listen events from the native library 
     INativeListener* nativeListener_; 

    internal: //hide from .net assembly 

     //the RECEIVER part, called when a native event received 
     void OnNativeEvent(const NativeEventArgs& args){ 
      //you can make necessary transformation between native types and .net types 

      //create .net argument using native argument 
      //required conversion is done by DotNetEventArg class 
      DotNetEventArg^ dotNetArgs = gcnew DotNetEventArg(args); 

      //fire .net event 
      OnEvent(dotNetArgs); 
     } 

    }; 
} 

//A concrete listener class. we need this class to register native library events. 
//Its our second gateway class which connects Native C++ and CLI/C++ 
//It basically gets events from NativeLibary and sends them to EventGateway 
class NativeListenerImp : public INativeListener { 
public: 
    NativeListenerImp(gcroot<GatewayLibrary::EventGateway^> gatewayObj){ 
     dotNetGateway_ = gatewayObj; 
    } 

    //this is the first place we know that a native event has happened 
    virtual void OnEvent(const NativeEventArgs& args) { 

     //inform the .net gateway which is responsible of transforming native event to .net event 
     dotNetGateway_->OnNativeEvent(args); 
    } 

private: 
    //class member to trigger .net gateway. 
    //gcroot is required to declare a CLR type as a member of native class. 
    gcroot<GatewayLibrary::EventGateway^> dotNetGateway_; 
}; 

////ctor and dtors of EventGateway class 
GatewayLibrary::EventGateway::EventGateway() 
{ 
    nativeCode_ = new NativeCode(); 

    //note; using 'this' in ctor is not a good practice 
    nativeListener_ = new NativeListenerImp(this); 

    //register native listener 
    nativeCode_->registerListener(nativeListener_); 
} 

GatewayLibrary::EventGateway::~EventGateway() 
{ 
    //call the non-deterministic destructor 
    this->!EventGateway(); 
} 

GatewayLibrary::EventGateway::!EventGateway() 
{ 
    //clean up native objects 
    delete nativeCode_; 
    delete nativeListener_; 
} 

#endif 


そして、C#での最終的なアプリケーション(または他の.NET言語で):

//Program.cs 
//C# the final evet consumer application 

using System; 
using System.Collections.Generic; 
using System.Text; 
using GatewayLibrary; 

namespace SharpClient 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      //create the gateway 
      EventGateway gateway = new EventGateway(); 

      //listen on .net events using the gateway 
      gateway.OnEvent += new EventGateway.DotNetEventHandler(gateway_OnEvent); 

     } 

     static void gateway_OnEvent(DotNetEventArg args) 
     { 
      //use the argument class 
      Console.WriteLine("On Native Event"); 
      Console.WriteLine(args.ArgInt32); 
      Console.WriteLine(args.ArgString); 
      Console.WriteLine(args.ArgWString); 
     } 
    } 
} 
+0

あなたの答えをありがとう。 GatewayListenerImpとは何ですか?ビジュアルスタジオはそれを知らない。 (VS2010) –

+1

OK、私は自分の答えを編集しました。それは 'NativeListenerImp'でなければなりません。私は書式設定中に間違いを犯したようです。 – xaero99

+0

ありがとうございました。それは働いています –

関連する問題