none
ArgumentNullException using 'ref' with struct RRS feed

  • Question

  • I'm doing some work on a c# wrapper and I have the following in C:

    DLM_API long DLM_CALL_CONV dlm_setYUVDataCallback(int SessionHandle, void (*callback)(long lPlayerID, unsigned char** yuvData, int* pitch, int width, int height, int64_t ts, char* extData));
    

    In my wrapper class I have the following:

    namespace DLMLib
    {
        public class DLMSDK
       {          
            public delegate int YUVDataCallback(dlm_yuvdataParametersStruct pParameters);
                                    
            [DllImport(@"DallmeiersDLL\davidapileolive.dll")]
            public extern static int dlm_setYUVDataCallback(int SessionHandle, YUVDataCallback yuvCallback);
                                    
            [StructLayout(LayoutKind.Explicit, Size = 32)]
            public struct dlm_yuvdataParametersStructure
            {
                [FieldOffset(0)]
                public int IPlayerID;
    			[FieldOffset(4), MarshalAs(UnmanagedType.ByValArray, SizeConst=3)]
                public IntPtr[] yuvData;
                [FieldOffset(8), MarshalAs(UnmanagedType.ByValArray, SizeConst=1)]
                public IntPtr[] pitch;
                [FieldOffset(12)]
                public int width;
                [FieldOffset(16)]
                public int height;
                [FieldOffset(18)]
                public long ts;
                [FieldOffset(28), MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
                public IntPtr[] extData;
            }
        }
    }

    In my form I setup the handler and the callback like this :

    public partial class Form1 : Form
    {
    	DLMSDK.YUVDataCallback yuvDataCallback;
    	
    	private void Form1_Load(object sender, EventArgs e)
    	{
    		yuvDataCallback = yuvDataHandler;
    	}
    	
    	public int yuvDataHandler(DLMSDK.dlm_yuvdataParametersStructure pParameters)
    	{
    		// handle pParameters values here
    		return 0;
    	}
    	
    	private void btnGetYUVImage_Click(object sender, EventArgs e)
    	{
    		try
    		{
    			error = DLMSDK.dlm_setYUVDataCallback(SessionHandle, yuvDataCallback);
    		}
    		catch (Exception ex)
    		{
    			throw;
    		}
    	}
    }

    This works but I feel that its incorrect, as other examples use 'ref', so I add 'ref' to the following :

    To the delegate in the wrapper class:
    public delegate int YUVDataCallback(ref dlm_yuvdataParametersStruct pParameters);

    And to my handler method:
    public int yuvDataHandler(ref DLMSDK.dlm_yuvdataParametersStructure pParameters)

    Now when I click on 'btnGetYUVImage' I get a 'ArgumentNullException was unhandled : value cannot be null'.
    I have used 'ref' on the connection/disconnection callbacks exactly this way and they all work.

    What am I missing? Do I need 'ref' for this example? It certainly works without it but I feel it may not return the correct values.

    Tuesday, April 6, 2010 8:27 AM

Answers

  • Hi,

    If you don't want to modify parameter's values in managed callback hanlder " yuvDataHandler ", the ref keyword is not needed.

    Else, if you want to modify parameter values, for example:

     

    public int yuvDataHandler(DLMSDK.dlm_yuvdataParametersStructure pParameters)

    {

    pParameters . height = 2;

    ...

    return 0;

    }

     

    You may consider adding ref keyword to the YUVDataCallback delegate, and refine native code, something like this:

     

    typedef struct

    {

        long lPlayerID;

        unsigned char** yuvData;

        int* pitch;

        int width;

        int height;

        int64_t ts;

        char* extData;

    }callbackpara;

     

    DLM_API long DLM_CALL_CONV dlm_setYUVDataCallback dlm_setYUVDataCallback(int SessionHandle, void (*callback)(callbackpara* p))

    {

       printf_s("[unmanaged] got callback address, calling it...\n");

       callbackpara* p = (callbackpara*)malloc(sizeof(callbackpara));

       p->width = 4;

       p->height = 3;

       callback(p);

    }


    Sincerely,
    Eric

    • Marked as answer by SamAgain Friday, April 16, 2010 10:21 AM
    Wednesday, April 7, 2010 3:45 AM

All replies

  • Hi,

    If you don't want to modify parameter's values in managed callback hanlder " yuvDataHandler ", the ref keyword is not needed.

    Else, if you want to modify parameter values, for example:

     

    public int yuvDataHandler(DLMSDK.dlm_yuvdataParametersStructure pParameters)

    {

    pParameters . height = 2;

    ...

    return 0;

    }

     

    You may consider adding ref keyword to the YUVDataCallback delegate, and refine native code, something like this:

     

    typedef struct

    {

        long lPlayerID;

        unsigned char** yuvData;

        int* pitch;

        int width;

        int height;

        int64_t ts;

        char* extData;

    }callbackpara;

     

    DLM_API long DLM_CALL_CONV dlm_setYUVDataCallback dlm_setYUVDataCallback(int SessionHandle, void (*callback)(callbackpara* p))

    {

       printf_s("[unmanaged] got callback address, calling it...\n");

       callbackpara* p = (callbackpara*)malloc(sizeof(callbackpara));

       p->width = 4;

       p->height = 3;

       callback(p);

    }


    Sincerely,
    Eric

    • Marked as answer by SamAgain Friday, April 16, 2010 10:21 AM
    Wednesday, April 7, 2010 3:45 AM
  • Why do you pack the callback parameters into a struct? A proper delegate should look something like this

    public delegate void YUVDataCallback(int lPlayerID, IntPtr yuvData, IntPtr pitch, int width, int height, long ts, IntPtr extData);

    Mattias, C# MVP
    Wednesday, April 7, 2010 12:10 PM
    Moderator