PInvoke DLL in C#

前端 未结 2 917
有刺的猬
有刺的猬 2021-01-03 14:51

I want to pass a structure to C function and I write the following code.

When I run it, the first function - Foo1 is working and then function Foo

相关标签:
2条回答
  • 2021-01-03 14:52

    To the downvoters: This answer solves two issues: the immediate issue of the calling convention/the MarhsalAs attribute, and the issue he will soon find where his TTest parameter won't work if he takes my suggestion of turning TTest into a struct.

    Your native code is asking for a void*, which in C# is an IntPtr. First you should define TTest as a struct and not a class. Second, you should change the declaration of Foo to:

    [DllImport(@"C:\.net course\unmanaged1\unmanaged3\Debug\unmanaged3.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
    public static extern void Foo(IntPtr lplf);
    

    And third, you should pin the TTest using the fixed keyword and pass it's pointer to Foo. If you're using a class, you can use Marhsal.StructureToPtr to get an IntPtr from your TTest.

    This provides the same functionality on both sides, where a pointer to any type can be passed in. You can also write overloads with all the class types that you want to use since they all equate to void* on the native side. With a struct, your parameters would be prepended with a ref.

    What I'm curious about is why your native code wants a void* instead of a TTest* when the first thing you do in the unmanaged code is cast to a TTest*. If you switched the parameter to a TTest*, then providing identical functionality becomes simpler. You declaration would become:

    [DllImport(@"C:\.net course\unmanaged1\unmanaged3\Debug\unmanaged3.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
    public static extern void Foo(ref TTest lplf);
    

    And you would call the function as Program.Foo(ref Test);

    If you're using the class, the ref isn't necessary as classes are reference types.

    0 讨论(0)
  • 2021-01-03 15:12

    You are using C call so you need to specify CallingConvention.Cdecl

    [DllImport(@"C:\.net course\unmanaged1\unmanaged3\Debug\unmanaged3.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
    

    By default its stdcall in C# pinvoke as i remember; You can also do change C code instead and leave your C# code as is like in below

    __declspec(dllexport) void __stdcall  Foo(void  *Test);
    

    But for me best is to both declare __cdecl (or stdcall) in your C export and CallingConvention.Cdecl (or stdcall) in your C# code to keep convenience. You can check https://docs.microsoft.com/en-gb/cpp/cpp/argument-passing-and-naming-conventions?view=vs-2017 and https://docs.microsoft.com/en-gb/dotnet/api/system.runtime.interopservices.callingconvention?view=netframework-4.7.2 for further info

    0 讨论(0)
提交回复
热议问题