简体   繁体   English

C DLL在C#中不起作用,但在C ++中起作用

[英]C DLL does NOT Work in C# but Does work in C++

I don`t understand this code below, that it is working with my c++ but it just does not want to work with c#. 我不明白下面的这段代码,它可以与我的c ++一起工作,但是它只是不想与c#一起工作。 Can you please help me to understand what is wrong here and i think i have to say that i am absolutely new to C#. 您能帮我了解这里有什么问题吗,我想我必须说我对C#绝对陌生。

    My_Lib.h 
    extern "C"  __declspec(dllexport) void __cdecl get(char** buffer);

    My_lib.c 
    void get(char** buffer)
    {
    *buffer = (char*)calloc(6, sizeof(char));
    assert(*buffer);

    buffer[5] = '\0';

    *buffer = "Hello";
    }

in my C#-----> 在我的C#----->

public static class NativeMethods
    {
        [DllImport("My_C_Lib.dll", CallingConvention = CallingConvention.Cdecl)]

        unsafe public static extern void get(char** buffer);
    }
 //////////////////// Main()///////
        unsafe
            {
                char* my_buf;

                NativeMethods.get(&my_buf);

                string s = new string(my_buf);

                Console.WriteLine(s);
            }

NOTE: Actually my DLL does Work when i call this c function from c++ but as i said above NOT in C#, there is no Errors but string s variable in C# prints some undefined sibols, but DLL "works" thanks in advance!!! 注意:实际上,当我从c ++调用此c函数时,我的DLL确实可以工作,但是正如我在C#中上面所说的那样,没有错误,但是C#中的string s变量会打印一些未定义的sibol,但是DLL是“有效的”,谢谢!!!

The code is nearly correct, but... 该代码几乎是正确的,但是...

C DLL does NOT Work in C# but Does work in C++ C DLL在C#中不起作用,但在C ++中起作用

In C and C++ char is a 8-bit data type. 在C和C ++中, char是8位数据类型。 In C# char is a 16-bit data type. 在C#中, char是16位数据类型。

This means that C# expects that the pointer returned by the get() function is expected to be a "wide string", while in C++ expects an "ANSI string". 这意味着C#期望由get()函数返回的指针应为“宽字符串”,而在C ++中则应为“ ANSI字符串”。

I simply changed one single line in your program: 我只是在程序中更改了一行:

*buffer = "H\0e\0l\0l\0o\0\0\0";

... and it works! ...而且有效!

You may of course also use the "wide string" functions of the modern C compilers: 您当然也可以使用现代C编译器的“宽字符串”功能:

void get(wchar_t** buffer)
{
    *buffer = L"Hello";
}

By the way 顺便说说

There is another error in your program: 您的程序中还有另一个错误:

*buffer = (char*)calloc(6, sizeof(char));
...
*buffer = "Hello";

This makes no sense: 这没有任何意义:

The second line ( *buffer = "Hello"; ) will not copy the string to the memory allocated by calloc , but it will write the address of the string "Hello" to the variable buffer and the value (address) returned by calloc is overwritten (and lost). 第二行( *buffer = "Hello";不会将字符串复制到calloc分配的内存中,但是会将字符串"Hello"的地址写入变量buffer并且calloc返回的值(地址)为被覆盖(丢失)。

Your best bet is to change the PInvoke signature of your C function to taking a ref IntPtr : 最好的选择是将C函数的PInvoke签名更改为ref IntPtr

[DllImport("My_C_Lib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void get(ref IntPtr buffer);

To call this, you'll need to instantiate an IntPtr and pass it by reference to the C function (this is analagous to declaring a char * in C and passing it by address): 要调用此方法,您需要实例化一个IntPtr并将其通过引用传递给C函数(这类似于在C中声明一个char *并通过地址传递它):

IntPtr ptr;
get(ref ptr);
// ptr is now an unmanaged pointer to the allocated string

Now, you need to convert the pointed-to string to a managed string . 现在,您需要将指向的字符串转换为托管string To do this you must make a copy of the string. 为此,您必须复制字符串。

string str = Marshal.PtrToStringAnsi(ptr);
  • Be sure you understand the distinctions between ANSI and Unicode strings and make sure you call the appropriate PtrToString...() variant. 确保了解ANSI和Unicode字符串之间的区别,并确保调用适当的PtrToString...()变体。
  • Note that the .NET runtime will not manage the allocated ptr for you since it was allocated by unmanaged code. 请注意, .NET运行时不会为您管理分配的ptr因为它是由非托管代码分配的。 You must free it yourself using whatever the appropriate mechanism is for your DLL (ideally, the DLL should provide a corresponding free function since it is the one who allocated the memory in the first place). 您必须使用适用于DLL的适当机制自己释放它(理想情况下,DLL应该提供相应的释放功能,因为它首先是分配内存的那个)。
  • For robustness, add appropriate error / null pointer checking. 为了增强鲁棒性,请添加适当的错误/空指针检查。 Make sure get() succeeded and that ptr is not IntPtr.Zero . 确保get()成功,并且ptr不是IntPtr.Zero
  • To avoid leaks, if there is any possibility of any code throwing an exception between the time get() returns and the time you free the pointer, the try/finally construct is your friend. 为避免泄漏,如果在get()返回时间与释放指针的时间之间任何代码都可能引发异常,则try/finally构造是您的朋友。

(Aside: Note that get is a Contextual Keyword in C# and thus while you can use it as an identifier, you may prefer not to in order to avoid confusion.) (此外:请注意, get是C#中的上下文关键字 ,因此尽管可以将其用作标识符,但为了避免混淆,您可能不希望这样做。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM