Dllimport 将字符串从 C# 传递到 C++

Posted

技术标签:

【中文标题】Dllimport 将字符串从 C# 传递到 C++【英文标题】:Dllimport passing string from C# to C++ 【发布时间】:2012-11-22 14:14:45 【问题描述】:

我正在尝试使用平台调用将字符串从 C# 传递到 C++。

C++ 代码:

#include<string>
using namespace std;

extern "C" 

     double __declspec(dllexport) Add(double a, double b)
     
         return a + b;
     
     string __declspec(dllexport) ToUpper(string s)
     
         string tmp = s;
         for(string::iterator it = tmp.begin();it != tmp.end();it++)
             (*it)-=32;
         return tmp;
     

C#代码:

[DllImport("TestDll.dll", CharSet = CharSet.Ansi, CallingConvention =CallingConvention.Cdecl)]
public static extern string ToUpper(string s); 

static void Main(string[] args)

    string s = "hello";
    Console.WriteLine(Add(a,b));
    Console.WriteLine(ToUpper(s));

我收到一个 SEHException。就不能这样使用std::string吗?我应该改用char* 吗?

【问题讨论】:

【参考方案1】:

正确的决定

C#端:

[DllImport("CppDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr GetString(string s);

public string GetString_(string s)
            
    var ptr = GetString(s);                                
    var answerStr = Marshal.PtrToStringAnsi(ptr);
    return answerStr;

C++ 方面:

extern "C" __declspec(dllexport) const char* GetString(char* s)
       
    string workStr(s);      
    int lenStr = workStr.length() + 1;
    char* answer = new char[lenStr];
    const char * constAnswer = new char[lenStr];
    strcpy(answer, workStr.c_str());
    constAnswer = answer;
    return constAnswer;

并在cpp项目的设置中禁用/sdl-。

【讨论】:

那是内存泄漏,没有人调用delete[]。好吧,比已接受答案中的悬空指针错误略好。【参考方案2】:

一种不引起内存泄漏的方法是使用回调。

C#端:

private delegate bool DLLCallback(IntPtr message);
    
[DllImport(@"YourLibrary.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
private static extern void Receive(DLLCallback callback);
    
private static bool callback(IntPtr ptr)

    string result = Marshal.PtrToStringAnsi(ptr);
        
    Console.WriteLine(result);
    // If the Heap is used               
    // Marshal.FreeHGlobal(ptr);
    return true;

        
private static void Main(string[] args)        
    Receive(callback);

C++ 方面:

extern "C" 
   typedef BOOL(__stdcall* OutputCallback)(const char* str);

   __declspec(dllexport) void Receive(OutputCallback callback)
   
        char buffer[BUFFER_SIZE];
        ZeroMemory(buffer, BUFFER_SIZE);
        BOOL callbackResult = callback(buffer);
   

还有其他选择。这是一篇关于在托管代码和非托管代码之间传递字符串的好文章:article

【讨论】:

【参考方案3】:

我建议使用 char*。这是一个可能的解决方案。

如果你创建另一个C#函数ToUpper_2如下

C#端:

[DllImport("TestDll.dll"), CallingConvention = CallingConvention.Cdecl]
private static extern IntPtr ToUpper(string s);

public static string ToUpper_2(string s) 

    return Marshal.PtrToStringAnsi(ToUpper(string s));

C++ 方面:

#include <algorithm>
#include <string>

extern "C" __declspec(dllexport) const char* ToUpper(char* s) 

    string tmp(s);

    // your code for a string applied to tmp

    return tmp.c_str();

你已经完成了!

【讨论】:

抱歉回复慢,但我将您的代码复制到我的项目中并且有一些奇怪的语法错误?? 它现在可以工作,但调用该函数后字符串仍然保持不变。为什么会发生这种情况? 那是我的错误。它现在可以工作但输出字符串不是我预期的。我认为它应该是原始字符串的大写? 不知道怎么回事,但我得到了这个错误:cannot convert from 'const char (__thiscall std::basic_string<_elem>:: )(void ) throw() const' to 'char *'。顺便说一句,你确定 tmp.c_str(),我使用 VC++ 2012,它给了我语法错误并将其改为 tmp.c_str。 return tmp.c_str(); 将返回垃圾。当ToUpper 在 C++ 中返回时,tmp 将被销毁。这个答案很糟糕。

以上是关于Dllimport 将字符串从 C# 传递到 C++的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 DLLImport 将字符串从 C# 传递到 C++(以及从 C++ 到 C#)?

如何将字符串从 C++ 原生传递到 C# Unity?

将字符串从 c# 编组到 c++

在不同的返回类型上将字符串从 C# 传递到 C++ DLL 不同的文本编码

将字节数组从 Unity C# 传递到 C++ 库方法

从 C# 到 C++ 的调用无法正确传递参数