나는이 WRG305API.dll을 사용하는 것으로 돌아 가면서 오래 전 게시물을 언급하고 있습니다. 에 의뢰GC가 C에서 대리인을 만날 수 없도록 예방하기 #
: calling C++ functions containing callbacks in 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;
}
}
}
내 응용 프로그램은 사용하기 쉬운 방법을 제공합니다 클래스 계층의 인터페이스입니다 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의 용도)에서 지속적으로 데이터를 스트리밍하는 데 훌륭하지만 DLL의 CodecRead 함수는 라디오 버퍼에서 지정된 바이트 수를 복사 할 수 있습니다. 이것은 내가 데이터를 얼마나 정기적으로 가져갈 지 제어하고 싶기 때문에 제가가는 길입니다. 따라서 왜 델리게이트 함수를 혼자 남겨 두었습니다. 그러나 이것이 현재로서는 GC의 랩퍼에서 대리인을 잃어 버리고 있으며이를 방지하는 방법이 정말 부족합니다.
미리 감사드립니다.
위와 같은 응답에서 위임자 개체가 수집되지 않도록 GC.Alloc()을 사용해야 할 수도 있다는 특정 경고가 표시됩니다. –