Advantech 硬件控制卡的 c# 接口函数

最近要用到 Advantech 的 PCI-1752、PCI-1754 卡,但却苦于没有 c# 的调用接口函数。这两天接连奋战,根据 Delphi 的调用接口给转换掉,终于调试出来了,辛苦。

现共享一下主要的接口部分,免得大家多走弯路。

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace Hardware.Advantech.Interface
{
    
#region PT_DEVLIST

    
/// <summary>
    
/// 安装在主机上所有的自动控制板卡设备结构。
    
/// </summary>
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack=1)]
    
public struct PT_DEVLIST
    {
        
public UInt32 dwDeviceNum;
        
/// <summary>
        
/// 设备名,50个字符长。
        
/// </summary>
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst=50)] 
        
public string szDeviceName;
        
/// <summary>
        
/// 设备的端口数,一般为8个端口。
        
/// </summary>
        public Int16 nNumOfSubdevices;
    }

    
/// <summary>
    
/// 用于 DRV_DeviceGetList 调用返回的设备列表结构。
    
/// 这一块真难改呀~~,耗费了我一整个晚上的时间~~~~~~~
    
/// 网上也找不到资料,最可气的是.Net带的函数都不支持结构数组,只好变相再来一个结构了~~
    
/// xiefang 2007/09/02
    
/// </summary>
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    
public struct PT_DEVLISTARRAY
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst 
= AdvantechAPI.MaxEntries)]
        
public PT_DEVLIST[] Devices;
    }

    
#endregion

    
#region PT_DeviceGetFeatures

    [StructLayout(LayoutKind.Sequential, CharSet 
= CharSet.Ansi, Pack = 1)]
    
internal struct PT_DeviceGetFeatures
    {
        
public IntPtr Buffer;
        
public int Size;
    }

    [StructLayout(LayoutKind.Sequential, CharSet 
= CharSet.Ansi, Pack = 1)]
    
public struct GainListBlob
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst 
= 448)]
        
public byte[] gainArr;
    }

    
/// <summary>
    
/// Define hardware board(device) features.
    
/// </summary>
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    
public struct DEVFEATURES
    {
        
/// <summary>
        
/// device driver version, array[0..7]
        
/// </summary>
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
        
public string szDriverVer;
        
/// <summary>
        
/// device driver name, array[0..MAX_DRIVER_NAME_LEN-1]
        
/// </summary>
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = AdvantechAPI.MAX_DRIVER_NAME_LEN)]
        
public string szDriverName;
        
/// <summary>
        
/// board ID, DWORD 4 bytes
        
/// </summary>
        public uint dwBoardID;
        
/// <summary>
        
/// Max. number of differential channel
        
/// </summary>
        public ushort usMaxAIDiffChl;
        
/// <summary>
        
/// Max. number of single-end channel
        
/// </summary>
        public ushort usMaxAISiglChl;
        
/// <summary>
        
/// Max. number of D/A channel
        
/// </summary>
        public ushort usMaxAOChl;
        
/// <summary>
        
/// Max. number of digital out channel
        
/// </summary>
        public ushort usMaxDOChl;
        
/// <summary>
        
/// Max. number of digital input channel
        
/// </summary>
        public ushort usMaxDIChl;
        
/// <summary>
        
/// specifies if programmable or not
        
/// </summary>
        public ushort usDIOPort;
        
/// <summary>
        
/// Max. number of Counter/Timer channel
        
/// </summary>
        public ushort usMaxTimerChl;
        
/// <summary>
        
/// Max number of  alram channel
        
/// </summary>
        public ushort usMaxAlarmChl;
        
/// <summary>
        
/// number of bits for A/D converter
        
/// </summary>
        public ushort usNumADBit;
        
/// <summary>
        
/// A/D channel width in bytes.
        
/// </summary>
        public ushort usNumADByte;
        
/// <summary>
        
/// number of bits for D/A converter. 
        
/// </summary>
        public ushort usNumDABit;
        
/// <summary>
        
/// D/A channel width in bytes.
        
/// </summary>
        public ushort usNumDAByte;
        
/// <summary>
        
/// Max. number of gain code
        
/// </summary>
        public ushort usNumGain;
        
/// <summary>
        
/// Gain listing array[0..15]
        
/// </summary>
        public GainListBlob glGainList;
        
/// <summary>
        
/// Permutation array[0..3]
        
///   Bit 0: Software AI                                           
        
///   Bit 1: DMA AI                                                
        
///   Bit 2: Interrupt AI                                          
        
///   Bit 3: Condition AI
        
///   Bit 4: Software AO
        
///   Bit 5: DMA AO
        
///   Bit 6: Interrupt AO
        
///   Bit 7: Condition AO
        
///   Bit 8: Software DI
        
///   Bit 9: DMA DI
        
///   Bit 10: Interrupt DI
        
///   Bit 11: Condition DI
        
///   Bit 12: Software DO
        
///   Bit 13: DMA DO
        
///   Bit 14: Interrupt DO
        
///   Bit 15: Condition DO
        
///   Bit 16: High Gain
        
///   Bit 17: Auto Channel Scan
        
///   Bit 18: Pacer Trigger
        
///   Bit 19: External Trigger
        
///   Bit 20: Down Counter
        
///   Bit 21: Dual DMA
        
///   Bit 22: Monitoring
        
///   Bit 23: QCounter                                             
        
/// </summary>
        public uint dwPermutation0;
        
public uint dwPermutation1;
        
public uint dwPermutation2;
        
public uint dwPermutation3;
    }

    
#endregion

    
/// <summary>
    
/// 写入设备的数据结构。
    
/// </summary>
    [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Pack = 1)]
    
internal struct PT_DioWritePortByte
    {
        [FieldOffset(
0)]
        
public short Port;
        [FieldOffset(
2)]
        
public short Mask;
        [FieldOffset(
4)]
        
public short State;
    }

    
/// <summary>
    
/// 读取IO设备的数据结构。
    
/// </summary>
    [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Pack = 1)]
    
internal struct PT_DioReadPortByte
    {
        [FieldOffset(
0)]
        
public short Port;
        [FieldOffset(
4)]
        
public IntPtr value;
    }

    
/// <summary>
    
/// 硬件调用的 API 函数封装类。
    
/// </summary>
    public static class AdvantechAPI
    {
        
/// <summary>
        
/// 最大设备个数
        
/// </summary>
        public const short MaxEntries = 255;
        
public const short MaxDevices = 255;
        
public const short MAX_DRIVER_NAME_LEN = 16;

        
#region interface

        
/// <summary>
        
/// 获取设备列表。
        
/// </summary>
        
/// <param name="deviceList">返回的设备列表清单数组</param>
        
/// <param name="maxEntries">最大的设备数</param>
        
/// <param name="outEntries">返回的设备数</param>
        
/// <returns>返回值为 0 则表示执行成功,否则执行失败。</returns>
        [DllImport("adsapi32.dll", CharSet = CharSet.Ansi)]
        
static extern int DRV_DeviceGetList(IntPtr deviceList, Int16 maxEntries, ref short outEntries);

        [DllImport(
"adsapi32.dll", CharSet = CharSet.Ansi)]
        
static extern int DRV_DeviceGetFeatures(int DriverHandle, ref PT_DeviceGetFeatures lpDeviceGetFeatures);

        
/// <summary>
        
/// 获取设备列表个数,我就基本用不到它,姑且留着。
        
/// </summary>
        
/// <param name="numOfDevices"></param>
        
/// <returns></returns>
        [DllImport("adsapi32.dll", CharSet = CharSet.Ansi)]
        
public static extern int DRV_DeviceGetNumOfList(ref short numOfDevices);

        
/// <summary>
        
/// 打开设备。
        
/// </summary>
        
/// <param name="deviceNum">设备号</param>
        
/// <param name="driverHandle">设备句柄</param>
        
/// <returns></returns>
        [DllImport("adsapi32.dll", CharSet = CharSet.Ansi)]
        
static extern int DRV_DeviceOpen(uint deviceNum, ref int deviceHandle);

        
/// <summary>
        
/// 关闭设备。
        
/// </summary>
        
/// <param name="deviceHandle"></param>
        
/// <returns></returns>
        [DllImport("adsapi32.dll", CharSet = CharSet.Ansi)]
        
static extern int DRV_DeviceClose(ref int deviceHandle);
        
/// <summary>
        
/// 向端口写数字信号。
        
/// </summary>
        
/// <param name="DriverHandle"></param>
        
/// <param name="lpDioWritePortByte"></param>
        
/// <returns></returns>
        [DllImport("adsapi32.dll", CharSet = CharSet.Ansi)]
        
static extern int DRV_DioWritePortByte(int driverHandle, ref PT_DioWritePortByte lpDioWritePortByte);

        [DllImport(
"adsapi32.dll", CharSet = CharSet.Ansi)]
        
static extern int DRV_DioReadPortByte(int driverHandle, ref PT_DioReadPortByte lpDioReadPortByte);

        
#endregion

        
/// <summary>
        
/// 打开设备
        
/// </summary>
        
/// <param name="deviceNum">设备号</param>
        
/// <param name="deviceHandle">设备句柄</param>
        
/// <returns>返回错误代码,如果无错误,则返回0。</returns>
        public static int OpenDevice(uint deviceNum, ref int deviceHandle)
        {
            
return DRV_DeviceOpen(deviceNum, ref deviceHandle);
        }

        
/// <summary>
        
/// 关闭设备。
        
/// </summary>
        
/// <param name="deviceHandle"></param>
        public static void CloseDevice(int deviceHandle)
        {
            DRV_DeviceClose(
ref deviceHandle);
        }

        
/// <summary>
        
/// 获取主机上安装的设备列表。
        
/// </summary>
        
/// <returns>返回错误代码,如果无错误,则返回0。</returns>
        public static int GetDeviceList(out PT_DEVLISTARRAY deviceList, ref short outEntries)
        {
            deviceList 
= new PT_DEVLISTARRAY();
            
int _DeviceListLenght = Marshal.SizeOf(deviceList);
            IntPtr _DeviceListPoint 
= Marshal.AllocHGlobal(_DeviceListLenght);
            
//打开设备的检查过程
            int errorCode = AdvantechAPI.DRV_DeviceGetList(_DeviceListPoint, MaxEntries, ref outEntries);
            deviceList 
= (PT_DEVLISTARRAY)Marshal.PtrToStructure(_DeviceListPoint, typeof(PT_DEVLISTARRAY));
            Marshal.FreeHGlobal(_DeviceListPoint);
            
return errorCode;
        }

        
public static int GetFeatures(int deviceHandle, out DEVFEATURES outDevFeatures)
        {
            
int iLength;
            
int ErrCde = 0;
            PT_DeviceGetFeatures ptDevGetFeatures 
= new PT_DeviceGetFeatures();
            outDevFeatures 
= new DEVFEATURES();

            outDevFeatures.szDriverVer 
= "?";
            outDevFeatures.szDriverName 
= "?";
            iLength 
= Marshal.SizeOf(outDevFeatures);
            
//and reserve the space 
            IntPtr DevFeaturesPointer = Marshal.AllocHGlobal(iLength);
            
//Copy the pointer into the struct
            ptDevGetFeatures.Buffer = DevFeaturesPointer;
            
//and get the features
            ErrCde = DRV_DeviceGetFeatures(deviceHandle, ref ptDevGetFeatures);
            
if (ErrCde == 0)
            {
                outDevFeatures 
= (DEVFEATURES)Marshal.PtrToStructure(DevFeaturesPointer, typeof(DEVFEATURES));
            }
            
else
            {
                
//Error
            }
            Marshal.FreeHGlobal(DevFeaturesPointer);
            
return ErrCde;
        }

        
/// <summary>
        
/// 数字信号按端口输出。
        
/// </summary>
        
/// <param name="deviceHandle"></param>
        
/// <param name="port"></param>
        
/// <param name="value"></param>
        
/// <param name="mask"></param>
        
/// <returns></returns>
        public static int Digital_WriteByteToPort(int deviceHandle, short port, short value, short mask)
        {
            PT_DioWritePortByte data 
= new PT_DioWritePortByte();
            data.Port 
= port;
            data.State 
= value;
            data.Mask 
= mask;
            
return DRV_DioWritePortByte(deviceHandle, ref data);
        }

        
public static int Digital_WriteByteToPort(int deviceHandle, short port, short value)
        {
            
return Digital_WriteByteToPort(deviceHandle, port, value, 255);
        }

        
/// <summary>
        
/// 从指定的端口获取数据。
        
/// </summary>
        
/// <param name="deviceHandle"></param>
        
/// <param name="port"></param>
        
/// <param name="value"></param>
        
/// <returns></returns>
        public static int Digital_ReadByteFromPort(int deviceHandle, short port, out short value)
        {
            
int error = 0;
            
short tempValue = 0;
            IntPtr vpoint 
= Marshal.AllocHGlobal(Marshal.SizeOf(tempValue));
            
try
            {
                Marshal.StructureToPtr(tempValue, vpoint, 
false);
                PT_DioReadPortByte data 
= new PT_DioReadPortByte();
                data.Port 
= port;
                data.value 
= vpoint;
                error 
= DRV_DioReadPortByte(deviceHandle, ref data);
                tempValue 
= (short)Marshal.PtrToStructure(vpoint, typeof(short));
                value 
= tempValue;
            }
            
finally
            {
                Marshal.FreeHGlobal(vpoint);
            }
            
return error;
        }

    }

}


PCI_Base:

using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Collections;
using System.Diagnostics;
using System.Text;
using System.Windows.Forms;

namespace Hardware.Advantech
{
    
using System.Runtime.InteropServices;
    
using Hardware.Advantech.Interface;

    
/// <summary>
    
/// PCI 硬件的基础类。
    
/// </summary>
    [ToolboxItem(false), DefaultProperty("Connected")]
    
public partial class PCI_Base : Component
    {
        
#region 公共静态变量

        
/// <summary>
        
/// 获取主机上能检测到的设备个数,这个设备数量包括输入设备以及输出设备。
        
/// </summary>
        private static short _OutEntries = 0;
        
private static PT_DEVLISTARRAY _DeviceList;

        
#endregion

        
private string _DeviceName = string.Empty;
        
private int _DeviceIndex = -1;
        
private int _PortCount = 0;
        
private uint _DeviceNum = 0;
        
private bool _Connected = false;
        
protected int _DeviceHandle = -1;
        
protected DEVFEATURES _DevFeatures;

        
public PCI_Base()
        {
            InitializeComponent();
        }

        
public PCI_Base(IContainer container)
        {
            container.Add(
this);

            InitializeComponent();
        }

        
#region 公共属性

        
#region 静态全局属性

        
/// <summary>
        
/// 获取主机上能检测到的设备个数,这个设备数量包括输入设备以及输出设备。
        
/// </summary>
        public static short OutEntries
        {
            
get { return _OutEntries; }
        }

        
/// <summary>
        
/// 
        
/// </summary>
        public static PT_DEVLISTARRAY DeviceList
        {
            
get { return _DeviceList; }
        }

        
#endregion

        
/// <summary>
        
/// 获取设备名称。
        
/// </summary>
        [Browsable(false)]
        
public string DeviceName
        {
            
get { return _DeviceName; }
        }

        
/// <summary>
        
/// 获取设备索引。
        
/// </summary>
        [Browsable(false)]
        
public int DeviceIndex
        {
            
get { return _DeviceIndex; }
        }

        
/// <summary>
        
/// 获取设备端口数。
        
/// </summary>
        [Browsable(false)]
        
public int PortCount
        {
            
get { return _PortCount; }
        }

        
/// <summary>
        
/// 获取设备数。
        
/// </summary>
        [Browsable(false)]
        
public uint DeviceNum
        {
            
get { return _DeviceNum; }
        }

        
/// <summary>
        
/// 获取设备的识别名。
        
/// </summary>
        [Browsable(false)]
        
public virtual string DeviceSymbol 
        {
            
get { return ""; }
        }

        
/// <summary>
        
/// 获取或设置连接属性。
        
/// </summary>
        [Description("获取或设置连接属性。"), DefaultValue(false)]
        
public bool Connected
        {
            
get { return _Connected; }
            
set
            {
                
if (value)
                {
                    
//打开设备的检查过程
                    if (_OutEntries <= 0)
                    {
                        
if (!RefreshDeviceList()) return;
                    }
                    _DeviceIndex 
= GetDeviceIndex();
                    
//如果找到设备的索引,则继续查找端口号
                    if (_DeviceIndex != -1)
                    {
                        _DeviceName 
= PCI_Base.DeviceList.Devices[_DeviceIndex].szDeviceName;
                        
int portCount = _DeviceList.Devices[_DeviceIndex].nNumOfSubdevices;
                        
if (portCount > AdvantechAPI.MaxDevices) portCount = AdvantechAPI.MaxDevices;
                        _DeviceNum 
= _DeviceList.Devices[_DeviceIndex].dwDeviceNum;

                        
//打开设备
                        if (!IsError(AdvantechAPI.OpenDevice(_DeviceNum, ref _DeviceHandle)))
                        {
                            _PortCount 
= GetPortCount(_DeviceHandle, out _DevFeatures);
                            _Connected 
= value;
                        }
                    }
                }
                
else
                {
                    AdvantechAPI.CloseDevice(_DeviceHandle);
                    _DeviceIndex 
= -1;
                    _PortCount 
= 0;
                    _DeviceNum 
= 0;
                    _DeviceHandle 
= -1;
                    _DeviceName 
= "";
                    _Connected 
= value;
                }
                
//触发连接变更事件
                if (OnConnectionChanged != null) OnConnectionChanged(this, EventArgs.Empty);
            }
        }

        
#endregion

        
#region 方法

        
/// <summary>
        
/// 检查错误代码是否是发生了错误。
        
/// </summary>
        
/// <param name="errorCode"></param>
        
/// <returns>如果是错误,则返回 True,否则返回 False。</returns>
        protected bool IsError(int errorCode)
        {
            
if (errorCode != 0
                MessageBox.Show(
"Error");
            
return errorCode != 0;
        }

        
/// <summary>
        
/// 更新设备列表。该方法一般在创建基于 PCI_BASE 的对象时会自动进行调用,以创建
        
/// 主机上存在的设备列表。除非需要手工刷新,否则,不应直接调用该方法。
        
/// </summary>
        public static bool RefreshDeviceList()
        {
            Debug.WriteLine(
"Execute RefreshDeviceList");
            
//打开设备的检查过程
            return AdvantechAPI.GetDeviceList(out _DeviceList, ref _OutEntries) == 0;
        }

        
/// <summary>
        
/// 获取设备索引号
        
/// </summary>
        
/// <returns></returns>
        protected int GetDeviceIndex()
        {
            
int iIndex = -1;
            
for (int i = 0; i < OutEntries; i++)
            {
                
string sDeviceName = PCI_Base.DeviceList.Devices[i].szDeviceName.ToUpper().Trim();
                
if (sDeviceName.StartsWith(DeviceSymbol.ToUpper()))
                {
                    iIndex 
= i;
                    
break;
                }
            }
            
return iIndex;
        }

        
/// <summary>
        
/// 获取端口数量,不应直接使用。
        
/// </summary>
        
/// <param name="deviceHandle"></param>
        
/// <param name="deviceFeatures"></param>
        
/// <returns></returns>
        protected virtual int GetPortCount(int deviceHandle, out DEVFEATURES deviceFeatures)
        {
            deviceFeatures 
= new DEVFEATURES();
            
return 0;
        }

        
private short ReadData(short port)
        {
            
short value = 255;
            IsError(AdvantechAPI.Digital_ReadByteFromPort(_DeviceHandle, port, 
out value));
            
return value;
        }

        
private void WriteData(short port, short value)
        {
            WriteData(port, value, 
255);
        }

        
private void WriteData(short port, short value, short mask)
        {
            IsError(AdvantechAPI.Digital_WriteByteToPort(_DeviceHandle, port, value, mask));
        }

        
/// <summary>
        
/// 清除所有端口数据。
        
/// </summary>
        public void Clear()
        {
            
for (short i = 0; i < PortCount; i++)
                
this[i] = 0;
        }

        
/// <summary>
        
/// 获取或设置指定端口数据。
        
/// </summary>
        
/// <param name="port">端口号,范围:0..最大端口 - 1。</param>
        
/// <returns>端口值</returns>
        public short this[short port]
        {
            
get
            {
                
return ReadData(port);
            }
            
set
            {
                WriteData(port, value);
            }
        }

        
/// <summary>
        
/// 获取或设置指定端口指定位的值。
        
/// </summary>
        
/// <param name="port">端口号,范围:0..最大端口 - 1。</param>
        
/// <param name="bit">端口中指定的位,范围:0..7。</param>
        
/// <returns></returns>
        public bool this[short port, int bit]
        {
            
get
            {
                
short a = (short)Math.Pow(2, bit);
                
int[] dt = new int[1] { (intthis[port] };
                BitArray result 
= new BitArray(dt);
                
if (result.Length > bit)
                {
                    
return result[bit];
                }
                
else return false;
            }
            
set
            {
                
if (value)
                {
                    
short a = (short)Math.Pow(2, bit);
                    
this[port] |= a;
                }
                
else
                {
                    
short a = (short)(255 - (short)Math.Pow(2, bit));
                    
this[port] &= a;
                }
            }
        }

        
#endregion

        
#region 公共事件

        
/// <summary>
        
/// 触发连接变更事件
        
/// </summary>
        public event EventHandler OnConnectionChanged;

        
#endregion
    }
}


 PCI_1752:

using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Collections;
using System.Diagnostics;
using System.Text;

namespace Hardware.Advantech
{
    
using Hardware.Advantech.Interface;

    
/// <summary>
    
/// 输出卡类。
    
/// </summary>
    [ToolboxItem(true)]
    
public partial class PCI_1752 : PCI_Base
    {
        
public PCI_1752()
        {
            InitializeComponent();
        }

        
public PCI_1752(IContainer container)
        {
            container.Add(
this);

            InitializeComponent();
        }

        
public override string DeviceSymbol
        {
            
get { return "PCI-1752"; }
        }

        
protected override int GetPortCount(int deviceHandle, out DEVFEATURES deviceFeatures)
        {
            
int portCount = 0;
            
if (!IsError(AdvantechAPI.GetFeatures(deviceHandle, out deviceFeatures)))
            {
                portCount 
= _DevFeatures.usMaxDOChl / 8;
            }
            
return portCount;
        }
    }
}

PCI_1754:

using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Windows.Forms;

namespace Hardware.Advantech
{
    
using Hardware.Advantech.Interface;

    
/// <summary>
    
/// 输入卡类。
    
/// </summary>
    [ToolboxItem(true), DefaultEvent("DataInput")]
    
public partial class PCI_1754 : PCI_Base
    {
        
int _interval = 100;

        
public PCI_1754()
        {
            InitializeComponent();
        }

        
public PCI_1754(IContainer container)
        {
            container.Add(
this);

            InitializeComponent();
        }

        
public override string DeviceSymbol
        {
            
get { return "PCI-1754"; }
        }

        
protected override int GetPortCount(int deviceHandle, out DEVFEATURES deviceFeatures)
        {
            
int portCount = 0;
            
if (!IsError(AdvantechAPI.GetFeatures(deviceHandle, out deviceFeatures)))
            {
                portCount 
= _DevFeatures.usMaxDIChl / 8;
            }
            
return portCount;
        }

        
#region Thread

        
/// <summary>
        
/// 获取或设置读信号线程的间隔时间,单位为毫秒。
        
/// </summary>
        [Browsable(true), Description("获取或设置读信号线程的间隔时间,单位为毫秒。"), DefaultValue(100)]
        
public int Interval
        {
            
get
            {
                
return _interval;
            }
            
set
            {
                _interval 
= value;
            }
        }

        
/// <summary>
        
/// 启动读线程。
        
/// </summary>
        public void StartReadWork()
        {
            backgroundReadWorker.RunWorkerAsync();
        }

        
/// <summary>
        
/// 停止读线程。
        
/// </summary>
        public void StopReadWork()
        {
            backgroundReadWorker.CancelAsync();
        }

        
private void backgroundReadWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker 
= sender as BackgroundWorker;
            
do
            {
                
for (short i = 0; i < PortCount; i++)
                {
                    
for (short j = 0; j < 8; j++)
                    {
                        
if (this[i, j] == true)
                        {
                            
if (DataInput != null)
                            {
                                DataInput(
this, i, j);
                            }
                        }
                    }
                }
                System.Threading.Thread.Sleep(_interval);
            }
            
while (!worker.CancellationPending);
            e.Cancel 
= true;
        }

        
private void backgroundReadWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            
if (e.Error != null)
            {
                
//MessageBox.Show(e.Error.Message);
            }
            
else if (e.Cancelled)
            {
                
// Next, handle the case where the user canceled 
                
// the operation.
                
// Note that due to a race condition in 
                
// the DoWork event handler, the Cancelled
                
// flag may not have been set, even though
                
// CancelAsync was called.
                
//触发停止事件。
            }
            
else
            {
                
// Finally, handle the case where the operation 
                
// succeeded.
                
//正常结束。
            }
        }

        
public event RaiseDataInput DataInput;

        
#endregion
    }

    
public delegate void RaiseDataInput(object sender, short port, short bit);
}
原文地址:https://www.cnblogs.com/xiefang2008/p/881907.html