none
Using Callback in C# with COM object RRS feed

  • Question

  • Hello All,
    I trying out tweak for callback function in C++ COM object. I do not want to complicate the situation using IDispatch and IConnectionPoint, because I believe that this method is slow and also does not provide intellisense information.

    I have currently exposed a method in the server which takes DWORD as an argument this will be cast into desired function and later called. This works if the client is C++ and also works if the server is Win32 dll for both C++ and C# clients.

    But does not work if the client is C#. I think that the function address of the C# client callback function is incorrectly transmitted to the server in this case. Should I need to do some kind of Marshalling in this case?

    Thanks a lot

    Thursday, March 26, 2009 11:36 AM

Answers

  • The C++ code must call through a stub to run the managed code.  That stub is created automatically by the P/Invoke marshaller when you pass a delegate instance to unmanaged code.  Or you can create one explicitly with Marshal.GetFunctionPointerForDelegate().  Same thing. 

    A couple of ways to get in trouble with this.  Letting the C# class object getting garbage collected would be an obvious one, it must stay alive at least as long as the callback is active.  More subtle is the garbage collector, it cannot see references held by unmanaged code.  You must store the delegate instance in a class field so it stays referenced.  Making everything static keeps you out of trouble.

    Hans Passant.
    • Marked as answer by RadiumBall Friday, March 27, 2009 5:32 PM
    Thursday, March 26, 2009 4:02 PM
    Moderator

All replies

  • Why don't you use a callback interface instead of passing around raw function pointers? COM is all about intefaces.


    Mattias, C# MVP
    Thursday, March 26, 2009 12:39 PM
    Moderator
  • Hello Mattias,
    What do you mean by "callback interface" ? Please explain.

    Thanks
    Thursday, March 26, 2009 12:53 PM
  • RadiumBall said:

    This works if the client is C++ and also works if the server is Win32 dll for both C++ and C# clients.

    But does not work if the client is C#

    That doesn't make sense.  I assume you meant "if the server is C#".  In which case you'd simply use an event.  .NET's COM interop automatically takes care of IConnectionPoint.

    Hans Passant.
    Thursday, March 26, 2009 1:06 PM
    Moderator
  • Hello Hans,
    Let me clarify,
    1) I am not using IConnectionPoint because for the reason mentioned before
    2) I am trying a tweak for callback by building a COM server in C++ with an interface containing a method with DWORD as an argument, internally this method would cast this DWORD to callback function and will be used to callback
    3) This works if client is C++  but does not work if client is C# I get a bad memory read-write exception.

    I think that the address of the C# function is incorrectly transmitted.

    Thanks
    Thursday, March 26, 2009 3:39 PM
  • The C++ code must call through a stub to run the managed code.  That stub is created automatically by the P/Invoke marshaller when you pass a delegate instance to unmanaged code.  Or you can create one explicitly with Marshal.GetFunctionPointerForDelegate().  Same thing. 

    A couple of ways to get in trouble with this.  Letting the C# class object getting garbage collected would be an obvious one, it must stay alive at least as long as the callback is active.  More subtle is the garbage collector, it cannot see references held by unmanaged code.  You must store the delegate instance in a class field so it stays referenced.  Making everything static keeps you out of trouble.

    Hans Passant.
    • Marked as answer by RadiumBall Friday, March 27, 2009 5:32 PM
    Thursday, March 26, 2009 4:02 PM
    Moderator
  • RadiumBall said:

    Hello Mattias,
    What do you mean by "callback interface" ? Please explain.

    Thanks

    Just another COM interface, with a method on it that will be used for the callback. Let your C# code implement it and pass a reference to the implementing object to the C++ code (instead of the function pointer / DWORD you're passing now).



    Mattias, C# MVP
    Thursday, March 26, 2009 4:19 PM
    Moderator