2013-12-22 23 views
1

我回头看了很久以前的一篇文章,因为我刚刚回到使用此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封装中的代表,并且我非常难以设法防止这种情况发生。

谢谢先进的家伙。

+0

您在答案中得到了一个特定警告,您可能必须使用GC.Alloc()来防止收集委托对象。 –

回答

3

将委托存储为字段。

private static CallbackFunc _callback = new CallbackFunc(MyCallbackFunc); 

public static bool startIFStream(int radioHandle) 
{ 


    bool bStarted = CodecStart(radioHandle, _callback, IntPtr.Zero); 
    return bStarted; 
}