p/invoke calling C dll from c#

2019-06-14 13:31发布

问题:

this is my C code

extern "C"
{ 
     __declspec(dllexport) void DisplayHelloFromDLL(string a)
   {    
     printf ("%s\n",a)
   }
}

this is my C# code

class HelloWorld
{
    [DllImport("TestLib.dll")]
    public static extern void DisplayHelloFromDLL(string a);

    static void Main ()
    {
        string a = "Hello";
        DisplayHelloFromDLL(a);
    }
}

It built successfully but crash like this:

Debug http://i44.tinypic.com/1qr9sj.jpg

SO,how to use P/invoke to call my own C dll from C#? Please help,thanx in advance.

回答1:

First of all your code is C++ rather than C. Your function receives a parameter of type std::string and the use of std::string means that your code is actually C++.

Now this parameter type is the root of your problem. You cannot create a std::string in .net and instead will need to use a char* to pass the string data. The following code is what you need:

C++

__declspec(dllexport) void DisplayHelloFromDLL(char* a)
{    
    printf("%s\n", a);
}

C#

[DllImport("TestLib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void DisplayHelloFromDLL(string a);

static void Main ()
{
    string a = "Hello";
    DisplayHelloFromDLL(a);
}

The default p/invoke marshalling for a .net string is to pass a char* as an [In] parameter. There is no need for the complexity of IntPtr, StringToHGlobalAnsi, FreeHGlobal as suggested by one of the other answers. If you can let the p/invoke marshaller do the work then it is preferable to do so.

Note that you also need to make sure that your calling conventions match. Under the assumption that you have not used any special compiler options when building your C++ code, that code will default to used cdecl calling convention. You can make that match with the CallingConvention parameter to the DllImport attribute.



回答2:

Please take a look at marshalling string at MSDN

In a nut shell, a C# string doesn't get marshalled as std::string but a char* by default



回答3:

For one thing the return type is not matching. In C it is void and in C# int.



回答4:

Change your C++ param type to char* and update your C# code as following

class HelloWorld
{
  [DllImport("TestLib.dll")]
  public static extern void DisplayHelloFromDLL(IntPtr a);

  static void Main ()
  {
    string a = "Hello";
    var ptr = System.Runtime.Marshal.StringToHGlobalAnsi(a);
    DisplayHelloFromDLL(ptr);
    System.Runtime.Marshal.FreeHGlobal(ptr);
  }
}


标签: c# c dll pinvoke