Share via


Passing a delegate to a callback function in unmanaged code using c-sharp

Question

Monday, May 11, 2020 6:37 AM

I have to register a callback function written in unmanaged code from c#. I have written the following codes:

//Declaration for c++ code
[DllImport("sdk.dll")]
public static extern void sdkSetDequeueCallback(DequeueCallback cbfunc);
//call back delegate
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DequeueCallback(OutData data);
GCHandle dequeueCallbackPinHandle;
//due to some security reason, not specifying the actual constructor name.
 Deque = new ConstructorName().DequeueCallback(CallBackMethod);
{//try out
// Getting error following line (1 line) , Error : Object contains non-primitive or non-blittable data.
 //dequeueCallbackPinHandle = GCHandle.Alloc(Deque, GCHandleType.Pinned);

 //GC.KeepAlive(Deque);
}
 SetDequeueCallback(Deque);
//Call back method in c#
 public async void CallBackMethod(OutData data)
        {}
 public void SetDequeueCallback(DequeueCallback cbfunc)
        {
            try
            {
                
                sdkSetDequeueCallback(cbfunc);
            }
            catch (Exception ex)
            {
               //here some exception logging code
            }
        }

The above code is working without the tryout block, but the issue is application is getting stopped after a random period of time( some times 30 mins, 1 Hr , 8 hr etc). No error detected in try..catch blocks, but getting following NullReferenceException error from the Windows Event Log(application): Description: The process was terminated due to an unhandled exception. Exception Info: System.NullReferenceException. I think this can be the issue, but tryout codes are not working. Please help me to resolve the issue

All replies (4)

Tuesday, May 12, 2020 6:26 AM ✅Answered

I still don't understand the reason for all the complexity. Why does the variable 'Deque' exist and what is it's type (you don't show it's declaration)?  What is the 'DequeueCallback' method that it refers to (I'm guessing you mean SetDequeueCallback)?  I'm guessing that the code at the bottom is in another class called ConstructorName. 

It seems that you create a temporary object called ConstructorName.  Get a reference to a method in the temporary object.  Then call a method with that reference as a parameter.  That method then calls the real method.  It is not at all clear what the lifetime of all these objects are, or even what objects the various methods are part of.  I think you are creating problems for yourself for no benefit.  I'm guessing that your commented out calls to the garbage collector are an attempt to trick the system into making a static method.  Why?  Just use a static method.

Keep it simple.  Call the sdkSetDequeueCallback method using a static method as the parameter.  No extra objects to create, no reference to methods, no lifetimes to worry about.  No garbage collector.  Everything can be in one class.

[DllImport("sdk.dll")]
public static extern void sdkSetDequeueCallback(DequeueCallback cbfunc);

public delegate void DequeueCallback(OutData data);

sdkSetDequeueCallback(CallBackMethod);

static void CallBackMethod(OutData data)
        {}

Monday, May 18, 2020 5:22 AM ✅Answered

Keep it simple.  Call the sdkSetDequeueCallback method using a static method as the parameter.  No extra objects to create, no reference to methods, no lifetimes to worry about.  No garbage collector.  Everything can be in one class.

I have created a static object and call the method. I have tested it for the past 6 days, now it's working fine. Thanks for the support


Monday, May 11, 2020 11:18 PM

I've never done this, but thought I would throw in an idea.

Looking in books it seems to me that your code is more complex than it needs to be.  What happens with simpler code, like

//Declaration for c++ code
[DllImport("sdk.dll")]
public static extern void sdkSetDequeueCallback(DequeueCallback cbfunc);

//call back delegate
public delegate void DequeueCallback(OutData data);

sdkSetDequeueCallback(CallBackMethod);

//Call back method in c#
public void CallBackMethod(OutData data)
        {}

Not all your names seem to line up.  Eg the declaration of the external method is sdkSetDequeueCallback but later you call SetDequeueCallback.  I'm guessing this is some variety of typo but is there are truly two different delegates with similar names you many be confusing them.

(I don't understand how you can 'new' a method call.  Does that really compile?)

If this doesn't help then it might be useful to get the stack dump from the exception to find out where the NullRefererenceException is occurring.  That is, try to confirm what it is that is null before making any assumptions about the problem.


Tuesday, May 12, 2020 5:46 AM

Not all your names seem to line up.  Eg the declaration of the external method is sdkSetDequeueCallback but later you call SetDequeueCallback.  I'm guessing this is some variety of typo but is there are truly two different delegates with similar names you many be confusing them.

Sorry I missed an intermediate function while posting. Now I updated the code segment, please have a look.

(I don't understand how you can 'new' a method call.  Does that really compile?)

Avoid the constructor due to some security reason, now just added a dummy one.

If this doesn't help then it might be useful to get the stack dump from the exception to find out where the NullRefererenceException is occurring.  That is, try to confirm what it is that is null before making any assumptions about the problem.

I have debugged the code and only got the information : ntdll not loaded

Dll is available in the running system, and error is initiated from the unmanaged code part.