我编写了一个Delphi DLL,它通过COM与第三方程序通信。一些用户报告第三方程序偶尔崩溃。其他以相同方式使用该软件的人从未经历过崩溃。发生此崩溃时,第三方程序似乎在我的DLL应用程序中变得不可用。
供应商发誓这是Delphi DLL如何编码的问题,虽然他们没有看到源代码并且无法分辨DLL正在做什么导致崩溃,但是他们知道它是“某事”
除了我认为第三方程序不应该由于我的DLL中的一些小问题而崩溃这一事实之外,让我们假设我的DLL中有一些东西需要修复。
如何确定我的应用可能导致此问题?有没有人有通过COM与这样的超敏感程序进行通信的经验?是否有一些常见的事情可能会导致第三方程序崩溃?
答案 0 :(得分: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}来启用这些日志记录功能,以启用/禁用诊断日志记录。
答案 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);