none
Marshalling C++ Struct with function pointers in C# RRS feed

  • Question

  • Im making a C# managed extension dll for NPS witch looks like this:

    [DllExport("RadiusExtensionProcess2", CallingConvention = CallingConvention.Cdecl)]
    internal static uint RadiusExtensionProcess2(RADIUS_EXTENSION_CONTROL_BLOCK pECB)
    {
       return 0;
    }

    (Does anyone know if Cdecl is the correct calling convention here? C++ definition here)

    NPS passed a control block to the function that contains 3 pointers to functions, C++ definition here
    I defined this structure

    [StructLayout(LayoutKind.Sequential)]
    public struct RADIUS_EXTENSION_CONTROL_BLOCK
    {
        uint cbSize;
        uint dwVersion;
        RADIUS_EXTENSION_POINT repPoint;
        RADIUS_CODE rcRequestType;
        RADIUS_CODE rcResponseType;
        IntPtr GetRequest;
        IntPtr GetResponse;
        IntPtr SetResponseType;
    }

    This works but obviously the functions are useless like this, what is the proper way to map them so they can be used as intended? i.e.

    RADIUS_ATTRIBUTE_ARRAY attrs = block.GetRequest();
    RADIUS_ATTRIBUTE_ARRAY attrs = block.GetResponse(RADIUS_CODE.rcAccessChallenge);
    block.SetResponseType(RADIUS_CODE.rcAccessAccept);

    Some Progress

    So i managed to get this partially working

        [UnmanagedFunctionPointer(CallingConvention.Winapi)]
        public delegate ref RADIUS_ATTRIBUTE AttributeAtDelegate([In] ref RADIUS_ATTRIBUTE_ARRAY Array, [In] uint dwIndex);
    
        [UnmanagedFunctionPointer(CallingConvention.Winapi)]
        public delegate uint GetSizeDelegate([In] ref RADIUS_ATTRIBUTE_ARRAY Array);
    
        [StructLayout(LayoutKind.Sequential)]
        public struct RADIUS_ATTRIBUTE_ARRAY
        {
            public uint cbSize;
            public IntPtr Add;
            public IntPtr AttributeAt;
            public IntPtr GetSize;
            public IntPtr InsertAt;
            public IntPtr RemoveAt;
            public IntPtr SetAt;
        }
    
        [StructLayout(LayoutKind.Sequential)]
        public struct RADIUS_ATTRIBUTE
        {
            public uint dwAttrType;
            public RADIUS_DATA_TYPE fDataType;
            public uint cbDataLength;
            public IntPtr lpValue;
        }
    
        [StructLayout(LayoutKind.Sequential)]
        public struct RADIUS_EXTENSION_CONTROL_BLOCK
        {
            public uint cbSize;
            public uint dwVersion;
            public RADIUS_EXTENSION_POINT repPoint;
            public RADIUS_CODE rcRequestType;
            public RADIUS_CODE rcResponseType;
            public IntPtr GetRequest;
            public IntPtr GetResponse;
            public IntPtr SetResponseType;
        }
    
        [DllExport("RadiusExtensionProcess2", CallingConvention = CallingConvention.Winapi)]
        public static uint RadiusExtensionProcess2(ref RADIUS_EXTENSION_CONTROL_BLOCK pECB)
        {
            GetRequestDelegate GetRequest = (GetRequestDelegate)Marshal.GetDelegateForFunctionPointer(pECB.GetRequest, typeof(GetRequestDelegate));
            GetResponseDelegate GetResponse = (GetResponseDelegate)Marshal.GetDelegateForFunctionPointer(pECB.GetResponse, typeof(GetResponseDelegate));
            SetResponseTypeDelegate SetResponseType = (SetResponseTypeDelegate)Marshal.GetDelegateForFunctionPointer(pECB.SetResponseType, typeof(SetResponseTypeDelegate));
    
            uint SetResponseTypeResult = SetResponseType(ref pECB, RADIUS_CODE.rcAccessAccept); //SetResponseTypeResult is 0 and NPS sends a access granted message
    
            RADIUS_ATTRIBUTE_ARRAY AttrArray = GetRequest(ref pECB);
    
            return 0;
        }
    SetResponseType works without crashing the dll and GetRequest returns the expected value for cbSize and what look like valid pointers for the functions defined in the RADIUS_ATTRIBUTE_ARRAY struct.
    So i proceeded to map AttributeAt and GetSize the same way but the data they return is nonsence.
    I double and triple checked the definitions here and here but so far i haven't been able to get the proper data from these functions, since the dll dosen't crash and i dont get null back, i can only assume there is something wrong with how I'm passing the parameters to the functions
    On that note, are the in/out keywords in the C++ function definitions just info for developers or do they effect how parameters are handled on the stack?


    • Moved by Baron BiModerator Monday, April 23, 2018 1:48 AM More related to c# code
    • Edited by xxVictorxx Wednesday, April 25, 2018 9:11 PM Code Update
    Friday, April 20, 2018 9:30 AM

All replies

  • Try obtaining a delegate using Marshal.GetDelegateForFunctionPointer. See an example with ‘MultiplyByTen’: https://blogs.msdn.microsoft.com/jonathanswift/2006/10/03/dynamically-calling-an-unmanaged-dll-from-net-c. You have to provide the corresponding definition of your delegate, which will include two parameters.

    Friday, April 20, 2018 10:08 AM
  • Ive tried

    public delegate uint SetResponseTypeDelegate(RADIUS_CODE rcResponseType);
    
    [DllExport("RadiusExtensionProcess2", CallingConvention = CallingConvention.Winapi)]
    internal static uint RadiusExtensionProcess2(RADIUS_EXTENSION_CONTROL_BLOCK pECB)
    {
        SetResponseTypeDelegate setResponseType = (SetResponseTypeDelegate)Marshal.GetDelegateForFunctionPointer(pECB.SetResponseType, typeof(SetResponseTypeDelegate));
        setResponseType(RADIUS_CODE.rcAccessReject);
        return 0;
    }

    but calling the function just throws this error
    System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'

    Friday, April 20, 2018 2:51 PM