Вызов функций 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#.