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/ANNOUNCE b/ANNOUNCE
index 8ba1e3b..662f7c4 100644
--- a/ANNOUNCE
+++ b/ANNOUNCE
@@ -1,15 +1,15 @@
-This is release 960225 of Wine the MS Windows emulator.  This is still a
+This is release 960302 of Wine the MS Windows emulator.  This is still a
 developer's only release.  There are many bugs and many unimplemented API
 features.  Most applications still do not work.
 
 Patches should be submitted to "julliard@lrc.epfl.ch".  Please don't
 forget to include a ChangeLog entry.
 
-WHAT'S NEW with Wine-960225: (see ChangeLog for details)
-	- Many caret fixes.
-	- New -mode option to replace -enhanced.
-	- Many listboxes improvements.
-	- Find and Replace dialogs in built-in COMMDLG fixed.
+WHAT'S NEW with Wine-960302: (see ChangeLog for details)
+	- Program manager clone using Winelib.
+	- Support for Esperanto language.
+	- Some scrollbar fixes.
+	- Edit control improvements.
 	- Lots of bug fixes.
 
 See the README file in the distribution for installation instructions.
@@ -18,10 +18,10 @@
 the release is available at the ftp sites.  The sources will be available
 from the following locations:
 
-    sunsite.unc.edu:/pub/Linux/ALPHA/wine/development/Wine-960225.tar.gz
-    tsx-11.mit.edu:/pub/linux/ALPHA/Wine/development/Wine-960225.tar.gz
-    ftp.infomagic.com:/pub/mirrors/linux/wine/development/Wine-960225.tar.gz
-    aris.com:/pub/linux/ALPHA/Wine/development/Wine-960225.tar.gz
+    sunsite.unc.edu:/pub/Linux/ALPHA/wine/development/Wine-960302.tar.gz
+    tsx-11.mit.edu:/pub/linux/ALPHA/Wine/development/Wine-960302.tar.gz
+    ftp.infomagic.com:/pub/mirrors/linux/wine/development/Wine-960302.tar.gz
+    aris.com:/pub/linux/ALPHA/Wine/development/Wine-960302.tar.gz
 
 It should also be available from any site that mirrors tsx-11 or sunsite.
 
diff --git a/ChangeLog b/ChangeLog
index 42953b0..3ab435b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,114 @@
 ----------------------------------------------------------------------
+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.
+
+----------------------------------------------------------------------
 Sat Feb 24 16:17:05 1996  Alexandre Julliard  <julliard@lrc.epfl.ch>
 
 	* [files/profile.c]
diff --git a/Make.rules.in b/Make.rules.in
index d871a6f..3ae1d05 100644
--- a/Make.rules.in
+++ b/Make.rules.in
@@ -42,7 +42,7 @@
 	echo "#include \"windows.h\"" >winerctmp.c
 	echo WINDOWS_H_ENDS_HERE >>winerctmp.c
 	cat $< >>winerctmp.c
-	$(CPP) $(DEFS) $(DIVINCL) -P winerctmp.c | sed -e '1,/^WINDOWS_H_ENDS_HERE/d' | $(WINERC) -c -o $* -p $*
+	$(CPP) $(DEFS) $(DIVINCL) -DRC_INVOKED -P winerctmp.c | sed -e '1,/^WINDOWS_H_ENDS_HERE/d' | $(WINERC) -c -o $* -p $*
 	$(RM) winerctmp.c
 
 .rc.h:
diff --git a/Makefile.in b/Makefile.in
index dbbe50e..42f935e 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -69,7 +69,9 @@
 
 LIBSUBDIRS = library
 
-ALLSUBDIRS = $(COMMONSUBDIRS) $(EMUSUBDIRS) $(LIBSUBDIRS) libtest
+PROGSUBDIRS = libtest programs
+
+ALLSUBDIRS = $(COMMONSUBDIRS) $(EMUSUBDIRS) $(LIBSUBDIRS) $(PROGSUBDIRS)
 
 COMMONOBJS = \
 	controls/controls.o \
diff --git a/configure b/configure
index ba6c93e..df78b45 100755
--- a/configure
+++ b/configure
@@ -1962,6 +1962,8 @@
 miscemu/Makefile
 multimedia/Makefile
 objects/Makefile
+programs/Makefile
+programs/progman/Makefile
 rc/Makefile
 resources/Makefile
 tools/Makefile
@@ -2034,6 +2036,8 @@
 miscemu/Makefile
 multimedia/Makefile
 objects/Makefile
+programs/Makefile
+programs/progman/Makefile
 rc/Makefile
 resources/Makefile
 tools/Makefile
diff --git a/configure.in b/configure.in
index 9fbbd12..ff6531b 100644
--- a/configure.in
+++ b/configure.in
@@ -97,6 +97,8 @@
 miscemu/Makefile
 multimedia/Makefile
 objects/Makefile
+programs/Makefile
+programs/progman/Makefile
 rc/Makefile
 resources/Makefile
 tools/Makefile
diff --git a/controls/desktop.c b/controls/desktop.c
index 77faca7..c0d48fb 100644
--- a/controls/desktop.c
+++ b/controls/desktop.c
@@ -149,6 +149,10 @@
     case WM_ERASEBKGND:
 	if (rootWindow == DefaultRootWindow(display)) return 1;
 	return DESKTOP_DoEraseBkgnd( hwnd, (HDC)wParam, infoPtr );
+
+    case WM_SYSCOMMAND:
+	if ((wParam & 0xfff0) != SC_CLOSE) return 0;
+	ExitWindows( 0, 0 );
     }
     
     return 0;
diff --git a/controls/edit.c b/controls/edit.c
index 73ce404..e952589 100644
--- a/controls/edit.c
+++ b/controls/edit.c
@@ -19,7 +19,7 @@
 #include "stddebug.h"
 #include "debug.h"
 #include "xmalloc.h"
-
+#include "callback.h"
 
 #ifdef WINELIB32
 #define NOTIFY_PARENT(hWndCntrl, wNotifyCode) \
@@ -71,8 +71,15 @@
     int ClientWidth;         /* computed from the window's ClientRect */
     int ClientHeight;        /* ditto */
     char PasswordChar;       /* The password character */
+    EDITWORDBREAKPROC WordBreakProc;
+    BOOL WeOwnCaret;         /* Do we own the caret ? */
+    int CaretPrepareCount;   /* Did we already prepare the caret ? */
+    BOOL CaretHidden;        /* Did we hide the caret during painting ? */
+    int oldWndCol;           /* WndCol before we started painting */
+    int oldWndRow;           /* ditto for WndRow */
 } EDITSTATE;
 
+
 #define EditBufStartLen(hwnd) (GetWindowLong(hwnd,GWL_STYLE) & ES_MULTILINE \
 			       ? EDITLEN : ENTRYLEN)
 #define CurrChar (EDIT_TextLine(hwnd, es->CurrLine) + es->CurrCol)
@@ -98,6 +105,7 @@
 
 #define SWAP_INT(x,y) do { int temp = (x); (x) = (y); (y) = temp; } while(0)
 
+
 /*********************************************************************
  *  EDIT_HeapAlloc
  *
@@ -197,6 +205,105 @@
 }
 
 /*********************************************************************
+ *  EDIT_CaretPrepare
+ *
+ *  Save the caret state before any painting is done.
+ */
+static void EDIT_CaretPrepare(HWND hwnd)
+{
+    EDITSTATE *es = EDIT_GetEditState(hwnd);
+
+    if (!es) return;
+
+    if (!es->CaretPrepareCount)
+    {
+	es->CaretHidden = FALSE;
+	es->oldWndCol = es->WndCol;
+	es->oldWndRow = es->WndRow;
+    }
+
+    es->CaretPrepareCount++;
+}
+
+/*********************************************************************
+ *  EDIT_CaretHide
+ *
+ *  Called before some painting is done.
+ */
+static void EDIT_CaretHide(HWND hwnd)
+{
+    EDITSTATE *es = EDIT_GetEditState(hwnd);
+
+    if (!es) return;
+    if (!es->WeOwnCaret) return;
+    if (!es->CaretPrepareCount) return;
+    
+    if (!es->CaretHidden)
+    {
+    	HideCaret(hwnd);
+    	es->CaretHidden = TRUE;
+    }
+}
+
+/*********************************************************************
+ *  EDIT_CaretUpdate
+ *
+ *  Called after all painting is done.
+ */
+static void EDIT_CaretUpdate(HWND hwnd)
+{
+    EDITSTATE *es = EDIT_GetEditState(hwnd);
+
+    if (!es) return;
+    if (!es->CaretPrepareCount) return;
+    
+    es->CaretPrepareCount--;
+    
+    if (es->CaretPrepareCount) return;
+    if (!es->WeOwnCaret) return;
+
+    if ((es->WndCol != es->oldWndCol) || (es->WndRow != es->oldWndRow))
+	SetCaretPos(es->WndCol, es->WndRow * es->txtht);
+
+    if (es->CaretHidden)
+    {
+	ShowCaret(hwnd);
+	es->CaretHidden = FALSE;
+    }
+}
+
+/*********************************************************************
+ *  EDIT_WordBreakProc
+ *
+ *  Find the beginning of words.
+ */
+static int CALLBACK EDIT_WordBreakProc(char * pch, int ichCurrent,
+					int cch, int code)
+{
+    dprintf_edit(stddeb, "EDIT_WordBreakProc: pch=%p, ichCurrent=%d"
+	", cch=%d, code=%d\n", pch, ichCurrent, cch, code);
+
+    dprintf_edit(stddeb, "string=%s\n", pch);
+    return 0;
+}
+
+/*********************************************************************
+ *  EDIT_CallWordBreakProc
+ *
+ *  Call appropriate WordBreakProc (internal or external).
+ */
+static int CALLBACK EDIT_CallWordBreakProc(HWND hwnd, char *pch, 
+					int ichCurrent, int cch, int code)
+{
+    EDITSTATE *es = EDIT_GetEditState(hwnd);
+    
+    if (es->WordBreakProc) {
+	/* FIXME: do some stuff to make pch a SEGPTR */
+	return CallWordBreakProc((FARPROC)es->WordBreakProc, (LONG)pch, ichCurrent, cch, code);
+    } else return EDIT_WordBreakProc(pch, ichCurrent, cch, code);
+}
+
+/*********************************************************************
  *  EDIT_GetNextTabStop
  *
  *  Return the next tab stop beyond _pcol_.
@@ -466,6 +573,8 @@
 
     dprintf_edit(stddeb,"EDIT_WriteText lp=%s, off=%d, len=%d, row=%d, col=%d, reverse=%d\n", lp, off, len, row, col, reverse);
 
+    EDIT_CaretHide(hwnd);
+
     if( off < 0 ) {
       len += off;
       col -= off;
@@ -832,6 +941,8 @@
 
     if (IsWindowVisible(hwnd))
     {
+	EDIT_CaretHide(hwnd);    
+
 	/* adjust client bottom to nearest whole line */
 	GetClientRect(hwnd, &rc);
 	rc.bottom = (rc.bottom / es->txtht) * es->txtht;
@@ -1196,6 +1307,8 @@
 
     if (IsWindowVisible(hwnd))
     {
+	EDIT_CaretHide(hwnd);
+
 	/* adjust client bottom to nearest whole line */
 	GetClientRect(hwnd, &rc);
 	rc.bottom = (rc.bottom / es->txtht) * es->txtht;
@@ -1747,7 +1860,6 @@
     NOTIFY_PARENT(hwnd, EN_UPDATE);
 
     /* re-adjust textwidth, if necessary, and redraw line */
-    HideCaret(hwnd);
     if (IsMultiLine(hwnd) && es->wlines > 1)
     {
 	es->textwidth = MAX(es->textwidth,
@@ -1775,8 +1887,6 @@
 	    rc.top = es->WndRow * es->txtht;
 	InvalidateRect(hwnd, &rc, FALSE);
 
-	SetCaretPos(es->WndCol, es->WndRow * es->txtht);
-	ShowCaret(hwnd);
 	UpdateWindow(hwnd);
 	NOTIFY_PARENT(hwnd, EN_CHANGE);
 	return;
@@ -1795,8 +1905,6 @@
     es->CurrCol++;
     EDIT_SetAnchor(hwnd, es->CurrLine, es->CurrCol);
     EDIT_WriteTextLine(hwnd, NULL, es->wtop + es->WndRow);
-    SetCaretPos(es->WndCol, es->WndRow * es->txtht);
-    ShowCaret(hwnd);
     NOTIFY_PARENT(hwnd, EN_CHANGE);
     dprintf_edit(stddeb,"KeyTyped O.K.\n");
 }
@@ -2150,6 +2258,14 @@
     es->PaintBkgd = TRUE;
     if (lParam) UpdateWindow(hwnd);
     EDIT_RecalcSize(hwnd,es);
+
+    if (es->WeOwnCaret)
+    {
+	EDIT_CaretHide(hwnd);
+	DestroyCaret();
+	CreateCaret(hwnd, 0, 2, es->txtht);
+	SetCaretPos(es->WndCol, es->WndRow * es->txtht);
+    }
 }
 
 /*********************************************************************
@@ -2186,6 +2302,8 @@
     RECT rc;
     EDITSTATE *es = EDIT_GetEditState(hwnd);
 
+    EDIT_CaretHide(hwnd);
+
     hdc = BeginPaint(hwnd, &ps);
     GetClientRect(hwnd, &rc);
     IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
@@ -2237,6 +2355,13 @@
     /* --- text buffer */
     es->MaxTextLen = MAXTEXTLEN + 1;
     es->PasswordChar = '*';
+    
+    es->WordBreakProc = NULL;
+    
+    /* Caret stuff */
+    es->CaretPrepareCount = 1;
+    es->CaretHidden = FALSE;
+    es->WeOwnCaret = FALSE;
     /*
      * Hack - If there is no local heap then hwnd should be a globalHeap block
      * and the local heap needs to be initilised to the same size(minus something)
@@ -2384,12 +2509,11 @@
  */
 static void EDIT_WM_VScroll(HWND hwnd, WORD wParam, LONG lParam)
 {
-    EDITSTATE *es = EDIT_GetEditState(hwnd);
-
+/*
+ *    EDITSTATE *es = EDIT_GetEditState(hwnd);
+ */
     if (IsMultiLine(hwnd))
     {
-	HideCaret(hwnd);
-
 	switch (wParam)
 	{
 	case SB_LINEUP:
@@ -2403,9 +2527,6 @@
 	    break;
 	}
     }
-    
-    SetCaretPos(es->WndCol, es->WndRow);
-    ShowCaret(hwnd);
 }
 
 /*********************************************************************
@@ -2413,16 +2534,13 @@
  */
 static void EDIT_WM_HScroll(HWND hwnd, WORD wParam, LONG lParam)
 {
-    EDITSTATE *es = EDIT_GetEditState(hwnd);
-
+/*
+ *    EDITSTATE *es = EDIT_GetEditState(hwnd);
+ */
     switch (wParam)
     {
     case SB_LINEUP:
     case SB_LINEDOWN:
-	HideCaret(hwnd);
-
-	SetCaretPos(es->WndCol, es->WndRow * es->txtht);
-	ShowCaret(hwnd);
 	break;
     }
 }
@@ -2489,11 +2607,11 @@
  */
 static void EDIT_WM_MouseMove(HWND hwnd, WORD wParam, LONG lParam)
 {
-    EDITSTATE *es = EDIT_GetEditState(hwnd);
-
+/*
+ *    EDITSTATE *es = EDIT_GetEditState(hwnd);
+ */
     if (!(wParam & MK_LBUTTON)) return;
 
-    HideCaret(hwnd);
     if (ButtonDown)
     {
 	TextMarking = TRUE;
@@ -2501,11 +2619,7 @@
     }
 
     if (TextMarking)
-    {
 	EDIT_ExtendSel(hwnd, LOWORD(lParam), HIWORD(lParam));
-        SetCaretPos(es->WndCol, es->WndRow * es->txtht);
-    }
-    ShowCaret(hwnd);
 }
 
 /*********************************************************************
@@ -2548,7 +2662,6 @@
 
     dprintf_edit(stddeb,"EDIT_WM_KeyDown: key=%x\n", wParam);
 
-    HideCaret(hwnd);
     switch (wParam)
     {
     case VK_UP:
@@ -2627,7 +2740,6 @@
         break;
 
     default:
-        ShowCaret(hwnd);
         return;
     }
 
@@ -2641,8 +2753,6 @@
     } else {
         EDIT_SetAnchor(hwnd, es->CurrLine, es->CurrCol);
     }
-    SetCaretPos(es->WndCol, es->WndRow * es->txtht);
-    ShowCaret(hwnd);
 }
 
 /*********************************************************************
@@ -2689,6 +2799,8 @@
     int len;
     EDITSTATE *es = EDIT_GetEditState(hwnd);
 
+    EDIT_CaretPrepare(hwnd);
+
     switch (uMsg) {
     case EM_CANUNDO:
 	lResult = (LONG)es->hDeletedText;
@@ -2733,7 +2845,6 @@
 	break;
 
     case EM_GETPASSWORDCHAR:
-        /* FIXME: is this the right place to return the character? */
         lResult = es->PasswordChar;
 	break;
 
@@ -2746,7 +2857,8 @@
 	break;
 
     case EM_GETWORDBREAKPROC:
-	fprintf(stdnimp,"edit: cannot process EM_GETWORDBREAKPROC message\n");
+	dprintf_edit(stddeb, "EM_GETWORDBREAKPROC\n");
+	lResult = (LONG)es->WordBreakProc;
 	break;
 
     case EM_LIMITTEXT:
@@ -2778,18 +2890,12 @@
 	break;
 
     case EM_REPLACESEL:
-	HideCaret(hwnd);
 	EDIT_ReplaceSel(hwnd, lParam);
-	SetCaretPos(es->WndCol, es->WndRow * es->txtht);
-	ShowCaret(hwnd);
 	break;
 
     case EM_SETHANDLE:
-	HideCaret(hwnd);
 	EDIT_ClearDeletedText(hwnd);
 	EDIT_SetHandleMsg(hwnd, wParam);
-	SetCaretPos(es->WndCol, es->WndRow * es->txtht);
-	ShowCaret(hwnd);
 	break;
 
     case EM_SETMODIFY:
@@ -2810,10 +2916,7 @@
 	break;
 
     case EM_SETSEL:
-	HideCaret(hwnd);
 	EDIT_SetSelMsg(hwnd, wParam, lParam);
-	SetCaretPos(es->WndCol, es->WndRow * es->txtht);
-	ShowCaret(hwnd);
 	break;
 
     case EM_SETTABSTOPS:
@@ -2821,18 +2924,18 @@
 	break;
 
     case EM_SETWORDBREAKPROC:
-	fprintf(stdnimp,"edit: cannot process EM_SETWORDBREAKPROC message\n");
+	dprintf_edit(stddeb, "EM_SETWORDBREAKPROC, lParam=%08lx\n",
+			(DWORD)lParam);
+	es->WordBreakProc = (EDITWORDBREAKPROC)lParam;
 	break;
 
     case EM_UNDO:
-	HideCaret(hwnd);
 	lResult = EDIT_UndoMsg(hwnd);
-	SetCaretPos(es->WndCol, es->WndRow * es->txtht);
-	ShowCaret(hwnd);
 	break;
 
     case WM_GETDLGCODE:
-        return DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS;
+        lResult = DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS;
+	break;
 
     case WM_CHAR:
 	EDIT_WM_Char(hwnd, wParam);
@@ -2895,6 +2998,7 @@
 	dprintf_edit(stddeb, "WM_KILLFOCUS\n");
 	es->HaveFocus = FALSE;
 	DestroyCaret();
+	es->WeOwnCaret = FALSE;
 	if (SelMarked(es))
             if(GetWindowLong(hwnd,GWL_STYLE) & ES_NOHIDESEL)
 	        EDIT_UpdateSel(hwnd);
@@ -2904,12 +3008,9 @@
 	break;
 
     case WM_LBUTTONDOWN:
-	HideCaret(hwnd);
 	SetFocus(hwnd);
 	SetCapture(hwnd);
 	EDIT_WM_LButtonDown(hwnd, wParam, lParam);
-	SetCaretPos(es->WndCol, es->WndRow * es->txtht);
-	ShowCaret(hwnd);
 	break;
 
     case WM_LBUTTONUP:
@@ -2945,16 +3046,14 @@
 	es->HaveFocus = TRUE;
 	if (SelMarked(es)) EDIT_UpdateSel(hwnd);
 	CreateCaret(hwnd, 0, 2, es->txtht);
+	es->WeOwnCaret = TRUE;
 	SetCaretPos(es->WndCol, es->WndRow * es->txtht);
-	ShowCaret(hwnd);
+	es->CaretHidden = TRUE;
 	NOTIFY_PARENT(hwnd, EN_SETFOCUS);
 	break;
 
     case WM_SETFONT:
-	HideCaret(hwnd);
 	EDIT_WM_SetFont(hwnd, wParam, lParam);
-	SetCaretPos(es->WndCol, es->WndRow * es->txtht);
-	ShowCaret(hwnd);
 	break;
 #if 0
     case WM_SETREDRAW:
@@ -2988,6 +3087,8 @@
 	break;
     }
 
+    EDIT_CaretUpdate(hwnd);
+
     return lResult;
 }
 
diff --git a/controls/listbox.c b/controls/listbox.c
index 3d24874..3365cde 100644
--- a/controls/listbox.c
+++ b/controls/listbox.c
@@ -2096,16 +2096,8 @@
         if (!filespec[0]) strcpy( mask, "*.*" );
         else
         {
-            const char *ptr;
-            BYTE attr;
-            if (((ptr = DOSFS_GetUnixFileName( filespec, TRUE )) != NULL) &&
-                FILE_Stat( ptr, &attr, NULL, NULL, NULL ) &&
-                (attr & FA_DIRECTORY))
-            {
-                /* If the path exists and is a directory, chdir to it */
-                if (!DRIVE_Chdir( drive, filespec )) return FALSE;
-                strcpy( mask, "*.*" );
-            }
+            /* If the path exists and is a directory, chdir to it */
+            if (DRIVE_Chdir( drive, filespec )) strcpy( mask, "*.*" );
             else
             {
                 char *p, *p2;
diff --git a/controls/scroll.c b/controls/scroll.c
index aac0ecf..e746ec5 100644
--- a/controls/scroll.c
+++ b/controls/scroll.c
@@ -70,6 +70,10 @@
     SCROLL_BOTTOM_ARROW  /* Bottom or right arrow */
 };
 
+ /* Thumb-tracking info */
+static HWND hwndTracking = 0;
+static int nBarTracking = 0;
+static UINT uTrackingPos = 0;
 
 /***********************************************************************
  *           SCROLL_LoadBitmaps
@@ -430,6 +434,8 @@
     Rectangle( hdc, r.left, r.top, r.right, r.bottom );
     InflateRect( &r, -1, -1 );
     GRAPH_DrawReliefRect( hdc, &r, 1, 2, FALSE );
+    if ((hwndTracking == hwnd) && (nBarTracking == nBar))
+        SCROLL_DrawMovingThumb( hdc, &rect, vertical, arrowSize, uTrackingPos);
 }
 
 
@@ -607,9 +613,6 @@
         {
             if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
             {
-                SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
-                                SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
-                                (FARPROC)0 );
 #ifdef WINELIB32
                 SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
                              (WPARAM)SB_LINEUP, (LPARAM)hwndCtl );
@@ -617,6 +620,9 @@
                 SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
                              SB_LINEUP, MAKELONG( 0, hwndCtl ));
 #endif
+                SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
+                                SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
+                                (FARPROC)0 );
             }
         }
         else KillSystemTimer( hwnd, SCROLL_TIMER );
@@ -630,9 +636,6 @@
         {
             if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
             {
-                SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
-                                SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
-                                (FARPROC)0 );
 #ifdef WINELIB32
                 SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
                              (WPARAM)SB_PAGEUP, (LPARAM)hwndCtl );
@@ -640,6 +643,9 @@
                 SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
                              SB_PAGEUP, MAKELONG( 0, hwndCtl ));
 #endif
+                SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
+                                SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
+                                (FARPROC)0 );
             }
         }
         else KillSystemTimer( hwnd, SCROLL_TIMER );
@@ -647,11 +653,18 @@
 
     case SCROLL_THUMB:
         if (msg == WM_LBUTTONDOWN)
+        {
             SCROLL_DrawMovingThumb( hdc, &rect, vertical, arrowSize,
                                  trackThumbPos + lastMousePos - lastClickPos );
+            hwndTracking = hwnd;
+            nBarTracking = nBar;
+        }
         else if (msg == WM_LBUTTONUP)
+        {
+            hwndTracking = 0;
             SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbPos,
                                  infoPtr->flags, vertical, FALSE, FALSE );
+        }
         else  /* WM_MOUSEMOVE */
         {
             UINT pos, val;
@@ -662,11 +675,11 @@
             {
                 SCROLL_DrawMovingThumb( hdc, &rect, vertical, arrowSize,
                                  trackThumbPos + lastMousePos - lastClickPos );
-                SCROLL_DrawMovingThumb( hdc, &rect, vertical, arrowSize,
-                                       trackThumbPos + pos - lastClickPos );
                 lastMousePos = pos;
                 val = SCROLL_GetThumbVal( infoPtr, &rect, vertical,
                                  trackThumbPos + lastMousePos - lastClickPos );
+                /* Save tracking info */
+                uTrackingPos = trackThumbPos + pos - lastClickPos;
 #ifdef WINELIB32
                 SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
                              MAKEWPARAM(SB_THUMBTRACK,val), (LPARAM)hwndCtl );
@@ -674,6 +687,8 @@
                 SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
                              SB_THUMBTRACK, MAKELONG( val, hwndCtl ));
 #endif
+                SCROLL_DrawMovingThumb( hdc, &rect, vertical,
+                                        arrowSize, uTrackingPos );
             }
         }
         break;
@@ -686,9 +701,6 @@
         {
             if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
             {
-                SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
-                                SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
-                                (FARPROC)0 );
 #ifdef WINELIB32
                 SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
                              (WPARAM)SB_PAGEDOWN, (LPARAM)hwndCtl );
@@ -696,6 +708,9 @@
                 SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
                              SB_PAGEDOWN, MAKELONG( 0, hwndCtl ));
 #endif
+                SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
+                                SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
+                                (FARPROC)0 );
             }
         }
         else KillSystemTimer( hwnd, SCROLL_TIMER );
@@ -708,9 +723,6 @@
         {
             if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
             {
-                SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
-                                SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
-                                (FARPROC)0 );
 #ifdef WINELIB32
                 SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
                              (WPARAM)SB_LINEDOWN, (LPARAM)hwndCtl );
@@ -718,6 +730,9 @@
                 SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
                              SB_LINEDOWN, MAKELONG( 0, hwndCtl ));
 #endif
+                SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
+                                SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
+                                (FARPROC)0 );
             }
         }
         else KillSystemTimer( hwnd, SCROLL_TIMER );
diff --git a/files/file.c b/files/file.c
index 0ba36fd..8ea3d1e 100644
--- a/files/file.c
+++ b/files/file.c
@@ -657,11 +657,6 @@
     lstrcpyn( ofs->szPathName, DOSFS_GetDosTrueName( ofs->szPathName, FALSE ),
               sizeof(ofs->szPathName) );
 
-    if (mode & OF_PARSE) 
-    {
-          dprintf_file( stddeb, "FILE_Openfile: %s  return = 0\n", name);
-          return 0;
-    }
     if (mode & OF_DELETE)
     {
         if (unlink( unixName ) == -1) goto not_found;
@@ -690,13 +685,18 @@
             if (memcmp( ofs->reserved, &st.st_mtime, sizeof(ofs->reserved) ))
             {
                 dprintf_file( stddeb, "FILE_Openfile: %s  return = -1\n", name);
+                close( handle );
                 return -1;
             }
         }
         memcpy( ofs->reserved, &st.st_mtime, sizeof(ofs->reserved) );
     }
 
-    if (mode & OF_EXIST) close( handle );
+    if (mode & OF_EXIST)
+    {
+        close( handle );
+        return 0;
+    }
     dprintf_file( stddeb, "FILE_Openfile: %s  return = %d\n", name,handle);
 
     return handle;
diff --git a/files/profile.c b/files/profile.c
index 9516811..9932328 100644
--- a/files/profile.c
+++ b/files/profile.c
@@ -7,6 +7,7 @@
 
 #include <ctype.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include "dos_fs.h"
diff --git a/if1632/relay32.c b/if1632/relay32.c
index 54c1898..a104958 100644
--- a/if1632/relay32.c
+++ b/if1632/relay32.c
@@ -142,7 +142,7 @@
 	struct w_files *wpnt;
 	int size;
 	HMODULE hModule;
-	LOADEDFILEINFO *pFileInfo;
+	OFSTRUCT *pFileInfo;
 	char *pStr;
 	wpnt=xmalloc(sizeof(struct w_files));
 	wpnt->hinstance=0;
@@ -151,7 +151,8 @@
 	wpnt->mz_header=wpnt->pe=0;
 	size=sizeof(NE_MODULE) +
 		/* loaded file info */
-		sizeof(LOADEDFILEINFO) + strlen(dll->name) +
+		sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName) +
+                strlen(dll->name) + 1 +
 		/* name table */
 		12 +
 		/* several empty tables */
@@ -177,10 +178,11 @@
 	pModule->fileinfo=sizeof(NE_MODULE);
 	pModule->os_flags=NE_OSFLAGS_WINDOWS;
 	pModule->expected_version=0x30A;
-	pFileInfo=(LOADEDFILEINFO *)(pModule + 1);
-	pFileInfo->length = sizeof(LOADEDFILEINFO)+strlen(dll->name)-1;
-	strcpy(pFileInfo->filename,dll->name);
-	pStr = ((char*)pFileInfo+pFileInfo->length+1);
+	pFileInfo=(OFSTRUCT *)(pModule + 1);
+	pFileInfo->cBytes = sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName)
+                            + strlen(dll->name);
+	strcpy( pFileInfo->szPathName, dll->name );
+	pStr = ((char*)pFileInfo) + pFileInfo->cBytes + 1;
 	pModule->name_table=(int)pStr-(int)pModule;
 	*pStr=strlen(dll->name);
 	strcpy(pStr+1,dll->name);
diff --git a/if1632/user.spec b/if1632/user.spec
index 9d4f57b..4df1c0f 100644
--- a/if1632/user.spec
+++ b/if1632/user.spec
@@ -280,7 +280,7 @@
 275 stub RepaintScreen
 276 stub LockMyTask
 277 pascal16 GetDlgCtrlID(word) GetDlgCtrlID
-278 pascal16 GetDeskTopHwnd() GetDesktopWindow
+278 pascal16 GetDesktopHwnd() GetDesktopHwnd
 279 stub OldSetDeskPattern
 280 stub SetSystemMenu
 281 pascal16 GetSysColorBrush(word) GetSysColorBrush
diff --git a/if1632/user32.spec b/if1632/user32.spec
index bb36b0b..763352f 100644
--- a/if1632/user32.spec
+++ b/if1632/user32.spec
@@ -181,7 +181,7 @@
 0170 stdcall EnableScrollBar(long long long)	EnableScrollBar
 0171 stdcall EnableWindow(long long)		EnableWindow
 0172 stub EndDeferWindowPos
-0173 stub EndDialog
+0173 stdcall EndDialog(long long) EndDialog
 0174 stub EndMenu
 0175 stdcall EndPaint(long ptr) USER32_EndPaint
 0176 stub EndTask
@@ -242,8 +242,8 @@
 0231 stub GetDesktopWindow
 0232 stub GetDialogBaseUnits
 0233 stub GetDlgCtrlID
-0234 stub GetDlgItem
-0235 stub GetDlgItemInt
+0234 stdcall GetDlgItem(long long) GetDlgItem
+0235 stdcall GetDlgItemInt(long long long long) GetDlgItemInt
 0236 stub GetDlgItemTextA
 0237 stub GetDlgItemTextW
 0238 stub GetDoubleClickTime
@@ -485,7 +485,7 @@
 0473 stub SetCursorPos
 0474 stub SetDebugErrorLevel
 0475 stub SetDeskWallpaper
-0476 stub SetDlgItemInt
+0476 stdcall SetDlgItemInt(long long long long) SetDlgItemInt
 0477 stub SetDlgItemTextA
 0478 stub SetDlgItemTextW
 0479 stub SetDoubleClickTime
diff --git a/include/callback.h b/include/callback.h
index 1e5649c..4f8b6dd 100644
--- a/include/callback.h
+++ b/include/callback.h
@@ -32,6 +32,7 @@
 extern LONG CallTo16_long_wwl  ( FARPROC, WORD, WORD, WORD, LONG );
 extern WORD CallTo16_word_llwl ( FARPROC, WORD, LONG, LONG, WORD, LONG );
 extern LONG CallTo16_long_wwwl ( FARPROC, WORD, WORD, WORD, WORD, LONG );
+extern WORD CallTo16_word_lwww ( FARPROC, WORD, LONG, WORD, WORD, WORD );
 extern WORD CallTo16_word_wllwl( FARPROC, WORD, WORD, LONG, LONG, WORD, LONG );
 extern WORD CallTo16_word_wwlll( FARPROC, WORD, WORD, WORD, LONG, LONG, LONG );
 
@@ -64,6 +65,8 @@
     CallTo16_word_wwlll( func, CURRENT_DS, id, msg, dwUser, dw1, dw2 )
 #define CallWndProc( func, ds, hwnd, msg, wParam, lParam ) \
     CallTo16_long_wwwl( func, ds, hwnd, msg, wParam, lParam )
+#define CallWordBreakProc( func, lpch, ichCurrent, cch, code ) \
+    CallTo16_word_lwww( func, CURRENT_DS, lpch, ichCurrent, cch, code )
 
 #else  /* WINELIB */
 
@@ -93,6 +96,8 @@
     (*func)( id, msg, dwUser, dw1, dw2 )
 #define CallWndProc( func, ds, hwnd, msg, wParam, lParam ) \
     (*func)( hwnd, msg, wParam, lParam )
+#define CallWordBreakProc( func, lpch, ichCurrent, cch, code ) \
+    (*func)( lpch, ichCurrent, cch, code )
 
 #endif  /* WINELIB */
 
diff --git a/include/module.h b/include/module.h
index 1641754..c19f764 100644
--- a/include/module.h
+++ b/include/module.h
@@ -21,7 +21,7 @@
     WORD    entry_table;      /* Near ptr to entry table */
     HMODULE next;             /* Selector to next module */
     WORD    dgroup_entry;     /* Near ptr to segment entry for DGROUP */
-    WORD    fileinfo;         /* Near ptr to file info (LOADEDFILEINFO) */
+    WORD    fileinfo;         /* Near ptr to file info (OFSTRUCT) */
     WORD    flags;            /* Module flags */
     WORD    dgroup;           /* Logical segment for DGROUP */
     WORD    heap_size;        /* Initial heap size */
@@ -51,17 +51,6 @@
     WORD    self_loading_sel; /* Selector used for self-loading apps. procs */
 } NE_MODULE;
 
-  /* Loaded file info */
-typedef struct
-{
-    BYTE  length;       /* Length of the structure, not counting this byte */
-    BYTE  fixed_media;  /* File is on removable media */
-    WORD  error;        /* Error code (?) */
-    WORD  date;         /* File date in MS-DOS format */
-    WORD  time;         /* File time in MS-DOS format */
-    char  filename[1];  /* File name */
-} LOADEDFILEINFO;
-
   /* In-memory segment table */
 typedef struct
 {
@@ -105,6 +94,9 @@
 #define NE_MODULE_TABLE(pModule) \
     ((WORD *)((char *)(pModule) + (pModule)->modref_table))
 
+#define NE_MODULE_NAME(pModule) \
+    (((OFSTRUCT *)((char*)(pModule) + (pModule)->fileinfo))->szPathName)
+
 #ifndef WINELIB
 #pragma pack(4)
 #endif
diff --git a/include/options.h b/include/options.h
index 9c89b37..1513a3a 100644
--- a/include/options.h
+++ b/include/options.h
@@ -17,7 +17,8 @@
     LANG_Fr,  /* French */
     LANG_Fi,  /* Finnish */
     LANG_Da,  /* Danish */
-    LANG_Cz   /* Czech */
+    LANG_Cz,  /* Czech */
+    LANG_Eo   /* Esperanto */
 } WINE_LANGUAGE;
 
 /* Supported modes */
diff --git a/include/wintypes.h b/include/wintypes.h
index 77b33fe..3884f3b 100644
--- a/include/wintypes.h
+++ b/include/wintypes.h
@@ -138,9 +138,11 @@
 #define FALSE 0
 #define CW_USEDEFAULT ((INT)0x8000)
 #define FAR
+#define _far
 #define NEAR
 #define _near
 #define PASCAL
+#define _pascal
 #define VOID                void
 #define WINAPI              PASCAL
 #define CALLBACK            PASCAL
diff --git a/include/xmalloc.h b/include/xmalloc.h
index 396fde0..f054edd 100644
--- a/include/xmalloc.h
+++ b/include/xmalloc.h
@@ -1,14 +1,8 @@
 #ifndef __WINE_XMALLOC_H
 #define __WINE_XMALLOC_H
 
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#else
-#define size_t unsigned int
-#endif
-
-void *xmalloc (size_t);
-void *xrealloc (void *, size_t);
-char *xstrdup( const char * );
+void *xmalloc( int size );
+void *xrealloc( void *ptr, int size );
+char *xstrdup( const char *str );
 
 #endif  /* __WINE_XMALLOC_H */
diff --git a/loader/module.c b/loader/module.c
index e97c806..f9dd6fe 100644
--- a/loader/module.c
+++ b/loader/module.c
@@ -27,6 +27,8 @@
 #include "callback.h"
 #include "wine.h"
 
+extern HINSTANCE PE_LoadModule( int fd, OFSTRUCT *ofs, LOADPARAMS* params );
+
 static HMODULE hFirstModule = 0;
 static HMODULE hCachedModule = 0;  /* Module cached by MODULE_OpenFile */
 
@@ -145,8 +147,7 @@
 
       /* Dump the file info */
 
-    printf( "Filename: '%s'\n",
-         ((LOADEDFILEINFO *)((BYTE *)pModule + pModule->fileinfo))->filename );
+    printf( "Filename: '%s'\n", NE_MODULE_NAME(pModule) );
 
       /* Dump the segment table */
 
@@ -269,7 +270,7 @@
     if (hCachedModule == hModule) return cachedfd;
     close( cachedfd );
     hCachedModule = hModule;
-    name = ((LOADEDFILEINFO*)((char*)pModule + pModule->fileinfo))->filename;
+    name = NE_MODULE_NAME( pModule );
     if (!(unixName = DOSFS_GetUnixFileName( name, TRUE )) ||
         (cachedfd = open( unixName, O_RDONLY )) == -1)
         fprintf( stderr, "MODULE_OpenFile: can't open file '%s' for module "NPFMT"\n",
@@ -444,7 +445,7 @@
 
     size = sizeof(NE_MODULE) +
              /* loaded file info */
-           sizeof(LOADEDFILEINFO) + strlen(ofs->szPathName) +
+           sizeof(OFSTRUCT)-sizeof(ofs->szPathName)+strlen(ofs->szPathName)+1+
              /* segment table */
            ne_header.n_segment_tab * sizeof(SEGTABLEENTRY) +
              /* resource table */
@@ -488,13 +489,10 @@
     /* Store the filename information */
 
     pModule->fileinfo = (int)pData - (int)pModule;
-    ((LOADEDFILEINFO*)pData)->length = sizeof(LOADEDFILEINFO)+strlen(ofs->szPathName);
-    ((LOADEDFILEINFO*)pData)->fixed_media = TRUE;
-    ((LOADEDFILEINFO*)pData)->error = 0;
-    ((LOADEDFILEINFO*)pData)->date = 0;
-    ((LOADEDFILEINFO*)pData)->time = 0;
-    strcpy( ((LOADEDFILEINFO*)pData)->filename, ofs->szPathName );
-    pData += ((LOADEDFILEINFO*)pData)->length--;
+    size = sizeof(OFSTRUCT)-sizeof(ofs->szPathName)+strlen(ofs->szPathName)+1;
+    memcpy( pData, ofs, size );
+    ((OFSTRUCT *)pData)->cBytes = size - 1;
+    pData += size;
 
     /* Get the segment table */
 
@@ -845,7 +843,7 @@
     {
         NE_MODULE *pModule = (NE_MODULE *)GlobalLock( hModule );
         if (!pModule) break;
-        modulepath = ((LOADEDFILEINFO*)((char*)pModule + pModule->fileinfo))->filename;
+        modulepath = NE_MODULE_NAME(pModule);
         if (!(modulename = strrchr( modulepath, '\\' )))
             modulename = modulepath;
         else modulename++;
@@ -916,8 +914,6 @@
 }
 
 
-HINSTANCE PE_LoadModule(int fd, OFSTRUCT *ofs, LOADPARAMS* params);
-
 /**********************************************************************
  *	    LoadModule    (KERNEL.45)
  */
@@ -1194,12 +1190,10 @@
 int GetModuleFileName( HANDLE hModule, LPSTR lpFileName, short nSize )
 {
     NE_MODULE *pModule;
-    char *name;
 
     hModule = GetExePtr( hModule );  /* In case we were passed an hInstance */
     if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
-    name = ((LOADEDFILEINFO*)((char*)pModule + pModule->fileinfo))->filename;
-    lstrcpyn( lpFileName, name, nSize );
+    lstrcpyn( lpFileName, NE_MODULE_NAME(pModule), nSize );
     dprintf_module( stddeb, "GetModuleFilename: %s\n", lpFileName );
     return strlen(lpFileName);
 }
@@ -1405,9 +1399,7 @@
     lpme->szModule[MAX_MODULE_NAME] = '\0';
     lpme->hModule = lpme->wNext;
     lpme->wcUsage = pModule->count;
-    strncpy( lpme->szExePath,
-             ((LOADEDFILEINFO*)((char*)pModule + pModule->fileinfo))->filename,
-             MAX_PATH );
+    strncpy( lpme->szExePath, NE_MODULE_NAME(pModule), MAX_PATH );
     lpme->szExePath[MAX_PATH] = '\0';
     lpme->wNext = pModule->next;
     return TRUE;
diff --git a/loader/ne_resource.c b/loader/ne_resource.c
index 5eee682..add76cf 100644
--- a/loader/ne_resource.c
+++ b/loader/ne_resource.c
@@ -240,7 +240,6 @@
 {
     NE_MODULE *pModule;
     NE_NAMEINFO *pNameInfo=NULL;
-    char *name;
     int fd;
 
     pModule = (NE_MODULE *)GlobalLock( hModule );
@@ -249,8 +248,7 @@
     pNameInfo = (NE_NAMEINFO*)((char*)pModule + hRsrc);
 #endif
 
-    name = ((LOADEDFILEINFO*)((char*)pModule + pModule->fileinfo))->filename;
-    if ((fd = _lopen( name, OF_READ )) != -1)
+    if ((fd = _lopen( NE_MODULE_NAME(pModule), OF_READ )) != -1)
     {
         WORD sizeShift = *(WORD *)((char *)pModule + pModule->res_table);
         _llseek( fd, (int)pNameInfo->offset << sizeShift, SEEK_SET );
diff --git a/loader/pe_image.c b/loader/pe_image.c
index 5abdeae..9d68504 100644
--- a/loader/pe_image.c
+++ b/loader/pe_image.c
@@ -536,12 +536,11 @@
 HINSTANCE MODULE_CreateInstance(HMODULE hModule,LOADPARAMS *params);
 void InitTask(struct sigcontext_struct context);
 
-HINSTANCE PE_LoadModule(int fd, OFSTRUCT *ofs, LOADPARAMS* params)
+HINSTANCE PE_LoadModule( int fd, OFSTRUCT *ofs, LOADPARAMS* params )
 {
 	struct w_files *wpnt;
-	int size;
+	int size, of_size;
 	NE_MODULE *pModule;
-	LOADEDFILEINFO *pFileInfo;
 	SEGTABLEENTRY *pSegment;
 	char *pStr;
 	DWORD cts;
@@ -561,15 +560,17 @@
 	wpnt->mz_header=xmalloc(sizeof(struct mz_header_s));
 	read(fd,wpnt->mz_header,sizeof(struct mz_header_s));
 
-	size=sizeof(NE_MODULE) +
-		/* loaded file info */
-		sizeof(LOADEDFILEINFO) + strlen(ofs->szPathName) +
-		/* segment table: DS,CS */
-		2 * sizeof(SEGTABLEENTRY) +
-		/* name table */
-		9 +
-		/* several empty tables */
-		8;
+        of_size = sizeof(OFSTRUCT) - sizeof(ofs->szPathName)
+                  + strlen(ofs->szPathName) + 1;
+	size = sizeof(NE_MODULE) +
+               /* loaded file info */
+               of_size +
+               /* segment table: DS,CS */
+               2 * sizeof(SEGTABLEENTRY) +
+               /* name table */
+               9 +
+               /* several empty tables */
+               8;
 
 	hModule = GlobalAlloc( GMEM_MOVEABLE | GMEM_ZEROINIT, size );
 	wpnt->hModule=hModule;
@@ -593,17 +594,16 @@
 	pModule->seg_count=1;
 	pModule->modref_count=0;
 	pModule->nrname_size=0;
-	pModule->seg_table=sizeof(NE_MODULE)+
-			sizeof(LOADEDFILEINFO)+strlen(ofs->szPathName);
+	pModule->seg_table=sizeof(NE_MODULE) + of_size;
 	pModule->fileinfo=sizeof(NE_MODULE);
 	pModule->os_flags=NE_OSFLAGS_WINDOWS;
 	pModule->expected_version=0x30A;
 
-	pFileInfo=(LOADEDFILEINFO *)(pModule + 1);
-	pFileInfo->length = sizeof(LOADEDFILEINFO)+strlen(ofs->szPathName)-1;
-	strcpy(pFileInfo->filename,ofs->szPathName);
+        /* Set loaded file information */
+        memcpy( pModule + 1, ofs, of_size );
+        ((OFSTRUCT *)(pModule+1))->cBytes = of_size - 1;
 
-	pSegment=(SEGTABLEENTRY*)((char*)pFileInfo+pFileInfo->length+1);
+	pSegment=(SEGTABLEENTRY*)((char*)(pModule + 1) + of_size);
 	pModule->dgroup_entry=(int)pSegment-(int)pModule;
 	pSegment->size=0;
 	pSegment->flags=NE_SEGFLAGS_DATA;
diff --git a/loader/task.c b/loader/task.c
index 08d730c..e721cf1 100644
--- a/loader/task.c
+++ b/loader/task.c
@@ -611,6 +611,8 @@
  */
 void TASK_KillCurrentTask( int exitCode )
 {
+    extern void EXEC_ExitWindows( int retCode );
+
     if (hTaskToKill && (hTaskToKill != hCurrentTask))
     {
         /* If another task is already marked for destruction, */
@@ -621,7 +623,7 @@
     if (nTaskCount <= 1)
     {
         dprintf_task( stddeb, "Killing the last task, exiting\n" );
-        ExitWindows( 0, 0 );
+        EXEC_ExitWindows( 0 );
     }
 
     /* Remove the task from the list to be sure we never switch back to it */
diff --git a/memory/atom.c b/memory/atom.c
index 0e42c92..fe807cd 100644
--- a/memory/atom.c
+++ b/memory/atom.c
@@ -92,6 +92,8 @@
     {
         if (!create) return NULL;
         if (!ATOM_InitTable( selector, DEFAULT_ATOMTABLE_SIZE )) return NULL;
+        /* Reload ptr in case it moved in linear memory */
+        ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 );
     }
     return (ATOMTABLE *)((char *)ptr + ptr->atomtable);
 }
@@ -156,6 +158,8 @@
 
     entry = LOCAL_Alloc( selector, LMEM_FIXED, sizeof(ATOMENTRY)+len-1 );
     if (!entry) return 0;
+    /* Reload the table ptr in case it moved in linear memory */
+    table = ATOM_GetTable( selector, FALSE );
     entryPtr = ATOM_MakePtr( selector, entry );
     entryPtr->next = table->entries[hash];
     entryPtr->refCount = 1;
diff --git a/misc/exec.c b/misc/exec.c
index 6cc85b3..6def5ad 100644
--- a/misc/exec.c
+++ b/misc/exec.c
@@ -14,6 +14,7 @@
 #include "callback.h"
 #include "stddebug.h"
 #include "debug.h"
+#include "win.h"
 
 #define HELP_CONTEXT      0x0001
 #define HELP_QUIT         0x0002
@@ -31,23 +32,82 @@
 #define HELP_SETWINPOS    0x0203
 
 
-/**********************************************************************
- *				ExitWindows		[USER.7]
+/***********************************************************************
+ *           EXEC_ExitWindows
+ *
+ * Clean-up everything and exit the Wine process.
+ * This is the back-end of ExitWindows(), called when all windows
+ * have agreed to be terminated.
  */
-BOOL ExitWindows(DWORD dwReturnCode, WORD wReserved)
+void EXEC_ExitWindows( int retCode )
 {
-    api_assert("ExitWindows", wReserved == 0);
-    api_assert("ExitWindows", HIWORD(dwReturnCode) == 0);
-
-    dprintf_exec( stdnimp,"PARTIAL STUB ExitWindows(%08lX, %04X)\n", 
-                  dwReturnCode, wReserved);
-
     /* Do the clean-up stuff */
 
     WriteOutProfiles();
     SHELL_SaveRegistry();
 
-    exit( LOWORD(dwReturnCode) );
+    exit( retCode );
+}
+
+
+/***********************************************************************
+ *           ExitWindows   (USER.7)
+ */
+BOOL ExitWindows( DWORD dwReturnCode, WORD wReserved )
+{
+    HWND hwnd, hwndDesktop;
+    WND *wndPtr;
+    HWND *list, *pWnd;
+    int count, i;
+    BOOL result;
+        
+    api_assert("ExitWindows", wReserved == 0);
+    api_assert("ExitWindows", HIWORD(dwReturnCode) == 0);
+
+    /* We have to build a list of all windows first, as in EnumWindows */
+
+    /* First count the windows */
+
+    hwndDesktop = GetDesktopWindow();
+    count = 0;
+    for (hwnd = GetTopWindow(hwndDesktop); hwnd != 0; hwnd = wndPtr->hwndNext)
+    {
+        if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
+        count++;
+    }
+    if (!count) /* No windows, we can exit at once */
+        EXEC_ExitWindows( LOWORD(dwReturnCode) );
+
+      /* Now build the list of all windows */
+
+    if (!(list = (HWND *)malloc( sizeof(HWND) * count ))) return FALSE;
+    for (hwnd = GetTopWindow(hwndDesktop), pWnd = list; hwnd != 0; hwnd = wndPtr->hwndNext)
+    {
+        wndPtr = WIN_FindWndPtr( hwnd );
+        *pWnd++ = hwnd;
+    }
+
+      /* Now send a WM_QUERYENDSESSION message to every window */
+
+    for (pWnd = list, i = 0; i < count; i++, pWnd++)
+    {
+          /* Make sure that window still exists */
+        if (!IsWindow(*pWnd)) continue;
+	if (!SendMessage( *pWnd, WM_QUERYENDSESSION, 0, 0 )) break;
+    }
+    result = (i == count);
+
+    /* Now notify all windows that got a WM_QUERYENDSESSION of the result */
+
+    for (pWnd = list; i > 0; i--, pWnd++)
+    {
+	if (!IsWindow(*pWnd)) continue;
+	SendMessage( *pWnd, WM_ENDSESSION, result, 0 );
+    }
+    free( list );
+
+    if (result) EXEC_ExitWindows( LOWORD(dwReturnCode) );
+    return FALSE;
 }
 
 
diff --git a/misc/main.c b/misc/main.c
index c7a6afa..eb19885 100644
--- a/misc/main.c
+++ b/misc/main.c
@@ -56,6 +56,7 @@
     "Fi",  /* LANG_Fi */
     "Da",  /* LANG_Da */
     "Cz",  /* LANG_Cz */
+    "Eo",  /* LANG_Eo */
     NULL
 };
 
@@ -138,7 +139,7 @@
   "    -fixedmap       Use a \"standard\" color map\n" \
   "    -iconic         Start as an icon\n" \
   "    -ipc            Enable IPC facilities\n" \
-  "    -language xx    Set the language (one of En,Es,De,No,Fr,Fi,Da,Cz)\n" \
+  "    -language xx    Set the language (one of En,Es,De,No,Fr,Fi,Da,Cz,Eo)\n" \
   "    -managed        Allow the window manager to manage created windows\n" \
   "    -mode mode      Start Wine in a particular mode (standard or enhanced)\n" \
   "    -name name      Set the application name\n" \
@@ -460,6 +461,7 @@
     XClassHint *class_hints;
     XSetWindowAttributes win_attr;
     XTextProperty window_name;
+    Atom XA_WM_DELETE_WINDOW;
 
     flags = XParseGeometry( Options.desktopGeometry,
 			    &desktopX, &desktopY, &width, &height );
@@ -505,6 +507,8 @@
     XStringListToTextProperty( &name, 1, &window_name );
     XSetWMProperties( display, rootWindow, &window_name, &window_name,
                       argv, argc, size_hints, wm_hints, class_hints );
+    XA_WM_DELETE_WINDOW = XInternAtom( display, "WM_DELETE_WINDOW", False );
+    XSetWMProtocols( display, rootWindow, &XA_WM_DELETE_WINDOW, 1 );
     XFree( size_hints );
     XFree( wm_hints );
     XFree( class_hints );
diff --git a/misc/ole2nls.c b/misc/ole2nls.c
index 500a3f2..51cd354 100644
--- a/misc/ole2nls.c
+++ b/misc/ole2nls.c
@@ -31,6 +31,7 @@
     case LANG_Fi:
     case LANG_Da:
     case LANG_Cz:
+    case LANG_Eo:
     default:
 	return 0;  /* Neutral language */
     }
@@ -421,6 +422,108 @@
 /* LOCVAL(LOCALE_INEGSEPBYSPACE) */
     break; /* LANG(Da) */
 
+    case LANG_Eo:
+/* LOCVAL(LOCALE_ILANGUAGE,"9") ISO numerical ID for language TODO */
+LOCVAL(LOCALE_SLANGUAGE,"Esperanto")
+LOCVAL(LOCALE_SENGLANGUAGE,"Esperanto")
+/* LOCVAL(LOCALE_SABBREVLANGNAME,"deu") */
+LOCVAL(LOCALE_SNATIVELANGNAME,"Esperanto")
+/* LOCVAL(LOCALE_ICOUNTRY,"49") not official in any one country */
+/* LOCVAL(LOCALE_SCOUNTRY,"Deutschland") */
+/* LOCVAL(LOCALE_SENGCOUNTRY,"Germany") */
+/* LOCVAL(LOCALE_SABBREVCTRYNAME,"De") */
+/* LOCVAL(LOCALE_SNATIVECTRYNAME,"Deutschland") */
+/* LOCVAL(LOCALE_IDEFAULTLANGUAGE,"9") ISO ID of lang TODO */
+/* LOCVAL(LOCALE_IDEFAULTCOUNTRY,"49") */
+LOCVAL(LOCALE_IDEFAULTCODEPAGE,3) /* is this right? TODO */
+LOCVAL(LOCALE_IDEFAULTANSICODEPAGE,3) /* is this right? TODO */
+LOCVAL(LOCALE_SLIST,";")
+LOCVAL(LOCALE_IMEASURE,"0")
+LOCVAL(LOCALE_SDECIMAL,",")
+LOCVAL(LOCALE_STHOUSAND,".")
+/* LOCVAL(LOCALE_SGROUPING) */
+LOCVAL(LOCALE_IDIGITS,"2")
+LOCVAL(LOCALE_ILZERO,"1")
+/* LOCVAL(LOCALE_INEGNUMBER) */
+/* LOCVAL(LOCALE_SNATIVEDIGITS) */
+LOCVAL(LOCALE_SCURRENCY,"NLG") /* accounting currency of UEA */
+/* LOCVAL(LOCALE_SINTLSYMBOL) */
+/* LOCVAL(LOCALE_SMONDECIMALSEP) */
+/* LOCVAL(LOCALE_SMONTHOUSANDSEP) */
+/* LOCVAL(LOCALE_SMONGROUPING) */
+/* LOCVAL(LOCALE_ICURRDIGITS,"2") */
+/* LOCVAL(LOCALE_IINTLCURRDIGITS) */
+LOCVAL(LOCALE_ICURRENCY,"3")
+LOCVAL(LOCALE_INEGCURR,"8")
+LOCVAL(LOCALE_SDATE,".")
+LOCVAL(LOCALE_STIME,":")
+LOCVAL(LOCALE_SSHORTDATE,"yyyy.mm.dd")
+LOCVAL(LOCALE_SLONGDATE,"ddd, d. MMMM yyyy")
+/* LOCVAL(LOCALE_STIMEFORMAT) */
+LOCVAL(LOCALE_IDATE,"1")
+/* LOCVAL(LOCALE_ILDATE) */
+LOCVAL(LOCALE_ITIME,"1")
+/* LOCVAL(LOCALE_ITIMEMARKPOSN) */
+/* LOCVAL(LOCALE_ICENTURY) */
+LOCVAL(LOCALE_ITLZERO,"1")
+/* LOCVAL(LOCALE_IDAYLZERO) */
+/* LOCVAL(LOCALE_IMONLZERO) */
+/* LOCVAL(LOCALE_S1159) */
+/* LOCVAL(LOCALE_S2359) */
+/* LOCVAL(LOCALE_ICALENDARTYPE) */
+/* LOCVAL(LOCALE_IOPTIONALCALENDAR) */
+/* LOCVAL(LOCALE_IFIRSTDAYOFWEEK) */
+/* LOCVAL(LOCALE_IFIRSTWEEKOFYEAR) */
+LOCVAL(LOCALE_SDAYNAME1,"lundo")
+LOCVAL(LOCALE_SDAYNAME2,"mardo")
+LOCVAL(LOCALE_SDAYNAME3,"merkredo")
+LOCVAL(LOCALE_SDAYNAME4,"¼aýdo")
+LOCVAL(LOCALE_SDAYNAME5,"vendredo")
+LOCVAL(LOCALE_SDAYNAME6,"sabato")
+LOCVAL(LOCALE_SDAYNAME7,"dimanæo")
+LOCVAL(LOCALE_SABBREVDAYNAME1,"lu")
+LOCVAL(LOCALE_SABBREVDAYNAME2,"ma")
+LOCVAL(LOCALE_SABBREVDAYNAME3,"me")
+LOCVAL(LOCALE_SABBREVDAYNAME4,"¼a")
+LOCVAL(LOCALE_SABBREVDAYNAME5,"ve")
+LOCVAL(LOCALE_SABBREVDAYNAME6,"sa")
+LOCVAL(LOCALE_SABBREVDAYNAME7,"di")
+LOCVAL(LOCALE_SMONTHNAME1,"januaro")
+LOCVAL(LOCALE_SMONTHNAME2,"februaro")
+LOCVAL(LOCALE_SMONTHNAME3,"marto")
+LOCVAL(LOCALE_SMONTHNAME4,"aprilo")
+LOCVAL(LOCALE_SMONTHNAME5,"majo")
+LOCVAL(LOCALE_SMONTHNAME6,"junio")
+LOCVAL(LOCALE_SMONTHNAME7,"julio")
+LOCVAL(LOCALE_SMONTHNAME8,"aýgusto")
+LOCVAL(LOCALE_SMONTHNAME9,"septembro")
+LOCVAL(LOCALE_SMONTHNAME10,"oktobro")
+LOCVAL(LOCALE_SMONTHNAME11,"novembro")
+LOCVAL(LOCALE_SMONTHNAME12,"decembro")
+LOCVAL(LOCALE_SMONTHNAME13,"")
+LOCVAL(LOCALE_SABBREVMONTHNAME1,"jan")
+LOCVAL(LOCALE_SABBREVMONTHNAME2,"feb")
+LOCVAL(LOCALE_SABBREVMONTHNAME3,"mar")
+LOCVAL(LOCALE_SABBREVMONTHNAME4,"apr")
+LOCVAL(LOCALE_SABBREVMONTHNAME5,"maj")
+LOCVAL(LOCALE_SABBREVMONTHNAME6,"jun")
+LOCVAL(LOCALE_SABBREVMONTHNAME7,"jul")
+LOCVAL(LOCALE_SABBREVMONTHNAME8,"aýg")
+LOCVAL(LOCALE_SABBREVMONTHNAME9,"sep")
+LOCVAL(LOCALE_SABBREVMONTHNAME10,"okt")
+LOCVAL(LOCALE_SABBREVMONTHNAME11,"nov")
+LOCVAL(LOCALE_SABBREVMONTHNAME12,"dec")
+LOCVAL(LOCALE_SABBREVMONTHNAME13,"")
+/* LOCVAL(LOCALE_SPOSITIVESIGN) */
+/* LOCVAL(LOCALE_SNEGATIVESIGN) */
+/* LOCVAL(LOCALE_IPOSSIGNPOSN) */
+/* LOCVAL(LOCALE_INEGSIGNPOSN) */
+/* LOCVAL(LOCALE_IPOSSYMPRECEDES) */
+/* LOCVAL(LOCALE_IPOSSEPBYSPACE) */
+/* LOCVAL(LOCALE_INEGSYMPRECEDES) */
+/* LOCVAL(LOCALE_INEGSEPBYSPACE) */
+    break;  /* LANG(Eo) */
+
 /*Insert other languages here*/
 
     default:
diff --git a/misc/xmalloc.c b/misc/xmalloc.c
index d79bd20..0765edf 100644
--- a/misc/xmalloc.c
+++ b/misc/xmalloc.c
@@ -14,11 +14,11 @@
 */
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include "xmalloc.h"
 
-void *
-xmalloc (size_t size)
+void *xmalloc( int size )
 {
     void *res;
 
@@ -32,8 +32,7 @@
 }
 
 
-void *
-xrealloc (void *ptr, size_t size)
+void *xrealloc( void *ptr, int size )
 {
     void *res = realloc (ptr, size);
     if (res == NULL)
diff --git a/programs/Makefile.in b/programs/Makefile.in
new file mode 100644
index 0000000..a954a5f
--- /dev/null
+++ b/programs/Makefile.in
@@ -0,0 +1,14 @@
+SUBDIRS = progman
+
+all: $(SUBDIRS)
+
+$(SUBDIRS): dummy
+	@cd $@; $(MAKE)
+
+depend:
+	for i in $(SUBDIRS); do (cd $$i; $(MAKE) depend); done
+
+clean:
+	for i in $(SUBDIRS); do (cd $$i; $(MAKE) clean); done
+
+dummy:
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
diff --git a/rc/winerc.c b/rc/winerc.c
index 7642ff2..494ab10 100644
--- a/rc/winerc.c
+++ b/rc/winerc.c
@@ -212,7 +212,7 @@
 	/*initially, no bits have to be reset*/
 	ret->and=-1;
 	/*initially, no bits are set*/
-	ret->or=0;
+	ret->or=WS_CHILD | WS_VISIBLE;
 	return ret;
 }
 
diff --git a/resources/Makefile.in b/resources/Makefile.in
index 3bcc5ef..7cb7871 100644
--- a/resources/Makefile.in
+++ b/resources/Makefile.in
@@ -2,7 +2,7 @@
 
 MODULE = resources
 
-LANGUAGES = En Es De No Fr Fi Da Cz
+LANGUAGES = En Es De No Fr Fi Da Cz Eo
 
 SYSRES_SRCS = $(LANGUAGES:%=sysres_%.c)
 
diff --git a/resources/sysres.c b/resources/sysres.c
index 4dac4bf..ae1cbd0 100644
--- a/resources/sysres.c
+++ b/resources/sysres.c
@@ -17,6 +17,7 @@
 #include "sysres_Fi.h"
 #include "sysres_Da.h"
 #include "sysres_Cz.h"
+#include "sysres_Eo.h"
 
 
 static const struct resource * const * SYSRES_Resources[] =
@@ -28,7 +29,8 @@
     sysres_Fr_Table,  /* LANG_Fr */
     sysres_Fi_Table,  /* LANG_Fi */
     sysres_Da_Table,  /* LANG_Da */
-    sysres_Cz_Table   /* LANG_Cz */
+    sysres_Cz_Table,  /* LANG_Cz */
+    sysres_Eo_Table   /* LANG_Eo */
 };
 
 
diff --git a/resources/sysres_Eo.rc b/resources/sysres_Eo.rc
new file mode 100644
index 0000000..09b3a93
--- /dev/null
+++ b/resources/sysres_Eo.rc
@@ -0,0 +1,201 @@
+SYSMENU MENU LOADONCALL MOVEABLE DISCARDABLE
+{
+ MENUITEM "&Renormaligu", 61728
+ MENUITEM "&Movi", 61456
+ MENUITEM "&Grando", 61440
+ MENUITEM "E&tigu", 61472
+ MENUITEM "&Egigu", 61488
+ MENUITEM SEPARATOR
+ MENUITEM "&Fermu\tAlt-F4", 61536
+ MENUITEM SEPARATOR
+ MENUITEM "&Alia tasko ...\tCtrl-Esc", 61744
+ MENUITEM SEPARATOR
+ MENUITEM "&Pri WINE ...", 61761
+}
+
+MSGBOX DIALOG 100, 80, 216, 168
+STYLE DS_SYSMODAL | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+BEGIN
+        ICON "", 1088, 8, 20, 16, 16, WS_CHILD | WS_VISIBLE
+        LTEXT "", 100, 32, 4, 176, 48, WS_CHILD | WS_VISIBLE | WS_GROUP
+        PUSHBUTTON "En&orde", 1, 16, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+        PUSHBUTTON "&Nuligu", 2, 64, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+        PUSHBUTTON "Æe&su", 3, 112, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+        PUSHBUTTON "&Reprovu", 4, 160, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+        PUSHBUTTON "&Ignoru", 5, 208, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+        PUSHBUTTON "&Jes", 6, 256, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+        PUSHBUTTON "N&e", 7, 304, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+END
+
+SHELL_ABOUT_MSGBOX DIALOG LOADONCALL MOVEABLE DISCARDABLE 50, 44, 223, 200
+STYLE DS_LOCALEDIT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Pri %s"
+FONT 10, "System"
+{
+ DEFPUSHBUTTON "Enorde", 1, 91, 180, 40, 14
+ CONTROL "", -1, "STATIC", SS_BLACKFRAME | WS_CHILD | WS_VISIBLE | WS_DISABLED, 4, 35, 215, 140
+ LTEXT "Text", 100, 11, 40, 200, 130, SS_NOPREFIX | WS_GROUP
+ ICON "", 1088, 195, 10, 18, 20
+}
+
+
+OPEN_FILE DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 275, 134
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Malfermu dosieron"
+FONT 8, "Helv"
+{
+ LTEXT "Dosier&nomo:", 1090, 6, 6, 76, 9
+ EDITTEXT 1152, 6, 16, 90, 12, ES_AUTOHSCROLL | ES_OEMCONVERT | WS_BORDER | WS_TABSTOP
+ LISTBOX 1120, 6, 32, 90, 68, LBS_STANDARD | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_DISABLENOSCROLL | WS_TABSTOP
+ LTEXT "Dosier&ujo:", -1, 110, 6, 92, 9
+ LTEXT "", 1088, 110, 18, 92, 9, SS_NOPREFIX | WS_GROUP
+ LISTBOX 1121, 110, 32, 92, 68, LBS_STANDARD | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_DISABLENOSCROLL | WS_TABSTOP
+ LTEXT "Dosier&speco:", 1089, 6, 104, 90, 9
+ COMBOBOX 1136, 6, 114, 90, 36, CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Disk&ilo:", 1091, 110, 104, 92, 9
+ COMBOBOX 1137, 110, 114, 92, 68, CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+ DEFPUSHBUTTON "Malfermu", 1, 208, 6, 56, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Nuligu", 2, 208, 24, 56, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "&Helpu", 1038, 208, 46, 56, 14, WS_GROUP | WS_TABSTOP
+ CHECKBOX "Nur &legebla", 1040, 208, 68, 50, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP
+}
+
+
+SAVE_FILE DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 275, 134
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Sekurigu dosieron"
+FONT 8, "Helv"
+{
+ LTEXT "Dosier&nomo:", 1090, 6, 6, 76, 9
+ EDITTEXT 1152, 6, 16, 90, 12, ES_AUTOHSCROLL | ES_OEMCONVERT | WS_BORDER | WS_TABSTOP
+ LISTBOX 1120, 6, 32, 90, 68, LBS_STANDARD | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_DISABLENOSCROLL | WS_TABSTOP
+ LTEXT "Dosier&ujo:", -1, 110, 6, 92, 9
+ LTEXT "", 1088, 110, 18, 92, 9, SS_NOPREFIX | WS_GROUP
+ LISTBOX 1121, 110, 32, 92, 68, LBS_STANDARD | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_DISABLENOSCROLL | WS_TABSTOP
+ LTEXT "Dosier&speco:", 1089, 6, 104, 90, 9
+ COMBOBOX 1136, 6, 114, 90, 36, CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Disk&ilo:", 1091, 110, 104, 92, 9
+ COMBOBOX 1137, 110, 114, 92, 68, CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+ DEFPUSHBUTTON "Sekurigu", 1, 208, 6, 56, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Nuligu", 2, 208, 24, 56, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "&Helpu", 1038, 208, 46, 56, 14, WS_GROUP | WS_TABSTOP
+ CHECKBOX "Nur &legebla", 1040, 208, 68, 50, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP
+}
+
+
+PRINT DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 264, 134
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Presu"
+FONT 8, "Helv"
+{
+ LTEXT "Presilo:", 1088, 6, 6, 40, 9
+ LTEXT "", 1089, 60, 6, 150, 9
+ GROUPBOX "Etendiøon", 1072, 6, 30, 160, 65, BS_GROUPBOX
+ RADIOBUTTON "æ&iujn", 1056, 16, 45, 60, 12
+ RADIOBUTTON "&elekton", 1057, 16, 60, 60, 12
+ RADIOBUTTON "&paøojn", 1058, 16, 75, 60, 12
+ DEFPUSHBUTTON "Presu", 1, 206, 6, 56, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Nuligu", 2, 206, 24, 56, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "&Aranøu", 1024, 206, 46, 56, 14, WS_GROUP | WS_TABSTOP
+ LTEXT "de:", 1090, 60, 80, 30, 9
+ LTEXT "øis:", 1091, 120, 80, 30, 9
+ LTEXT "&Kvalito:", 1092, 6, 100, 76, 9
+ COMBOBOX 1136, 80, 100, 92, 68, CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+ CHECKBOX "Presu &dosieren", 1040, 20, 100, 50, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP
+ CHECKBOX "Mallarøtipe", 1041, 160, 100, 50, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP
+}
+
+
+PRINT_SETUP DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 264, 134
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Presada Aranøo"
+FONT 8, "Helv"
+{
+ GROUPBOX "Presilo", 1072, 6, 10, 180, 65, BS_GROUPBOX
+ RADIOBUTTON "&Implicita Presilo", 1056, 16, 20, 80, 12
+ LTEXT "[none]", 1088, 35, 35, 120, 9
+ RADIOBUTTON "&Specifa Presilo", 1057, 16, 50, 80, 12
+ COMBOBOX 1136, 35, 65, 149, 68, CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+ DEFPUSHBUTTON "Enorde", 1, 206, 6, 56, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Nuligu", 2, 206, 24, 56, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "&Agordo", 1024, 206, 46, 56, 14, WS_GROUP | WS_TABSTOP
+ GROUPBOX "Formato", 1073, 6, 85, 100, 50, BS_GROUPBOX
+ RADIOBUTTON "&Vertikala", 1058, 50, 100, 40, 12
+ RADIOBUTTON "&Horizontala", 1059, 50, 115, 40, 12
+ ICON "LANDSCAP", 1097, 10, 95, 32, 32
+ ICON "PORTRAIT", 1098, 10, 95, 32, 32
+ GROUPBOX "Papero", 1074, 120, 85, 180, 50, BS_GROUPBOX
+ LTEXT "&Grando", 1089, 130, 95, 30, 9
+ LTEXT "&Fonto", 1090, 130, 110, 30, 9
+ COMBOBOX 1137, 155, 95, 92, 68, CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+ COMBOBOX 1138, 155, 110, 92, 68, CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+}
+
+
+CHOOSE_FONT DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 264, 134
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Tiparo"
+FONT 8, "Helv"
+{
+ LTEXT "Tiparo:", 1088, 6, 6, 40, 9
+ LTEXT "", 1089, 60, 6, 150, 9
+ DEFPUSHBUTTON "Enorde", 1, 206, 6, 56, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Nuligu", 2, 206, 24, 56, 14, WS_GROUP | WS_TABSTOP
+}
+
+
+CHOOSE_COLOR DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 264, 200
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Koloro"
+FONT 8, "Helv"
+{
+ LTEXT "&Normala koloraro:", 1088, 6, 6, 40, 9
+ LTEXT "&Persona koloraro:", 1089, 6, 126, 40, 9
+ LTEXT "Color|Sol&id", 1090, 100, 146, 40, 9
+ LTEXT "&Farbo:", 1091, 150, 126, 40, 9
+ LTEXT "&Saturo:", 1092, 150, 146, 40, 9
+ LTEXT "&Helo:", 1093, 150, 166, 40, 9
+ LTEXT "&Ruøo:", 1094, 150, 126, 40, 9
+ LTEXT "&Verda:", 1095, 150, 146, 40, 9
+ LTEXT "&Bluo:", 1096, 150, 166, 40, 9
+ DEFPUSHBUTTON "Enorde", 1, 6, 182, 56, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "&Aldonu al persona koloraro", 1024, 120, 182, 100, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Forv&iþu personan koloraron", 1025, 6, 164, 56, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Nuligu", 2, 76, 182, 56, 14, WS_GROUP | WS_TABSTOP
+}
+
+
+FIND_TEXT DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 264, 84
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Seræu"
+FONT 8, "Helv"
+{
+ LTEXT "&Seræu:", 1088, 6, 6, 40, 9
+ LTEXT "", 1089, 60, 6, 150, 9
+ CHECKBOX "Nur tutan &vorton", 1040, 20, 30, 50, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP
+ CHECKBOX "Atentu &Usklecon", 1041, 20, 50, 50, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP
+ GROUPBOX "Direkto", 1072, 90, 40, 80, 40, BS_GROUPBOX
+ RADIOBUTTON "&Retro", 1056, 100, 50, 50, 12
+ RADIOBUTTON "&Antaýen", 1057, 150, 50, 50, 12
+ DEFPUSHBUTTON "&Pluseræu", 1, 206, 6, 56, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Nuligu", 2, 206, 24, 56, 14, WS_GROUP | WS_TABSTOP
+}
+
+
+REPLACE_TEXT DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 264, 114
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Anstataýigu"
+FONT 8, "Helv"
+{
+ LTEXT "Anstataýigu:", 1088, 6, 6, 40, 9
+ LTEXT "", 1089, 60, 6, 150, 9
+ LTEXT "&per:", 1090, 6, 26, 40, 9
+ LTEXT "", 1091, 60, 26, 150, 9
+ CHECKBOX "Nur tutan &vorton", 1040, 20, 40, 50, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP
+ CHECKBOX "Atentu &Usklecon", 1041, 20, 60, 50, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP
+ DEFPUSHBUTTON "Plu&seræu", 1, 206, 6, 56, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "&Anstataýigu", 1024, 206, 24, 56, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Anstataýigu æ&iujn", 1025, 206, 44, 56, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Nuligu", 2, 206, 64, 56, 14, WS_GROUP | WS_TABSTOP
+}
+
diff --git a/tools/build.c b/tools/build.c
index 13d2913..938f99f 100644
--- a/tools/build.c
+++ b/tools/build.c
@@ -11,6 +11,7 @@
 #include "wine.h"
 #include "module.h"
 #include "neexe.h"
+#include "windows.h"
 
 /* ELF symbols do not have an underscore in front */
 #if defined (__ELF__) || defined (__svr4__)
@@ -560,13 +561,13 @@
     char *buffer;
     NE_MODULE *pModule;
     SEGTABLEENTRY *pSegment;
-    LOADEDFILEINFO *pFileInfo;
+    OFSTRUCT *pFileInfo;
     BYTE *pstr, *bundle;
     WORD *pword;
 
     /*   Module layout:
      * NE_MODULE       Module
-     * LOADEDFILEINFO  File information
+     * OFSTRUCT        File information
      * SEGTABLEENTRY   Segment 1 (code)
      * SEGTABLEENTRY   Segment 2 (data)
      * WORD[2]         Resource table (empty)
@@ -606,15 +607,13 @@
 
       /* File information */
 
-    pFileInfo = (LOADEDFILEINFO *)(pModule + 1);
+    pFileInfo = (OFSTRUCT *)(pModule + 1);
     pModule->fileinfo = (int)pFileInfo - (int)pModule;
-    pFileInfo->length = sizeof(LOADEDFILEINFO) + strlen(UpperDLLName) + 3;
-    pFileInfo->fixed_media = 0;
-    pFileInfo->error = 0;
-    pFileInfo->date = 0;
-    pFileInfo->time = 0;
-    sprintf( pFileInfo->filename, "%s.DLL", UpperDLLName );
-    pstr = (char *)pFileInfo + pFileInfo->length + 1;
+    memset( pFileInfo, 0, sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName) );
+    pFileInfo->cBytes = sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName)
+                        + strlen(UpperDLLName) + 4;
+    sprintf( pFileInfo->szPathName, "%s.DLL", UpperDLLName );
+    pstr = (char *)pFileInfo + pFileInfo->cBytes + 1;
         
       /* Segment table */
 
diff --git a/win32/init.c b/win32/init.c
index 2081fe1..fa923b2 100644
--- a/win32/init.c
+++ b/win32/init.c
@@ -12,6 +12,7 @@
 #include "kernel32.h"
 #include "handle32.h"
 #include "pe_image.h"
+#include "task.h"
 #include "stddebug.h"
 #define DEBUG_WIN32
 #include "debug.h"
@@ -76,8 +77,13 @@
     HMODULE hModule;
 
     dprintf_win32(stddeb, "GetModuleHandle: %s\n", module ? module : "NULL");
-    if (module == NULL) hModule = GetExePtr( GetCurrentTask() );
-    else hModule = GetModuleHandle(module);
+/* Freecell uses the result of GetModuleHandleA(0) as the hInstance in
+all calls to e.g. CreateWindowEx. */
+    if (module == NULL) {
+	TDB *pTask = (TDB *)GlobalLock( GetCurrentTask() );
+	hModule = pTask->hInstance;
+    } else
+	hModule = GetModuleHandle(module);
     dprintf_win32(stddeb, "GetModuleHandle: returning %d\n", hModule );
     return hModule;
 }
diff --git a/win32/resource.c b/win32/resource.c
index b2f055b..ed81d60 100644
--- a/win32/resource.c
+++ b/win32/resource.c
@@ -97,9 +97,7 @@
     DWORD root;
 	HANDLE32 result;
 
-#if 0
     hModule = GetExePtr( hModule );  /* In case we were passed an hInstance */
-#endif
     dprintf_resource(stddeb, "FindResource: module=%08x type=", hModule );
     PrintId( type );
     dprintf_resource( stddeb, " name=" );
@@ -133,9 +131,7 @@
 #ifndef WINELIB
     struct w_files *wptr = wine_files;
 
-#if 0
     hModule = GetExePtr( hModule );  /* In case we were passed an hInstance */
-#endif
     dprintf_resource(stddeb, "LoadResource: module="NPFMT" res="NPFMT"\n",
                      hModule, hRsrc );
     if (!hRsrc) return 0;
diff --git a/win32/string32.c b/win32/string32.c
index 1ae569b..e09042a 100644
--- a/win32/string32.c
+++ b/win32/string32.c
@@ -17,7 +17,7 @@
 int STRING32_UniLen(LPWSTR s)
 {
 	int i;
-	for(i=0;*s;s++);
+	for(i=0;*s;s++)
 		i++;
 	return i;
 }
diff --git a/win32/time.c b/win32/time.c
index 24be6a3..8dd88fc 100644
--- a/win32/time.c
+++ b/win32/time.c
@@ -23,9 +23,9 @@
     struct tm *local_tm;
     struct timeval tv;
 
-    time(&local_time);
-    local_tm = localtime(&local_time);
     gettimeofday(&tv, NULL);
+    local_time = tv.tv_sec;
+    local_tm = localtime(&local_time);
 
     systime->wYear = local_tm->tm_year + 1900;
     systime->wMonth = local_tm->tm_mon + 1;
@@ -46,9 +46,9 @@
     struct tm *local_tm;
     struct timeval tv;
 
-    time(&local_time);
-    local_tm = gmtime(&local_time);
     gettimeofday(&tv, NULL);
+    local_time = tv.tv_sec;
+    local_tm = gmtime(&local_time);
 
     systime->wYear = local_tm->tm_year + 1900;
     systime->wMonth = local_tm->tm_mon + 1;
diff --git a/windows/caret.c b/windows/caret.c
index 863a75c..268b937 100644
--- a/windows/caret.c
+++ b/windows/caret.c
@@ -155,7 +155,6 @@
 /*****************************************************************
  *               CreateCaret          (USER.163)
  */
-
 BOOL CreateCaret(HWND hwnd, HBITMAP bitmap, INT width, INT height)
 {
     dprintf_caret(stddeb,"CreateCaret: hwnd="NPFMT"\n", hwnd);
@@ -186,7 +185,7 @@
 	Caret.color = GetSysColor(COLOR_GRAYTEXT);
     else
 	Caret.color = GetSysColor(COLOR_WINDOW);
-    Caret.timeout = 750;
+    Caret.timeout = GetProfileInt( "windows", "CursorBlinkRate", 750 );
 
     CARET_Initialize();
 
@@ -220,6 +219,7 @@
 void SetCaretPos(short x, short y)
 {
     if (!Caret.hwnd) return;
+    if ((x == Caret.x) && (y == Caret.y)) return;
 
     dprintf_caret(stddeb,"SetCaretPos: x=%d, y=%d\n", x, y);
 
diff --git a/windows/event.c b/windows/event.c
index 780cc31..7ab8e42 100644
--- a/windows/event.c
+++ b/windows/event.c
@@ -145,6 +145,7 @@
 static void EVENT_SelectionRequest( HWND hwnd, XSelectionRequestEvent *event);
 static void EVENT_SelectionNotify( HWND hwnd, XSelectionEvent *event);
 static void EVENT_SelectionClear( HWND hwnd, XSelectionClearEvent *event);
+static void EVENT_ClientMessage( HWND hwnd, XClientMessageEvent *event );
 
 
 /***********************************************************************
@@ -220,6 +221,10 @@
 	EVENT_SelectionClear( hwnd, (XSelectionClearEvent*) event );
 	break;
 
+    case ClientMessage:
+	EVENT_ClientMessage( hwnd, (XClientMessageEvent *) event );
+	break;
+
     default:    
 	dprintf_event(stddeb, "Unprocessed event %s for hwnd "NPFMT"\n",
 	        event_names[event->type], hwnd );
@@ -616,6 +621,30 @@
     CLIPBOARD_ReleaseSelection(hwnd); 
 }
 
+
+/**********************************************************************
+ *           EVENT_ClientMessage
+ */
+static void EVENT_ClientMessage (HWND hwnd, XClientMessageEvent *event )
+{
+    static Atom wmProtocols = None;
+    static Atom wmDeleteWindow = None;
+
+    if (wmProtocols == None)
+        wmProtocols = XInternAtom( display, "WM_PROTOCOLS", True );
+    if (wmDeleteWindow == None)
+        wmDeleteWindow = XInternAtom( display, "WM_DELETE_WINDOW", True );
+
+    if ((event->format != 32) || (event->message_type != wmProtocols) ||
+        (((Atom) event->data.l[0]) != wmDeleteWindow))
+    {
+	dprintf_event( stddeb, "unrecognized ClientMessage\n" );
+	return;
+    }
+    SendMessage( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
+}
+
+
 /**********************************************************************
  *		SetCapture 	(USER.18)
  */
diff --git a/windows/syscolor.c b/windows/syscolor.c
index 066eb24..4e5bc07 100644
--- a/windows/syscolor.c
+++ b/windows/syscolor.c
@@ -86,7 +86,7 @@
 	break;
     case COLOR_WINDOWTEXT:
 	DeleteObject( sysColorObjects.hpenWindowText );
-	sysColorObjects.hpenWindowText = CreatePen( PS_SOLID, 1, color );
+	sysColorObjects.hpenWindowText = CreatePen( PS_DOT, 1, color );
 	break;
     case COLOR_CAPTIONTEXT:
 	break;
diff --git a/windows/win.c b/windows/win.c
index 81133a4..697bef1 100644
--- a/windows/win.c
+++ b/windows/win.c
@@ -306,11 +306,12 @@
 {
     HANDLE class, hwnd;
     CLASS *classPtr;
-    WND *wndPtr;
+    WND *wndPtr, *parentWndPtr;
     POINT maxSize, maxPos, minTrack, maxTrack;
     CREATESTRUCT createStruct;
     int wmcreate;
     XSetWindowAttributes win_attr;
+    Atom XA_WM_DELETE_WINDOW;
 
     /* FIXME: windowName and className should be SEGPTRs */
 
@@ -473,6 +474,15 @@
                                         CWColormap | CWCursor | CWSaveUnder |
                                         CWBackingStore, &win_attr );
         XStoreName( display, wndPtr->window, PTR_SEG_TO_LIN(windowName) );
+	XA_WM_DELETE_WINDOW = XInternAtom( display, "WM_DELETE_WINDOW",
+					   False );
+	XSetWMProtocols( display, wndPtr->window, &XA_WM_DELETE_WINDOW, 1 );
+	if (parent)  /* Get window owner */
+	{
+            Window win = WIN_GetXWindow( parent );
+            if (win) XSetTransientForHint( display, wndPtr->window, win );
+	}
+	    
         EVENT_RegisterWindow( wndPtr->window, hwnd );
     }
     
@@ -663,8 +673,7 @@
  
  
 /**********************************************************************
- *           GetDesktopWindow        (USER.286)
- *	     GetDeskTopHwnd          (USER.278)
+ *           GetDesktopWindow   (USER.286)
  */
 HWND GetDesktopWindow(void)
 {
@@ -672,6 +681,18 @@
 }
 
 
+/**********************************************************************
+ *           GetDesktopHwnd   (USER.278)
+ *
+ * Exactly the same thing as GetDesktopWindow(), but not documented.
+ * Don't ask me why...
+ */
+HWND GetDesktopHwnd(void)
+{
+    return hwndDesktop;
+}
+
+
 /*******************************************************************
  *           EnableWindow   (USER.34)
  */
diff --git a/windows/winpos.c b/windows/winpos.c
index 683bde0..40929f4 100644
--- a/windows/winpos.c
+++ b/windows/winpos.c
@@ -1219,6 +1219,7 @@
 
     if ((flags & SWP_FRAMECHANGED) && !(flags & SWP_NOREDRAW))
         RedrawWindow( winpos.hwnd, NULL, 0,
+                      RDW_ALLCHILDREN | /*FIXME: this should not be necessary*/
                       RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
     if (!(flags & SWP_DEFERERASE))
         RedrawWindow( wndPtr->hwndParent, NULL, 0,
diff --git a/wine.man b/wine.man
index 5e79214..2f3f6c5 100644
--- a/wine.man
+++ b/wine.man
@@ -104,7 +104,7 @@
 .I -language xx
 Set the language to
 .I xx
-(one of En, Es, De, No, Fr, Fi, Da, Cz)
+(one of En, Es, De, No, Fr, Fi, Da, Cz, Eo)
 .TP
 .I -managed
 Create each top-level window as a properly managed X window