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");
}