2014-10-15 3 views
0

Для того, чтобы скрыть реализацию функции, я обычно пишу следующий C++ код и разоблачить свою функцию как «интерфейсы»Как использовать C++-интерфейс в C#?

// the interface to expose 
class ICalcService 
{ 
public: 
    virtual double Multiple(double a, double b) const = 0; 
}; 

// the implementation of the interface 
class CalcService final : public ICalcService 
{ 
    virtual double Multiple(double a, double b) const override 
    { 
     return a * b; 
    } 
}; 

// expose the 'CreateCalcService' to mydll.dll as C function 
extern "C" __declspec(dllexport) void CreateCalcService(void** obj) 
{ 
    *obj = new CalcService(); 
} 

И типичное использование в C++ является

// typical way to consume the interface in C++ 
void test_cpp_code() 
{ 
    ICalcService* calc; 
    CreateCalcService(reinterpret_cast<void**>(&calc)); 
    cout << calc->Multiple(15, 23) << endl; 
} 

сейчас Я хотел бы использовать его в коде C#. После периода исследований, я написал следующий код

using System.Runtime.InteropServices; 
class Program 
{ 
    interface ICalcService 
    { 
     double Multiple(double a, double b); 
    } 

    [DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)] 
    private extern static void CreateCalcService(out object obj); 

    static void Main(string[] args) 
    { 
     object o; 
     CreateCalcService(out o); 
     var calc = o as ICalcService; 
     calc.Multiple(14, 29); 
    } 
} 

Но это не будет работать, как я ожидал. Вместо этого исключение было выбрано в строке CreateCalcService(out o).

Помощник по удаленной работе «InvalidVariant» обнаружил проблему в «xx \ xx \ myloader.vshost.exe». Дополнительная информация: Недействительный VARIANT был обнаружен во время преобразования из неуправляемого VARIANT в управляемый объект. Передача недействительных VARIANT в среду CLR может вызвать неожиданные исключения, повреждение или потерю данных. Если для этого исключения есть обработчик, программа может быть безопасно продолжена. Необработанное исключение типа «System.Runtime.InteropServices.InvalidOleVariantTypeException» произошло в myloader.exe Дополнительная информация: Указанный вариант OLE недопустим.

Может ли кто-нибудь любезно сообщить мне, в чем проблема и как заставить его работать? например неправильная подпись C# dllimport.

Заранее благодарен!

ответ

0

Нет, вы не можете напрямую обращаться к интерфейсам на C++. Есть несколько альтернатив.

1) Оберните код C++ в C.

// expose the 'CreateCalcService' to mydll.dll as C function 
extern "C" __declspec(dllexport) void CreateCalcService(void** obj) 
{ 
    *obj = new CalcService(); 
} 

extern "C" __declspec(dllexport) double Multiple(void* obj, double a, double b) 
{ 
    ICalcService calc = (ICalcService)obj; 
    calc->Multiple(a, b); 
} 

с C# кода:

[DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)] 
private extern static void CreateCalcService(out IntPtr obj); 

[DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)] 
private extern static double Multiple(IntPtr obj, double a, double b); 

static void Main(string[] args) 
{ 
    IntPtr calc; 
    CreateCalcService(out handle); 
    Multiple(calc, 14, 29); 
} 

2) Написать C++/CLI обертку.

+1

Быстро разочарован тем, что нет встроенного подхода. Первая альтернатива на самом деле не изящна, в то время как вторая не пересекается с платформой :(В любом случае, спасибо за информацию! –

0

Это не сработает. Интерфейс C++ (который не что иное, как class) отличается от C# interface. Вы не можете придать экземпляр объекта C++ экземпляру C# интерфейса.

0
private extern static void CreateCalcService(out object obj); 

парам не прав, он не может быть объектом. Попробуйте байт []. таких как

byte[] mac = new byte[16]; 
private extern static void CreateCalcService(mac); 
+0

Тогда как придать тип байту [] mac для ICalcService? –

Смежные вопросы