2012-02-15 2 views
1

Я опытный инженер-программист, но несколько новичок в C#. У меня есть DLL, которая состоит из объектов C++ с интерфейсом C, как показано. Я использовал этот интерфейс C, потому что не был уверен, есть ли способ доступа к точкам входа C++ в DLL из моего приложения C#.Как передать указатель объекта из и в DLL?

__declspec(dllexport) void *Constructor(); 
    __declspec(dllexport) void Destructor(void *pObj); 
    __declspec(dllexport) int Method(void *pObj, char *pSrcDst, int len); 

Это код C для вышеуказанного интерфейса.

extern "C" void *Constructor() 
{ 
    return (void *)new Object; 
} 
extern "C" void Destructor(void *pObj) 
{ 
    delete (Object *)pObj; 
} 
extern "C" int Method(void *pObj, char *pSrcDst, int len) 
{ 
    if (!pObj) return 0; 
    return ((Object *)pObj)->Method(pSrcDst, len); 
} 

Пока все хорошо. Теперь мне нужно иметь доступ к этому интерфейсу из приложения C#. Из того, что я узнал, я реализовал следующий интерфейс C#.

unsafe public class Wrapper 
    { 
     [SuppressUnmanagedCodeSecurityAttribute()] 
     [DllImport("MyDLL.dll")] 
     public static extern 
     IntPtr Constructor(); 
     [SuppressUnmanagedCodeSecurityAttribute()] 
     [DllImport("MyDLL.dll")] 
     public static extern 
     void Destructor(IntPtr pObj); 
     [SuppressUnmanagedCodeSecurityAttribute()] 
     [DllImport("MyDLL.dll")] 
     public static extern 
     int Method(IntPtr pObj, [In,Out] byte[] pSrcDst, int len); 

И вот код C#, который использует вышеуказанный интерфейс.

private IntPtr pObject; 
    public object() 
    { 
    pObject = Wrapper.Constructor(); 
    } 
    ~object() 
    { 
    Wrapper.Destructor(pObject); 
    } 
    public override byte[] method() 
    { 
    byte[] bytes = new byte[100]; 
    int converted = Wrapper.Method(pObject, bytes, bytes.length); 
    return bytes; 
    } 

Код утверждает как при вызове Wrapper.Method, а также Wrapper.Destructor. Я предполагаю, что я неправильно обрабатываю указатель на объект. Какие-либо предложения?

+0

Что значит «код утверждает»? Вы получаете сообщение об ошибке? – svick

+0

Да, «обнаружен PInvokeStackImbalance». –

+0

Имейте в виду, что большинство компиляторов предполагают, что 'extern 'C' 'функции не генерируют исключений (особенно если код C вызывает их), поэтому вы захотите обернуть бит' new Object() 'в блок исключений, чтобы предотвратить исключение любых исключений (в частности, 'std :: bad_alloc') из экранирования. –

ответ

3

Наиболее вероятная проблема заключается в том, что ваш код не использует правильный calling convention. В C++ значение по умолчанию - __cdecl, но для DllImport по умолчанию __stdcall.

Чтобы это исправить, specify the calling convention explicitly:

[DllImport("MyDLL.dll", CallingConvention = CallingConvention.Cdecl)] 
+0

В случае, если OP не знает, соглашение по умолчанию в Visual Studio является [установкой компилятора] (http: // msdn.microsoft.com/en-us/library/46t77ak2.aspx). Его можно изменить на '__stdcall', чтобы соответствовать стандарту' [DllImport()] '. –

+0

Похоже, это была проблема, спасибо! –

+1

@RobertKirnum, если этот ответ решил вашу проблему, вы должны [принять его] (http://meta.stackexchange.com/a/5235/130186). – svick

1

Я был под впечатлением, что лучший способ сделать такого рода вещи использует управляемый C++/CLI оболочки.

Creating simple c++.net wrapper. Step-by-step

и

http://devmaster.net/forums/topic/7357-how-to-build-a-net-wrapper-for-a-c-library/

выглядеть перспективных потенциальных клиентов.

+1

Если вам просто нужно вызвать несколько неуправляемых функций, PInvoke, вероятно, будет проще. Но да, C++/CLI, безусловно, является альтернативой. – svick

+0

Правда, но единственная причина, по которой эти несколько неуправляемых функций даже существуют, - это отсутствие знаний о C++/CLI. Если есть способ «сделать это правильно», почему бы не использовать его. Вы действительно хотите использовать функцию «void * Constructor»? – Andrei

+0

До тех пор, пока он не будет публично открыт для остальной части кода C#, у меня нет проблем с этим. Если вы знаете C#, обучение использованию PInvoke намного проще, чем обучение использованию C++/CLI. – svick

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