Search code examples
c#dllmarshalling.net-cf-3.5notsupportedexception

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.


Solution

  • 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.