Interfacing C# to very old ActiveX control

1

I'm trying to integrate an old RFSpace SDR-IQ radio into an existing C# program. SDR-IQ info: http://www.rfspace.com/RFSPACE/SDR-IQ.html

The SDR-IQ connects to the PC via USB.

I've found a very old ActiveX control that successfully drops onto the C# dialog (after registering the DLL manually). ActiveX control: http://www.moetronix.com/files/sdr14xsdk127.zip

Here is the C# metadata for the control:

namespace AxSDR14XLib
{
    [DefaultEvent("StatusChange")]
    [DesignTimeVisible(true)]
    public class AxSDR14X : AxHost
    {
        public AxSDR14X();

        [DispId(12)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual short BootRevision { get; set; }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [DispId(1)]
        public virtual int ClockFrequency { get; set; }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [DispId(2)]
        public virtual string DeviceName { get; set; }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [DispId(3)]
        public virtual int FirmwareRevision { get; set; }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [DispId(4)]
        public virtual int HFgain { get; set; }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [DispId(5)]
        public virtual int IFfilter { get; set; }
        [DispId(10)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual int IFgain { get; set; }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [DispId(6)]
        public virtual int InputSource { get; set; }
        [DispId(7)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual int InterfaceVersion { get; set; }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [DispId(13)]
        public virtual double IQOffset { get; set; }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [DispId(8)]
        public virtual int NCOfrequency { get; set; }
        [DispId(11)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual int SampleRate { get; set; }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [DispId(9)]
        public virtual string SerialNumber { get; set; }

        public event _DSDR14XEvents_DataRdyEventHandler DataRdy;
        public event _DSDR14XEvents_StatusChangeEventHandler StatusChange;
        public event EventHandler UartDataRdy;

        public virtual void AboutBox();
        protected override void AttachInterfaces();
        public virtual void CloseI2CPort();
        public virtual void CloseSpiPort();
        public virtual void CloseUartPort();
        protected override void CreateSink();
        protected override void DetachSink();
        public virtual int GetDoubleData(ref double dataArray);
        public virtual bool GetFftDoubleData(ref double dataArray);
        public virtual bool GetFftScreendata(int plotHeght, int plotWidth, double maxdB, double mindB, int startFreq, int endFreq, ref int plotBuf);
        public virtual int GetIntegerData(ref short dataArray);
        public virtual int GetLongData(ref int dataArray);
        public virtual short GetUartData(ref short uartRxArray);
        public virtual void InitControl();
        public virtual void OpenI2CPort(short adrWidth);
        public virtual void OpenSpiPort(short clkPolarity);
        public virtual void OpenUartPort(int baudRate, short parity, bool flowControl);
        public virtual void ResetFftAverage();
        public virtual void Send6620RawCmd(short address, short d0, short d1, short d2, short d3, short d4);
        public virtual void SendI2CData(ref short txDataArray, short numDataItems);
        public virtual void SendSpiData(int data32High, int data32Low, short numberBits);
        public virtual void SendUartData(ref short uartTxArray, short numDataItems);
        public virtual void SetupFFT(int fftPoints, short fftaverages, bool fftInverted);
        public virtual void Start(short blocks, short mode);
        public virtual void Stop();
    }

The control's .InitControl() and .Start() methods work correctly. The StatusChange and DataRdy events also work. So, the control is successfully communicating with the radio.

The problem comes when I try to get the data out of the control in the DataRdy event handler via .GetLongData().

Despite many hours of googling, no matter what I try, my code just crashes with the error:

The program '[9036] sdriq.vshost.exe: Managed (v4.0.30319)' has exited with code -1073741819 (0xc0000005).

There isn't any further detailed information about the crash in the Exception object.

Here's one example of a call to .GetLongData() that fails:

private int[] m_SdrData = new int[40000];

private void axSDR14X1_DataRdy(object sender, AxSDR14XLib._DSDR14XEvents_DataRdyEvent e)
{
    unsafe
    {
        var unmanagedArray = (int*)Marshal.AllocHGlobal(m_SdrData.Length * sizeof(int));
        int samples = axSDR14X1.GetLongData(ref unmanagedArray[0]);
        for (int i = 0; i < m_SdrData.Length; i++) m_SdrData[i] = unmanagedArray[i];
        Marshal.FreeHGlobal((IntPtr)unmanagedArray);
    }
}

The original author of the control did reply when I wrote to the address in the control's readme: "Yes the dll i wrote along time ago was an activex dll and I don't think uSoft allows passing memory pointers anymore. I don't know C# but I suspect it doesn't allow direct memory pointers either."

So though it's not explicitly stated, I'm 99% sure the control is written in C++.

I'm not very savvy when it comes to calling into C++ from C#. Given the signature of .GetLongData shown above, I'm looking for help in finding the magical combination of unsafe, IntPtr, Marshal.AllocHGlobal, etc., to get the radio's data from the unmanaged C++ ActiveX control into my managed C# code.

Thanks very much in advance for any help.

c#
memory
unmanaged
software-defined-radio
asked on Stack Overflow Dec 17, 2018 by TJH • edited Dec 17, 2018 by David Tansey

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0