本帖最后由 anneall 于 2012-07-28 11:00:08 编辑

解决方案 »

  1.   

    据传这是一个bug,微软至今未能修复。
    一些解决方案都包括部分或者全部使用WinAPI。
      

  2.   

    关闭程序时,还会访问串口,但实际上已经拔掉了USB转串口线,导致提示错误“对端口的访问被拒绝”。http://blog.csdn.net/wuyazhe/article/details/5606276看看这篇文章,看看有没有帮助
      

  3.   

    问题补充:
    我刚才试了下添加timer控件不断检测com口,然后或者关闭,或者重新赋值为其他com口,或者dispose,还是解决不了问题,软件关闭时仍然报错
    啊啊啊啊啊啊啊啊啊啊啊啊啊,555555,还以为这个方法可行呢,这下彻底没招了啊。巨期待高手。。
    另外,我就纳闷了,使用timer控件监测串口,发现没了映射com口后,serialport就重新改变了,软件代码与映射端口毛关系没有了,怎么关闭还会报错?不是修改后与映射的那个com口都没有关系了吗
    想不通啊想不通,@高手,嘿嘿嘿
      

  4.   

    不可能真的是微软的bug吧?晕啊。。
    另外,三楼的哥们,可不可以在关闭的时候禁止软件访问串口?谢谢啦。。
      

  5.   

    弱弱地以为,可以试试DefWndProc(ref Message m)方法来监测插入或拔出PC的硬件,如果是你的设备,你就把它映射的COM口关掉。
    不确定的是,你插拔你的设备时,DefWndProc(ref Message m)方法是否能监测到。以下代码试试能否监测到你的设备:(如果插拔设备能,弹出了MessageBox,就说明能监测到;如果没弹出,就说明监测不到。)
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;namespace TorquePcSoftware
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }        int i = 0;
            protected override void DefWndProc(ref Message m)
            {
                if (m.Msg == 0x0219)
                {
                    i++;
                    Console.WriteLine(i.ToString() + ": " + m.ToString());
                    MessageBox.Show(i.ToString() + ": " + m.ToString());                //deviceChangeDeal();
                }            base.DefWndProc(ref m);
            }
        }
    }第一次回答帖子,希望有帮助
      

  6.   

    退出的时候,先
                try { serialPort1.BaseStream.Close(); }
                catch (Exception ex) { MessageBox.Show(ex.ToString()); }
    这样就不会再抛出IOException了,亲测可行。
      

  7.   

    在关闭串口时设置一个全局布尔变量代表正在关闭程序,这时DataRecieved事件里加上一句如果这个变量为真就return什么也不做,这样就不会再关闭程序时也去接收串口数据了。具体的代码在我给你的连接里。
      

  8.   

    系统有相对应的触发事件。不过这个事件也会有遗漏
    所有。果断用timer。没错USB监控平台。路过。
      

  9.   


    今天上午用timer试了,还是那个问题,解决不了,详述在四楼。
    求大侠指教解决方法
      

  10.   

    这不是一个传说,这是真实存在的BUG。
    解决方法很简单把对应的服务重起一下就好了。
    程序报错是正常的直接屏蔽掉。
      

  11.   


    usb转串口。后台有个服务在运行。
    就算你拔掉了设备后台服务并不是立即或根本不会检测到。
    你的程序发的包只是发到了这个后台服务。再由这个服务转发。
    这个后台的服务并不健壮。并不会每时每刻都会去轮询设备还在不在。
      

  12.   

    加一段代码(一个单独类,调用静态方法):using System;
    using System.IO;
    using System.IO.Ports;
    using System.Runtime.InteropServices;
    using System.Text;
    using Microsoft.Win32.SafeHandles;namespace SerialPortTester
    {
        public class SerialPortFixer : IDisposable
        {
            public static void Execute(string portName)
            {
                using (new SerialPortFixer(portName))
                {
                }
            }
            #region IDisposable Members        public void Dispose()
            {
                if (m_Handle != null)
                {
                    m_Handle.Close();
                    m_Handle = null;
                }
            }        #endregion        #region Implementation        private const int DcbFlagAbortOnError = 14;
            private const int CommStateRetries = 10;
            private SafeFileHandle m_Handle;        private SerialPortFixer(string portName)
            {
                const int dwFlagsAndAttributes = 0x40000000;
                const int dwAccess = unchecked((int)0xC0000000);            if ((portName == null) || !portName.StartsWith("COM", StringComparison.OrdinalIgnoreCase))
                {
                    throw new ArgumentException("Invalid Serial Port", "portName");
                }
                SafeFileHandle hFile = CreateFile(@"\\.\" + portName, dwAccess, 0, IntPtr.Zero, 3, dwFlagsAndAttributes,
                                                  IntPtr.Zero);
                if (hFile.IsInvalid)
                {
                    WinIoError();
                }
                try
                {
                    int fileType = GetFileType(hFile);
                    if ((fileType != 2) && (fileType != 0))
                    {
                        throw new ArgumentException("Invalid Serial Port", "portName");
                    }
                    m_Handle = hFile;
                    InitializeDcb();
                }
                catch
                {
                    hFile.Close();
                    m_Handle = null;
                    throw;
                }
            }        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern int FormatMessage(int dwFlags, HandleRef lpSource, int dwMessageId, int dwLanguageId,
                                                    StringBuilder lpBuffer, int nSize, IntPtr arguments);        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern bool GetCommState(SafeFileHandle hFile, ref Dcb lpDcb);        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern bool SetCommState(SafeFileHandle hFile, ref Dcb lpDcb);        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern bool ClearCommError(SafeFileHandle hFile, ref int lpErrors, ref Comstat lpStat);        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode,
                                                            IntPtr securityAttrs, int dwCreationDisposition,
                                                            int dwFlagsAndAttributes, IntPtr hTemplateFile);        [DllImport("kernel32.dll", SetLastError = true)]
            private static extern int GetFileType(SafeFileHandle hFile);        private void InitializeDcb()
            {
                Dcb dcb = new Dcb();
                GetCommStateNative(ref dcb);
                dcb.Flags &= ~(1u << DcbFlagAbortOnError);
                SetCommStateNative(ref dcb);
            }        private static string GetMessage(int errorCode)
            {
                StringBuilder lpBuffer = new StringBuilder(0x200);
                if (
                    FormatMessage(0x3200, new HandleRef(null, IntPtr.Zero), errorCode, 0, lpBuffer, lpBuffer.Capacity,
                                  IntPtr.Zero) != 0)
                {
                    return lpBuffer.ToString();
                }
                return "Unknown Error";
            }        private static int MakeHrFromErrorCode(int errorCode)
            {
                return (int)(0x80070000 | (uint)errorCode);
            }        private static void WinIoError()
            {
                int errorCode = Marshal.GetLastWin32Error();
                throw new IOException(GetMessage(errorCode), MakeHrFromErrorCode(errorCode));
            }        private void GetCommStateNative(ref Dcb lpDcb)
            {
                int commErrors = 0;
                Comstat comStat = new Comstat();            for (int i = 0; i < CommStateRetries; i++)
                {
                    if (!ClearCommError(m_Handle, ref commErrors, ref comStat))
                    {
                        WinIoError();
                    }
                    if (GetCommState(m_Handle, ref lpDcb))
                    {
                        break;
                    }
                    if (i == CommStateRetries - 1)
                    {
                        WinIoError();
                    }
                }
            }        private void SetCommStateNative(ref Dcb lpDcb)
            {
                int commErrors = 0;
                Comstat comStat = new Comstat();            for (int i = 0; i < CommStateRetries; i++)
                {
                    if (!ClearCommError(m_Handle, ref commErrors, ref comStat))
                    {
                        WinIoError();
                    }
                    if (SetCommState(m_Handle, ref lpDcb))
                    {
                        break;
                    }
                    if (i == CommStateRetries - 1)
                    {
                        WinIoError();
                    }
                }
            }        #region Nested type: COMSTAT        [StructLayout(LayoutKind.Sequential)]
            private struct Comstat
            {
                public readonly uint Flags;
                public readonly uint cbInQue;
                public readonly uint cbOutQue;
            }        #endregion        #region Nested type: DCB        [StructLayout(LayoutKind.Sequential)]
            private struct Dcb
            {
                public readonly uint DCBlength;
                public readonly uint BaudRate;
                public uint Flags;
                public readonly ushort wReserved;
                public readonly ushort XonLim;
                public readonly ushort XoffLim;
                public readonly byte ByteSize;
                public readonly byte Parity;
                public readonly byte StopBits;
                public readonly byte XonChar;
                public readonly byte XoffChar;
                public readonly byte ErrorChar;
                public readonly byte EofChar;
                public readonly byte EvtChar;
                public readonly ushort wReserved1;
            }        #endregion        #endregion
        }
    }源码来自blogpost地址就算了。在
    serialPort.Open();
    前加一句
    SerialPortTester.SerialPortFixer.Execute(Settings.Default.PortName);
    顺带我的系统是win7 64位,USB-串口是PL2303,框架版本是4.0 Client Profile
      

  13.   

    在close事件加try{this.Dispose();}catch{}
    虽然不能解决你的报错根源问题但报错还是不会提示的
    这个报错。估计是释放资源报错。也可能是线程出了问题报错。总之。如果多线程没管理好的话。或者辅助线程接触到UI线程也会可能报类似的错误
    这个是原理和结构问题试试看能不能解决眼前的问题
      

  14.   

    虽然代码都看不懂,但是还是照做了,可是也不行啊——照着敲这么多代码,好累啊,呵呵
    iyomumx,可以提供你的QQ吗,请教一下,这问题真的困着我了
      

  15.   

    在窗体的closing事件中已经加了你说的方法,关闭程序仍然报错,现象一模一样。
    注意∶报错时不会定位到如何一行代码,晕死,这样的不错第一次碰到,好头疼
      

  16.   

    再次回复求助。期待更多朋友给予我指点
    软件都做完了,就剩下这么个问题困扰我,叫同事也看了,也是束手无策,只是建议我不用serialport控件,改用api函数实现,晕,那个我也是差不多门外汉,工作量也大,而且能不能解决这样的问题也暂不知道。。
    求助大神,再次拜谢大神们,请支支招,万分感谢。。
      

  17.   

    VS03的时候 没有serialport类 都是用API的嘛
    姑且试试吧 网上现成源码 无非替换下
    不过 有可能一样会报错还有一个办法是在串口关闭前 重启后台服务
      

  18.   

    ServiceController[] slist= ServiceController.GetDevices();
    foreach (ServiceController service in slist)
        {
            if (service.ServiceName == "服务名")
               {
                    service.Stop();
                    service.Start();
               }
         }          
      

  19.   

    我用的USB虚拟的串口软件(或者RJ45虚拟的),在DELPHI中也碰到过类似问题,在WinApi层好象CreateHandle()、PurgeComm()等出错,没仔细研究,我是在上层就把错误屏蔽了
      

  20.   

    由于设备是连接到电脑USB接口的,所以存在随时拔掉该设备的情况。如果软件正在运行的时候,突然拔掉该USB,软件失去和设备的联系,监测和控制功能丧失,软件也不会报错,一切正常。但是,如果关闭软件,软件就会报错,在VS2005下提示“对端口的访问被拒绝”,而且报错不会定位到程序的任何一个代码行(这个最头疼,问题出在哪儿都不好找),关闭该报错提示窗口,软件窗口被关闭,但是程序仍然处于运行中,必须手动点击VS2005中停止按钮,程序才最终得到终止。从这两个红色标注的地方,可以猜测LZ应该是用的多线程。
    第一个标注红色地方:猜测你的程序不会报错是因为你catch住不处理,但是还是一直在发送数据。第二个标注红色地方:你的程序界面关闭,但是还在运行。这说明你的多线程应该没有 IsBackground = true; 导致程序退出时没有关闭线程。你试着把 Thread 的 IsBackground 设为 true 看看。
      

  21.   

    再次顶上,期待高手们的光临指导!这次附上问题程序的源代码工程(VS2005下编译的):
    下载:
    http://115.com/file/e704quat#或者:http://163.fm/IFzgf2L     提取码:LucGDi3Q    (163邮箱的网盘)
    问题程序源代码:
    private void Form1_Load(object sender, EventArgs e)
            {
                serialPort1.Close();
                serialPort1.BaudRate = 9600;
                serialPort1.DataBits = 8;
                serialPort1.StopBits = StopBits.One;
                serialPort1.Parity = Parity.None;
                serialPort1.PortName = "COM4";     //USB 转串口映射的串口号为com4
                serialPort1.Open();
            }        private void button1_Click(object sender, EventArgs e)    //发送数据到设备
            {
                byte[] bytWrite = new byte[] { 0xe1, 0xee, 0xee, 0xee,0x30 };   //byte数组
                try
                {
                    if (!serialPort1.IsOpen)
                        serialPort1.Open();
                    serialPort1.Write(bytWrite, 0, bytWrite.Length);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                    serialPort1.Close();
                    serialPort1.Dispose();
                }
            }        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)   //从串口接收数据
            {
                int n = serialPort1.BytesToRead;
                byte[] buf = new byte[n];
                serialPort1.Read(buf, 0, n);
                Console.WriteLine("当前串口收到数据:  "+BitConverter.ToString(buf));
            }        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
            {
                serialPort1.Close();     //窗体关闭前关闭串口
                serialPort1.Dispose();    //窗体关闭前释放串口
            }另外,我发现了用很多网络上下载的串口调试程序进行调试的时候,很多串口调试软件也存在这个问题,当USB拔掉后,关闭软件出错,而且有些软件根本就关不掉,一直弹出出错提示,看来这个问题还是普遍存在啊,相当多的程序员在写串口程序的时候,都忽略了这个问题。因为平常的情况下,com口在软件运行过程中都是一直存在的,刚好这次我写程序遇到usb转串口这样的情况,调试软件时才发现了这个问题。呵呵
    但是,也不是所有的串口调试软件在这种情况下都会出错,现目前我发现一个叫做UartAssist.exe的串口调试软件在遇到这种情况的时候不会出错,关闭软件一切正常,呵呵,看来这个问题还是能够避免的,就是我才疏学浅还没有掌握到,所以特地再来此顶贴,希望高手们都来看看,不要忽略了这个问题。
    小弟不胜感谢!!!
      

  22.   

    退出前检测下刚才打开得串口是否还存在或者处于打开状态,不存在直接退出,存在则关闭并且释放上面这个方法你试了?不行?我觉得这种是可行的,意外拔掉USB,系统就找不到那个串口,所以那个时候关闭是会出错的,你在关之前自己动查找下COM口是,是不是和打开的COM相同,有就正常关闭,没有就直接退出。
      

  23.   


    这个方法是不行的,已经试了。软件故障现象是:拔掉usb接口后,即使在关闭软件之前再次插上usb线缆,关闭时也会报错。总之,软件运行过程中只要有拔掉usb线缆,之后任何情况软件关闭都会出错,也就是说即使那个com口还存在,依然报错。
    痛苦,现在还没有找到解决方法。
      

  24.   

    LZ你好,我自己测试没有向串口写入数据,应该是这个原因不能重现这个问题。你可以考虑对
    AppDomain.Current.UnhandledException 事件
    注册处理程序,在这里应该可以捕捉到错误,并能通过设置UnhandledExceptionEventArgs.ExitApplication来保证应用程序正常退出。
      

  25.   

    建议选用波仕电子的型号为USB232ET的USB网络串口转换器,内部使用的是TCP/IP协议,也可以虚拟成为串口,使用SOCKET控件代替串口通信控件这样就自然解决了这个问题。
      

  26.   

    我写的也一直存在相似问题,若串口处于打开状态时直接拨掉后,再重新插入串口就不能用了,除非把软件关闭再打开才可以。很是郁闷,这问题缠了我一年多了。 无奈好像用serialport组件的人太少了!
      

  27.   

    这个问题不好整,你看看串口调试助手,都是拔掉串口后程序出错连结束都不让点。
    我们经常用串口一样的毛病,串口故障了,软件反应的是数据没获得。
    你去用软件解决这个问题,为什么不保持你的串口不变动呢?USB转串口我们都是笔记本临时调试用,就这还有时候会罢工呢,不用说用到成品软件上了。
      

  28.   

    "如果软件正在运行的时候,突然拔掉该USB,软件失去和设备的联系,监测和控制功能丧失,软件也不会报错,一切正常。但是,如果关闭软件,软件就会报错,在VS2005下提示“对端口的访问被拒绝”,而且报错不会定位到程序的任何一个代码行(这个最头疼,问题出在哪儿都不好找)"
    ==================
    拔掉USB不会出错是因为串口没有数据,不会触发DataReceived事件,此过程中没有对端口进行操作。
    但是关闭窗体的时候,是要释放串口资源的,于是就出错了。没想到什么好的办法,试试在关闭窗口的时候直接退出程序“Environment.Exit(0);"
      

  29.   

    这个问题的根源就是出在微软,因为打开一个串口,相当于打开一个文件,在微软认为,打开的文件是无法被删除的。但是,出现了USB转串口之后,这个问题就出现了,即使打开一个串口,仍然可以强制拔掉USB线,这样,打开的文件就不存在了,那么就会出现楼主的问题,暂时没有想到解决办法
      

  30.   

    解决方法:https://connect.microsoft.com/VisualStudio/feedback/details/140018/serialport-crashes-after-disconnect-of-usb-com-port
      

  31.   

    没什么办法,亲测,即使拔掉USB,IsOpend属性依然为true
    这样在执行close的时候一定会出错
      

  32.   

    使用.net 4.0 应该不会有下面的问题
      

  33.   

    4.0修复了这个BUG?
    测试过吗,不要靠猜想