【问题标题】:Dllimport passing string from C# to C++Dllimport 将字符串从 C# 传递到 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* 吗?

【问题讨论】:

    标签: c# c++ string dllimport


    【解决方案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 将被销毁。这个答案很糟糕。
      猜你喜欢
      • 2012-06-03
      • 1970-01-01
      • 2012-02-12
      • 1970-01-01
      • 2015-12-23
      • 2018-07-18
      • 2014-02-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多