2012-04-13 2 views
1

Я вызываю внешнюю библиотеку C из оболочки C#, которую я пишу. Одна из функций, которые я вызываю, - зарегистрировать функцию обратного вызова. У меня нет ошибок, когда я вызываю функцию setCallback, но когда функция обратного вызова позже называется, я получаю ошибки, к сожалению, не указанные в библиотеке C.Использование функции обратного вызова с параметрами при использовании P/Invoke

Вот метод C (из файла заголовка)

DLLExport int setCallbacks(Client handle, void* context, connectionLost* cl, 
messageArrived* ma, deliveryComplete* dc); 

Вот мой C# декларация метода

[DllImport("some.dll", CharSet = CharSet.Auto, ExactSpelling = false, 
CallingConvention = CallingConvention.Cdecl)] 
private static extern int setCallbacks(IntPtr client, IntPtr context, 
MulticastDelegate connectionLost, MulticastDelegate messageArrived, 
MulticastDelegate messageDelivered); 

Это мои делегаты

private delegate int ConnectionLostDelegate(IntPtr context, [MarshalAs(UnmanagedType.LPStr)] String cause); 
private delegate int MessageArrivedDelegate(IntPtr context, [MarshalAs(UnmanagedType.LPStr)] String title, Int32 titleLength, MessageObject message); 
private delegate int MessageDeliveredDelegate(IntPtr context, int deliveryToken); 

Это, как я позвонить по методу

ConnectionLostDelegate conLost = new ConnectionLostDelegate(ConnectionLost); 
MessageArrivedDelegate mesArr = new MessageArrivedDelegate(MessageArrived); 
MessageDeliveredDelegate mesDel = new MessageDeliveredDelegate(MessageDelivered); 

result = setCallbacks(client, IntPtr.Zero, conLost, mesArr, mesDel); 

Вот структура, которая используется один из обратных вызовов

[StructLayout(LayoutKind.Sequential)] 
public class MessageObject 
{ 
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.U1)] 
    public byte[] struct_id; 
    Int32 struct_version; 
    Int32 payloadlen; 
    IntPtr payload; 
    Int32 qos; 
    Int32 retained; 
    Int32 dup; 
    Int32 msgid; 

    public MessageObject() 
    { 
     struct_id = Encoding.ASCII.GetBytes("WXYZ"); 
     struct_version = 0; 
     payload = IntPtr.Zero; 
    } 
} 

C заголовков для функций обратного вызова следующим образом ..

typedef int messageArrived(void* context, char* title, int titleLen, MessageObject* message); 

typedef void deliveryComplete(void* context, int token); 

typedef void connectionLost(void* context, char* cause); 
+0

Можете ли вы также показать подпись из заголовков c для соединенияLost, messageArrived, deliveryComplete? – Nikolay

+0

Привет, Николай, я добавил их сейчас. –

ответ

1

У меня нет большого опыта с р/invoke, но похоже, что вы должны исправить подписи делегатов, чтобы вернуть пустоту там, это недействительно в c. А также использовать ref для параметров указателя, таких как контекст и сообщение

+0

Благодарим за то, что хедз-ап вернули типы возвращаемых подписей, что не помогло. Мне не нужен параметр 'ref' для параметров, поскольку они имеют тип' IntPtr' и класс, который будет по ссылке в любом случае. –

+0

Это IntPtr для контекста, но не для сообщения. Я думаю, что это должно быть 'private delegate int MessageArrivedDelegate (IntPtr context, ..., ref MessageObject message);' – Nikolay

+0

Если 'MessageObject' был структурой, а не классом, я бы согласился с вами. Я попробовал его с префиксом 'ref', и он все еще не работает. –