2012-02-18 4 views
1

私はC#からいくつかのC++メソッドを呼び出す小さな相互運用アプリケーションを試しています。私はメソッドを呼び出して整数を返すための非常に基本的な例を用意しています。これはうまくいきます。C++配列をC#に返す

InteropApp.h

#ifdef DLLFUNCTIONEXPOSETEST_EXPORTS 
#define DLLFUNCTIONEXPOSETEST_API __declspec(dllexport) 
#else 
#define DLLFUNCTIONEXPOSETEST_API __declspec(dllimport) 
#endif 

extern "C" DLLFUNCTIONEXPOSETEST_API int fnSumofTwoDigits(int a, int b); 

InteropApp.cpp

#include "stdafx.h" 
#include "DLLFunctionExposeTest.h" 
BOOL APIENTRY DllMain(HMODULE hModule, 
         DWORD ul_reason_for_call, 
         LPVOID lpReserved 
        ) 
{ 
    return TRUE; 
} 
DLLFUNCTIONEXPOSETEST_API int fnSumofTwoDigits(int a, int b) 
{ 
    return a + b; 
} 

C#ABでInteropAppTest

static class TestImport 
    { 
     [DllImport("DLLFunctionExposeTest.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "fnSumofTwoDigits")] 
     public static extern int fnSumofTwoDigits(int a, int b); 
    } 
public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      try 
      { 
      InitializeComponent(); 
      int g = TestImport.fnSumofTwoDigits(2, 1); 
     } 
     catch (Exception ex) 
     { 
      MessageBox.Show(ex.ToString()); 
     } 
    } 
} 

C++アプリケーションの場合、stringsの配列を返すメソッドと、integersの配列を返す別のメソッドが必要です。しかし、同じことをするために私が読んだように、これがマーシャルを伴うのであれば混乱しますか?メソッドのプロトタイプはC++とC#の両方のように見えますか? C#アプリケーションでC++配列を返す関数を呼び出すために何が変更されるのでしょうか?

私は何か簡単な例を見つけることができなかったので、上のことのための簡単な例を得ることは素晴らしいことです。

+0

何を試しましたか?どのようなタイプが正確に意味していますか? 'std :: string'(または' char * '?)と' int'ですか?それとも問題じゃない? – svick

+0

@svick:メソッドを返す 'char *'と 'int'配列から始めたいと思います。 – Cipher

答えて

0

このための推奨方法は、(暗黙P/tecniqueを起動呼ばれる)の中間C++/CLIのプロジェクトを使用しています。 stlコンテナや複雑なクラスの使用を含む何らかのものに対して明示的なP/Invoke(DllImport)を行うことは、イライラすることも、不可能なこともあります。さらに、安全ではないタイプです:マーシャリングを行うために正しいシグネチャを推測しなければならず、しばしば複数の可能性があり、これが混乱する可能性があります。 C++(stl)とCLRの文字列の内部表現は単純に一致しないので、それらを変換する必要があります。このレンダリングと明示的なP/Invokeマーシャリングは苦労します。

推奨される方法は次のとおりです。私はコードをコンパイルしていないので、いくつかの小さなエラーがあるかもしれないことに注意してくださいが、私はあなたがそれがこのように行われることを保証することができます。

みましょうあなたはDLLのネイティブプロジェクト(ヘッダUtils.h)でこれを持っていると言う:

DLLFUNCTIONEXPOSETEST_API std::vector<std::string> GetStrings(); 

それはそれらの文字列が内部のC++のSTLでエンコードされているかを知ることが重要であることに注意してください::文字列(のためにたとえば、UTF-8あなたはクールされている場合):

今、あなたは、CRL C++プロジェクト(UtilsW.h/UtilsW.cppのペア)を作成します。

#include <Utils.h> 

using namespace std; 
using namespace System; 
using namespace System::Text; 
using namespace System::Collections::Generics; 

namespace Interop 
{ 
    public ref class Utils 
    { 
    public: 
     static List<String ^>^GetStrings() 
     { 
      List<String ^> ^ret = gcnew List<String ^>(); 
      vector<string> strings = ::GetStrings(); 
      vector<string>::iterator begin = strings.begin(); 
      vector<string>::iterator end = strings.end(); 
      for (; it != end; it++) 
       ret.Add(gcnew String((*it).c_str(), 0, (*it).lenght(), Encoding::UTF-8); 
      return ret; 
     } 
    }; 
} 

今、あなたは、C#で例えば.NETプロジェクトを作成します:

using Interop; 

namespace NET 
{ 
    public class Program 
    { 
     void foo() 
     { 
      List<string> strings = Utils.GetStrings(); 
      // Do something with strings 
     } 
    } 
} 
+0

彼は実際には "stlコンテナや複雑なクラス"は必要ないと思われますので、PInvokeはおそらく簡単な方法です。 – svick

0

C++ dllで配列を割り当てる必要がない場合は、関数に空の整数配列を渡してそこに入力させることができます。これは、デフォルトマーシャリングで機能します。

ただし、このクラスがわからないため、std :: stringをC#にマーシャリングすることはできません。文字列をCの文字列、好ましくはwchar_t *として渡す必要があります。

参照:http://msdn.microsoft.com/en-us/library/bd99e6zt.aspx