【问题标题】:How to handle an exception when USB-Serial port is removed unexpectedly?USB-Serial端口被意外移除时如何处理异常?
【发布时间】:2013-03-13 12:15:09
【问题描述】:

我的 Delphi 应用程序(使用 XE3)需要处理移除 USB 串行端口时发生的 EInOutError 异常。该应用程序在测试环境中使用,因此不能依赖操作员单击“确定”按钮来关闭“应用程序错误”对话框。

我尝试了以下方法:

  • “try ..except”方法 - 这不会捕获这些异常。我认为这不起作用,因为异常不是由“try”块中的代码引起的。这似乎是一个较低级别的“系统级”异常。

  • 我尝试将“ApplicationEvents”组件添加到我的表单中。 OnException 方法会捕获我的应用程序生成的“自定义”异常,但不会捕获系统级异常。

  • 我还尝试添加一个全局异常挂钩(如Is it possible to have a global exception hook? 中所述)。这部分有效 - 它允许我在应用程序错误对话框之前执行操作,但不会停止错误对话框。

我会很感激任何想法!

【问题讨论】:

  • 如果 try-except 块没有捕捉到异常,那么要么异常没有在你认为的地方发生,它在你尝试之前被其他代码捕捉和处理抓住它,或者它不是真正的例外。既然抓不到,怎么知道是EInOutError异常?
  • 当 USB-Serial 被移除时,您是否会收到带有 DBT_DEVICEREMOVECOMPLETE 类型和 DBT_DEVTYP_PORT 设备类型的消息 WM_DEVICECHANGE?
  • 嗨,Rob,我弹出一个标题为“应用程序错误”的对话框。对话框内的消息是“001C7052 模块 Project1.exe 中的异常 EInOutError”。这是在 IDE/调试器之外运行应用程序。
  • 当对话框出现时,暂停程序的执行。查看当前线程的调用堆栈。您可以使用它来确定哪个线程正在显示对话框以及导致它的代码路径。确保您的异常处理程序位于该代码路径上。
  • @RobKennedy 谢谢 - 调用堆栈指出了问题的解决方案。当端口被移除时,AsyncPro Com Port 组件调用一个 ThreadGone 函数。这会调用一个引发 FileIO 错误的 CheckException 函数。最简单的解决方案似乎是修改组件源以根据需要处理此错误。

标签: delphi exception-handling


【解决方案1】:

由于 USB-Com 移除而出现的异常非常烦人。所以我建议消除他们的大部分原因。

您必须处理 Windows 消息 WM_DEVICECHANGE 并检测端口删除。然后设置特殊标志,不要对带有此标志的端口进行任何操作!如果再次插入 USB-Com,则重新初始化串行端口。一些帮助的代码:

    const
      DBT_DEVICEARRIVAL = $8000;
      DBT_DEVICEREMOVECOMPLETE = $8004;
      DBT_DEVICEQUERYREMOVE = $8001;
      DBT_DEVTYP_PORT = 3;

    type
       PDevBroadcastHdr = ^TDevBroadcastHdr;
       TDevBroadcastHdr = packed record
        dbcd_size: DWORD;
        dbcd_devicetype: DWORD;
        dbcd_reserved: DWORD;
      end;

      PDEV_BROADCAST_PORT = ^TDEV_BROADCAST_PORT;
      TDEV_BROADCAST_PORT = packed record
        dbcp_size: DWord;
        dbcp_devicetype: DWord;
        dbcp_reserved: DWord;
        dbcp_name: array[0..MAX_PATH] of Char;
      end;

    ...
    procedure WMDEVICECHANGE(var Msg: TMessage); message WM_DEVICECHANGE;
    ...

procedure TForm1.WMDEVICECHANGE(var Msg: TMessage);
var
  prt: PDEV_BROADCAST_PORT;
  s: string;
begin

  if Msg.wparam =  DBT_DEVICEREMOVECOMPLETE then
    if PDevBroadcastHdr(Msg.lParam)^.dbcd_devicetype = DBT_DEVTYP_PORT then
      begin

        b_PortRemoved := True; //check this flag before each operation with port.


        prt := PDEV_BROADCAST_PORT(PDEV_BROADCAST_PORT(Msg.lParam));
        s := prt.dbcp_name;
        ShowMessage('ComPort ' + s + ' has been removed. What can I do?');
    end;

  if Msg.wparam =  DBT_DEVICEARRIVAL then
    if PDevBroadcastHdr(Msg.lParam)^.dbcd_devicetype = DBT_DEVTYP_PORT then begin
       // USB-COM plugged, you can find it and make some reinitialisation
    end;


end;

【讨论】:

  • 感谢示例代码!即使我没有“打开”端口,它也能正确检测到正在插入和移除的端口。但是,一旦端口被删除,我仍然会收到应用程序错误(即使我没有向其写入任何内容)。
  • 这很奇怪。我使用sourceforge.net/projects/comport 并且在移除端口后看不到此类错误。可能是,您的库执行连续端口轮询?您可以通过technet.microsoft.com/en-us/sysinternals/bb896644.aspx 查询
猜你喜欢
  • 1970-01-01
  • 2013-01-11
  • 1970-01-01
  • 2021-09-14
  • 2022-08-13
  • 1970-01-01
  • 2013-04-13
  • 2021-10-20
  • 1970-01-01
相关资源
最近更新 更多