2011-12-28 2 views
1

Я пытаюсь выполнить некоторые методы (в данном конкретном случае, rdOnAllDone) из сторонней библиотеки DLL, написанные на C, и глядя через файлы заголовков, я нашел это:Правильный способ вызова C DLL-метода из C#

#ifndef TDECLSDONE 
#ifdef STDCALL 
#define  CCON  __stdcall 
#else 
#define  CCON  __cdecl 
#endif 
#define TDECLSDONE 
#endif 
#define  DLLIMP  __declspec (dllimport) 
DLLIMP int CCON rdOnAllDone (void(CCON *)(int)); 

После выпучив способ вызвать этот метод, я сделал это:

[DllImport("sb6lib.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern int rdOnAllDone(Delegate d); 
public delegate void rdOnAllDoneCallbackDelegate(); 

private static void rdOnAllDoneCallback() 
{ 
    Console.WriteLine("rdOnAllDoneCallback invoked"); 
} 

метод был назван правильно, за исключением, что я не мог получить параметр Int. Таким образом, я попытался добавить входной параметр Int, как этот

[DllImport("sb6lib.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern int rdOnAllDone(Delegate d); 
public delegate void rdOnAllDoneCallbackDelegate(int number); 

private static void rdOnAllDoneCallback(int number) 
{ 
    Console.WriteLine("rdOnAllDoneCallback invoked " + number); 
} 

Но теперь делегат называется дважды, и он выходит из строя программы со следующей ошибкой «vshosts32.exe перестал работать»

Что правильный способ вызвать этот DLL-метод?

EDIT: Забыл добавить Основной метод:

public static void Main() 
{ 
    rdOnAllDoneCallbackDelegate del3 = new rdOnAllDoneCallbackDelegate(rdOnAllDoneCallback); 
rdOnAllDone(del3); 

    while (true) 
    { 
     Thread.Sleep(1000); 
    } 
} 

ответ

3

Три вещи, которые нужно сделать, чтобы это работало правильно:

  • вы должны сказать PInvoke marshaller о действительный тип делегата, используя делегата, недостаточно. Это создаст неправильный thunk, который не будет должным образом маршалировать аргумент. Это то, что вы видели.
  • вам нужно сообщить маршаллеру о вызывающем соглашении, если это не __stdcall с атрибутом [UnmanagedFunctionPointer]. Получение этого неправильного дисбаланса в стеке с хорошими шансами на жесткий крушение.
  • вам нужно сохранить ссылку на объект делегата, чтобы сборщик мусора не собирал его. Он не может видеть ссылки, хранящиеся в собственном коде. Если вы ошибетесь, это приведет к сбою внутреннего кода с жестким сбоем после следующей сборки мусора.

Так это должно работать лучше, настройки по мере необходимости:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)] 
public delegate void rdOnAllDoneCallbackDelegate(int parameter); 

[DllImport("sb6lib.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern int rdOnAllDone(rdOnAllDoneCallbackDelegate d); 

class Foo { 
    private static rdOnAllDoneCallbackDelegate callback; // Keeps it referenced 

    public static void SetupCallback() { 
     callback = new rdOnAllDoneCallbackDelegate(rdOnAllDoneCallback); 
     rdOnAllDone(callback); 
    } 

    private static void rdOnAllDoneCallback(int parameter) { 
     Console.WriteLine("rdOnAllDoneCallback invoked, parameter={0}", parameter); 
    } 
} 
1

Ваша делегирует подпись должна соответствовать нативной обратного вызова, также он должен иметь UnmanagedFunctionPointerAttribute устанавливается соответствующим образом.

В вашем случае, как так:

[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] 
public delegate void rdOnAllDoneCallbackDelegate(int parameter); 

[DllImport("sb6lib.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern int rdOnAllDone(rdOnAllDoneCallbackDelegate callback); 

Использование:

{ 
    rdOnAllDone(rdOnAllDoneCallback); 
} 

private static void rdOnAllDoneCallback(int parameter) 
{ 
    Console.WriteLine("rdOnAllDoneCallback invoked, parameter={0}", parameter); 
} 
+0

Пробовал, что прямо сейчас, и делегат еще называют дважды, и он выходит из строя программу с той же ошибкой "vshosts32.exe остановилась рабочий " –

+0

Вы правы, я попробовал и испытал то же самое. После небольшого поиска в Google я нашел рабочее решение и обновил сообщение. :) –