我已经写了一个Delphi DLL,通过COM与第三方程序进行通信。 有些用户报告说第三方程序偶尔崩溃。 其他人以相同的方式使用软件从未遇到过崩溃。 发生这种崩溃时,第三方程序似乎只是在我的DLL应用程序中变得不可用。
供应商发誓,Delphi DLL的编码是一个问题,虽然他们没有看到源代码,也不知道DLL是如何导致崩溃的,但是他们知道这是“某种东西”。
除了我相信第三方程序不会由于我的DLL中的一些小问题而崩溃,我们假设在我的DLL中有一些东西需要修复。
我怎样才能确定我的应用程序可能导致这个? 有没有人有通过COM与这样的高敏感程序通信的经验? 有没有一些常见的东西可能会崩溃的第三方程序?
以下是它的样子
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}来启用这些日志功能,以启用/禁用诊断日志记录。
这也可能是有用的。
质量中心查看报告58409。
这是关于FPU Mask和Dll的。
简而言之:
FPU掩码的设置决定如何处理浮点异常。
例如,如果您有一个加载Dll_A(由其他编码)和Dll_B(由您编码)的Applicaion_A(由其他编码),并且您的Dll更改了FPU掩码,则此更改对于Application_A和Dll_A也是有效的。
举个例子:你已经安装了例如WinZIP,SubVersion等,它在Windows文件管理器(右键单击弹出菜单)中注册了附加功能,现在你可以从你的application.exe中调用TOpenDialog,然后这个附加功能可能妥协你的FPU设置。
希望这可以帮助。 (附加提示:以Sysinternal来查看你的应用程序加载了哪些dll)
你有没有考虑过使用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交互,这种方法对我来说工作得很好。
如果他们的程序在使用他们发布的界面时崩溃了,我很确定它有什么问题。 证明这是另一回事。
你可以用一个小的Delphi应用程序可靠地复制问题,你可以给供应商? 看到一个可重复的失败可能有助于说服他们,他们需要做一个修复。 至少,它可以帮助确定他们认为自己在做什么“错误”,并告诉你如何做到“正确”。
您也可以尝试使用C#甚至VBScript来复制失败。
如果我正确地理解了这种情况,那么不幸的是,如果你的DLL没有崩溃,被叫的第三方程序停止响应,那么你可以做的事情就不多了。 崩溃是在他们的代码中,但只能由您的DLL调用它触发。 调试日志应该真的在他们的应用程序中完成。
你可以做的事情是记录所有的DLL调用这个参数和一些上下文信息的第三方程序的调用。
然后在崩溃之前查看最后一个痕迹可能会给你一些信息…
我不知道如何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也有一个“JclHookExceptionsInmodulee”过程,所以你可以强制(?)钩住特定库中的所有异常…
一些演示代码:
procedure AnyExceptionNotify(ExceptObj: TObject; ExceptAddr: Pointer; OSException: Boolean); begin //log exception end; initialization // Start Exception tracking JclStartExceptionTracking; JclTrackExceptionsFromLibraries; JclStackTrackingOptions := [stStack, stRawMode, stAllmodulees]; // Assign notification procedure for hooked RaiseException API call. This // allows being notified of any exception JclAddExceptNotifier(AnyExceptionNotify);