0

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

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

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

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

首先.. VB.NET Public Class ImagerOposDevice Inherits AbstractOPOSDevice Dim PortHandle As SafeFileHandle Dim ImagerPort As SerialPort Public exitCode = 1 Sub New(ByVal comName As String) ImagerPort = New SerialPort(comName) End Sub

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);
4

1 回答 1

0

事实证明,LightStriker 帮助我看到了昨天让我失明的迷雾。我仍然没有工作的 vb.net 版本,但它最终是当一个单独的线程(即 dataevent)调用它时,我的 C# 程序中使用的 IntPtr 没有被保留。当我单步执行数据事件部分时,它直到我调用 TurnImagerOff() 部分才失败。这是一个简单的解决方法,我所要做的就是将我的串行端口和我的 IntPtr 都更改为静态成员。我在 VB.net 代码中尝试过……但显然我不够聪明,无法弄清楚。哦,今天又是一天,我的代码至少有 50% 有效。

所以对于那些有空引用错误并且在任何地方都找不到它的人来说。而且堆栈跟踪不会给你一个行号,检查在另一个线程上运行的任何东西,它正在调用任何指针成员。(或反映为指针)。检查数据事件、线程池、后台工作人员、计时器、委托等。我希望我的愚蠢能帮助别人。

于 2012-11-08T12:21:49.043 回答