unit HtmlHelpFunc;

{
  Inno Setup
  Copyright (C) 1997-2006 Jordan Russell
  Portions by Martijn Laan
  For conditions of distribution and use, see LICENSE.TXT.

  Functions for HTML Help

  $jrsoftware: issrc/Projects/HtmlHelpFunc.pas,v 1.6 2009/03/23 23:16:44 mlaan Exp $
}

interface

{$I VERSION.INC}

uses
  Windows;

const
  HH_DISPLAY_TOPIC = $0000;
  HH_KEYWORD_LOOKUP = $000D;

type
  THtmlHelp = function(hwndCaller: HWND; pszFile: PChar; uCommand: UINT; dwData: DWORD): HWND; stdcall;

  PHH_AKLink = ^THH_AKLink;
  THH_AKLINK = record
    cbStruct: Integer;
    fReserved: Bool;
    pszKeywords: PChar;
    pszUrl: PChar;
    pszMsgText: PChar;
    pszMsgTitle: PChar;
    pszWindow: PChar;
    fIndexOnFail: Bool;
  end;

var
  HtmlHelp: THtmlHelp;

procedure InitHtmlHelpLibrary;
procedure FreeHtmlHelpLibrary;

implementation

uses
  Messages, SysUtils;

var
  HHCtrl: THandle;

procedure InitHtmlHelpLibrary;
begin
  if HHCtrl = 0 then begin
    HHCtrl := LoadLibrary('hhctrl.ocx');
    if HHCtrl <> 0 then
      HtmlHelp := GetProcAddress(HHCtrl, {$IFDEF UNICODE}'HtmlHelpW'{$ELSE}'HtmlHelpA'{$ENDIF})
    else
      HtmlHelp := nil;
   end;
end;

procedure FreeHtmlHelpLibrary;
begin
  if HHCtrl <> 0 then begin
    HtmlHelp := nil;
    FreeLibrary(HHCtrl);
    HHCtrl := 0;
  end;
end;

function CloseHtmlHelpWindowsEnumProc(Wnd: HWND; lParam: LPARAM): BOOL; stdcall;
var
  PID: DWORD;
  ClassName: array[0..31] of Char;
  MsgResult: DWORD;
begin
  if (GetWindowThreadProcessId(Wnd, @PID) <> 0) and
     (PID = GetCurrentProcessId) then begin
    if (GetClassName(Wnd, ClassName, SizeOf(ClassName) div SizeOf(ClassName[0])) > 0) and
       (StrIComp(ClassName, 'HH Parent') = 0) then begin
      { Consider only enabled windows. If an HTML Help window is disabled
        because it's waiting on a modal dialog (e.g. Properties) then it's
        probably not safe to close it. }
      if IsWindowEnabled(Wnd) then
        SendMessageTimeout(Wnd, WM_CLOSE, 0, 0, SMTO_BLOCK, 7500, MsgResult);
    end;
  end;
  Result := True;
end;

procedure CloseHtmlHelpWindows;
begin
  { Note: We don't call HtmlHelp(HH_CLOSE_ALL) here because its operation is
    asynchronous. (See: http://helpware.net/FAR/far_faq.htm#HH_CLOSE_ALL)
    If HHCTRL.OCX is unloaded too quickly after HH_CLOSE_ALL, a crash can
    occur. Even if HHCTRL.OCX isn't explicitly unloaded, it still *might* be
    possible for the main thread to exit while the HH thread is still in the
    process of closing the window and cleaning up the temporary file.
    Therefore, we use a different approach: we find the window(s) and send a
    WM_CLOSE message synchronously. }
  if Assigned(HtmlHelp) then
    EnumWindows(@CloseHtmlHelpWindowsEnumProc, 0);
end;

initialization
finalization
  { Must explicitly close any open HTML Help window before terminating,
    otherwise it leaves behind a temporary file. (Most apps don't bother
    doing this, including IE and Outlook Express.) }
  CloseHtmlHelpWindows;
end.
