вызов функций C ++, содержащих обратные вызовы в C # - PullRequest
4 голосов
/ 12 марта 2012

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

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

это из API WinRadio, найденного здесь 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 ]

4 голосов
/ 12 марта 2012

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

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, чтобы закрепить в памяти и не допустить ее попадания в мусор.-collected.
    Это, однако, добавит некоторые накладные расходы на обслуживание для GCHandle.
0 голосов
/ 12 марта 2012

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

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

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

// somewhere else in your code
var cb = new CallbackFunc(MyCallback);
CodecStart(..., cb, ...);
0 голосов
/ 12 марта 2012

A функция обратного вызова - это код, который вызывается библиотекой 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 #.

...