初めて自分の家と他人の家が違う、と意識した時

教えてください!
C++のアンマネージドDLLから、複数のファイル名(文字列)をC#に渡したいです。

ステップとしては、
C#から、C++のDLLの関数を最初に呼んで、コールバック関数を渡しています。
次に、DLLからコールバック関数を呼ぶ時に、複数のファイル名を渡したいです。

以下のコードを動かすと、、
C++からは2つ渡しているつもりなのに、
C#ではfilesがサイズ1のString配列として引数に入ってきます。

なぜでしょう?
またどうすればC#から複数受け取れるでしょうか?
教えてください!

C#
public delegate int StringArrayCallback(String[] files);

// C# -> C++
public static int start() {

StringArrayCallback cb = new StringArrayCallback(onReceivedFiles);
int ret = start(cb);
return ret;
}

// C++ -> C# callback
public static int onReceivedFiles(String[] files)
{
return 1;
}

C++コード
typedef int (__stdcall *OnReceivedFilesProc )(char**);
int start( OnReceivedFilesProc callback ) {
std::string message1_ = "from C++1";
std::string message2_ = "from C++2";
char* messages_[2] = { (char*)message1_.c_str(), (char*)message2_.c_str() };
int ret_ = callback(messages_);
std::cout << "[from c#]" << ret_;
}

A 回答 (2件)

もうひとつの手段としてはやはりデリゲートの定義などを変更せざるを得ないのですがマーシャリング手段を指示しましょう



public delegate int StringArrayCallback2([MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr, SizeParamIndex = 1)] string[] files, int n);
とします nには配列の個数が返されます
と定義します

ArraySubType = UnmanagedType.LPStrはDLL側の文字セットにあわせましょう
Unicodeならば ArraySubType = UnmanagedType.LPWStr とします

コールバック関数の定義を
public static int onReceivedFiles2(string[] files, int n)
{
  return 1;
}
といった具合にしてやれば 引数files配列は要素n個として認識されます

下記参考URLなども熟読してましょう

参考URL:http://msdn.microsoft.com/ja-jp/library/z6cfh6e6 …
    • good
    • 0

この方法だと無理がありそうです



C++側からは messages_ ポインタと strngをいくつ返したかの int型をを渡す方が良いでしょう
アンマネージのC++側ではマネージコード側の配列をいくつに設定したのかを制御していません

typedef int (__stdcall *OnReceivedFilesProc )(char**, int);
で宣言
int ret_ = callback(messages_, sizeof(message_)/sizeof(message_[0]));
としてコールバックを呼び出す

デリゲートは
public delegate int StringArrayCallback(IntPtr ptr, int nVal);
と宣言

コールバック関数を
public static int onReceivedFiles(IntPtr ptr, int nVal)
{
  IntPtr pptr;
  string[] files = new string[nVal];
  for( int n = 0; n < nval; n++ ) {
    // スタックに積まれて来るのはポインタのみなので
    pptr = Marshal.ReadIntPtr( ptr, n * 4 );
    files[n] = Marshal.PtrToStringAuto( pptr );
  }
  return 1;
}
といった具合にすればよさそうです
    • good
    • 0
この回答へのお礼

ありがとうございます。まさにおっしゃるとおりのやり方でできました!

お礼日時:2008/11/03 15:30

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています


おすすめ情報