2013-12-22 1 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; 
}