更新
进一步的调查表明,由于一些不正确的配置文件,断言没有使用 Delphi 主机触发。一旦解决了这个问题,Delphi 主机就和 C# 主机一样剧烈地死掉了。
请注意,所有这些都与 XE2 64 位构建相关联。我们已经注意到断言杀死了 Delphi 64 位调试器,而它们不使用 32 位平台。
替换AssertErrorProc
并在那里做一些日志记录可以纠正这种情况,无论是对于作为我们的 C# 和 Delphi 主机的 Delphi 调试器。
两个主机也可以在断言位置抛出异常。异常被现有的异常块捕获。
使用 Delphi XE3 无法重现该问题(感谢@David 提供帮助),因此当前状态是这与 Delphi XE2 中的(错误)异常/断言处理有关,尤其是在 64 位平台上。
我有一个 Delphi DLL,它可以从自托管的 C# web 服务中调用。出于调试目的,该 DLL 也可以从 Delphi 可执行文件中调用。
DLL 可以并且已经在 Delphi 和 C# 主机上成功使用。
今天遇到了在DLL初始化时执行的代码中触发断言的情况,发现在Delphi进程托管时成功阻止了断言离开DLL,但没有被捕获并导致主机死机是一个 C# 进程。
德尔福DLL
Delphi DLL 有它自己的 DllProc 过程,它是从 dpr 手动调用的,因为 Delphi RTL “劫持”了入口点以允许单元初始化。有关详细信息,请参阅http://docwiki.embarcadero.com/VCL/XE/en/System.DLLProc。
Delphi DLL dpr 代码:
begin
DllProc := MyDllMain;
MyDllMain(DLL_PROCESS_ATTACH);
end.
自定义 dll 主过程只是确保某些结构在第一次加载 DLL 时初始化,并在最后一个“加载器”离开时完成。
procedure MyDllMain(Reason: Integer);
begin
// ...
// DLL_PROCESS_ATTACH:
begin
if _RefCount < 1 then
InitializeDLL;
Inc(_RefCount);
end;
// ...
end;
InitializeDLL 过程受到 try except 块的保护,特别是为了防止异常逃逸 DLL。
procedure InitializeDLL;
begin
try
// Some code triggering an Assert(False, 'Whatever');
except
on E: Exception do
TLogger.LogException('InitializeDLL');
// Don't raise through. Exceptions should not leave DLL.
end;
end;
德尔福主机
Delphi 主机为 Delphi DLL 手动调用 LoadLibrary,检索指向它需要的函数的指针并使用这些函数调用 DLL。
procedure InternalSetup;
begin
FLibrary := LoadLibrary(CLibraryPath);
GetResource := GetProcAddress(FLibrary, 'GetResource');
PostResource := GetProcAddress(FLibrary, 'PostResource');
PutResource := GetProcAddress(FLibrary, 'PutResource');
DeleteResource := GetProcAddress(FLibrary, 'DeleteResource');
end;
调用:结果 := GetResource(INVALID_URI, {aQueryParams=}'', {out}ResponseBody);
C# 主机
C#主机包含以下代码来调用DLL
[DllImport("EAConfigurationEngine.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
// Delphi:
// function GetResource(aURI: string; aQueryParams: string; out aResponseBody: WideString): THTTPStatusCode; stdcall; export;
private static extern int GetResource(
string uri,
string queryParams,
[MarshalAs(UnmanagedType.BStr)] out string responseBody);
问题
如上所述,当 DLL 的主机是 Delphi 可执行文件时,会命中 except 块。但是,当从 C# 主机调用 Delphi DLL 时,断言触发,未到达except 块(未记录消息,而是未初始化的记录器记录有关断言的未处理异常),并且 C#进程因“vshost.exe 已停止工作”对话框而终止。
是什么导致这种情况发生,我该如何预防?