2009-12-01 3 views
11

私はちょっと錆びていて、実際は私のC++で錆びています。それはしばらくしていたので、大学1年生からそれに触れていない。C#とC++の間にブリッジを形成する管理されたC++

とにかく、私はほとんどの人とは逆のことをしています。 C++からC#コードを呼び出します。私はオンラインでいくつかのリサーチを行っており、ブリッジを形成するために管理されたC++を作成する必要があるようです。 __declspec(dllexport)を使用し、それからdllを作成し、全体をラッパーとして使用します。

しかし、私の問題は - 私は実際に例を見つけるのに苦労しています。私はString.ToUpper()にC#バージョンを使用したいと思っていた基本的なものをいくつか見つけましたが、それは非常に基本的で、小さなコードスニペットでした。

誰かが私が何かもっと具体的なものを探すことができるというアイデアは誰にでもありますか? COMを使用したくないことに注意してください。目標は、C#コードに全く触れないことです。

+0

アンマネージC/C++に公開したいインターフェイスはどれくらい複雑ですか? – CuppM

+0

同様の質問/回答については、このリンクを参照してください:http://stackoverflow.com/questions/13293888/how-to-call-ac-sharp-library-from-native-c-using-c-cli-and-ijw 。 – amalgamate

答えて

11

が、私は念のためにとにかくそれを投稿します...

独自のライブラリにアクセスするためのラッパーを書き込む処理を標準の.Netライブラリの1つにアクセスするのと同じです。

CsharpProjectと呼ばれるプロジェクトでの例C#クラスコード:

using System; 

namespace CsharpProject { 
    public class CsharpClass { 
     public string Name { get; set; } 
     public int Value { get; set; } 

     public string GetDisplayString() { 
      return string.Format("{0}: {1}", this.Name, this.Value); 
     } 
    } 
} 

あなたは、管理C++クラスライブラリプロジェクト(例はCsharpWrapperである)を作成し、それを基準として、あなたのC#プロジェクトを追加します。内部使用と参照プロジェクトで同じヘッダーファイルを使用するには、正しいdeclspecを使用する方法が必要です。これは、プリプロセッサディレクティブ(この場合はCSHARPWRAPPER_EXPORTS)を定義し、#ifdefを使用して、ヘッダーファイルのC/C++インターフェイスでエクスポートマクロを設定することによって実行できます。管理されていないインターフェイスヘッダーファイルには、管理されていないものが含まれている必要があります(または、プリプロセッサによって除外されている必要があります)。

アンマネージドC++インターフェイスヘッダーファイル(CppInterface。h):

#pragma once 

#include <string> 

// Sets the interface function's decoration as export or import 
#ifdef CSHARPWRAPPER_EXPORTS 
#define EXPORT_SPEC __declspec(dllexport) 
#else 
#define EXPORT_SPEC __declspec(dllimport) 
#endif 

// Unmanaged interface functions must use all unmanaged types 
EXPORT_SPEC std::string GetDisplayString(const char * pName, int iValue); 

次に、管理対象ライブラリファイルに含めることができる内部ヘッダーファイルを作成できます。これにより、using namespaceステートメントが追加され、必要なヘルパー関数を含めることができます。

マネージドC++インタフェースヘッダファイル(CsharpInterface.h):

#pragma once 

#include <string> 

// .Net System Namespaces 
using namespace System; 
using namespace System::Runtime::InteropServices; 

// C# Projects 
using namespace CsharpProject; 


////////////////////////////////////////////////// 
// String Conversion Functions 

inline 
String^ToManagedString(const char * pString) { 
return Marshal::PtrToStringAnsi(IntPtr((char *) pString)); 
} 

inline 
const std::string ToStdString(String^strString) { 
IntPtr ptrString = IntPtr::Zero; 
std::string strStdString; 
try { 
    ptrString = Marshal::StringToHGlobalAnsi(strString); 
    strStdString = (char *) ptrString.ToPointer(); 
} 
finally { 
    if (ptrString != IntPtr::Zero) { 
    Marshal::FreeHGlobal(ptrString); 
    } 
} 
return strStdString; 
} 

は、次に、あなただけのラッピングを行い、あなたのインターフェイスのコードを記述します。

マネージドC++インタフェースのソースファイル(CppInterface.cpp):

#include "CppInterface.h" 
#include "CsharpInterface.h" 

std::string GetDisplayString(const char * pName, int iValue) { 
CsharpClass^oCsharpObject = gcnew CsharpClass(); 

oCsharpObject->Name = ToManagedString(pName); 
oCsharpObject->Value = iValue; 

return ToStdString(oCsharpObject->GetDisplayString()); 
} 

は、それからちょうどあなたの管理されていないプロジェクトで管理されていないヘッダ、リンク時に生成されたの.libファイルを使用するようにリンカーに指示して、確認してくださいが含まれます.NetとラッパーのDLLは、アンマネージアプリケーションと同じフォルダにあります。

#include <stdlib.h> 

// Include the wrapper header 
#include "CppInterface.h" 

void main() { 
// Call the unmanaged wrapper function 
std::string strDisplayString = GetDisplayString("Test", 123); 

// Do something with it 
printf("%s\n", strDisplayString.c_str()); 
} 
+0

あなたは事をもう少し説明しました - 私は両方の答えを選択できたらいいですか?ありがとう! –

+0

文字列は、文字列をネイティブからマネージドにマーシャルする必要があるとすぐに変換関数が必要になるため、良い例です。 – Iain

+0

「そのようなファイルやディレクトリはありません。いずれか:1)アンマネージドアプリケーションに 'CppInterface.h'を追加します。すべてのプロジェクトが同じ場所/リポジトリに存在する場合、私はこれをしません。あなたが維持するために重複するファイルを持っているので。 2)アンマネージドアプリケーションのコンパイルインクルードフォルダの下にあるラッパープロジェクトのファイルにパスを追加します。 Visual Studioの場合、プロジェクトを右クリックして[プロパティ]を選択します。次に、 "構成プロパティ" - > "C/C++" - > "一般" - > "追加のインクルードディレクトリ"で、パスを 'CppInterface.h'の場所に追加します。 – CuppM

10

Visual Studioで新しいC++/CLIプロジェクトを作成し、C#dllへの参照を追加します。我々はC#のDLLはこのクラスでDotNetLib.dllと呼ばれていると想定します

namespace DotNetLib 
{ 
    public class Calc 
    { 
     public int Add(int a, int b) 
     { 
      return a + b; 
     } 
    } 
} 

は今、あなたのC++/CLIのプロジェクトへのCLR C++クラスを追加します。

// TestCPlusPlus.h 

#pragma once 

using namespace System; 
using namespace DotNetLib; 

namespace TestCPlusPlus { 

    public ref class ManagedCPlusPlus 
    { 
    public: 
     int Add(int a, int b) 
     { 
      Calc^ c = gcnew Calc(); 
      int result = c->Add(a, b); 
      return result; 
     } 
    }; 
} 

これは、C++からのC#を呼び出します。

今、あなたはCLR C++のクラスに話をすることができ、あなたのC++/CLIのプロジェクトにネイティブのC++クラスを追加することができ、必要に応じて:

// Native.h 
#pragma once 

class Native 
{ 
public: 
    Native(void); 
    int Add(int a, int b); 
    ~Native(void); 
}; 

と:

// Native.cpp 
#include "StdAfx.h" 
#include "Native.h" 
#include "TestCPlusPlus.h" 

Native::Native(void) 
{ 
} 

Native::~Native(void) 
{ 
} 

int Native::Add(int a, int b) 
{ 
    TestCPlusPlus::ManagedCPlusPlus^ c = gcnew TestCPlusPlus::ManagedCPlusPlus(); 
    return c->Add(a, b); 
} 

次のことができるようにすべきです他のネイティブC++ dllからネイティブクラスを呼び出す

また、Managed C++はC++/CLIとは異なり、C++/CLIがこれを上回りました。ウィキペディアは最高のそれを説明する:LAINは、例を書くことに私を打つものの

関連する問題