Вызов функций C++, содержащих обратные вызовы в C#

Привет всем, я пытаюсь разобраться с вызовом этой функции C++ в C#:

BOOL __stdcall CodecStart(int hRadio,void __stdcall (*CallbackFunc)(void *),void *CallbackTarget);

это из WinRadio API, найденный здесь http://www.winradio.com/home/g305_sdk.htm.

я обнаружил, что другие люди спрашивали о вызове этой конкретной функции в сети, и у них было:

    public delegate void CallbackFunc( IntPtr p);

    [DllImport("WRG305API.dll")]
    public static extern bool CodecStart(int hRadio, CallbackFunc func, IntPtr CallbackTarget);

но я не могу понять, как реализовать это дальше.

какие-нибудь мысли или указания относительно того, как это назвать?

большое спасибо

3 ответа

Решение

Вот простая реализация, которая объединит все это.

class WinRadioWrapper
{
    public delegate void CallbackFunc( IntPtr pData );

    [DllImport( "WRG305API.dll" )]
    public static extern bool CodecStart( int hRadio, CallbackFunc func, IntPtr CallbackTarget );

    public bool CodecStartTest(int hRadio)
    {
        bool bStarted = CodecStart( hRadio, MyCallbackFunc, IntPtr.Zero );
        return bStarted;
    }

    // Note: this method will be called from a different thread!
    static void MyCallbackFunc( IntPtr pData )
    {
        // Sophisticated work goes here...
    }
}
  • Обратите внимание, что, потому что MyCallbackFunc будет выполняться в другом потоке, я решил сделать это static, Таким образом, вы не будете испытывать желание получить доступ WinRadioWrapper члены данных.

  • Для простоты я прошел IntPtr.Zero параметр для обратного вызова, но это может указывать на любые данные, которые вы хотели бы использовать в обратном вызове.

    [Пожалуйста, игнорируйте этот параграф] Marshal.StructureToPtr если вы хотите передать данные в обратный вызов, но обязательно закрепите данные, которые вы передаете, чтобы убедиться, что это не сборщик мусора (см. GCHandle Больше подробностей).

РЕДАКТИРОВАТЬ:
С интересными словами svick (спасибо!) Я понимаю, что смешивал скопированный объект с прикрепленным.
Итак, чтобы разобраться:

  • Marshal.StructureToPtr следует использовать, если вы хотите скопировать существующую структуру данных и затем передать ее в функцию обратного вызова.
  • Если, с другой стороны, вы хотите использовать и существующую структуру данных (например, для изменения ее содержимого), вам следует использовать GCHandle чтобы закрепить его в памяти и предотвратить сборку мусора.
    Это, однако, добавит некоторые накладные расходы на обслуживание GCHandle,

Все, что вам нужно сделать, это создать функцию aC#, которая соответствует подписи делегата, которого вы объявили. Создайте делегат, удерживайте ссылку на этот делегат, чтобы он не собирал мусор, и вызовите импорт dll с делегатом в качестве обратного вызова.

так что у вас будет что-то вроде этого:

public void MyCallback(IntPtr P)
{
    //do something
}

// somewhere else in your code
var cb = new CallbackFunc(MyCallback);
CodecStart(..., cb, ...);

Функция обратного вызова - это код, который вызывается библиотекой DLL (в данном случае вы импортируете), которая выполняет некоторые функции. Вам также нужно научиться работать с делегатами в C#. Вы можете реализовать код следующим образом:

public void MyCallback(IntPtr p)
{
    //do something
}

и тогда ваш вызов dll будет таким:

[DllImport("WRG305API.dll")]
    public static extern bool CodecStart(int hRadio, func, IntPtr CallbackTarget);

Если вам нужны дополнительные рекомендации, опубликуйте версию C++ кода, который вы хотите преобразовать, и мы поможем вам с версией C#.

Другие вопросы по тегам