0

I have the following situation: I have 2 c++ DLL files communicating with a C# application using events. The C# application passes function pointers within a Setup() method to both files which may later raise an event using this function pointer. The application is written for Windows CE 8 and the target framework Windows Embedded Compact V3.9 (.NET CF 3.9).

Each DLL communication is wrapped within a single class containing a Setup() method and a NativeMethods sub-class containing all DLL methods. Both DLL files have an ItemChanged event.

Sample Code:

private delegate void EventDelegate(int item, int value);
private EventDelegate _eventCallback;
private IntPtr _eventCallbackAddress;

private void OnEvent(int item, int value)
{
  Debug.WriteLine("Item: " + item + ", value: " + value);
}

private void Setup()
{
  _eventCallback = new EventDelegate(OnEvent);
  _eventCallbackAddress = Marshal.GetFunctionPointerForDelegate(_eventCallback); // NotSupportedException
  try
  {
    NativeMethods.Configure(_eventCallbackAddress);
  }
  catch (Exception ex)
  {
    Debug.WriteLine(this, ex.Message);
  }
}

private static class NativeMethods
{
  [DllImport("A.dll", EntryPoint = "Configure", CallingConvention = CallingConvention.WinApi)]
  public static extern void Configure(IntPtr eventCallback);
}

This snippet is used in both classes without changes except DllImport reference.

My problem is that after successfully passing classA.Setup() method, I receive a System.NotSupportedException on Marshal.GetFunctionPointerForDelegate method invocation in ClassB.Setup().

MSDN documentation did not help and I found no further documentation while crawling through the internet. Which is why I came here.

I've observed that the exception does not occur when calling Marshal.GetFunctionPointer method for another "test" delegate, but it is still thrown on Marshal.GetFunctionPointer(_eventCallback)

private Delegate testDelegate;
private void Foo() { };

private void Setup()
{
  testDelegate = new Action(Foo);
  IntPtr p = Marshal.GetFunctionPointerForDelegate(testDelegate);

  _eventCallback = new EventDelegate(OnEvent);
  _eventCallbackAddress = Marshal.GetFunctionPointerForDelegate(_eventCallback); // NotSupportedException
  try
  {
    NativeMethods.Configure(_eventCallbackAddress);
  }
  catch (Exception ex)
  {
    Debug.WriteLine(this, ex.Message);
  }

Do you have any suggestions? Did I forget something?

Thank you.

Aureon
  • 387
  • 3
  • 4
  • 15
  • The *one* detail that is important to answer this question is missing from the snippets. The return type of the delegate. Consulting my crystal ball: change bool to int. – Hans Passant Nov 29 '18 at 10:16
  • Thanks Hans Passant for pointing that out; the return type is void. I'll correct it in the description. – Aureon Nov 29 '18 at 10:25
  • 1
    Hmya, you are asking this question a decade too late. Consider to not use GetFunctionPointerForDelegate at all. It is not necessary, you can simply declare the method as void Configure(EventDelegate eventCallback). Beware that you still have to store the delegate object in a variable to ensure it doesn't get garbage-collected. – Hans Passant Nov 29 '18 at 10:31
  • Thank you Hans, I'll try this out and check back later with an update. – Aureon Nov 29 '18 at 10:38

1 Answers1

0

The signature of ClassB had generic type parameters <T, U> to utilize generic int-based enumerations for an external communication interface, lets say these enumerations are named RequestItems and ResponseItems.

During problem analysis, the code was commented out until a working minimal example has been retrieved. After that it was step-wise uncommented and tested - it still worked, but after adding back the generic type parameters <T, U>, the exception was thrown again.

I did not expect that the class signature can have such an impact to system method invocations like Marshal.GetFunctionPointerFromDelegate method.

Working minimal example:

public ClassA
{
  private delegate void EventDelegate(int item, int value);
  private EventDelegate _eventCallback;
  private IntPtr _eventCallbackAddress;

  private void OnEvent(int item, int value)
  {
    Debug.WriteLine("Item: " + item + ", value: " + value);
  }

  private void Setup()
  {
    _eventCallback = new EventDelegate(OnEvent);
    _eventCallbackAddress = Marshal.GetFunctionPointerForDelegate(_eventCallback);
    try
    {
      NativeMethods.Configure(_eventCallbackAddress);
    }
    catch (Exception ex)
    {
      Debug.WriteLine(this, ex.Message);
    }
  }

  private static class NativeMethods
  {
    [DllImport("A.dll", EntryPoint = "Configure", CallingConvention = CallingConvention.WinApi)]
    public static extern void Configure(IntPtr eventCallback);
  }
}        

Not working example - add :

public ClassB<T, U>
{
  //..
}

Thank you for your help.

Aureon
  • 387
  • 3
  • 4
  • 15