的傳統方式來做到這一點是:
__declspec(dllexport) void get_string(int size, char *buffer)
{
std::string str = getString();
strncpy(buffer, str.c_str(), size);
buffer[size - 1] = '\0';
}
C#的一面:
[DllImport("NativeLibrary", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern void get_string(int len, [Out] StringBuilder sb);
,然後(很重要!你必須預先尺寸StringBuilder
)
var sb = new StringBuilder(100);
get_string(sb.Capacity, sb);
string str = sb.ToString();
可以使用char[]
,但它更復雜,因爲那時你必須手動「修剪」\0
。
還有一種更復雜的方式與內存少了一個副本,做...但它更是一個有點複雜:
C++方面:
__declspec(dllexport) void get_string(void (*func)(const char*))
{
std::string str = getString();
func(str.c_str());
}
C#的一面:
[DllImport("NativeLibrary", CallingConvention = CallingConvention.Cdecl)]
public static extern void get_string(StringFromIntPtr.FromIntPtrDelegate func);
public class StringFromIntPtr
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void FromIntPtrDelegate(IntPtr ptr);
public string Value { get; protected set; }
public void FromIntPtr(IntPtr ptr)
{
Value = Marshal.PtrToStringAnsi(ptr);
}
}
然後你使用這樣的:
var sfip = new StringFromIntPtr();
get_string(sfip.FromIntPtr);
string str = sfip.Value;
關鍵是你將一個代理傳遞給C#方法,知道如何處理一個字符串的原始指針(例如通過使用Marshal.PtrToStringAnsi
),並且C++代碼使用它。請注意,在C++/CLI中執行此操作會更容易(因爲您不需要委託,C++/CLI可以同時使用std::string
和System.String^
)
我認爲返回'std: :string' - 除非您使用manage C++,否則C#CLR只能處理基元。我會選擇後者(將'char *'傳遞給C++實現) – NirMH
正如你寫的那樣...只要記住'strncpy'不能保證添加終止'\ 0',所以你應該手動添加它。 – xanatos
@xanatos:非常感謝您的幫助!我該如何在C#中聲明緩衝區?字節[]還是我使用StringBuilder? – Andy