Aureon
Aureon

Reputation: 387

C# System.NotSupportedException on Marshal.GetFunctionPointerForDelegate

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.

Upvotes: 0

Views: 542

Answers (1)

Aureon
Aureon

Reputation: 387

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.

Upvotes: 0

Related Questions