2

C# 文字列の配列を C コードに渡す必要があります

C コードの例

void print_string_array(const char** str_array, int length){
    for (int i = 0; i < length; ++i) {
        printf("Sting[%l] = %s\n", i, str_array[i]);
    }
}

私が試したC#(これはうまくいきませんでした)

string foo[] = {"testing", "one", "two", "three"};  
print_string_array(foo, foo.Length);

[DllImport(my_C_dll, CharSet = CharSet.Ansi)]
private static extern void print_string_array([In][MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr)] string[] sa, int length);

System.AccessViolationException で失敗 System.AccessViolationException : 保護されたメモリの読み取りまたは書き込みを試みました。これは多くの場合、他のメモリが破損していることを示しています。

私も試しました(これもうまくいきませんでした)

string[] foo = {"testing", "one", "two", "three"};  
IntPtr[] s_array = new IntPtr[foo.Length];

for(int i = 0; i < foo.Length; ++i) 
{
    s_array[i] = Marshal.StringToCoTaskMemAnsi(foo[i])
}
print_string_array( s_array, s_array.Length);

[DllImport(my_C_dll, CharSet = CharSet.Ansi)]
private static extern void print_string_array(IntPtr[] sa, int length);

これも失敗します

System.AccessViolationException
System.AccessViolationException : Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

c# から C に文字列の配列を渡す方法を知っている人はいますか?


更新: David Heffernan からの提案ごとにエラー メッセージを追加しました。私がやろうとしていたことに影響しなかったので、C コードで size_t を int に変更します。それでも同じエラーが発生します。

4

2 に答える 2

7

次のように、C# で関数を簡単に宣言できます。

[DllImport(my_C_dll, CallingConvention=CallingConvention.Cdecl)]
static extern void print_string_array([In] string[] str_array, IntPtr length);

書かれているように、C++ コードはcdecl呼び出し規約を使用しているように見えます。そのため、C# 宣言を一致させる必要がある場合があります。それがあなたが直面している主な問題だと思います。

size_tパラメータに使用する はlength、32 ビット プロセスでは 32 ビット幅、64 ビット プロセスでは 64 ビット幅であることにも注意してください。したがって、正しい C# 型はIntPtr. int個人的には、C++ コードと C# コードの両方にあると宣言します。


最後に一言アドバイス。エラーが発生した場合は、質問にエラー メッセージを含めてください。最初のコードが次のエラーで失敗したと思われます:

PInvoke 関数 'MyApp!MyApp.Program::print_string_array' の呼び出しにより、スタックのバランスが崩れています。

そして、それを質問に含めていれば、それは大きな助けになったでしょう.

于 2012-11-10T19:29:25.167 に答える
1

あなたの 2 回目の試みはかなり近いです。次のことを試してください。

string[] foo = {"testing", "one", "two", "three"};  
IntPtr[] s_array = new IntPtr[foo.Length];

for(int i = 0; i < foo.Length; ++i) 
{
    s_array[i] = Marshal.StringToHGlobalAnsi(foo[i])
}
GCHandle gH = GCHandle.Alloc(s_array, GCHandleType.Pinned);
print_string_array( gH.AddrOfPinnedObject(), s_array.Length);
gH.Free();
for(int i = 0; i < foo.Length; ++i) 
{
    Marshal.FreeHGlobal(s_array[i])
}

[DllImport(my_C_dll, CharSet = CharSet.Ansi)]
private static extern int print_string_array(IntPtr sa, int length);
于 2012-11-10T18:08:04.470 に答える