【问题标题】:Prevent Delphi COM component from showing MessageBox()防止 Delphi COM 组件显示 MessageBox()
【发布时间】:2010-10-31 00:02:57
【问题描述】:

我们有一个从 ISAPI 应用程序执行的 Delphi 2007 COM 组件。 COM 组件正在挂起应用程序,因为它正在尝试显示 MessageBox()。对 MessageBox() 的调用必须在 Delphi RTL 中进行,因为它不在我们的用户代码中。

应用程序挂起,当然,因为没有人登录服务器来清除 MessageBox()。

我们如何配置我们的 Delphi 项目,以便 Delphi RTL 不会尝试在异常时显示 MessageBox()?

【问题讨论】:

    标签: delphi com isapi


    【解决方案1】:

    我不知道 Delphi 有什么直接的方法,但你可以做的是在 AutoIT/AutoHotKey 中编写一个小脚本,并让该脚本在系统托盘中运行,这样它就会自动关闭 MessageBox。

    相信我,这很简单。

    http://www.autoitscript.com/autoit3/index.shtml

    http://www.autohotkey.com/

    HTH

    【讨论】:

    • 假设应用有桌面。情况可能并非如此。
    • 我不认为它是一个非桌面应用程序。海报是用 Delphi 开发的,目前 Delphi 只生成桌面应用程序。
    • 没有桌面也没有 GUI。它是一个从 ISAPI dll 调用的 COM 组件。你肯定可以在 Delphi 中开发非“桌面应用程序”。该建议不能解决问题,但可能是防止挂起的一种解决方法。
    【解决方案2】:

    消息框说什么?我假设这是一个例外。为什么不在 COM 组件中的代码周围放置一个异常处理程序,并以不同的方式记录异常? (例如,使用事件日志)。和/或首先解决导致异常的问题。

    【讨论】:

    • 不知道消息框说了什么。由于没有人登录,因此无法查看它。是的,它是一个异常处理程序,因为这些是 RTL 中唯一的 MessageBox() 调用。
    • 我的第一个念头是 Jim,确保不是显示消息框的人。接下来的事情是确保您正确地将所有 COM 方法标记为safecall。这样,方法期间抛出的任何异常都会被隐式添加到方法中的 try-catch 捕获,并将异常作为 E_FAIL HRESULT 返回。
    • ...因为 COM 的规则是不能抛出异常。当您将方法标记为安全调用时,它们的编译器会为您完成工作,并将您的代码包装在 try-except 中并在隐式 hresult 返回值中返回异常。
    • 但是我们的 COM 组件的方法之一没有发生异常。它在 RTL 的启动代码中。异常发生在 System.pas 中的 InitUnits 中,然后调用 FinializeUnits 然后引发。当引发异常时,RTL 会显示 MessageBox。
    【解决方案3】:

    编写您自己的异常处理程序并将其附加到 Application.OnException 事件。如果存在 OnException 事件处理程序,应用程序将不会使用其默认的 MessageBox 例程。签名定义为:

    TExceptionEvent = procedure (Sender: TObject; E: Exception) of object;
    

    如果这是服务器,您可能希望将异常信息写入日志,并可能向用户返回一些错误。

    【讨论】:

    • +1 这是处理异常的最佳方式。如果您从服务登录,请确保 IIS 进程对您登录的位置拥有完全权限。
    • 这一切都很好,但是如果它是一个 COM 组件并且它不使用 Forms 单元,那么您甚至没有应用程序引用。我有很多用 Delphi 编写的进程内 DLL COM 服务器,它们不显示任何 UI。
    • 嗯,基本原理还是一样的。在外循环的某个地方,您有一个默认的异常处理程序,它可以捕获所有内容并显示一个消息框。也许它不是一个应用程序变量。也许它只是一个简单的 try 块,就像控制台应用程序使用的一样。不管它是什么,你必须找到它并替换它的功能。
    • 没有 Application 对象,因为 COM 组件不使用 Forms 或 SvcMgr 单元。 (并且我们想要写入事件日志时使用的 SvcMgr 单元中的 Application 对象没有 OnException 事件)消息框在初始化期间显示,位于 RTL 源中的某个位置。您可以在 COM 组件单元的初始化部分中使用 try/except 构造并将其包装在 Factory.Create() 调用中吗? (看起来答案是肯定的)
    • 当然。你几乎可以在任何东西上包裹一个 try 块。这里没有“魔法”。如果您可以在调试器中重现引发异常的条件,那么请执行此操作,并跟踪展开的堆栈,直到找到处理它的位置。 (当然,在调试 DCU 的情况下构建。)找到将其变成对话框的异常处理程序,并将您自己的异常处理程序放置在此点之前的某个位置以拦截它。除非您的 COM 服务器的结构非常奇怪,否则只有在找到合适的位置放置它时才需要放置它。
    【解决方案4】:

    我创建了一个单元来挂钩 MessageBox/MessageDlg 调用(通过绕行),因此我可以在 Windows 服务中抑制这些调用(以避免由于其他人的一些愚蠢代码而“挂起”我的服务 dll消息框调用它)。 如果你想要,我可以搜索这个单元并发送给你。

    【讨论】:

    • 你的邮箱是什么,我可以发给你吗?
    • kbyington at netrate dot com 感谢 在不支付 10,000 美元许可费的情况下使用 Microsoft 绕道而行是否合法? microsoft.com/iplicensing/…
    • 我给你发了一封电子邮件。它不使用 MS Detouring,因此您不必支付许可费 :-)
    • 能否请您在答案中发布代码?如果没有,请访问 inedo dot com 的 apapadimoulis。
    【解决方案5】:

    是否可以将应用程序编译为控制台应用程序?我不确定你是否可以这样做并且仍然让它包含 COM 对象,我敢肯定这会阻止显示消息对话框。

    只是一个想法。

    【讨论】:

    • 根据帮助,{$APPTYPE CONSOLE} 在 .dll 中没有任何意义。 '$APPTYPE 指令仅在程序中有意义。不应在库、单元或包中使用它。'
    猜你喜欢
    • 2013-01-04
    • 1970-01-01
    • 2015-08-27
    • 1970-01-01
    • 2021-11-11
    • 2012-06-16
    • 1970-01-01
    • 1970-01-01
    • 2013-06-23
    相关资源
    最近更新 更多