2009-06-25 120 views
4

我写了一个德尔福DLL通过COM与第三方程序进行通信。一些用户报告说第三方程序偶尔崩溃。其他人以相同的方式使用软件从未遇到过崩溃。发生这种崩溃时,第三方程序似乎只是在我的DLL应用程序中变得不可用。德尔福应用程序通讯偶尔会导致崩溃 - 供应商导致我的德尔福应用

供应商发誓,虽然他们没有看到源代码,也不知道DLL是如何导致崩溃的,但它是Delphi DLL编码的问题,但他们知道这是“某种东西”。

除了我相信第三方程序不应该因我的DLL中的一些微小问题而崩溃的事实,让我们假设我的DLL中有某些东西需要修复。

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

回答

4
  1. 让客户满意。
  2. 不要以为它不是你的DLL,它可能是。即使“其他人使用相同的方式使用软件从未遇到过崩溃”,它可能是与不同​​的数据,它做不同的事情...
  3. 我建议你设置日志记录到文本文件一个“特殊”的诊断版本。
  4. 记录一切,您的参数,您的例外情况以及您正在经历的步骤。甚至可能是每个函数的开始和结束,以及其他每一行。

下面是它怎么会看...

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.

2

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

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

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

+0

我非常同意。我以前曾经在这个地方工作过很多次,最快的解决方案一直是创建一个新的可重复测试程序,并将其提供给供应商提供完整的源代码。如果可能,记录与API的所有交互(正在传递哪些参数以及返回的内容)。 – skamradt 2009-06-25 16:16:41

+4

供应商说Dave的DLL是错误的。供应商是谁应该制定测试计划,而不是戴夫,因为供应商是真正看到问题的人。如果不是测试程序,那么至少要列出一系列步骤来证明问题。 – 2009-06-25 17:39:25

+1

我不认为供应商看到这个。我认为这是戴夫的顾客。无论如何,我同意供应商应该加强工作,至少帮助解决问题。不幸的是,他们似乎并不急切,所以落到戴夫身上可以帮助他们说服他们存在问题,或者找到解决办法。谁知道,重复这个问题,他可能会发现他毕竟犯了一个错误。底线;戴夫让他的顾客担心。 – 2009-06-25 19:14:48

4

看质量为中心报告58409.

这是关于FPU面具和DLL的。

解释它在短:

的FPU面膜determ的浮点异常是如何处理的设置。如果你有例如载入Dll_A(也由其他编码)和Dll_B(由你编码)的Applicaion_A(由其他编码),并且你的Dll改变了FPU掩码,那么这个改变对于Application_A是有效的和Dll_A。

让我们来举个例子吧: 你已经安装了例如WinZIP,SubVersion等在windows文件资源管理器中注册附加功能(右键单击弹出菜单),现在你可以从application.exe中调用TOpenDialog,那么这些附加功能可能会危及您的FPU设置。

希望这会有所帮助。 (附加提示:以Sysinternal来查看你的应用加载了哪些dll)

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交互,这种方法对我来说效果很好。

2

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

2

我不知道该怎么madExcept等工作,但我用jclDebug.pas + JclHookExcept.pas(从JEDI JCL库)一许多。它使一个Windows API钩子,所以它捕获所有异常,即使你做这样的事情(!):

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

通常你不会看到这个异常,因为它是“吃掉” ......但是,随着钩子你会得到所有的例外。例如:我曾经在Midas.dll中遇到过“灾难性故障”,并且通过钩子,我在这个异常之前看到了dll中的“数据库连接丢失”错误,所以我知道发生了什么。 (btw: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);