Return 从 c# 调用的 c++ dll 导出函数中的字符串
Return string from c++ dll export function called from c#
我正在尝试 return 来自 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 创建这个
已编辑------------------------
是否有类似的东西,我可以从 C# 向 C++ 传递一个空缓冲区,C++ 函数将填充数据,我可以在 C# 中重用它
我最近也遇到了这个问题,虽然我有一个解决方案给你,遗憾的是我无法真正解释它。我还没有找到合理的解释。
我用于检索字符串的 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();
}
.NET 运行时使用 unicode (wchar_t) 字符串,而不是 ascii (char),因此这需要一些更改。
您还应该考虑到 .NET 无法释放已由 C/C++ 应用程序分配的字符串,因此预先分配缓冲区并从 C# 传入是唯一安全的管理方式,无需内存泄漏或更糟。
这个怎么样(注意,它假设长度正确 - 你应该传入缓冲区长度并防止溢出等):
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。
在 windows 上,您可以 return 直接使用 BSTR
字符串(来自 wtypes.h
包含在 windows.h
中)。 BSTR
可以通过SysAllocString
函数从标准宽字符串创建:
_declspec(dllexport) BSTR getDataFromTable(const char* tableName)
{
return SysAllocString(L"String to return");
}
然后在 C# 中将 return 类型编组为 BStr
:
[DllImport("\SD Card\ISAPI1.dll", CallingConvention = CallingConvention.Cdecl )]
[return: MarshalAs(UnmanagedType.BStr)]
static extern string getDataFromTable(string tableName);
这很有效:)
_strdup
在内存中创建字符串的副本,只能使用 delete
.
销毁
https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/strdup-wcsdup-mbsdup?view=msvc-170
const char* returnStringFunc()
{
return _strdup("String to Return");
}
我正在尝试 return 来自 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 创建这个
已编辑------------------------
是否有类似的东西,我可以从 C# 向 C++ 传递一个空缓冲区,C++ 函数将填充数据,我可以在 C# 中重用它
我最近也遇到了这个问题,虽然我有一个解决方案给你,遗憾的是我无法真正解释它。我还没有找到合理的解释。
我用于检索字符串的 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();
}
.NET 运行时使用 unicode (wchar_t) 字符串,而不是 ascii (char),因此这需要一些更改。 您还应该考虑到 .NET 无法释放已由 C/C++ 应用程序分配的字符串,因此预先分配缓冲区并从 C# 传入是唯一安全的管理方式,无需内存泄漏或更糟。
这个怎么样(注意,它假设长度正确 - 你应该传入缓冲区长度并防止溢出等):
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。
在 windows 上,您可以 return 直接使用 BSTR
字符串(来自 wtypes.h
包含在 windows.h
中)。 BSTR
可以通过SysAllocString
函数从标准宽字符串创建:
_declspec(dllexport) BSTR getDataFromTable(const char* tableName)
{
return SysAllocString(L"String to return");
}
然后在 C# 中将 return 类型编组为 BStr
:
[DllImport("\SD Card\ISAPI1.dll", CallingConvention = CallingConvention.Cdecl )]
[return: MarshalAs(UnmanagedType.BStr)]
static extern string getDataFromTable(string tableName);
这很有效:)
_strdup
在内存中创建字符串的副本,只能使用 delete
.
https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/strdup-wcsdup-mbsdup?view=msvc-170
const char* returnStringFunc()
{
return _strdup("String to Return");
}