2

我指的是我很久以前发表的一篇文章,因为我刚刚开始使用这个 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;
        }
    }
}

这是我的应用程序接口类层,它提供了使用 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,我真的很难过如何防止这种情况。

在此先感谢各位。

4

1 回答 1

4

将委托存储为字段。

private static CallbackFunc _callback = new CallbackFunc(MyCallbackFunc);

public static bool startIFStream(int radioHandle)
{


   bool bStarted = CodecStart(radioHandle, _callback, IntPtr.Zero);
   return bStarted;
}
于 2013-12-22T23:21:36.477 回答