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

Dllimport passing string from C# to C++

本文关键字:C++ 字符串 Dllimport      更新时间:2023-10-16

我正在尝试使用平台调用将字符串从 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*吗?

Сorrect decision

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-。

在不导致内存泄漏的情况下执行此操作的一种方法是使用回调。

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

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

我建议使用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();
}

大功告成!