PInvoke DLL in C#

14,905

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.

Share:
14,905
ifefer
Author by

ifefer

Updated on June 04, 2022

Comments

  • ifefer
    ifefer almost 2 years

    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 gets an exception. Can you help me to understand what the problem is?...

    The C code:

    typedef struct 
    {
        int Size; 
        //char *Array;
    }TTest;
    
    __declspec(dllexport) void Foo(void  *Test);
    __declspec(dllexport) int  Foo1();
    
    void Foo(void  *Test)
    {
        TTest *X = (TTest *)Test;
        int i = X->Size;
        /*for(int i=0;i<Test->Size;Test++)
        {
            Test->Array[i] = 127;
        }*/
    }
    
    int Foo1()
    {
        return 10;
    }
    

    The C# code:

    using System;
    using System.Runtime.InteropServices;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ConsoleApplication1
    {
        [StructLayout(LayoutKind.Sequential)]
        public class TTest 
        {
            public int Size; 
        }
    
        class Program
        {
            [DllImport(@"C:\.net course\unmanaged1\unmanaged3\Debug\unmanaged3.dll", CharSet = CharSet.Auto)]
            public static extern void Foo(
                [MarshalAs(UnmanagedType.LPStruct)]
                TTest lplf   // characteristics
            );
    
            [DllImport(@"C:\.net course\unmanaged1\unmanaged3\Debug\unmanaged3.dll", CharSet = CharSet.Auto)]
            public static extern int Foo1();
    
            static void Main(string[] args)
            {
                TTest Test = new TTest();
                Test.Size = 25;
    
                int XX = Program.Foo1();
                Program.Foo(Test);
            }
        }
    }