Release 960302

Sat Mar  2 18:19:06 1996  Alexandre Julliard  <julliard@lrc.epfl.ch>

	* [controls/scroll.c]
	Fixed SCROLL_THUMB painting fixes from Alex Korobka to store the
 	current tracking window.

	* [files/file.c]
	Fixed two file descriptor leaks in FILE_OpenFile().

	* [if1632/relay32.c] [loader/module.c] [loader/pe_image.c]
	  [tools/build.c]
	Replaced LOADEDFILEINFO structure by OFSTRUCT.

	* [memory/atom.c]
	Reload the pointer to the atom table in ATOM_GetTable() and
 	ATOM_AddAtom() in case the LOCAL_Alloc() calls caused the table to
 	move in linear memory.

Fri Mar  1 11:57:13 1996  Frans van Dorsselaer <dorssel@rulhm1.leidenuniv.nl>

	* [include/callback.h]
	Added support for CallWordBreakProc().

	* [controls/edit.c]
	New caret handling (really efficient / fast).
	Implemented EM_SETWORDBREAKPROC and EM_GETWORDBREAKPROC.
	Fixed EM_SETFONT so it now also creates a proper new caret.

Wed Feb 28 22:03:34 1996  Daniel Schepler  <daniel@frobnitz.wustl.edu>

	* [controls/desktop.c] [misc/main.c] [windows/event.c] [windows/win.c]
	Added WM_DELETE protocol to top-level windows.

	* [controls/scroll.c]
	Fixed a problem which caused slow scrolling to continue	uncontrollably.

	* [misc/exec.c]
	Implemented ExitWindows().

	* [windows/win.c]
	Set top-level owned windows to be transient.

Wed Feb 28 19:13:22 1996  Ulrich Schmid  <uschmid@mail.hh.provi.de>

	* [programs/progman/*]
	Added a program manager.

Wed Feb 28 18:38:01 1996  Duncan C Thomson <duncan@spd.eee.strath.ac.uk>

	* [resources/sysres_Eo.c]
	Added support for Esperanto [Eo] language.

Wed Feb 28 00:23:00 1996  Thomas Sandford <t.d.g.sandford@prds-grn.demon.co.uk>

	* [if1632/user32.spec]
	Added EndDialog, GetDlgItem, GetDlgItemInt, SetDlgItemInt,

	* [win32/init.c]
	Added task.h to includes. GetModuleHandleA() - return hInstance
	if called with NULL parameter. Freecell needs this. NOTE this
	may indicate a problem with differentiation between hModule and
	hInstance within Wine.

	* [win32/resource.c]
	FindResource32() and LoadResource32() - Removed #if 0's around
	conversion from hInstance to hModule. See remarks above.

	* [win32/string32.c]
	WIN32_UniLen() - removed stray semicolon.

Tue Feb 27 21:05:18 1996  Jim Peterson <jspeter@birch.ee.vt.edu>
	
	* [windows/caret.c]
	Set blink rate with call to GetProfileInt().

	* [rc/winerc.c]
	In new_style(), made initial flag settings WS_CHILD | WS_VISIBLE
 	instead of 0.  This seems to correspond to Borland's defaults, and
 	the flags can be unset by using the (rather obtuse) "| NOT WS_CHILD"
	or "| NOT WS_VISIBLE" technique in the *.rc file.

	* [win32/time.c]
	In GetLocalTime() and GetSystemTime(), used tv_sec field of result
 	returned by gettimeofday() instead of making second call to
 	time().  This eliminates clock jitter if the seconds change
 	between the two calls (rare, but possible).

	* [include/wintypes.h]
	Added "#define _far" and "#define _pascal".

	* [windows/win.c]
	Added function GetDesktopHwnd().

	* [include/xmalloc.h]
	Removed the '#ifdef HAVE_STDLIB_H' structure, since it seemed to
 	have been removed from 'configure', and was causing redefinition
 	warnings.

Tue Feb 27 19:31:11 1996  Albrecht Kleine <kleine@ak.sax.de>

	* [windows/winpos.c] 
	Added RDW_ALLCHILDREN flag in SetWindowPos (handling SWP_FRAMECHANGED)
	to force a repaint when setting menu bars with different rows.

Sun Feb 25 21:15:00 1996 Alex Korobka <alex@phm30.pharm.sunysb.edu>

	* [windows/syscolors.c] [controls/scroll.c]
	Fixed DrawFocusRect pen and SCROLL_THUMB painting.
diff --git a/programs/progman/ChangeLog b/programs/progman/ChangeLog
new file mode 100644
index 0000000..7a14e2d
--- /dev/null
+++ b/programs/progman/ChangeLog
@@ -0,0 +1,6 @@
+Wed Feb 28 19:21:55 1996  Ulrich Schmid  <uschmid@mail.hh.provi.de>
+
+	* [progman.h] [main.c] [group.c] [program.c] [dialog.c]
+	[grpfile.c] [string.c] [winexec.c] [license.h] [license.c] [Xx.rc]
+	[accel.rc] [En.rc] [Strings_En.c] [License_En.c] [De.rc]
+	[Strings_De.c] Original by Ulrich Schmid
diff --git a/programs/progman/De.rc b/programs/progman/De.rc
new file mode 100644
index 0000000..9284517
--- /dev/null
+++ b/programs/progman/De.rc
@@ -0,0 +1,93 @@
+/*
+ * Program Manager
+ *
+ * Copyright 1996 Ulrich Schmid
+ */
+
+/* Menu */
+
+#define MENU_Xx                      MENU_De
+
+#define MENU_FILE                    "&Datei"
+#define MENU_FILE_NEW                "&Neu..."
+#define MENU_FILE_OPEN               "Ö&ffnen\tEingabetaste"
+#define MENU_FILE_MOVE               "&Verschieben...\tF7"
+#define MENU_FILE_COPY               "&Kopieren...\tF8"
+#define MENU_FILE_DELETE             "&Löschen\tEntf"
+#define MENU_FILE_ATTRIBUTES         "&Eigenschaften...\tAlt+Eingabetaste"
+#define MENU_FILE_EXECUTE            "&Ausführen..."
+#define MENU_FILE_EXIT               "&Programm-Manager &beenden..."
+
+#define MENU_OPTIONS                 "&Optionen"
+#define MENU_OPTIONS_AUTO_ARRANGE    "&Automatisch anordnen"
+#define MENU_OPTIONS_MIN_ON_RUN      "&Symbol nach Programmstart"
+#define MENU_OPTIONS_SAVE_SETTINGS   "&Einstellungen beim Beenden speichern"
+
+#define MENU_WINDOWS                 "&Fenster"
+#define MENU_WINDOWS_OVERLAP         "Über&lappend\tUmschalt+F5"
+#define MENU_WINDOWS_SIDE_BY_SIDE    "&Nebeneinander\tUmschalt+F4"
+#define MENU_WINDOWS_ARRANGE         "&Symbole anordnen"
+
+#define MENU_LANGUAGE                "&Sprache"
+
+#define MENU_HELP                    "&Hilfe"
+#define MENU_HELP_CONTENTS           "&Inhalt"
+#define MENU_HELP_SEARCH             "&Suchen..."
+#define MENU_HELP_HELP_ON_HELP       "&Hilfe benutzen"
+#define MENU_HELP_TUTORIAL           "&Lernprogramm"
+
+#define MENU_INFO                    "Inf&o..."
+#define MENU_INFO_LICENSE            "&Lizenz"
+#define MENU_INFO_NO_WARRANTY        "&KEINE GARANTIE"
+#define MENU_INFO_ABOUT_WINE         "&Über WINE"
+
+/* Dialogs */
+
+#define DIALOG_OK                    "OK"
+#define DIALOG_CANCEL                "Abbrechen"
+#define DIALOG_BROWSE                "&Durchsuchen..."
+#define DIALOG_HELP                  "&Hilfe"
+
+#define DIALOG_NEW_Xx                DIALOG_NEW_De
+#define DIALOG_NEW_CAPTION           "Neues Programmobject"
+#define DIALOG_NEW_NEW               "Neu"
+#define DIALOG_NEW_GROUP             "Programmgrupp&e"
+#define DIALOG_NEW_PROGRAM           "&Programm"
+
+#define DIALOG_MOVE_Xx               DIALOG_MOVE_De
+#define DIALOG_MOVE_CAPTION          "Programm verschieben"
+#define DIALOG_MOVE_PROGRAM          "Verschiebe Programm:"
+#define DIALOG_MOVE_FROM_GROUP       "Von Programmgruppe:"
+#define DIALOG_MOVE_TO_GROUP         "&In Gruppe:"
+
+#define DIALOG_COPY_Xx               DIALOG_COPY_De
+#define DIALOG_COPY_CAPTION          "Programm kopieren"
+#define DIALOG_COPY_PROGRAM          "Kopiere Programm:"
+#define DIALOG_COPY_FROM_GROUP       DIALOG_MOVE_FROM_GROUP
+#define DIALOG_COPY_TO_GROUP         DIALOG_MOVE_TO_GROUP
+
+#define DIALOG_GROUP_Xx              DIALOG_GROUP_De
+#define DIALOG_GROUP_CAPTION         "Programmgruppeneigenschaften"
+#define DIALOG_GROUP_DESCRIPTION     "&Beschreibung:"
+#define DIALOG_GROUP_FILE            "&Gruppendatei:"
+
+#define DIALOG_PROGRAM_Xx            DIALOG_PROGRAM_De
+#define DIALOG_PROGRAM_CAPTION       "Programmeigenschaften"
+#define DIALOG_PROGRAM_DESCRIPTION   DIALOG_GROUP_DESCRIPTION
+#define DIALOG_PROGRAM_COMMAND_LINE  "Befehls&zeile:"
+#define DIALOG_PROGRAM_DIRECTORY     "&Arbeitsverzeichnis:"
+#define DIALOG_PROGRAM_HOT_KEY       "&Tastenkombination:"
+#define DIALOG_PROGRAM_SYMBOL        "Als Sy&mbol"
+#define DIALOG_PROGRAM_OTHER_SYMBOL  "Anderes &Symbol..."
+
+#define DIALOG_SYMBOL_Xx             DIALOG_SYMBOL_De
+#define DIALOG_SYMBOL_CAPTION        "Symbol auswählen"
+#define DIALOG_SYMBOL_FILE           "Datei&name:"
+#define DIALOG_SYMBOL_CURRENT        "&Aktuelles Symbol:"
+
+#define DIALOG_EXECUTE_Xx            DIALOG_EXECUTE_De
+#define DIALOG_EXECUTE_CAPTION       "Programm Ausführen"
+#define DIALOG_EXECUTE_COMMAND_LINE  DIALOG_PROGRAM_COMMAND_LINE
+#define DIALOG_EXECUTE_SYMBOL        DIALOG_PROGRAM_SYMBOL
+
+#include "Xx.rc"
diff --git a/programs/progman/En.rc b/programs/progman/En.rc
new file mode 100644
index 0000000..97fb14b
--- /dev/null
+++ b/programs/progman/En.rc
@@ -0,0 +1,93 @@
+/*
+ * Program Manager
+ *
+ * Copyright 1996 Ulrich Schmid
+ */
+
+/* Menu */
+
+#define MENU_Xx                      MENU_En
+
+#define MENU_FILE                    "&File"
+#define MENU_FILE_NEW                "&New..."
+#define MENU_FILE_OPEN               "O&pen\tEnter"
+#define MENU_FILE_MOVE               "&Move...\tF7"
+#define MENU_FILE_COPY               "&Copy...\tF8"
+#define MENU_FILE_DELETE             "&Delete\tEntf"
+#define MENU_FILE_ATTRIBUTES         "&Attributes...\tAlt+Enter"
+#define MENU_FILE_EXECUTE            "&Execute..."
+#define MENU_FILE_EXIT               "E&xit Windows..."
+
+#define MENU_OPTIONS                 "&Options"
+#define MENU_OPTIONS_AUTO_ARRANGE    "&Arrange automatically"
+#define MENU_OPTIONS_MIN_ON_RUN      "&Minimize on run"
+#define MENU_OPTIONS_SAVE_SETTINGS   "&Save settings on exit"
+
+#define MENU_WINDOWS                 "&Windows"
+#define MENU_WINDOWS_OVERLAP         "&Overlapped\tShift+F5"
+#define MENU_WINDOWS_SIDE_BY_SIDE    "&Side by side\tShift+F4"
+#define MENU_WINDOWS_ARRANGE         "&Arrange Symbols"
+
+#define MENU_LANGUAGE                "&Language"
+
+#define MENU_HELP                    "&Help"
+#define MENU_HELP_CONTENTS           "&Contents"
+#define MENU_HELP_SEARCH             "&Search..."
+#define MENU_HELP_HELP_ON_HELP       "&Help on Help"
+#define MENU_HELP_TUTORIAL           "&Tutorial"
+
+#define MENU_INFO                    "&Info..."
+#define MENU_INFO_LICENSE            "&License"
+#define MENU_INFO_NO_WARRANTY        "&NO WARRANTY"
+#define MENU_INFO_ABOUT_WINE         "&About WINE"
+
+/* Dialogs */
+
+#define DIALOG_OK                    "OK"
+#define DIALOG_CANCEL                "Cancel"
+#define DIALOG_BROWSE                "&Browse"
+#define DIALOG_HELP                  "&Help"
+
+#define DIALOG_NEW_Xx                DIALOG_NEW_En
+#define DIALOG_NEW_CAPTION           "New Program Object"
+#define DIALOG_NEW_NEW               "New"
+#define DIALOG_NEW_GROUP             "Program &group"
+#define DIALOG_NEW_PROGRAM           "&Program"
+
+#define DIALOG_MOVE_Xx               DIALOG_MOVE_En
+#define DIALOG_MOVE_CAPTION          "Move Program"
+#define DIALOG_MOVE_PROGRAM          "Move program:"
+#define DIALOG_MOVE_FROM_GROUP       "From group:"
+#define DIALOG_MOVE_TO_GROUP         "&To group:"
+
+#define DIALOG_COPY_Xx               DIALOG_COPY_En
+#define DIALOG_COPY_CAPTION          "Copy Program"
+#define DIALOG_COPY_PROGRAM          "Copy program:"
+#define DIALOG_COPY_FROM_GROUP       DIALOG_MOVE_FROM_GROUP
+#define DIALOG_COPY_TO_GROUP         DIALOG_MOVE_TO_GROUP
+
+#define DIALOG_GROUP_Xx              DIALOG_GROUP_En
+#define DIALOG_GROUP_CAPTION         "Program Group Attributes"
+#define DIALOG_GROUP_DESCRIPTION     "&Description:"
+#define DIALOG_GROUP_FILE            "&Group file:"
+
+#define DIALOG_PROGRAM_Xx            DIALOG_PROGRAM_En
+#define DIALOG_PROGRAM_CAPTION       "Program Attributes"
+#define DIALOG_PROGRAM_DESCRIPTION   DIALOG_GROUP_DESCRIPTION
+#define DIALOG_PROGRAM_COMMAND_LINE  "&Command line:"
+#define DIALOG_PROGRAM_DIRECTORY     "&Working directory:"
+#define DIALOG_PROGRAM_HOT_KEY       "&Key combination:"
+#define DIALOG_PROGRAM_SYMBOL        "As &Symbol"
+#define DIALOG_PROGRAM_OTHER_SYMBOL  "&Other Symbol..."
+
+#define DIALOG_SYMBOL_Xx             DIALOG_SYMBOL_En
+#define DIALOG_SYMBOL_CAPTION        "Select Symbol"
+#define DIALOG_SYMBOL_FILE           "&Filename:"
+#define DIALOG_SYMBOL_CURRENT        "&Current Symbol:"
+
+#define DIALOG_EXECUTE_Xx            DIALOG_EXECUTE_En
+#define DIALOG_EXECUTE_CAPTION       "Execute Program"
+#define DIALOG_EXECUTE_COMMAND_LINE  DIALOG_PROGRAM_COMMAND_LINE
+#define DIALOG_EXECUTE_SYMBOL        DIALOG_PROGRAM_SYMBOL
+
+#include "Xx.rc"
diff --git a/programs/progman/License_En.c b/programs/progman/License_En.c
new file mode 100644
index 0000000..efe3437
--- /dev/null
+++ b/programs/progman/License_En.c
@@ -0,0 +1,47 @@
+#include <windows.h>
+#include "license.h"
+
+static CHAR LicenseCaption_En[] = "LICENSE";
+static CHAR License_En[] = "\
+You may without charge, royalty or other payment, copy and\
+ distribute copies of this work and derivative works of this work\
+ in source or binary form provided that: (1)\
+ you appropriately publish on each copy an appropriate copyright\
+ notice; (2) faithfully reproduce all prior copyright notices\
+ included in the original work (you may also add your own\
+ copyright notice); and (3) agree to indemnify and hold all prior\
+ authors, copyright holders and licensors of the work harmless\
+ from and against all damages arising from use of the work.\
+\n\
+You may distribute sources of derivative works of the work\
+ provided that (1) (a) all source files of the original work that\
+ have been modified, (b) all source files of the derivative work\
+ that contain any party of the original work, and (c) all source\
+ files of the derivative work that are necessary to compile, link\
+ and run the derivative work without unresolved external calls and\
+ with the same functionality of the original work (\"Necessary\
+ Sources\") carry a prominent notice explaining the nature and date\
+ of the modification and/or creation.  You are encouraged to make\
+ the Necessary Sources available under this license in order to\
+ further the development and acceptance of the work.\
+\n\
+EXCEPT AS OTHERWISE RESTRICTED BY LAW, THIS WORK IS PROVIDED\
+ WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES OF ANY KIND, INCLUDING\
+ BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF FITNESS FOR A\
+ PARTICULAR PURPOSE, MERCHANTABILITY OR TITLE.  EXCEPT AS\
+ OTHERWISE PROVIDED BY LAW, NO AUTHOR, COPYRIGHT HOLDER OR\
+ LICENSOR SHALL BE LIABLE TO YOU FOR DAMAGES OF ANY KIND, EVEN IF\
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.";
+
+static CHAR NoWarrantyCaption_En[] = "NO WARRANTY";
+static CHAR NoWarranty_En[] = "\
+EXCEPT AS OTHERWISE RESTRICTED BY LAW, THIS WORK IS PROVIDED\
+ WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES OF ANY KIND, INCLUDING\
+ BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF FITNESS FOR A\
+ PARTICULAR PURPOSE, MERCHANTABILITY OR TITLE.  EXCEPT AS\
+ OTHERWISE PROVIDED BY LAW, NO AUTHOR, COPYRIGHT HOLDER OR\
+ LICENSOR SHALL BE LIABLE TO YOU FOR DAMAGES OF ANY KIND, EVEN IF\
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.";
+
+LICENSE WineLicense_En = {License_En, LicenseCaption_En,
+			  NoWarranty_En, NoWarrantyCaption_En};
diff --git a/programs/progman/Makefile.in b/programs/progman/Makefile.in
new file mode 100644
index 0000000..32f4a44
--- /dev/null
+++ b/programs/progman/Makefile.in
@@ -0,0 +1,41 @@
+TOPSRC   = @top_srcdir@
+MODULE   = none
+PROGRAMS = progman
+ALL_LIBS = $(WINELIB) $(X_LIBS) $(XPM_LIB) $(XLIB) $(LDLIBS)
+
+LANGUAGES   = En De
+LICENSELANG = En
+
+MOSTOBJS = \
+	dialog.o \
+	group.o \
+	grpfile.o \
+	license.o \
+	main.o \
+	program.o \
+	winexec.o
+
+STRINGOBJS = \
+	accel.o \
+	string.o \
+	$(LANGUAGES:%=%.o) \
+	$(LICENSELANG:%=License_%.o) \
+	$(LANGUAGES:%=Strings_%.o) 
+
+C_SRCS = $(MOSTOBJS:.o=.c) $(STRINGOBJS:.o=.c)
+
+all: check_winerc $(PROGRAMS)
+
+@MAKE_RULES@
+
+# Some strings need addresses >= 0x10000
+progman: $(MOSTOBJS) $(STRINGOBJS)
+	$(CC) -o progman $(MOSTOBJS) $(LDOPTIONS) $(ALL_LIBS) $(STRINGOBJS)
+
+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
+
+### Dependencies:
diff --git a/programs/progman/README b/programs/progman/README
new file mode 100644
index 0000000..b145c28
--- /dev/null
+++ b/programs/progman/README
@@ -0,0 +1,16 @@
+This is a Program Manager for WINE.
+
+There is a checksum in the Microsoft `*.grp' files. I don't know how
+to calculate it. Therefore the group files written by this Program Manager
+cannot be used with the Microsoft Program Manager!!
+
+To prevent overwriting original files:
+If there is an existing `*.grp' file this program uses the extension
+`.gr' instead.
+
+It's possible to use an alternate `progman.ini' file by adding to
+`wine.conf' something like:
+[progman]
+progman.ini=/my/wine/path/progman.ini
+
+It's possible to start both Windows and UNIX programs.
diff --git a/programs/progman/Strings_De.c b/programs/progman/Strings_De.c
new file mode 100644
index 0000000..de3d369
--- /dev/null
+++ b/programs/progman/Strings_De.c
@@ -0,0 +1,34 @@
+#include <windows.h>
+#include "progman.h"
+
+LPCSTR StringTableDe[NUMBER_OF_STRINGS] =
+{
+  "Programm-Manager",
+  "FEHLER",
+  "Information",
+  "Löschen",
+  "Lösche Programmgruppe `%s' ?",
+  "Lösche Programm `%s' ?",
+  "Nicht implementiert",
+  "Fehler beim Lesen von `%s'",
+  "Fehler beim Schreiben von `%s'",
+
+  "Die Programmgruppendatei `%s' kann nicht geöffnet werden.\n"
+  "Soll weiterhin versucht werden, diese Datei zu laden?",
+
+  "Zu wenig Hauptspeicher",
+  "Keine Hilfe verfügbar",
+  "Unbekannte Eigenschaft der `.grp' Datei",
+  "Datei `%s' existiert. Sie wird nicht überschrieben.",
+  "Die Programmgruppe wird als `%s' gesichert um das Überschreiben der Originaldatei zu verhindern.",
+  "Keine",
+
+  "Alle Dateien (*.*)\0"   "*.*\0"
+  "Programme\0"            "*.exe;*.pif;*.com;*.bat\0",
+
+  "Alle Dateien (*.*)\0"   "*.*\0"
+  "Bibliotheken (*.dll)\0" "*.dll\0"
+  "Programme\0"            "*.exe\0"
+  "Symboldateien\0"        "*.ico;*.exe;*.dll\0"
+  "Symbole (*.ico)\0"      "*.ico\0"
+};
diff --git a/programs/progman/Strings_En.c b/programs/progman/Strings_En.c
new file mode 100644
index 0000000..da3f19d
--- /dev/null
+++ b/programs/progman/Strings_En.c
@@ -0,0 +1,34 @@
+#include <windows.h>
+#include "progman.h"
+
+LPCSTR StringTableEn[NUMBER_OF_STRINGS] =
+{
+  "Program Manager",
+  "ERROR",
+  "Information",
+  "Delete",
+  "Delete group `%s' ?",
+  "Delete program `%s' ?",
+  "Not implemented",
+  "Error reading `%s'",
+  "Error writeing `%s'",
+
+  "The group file `%s' cannot be opened.\n"
+  "Should it be tried further on?",
+
+  "Out of memory",
+  "Help not available",
+  "Unknown feature in `.grp' file",
+  "File `%s' exists. Not overwritten.",
+  "Save group as `%s' to prevent overwriting original files",
+  "None",
+
+  "All files (*.*)\0"   "*.*\0"
+  "Programs\0"          "*.exe;*.pif;*.com;*.bat\0",
+
+  "All files (*.*)\0"   "*.*\0"
+  "Libraries (*.dll)\0" "*.dll\0"
+  "Programs\0"          "*.exe\0"
+  "Symbol files\0"      "*.ico;*.exe;*.dll\0"
+  "Symbols (*.ico)\0"   "*.ico\0"
+};
diff --git a/programs/progman/TODO b/programs/progman/TODO
new file mode 100644
index 0000000..c3685a2
--- /dev/null
+++ b/programs/progman/TODO
@@ -0,0 +1,6 @@
+* Microsoft `*.grp' files use a checksum.
+  Find out how to calculate it.
+
+* Accelerators
+
+* Create some icons
diff --git a/programs/progman/Xx.rc b/programs/progman/Xx.rc
new file mode 100644
index 0000000..44d7991
--- /dev/null
+++ b/programs/progman/Xx.rc
@@ -0,0 +1,174 @@
+/*
+ * Program Manager
+ *
+ * Copyright 1996 Ulrich Schmid
+ */
+
+#include "progman.h"
+
+/* Menu */
+
+MENU_Xx MENU
+{
+ POPUP MENU_FILE {
+   MENUITEM MENU_FILE_NEW,              PM_NEW 
+   MENUITEM MENU_FILE_OPEN,             PM_OPEN
+   MENUITEM MENU_FILE_MOVE,             PM_MOVE,      GRAYED
+   MENUITEM MENU_FILE_COPY,             PM_COPY,      GRAYED
+   MENUITEM MENU_FILE_DELETE,           PM_DELETE
+   MENUITEM MENU_FILE_ATTRIBUTES,       PM_ATTRIBUTES
+   MENUITEM SEPARATOR   
+   MENUITEM MENU_FILE_EXECUTE,          PM_EXECUTE
+   MENUITEM SEPARATOR   
+   MENUITEM MENU_FILE_EXIT,             PM_EXIT
+ }
+ POPUP MENU_OPTIONS {
+   MENUITEM MENU_OPTIONS_AUTO_ARRANGE,  PM_AUTO_ARRANGE
+   MENUITEM MENU_OPTIONS_MIN_ON_RUN,    PM_MIN_ON_RUN
+   MENUITEM MENU_OPTIONS_SAVE_SETTINGS, PM_SAVE_SETTINGS
+ }
+ POPUP MENU_WINDOWS {
+   MENUITEM MENU_WINDOWS_OVERLAP,       PM_OVERLAP
+   MENUITEM MENU_WINDOWS_SIDE_BY_SIDE,  PM_SIDE_BY_SIDE
+   MENUITEM MENU_WINDOWS_ARRANGE,       PM_ARRANGE
+ }
+ POPUP MENU_LANGUAGE {
+   MENUITEM "&English",                 PM_En
+   MENUITEM "&Deutsch",                 PM_De
+ }
+ POPUP MENU_HELP {
+   MENUITEM MENU_HELP_CONTENTS,         PM_CONTENTS
+   MENUITEM MENU_HELP_SEARCH,           PM_SEARCH
+   MENUITEM SEPARATOR   
+   MENUITEM MENU_HELP_HELP_ON_HELP,     PM_HELPONHELP
+   MENUITEM MENU_HELP_TUTORIAL,         PM_TUTORIAL
+   MENUITEM SEPARATOR   
+
+   POPUP MENU_INFO {
+     MENUITEM MENU_INFO_LICENSE,        PM_LICENSE
+     MENUITEM MENU_INFO_NO_WARRANTY,    PM_NO_WARRANTY
+     MENUITEM MENU_INFO_ABOUT_WINE,     PM_ABOUT_WINE
+   }
+ }
+}
+
+/* Dialog `New' */
+
+DIALOG_NEW_Xx DIALOG 0, 0, 170, 65
+STYLE DS_MODALFRAME
+CAPTION DIALOG_NEW_CAPTION
+{
+RADIOBUTTON   "",                 PM_NEW_GROUP,    10, 15,  10, 15
+LTEXT         DIALOG_NEW_GROUP,   PM_NEW_GROUP,    20, 18,  80, 15
+RADIOBUTTON   "",                 PM_NEW_PROGRAM,  10, 35,  10, 15
+LTEXT         DIALOG_NEW_PROGRAM, PM_NEW_PROGRAM,  20, 38,  80, 15
+DEFPUSHBUTTON DIALOG_OK,          IDOK,           105,  5,  60, 15
+PUSHBUTTON    DIALOG_CANCEL,      IDCANCEL,       105, 25,  60, 15
+PUSHBUTTON    DIALOG_HELP,        PM_HELP,        105, 45,  60, 15
+}
+
+/* Dialog `Move' */
+
+DIALOG_MOVE_Xx DIALOG 0, 0, 250, 65
+STYLE DS_MODALFRAME
+CAPTION DIALOG_MOVE_CAPTION
+{
+LTEXT         DIALOG_MOVE_PROGRAM,    IDIGNORE,            5,  5,  90, 15
+LTEXT         "",                     PM_PROGRAM,         95,  5,  90, 15
+LTEXT         DIALOG_MOVE_FROM_GROUP, IDIGNORE,            5, 13,  90, 15
+LTEXT         "",                     PM_FROM_GROUP,      95, 13,  90, 15
+LTEXT         DIALOG_MOVE_TO_GROUP,   PM_TO_GROUP_TXT,     5, 28, 140, 15
+COMBOBOX                              PM_TO_GROUP,         5, 38, 140, 50, CBS_DROPDOWNLIST
+DEFPUSHBUTTON DIALOG_OK,              IDOK,              185,  5,  60, 15
+PUSHBUTTON    DIALOG_CANCEL,          IDCANCEL,          185, 25,  60, 15
+PUSHBUTTON    DIALOG_HELP,            PM_HELP,           185, 45,  60, 15
+}
+
+/* Dialog `Copy' */
+
+DIALOG_COPY_Xx DIALOG 0, 0, 250, 65
+STYLE DS_MODALFRAME
+CAPTION DIALOG_COPY_CAPTION
+{
+LTEXT         DIALOG_COPY_PROGRAM,    IDIGNORE,            5,  5,  90, 15
+LTEXT         "",                     PM_PROGRAM,         95,  5,  90, 15
+LTEXT         DIALOG_COPY_FROM_GROUP, IDIGNORE,            5, 13,  90, 15
+LTEXT         "",                     PM_FROM_GROUP,      95, 13,  90, 15
+LTEXT         DIALOG_COPY_TO_GROUP,   PM_TO_GROUP_TXT,     5, 28, 140, 15
+COMBOBOX                              PM_TO_GROUP,         5, 38, 140, 50, CBS_DROPDOWNLIST
+DEFPUSHBUTTON DIALOG_OK,              IDOK,              185,  5,  60, 15
+PUSHBUTTON    DIALOG_CANCEL,          IDCANCEL,          185, 25,  60, 15
+PUSHBUTTON    DIALOG_HELP,            PM_HELP,           185, 45,  60, 15
+}
+
+/* Dialog `Group attributes' */
+
+DIALOG_GROUP_Xx DIALOG 0, 0, 230, 65
+STYLE DS_MODALFRAME
+CAPTION DIALOG_GROUP_CAPTION
+{
+LTEXT     DIALOG_GROUP_DESCRIPTION, PM_DESCRIPTION_TXT,   05, 18,  50, 10
+EDITTEXT                            PM_DESCRIPTION,       60, 18,  90, 15
+LTEXT     DIALOG_GROUP_FILE,        PM_FILE_TXT,          05, 38,  50, 10
+EDITTEXT                            PM_FILE,              60, 38,  90, 15
+DEFPUSHBUTTON DIALOG_OK,            IDOK,                155,  5,  60, 15
+PUSHBUTTON    DIALOG_CANCEL,        IDCANCEL,            155, 25,  60, 15
+PUSHBUTTON    DIALOG_HELP,          PM_HELP,             155, 45,  60, 15
+}
+
+/* Dialog `Program attributes' */
+
+DIALOG_PROGRAM_Xx DIALOG 0, 0, 250, 105
+STYLE DS_MODALFRAME
+CAPTION DIALOG_PROGRAM_CAPTION
+{
+LTEXT         DIALOG_PROGRAM_DESCRIPTION,  PM_DESCRIPTION_TXT,   05, 10,  60, 10
+EDITTEXT                                   PM_DESCRIPTION,       80, 10,  90, 15
+LTEXT         DIALOG_PROGRAM_COMMAND_LINE, PM_COMMAND_LINE_TXT,  05, 25,  60, 10
+EDITTEXT                                   PM_COMMAND_LINE,      80, 25,  90, 15
+LTEXT         DIALOG_PROGRAM_DIRECTORY,    PM_DIRECTORY_TXT,     05, 40,  60, 10
+EDITTEXT                                   PM_DIRECTORY,         80, 40,  90, 15
+LTEXT         DIALOG_PROGRAM_HOT_KEY,      PM_HOT_KEY_TXT,       05, 55,  60, 10
+EDITTEXT                                   PM_HOT_KEY,           80, 55,  90, 15
+ICON          "",                          PM_ICON,              20, 70
+CHECKBOX      "",                          PM_SYMBOL,            80, 75,  10, 10
+LTEXT         DIALOG_PROGRAM_SYMBOL,       IDIGNORE,             95, 75,  75, 10
+DEFPUSHBUTTON DIALOG_OK,                   IDOK,                185,  5,  60, 15
+PUSHBUTTON    DIALOG_CANCEL,               IDCANCEL,            185, 25,  60, 15
+PUSHBUTTON    DIALOG_BROWSE,               PM_BROWSE,           185, 45,  60, 15
+PUSHBUTTON    DIALOG_PROGRAM_OTHER_SYMBOL, PM_OTHER_SYMBOL,     185, 65,  60, 15
+PUSHBUTTON    DIALOG_HELP,                 PM_HELP,             185, 85,  60, 15
+}
+
+/* Dialog `Symbol' */
+
+DIALOG_SYMBOL_Xx DIALOG 0, 0, 200, 85
+STYLE DS_MODALFRAME
+CAPTION DIALOG_SYMBOL_CAPTION
+{
+LTEXT     DIALOG_SYMBOL_FILE,    PM_ICON_FILE_TXT,    5, 15,  40, 10
+EDITTEXT                         PM_ICON_FILE,       45, 15,  85, 15
+LTEXT     DIALOG_SYMBOL_CURRENT, PM_SYMBOL_LIST_TXT,  5, 30, 125, 10
+COMBOBOX                         PM_SYMBOL_LIST,      5, 40, 125, 50,
+   CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | CBS_OWNERDRAWFIXED
+DEFPUSHBUTTON DIALOG_OK,         IDOK,              135,  5,  60, 15
+PUSHBUTTON    DIALOG_CANCEL,     IDCANCEL,          135, 25,  60, 15
+PUSHBUTTON    DIALOG_BROWSE ,    PM_BROWSE,         135, 45,  60, 15
+PUSHBUTTON    DIALOG_HELP,       PM_HELP,           135, 65,  60, 15
+}
+
+/* Dialog `Execute' */
+
+DIALOG_EXECUTE_Xx DIALOG 0, 0, 200, 85
+STYLE DS_MODALFRAME
+CAPTION DIALOG_EXECUTE_CAPTION
+{
+LTEXT     DIALOG_EXECUTE_COMMAND_LINE, IDIGNORE,   05, 15, 120, 10
+EDITTEXT                               PM_COMMAND, 05, 25, 120, 15
+CHECKBOX      "",                      PM_SYMBOL,  05, 45,  10, 10
+LTEXT         DIALOG_EXECUTE_SYMBOL,   IDIGNORE,   20, 45, 120, 10
+DEFPUSHBUTTON DIALOG_OK,               IDOK,      135,  5,  60, 15
+PUSHBUTTON    DIALOG_CANCEL,           IDCANCEL,  135, 25,  60, 15
+PUSHBUTTON    DIALOG_BROWSE ,          PM_BROWSE, 135, 45,  60, 15
+PUSHBUTTON    DIALOG_HELP,             PM_HELP,   135, 65,  60, 15
+}
diff --git a/programs/progman/accel.rc b/programs/progman/accel.rc
new file mode 100644
index 0000000..3409682
--- /dev/null
+++ b/programs/progman/accel.rc
@@ -0,0 +1,6 @@
+#include "progman.h"
+
+ACCEL ACCELERATORS
+{
+VK_RETURN, PM_EXECUTE, VIRTKEY, ALT
+}
diff --git a/programs/progman/dialog.c b/programs/progman/dialog.c
new file mode 100644
index 0000000..c19ca83
--- /dev/null
+++ b/programs/progman/dialog.c
@@ -0,0 +1,569 @@
+/*
+ * Program Manager
+ *
+ * Copyright 1996 Ulrich Schmid
+ */
+
+#include <windows.h>
+#include <commdlg.h>
+#include "progman.h"
+
+static BOOL DIALOG_Browse(HWND, LPCSTR, LPSTR, INT);
+static LRESULT DIALOG_NEW_DlgProc(HWND, UINT, WPARAM, LPARAM);
+static LRESULT DIALOG_COPY_MOVE_DlgProc(HWND, UINT, WPARAM, LPARAM);
+static LRESULT DIALOG_GROUP_DlgProc(HWND, UINT, WPARAM, LPARAM);
+static LRESULT DIALOG_PROGRAM_DlgProc(HWND, UINT, WPARAM, LPARAM);
+static LRESULT DIALOG_SYMBOL_DlgProc(HWND, UINT, WPARAM, LPARAM);
+static LRESULT DIALOG_EXECUTE_DlgProc(HWND, UINT, WPARAM, LPARAM);
+
+/***********************************************************************
+ *
+ *           DIALOG_New
+ */
+
+static struct
+{
+  INT nDefault;
+} New;
+
+INT DIALOG_New(INT nDefault)
+{
+  WNDPROC lpfnDlg = MakeProcInstance(DIALOG_NEW_DlgProc, Globals.hInstance);
+  INT ret;
+
+  New.nDefault = nDefault;
+
+  ret = DialogBox(Globals.hInstance,  STRING_NEW_Xx,
+		  Globals.hMainWnd, lpfnDlg);
+  FreeProcInstance(lpfnDlg);
+  return ret;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *           DIALOG_NEW_DlgProc
+ */
+
+static LRESULT DIALOG_NEW_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+  switch (msg)
+    {
+    case WM_INITDIALOG:
+      CheckRadioButton(hDlg, PM_NEW_GROUP, PM_NEW_PROGRAM, New.nDefault);
+      break;
+
+    case WM_COMMAND:
+      switch (wParam)
+	{
+	case PM_NEW_GROUP:
+	case PM_NEW_PROGRAM:
+	  CheckRadioButton(hDlg, PM_NEW_GROUP, PM_NEW_PROGRAM, wParam);
+	  return TRUE;
+
+	case IDOK:
+	  EndDialog(hDlg, IsDlgButtonChecked(hDlg, PM_NEW_GROUP) ?
+		    PM_NEW_GROUP : PM_NEW_PROGRAM);
+	  return TRUE;
+
+	case IDCANCEL:
+	  EndDialog(hDlg, IDCANCEL);
+	  return TRUE;
+	}
+    }
+  return FALSE;
+}
+
+/***********************************************************************
+ *
+ *           DIALOG_CopyMove
+ */
+
+static struct
+{
+  LPCSTR lpszProgramName, lpszFromGroupName;
+  HLOCAL hToGroup;
+} CopyMove;
+
+HLOCAL DIALOG_CopyMove(LPCSTR lpszProgramName, LPCSTR lpszFromGroupName,
+		     BOOL bMove)
+{
+  WNDPROC lpfnDlg = MakeProcInstance(DIALOG_COPY_MOVE_DlgProc, Globals.hInstance);
+  INT ret;
+
+  CopyMove.lpszProgramName   = lpszProgramName;
+  CopyMove.lpszFromGroupName = lpszFromGroupName;
+  CopyMove.hToGroup          = 0;
+
+  ret = DialogBox(Globals.hInstance,
+		  bMove ? STRING_MOVE_Xx : STRING_COPY_Xx,
+		  Globals.hMainWnd, lpfnDlg);
+  FreeProcInstance(lpfnDlg);
+
+  return((ret == IDOK) ? CopyMove.hToGroup : 0);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *           DIALOG_COPY_MOVE_DlgProc
+ */
+
+static LRESULT DIALOG_COPY_MOVE_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+  HLOCAL hGroup;
+
+  switch (msg)
+    {
+    case WM_INITDIALOG:
+      /* List all group names */
+      for (hGroup = GROUP_FirstGroup(); hGroup; hGroup = GROUP_NextGroup(hGroup))
+	SendDlgItemMessage(hDlg, PM_TO_GROUP, CB_ADDSTRING, 0,
+			   (LPARAM) GROUP_GroupName(hGroup));
+
+      SetDlgItemText(hDlg, PM_PROGRAM,    (LPSTR)CopyMove.lpszProgramName);
+      SetDlgItemText(hDlg, PM_FROM_GROUP, (LPSTR)CopyMove.lpszFromGroupName);
+      break;
+
+    case WM_COMMAND:
+      switch (wParam)
+	{
+	case IDOK:
+	{
+	  /* Get selected group */
+	  INT nCurSel    = SendDlgItemMessage(hDlg, PM_TO_GROUP, CB_GETCURSEL, 0, 0);
+	  INT nLen       = SendDlgItemMessage(hDlg, PM_TO_GROUP, CB_GETLBTEXTLEN, nCurSel, 0);
+	  HLOCAL hBuffer = LocalAlloc(LMEM_FIXED, nLen + 1);
+	  LPSTR   buffer = LocalLock(hBuffer);
+
+	  SendDlgItemMessage(hDlg, PM_TO_GROUP, CB_GETLBTEXT, nCurSel, (LPARAM)buffer);
+	  for (hGroup = GROUP_FirstGroup(); hGroup; hGroup = GROUP_NextGroup(hGroup))
+	    if (!lstrcmp(buffer, GROUP_GroupName(hGroup))) break;
+	  LocalFree(hBuffer);
+
+	  CopyMove.hToGroup = hGroup;
+	  EndDialog(hDlg, IDOK);
+	  return TRUE;
+	}
+
+	case IDCANCEL:
+	  EndDialog(hDlg, IDCANCEL);
+	  return TRUE;
+	}
+    }
+  return FALSE;
+}
+
+/***********************************************************************
+ *
+ *           DIALOG_Delete
+ */
+
+BOOL DIALOG_Delete(LPCSTR lpszFormat_s, LPCSTR lpszName)
+{
+  CHAR msg[1000];
+  if (sizeof(msg) <= lstrlen(lpszFormat_s) + lstrlen(lpszName)) return FALSE;
+  wsprintf(msg, (LPSTR)lpszFormat_s, lpszName);
+  return (IDYES == MessageBox(Globals.hMainWnd, msg, STRING_DELETE,
+			      MB_YESNO | MB_DEFBUTTON2));
+}
+
+
+/***********************************************************************
+ *
+ *           DIALOG_GroupAttributes
+ */
+
+static struct
+{
+  LPSTR lpszTitle, lpszGrpFile;
+  INT   nSize;
+} GroupAttributes;
+
+BOOL DIALOG_GroupAttributes(LPSTR lpszTitle, LPSTR lpszGrpFile, INT nSize)
+{
+  WNDPROC lpfnDlg = MakeProcInstance(DIALOG_GROUP_DlgProc, Globals.hInstance);
+  INT ret;
+
+  GroupAttributes.nSize       = nSize;
+  GroupAttributes.lpszTitle   = lpszTitle;
+  GroupAttributes.lpszGrpFile = lpszGrpFile;
+
+  ret = DialogBox(Globals.hInstance,  STRING_GROUP_Xx,
+		  Globals.hMainWnd, lpfnDlg);
+  FreeProcInstance(lpfnDlg);
+  return(ret == IDOK);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *           DIALOG_GROUP_DlgProc
+ */
+
+static LRESULT DIALOG_GROUP_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+  switch (msg)
+    {
+    case WM_INITDIALOG:
+      SetDlgItemText(hDlg, PM_DESCRIPTION, GroupAttributes.lpszTitle);
+      SetDlgItemText(hDlg, PM_FILE, GroupAttributes.lpszGrpFile);
+      break;
+
+    case WM_COMMAND:
+      switch (wParam)
+	{
+	case IDOK:
+	  GetDlgItemText(hDlg, PM_DESCRIPTION, GroupAttributes.lpszTitle,
+			 GroupAttributes.nSize);
+	  GetDlgItemText(hDlg, PM_FILE, GroupAttributes.lpszGrpFile,
+			 GroupAttributes.nSize);
+	  EndDialog(hDlg, IDOK);
+	  return TRUE;
+
+	case IDCANCEL:
+	  EndDialog(hDlg, IDCANCEL);
+	  return TRUE;
+	}
+    }
+  return FALSE;
+}
+
+/***********************************************************************
+ *
+ *           DIALOG_ProgramAttributes
+ */
+
+static struct
+{
+  LPSTR lpszTitle, lpszCmdLine, lpszWorkDir, lpszIconFile, lpszTmpIconFile;
+  INT   nSize;
+  INT   *lpnCmdShow;
+  INT   *lpnHotKey;
+  HWND  hSelGroupWnd;
+  HICON *lphIcon, hTmpIcon;
+  INT   *lpnIconIndex, nTmpIconIndex;
+} ProgramAttributes;
+
+BOOL DIALOG_ProgramAttributes(LPSTR lpszTitle, LPSTR lpszCmdLine,
+			      LPSTR lpszWorkDir, LPSTR lpszIconFile,
+			      HICON *lphIcon, INT *lpnIconIndex,
+			      INT *lpnHotKey, INT *lpnCmdShow, INT nSize)
+{
+  CHAR szTmpIconFile[MAX_PATHNAME_LEN];
+  WNDPROC lpfnDlg = MakeProcInstance(DIALOG_PROGRAM_DlgProc, Globals.hInstance);
+  INT ret;
+
+  ProgramAttributes.nSize = nSize;
+  ProgramAttributes.lpszTitle = lpszTitle;
+  ProgramAttributes.lpszCmdLine = lpszCmdLine;
+  ProgramAttributes.lpszWorkDir = lpszWorkDir;
+  ProgramAttributes.lpszIconFile = lpszIconFile;
+  ProgramAttributes.lpnCmdShow = lpnCmdShow;
+  ProgramAttributes.lpnHotKey = lpnHotKey;
+  ProgramAttributes.lphIcon = lphIcon;
+  ProgramAttributes.lpnIconIndex = lpnIconIndex;
+
+#if 0
+  ProgramAttributes.hTmpIcon = 0;
+#else
+  ProgramAttributes.hTmpIcon = *lphIcon;
+#endif
+  ProgramAttributes.nTmpIconIndex = *lpnIconIndex;
+  ProgramAttributes.lpszTmpIconFile = szTmpIconFile;
+  lstrcpyn(ProgramAttributes.lpszTmpIconFile, lpszIconFile, MAX_PATHNAME_LEN);
+
+  ret = DialogBox(Globals.hInstance,  STRING_PROGRAM_Xx,
+		  Globals.hMainWnd, lpfnDlg);
+  FreeProcInstance(lpfnDlg);
+
+  return(ret == IDOK);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *           DIALOG_PROGRAM_DlgProc
+ */
+
+static LRESULT DIALOG_PROGRAM_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+  switch (msg)
+    {
+    case WM_INITDIALOG:
+      SetDlgItemText(hDlg, PM_DESCRIPTION, ProgramAttributes.lpszTitle);
+      SetDlgItemText(hDlg, PM_COMMAND_LINE, ProgramAttributes.lpszCmdLine);
+      SetDlgItemText(hDlg, PM_DIRECTORY, ProgramAttributes.lpszWorkDir);
+      if (!*ProgramAttributes.lpnHotKey)
+	SetDlgItemText(hDlg, PM_HOT_KEY, (LPSTR)STRING_NO_HOT_KEY);
+
+      CheckDlgButton(hDlg, PM_SYMBOL,
+		     (*ProgramAttributes.lpnCmdShow == SW_SHOWMINIMIZED));
+      SendDlgItemMessage(hDlg, PM_ICON, STM_SETICON,
+			 (WPARAM) ProgramAttributes.hTmpIcon, 0);
+      break;
+
+    case WM_COMMAND:
+      switch (wParam)
+	{
+	case PM_SYMBOL:
+	  CheckDlgButton(hDlg, PM_SYMBOL, !IsDlgButtonChecked(hDlg, PM_SYMBOL));
+	  return TRUE;
+
+	case PM_BROWSE:
+	  {
+	    CHAR filename[MAX_PATHNAME_LEN];
+	    if (DIALOG_Browse(hDlg, STRING_BROWSE_EXE_FILTER,
+			      filename, sizeof(filename)))
+	      SetDlgItemText(hDlg, PM_COMMAND_LINE, filename);
+	    return TRUE;
+	  }
+
+	case PM_OTHER_SYMBOL:
+	  {
+	    DIALOG_Symbol(&ProgramAttributes.hTmpIcon,
+			  ProgramAttributes.lpszTmpIconFile,
+			  &ProgramAttributes.nTmpIconIndex,
+			  MAX_PATHNAME_LEN);
+
+	    SendDlgItemMessage(hDlg, PM_ICON, STM_SETICON,
+			       (WPARAM) ProgramAttributes.hTmpIcon, 0);
+	    return TRUE;
+	  }
+
+	case IDOK:
+	  GetDlgItemText(hDlg, PM_DESCRIPTION,
+			 ProgramAttributes.lpszTitle,
+			 ProgramAttributes.nSize);
+	  GetDlgItemText(hDlg, PM_COMMAND_LINE,
+			 ProgramAttributes.lpszCmdLine,
+			 ProgramAttributes.nSize);
+	  GetDlgItemText(hDlg, PM_DIRECTORY,
+			 ProgramAttributes.lpszWorkDir,
+			 ProgramAttributes.nSize);
+
+	  if (ProgramAttributes.hTmpIcon)
+	    {
+#if 0
+	      if (*ProgramAttributes.lphIcon)
+		DestroyIcon(*ProgramAttributes.lphIcon);
+#endif
+	      *ProgramAttributes.lphIcon = ProgramAttributes.hTmpIcon;
+	      *ProgramAttributes.lpnIconIndex = ProgramAttributes.nTmpIconIndex;
+	      lstrcpyn(ProgramAttributes.lpszIconFile,
+		       ProgramAttributes.lpszTmpIconFile,
+		       ProgramAttributes.nSize);
+	    }
+
+	  *ProgramAttributes.lpnCmdShow =
+	    IsDlgButtonChecked(hDlg, PM_SYMBOL) ?
+	    SW_SHOWMINIMIZED : SW_SHOWNORMAL;
+	  EndDialog(hDlg, IDOK);
+	  return TRUE;
+
+	case IDCANCEL:
+	  EndDialog(hDlg, IDCANCEL);
+	  return TRUE;
+	}
+      return FALSE;
+    }
+  return FALSE;
+}
+
+/***********************************************************************
+ *
+ *           DIALOG_Symbol
+ */
+
+static struct
+{
+  LPSTR  lpszIconFile;
+  INT    nSize;
+  HICON  *lphIcon;
+  INT    *lpnIconIndex;
+} Symbol;
+
+VOID DIALOG_Symbol(HICON *lphIcon, LPSTR lpszIconFile,
+		   INT *lpnIconIndex, INT nSize)
+{
+  WNDPROC lpfnDlg = MakeProcInstance(DIALOG_SYMBOL_DlgProc, Globals.hInstance);
+
+  Symbol.nSize = nSize;
+  Symbol.lpszIconFile = lpszIconFile;
+  Symbol.lphIcon = lphIcon;
+  Symbol.lpnIconIndex = lpnIconIndex;
+
+  DialogBox(Globals.hInstance, STRING_SYMBOL_Xx,
+	    Globals.hMainWnd, lpfnDlg);
+  FreeProcInstance(lpfnDlg);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *           DIALOG_SYMBOL_DlgProc
+ */
+
+static LRESULT DIALOG_SYMBOL_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+  switch (msg)
+    {
+    case WM_INITDIALOG:
+      SetDlgItemText(hDlg, PM_ICON_FILE, Symbol.lpszIconFile);
+      SendDlgItemMessage(hDlg, PM_SYMBOL_LIST, CB_SETITEMHEIGHT, 0, (LPARAM) 32);
+      SendDlgItemMessage(hDlg, PM_SYMBOL_LIST, CB_ADDSTRING, 0, (LPARAM)*Symbol.lphIcon);
+      SendDlgItemMessage(hDlg, PM_SYMBOL_LIST, CB_ADDSTRING, 0, (LPARAM)Globals.hDefaultIcon);
+      SendDlgItemMessage(hDlg, PM_SYMBOL_LIST, CB_SETCURSEL, 0, 0);
+      return TRUE;
+
+    case WM_MEASUREITEM:
+      {
+	PMEASUREITEMSTRUCT measure = (PMEASUREITEMSTRUCT) lParam;
+	measure->itemWidth = 32;
+	measure->itemHeight = 32;
+	return TRUE;
+      }
+
+    case WM_DRAWITEM:
+      {
+	PDRAWITEMSTRUCT dis = (PDRAWITEMSTRUCT) lParam;
+	DrawIcon(dis->hDC, dis->rcItem.left, dis->rcItem.top, (HICON)dis->itemData);
+	return TRUE;
+      }
+
+    case WM_COMMAND:
+      switch (wParam)
+	{
+	case PM_BROWSE:
+	  {
+	    CHAR filename[MAX_PATHNAME_LEN];
+	    if (DIALOG_Browse(hDlg, STRING_BROWSE_ICO_FILTER,
+			      filename, sizeof(filename)))
+	      SetDlgItemText(hDlg, PM_ICON_FILE, filename);
+	    return TRUE;
+	  }
+
+	case PM_HELP:
+	  MAIN_NotImplementedError();
+	  return TRUE;
+
+	case IDOK:
+	  {
+	    INT nCurSel = SendDlgItemMessage(hDlg, PM_SYMBOL_LIST, CB_GETCURSEL, 0, 0);
+
+	    GetDlgItemText(hDlg, PM_ICON_FILE, Symbol.lpszIconFile, Symbol.nSize);
+
+	    *Symbol.lphIcon = (HICON)SendDlgItemMessage(hDlg, PM_SYMBOL_LIST,
+							CB_GETITEMDATA,
+							(WPARAM) nCurSel, 0);
+#if 0
+	    *Symbol.lphIcon = CopyIcon(*Symbol.lphIcon);
+#endif
+
+	    EndDialog(hDlg, IDOK);
+	    return TRUE;
+	  }
+
+	case IDCANCEL:
+	  EndDialog(hDlg, IDCANCEL);
+	  return TRUE;
+	}
+    }
+  return FALSE;
+}
+
+/***********************************************************************
+ *
+ *           DIALOG_Execute
+ */
+
+VOID DIALOG_Execute()
+{
+  WNDPROC lpfnDlg = MakeProcInstance(DIALOG_EXECUTE_DlgProc, Globals.hInstance);
+  DialogBox(Globals.hInstance, STRING_EXECUTE_Xx,
+	    Globals.hMainWnd, lpfnDlg);
+  FreeProcInstance(lpfnDlg);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *           DIALOG_EXECUTE_DlgProc
+ */
+
+static LRESULT DIALOG_EXECUTE_DlgProc(HWND hDlg, UINT msg,
+				      WPARAM wParam, LPARAM lParam)
+{
+  switch (msg)
+    {
+    case WM_COMMAND:
+      switch (wParam)
+	{
+	case PM_SYMBOL:
+	  CheckDlgButton(hDlg, PM_SYMBOL, !IsDlgButtonChecked(hDlg, PM_SYMBOL));
+	  return TRUE;
+
+	case PM_BROWSE:
+	  {
+	    CHAR filename[MAX_PATHNAME_LEN];
+	    if (DIALOG_Browse(hDlg, STRING_BROWSE_EXE_FILTER,
+			      filename, sizeof(filename)))
+	      SetDlgItemText(hDlg, PM_COMMAND, filename);
+	    return TRUE;
+	  }
+
+	case PM_HELP:
+	  MAIN_NotImplementedError();
+	  return TRUE;
+
+	case IDOK:
+	  {
+	    CHAR cmdline[MAX_PATHNAME_LEN];
+	    GetDlgItemText(hDlg, PM_COMMAND, cmdline, sizeof(cmdline));
+
+	    WinExec(cmdline, IsDlgButtonChecked(hDlg, PM_SYMBOL) ?
+		    SW_SHOWMINIMIZED : SW_SHOWNORMAL);
+	    if (Globals.bMinOnRun) CloseWindow(Globals.hMainWnd);
+
+	    EndDialog(hDlg, IDOK);
+	    return TRUE;
+	  }
+
+	case IDCANCEL:
+	  EndDialog(hDlg, IDCANCEL);
+	  return TRUE;
+	}
+    }
+  return FALSE;
+}
+
+/***********************************************************************
+ *
+ *           DIALOG_Browse
+ */
+
+/* FIXME is this correct ? */
+static BOOL DIALOG_Browse(HWND hDlg, LPCSTR lpcstrFilter,
+			  LPSTR lpstrFile, INT nMaxFile)
+{
+  OPENFILENAME openfilename;
+  openfilename.lStructSize       = 0;
+  openfilename.hwndOwner         = hDlg;
+  openfilename.hInstance         = Globals.hInstance;
+  openfilename.lpstrFilter       = (LPSTR)lpcstrFilter;
+  openfilename.lpstrCustomFilter = 0;
+  openfilename.nMaxCustFilter    = 0;
+  openfilename.nFilterIndex      = 0;
+  openfilename.lpstrFile         = lpstrFile;
+  openfilename.nMaxFile          = sizeof(lpstrFile);
+  openfilename.lpstrFileTitle    = 0;
+  openfilename.nMaxFileTitle     = 0;
+  openfilename.lpstrInitialDir   = 0;
+  openfilename.lpstrTitle        = 0;
+  openfilename.Flags             = 0;
+  openfilename.nFileOffset       = 0;
+  openfilename.nFileExtension    = 0;
+  openfilename.lpstrDefExt       = 0;
+  openfilename.lCustData         = 0;
+  openfilename.lpfnHook          = 0;
+  openfilename.lpTemplateName    = 0;
+  return GetOpenFileName(&openfilename);
+}
+
+/* Local Variables:    */
+/* c-file-style: "GNU" */
+/* End:                */
diff --git a/programs/progman/group.c b/programs/progman/group.c
new file mode 100644
index 0000000..0646f8f
--- /dev/null
+++ b/programs/progman/group.c
@@ -0,0 +1,313 @@
+/*
+ * Program Manager
+ *
+ * Copyright 1996 Ulrich Schmid
+ */
+
+#include <stdio.h>
+#include <windows.h>
+#include "progman.h"
+
+/***********************************************************************
+ *
+ *           GROUP_GroupWndProc
+ */
+
+static LRESULT GROUP_GroupWndProc (HWND hWnd, UINT msg,
+				   WPARAM wParam, LPARAM lParam)
+{
+#if 0
+  printf("G %4.4x %4.4x\n", msg, wParam);
+#endif
+  switch (msg)
+    {
+    case WM_SYSCOMMAND:
+      if (wParam == SC_CLOSE) wParam = SC_MINIMIZE;
+      break;
+
+    case WM_CHILDACTIVATE:
+    case WM_NCLBUTTONDOWN:
+      Globals.hActiveGroup = (HLOCAL) GetWindowLong(hWnd, 0);
+      EnableMenuItem(Globals.hFileMenu, PM_MOVE , MF_GRAYED);
+      EnableMenuItem(Globals.hFileMenu, PM_COPY , MF_GRAYED);
+      break;
+    }
+  return(DefMDIChildProc(hWnd, msg, wParam, lParam));
+}
+
+/***********************************************************************
+ *
+ *           GROUP_RegisterGroupWinClass
+ */
+
+ATOM GROUP_RegisterGroupWinClass()
+{
+  WNDCLASS class;
+
+  class.style         = CS_HREDRAW | CS_VREDRAW;
+  class.lpfnWndProc   = GROUP_GroupWndProc;
+  class.cbClsExtra    = 0;
+  class.cbWndExtra    = sizeof(LONG);
+  class.hInstance     = Globals.hInstance;
+  class.hIcon         = LoadIcon (0, MAKEINTRESOURCE(OIC_WINEICON));
+  class.hCursor       = LoadCursor (0, IDC_ARROW);
+  class.hbrBackground = GetStockObject (WHITE_BRUSH);
+  class.lpszMenuName  = 0;
+  class.lpszClassName = STRING_GROUP_WIN_CLASS_NAME;
+
+  return RegisterClass(&class);
+}
+
+/***********************************************************************
+ *
+ *           GROUP_NewGroup
+ */
+
+VOID GROUP_NewGroup()
+{
+  CHAR szName[MAX_PATHNAME_LEN] = "";
+  CHAR szFile[MAX_PATHNAME_LEN] = "";
+  OFSTRUCT dummy;
+
+  if (!DIALOG_GroupAttributes(szName, szFile, MAX_PATHNAME_LEN)) return;
+
+  if (OpenFile(szFile, &dummy, OF_EXIST) == HFILE_ERROR)
+    {
+      /* File doesn't exist */
+      HLOCAL hGroup =
+	GROUP_AddGroup(szName, szFile, SW_SHOWNORMAL,
+		       DEF_GROUP_WIN_XPOS, DEF_GROUP_WIN_YPOS,
+		       DEF_GROUP_WIN_WIDTH, DEF_GROUP_WIN_HEIGHT, 0, 0,
+		       FALSE, FALSE, FALSE);
+      if (!hGroup) return;
+      GRPFILE_WriteGroupFile(hGroup);
+    }
+  else /* File exist */
+    GRPFILE_ReadGroupFile(szFile);
+
+  /* FIXME Update progman.ini */
+}
+
+/***********************************************************************
+ *
+ *           GROUP_AddGroup
+ */
+
+HLOCAL GROUP_AddGroup(LPCSTR lpszName, LPCSTR lpszGrpFile, INT nCmdShow,
+		      INT x, INT y, INT width, INT height,
+		      INT iconx, INT icony,
+		      BOOL bFileNameModified, BOOL bOverwriteFileOk,
+		      /* FIXME shouldn't be necessary */
+		      BOOL bSuppressShowWindow)
+{
+  GROUP *group, *prior;
+  MDICREATESTRUCT cs;
+  INT    seqnum;
+  HLOCAL hPrior, *p;
+  HLOCAL hGroup   = LocalAlloc(LMEM_FIXED, sizeof(GROUP));
+  HLOCAL hName    = LocalAlloc(LMEM_FIXED, 1 + lstrlen(lpszName));
+  HLOCAL hGrpFile = LocalAlloc(LMEM_FIXED, 1 + lstrlen(lpszGrpFile));
+  if (!hGroup || !hName || !hGrpFile)
+    {
+      MessageBox(Globals.hMainWnd, "out of memory", lpszName, MB_OK);
+      if (hGroup)   LocalFree(hGroup);
+      if (hName)    LocalFree(hName);
+      if (hGrpFile) LocalFree(hGrpFile);
+      return(0);
+    }
+  hmemcpy(LocalLock(hName), lpszName, 1 + lstrlen(lpszName));
+  hmemcpy(LocalLock(hGrpFile), lpszGrpFile, 1 + lstrlen(lpszGrpFile));
+
+  Globals.hActiveGroup   = hGroup;
+
+  seqnum = 1;
+  hPrior = 0;
+  p = &Globals.hGroups;
+  while (*p)
+    {
+      hPrior = *p;
+      prior  = LocalLock(hPrior);
+      p      = &prior->hNext;
+      if (prior->seqnum >= seqnum)
+	seqnum = prior->seqnum + 1;
+    }
+  *p = hGroup;
+
+  group = LocalLock(hGroup);
+  group->hPrior    = hPrior;
+  group->hNext     = 0;
+  group->hName     = hName;
+  group->hGrpFile  = hGrpFile;
+  group->bFileNameModified = bFileNameModified;
+  group->bOverwriteFileOk  = bOverwriteFileOk;
+  group->seqnum    = seqnum;
+  group->nCmdShow  = nCmdShow;
+  group->x         = x;
+  group->y         = y;
+  group->width     = width;
+  group->height    = height;
+  group->iconx     = iconx;
+  group->icony     = icony;
+  group->hPrograms = 0;
+  group->hActiveProgram = 0;
+
+  cs.szClass = STRING_GROUP_WIN_CLASS_NAME;
+  cs.szTitle = (LPSTR)lpszName;
+  cs.hOwner  = 0;
+  cs.x       = x;
+  cs.y       = y;
+  cs.cx      = width;
+  cs.cy      = height;
+  cs.style   = 0;
+  cs.lParam  = 0;
+
+  group->hWnd = (HWND)SendMessage(Globals.hMDIWnd, WM_MDICREATE, 0, (LPARAM)&cs);
+
+  SetWindowLong(group->hWnd, 0, (LONG) hGroup);
+
+#if 1
+  if (!bSuppressShowWindow) /* FIXME shouldn't be necessary */
+#endif
+    {
+      ShowWindow (group->hWnd, nCmdShow);
+      UpdateWindow (group->hWnd);
+    }
+
+  return(hGroup);
+}
+
+/***********************************************************************
+ *
+ *           GROUP_ModifyGroup
+ */
+
+VOID GROUP_ModifyGroup(HLOCAL hGroup)
+{
+  GROUP *group = LocalLock(hGroup);
+  CHAR szName[MAX_PATHNAME_LEN];
+  CHAR szFile[MAX_PATHNAME_LEN];
+  lstrcpyn(szName, LocalLock(group->hName), MAX_PATHNAME_LEN);
+  lstrcpyn(szFile, LocalLock(group->hGrpFile), MAX_PATHNAME_LEN);
+
+  if (!DIALOG_GroupAttributes(szName, szFile, MAX_PATHNAME_LEN)) return;
+
+  if (strcmp(szFile, LocalLock(group->hGrpFile)))
+    group->bOverwriteFileOk = FALSE;
+
+  MAIN_ReplaceString(&group->hName,    szName);
+  MAIN_ReplaceString(&group->hGrpFile, szFile);
+
+  GRPFILE_WriteGroupFile(hGroup);
+
+  /* FIXME Delete old GrpFile if GrpFile changed */
+
+  /* FIXME Update progman.ini */
+
+  SetWindowText(group->hWnd, szName);
+}
+
+/***********************************************************************
+ *
+ *           GROUP_ShowGroupWindow
+ */
+
+/* FIXME shouldn't be necessary */
+VOID GROUP_ShowGroupWindow(HLOCAL hGroup)
+{
+  GROUP *group = LocalLock(hGroup);
+  ShowWindow (group->hWnd, group->nCmdShow);
+  UpdateWindow (group->hWnd);
+}
+
+/***********************************************************************
+ *
+ *           GROUP_DeleteGroup
+ */
+
+VOID GROUP_DeleteGroup(HLOCAL hGroup)
+{
+  GROUP *group = LocalLock(hGroup);
+
+  Globals.hActiveGroup = 0;
+
+  if (group->hPrior)
+    ((GROUP*)LocalLock(group->hPrior))->hNext = group->hNext;
+  else Globals.hGroups = group->hNext;
+
+  if (group->hNext)
+    ((GROUP*)LocalLock(group->hNext))->hPrior = group->hPrior;
+
+  while (group->hPrograms)
+    PROGRAM_DeleteProgram(group->hPrograms, FALSE);
+
+  /* FIXME Update progman.ini */
+
+  SendMessage(Globals.hMDIWnd, WM_MDIDESTROY, (WPARAM)group->hWnd, 0);
+
+  LocalFree(group->hName);
+  LocalFree(group->hGrpFile);
+  LocalFree(hGroup);
+}
+
+/***********************************************************************
+ *
+ *           GROUP_FirstGroup
+ */
+
+HLOCAL GROUP_FirstGroup()
+{
+  return(Globals.hGroups);
+}
+
+/***********************************************************************
+ *
+ *           GROUP_NextGroup
+ */
+
+HLOCAL GROUP_NextGroup(HLOCAL hGroup)
+{
+  GROUP *group;
+  if (!hGroup) return(0);
+  group = LocalLock(hGroup);
+  return(group->hNext);
+}
+
+/***********************************************************************
+ *
+ *           GROUP_ActiveGroup
+ */
+
+HLOCAL GROUP_ActiveGroup()
+{
+  return(Globals.hActiveGroup);
+}
+
+/***********************************************************************
+ *
+ *           GROUP_GroupWnd
+ */
+
+HWND GROUP_GroupWnd(HLOCAL hGroup)
+{
+  GROUP *group;
+  if (!hGroup) return(0);
+  group = LocalLock(hGroup);
+  return(group->hWnd);
+}
+
+/***********************************************************************
+ *
+ *           GROUP_GroupName
+ */
+
+LPCSTR GROUP_GroupName(HLOCAL hGroup)
+{
+  GROUP *group;
+  if (!hGroup) return(0);
+  group = LocalLock(hGroup);
+  return(LocalLock(group->hName));
+}
+
+/* Local Variables:    */
+/* c-file-style: "GNU" */
+/* End:                */
diff --git a/programs/progman/grpfile.c b/programs/progman/grpfile.c
new file mode 100644
index 0000000..50e99ec
--- /dev/null
+++ b/programs/progman/grpfile.c
@@ -0,0 +1,645 @@
+/*
+ * Program Manager
+ *
+ * Copyright 1996 Ulrich Schmid
+ */
+
+#include <windows.h>
+#include "progman.h"
+
+#define MALLOCHUNK 1000
+
+#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 PUT_SHORT(buffer, i, s)\
+  (((buffer)[(i)] = (s) & 0xff, (buffer)[(i)+1] = ((s) >> 8) & 0xff))
+
+static BOOL   GRPFILE_ReadFileToBuffer(LPCSTR, HLOCAL*, INT*);
+static HLOCAL GRPFILE_ScanGroup(LPCSTR, INT, LPCSTR, BOOL);
+static HLOCAL GRPFILE_ScanProgram(LPCSTR, INT, LPCSTR, INT,
+				  LPCSTR, HLOCAL,LPCSTR);
+static BOOL GRPFILE_DoWriteGroupFile(HFILE file, GROUP *group);
+
+/***********************************************************************
+ *
+ *           GRPFILE_ModifyFileName
+ *
+ *  Change extension `.grp' to `.gr'
+ */
+
+static VOID GRPFILE_ModifyFileName(LPSTR lpszNewName, LPCSTR lpszOrigName,
+				   INT nSize, BOOL bModify)
+{
+  lstrcpyn(lpszNewName, lpszOrigName, nSize);
+  lpszNewName[nSize-1] = '\0';
+  if (!bModify) return;
+  if (!lstrcmpi(lpszNewName + strlen(lpszNewName) - 4, ".grp"))
+    lpszNewName[strlen(lpszNewName) - 1] = '\0';
+}
+
+/***********************************************************************
+ *
+ *           GRPFILE_ReadGroupFile
+ */
+
+HLOCAL GRPFILE_ReadGroupFile(LPCSTR lpszPath)
+{
+  CHAR   szPath_gr[MAX_PATHNAME_LEN];
+  BOOL   bFileNameModified = FALSE;
+  OFSTRUCT dummy;
+  HLOCAL hBuffer, hGroup;
+  INT    size;
+
+  /* if `.gr' file exists use that */
+  GRPFILE_ModifyFileName(szPath_gr, lpszPath, MAX_PATHNAME_LEN, TRUE);
+  if (OpenFile(szPath_gr, &dummy, OF_EXIST) != HFILE_ERROR)
+    {
+      lpszPath = szPath_gr;
+      bFileNameModified = TRUE;
+    }
+
+  /* Read the whole file into a buffer */
+  if (!GRPFILE_ReadFileToBuffer(lpszPath, &hBuffer, &size))
+    {
+      MAIN_GrpFileReadError(lpszPath);
+      return(0);
+    }
+
+  /* Interpret buffer */
+  hGroup = GRPFILE_ScanGroup(LocalLock(hBuffer), size,
+			     lpszPath, bFileNameModified);
+  if (!hGroup) MAIN_GrpFileReadError(lpszPath);
+
+  LocalFree(hBuffer);
+
+  return(hGroup);
+}
+
+/***********************************************************************
+ *
+ *           GRPFILE_ReadFileToBuffer
+ */
+
+static BOOL GRPFILE_ReadFileToBuffer(LPCSTR path, HLOCAL *phBuffer,
+				     INT *piSize)
+{
+  INT    len, size;
+  LPSTR  buffer;
+  HLOCAL hBuffer, hNewBuffer;
+  HFILE  file;
+
+  file=_lopen(path, OF_READ);
+  if (file == HFILE_ERROR) return FALSE;
+
+  size = 0;
+  hBuffer = LocalAlloc(LMEM_FIXED, size + MALLOCHUNK + 1);
+  if (!hBuffer) return FALSE;
+  buffer = LocalLock(hBuffer);
+
+  while ((len = _lread(file, buffer + size, MALLOCHUNK))
+	 == MALLOCHUNK)
+    {
+      size += len;
+      hNewBuffer = LocalReAlloc(hBuffer, size + MALLOCHUNK + 1,
+				LMEM_FIXED);
+      if (!hNewBuffer)
+	{
+	  LocalFree(hBuffer);
+	  return FALSE;
+	}
+      hBuffer = hNewBuffer;
+      buffer = LocalLock(hBuffer);
+    }
+
+  _lclose(file);
+
+  if (len == HFILE_ERROR)
+    {
+      LocalFree(hBuffer);
+      return FALSE;
+    }
+
+  size += len;
+  buffer[size] = 0;
+
+  *phBuffer = hBuffer;
+  *piSize   = size;
+  return TRUE;
+}
+
+/***********************************************************************
+ *           GRPFILE_ScanGroup
+ */
+
+static HLOCAL GRPFILE_ScanGroup(LPCSTR buffer, INT size,
+				LPCSTR lpszGrpFile,
+				BOOL bModifiedFileName)
+{
+  HLOCAL  hGroup;
+  INT     i, seqnum;
+  LPCSTR  extension;
+  LPCSTR  lpszName;
+  INT     x, y, width, height, iconx, icony, nCmdShow;
+  INT     number_of_programs;
+  BOOL    bOverwriteFileOk;
+
+  if (buffer[0] != 'P' || buffer[1] != 'M') return(0);
+  if (buffer[2] == 'C' && buffer[3] == 'C')
+    /* original with checksum */
+    bOverwriteFileOk = FALSE;
+  else if (buffer[2] == 'X' && buffer[3] == 'X')
+    /* modified without checksum */
+    bOverwriteFileOk = TRUE;
+  else return(0);
+
+  /* checksum = GET_USHORT(buffer, 4)   (ignored) */
+
+  extension = buffer + GET_USHORT(buffer, 6);
+  if (extension == buffer + size) extension = 0;
+  else if (extension + 6 > buffer + size) return(0);
+
+  nCmdShow = GET_USHORT(buffer,  8);
+  x        = GET_SHORT(buffer,  10);
+  y        = GET_SHORT(buffer,  12);
+  width    = GET_USHORT(buffer, 14);
+  height   = GET_USHORT(buffer, 16);
+  iconx    = GET_SHORT(buffer,  18);
+  icony    = GET_SHORT(buffer,  20);
+  lpszName = buffer + GET_USHORT(buffer, 22);
+  if (lpszName >= buffer + size) return(0);
+
+  /* unknown bytes 24 - 31 ignored */ 
+
+  hGroup = GROUP_AddGroup(lpszName, lpszGrpFile, nCmdShow, x, y,
+			  width, height, iconx, icony,
+			  bModifiedFileName, bOverwriteFileOk,
+			  TRUE);
+  if (!hGroup) return(0);
+
+  number_of_programs = GET_USHORT(buffer, 32);
+  if (2 * number_of_programs + 34 > size) return(0);
+  for (i=0, seqnum=0; i < number_of_programs; i++, seqnum++)
+    {
+      LPCSTR program_ptr = buffer + GET_USHORT(buffer, 34 + 2*i);
+      if (program_ptr + 24 > buffer + size) return(0);
+      if (!GET_USHORT(buffer, 34 + 2*i)) continue;
+      if (!GRPFILE_ScanProgram(buffer, size, program_ptr, seqnum,
+			       extension, hGroup, lpszGrpFile))
+	{
+	  GROUP_DeleteGroup(hGroup);
+	  return(0);
+	}
+    }
+
+  /* FIXME shouldn't be necessary */
+  GROUP_ShowGroupWindow(hGroup);
+
+  return hGroup;
+}
+
+/***********************************************************************
+ *           GRPFILE_ScanProgram
+ */
+
+static HLOCAL GRPFILE_ScanProgram(LPCSTR buffer, INT size,
+				  LPCSTR program_ptr, INT seqnum,
+				  LPCSTR extension, HLOCAL hGroup,
+				  LPCSTR lpszGrpFile)
+{
+  INT    icontype;
+  HICON  hIcon;
+  LPCSTR lpszName, lpszCmdLine, lpszIconFile, lpszWorkDir;
+  LPCSTR iconinfo_ptr, iconANDbits_ptr, iconXORbits_ptr;
+  INT    x, y, nIconIndex, iconANDsize, iconXORsize;
+  INT    nHotKey, nCmdShow;
+  CURSORICONINFO iconinfo;
+
+  x               = GET_SHORT(program_ptr, 0);
+  y               = GET_SHORT(program_ptr, 2);
+  nIconIndex      = GET_USHORT(program_ptr, 4);
+
+  /* FIXME is this correct ?? */
+  icontype = GET_USHORT(program_ptr,  6);
+  switch (icontype)
+    {
+    default:
+      MessageBox(Globals.hMainWnd, STRING_UNKNOWN_FEATURE_IN_GRPFILE,
+		 lpszGrpFile, MB_OK);
+    case 0x048c:
+      iconXORsize     = GET_USHORT(program_ptr,  8);
+      iconANDsize     = GET_USHORT(program_ptr, 10) / 8;
+      iconinfo_ptr    = buffer + GET_USHORT(program_ptr, 12);
+      iconXORbits_ptr = buffer + GET_USHORT(program_ptr, 14);
+      iconANDbits_ptr = buffer + GET_USHORT(program_ptr, 16);
+      iconinfo.ptHotSpot.x   = GET_USHORT(iconinfo_ptr, 0);
+      iconinfo.ptHotSpot.y   = GET_USHORT(iconinfo_ptr, 2);
+      iconinfo.nWidth        = GET_USHORT(iconinfo_ptr, 4);
+      iconinfo.nHeight       = GET_USHORT(iconinfo_ptr, 6);
+      iconinfo.nWidthBytes   = GET_USHORT(iconinfo_ptr, 8);
+      iconinfo.bPlanes       = GET_USHORT(iconinfo_ptr, 10);
+      iconinfo.bBitsPerPixel = GET_USHORT(iconinfo_ptr, 11);
+      break;
+    case 0x000c:
+      iconANDsize     = GET_USHORT(program_ptr,  8);
+      iconXORsize     = GET_USHORT(program_ptr, 10);
+      iconinfo_ptr    = buffer + GET_USHORT(program_ptr, 12);
+      iconANDbits_ptr = buffer + GET_USHORT(program_ptr, 14);
+      iconXORbits_ptr = buffer + GET_USHORT(program_ptr, 16);
+      iconinfo.ptHotSpot.x   = GET_USHORT(iconinfo_ptr, 0);
+      iconinfo.ptHotSpot.y   = GET_USHORT(iconinfo_ptr, 2);
+      iconinfo.nWidth        = GET_USHORT(iconinfo_ptr, 4);
+      iconinfo.nHeight       = GET_USHORT(iconinfo_ptr, 6);
+      iconinfo.nWidthBytes = GET_USHORT(iconinfo_ptr, 8) * 8;
+      iconinfo.bPlanes       = GET_USHORT(iconinfo_ptr, 10);
+      iconinfo.bBitsPerPixel = GET_USHORT(iconinfo_ptr, 11);
+    }
+
+  if (iconANDbits_ptr + iconANDsize > buffer + size ||
+      iconXORbits_ptr + iconXORsize > buffer + size) return(0);
+
+  hIcon = CreateCursorIconIndirect(Globals.hInstance, &iconinfo,
+				   (LPSTR)iconANDbits_ptr,
+				   (LPSTR)iconXORbits_ptr);
+
+  lpszName        = buffer + GET_USHORT(program_ptr, 18);
+  lpszCmdLine     = buffer + GET_USHORT(program_ptr, 20);
+  lpszIconFile    = buffer + GET_USHORT(program_ptr, 22);
+  if (iconinfo_ptr + 6 > buffer + size ||
+      lpszName         > buffer + size ||
+      lpszCmdLine      > buffer + size ||
+      lpszIconFile     > buffer + size) return(0);
+
+  /* Scan Extensions */
+  lpszWorkDir = "";
+  nHotKey     = 0;
+  nCmdShow    = SW_SHOWNORMAL;
+  if (extension)
+    {
+      LPCSTR ptr = extension;
+      while (ptr + 6 <= buffer + size)
+	{
+	  UINT type   = GET_USHORT(ptr, 0);
+	  UINT number = GET_USHORT(ptr, 2);
+	  UINT skip   = GET_USHORT(ptr, 4);
+
+	  if (number == seqnum)
+	    {
+	      switch (type)
+		{
+		case 0x8000:
+		  if (ptr + 10 > buffer + size) return(0);
+		  if (ptr[6] != 'P' || ptr[7] != 'M' ||
+		      ptr[8] != 'C' || ptr[9] != 'C') return(0);
+		  break;
+		case 0x8101:
+		  lpszWorkDir = ptr + 6;
+		  break;
+		case 0x8102:
+		  if (ptr + 8 > buffer + size) return(0);
+		  nHotKey = GET_USHORT(ptr, 6);
+		  break;
+		case 0x8103:
+		  if (ptr + 8 > buffer + size) return(0);
+		  nCmdShow = GET_USHORT(ptr, 6);
+		  break;
+		default:
+		  MessageBox(Globals.hMainWnd,
+			     STRING_UNKNOWN_FEATURE_IN_GRPFILE,
+			     lpszGrpFile, MB_OK);
+		}
+	    }
+	  if (!skip) break;
+	  ptr += skip;
+	}
+    }
+
+  return (PROGRAM_AddProgram(hGroup, hIcon, lpszName, x, y,
+			     lpszCmdLine, lpszIconFile,
+			     nIconIndex, lpszWorkDir,
+			     nHotKey, nCmdShow));
+}
+
+/***********************************************************************
+ *
+ *           GRPFILE_WriteGroupFile
+ */
+
+BOOL GRPFILE_WriteGroupFile(HLOCAL hGroup)
+{
+  CHAR szPath[MAX_PATHNAME_LEN];
+  GROUP *group = LocalLock(hGroup);
+  OFSTRUCT dummy;
+  HFILE file;
+  BOOL ret;
+
+  GRPFILE_ModifyFileName(szPath, LocalLock(group->hGrpFile),
+			 MAX_PATHNAME_LEN,
+			 group->bFileNameModified);
+
+  /* Try not to overwrite original files */
+
+  /* group->bOverwriteFileOk == TRUE only if a file has the modified format */
+  if (!group->bOverwriteFileOk &&
+      OpenFile(szPath, &dummy, OF_EXIST) != HFILE_ERROR)
+    {
+      CHAR msg[MAX_PATHNAME_LEN + 1000];
+
+      /* Original file exists, try `.gr' extension */
+      GRPFILE_ModifyFileName(szPath, LocalLock(group->hGrpFile),
+			     MAX_PATHNAME_LEN, TRUE);
+      if (OpenFile(szPath, &dummy, OF_EXIST) != HFILE_ERROR)
+	{
+	  /* File exists. Do not overwrite */
+	  if (sizeof(msg) <= lstrlen(STRING_FILE_NOT_OVERWRITTEN_s) + lstrlen(szPath))
+	    return FALSE;
+	  wsprintf(msg, (LPSTR)STRING_FILE_NOT_OVERWRITTEN_s, szPath);
+	  MessageBox(Globals.hMainWnd, msg, STRING_ERROR, MB_OK);
+	  return FALSE;
+	}
+      /* Inform about the modified file name */
+      if (sizeof(msg) <= lstrlen(STRING_SAVE_GROUP_AS_s) + lstrlen(szPath))
+	return FALSE;
+      wsprintf(msg, (LPSTR)STRING_SAVE_GROUP_AS_s, szPath);
+      if (IDCANCEL == MessageBox(Globals.hMainWnd, msg, STRING_INFO,
+				 MB_OKCANCEL | MB_ICONINFORMATION))
+	return FALSE;
+    }
+
+  {
+    /* Warn about the incompatibility */
+    CHAR msg[MAX_PATHNAME_LEN + 200];
+    wsprintf(msg,
+	     "Group files written by this DRAFT Program Manager "
+	     "cannot be read by the Microsoft Program Manager!!\n"
+	     "Are you sure to write %s?", szPath);
+    if (IDOK != MessageBox(Globals.hMainWnd, msg, "WARNING",
+			   MB_OKCANCEL | MB_DEFBUTTON2)) return FALSE;
+  }
+
+  /* FIXME */
+  if (OpenFile(szPath, &dummy, OF_EXIST) == HFILE_ERROR)
+    {
+      CHAR msg[MAX_PATHNAME_LEN + 200];
+      wsprintf(msg, "Cause of a bug you must now touch the file %s\n", szPath);
+      MessageBox(Globals.hMainWnd, msg, "", MB_OK);
+    }
+
+  /* Open file */
+  file = _lopen(szPath, OF_WRITE);
+  if (file != HFILE_ERROR)
+    {
+      ret = GRPFILE_DoWriteGroupFile(file, group);
+      _lclose(file);
+    }
+  else ret = FALSE;
+
+  if (!ret) MAIN_FileWriteError(szPath);
+
+  return(ret);
+}
+
+/***********************************************************************
+ *
+ *           GRPFILE_CalculateSizes
+ */
+
+static VOID GRPFILE_CalculateSizes(PROGRAM *program,
+				   INT *Progs, INT *Icons)
+{
+  CURSORICONINFO *iconinfo = LocalLock(program->hIcon);
+  INT sizeXor = iconinfo->nHeight * iconinfo->nWidthBytes;
+  INT sizeAnd = iconinfo->nHeight * ((iconinfo->nWidth + 15) / 16 * 2);
+
+  *Progs += 24;
+  *Progs += lstrlen(LocalLock(program->hName)) + 1;
+  *Progs += lstrlen(LocalLock(program->hCmdLine)) + 1;
+  *Progs += lstrlen(LocalLock(program->hIconFile)) + 1;
+
+  *Icons += 12; /* IconInfo */
+  *Icons += sizeAnd;
+  *Icons += sizeXor;
+}
+
+/***********************************************************************
+ *
+ *           GRPFILE_DoWriteGroupFile
+ */
+
+static BOOL GRPFILE_DoWriteGroupFile(HFILE file, GROUP *group)
+{
+  BYTE buffer[34];
+  HLOCAL hProgram;
+  INT    NumProg, Title, Progs, Icons, Extension;
+  INT    CurrProg, CurrIcon, nCmdShow, ptr, seqnum;
+  BOOL   need_extension;
+  LPCSTR lpszTitle = LocalLock(group->hName);
+
+  /* Calculate offsets */
+  NumProg = 0;
+  Icons   = 0;
+  Extension = 0;
+  need_extension = FALSE;
+  hProgram = group->hPrograms;
+  while(hProgram)
+    {
+      PROGRAM *program = LocalLock(hProgram);
+      LPCSTR lpszWorkDir = LocalLock(program->hWorkDir);
+
+      NumProg++;
+      GRPFILE_CalculateSizes(program, &Icons, &Extension);
+
+      /* Set a flag if an extension is needed */
+      if (lpszWorkDir[0] || program->nHotKey ||
+	  program->nCmdShow != SW_SHOWNORMAL) need_extension = TRUE;
+
+      hProgram = program->hNext;
+    }
+  Title      = 34 + NumProg * 2;
+  Progs      = Title + lstrlen(lpszTitle) + 1;
+  Icons     += Progs;
+  Extension += Icons;
+
+  /* Header */
+  buffer[0] = 'P';
+  buffer[1] = 'M';
+#if 0
+  buffer[2] = 'C'; /* Original magic number */
+  buffer[3] = 'C';
+#else
+  buffer[2] = 'X'; /* Modified magic number: no checksum */
+  buffer[3] = 'X';
+#endif
+  PUT_SHORT(buffer,  4, 0); /* Checksum ignored */
+  PUT_SHORT(buffer,  6, Extension);
+  /* Update group->nCmdShow */
+  if (IsIconic(group->hWnd))      nCmdShow = SW_SHOWMINIMIZED;
+  else if (IsZoomed(group->hWnd)) nCmdShow = SW_SHOWMAXIMIZED;
+  else                            nCmdShow = SW_SHOWNORMAL;
+  PUT_SHORT(buffer,  8, nCmdShow);
+  PUT_SHORT(buffer, 10, group->x);
+  PUT_SHORT(buffer, 12, group->y);
+  PUT_SHORT(buffer, 14, group->width);
+  PUT_SHORT(buffer, 16, group->height);
+  PUT_SHORT(buffer, 18, group->iconx);
+  PUT_SHORT(buffer, 20, group->icony);
+  PUT_SHORT(buffer, 22, Title);
+  PUT_SHORT(buffer, 24, 0x0020); /* unknown */
+  PUT_SHORT(buffer, 26, 0x0020); /* unknown */
+  PUT_SHORT(buffer, 28, 0x0108); /* unknown */
+  PUT_SHORT(buffer, 30, 0x0000); /* unknown */
+  PUT_SHORT(buffer, 32, NumProg);
+
+  if (HFILE_ERROR == _lwrite(file, buffer, 34)) return FALSE;
+
+  /* Program table */
+  CurrProg = Progs;
+  CurrIcon = Icons;
+  hProgram = group->hPrograms;
+  while(hProgram)
+    {
+      PROGRAM *program = LocalLock(hProgram);
+
+      PUT_SHORT(buffer, 0, CurrProg);
+      if (HFILE_ERROR == _lwrite(file, buffer, 2)) return FALSE;
+
+      GRPFILE_CalculateSizes(program, &CurrProg, &CurrIcon);
+      hProgram = program->hNext;
+    }
+
+  /* Title */
+  if (HFILE_ERROR == _lwrite(file, lpszTitle, lstrlen(lpszTitle) + 1))
+    return FALSE;
+
+  /* Program entries */
+  CurrProg = Progs;
+  CurrIcon = Icons;
+  hProgram = group->hPrograms;
+  while(hProgram)
+    {
+      PROGRAM *program = LocalLock(hProgram);
+      CURSORICONINFO *iconinfo = LocalLock(program->hIcon);
+      LPCSTR Name     = LocalLock(program->hName);
+      LPCSTR CmdLine  = LocalLock(program->hCmdLine);
+      LPCSTR IconFile = LocalLock(program->hIconFile);
+      INT sizeXor = iconinfo->nHeight * iconinfo->nWidthBytes;
+      INT sizeAnd = iconinfo->nHeight * ((iconinfo->nWidth + 15) / 16 * 2);
+
+      PUT_SHORT(buffer,  0, program->x);
+      PUT_SHORT(buffer,  2, program->y);
+      PUT_SHORT(buffer,  4, program->nIconIndex);
+      PUT_SHORT(buffer,  6, 0x048c);            /* unknown */
+      PUT_SHORT(buffer,  8, sizeXor);
+      PUT_SHORT(buffer, 10, sizeAnd * 8);
+      PUT_SHORT(buffer, 12, CurrIcon);
+      PUT_SHORT(buffer, 14, CurrIcon + 12 + sizeAnd);
+      PUT_SHORT(buffer, 16, CurrIcon + 12);
+      ptr = CurrProg + 24;
+      PUT_SHORT(buffer, 18, ptr);
+      ptr += lstrlen(Name) + 1;
+      PUT_SHORT(buffer, 20, ptr);
+      ptr += lstrlen(CmdLine) + 1;
+      PUT_SHORT(buffer, 22, ptr);
+
+      if (HFILE_ERROR == _lwrite(file, buffer, 24) ||
+	  HFILE_ERROR == _lwrite(file, Name, lstrlen(Name) + 1) ||
+	  HFILE_ERROR == _lwrite(file, CmdLine, lstrlen(CmdLine) + 1) ||
+	  HFILE_ERROR == _lwrite(file, IconFile, lstrlen(IconFile) + 1))
+	return FALSE;
+
+      GRPFILE_CalculateSizes(program, &CurrProg, &CurrIcon);
+      hProgram = program->hNext;
+    }
+
+  /* Icons */
+  hProgram = group->hPrograms;
+  while(hProgram)
+    {
+      PROGRAM *program = LocalLock(hProgram);
+      CURSORICONINFO *iconinfo = LocalLock(program->hIcon);
+      SEGPTR XorBits, AndBits;
+      INT sizeXor = iconinfo->nHeight * iconinfo->nWidthBytes;
+      INT sizeAnd = iconinfo->nHeight * ((iconinfo->nWidth + 15) / 16 * 2);
+      DumpIcon(LocalLock(program->hIcon), 0, &XorBits, &AndBits);
+
+      PUT_SHORT(buffer, 0, iconinfo->ptHotSpot.x);
+      PUT_SHORT(buffer, 2, iconinfo->ptHotSpot.y);
+      PUT_SHORT(buffer, 4, iconinfo->nWidth);
+      PUT_SHORT(buffer, 6, iconinfo->nHeight);
+      PUT_SHORT(buffer, 8, iconinfo->nWidthBytes);
+      buffer[10] = iconinfo->bPlanes;
+      buffer[11] = iconinfo->bBitsPerPixel;
+
+      if (HFILE_ERROR == _lwrite(file, buffer, 12) ||
+	  HFILE_ERROR == _lwrite(file, AndBits, sizeAnd) ||
+	  HFILE_ERROR == _lwrite(file, XorBits, sizeXor)) return FALSE;
+
+      hProgram = program->hNext;
+    }
+
+  if (need_extension)
+    {
+      /* write `PMCC' extension */
+      PUT_SHORT(buffer, 0, 0x8000);
+      PUT_SHORT(buffer, 2, 0xffff);
+      PUT_SHORT(buffer, 4, 0x000a);
+      buffer[6] = 'P', buffer[7] = 'M';
+      buffer[8] = 'C', buffer[9] = 'C';
+      if (HFILE_ERROR == _lwrite(file, buffer, 10)) return FALSE;
+
+      seqnum = 0;
+      hProgram = group->hPrograms;
+      while(hProgram)
+	{
+	  PROGRAM *program = LocalLock(hProgram);
+	  LPCSTR lpszWorkDir = LocalLock(program->hWorkDir);
+
+	  /* Working directory */
+	  if (lpszWorkDir[0])
+	    {
+	      PUT_SHORT(buffer, 0, 0x8101);
+	      PUT_SHORT(buffer, 2, seqnum);
+	      PUT_SHORT(buffer, 4, 7 + lstrlen(lpszWorkDir));
+	      if (HFILE_ERROR == _lwrite(file, buffer, 6) ||
+		  HFILE_ERROR == _lwrite(file, lpszWorkDir, lstrlen(lpszWorkDir) + 1))
+		return FALSE;
+	    }
+
+	  /* Hot key */
+	  if (program->nHotKey)
+	    {
+	      PUT_SHORT(buffer, 0, 0x8102);
+	      PUT_SHORT(buffer, 2, seqnum);
+	      PUT_SHORT(buffer, 4, 8);
+	      PUT_SHORT(buffer, 6, program->nHotKey);
+	      if (HFILE_ERROR == _lwrite(file, buffer, 8)) return FALSE;
+	    }
+
+	  /* Show command */
+	  if (program->nCmdShow)
+	    {
+	      PUT_SHORT(buffer, 0, 0x8103);
+	      PUT_SHORT(buffer, 2, seqnum);
+	      PUT_SHORT(buffer, 4, 8);
+	      PUT_SHORT(buffer, 6, program->nCmdShow);
+	      if (HFILE_ERROR == _lwrite(file, buffer, 8)) return FALSE;
+	    }
+
+	  seqnum++;
+	  hProgram = program->hNext;
+	}
+
+      /* Write `End' extension */
+      PUT_SHORT(buffer, 0, 0xffff);
+      PUT_SHORT(buffer, 2, 0xffff);
+      PUT_SHORT(buffer, 4, 0x0000);
+      if (HFILE_ERROR == _lwrite(file, buffer, 6)) return FALSE;
+    }
+
+  return TRUE;
+}
+
+/* Local Variables:    */
+/* c-file-style: "GNU" */
+/* End:                */
diff --git a/programs/progman/license.c b/programs/progman/license.c
new file mode 100644
index 0000000..14308cd
--- /dev/null
+++ b/programs/progman/license.c
@@ -0,0 +1,32 @@
+#include <windows.h>
+#include "license.h"
+
+static LICENSE* SelectLanguage(LPCSTR Language)
+{
+#if 0
+  if (!lstrcmp(Language, "Da")) return(&WineLicense_Cz);
+  if (!lstrcmp(Language, "Da")) return(&WineLicense_Da);
+  if (!lstrcmp(Language, "De")) return(&WineLicense_De);
+  if (!lstrcmp(Language, "Es")) return(&WineLicense_Es);
+  if (!lstrcmp(Language, "Fi")) return(&WineLicense_Fi);
+  if (!lstrcmp(Language, "Fr")) return(&WineLicense_Fr);
+  if (!lstrcmp(Language, "No")) return(&WineLicense_No);
+#endif
+  return(&WineLicense_En);
+}
+
+VOID WineLicense(HWND Wnd, LPCSTR Language)
+{
+  LICENSE *License = SelectLanguage(Language);
+
+  MessageBox(Wnd, License->License, License->LicenseCaption,
+	     MB_ICONINFORMATION | MB_OK);
+}
+
+VOID WineWarranty(HWND Wnd, LPCSTR Language)
+{
+  LICENSE *License = SelectLanguage(Language);
+
+  MessageBox(Wnd, License->Warranty, License->WarrantyCaption,
+	     MB_ICONEXCLAMATION | MB_OK);
+}
diff --git a/programs/progman/license.h b/programs/progman/license.h
new file mode 100644
index 0000000..97fa9ba
--- /dev/null
+++ b/programs/progman/license.h
@@ -0,0 +1,11 @@
+VOID WineLicense(HWND hWnd, LPCSTR lpszLanguage);
+VOID WineWarranty(HWND hWnd, LPCSTR language);
+
+typedef struct
+{
+  LPCSTR License, LicenseCaption;
+  LPCSTR Warranty, WarrantyCaption;
+} LICENSE;
+
+extern LICENSE WineLicense_Cz, WineLicense_Da, WineLicense_De, WineLicense_En;
+extern LICENSE WineLicense_Es, WineLicense_Fi, WineLicense_Fr, WineLicense_No;
diff --git a/programs/progman/main.c b/programs/progman/main.c
new file mode 100644
index 0000000..f6173e2
--- /dev/null
+++ b/programs/progman/main.c
@@ -0,0 +1,553 @@
+/*
+ * Program Manager
+ *
+ * Copyright 1996 Ulrich Schmid <uschmid@mail.hh.provi.de>
+ */
+
+#include <stdio.h>
+#include <windows.h>
+#include "license.h"
+#include "progman.h"
+#ifdef WINELIB
+#include <options.h>
+#include <shell.h>
+#endif
+
+GLOBALS Globals;
+
+static VOID MAIN_CreateGroups(void);
+static VOID MAIN_MenuCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static ATOM MAIN_RegisterMainWinClass(void);
+static VOID MAIN_CreateMainWindow(void);
+static VOID MAIN_CreateMDIWindow(void);
+static VOID MAIN_AutoStart(void);
+
+#define BUFFER_SIZE 1000
+
+/***********************************************************************
+ *
+ *           WinMain
+ */
+
+int PASCAL WinMain (HANDLE hInstance, HANDLE prev, LPSTR cmdline, int show)
+{
+  MSG      msg;
+
+#ifndef WINELIB
+  Globals.lpszIniFile         = "progman.ini";
+  Globals.lpszIcoFile         = "progman.ico";
+#else /* Configuration in `wine.ini' */
+  {
+    CHAR buffer[MAX_PATHNAME_LEN], *p;
+
+    /* Redirect `progman.ini' */
+    PROFILE_GetWineIniString("progman", "progman.ini", "progman.ini", 
+			     buffer, sizeof(buffer));
+    Globals.lpszIniFile = p = LocalLock(LocalAlloc(LMEM_FIXED, lstrlen(buffer)));
+    hmemcpy(p, buffer, 1 + lstrlen(buffer));
+
+    /* Redirect `progman.ico' */
+    PROFILE_GetWineIniString("progman", "progman.ico", "progman.ico", 
+			     buffer, sizeof(buffer));
+    Globals.lpszIcoFile = p = LocalLock(LocalAlloc(LMEM_FIXED, lstrlen(buffer)));
+    hmemcpy(p, buffer, 1 + lstrlen(buffer));
+  }
+#endif
+
+  /* Select Language */
+  Globals.lpszLanguage = "En";
+#ifdef WINELIB
+  if (Options.language == LANG_Cz) Globals.lpszLanguage = "Cz"; 
+  if (Options.language == LANG_Da) Globals.lpszLanguage = "Da"; 
+  if (Options.language == LANG_De) Globals.lpszLanguage = "De"; 
+  if (Options.language == LANG_Es) Globals.lpszLanguage = "Es"; 
+  if (Options.language == LANG_Fi) Globals.lpszLanguage = "Fi"; 
+  if (Options.language == LANG_Fr) Globals.lpszLanguage = "Fr"; 
+  if (Options.language == LANG_No) Globals.lpszLanguage = "No"; 
+#ifndef HAVE_WINE_CONSTRUCTOR
+  /* Register resources */
+  LIBWINE_Register_accel();
+  LIBWINE_Register_De();
+  LIBWINE_Register_En();
+#endif
+#endif
+
+  Globals.hInstance           = hInstance;
+  Globals.hGroups             = 0;
+
+  /* FIXME should use MDI */
+  Globals.hActiveGroup = 0;
+
+  /* Read Options from `progman.ini' */
+  Globals.bAutoArrange =
+    GetPrivateProfileInt("Settings", "AutoArrange", 0, Globals.lpszIniFile);
+  Globals.bMinOnRun =
+    GetPrivateProfileInt("Settings", "MinOnRun", 0, Globals.lpszIniFile);
+  Globals.bSaveSettings =
+    GetPrivateProfileInt("Settings", "SaveSettings", 0, Globals.lpszIniFile);
+
+  /* Load default icons */
+  Globals.hMainIcon    = ExtractIcon(Globals.hInstance, Globals.lpszIcoFile, 0);
+  Globals.hGroupIcon   = ExtractIcon(Globals.hInstance, Globals.lpszIcoFile, 0);
+  Globals.hDefaultIcon = ExtractIcon(Globals.hInstance, Globals.lpszIcoFile, 0);
+  if (!Globals.hMainIcon)    Globals.hMainIcon = LoadIcon(0, MAKEINTRESOURCE(DEFAULTICON));
+  if (!Globals.hGroupIcon)   Globals.hGroupIcon = LoadIcon(0, MAKEINTRESOURCE(DEFAULTICON));
+  if (!Globals.hDefaultIcon) Globals.hDefaultIcon = LoadIcon(0, MAKEINTRESOURCE(DEFAULTICON));
+
+  /* Register classes */
+  if (!prev)
+    {
+      if (!MAIN_RegisterMainWinClass()) return(FALSE);
+      if (!GROUP_RegisterGroupWinClass()) return(FALSE);
+      if (!PROGRAM_RegisterProgramWinClass()) return(FALSE);
+    }
+
+  /* Create main window */
+  MAIN_CreateMainWindow();
+  Globals.hAccel = LoadAccelerators(Globals.hInstance, STRING_ACCEL);
+
+  /* Setup menu, stringtable and resourcenames */
+  STRING_SelectLanguage(Globals.lpszLanguage);
+
+  MAIN_CreateMDIWindow();
+
+  /* Initialize groups */
+  MAIN_CreateGroups();
+
+  /* Start initial applications */
+  MAIN_AutoStart();
+
+  /* Message loop */
+  while (GetMessage (&msg, 0, 0, 0))
+    if (!TranslateAccelerator(Globals.hMainWnd, Globals.hAccel, &msg))
+      {
+	TranslateMessage (&msg);
+	DispatchMessage (&msg);
+      }
+  return 0;
+}
+
+/***********************************************************************
+ *
+ *           MAIN_CreateGroups
+ */
+
+static VOID MAIN_CreateGroups()
+{
+  CHAR buffer[BUFFER_SIZE];
+  CHAR szPath[MAX_PATHNAME_LEN];
+  CHAR key[20], *ptr;
+
+  /* Initialize groups according the `Order' entry of `progman.ini' */
+  GetPrivateProfileString("Settings", "Order", "", buffer, sizeof(buffer), Globals.lpszIniFile);
+  ptr = buffer;
+  while (ptr < buffer + sizeof(buffer))
+    {
+      int num, skip, ret;
+      ret = sscanf(ptr, "%d%n", &num, &skip);
+      if (ret == 0) MAIN_FileReadError(Globals.lpszIniFile);
+      if (ret != 1) break;
+
+      sprintf(key, "Group%d", num);
+      GetPrivateProfileString("Groups", key, "", szPath,
+			      sizeof(szPath), Globals.lpszIniFile);
+      if (!szPath[0]) continue;
+
+      GRPFILE_ReadGroupFile(szPath);
+
+      ptr += skip;
+    }
+  /* FIXME initialize other groups, not enumerated by `Order' */
+}
+
+/***********************************************************************
+ *
+ *           MAIN_AutoStart
+ */
+
+VOID MAIN_AutoStart()
+{
+  CHAR buffer[BUFFER_SIZE];
+  HLOCAL hGroup, hProgram;
+
+  GetPrivateProfileString("Settings", "AutoStart", "Autostart", buffer,
+			  sizeof(buffer), Globals.lpszIniFile);
+
+  for (hGroup = GROUP_FirstGroup(); hGroup; hGroup = GROUP_NextGroup(hGroup))
+    if (!lstrcmp(buffer, GROUP_GroupName(hGroup)))
+      for (hProgram = PROGRAM_FirstProgram(hGroup); hProgram;
+	   hProgram = PROGRAM_NextProgram(hProgram))
+	PROGRAM_ExecuteProgram(hProgram);
+}
+
+/***********************************************************************
+ *
+ *           MAIN_MainWndProc
+ */
+
+static LRESULT MAIN_MainWndProc (HWND hWnd, UINT msg,
+				 WPARAM wParam, LPARAM lParam)
+{
+#if 0
+  printf("M %4.4x %4.4x\n", msg, wParam);
+#endif
+  switch (msg)
+    {
+    case WM_INITMENU:
+      CheckMenuItem(Globals.hOptionMenu, PM_AUTO_ARRANGE,
+		    MF_BYCOMMAND | (Globals.bAutoArrange ? MF_CHECKED : MF_UNCHECKED));
+      CheckMenuItem(Globals.hOptionMenu, PM_MIN_ON_RUN,
+		    MF_BYCOMMAND | (Globals.bMinOnRun ? MF_CHECKED : MF_UNCHECKED));
+      CheckMenuItem(Globals.hOptionMenu, PM_SAVE_SETTINGS,
+		    MF_BYCOMMAND | (Globals.bSaveSettings ? MF_CHECKED : MF_UNCHECKED));
+      break;
+
+    case WM_COMMAND:
+      if (wParam < PM_FIRST_CHILD)
+	MAIN_MenuCommand(hWnd, wParam, lParam);
+      break;
+
+    case WM_DESTROY:
+      PostQuitMessage (0);
+      break;
+    }
+  return(DefFrameProc(hWnd, Globals.hMDIWnd, msg, wParam, lParam));
+}
+
+/***********************************************************************
+ *
+ *           MAIN_MenuCommand
+ */
+
+static VOID MAIN_MenuCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+  HLOCAL hActiveGroup    = GROUP_ActiveGroup();
+  HLOCAL hActiveProgram  = PROGRAM_ActiveProgram(hActiveGroup);
+  HWND   hActiveGroupWnd = GROUP_GroupWnd(hActiveGroup);
+
+  switch(wParam)
+    {
+      /* Menu File */
+    case PM_NEW:
+      switch (DIALOG_New((hActiveGroupWnd && !IsIconic(hActiveGroupWnd)) ?
+			 PM_NEW_PROGRAM : PM_NEW_GROUP))
+      {
+      case PM_NEW_PROGRAM:
+	if (hActiveGroup) PROGRAM_NewProgram(hActiveGroup);
+	break;
+
+      case PM_NEW_GROUP:
+	GROUP_NewGroup();
+	break;
+      }
+      break;
+
+    case PM_OPEN:
+      if (hActiveProgram)
+	PROGRAM_ExecuteProgram(hActiveProgram);
+      else if (hActiveGroupWnd)
+	OpenIcon(hActiveGroupWnd);
+      break;
+
+    case PM_MOVE:
+    case PM_COPY:
+      if (hActiveProgram)
+	PROGRAM_CopyMoveProgram(hActiveProgram, wParam == PM_MOVE);
+      break;
+
+    case PM_DELETE:
+      if (hActiveProgram)
+	{
+	if (DIALOG_Delete(STRING_DELETE_PROGRAM_s, PROGRAM_ProgramName(hActiveProgram)))
+	  PROGRAM_DeleteProgram(hActiveProgram, TRUE);
+	}
+      else if (hActiveGroup)
+	{
+	if (DIALOG_Delete(STRING_DELETE_GROUP_s, GROUP_GroupName(hActiveGroup)))
+	  GROUP_DeleteGroup(hActiveGroup);
+	}
+      break;
+
+    case PM_ATTRIBUTES:
+      if (hActiveProgram)
+	PROGRAM_ModifyProgram(hActiveProgram);
+      else if (hActiveGroup)
+	GROUP_ModifyGroup(hActiveGroup);
+      break;
+
+    case PM_EXECUTE:
+      DIALOG_Execute();
+      break;
+
+    case PM_EXIT:
+      PostQuitMessage(0);
+      break;
+
+      /* Menu Options */
+    case PM_AUTO_ARRANGE:
+      Globals.bAutoArrange = !Globals.bAutoArrange;
+      CheckMenuItem(Globals.hOptionMenu, PM_AUTO_ARRANGE,
+		    MF_BYCOMMAND | (Globals.bAutoArrange ?
+				    MF_CHECKED : MF_UNCHECKED));
+      WritePrivateProfileString("Settings", "AutoArrange",
+				Globals.bAutoArrange ? "1" : "0",
+				Globals.lpszIniFile);
+      WriteOutProfiles();
+      break;
+
+    case PM_MIN_ON_RUN:
+      Globals.bMinOnRun = !Globals.bMinOnRun;
+      CheckMenuItem(Globals.hOptionMenu, PM_MIN_ON_RUN,
+		    MF_BYCOMMAND | (Globals.bMinOnRun ?
+				    MF_CHECKED : MF_UNCHECKED));
+      WritePrivateProfileString("Settings", "MinOnRun",
+				Globals.bMinOnRun ? "1" : "0",
+				Globals.lpszIniFile);
+      WriteOutProfiles();
+      break;
+
+    case PM_SAVE_SETTINGS:
+      Globals.bSaveSettings = !Globals.bSaveSettings;
+      CheckMenuItem(Globals.hOptionMenu, PM_SAVE_SETTINGS,
+		    MF_BYCOMMAND | (Globals.bSaveSettings ?
+				    MF_CHECKED : MF_UNCHECKED));
+      WritePrivateProfileString("Settings", "SaveSettings",
+				Globals.bSaveSettings ? "1" : "0",
+				Globals.lpszIniFile);
+      WriteOutProfiles();
+      break;
+
+      /* Menu Windows */
+    case PM_ARRANGE:
+      SendMessage(Globals.hMDIWnd, WM_MDIICONARRANGE, 0, 0);
+      break;
+
+      /* Menu Language */
+    case PM_Da: STRING_SelectLanguage("Da"); break;
+    case PM_De: STRING_SelectLanguage("De"); break;
+    case PM_En: STRING_SelectLanguage("En"); break;
+    case PM_Es: STRING_SelectLanguage("Es"); break;
+    case PM_Fi: STRING_SelectLanguage("Fi"); break;
+    case PM_Fr: STRING_SelectLanguage("Fr"); break;
+    case PM_No: STRING_SelectLanguage("No"); break;
+
+      /* Menu Help */
+    case PM_CONTENTS:
+      if (!WinHelp(Globals.hMainWnd, "progman.hlp", HELP_INDEX, 0))
+	MAIN_WinHelpError();
+      break;
+
+    case PM_HELPONHELP:
+      if (!WinHelp(Globals.hMainWnd, "progman.hlp", HELP_HELPONHELP, 0))
+	MAIN_WinHelpError();
+      break;
+
+    case PM_TUTORIAL:
+      WinExec("wintutor.exe", SW_SHOWNORMAL);
+      break;
+
+    case PM_LICENSE:
+      WineLicense(Globals.hMainWnd, Globals.lpszLanguage);
+      break;
+
+    case PM_NO_WARRANTY:
+      WineWarranty(Globals.hMainWnd, Globals.lpszLanguage);
+      break;
+
+#ifdef WINELIB
+    case PM_ABOUT_WINE:
+      {
+	extern const char people[];
+	ShellAbout(hWnd, "WINE", people, 0);
+      }
+      break;
+#endif
+
+    default:
+      MAIN_NotImplementedError();
+      break;
+    }
+}
+
+/***********************************************************************
+ *
+ *           MAIN_RegisterMainWinClass
+ */
+
+static ATOM MAIN_RegisterMainWinClass()
+{
+  WNDCLASS class;
+
+  class.style         = CS_HREDRAW | CS_VREDRAW;
+  class.lpfnWndProc   = MAIN_MainWndProc;
+  class.cbClsExtra    = 0;
+  class.cbWndExtra    = 0;
+  class.hInstance     = Globals.hInstance;
+  class.hIcon         = Globals.hMainIcon;
+  class.hCursor       = LoadCursor (0, IDC_ARROW);
+  class.hbrBackground = GetStockObject (NULL_BRUSH);
+  class.lpszMenuName  = 0;
+  class.lpszClassName = STRING_MAIN_WIN_CLASS_NAME;
+
+  return RegisterClass(&class);
+}
+
+/***********************************************************************
+ *
+ *           MAIN_CreateMainWindow
+ */
+
+static VOID MAIN_CreateMainWindow()
+{
+  INT  left , top, right, bottom, width, height, show;
+  CHAR buffer[100];
+
+  Globals.hMDIWnd   = 0;
+  Globals.hMainMenu = 0;
+
+  /* Get the geometry of the main window */
+  GetPrivateProfileString("Settings", "Window", "",
+			  buffer, sizeof(buffer), Globals.lpszIniFile);
+  if (5 == sscanf(buffer, "%d %d %d %d %d", &left, &top, &right, &bottom, &show))
+  {
+    width  = right - left;
+    height = bottom - top;
+  }
+  else
+  {
+    left = top = width = height = CW_USEDEFAULT;
+    show = SW_SHOWNORMAL;
+  }
+
+  /* Create main Window */
+  Globals.hMainWnd =
+    CreateWindow (STRING_MAIN_WIN_CLASS_NAME, "",
+		  WS_OVERLAPPEDWINDOW, left, top, width, height,
+		  0, 0, Globals.hInstance, 0);
+
+  ShowWindow (Globals.hMainWnd, show);
+  UpdateWindow (Globals.hMainWnd);
+}
+
+/***********************************************************************
+ *
+ *           MAIN_CreateMDIWindow
+ */
+
+static VOID MAIN_CreateMDIWindow()
+{
+  CLIENTCREATESTRUCT ccs;
+  RECT rect;
+
+  /* Get the geometry of the MDI window */
+  GetClientRect(Globals.hMainWnd, &rect);
+
+  ccs.hWindowMenu  = Globals.hWindowsMenu;
+  ccs.idFirstChild = PM_FIRST_CHILD;
+
+  /* Create MDI Window */
+  Globals.hMDIWnd =
+    CreateWindow (STRING_MDI_WIN_CLASS_NAME, "",
+		  WS_CHILD, rect.left, rect.top,
+		  rect.right - rect.left, rect.bottom - rect.top,
+		  Globals.hMainWnd, 0,
+		  Globals.hInstance, &ccs);
+
+  ShowWindow (Globals.hMDIWnd, SW_SHOW);
+  UpdateWindow (Globals.hMDIWnd);
+}
+
+/**********************************************************************/
+/***********************************************************************
+ *
+ *           MAIN_ReplaceString
+ */
+
+VOID MAIN_ReplaceString(HLOCAL *handle, LPSTR replace)
+{
+  HLOCAL newhandle = LocalAlloc(LMEM_FIXED, strlen(replace) + 1);
+  if (newhandle)
+    {
+      LPSTR  newstring = LocalLock(newhandle);
+      lstrcpy(newstring, replace);
+      LocalFree(*handle);
+      *handle = newhandle;
+    }
+  else MAIN_OutOfMemoryError();
+}
+
+/***********************************************************************
+ *
+ *           MAIN_NotImplementedError
+ */
+
+VOID MAIN_NotImplementedError()
+{
+  MessageBox(Globals.hMainWnd,
+	     STRING_NOT_IMPLEMENTED, STRING_ERROR, MB_OK);
+}
+
+/***********************************************************************
+ *
+ *           MAIN_OutOfMemoryError
+ */
+
+VOID MAIN_OutOfMemoryError()
+{
+  MessageBox(Globals.hMainWnd,
+	     STRING_OUT_OF_MEMORY, STRING_ERROR, MB_OK);
+}
+
+/***********************************************************************
+ *
+ *           MAIN_WinHelpError
+ */
+
+VOID MAIN_WinHelpError()
+{
+  MessageBox(Globals.hMainWnd,
+	     STRING_WINHELP_ERROR, STRING_ERROR, MB_OK);
+}
+
+/***********************************************************************
+ *
+ *           MAIN_FileReadError
+ */
+
+VOID MAIN_FileReadError(LPCSTR lpszPath)
+{
+  CHAR msg[MAX_PATHNAME_LEN + 1000];
+  if (sizeof(msg) <= strlen(STRING_FILE_READ_ERROR_s) + strlen(lpszPath)) return;
+  wsprintf(msg, (LPSTR)STRING_FILE_READ_ERROR_s, lpszPath);
+  MessageBox(Globals.hMainWnd, msg, STRING_ERROR, MB_OK);
+}
+
+/***********************************************************************
+ *
+ *           MAIN_FileWriteError
+ */
+
+VOID MAIN_FileWriteError(LPCSTR lpszPath)
+{
+  CHAR msg[MAX_PATHNAME_LEN + 1000];
+  if (sizeof(msg) <= strlen(STRING_FILE_WRITE_ERROR_s) + strlen(lpszPath)) return;
+  wsprintf(msg, (LPSTR)STRING_FILE_WRITE_ERROR_s, lpszPath);
+  MessageBox(Globals.hMainWnd, msg, STRING_ERROR, MB_OK);
+}
+
+/***********************************************************************
+ *
+ *           MAIN_GrpFileReadError
+ */
+
+VOID MAIN_GrpFileReadError(LPCSTR lpszPath)
+{
+  CHAR msg[MAX_PATHNAME_LEN + 1000];
+  if (sizeof(msg) <= strlen(STRING_GRPFILE_READ_ERROR_s) + strlen(lpszPath)) return;
+  wsprintf(msg, (LPSTR)STRING_GRPFILE_READ_ERROR_s, lpszPath);
+  MessageBox(Globals.hMainWnd, msg, STRING_ERROR, MB_YESNO);
+}
+
+/* Local Variables:    */
+/* c-file-style: "GNU" */
+/* End:                */
diff --git a/programs/progman/progman.h b/programs/progman/progman.h
new file mode 100644
index 0000000..5d72ed9
--- /dev/null
+++ b/programs/progman/progman.h
@@ -0,0 +1,347 @@
+/*
+ * Program Manager
+ *
+ * Copyright 1996 Ulrich Schmid
+ */
+
+#ifndef PROGMAN_H
+#define PROGMAN_H
+
+#ifndef RC_INVOKED
+
+#include "windows.h"
+
+/* FIXME should use WinExec from -lwine */
+#ifdef WINELIB
+#define WinExec ProgmanWinExec
+#define WinHelp ProgmanWinHelp
+HANDLE  ProgmanWinExec(LPSTR,WORD);
+BOOL    ProgmanWinHelp(HWND,LPSTR,WORD,DWORD);
+#endif
+
+#define MAX_PATHNAME_LEN 1024
+
+/* Fallback icon */
+#ifdef WINELIB
+#define DEFAULTICON OIC_WINEICON
+#else
+#define DEFAULTICON OIC_LANDSCAPE
+#endif
+
+/* Icon index in M$ Window's progman.exe  */
+#define PROGMAN_ICON_INDEX 0
+#define GROUP_ICON_INDEX   6
+#define DEFAULT_ICON_INDEX 7
+
+#define DEF_GROUP_WIN_XPOS   100
+#define DEF_GROUP_WIN_YPOS   100
+#define DEF_GROUP_WIN_WIDTH  300
+#define DEF_GROUP_WIN_HEIGHT 200
+
+typedef struct
+{
+  HLOCAL   hGroup;
+  HLOCAL   hPrior;
+  HLOCAL   hNext;
+  HWND     hWnd;
+  /**/              /* Numbers are byte indexes in *.grp */
+
+  /**/                       /* Program entry */
+  INT      x, y;               /*  0 -  3 */
+  INT      nIconIndex;         /*  4 -  5 */
+  HICON    hIcon;
+  /* icon flags ??? */         /*  6 -  7 */
+  /* iconANDsize */            /*  8 -  9 */
+  /* iconXORsize */            /* 10 - 11 */
+  /* pointer to IconInfo    */ /* 12 - 13 */
+  /* pointer to iconXORbits */ /* 14 - 15 */ /* sometimes iconANDbits ?! */
+  /* pointer to iconANDbits */ /* 16 - 17 */ /* sometimes iconXORbits ?! */
+  HLOCAL   hName;              /* 18 - 19 */
+  HLOCAL   hCmdLine;           /* 20 - 21 */
+  HLOCAL   hIconFile;          /* 22 - 23 */        
+  HLOCAL   hWorkDir;           /* Extension 0x8101 */
+  INT      nHotKey;            /* Extension 0x8102 */
+  /* Modifier: bit 8... */
+  INT      nCmdShow;           /* Extension 0x8103 */
+
+  /**/                         /* IconInfo */
+  /* HotSpot x   ??? */        /*  0 -  1 */
+  /* HotSpot y   ??? */        /*  2 -  3 */
+  /* Width           */        /*  4 -  5 */
+  /* Height          */        /*  6 -  7 */
+  /* WidthBytes  ??? */        /*  8 -  9 */
+  /* Planes          */        /* 10 - 10 */
+  /* BitsPerPixel    */        /* 11 - 11 */
+} PROGRAM;
+
+typedef struct
+{
+  HLOCAL   hPrior;
+  HLOCAL   hNext;
+  HWND     hWnd;
+  HLOCAL   hGrpFile;
+  HLOCAL   hActiveProgram;
+  BOOL     bFileNameModified;
+  BOOL     bOverwriteFileOk;
+  INT      seqnum;
+
+  /**/                         /* Absolute */
+  /* magic `PMCC'  */          /*  0 -  3 */
+  /* checksum      */          /*  4 -  5 */
+  /* Extension ptr */          /*  6 -  7 */
+  INT      nCmdShow;           /*  8 -  9 */
+  INT      x, y;               /* 10 - 13 */
+  INT      width, height;      /* 14 - 17 */
+  INT      iconx, icony;       /* 18 - 21 */
+  HLOCAL   hName;              /* 22 - 23 */
+  /* unknown */                /* 24 - 31 */
+  /* number of programs */     /* 32 - 33 */
+  HLOCAL   hPrograms;          /* 34 ...  */
+
+  /**/                        /* Extensions */
+  /* Extension type */         /*  0 -  1 */           
+  /* Program number */         /*  2 -  3 */
+  /* Size of entry  */         /*  4 -  5 */
+  /* Data           */         /*  6 ...  */
+
+  /* magic `PMCC' */           /* Extension 0x8000 */
+  /* End of Extensions */      /* Extension 0xffff */
+} GROUP;
+
+typedef struct
+{
+  HANDLE  hInstance;
+  HANDLE  hAccel;
+  HWND    hMainWnd;
+  HWND    hMDIWnd;
+  HICON   hMainIcon;
+  HICON   hGroupIcon;
+  HICON   hDefaultIcon;
+  HMENU   hMainMenu;
+  HMENU   hFileMenu;
+  HMENU   hOptionMenu;
+  HMENU   hWindowsMenu;
+  LPCSTR  lpszIniFile;
+  LPCSTR  lpszIcoFile;
+  BOOL    bAutoArrange;
+  BOOL    bSaveSettings;
+  BOOL    bMinOnRun;
+  HLOCAL  hGroups;
+  LPCSTR  lpszLanguage;
+  LPCSTR *StringTable;
+  /* FIXME should use MDI */
+  HLOCAL  hActiveGroup;
+} GLOBALS;
+
+extern GLOBALS Globals;
+
+VOID MAIN_ReplaceString(HLOCAL *handle, LPSTR replacestring);
+VOID MAIN_NotImplementedError(void);
+VOID MAIN_FileReadError(LPCSTR lpszPath);
+VOID MAIN_FileWriteError(LPCSTR lpszPath);
+VOID MAIN_GrpFileReadError(LPCSTR lpszPath);
+VOID MAIN_OutOfMemoryError(void);
+VOID MAIN_WinHelpError(void);
+
+HLOCAL GRPFILE_ReadGroupFile(const char* path);
+BOOL   GRPFILE_WriteGroupFile(HLOCAL hGroup);
+
+ATOM   GROUP_RegisterGroupWinClass(void);
+HLOCAL GROUP_AddGroup(LPCSTR lpszName, LPCSTR lpszGrpFile, INT showcmd,
+		      INT x, INT y, INT width, INT heiht,
+		      INT iconx, INT icony,
+		      BOOL bModifiedFileName, BOOL bOverwriteFileOk,
+		      /* FIXME shouldn't be necessary */
+		      BOOL bSuppressShowWindow);
+VOID   GROUP_NewGroup(void);
+VOID   GROUP_ModifyGroup(HLOCAL hGroup);
+VOID   GROUP_DeleteGroup(HLOCAL hGroup);
+/* FIXME shouldn't be necessary */
+VOID   GROUP_ShowGroupWindow(HLOCAL hGroup);
+HLOCAL GROUP_FirstGroup(void);
+HLOCAL GROUP_NextGroup(HLOCAL hGroup);
+HLOCAL GROUP_ActiveGroup(void);
+HWND   GROUP_GroupWnd(HLOCAL hGroup);
+LPCSTR GROUP_GroupName(HLOCAL hGroup);
+
+ATOM   PROGRAM_RegisterProgramWinClass(void);
+HLOCAL PROGRAM_AddProgram(HLOCAL hGroup, HICON hIcon, LPCSTR lpszName,
+			  INT x, INT y, LPCSTR lpszCmdLine,
+			  LPCSTR lpszIconFile, INT nIconIndex,
+			  LPCSTR lpszWorkDir, INT nHotKey, INT nCmdShow);
+VOID   PROGRAM_NewProgram(HLOCAL hGroup);
+VOID   PROGRAM_ModifyProgram(HLOCAL hProgram);
+VOID   PROGRAM_CopyMoveProgram(HLOCAL hProgram, BOOL bMove);
+VOID   PROGRAM_DeleteProgram(HLOCAL hProgram, BOOL BUpdateGrpFile);
+HLOCAL PROGRAM_FirstProgram(HLOCAL hGroup);
+HLOCAL PROGRAM_NextProgram(HLOCAL hProgram);
+HLOCAL PROGRAM_ActiveProgram(HLOCAL hGroup);
+LPCSTR PROGRAM_ProgramName(HLOCAL hProgram);
+VOID   PROGRAM_ExecuteProgram(HLOCAL hLocal);
+
+INT    DIALOG_New(INT nDefault);
+HLOCAL DIALOG_CopyMove(LPCSTR lpszProgramName, LPCSTR lpszGroupName, BOOL bMove);
+BOOL   DIALOG_Delete(LPCSTR lpszFormat, LPCSTR lpszName);
+BOOL   DIALOG_GroupAttributes(LPSTR lpszTitle, LPSTR lpszPath, INT nSize);
+BOOL   DIALOG_ProgramAttributes(LPSTR lpszTitle, LPSTR lpszCmdLine,
+				LPSTR lpszWorkDir, LPSTR lpszIconFile,
+				HICON *lphIcon, INT *nIconIndex,
+				INT *lpnHotKey, INT *lpnCmdShow, INT nSize);
+VOID   DIALOG_Symbol(HICON *lphIcon, LPSTR lpszIconFile,
+		     INT *lpnIconIndex, INT nSize);
+VOID   DIALOG_Execute(void);
+
+VOID STRING_SelectLanguage(LPCSTR lang);
+
+/* Class names */
+extern CHAR STRING_MAIN_WIN_CLASS_NAME[];
+extern CHAR STRING_MDI_WIN_CLASS_NAME[];
+extern CHAR STRING_GROUP_WIN_CLASS_NAME[];
+extern CHAR STRING_PROGRAM_WIN_CLASS_NAME[];
+
+/* Resource names */
+extern CHAR STRING_ACCEL[];
+extern CHAR STRING_MAIN_Xx[];
+extern CHAR STRING_NEW_Xx[];
+extern CHAR STRING_OPEN_Xx[];
+extern CHAR STRING_MOVE_Xx[];
+extern CHAR STRING_COPY_Xx[];
+extern CHAR STRING_DELETE_Xx[];
+extern CHAR STRING_GROUP_Xx[];
+extern CHAR STRING_PROGRAM_Xx[];
+extern CHAR STRING_SYMBOL_Xx[];
+extern CHAR STRING_EXECUTE_Xx[];
+
+/* Strings */
+#define STRING_PROGRAM_MANAGER            Globals.StringTable[ 0]
+#define STRING_ERROR                      Globals.StringTable[ 1]
+#define STRING_INFO                       Globals.StringTable[ 2]
+#define STRING_DELETE                     Globals.StringTable[ 3]
+#define STRING_DELETE_GROUP_s             Globals.StringTable[ 4]
+#define STRING_DELETE_PROGRAM_s           Globals.StringTable[ 5]
+#define STRING_NOT_IMPLEMENTED            Globals.StringTable[ 6]
+#define STRING_FILE_READ_ERROR_s          Globals.StringTable[ 7]
+#define STRING_FILE_WRITE_ERROR_s         Globals.StringTable[ 8]
+#define STRING_GRPFILE_READ_ERROR_s       Globals.StringTable[ 9]
+#define STRING_OUT_OF_MEMORY              Globals.StringTable[10]
+#define STRING_WINHELP_ERROR              Globals.StringTable[11]
+#define STRING_UNKNOWN_FEATURE_IN_GRPFILE Globals.StringTable[12]
+#define STRING_FILE_NOT_OVERWRITTEN_s     Globals.StringTable[13]
+#define STRING_SAVE_GROUP_AS_s            Globals.StringTable[14]
+#define STRING_NO_HOT_KEY                 Globals.StringTable[15]
+#define STRING_BROWSE_EXE_FILTER          Globals.StringTable[16]
+#define STRING_BROWSE_ICO_FILTER          Globals.StringTable[17]
+#define NUMBER_OF_STRINGS                                     18
+
+extern LPCSTR StringTableCz[];
+extern LPCSTR StringTableDa[];
+extern LPCSTR StringTableDe[];
+extern LPCSTR StringTableEn[];
+extern LPCSTR StringTableEs[];
+extern LPCSTR StringTableFi[];
+extern LPCSTR StringTableFr[];
+extern LPCSTR StringTableNo[];
+
+#if defined(WINELIB) && !defined(HAVE_WINE_CONSTRUCTOR)
+  VOID LIBWINE_Register_accel(void);
+  VOID LIBWINE_Register_Cz(void);
+  VOID LIBWINE_Register_Da(void);
+  VOID LIBWINE_Register_De(void);
+  VOID LIBWINE_Register_Es(void);
+  VOID LIBWINE_Register_En(void);
+  VOID LIBWINE_Register_Fi(void);
+  VOID LIBWINE_Register_Fr(void);
+  VOID LIBWINE_Register_No(void);
+#endif
+
+#endif /* !RC_INVOKED */
+
+/* Menu */
+
+#define PM_NEW              100
+#define PM_OPEN             101
+#define PM_MOVE             102
+#define PM_COPY             103
+#define PM_DELETE           104
+#define PM_ATTRIBUTES       105
+#define PM_EXECUTE          107
+#define PM_EXIT             108
+
+#define PM_AUTO_ARRANGE     200
+#define PM_MIN_ON_RUN       201
+#define PM_SAVE_SETTINGS    203
+
+#define PM_OVERLAP          300
+#define PM_SIDE_BY_SIDE     301
+#define PM_ARRANGE          302
+#define PM_FIRST_CHILD      3030
+
+#define PM_En               400
+#define PM_Es               401
+#define PM_De               402
+#define PM_No               403
+#define PM_Fr               404
+#define PM_Fi               405
+#define PM_Da               406
+#define PM_Cz               407
+
+#define PM_CONTENTS         501
+#define PM_SEARCH           502
+#define PM_HELPONHELP       503
+#define PM_TUTORIAL         504
+
+#define PM_LICENSE          510
+#define PM_NO_WARRANTY      511
+#define PM_ABOUT_WINE       512
+
+/* Dialog `New' */
+
+/* RADIOBUTTON: The next two must be in sequence */
+#define PM_NEW_GROUP        1000
+#define PM_NEW_PROGRAM      1001
+#define PM_NEW_GROUP_TXT    1002
+#define PM_NEW_PROGRAM_TXT  1003
+
+/* Dialogs `Copy', `Move' */
+
+#define PM_PROGRAM          1200
+#define PM_FROM_GROUP       1201
+#define PM_TO_GROUP         1202
+#define PM_TO_GROUP_TXT     1203
+
+/* Dialogs `Group attributes' */
+
+#define PM_DESCRIPTION      1500
+#define PM_DESCRIPTION_TXT  1501
+#define PM_FILE             1502
+#define PM_FILE_TXT         1503
+
+/* Dialogs `Program attributes' */
+#define PM_COMMAND_LINE     1510
+#define PM_COMMAND_LINE_TXT 1511
+#define PM_DIRECTORY        1512
+#define PM_DIRECTORY_TXT    1513
+#define PM_HOT_KEY          1514
+#define PM_HOT_KEY_TXT      1515
+#define PM_ICON             1516
+#define PM_OTHER_SYMBOL     1517
+
+/* Dialog `Symbol' */
+
+#define PM_ICON_FILE        1520
+#define PM_ICON_FILE_TXT    1521
+#define PM_SYMBOL_LIST      1522
+#define PM_SYMBOL_LIST_TXT  1523
+
+/* Dialog `Execute' */
+
+#define PM_COMMAND          1600
+#define PM_SYMBOL           1601
+#define PM_BROWSE           1602
+#define PM_HELP             1603
+
+#endif /* PROGMAN_H */
+
+/* Local Variables:    */
+/* c-file-style: "GNU" */
+/* End:                */
diff --git a/programs/progman/program.c b/programs/progman/program.c
new file mode 100644
index 0000000..adf30ed
--- /dev/null
+++ b/programs/progman/program.c
@@ -0,0 +1,356 @@
+/*
+ * Program Manager
+ *
+ * Copyright 1996 Ulrich Schmid
+ */
+
+#include <windows.h>
+#include "progman.h"
+
+/***********************************************************************
+ *
+ *           PROGRAM_ProgramWndProc
+ */
+
+static LRESULT PROGRAM_ProgramWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+  switch (msg)
+    {
+    case WM_NCLBUTTONDOWN:
+      {
+	HLOCAL  hProgram = (HLOCAL) GetWindowLong(hWnd, 0);
+	PROGRAM *program = LocalLock(hProgram);
+	GROUP   *group   = LocalLock(program->hGroup);
+	group->hActiveProgram = hProgram;
+	EnableMenuItem(Globals.hFileMenu, PM_MOVE , MF_ENABLED);
+	EnableMenuItem(Globals.hFileMenu, PM_COPY , MF_ENABLED);
+	break;
+      }
+    case WM_NCLBUTTONDBLCLK:
+      {
+	PROGRAM_ExecuteProgram((HLOCAL) GetWindowLong(hWnd, 0));
+	return(0);
+      }
+
+    case WM_PAINT:
+      {
+	PROGRAM *program;
+	PAINTSTRUCT      ps;
+	HDC              hdc;
+	hdc     = BeginPaint(hWnd,&ps);
+	program = LocalLock((HLOCAL) GetWindowLong(hWnd, 0));
+	if (program->hIcon)
+	  DrawIcon(hdc, 0, 0, program->hIcon);
+	EndPaint(hWnd,&ps);
+	break;
+      }
+    }
+  return(DefWindowProc(hWnd, msg, wParam, lParam));
+}
+
+/***********************************************************************
+ *
+ *           PROGRAM_RegisterProgramWinClass
+ */
+
+ATOM PROGRAM_RegisterProgramWinClass()
+{
+  WNDCLASS class;
+
+  class.style         = CS_HREDRAW | CS_VREDRAW;
+  class.lpfnWndProc   = PROGRAM_ProgramWndProc;
+  class.cbClsExtra    = 0;
+  class.cbWndExtra    = sizeof(LONG);
+  class.hInstance     = Globals.hInstance;
+  class.hIcon         = 0;
+  class.hCursor       = LoadCursor (0, IDC_ARROW);
+  class.hbrBackground = GetStockObject (WHITE_BRUSH);
+  class.lpszMenuName  = 0;
+  class.lpszClassName = STRING_PROGRAM_WIN_CLASS_NAME;
+
+  return RegisterClass(&class);
+}
+
+/***********************************************************************
+ *
+ *           PROGRAM_NewProgram
+ */
+
+VOID PROGRAM_NewProgram(HLOCAL hGroup)
+{
+  INT  nCmdShow = SW_SHOWNORMAL;
+  INT  nHotKey = 0;
+  INT  nIconIndex = 0;
+  CHAR szName[MAX_PATHNAME_LEN] = "";
+  CHAR szCmdLine[MAX_PATHNAME_LEN] = "";
+  CHAR szIconFile[MAX_PATHNAME_LEN] = "";
+  CHAR szWorkDir[MAX_PATHNAME_LEN] = "";
+  HICON hIcon = 0;
+
+  if (!DIALOG_ProgramAttributes(szName, szCmdLine, szWorkDir, szIconFile,
+				&hIcon, &nIconIndex, &nHotKey,
+				&nCmdShow, MAX_PATHNAME_LEN))
+    return;
+
+  if (!hIcon) hIcon = LoadIcon(0, MAKEINTRESOURCE(OIC_WINEICON));
+
+
+  if (!PROGRAM_AddProgram(hGroup, hIcon, szName, 0, 0, szCmdLine, szIconFile,
+			  nIconIndex, szWorkDir, nHotKey, nCmdShow))
+    return;
+
+  GRPFILE_WriteGroupFile(hGroup);
+}
+
+/***********************************************************************
+ *
+ *           PROGRAM_ModifyProgram
+ */
+
+VOID PROGRAM_ModifyProgram(HLOCAL hProgram)
+{
+  PROGRAM *program = LocalLock(hProgram);
+  CHAR szName[MAX_PATHNAME_LEN];
+  CHAR szCmdLine[MAX_PATHNAME_LEN];
+  CHAR szIconFile[MAX_PATHNAME_LEN];
+  CHAR szWorkDir[MAX_PATHNAME_LEN];
+
+  lstrcpyn(szName, LocalLock(program->hName), MAX_PATHNAME_LEN);
+  lstrcpyn(szCmdLine, LocalLock(program->hCmdLine), MAX_PATHNAME_LEN);
+  lstrcpyn(szIconFile, LocalLock(program->hIconFile), MAX_PATHNAME_LEN);
+  lstrcpyn(szWorkDir, LocalLock(program->hWorkDir), MAX_PATHNAME_LEN);
+
+  if (!DIALOG_ProgramAttributes(szName, szCmdLine, szWorkDir, szIconFile,
+				&program->hIcon, &program->nIconIndex,
+				&program->nHotKey, &program->nCmdShow,
+				MAX_PATHNAME_LEN))
+    return;
+
+  MAIN_ReplaceString(&program->hName, szName);
+  MAIN_ReplaceString(&program->hCmdLine, szCmdLine);
+  MAIN_ReplaceString(&program->hIconFile, szIconFile);
+  MAIN_ReplaceString(&program->hWorkDir, szWorkDir);
+
+  SetWindowText(program->hWnd, szName);
+  UpdateWindow(program->hWnd);
+
+  GRPFILE_WriteGroupFile(program->hGroup);
+
+  return;
+}
+
+/***********************************************************************
+ *
+ *           PROGRAM_AddProgram
+ */
+
+HLOCAL PROGRAM_AddProgram(HLOCAL hGroup, HICON hIcon, LPCSTR lpszName,
+			  INT x, INT y, LPCSTR lpszCmdLine,
+			  LPCSTR lpszIconFile, INT nIconIndex,
+			  LPCSTR lpszWorkDir, INT nHotKey, INT nCmdShow)
+{
+  GROUP *group = LocalLock(hGroup);
+  PROGRAM *program;
+  HLOCAL hPrior, *p;
+  HLOCAL hProgram  = LocalAlloc(LMEM_FIXED, sizeof(PROGRAM));
+  HLOCAL hName     = LocalAlloc(LMEM_FIXED, 1 + lstrlen(lpszName));
+  HLOCAL hCmdLine  = LocalAlloc(LMEM_FIXED, 1 + lstrlen(lpszCmdLine));
+  HLOCAL hIconFile = LocalAlloc(LMEM_FIXED, 1 + lstrlen(lpszIconFile));
+  HLOCAL hWorkDir  = LocalAlloc(LMEM_FIXED, 1 + lstrlen(lpszWorkDir));
+  if (!hProgram || !hName || !hCmdLine || !hIconFile || !hWorkDir)
+    {
+      MAIN_OutOfMemoryError();
+      if (hProgram)  LocalFree(hProgram);
+      if (hName)     LocalFree(hName);
+      if (hCmdLine)  LocalFree(hCmdLine);
+      if (hIconFile) LocalFree(hIconFile);
+      if (hWorkDir)  LocalFree(hWorkDir);
+      return(0);
+    }
+  hmemcpy(LocalLock(hName),     lpszName,     1 + lstrlen(lpszName));
+  hmemcpy(LocalLock(hCmdLine),  lpszCmdLine,  1 + lstrlen(lpszCmdLine));
+  hmemcpy(LocalLock(hIconFile), lpszIconFile, 1 + lstrlen(lpszIconFile));
+  hmemcpy(LocalLock(hWorkDir),  lpszWorkDir,  1 + lstrlen(lpszWorkDir));
+
+  group->hActiveProgram  = hProgram;
+
+  hPrior = 0;
+  p = &group->hPrograms;
+  while (*p)
+    {
+      hPrior = *p;
+      p = &((PROGRAM*)LocalLock(hPrior))->hNext;
+    }
+  *p = hProgram;
+
+  program = LocalLock(hProgram);
+  program->hGroup     = hGroup;
+  program->hPrior     = hPrior;
+  program->hNext      = 0;
+  program->hName      = hName;
+  program->hCmdLine   = hCmdLine;
+  program->hIconFile  = hIconFile;
+  program->nIconIndex = nIconIndex;
+  program->hWorkDir   = hWorkDir;
+  program->hIcon      = hIcon;
+  program->nCmdShow   = nCmdShow;
+  program->nHotKey    = nHotKey;
+
+  program->hWnd =
+    CreateWindow (STRING_PROGRAM_WIN_CLASS_NAME, (LPSTR)lpszName,
+		  WS_CHILD | WS_OVERLAPPEDWINDOW,
+		  x, y, CW_USEDEFAULT, CW_USEDEFAULT,
+		  group->hWnd, 0, Globals.hInstance, 0);
+
+  SetWindowLong(program->hWnd, 0, (LONG) hProgram);
+
+  ShowWindow (program->hWnd, SW_SHOWMINIMIZED);
+  UpdateWindow (program->hWnd);
+
+  return hProgram;
+}
+
+/***********************************************************************
+ *
+ *           PROGRAM_CopyMoveProgram
+ */
+
+VOID PROGRAM_CopyMoveProgram(HLOCAL hProgram, BOOL bMove)
+{
+  PROGRAM *program = LocalLock(hProgram);
+  GROUP   *fromgroup = LocalLock(program->hGroup);
+  HLOCAL hGroup = DIALOG_CopyMove(LocalLock(program->hName),
+				  LocalLock(fromgroup->hName), bMove);
+  if (!hGroup) return;
+
+  /* FIXME shouldn't be necessary */
+  OpenIcon(((GROUP*)LocalLock(hGroup))->hWnd);
+
+  if (!PROGRAM_AddProgram(hGroup,
+#if 0
+			  CopyIcon(program->hIcon),
+#else
+			  program->hIcon,
+#endif
+			  LocalLock(program->hName),
+			  program->x, program->y,
+			  LocalLock(program->hCmdLine),
+			  LocalLock(program->hIconFile),
+			  program->nIconIndex,
+			  LocalLock(program->hWorkDir),
+			  program->nHotKey, program->nCmdShow)) return;
+  GRPFILE_WriteGroupFile(hGroup);
+
+  if (bMove) PROGRAM_DeleteProgram(hProgram, TRUE);
+}
+
+/***********************************************************************
+ *
+ *           PROGRAM_ExecuteProgram
+ */
+
+VOID PROGRAM_ExecuteProgram(HLOCAL hProgram)
+{
+  PROGRAM *program = LocalLock(hProgram);
+  LPSTR lpszCmdLine = LocalLock(program->hCmdLine);
+  LPSTR lpszWorkDir = LocalLock(program->hWorkDir);
+
+  /* FIXME set working direktory */
+  lpszWorkDir = lpszWorkDir;
+
+  WinExec(lpszCmdLine, program->nCmdShow);
+  if (Globals.bMinOnRun) CloseWindow(Globals.hMainWnd);
+}
+
+/***********************************************************************
+ *
+ *           PROGRAM_DeleteProgram
+ */
+
+VOID PROGRAM_DeleteProgram(HLOCAL hProgram, BOOL bUpdateGrpFile)
+{
+  PROGRAM *program = LocalLock(hProgram);
+  GROUP   *group   = LocalLock(program->hGroup);
+
+  group->hActiveProgram = 0;
+
+  if (program->hPrior)
+    ((PROGRAM*)LocalLock(program->hPrior))->hNext = program->hNext;
+  else
+    ((GROUP*)LocalLock(program->hGroup))->hPrograms = program->hNext;
+	
+  if (program->hNext)
+    ((PROGRAM*)LocalLock(program->hNext))->hPrior = program->hPrior;
+
+  if (bUpdateGrpFile)
+    GRPFILE_WriteGroupFile(program->hGroup);
+
+  DestroyWindow(program->hWnd);
+#if 0
+  if (program->hIcon)
+    DestroyIcon(program->hIcon);
+#endif
+  LocalFree(program->hName);
+  LocalFree(program->hCmdLine);
+  LocalFree(program->hIconFile);
+  LocalFree(program->hWorkDir);
+  LocalFree(hProgram);
+}
+
+/***********************************************************************
+ *
+ *           PROGRAM_FirstProgram
+ */
+
+HLOCAL PROGRAM_FirstProgram(HLOCAL hGroup)
+{
+  GROUP *group;
+  if (!hGroup) return(0);
+  group = LocalLock(hGroup);
+  return(group->hPrograms);
+}
+
+/***********************************************************************
+ *
+ *           PROGRAM_NextProgram
+ */
+
+HLOCAL PROGRAM_NextProgram(HLOCAL hProgram)
+{
+  PROGRAM *program;
+  if (!hProgram) return(0);
+  program = LocalLock(hProgram);
+  return(program->hNext);
+}
+
+/***********************************************************************
+ *
+ *           PROGRAM_ActiveProgram
+ */
+
+HLOCAL PROGRAM_ActiveProgram(HLOCAL hGroup)
+{
+  GROUP *group;
+  if (!hGroup) return(0);
+  group = LocalLock(hGroup);
+  if (IsIconic(group->hWnd)) return(0);
+
+  return(group->hActiveProgram);
+}
+
+/***********************************************************************
+ *
+ *           PROGRAM_ProgramName
+ */
+
+LPCSTR PROGRAM_ProgramName(HLOCAL hProgram)
+{
+  PROGRAM *program;
+  if (!hProgram) return(0);
+  program = LocalLock(hProgram);
+  return(LocalLock(program->hName));
+}
+
+/* Local Variables:    */
+/* c-file-style: "GNU" */
+/* End:                */
diff --git a/programs/progman/string.c b/programs/progman/string.c
new file mode 100644
index 0000000..a040855
--- /dev/null
+++ b/programs/progman/string.c
@@ -0,0 +1,92 @@
+/*
+ * Program Manager
+ *
+ * Copyright 1996 Ulrich Schmid
+ */
+
+#include <windows.h>
+#include "progman.h"
+
+/* Class names */
+
+CHAR STRING_MAIN_WIN_CLASS_NAME[]    = "PMMain";
+CHAR STRING_MDI_WIN_CLASS_NAME[]     = "MDICLIENT";
+CHAR STRING_GROUP_WIN_CLASS_NAME[]   = "PMGroup";
+CHAR STRING_PROGRAM_WIN_CLASS_NAME[] = "PMProgram";
+
+/* Resource names */
+/* Xx will be overwritten with En, ... */
+CHAR STRING_ACCEL[]      = "ACCEL";
+CHAR STRING_MAIN_Xx[]    = "MENU_Xx";
+CHAR STRING_NEW_Xx[]     = "DIALOG_NEW_Xx";
+CHAR STRING_OPEN_Xx[]    = "DIALOG_OPEN_Xx";
+CHAR STRING_MOVE_Xx[]    = "DIALOG_MOVE_Xx";
+CHAR STRING_COPY_Xx[]    = "DIALOG_COPY_Xx";
+CHAR STRING_DELETE_Xx[]  = "DIALOG_DELETE_Xx";
+CHAR STRING_GROUP_Xx[]   = "DIALOG_GROUP_Xx";
+CHAR STRING_PROGRAM_Xx[] = "DIALOG_PROGRAM_Xx";
+CHAR STRING_SYMBOL_Xx[]  = "DIALOG_SYMBOL_Xx";
+CHAR STRING_EXECUTE_Xx[] = "DIALOG_EXECUTE_Xx";
+
+static LPCSTR StringTableEn[];
+static LPCSTR StringTableDe[];
+
+VOID STRING_SelectLanguage(LPCSTR lang)
+{
+  /* Change string table */
+  Globals.StringTable = StringTableEn;
+  if (!lstrcmp(lang, "De")) Globals.StringTable = StringTableDe;
+
+  SetWindowText(Globals.hMainWnd, STRING_PROGRAM_MANAGER);
+
+  /* Change Resource names */
+  lstrcpyn(STRING_MAIN_Xx    + sizeof(STRING_MAIN_Xx)    - 3, lang, 3);
+  lstrcpyn(STRING_NEW_Xx     + sizeof(STRING_NEW_Xx)     - 3, lang, 3);
+  lstrcpyn(STRING_OPEN_Xx    + sizeof(STRING_OPEN_Xx)    - 3, lang, 3);
+  lstrcpyn(STRING_MOVE_Xx    + sizeof(STRING_MOVE_Xx)    - 3, lang, 3);
+  lstrcpyn(STRING_COPY_Xx    + sizeof(STRING_COPY_Xx)    - 3, lang, 3);
+  lstrcpyn(STRING_DELETE_Xx  + sizeof(STRING_DELETE_Xx)  - 3, lang, 3);
+  lstrcpyn(STRING_GROUP_Xx   + sizeof(STRING_GROUP_Xx)   - 3, lang, 3);
+  lstrcpyn(STRING_PROGRAM_Xx + sizeof(STRING_PROGRAM_Xx) - 3, lang, 3);
+  lstrcpyn(STRING_SYMBOL_Xx  + sizeof(STRING_SYMBOL_Xx)  - 3, lang, 3);
+  lstrcpyn(STRING_EXECUTE_Xx + sizeof(STRING_EXECUTE_Xx) - 3, lang, 3);
+
+  /* Destroy old menu */
+  if (Globals.hMainMenu)
+  {
+    SendMessage(Globals.hMDIWnd, WM_MDISETMENU, (WPARAM) NULL, (LPARAM) NULL);
+#if 0 /* FIXME when MDISetMenu is complete */
+    DestroyMenu(Globals.hMainMenu);
+#endif
+  }
+
+  /* Create new menu */
+  Globals.hMainMenu = LoadMenu(Globals.hInstance, STRING_MAIN_Xx);
+  if (Globals.hMainMenu)
+  {
+    Globals.hFileMenu    = GetSubMenu(Globals.hMainMenu, 0);
+    Globals.hOptionMenu  = GetSubMenu(Globals.hMainMenu, 1);
+    Globals.hWindowsMenu = GetSubMenu(Globals.hMainMenu, 2);
+
+    if (Globals.hMDIWnd)
+      SendMessage(Globals.hMDIWnd, WM_MDISETMENU,
+		  (WPARAM) Globals.hMainMenu,
+		  (LPARAM) Globals.hWindowsMenu);
+    else SetMenu(Globals.hMainWnd, Globals.hMainMenu);
+  }
+  /* Unsupported language */
+  else if(lstrcmp(lang, "En")) STRING_SelectLanguage("En");
+  else
+  {
+    MessageBox(Globals.hMainWnd, "No language found", "FATAL ERROR", MB_OK);
+    PostQuitMessage(1);
+  }
+
+  /* have to be last because of
+   * the possible recursion */
+  Globals.lpszLanguage = lang;
+}
+
+/* Local Variables:    */
+/* c-file-style: "GNU" */
+/* End:                */
diff --git a/programs/progman/winexec.c b/programs/progman/winexec.c
new file mode 100644
index 0000000..722576c
--- /dev/null
+++ b/programs/progman/winexec.c
@@ -0,0 +1,91 @@
+#ifdef WINELIB
+#include <unistd.h>
+#include <string.h>
+#include "windows.h"
+#include "winbase.h"
+#include "options.h"
+#include "dos_fs.h"
+#include "debug.h"
+#include "progman.h"
+
+#define MAX_CMDLINE_SIZE 256
+
+/* FIXME should use WinExec from -lwine */
+
+HANDLE ProgmanWinExec( LPSTR lpCmdLine, WORD nCmdShow )
+{
+  char  wine[MAX_CMDLINE_SIZE];
+  char  filename[MAX_CMDLINE_SIZE], *p;
+  char  cmdline[MAX_CMDLINE_SIZE];
+  const char *argv[10], **argptr;
+  const char *unixfilename;
+  int   simplename = 1;
+
+  if (fork()) return(INVALID_HANDLE_VALUE);
+
+  strncpy( filename, lpCmdLine, MAX_CMDLINE_SIZE );
+  filename[MAX_CMDLINE_SIZE-1] = '\0';
+  for (p = filename; *p && (*p != ' ') && (*p != '\t'); p++)
+    if ((*p == ':') || (*p == ':') || (*p == '/')) simplename = 0;
+  if (*p)
+    {
+      strncpy( cmdline, p + 1, 128 );
+      cmdline[127] = '\0';
+    }
+  else cmdline[0] = '\0';
+  *p = '\0';
+
+  if (simplename) unixfilename = filename;
+  else unixfilename = DOSFS_GetUnixFileName(filename, 0);
+
+  argptr = argv;
+  *argptr++ = unixfilename;
+  if (nCmdShow == SW_SHOWMINIMIZED) *argptr++ = "-iconic";
+  if (cmdline[0]) *argptr++ = cmdline;
+  *argptr++ = 0;
+  execvp(argv[0], (char**)argv);
+
+  PROFILE_GetWineIniString("progman", "wine", "wine", 
+			   wine, sizeof(wine));
+  argptr = argv;
+  *argptr++ = wine;
+  *argptr++ = "-language";
+  *argptr++ = Globals.lpszLanguage;
+  if (nCmdShow == SW_SHOWMINIMIZED) *argptr++ = "-iconic";
+  *argptr++ = lpCmdLine;
+  *argptr++ = 0;
+  execvp(argv[0] , (char**)argv);
+
+  printf("Cannot exec `%s %s %s%s %s'\n",
+	 wine, "-language", Globals.lpszLanguage,
+	 nCmdShow == SW_SHOWMINIMIZED ? " -iconic" : "",
+	 lpCmdLine);
+  exit(1);
+}
+
+BOOL ProgmanWinHelp(HWND hWnd, LPSTR lpHelpFile, WORD wCommand, DWORD dwData)
+{
+  char	str[256];
+  dprintf_exec(stddeb,"WinHelp(%s, %u, %lu)\n", 
+	       lpHelpFile, wCommand, dwData);
+  switch(wCommand) {
+  case 0:
+  case HELP_HELPONHELP:
+    GetWindowsDirectory(str, sizeof(str));
+    strcat(str, "\\winhelp.exe winhelp.hlp");
+    dprintf_exec(stddeb,"'%s'\n", str);
+    break;
+  case HELP_INDEX:
+    GetWindowsDirectory(str, sizeof(str));
+    strcat(str, "\\winhelp.exe ");
+    strcat(str, lpHelpFile);
+    dprintf_exec(stddeb,"'%s'\n", str);
+    break;
+  default:
+    return FALSE;
+  }
+  WinExec(str, SW_SHOWNORMAL);
+  return(TRUE);
+}
+
+#endif