Из C # как я могу использовать собственный C ++ обратный вызов с унаследованной структурой? - PullRequest
2 голосов
/ 19 апреля 2011

Из C # мне нужно настроить обратный вызов в C ++, где данные, полученные в результате обратного вызова, происходят из структур с наследованием (см. Дистиллированный код ниже в разделе C ++).

Я считаю, что структуры в C ++ свернуты компилятором, потому что они не содержат никаких виртуальных функций? Поэтому использование свернутого класса данных CollapsedCallbackInfo в C # действительно работает для этого конкретного класса данных. Но если в реальной проблеме много разных классов данных с несколькими уровнями наследования, есть ли способ решить эту проблему? Мне нужен какой-то общий тип для использования в моем определении делегата.

C #

Настройка обратного вызова

[DllImport("NativeDLL", CallingConvention = CallingConvention.Cdecl)] 
public static extern void SetupCallback(CallbackFunc callback);

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void CallbackFunc(BaseCallbackInfo baseCallbackInfo);

C # Классы данных

[StructLayout(LayoutKind.Sequential)]
public class BaseCallbackInfo 
{
    public uint base_data;
};

[StructLayout(LayoutKind.Sequential)]
public class ConcreteCallbackInfo : BaseCallbackInfo 
{
    public uint concrete_data;
};   

Свернутый класс данных

[StructLayout(LayoutKind.Sequential)]
public class CollapsedCallbackInfo 
{
    public uint base_data;
    public uint concrete_data;
};

Тестовый класс, иллюстрирующий настройку обратного вызова

public class TestClass
{
   public void RegisterCallback()
   {    
      SetupCallback(new CallbackFunc(OnCallback));
   }

   public void OnCallback(BaseCallbackInfo baseCallbackInfo)
   {
      // In the real problem I know this cast is valid
      ConcreteCallbackInfo ccbi = baseCallbackInfo as ConcreteCallbackInfo;
      Debug.Log(ccbi.concrete_data)
   }  
}

C ++

Классы данных

struct BaseCallbackInfo
{
   uint base_data;
};

struct ConcreteCallbackInfo : public BaseCallbackInfo
{
   uint concrete_data;
};

Определение обратного вызова в стиле C и внешний интерфейс

typedef void( *CallbackFunc )( BaseCallbackInfo* in_pCallbackInfo );

extern "C"
__declspec(dllexport) void SetupCallback(CallbackFunc callback);    

1 Ответ

1 голос
/ 19 апреля 2011

Просто определите несколько DllImports одного и того же, например

[DllImport("NativeDLL", EntryPoint="SetupCallback", CallingConvention = CallingConvention.Cdecl)] 
public static extern void SetupCallback_Base(BaseCallbackFunc callback);

[DllImport("NativeDLL", EntryPoint="SetupCallback", CallingConvention = CallingConvention.Cdecl)] 
public static extern void SetupCallback_Concrete1(Concrete1CallbackFunc callback);

[DllImport("NativeDLL", EntryPoint="SetupCallback", CallingConvention = CallingConvention.Cdecl)] 
public static extern void SetupCallback_Concrete2(Concrete2CallbackFunc callback);

Я бы порекомендовал вам _stdcall вместо _cdecl.

...