Delphi应用程序与偶尔崩溃的程序进行通信 - 供应商责备我的Delphi应用程序

时间:2009-06-25 15:15:39

标签: windows performance delphi debugging com

我编写了一个Delphi DLL,它通过COM与第三方程序通信。一些用户报告第三方程序偶尔崩溃。其他以相同方式使用该软件的人从未经历过崩溃。发生此崩溃时,第三方程序似乎在我的DLL应用程序中变得不可用。

供应商发誓这是Delphi DLL如何编码的问题,虽然他们没有看到源代码并且无法分辨DLL正在做什么导致崩溃,但是他们知道它是“某事”

除了我认为第三方程序不应该由于我的DLL中的一些小问题而崩溃这一事实之外,让我们假设我的DLL中有一些东西需要修复。

如何确定我的应用可能导致此问题?有没有人有通过COM与这样的超敏感程序进行通信的经验?是否有一些常见的事情可能会导致第三方程序崩溃?

6 个答案:

答案 0 :(得分:4)

  1. 让客户满意。
  2. 不要以为它不是你的dll,它可能是。即使“其他人以相同的方式使用该软件从未经历过崩溃”,也可能是因为使用不同的数据,它会做出不同的事情......
  3. 我建议您在“特殊”诊断版本中设置日志文件。
  4. 记录所有内容,参数,异常以及您要完成的步骤。甚至可能是每个功能的开始和结束,以及其他每一行。
  5. 以下是它的外观......

    Loaded DLL
    Started MyFunction1 with parameters: 1,4,hello
       1
       2
       ...
       500
    Ended MyFunction1
    

    要做到这一点,,,我设置了一些功能(在他们自己的单元中):

    // opens a text file (fixed name), and appends to it.
    function InitializeLog; 
    
    // closes the file
    function CloseLog;      
    
    //add a log line.
    function Log(message:string='', startNewFunction:boolean:False); 
    
    你会这样称呼它:

    function MyFunction1(Integer,Integer,String);
    begin
      try
        Log('Loaded DLL');
    
        //use inttostr and do some string concats to get the params
        Log('Started MyFunction1 with parameters: 1,4,hello',true); 
    
        //Then every other line:
        Log; 
        //this would increment a global variable FuncLine:Integer
        //and write it to the file.    
    
      except
        On E:Exception (Log('***'+E.Message));
      end;
    end;
    

    这样的事情应该有{$ DEFINE}来启用这些日志记录功能,以启用/禁用诊断日志记录。

    This could also be useful.

答案 1 :(得分:4)

请查看Quality Central报告58409。

这是关于FPU Mask和Dll的。

简而言之:

FPU Mask的设置确定如何处理浮点异常。

如果您有例如Applicaion_A(由其他人编码)加载Dll_A(也由其他人编码)和Dll_B(由您编码),并且您的Dll更改FPU掩码,则此更改对Application_A和Dll_A也是。

我们举一个例子: 您已经安装了WinZIP,SubVersion等,它们在Windows文件资源管理器中注册了其他功能(右键单击弹出菜单),现在您从application.exe中调用TOpenDialog,这些附加功能可能会影响您的FPU设置。

希望这会有所帮助。 (附加提示:使用Sysinternal查看应用程序加载的dll)

答案 2 :(得分:3)

您是否考虑过使用MadExcept?如果您在接口方法中捕获错误,您可以记录调用堆栈或向用户显示一个对话框,并将标准EOleSysError返回给调用exe。

这样的事情:

  except
    on e: Exception do
    begin
      MadExcept.HandleException();

      raise EOleSysError.Create('InitializeObject Failed',
        ErrorNumberToHResult(1 + CODE_BASE), 1);
    end;

如果应用程序挂起但不是抛出异常,您可以通过使用MadExcept实用程序madTraceProcess查看发生的情况。这将允许您为正在运行的应用程序生成一个调用堆栈。你的dll不会出现在主线程上,但是你可以看到你的调用堆栈。这是一个好方法,可以判断你的dll在发生挂起时是否真的在做任何事情。

我有一个COM dll与不使用MadExcept的exe交互,这种方法对我来说效果很好。

答案 3 :(得分:2)

如果他们的程序在你使用他们发布的界面时崩溃了,我很确定它有问题。证明这是另一回事。

您是否可以使用可以提供给供应商的小型Delphi应用程序可靠地复制问题?看到可重现的失败可能有助于说服他们需要做出修复。至少,它可以帮助确定他们认为你在做什么“错误”并告诉你如何“正确”做到这一点。

您也可以尝试使用C#甚至VBScript复制失败。

答案 4 :(得分:2)

如果我理解了这种情况,那么幸运的是,如果您的DLL没有崩溃并且被叫第三方程序停止响应,那么您可以做的就不多了。崩溃在他们的代码中,但只是由你的DLL调用它触发。调试日志应该在他们的应用程序中完成。
你可以做的是用参数和一些上下文信息记录你的DLL对这个第三方程序的所有调用 然后在崩溃前查看最后一条跟踪可能会给你一些信息......

答案 5 :(得分:2)

我不知道madExcept如何工作,但我使用jclDebug.pas + JclHookExcept.pas(来自JEDI JCL库)很多。它构成了一个Windows API钩子,所以它捕获所有(!)异常,即使你做了这样的事情:

try
  raise exception.create('test');
except
  //eat exception
end;

通常你没有看到这个例外,因为它被“吃掉”了......但是有了钩子你会得到所有例外。例如:我曾经在Midas.dll中遇到“灾难性故障”,并且通过钩子我在此异常之前看到了dll中的“数据库连接丢失”错误,所以我知道发生了什么。 (顺便说一下:JclHookExcept.pas = hook,jclDebug.pas = strack trace)。

我现在看到JclHookExcept.pas也有一个“JclHookExceptionsInModule”过程,所以你可以强制(?)挂钩来自特定库的所有异常......

一些演示代码:

procedure AnyExceptionNotify(ExceptObj: TObject; ExceptAddr: Pointer; OSException: Boolean);
begin
  //log exception
end;

initialization
  // Start Exception tracking
  JclStartExceptionTracking;
  JclTrackExceptionsFromLibraries;
  JclStackTrackingOptions := [stStack, stRawMode, stAllModules];
  // Assign notification procedure for hooked RaiseException API call. This
  // allows being notified of any exception
  JclAddExceptNotifier(AnyExceptionNotify);