Release 960506

Mon May  6 12:56:26 1996  Alexandre Julliard  <julliard@lrc.epfl.ch>

	* [DEVELOPERS-HINTS]
	Added paragraph on naming conventions for Win16/Win32/Winelib.

	* [controls/menu.c]
	Create a default system menu that is the same for all windows
	instead of making a copy every time.

	* [include/wintypes.h]
	Added WINELIB_NAME and DECL_WINELIB_TYPE macros.
	Added xx16 and xx32 definitions for most types. General clean-up.

	* [memory/global.c] [memory/local.c] [*/*]
	Renamed Global and Local heap functions to xxx16. Added all xxx32
	versions of the same functions.

	* [memory/selector.c]
	Mask out lower bits of selector in FreeSelector().

	* [misc/lstr.c]
	Fixed wvsprintf().

	* [windows/class.c]
	Changed the class structure to make Win32 support easier.

	* [windows/defwnd.c]
	Added handling of WM_INITMENUPOPUP for system menu to gray out
	invalid options.

	* [windows/winpos.c]
	Bug fix: the WINDOSPOS structure pointer in WM_NCCALCSIZE must be
	a SEGPTR.

Sun May  5 03:51:26 1996  Huw D. M. Davies <h.davies1@physics.oxford.ac.uk>

	* [memory/local.c]
	Implementation of moveable and (rudimentary) support for
 	discardable local memory, plus several bug fixes.

Sat May  4 18:33:35 1996  Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>

	* [include/windows.h] [windows/win.c] [if1632/user.spec] 
	FindWindowEx() implemented (someone reported it was missing
	for FrameMaker 4.1).

	* [if1632/kernel32.spec] [if1632/user32.spec] [win32/memory.c]
	  [win32/resource.c]
	Misc small stubs/small functions which bring win95 binaries
	further down the road. (IsBadCodePtr, LocalReAlloc,GetCursorPos)
	Small fix in WIN32_LoadAcceleratorsA.

Fri May  3 19:43:12 1996  Frans van Dorsselaer <dorssel@rulhm1.LeidenUniv.nl>

	* [controls/edit.c] [controls/EDIT.TODO]
	Changed / fixed some types and typecasts.
	Fixed the scrollbar reset after WM_SETHANDLE / WM_SETTEXT.
	Added heap initialization in WM_CREATE.

Fri May  3 19:30:02 1996  Greg Kreider <kreider@natlab.research.philips.com>

	* [controls/combo.c] [controls/listbox.c]
	Pass WM_[HV]SCROLL to listbox, but not combo.
	Don't try to redraw non-existant scroll bars (changes dwStyle flags).
	Combo box gets border.
	Combo box includes button (otherwise button won't trigger dropdown).
	Proper border around RectButton.
	Check size consistancy of combo, listbox, and button after resizing 
	or before painting.  These routines still aren't completely correct.
	Localize size checks in separate routines.
	Listboxes are white.

Thu May  2 19:21:23 1996  Albrecht Kleine  <kleine@ak.sax.de>

	* [controls/combo.c][include/commdlg.h][include/commdlg.c]
	  [resources/sysres_De.rc][resources/sysres_En.rc]
	Introduced ChooseFont dialog, but needed some patches in 
	handling of comboboxes with edit controls.

Tue Apr 30 00:33:27 1996  Ulrich Schmid  <uschmid@mail.hh.provi.de>

	* [programs/winhelp/*]
	Added a help viewer and a simple `.hlp' to `.sgml' converter.

Mon Apr 29 14:17:57 1996  Tristan Tarrant <tst@sthinc.demon.co.uk>

	* [resources/sysres_*.rc] [misc/shell.c]
	Modified size of "About" dialog boxes.

Sat Apr 27 18:10:11 Martin von Loewis <loewis@informatik.hu-berlin.de>

	* [if1632/Makefile.in][loader/builtin.c]
	crtdll.spec, ntdll.spec, wsock32.spec: new files.

	* [loader/pe_image.c]
	Fix error message if import by ordinal failed.
diff --git a/programs/Makefile.in b/programs/Makefile.in
index a954a5f..c42928d 100644
--- a/programs/Makefile.in
+++ b/programs/Makefile.in
@@ -1,4 +1,4 @@
-SUBDIRS = progman
+SUBDIRS = progman winhelp
 
 all: $(SUBDIRS)
 
@@ -8,6 +8,9 @@
 depend:
 	for i in $(SUBDIRS); do (cd $$i; $(MAKE) depend); done
 
+install:
+	for i in $(SUBDIRS); do (cd $$i; $(MAKE) install); done
+
 clean:
 	for i in $(SUBDIRS); do (cd $$i; $(MAKE) clean); done
 
diff --git a/programs/progman/Makefile.in b/programs/progman/Makefile.in
index 37af394..8db65d2 100644
--- a/programs/progman/Makefile.in
+++ b/programs/progman/Makefile.in
@@ -6,6 +6,19 @@
 LANGUAGES   = En De Fr
 LICENSELANG = En
 
+# Installation infos
+
+INSTALL         = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA    = @INSTALL_DATA@
+prefix          = @prefix@
+exec_prefix     = @exec_prefix@
+bindir          = @bindir@
+libdir          = @libdir@
+sysconfdir      = @sysconfdir@
+mandir          = @mandir@/man1
+manext          = .1
+
 MOSTOBJS = \
 	dialog.o \
 	group.o \
@@ -30,10 +43,15 @@
 progman: $(MOSTOBJS) $(STRINGOBJS) $(WINELIB)
 	$(CC) -o progman $(MOSTOBJS) $(LDOPTIONS) $(ALL_LIBS) $(STRINGOBJS)
 
+install: dummy
+	$(INSTALL_PROGRAM) progman $(bindir)/progman
+
 clean::
 	$(RM) accel.c accel.h $(LANGUAGES:%=%.c) $(LANGUAGES:%=%.h) progman
 
 accel.c accel.h: $(WINERC) Xx.rc
 $(LANGUAGES:%=%.c) $(LANGUAGES:%=%.h): $(WINERC) Xx.rc
 
+dummy:
+
 ### Dependencies:
diff --git a/programs/winhelp/ChangeLog b/programs/winhelp/ChangeLog
new file mode 100644
index 0000000..9ba2f94
--- /dev/null
+++ b/programs/winhelp/ChangeLog
@@ -0,0 +1,7 @@
+Mon Apr 29 19:48:15 1996  Ulrich Schmid  <uschmid@mail.hh.provi.de>
+
+	* [winhelp.c] [winhelp.h] [hlpfile.c] [hlpfile.h]
+	[macro.c] [macro.h] [macro.lex.l] [macro.yacc.y]
+ 	[string.c] [En.rc] [De.rc] [Xx.rc] [hlp2sgml.c]
+	Original by Ulrich Schmid
+
diff --git a/programs/winhelp/De.rc b/programs/winhelp/De.rc
new file mode 100644
index 0000000..38a0c17
--- /dev/null
+++ b/programs/winhelp/De.rc
@@ -0,0 +1,48 @@
+/*
+ * Help Viewer
+ *
+ * Copyright 1996 Ulrich Schmid
+ */
+
+/* This file is not yet complete !! */
+
+#define LANGUAGE_ID                  De
+#define LANGUAGE_NUMBER              2
+
+/* Menu */
+
+#define MENU_FILE                    "&Datei"
+#define MENU_FILE_OPEN               "Ö&ffnen..."
+#define MENU_FILE_PRINT              "Thema &drucken"
+#define MENU_FILE_PRINTER_SETUP      "Drucker&einrichtung..."
+#define MENU_FILE_EXIT               "&Beenden"
+
+#define MENU_EDIT                    "&Bearbeiten"
+#define MENU_EDIT_COPY_DIALOG        "&Kopieren..."
+#define MENU_EDIT_ANNOTATE           "&Anmerken..."
+
+#define MENU_BOOKMARK                "&Lesezeichen"
+#define MENU_BOOKMARK_DEFINE         "&Definieren..."
+
+#define MENU_HELP                    "&Hilfe"
+#define MENU_HELP_ON_HELP            "&Hilfe benutzen"
+#define MENU_HELP_ON_TOP             "Immer im &Vordergrund"
+#define MENU_HELP_INFO               "Inf&o..."
+#define MENU_HELP_ABOUT_WINE         "&Über WINE"
+
+/* Strings */
+
+#define STRING_WINE_HELP             "WINE Hilfe"
+#define STRING_ERROR                 "FEHLER"
+#define STRING_WARNING               "ACHTUNG"
+#define STRING_INFO                  "Information"
+#define STRING_NOT_IMPLEMENTED       "Nicht implementiert"
+#define STRING_HLPFILE_ERROR_s       "Fehler beim Lesen der Hilfe-Datei `%s'"
+#define STRING_CONTENTS              "&Inhalt"
+#define STRING_SEARCH                "&Suchen"
+#define STRING_BACK                  "&Zurück"
+#define STRING_HISTORY               "&Bisher"
+#define STRING_ALL_FILES             "Alle Dateien (*.*)"
+#define STRING_HELP_FILES_HLP        "Hilfe-Dateien (*.hlp)"
+
+#include "Xx.rc"
diff --git a/programs/winhelp/En.rc b/programs/winhelp/En.rc
new file mode 100644
index 0000000..b14389b
--- /dev/null
+++ b/programs/winhelp/En.rc
@@ -0,0 +1,48 @@
+/*
+ * Help Viewer
+ *
+ * Copyright 1996 Ulrich Schmid
+ */
+
+/* This file is not yet complete !! */
+
+#define LANGUAGE_ID                  En
+#define LANGUAGE_NUMBER              0
+
+/* Menu */
+
+#define MENU_FILE                    "&File"
+#define MENU_FILE_OPEN               "&Open..."
+#define MENU_FILE_PRINT              "&Print"
+#define MENU_FILE_PRINTER_SETUP      "Printer &setup..."
+#define MENU_FILE_EXIT               "&Exit"
+
+#define MENU_EDIT                    "&Edit"
+#define MENU_EDIT_COPY_DIALOG        "&Copy..."
+#define MENU_EDIT_ANNOTATE           "&Annotate..."
+
+#define MENU_BOOKMARK                "&Bookmark"
+#define MENU_BOOKMARK_DEFINE         "&Define..."
+
+#define MENU_HELP                    "&Help"
+#define MENU_HELP_ON_HELP            "Help &on help"
+#define MENU_HELP_ON_TOP             "Always on &top"
+#define MENU_HELP_INFO               "&Info..."
+#define MENU_HELP_ABOUT_WINE         "&About WINE"
+
+/* Strings */
+
+#define STRING_WINE_HELP             "WINE Help"
+#define STRING_ERROR                 "ERROR"
+#define STRING_WARNING               "WARNING"
+#define STRING_INFO                  "Information"
+#define STRING_NOT_IMPLEMENTED       "Not implemented"
+#define STRING_HLPFILE_ERROR_s       "Error while reading the help file `%s'"
+#define STRING_CONTENTS              "&Contents"
+#define STRING_SEARCH                "&Search"
+#define STRING_BACK                  "&Back"
+#define STRING_HISTORY               "&History"
+#define STRING_ALL_FILES             "All files (*.*)"
+#define STRING_HELP_FILES_HLP        "Help files (*.hlp)"
+
+#include "Xx.rc"
diff --git a/programs/winhelp/Makefile.in b/programs/winhelp/Makefile.in
new file mode 100644
index 0000000..96a5fcb
--- /dev/null
+++ b/programs/winhelp/Makefile.in
@@ -0,0 +1,63 @@
+TOPSRC   = @top_srcdir@
+MODULE   = none
+PROGRAMS = winhelp hlp2sgml
+ALL_LIBS = $(WINELIB) $(X_LIBS) $(XPM_LIB) $(XLIB) $(LDLIBS)
+
+LANGUAGES   = En De
+
+# Installation infos
+
+INSTALL         = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA    = @INSTALL_DATA@
+prefix          = @prefix@
+exec_prefix     = @exec_prefix@
+bindir          = @bindir@
+libdir          = @libdir@
+sysconfdir      = @sysconfdir@
+mandir          = @mandir@/man1
+manext          = .1
+
+MOSTOBJS = \
+	winhelp.o \
+	hlpfile.o \
+	macro.o \
+	y.tab.o \
+	lex.yy.o
+
+STRINGOBJS = \
+	string.o \
+	$(LANGUAGES:%=%.o)
+
+C_SRCS = $(MOSTOBJS:.o=.c) $(STRINGOBJS:.o=.c) hlp2sgml.c
+
+all: check_winerc $(PROGRAMS)
+
+@MAKE_RULES@
+
+# Some strings need addresses >= 0x10000
+winhelp: $(MOSTOBJS) $(STRINGOBJS) $(WINELIB)
+	$(CC) -o winhelp $(MOSTOBJS) $(LDOPTIONS) $(ALL_LIBS) $(STRINGOBJS)
+
+hlp2sgml: hlp2sgml.o hlpfile.o
+	$(CC) -o hlp2sgml hlp2sgml.o hlpfile.o
+
+install: dummy
+	$(INSTALL_PROGRAM) winhelp $(bindir)/winhelp
+	$(INSTALL_PROGRAM) hlp2sgml $(bindir)/hlp2sgml
+
+clean::
+	$(RM) $(PROGRAMS) lex.yy.c y.tab.c y.tab.h
+	$(RM) $(LANGUAGES:%=%.c) $(LANGUAGES:%=%.h)
+
+y.tab.c y.tab.h: macro.yacc.y
+	$(YACC) -d -t macro.yacc.y
+
+lex.yy.c: macro.lex.l
+	$(LEX) -8 -I macro.lex.l
+
+$(LANGUAGES:%=%.c) $(LANGUAGES:%=%.h): $(WINERC) Xx.rc
+
+dummy:
+
+### Dependencies:
diff --git a/programs/winhelp/Xx.rc b/programs/winhelp/Xx.rc
new file mode 100644
index 0000000..d2e713b
--- /dev/null
+++ b/programs/winhelp/Xx.rc
@@ -0,0 +1,80 @@
+/*
+ * Help Viewer
+ *
+ * Copyright 1996 Ulrich Schmid
+ */
+
+#include "winhelp.h"
+
+#define CONCAT(a, b) CONCAT1(a, b)
+#define CONCAT1(a, b) a##b
+
+/* Menu */
+
+CONCAT(MENU_, LANGUAGE_ID) MENU
+{
+ POPUP MENU_FILE {
+   MENUITEM MENU_FILE_OPEN,             WH_OPEN
+   MENUITEM SEPARATOR   
+   MENUITEM MENU_FILE_PRINT,            WH_PRINT
+   MENUITEM MENU_FILE_PRINTER_SETUP,    WH_PRINTER_SETUP
+   MENUITEM SEPARATOR   
+   MENUITEM MENU_FILE_EXIT,             WH_EXIT
+ }
+ POPUP MENU_EDIT {
+   MENUITEM MENU_EDIT_COPY_DIALOG,      WH_COPY_DIALOG
+   MENUITEM SEPARATOR   
+   MENUITEM MENU_EDIT_ANNOTATE,         WH_ANNOTATE
+ }
+ POPUP MENU_BOOKMARK {
+   MENUITEM MENU_BOOKMARK_DEFINE,       WH_BOOKMARK_DEFINE
+ }
+ POPUP MENU_HELP {
+   MENUITEM MENU_HELP_ON_HELP,          WH_HELP_ON_HELP
+   MENUITEM MENU_HELP_ON_TOP,           WH_HELP_ON_TOP
+   MENUITEM SEPARATOR   
+   MENUITEM MENU_HELP_INFO,             WH_ABOUT
+#ifdef WINELIB
+   MENUITEM MENU_HELP_ABOUT_WINE,       WH_ABOUT_WINE
+#endif
+ }
+}
+
+/* Dialogs */
+
+DIALOG_TEST DIALOG 0, 0, 150, 22
+STYLE DS_MODALFRAME
+CAPTION "Macro Test"
+{
+GROUPBOX      "",   IDIGNORE,   4, 4, 102, 12
+EDITTEXT            99,         5, 7, 100,  8
+DEFPUSHBUTTON "OK", IDOK,     110, 5, 35,  12
+}
+
+/* Strings */
+
+#define ADDSTRING(str) ADDSTRING1(LANGUAGE_NUMBER, IDS_ ## str) STRING_ ## str
+#define ADDSTRING1(langnum, ids) ADDSTRING2(langnum, ids)
+#define ADDSTRING2(langnum, ids) 0x ## langnum ## ids
+
+#define STRINGIFY(str) STRINGIFY1(str)
+#define STRINGIFY1(str) #str
+
+#define STRING_LANGUAGE_ID        STRINGIFY(LANGUAGE_ID)
+
+STRINGTABLE
+{
+ADDSTRING(LANGUAGE_ID)
+ADDSTRING(WINE_HELP)
+ADDSTRING(ERROR)
+ADDSTRING(WARNING)
+ADDSTRING(INFO)
+ADDSTRING(NOT_IMPLEMENTED)
+ADDSTRING(HLPFILE_ERROR_s)
+ADDSTRING(CONTENTS)
+ADDSTRING(SEARCH)
+ADDSTRING(BACK)
+ADDSTRING(HISTORY)
+ADDSTRING(ALL_FILES)
+ADDSTRING(HELP_FILES_HLP)
+}
diff --git a/programs/winhelp/hlp2sgml.c b/programs/winhelp/hlp2sgml.c
new file mode 100644
index 0000000..7df0184
--- /dev/null
+++ b/programs/winhelp/hlp2sgml.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright 1996 Ulrich Schmid
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include "windows.h"
+#include "hlpfile.h"
+
+typedef struct
+{
+  const char *header1;
+  const char *header2;
+  const char *section;
+  const char *first_paragraph;
+  const char *newline;
+  const char *next_paragraph;
+  const char *special_char;
+  const char *begin_italic;
+  const char *end_italic;
+  const char *begin_boldface;
+  const char *end_boldface;
+  const char *begin_typewriter;
+  const char *end_typewriter;
+  const char *tail;
+} FORMAT;
+
+typedef struct
+{
+  const char ch;
+  const char *subst;
+} CHARMAP[];
+
+
+FORMAT format =
+{
+  "<!doctype linuxdoc system>\n"
+  "<article>\n"
+  "<title>\n",
+
+  "\n<author>\n%s\n"
+  "<date>\n%s\n",
+
+  "\n<sect>\n",
+  "\n<p>\n",
+  "\n<newline>\n",
+  "\n\n",
+
+  "&%s;",
+
+  "<em>",
+  "</em>",
+  "<bf>",
+  "</bf>",
+  "<tt>",
+  "</tt>",
+
+  "\n</article>\n"
+};
+
+CHARMAP charmap =
+  {{'Æ', "AElig"},
+   {'Á', "Aacute"},
+   {'Â', "Acirc"},
+   {'À', "Agrave"},
+   {'Ã', "Atilde"},
+   {'Ç', "Ccedil"},
+   {'É', "Eacute"},
+   {'È', "Egrave"},
+   {'Ë', "Euml"},
+   {'Í', "Iacute"},
+   {'Î', "Icirc"},
+   {'Ì', "Igrave"},
+   {'Ï', "Iuml"},
+   {'Ñ', "Ntilde"},
+   {'Ó', "Oacute"},
+   {'Ô', "Ocirc"},
+   {'Ò', "Ograve"},
+   {'Ø', "Oslash"},
+   {'Ú', "Uacute"},
+   {'Ù', "Ugrave"},
+   {'Ý', "Yacute"},
+   {'á', "aacute"},
+   {'â', "acirc"},
+   {'æ', "aelig"},
+   {'à', "agrave"},
+   {'å', "aring"},
+   {'ã', "atilde"},
+   {'ç', "ccedil"},
+   {'é', "eacute"},
+   {'ê', "ecirc"},
+   {'è', "egrave"},
+   {'ë', "euml"},
+   {'í', "iacute"},
+   {'î', "icirc"},
+   {'ì', "igrave"},
+   {'ï', "iuml"},
+   {'ñ', "ntilde"},
+   {'ó', "oacute"},
+   {'ÿ', "yuml"},
+   {'ô', "ocirc"},
+   {'ò', "ograve"},
+   {'ø', "oslash"},
+   {'õ', "otilde"},
+   {'ú', "uacute"},
+   {'û', "ucirc"},
+   {'ù', "ugrave"},
+   {'ý', "yacute"},
+   {'<', "lt"},
+   {'&', "amp"},
+   {'"', "dquot"},
+   {'#', "num"},
+   {'%', "percnt"},
+   {'\'', "quot"},
+#if 0
+   {'(', "lpar"},
+   {')', "rpar"},
+   {'*', "ast"},
+   {'+', "plus"},
+   {',', "comma"},
+   {'-', "hyphen"},
+   {':', "colon"},
+   {';', "semi"},
+   {'=', "equals"},
+   {'@', "commat"},
+   {'[', "lsqb"},
+   {']', "rsqb"},
+   {'^', "circ"},
+   {'_', "lowbar"},
+   {'{', "lcub"},
+   {'|', "verbar"},
+   {'}', "rcub"},
+   {'~', "tilde"},
+#endif
+   {'\\', "bsol"},
+   {'$', "dollar"},
+   {'Ä', "Auml"},
+   {'ä', "auml"},
+   {'Ö', "Ouml"},
+   {'ö', "ouml"},
+   {'Ü', "Uuml"},
+   {'ü', "uuml"},
+   {'ß', "szlig"},
+   {'>', "gt"},
+   {'§', "sect"},
+   {'¶', "para"},
+   {'©', "copy"},
+   {'¡', "iexcl"},
+   {'¿', "iquest"},
+   {'¢', "cent"},
+   {'£', "pound"},
+   {'×', "times"},
+   {'±', "plusmn"},
+   {'÷', "divide"},
+   {'¬', "not"},
+   {'µ', "mu"},
+   {0,0}};
+
+/***********************************************************************
+ *
+ *           print_text
+ */
+
+static void print_text(const char *p)
+{
+  int i;
+
+  for (; *p; p++)
+    {
+      for (i = 0; charmap[i].ch; i++)
+	if (*p == charmap[i].ch)
+	  {
+	    printf(format.special_char, charmap[i].subst);
+	    break;
+	  }
+      if (!charmap[i].ch)
+	printf("%c", *p);
+    }
+}
+
+/***********************************************************************
+ *
+ *           main
+ */
+
+int main(int argc, char **argv)
+{
+  HLPFILE   *hlpfile;
+  HLPFILE_PAGE *page;
+  HLPFILE_PARAGRAPH *paragraph;
+  time_t t;
+  char date[50];
+  char *filename;
+
+  hlpfile = HLPFILE_ReadHlpFile(argc > 1 ? argv[1] : "");
+
+  if (!hlpfile) return(2);
+
+  time(&t);
+  strftime(date, sizeof(date), "%x", localtime(&t));
+  filename = strrchr(hlpfile->lpszPath, '/');
+  if (filename) filename++;
+  else filename = hlpfile->lpszPath;
+
+  /* Header */
+  printf(format.header1);
+  print_text(hlpfile->lpszTitle);
+  printf(format.header2, filename, date);
+
+  for (page = hlpfile->first_page; page; page = page->next)
+    {
+      paragraph = page->first_paragraph;
+      if (!paragraph) continue;
+
+      /* Section */
+      printf(format.section);
+      for (; paragraph && !paragraph->wVSpace; paragraph = paragraph->next)
+	print_text(paragraph->lpszText);
+      printf(format.first_paragraph);
+
+      for (; paragraph; paragraph = paragraph->next)
+	{
+	  /* New line; new paragraph */
+	  if (paragraph->wVSpace == 1)
+	    printf(format.newline);
+	  else if (paragraph->wVSpace > 1)
+	    printf(format.next_paragraph);
+
+	  if (paragraph->wFont)
+	    printf(format.begin_boldface);
+
+	  print_text(paragraph->lpszText);
+
+	  if (paragraph->wFont)
+	    printf(format.end_boldface);
+	}
+    }
+
+  printf(format.tail);
+
+  return(0);
+}
+
+/***********************************************************************
+ *
+ *           Substitutions for some WINELIB functions
+ */
+
+HFILE OpenFile( LPCSTR path, OFSTRUCT *ofs, UINT mode )
+{
+  FILE *file;
+
+  if (!*path) return (HFILE) stdin;
+
+  file = fopen(path, "r");
+  if (!file) return HFILE_ERROR;
+  return (HFILE) file;
+}
+
+HFILE _lclose( HFILE hFile )
+{
+  fclose((FILE*) hFile);
+  return 0;
+}
+
+LONG _hread( HFILE hFile, SEGPTR buffer, LONG count )
+{
+  return fread(buffer, 1, count, (FILE*) hFile);
+}
+
+HGLOBAL GlobalAlloc( WORD flags, DWORD size )
+{
+  return (HGLOBAL) malloc(size);
+}
+
+LPVOID GlobalLock( HGLOBAL handle )
+{
+  return (LPVOID) handle;
+}
+
+HGLOBAL GlobalFree( HGLOBAL handle )
+{
+  free((VOID*) handle);
+  return(0);
+}
+
+/*
+ * String functions
+ *
+ * Copyright 1993 Yngvi Sigurjonsson (yngvi@hafro.is)
+ */
+
+INT lstrcmp(LPCSTR str1,LPCSTR str2)
+{
+  return strcmp( str1, str2 );
+}
+
+INT lstrcmpi( LPCSTR str1, LPCSTR str2 )
+{
+  INT res;
+
+  while (*str1)
+    {
+      if ((res = toupper(*str1) - toupper(*str2)) != 0) return res;
+      str1++;
+      str2++;
+    }
+  return toupper(*str1) - toupper(*str2);
+}
+
+INT lstrlen(LPCSTR str)
+{
+  return strlen(str);
+}
+
+SEGPTR lstrcpy( SEGPTR target, SEGPTR source )
+{
+  strcpy( (char *)target, (char *)source );
+  return target;
+}
+
+void hmemcpy(LPVOID hpvDest, LPCVOID hpvSource, LONG cbCopy)
+{
+  memcpy(hpvDest, hpvSource, cbCopy);
+}
+
+/* Local Variables:    */
+/* c-file-style: "GNU" */
+/* End:                */
diff --git a/programs/winhelp/hlpfile.c b/programs/winhelp/hlpfile.c
new file mode 100644
index 0000000..80232d9
--- /dev/null
+++ b/programs/winhelp/hlpfile.c
@@ -0,0 +1,989 @@
+/*
+ * Help Viewer
+ *
+ * Copyright 1996 Ulrich Schmid
+ */
+
+#include <stdio.h>
+#include <windows.h>
+#include "winhelp.h"
+
+static void Report(LPCSTR str)
+{
+#if 0
+  fprintf(stderr, "%s\n", str);
+#endif
+}
+
+#define GET_USHORT(buffer, i)\
+(((BYTE)((buffer)[(i)]) + 0x100 * (BYTE)((buffer)[(i)+1])))
+#define GET_SHORT(buffer, i)\
+(((BYTE)((buffer)[(i)]) + 0x100 * (signed char)((buffer)[(i)+1])))
+#define GET_UINT(buffer, i)\
+GET_USHORT(buffer, i) + 0x10000 * GET_USHORT(buffer, i+2)
+
+static BOOL HLPFILE_DoReadHlpFile(HLPFILE*, LPCSTR);
+static BOOL HLPFILE_ReadFileToBuffer(HFILE);
+static BOOL HLPFILE_FindSubFile(LPCSTR name, BYTE**, BYTE**);
+static VOID HLPFILE_SystemCommands(HLPFILE*);
+static BOOL HLPFILE_Uncompress1_Phrases();
+static BOOL HLPFILE_Uncompress1_Topic();
+static BOOL HLPFILE_GetContext(HLPFILE*);
+static BOOL HLPFILE_AddPage(HLPFILE*, BYTE*, BYTE*);
+static BOOL HLPFILE_AddParagraph(HLPFILE*, BYTE *, BYTE*);
+static UINT HLPFILE_Uncompressed2_Size(BYTE*, BYTE*);
+static VOID HLPFILE_Uncompress2(BYTE**, BYTE*, BYTE*);
+
+static HLPFILE *first_hlpfile = 0;
+static HGLOBAL  hFileBuffer;
+static BYTE    *file_buffer;
+
+static struct
+{
+  UINT    num;
+  BYTE   *buf;
+  HGLOBAL hBuffer;
+} phrases;
+
+static struct
+{
+  BYTE    **map;
+  BYTE    *end;
+  UINT    wMapLen;
+  HGLOBAL hMap;
+  HGLOBAL hBuffer;
+} topic;
+
+static struct
+{
+  UINT  bDebug;
+  UINT  wFont;
+  UINT  wIndent;
+  UINT  wHSpace;
+  UINT  wVSpace;
+  UINT  wVBackSpace;
+  HLPFILE_LINK link;
+} attributes;
+
+/***********************************************************************
+ *
+ *           HLPFILE_Contents
+ */
+
+HLPFILE_PAGE *HLPFILE_Contents(LPCSTR lpszPath)
+{
+  HLPFILE *hlpfile = HLPFILE_ReadHlpFile(lpszPath);
+
+  if (!hlpfile) return(0);
+
+  return(hlpfile->first_page);
+}
+
+/***********************************************************************
+ *
+ *           HLPFILE_PageByNumber
+ */
+
+HLPFILE_PAGE *HLPFILE_PageByNumber(LPCSTR lpszPath, UINT wNum)
+{
+  HLPFILE_PAGE *page;
+  HLPFILE *hlpfile = HLPFILE_ReadHlpFile(lpszPath);
+
+  if (!hlpfile) return(0);
+
+  for (page = hlpfile->first_page; page && wNum; page = page->next) wNum--;
+
+  return page;
+}
+
+/***********************************************************************
+ *
+ *           HLPFILE_HlpFilePageByHash
+ */
+
+HLPFILE_PAGE *HLPFILE_PageByHash(LPCSTR lpszPath, LONG lHash)
+{
+  INT i;
+  UINT wNum;
+  HLPFILE_PAGE *page;
+  HLPFILE *hlpfile = HLPFILE_ReadHlpFile(lpszPath);
+
+  if (!hlpfile) return(0);
+
+  for (i = 0; i < hlpfile->wContextLen; i++)
+    if (hlpfile->Context[i].lHash == lHash) break;
+
+  if (i >= hlpfile->wContextLen)
+    {
+      HLPFILE_FreeHlpFile(hlpfile);
+      return(0);
+    }
+
+  wNum = hlpfile->Context[i].wPage;
+  for (page = hlpfile->first_page; page && wNum; page = page->next) wNum--;
+
+  return page;
+}
+
+/***********************************************************************
+ *
+ *           HLPFILE_Hash
+ */
+
+LONG HLPFILE_Hash(LPCSTR lpszContext)
+{
+  LONG lHash = 0;
+  CHAR c;
+  while((c = *lpszContext++))
+    {
+      CHAR x = 0;
+      if (c >= 'A' && c <= 'Z') x = c - 'A' + 17;
+      if (c >= 'a' && c <= 'z') x = c - 'a' + 17;
+      if (c >= '1' && c <= '9') x = c - '0';
+      if (c == '0') x = 10;
+      if (c == '.') x = 12;
+      if (c == '_') x = 13;
+      if (x) lHash = lHash * 43 + x;
+    }
+  return lHash;
+}
+
+/***********************************************************************
+ *
+ *           HLPFILE_ReadHlpFile
+ */
+
+HLPFILE *HLPFILE_ReadHlpFile(LPCSTR lpszPath)
+{
+  HGLOBAL   hHlpFile;
+  HLPFILE *hlpfile;
+
+  for (hlpfile = first_hlpfile; hlpfile; hlpfile = hlpfile->next)
+    if (!lstrcmp(hlpfile->lpszPath, lpszPath))
+      {
+	hlpfile->wRefCount++;
+	return(hlpfile);
+      }
+
+  hHlpFile = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE) + lstrlen(lpszPath) + 1);
+  if (!hHlpFile) return(0);
+
+  hlpfile              = GlobalLock(hHlpFile);
+  hlpfile->hSelf       = hHlpFile;
+  hlpfile->wRefCount   = 1;
+  hlpfile->hTitle      = 0;
+  hlpfile->hContext    = 0;
+  hlpfile->wContextLen = 0;
+  hlpfile->first_page  = 0;
+  hlpfile->first_macro = 0;
+  hlpfile->prev        = 0;
+  hlpfile->next        = first_hlpfile;
+  first_hlpfile   = hlpfile;
+  if (hlpfile->next) hlpfile->next->prev = hlpfile;
+
+  hlpfile->lpszPath   = GlobalLock(hHlpFile);
+  hlpfile->lpszPath  += sizeof(HLPFILE);
+  lstrcpy(hlpfile->lpszPath, (SEGPTR) lpszPath);
+
+  phrases.hBuffer = topic.hBuffer = hFileBuffer = 0;
+
+  if (!HLPFILE_DoReadHlpFile(hlpfile, lpszPath))
+    {
+      HLPFILE_FreeHlpFile(hlpfile);
+      hlpfile = 0;
+    }
+
+  if (phrases.hBuffer) GlobalFree(phrases.hBuffer);
+  if (topic.hBuffer)   GlobalFree(topic.hBuffer);
+  if (topic.hMap)      GlobalFree(topic.hMap);
+  if (hFileBuffer)     GlobalFree(hFileBuffer);
+
+  return(hlpfile);
+}
+
+/***********************************************************************
+ *
+ *           HLPFILE_DoReadHlpFile
+ */
+
+static BOOL HLPFILE_DoReadHlpFile(HLPFILE *hlpfile, LPCSTR lpszPath)
+{
+  BOOL     ret;
+  HFILE    hFile;
+  OFSTRUCT ofs;
+  BYTE     *buf;
+
+  hFile=OpenFile(lpszPath, &ofs, OF_READ | OF_SEARCH);
+  if (hFile == HFILE_ERROR) return FALSE;
+
+  ret = HLPFILE_ReadFileToBuffer(hFile);
+  _lclose(hFile);
+  if (!ret) return FALSE;
+
+  HLPFILE_SystemCommands(hlpfile);
+  if (!HLPFILE_Uncompress1_Phrases()) return FALSE;
+  if (!HLPFILE_Uncompress1_Topic()) return FALSE;
+
+  buf = topic.map[0] + 0xc;
+  while(buf + 0xc < topic.end)
+    {
+      BYTE *end = MIN(buf + GET_UINT(buf, 0), topic.end);
+      UINT next, index, offset;
+
+      switch (buf[0x14])
+	{
+	case 0x02:
+	  if (!HLPFILE_AddPage(hlpfile, buf, end)) return(FALSE);
+	  break;
+
+	case 0x20:
+	  if (!HLPFILE_AddParagraph(hlpfile, buf, end)) return(FALSE);
+	  break;
+
+	case 0x23:
+	  if (!HLPFILE_AddParagraph(hlpfile, buf, end)) return(FALSE);
+	  break;
+
+	default:
+	  fprintf(stderr, "buf[0x14] = %x\n", buf[0x14]);
+	}
+
+      next   = GET_UINT(buf, 0xc);
+      if (next == 0xffffffff) break;
+
+      index  = next >> 14;
+      offset = next & 0x3fff;
+      if (index > topic.wMapLen) {Report("maplen"); break;}
+      buf = topic.map[index] + offset;
+    }
+
+  return(HLPFILE_GetContext(hlpfile));
+}
+
+/***********************************************************************
+ *
+ *           HLPFILE_AddPage
+ */
+
+static BOOL HLPFILE_AddPage(HLPFILE *hlpfile, BYTE *buf, BYTE *end)
+{
+  HGLOBAL   hPage;
+  HLPFILE_PAGE *page, **pageptr;
+  BYTE      *title;
+  UINT      titlesize;
+
+  for (pageptr = &hlpfile->first_page; *pageptr; pageptr = &(*pageptr)->next)
+    /* Nothing */; 
+
+  if (buf + 0x31 > end) {Report("page1"); return(FALSE);};
+  title = buf + GET_UINT(buf, 0x10);
+  if (title > end) {Report("page2"); return(FALSE);};
+
+  titlesize = HLPFILE_Uncompressed2_Size(title, end);
+  hPage = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE_PAGE) + titlesize);
+  if (!hPage) return FALSE;
+  page = *pageptr = GlobalLock(hPage);
+  pageptr               = &page->next;
+  page->hSelf           = hPage;
+  page->file            = hlpfile;
+  page->next            = 0;
+  page->first_paragraph = 0;
+
+  page->lpszTitle = GlobalLock(hPage);
+  page->lpszTitle += sizeof(HLPFILE_PAGE);
+  HLPFILE_Uncompress2(&title, end, page->lpszTitle);
+
+  page->wNumber = GET_UINT(buf, 0x21);
+
+  attributes.bDebug        = 0;
+  attributes.wFont         = 0;
+  attributes.wVSpace       = 0;
+  attributes.wVBackSpace   = 0;
+  attributes.wHSpace       = 0;
+  attributes.wIndent       = 0;
+  attributes.link.lpszPath = 0;
+
+  return TRUE;
+}
+
+/***********************************************************************
+ *
+ *           HLPFILE_AddParagraph
+ */
+
+static BOOL HLPFILE_AddParagraph(HLPFILE *hlpfile, BYTE *buf, BYTE *end)
+{
+  HGLOBAL            hParagraph;
+  HLPFILE_PAGE      *page;
+  HLPFILE_PARAGRAPH *paragraph, **paragraphptr;
+  UINT               textsize;
+  BYTE              *format, *text;
+  BOOL               format_header = TRUE;
+  BOOL               format_end = FALSE;
+  UINT               mask, i;
+
+  if (!hlpfile->first_page) {Report("paragraph1"); return(FALSE);};
+
+  for (page = hlpfile->first_page; page->next; page = page->next) /* Nothing */;
+  for (paragraphptr = &page->first_paragraph; *paragraphptr;
+       paragraphptr = &(*paragraphptr)->next) /* Nothing */; 
+
+  if (buf + 0x19 > end) {Report("paragraph2"); return(FALSE);};
+
+  if (buf[0x14] == 0x02) return TRUE;
+
+  text   = buf + GET_UINT(buf, 0x10);
+
+  switch (buf[0x14])
+    {
+    case 0x20:
+      format = buf + 0x18;
+      while (*format) format++;
+      format += 4;
+      break;
+
+    case 0x23:
+      format = buf + 0x2b;
+      if (buf[0x17] & 1) format++;
+      break;
+
+    default:
+      Report("paragraph3");
+      return FALSE;
+    }
+
+  while (text < end)
+    {
+      if (format_header)
+	{
+	  format_header = FALSE;
+
+	  mask = GET_USHORT(format, 0);
+	  mask &= 0x3ff;
+	  format += 2;
+
+	  for (i = 0; i < 10; i++, mask = mask >> 1)
+	    {
+	      if (mask & 1)
+		{
+		  BOOL twoargs = FALSE;
+		  CHAR prefix0 = ' ';
+		  CHAR prefix1 = '*';
+
+		  if (i == 9 && !twoargs)
+		    {
+		      switch (*format++)
+			{
+			default:
+			  prefix0 = prefix1 = '?';
+			  break;
+
+			case 0x82:
+			  prefix0 = prefix1 = 'x';
+			  break;
+
+			case 0x84:
+			  prefix0 = prefix1 = 'X';
+			  twoargs = TRUE;
+			}
+		    }
+
+		  if (*format & 1)
+		    switch(*format)
+		      {
+		      default:
+			format += 2;
+			break;
+		      }
+		  else
+		    switch(*format)
+		      {
+
+		      default:
+			format++;
+			break;
+
+		      case 0x08:
+			format += 3;
+			break;
+		      }
+
+		  if (twoargs) format += (*format & 1) ? 2 : 1;
+		}
+	    }
+	}
+
+      for (; !format_header && text < end && format < end && !*text; text++)
+	{
+	  switch(*format)
+	    {
+	    case 0x80:
+	      attributes.wFont = GET_USHORT(format, 1);
+	      format += 3;
+	      break;
+
+	    case 0x81:
+	      attributes.wVSpace++;
+	      format += 1;
+	      break;
+
+	    case 0x82:
+	      attributes.wVSpace += 2 - attributes.wVBackSpace;
+	      attributes.wVBackSpace = 0;
+	      attributes.wIndent = 0;
+	      format += 1;
+	      break;
+
+	    case 0x83:
+	      attributes.wIndent++;
+	      format += 1;
+	      break;
+
+	    case 0x84:
+	      format += 3;
+	      break;
+
+	    case 0x86:
+	    case 0x87:
+	    case 0x88:
+	      format += 9;
+	      break;
+
+	    case 0x89:
+	      attributes.wVBackSpace++;
+	      format += 1;
+	      break;
+
+	    case 0xa9:
+	      format += 2;
+	      break;
+
+	    case 0xe2:
+	    case 0xe3:
+	      attributes.link.lpszPath = hlpfile->lpszPath;
+	      attributes.link.lHash    = GET_UINT(format, 1);
+	      attributes.link.bPopup   = !(*format & 1);
+	      format += 5;
+	      break;
+
+	    case 0xea:
+	      attributes.link.lpszPath = format + 8;
+	      attributes.link.lHash    = GET_UINT(format, 4);
+	      attributes.link.bPopup   = !(*format & 1);
+	      format += 3 + GET_USHORT(format, 1);
+	      break;
+
+	    case 0xff:
+	      if (buf[0x14] != 0x23 || GET_USHORT(format, 1) == 0xffff)
+		{
+		  if (format_end) Report("format_end");
+		  format_end = TRUE;
+		  break;
+		}
+	      else
+		{
+		  format_header = TRUE;
+		  format += 10;
+		  break;
+		}
+
+	    default:
+	      Report("format");
+	      format++;
+	    }
+	}
+
+      if (text > end || format > end) {Report("paragraph_end"); return(FALSE);};
+      if (text == end && !format_end) Report("text_end");
+
+      if (text == end) break;
+
+      textsize = HLPFILE_Uncompressed2_Size(text, end);
+      hParagraph = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE_PARAGRAPH) + textsize);
+      if (!hParagraph) return FALSE;
+      paragraph = *paragraphptr = GlobalLock(hParagraph);
+      paragraphptr = &paragraph->next;
+      paragraph->hSelf    = hParagraph;
+      paragraph->next     = 0;
+      paragraph->link     = 0;
+
+      paragraph->lpszText = GlobalLock(hParagraph);
+      paragraph->lpszText += sizeof(HLPFILE_PARAGRAPH);
+      HLPFILE_Uncompress2(&text, end, paragraph->lpszText);
+
+      paragraph->bDebug      = attributes.bDebug;
+      paragraph->wFont       = attributes.wFont;
+      paragraph->wVSpace     = attributes.wVSpace;
+      paragraph->wHSpace     = attributes.wHSpace;
+      paragraph->wIndent     = attributes.wIndent;
+      if (attributes.link.lpszPath)
+	{
+	  LPSTR ptr;
+	  HGLOBAL handle = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE_LINK) +
+					   strlen(attributes.link.lpszPath) + 1);
+	  if (!handle) return FALSE;
+	  paragraph->link = GlobalLock(handle);
+	  paragraph->link->hSelf = handle;
+
+	  ptr = GlobalLock(handle);
+	  ptr += sizeof(HLPFILE_LINK);
+	  lstrcpy(ptr, (LPSTR) attributes.link.lpszPath);
+
+	  paragraph->link->lpszPath = ptr;
+	  paragraph->link->lHash    = attributes.link.lHash;
+	  paragraph->link->bPopup   = attributes.link.bPopup;
+	}
+
+      attributes.bDebug        = 0;
+      attributes.wVSpace       = 0;
+      attributes.wHSpace       = 0;
+      attributes.link.lpszPath = 0;
+    }
+
+  return TRUE;
+}
+
+/***********************************************************************
+ *
+ *           HLPFILE_ReadFileToBuffer
+ */
+
+static BOOL HLPFILE_ReadFileToBuffer(HFILE hFile)
+{
+  BYTE  header[16], dummy[1];
+  UINT  size;
+
+  if (_hread(hFile, header, 16) != 16) {Report("header"); return(FALSE);};
+
+  size = GET_UINT(header, 12);
+  hFileBuffer = GlobalAlloc(GMEM_FIXED, size + 1);
+  if (!hFileBuffer) return FALSE;
+  file_buffer = GlobalLock(hFileBuffer);
+
+  memcpy(file_buffer, header, 16);
+  if (_hread(hFile, file_buffer + 16, size - 16) != size - 16)
+    {Report("filesize1"); return(FALSE);};
+
+  if (_hread(hFile, dummy, 1) != 0) Report("filesize2"); 
+
+  file_buffer[size] = '0';
+
+  return TRUE;
+}
+
+/***********************************************************************
+ *
+ *           HLPFILE_FindSubFile
+ */
+
+static BOOL HLPFILE_FindSubFile(LPCSTR name, BYTE **subbuf, BYTE **subend)
+{
+  BYTE *root = file_buffer + GET_UINT(file_buffer,  4);
+  BYTE *end  = file_buffer + GET_UINT(file_buffer, 12);
+  BYTE *ptr  = root + 0x37;
+
+  while (ptr < end && ptr[0] == 0x7c)
+    {
+      BYTE *fname = ptr + 1;
+      ptr += strlen(ptr) + 1;
+      if (!lstrcmpi(fname, name))
+	{
+	  *subbuf = file_buffer + GET_UINT(ptr, 0);
+	  *subend = *subbuf + GET_UINT(*subbuf, 0);
+	  if (file_buffer > *subbuf || *subbuf > *subend || *subend >= end)
+	    {
+	      Report("subfile");
+	      return FALSE;
+	    }
+	  return TRUE;
+	}
+      else ptr += 4;
+    }
+  return FALSE;
+}
+
+/***********************************************************************
+ *
+ *           HLPFILE_SystemCommands
+ */
+static VOID HLPFILE_SystemCommands(HLPFILE* hlpfile)
+{
+  BYTE *buf, *ptr, *end;
+  HGLOBAL handle;
+  HLPFILE_MACRO *macro, **m;
+  LPSTR p;
+
+  hlpfile->lpszTitle = "";
+
+  if (!HLPFILE_FindSubFile("SYSTEM", &buf, &end)) return;
+
+  for (ptr = buf + 0x15; ptr + 4 <= end; ptr += GET_USHORT(ptr, 2) + 4)
+    {
+      switch (GET_USHORT(ptr, 0))
+	{
+	case 1:
+	  if (hlpfile->hTitle) {Report("title"); break;}
+	  hlpfile->hTitle = GlobalAlloc(GMEM_FIXED, strlen(ptr + 4) + 1);
+	  if (!hlpfile->hTitle) return;
+	  hlpfile->lpszTitle = GlobalLock(hlpfile->hTitle);
+	  lstrcpy(hlpfile->lpszTitle, ptr + 4);
+	  break;
+
+	case 2:
+	  if (GET_USHORT(ptr, 2) != 1 || ptr[4] != 0) Report("system2");
+	  break;
+
+	case 3:
+	  if (GET_USHORT(ptr, 2) != 4 || GET_UINT(ptr, 4) != 0) Report("system3");
+	  break;
+
+	case 4:
+	  handle = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE_MACRO) + lstrlen(ptr + 4) + 1);
+	  if (!handle) break;
+	  macro = GlobalLock(handle);
+	  macro->hSelf = handle;
+	  p  = GlobalLock(handle);
+	  p += sizeof(HLPFILE_MACRO);
+	  lstrcpy(p, (LPSTR) ptr + 4);
+	  macro->lpszMacro = p;
+	  macro->next = 0;
+	  for (m = &hlpfile->first_macro; *m; m = &(*m)->next);
+	  *m = macro;
+	  break;
+
+	default:
+	  Report("system");
+	}
+    }
+}
+
+/***********************************************************************
+ *
+ *           HLPFILE_Uncompressed1_Size
+ */
+
+static INT HLPFILE_Uncompressed1_Size(BYTE *ptr, BYTE *end)
+{
+  INT  i, newsize = 0;
+
+  while (ptr < end)
+    {
+      INT mask=*ptr++;
+      for (i = 0; i < 8 && ptr < end; i++, mask = mask >> 1)
+	{
+	  if (mask & 1)
+	    {
+	      INT code = GET_USHORT(ptr, 0);
+	      INT len  = 3 + (code >> 12);
+	      newsize += len;
+	      ptr     += 2;
+	    }
+	  else newsize++, ptr++;
+	}
+    }
+
+  return(newsize);
+}
+
+/***********************************************************************
+ *
+ *           HLPFILE_Uncompress1
+ */
+
+static BYTE *HLPFILE_Uncompress1(BYTE *ptr, BYTE *end, BYTE *newptr)
+{
+  INT i;
+
+  while (ptr < end)
+    {
+      INT mask=*ptr++;
+      for (i = 0; i < 8 && ptr < end; i++, mask = mask >> 1)
+	{
+	  if (mask & 1)
+	    {
+	      INT code   = GET_USHORT(ptr, 0);
+	      INT len    = 3 + (code >> 12);
+	      INT offset = code & 0xfff;
+	      hmemcpy(newptr, newptr - offset - 1, len);
+	      newptr += len;
+	      ptr    += 2;
+	    }
+	  else *newptr++ = *ptr++;
+	}
+    }
+
+  return(newptr);
+}
+
+/***********************************************************************
+ *
+ *           HLPFILE_Uncompress1_Phrases
+ */
+
+static BOOL HLPFILE_Uncompress1_Phrases()
+{
+  UINT i, num, newsize;
+  BYTE *buf, *end, *newbuf;
+
+  if (!HLPFILE_FindSubFile("Phrases", &buf, &end)) {Report("phrases0"); return FALSE;}
+
+  num = phrases.num = GET_USHORT(buf, 9);
+  if (buf + 2 * num + 0x13 >= end) {Report("uncompress1a"); return(FALSE);};
+
+  newsize  = 2 * num + 2;
+  newsize += HLPFILE_Uncompressed1_Size(buf + 0x13 + 2 * num, end);
+  phrases.hBuffer = GlobalAlloc(GMEM_FIXED, newsize);
+  if (!phrases.hBuffer) return FALSE;
+  newbuf = phrases.buf = GlobalLock(phrases.hBuffer);
+
+  hmemcpy(newbuf, buf + 0x11, 2 * num + 2);
+  HLPFILE_Uncompress1(buf + 0x13 + 2 * num, end, newbuf + 2 * num + 2);
+
+  for (i = 0; i < num; i++)
+    {
+      INT i0 = GET_USHORT(newbuf, 2 * i);
+      INT i1 = GET_USHORT(newbuf, 2 * i + 2);
+      if (i1 < i0 || i1 > newsize) {Report("uncompress1b"); return(FALSE);};
+    }
+  return TRUE;
+}
+
+/***********************************************************************
+ *
+ *           HLPFILE_Uncompress1_Topic
+ */
+
+static BOOL HLPFILE_Uncompress1_Topic()
+{
+  BYTE *buf, *ptr, *end, *newptr;
+  INT  i, newsize = 0;
+
+  if (!HLPFILE_FindSubFile("TOPIC", &buf, &end)) {Report("topic0"); return FALSE;}
+
+  buf += 9;
+  topic.wMapLen = (end - buf - 1) / 0x1000 + 1;
+
+  for (i = 0; i < topic.wMapLen; i++)
+    {
+      ptr = buf + i * 0x1000;
+
+      /* I don't know why, it's necessary for printman.hlp */
+      if (ptr + 0x44 > end) ptr = end - 0x44;
+
+      newsize += HLPFILE_Uncompressed1_Size(ptr + 0xc, MIN(end, ptr + 0x1000));
+    }
+
+  topic.hMap    = GlobalAlloc(GMEM_FIXED, topic.wMapLen * sizeof(topic.map[0]));
+  topic.hBuffer = GlobalAlloc(GMEM_FIXED, newsize);
+  if (!topic.hMap || !topic.hBuffer) return FALSE;
+  topic.map = GlobalLock(topic.hMap);
+  newptr = GlobalLock(topic.hBuffer);
+  topic.end = newptr + newsize;
+
+  for (i = 0; i < topic.wMapLen; i++)
+    {
+      ptr = buf + i * 0x1000;
+      if (ptr + 0x44 > end) ptr = end - 0x44;
+
+      topic.map[i] = newptr - 0xc;
+      newptr = HLPFILE_Uncompress1(ptr + 0xc, MIN(end, ptr + 0x1000), newptr);
+    }
+
+  return TRUE;
+}
+
+/***********************************************************************
+ *
+ *           HLPFILE_Uncompressed2_Size
+ */
+
+static UINT HLPFILE_Uncompressed2_Size(BYTE *ptr, BYTE *end)
+{
+  UINT wSize   = 0;
+
+  while (ptr < end && *ptr)
+    {
+      if (*ptr >= 0x20)
+	wSize++, ptr++;
+      else
+	{
+	  BYTE *phptr, *phend;
+	  UINT code  = 0x100 * ptr[0] + ptr[1];
+	  UINT index = (code - 0x100) / 2;
+	  BOOL space = code & 1;
+
+	  if (index < phrases.num)
+	    {
+	      phptr = phrases.buf + GET_USHORT(phrases.buf, 2 * index);
+	      phend = phrases.buf + GET_USHORT(phrases.buf, 2 * index + 2);
+
+	      if (phend < phptr) Report("uncompress2a");
+
+	      wSize += phend - phptr;
+	      if (space) wSize++;
+	    }
+	  else Report("uncompress2b");
+
+	  ptr += 2;
+	}
+    }
+
+  return(wSize + 1);
+}
+
+/***********************************************************************
+ *
+ *           HLPFILE_Uncompress2
+ */
+
+static VOID HLPFILE_Uncompress2(BYTE **pptr, BYTE *end, BYTE *newptr)
+{
+  BYTE *ptr    = *pptr;
+
+  while (ptr < end && *ptr)
+    {
+      if (*ptr >= 0x20)
+	*newptr++ = *ptr++;
+      else
+	{
+	  BYTE *phptr, *phend;
+	  UINT code  = 0x100 * ptr[0] + ptr[1];
+	  UINT index = (code - 0x100) / 2;
+	  BOOL space = code & 1;
+
+	  phptr = phrases.buf + GET_USHORT(phrases.buf, 2 * index);
+	  phend = phrases.buf + GET_USHORT(phrases.buf, 2 * index + 2);
+
+	  hmemcpy(newptr, phptr, phend - phptr);
+	  newptr += phend - phptr;
+	  if (space) *newptr++ = ' ';
+
+	  ptr += 2;
+	}
+    }
+  *newptr  = '\0';
+  *pptr    = ptr;
+}
+
+/***********************************************************************
+ *
+ *           HLPFILE_GetContext
+ */
+
+static BOOL HLPFILE_GetContext(HLPFILE *hlpfile)
+{
+  UINT i, j, clen, tlen;
+  BYTE *cbuf, *cptr, *cend, *tbuf, *tptr, *tend;
+
+  if (!HLPFILE_FindSubFile("CONTEXT", &cbuf, &cend)) {Report("context0"); return FALSE;}
+  if (cbuf + 0x37 > cend) {Report("context1"); return(FALSE);};
+  clen = GET_UINT(cbuf, 0x2b);
+  if (cbuf + 0x37 + 8 * hlpfile->wContextLen > cend) {Report("context2"); return(FALSE);};
+
+  if (!HLPFILE_FindSubFile("TTLBTREE", &tbuf, &tend)) {Report("ttlb0"); return FALSE;}
+  if (tbuf + 0x37 > tend) {Report("ttlb1"); return(FALSE);};
+  tlen = GET_UINT(tbuf, 0x2b);
+
+  hlpfile->hContext = GlobalAlloc(GMEM_FIXED, clen * sizeof(HLPFILE_CONTEXT));
+  if (!hlpfile->hContext) return FALSE;
+  hlpfile->Context = GlobalLock(hlpfile->hContext);
+  hlpfile->wContextLen = clen;
+
+  cptr = cbuf + 0x37;
+  for (i = 0; i < clen; i++, cptr += 8)
+    {
+      tptr = tbuf + 0x37;
+      for (j = 0; j < tlen; j++, tptr += 5 + strlen(tptr + 4))
+	{
+	  if (tptr + 4 >= tend) {Report("ttlb2"); return(FALSE);};
+	  if (GET_UINT(tptr, 0) == GET_UINT(cptr, 4)) break;
+	}
+      if (j >= tlen)
+	{
+	  Report("ttlb3");
+	  j = 0;
+	}
+      hlpfile->Context[i].lHash = GET_UINT(cptr, 0);
+      hlpfile->Context[i].wPage = j;
+    }
+
+  return TRUE;
+}
+
+/***********************************************************************
+ *
+ *           HLPFILE_DeleteParagraph
+ */
+
+static VOID HLPFILE_DeleteParagraph(HLPFILE_PARAGRAPH* paragraph)
+{
+  if (!paragraph) return;
+
+  if (paragraph->link) GlobalFree(paragraph->link->hSelf);
+
+  HLPFILE_DeleteParagraph(paragraph->next);
+  GlobalFree(paragraph->hSelf);
+}
+
+/***********************************************************************
+ *
+ *           DeletePage
+ */
+
+static VOID HLPFILE_DeletePage(HLPFILE_PAGE* page)
+{
+  if (!page) return;
+
+  HLPFILE_DeletePage(page->next);
+  HLPFILE_DeleteParagraph(page->first_paragraph);
+  GlobalFree(page->hSelf);
+}
+
+/***********************************************************************
+ *
+ *           DeleteMacro
+ */
+
+static VOID HLPFILE_DeleteMacro(HLPFILE_MACRO* macro)
+{
+  if (!macro) return;
+
+  HLPFILE_DeleteMacro(macro->next);
+  GlobalFree(macro->hSelf);
+}
+
+/***********************************************************************
+ *
+ *           HLPFILE_FreeHlpFile
+ */
+
+VOID HLPFILE_FreeHlpFile(HLPFILE* hlpfile)
+{
+  if (!hlpfile) return;
+  if (--hlpfile->wRefCount) return;
+
+  if (hlpfile->next) hlpfile->next->prev = hlpfile->prev;
+  if (hlpfile->prev) hlpfile->prev->next = hlpfile->next;
+  else first_hlpfile = 0;
+
+  HLPFILE_DeletePage(hlpfile->first_page);
+  HLPFILE_DeleteMacro(hlpfile->first_macro);
+  GlobalFree(hlpfile->hContext);
+  GlobalFree(hlpfile->hTitle);
+  GlobalFree(hlpfile->hSelf);
+}
+
+/***********************************************************************
+ *
+ *           FreeHlpFilePage
+ */
+
+VOID HLPFILE_FreeHlpFilePage(HLPFILE_PAGE* page)
+{
+  if (!page) return;
+  HLPFILE_FreeHlpFile(page->file);
+}
+
+/* Local Variables:    */
+/* c-file-style: "GNU" */
+/* End:                */
diff --git a/programs/winhelp/hlpfile.h b/programs/winhelp/hlpfile.h
new file mode 100644
index 0000000..fb525db
--- /dev/null
+++ b/programs/winhelp/hlpfile.h
@@ -0,0 +1,90 @@
+/*
+ * Help Viewer
+ *
+ * Copyright 1996 Ulrich Schmid
+ */
+
+struct tagHelpFile;
+
+typedef struct
+{
+  LPCSTR  lpszPath;
+  LONG    lHash;
+  BOOL    bPopup;
+
+  HGLOBAL hSelf;
+} HLPFILE_LINK;
+
+typedef struct tagHlpFileParagraph
+{
+  LPSTR  lpszText;
+
+  UINT   bDebug;
+  UINT   wFont;
+  UINT   wIndent;
+  UINT   wHSpace;
+  UINT   wVSpace;
+
+  HLPFILE_LINK *link;
+
+  struct tagHlpFileParagraph *next;
+
+  HGLOBAL hSelf;
+} HLPFILE_PARAGRAPH;
+
+typedef struct tagHlpFilePage
+{
+  LPSTR          lpszTitle;
+  HLPFILE_PARAGRAPH *first_paragraph;
+
+  UINT wNumber;
+
+  struct tagHlpFilePage *next;
+  struct tagHlpFileFile *file;
+
+  HGLOBAL hSelf;
+} HLPFILE_PAGE;
+
+typedef struct
+{
+  LONG lHash;
+  UINT wPage;
+} HLPFILE_CONTEXT;
+
+typedef struct tagHlpFileMacro
+{
+  LPCSTR lpszMacro;
+
+  HGLOBAL hSelf;
+  struct tagHlpFileMacro *next;
+} HLPFILE_MACRO;
+
+typedef struct tagHlpFileFile
+{
+  LPSTR        lpszPath;
+  LPSTR        lpszTitle;
+  HLPFILE_PAGE    *first_page;
+  HLPFILE_MACRO   *first_macro;
+  UINT         wContextLen;
+  HLPFILE_CONTEXT *Context;
+
+  struct tagHlpFileFile *prev;
+  struct tagHlpFileFile *next;
+
+  UINT       wRefCount;
+
+  HGLOBAL    hTitle;
+  HGLOBAL    hContext;
+  HGLOBAL    hSelf;
+} HLPFILE;
+
+HLPFILE      *HLPFILE_ReadHlpFile(LPCSTR lpszPath);
+HLPFILE_PAGE *HLPFILE_Contents(LPCSTR lpszPath);
+HLPFILE_PAGE *HLPFILE_PageByHash(LPCSTR lpszPath, LONG wNum);
+LONG          HLPFILE_Hash(LPCSTR lpszContext);
+VOID          HLPFILE_FreeHlpFilePage(HLPFILE_PAGE*);
+VOID          HLPFILE_FreeHlpFile(HLPFILE*);
+
+/* Local Variables:    */
+/* c-file-style: "GNU" */
+/* End:                */
diff --git a/programs/winhelp/macro.c b/programs/winhelp/macro.c
new file mode 100644
index 0000000..7355270
--- /dev/null
+++ b/programs/winhelp/macro.c
@@ -0,0 +1,555 @@
+/*
+ * Help Viewer
+ *
+ * Copyright 1996 Ulrich Schmid
+ */
+
+#include <stdio.h>
+#include <windows.h>
+#include <commdlg.h>
+#ifdef WINELIB
+#include <shell.h>
+#endif
+#include "winhelp.h"
+#include "macro.h"
+
+VOID MACRO_About(VOID)
+{
+  fprintf(stderr, "About()\n");
+}
+
+VOID MACRO_AddAccelerator(LONG u1, LONG u2, LPCSTR str)
+{
+  fprintf(stderr, "AddAccelerator(%lu, %lu, \"%s\")\n", u1, u2, str);
+}
+
+VOID MACRO_ALink(LPCSTR str1, LONG u, LPCSTR str2)
+{
+  fprintf(stderr, "ALink(\"%s\", %lu, \"%s\")\n", str1, u, str2);
+}
+
+VOID MACRO_Annotate(VOID)
+{
+  fprintf(stderr, "Annotate()\n");
+}
+
+VOID MACRO_AppendItem(LPCSTR str1, LPCSTR str2, LPCSTR str3, LPCSTR str4)
+{
+  fprintf(stderr, "AppendItem(\"%s\", \"%s\", \"%s\", \"%s\")\n", str1, str2, str3, str4);
+}
+
+VOID MACRO_Back(VOID)
+{
+  fprintf(stderr, "Back()\n");
+}
+
+VOID MACRO_BackFlush(VOID)
+{
+  fprintf(stderr, "BackFlush()\n");
+}
+
+VOID MACRO_BookmarkDefine(VOID)
+{
+  fprintf(stderr, "BookmarkDefine()\n");
+}
+
+VOID MACRO_BookmarkMore(VOID)
+{
+  fprintf(stderr, "BookmarkMore()\n");
+}
+
+VOID MACRO_BrowseButtons(VOID)
+{
+  MACRO_CreateButton("BTN_PREV", "&<<", "Prev()");
+  MACRO_CreateButton("BTN_NEXT", "&>>", "Next()");
+}
+
+VOID MACRO_ChangeButtonBinding(LPCSTR str1, LPCSTR str2)
+{
+  fprintf(stderr, "ChangeButtonBinding(\"%s\", \"%s\")\n", str1, str2);
+}
+
+VOID MACRO_ChangeEnable(LPCSTR str1, LPCSTR str2)
+{
+  fprintf(stderr, "ChangeEnable(\"%s\", \"%s\")\n", str1, str2);
+}
+
+VOID MACRO_ChangeItemBinding(LPCSTR str1, LPCSTR str2)
+{
+  fprintf(stderr, "ChangeItemBinding(\"%s\", \"%s\")\n", str1, str2);
+}
+
+VOID MACRO_CheckItem(LPCSTR str)
+{
+  fprintf(stderr, "CheckItem(\"%s\")\n", str);
+}
+
+VOID MACRO_CloseSecondarys(VOID)
+{
+  WINHELP_WINDOW *win;
+  for (win = Globals.win_list; win; win = win->next)
+    if (win->lpszName && lstrcmpi(win->lpszName, "main"))
+      DestroyWindow(win->hMainWnd);
+}
+
+VOID MACRO_CloseWindow(LPCSTR lpszWindow)
+{
+  WINHELP_WINDOW *win;
+  if (!lpszWindow || !lpszWindow[0]) lpszWindow = "main";
+
+  for (win = Globals.win_list; win; win = win->next)
+    if (win->lpszName && !lstrcmpi(win->lpszName, lpszWindow))
+      DestroyWindow(win->hMainWnd);
+}
+
+VOID MACRO_Compare(LPCSTR str)
+{
+  fprintf(stderr, "Compare(\"%s\")\n", str);
+}
+
+VOID MACRO_Contents(VOID)
+{
+  if (Globals.active_win->page)
+    MACRO_JumpContents(Globals.active_win->page->file->lpszPath, NULL);
+}
+
+VOID MACRO_ControlPanel(LPCSTR str1, LPCSTR str2, LONG u)
+{
+  fprintf(stderr, "ControlPanel(\"%s\", \"%s\", %lu)\n", str1, str2, u);
+}
+
+VOID MACRO_CopyDialog(VOID)
+{
+  fprintf(stderr, "CopyDialog()\n");
+}
+
+VOID MACRO_CopyTopic(VOID)
+{
+  fprintf(stderr, "CopyTopic()\n");
+}
+
+VOID MACRO_CreateButton(LPCSTR id, LPCSTR name, LPCSTR macro)
+{
+  WINHELP_WINDOW *win = Globals.active_win;
+  WINHELP_BUTTON *button, **b;
+  LONG            size;
+  HGLOBAL         handle;
+  LPSTR           ptr;
+
+  size = sizeof(WINHELP_BUTTON) + lstrlen(id) + lstrlen(name) + lstrlen(macro) + 3;
+  handle = GlobalAlloc(GMEM_FIXED, size);
+  if (!handle) return;
+
+  button = GlobalLock(handle);
+  button->hSelf = handle;
+  button->next  = 0;
+  button->hWnd  = 0;
+
+  ptr = GlobalLock(handle);
+  ptr += sizeof(WINHELP_BUTTON);
+
+  lstrcpy(ptr, (LPSTR) id);
+  button->lpszID = ptr;
+  ptr += lstrlen(id) + 1;
+
+  lstrcpy(ptr, (LPSTR) name);
+  button->lpszName = ptr;
+  ptr += lstrlen(name) + 1;
+
+  lstrcpy(ptr, (LPSTR) macro);
+  button->lpszMacro = ptr;
+
+  button->wParam = WH_FIRST_BUTTON;
+  for (b = &win->first_button; *b; b = &(*b)->next)
+    button->wParam = MAX(button->wParam, (*b)->wParam + 1);
+  *b = button;
+
+  SendMessage(win->hMainWnd, WM_USER, 0, 0);
+}
+
+VOID MACRO_DeleteItem(LPCSTR str)
+{
+  fprintf(stderr, "DeleteItem(\"%s\")\n", str);
+}
+
+VOID MACRO_DeleteMark(LPCSTR str)
+{
+  fprintf(stderr, "DeleteMark(\"%s\")\n", str);
+}
+
+VOID MACRO_DestroyButton(LPCSTR str)
+{
+  fprintf(stderr, "DestroyButton(\"%s\")\n", str);
+}
+
+VOID MACRO_DisableButton(LPCSTR str)
+{
+  fprintf(stderr, "DisableButton(\"%s\")\n", str);
+}
+
+VOID MACRO_DisableItem(LPCSTR str)
+{
+  fprintf(stderr, "DisableItem(\"%s\")\n", str);
+}
+
+VOID MACRO_EnableButton(LPCSTR str)
+{
+  fprintf(stderr, "EnableButton(\"%s\")\n", str);
+}
+
+VOID MACRO_EnableItem(LPCSTR str)
+{
+  fprintf(stderr, "EnableItem(\"%s\")\n", str);
+}
+
+VOID MACRO_EndMPrint(VOID)
+{
+  fprintf(stderr, "EndMPrint()\n");
+}
+
+VOID MACRO_ExecFile(LPCSTR str1, LPCSTR str2, LONG u, LPCSTR str3)
+{
+  fprintf(stderr, "ExecFile(\"%s\", \"%s\", %lu, \"%s\")\n", str1, str2, u, str3);
+}
+
+VOID MACRO_ExecProgram(LPCSTR str, LONG u)
+{
+  fprintf(stderr, "ExecProgram(\"%s\", %lu)\n", str, u);
+}
+
+VOID MACRO_Exit(VOID)
+{
+  while(Globals.win_list)
+    DestroyWindow(Globals.win_list->hMainWnd);
+}
+
+VOID MACRO_ExtAbleItem(LPCSTR str, LONG u)
+{
+  fprintf(stderr, "ExtAbleItem(\"%s\", %lu)\n", str, u);
+}
+
+VOID MACRO_ExtInsertItem(LPCSTR str1, LPCSTR str2, LPCSTR str3, LPCSTR str4, LONG u1, LONG u2)
+{
+  fprintf(stderr, "ExtInsertItem(\"%s\", \"%s\", \"%s\", \"%s\", %lu, %lu)\n", str1, str2, str3, str4, u1, u2);
+}
+
+VOID MACRO_ExtInsertMenu(LPCSTR str1, LPCSTR str2, LPCSTR str3, LONG u1, LONG u2)
+{
+  fprintf(stderr, "ExtInsertMenu(\"%s\", \"%s\", \"%s\", %lu, %lu)\n", str1, str2, str3, u1, u2);
+}
+
+BOOL MACRO_FileExist(LPCSTR str)
+{
+  fprintf(stderr, "FileExist(\"%s\")\n", str);
+  return TRUE;
+}
+
+VOID MACRO_FileOpen(VOID)
+{
+  OPENFILENAME openfilename;
+  CHAR szPath[MAX_PATHNAME_LEN];
+  CHAR szDir[MAX_PATHNAME_LEN];
+  CHAR szzFilter[2 * MAX_STRING_LEN + 100];
+  LPSTR p = szzFilter;
+
+  LoadString(Globals.hInstance, IDS_HELP_FILES_HLP, p, MAX_STRING_LEN);
+  p += strlen(p) + 1;
+  lstrcpy(p, "*.hlp");
+  p += strlen(p) + 1;
+  LoadString(Globals.hInstance, IDS_ALL_FILES, p, MAX_STRING_LEN);
+  p += strlen(p) + 1;
+  lstrcpy(p, "*.*");
+  p += strlen(p) + 1;
+  *p = '\0';
+
+  GetWindowsDirectory(szDir, sizeof(szDir));
+
+  openfilename.lStructSize       = 0;
+  openfilename.hwndOwner         = Globals.active_win->hMainWnd;
+  openfilename.hInstance         = Globals.hInstance;
+  openfilename.lpstrFilter       = szzFilter;
+  openfilename.lpstrCustomFilter = 0;
+  openfilename.nMaxCustFilter    = 0;
+  openfilename.nFilterIndex      = 0;
+  openfilename.lpstrFile         = szPath;
+  openfilename.nMaxFile          = sizeof(szPath);
+  openfilename.lpstrFileTitle    = 0;
+  openfilename.nMaxFileTitle     = 0;
+  openfilename.lpstrInitialDir   = szDir;
+  openfilename.lpstrTitle        = 0;
+  openfilename.Flags             = 0;
+  openfilename.nFileOffset       = 0;
+  openfilename.nFileExtension    = 0;
+  openfilename.lpstrDefExt       = 0;
+  openfilename.lCustData         = 0;
+  openfilename.lpfnHook          = 0;
+  openfilename.lpTemplateName    = 0;
+
+  if (GetOpenFileName(&openfilename))
+    WINHELP_CreateHelpWindow(szPath, 0, "main", FALSE, NULL, NULL, SW_SHOWNORMAL);
+}
+
+VOID MACRO_Find(VOID)
+{
+  fprintf(stderr, "Find()\n");
+}
+
+VOID MACRO_Finder(VOID)
+{
+  fprintf(stderr, "Finder()\n");
+}
+
+VOID MACRO_FloatingMenu(VOID)
+{
+  fprintf(stderr, "FloatingMenu()\n");
+}
+
+VOID MACRO_Flush(VOID)
+{
+  fprintf(stderr, "Flush()\n");
+}
+
+VOID MACRO_FocusWindow(LPCSTR str)
+{
+  fprintf(stderr, "FocusWindow(\"%s\")\n", str);
+}
+
+VOID MACRO_Generate(LPCSTR str, WPARAM w, LPARAM l)
+{
+  fprintf(stderr, "Generate(\"%s\", %x, %lx)\n", str, w, l);
+}
+
+VOID MACRO_GotoMark(LPCSTR str)
+{
+  fprintf(stderr, "GotoMark(\"%s\")\n", str);
+}
+
+VOID MACRO_HelpOn(VOID)
+{
+  MACRO_JumpContents((Globals.wVersion > 4) ? "winhelp32.hlp" : "winhelp.hlp", NULL);
+}
+
+VOID MACRO_HelpOnTop(VOID)
+{
+  fprintf(stderr, "HelpOnTop()\n");
+}
+
+VOID MACRO_History(VOID)
+{
+  fprintf(stderr, "History()\n");
+}
+
+BOOL MACRO_InitMPrint(VOID)
+{
+  fprintf(stderr, "InitMPrint()\n");
+  return FALSE;
+}
+
+VOID MACRO_InsertItem(LPCSTR str1, LPCSTR str2, LPCSTR str3, LPCSTR str4, LONG u)
+{
+  fprintf(stderr, "InsertItem(\"%s\", \"%s\", \"%s\", \"%s\", %lu)\n", str1, str2, str3, str4, u);
+}
+
+VOID MACRO_InsertMenu(LPCSTR str1, LPCSTR str2, LONG u)
+{
+  fprintf(stderr, "InsertMenu(\"%s\", \"%s\", %lu)\n", str1, str2, u);
+}
+
+BOOL MACRO_IsBook(VOID)
+{
+  fprintf(stderr, "IsBook()\n");
+  return TRUE;
+}
+
+BOOL MACRO_IsMark(LPCSTR str)
+{
+  fprintf(stderr, "IsMark(\"%s\")\n", str);
+  return FALSE;
+}
+
+BOOL MACRO_IsNotMark(LPCSTR str)
+{
+  fprintf(stderr, "IsNotMark(\"%s\")\n", str);
+  return TRUE;
+}
+
+VOID MACRO_JumpContents(LPCSTR lpszPath, LPCSTR lpszWindow)
+{
+  WINHELP_CreateHelpWindow(lpszPath, 0, lpszWindow, FALSE, NULL, NULL, SW_NORMAL);
+}
+
+VOID MACRO_JumpContext(LPCSTR lpszPath, LPCSTR lpszWindow, LONG context)
+{
+  fprintf(stderr, "JumpContext(\"%s\", \"%s\", %lu)\n", lpszPath, lpszWindow, context);
+}
+
+VOID MACRO_JumpHash(LPCSTR lpszPath, LPCSTR lpszWindow, LONG lHash)
+{
+  WINHELP_CreateHelpWindow(lpszPath, lHash, lpszWindow, FALSE, NULL, NULL, SW_NORMAL);
+}
+
+VOID MACRO_JumpHelpOn(VOID)
+{
+  fprintf(stderr, "JumpHelpOn()\n");
+}
+
+VOID MACRO_JumpID(LPCSTR lpszPath, LPCSTR lpszWindow, LPCSTR topic_id)
+{
+  MACRO_JumpHash(lpszPath, lpszWindow, HLPFILE_Hash(topic_id));
+}
+
+VOID MACRO_JumpKeyword(LPCSTR lpszPath, LPCSTR lpszWindow, LPCSTR keyword)
+{
+  fprintf(stderr, "JumpKeyword(\"%s\", \"%s\", \"%s\")\n", lpszPath, lpszWindow, keyword);
+}
+
+VOID MACRO_KLink(LPCSTR str1, LONG u, LPCSTR str2, LPCSTR str3)
+{
+  fprintf(stderr, "KLink(\"%s\", %lu, \"%s\", \"%s\")\n", str1, u, str2, str3);
+}
+
+VOID MACRO_Menu(VOID)
+{
+  fprintf(stderr, "Menu()\n");
+}
+
+VOID MACRO_MPrintHash(LONG u)
+{
+  fprintf(stderr, "MPrintHash(%lu)\n", u);
+}
+
+VOID MACRO_MPrintID(LPCSTR str)
+{
+  fprintf(stderr, "MPrintID(\"%s\")\n", str);
+}
+
+VOID MACRO_Next(VOID)
+{
+  fprintf(stderr, "Next()\n");
+}
+
+VOID MACRO_NoShow(VOID)
+{
+  fprintf(stderr, "NoShow()\n");
+}
+
+VOID MACRO_PopupContext(LPCSTR str, LONG u)
+{
+  fprintf(stderr, "PopupContext(\"%s\", %lu)\n", str, u);
+}
+
+VOID MACRO_PopupHash(LPCSTR str, LONG u)
+{
+  fprintf(stderr, "PopupHash(\"%s\", %lu)\n", str, u);
+}
+
+VOID MACRO_PopupId(LPCSTR str1, LPCSTR str2)
+{
+  fprintf(stderr, "PopupId(\"%s\", \"%s\")\n", str1, str2);
+}
+
+VOID MACRO_PositionWindow(LONG i1, LONG i2, LONG u1, LONG u2, LONG u3, LPCSTR str)
+{
+  fprintf(stderr, "PositionWindow(%li, %li, %lu, %lu, %lu, \"%s\")\n", i1, i2, u1, u2, u3, str);
+}
+
+VOID MACRO_Prev(VOID)
+{
+  fprintf(stderr, "Prev()\n");
+}
+
+VOID MACRO_Print(VOID)
+{
+  fprintf(stderr, "Print()\n");
+}
+
+VOID MACRO_PrinterSetup(VOID)
+{
+  fprintf(stderr, "PrinterSetup()\n");
+}
+
+VOID MACRO_RegisterRoutine(LPCSTR str1, LPCSTR str2, LPCSTR str3)
+{
+  fprintf(stderr, "RegisterRoutine(\"%s\", \"%s\", \"%s\")\n", str1, str2, str3);
+}
+
+VOID MACRO_RemoveAccelerator(LONG u1, LONG u2)
+{
+  fprintf(stderr, "RemoveAccelerator(%lu, %lu)\n", u1, u2);
+}
+
+VOID MACRO_ResetMenu(VOID)
+{
+  fprintf(stderr, "ResetMenu()\n");
+}
+
+VOID MACRO_SaveMark(LPCSTR str)
+{
+  fprintf(stderr, "SaveMark(\"%s\")\n", str);
+}
+
+VOID MACRO_Search(VOID)
+{
+  fprintf(stderr, "Search()\n");
+}
+
+VOID MACRO_SetContents(LPCSTR str, LONG u)
+{
+  fprintf(stderr, "SetContents(\"%s\", %lu)\n", str, u);
+}
+
+VOID MACRO_SetHelpOnFile(LPCSTR str)
+{
+  fprintf(stderr, "SetHelpOnFile(\"%s\")\n", str);
+}
+
+VOID MACRO_SetPopupColor(LONG u1, LONG u2, LONG u3)
+{
+  fprintf(stderr, "SetPopupColor(%lu, %lu, %lu)\n", u1, u2, u3);
+}
+
+VOID MACRO_ShellExecute(LPCSTR str1, LPCSTR str2, LONG u1, LONG u2, LPCSTR str3, LPCSTR str4)
+{
+  fprintf(stderr, "ShellExecute(\"%s\", \"%s\", %lu, %lu, \"%s\", \"%s\")\n", str1, str2, u1, u2, str3, str4);
+}
+
+VOID MACRO_ShortCut(LPCSTR str1, LPCSTR str2, WPARAM w, LPARAM l, LPCSTR str)
+{
+  fprintf(stderr, "ShortCut(\"%s\", \"%s\", %x, %lx, \"%s\")\n", str1, str2, w, l, str);
+}
+
+VOID MACRO_TCard(LONG u)
+{
+  fprintf(stderr, "TCard(%lu)\n", u);
+}
+
+VOID MACRO_Test(LONG u)
+{
+  fprintf(stderr, "Test(%lu)\n", u);
+}
+
+BOOL MACRO_TestALink(LPCSTR str)
+{
+  fprintf(stderr, "TestALink(\"%s\")\n", str);
+  return FALSE;
+}
+
+BOOL MACRO_TestKLink(LPCSTR str)
+{
+  fprintf(stderr, "TestKLink(\"%s\")\n", str);
+  return FALSE;
+}
+
+VOID MACRO_UncheckItem(LPCSTR str)
+{
+  fprintf(stderr, "UncheckItem(\"%s\")\n", str);
+}
+
+VOID MACRO_UpdateWindow(LPCSTR str1, LPCSTR str2)
+{
+  fprintf(stderr, "UpdateWindow(\"%s\", \"%s\")\n", str1, str2);
+}
+
+/* Local Variables:    */
+/* c-file-style: "GNU" */
+/* End:                */
diff --git a/programs/winhelp/macro.h b/programs/winhelp/macro.h
new file mode 100644
index 0000000..b09e8dd
--- /dev/null
+++ b/programs/winhelp/macro.h
@@ -0,0 +1,108 @@
+/*
+ * Help Viewer
+ *
+ * Copyright 1996 Ulrich Schmid
+ */
+
+#include <windows.h>
+
+VOID MACRO_ExecuteMacro(LPCSTR);
+
+INT  yyparse(VOID);
+INT  yylex(VOID);
+VOID yyerror(LPCSTR);
+extern CHAR MACRO_extra_separator;
+
+VOID MACRO_About(VOID);
+VOID MACRO_AddAccelerator(LONG, LONG, LPCSTR);
+VOID MACRO_ALink(LPCSTR, LONG, LPCSTR);
+VOID MACRO_Annotate(VOID);
+VOID MACRO_AppendItem(LPCSTR, LPCSTR, LPCSTR, LPCSTR);
+VOID MACRO_Back(VOID);
+VOID MACRO_BackFlush(VOID);
+VOID MACRO_BookmarkDefine(VOID);
+VOID MACRO_BookmarkMore(VOID);
+VOID MACRO_BrowseButtons(VOID);
+VOID MACRO_ChangeButtonBinding(LPCSTR, LPCSTR);
+VOID MACRO_ChangeEnable(LPCSTR, LPCSTR);
+VOID MACRO_ChangeItemBinding(LPCSTR, LPCSTR);
+VOID MACRO_CheckItem(LPCSTR);
+VOID MACRO_CloseSecondarys(VOID);
+VOID MACRO_CloseWindow(LPCSTR);
+VOID MACRO_Compare(LPCSTR);
+VOID MACRO_Contents(VOID);
+VOID MACRO_ControlPanel(LPCSTR, LPCSTR, LONG);
+VOID MACRO_CopyDialog(VOID);
+VOID MACRO_CopyTopic(VOID);
+VOID MACRO_CreateButton(LPCSTR, LPCSTR, LPCSTR);
+VOID MACRO_DeleteItem(LPCSTR);
+VOID MACRO_DeleteMark(LPCSTR);
+VOID MACRO_DestroyButton(LPCSTR);
+VOID MACRO_DisableButton(LPCSTR);
+VOID MACRO_DisableItem(LPCSTR);
+VOID MACRO_EnableButton(LPCSTR);
+VOID MACRO_EnableItem(LPCSTR);
+VOID MACRO_EndMPrint(VOID);
+VOID MACRO_ExecFile(LPCSTR, LPCSTR, LONG, LPCSTR);
+VOID MACRO_ExecProgram(LPCSTR, LONG);
+VOID MACRO_Exit(VOID);
+VOID MACRO_ExtAbleItem(LPCSTR, LONG);
+VOID MACRO_ExtInsertItem(LPCSTR, LPCSTR, LPCSTR, LPCSTR, LONG, LONG);
+VOID MACRO_ExtInsertMenu(LPCSTR, LPCSTR, LPCSTR, LONG, LONG);
+BOOL MACRO_FileExist(LPCSTR);
+VOID MACRO_FileOpen(VOID);
+VOID MACRO_Find(VOID);
+VOID MACRO_Finder(VOID);
+VOID MACRO_FloatingMenu(VOID);
+VOID MACRO_Flush(VOID);
+VOID MACRO_FocusWindow(LPCSTR);
+VOID MACRO_Generate(LPCSTR, WPARAM, LPARAM);
+VOID MACRO_GotoMark(LPCSTR);
+VOID MACRO_HelpOn(VOID);
+VOID MACRO_HelpOnTop(VOID);
+VOID MACRO_History(VOID);
+BOOL MACRO_InitMPrint(VOID);
+VOID MACRO_InsertItem(LPCSTR, LPCSTR, LPCSTR, LPCSTR, LONG);
+VOID MACRO_InsertMenu(LPCSTR, LPCSTR, LONG);
+BOOL MACRO_IsBook(VOID);
+BOOL MACRO_IsMark(LPCSTR);
+BOOL MACRO_IsNotMark(LPCSTR);
+VOID MACRO_JumpContents(LPCSTR, LPCSTR);
+VOID MACRO_JumpContext(LPCSTR, LPCSTR, LONG);
+VOID MACRO_JumpHash(LPCSTR, LPCSTR, LONG);
+VOID MACRO_JumpHelpOn(VOID);
+VOID MACRO_JumpID(LPCSTR, LPCSTR, LPCSTR);
+VOID MACRO_JumpKeyword(LPCSTR, LPCSTR, LPCSTR);
+VOID MACRO_KLink(LPCSTR, LONG, LPCSTR, LPCSTR);
+VOID MACRO_Menu(VOID);
+VOID MACRO_MPrintHash(LONG);
+VOID MACRO_MPrintID(LPCSTR);
+VOID MACRO_Next(VOID);
+VOID MACRO_NoShow(VOID);
+VOID MACRO_PopupContext(LPCSTR, LONG);
+VOID MACRO_PopupHash(LPCSTR, LONG);
+VOID MACRO_PopupId(LPCSTR, LPCSTR);
+VOID MACRO_PositionWindow(LONG, LONG, LONG, LONG, LONG, LPCSTR);
+VOID MACRO_Prev(VOID);
+VOID MACRO_Print(VOID);
+VOID MACRO_PrinterSetup(VOID);
+VOID MACRO_RegisterRoutine(LPCSTR, LPCSTR, LPCSTR);
+VOID MACRO_RemoveAccelerator(LONG, LONG);
+VOID MACRO_ResetMenu(VOID);
+VOID MACRO_SaveMark(LPCSTR);
+VOID MACRO_Search(VOID);
+VOID MACRO_SetContents(LPCSTR, LONG);
+VOID MACRO_SetHelpOnFile(LPCSTR);
+VOID MACRO_SetPopupColor(LONG, LONG, LONG);
+VOID MACRO_ShellExecute(LPCSTR, LPCSTR, LONG, LONG, LPCSTR, LPCSTR);
+VOID MACRO_ShortCut(LPCSTR, LPCSTR, WPARAM, LPARAM, LPCSTR);
+VOID MACRO_TCard(LONG);
+VOID MACRO_Test(LONG);
+BOOL MACRO_TestALink(LPCSTR);
+BOOL MACRO_TestKLink(LPCSTR);
+VOID MACRO_UncheckItem(LPCSTR);
+VOID MACRO_UpdateWindow(LPCSTR, LPCSTR);
+
+/* Local Variables:    */
+/* c-file-style: "GNU" */
+/* End:                */
diff --git a/programs/winhelp/macro.lex.l b/programs/winhelp/macro.lex.l
new file mode 100644
index 0000000..146c8ea
--- /dev/null
+++ b/programs/winhelp/macro.lex.l
@@ -0,0 +1,235 @@
+%{
+/*
+ * Help Viewer
+ *
+ * Copyright 1996 Ulrich Schmid
+ */
+%}
+%x quote dquote
+%x null_string
+%{
+#include "macro.h"
+#include "y.tab.h"
+
+static LPCSTR  macroptr, firsttoken, thistoken, nexttoken, current_string;
+static LPSTR   strptr;
+static HGLOBAL hStringBuffer = 0;
+
+CHAR MACRO_extra_separator = 0;
+
+#define YY_INPUT(buf,result,max_size)\
+  if ((result = *macroptr ? 1 : 0)) buf[0] = *macroptr++;
+
+#define YY_USER_ACTION\
+  if (YY_START == INITIAL) thistoken = nexttoken, nexttoken = macroptr;
+
+#define YY_NO_UNPUT
+#define YY_NO_TOP_STATE
+%}
+%%
+About			yylval = MACRO_About;			return VOID_FUNCTION_VOID;
+AddAccelerator|AA	yylval = MACRO_AddAccelerator;		return VOID_FUNCTION_2UINT_STRING;
+ALink|AL		yylval = MACRO_ALink;			return VOID_FUNCTION_STRING_UINT_STRING;
+Annotate		yylval = MACRO_Annotate;		return VOID_FUNCTION_VOID;
+AppendItem		yylval = MACRO_AppendItem;		return VOID_FUNCTION_4STRING;
+Back			yylval = MACRO_Back;			return VOID_FUNCTION_VOID;
+BackFlush|BF		yylval = MACRO_BackFlush;		return VOID_FUNCTION_VOID;
+BookmarkDefine		yylval = MACRO_BookmarkDefine;		return VOID_FUNCTION_VOID;
+BookmarkMore		yylval = MACRO_BookmarkMore;		return VOID_FUNCTION_VOID;
+BrowseButtons		yylval = MACRO_BrowseButtons;		return VOID_FUNCTION_VOID;
+ChangeButtonBinding|CBB	yylval = MACRO_ChangeButtonBinding;	return VOID_FUNCTION_2STRING;
+ChangeEnable|CE		yylval = MACRO_ChangeEnable;		return VOID_FUNCTION_2STRING;
+ChangeItemBinding|CIB	yylval = MACRO_ChangeItemBinding;	return VOID_FUNCTION_2STRING;
+CheckItem|CI		yylval = MACRO_CheckItem;		return VOID_FUNCTION_STRING;
+CloseSecondarys|CS	yylval = MACRO_CloseSecondarys;		return VOID_FUNCTION_VOID;
+CloseWindow|CW		yylval = MACRO_CloseWindow;		return VOID_FUNCTION_STRING;
+Compare			yylval = MACRO_Compare;			return VOID_FUNCTION_STRING;
+Contents		yylval = MACRO_Contents;		return VOID_FUNCTION_VOID;
+ControlPanel		yylval = MACRO_ControlPanel;		return VOID_FUNCTION_2STRING_UINT;
+CopyDialog		yylval = MACRO_CopyDialog;		return VOID_FUNCTION_VOID;
+CopyTopic|CT		yylval = MACRO_CopyTopic;		return VOID_FUNCTION_VOID;
+CreateButton|CB		yylval = MACRO_CreateButton;		return VOID_FUNCTION_3STRING;
+DeleteItem		yylval = MACRO_DeleteItem;		return VOID_FUNCTION_STRING;
+DeleteMark		yylval = MACRO_DeleteMark;		return VOID_FUNCTION_STRING;
+DestroyButton		yylval = MACRO_DestroyButton;		return VOID_FUNCTION_STRING;
+DisableButton|DB	yylval = MACRO_DisableButton;		return VOID_FUNCTION_STRING;
+DisableItem|DI		yylval = MACRO_DisableItem;		return VOID_FUNCTION_STRING;
+EnableButton|EB		yylval = MACRO_EnableButton;		return VOID_FUNCTION_STRING;
+EnableItem|EI		yylval = MACRO_EnableItem;		return VOID_FUNCTION_STRING;
+EndMPrint		yylval = MACRO_EndMPrint;		return VOID_FUNCTION_VOID;
+ExecFile|EF		yylval = MACRO_ExecFile;		return VOID_FUNCTION_2STRING_UINT_STRING;
+ExecProgram|EP		yylval = MACRO_ExecProgram;		return VOID_FUNCTION_STRING_UINT;
+Exit			yylval = MACRO_Exit;			return VOID_FUNCTION_VOID;
+ExtAbleItem		yylval = MACRO_ExtAbleItem;		return VOID_FUNCTION_STRING_UINT;
+ExtInsertItem		yylval = MACRO_ExtInsertItem;		return VOID_FUNCTION_4STRING_2UINT;
+ExtInsertMenu		yylval = MACRO_ExtInsertMenu;		return VOID_FUNCTION_3STRING_2UINT;
+FileExist|FE		yylval = MACRO_FileExist;		return BOOL_FUNCTION_STRING;
+FileOpen|FO		yylval = MACRO_FileOpen;		return VOID_FUNCTION_VOID;
+Find			yylval = MACRO_Find;			return VOID_FUNCTION_VOID;
+Finder|FD		yylval = MACRO_Finder;			return VOID_FUNCTION_VOID;
+FloatingMenu		yylval = MACRO_FloatingMenu;		return VOID_FUNCTION_VOID;
+Flush|FH		yylval = MACRO_Flush;			return VOID_FUNCTION_VOID;
+FocusWindow		yylval = MACRO_FocusWindow;		return VOID_FUNCTION_STRING;
+Generate		yylval = MACRO_Generate;		return VOID_FUNCTION_STRING_WPARAM_LPARAM;
+GotoMark		yylval = MACRO_GotoMark;		return VOID_FUNCTION_STRING;
+HelpOn			yylval = MACRO_HelpOn;			return VOID_FUNCTION_VOID;
+HelpOnTop		yylval = MACRO_HelpOnTop;		return VOID_FUNCTION_VOID;
+History			yylval = MACRO_History;			return VOID_FUNCTION_VOID;
+IfThen|IF							return IF_THEN;
+IfThenElse|IE							return IF_THEN_ELSE;
+InitMPrint		yylval = MACRO_InitMPrint;		return BOOL_FUNCTION_VOID;
+InsertItem		yylval = MACRO_InsertItem;		return VOID_FUNCTION_4STRING_UINT;
+InsertMenu		yylval = MACRO_InsertMenu;		return VOID_FUNCTION_2STRING_UINT;
+IsBook			yylval = MACRO_IsBook;			return BOOL_FUNCTION_VOID;
+IsMark			yylval = MACRO_IsMark;			return BOOL_FUNCTION_STRING;
+IsNotMark|NM		yylval = MACRO_IsNotMark;		return BOOL_FUNCTION_STRING;
+JumpContents		yylval = MACRO_JumpContents;		return VOID_FUNCTION_FILE_WIN;
+JumpContext|JC		yylval = MACRO_JumpContext;		return VOID_FUNCTION_FILE_WIN_UINT;
+JumpHash|JH		yylval = MACRO_JumpHash;		return VOID_FUNCTION_FILE_WIN_UINT;
+JumpHelpOn		yylval = MACRO_JumpHelpOn;		return VOID_FUNCTION_VOID;
+JumpID|JI		yylval = MACRO_JumpID;			return VOID_FUNCTION_FILE_WIN_STRING;
+JumpKeyword|JK		yylval = MACRO_JumpKeyword;		return VOID_FUNCTION_FILE_WIN_STRING;
+KLink|KL		yylval = MACRO_KLink;			return VOID_FUNCTION_STRING_UINT_2STRING;
+Menu|MU			yylval = MACRO_Menu;			return VOID_FUNCTION_VOID;
+MPrintHash		yylval = MACRO_MPrintHash;		return VOID_FUNCTION_UINT;
+MPrintID		yylval = MACRO_MPrintID;		return VOID_FUNCTION_STRING;
+Next			yylval = MACRO_Next;			return VOID_FUNCTION_VOID;
+NoShow			yylval = MACRO_NoShow;			return VOID_FUNCTION_VOID;
+Not								return NOT;
+PopupContext|PC		yylval = MACRO_PopupContext;		return VOID_FUNCTION_STRING_UINT;
+PopupHash		yylval = MACRO_PopupHash;		return VOID_FUNCTION_STRING_UINT;
+PopupId|PI		yylval = MACRO_PopupId;			return VOID_FUNCTION_2STRING;
+PositionWindow|PW	yylval = MACRO_PositionWindow;		return VOID_FUNCTION_2INT_3UINT_STRING;
+Prev			yylval = MACRO_Prev;			return VOID_FUNCTION_VOID;
+Print			yylval = MACRO_Print;			return VOID_FUNCTION_VOID;
+PrinterSetup		yylval = MACRO_PrinterSetup;		return VOID_FUNCTION_VOID;
+RegisterRoutine|RR	yylval = MACRO_RegisterRoutine;		return VOID_FUNCTION_3STRING;
+RemoveAccelerator|RA	yylval = MACRO_RemoveAccelerator;	return VOID_FUNCTION_2UINT;
+ResetMenu		yylval = MACRO_ResetMenu;		return VOID_FUNCTION_VOID;
+SaveMark		yylval = MACRO_SaveMark;		return VOID_FUNCTION_STRING;
+Search			yylval = MACRO_Search;			return VOID_FUNCTION_VOID;
+SetContents		yylval = MACRO_SetContents;		return VOID_FUNCTION_STRING_UINT;
+SetHelpOnFile		yylval = MACRO_SetHelpOnFile;		return VOID_FUNCTION_STRING;
+SetPopupColor|SPC	yylval = MACRO_SetPopupColor;		return VOID_FUNCTION_3UINT;
+ShellExecute|SE		yylval = MACRO_ShellExecute;		return VOID_FUNCTION_2STRING_2UINT_2STRING;
+ShortCut|SH		yylval = MACRO_ShortCut;		return VOID_FUNCTION_2STRING_WPARAM_LPARAM_STRING;
+TCard			yylval = MACRO_TCard;			return VOID_FUNCTION_UINT;
+Test			yylval = MACRO_Test;			return VOID_FUNCTION_UINT;
+TestALink		yylval = MACRO_TestALink;		return BOOL_FUNCTION_STRING;
+TestKLink		yylval = MACRO_TestKLink;		return BOOL_FUNCTION_STRING;
+UncheckItem|UI		yylval = MACRO_UncheckItem;		return VOID_FUNCTION_STRING;
+UpdateWindow|UW		yylval = MACRO_UpdateWindow;		return VOID_FUNCTION_2STRING;
+
+[-+]?[0-9]+		yylval.integer = strtol(yytext, NULL, 10);	return INTEGER;
+[-+]?0[xX][0-9a-f]+	yylval.integer = strtol(yytext, NULL, 16);	return INTEGER;
+
+\`			|
+\"			{
+  			  if (!hStringBuffer)
+			    {
+			      hStringBuffer = GlobalAlloc(GMEM_FIXED, strlen(macroptr));
+			      strptr = GlobalLock(hStringBuffer);
+			    }
+			  current_string = strptr;
+			  yy_push_state(yytext[0] == '`' ? quote : dquote);
+			}
+
+<quote>\`		{
+			  *strptr++ = yytext[0];
+			  yy_push_state(quote);
+			}
+
+<quote>\'		|
+<dquote>\"		{
+			  yy_pop_state();
+			  if (YY_START == INITIAL)
+			    {
+			      *strptr++ = '\0';
+			      if (MACRO_extra_separator)
+				{
+				  yy_push_state(null_string);
+				  MACRO_extra_separator = 0;
+				}
+			      yylval = current_string;
+			      return STRING;
+			    }
+			  else *strptr++ = yytext[0];
+			}
+
+<quote,dquote>{
+
+.			{
+			  if (MACRO_extra_separator == (CHAR) yytext[0])
+			    {
+			      *strptr++ = '\0';
+			      MACRO_extra_separator = 0;
+			      yylval = current_string;
+			      current_string = strptr;
+			      return STRING;
+			    }
+			  else *strptr++ = yytext[0];
+			}
+
+\\.			*strptr++ = yytext[1];
+
+<<EOF>>			return 0;
+}
+
+<null_string>""		{
+			  yy_pop_state();
+			  yylval = (LPCSTR) 0;
+			  return STRING;
+			}
+
+" "
+
+.			return yytext[0];
+%%
+#include "winhelp.h"
+static CHAR szTestMacro[256];
+
+static LRESULT MACRO_TestDialogProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+  if (msg == WM_COMMAND && wParam == IDOK)
+    {
+      GetDlgItemText(hDlg, 99, szTestMacro, sizeof(szTestMacro));
+      EndDialog(hDlg, IDCANCEL);
+      return TRUE;
+    }
+  return FALSE;
+}
+
+VOID MACRO_ExecuteMacro(LPCSTR macro)
+{
+  static BOOL init = TRUE;
+
+  if (init) init = FALSE;
+  else
+    {
+      YY_FLUSH_BUFFER;
+      while (YY_START != INITIAL)
+	yy_pop_state();
+    }
+
+  if (!lstrcmpi(macro, "MacroTest"))
+    {
+      WNDPROC lpfnDlg = MakeProcInstance(MACRO_TestDialogProc, Globals.hInstance);
+      DialogBox(Globals.hInstance, STRING_DIALOG_TEST, Globals.active_win->hMainWnd, lpfnDlg);
+      FreeProcInstance(lpfnDlg);
+      macro = szTestMacro;
+    }
+
+  macroptr = firsttoken = thistoken = nexttoken = macro;
+
+  yyparse();
+
+  if (hStringBuffer) GlobalFree(hStringBuffer);
+  hStringBuffer = 0;
+}
+
+void yyerror (const char *s)
+{
+  fprintf(stderr, "%s\n%.*s\n%*s%s\n", s,
+	  thistoken - firsttoken, firsttoken,
+	  thistoken - firsttoken, "", thistoken);
+}
diff --git a/programs/winhelp/macro.yacc.y b/programs/winhelp/macro.yacc.y
new file mode 100644
index 0000000..66bce6e
--- /dev/null
+++ b/programs/winhelp/macro.yacc.y
@@ -0,0 +1,170 @@
+%{
+/*
+ * Help Viewer
+ *
+ * Copyright 1996 Ulrich Schmid
+ */
+
+#include "macro.h"
+static int skip = 0;
+%}
+%union
+  {
+    BOOL    bool;
+    LPCSTR  string;
+    LONG    integer;
+    VOID    (*void_function_void)(VOID);
+    BOOL    (*bool_function_void)(VOID);
+    VOID    (*void_function_string)(LPCSTR);
+    BOOL    (*bool_function_string)(LPCSTR);
+
+    BOOL    (*bool_funktion_string)(LPCSTR);
+    BOOL    (*bool_funktion_void)(VOID);
+    VOID    (*void_funktion_2int_3uint_string)(LONG,LONG,LONG,LONG,LONG,LPCSTR);
+    VOID    (*void_funktion_2string)(LPCSTR,LPCSTR);
+    VOID    (*void_funktion_2string_2uint_2string)(LPCSTR,LPCSTR,LONG,LONG,LPCSTR,LPCSTR);
+    VOID    (*void_funktion_2string_uint)(LPCSTR,LPCSTR,LONG);
+    VOID    (*void_funktion_2string_uint_string)(LPCSTR,LPCSTR,LONG,LPCSTR);
+    VOID    (*void_funktion_2string_wparam_lparam_string)(LPCSTR,LPCSTR,WPARAM,LPARAM,LPCSTR);
+    VOID    (*void_funktion_2uint)(LONG,LONG);
+    VOID    (*void_funktion_2uint_string)(LONG,LONG,LPCSTR);
+    VOID    (*void_funktion_3string)(LPCSTR,LPCSTR,LPCSTR);
+    VOID    (*void_funktion_3string_2uint)(LPCSTR,LPCSTR,LPCSTR,LONG,LONG);
+    VOID    (*void_funktion_3uint)(LONG,LONG,LONG);
+    VOID    (*void_funktion_4string)(LPCSTR,LPCSTR,LPCSTR,LPCSTR);
+    VOID    (*void_funktion_4string_2uint)(LPCSTR,LPCSTR,LPCSTR,LPCSTR,LONG,LONG);
+    VOID    (*void_funktion_4string_uint)(LPCSTR,LPCSTR,LPCSTR,LPCSTR,LONG);
+    VOID    (*void_funktion_string)(LPCSTR);
+    VOID    (*void_funktion_string_uint)(LPCSTR,LONG);
+    VOID    (*void_funktion_string_uint_2string)(LPCSTR,LONG,LPCSTR,LPCSTR);
+    VOID    (*void_funktion_string_uint_string)(LPCSTR,LONG,LPCSTR);
+    VOID    (*void_funktion_string_wparam_lparam)(LPCSTR,WPARAM,LPARAM);
+    VOID    (*void_funktion_uint)(LONG);
+    VOID    (*void_funktion_void)(VOID);
+  }
+%token							NOT
+%token 							IF_THEN
+%token 							IF_THEN_ELSE
+%token <string>	 					STRING
+%token <integer> 					INTEGER
+%token <bool_funktion_string>				BOOL_FUNCTION_STRING
+%token <bool_funktion_void>				BOOL_FUNCTION_VOID
+%token <void_funktion_2int_3uint_string>		VOID_FUNCTION_2INT_3UINT_STRING
+%token <void_funktion_2string>				VOID_FUNCTION_2STRING
+%token <void_funktion_2string_2uint_2string>		VOID_FUNCTION_2STRING_2UINT_2STRING
+%token <void_funktion_2string_uint>			VOID_FUNCTION_2STRING_UINT
+%token <void_funktion_2string_uint_string>		VOID_FUNCTION_2STRING_UINT_STRING
+%token <void_funktion_2string_wparam_lparam_string>	VOID_FUNCTION_2STRING_WPARAM_LPARAM_STRING
+%token <void_funktion_2uint>				VOID_FUNCTION_2UINT
+%token <void_funktion_2uint_string>			VOID_FUNCTION_2UINT_STRING
+%token <void_funktion_3string>				VOID_FUNCTION_3STRING
+%token <void_funktion_3string_2uint>			VOID_FUNCTION_3STRING_2UINT
+%token <void_funktion_3uint>				VOID_FUNCTION_3UINT
+%token <void_funktion_4string>				VOID_FUNCTION_4STRING
+%token <void_funktion_4string_2uint>			VOID_FUNCTION_4STRING_2UINT
+%token <void_funktion_4string_uint>			VOID_FUNCTION_4STRING_UINT
+%token <void_funktion_string>				VOID_FUNCTION_STRING
+%token <void_funktion_string_uint>			VOID_FUNCTION_STRING_UINT
+%token <void_funktion_string_uint_2string>		VOID_FUNCTION_STRING_UINT_2STRING
+%token <void_funktion_string_uint_string>		VOID_FUNCTION_STRING_UINT_STRING
+%token <void_funktion_string_wparam_lparam>		VOID_FUNCTION_STRING_WPARAM_LPARAM
+%token <void_funktion_uint>				VOID_FUNCTION_UINT
+%token <void_funktion_void>				VOID_FUNCTION_VOID
+%token <void_funktion_2string>				VOID_FUNCTION_FILE_WIN
+%token <void_funktion_3string>				VOID_FUNCTION_FILE_WIN_STRING
+%token <void_funktion_2string_uint>			VOID_FUNCTION_FILE_WIN_UINT
+%type  <bool> bool_macro
+%type  <string> filename
+%%
+
+macrostring:	macro |
+		macro macrosep macrostring ;
+
+macrosep:	';' |
+		':' ;
+
+macro:		/* Empty */ |
+		IF_THEN      '(' bool_macro ','  {if (! $3) skip++;}
+                                 macrostring ')' {if (! $3) skip--;} |
+		IF_THEN_ELSE '(' bool_macro ','  {if (! $3) skip++;}
+                                 macrostring ',' {if (! $3) skip--; else skip++;}
+                                 macrostring ')' {if (  $3) skip--;} |
+		VOID_FUNCTION_VOID
+			'(' ')'
+			{if (! skip) (*$1)();} |
+		VOID_FUNCTION_STRING
+			'(' STRING ')'
+			{if (! skip) (*$1)($3);} |
+		VOID_FUNCTION_2STRING
+			'(' STRING ',' STRING ')'
+			{if (! skip) (*$1)($3, $5);} |
+		VOID_FUNCTION_2STRING_UINT
+			'(' STRING ',' STRING ',' INTEGER ')'
+			{if (! skip) (*$1)($3, $5, $7);} |
+		VOID_FUNCTION_2STRING_UINT_STRING
+			'(' STRING ',' STRING ',' INTEGER ',' STRING ')'
+			{if (! skip) (*$1)($3, $5, $7, $9);} |
+		VOID_FUNCTION_2STRING_2UINT_2STRING
+			'(' STRING ',' STRING ',' INTEGER ',' INTEGER ',' STRING ',' STRING ')'
+			{if (! skip) (*$1)($3, $5, $7, $9, $11, $13);} |
+		VOID_FUNCTION_2STRING_WPARAM_LPARAM_STRING
+			'(' STRING ',' STRING ',' INTEGER ',' INTEGER ',' STRING ')'
+			{if (! skip) (*$1)($3, $5, $7, $9, $11);} |
+		VOID_FUNCTION_3STRING
+			'(' STRING ',' STRING ',' STRING ')'
+			{if (! skip) (*$1)($3, $5, $7);} |
+		VOID_FUNCTION_3STRING_2UINT
+			'(' STRING ',' STRING ',' STRING ',' INTEGER ',' INTEGER ')'
+			{if (! skip) (*$1)($3, $5, $7, $9, $11);} |
+		VOID_FUNCTION_4STRING
+			'(' STRING ',' STRING ',' STRING ',' STRING ')'
+			{if (! skip) (*$1)($3, $5, $7, $9);} |
+		VOID_FUNCTION_4STRING_UINT
+			'(' STRING ',' STRING ',' STRING ',' STRING ',' INTEGER')'
+			{if (! skip) (*$1)($3, $5, $7, $9, $11);} |
+		VOID_FUNCTION_4STRING_2UINT
+			'(' STRING ',' STRING ',' STRING ',' STRING ',' INTEGER ',' INTEGER')'
+			{if (! skip) (*$1)($3, $5, $7, $9, $11, $13);} |
+		VOID_FUNCTION_STRING_UINT
+			'(' STRING ',' INTEGER ')'
+			{if (! skip) (*$1)($3, $5);} |
+		VOID_FUNCTION_STRING_UINT_STRING
+			'(' STRING ',' INTEGER ',' STRING ')'
+			{if (! skip) (*$1)($3, $5, $7);} |
+		VOID_FUNCTION_STRING_UINT_2STRING
+			'(' STRING ',' INTEGER ',' STRING ',' STRING ')'
+			{if (! skip) (*$1)($3, $5, $7, $9);} |
+		VOID_FUNCTION_STRING_WPARAM_LPARAM
+			'(' STRING ',' INTEGER ',' INTEGER ')'
+			{if (! skip) (*$1)($3, $5, $7);} |
+		VOID_FUNCTION_UINT
+			'(' INTEGER ')'
+			{if (! skip) (*$1)($3);} |
+		VOID_FUNCTION_2UINT
+			'(' INTEGER ',' INTEGER ')'
+			{if (! skip) (*$1)($3, $5);} |
+		VOID_FUNCTION_2UINT_STRING
+			'(' INTEGER ',' INTEGER ',' STRING ')'
+			{if (! skip) (*$1)($3, $5, $7);} |
+		VOID_FUNCTION_3UINT
+			'(' INTEGER ',' INTEGER ',' INTEGER ')'
+			{if (! skip) (*$1)($3, $5, $7);} |
+		VOID_FUNCTION_2INT_3UINT_STRING
+			'(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ',' STRING ')'
+			{if (! skip) (*$1)($3, $5, $7, $9, $11, $13);} |
+		VOID_FUNCTION_FILE_WIN
+			'(' filename STRING ')'
+			{if (! skip) (*$1)($3, $4);} |
+		VOID_FUNCTION_FILE_WIN_STRING
+			'(' filename STRING ',' STRING ')'
+			{if (! skip) (*$1)($3, $4, $6);} |
+		VOID_FUNCTION_FILE_WIN_UINT
+			'(' filename STRING ',' INTEGER ')'
+			{if (! skip) (*$1)($3, $4, $6);} ;
+
+filename:	{MACRO_extra_separator = '>'} STRING {$$ = $2;} ;
+
+bool_macro:     NOT '(' bool_macro ')' {$$ = ! $3;} |
+		STRING {$$ = MACRO_IsMark($1);} |
+		BOOL_FUNCTION_VOID '(' ')' {$$ = (*$1)();} |
+		BOOL_FUNCTION_STRING '(' STRING ')' {$$ = (*$1)($3);} ;
diff --git a/programs/winhelp/string.c b/programs/winhelp/string.c
new file mode 100644
index 0000000..647b968
--- /dev/null
+++ b/programs/winhelp/string.c
@@ -0,0 +1,25 @@
+/*
+ * Help Viewer
+ *
+ * Copyright 1996 Ulrich Schmid
+ */
+
+#include <windows.h>
+#include "winhelp.h"
+
+/* Class names */
+
+CHAR MAIN_WIN_CLASS_NAME[]       = "WHMain";
+CHAR BUTTON_BOX_WIN_CLASS_NAME[] = "WHButtonBox";
+CHAR TEXT_WIN_CLASS_NAME[]       = "WHText";
+CHAR SHADOW_WIN_CLASS_NAME[]     = "WHShadow";
+CHAR STRING_BUTTON[]             = "BUTTON";
+
+/* Resource names */
+/* Xx will be overwritten with En, ... */
+CHAR STRING_MENU_Xx[]        = "MENU_Xx";
+CHAR STRING_DIALOG_TEST[]    = "DIALOG_TEST";
+
+/* Local Variables:    */
+/* c-file-style: "GNU" */
+/* End:                */
diff --git a/programs/winhelp/winhelp.c b/programs/winhelp/winhelp.c
new file mode 100644
index 0000000..c7244b0
--- /dev/null
+++ b/programs/winhelp/winhelp.c
@@ -0,0 +1,1069 @@
+/*
+ * Help Viewer
+ *
+ * Copyright 1996 Ulrich Schmid <uschmid@mail.hh.provi.de>
+ */
+
+#include <stdio.h>
+#include <windows.h>
+#ifdef WINELIB
+#include <resource.h>
+#include <options.h>
+#include <shell.h>
+extern const char people[];
+#endif
+#include "winhelp.h"
+
+VOID LIBWINE_Register_De(void);
+VOID LIBWINE_Register_En(void);
+
+static BOOL    WINHELP_RegisterWinClasses();
+static LRESULT WINHELP_MainWndProc(HWND, UINT, WPARAM, LPARAM);
+static LRESULT WINHELP_TextWndProc(HWND, UINT, WPARAM, LPARAM);
+static LRESULT WINHELP_ButtonBoxWndProc(HWND, UINT, WPARAM, LPARAM);
+static VOID    WINHELP_CheckPopup(UINT);
+static BOOL    WINHELP_SplitLines(HWND hWnd, LPSIZE);
+static VOID    WINHELP_InitFonts(HWND hWnd);
+static VOID    WINHELP_DeleteLines(WINHELP_WINDOW*);
+static VOID    WINHELP_DeleteWindow(WINHELP_WINDOW*);
+static VOID    WINHELP_SetupText(HWND hWnd);
+static BOOL    WINHELP_AppendText(WINHELP_LINE***, WINHELP_LINE_PART***,
+				  LPSIZE, LPSIZE, INT*, INT, LPCSTR, UINT,
+				  HFONT, COLORREF, HLPFILE_LINK*);
+
+WINHELP_GLOBALS Globals = {3, 0, 0, 0, 0, 0};
+
+static BOOL MacroTest = FALSE;
+
+/***********************************************************************
+ *
+ *           WinMain
+ */
+
+int PASCAL WinMain (HANDLE hInstance, HANDLE prev, LPSTR cmdline, int show)
+{
+  LPCSTR opt_lang = "En";
+  CHAR   lang[3];
+  MSG    msg;
+  LONG   lHash = 0;
+  INT    langnum;
+
+#if defined(WINELIB) && !defined(HAVE_WINE_CONSTRUCTOR)
+  /* Register resources */
+  LIBWINE_Register_De();
+  LIBWINE_Register_En();
+#endif
+
+  Globals.hInstance = hInstance;
+
+  /* Get options */
+  while (*cmdline && (*cmdline == ' ' || *cmdline == '-'))
+    {
+      CHAR   option;
+      LPCSTR topic_id;
+      if (*cmdline++ == ' ') continue;
+
+      option = *cmdline;
+      if (option) cmdline++;
+      while (*cmdline && *cmdline == ' ') cmdline++;
+      switch(option)
+	{
+	case 'i':
+	case 'I':
+	  topic_id = cmdline;
+	  while (*cmdline && *cmdline != ' ') cmdline++;
+	  if (*cmdline) *cmdline++ = '\0';
+	  lHash = HLPFILE_Hash(topic_id);
+	  break;
+
+	case '3':
+	case '4':
+	  Globals.wVersion = option - '0';
+	  break;
+
+	case 't':
+	  MacroTest = TRUE;
+	  break;
+	}
+    }
+
+#ifdef WINELIB
+  opt_lang = langNames[Options.language];
+#endif
+
+  /* Find language specific string table */
+  for (langnum = 0; langnum <= MAX_LANGUAGE_NUMBER; langnum++)
+    {
+      Globals.wStringTableOffset = langnum * 0x100;
+      if (LoadString(hInstance, IDS_LANGUAGE_ID, lang, sizeof(lang)) &&
+	  !lstrcmp(opt_lang, lang))
+	break;
+    }
+  if (langnum > MAX_LANGUAGE_NUMBER)
+    {
+      /* Find fallback language */
+      for (langnum = 0; langnum <= MAX_LANGUAGE_NUMBER; langnum++)
+	{
+	  Globals.wStringTableOffset = langnum * 0x100;
+	  if (LoadString(hInstance, IDS_LANGUAGE_ID, lang, sizeof(lang)))
+	    break;
+	}
+      if (langnum > MAX_LANGUAGE_NUMBER)
+	{
+	MessageBox(0, "No language found", "FATAL ERROR", MB_OK);
+	return(1);
+	}
+    }
+
+  /* Change Resource names */
+  lstrcpyn(STRING_MENU_Xx + lstrlen(STRING_MENU_Xx) - 2, lang, 3);
+
+  /* Create primary window */
+  WINHELP_RegisterWinClasses();
+  WINHELP_CreateHelpWindow(cmdline, lHash, "main", FALSE, NULL, NULL, show);
+
+  /* Message loop */
+  while (GetMessage (&msg, 0, 0, 0))
+    {
+      TranslateMessage (&msg);
+      DispatchMessage (&msg);
+    }
+  return 0;
+}
+
+/***********************************************************************
+ *
+ *           RegisterWinClasses
+ */
+
+static BOOL WINHELP_RegisterWinClasses()
+{
+  WNDCLASS class_main, class_button_box, class_text, class_shadow;
+
+  class_main.style               = CS_HREDRAW | CS_VREDRAW;
+  class_main.lpfnWndProc         = WINHELP_MainWndProc;
+  class_main.cbClsExtra          = 0;
+  class_main.cbWndExtra          = sizeof(LONG);
+  class_main.hInstance           = Globals.hInstance;
+  class_main.hIcon               = LoadIcon (0, IDI_APPLICATION);
+  class_main.hCursor             = LoadCursor (0, IDC_ARROW);
+  class_main.hbrBackground       = GetStockObject (WHITE_BRUSH);
+  class_main.lpszMenuName        = 0;
+  class_main.lpszClassName       = MAIN_WIN_CLASS_NAME;
+
+  class_button_box               = class_main;
+  class_button_box.lpfnWndProc   = WINHELP_ButtonBoxWndProc;
+  class_button_box.hbrBackground = GetStockObject(GRAY_BRUSH);
+  class_button_box.lpszClassName = BUTTON_BOX_WIN_CLASS_NAME;
+
+  class_text = class_main;
+  class_text.lpfnWndProc         = WINHELP_TextWndProc;
+  class_text.lpszClassName       = TEXT_WIN_CLASS_NAME;
+
+  class_shadow = class_main;
+  class_shadow.lpfnWndProc       = DefWindowProc;
+  class_shadow.hbrBackground     = GetStockObject(GRAY_BRUSH);
+  class_shadow.lpszClassName     = SHADOW_WIN_CLASS_NAME;
+
+  return (RegisterClass(&class_main) &&
+	  RegisterClass(&class_button_box) &&
+	  RegisterClass(&class_text) &&
+	  RegisterClass(&class_shadow));
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_CreateHelpWindow
+ */
+
+VOID WINHELP_CreateHelpWindow(LPCSTR lpszFile, LONG lHash, LPCSTR lpszWindow,
+			      BOOL bPopup, HWND hParentWnd, LPPOINT mouse, INT nCmdShow)
+{
+  CHAR    szCaption[MAX_STRING_LEN];
+  CHAR    szContents[MAX_STRING_LEN];
+  CHAR    szSearch[MAX_STRING_LEN];
+  CHAR    szBack[MAX_STRING_LEN];
+  CHAR    szHistory[MAX_STRING_LEN];
+  SIZE    size   = {CW_USEDEFAULT, CW_USEDEFAULT};
+  POINT   origin = {240, 0};
+  LPSTR   ptr;
+  HGLOBAL handle;
+  WINHELP_WINDOW *win, *oldwin;
+  HLPFILE_PAGE   *page;
+  HLPFILE_MACRO  *macro;
+  HWND hWnd;
+  BOOL bPrimary;
+
+  if (bPopup)
+    lpszWindow = NULL;
+  else if (!lpszWindow)
+    lpszWindow = Globals.active_win->lpszName;
+  bPrimary = lpszWindow && !lstrcmpi(lpszWindow, "main");
+
+  /* Read help file */
+  if (lpszFile[0])
+    {
+      page = lHash ? HLPFILE_PageByHash(lpszFile, lHash) : HLPFILE_Contents(lpszFile);
+
+      /* Add Suffix `.hlp' */
+      if (!page && lstrcmpi(lpszFile + strlen(lpszFile) - 4, ".hlp"))
+	{
+	  CHAR      szFile_hlp[MAX_PATHNAME_LEN];
+
+	  lstrcpyn(szFile_hlp, lpszFile, sizeof(szFile_hlp) - 4);
+	  szFile_hlp[sizeof(szFile_hlp) - 5] = '\0';
+	  lstrcat(szFile_hlp, ".hlp");
+
+	  page = lHash ? HLPFILE_PageByHash(szFile_hlp, lHash) : HLPFILE_Contents(szFile_hlp);
+	  if (!page)
+	    {
+	      WINHELP_MessageBoxIDS_s(IDS_HLPFILE_ERROR_s, lpszFile, IDS_ERROR, MB_OK);
+	      if (Globals.win_list) return;
+	    }
+	}
+    }
+  else page = 0;
+
+  /* Calculate horizontal size and position of a popup window */
+  if (bPopup)
+    {
+      RECT parent_rect;
+      GetWindowRect(hParentWnd, &parent_rect);
+      size.cx = (parent_rect.right  - parent_rect.left) / 2;
+
+      origin = *mouse;
+      ClientToScreen(hParentWnd, &origin);
+      origin.x -= size.cx / 2;
+      origin.x  = MIN(origin.x, GetSystemMetrics(SM_CXSCREEN) - size.cx);
+      origin.x  = MAX(origin.x, 0);
+    }
+
+  /* Initialize WINHELP_WINDOW struct */
+  handle = GlobalAlloc(GMEM_FIXED, sizeof(WINHELP_WINDOW) +
+		       (lpszWindow ? strlen(lpszWindow) + 1 : 0));
+  if (!handle) return;
+  win = GlobalLock(handle);
+  win->hSelf = handle;
+  win->next  = Globals.win_list;
+  Globals.win_list = win;
+  if (lpszWindow)
+    {
+      ptr = GlobalLock(handle);
+      ptr += sizeof(WINHELP_WINDOW);
+      lstrcpy(ptr, (LPSTR) lpszWindow);
+      win->lpszName = ptr;
+    }
+  else win->lpszName = NULL;
+  win->page = page;
+  win->first_button = 0;
+  win->first_line = 0;
+  win->hMainWnd = 0;
+  win->hButtonBoxWnd = 0;
+  win->hTextWnd = 0;
+  win->hShadowWnd = 0;
+
+  Globals.active_win = win;
+
+  /* Initialize default pushbuttons */
+  if (MacroTest && !bPopup)
+    MACRO_CreateButton("BTN_TEST", "&Test", "MacroTest");
+  if (bPrimary && page)
+    {
+      LoadString(Globals.hInstance, IDS_CONTENTS, szContents, sizeof(szContents));
+      LoadString(Globals.hInstance, IDS_SEARCH,   szSearch,   sizeof(szSearch));
+      LoadString(Globals.hInstance, IDS_BACK,     szBack,     sizeof(szBack));
+      LoadString(Globals.hInstance, IDS_HISTORY,  szHistory,  sizeof(szHistory));
+      MACRO_CreateButton("BTN_CONTENTS", szContents, "Contents()");
+      MACRO_CreateButton("BTN_SEARCH",   szSearch,   "Search()");
+      MACRO_CreateButton("BTN_BACK",     szBack,     "Back()");
+      MACRO_CreateButton("BTN_HISTORY",  szHistory,  "History()");
+    }
+
+  /* Initialize file specific pushbuttons */
+  if (!bPopup && page)
+    for (macro = page->file->first_macro; macro; macro = macro->next)
+      MACRO_ExecuteMacro(macro->lpszMacro);
+
+  /* Reuse existing window */
+  if (lpszWindow)
+    for (oldwin = win->next; oldwin; oldwin = oldwin->next)
+      if (oldwin->lpszName && !lstrcmpi(oldwin->lpszName, lpszWindow))
+	{
+	  WINHELP_BUTTON *button;
+
+	  win->hMainWnd      = oldwin->hMainWnd;
+	  win->hButtonBoxWnd = oldwin->hButtonBoxWnd;
+	  win->hTextWnd      = oldwin->hTextWnd;
+	  oldwin->hMainWnd = oldwin->hButtonBoxWnd = oldwin->hTextWnd = 0;
+
+	  SetWindowLong(win->hMainWnd,      0, (LONG) win);
+	  SetWindowLong(win->hButtonBoxWnd, 0, (LONG) win);
+	  SetWindowLong(win->hTextWnd,      0, (LONG) win);
+
+	  WINHELP_InitFonts(win->hMainWnd);
+
+	  SetWindowText(win->hMainWnd, page->file->lpszTitle);
+
+	  WINHELP_SetupText(win->hTextWnd);
+	  InvalidateRect(win->hTextWnd, NULL, TRUE);
+	  SendMessage(win->hMainWnd, WM_USER, 0, 0);
+	  UpdateWindow(win->hTextWnd);
+
+
+	  for (button = oldwin->first_button; button; button = button->next)
+	    DestroyWindow(button->hWnd);
+  
+	  WINHELP_DeleteWindow(oldwin);
+	  return;
+	}
+
+  /* Create main Window */
+  if (!page) LoadString(Globals.hInstance, IDS_WINE_HELP, szCaption, sizeof(szCaption));
+  hWnd = CreateWindow (bPopup ? TEXT_WIN_CLASS_NAME : MAIN_WIN_CLASS_NAME,
+		       page ? (SEGPTR) page->file->lpszTitle : (SEGPTR) szCaption,
+		       bPopup ? WS_POPUPWINDOW | WS_BORDER : WS_OVERLAPPEDWINDOW,
+		       origin.x, origin.y, size.cx, size.cy,
+		       0, bPrimary ? LoadMenu(Globals.hInstance, STRING_MENU_Xx) : 0,
+		       Globals.hInstance, (SEGPTR) win);
+
+  ShowWindow (hWnd, nCmdShow);
+  UpdateWindow (hWnd);
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_MainWndProc
+ */
+
+static LRESULT WINHELP_MainWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+  WINHELP_WINDOW *win;
+  WINHELP_BUTTON *button;
+  RECT rect, button_box_rect;
+  INT  text_top;
+
+  WINHELP_CheckPopup(msg);
+
+  switch (msg)
+    {
+    case WM_NCCREATE:
+      win = (WINHELP_WINDOW*) ((LPCREATESTRUCT) lParam)->lpCreateParams;
+      SetWindowLong(hWnd, 0, (LONG) win);
+      win->hMainWnd = hWnd;
+      break;
+
+    case WM_CREATE:
+      win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
+
+      /* Create button box and text Window */
+      CreateWindow(BUTTON_BOX_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE,
+		   0, 0, 0, 0, hWnd, 0, Globals.hInstance, (SEGPTR) win);
+
+      CreateWindow(TEXT_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE,
+		   0, 0, 0, 0, hWnd, 0, Globals.hInstance, (SEGPTR) win);
+
+      /* Fall through */
+    case WM_USER:
+    case WM_WINDOWPOSCHANGED:
+      win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
+      GetClientRect(hWnd, &rect);
+
+      /* Update button box and text Window */
+      SetWindowPos(win->hButtonBoxWnd, HWND_TOP,
+		   rect.left, rect.top,
+		   rect.right - rect.left,
+		   rect.bottom - rect.top, 0);
+
+      GetWindowRect(win->hButtonBoxWnd, &button_box_rect);
+      text_top = rect.top + button_box_rect.bottom - button_box_rect.top;
+
+      SetWindowPos(win->hTextWnd, HWND_TOP,
+		   rect.left, text_top,
+		   rect.right - rect.left,
+		   rect.bottom - text_top, 0);
+
+      break;
+
+    case WM_COMMAND:
+      Globals.active_win = win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
+      switch (wParam)
+	{
+	  /* Menu FILE */
+	case WH_OPEN:            MACRO_FileOpen();       break;
+	case WH_PRINT:           MACRO_Print();          break;
+	case WH_PRINTER_SETUP:   MACRO_PrinterSetup();   break;
+	case WH_EXIT:            MACRO_Exit();           break;
+
+	  /* Menu EDIT */
+	case WH_COPY_DIALOG:     MACRO_CopyDialog();     break;
+	case WH_ANNOTATE:        MACRO_Annotate();       break;
+
+	  /* Menu Bookmark */
+	case WH_BOOKMARK_DEFINE: MACRO_BookmarkDefine(); break;
+
+	  /* Menu Help */
+	case WH_HELP_ON_HELP:    MACRO_HelpOn();         break;
+	case WH_HELP_ON_TOP:     MACRO_HelpOnTop();      break;
+
+	  /* Menu Info */
+	case WH_ABOUT:           MACRO_About();          break;
+#ifdef WINELIB
+	case WH_ABOUT_WINE: 
+	  ShellAbout(hWnd, "WINE", people, 0);
+	  break;
+#endif
+
+	default:
+	  /* Buttons */
+	  for (button = win->first_button; button; button = button->next)
+	    if (wParam == button->wParam) break;
+	  if (button)
+	    MACRO_ExecuteMacro(button->lpszMacro);
+	  else
+	    WINHELP_MessageBoxIDS(IDS_NOT_IMPLEMENTED, IDS_ERROR, MB_OK);
+	  break;
+	}
+      break;
+    }
+
+  return DefWindowProc (hWnd, msg, wParam, lParam);
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_ButtonBoxWndProc
+ */
+
+static LRESULT WINHELP_ButtonBoxWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+  WINDOWPOS      *winpos;
+  WINHELP_WINDOW *win;
+  WINHELP_BUTTON *button;
+  SIZE button_size;
+  INT  x, y;
+
+  WINHELP_CheckPopup(msg);
+
+  switch(msg)
+    {
+    case WM_NCCREATE:
+      win = (WINHELP_WINDOW*) ((LPCREATESTRUCT) lParam)->lpCreateParams;
+      SetWindowLong(hWnd, 0, (LONG) win);
+      win->hButtonBoxWnd = hWnd;
+      break;
+
+    case WM_WINDOWPOSCHANGING:
+      winpos = (WINDOWPOS*) lParam;
+      win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
+
+      /* Update buttons */
+      button_size.cx = 0;
+      button_size.cy = 0;
+      for (button = win->first_button; button; button = button->next)
+	{
+	  HDC  hDc;
+	  SIZE textsize;
+	  if (!button->hWnd)
+	    button->hWnd = CreateWindow(STRING_BUTTON, (LPSTR) button->lpszName,
+					WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
+					0, 0, 0, 0,
+					hWnd, (HMENU) button->wParam,
+					Globals.hInstance, 0);
+	  hDc = GetDC(button->hWnd);
+	  GetTextExtentPoint(hDc, button->lpszName,
+			     lstrlen(button->lpszName), &textsize);
+	  ReleaseDC(button->hWnd, hDc);
+
+	  button_size.cx = MAX(button_size.cx, textsize.cx + BUTTON_CX);
+	  button_size.cy = MAX(button_size.cy, textsize.cy + BUTTON_CY);
+	}
+
+      x = 0;
+      y = 0;
+      for (button = win->first_button; button; button = button->next)
+	{
+	  SetWindowPos(button->hWnd, HWND_TOP, x, y, button_size.cx, button_size.cy, 0);
+
+	  if (x + 2 * button_size.cx <= winpos->cx)
+	    x += button_size.cx;
+	  else
+	    x = 0, y += button_size.cy;
+	}
+      winpos->cy = y + (x ? button_size.cy : 0);
+      break;
+
+    case WM_COMMAND:
+      SendMessage(GetParent(hWnd), msg, wParam, lParam);
+      break;
+    }
+
+  return(DefWindowProc(hWnd, msg, wParam, lParam));
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_TextWndProc
+ */
+
+static LRESULT WINHELP_TextWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+  WINHELP_WINDOW    *win;
+  WINHELP_LINE      *line;
+  WINHELP_LINE_PART *part;
+  WINDOWPOS         *winpos;
+  PAINTSTRUCT        ps;
+  HDC   hDc;
+  POINT mouse;
+  INT   scroll_pos;
+  HWND  hPopupWnd;
+  BOOL  bExit;
+
+  if (msg != WM_LBUTTONDOWN)
+    WINHELP_CheckPopup(msg);
+
+  switch (msg)
+    {
+    case WM_NCCREATE:
+      win = (WINHELP_WINDOW*) ((LPCREATESTRUCT) lParam)->lpCreateParams;
+      SetWindowLong(hWnd, 0, (LONG) win);
+      win->hTextWnd = hWnd;
+      if (!win->lpszName) Globals.hPopupWnd = win->hMainWnd = hWnd;
+      WINHELP_InitFonts(hWnd);
+      break;
+
+    case WM_CREATE:
+      win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
+
+      /* Calculate vertical size and position of a popup window */
+      if (!win->lpszName)
+	{
+	  POINT origin;
+	  RECT old_window_rect;
+	  RECT old_client_rect;
+	  SIZE old_window_size;
+	  SIZE old_client_size;
+	  SIZE new_client_size;
+	  SIZE new_window_size;
+
+	  GetWindowRect(hWnd, &old_window_rect);
+	  origin.x = old_window_rect.left;
+	  origin.y = old_window_rect.top;
+	  old_window_size.cx = old_window_rect.right  - old_window_rect.left;
+	  old_window_size.cy = old_window_rect.bottom - old_window_rect.top;
+
+	  GetClientRect(hWnd, &old_client_rect);
+	  old_client_size.cx = old_client_rect.right  - old_client_rect.left;
+	  old_client_size.cy = old_client_rect.bottom - old_client_rect.top;
+
+	  new_client_size = old_client_size;
+	  WINHELP_SplitLines(hWnd, &new_client_size);
+
+	  if (origin.y + POPUP_YDISTANCE + new_client_size.cy <= GetSystemMetrics(SM_CYSCREEN))
+	    origin.y += POPUP_YDISTANCE;
+	  else
+	    origin.y -= POPUP_YDISTANCE + new_client_size.cy;
+
+	  new_window_size.cx = old_window_size.cx - old_client_size.cx + new_client_size.cx;
+	  new_window_size.cy = old_window_size.cy - old_client_size.cy + new_client_size.cy;
+
+	  win->hShadowWnd = 
+	    CreateWindow(SHADOW_WIN_CLASS_NAME, "", WS_POPUP | WS_VISIBLE,
+			 origin.x + SHADOW_DX, origin.y + SHADOW_DY,
+			 new_window_size.cx, new_window_size.cy,
+			 0, 0, Globals.hInstance, 0);
+
+	  SetWindowPos(hWnd, HWND_TOP, origin.x, origin.y,
+		       new_window_size.cx, new_window_size.cy,
+		       SWP_NOZORDER | SWP_NOACTIVATE);
+	  ShowWindow(win->hShadowWnd, SW_NORMAL);
+	}
+      break;
+
+    case WM_WINDOWPOSCHANGED:
+      winpos = (WINDOWPOS*) lParam;
+      if (!(winpos->flags & SWP_NOSIZE)) WINHELP_SetupText(hWnd);
+      break;
+
+    case WM_VSCROLL:
+      {
+	BOOL update = TRUE;
+	RECT rect;
+	INT  Min, Max;
+	INT  CurPos = GetScrollPos(hWnd, SB_VERT);
+	GetScrollRange(hWnd, SB_VERT, &Min, &Max);
+	GetClientRect(hWnd, &rect);
+
+	switch (wParam & 0xffff)
+	  {
+	  case SB_THUMBTRACK:
+	  case SB_THUMBPOSITION: CurPos  = wParam >> 16;                   break;
+	  case SB_TOP:           CurPos  = Min;                            break;
+	  case SB_BOTTOM:        CurPos  = Max;                            break;
+	  case SB_PAGEUP:        CurPos -= (rect.bottom - rect.top) / 2;   break;
+	  case SB_PAGEDOWN:      CurPos += (rect.bottom - rect.top) / 2;   break;
+	  case SB_LINEUP:        CurPos -= GetSystemMetrics(SM_CXVSCROLL); break;
+	  case SB_LINEDOWN:      CurPos += GetSystemMetrics(SM_CXVSCROLL); break;
+	  default: update = FALSE;
+	  }
+	if (update)
+	  {
+	    INT dy = GetScrollPos(hWnd, SB_VERT) - CurPos;
+	    SetScrollPos(hWnd, SB_VERT, CurPos, TRUE);
+	    ScrollWindow(hWnd, 0, dy, NULL, NULL);
+	    UpdateWindow(hWnd);
+	  }
+      }
+      break;
+
+    case WM_PAINT:
+      hDc = BeginPaint (hWnd, &ps);
+      win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
+      scroll_pos = GetScrollPos(hWnd, SB_VERT);
+
+      for (line = win->first_line; line; line = line->next)
+	for (part = &line->first_part; part; part = part->next)
+	  {
+	    SelectObject(hDc, part->hFont);
+	    SetTextColor(hDc, part->color);
+	    TextOut(hDc, part->rect.left, part->rect.top - scroll_pos,
+		    (LPSTR) part->lpsText, part->wTextLen);
+	  }
+
+      EndPaint (hWnd, &ps);
+      break;
+
+    case WM_LBUTTONDOWN:
+      win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
+      scroll_pos = GetScrollPos(hWnd, SB_VERT);
+
+      hPopupWnd = Globals.hPopupWnd;
+      Globals.hPopupWnd = 0;
+
+      mouse.x = LOWORD(lParam);
+      mouse.y = HIWORD(lParam);
+      for (line = win->first_line; line; line = line->next)
+	for (part = &line->first_part; part; part = part->next)
+	  if (part->link.lpszPath &&
+	      part->rect.left   <= mouse.x &&
+	      part->rect.right  >= mouse.x &&
+	      part->rect.top    <= mouse.y + scroll_pos &&
+	      part->rect.bottom >= mouse.y + scroll_pos)
+	    WINHELP_CreateHelpWindow(part->link.lpszPath, part->link.lHash, NULL,
+				     part->link.bPopup, hWnd, &mouse,  SW_NORMAL);
+      if (hPopupWnd)
+	DestroyWindow(hPopupWnd);
+      break;
+
+    case WM_NCDESTROY:
+      win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
+
+      if (hWnd == Globals.hPopupWnd) Globals.hPopupWnd = 0;
+
+      bExit = (Globals.wVersion >= 4 && !lstrcmpi(win->lpszName, "main"));
+
+      WINHELP_DeleteWindow(win);
+
+      if (bExit) MACRO_Exit();
+
+      if (!Globals.win_list)
+	PostQuitMessage (0);
+      break;
+    }
+
+  return DefWindowProc (hWnd, msg, wParam, lParam);
+}
+
+/***********************************************************************
+ *
+ *           SetupText
+ */
+
+static VOID WINHELP_SetupText(HWND hWnd)
+{
+  HDC  hDc = GetDC(hWnd);
+  RECT rect;
+  SIZE newsize;
+
+  ShowScrollBar(hWnd, SB_VERT, FALSE);
+  if (!WINHELP_SplitLines(hWnd, NULL))
+    {
+      ShowScrollBar(hWnd, SB_VERT, TRUE);
+      GetClientRect(hWnd, &rect);
+
+      WINHELP_SplitLines(hWnd, &newsize);
+      SetScrollRange(hWnd, SB_VERT, 0, rect.top + newsize.cy - rect.bottom, TRUE);
+    }
+  else SetScrollPos(hWnd, SB_VERT, 0, FALSE);
+
+  ReleaseDC(hWnd, hDc);
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_SplitLines
+ */
+
+static BOOL WINHELP_SplitLines(HWND hWnd, LPSIZE newsize)
+{
+  WINHELP_WINDOW     *win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
+  HLPFILE_PARAGRAPH  *p;
+  WINHELP_LINE      **line = &win->first_line;
+  WINHELP_LINE_PART **part = 0;
+  INT                 line_ascent = 0;
+  SIZE                space;
+  RECT                rect;
+  HDC                 hDc;
+
+  if (newsize) newsize->cx = newsize->cy = 0;
+
+  if (!win->page) return TRUE;
+
+  WINHELP_DeleteLines(win);
+
+  GetClientRect(hWnd, &rect);
+
+  rect.top    += INTERNAL_BORDER_WIDTH;
+  rect.left   += INTERNAL_BORDER_WIDTH;
+  rect.right  -= INTERNAL_BORDER_WIDTH;
+  rect.bottom -= INTERNAL_BORDER_WIDTH;
+
+
+  space.cy = rect.top;
+  space.cx = rect.left;
+
+  hDc = GetDC(hWnd);
+
+  for (p = win->page->first_paragraph; p; p = p->next)
+    {
+      TEXTMETRIC tm;
+      SIZE textsize = {0, 0};
+      LPCSTR text    = p->lpszText;
+      UINT len    = strlen(text);
+      UINT indent = 0;
+
+      UINT  wFont      = (p->wFont < win->fonts_len) ? p->wFont : 0;
+      BOOL  bUnderline = p->link && !p->link->bPopup;
+      HFONT hFont      = win->fonts[wFont][bUnderline ? 1 : 0];
+
+      COLORREF       color = RGB(0, 0, 0);
+      if (p->link)   color = RGB(0, 0x80, 0);
+      if (p->bDebug) color = RGB(0xff, 0, 0);
+
+      SelectObject(hDc, hFont);
+
+      GetTextMetrics (hDc, &tm);
+
+      if (p->wIndent)
+	{
+	  indent = p->wIndent * 5 * tm.tmAveCharWidth;
+	  if (!part)
+	    space.cx = rect.left + indent - 2 * tm.tmAveCharWidth;
+	}
+
+      if (p->wVSpace)
+	{
+	  part = 0;
+	  space.cx = rect.left + indent;
+	  space.cy += (p->wVSpace - 1) * tm.tmHeight;
+	}
+
+      if (p->wHSpace)
+	{
+	  space.cx += p->wHSpace * 2 * tm.tmAveCharWidth;
+	}
+
+      while (len)
+	{
+	  INT free_width = rect.right - (part ? (*line)->rect.right : rect.left) - space.cx;
+	  UINT low = 0, curr = len, high = len, textlen;
+
+	  if (free_width > 0)
+	    {
+	      while (1)
+		{
+		  GetTextExtentPoint(hDc, text, curr, &textsize);
+
+		  if (textsize.cx <= free_width) low = curr;
+		  else high = curr;
+
+		  if (high <= low + 1) break;
+
+		  if (textsize.cx) curr = (curr * free_width) / textsize.cx;
+		  if (curr <= low)  curr = low + 1;
+		  else if (curr >= high) curr = high - 1;
+		}
+	      textlen = low;
+	      while (textlen && text[textlen] && text[textlen] != ' ') textlen--;
+	    }
+	  if (!part && !textlen) textlen = MAX(low, 1);
+
+	  if (free_width <= 0 || !textlen)
+	    {
+	      part = 0;
+	      space.cx = rect.left + indent;
+	      space.cx = MIN(space.cx, rect.right - rect.left - 1);
+	      continue;
+	    }
+
+	  if (!WINHELP_AppendText(&line, &part, &space, &textsize,
+				  &line_ascent, tm.tmAscent,
+				  text, textlen, hFont, color, p->link) ||
+	      (!newsize && (*line)->rect.bottom > rect.bottom))
+	    {
+	      ReleaseDC(hWnd, hDc);
+	      return FALSE;
+	    }
+
+	  if (newsize)
+	    newsize->cx = MAX(newsize->cx, (*line)->rect.right + INTERNAL_BORDER_WIDTH);
+
+	  len -= textlen;
+	  text += textlen;
+	  if (text[0] == ' ') text++, len--;
+	}
+    }
+
+  if (newsize)
+    newsize->cy = (*line)->rect.bottom + INTERNAL_BORDER_WIDTH;
+
+  ReleaseDC(hWnd, hDc);
+  return TRUE;
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_AppendText
+ */
+
+static BOOL WINHELP_AppendText(WINHELP_LINE ***linep, WINHELP_LINE_PART ***partp,
+			       LPSIZE space, LPSIZE textsize,
+			       INT *line_ascent, INT ascent,
+			       LPCSTR text, UINT textlen,
+			       HFONT font, COLORREF color, HLPFILE_LINK *link)
+{
+  HGLOBAL handle;
+  WINHELP_LINE      *line;
+  WINHELP_LINE_PART *part;
+  LPSTR ptr;
+
+  if (!*partp) /* New line */
+    {
+      *line_ascent  = ascent;
+
+      handle = GlobalAlloc(GMEM_FIXED, sizeof(WINHELP_LINE) + textlen +
+			   (link ? lstrlen(link->lpszPath) + 1 : 0));
+      if (!handle) return FALSE;
+      line          = GlobalLock(handle);
+      line->next    = 0;
+      part          = &line->first_part;
+      ptr           = GlobalLock(handle);
+      ptr          += sizeof(WINHELP_LINE);
+
+      line->rect.top    = (**linep ? (**linep)->rect.bottom : 0) + space->cy;
+      line->rect.bottom = line->rect.top;
+      line->rect.left   = space->cx;
+      line->rect.right  = space->cx;
+
+      if (**linep) *linep = &(**linep)->next; 
+      **linep = line;
+      space->cy = 0;
+    }
+  else /* Same line */
+    {
+      line = **linep;
+
+      if (*line_ascent < ascent)
+	{
+	  WINHELP_LINE_PART *p;
+	  for (p = &line->first_part; p; p = p->next)
+	    {
+	      p->rect.top    += ascent - *line_ascent;
+	      p->rect.bottom += ascent - *line_ascent;
+	    }
+	  line->rect.bottom += ascent - *line_ascent;
+	  *line_ascent = ascent;
+	}
+
+      handle = GlobalAlloc(GMEM_FIXED, sizeof(WINHELP_LINE_PART) + textlen +
+			   (link ? lstrlen(link->lpszPath) + 1 : 0));
+      if (!handle) return FALSE;
+      part    = GlobalLock(handle);
+      **partp = part;
+      ptr     = GlobalLock(handle);
+      ptr    += sizeof(WINHELP_LINE_PART);
+    }
+
+  hmemcpy(ptr, text, textlen);
+  part->rect.left     = line->rect.right + (*partp ? space->cx : 0);
+  part->rect.right    = part->rect.left + textsize->cx;
+  line->rect.right    = part->rect.right;
+  part->rect.top      =
+    ((*partp) ? line->rect.top : line->rect.bottom) + *line_ascent - ascent;
+  part->rect.bottom   = part->rect.top + textsize->cy;
+  line->rect.bottom   = MAX(line->rect.bottom, part->rect.bottom);
+  part->hSelf         = handle;
+  part->lpsText       = ptr;
+  part->wTextLen      = textlen;
+  part->hFont         = font;
+  part->color         = color;
+  if (link)
+    {
+      strcpy(ptr + textlen, link->lpszPath);
+      part->link.lpszPath = ptr + textlen;
+      part->link.lHash    = link->lHash;
+      part->link.bPopup   = link->bPopup;
+    }
+  else part->link.lpszPath = 0;
+
+  part->next          = 0;
+  *partp              = &part->next;
+
+  space->cx = 0;
+
+  return TRUE;
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_CheckPopup
+ */
+
+static VOID WINHELP_CheckPopup(UINT msg)
+{
+  if (!Globals.hPopupWnd) return;
+
+  switch (msg)
+    {
+    case WM_COMMAND:
+    case WM_LBUTTONDOWN:
+    case WM_MBUTTONDOWN:
+    case WM_RBUTTONDOWN:
+    case WM_NCLBUTTONDOWN:
+    case WM_NCMBUTTONDOWN:
+    case WM_NCRBUTTONDOWN:
+      DestroyWindow(Globals.hPopupWnd);
+      Globals.hPopupWnd = 0;
+    }
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_DeleteLines
+ */
+
+static VOID WINHELP_DeleteLines(WINHELP_WINDOW *win)
+{
+  WINHELP_LINE      *line, *next_line;
+  WINHELP_LINE_PART *part, *next_part;
+  for(line = win->first_line; line; line = next_line)
+    {
+      next_line = line->next;
+      for(part = &line->first_part; part; part = next_part)
+	{
+	  next_part = part->next;
+	  GlobalFree(part->hSelf);
+	}
+    }
+  win->first_line = 0;
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_DeleteWindow
+ */
+
+static VOID WINHELP_DeleteWindow(WINHELP_WINDOW *win)
+{
+  WINHELP_WINDOW **w;
+
+  for (w = &Globals.win_list; *w; w = &(*w)->next)
+    if (*w == win)
+      {
+	*w = win->next;
+	break;
+      }
+
+  if (win->hShadowWnd) DestroyWindow(win->hShadowWnd);
+  HLPFILE_FreeHlpFilePage(win->page);
+  WINHELP_DeleteLines(win);
+  GlobalFree(win->hSelf);
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_InitFonts
+ */
+
+static VOID WINHELP_InitFonts(HWND hWnd)
+{
+  WINHELP_WINDOW *win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
+  LOGFONT logfontlist[] = {
+    {-10, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
+    {-12, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
+    {-12, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
+    {-12, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
+    {-12, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
+    {-10, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"},
+    { -8, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 32, "Helv"}};
+#define FONTS_LEN (sizeof(logfontlist)/sizeof(*logfontlist))
+
+  static HFONT fonts[FONTS_LEN][2];
+  static BOOL init = 0;
+
+  win->fonts_len = FONTS_LEN;
+  win->fonts = fonts;
+
+  if (!init)
+    {
+      INT i;
+
+      for(i = 0; i < FONTS_LEN; i++)
+	{
+	  LOGFONT logfont = logfontlist[i];
+
+	  fonts[i][0] = CreateFontIndirect(&logfont);
+	  logfont.lfUnderline = 1;
+	  fonts[i][1] = CreateFontIndirect(&logfont);
+	}
+
+      init = 1;
+    }
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_MessageBoxIDS
+ */
+
+INT WINHELP_MessageBoxIDS(UINT ids_text, UINT ids_title, WORD type)
+{
+  CHAR text[MAX_STRING_LEN];
+  CHAR title[MAX_STRING_LEN];
+
+  LoadString(Globals.hInstance, ids_text, text, sizeof(text));
+  LoadString(Globals.hInstance, ids_title, title, sizeof(title));
+
+  return(MessageBox(0, text, title, type));
+}
+
+/***********************************************************************
+ *
+ *           MAIN_MessageBoxIDS_s
+ */
+
+INT WINHELP_MessageBoxIDS_s(UINT ids_text, LPCSTR str, UINT ids_title, WORD type)
+{
+  CHAR text[MAX_STRING_LEN];
+  CHAR title[MAX_STRING_LEN];
+  CHAR newtext[MAX_STRING_LEN + MAX_PATHNAME_LEN];
+
+  LoadString(Globals.hInstance, ids_text, text, sizeof(text));
+  LoadString(Globals.hInstance, ids_title, title, sizeof(title));
+  wsprintf(newtext, text, str);
+
+  return(MessageBox(0, newtext, title, type));
+}
+
+/* Local Variables:    */
+/* c-file-style: "GNU" */
+/* End:                */
diff --git a/programs/winhelp/winhelp.h b/programs/winhelp/winhelp.h
new file mode 100644
index 0000000..debf695
--- /dev/null
+++ b/programs/winhelp/winhelp.h
@@ -0,0 +1,156 @@
+/*
+ * Help Viewer
+ *
+ * Copyright 1996 Ulrich Schmid
+ */
+
+#define MAX_LANGUAGE_NUMBER 255
+#define MAX_PATHNAME_LEN   1024
+#define MAX_STRING_LEN      255
+
+#define INTERNAL_BORDER_WIDTH  5
+#define POPUP_YDISTANCE       20
+#define SHADOW_DX     20
+#define SHADOW_DY     20
+#define BUTTON_CX      6
+#define BUTTON_CY      6
+
+#ifndef RC_INVOKED
+
+#include "hlpfile.h"
+#include "macro.h"
+
+typedef struct tagHelpLinePart
+{
+  RECT      rect;
+  LPCSTR    lpsText;
+  UINT      wTextLen;
+  HFONT     hFont;
+  COLORREF  color;
+
+  struct
+  {
+  LPCSTR    lpszPath;
+  LONG      lHash;
+  BOOL      bPopup;
+  }         link;
+
+  HGLOBAL   hSelf;
+  struct tagHelpLinePart *next;
+} WINHELP_LINE_PART;
+
+typedef struct tagHelpLine
+{
+  RECT              rect;
+  WINHELP_LINE_PART first_part;
+  struct tagHelpLine *next;
+} WINHELP_LINE;
+
+typedef struct tagHelpButton
+{
+  HWND hWnd;
+
+  LPCSTR lpszID;
+  LPCSTR lpszName;
+  LPCSTR lpszMacro;
+
+  WPARAM wParam;
+
+  RECT rect;
+
+  HGLOBAL hSelf;
+  struct tagHelpButton *next;
+} WINHELP_BUTTON;
+
+typedef struct tagWinHelp
+{
+  LPCSTR lpszName;
+
+  WINHELP_BUTTON *first_button;
+  HLPFILE_PAGE   *page;
+  WINHELP_LINE   *first_line;
+
+  HWND hMainWnd;
+  HWND hButtonBoxWnd;
+  HWND hTextWnd;
+  HWND hShadowWnd;
+
+  HFONT (*fonts)[2];
+  UINT  fonts_len;
+
+  HGLOBAL hSelf;
+  struct tagWinHelp *next;
+} WINHELP_WINDOW;
+
+typedef struct
+{
+  UINT   wVersion;
+  HANDLE hInstance;
+  HWND   hPopupWnd;
+  UINT   wStringTableOffset;
+  WINHELP_WINDOW *active_win;
+  WINHELP_WINDOW *win_list;
+} WINHELP_GLOBALS;
+
+extern WINHELP_GLOBALS Globals;
+
+VOID WINHELP_CreateHelpWindow(LPCSTR, LONG, LPCSTR, BOOL, HWND, LPPOINT, INT);
+INT  WINHELP_MessageBoxIDS(UINT, UINT, WORD);
+INT  WINHELP_MessageBoxIDS_s(UINT, LPCSTR, UINT, WORD);
+
+extern CHAR MAIN_WIN_CLASS_NAME[];
+extern CHAR BUTTON_BOX_WIN_CLASS_NAME[];
+extern CHAR TEXT_WIN_CLASS_NAME[];
+extern CHAR SHADOW_WIN_CLASS_NAME[];
+extern CHAR STRING_BUTTON[];
+extern CHAR STRING_MENU_Xx[];
+extern CHAR STRING_DIALOG_TEST[];
+
+#define STRINGID(id) (0x##id + Globals.wStringTableOffset)
+
+#else /* RC_INVOKED */
+
+#define STRINGID(id) id
+
+#endif
+
+/* Stringtable index */
+#define IDS_LANGUAGE_ID      STRINGID(00)
+#define IDS_WINE_HELP        STRINGID(01)
+#define IDS_ERROR            STRINGID(02)
+#define IDS_WARNING          STRINGID(03)
+#define IDS_INFO             STRINGID(04)
+#define IDS_NOT_IMPLEMENTED  STRINGID(05)
+#define IDS_HLPFILE_ERROR_s  STRINGID(06)
+#define IDS_CONTENTS         STRINGID(07)
+#define IDS_SEARCH           STRINGID(08)
+#define IDS_BACK             STRINGID(09)
+#define IDS_HISTORY          STRINGID(0a)
+#define IDS_ALL_FILES        STRINGID(0b)
+#define IDS_HELP_FILES_HLP   STRINGID(0c)
+
+/* Menu `File' */
+#define WH_OPEN             11
+#define WH_PRINT            12
+#define WH_PRINTER_SETUP    13
+#define WH_EXIT             14
+
+/* Menu `Edit' */
+#define WH_COPY_DIALOG      21
+#define WH_ANNOTATE         22
+
+/* Menu `Bookmark' */
+#define WH_BOOKMARK_DEFINE  31
+
+/* Menu `Help' */
+#define WH_HELP_ON_HELP     41
+#define WH_HELP_ON_TOP      42
+#define WH_ABOUT            43
+#define WH_ABOUT_WINE       44
+
+/* Buttons */
+#define WH_FIRST_BUTTON     500
+
+/* Local Variables:    */
+/* c-file-style: "GNU" */
+/* End:                */