Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi FreeLibrary for hhctrl.ocx在程序关闭时挂起的原因是什么?我怎样才能避免这种情况?_Delphi_Delphi 2007_Html Help - Fatal编程技术网

Delphi FreeLibrary for hhctrl.ocx在程序关闭时挂起的原因是什么?我怎样才能避免这种情况?

Delphi FreeLibrary for hhctrl.ocx在程序关闭时挂起的原因是什么?我怎样才能避免这种情况?,delphi,delphi-2007,html-help,Delphi,Delphi 2007,Html Help,我有一个用Delphi2007编写的程序,它使用html帮助。它经常挂起在退出时(即使实际上没有调用html帮助),我在Windows.pas的finalization部分将问题追溯到这个调用 finalization if HtmlHelpModule <> 0 then FreeLibrary(HtmlHelpModule); end. 定稿 如果HTMLHELPMODEL为0,则为自由库(HTMLHELPMODEL); 终止 由于hhctrl.ocx的卸载代码中有一个N

我有一个用Delphi2007编写的程序,它使用html帮助。它经常挂起在退出时(即使实际上没有调用html帮助),我在Windows.pas的finalization部分将问题追溯到这个调用

finalization
  if HtmlHelpModule <> 0 then FreeLibrary(HtmlHelpModule);
end.
定稿
如果HTMLHELPMODEL为0,则为自由库(HTMLHELPMODEL);
终止
由于hhctrl.ocx的卸载代码中有一个NTWaitFormMultipleObjects,因此主线程在此调用中挂起。还有其他线程(我的代码没有创建任何线程)显然在等待相同的线程,因此我的程序挂起。我猜其中一些线程是由ADO和/或Microsoft SQL Server客户端库创建的

我找到了一个解决方法:对LoadLibrary('hhctrl.ocx')的额外调用,因此在Windows.pas中对FreeLibrary的调用实际上不会卸载dll,而只是将引用计数减少到1。虽然这似乎有效,但感觉不太对

这是一个已知的问题吗?有合适的解决办法吗

(是的,我在谷歌上搜索了一下,但没有找到任何有用的东西。 这似乎描述了一个类似的问题 使用不同的DLL。)

编辑:更多信息:

显然,只有在程序中从未调用html帮助时(因此没有调用LoadLibrary('hhctl.ocx'),问题才会出现。关闭时,htmlhelp.pas中的终结代码尝试关闭所有htmlhelp查看器窗口(其中没有窗口),并首次调用htmlhelp函数。这导致调用windows.pas中的LoadLibrary。 如果我在程序中显示任何htmlhelp,则一切正常。
因此,我认为这可能是在RTL最终确定过程中调用LoadLibrary('hhctl.ocx')的问题。但我不知道如何避免这种情况。

通常,当主机应用程序关闭时,Windows会自动关闭该应用程序打开的所有帮助窗口。有一个问题。。。这可能会导致访问冲突

我不是一个Delphi程序员——我更忙于帮助编写(CHM)和VB。您可以尝试使用HH_INITIALIZE、HH_UNINITIALIZE命令。这些都记录在HH研讨会在线帮助中。但是-请检查您的代码是否为HH_CLOSE或HH_CLOSE_

早点打电话给HH_CLOSE_。在HH_CLOSE_ALL和调用UnloadLibrary之间获得更多空间。在VB和Delphi中,您将对表单QueryLoad执行调用,而不是对表单Close或Destroy执行调用

一种解决方法是手动关闭HH窗口或在CloseQuery()事件中的较早时间关闭HH窗口,并使用sleep(0)为HTMLHelp提供几个周期以稳定下来

//Will close all Help windows opened by the application - no handle required
HtmlHelp(0, nil, HH_CLOSE_ALL, 0);

样本:

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
   //if IsWindow(_HHwinHwnd) then
   //  SendMessage( _HHwinHwnd, wm_close, 0, 0 );
   HtmlHelpA(0, nil, HH_CLOSE_ALL, 0);
   Sleep(0);
end;
不要盲目地在关机时呼叫HH_CLOSE_。如果用户没有安装HTML帮助,则此调用将使应用程序崩溃。这里是更安全的代码。注意,在调用HtmlHelp()之前,我们正在检查HH是否已安装

procedure;
开始
如果@HH.HtmlHelp Nil,则//HH API可用
开始
HH.HtmlHelp(0,无,HH_CLOSE_ALL,0);
睡眠(0);
终止
终止
定稿
如果HTMLHELPMODEL为0,则为自由库(HTMLHELPMODEL);
终止
这是问题的主要根源。任何人都不应在初始化或终结部分(显式或隐式)使用LoadLibrary/FreeLibrary

简而言之,这是因为初始化和终结代码在特殊条件下运行,在DllMain函数内部,加载程序锁处于活动状态。在这些情况下,不应该调用上述两个函数(实际上,甚至GetModuleHandle和GetProcAddress也可能失败!),不应该使用锁,也不应该启动或终止线程。您可以从中了解装载机锁。我还推荐Chris Brumme的综合研究文章


那么,Embarcadero要对这个bug负责,我们能做什么?最简单的解决方法是(正如您已经发现的那样)始终从程序中调用HtmlHelp,或者简单地调用LoadLibrary('hhctrl.ocx'),记住不要将此调用放在任何单元的初始化部分。

LoadLibrary('hhctrl.ocx')
的额外调用可能只会导致内存泄漏(实际上取决于您调用它的方式),而忽略错误可能是一个非常丑陋的解决方法。请发布用于初始化库的代码。您能显示一个吗?很多人使用D2007时没有这些问题。你的计划有什么不同?@DavidHeffernan不,不幸的是我不能。这是一个非常复杂的程序(我们目前维护的最复杂的程序),我无法用任何简单的方法重现这个问题。我以前也从未遇到过这种情况,我自己也经常使用Delphi2007。我希望其他人可能在一个更简单的程序中遇到了同样的问题,并且能够找到解决方案。@quasoft该代码是Windows.pas中Delphi 2007 RTL的标准代码,第31980行及以下代码。我的程序没有做任何特殊的事情。但你可能真的帮了我这个问题,因为我刚刚发现这个库只从HtmlHelpViewer.pas的最终代码加载,我会进一步调查。你为什么不调试这个问题呢?谢谢你的回答,但这不是我面临的问题。Delphi RTL已经在定稿中调用了HtmlHelp(0,nil,HH_CLOSE_ALL,0)。不幸的是,这实际上似乎是问题的根源。请参阅我的编辑部分,以了解问题的原因。@dummzeuch您写道“问题显然只在程序中从未调用html帮助时出现…”,正如我在上面的一个示例代码“if IsWindow(_HHwinHwnd)then…”中提到的那样。你能检查你的代码是否存在HTMLHelp窗口,然后只有当这是真的时才给它一个HH_CLOSE_ALL吗?@dummzeuch问题是在编译代码中还是在运行IDE时发生的?我无法更改RTL代码。(或者更确切地说,我不愿意)。此代码不检查HTMLHelp窗口。问题发生在编译后的代码中。好的,不要碰正在运行的系统-但我认为测试睡眠(0);这很容易。下面有一些进一步的问题
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
   //if IsWindow(_HHwinHwnd) then
   //  SendMessage( _HHwinHwnd, wm_close, 0, 0 );
   HtmlHelpA(0, nil, HH_CLOSE_ALL, 0);
   Sleep(0);
end;
procedure HHCloseAll;
begin
  If @HH.HtmlHelp <> Nil then  //HH API is available
    begin
    HH.HtmlHelp(0, nil, HH_CLOSE_ALL, 0);
    Sleep(0); 
  end;
end;
finalization
  if HtmlHelpModule <> 0 then FreeLibrary(HtmlHelpModule);
end.