Предотвращение GC от принятия моего делегата в C #

Я возвращаюсь к сообщению, которое я сделал давно, так как я только что вернулся к работе с этим WRG305API.dll.

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

Я пытался написать приложение, которое взаимодействует с этой DLL, и спасибо ребятам, которые помогли мне тогда. Я смог заставить его работать в течение короткого периода времени.

Я был остановлен этой раздражающей проблемой, которая заявлена ​​как:

A callback was made on a garbage collected delegate of type 'WinFFT!WinFFT.winradioIO.winRadioIOWrapper+CallbackFunc::Invoke'. This may cause application crashes ...

Вот код оболочки:

using System;
using System.Collections.Generic;
using System.Text;

using System.Runtime.InteropServices;

namespace WinFFT.winradioIO
{
class winRadioIOWrapper
{
private const string APIDLL_PATH = "WRG305API.dll";

public delegate void CallbackFunc(IntPtr p);

public CallbackFunc mycallback;

[StructLayout(LayoutKind.Sequential)]
public struct Features
{
public uint feature;
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct RadioInfo
{
public uint length;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public string serialNumber;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public string productName;
public UInt64 minFrequency;
public UInt64 maxFrequency;
public Features feature;
}

[DllImport(APIDLL_PATH)]
public static extern int OpenRadioDevice(int deviceNumber);

[DllImport(APIDLL_PATH)]
public static extern bool CloseRadioDevice(int radioHandle);

[DllImport(APIDLL_PATH)]
public static extern int GetRadioList(ref RadioInfo info, int bufferSize, ref int infoSize);

[DllImport(APIDLL_PATH)]
public static extern bool IsDeviceConnected(int radioHandle);

[DllImport(APIDLL_PATH)]
public static extern bool GetInfo(int radioHandle, ref RadioInfo info);

[DllImport(APIDLL_PATH)]
public static extern int GetFrequency(int radioHandle);

[DllImport(APIDLL_PATH)]
public static extern bool SetFrequency(int radioHandle, int frequency);

[DllImport(APIDLL_PATH)]
private static extern bool CodecStart(int hRadio, CallbackFunc func, IntPtr CallbackTarget);

[DllImport(APIDLL_PATH)]
private static extern uint CodecRead(int hRadio, byte[] Buf, uint Size);

[DllImport(APIDLL_PATH)]
private static extern bool CodecStop(int hRadio);public static bool startIFStream(int radioHandle)
{bool bStarted = CodecStart(radioHandle, MyCallbackFunc, IntPtr.Zero);
return bStarted;
}

// Note: this method will be called from a different thread!
private static void MyCallbackFunc(IntPtr pData)
{
// Sophisticated work goes here...
}

public static void readIFStreamBlock(int radioHandle, byte[] streamDumpLocation, uint blockSize)
{
CodecRead(radioHandle, streamDumpLocation, blockSize);
}

public static bool stopIFStream(int radioHandle)
{
bool bStoped = CodecStop(radioHandle);
return bStoped;
}
}
}

Вот мой уровень класса интерфейса Application, который предоставляет дружественные методы для использования интерфейса dll:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

namespace WinFFT.winradioIO
{
class radioInterface
{
enum DeviceStatus { Disconnected, Connected, Unknown };
private static DeviceStatus deviceStatus = DeviceStatus.Unknown;

public static string radioName, serialNumber;
public static int minimumFreq, maximumFreq;

static int radioHandle;

static radioInterface()
{
InitializeDeviceConnection();
}

public static void duffMethod(IntPtr ptr)
{
}

private static void InitializeDeviceConnection()
{
winRadioIOWrapper.CloseRadioDevice(radioHandle);

deviceStatus = DeviceStatus.Disconnected;

// Get Radio Info
winRadioIOWrapper.RadioInfo radioInfo = new winRadioIOWrapper.RadioInfo();
int aStructSize = Marshal.SizeOf(radioInfo), anInfoSize = 0;
radioInfo.length = (uint)aStructSize;

if (winRadioIOWrapper.GetRadioList(ref radioInfo, aStructSize, ref anInfoSize) == 1)
{
radioName = radioInfo.productName;
serialNumber = radioInfo.serialNumber;

minimumFreq = (int)radioInfo.minFrequency;
maximumFreq = (int)radioInfo.maxFrequency;
}

// Open device
radioHandle = winRadioIOWrapper.OpenRadioDevice(0);

CheckDeviceConnection();
}

private static void CheckDeviceConnection()
{
bool anIsDeviceConnected = winRadioIOWrapper.IsDeviceConnected(radioHandle);

if (deviceStatus == DeviceStatus.Unknown ||
deviceStatus == DeviceStatus.Disconnected && anIsDeviceConnected ||
deviceStatus == DeviceStatus.Connected && !anIsDeviceConnected)
{
if (anIsDeviceConnected)
{
deviceStatus = DeviceStatus.Connected;

winRadioIOWrapper.startIFStream(radioHandle);

}
else
{
winRadioIOWrapper.CloseRadioDevice(radioHandle);

deviceStatus = DeviceStatus.Disconnected;
}
}
}

public static void ReadIFStream(ref byte[] bufferLocation)
{
winRadioIOWrapper.readIFStreamBlock(radioHandle, bufferLocation, (uint)bufferLocation.Length);
}

public static void SetFreq(int valueInHz)
{
winRadioIOWrapper.SetFrequency(radioHandle, valueInHz);
}

public static void ShutDownRadio()
{
winRadioIOWrapper.CloseRadioDevice(radioHandle);
}

}
}

Я понимаю, почему AVIDeveloper выбрал путь, он великолепен для непрерывной потоковой передачи данных из WinRadio Reciever (для чего предназначена DLL), но функция CodecRead в DLL позволяет копировать указанное количество байтов из радиомодуля. буфер. Это путь, по которому я пошел, поскольку я хочу контролировать, как регулярно я беру данные, и, следовательно, почему я оставил функцию делегата в покое. Но с этим, как это происходит в настоящее время, я теряю делегата в обертке для GC, и я действительно озадачен тем, как предотвратить это.

Заранее спасибо, ребята.

1

Решение

Сохраните делегата как поле.

private static CallbackFunc _callback = new CallbackFunc(MyCallbackFunc);

public static bool startIFStream(int radioHandle)
{bool bStarted = CodecStart(radioHandle, _callback, IntPtr.Zero);
return bStarted;
}
4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]