Dmitry
Dmitry

Reputation: 14622

DLL registration with regsvr32.exe freezes when unit HtmlHelpViewer is used in Delphi XE or Delphi XE2

DLL registration with regsvr32.exe freezes when unit HtmlHelpViewer is used in DLL sources in Delphi XE or Delphi XE2 Update 3. Just add the unit to interface uses list. The main project (that uses DLL) freezes on exit too.

How to fix the issue?

Thanks for the help!

STEPS TO REPRODUCE THE ISSUE AND ISSUE IN SUGGESTED FIX:

1). Please create the following DLL:

library Test;

uses
  ComServ,
  HtmlHelpFixer,
  HtmlHelpViewer;

exports
  DllGetClassObject,
  DllCanUnloadNow,
  DllRegisterServer,
  DllUnregisterServer;

begin
end.

2). Also create the following BPL linked to this DLL (by -LUTestBpl dcc32 parameter for example):

package TestBpl;

requires
  Vcl;

end.

3). Then just execute: regsvr32.exe /s Test.dll. OS Windows 7 32-bit.

Upvotes: 1

Views: 2202

Answers (2)

David Heffernan
David Heffernan

Reputation: 612963

Update

According to the latest comments on the QC report submitted by Altaveron, this problem will be resolved in the next Delphi update, update 4. And indeed, Altaveron now confirms that update 4 does resolve the issue.


This is a known problem with the MS HTML help control, hhctrl.ocx. The best description of it that I am aware of is at the HelpWare FAR HTML FAQ. There are many QC reports describing the issue: 48983, 67463, 78998, 89616.

According to the latest QC report, this is fixed in XE2 but you report otherwise and I'd be inclined to believe you. Especially as a comparison of the source for the HtmlHelpViewer unit from XE and XE2 reveals no changes that appear related to this issue.

It's quite hard to work around the issue since the code that needs to be modified is buried deep inside the HtmlHelpViewer unit. I've had to resort to patching the HtmlHelp API call. Like this:

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.

Include this unit early in your .dpr uses list, before any unit that does anything with HTML help.

The version of the code that I use does a little more and takes steps to ensure that any open help windows are closed when the DLL unloads. This no longer happens because we have stopped sending HH_CLOSE_ALL.

You will want to make sure that any help windows are shut down then keep track of the window handles returned by HtmlHelp calls, which you can now intercept. Then at shutdown send a WM_CLOSE message to those windows which replaces the missing HH_CLOSE_ALL call to HtmlHelp.

However, I believe that the code above should get you over your immediate hurdle with regsvr32 which won't be showing help windows.

Feel free to do some experimentation! At the very least, the code above gives you entry points with which you can modify the behaviour of the HtmlHelpViewer unit.

Upvotes: 9

Dmitry
Dmitry

Reputation: 14622

Embarcadero have fixed this issue on Delphi XE2 Update 4. But now context help doesn't work on IDE while you're using BPL with HtmlHelpViewer unit on uses clause.

Upvotes: 0

Related Questions