none
Convert in c# a function with structure containing a pointer RRS feed

  • Question

  • In a dll library I have the function `DRV_DioReadBit`, containing the structure `PT_DioReadBit`. The C++ declaration is:

       

        FEXPORT LRESULT FTYPE DRV_DioReadBit(LONG_PTR DriverHandle, LPT_DioReadBit lpDioReadBit);

    The structure `PT_DioReadBit` contains the pointer `*state` as below (in C++):

       

         typedef struct tagPT_DioReadBit

        {

            USHORT      port;

            USHORT      bit;

            USHORT far  *state;

        } PT_DioReadBit, FAR * LPT_DioReadBit;

    The `lpDioReadBit` is a pointer to the structure `PT_DioReadBit` that stores target port number `USHORT port`, bit order number `USHORT bit` and returned bit status `USHORT *state`. I set the port and the bit, then I want to read the state.

    How can I convert in C#, USING dLLiMPORT, the C function DRV_DioReadBit containing the structure PT_DioReadBit.



    • Edited by Rosu Dan Sunday, February 9, 2014 8:10 AM
    Saturday, February 8, 2014 3:05 PM

Answers

  • Hello Rosu Dan,

    1. Concerning the "state" pointer field, it is important to specify :

    1.1 who will allocate the original USHORT memory ?

    - E.g. is the actual USHORT originally allocated by the C# program and then passed to the C++ code via a pointer for it to fill ?

    - Or is the USHORT allocated by the C++ program (as a global variable or as a dynamic variable allocated from the heap) in which case the C# program will refer to the "state" pointer

    1.2 who will own it ?

    - Memory ownership will dictate the side (the C# program or the C++ DLL) that will perform the final memory de-allocation of the USHORT.

    2. Provided below is an example of how you can access the "state" USHORT pointer from C#.

    2.1 I assume that "state" is made to point to a USHORT global variable defined in the C++ DLL.

    2.2 My sample C++ code (a DLL) is as follows :

    typedef struct tagPT_DioReadBit
    {
            USHORT      port;
            USHORT      bit;
            USHORT far  *state;
    } PT_DioReadBit, FAR * LPT_DioReadBit;
    
    USHORT g_usState = 100;
    
    extern "C" __declspec(dllexport) LRESULT __stdcall DRV_DioReadBit(LONG_PTR DriverHandle, LPT_DioReadBit lpDioReadBit)
    {
    	lpDioReadBit -> state = &g_usState;
    	
    	return 0;
    }
    

    2.3 The C# code is as follows :

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Runtime.InteropServices;
    
    namespace CSConsoleClient01
    {
        class Program
        {
            [StructLayout(LayoutKind.Sequential, Pack=1)]
            struct PT_DioReadBit
            {
                public UInt16   port;
                public UInt16   bit;
                public IntPtr   state;
            };
    
            [DllImport("RosuDanDLL.dll", CallingConvention = CallingConvention.StdCall)]
            extern private static Int32 DRV_DioReadBit(IntPtr DriverHandle, ref PT_DioReadBit lpDioReadBit);
    
            static void DoTest()
            {
                PT_DioReadBit pt_dioreadbit = new PT_DioReadBit();
    
                pt_dioreadbit.port = 1;
                pt_dioreadbit.bit = 2;
                
                DRV_DioReadBit(IntPtr.Zero, ref pt_dioreadbit);
    
                UInt16 state = 0;
    
                state = (UInt16)(Marshal.PtrToStructure(pt_dioreadbit.state, typeof(UInt16)));
            }
    
            static void Main(string[] args)
            {
                DoTest();
            }
        }
    }
    

    2.4 After "state" has been assigned to point to the "g_usState" global variable, it can be accessed by using the Marshal.PtrToStructure() function. Marshal.PtrToStructure() converts an unmanaged piece of data (pointed to by an IntPtr) to a managed one.

    2.5 Note that if it is the C# side that must assign the memory block for the USHORT, the code will be different.

    2.6 Please let me know more about the "state" pointer field and the nature of the actual USHORT that it points to.

    - Bio.


    Please visit my blog : http://limbioliong.wordpress.com/

    Tuesday, February 11, 2014 8:47 AM

All replies

  • It depends if the C# code or the C code is allocating the memory of the parameters.   It also looks like the structure may be an array of struct.  How do you determine the muber of items in the array?

    jdweng

    Saturday, February 8, 2014 4:36 PM
  • The lpDioReadBit is a pointer to the structure PT_DioReadBit that stores target port number (USHORT port), bit order number (USHORT bit) and returned bit status (USHORT *state). I set the port and the bit, then I want to read the state.

    Saturday, February 8, 2014 5:44 PM
  • Hello Rosu Dan,

    1. Concerning the "state" pointer field, it is important to specify :

    1.1 who will allocate the original USHORT memory ?

    - E.g. is the actual USHORT originally allocated by the C# program and then passed to the C++ code via a pointer for it to fill ?

    - Or is the USHORT allocated by the C++ program (as a global variable or as a dynamic variable allocated from the heap) in which case the C# program will refer to the "state" pointer

    1.2 who will own it ?

    - Memory ownership will dictate the side (the C# program or the C++ DLL) that will perform the final memory de-allocation of the USHORT.

    2. Provided below is an example of how you can access the "state" USHORT pointer from C#.

    2.1 I assume that "state" is made to point to a USHORT global variable defined in the C++ DLL.

    2.2 My sample C++ code (a DLL) is as follows :

    typedef struct tagPT_DioReadBit
    {
            USHORT      port;
            USHORT      bit;
            USHORT far  *state;
    } PT_DioReadBit, FAR * LPT_DioReadBit;
    
    USHORT g_usState = 100;
    
    extern "C" __declspec(dllexport) LRESULT __stdcall DRV_DioReadBit(LONG_PTR DriverHandle, LPT_DioReadBit lpDioReadBit)
    {
    	lpDioReadBit -> state = &g_usState;
    	
    	return 0;
    }
    

    2.3 The C# code is as follows :

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Runtime.InteropServices;
    
    namespace CSConsoleClient01
    {
        class Program
        {
            [StructLayout(LayoutKind.Sequential, Pack=1)]
            struct PT_DioReadBit
            {
                public UInt16   port;
                public UInt16   bit;
                public IntPtr   state;
            };
    
            [DllImport("RosuDanDLL.dll", CallingConvention = CallingConvention.StdCall)]
            extern private static Int32 DRV_DioReadBit(IntPtr DriverHandle, ref PT_DioReadBit lpDioReadBit);
    
            static void DoTest()
            {
                PT_DioReadBit pt_dioreadbit = new PT_DioReadBit();
    
                pt_dioreadbit.port = 1;
                pt_dioreadbit.bit = 2;
                
                DRV_DioReadBit(IntPtr.Zero, ref pt_dioreadbit);
    
                UInt16 state = 0;
    
                state = (UInt16)(Marshal.PtrToStructure(pt_dioreadbit.state, typeof(UInt16)));
            }
    
            static void Main(string[] args)
            {
                DoTest();
            }
        }
    }
    

    2.4 After "state" has been assigned to point to the "g_usState" global variable, it can be accessed by using the Marshal.PtrToStructure() function. Marshal.PtrToStructure() converts an unmanaged piece of data (pointed to by an IntPtr) to a managed one.

    2.5 Note that if it is the C# side that must assign the memory block for the USHORT, the code will be different.

    2.6 Please let me know more about the "state" pointer field and the nature of the actual USHORT that it points to.

    - Bio.


    Please visit my blog : http://limbioliong.wordpress.com/

    Tuesday, February 11, 2014 8:47 AM