我正在尝试从c ++ dll导出函数返回一个字符串。我从c#调用这个函数。我在互联网上看到了很多例子,我真的很困惑该怎么做。
我的导出函数的c ++代码:
extern "C" __declspec(dllexport) char* __cdecl getDataFromTable(char* tableName)
{
std::string st = getDataTableWise(statementObject, columnIndex);
printf(st.c_str());
char *cstr = new char[st.length() + 1];
strcpy(cstr, st.c_str());
return cstr;
}
当我尝试从c#调用此函数时:
[DllImport("\\SD Card\\ISAPI1.dll")]
private static extern string getDataFromTable(byte[] tablename);
static void Main(string[] args)
{
string str = getDataFromTable(byteArray);
Console.writeLine(str);
}
我在调用它时遇到错误。我正在为WinCE 6.0创建这个
EDITED ------------------------
有类似的东西,我可以从c#传递空缓冲区到c ++,c ++函数将填充数据,我可以在C#中重用它#
答案 0 :(得分:4)
我最近也遇到过这个问题,虽然我有一个解决方案,但遗憾的是我无法解释它。我还没有找到合理的解释。
我检索字符串的c ++代码是:
extern "C" { __declspec(dllexport) void __GetValue__(char* str, int strlen); }
和我的C#代码:
[DllImport("MyDLL.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void __GetValue__(StringBuilder str, int strlen);
正如您所看到的,您可以提供一个字符串(通过使用StringBuilder)而不是返回值,并让C ++填写如下数据:
void __GetValue__(char* str, int strlen) {
std::string result = "Result";
result = result.substr(0, strlen);
std::copy(result.begin(), result.end(), str);
str[std::min(strlen-1, (int)result.size())] = 0;
}
为了完整性,请求字符串的C#代码:
public String GetValue() {
StringBuilder str = new StringBuilder(STRING_MAX_LENGTH);
__GetValue__(str, STRING_MAX_LENGTH);
return str.ToString();
}
答案 1 :(得分:4)
这个怎么样(注意,它假设正确的长度 - 你应该传递缓冲区长度并防止溢出等):
extern "C" __declspec(dllexport) void __cdecl getDataFromTable(char* tableName, char* buf)
{
std::string st = getDataTableWise(statementObject, columnIndex);
printf(st.c_str());
strcpy(buf, st.c_str());
}
然后在C#中:
[DllImport("\\SD Card\\ISAPI1.dll")]
private static extern string getDataFromTable(byte[] tablename, byte[] buf);
static void Main(string[] args)
{
byte[] buf = new byte[300];
getDataFromTable(byteArray, buf);
Console.writeLine(System.Text.Encoding.ASCII.GetString(buf));
}
注意,这确实会对您的C ++应用中的字符编码做出一些假设,而不是unicode。如果它们是unicode,请使用UTF16而不是ASCII。
答案 2 :(得分:2)
.NET运行时使用unicode(wchar_t)字符串,而不是ascii(char),因此需要进行一些更改。 您还应该考虑.NET无法释放已由C / C ++应用程序分配的字符串,因此预先分配缓冲区并从C#传入的缓冲区是唯一安全的方法来管理它而不会出现内存泄漏或更糟糕的情况
答案 3 :(得分:1)
在 Windows 上,您可以使用 BSTR
直接返回字符串(来自 wtypes.h
包含的 windows.h
)。 BSTR
可以通过SysAllocString
函数从标准宽字符串创建:
_declspec(dllexport) BSTR getDataFromTable(const char* tableName)
{
return SysAllocString(L"String to return");
}
然后在 C# 中将返回类型编组为 BStr
:
[DllImport("\\SD Card\\ISAPI1.dll", CallingConvention = CallingConvention.Cdecl )]
[return: MarshalAs(UnmanagedType.BStr)]
static extern string getDataFromTable(string tableName);