无法弄清楚这个NullReferenceException

时间:2012-11-07 20:59:39

标签: c# vb.net nullreferenceexception

StackTrace:在System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode,UInt32 numBytes,NativeOverlapped * pOVERLAP) 资料来源:mscorlib

我在目标源中看到一些关于反射的东西。所以我会发布使用反射的极少量代码。

我通常能够轻松找到NullReferenceExceptions。这个虽然似乎不是我的代码,但我无法弄清楚是为了挽救我的生命。我在VB.net中有这个代码机器人,而C#.Net都有同样的问题。我认为我的问题在于我的指针是如何工作的,但我可能是错的。

代码很简单。我有一个条形码扫描仪通过usb连接,处于COM模式。我从另一个使用相同条形码的程序中复制了我的一些代码,这些代码完美无缺。但总结一下它的作用是打开,然后,通过使用反射,获取指向开放com端口的指针,设置一个DataEventListener。当我扫描我等待100ms的东西时,然后以字符串形式吐出数据。很简单。我的代码和另一个有问题的代码之间的区别在于我必须得到指针。要打开我的扫描仪,我需要使用IntPtr指向comport。 C#我使用IntPtr,在VB中我使用SafeFileHandle。两者都有相同的错误。发生错误的唯一时间是触发数据事件。这就是为什么我认为它必须与句柄。奇怪的是需要把手打开和关闭成像器,所以我知道我有一个有效的手柄。 (只是不知道它是否被保留)所以有没有人有任何帮助或资源,为什么我有这个错误?

首先...... VB.NET 公共类ImagerOposDevice     继承AbstractOPOSDevice     昏暗的PortHandle作为SafeFileHandle     昏暗的ImagerPort作为SerialPort     公共exitCode = 1     Sub New(ByVal comName As String)         ImagerPort =新的SerialPort(comName)     结束子

Protected Overrides Function Open() As Boolean
    ImagerPort.Open()
    PortHandle = GetHandleFromSerialPort(ImagerPort)

    If Not PortHandle.IsInvalid Then
        AddHandler ImagerPort.DataReceived, AddressOf DataReceivedHandler
    End If

    Return (Not PortHandle.IsInvalid)
End Function
Protected Overrides Sub Close()
    Try
        ImagerPort.Close()
        ImagerPort.Dispose()
    Catch ex As Exception
        Console.WriteLine(ex.Message)
        Console.ReadLine()
    End Try

End Sub

Protected Overrides Function RunCommand(ByVal X As Integer) As Boolean
    If X = 0 Then
        Return TurnImagerOn()
    ElseIf X = 1 Then
        Return TurnImagerOff()
    Else
        Return False
    End If
End Function

Private Shared Function GetHandleFromSerialPort(ByVal sp As SerialPort) As SafeFileHandle
    Dim BaseStream As Object = sp.BaseStream
    Dim BaseStreamType As Type = BaseStream.GetType
    Return BaseStreamType.GetField("_handle", BindingFlags.NonPublic Or BindingFlags.Instance).GetValue(BaseStream)
End Function
Private Sub DataReceivedHandler(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs)
    Try
        'Dim sp As SerialPort = CType(sender, SerialPort)
        System.Threading.Thread.Sleep(100)
        Dim len = ImagerPort.BytesToRead
        Dim buffer(len - 1) As Byte
        ImagerPort.Read(buffer, 0, len)

        Dim indata As String = System.Text.ASCIIEncoding.ASCII.GetString(buffer)
        Console.WriteLine("Data Received:")
        Console.Write(indata)
        TurnImagerOff()
    Catch ex As Exception
        Console.WriteLine(ex.Message)
    End Try
    exitCode = 0
End Sub

在我的主要形式中,它是直截了当的

    imager = New ImagerOposDevice("COM7")
    imager.OpenDevice()
    imager.SendCommand(0)
    For index = 1 To 100 Step 1
        System.Threading.Thread.Sleep(100)
        If imager.exitCode = 0 Then
            Exit For
        End If
    Next
    Console.WriteLine("Press Enter to Close")
    Console.ReadLine()
    CloseDevices()

现在为C#代码。它是一种窗体形式,但概念几乎是相同的。

    private SerialPort devicePort;
    private IntPtr deviceHandle;
    public Imager(string Port) : base()
    {
        devicePort = new SerialPort(Port);
    }
    protected override bool Open()
    {
        try
        {
            devicePort.Open();
            deviceHandle = GetHandleFromSerialPort(devicePort);
            Console.WriteLine("Device Handle:{0}", deviceHandle);
            Console.WriteLine("Device Open:{0}", devicePort.IsOpen);
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
        return devicePort.IsOpen;
    }
    protected override bool Close()
    {
            devicePort.Close();
            devicePort.Dispose();
        return true;
    }
    protected override CommandReturnCodes RunCommand(int command)
    {
        switch (command)
        {
            case 0:
                TurnImagerOn();
                break;
            case 1:
                TurnImagerOff();
                break;
            case 2:
                ReadLatch();
                break;
            case 3:
                GetPartNumber();
                break;
            case 4:
                GetSerialNumber();
                break;
            case 5:
                GetProductString();
                break;
            default:
                return CommandReturnCodes.FAIL;
        }
        return CommandReturnCodes.SUCCESS;
    }
    private static IntPtr GetHandleFromSerialPort(SerialPort sp)
    {
        Type t = typeof(SerialPort);
        BindingFlags bf = BindingFlags.Instance | BindingFlags.NonPublic;
        FieldInfo fi = t.GetField("internalSerialStream", bf);
        object ss = fi.GetValue(sp);
        Type t2 = fi.FieldType;
        FieldInfo fi2 = t2.GetField("_handle", bf);
        SafeFileHandle _handle = (SafeFileHandle)fi2.GetValue(ss);
        Type t3 = typeof(SafeFileHandle);
        FieldInfo fi3 = t3.GetField("handle", bf);
        IntPtr handle = (IntPtr)fi3.GetValue(_handle);
        return handle;
    }
    public void TurnOnImagerEventListener()
    {
        devicePort.DataReceived += new SerialDataReceivedEventHandler(devicePort_DataReceived);
    }

    void devicePort_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        System.Threading.Thread.Sleep(100);
        SerialPort imager = sender as SerialPort;
        byte[] buffer = new byte[imager.BytesToRead];
        imager.Read(buffer, 0, imager.BytesToRead);
        var scannedText = System.Text.Encoding.ASCII.GetString(buffer).Trim();
        SendBarcodeEvent(scannedText);
        TurnImagerOff();
        Console.WriteLine(scannedText);
    }

并称之为同样的事情

        im = new Imager(comportBox.Text);
        im.OpenDevice();
        im.TurnOnImagerEventListener();
        im.BarcodeScanned += new DataAvailableHandler(DeviceInformationReceived);

1 个答案:

答案 0 :(得分:0)

事实证明,LightStriker让我看到了昨天让我眼花缭乱的迷雾。我仍然没有vb.net版本工作,但它最终是因为我的C#程序中使用的IntPtr没有被保留,当一个单独的线程(IE的数据事件)调用它。当我逐步完成数据事件部分时,直到我调用TurnImagerOff()部分才会失败。这是一个简单的解决方案,我所要做的就是将我的串口和我的IntPtr改为静态成员。我在VB.net代码中尝试过这个...但显然我不够聪明,无法解决这个问题。哦,今天是另一天,至少有50%的代码可以使用。

所以对于那些有空引用错误但无法在任何地方找到它的人。并且Stack Trace不会给你一个行号,检查正在调用任何指针成员的另一个线程上运行的任何内容。 (或反映为指针)。检查数据事件,线程池,后台工作人员,计时器,代表等。我希望我的愚蠢行为会帮助其他人。