在Delphi XE或Delphi XE2中使用单元HtmlHelpViewer时,regsvr32.exe的DLL注册冻结

Dmi*_*try 1 delphi delphi-xe delphi-xe2

当在Delphi XE或Delphi XE2 Update 3的DLL源代码中使用单元HtmlHelpViewer时,regsvr32.exe的DLL注册会冻结.只需将该单元添加到接口使用列表即可.主要项目(使用DLL)也在退出时冻结.

如何解决这个问题?

谢谢您的帮助!

在建议的修复中重现问题和问题的步骤:

1).请创建以下DLL:

library Test;

uses
  ComServ,
  HtmlHelpFixer,
  HtmlHelpViewer;

exports
  DllGetClassObject,
  DllCanUnloadNow,
  DllRegisterServer,
  DllUnregisterServer;

begin
end.
Run Code Online (Sandbox Code Playgroud)

2).还创建链接到此DLL的以下BPL(-LUTestBpl例如,通过dcc32参数):

package TestBpl;

requires
  Vcl;

end.
Run Code Online (Sandbox Code Playgroud)

3).然后执行:regsvr32.exe /s Test.dll.OS Windows 7 32位.

Dav*_*nan 9

更新

根据Altaveron提交的QC报告的最新评论,这个问题将在下一次Delphi更新中得到解决,更新4.事实上,Altaveron现在确认更新4确实解决了这个问题.


这是MS HTML帮助控件hhctrl.ocx的已知问题.我所知道的最好的描述是在HelpWare FAR HTML FAQ中.有许多描述了这个问题QC报告:48983,67463,78998,89616.

根据最新的质量控制报告,这在XE2中得到了修复,但是你报告了其他情况,我倾向于相信你.特别是作为HtmlHelpViewerXE和XE2单位来源的比较,没有发现与此问题相关的变化.

由于需要修改的代码深埋在HtmlHelpViewer单元内,因此很难解决这个问题.我不得不求助于修补HtmlHelpAPI调用.像这样:

unit HtmlHelpFixer;

interface

implementation

uses
  Windows;

function HtmlHelp(hWndCaller: HWND; pszFile: PWideChar; uCommand: UINT; dwData: DWORD): HWND;
begin
  if uCommand=HH_CLOSE_ALL then begin
    //don't call HtmlHelpW because it can result in a hang due to a bug in hhctrl.ocx
    Result := 0;
  end else begin
    Result := HtmlHelpW(hWndCaller, pszFile, uCommand, dwData);
  end;
end;

procedure PatchCode(Address: Pointer; const NewCode; Size: Integer);
var
  OldProtect: DWORD;
begin
  if VirtualProtect(Address, Size, PAGE_EXECUTE_READWRITE, OldProtect) then begin
    Move(NewCode, Address^, Size);
    FlushInstructionCache(GetCurrentProcess, Address, Size);
    VirtualProtect(Address, Size, OldProtect, @OldProtect);
  end;
end;

type
  PInstruction = ^TInstruction;
  TInstruction = packed record
    Opcode: Byte;
    Offset: Integer;
  end;

procedure RedirectProcedure(OldAddress, NewAddress: Pointer);
var
  NewCode: TInstruction;
begin
  NewCode.Opcode := $E9;//jump relative
  NewCode.Offset := NativeInt(NewAddress)-NativeInt(OldAddress)-SizeOf(NewCode);
  PatchCode(OldAddress, NewCode, SizeOf(NewCode));
end;

procedure RedirectHtmlHelp;
var
  HtmlHelp: function(hWndCaller: HWND; pszFile: PWideChar; uCommand: UINT; dwData: DWORD_PTR): HWND;
begin
  HtmlHelp := Windows.HtmlHelp;
  RedirectProcedure(@HtmlHelp, @HtmlHelpFixer.HtmlHelp);
end;

initialization
  RedirectHtmlHelp;

end.
Run Code Online (Sandbox Code Playgroud)

uses任何使用HTML帮助的单位之前,请先在.dpr 列表中包含此单元.

我使用的代码版本稍微多一些,并采取措施确保在DLL卸载时关闭所有打开的帮助窗口.这不再发生,因为我们已停止发送HH_CLOSE_ALL.

您需要确保关闭所有帮助窗口,然后跟踪HtmlHelp调用返回的窗口句柄,您现在可以拦截它们.然后在关机时向WM_CLOSE那些替换丢失的HH_CLOSE_ALL呼叫的窗口发送一条消息HtmlHelp.

但是,我相信上面的代码可以帮助您解决使用regsvr32的直接障碍,它不会显示帮助窗口.

随意做一些实验!至少,上面的代码为您提供了可以修改HtmlHelpViewer单元行为的入口点.