Remove code that starts wineshelllink, instead create a windows
compatible shortcut (*.lnk) file. After creating that file, start a
link processor (winemenubuilder) on it, which reads it back then calls
wineshelllink.
Rework CreateStreamFromFile to create an IStream object that is
writeable.

diff --git a/configure b/configure
index 43131c7..be41379 100755
--- a/configure
+++ b/configure
@@ -16038,7 +16038,7 @@
 MAKE_PROG_RULES=programs/Makeprog.rules
 
 
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          ac_config_files="$ac_config_files Make.rules dlls/Makedll.rules dlls/Maketest.rules libs/Makelib.rules programs/Makeprog.rules Makefile dlls/Makefile dlls/advapi32/Makefile dlls/advapi32/tests/Makefile dlls/avicap32/Makefile dlls/avifil32/Makefile dlls/cabinet/Makefile dlls/comcat/Makefile dlls/comctl32/Makefile dlls/comctl32/tests/Makefile dlls/commdlg/Makefile dlls/crtdll/Makefile dlls/crypt32/Makefile dlls/ctl3d/Makefile dlls/d3d8/Makefile dlls/d3dim/Makefile dlls/d3dx8/Makefile dlls/dciman32/Makefile dlls/ddraw/Makefile dlls/devenum/Makefile dlls/dinput/Makefile dlls/dinput8/Makefile dlls/dmband/Makefile dlls/dmcompos/Makefile dlls/dmime/Makefile dlls/dmloader/Makefile dlls/dmscript/Makefile dlls/dmstyle/Makefile dlls/dmsynth/Makefile dlls/dmusic/Makefile dlls/dmusic32/Makefile dlls/dplay/Makefile dlls/dplayx/Makefile dlls/dpnhpast/Makefile dlls/dsound/Makefile dlls/dsound/tests/Makefile dlls/gdi/Makefile dlls/gdi/tests/Makefile dlls/glu32/Makefile dlls/icmp/Makefile dlls/imagehlp/Makefile dlls/imm32/Makefile dlls/iphlpapi/Makefile dlls/kernel/Makefile dlls/kernel/tests/Makefile dlls/lzexpand/Makefile dlls/mapi32/Makefile dlls/mpr/Makefile dlls/msacm/Makefile dlls/msacm/imaadp32/Makefile dlls/msacm/msadp32/Makefile dlls/msacm/msg711/Makefile dlls/msacm/winemp3/Makefile dlls/msdmo/Makefile dlls/msimg32/Makefile dlls/msisys/Makefile dlls/msnet32/Makefile dlls/msvcrt/Makefile dlls/msvcrt/tests/Makefile dlls/msvcrt20/Makefile dlls/msvcrtd/Makefile dlls/msvideo/Makefile dlls/msvideo/msrle32/Makefile dlls/netapi32/Makefile dlls/netapi32/tests/Makefile dlls/ntdll/Makefile dlls/ntdll/tests/Makefile dlls/odbc32/Makefile dlls/ole32/Makefile dlls/oleaut32/Makefile dlls/oleaut32/tests/Makefile dlls/olecli/Makefile dlls/oledlg/Makefile dlls/olepro32/Makefile dlls/olesvr/Makefile dlls/opengl32/Makefile dlls/psapi/Makefile dlls/qcap/Makefile dlls/quartz/Makefile dlls/rasapi32/Makefile dlls/richedit/Makefile dlls/rpcrt4/Makefile dlls/rpcrt4/tests/Makefile dlls/serialui/Makefile dlls/setupapi/Makefile dlls/shdocvw/Makefile dlls/shell32/Makefile dlls/shell32/tests/Makefile dlls/shfolder/Makefile dlls/shlwapi/Makefile dlls/shlwapi/tests/Makefile dlls/snmpapi/Makefile dlls/sti/Makefile dlls/tapi32/Makefile dlls/ttydrv/Makefile dlls/twain/Makefile dlls/url/Makefile dlls/urlmon/Makefile dlls/urlmon/tests/Makefile dlls/user/Makefile dlls/user/tests/Makefile dlls/version/Makefile dlls/win32s/Makefile dlls/winaspi/Makefile dlls/winedos/Makefile dlls/wineps/Makefile dlls/wininet/Makefile dlls/wininet/tests/Makefile dlls/winmm/Makefile dlls/winmm/joystick/Makefile dlls/winmm/mcianim/Makefile dlls/winmm/mciavi/Makefile dlls/winmm/mcicda/Makefile dlls/winmm/mciseq/Makefile dlls/winmm/mciwave/Makefile dlls/winmm/midimap/Makefile dlls/winmm/tests/Makefile dlls/winmm/wavemap/Makefile dlls/winmm/winealsa/Makefile dlls/winmm/winearts/Makefile dlls/winmm/wineaudioio/Makefile dlls/winmm/winenas/Makefile dlls/winmm/winejack/Makefile dlls/winmm/wineoss/Makefile dlls/winnls/Makefile dlls/winsock/Makefile dlls/winsock/tests/Makefile dlls/winspool/Makefile dlls/winspool/tests/Makefile dlls/wintab32/Makefile dlls/wintrust/Makefile dlls/wow32/Makefile dlls/wsock32/Makefile dlls/x11drv/Makefile documentation/Makefile include/Makefile libs/Makefile libs/port/Makefile libs/unicode/Makefile libs/uuid/Makefile libs/wine/Makefile libs/wpp/Makefile miscemu/Makefile programs/Makefile programs/avitools/Makefile programs/clock/Makefile programs/cmdlgtst/Makefile programs/control/Makefile programs/expand/Makefile programs/notepad/Makefile programs/osversioncheck/Makefile programs/progman/Makefile programs/regapi/Makefile programs/regedit/Makefile programs/regsvr32/Makefile programs/regtest/Makefile programs/rpcss/Makefile programs/rundll32/Makefile programs/start/Makefile programs/uninstaller/Makefile programs/view/Makefile programs/wcmd/Makefile programs/wineboot/Makefile programs/winecfg/Makefile programs/wineconsole/Makefile programs/winedbg/Makefile programs/winefile/Makefile programs/winemine/Makefile programs/winepath/Makefile programs/winevdm/Makefile programs/winhelp/Makefile programs/winver/Makefile server/Makefile tools/Makefile tools/widl/Makefile tools/winapi/Makefile tools/winebuild/Makefile tools/winedump/Makefile tools/wmc/Makefile tools/wrc/Makefile"
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    ac_config_files="$ac_config_files Make.rules dlls/Makedll.rules dlls/Maketest.rules libs/Makelib.rules programs/Makeprog.rules Makefile dlls/Makefile dlls/advapi32/Makefile dlls/advapi32/tests/Makefile dlls/avicap32/Makefile dlls/avifil32/Makefile dlls/cabinet/Makefile dlls/comcat/Makefile dlls/comctl32/Makefile dlls/comctl32/tests/Makefile dlls/commdlg/Makefile dlls/crtdll/Makefile dlls/crypt32/Makefile dlls/ctl3d/Makefile dlls/d3d8/Makefile dlls/d3dim/Makefile dlls/d3dx8/Makefile dlls/dciman32/Makefile dlls/ddraw/Makefile dlls/devenum/Makefile dlls/dinput/Makefile dlls/dinput8/Makefile dlls/dmband/Makefile dlls/dmcompos/Makefile dlls/dmime/Makefile dlls/dmloader/Makefile dlls/dmscript/Makefile dlls/dmstyle/Makefile dlls/dmsynth/Makefile dlls/dmusic/Makefile dlls/dmusic32/Makefile dlls/dplay/Makefile dlls/dplayx/Makefile dlls/dpnhpast/Makefile dlls/dsound/Makefile dlls/dsound/tests/Makefile dlls/gdi/Makefile dlls/gdi/tests/Makefile dlls/glu32/Makefile dlls/icmp/Makefile dlls/imagehlp/Makefile dlls/imm32/Makefile dlls/iphlpapi/Makefile dlls/kernel/Makefile dlls/kernel/tests/Makefile dlls/lzexpand/Makefile dlls/mapi32/Makefile dlls/mpr/Makefile dlls/msacm/Makefile dlls/msacm/imaadp32/Makefile dlls/msacm/msadp32/Makefile dlls/msacm/msg711/Makefile dlls/msacm/winemp3/Makefile dlls/msdmo/Makefile dlls/msimg32/Makefile dlls/msisys/Makefile dlls/msnet32/Makefile dlls/msvcrt/Makefile dlls/msvcrt/tests/Makefile dlls/msvcrt20/Makefile dlls/msvcrtd/Makefile dlls/msvideo/Makefile dlls/msvideo/msrle32/Makefile dlls/netapi32/Makefile dlls/netapi32/tests/Makefile dlls/ntdll/Makefile dlls/ntdll/tests/Makefile dlls/odbc32/Makefile dlls/ole32/Makefile dlls/oleaut32/Makefile dlls/oleaut32/tests/Makefile dlls/olecli/Makefile dlls/oledlg/Makefile dlls/olepro32/Makefile dlls/olesvr/Makefile dlls/opengl32/Makefile dlls/psapi/Makefile dlls/qcap/Makefile dlls/quartz/Makefile dlls/rasapi32/Makefile dlls/richedit/Makefile dlls/rpcrt4/Makefile dlls/rpcrt4/tests/Makefile dlls/serialui/Makefile dlls/setupapi/Makefile dlls/shdocvw/Makefile dlls/shell32/Makefile dlls/shell32/tests/Makefile dlls/shfolder/Makefile dlls/shlwapi/Makefile dlls/shlwapi/tests/Makefile dlls/snmpapi/Makefile dlls/sti/Makefile dlls/tapi32/Makefile dlls/ttydrv/Makefile dlls/twain/Makefile dlls/url/Makefile dlls/urlmon/Makefile dlls/urlmon/tests/Makefile dlls/user/Makefile dlls/user/tests/Makefile dlls/version/Makefile dlls/win32s/Makefile dlls/winaspi/Makefile dlls/winedos/Makefile dlls/wineps/Makefile dlls/wininet/Makefile dlls/wininet/tests/Makefile dlls/winmm/Makefile dlls/winmm/joystick/Makefile dlls/winmm/mcianim/Makefile dlls/winmm/mciavi/Makefile dlls/winmm/mcicda/Makefile dlls/winmm/mciseq/Makefile dlls/winmm/mciwave/Makefile dlls/winmm/midimap/Makefile dlls/winmm/tests/Makefile dlls/winmm/wavemap/Makefile dlls/winmm/winealsa/Makefile dlls/winmm/winearts/Makefile dlls/winmm/wineaudioio/Makefile dlls/winmm/winenas/Makefile dlls/winmm/winejack/Makefile dlls/winmm/wineoss/Makefile dlls/winnls/Makefile dlls/winsock/Makefile dlls/winsock/tests/Makefile dlls/winspool/Makefile dlls/winspool/tests/Makefile dlls/wintab32/Makefile dlls/wintrust/Makefile dlls/wow32/Makefile dlls/wsock32/Makefile dlls/x11drv/Makefile documentation/Makefile include/Makefile libs/Makefile libs/port/Makefile libs/unicode/Makefile libs/uuid/Makefile libs/wine/Makefile libs/wpp/Makefile miscemu/Makefile programs/Makefile programs/avitools/Makefile programs/clock/Makefile programs/cmdlgtst/Makefile programs/control/Makefile programs/expand/Makefile programs/notepad/Makefile programs/osversioncheck/Makefile programs/progman/Makefile programs/regapi/Makefile programs/regedit/Makefile programs/regsvr32/Makefile programs/regtest/Makefile programs/rpcss/Makefile programs/rundll32/Makefile programs/start/Makefile programs/uninstaller/Makefile programs/view/Makefile programs/wcmd/Makefile programs/wineboot/Makefile programs/winecfg/Makefile programs/wineconsole/Makefile programs/winedbg/Makefile programs/winefile/Makefile programs/winemenubuilder/Makefile programs/winemine/Makefile programs/winepath/Makefile programs/winevdm/Makefile programs/winhelp/Makefile programs/winver/Makefile server/Makefile tools/Makefile tools/widl/Makefile tools/winapi/Makefile tools/winebuild/Makefile tools/winedump/Makefile tools/wmc/Makefile tools/wrc/Makefile"
 
 
 cat >confcache <<\_ACEOF
@@ -16740,6 +16740,7 @@
   "programs/wineconsole/Makefile" ) CONFIG_FILES="$CONFIG_FILES programs/wineconsole/Makefile" ;;
   "programs/winedbg/Makefile" ) CONFIG_FILES="$CONFIG_FILES programs/winedbg/Makefile" ;;
   "programs/winefile/Makefile" ) CONFIG_FILES="$CONFIG_FILES programs/winefile/Makefile" ;;
+  "programs/winemenubuilder/Makefile" ) CONFIG_FILES="$CONFIG_FILES programs/winemenubuilder/Makefile" ;;
   "programs/winemine/Makefile" ) CONFIG_FILES="$CONFIG_FILES programs/winemine/Makefile" ;;
   "programs/winepath/Makefile" ) CONFIG_FILES="$CONFIG_FILES programs/winepath/Makefile" ;;
   "programs/winevdm/Makefile" ) CONFIG_FILES="$CONFIG_FILES programs/winevdm/Makefile" ;;
diff --git a/configure.ac b/configure.ac
index 2590fce..9342cca 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1525,6 +1525,7 @@
 programs/wineconsole/Makefile
 programs/winedbg/Makefile
 programs/winefile/Makefile
+programs/winemenubuilder/Makefile
 programs/winemine/Makefile
 programs/winepath/Makefile
 programs/winevdm/Makefile
diff --git a/dlls/shell32/Makefile.in b/dlls/shell32/Makefile.in
index 65d9ef6..f132e52 100644
--- a/dlls/shell32/Makefile.in
+++ b/dlls/shell32/Makefile.in
@@ -58,13 +58,6 @@
 
 @MAKE_DLL_RULES@
 
-install::
-	$(MKINSTALLDIRS) $(bindir)
-	$(INSTALL_SCRIPT) $(TOPSRCDIR)/tools/wineshelllink $(bindir)/wineshelllink
-
-uninstall::
-	$(RM) $(bindir)/wineshelllink
-
 # Special rules for 16-bit resource files
 
 version16.res: version16.rc
diff --git a/dlls/shell32/memorystream.c b/dlls/shell32/memorystream.c
index 9b225af..0bcd5f8 100644
--- a/dlls/shell32/memorystream.c
+++ b/dlls/shell32/memorystream.c
@@ -9,6 +9,7 @@
  *	access in a IStream to.
  *
  * Copyright 1999 Juergen Schmied
+ * Copyright 2003 Mike McCormack for Codeweavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -73,10 +74,7 @@
 typedef struct
 {	ICOM_VTABLE(IStream)	*lpvtst;
 	DWORD		ref;
-	LPBYTE		pImage;
-	HANDLE		hMapping;
-	DWORD		dwLength;
-	DWORD		dwPos;
+	HANDLE		handle;
 } ISHFileStream;
 
 /**************************************************************************
@@ -84,40 +82,42 @@
  *
  *   similar to CreateStreamOnHGlobal
  */
-HRESULT CreateStreamOnFile (LPCSTR pszFilename, IStream ** ppstm)
+HRESULT CreateStreamOnFile (LPCWSTR pszFilename, DWORD grfMode, IStream ** ppstm)
 {
 	ISHFileStream*	fstr;
-	OFSTRUCT	ofs;
-	HFILE		hFile = OpenFile( pszFilename, &ofs, OF_READ );
-	HRESULT		ret = E_FAIL;
+	HANDLE		handle;
+	DWORD		access = GENERIC_READ, creat;
 
-	fstr = (ISHFileStream*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ISHFileStream));
+	if( grfMode & STGM_TRANSACTED )
+		return E_INVALIDARG;
+
+	if( grfMode & STGM_WRITE )
+		access |= GENERIC_WRITE;
+        if( grfMode & STGM_READWRITE )
+		access = GENERIC_WRITE | GENERIC_READ;
+
+	if( grfMode & STGM_CREATE )
+		creat = CREATE_ALWAYS;
+	else
+		creat = OPEN_EXISTING;
+
+	TRACE("Opening %s\n", debugstr_w(pszFilename) );
+
+	handle = CreateFileW( pszFilename, access, 0, NULL, creat, 0, NULL );
+	if( handle == INVALID_HANDLE_VALUE )
+		return E_FAIL;
+
+	fstr = (ISHFileStream*)HeapAlloc(GetProcessHeap(),
+		HEAP_ZERO_MEMORY,sizeof(ISHFileStream));
+	if( !fstr )
+		return E_FAIL;
 	fstr->lpvtst=&stvt;
 	fstr->ref = 1;
-	fstr->dwLength = GetFileSize ((HANDLE)hFile, NULL);
+	fstr->handle = handle;
 
-	if (!(fstr->hMapping = CreateFileMappingA((HANDLE)hFile,NULL,PAGE_READONLY|SEC_COMMIT,0,0,NULL)))
-	{
-	  WARN("failed to create filemap.\n");
-	  goto end_2;
-	}
-
-	if (!(fstr->pImage = MapViewOfFile(fstr->hMapping,FILE_MAP_READ,0,0,0)))
-	{
-	  WARN("failed to mmap filemap.\n");
-	  goto end_3;
-	}
-
-	ret = S_OK;
-	goto end_1;
-
-end_3:	CloseHandle(fstr->hMapping);
-end_2:	HeapFree(GetProcessHeap(), 0, fstr);
-	fstr = NULL;
-
-end_1:	_lclose(hFile);
 	(*ppstm) = (IStream*)fstr;
-	return ret;
+
+	return S_OK;
 }
 
 /**************************************************************************
@@ -169,13 +169,10 @@
 	TRACE("(%p)->()\n",This);
 
 	if (!--(This->ref))
-	{ TRACE(" destroying SHFileStream (%p)\n",This);
-
-	  UnmapViewOfFile(This->pImage);
-	  CloseHandle(This->hMapping);
-
-	  HeapFree(GetProcessHeap(),0,This);
-	  return 0;
+	{
+		TRACE(" destroying SHFileStream (%p)\n",This);
+		CloseHandle(This->handle);
+		HeapFree(GetProcessHeap(),0,This);
 	}
 	return This->ref;
 }
@@ -184,52 +181,64 @@
 {
 	ICOM_THIS(ISHFileStream, iface);
 
-	DWORD dwBytesToRead, dwBytesLeft;
-
 	TRACE("(%p)->(%p,0x%08lx,%p)\n",This, pv, cb, pcbRead);
 
 	if ( !pv )
-	  return STG_E_INVALIDPOINTER;
+		return STG_E_INVALIDPOINTER;
 
-	dwBytesLeft = This->dwLength - This->dwPos;
-
-	if ( 0 >= dwBytesLeft )						/* end of buffer */
-	  return S_FALSE;
-
-	dwBytesToRead = ( cb > dwBytesLeft) ? dwBytesLeft : cb;
-
-	memmove ( pv, (This->pImage) + (This->dwPos), dwBytesToRead);
-
-	This->dwPos += dwBytesToRead;					/* adjust pointer */
-
-	if (pcbRead)
-	  *pcbRead = dwBytesToRead;
+	if ( ! ReadFile( This->handle, pv, cb, pcbRead, NULL ) )
+		return E_FAIL;
 
 	return S_OK;
 }
+
 static HRESULT WINAPI IStream_fnWrite (IStream * iface, const void* pv, ULONG cb, ULONG* pcbWritten)
 {
 	ICOM_THIS(ISHFileStream, iface);
 
 	TRACE("(%p)\n",This);
 
-	return E_NOTIMPL;
+	if( !pv )
+		return STG_E_INVALIDPOINTER;
+
+	if( ! WriteFile( This->handle, pv, cb, pcbWritten, NULL ) )
+		return E_FAIL;
+
+	return S_OK;
 }
+
 static HRESULT WINAPI IStream_fnSeek (IStream * iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
 {
+	DWORD pos, newposlo, newposhi;
+
 	ICOM_THIS(ISHFileStream, iface);
 
 	TRACE("(%p)\n",This);
 
-	return E_NOTIMPL;
+	pos = dlibMove.QuadPart; /* FIXME: truncates */
+	newposhi = 0;
+	newposlo = SetFilePointer( This->handle, pos, &newposhi, dwOrigin );
+	if( newposlo == INVALID_SET_FILE_POINTER )
+		return E_FAIL;
+
+	plibNewPosition->QuadPart = newposlo | ( (LONGLONG)newposhi<<32);
+
+	return S_OK;
 }
+
 static HRESULT WINAPI IStream_fnSetSize (IStream * iface, ULARGE_INTEGER libNewSize)
 {
 	ICOM_THIS(ISHFileStream, iface);
 
 	TRACE("(%p)\n",This);
 
-	return E_NOTIMPL;
+	if( ! SetFilePointer( This->handle, libNewSize.QuadPart, NULL, FILE_BEGIN ) )
+		return E_FAIL;
+
+	if( ! SetEndOfFile( This->handle ) )
+		return E_FAIL;
+
+	return S_OK;
 }
 static HRESULT WINAPI IStream_fnCopyTo (IStream * iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten)
 {
diff --git a/dlls/shell32/shell32_main.h b/dlls/shell32/shell32_main.h
index b354450..0f64d97 100644
--- a/dlls/shell32/shell32_main.h
+++ b/dlls/shell32/shell32_main.h
@@ -101,14 +101,12 @@
 
 LPEXTRACTICONA	IExtractIconA_Constructor(LPITEMIDLIST);
 LPEXTRACTICONW	IExtractIconW_Constructor(LPITEMIDLIST);
-HRESULT		CreateStreamOnFile (LPCSTR pszFilename, IStream ** ppstm);
+HRESULT		CreateStreamOnFile (LPCWSTR pszFilename, DWORD grfMode, IStream ** ppstm);
 
 /* FIXME: rename the functions when the shell32.dll has it's own exports namespace */
 HRESULT WINAPI  SHELL32_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID * ppv);
 HRESULT WINAPI  SHELL32_DllCanUnloadNow(void);
 
-/* FIXME: move away */
-#define ResultFromShort(i) MAKE_SCODE(SEVERITY_SUCCESS, 0, (USHORT)(i))
 
 /* menu merging */
 #define MM_ADDSEPARATOR         0x00000001L
diff --git a/dlls/shell32/shelllink.c b/dlls/shell32/shelllink.c
index 423a820..dfcc2be 100644
--- a/dlls/shell32/shelllink.c
+++ b/dlls/shell32/shelllink.c
@@ -20,12 +20,14 @@
 
 #include "config.h"
 
+#include <ctype.h>
 #include <string.h>
 #include <stdio.h>
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif
 #include <errno.h>
+#include <limits.h>
 #ifdef HAVE_SYS_WAIT_H
 # include <sys/wait.h>
 #endif
@@ -38,7 +40,6 @@
 
 #include "shlobj.h"
 #include "undocshell.h"
-#include "bitmaps/wine.xpm"
 
 #include "heap.h"
 #include "pidl.h"
@@ -49,87 +50,60 @@
 
 /* link file formats */
 
+/* flag1: lnk elements: simple link has 0x0B */
+#define SCF_PIDL   1
+#define SCF_NORMAL 2
+#define SCF_DESCRIPTION 4
+#define SCF_RELATIVE 8
+#define SCF_WORKDIR 0x10
+#define SCF_ARGS 0x20
+#define SCF_CUSTOMICON 0x40
+#define SCF_UNC 0x80
+#define SCF_UNICODE 0x1000
+
 #include "pshpack1.h"
 
-/* flag1: lnk elements: simple link has 0x0B */
-#define	WORKDIR		0x10
-#define	ARGUMENT	0x20
-#define	ICON		0x40
-#define UNC		0x80
-
-/* fStartup */
-#define	NORMAL		0x01
-#define	MAXIMIZED	0x03
-#define	MINIMIZED	0x07
-
 typedef struct _LINK_HEADER
-{	DWORD	MagicStr;	/* 0x00 'L','\0','\0','\0' */
-	GUID	MagicGuid;	/* 0x04 is CLSID_ShellLink */
-	DWORD	Flag1;		/* 0x14 describes elements following */
-	DWORD	Flag2;		/* 0x18 */
+{
+	DWORD    dwSize;	/* 0x00 size of the header - 0x4c */
+	GUID     MagicGuid;	/* 0x04 is CLSID_ShellLink */
+	DWORD    dwFlags;	/* 0x14 describes elements following */
+	DWORD    dwFileAttr;	/* 0x18 attributes of the target file */
 	FILETIME Time1;		/* 0x1c */
 	FILETIME Time2;		/* 0x24 */
 	FILETIME Time3;		/* 0x2c */
-	DWORD	Unknown1;	/* 0x34 */
-	DWORD	Unknown2;	/* 0x38 icon number */
+	DWORD    dwFileLength;	/* 0x34 File length */
+	DWORD    nIcon;		/* 0x38 icon number */
 	DWORD	fStartup;	/* 0x3c startup type */
 	DWORD	wHotKey;	/* 0x40 hotkey */
 	DWORD	Unknown5;	/* 0x44 */
 	DWORD	Unknown6;	/* 0x48 */
-	USHORT	PidlSize;	/* 0x4c */
-	ITEMIDLIST Pidl;	/* 0x4e */
 } LINK_HEADER, * PLINK_HEADER;
 
-#define LINK_HEADER_SIZE (sizeof(LINK_HEADER)-sizeof(ITEMIDLIST))
+#define SHLINK_LOCAL  0
+#define SHLINK_REMOTE 1
 
-typedef struct
+typedef struct _LOCATION_INFO
 {
-	BYTE bWidth;
-	BYTE bHeight;
-	BYTE bColorCount;
-	BYTE bReserved;
-	WORD wPlanes;
-	WORD wBitCount;
-	DWORD dwBytesInRes;
-	WORD nID;
-} GRPICONDIRENTRY;
+    DWORD  dwTotalSize;
+    DWORD  dwHeaderSize;
+    DWORD  dwFlags;
+    DWORD  dwVolTableOfs;
+    DWORD  dwLocalPathOfs;
+    DWORD  dwNetworkVolTableOfs;
+    DWORD  dwFinalPathOfs;
+} LOCATION_INFO;
 
-typedef struct
+typedef struct _LOCAL_VOLUME_INFO
 {
-	WORD idReserved;
-	WORD idType;
-	WORD idCount;
-	GRPICONDIRENTRY idEntries[1];
-} GRPICONDIR;
-
-typedef struct
-{
-	BYTE bWidth;
-	BYTE bHeight;
-	BYTE bColorCount;
-	BYTE bReserved;
-	WORD wPlanes;
-	WORD wBitCount;
-	DWORD dwBytesInRes;
-	DWORD dwImageOffset;
-} ICONDIRENTRY;
-
-typedef struct
-{
-	WORD idReserved;
-	WORD idType;
-	WORD idCount;
-} ICONDIR;
-
+    DWORD dwSize;
+    DWORD dwType;
+    DWORD dwVolSerial;
+    DWORD dwVolLabelOfs;
+} LOCAL_VOLUME_INFO;
 
 #include "poppack.h"
 
-typedef struct
-{
-        HRSRC *pResInfo;
-        int   nIndex;
-} ENUMRESSTRUCT;
-
 static ICOM_VTABLE(IShellLinkA)		slvt;
 static ICOM_VTABLE(IShellLinkW)		slvtw;
 static ICOM_VTABLE(IPersistFile)	pfvt;
@@ -146,41 +120,42 @@
 	ICOM_VTABLE(IPersistFile)*	lpvtblPersistFile;
 	ICOM_VTABLE(IPersistStream)*	lpvtblPersistStream;
 
-	/* internal stream of the IPersistFile interface */
-	IStream*			lpFileStream;
-
 	/* data structures according to the informations in the lnk */
-	LPSTR		sPath;
 	LPITEMIDLIST	pPidl;
 	WORD		wHotKey;
 	SYSTEMTIME	time1;
 	SYSTEMTIME	time2;
 	SYSTEMTIME	time3;
 
-	LPSTR		sIcoPath;
-	INT		iIcoNdx;
-	LPSTR		sArgs;
-	LPSTR		sWorkDir;
-	LPSTR		sDescription;
+	DWORD         iShowCmd;
+	LPWSTR        sIcoPath;
+	INT           iIcoNdx;
+	LPWSTR        sPath;
+	LPWSTR        sArgs;
+	LPWSTR        sWorkDir;
+	LPWSTR        sDescription;
+	LPWSTR        sPathRel;
 } IShellLinkImpl;
 
 #define _IShellLinkW_Offset ((int)(&(((IShellLinkImpl*)0)->lpvtblw)))
-#define _ICOM_THIS_From_IShellLinkW(class, name) class* This = (class*)(((char*)name)-_IShellLinkW_Offset);
+#define _ICOM_THIS_From_IShellLinkW(class, name) class* This = (class*)(((char*)name)-_IShellLinkW_Offset)
 
 #define _IPersistFile_Offset ((int)(&(((IShellLinkImpl*)0)->lpvtblPersistFile)))
-#define _ICOM_THIS_From_IPersistFile(class, name) class* This = (class*)(((char*)name)-_IPersistFile_Offset);
+#define _ICOM_THIS_From_IPersistFile(class, name) class* This = (class*)(((char*)name)-_IPersistFile_Offset)
 
 #define _IPersistStream_Offset ((int)(&(((IShellLinkImpl*)0)->lpvtblPersistStream)))
-#define _ICOM_THIS_From_IPersistStream(class, name) class* This = (class*)(((char*)name)-_IPersistStream_Offset);
-#define _IPersistStream_From_ICOM_THIS(class, name) class* StreamThis = (class*)(((char*)name)+_IPersistStream_Offset);
+#define _ICOM_THIS_From_IPersistStream(class, name) class* This = (class*)(((char*)name)-_IPersistStream_Offset)
+#define _IPersistStream_From_ICOM_THIS(class, name) class* StreamThis = (class*)(((char*)name)+_IPersistStream_Offset)
 
 
 /* strdup on the process heap */
-inline static LPSTR heap_strdup( LPCSTR str )
+inline static LPWSTR HEAP_strdupAtoW( HANDLE heap, DWORD flags, LPCSTR str)
 {
-    INT len = strlen(str) + 1;
-    LPSTR p = HeapAlloc( GetProcessHeap(), 0, len );
-    if (p) memcpy( p, str, len );
+    INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
+    LPWSTR p = HeapAlloc( heap, flags, len*sizeof (WCHAR) );
+    if( !p )
+        return p;
+    MultiByteToWideChar( CP_ACP, 0, str, -1, p, len );
     return p;
 }
 
@@ -193,7 +168,7 @@
 	REFIID riid,
 	LPVOID *ppvObj)
 {
-	_ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface)
+	_ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
 
 	TRACE("(%p)\n",This);
 
@@ -205,7 +180,7 @@
  */
 static ULONG WINAPI IPersistFile_fnAddRef(IPersistFile* iface)
 {
-	_ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface)
+	_ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
 
 	TRACE("(%p)->(count=%lu)\n",This,This->ref);
 
@@ -216,7 +191,7 @@
  */
 static ULONG WINAPI IPersistFile_fnRelease(IPersistFile* iface)
 {
-	_ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface)
+	_ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
 
 	TRACE("(%p)->(count=%lu)\n",This,This->ref);
 
@@ -225,558 +200,95 @@
 
 static HRESULT WINAPI IPersistFile_fnGetClassID(IPersistFile* iface, CLSID *pClassID)
 {
-	_ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface)
+	_ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
 	FIXME("(%p)\n",This);
 	return NOERROR;
 }
 static HRESULT WINAPI IPersistFile_fnIsDirty(IPersistFile* iface)
 {
-	_ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface)
+	_ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
 	FIXME("(%p)\n",This);
 	return NOERROR;
 }
 static HRESULT WINAPI IPersistFile_fnLoad(IPersistFile* iface, LPCOLESTR pszFileName, DWORD dwMode)
 {
-	_ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface)
-	_IPersistStream_From_ICOM_THIS(IPersistStream, This)
+	_ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
+	_IPersistStream_From_ICOM_THIS(IPersistStream, This);
+        HRESULT r;
+        IStream *stm;
 
-	LPSTR		sFile = HEAP_strdupWtoA ( GetProcessHeap(), 0, pszFileName);
-	HRESULT		hRet = E_FAIL;
+        TRACE("(%p, %s)\n",This, debugstr_w(pszFileName));
 
-	TRACE("(%p, %s)\n",This, sFile);
-
-
-	if (This->lpFileStream)
-	  IStream_Release(This->lpFileStream);
-
-	if SUCCEEDED(CreateStreamOnFile(sFile, &(This->lpFileStream)))
-	{
-	  if SUCCEEDED (IPersistStream_Load(StreamThis, This->lpFileStream))
-	  {
-	    return NOERROR;
-	  }
-	}
-
-	return hRet;
-}
-
-
-/* Icon extraction routines
- *
- * FIXME: should use PrivateExtractIcons and friends
- * FIXME: should not use stdio
- */
-
-static BOOL SaveIconResAsXPM(const BITMAPINFO *pIcon, const char *szXPMFileName)
-{
-    FILE *fXPMFile;
-    int nHeight;
-    int nXORWidthBytes;
-    int nANDWidthBytes;
-    BOOL b8BitColors;
-    int nColors;
-    BYTE *pXOR;
-    BYTE *pAND;
-    BOOL aColorUsed[256] = {0};
-    int nColorsUsed = 0;
-    int i,j;
-
-    if (!((pIcon->bmiHeader.biBitCount == 4) || (pIcon->bmiHeader.biBitCount == 8)))
-        return 0;
-
-    if (!(fXPMFile = fopen(szXPMFileName, "w")))
-        return 0;
-
-    nHeight = pIcon->bmiHeader.biHeight / 2;
-    nXORWidthBytes = 4 * ((pIcon->bmiHeader.biWidth * pIcon->bmiHeader.biBitCount / 32)
-                          + ((pIcon->bmiHeader.biWidth * pIcon->bmiHeader.biBitCount % 32) > 0));
-    nANDWidthBytes = 4 * ((pIcon->bmiHeader.biWidth / 32)
-                          + ((pIcon->bmiHeader.biWidth % 32) > 0));
-    b8BitColors = pIcon->bmiHeader.biBitCount == 8;
-    nColors = pIcon->bmiHeader.biClrUsed ? pIcon->bmiHeader.biClrUsed
-        : 1 << pIcon->bmiHeader.biBitCount;
-    pXOR = (BYTE*) pIcon + sizeof (BITMAPINFOHEADER) + (nColors * sizeof (RGBQUAD));
-    pAND = pXOR + nHeight * nXORWidthBytes;
-
-#define MASK(x,y) (pAND[(x) / 8 + (nHeight - (y) - 1) * nANDWidthBytes] & (1 << (7 - (x) % 8)))
-#define COLOR(x,y) (b8BitColors ? pXOR[(x) + (nHeight - (y) - 1) * nXORWidthBytes] : (x) % 2 ? pXOR[(x) / 2 + (nHeight - (y) - 1) * nXORWidthBytes] & 0xF : (pXOR[(x) / 2 + (nHeight - (y) - 1) * nXORWidthBytes] & 0xF0) >> 4)
-
-    for (i = 0; i < nHeight; i++)
-        for (j = 0; j < pIcon->bmiHeader.biWidth; j++)
-            if (!aColorUsed[COLOR(j,i)] && !MASK(j,i))
-            {
-                aColorUsed[COLOR(j,i)] = TRUE;
-                nColorsUsed++;
-            }
-
-    if (fprintf(fXPMFile, "/* XPM */\nstatic char *icon[] = {\n") <= 0)
-        goto error;
-    if (fprintf(fXPMFile, "\"%d %d %d %d\",\n",
-                (int) pIcon->bmiHeader.biWidth, nHeight, nColorsUsed + 1, 2) <=0)
-        goto error;
-
-    for (i = 0; i < nColors; i++)
-        if (aColorUsed[i])
-            if (fprintf(fXPMFile, "\"%.2X c #%.2X%.2X%.2X\",\n", i, pIcon->bmiColors[i].rgbRed,
-                        pIcon->bmiColors[i].rgbGreen, pIcon->bmiColors[i].rgbBlue) <= 0)
-                goto error;
-    if (fprintf(fXPMFile, "\"   c None\"") <= 0)
-        goto error;
-
-    for (i = 0; i < nHeight; i++)
-    {
-        if (fprintf(fXPMFile, ",\n\"") <= 0)
-            goto error;
-        for (j = 0; j < pIcon->bmiHeader.biWidth; j++)
+        r = CreateStreamOnFile(pszFileName, dwMode, &stm);
+        if( SUCCEEDED( r ) )
         {
-            if MASK(j,i)
-                {
-                    if (fprintf(fXPMFile, "  ") <= 0)
-                        goto error;
-                }
-            else
-                if (fprintf(fXPMFile, "%.2X", COLOR(j,i)) <= 0)
-                    goto error;
-        }
-        if (fprintf(fXPMFile, "\"") <= 0)
-            goto error;
-    }
-    if (fprintf(fXPMFile, "};\n") <= 0)
-        goto error;
-
-#undef MASK
-#undef COLOR
-
-    fclose(fXPMFile);
-    return 1;
-
- error:
-    fclose(fXPMFile);
-    unlink( szXPMFileName );
-    return 0;
-}
-
-static BOOL CALLBACK EnumResNameProc(HANDLE hModule, const char *lpszType, char *lpszName, LONG lParam)
-{
-    ENUMRESSTRUCT *sEnumRes = (ENUMRESSTRUCT *) lParam;
-
-    if (!sEnumRes->nIndex--)
-    {
-      *sEnumRes->pResInfo = FindResourceA(hModule, lpszName, RT_GROUP_ICONA);
-      return FALSE;
-    }
-    else
-      return TRUE;
-}
-
-static int ExtractFromEXEDLL(const char *szFileName, int nIndex, const char *szXPMFileName)
-{
-    HMODULE hModule;
-    HRSRC hResInfo;
-    char *lpName = NULL;
-    HGLOBAL hResData;
-    GRPICONDIR *pIconDir;
-    BITMAPINFO *pIcon;
-    ENUMRESSTRUCT sEnumRes;
-    int nMax = 0;
-    int nMaxBits = 0;
-    int i;
-
-    if (!(hModule = LoadLibraryExA(szFileName, 0, LOAD_LIBRARY_AS_DATAFILE)))
-    {
-        TRACE("LoadLibraryExA (%s) failed, error %ld\n", szFileName, GetLastError());
-        goto error1;
-    }
-
-    if (nIndex < 0)
-    {
-        hResInfo = FindResourceA(hModule, MAKEINTRESOURCEA(-nIndex), RT_GROUP_ICONA);
-        TRACE("FindResourceA (%s) called, return %p, error %ld\n", szFileName, hResInfo, GetLastError());
-    }
-    else
-    {
-        sEnumRes.pResInfo = &hResInfo;
-        sEnumRes.nIndex = nIndex;
-        if (EnumResourceNamesA(hModule, RT_GROUP_ICONA,
-			       (ENUMRESNAMEPROCA)&EnumResNameProc,
-			       (LONG) &sEnumRes))
-        {
-            TRACE("EnumResourceNamesA failed, error %ld\n", GetLastError());
-            goto error2;
-        }
-    }
-
-    if (!hResInfo)
-    {
-        TRACE("ExtractFromEXEDLL failed, error %ld\n", GetLastError());
-        goto error2;
-    }
-
-    if (!(hResData = LoadResource(hModule, hResInfo)))
-    {
-        TRACE("LoadResource failed, error %ld\n", GetLastError());
-        goto error2;
-    }
-    if (!(pIconDir = LockResource(hResData)))
-    {
-        TRACE("LockResource failed, error %ld\n", GetLastError());
-        goto error3;
-    }
-
-    for (i = 0; i < pIconDir->idCount; i++)
-        if ((pIconDir->idEntries[i].wBitCount >= nMaxBits) && (pIconDir->idEntries[i].wBitCount <= 8))
-        {
-          if (pIconDir->idEntries[i].wBitCount > nMaxBits)
-          {
-              nMaxBits = pIconDir->idEntries[i].wBitCount;
-              nMax = 0;
-          }
-          if ((pIconDir->idEntries[i].bHeight * pIconDir->idEntries[i].bWidth) > nMax)
-          {
-              lpName = MAKEINTRESOURCEA(pIconDir->idEntries[i].nID);
-              nMax = pIconDir->idEntries[i].bHeight * pIconDir->idEntries[i].bWidth;
-          }
+            r = IPersistStream_Load(StreamThis, stm);
+            IStream_Release( stm );
         }
 
-    FreeResource(hResData);
-
-    if (!(hResInfo = FindResourceA(hModule, lpName, RT_ICONA)))
-    {
-        TRACE("Second FindResourceA failed, error %ld\n", GetLastError());
-        goto error2;
-    }
-    if (!(hResData = LoadResource(hModule, hResInfo)))
-    {
-        TRACE("Second LoadResource failed, error %ld\n", GetLastError());
-        goto error2;
-    }
-    if (!(pIcon = LockResource(hResData)))
-    {
-        TRACE("Second LockResource failed, error %ld\n", GetLastError());
-        goto error3;
-    }
-
-    if(!SaveIconResAsXPM(pIcon, szXPMFileName))
-    {
-        TRACE("Failed saving icon as XPM, error %ld\n", GetLastError());
-        goto error3;
-    }
-
-    FreeResource(hResData);
-    FreeLibrary(hModule);
-
-    return 1;
-
- error3:
-    FreeResource(hResData);
- error2:
-    FreeLibrary(hModule);
- error1:
-    return 0;
+        return r;
 }
 
-/* get the Unix file name for a given path, allocating the string */
-inline static char *get_unix_file_name( const char *dos )
+static BOOL StartLinkProcessor( LPCOLESTR szLink )
 {
-    char buffer[MAX_PATH];
+    const WCHAR szFormat[] = {'w','i','n','e','m','e','n','u','b','u','i','l','d','e','r','.','e','x','e',
+                              ' ','-','r',' ','"','%','s','"',0 };
+    LONG len;
+    LPWSTR buffer;
+    STARTUPINFOW si;
+    PROCESS_INFORMATION pi;
 
-    if (!wine_get_unix_file_name( dos, buffer, sizeof(buffer) )) return NULL;
-    return heap_strdup( buffer );
-}
+    len = sizeof(szFormat) + lstrlenW( szLink ) * sizeof(WCHAR);
+    buffer = HeapAlloc( GetProcessHeap(), 0, len );
+    if( !buffer )
+        return FALSE;
 
-static int ExtractFromICO(const char *szFileName, const char *szXPMFileName)
-{
-    FILE *fICOFile;
-    ICONDIR iconDir;
-    ICONDIRENTRY *pIconDirEntry;
-    int nMax = 0;
-    int nIndex = 0;
-    void *pIcon;
-    int i;
-    char *filename;
+    wsprintfW( buffer, szFormat, szLink );
 
-    filename = get_unix_file_name(szFileName);
-    if (!(fICOFile = fopen(filename, "r")))
-        goto error1;
+    TRACE("starting %s\n",debugstr_w(buffer));
 
-    if (fread(&iconDir, sizeof (ICONDIR), 1, fICOFile) != 1)
-        goto error2;
-    if ((iconDir.idReserved != 0) || (iconDir.idType != 1))
-        goto error2;
+    memset(&si, 0, sizeof si);
+    si.cb = sizeof si;
+    if (!CreateProcessW( NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) return FALSE;
 
-    if ((pIconDirEntry = malloc(iconDir.idCount * sizeof (ICONDIRENTRY))) == NULL)
-        goto error2;
-    if (fread(pIconDirEntry, sizeof (ICONDIRENTRY), iconDir.idCount, fICOFile) != iconDir.idCount)
-        goto error3;
+    /* wait for a while to throttle the creation of linker processes */
+    if( WAIT_OBJECT_0 != WaitForSingleObject( pi.hProcess, 10000 ) )
+        WARN("Timed out waiting for shell linker\n");
 
-    for (i = 0; i < iconDir.idCount; i++)
-        if ((pIconDirEntry[i].bHeight * pIconDirEntry[i].bWidth) > nMax)
-        {
-            nIndex = i;
-            nMax = pIconDirEntry[i].bHeight * pIconDirEntry[i].bWidth;
-        }
-    if ((pIcon = malloc(pIconDirEntry[nIndex].dwBytesInRes)) == NULL)
-        goto error3;
-    if (fseek(fICOFile, pIconDirEntry[nIndex].dwImageOffset, SEEK_SET))
-        goto error4;
-    if (fread(pIcon, pIconDirEntry[nIndex].dwBytesInRes, 1, fICOFile) != 1)
-        goto error4;
+    CloseHandle( pi.hProcess );
+    CloseHandle( pi.hThread );
 
-    if(!SaveIconResAsXPM(pIcon, szXPMFileName))
-        goto error4;
-
-    free(pIcon);
-    free(pIconDirEntry);
-    fclose(fICOFile);
-
-    return 1;
-
- error4:
-    free(pIcon);
- error3:
-    free(pIconDirEntry);
- error2:
-    fclose(fICOFile);
- error1:
-    HeapFree(GetProcessHeap(), 0, filename);
-    return 0;
-}
-
-static BOOL create_default_icon( const char *filename )
-{
-    FILE *fXPM;
-    int i;
-
-    if (!(fXPM = fopen(filename, "w"))) return FALSE;
-    fprintf(fXPM, "/* XPM */\nstatic char * icon[] = {");
-    for (i = 0; i < sizeof(wine_xpm)/sizeof(wine_xpm[0]); i++)
-        fprintf( fXPM, "\n\"%s\",", wine_xpm[i]);
-    fprintf( fXPM, "};\n" );
-    fclose( fXPM );
     return TRUE;
 }
 
-/* extract an icon from an exe or icon file; helper for IPersistFile_fnSave */
-static char *extract_icon( const char *path, int index)
-{
-    int fd, nodefault = 1;
-    char *filename, tmpfn[25];
-
-    strcpy(tmpfn,"/tmp/icon.XXXXXX.xpm");
-    fd = mkstemps( tmpfn, 4 );
-    if (fd == -1)
-        return NULL;
-    filename = heap_strdup( tmpfn );
-    close(fd); /* not needed */
-
-    /* If icon path begins with a '*' then this is a deferred call */
-    if (path[0] == '*')
-    {
-        path++;
-        nodefault = 0;
-    }
-    if (ExtractFromEXEDLL( path, index, filename )) return filename;
-    if (ExtractFromICO( path, filename )) return filename;
-    if (!nodefault)
-        if (create_default_icon( filename )) return filename;
-    HeapFree( GetProcessHeap(), 0, filename );
-    return NULL;
-}
-
-/* This escapes \ in filenames */
-static LPSTR
-escape(LPCSTR arg) {
-    LPSTR      narg, x;
-
-    narg = HeapAlloc(GetProcessHeap(),0,2*strlen(arg)+2);
-    x = narg;
-    while (*arg) {
-	*x++ = *arg;
-	if (*arg == '\\')
-	    *x++='\\'; /* escape \ */
-	arg++;
-    }
-    *x = 0;
-    return narg;
-}
-
 static HRESULT WINAPI IPersistFile_fnSave(IPersistFile* iface, LPCOLESTR pszFileName, BOOL fRemember)
 {
-    HRESULT ret = NOERROR;
-    int pid, status;
-    char buffer[MAX_PATH], buff2[MAX_PATH], ascii_filename[MAX_PATH];
-    char *filename, *link_name, *p;
-    char *shell_link_app = NULL;
-    char *icon_name = NULL;
-    char *work_dir = NULL;
-    char *escaped_path = NULL;
-    char *escaped_args = NULL;
-    BOOL bDesktop;
-    HKEY hkey;
-
     _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
+    _IPersistStream_From_ICOM_THIS(IPersistStream, This);
+    HRESULT r;
+    IStream *stm;
 
     TRACE("(%p)->(%s)\n",This,debugstr_w(pszFileName));
 
     if (!pszFileName || !This->sPath)
         return ERROR_UNKNOWN;
 
-    /* check for .exe extension */
-    if (!(p = strrchr( This->sPath, '.' ))) return NOERROR;
-    if (strchr( p, '\\' ) || strchr( p, '/' )) return NOERROR;
-    if (strcasecmp( p, ".exe" )) return NOERROR;
-
-    /* check if ShellLinker configured */
-    buffer[0] = 0;
-    if (!RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\Wine",
-                        0, KEY_ALL_ACCESS, &hkey ))
+    r = CreateStreamOnFile(pszFileName, STGM_READWRITE | STGM_CREATE, &stm);
+    if( SUCCEEDED( r ) )
     {
-        DWORD type, count = sizeof(buffer);
-        if (RegQueryValueExA( hkey, "ShellLinker", 0, &type, buffer, &count )) buffer[0] = 0;
-        RegCloseKey( hkey );
-    }
-    if (!*buffer) return NOERROR;
-    shell_link_app = heap_strdup( buffer );
+        r = IPersistStream_Save(StreamThis, stm, FALSE);
+        IStream_Release( stm );
 
-    if (!WideCharToMultiByte( CP_ACP, 0, pszFileName, -1, ascii_filename, sizeof(ascii_filename), NULL, NULL))
-        return ERROR_UNKNOWN;
-    GetFullPathNameA( ascii_filename, sizeof(buff2), buff2, NULL );
-    filename = heap_strdup( buff2 );
-
-    if (SHGetSpecialFolderPathA( 0, buffer, CSIDL_STARTUP, FALSE ))
-    {
-        /* ignore startup for now */
-        if (!strncasecmp( filename, buffer, strlen(buffer) )) goto done;
-    }
-    if (SHGetSpecialFolderPathA( 0, buffer, CSIDL_DESKTOPDIRECTORY, FALSE ))
-    {
-        if (!strncasecmp( filename, buffer, strlen(buffer) ))
+        if( SUCCEEDED( r ) )
+            StartLinkProcessor( pszFileName );
+        else
         {
-            link_name = filename + strlen(buffer);
-            bDesktop = TRUE;
-            goto found;
+            DeleteFileW( pszFileName );
+            WARN("Failed to create shortcut %s\n", debugstr_w(pszFileName) );
         }
     }
-    if (SHGetSpecialFolderPathA( 0, buffer, CSIDL_STARTMENU, FALSE ))
-    {
-        if (!strncasecmp( filename, buffer, strlen(buffer) ))
-        {
-            link_name = filename + strlen(buffer);
-            bDesktop = FALSE;
-            goto found;
-        }
-    }
-    goto done;
 
- found:
-    /* make link name a Unix name */
-    for (p = link_name; *p; p++) if (*p == '\\') *p = '/';
-    /* strip leading slashes */
-    while (*link_name == '/') link_name++;
-    /* remove extension */
-    if ((p = strrchr( link_name, '.' ))) *p = 0;
-
-    /* convert app working dir */
-    if (This->sWorkDir) work_dir = get_unix_file_name( This->sWorkDir );
-
-    /* extract the icon */
-    if (!(icon_name = extract_icon( This->sIcoPath && strlen(This->sIcoPath) ?
-                                      This->sIcoPath : This->sPath,
-                                      This->iIcoNdx )))
-    {
-	/* Couldn't extract icon --  defer this menu entry to runonce. */
-	HKEY hRunOnce;
-	char* buffer = NULL;
-
-	TRACE("Deferring icon creation to reboot.\n");
-	if (RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce", 0,
-                NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hRunOnce, NULL) != ERROR_SUCCESS)
-	{
-	    ret = ERROR_UNKNOWN;
-	    goto done;
-	}
-	buffer = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * 3 + (This->sArgs ? strlen(This->sArgs) : 0) +
-                           (This->sDescription ? strlen(This->sDescription) : 0) + 200);
-	sprintf(buffer, "link:%s\xff*%s\xff%d\xff%s\xff%s\xff%s", This->sPath, This->sIcoPath ? This->sIcoPath : "", This->iIcoNdx,
-	    This->sArgs ? This->sArgs : "", This->sDescription ? This->sDescription : "",
-	    This->sWorkDir ? This->sWorkDir : "");
-	if (RegSetValueExA(hRunOnce, ascii_filename, 0, REG_SZ, buffer, strlen(buffer) + 1) != ERROR_SUCCESS)
-	{
-	    HeapFree(GetProcessHeap(), 0, buffer);
-	    RegCloseKey(hRunOnce);
-	    ret = ERROR_UNKNOWN;
-	    goto done;
-	}
-	HeapFree(GetProcessHeap(), 0, buffer);
-	RegCloseKey(hRunOnce);
-	goto done;
-    }
-
-    TRACE("linker app='%s' link='%s' mode=%s path='%s' args='%s' icon='%s' workdir='%s' descr='%s'\n",
-        shell_link_app, link_name, bDesktop ? "desktop" : "menu", This->sPath,
-        This->sArgs ? This->sArgs : "", icon_name, work_dir ? work_dir : "",
-        This->sDescription ? This->sDescription : "" );
-
-    if ((pid = fork()) == -1) goto done;
-
-    escaped_path = escape(This->sPath);
-    if (This->sArgs)
-        escaped_args = escape(This->sArgs);
-
-    if (!pid)
-    {
-        int pos = 0;
-        char *argv[20];
-        argv[pos++] = shell_link_app;
-        argv[pos++] = "--link";
-        argv[pos++] = link_name;
-        argv[pos++] = "--path";
-        argv[pos++] = escaped_path;
-        argv[pos++] = bDesktop ? "--desktop" : "--menu";
-        if (This->sArgs && strlen(This->sArgs))
-        {
-            argv[pos++] = "--args";
-            argv[pos++] = escaped_args;
-        }
-        if (icon_name)
-        {
-            argv[pos++] = "--icon";
-            argv[pos++] = icon_name;
-        }
-        if (This->sWorkDir && strlen(This->sWorkDir))
-        {
-            argv[pos++] = "--workdir";
-            argv[pos++] = work_dir;
-        }
-        if (This->sDescription && strlen(This->sDescription))
-        {
-            argv[pos++] = "--descr";
-            argv[pos++] = This->sDescription;
-        }
-        argv[pos] = NULL;
-        execvp( shell_link_app, argv );
-        _exit(1);
-    }
-
-    while (waitpid( pid, &status, 0 ) == -1)
-    {
-        if (errno != EINTR)
-        {
-            ret = ERROR_UNKNOWN;
-            goto done;
-        }
-    }
-    if (status) ret = E_ACCESSDENIED;
-
- done:
-    if (icon_name) unlink( icon_name );
-    HeapFree( GetProcessHeap(), 0, shell_link_app );
-    HeapFree( GetProcessHeap(), 0, filename );
-    HeapFree( GetProcessHeap(), 0, icon_name );
-    HeapFree( GetProcessHeap(), 0, work_dir );
-    if (escaped_args) HeapFree( GetProcessHeap(), 0, escaped_args );
-    if (escaped_path) HeapFree( GetProcessHeap(), 0, escaped_path );
-    return ret;
+    return r;
 }
 
 static HRESULT WINAPI IPersistFile_fnSaveCompleted(IPersistFile* iface, LPCOLESTR pszFileName)
@@ -879,99 +391,339 @@
 
 	return S_OK;
 }
+
+
+static HRESULT Stream_LoadString( IStream* stm, BOOL unicode, LPWSTR *pstr )
+{
+    DWORD count;
+    USHORT len;
+    LPVOID temp;
+    LPWSTR str;
+    HRESULT r;
+
+    TRACE("%p\n", stm);
+
+    count = 0;
+    r = IStream_Read(stm, &len, sizeof len, &count);
+    if ( FAILED (r) || ( count != sizeof len ) )
+        return E_FAIL;
+
+    if( unicode )
+        len *= sizeof (WCHAR);
+
+    TRACE("reading %d\n", len);
+    temp = HeapAlloc(GetProcessHeap(), 0, len+sizeof(WCHAR));
+    if( !temp )
+        return E_OUTOFMEMORY;
+    count = 0;
+    r = IStream_Read(stm, temp, len, &count);
+    if( FAILED (r) || ( count != len ) )
+    {
+        HeapFree( GetProcessHeap(), 0, temp );
+        return E_FAIL;
+    }
+
+    TRACE("read %s\n", debugstr_an(temp,len));
+
+    /* convert to unicode if necessary */
+    if( !unicode )
+    {
+        count = MultiByteToWideChar( CP_ACP, 0, (LPSTR) temp, len, NULL, 0 );
+        str = HeapAlloc( GetProcessHeap(), 0, (count+1)*sizeof (WCHAR) );
+        if( str )
+            MultiByteToWideChar( CP_ACP, 0, (LPSTR) temp, len, str, count );
+        HeapFree( GetProcessHeap(), 0, temp );
+    }
+    else
+    {
+        count /= 2;
+        str = (LPWSTR) temp;
+    }
+    str[count] = 0;
+
+    *pstr = str;
+
+    return S_OK;
+}
+
+static HRESULT Stream_LoadLocation( IStream* stm )
+{
+    DWORD size;
+    ULONG count;
+    HRESULT r;
+    LOCATION_INFO *loc;
+
+    TRACE("%p\n",stm);
+
+    r = IStream_Read( stm, &size, sizeof size, &count );
+    if( FAILED( r ) )
+        return r;
+    if( count != sizeof loc->dwTotalSize )
+        return E_FAIL;
+
+    loc = HeapAlloc( GetProcessHeap(), 0, size );
+    if( ! loc )
+        return E_OUTOFMEMORY;
+
+    r = IStream_Read( stm, &loc->dwHeaderSize, size-sizeof size, &count );
+    if( FAILED( r ) )
+        goto end;
+    if( count != (size - sizeof size) )
+    {
+        r = E_FAIL;
+        goto end;
+    }
+    loc->dwTotalSize = size;
+
+    TRACE("Read %ld bytes\n",count);
+
+    /* FIXME: do something useful with it */
+    HeapFree( GetProcessHeap(), 0, loc );
+
+    return S_OK;
+end:
+    HeapFree( GetProcessHeap(), 0, loc );
+    return r;
+}
+
 /************************************************************************
  * IPersistStream_Load (IPersistStream)
  */
-
 static HRESULT WINAPI IPersistStream_fnLoad(
 	IPersistStream*  iface,
-	IStream*         pLoadStream)
+    IStream*         stm)
 {
-	PLINK_HEADER lpLinkHeader = HeapAlloc(GetProcessHeap(), 0, LINK_HEADER_SIZE);
-	ULONG	dwBytesRead;
-	DWORD	ret = E_FAIL;
-	char	sTemp[MAX_PATH];
+    LINK_HEADER hdr;
+    ULONG    dwBytesRead;
+    BOOL     unicode;
+    WCHAR    sTemp[MAX_PATH];
+    HRESULT  r;
 
-	_ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
+    _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
 
-	TRACE("(%p)(%p)\n", This, pLoadStream);
+    TRACE("(%p)(%p)\n", This, stm);
 
-	if ( ! pLoadStream)
-	{
+    if( !stm )
 	  return STG_E_INVALIDPOINTER;
-	}
 
-	IStream_AddRef (pLoadStream);
-	if(!lpLinkHeader)
-          goto end;
+    dwBytesRead = 0;
+    r = IStream_Read(stm, &hdr, sizeof hdr, &dwBytesRead);
+    if( FAILED( r ) )
+        return r;
 
-        dwBytesRead = 0;
-	if (!(SUCCEEDED(IStream_Read(pLoadStream, lpLinkHeader, LINK_HEADER_SIZE, &dwBytesRead))))
-          goto end;
+    if( dwBytesRead != sizeof hdr)
+        return E_FAIL;
+    if( hdr.dwSize != sizeof hdr)
+        return E_FAIL;
+    if( !IsEqualIID(&hdr.MagicGuid, &CLSID_ShellLink) )
+        return E_FAIL;
 
-	if (dwBytesRead != LINK_HEADER_SIZE)
-          goto end;
-
-	if ( (lpLinkHeader->MagicStr != 0x0000004CL) || !IsEqualIID(&lpLinkHeader->MagicGuid, &CLSID_ShellLink) )
-          goto end;
-
-	if(lpLinkHeader->PidlSize)
-	{
-	  lpLinkHeader = HeapReAlloc(GetProcessHeap(), 0, lpLinkHeader, LINK_HEADER_SIZE+lpLinkHeader->PidlSize);
-	  if (!lpLinkHeader)
-            goto end;
-          dwBytesRead = 0;
-	  if (!(SUCCEEDED(IStream_Read(pLoadStream, &(lpLinkHeader->Pidl), lpLinkHeader->PidlSize, &dwBytesRead))))
-            goto end;
-          if(dwBytesRead != lpLinkHeader->PidlSize)
-            goto end;
-
-          if (pcheck (&lpLinkHeader->Pidl))
-          {
-            This->pPidl = ILClone (&lpLinkHeader->Pidl);
-
-            SHGetPathFromIDListA(&lpLinkHeader->Pidl, sTemp);
-            This->sPath = heap_strdup( sTemp );
-          }
-        }
-	This->wHotKey = lpLinkHeader->wHotKey;
-	FileTimeToSystemTime (&lpLinkHeader->Time1, &This->time1);
-	FileTimeToSystemTime (&lpLinkHeader->Time2, &This->time2);
-	FileTimeToSystemTime (&lpLinkHeader->Time3, &This->time3);
+    /* if( hdr.dwFlags & SCF_PIDL ) */  /* FIXME: seems to always have a PIDL */
+    {
+        r = ILLoadFromStream( stm, &This->pPidl );
+        if( FAILED( r ) )
+            return r;
+    }
+    This->wHotKey = hdr.wHotKey;
+    This->iIcoNdx = hdr.nIcon;
+    FileTimeToSystemTime (&hdr.Time1, &This->time1);
+    FileTimeToSystemTime (&hdr.Time2, &This->time2);
+    FileTimeToSystemTime (&hdr.Time3, &This->time3);
 #if 1
-	GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&This->time1, NULL, sTemp, 256);
-	TRACE("-- time1: %s\n", sTemp);
-	GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&This->time2, NULL, sTemp, 256);
-	TRACE("-- time1: %s\n", sTemp);
-	GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&This->time3, NULL, sTemp, 256);
-	TRACE("-- time1: %s\n", sTemp);
-	pdump (This->pPidl);
+    GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&This->time1, NULL, sTemp, 256);
+    TRACE("-- time1: %s\n", debugstr_w(sTemp) );
+    GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&This->time2, NULL, sTemp, 256);
+    TRACE("-- time1: %s\n", debugstr_w(sTemp) );
+    GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&This->time3, NULL, sTemp, 256);
+    TRACE("-- time1: %s\n", debugstr_w(sTemp) );
+    pdump (This->pPidl);
 #endif
-	ret = S_OK;
+    if( hdr.dwFlags & SCF_NORMAL )
+        r = Stream_LoadLocation( stm );
+    if( FAILED( r ) )
+        goto end;
+    unicode = hdr.dwFlags & SCF_UNICODE;
+    if( hdr.dwFlags & SCF_DESCRIPTION )
+    {
+        r = Stream_LoadString( stm, unicode, &This->sDescription );
+        TRACE("Description  -> %s\n",debugstr_w(This->sDescription));
+    }
+    if( FAILED( r ) )
+        goto end;
 
+    if( hdr.dwFlags & SCF_RELATIVE )
+    {
+        r = Stream_LoadString( stm, unicode, &This->sPathRel );
+        TRACE("Relative Path-> %s\n",debugstr_w(This->sPathRel));
+    }
+    if( FAILED( r ) )
+        goto end;
+
+    if( hdr.dwFlags & SCF_WORKDIR )
+          {
+        r = Stream_LoadString( stm, unicode, &This->sWorkDir );
+        TRACE("Working Dir  -> %s\n",debugstr_w(This->sWorkDir));
+    }
+    if( FAILED( r ) )
+        goto end;
+
+    if( hdr.dwFlags & SCF_ARGS )
+    {
+        r = Stream_LoadString( stm, unicode, &This->sArgs );
+        TRACE("Working Dir  -> %s\n",debugstr_w(This->sArgs));
+    }
+    if( FAILED( r ) )
+        goto end;
+
+    if( hdr.dwFlags & SCF_CUSTOMICON )
+    {
+        r = Stream_LoadString( stm, unicode, &This->sIcoPath );
+        TRACE("Icon file    -> %s\n",debugstr_w(This->sIcoPath));
+    }
+    if( FAILED( r ) )
+        goto end;
+
+    TRACE("OK\n");
+
+    pdump (This->pPidl);
+
+    return S_OK;
 end:
-	IStream_Release (pLoadStream);
+    return r;
+}
 
-	pdump(This->pPidl);
+/************************************************************************
+ * Stream_WriteString
+ *
+ * Helper function for IPersistStream_Save. Writes a unicode string 
+ *  with terminating nul byte to a stream, preceded by the its length.
+ */
+static HRESULT Stream_WriteString( IStream* stm, LPCWSTR str )
+{
+    USHORT len = lstrlenW( str ) + 1;
+    DWORD count;
+    HRESULT r;
 
-	HeapFree(GetProcessHeap(), 0, lpLinkHeader);
+    r = IStream_Write( stm, &len, sizeof len, &count );
+    if( FAILED( r ) )
+        return r;
 
-	return ret;
+    len *= sizeof(WCHAR);
+
+    r = IStream_Write( stm, str, len, &count );
+    if( FAILED( r ) )
+        return r;
+
+    return S_OK;
+}
+
+static HRESULT Stream_WriteLocationInfo( IStream* stm, LPCWSTR filename )
+{
+    LOCATION_INFO loc;
+    ULONG count;
+
+    FIXME("writing empty location info\n");
+
+    memset( &loc, 0, sizeof loc );
+    loc.dwTotalSize = sizeof loc - sizeof loc.dwTotalSize;
+
+    /* FIXME: fill this in */
+
+    return IStream_Write( stm, &loc, loc.dwTotalSize, &count );
 }
 
 /************************************************************************
  * IPersistStream_Save (IPersistStream)
+ *
+ * FIXME: makes assumptions about byte order
  */
 static HRESULT WINAPI IPersistStream_fnSave(
 	IPersistStream*  iface,
-	IStream*         pOutStream,
+	IStream*         stm,
 	BOOL             fClearDirty)
 {
+    LINK_HEADER header;
+    ULONG    count;
+    HRESULT    r;
+
 	_ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
 
-	TRACE("(%p) %p %x\n", This, pOutStream, fClearDirty);
+    TRACE("(%p) %p %x\n", This, stm, fClearDirty);
 
-	return E_NOTIMPL;
+    /* if there's no PIDL, generate one */
+    if( ! This->pPidl )
+    {
+        if( ! This->sPath )
+            return E_FAIL;
+        This->pPidl = ILCreateFromPathW( This->sPath );
+    }
+
+    memset(&header, 0, sizeof header);
+    header.dwSize = sizeof header;
+    memcpy(&header.MagicGuid, &CLSID_ShellLink, sizeof header.MagicGuid );
+
+    header.wHotKey = This->wHotKey;
+    header.nIcon = This->iIcoNdx;
+    header.dwFlags = SCF_UNICODE;   /* strings are in unicode */
+    header.dwFlags |= SCF_NORMAL;   /* how do we determine this ? */
+    if( This->pPidl )
+        header.dwFlags |= SCF_PIDL;
+    if( This->sDescription )
+        header.dwFlags |= SCF_DESCRIPTION;
+    if( This->sWorkDir )
+        header.dwFlags |= SCF_WORKDIR;
+    if( This->sArgs )
+        header.dwFlags |= SCF_ARGS;
+    if( This->sIcoPath )
+        header.dwFlags |= SCF_CUSTOMICON;
+
+    SystemTimeToFileTime ( &This->time1, &header.Time1 );
+    SystemTimeToFileTime ( &This->time2, &header.Time2 );
+    SystemTimeToFileTime ( &This->time3, &header.Time3 );
+
+    /* write the Shortcut header */
+    r = IStream_Write( stm, &header, sizeof header, &count );
+    if( FAILED( r ) )
+    {
+        ERR("Write failed at %d\n",__LINE__);
+        return r;
+    }
+
+    TRACE("Writing pidl \n");
+
+    /* write the PIDL to the shortcut */
+    if( This->pPidl )
+    {
+        r = ILSaveToStream( stm, This->pPidl );
+        if( FAILED( r ) )
+        {
+            ERR("Failed to write PIDL at %d\n",__LINE__);
+            return r;
+        }
+    }
+
+    TRACE("Path = %s\n", debugstr_w(This->sPath));
+    if( ! This->sPath )
+        return E_FAIL;
+    Stream_WriteLocationInfo( stm, This->sPath );
+
+    TRACE("Description = %s\n", debugstr_w(This->sDescription));
+    if( This->sDescription )
+        r = Stream_WriteString( stm, This->sDescription );
+
+    if( This->sPathRel )
+        r = Stream_WriteString( stm, This->sPathRel );
+
+    if( This->sWorkDir )
+        r = Stream_WriteString( stm, This->sWorkDir );
+
+    if( This->sArgs )
+        r = Stream_WriteString( stm, This->sArgs );
+
+    if( This->sIcoPath )
+        r = Stream_WriteString( stm, This->sIcoPath );
+
+    return S_OK;
 }
 
 /************************************************************************
@@ -1024,6 +776,7 @@
 	sl->lpvtblw = &slvtw;
 	sl->lpvtblPersistFile = &pfvt;
 	sl->lpvtblPersistStream = &psvt;
+	sl->iShowCmd = SW_SHOWNORMAL;
 
 	TRACE("(%p)->()\n",sl);
 
@@ -1095,55 +848,55 @@
  */
 static ULONG WINAPI IShellLinkA_fnRelease(IShellLinkA * iface)
 {
-	ICOM_THIS(IShellLinkImpl, iface);
+    ICOM_THIS(IShellLinkImpl, iface);
 
-	TRACE("(%p)->(count=%lu)\n",This,This->ref);
+    TRACE("(%p)->(count=%lu)\n",This,This->ref);
 
-	if (!--(This->ref))
-	{ TRACE("-- destroying IShellLink(%p)\n",This);
+    if (--(This->ref))
+        return This->ref;
 
-	  if (This->sIcoPath)
-	    HeapFree(GetProcessHeap(), 0, This->sIcoPath);
+    TRACE("-- destroying IShellLink(%p)\n",This);
 
-	  if (This->sArgs)
-	    HeapFree(GetProcessHeap(), 0, This->sArgs);
+    if (This->sIcoPath)
+        HeapFree(GetProcessHeap(), 0, This->sIcoPath);
 
-	  if (This->sWorkDir)
-	    HeapFree(GetProcessHeap(), 0, This->sWorkDir);
+    if (This->sArgs)
+        HeapFree(GetProcessHeap(), 0, This->sArgs);
 
-	  if (This->sDescription)
-	    HeapFree(GetProcessHeap(), 0, This->sDescription);
+    if (This->sWorkDir)
+        HeapFree(GetProcessHeap(), 0, This->sWorkDir);
 
-	  if (This->sPath)
-	    HeapFree(GetProcessHeap(),0,This->sPath);
+    if (This->sDescription)
+        HeapFree(GetProcessHeap(), 0, This->sDescription);
 
-	  if (This->pPidl)
-	    SHFree(This->pPidl);
+    if (This->sPath)
+        HeapFree(GetProcessHeap(),0,This->sPath);
 
-	  if (This->lpFileStream)
-	    IStream_Release(This->lpFileStream);
+    if (This->pPidl)
+        ILFree(This->pPidl);
 
-	  This->iIcoNdx = 0;
+    LocalFree((HANDLE)This);
 
-	  LocalFree((HANDLE)This);
-	  return 0;
-	}
-	return This->ref;
+    return 0;
 }
 
-static HRESULT WINAPI IShellLinkA_fnGetPath(IShellLinkA * iface, LPSTR pszFile,INT cchMaxPath, WIN32_FIND_DATAA *pfd, DWORD fFlags)
+static HRESULT WINAPI IShellLinkA_fnGetPath(IShellLinkA * iface, LPSTR pszFile,
+                  INT cchMaxPath, WIN32_FIND_DATAA *pfd, DWORD fFlags)
 {
-	ICOM_THIS(IShellLinkImpl, iface);
+    ICOM_THIS(IShellLinkImpl, iface);
 
-	TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%lu)(%s)\n",This, pszFile, cchMaxPath, pfd, fFlags, debugstr_a(This->sPath));
+    TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%lu)(%s)\n",
+          This, pszFile, cchMaxPath, pfd, fFlags, debugstr_w(This->sPath));
 
-	if (This->sPath)
-	  lstrcpynA(pszFile,This->sPath, cchMaxPath);
-	else
-	  return E_FAIL;
+    if( cchMaxPath )
+        pszFile[0] = 0;
+    if (This->sPath)
+        WideCharToMultiByte( CP_ACP, 0, This->sPath, -1,
+                             pszFile, cchMaxPath, NULL, NULL);
 
-	return NOERROR;
+    return NOERROR;
 }
+
 static HRESULT WINAPI IShellLinkA_fnGetIDList(IShellLinkA * iface, LPITEMIDLIST * ppidl)
 {
 	ICOM_THIS(IShellLinkImpl, iface);
@@ -1151,8 +904,10 @@
 	TRACE("(%p)->(ppidl=%p)\n",This, ppidl);
 
 	*ppidl = ILClone(This->pPidl);
+
 	return NOERROR;
 }
+
 static HRESULT WINAPI IShellLinkA_fnSetIDList(IShellLinkA * iface, LPCITEMIDLIST pidl)
 {
 	ICOM_THIS(IShellLinkImpl, iface);
@@ -1160,77 +915,101 @@
 	TRACE("(%p)->(pidl=%p)\n",This, pidl);
 
 	if (This->pPidl)
-	    SHFree(This->pPidl);
+            ILFree(This->pPidl);
 	This->pPidl = ILClone (pidl);
-	return NOERROR;
+
+    return S_OK;
 }
+
 static HRESULT WINAPI IShellLinkA_fnGetDescription(IShellLinkA * iface, LPSTR pszName,INT cchMaxName)
 {
-	ICOM_THIS(IShellLinkImpl, iface);
+    ICOM_THIS(IShellLinkImpl, iface);
 
-	FIXME("(%p)->(%p len=%u)\n",This, pszName, cchMaxName);
-	lstrcpynA(pszName,"Description, FIXME",cchMaxName);
-	return NOERROR;
+    TRACE("(%p)->(%p len=%u)\n",This, pszName, cchMaxName);
+
+    if( cchMaxName )
+        pszName[0] = 0;
+    if( This->sDescription )
+        WideCharToMultiByte( CP_ACP, 0, This->sDescription, -1,
+            pszName, cchMaxName, NULL, NULL);
+
+    return S_OK;
 }
 static HRESULT WINAPI IShellLinkA_fnSetDescription(IShellLinkA * iface, LPCSTR pszName)
 {
-	ICOM_THIS(IShellLinkImpl, iface);
+    ICOM_THIS(IShellLinkImpl, iface);
 
-	TRACE("(%p)->(pName=%s)\n", This, pszName);
+    TRACE("(%p)->(pName=%s)\n", This, pszName);
 
-	if (This->sDescription)
-	    HeapFree(GetProcessHeap(), 0, This->sDescription);
-	if (!(This->sDescription = heap_strdup(pszName)))
-	    return E_OUTOFMEMORY;
+    if (This->sDescription)
+        HeapFree(GetProcessHeap(), 0, This->sDescription);
+    This->sDescription = HEAP_strdupAtoW( GetProcessHeap(), 0, pszName);
+    if ( !This->sDescription )
+        return E_OUTOFMEMORY;
 
-	return NOERROR;
+    return S_OK;
 }
+
 static HRESULT WINAPI IShellLinkA_fnGetWorkingDirectory(IShellLinkA * iface, LPSTR pszDir,INT cchMaxPath)
 {
-	ICOM_THIS(IShellLinkImpl, iface);
+    ICOM_THIS(IShellLinkImpl, iface);
 
-	TRACE("(%p)->(%p len=%u)\n", This, pszDir, cchMaxPath);
+    TRACE("(%p)->(%p len=%u)\n", This, pszDir, cchMaxPath);
 
-	lstrcpynA( pszDir, This->sWorkDir ? This->sWorkDir : "", cchMaxPath );
+    if( cchMaxPath )
+        pszDir[0] = 0;
+    if( This->sWorkDir )
+        WideCharToMultiByte( CP_ACP, 0, This->sWorkDir, -1,
+                             pszDir, cchMaxPath, NULL, NULL);
 
-	return NOERROR;
+    return S_OK;
 }
+
 static HRESULT WINAPI IShellLinkA_fnSetWorkingDirectory(IShellLinkA * iface, LPCSTR pszDir)
 {
-	ICOM_THIS(IShellLinkImpl, iface);
+    ICOM_THIS(IShellLinkImpl, iface);
 
-	TRACE("(%p)->(dir=%s)\n",This, pszDir);
+    TRACE("(%p)->(dir=%s)\n",This, pszDir);
 
-	if (This->sWorkDir)
-	    HeapFree(GetProcessHeap(), 0, This->sWorkDir);
-	if (!(This->sWorkDir = heap_strdup(pszDir)))
-	    return E_OUTOFMEMORY;
+    if (This->sWorkDir)
+        HeapFree(GetProcessHeap(), 0, This->sWorkDir);
+    This->sWorkDir = HEAP_strdupAtoW( GetProcessHeap(), 0, pszDir);
+    if ( !This->sWorkDir )
+        return E_OUTOFMEMORY;
 
-	return NOERROR;
+    return S_OK;
 }
+
 static HRESULT WINAPI IShellLinkA_fnGetArguments(IShellLinkA * iface, LPSTR pszArgs,INT cchMaxPath)
 {
-	ICOM_THIS(IShellLinkImpl, iface);
+    ICOM_THIS(IShellLinkImpl, iface);
 
-	TRACE("(%p)->(%p len=%u)\n", This, pszArgs, cchMaxPath);
+    TRACE("(%p)->(%p len=%u)\n", This, pszArgs, cchMaxPath);
 
-	lstrcpynA( pszArgs, This->sArgs ? This->sArgs : "", cchMaxPath );
+    if( cchMaxPath )
+        pszArgs[0] = 0;
+    if( This->sArgs )
+        WideCharToMultiByte( CP_ACP, 0, This->sArgs, -1,
+                             pszArgs, cchMaxPath, NULL, NULL);
 
-	return NOERROR;
+    return S_OK;
 }
+
 static HRESULT WINAPI IShellLinkA_fnSetArguments(IShellLinkA * iface, LPCSTR pszArgs)
 {
-	ICOM_THIS(IShellLinkImpl, iface);
+    ICOM_THIS(IShellLinkImpl, iface);
 
-	TRACE("(%p)->(args=%s)\n",This, pszArgs);
+    TRACE("(%p)->(args=%s)\n",This, pszArgs);
 
-	if (This->sArgs)
-	    HeapFree(GetProcessHeap(), 0, This->sArgs);
-	if (!(This->sArgs = heap_strdup(pszArgs)))
-	    return E_OUTOFMEMORY;
+    if (This->sArgs)
+        HeapFree(GetProcessHeap(), 0, This->sArgs);
+    This->sArgs = HEAP_strdupAtoW( GetProcessHeap(), 0, pszArgs);
+    if( !This->sArgs )
+        return E_OUTOFMEMORY;
 
-	return NOERROR;
+    return S_OK;
 }
+
 static HRESULT WINAPI IShellLinkA_fnGetHotkey(IShellLinkA * iface, WORD *pwHotkey)
 {
 	ICOM_THIS(IShellLinkImpl, iface);
@@ -1239,8 +1018,9 @@
 
 	*pwHotkey = This->wHotKey;
 
-	return NOERROR;
+	return S_OK;
 }
+
 static HRESULT WINAPI IShellLinkA_fnSetHotkey(IShellLinkA * iface, WORD wHotkey)
 {
 	ICOM_THIS(IShellLinkImpl, iface);
@@ -1249,79 +1029,95 @@
 
 	This->wHotKey = wHotkey;
 
-	return NOERROR;
+	return S_OK;
 }
+
 static HRESULT WINAPI IShellLinkA_fnGetShowCmd(IShellLinkA * iface, INT *piShowCmd)
 {
-	ICOM_THIS(IShellLinkImpl, iface);
+    ICOM_THIS(IShellLinkImpl, iface);
 
-	FIXME("(%p)->(%p)\n",This, piShowCmd);
-	*piShowCmd=0;
-	return NOERROR;
+    TRACE("(%p)->(%p)\n",This, piShowCmd);
+    *piShowCmd = This->iShowCmd;
+    return S_OK;
 }
+
 static HRESULT WINAPI IShellLinkA_fnSetShowCmd(IShellLinkA * iface, INT iShowCmd)
 {
-	ICOM_THIS(IShellLinkImpl, iface);
+    ICOM_THIS(IShellLinkImpl, iface);
 
-	/* SW_SHOWNORMAL is the default ... The others would have 
-	 * to be somehow passed through the link file ... We can't 
-	 * do that currently.
-	 */
-	if (iShowCmd != SW_SHOWNORMAL)
-		FIXME("(%p)->(showcmd=%x)\n",This, iShowCmd);
-	return NOERROR;
+    TRACE("(%p) %d\n",This, iShowCmd);
+
+    This->iShowCmd = iShowCmd;
+
+    return NOERROR;
 }
+
 static HRESULT WINAPI IShellLinkA_fnGetIconLocation(IShellLinkA * iface, LPSTR pszIconPath,INT cchIconPath,INT *piIcon)
 {
-	ICOM_THIS(IShellLinkImpl, iface);
+    ICOM_THIS(IShellLinkImpl, iface);
 
-	TRACE("(%p)->(%p len=%u iicon=%p)\n", This, pszIconPath, cchIconPath, piIcon);
+    TRACE("(%p)->(%p len=%u iicon=%p)\n", This, pszIconPath, cchIconPath, piIcon);
 
-	lstrcpynA( pszIconPath, This->sIcoPath ? This->sIcoPath : "", cchIconPath );
-	*piIcon = This->iIcoNdx;
+    if( cchIconPath )
+        pszIconPath[0] = 0;
+    if( This->sIcoPath )
+        WideCharToMultiByte( CP_ACP, 0, This->sIcoPath, -1,
+                             pszIconPath, cchIconPath, NULL, NULL);
+    *piIcon = This->iIcoNdx;
 
-	return NOERROR;
+    return NOERROR;
 }
+
 static HRESULT WINAPI IShellLinkA_fnSetIconLocation(IShellLinkA * iface, LPCSTR pszIconPath,INT iIcon)
 {
-	ICOM_THIS(IShellLinkImpl, iface);
+    ICOM_THIS(IShellLinkImpl, iface);
 
-	TRACE("(%p)->(path=%s iicon=%u)\n",This, pszIconPath, iIcon);
+    TRACE("(%p)->(path=%s iicon=%u)\n",This, pszIconPath, iIcon);
 
-	if (This->sIcoPath)
-	    HeapFree(GetProcessHeap(), 0, This->sIcoPath);
-	if (!(This->sIcoPath = heap_strdup(pszIconPath)))
-	    return E_OUTOFMEMORY;
-	This->iIcoNdx = iIcon;
+    if (This->sIcoPath)
+        HeapFree(GetProcessHeap(), 0, This->sIcoPath);
+    This->sIcoPath = HEAP_strdupAtoW(GetProcessHeap(), 0, pszIconPath);
+    if ( !This->sIcoPath )
+        return E_OUTOFMEMORY;
+    This->iIcoNdx = iIcon;
 
-	return NOERROR;
+    return S_OK;
 }
+
 static HRESULT WINAPI IShellLinkA_fnSetRelativePath(IShellLinkA * iface, LPCSTR pszPathRel, DWORD dwReserved)
 {
-	ICOM_THIS(IShellLinkImpl, iface);
+    ICOM_THIS(IShellLinkImpl, iface);
 
-	FIXME("(%p)->(path=%s %lx)\n",This, pszPathRel, dwReserved);
-	return NOERROR;
+    FIXME("(%p)->(path=%s %lx)\n",This, pszPathRel, dwReserved);
+
+    if (This->sPathRel)
+        HeapFree(GetProcessHeap(), 0, This->sPathRel);
+    This->sPathRel = HEAP_strdupAtoW(GetProcessHeap(), 0, pszPathRel);
+
+    return S_OK;
 }
+
 static HRESULT WINAPI IShellLinkA_fnResolve(IShellLinkA * iface, HWND hwnd, DWORD fFlags)
 {
 	ICOM_THIS(IShellLinkImpl, iface);
 
 	FIXME("(%p)->(hwnd=%p flags=%lx)\n",This, hwnd, fFlags);
-	return NOERROR;
+	return S_OK;
 }
+
 static HRESULT WINAPI IShellLinkA_fnSetPath(IShellLinkA * iface, LPCSTR pszFile)
 {
-	ICOM_THIS(IShellLinkImpl, iface);
+    ICOM_THIS(IShellLinkImpl, iface);
 
-	TRACE("(%p)->(path=%s)\n",This, pszFile);
+    TRACE("(%p)->(path=%s)\n",This, pszFile);
 
-	if (This->sPath)
-	    HeapFree(GetProcessHeap(), 0, This->sPath);
-	if (!(This->sPath = heap_strdup(pszFile)))
-	    return E_OUTOFMEMORY;
+    if (This->sPath)
+        HeapFree(GetProcessHeap(), 0, This->sPath);
+    This->sPath = HEAP_strdupAtoW(GetProcessHeap(), 0, pszFile);
+    if( !This->sPath )
+        return E_OUTOFMEMORY;
 
-	return NOERROR;
+    return S_OK;
 }
 
 /**************************************************************************
@@ -1392,197 +1188,256 @@
 
 static HRESULT WINAPI IShellLinkW_fnGetPath(IShellLinkW * iface, LPWSTR pszFile,INT cchMaxPath, WIN32_FIND_DATAA *pfd, DWORD fFlags)
 {
-	_ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+    _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
 
-	FIXME("(%p)->(pfile=%p len=%u find_data=%p flags=%lu)\n",This, pszFile, cchMaxPath, pfd, fFlags);
-        MultiByteToWideChar( CP_ACP, 0, "c:\\foo.bar", -1, pszFile, cchMaxPath );
-	return NOERROR;
+    FIXME("(%p)->(pfile=%p len=%u find_data=%p flags=%lu)\n",This, pszFile, cchMaxPath, pfd, fFlags);
+    if( cchMaxPath )
+        pszFile[0] = 0;
+    if( This->sPath )
+        lstrcpynW( pszFile, This->sPath, cchMaxPath );
+
+    return NOERROR;
 }
 
 static HRESULT WINAPI IShellLinkW_fnGetIDList(IShellLinkW * iface, LPITEMIDLIST * ppidl)
 {
-	_ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+    _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
 
-	FIXME("(%p)->(ppidl=%p)\n",This, ppidl);
-	*ppidl = _ILCreateDesktop();
-	return NOERROR;
+    TRACE("(%p)->(ppidl=%p)\n",This, ppidl);
+
+    if( This->pPidl)
+        *ppidl = ILClone( This->pPidl );
+    else
+        *ppidl = NULL;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI IShellLinkW_fnSetIDList(IShellLinkW * iface, LPCITEMIDLIST pidl)
 {
-	_ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+    _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
 
-	FIXME("(%p)->(pidl=%p)\n",This, pidl);
-	return NOERROR;
+    TRACE("(%p)->(pidl=%p)\n",This, pidl);
+
+    if( This->pPidl )
+        ILFree( This->pPidl );
+    This->pPidl = ILClone( pidl );
+    if( !This->pPidl )
+        return E_FAIL;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI IShellLinkW_fnGetDescription(IShellLinkW * iface, LPWSTR pszName,INT cchMaxName)
 {
-	_ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+    _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
 
-	FIXME("(%p)->(%p len=%u)\n",This, pszName, cchMaxName);
-        MultiByteToWideChar( CP_ACP, 0, "Description, FIXME", -1, pszName, cchMaxName );
-	return NOERROR;
+    TRACE("(%p)->(%p len=%u)\n",This, pszName, cchMaxName);
+
+    if( cchMaxName )
+        pszName[0] = 0;
+    if( This->sDescription )
+        lstrcpynW( pszName, This->sDescription, cchMaxName );
+
+    return S_OK;
 }
 
 static HRESULT WINAPI IShellLinkW_fnSetDescription(IShellLinkW * iface, LPCWSTR pszName)
 {
-	_ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+    _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
 
-	TRACE("(%p)->(desc=%s)\n",This, debugstr_w(pszName));
+    TRACE("(%p)->(desc=%s)\n",This, debugstr_w(pszName));
 
-	if (This->sDescription)
-	    HeapFree(GetProcessHeap(), 0, This->sDescription);
-	if (!(This->sDescription = HEAP_strdupWtoA(GetProcessHeap(), 0, pszName)))
-	    return E_OUTOFMEMORY;
+    if (This->sDescription)
+        HeapFree(GetProcessHeap(), 0, This->sDescription);
+    This->sDescription = HeapAlloc( GetProcessHeap(), 0,
+                                    (lstrlenW( pszName )+1)*sizeof(WCHAR) );
+    if ( !This->sDescription )
+        return E_OUTOFMEMORY;
+    lstrcpyW( This->sDescription, pszName );
 
-	return NOERROR;
+    return S_OK;
 }
 
 static HRESULT WINAPI IShellLinkW_fnGetWorkingDirectory(IShellLinkW * iface, LPWSTR pszDir,INT cchMaxPath)
 {
-	_ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+    _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
 
-	TRACE("(%p)->(%p len %u)\n", This, pszDir, cchMaxPath);
+    TRACE("(%p)->(%p len %u)\n", This, pszDir, cchMaxPath);
 
-	MultiByteToWideChar( CP_ACP, 0, This->sWorkDir ? This->sWorkDir : "", -1, pszDir, cchMaxPath );
+    if( cchMaxPath )
+        pszDir[0] = 0;
+    if( This->sWorkDir )
+        lstrcpynW( pszDir, This->sWorkDir, cchMaxPath );
 
-	return NOERROR;
+    return S_OK;
 }
 
 static HRESULT WINAPI IShellLinkW_fnSetWorkingDirectory(IShellLinkW * iface, LPCWSTR pszDir)
 {
-	_ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+    _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
 
-	TRACE("(%p)->(dir=%s)\n",This, debugstr_w(pszDir));
+    TRACE("(%p)->(dir=%s)\n",This, debugstr_w(pszDir));
 
-	if (This->sWorkDir)
-	    HeapFree(GetProcessHeap(), 0, This->sWorkDir);
-	if (!(This->sWorkDir = HEAP_strdupWtoA(GetProcessHeap(), 0, pszDir)))
-	    return E_OUTOFMEMORY;
+    if (This->sWorkDir)
+        HeapFree(GetProcessHeap(), 0, This->sWorkDir);
+    This->sWorkDir = HeapAlloc( GetProcessHeap(), 0,
+                                (lstrlenW( pszDir )+1)*sizeof (WCHAR) );
+    if ( !This->sWorkDir )
+        return E_OUTOFMEMORY;
+    lstrcpyW( This->sWorkDir, pszDir );
 
-	return NOERROR;
+    return S_OK;
 }
 
 static HRESULT WINAPI IShellLinkW_fnGetArguments(IShellLinkW * iface, LPWSTR pszArgs,INT cchMaxPath)
 {
-	_ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+    _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
 
-	TRACE("(%p)->(%p len=%u)\n", This, pszArgs, cchMaxPath);
+    TRACE("(%p)->(%p len=%u)\n", This, pszArgs, cchMaxPath);
 
-	MultiByteToWideChar( CP_ACP, 0, This->sArgs ? This->sArgs : "", -1, pszArgs, cchMaxPath );
+    if( cchMaxPath )
+        pszArgs[0] = 0;
+    if( This->sArgs )
+        lstrcpynW( pszArgs, This->sArgs, cchMaxPath );
 
-	return NOERROR;
+    return NOERROR;
 }
 
 static HRESULT WINAPI IShellLinkW_fnSetArguments(IShellLinkW * iface, LPCWSTR pszArgs)
 {
-	_ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+    _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
 
-	TRACE("(%p)->(args=%s)\n",This, debugstr_w(pszArgs));
+    TRACE("(%p)->(args=%s)\n",This, debugstr_w(pszArgs));
 
-	if (This->sArgs)
-	    HeapFree(GetProcessHeap(), 0, This->sArgs);
-	if (!(This->sArgs = HEAP_strdupWtoA(GetProcessHeap(), 0, pszArgs)))
-	    return E_OUTOFMEMORY;
+    if (This->sArgs)
+        HeapFree(GetProcessHeap(), 0, This->sArgs);
+    This->sArgs = HeapAlloc( GetProcessHeap(), 0,
+                             (lstrlenW( pszArgs )+1)*sizeof (WCHAR) );
+    if ( !This->sArgs )
+        return E_OUTOFMEMORY;
+    lstrcpyW( This->sArgs, pszArgs );
 
-	return NOERROR;
+    return S_OK;
 }
 
 static HRESULT WINAPI IShellLinkW_fnGetHotkey(IShellLinkW * iface, WORD *pwHotkey)
 {
-	_ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+    _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
 
-	FIXME("(%p)->(%p)\n",This, pwHotkey);
-	*pwHotkey=0x0;
-	return NOERROR;
+    TRACE("(%p)->(%p)\n",This, pwHotkey);
+
+    *pwHotkey=This->wHotKey;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI IShellLinkW_fnSetHotkey(IShellLinkW * iface, WORD wHotkey)
 {
-	_ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+    _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
 
-	FIXME("(%p)->(hotkey=%x)\n",This, wHotkey);
-	return NOERROR;
+    TRACE("(%p)->(hotkey=%x)\n",This, wHotkey);
+
+    This->wHotKey = wHotkey;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI IShellLinkW_fnGetShowCmd(IShellLinkW * iface, INT *piShowCmd)
 {
-	_ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+    _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
 
-	FIXME("(%p)->(%p)\n",This, piShowCmd);
-	*piShowCmd=0;
-	return NOERROR;
+    TRACE("(%p)->(%p)\n",This, piShowCmd);
+
+    *piShowCmd = This->iShowCmd;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI IShellLinkW_fnSetShowCmd(IShellLinkW * iface, INT iShowCmd)
 {
-	_ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+    _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
 
-	/* SW_SHOWNORMAL is the default ... The others would have 
-	 * to be somehow passed through the link file ... We can't 
-	 * do that currently.
-	 */
-	if (iShowCmd != SW_SHOWNORMAL)
-		FIXME("(%p)->(showcmd=%x)\n",This, iShowCmd);
-	return NOERROR;
+    This->iShowCmd = iShowCmd;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI IShellLinkW_fnGetIconLocation(IShellLinkW * iface, LPWSTR pszIconPath,INT cchIconPath,INT *piIcon)
 {
-	_ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+    _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
 
-	TRACE("(%p)->(%p len=%u iicon=%p)\n", This, pszIconPath, cchIconPath, piIcon);
+    TRACE("(%p)->(%p len=%u iicon=%p)\n", This, pszIconPath, cchIconPath, piIcon);
 
-        MultiByteToWideChar( CP_ACP, 0, This->sIcoPath ? This->sIcoPath : "", -1, pszIconPath, cchIconPath );
-	*piIcon = This->iIcoNdx;
+    if( cchIconPath )
+        pszIconPath[0] = 0;
+    if( This->sIcoPath )
+        lstrcpynW( pszIconPath, This->sIcoPath, cchIconPath );
+    *piIcon = This->iIcoNdx;
 
-	return NOERROR;
+    return S_OK;
 }
 
 static HRESULT WINAPI IShellLinkW_fnSetIconLocation(IShellLinkW * iface, LPCWSTR pszIconPath,INT iIcon)
 {
-	_ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+    _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
 
-	TRACE("(%p)->(path=%s iicon=%u)\n",This, debugstr_w(pszIconPath), iIcon);
+    TRACE("(%p)->(path=%s iicon=%u)\n",This, debugstr_w(pszIconPath), iIcon);
 
-	if (This->sIcoPath)
-	    HeapFree(GetProcessHeap(), 0, This->sIcoPath);
-	if (!(This->sIcoPath = HEAP_strdupWtoA(GetProcessHeap(), 0, pszIconPath)))
-	    return E_OUTOFMEMORY;
-	This->iIcoNdx = iIcon;
+    if (This->sIcoPath)
+        HeapFree(GetProcessHeap(), 0, This->sIcoPath);
+    This->sIcoPath = HeapAlloc( GetProcessHeap(), 0,
+                                (lstrlenW( pszIconPath )+1)*sizeof (WCHAR) );
+    if ( !This->sIcoPath )
+        return E_OUTOFMEMORY;
+    lstrcpyW( This->sIcoPath, pszIconPath );
 
-	return NOERROR;
+    This->iIcoNdx = iIcon;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI IShellLinkW_fnSetRelativePath(IShellLinkW * iface, LPCWSTR pszPathRel, DWORD dwReserved)
 {
-	_ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+    _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
 
-	FIXME("(%p)->(path=%s %lx)\n",This, debugstr_w(pszPathRel), dwReserved);
-	return NOERROR;
+    TRACE("(%p)->(path=%s %lx)\n",This, debugstr_w(pszPathRel), dwReserved);
+
+    if (This->sPathRel)
+        HeapFree(GetProcessHeap(), 0, This->sPathRel);
+    This->sPathRel = HeapAlloc( GetProcessHeap(), 0,
+                                (lstrlenW( pszPathRel )+1) * sizeof (WCHAR) );
+    if ( !This->sPathRel )
+        return E_OUTOFMEMORY;
+    lstrcpyW( This->sPathRel, pszPathRel );
+
+    return S_OK;
 }
 
 static HRESULT WINAPI IShellLinkW_fnResolve(IShellLinkW * iface, HWND hwnd, DWORD fFlags)
 {
-	_ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+    _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
 
-	FIXME("(%p)->(hwnd=%p flags=%lx)\n",This, hwnd, fFlags);
-	return NOERROR;
+    FIXME("(%p)->(hwnd=%p flags=%lx)\n",This, hwnd, fFlags);
+
+    return S_OK;
 }
 
 static HRESULT WINAPI IShellLinkW_fnSetPath(IShellLinkW * iface, LPCWSTR pszFile)
 {
-	_ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+    _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
 
-	TRACE("(%p)->(path=%s)\n",This, debugstr_w(pszFile));
+    TRACE("(%p)->(path=%s)\n",This, debugstr_w(pszFile));
 
-	if (This->sPath)
-	    HeapFree(GetProcessHeap(), 0, This->sPath);
-	if (!(This->sPath = HEAP_strdupWtoA(GetProcessHeap(), 0, pszFile)))
-	    return E_OUTOFMEMORY;
+    if (This->sPath)
+        HeapFree(GetProcessHeap(), 0, This->sPath);
+    This->sPath = HeapAlloc( GetProcessHeap(), 0,
+                             (lstrlenW( pszFile )+1) * sizeof (WCHAR) );
+    if ( !This->sPath )
+        return E_OUTOFMEMORY;
+    lstrcpyW( This->sPath, pszFile );
 
-	return NOERROR;
+    return S_OK;
 }
 
 /**************************************************************************
diff --git a/include/wine/obj_shelllink.h b/include/wine/obj_shelllink.h
index 55d5fdc..61b65c5 100644
--- a/include/wine/obj_shelllink.h
+++ b/include/wine/obj_shelllink.h
@@ -49,7 +49,8 @@
  */
 typedef enum
 {	SLGP_SHORTPATH		= 0x0001,
-	SLGP_UNCPRIORITY	= 0x0002
+	SLGP_UNCPRIORITY	= 0x0002,
+	SLGP_RAWPATH		= 0x0004
 } SLGP_FLAGS;
 /*****************************************************************************
  * IShellLink interface
diff --git a/programs/Makefile.in b/programs/Makefile.in
index 762fb30..5a6e5c8 100644
--- a/programs/Makefile.in
+++ b/programs/Makefile.in
@@ -28,6 +28,7 @@
 	wineconsole \
 	winedbg \
 	winefile \
+	winemenubuilder \
 	winemine \
 	winepath \
 	winevdm \
@@ -54,6 +55,7 @@
 	wineconsole \
 	winedbg \
 	winefile \
+	winemenubuilder \
 	winemine \
 	winepath \
 	winevdm \
@@ -84,6 +86,7 @@
 	wcmd.exe \
 	wineconsole.exe \
 	winedbg.exe \
+	winemenubuilder.exe \
 	winevdm.exe \
 	winhelp.exe
 
@@ -142,6 +145,9 @@
 winedbg.exe$(DLLEXT): winedbg/winedbg.exe$(DLLEXT)
 	$(RM) $@ && $(LN_S) winedbg/winedbg.exe$(DLLEXT) $@
 
+winemenubuilder.exe$(DLLEXT): winemenubuilder/winemenubuilder.exe$(DLLEXT)
+	$(RM) $@ && $(LN_S) winemenubuilder/winemenubuilder.exe$(DLLEXT) $@
+
 winevdm.exe$(DLLEXT): winevdm/winevdm.exe$(DLLEXT)
 	$(RM) $@ && $(LN_S) winevdm/winevdm.exe$(DLLEXT) $@
 
@@ -151,6 +157,7 @@
 wcmd/wcmd.exe$(DLLEXT): wcmd
 wineconsole/wineconsole.exe$(DLLEXT): wineconsole
 winedbg/winedbg.exe$(DLLEXT): winedbg
+winemenubuilder/winemenubuilder.exe$(DLLEXT): winemenubuilder
 winevdm/winevdm.exe$(DLLEXT): winevdm
 winhelp/winhelp.exe$(DLLEXT): winhelp
 
diff --git a/programs/winemenubuilder/.cvsignore b/programs/winemenubuilder/.cvsignore
new file mode 100644
index 0000000..fef4f8e
--- /dev/null
+++ b/programs/winemenubuilder/.cvsignore
@@ -0,0 +1,3 @@
+Makefile
+winemenubuilder.exe.dbg.c
+winemenubuilder.exe.spec.c
diff --git a/programs/winemenubuilder/Makefile.in b/programs/winemenubuilder/Makefile.in
new file mode 100644
index 0000000..aa586d8
--- /dev/null
+++ b/programs/winemenubuilder/Makefile.in
@@ -0,0 +1,22 @@
+TOPSRCDIR = @top_srcdir@
+TOPOBJDIR = ../..
+SRCDIR    = @srcdir@
+VPATH     = @srcdir@
+MODULE    = winemenubuilder.exe
+APPMODE   = gui
+IMPORTS   = shell32 ole32 user32 advapi32 kernel32
+EXTRALIBS = $(LIBUUID)
+
+C_SRCS = \
+	winemenubuilder.c
+
+@MAKE_PROG_RULES@
+
+install::
+	$(MKINSTALLDIRS) $(bindir)
+	$(INSTALL_SCRIPT) $(TOPSRCDIR)/tools/wineshelllink $(bindir)/wineshelllink
+
+uninstall::
+	$(RM) $(bindir)/wineshelllink
+
+### Dependencies:
diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c
new file mode 100644
index 0000000..7c7a6a5
--- /dev/null
+++ b/programs/winemenubuilder/winemenubuilder.c
@@ -0,0 +1,980 @@
+/*
+ * Helper program to build unix menu entries
+ *
+ * Copyright 1997 Marcus Meissner
+ * Copyright 1998 Juergen Schmied
+ * Copyright 2003 Mike McCormack for Codeweavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ *  This program will read a Windows shortcut file using the IShellLink
+ * interface, then invoke wineshelllink with the appropriate arguments
+ * to create a KDE/Gnome menu entry for the shortcut.
+ *
+ *  winemenubuilder [ -r ] <shortcut.lnk>
+ *
+ *  If the -r parameter is passed, and the shortcut cannot be created,
+ * this program will add RunOnce entry to invoke itself at the next
+ * reboot.  This covers the case when a ShortCut is created before the
+ * executable containing its icon.
+ *
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#include <stdarg.h>
+#ifdef HAVE_SYS_SIGNAL_H
+#include <signal.h>
+#endif
+
+#include <windows.h>
+#include <shlobj.h>
+#include <objidl.h>
+#include <shlguid.h>
+
+#include "bitmaps/wine.xpm"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(menubuilder);
+
+/* link file formats */
+
+#include "pshpack1.h"
+
+typedef struct
+{
+    BYTE bWidth;
+    BYTE bHeight;
+    BYTE bColorCount;
+    BYTE bReserved;
+    WORD wPlanes;
+    WORD wBitCount;
+    DWORD dwBytesInRes;
+    WORD nID;
+} GRPICONDIRENTRY;
+
+typedef struct
+{
+    WORD idReserved;
+    WORD idType;
+    WORD idCount;
+    GRPICONDIRENTRY idEntries[1];
+} GRPICONDIR;
+
+typedef struct
+{
+    BYTE bWidth;
+    BYTE bHeight;
+    BYTE bColorCount;
+    BYTE bReserved;
+    WORD wPlanes;
+    WORD wBitCount;
+    DWORD dwBytesInRes;
+    DWORD dwImageOffset;
+} ICONDIRENTRY;
+
+typedef struct
+{
+    WORD idReserved;
+    WORD idType;
+    WORD idCount;
+} ICONDIR;
+
+
+#include "poppack.h"
+
+typedef struct
+{
+        HRSRC *pResInfo;
+        int   nIndex;
+} ENUMRESSTRUCT;
+
+
+/* Icon extraction routines
+ *
+ * FIXME: should use PrivateExtractIcons and friends
+ * FIXME: should not use stdio
+ */
+
+static BOOL SaveIconResAsXPM(const BITMAPINFO *pIcon, const char *szXPMFileName, const char *comment)
+{
+    FILE *fXPMFile;
+    int nHeight;
+    int nXORWidthBytes;
+    int nANDWidthBytes;
+    BOOL b8BitColors;
+    int nColors;
+    BYTE *pXOR;
+    BYTE *pAND;
+    BOOL aColorUsed[256] = {0};
+    int nColorsUsed = 0;
+    int i,j;
+
+    if (!((pIcon->bmiHeader.biBitCount == 4) || (pIcon->bmiHeader.biBitCount == 8)))
+        return FALSE;
+
+    if (!(fXPMFile = fopen(szXPMFileName, "w")))
+        return FALSE;
+
+    nHeight = pIcon->bmiHeader.biHeight / 2;
+    nXORWidthBytes = 4 * ((pIcon->bmiHeader.biWidth * pIcon->bmiHeader.biBitCount / 32)
+                          + ((pIcon->bmiHeader.biWidth * pIcon->bmiHeader.biBitCount % 32) > 0));
+    nANDWidthBytes = 4 * ((pIcon->bmiHeader.biWidth / 32)
+                          + ((pIcon->bmiHeader.biWidth % 32) > 0));
+    b8BitColors = pIcon->bmiHeader.biBitCount == 8;
+    nColors = pIcon->bmiHeader.biClrUsed ? pIcon->bmiHeader.biClrUsed
+        : 1 << pIcon->bmiHeader.biBitCount;
+    pXOR = (BYTE*) pIcon + sizeof (BITMAPINFOHEADER) + (nColors * sizeof (RGBQUAD));
+    pAND = pXOR + nHeight * nXORWidthBytes;
+
+#define MASK(x,y) (pAND[(x) / 8 + (nHeight - (y) - 1) * nANDWidthBytes] & (1 << (7 - (x) % 8)))
+#define COLOR(x,y) (b8BitColors ? pXOR[(x) + (nHeight - (y) - 1) * nXORWidthBytes] : (x) % 2 ? pXOR[(x) / 2 + (nHeight - (y) - 1) * nXORWidthBytes] & 0xF : (pXOR[(x) / 2 + (nHeight - (y) - 1) * nXORWidthBytes] & 0xF0) >> 4)
+
+    for (i = 0; i < nHeight; i++) {
+        for (j = 0; j < pIcon->bmiHeader.biWidth; j++) {
+            if (!aColorUsed[COLOR(j,i)] && !MASK(j,i))
+            {
+                aColorUsed[COLOR(j,i)] = TRUE;
+                nColorsUsed++;
+            }
+        }
+    }
+
+    if (fprintf(fXPMFile, "/* XPM */\n/* %s */\nstatic char *icon[] = {\n", comment) <= 0)
+        goto error;
+    if (fprintf(fXPMFile, "\"%d %d %d %d\",\n",
+                (int) pIcon->bmiHeader.biWidth, nHeight, nColorsUsed + 1, 2) <=0)
+        goto error;
+
+    for (i = 0; i < nColors; i++) {
+        if (aColorUsed[i])
+            if (fprintf(fXPMFile, "\"%.2X c #%.2X%.2X%.2X\",\n", i, pIcon->bmiColors[i].rgbRed,
+                        pIcon->bmiColors[i].rgbGreen, pIcon->bmiColors[i].rgbBlue) <= 0)
+                goto error;
+    }
+    if (fprintf(fXPMFile, "\"   c None\"") <= 0)
+        goto error;
+
+    for (i = 0; i < nHeight; i++)
+    {
+        if (fprintf(fXPMFile, ",\n\"") <= 0)
+            goto error;
+        for (j = 0; j < pIcon->bmiHeader.biWidth; j++)
+        {
+            if MASK(j,i)
+                {
+                    if (fprintf(fXPMFile, "  ") <= 0)
+                        goto error;
+                }
+            else
+                if (fprintf(fXPMFile, "%.2X", COLOR(j,i)) <= 0)
+                    goto error;
+        }
+        if (fprintf(fXPMFile, "\"") <= 0)
+            goto error;
+    }
+    if (fprintf(fXPMFile, "};\n") <= 0)
+        goto error;
+
+#undef MASK
+#undef COLOR
+
+    fclose(fXPMFile);
+    return TRUE;
+
+ error:
+    fclose(fXPMFile);
+    unlink( szXPMFileName );
+    return FALSE;
+}
+
+static BOOL CALLBACK EnumResNameProc(HMODULE hModule, LPCSTR lpszType, LPSTR lpszName, LONG lParam)
+{
+    ENUMRESSTRUCT *sEnumRes = (ENUMRESSTRUCT *) lParam;
+
+    if (!sEnumRes->nIndex--)
+    {
+      *sEnumRes->pResInfo = FindResourceA(hModule, lpszName, RT_GROUP_ICONA);
+      return FALSE;
+    }
+    else
+      return TRUE;
+}
+
+static BOOL ExtractFromEXEDLL(const char *szFileName, int nIndex, const char *szXPMFileName)
+{
+    HMODULE hModule;
+    HRSRC hResInfo;
+    char *lpName = NULL;
+    HGLOBAL hResData;
+    GRPICONDIR *pIconDir;
+    BITMAPINFO *pIcon;
+    ENUMRESSTRUCT sEnumRes;
+    int nMax = 0;
+    int nMaxBits = 0;
+    int i;
+
+    if (!(hModule = LoadLibraryExA(szFileName, 0, LOAD_LIBRARY_AS_DATAFILE)))
+    {
+        WINE_ERR("LoadLibraryExA (%s) failed, error %ld\n", szFileName, GetLastError());
+        goto error1;
+    }
+
+    if (nIndex < 0)
+    {
+        hResInfo = FindResourceA(hModule, MAKEINTRESOURCEA(-nIndex), RT_GROUP_ICONA);
+        WINE_ERR("FindResourceA (%s) called, return %p, error %ld\n", szFileName, hResInfo, GetLastError());
+    }
+    else
+    {
+        hResInfo=(HRSRC)NULL;
+        sEnumRes.pResInfo = &hResInfo;
+        sEnumRes.nIndex = nIndex;
+        EnumResourceNamesA(hModule, RT_GROUP_ICONA, &EnumResNameProc, (LONG) &sEnumRes);
+    }
+
+    if (!hResInfo)
+    {
+        WINE_ERR("ExtractFromEXEDLL failed, error %ld\n", GetLastError());
+        goto error2;
+    }
+
+    if (!(hResData = LoadResource(hModule, hResInfo)))
+    {
+        WINE_ERR("LoadResource failed, error %ld\n", GetLastError());
+        goto error2;
+    }
+    if (!(pIconDir = LockResource(hResData)))
+    {
+        WINE_ERR("LockResource failed, error %ld\n", GetLastError());
+        goto error3;
+    }
+
+    for (i = 0; i < pIconDir->idCount; i++)
+        if ((pIconDir->idEntries[i].wBitCount >= nMaxBits) && (pIconDir->idEntries[i].wBitCount <= 8))
+        {
+          if (pIconDir->idEntries[i].wBitCount > nMaxBits)
+          {
+              nMaxBits = pIconDir->idEntries[i].wBitCount;
+              nMax = 0;
+          }
+          if ((pIconDir->idEntries[i].bHeight * pIconDir->idEntries[i].bWidth) > nMax)
+          {
+              lpName = MAKEINTRESOURCEA(pIconDir->idEntries[i].nID);
+              nMax = pIconDir->idEntries[i].bHeight * pIconDir->idEntries[i].bWidth;
+          }
+        }
+
+    FreeResource(hResData);
+
+    if (!(hResInfo = FindResourceA(hModule, lpName, RT_ICONA)))
+    {
+        WINE_ERR("Second FindResourceA failed, error %ld\n", GetLastError());
+        goto error2;
+    }
+    if (!(hResData = LoadResource(hModule, hResInfo)))
+    {
+        WINE_ERR("Second LoadResource failed, error %ld\n", GetLastError());
+        goto error2;
+    }
+    if (!(pIcon = LockResource(hResData)))
+    {
+        WINE_ERR("Second LockResource failed, error %ld\n", GetLastError());
+        goto error3;
+    }
+
+    if(!SaveIconResAsXPM(pIcon, szXPMFileName, szFileName))
+    {
+        WINE_ERR("Failed saving icon as XPM, error %ld\n", GetLastError());
+        goto error3;
+    }
+
+    FreeResource(hResData);
+    FreeLibrary(hModule);
+
+    return TRUE;
+
+ error3:
+    FreeResource(hResData);
+ error2:
+    FreeLibrary(hModule);
+ error1:
+    return FALSE;
+}
+
+/* get the Unix file name for a given path, allocating the string */
+inline static char *get_unix_file_name( const char *dos )
+{
+    char buffer[MAX_PATH], *ret;
+
+    if (!wine_get_unix_file_name( dos, buffer, sizeof(buffer) )) return NULL;
+    ret = HeapAlloc( GetProcessHeap(), 0, lstrlenA( buffer ) + 1 );
+    lstrcpyA( ret, buffer );
+    return ret;
+}
+
+static int ExtractFromICO(const char *szFileName, const char *szXPMFileName)
+{
+    FILE *fICOFile;
+    ICONDIR iconDir;
+    ICONDIRENTRY *pIconDirEntry;
+    int nMax = 0;
+    int nIndex = 0;
+    void *pIcon;
+    int i;
+    char *filename;
+
+    filename = get_unix_file_name(szFileName);
+    if (!(fICOFile = fopen(filename, "r")))
+        goto error1;
+
+    if (fread(&iconDir, sizeof (ICONDIR), 1, fICOFile) != 1)
+        goto error2;
+    if ((iconDir.idReserved != 0) || (iconDir.idType != 1))
+        goto error2;
+
+    if ((pIconDirEntry = malloc(iconDir.idCount * sizeof (ICONDIRENTRY))) == NULL)
+        goto error2;
+    if (fread(pIconDirEntry, sizeof (ICONDIRENTRY), iconDir.idCount, fICOFile) != iconDir.idCount)
+        goto error3;
+
+    for (i = 0; i < iconDir.idCount; i++)
+        if ((pIconDirEntry[i].bHeight * pIconDirEntry[i].bWidth) > nMax)
+        {
+            nIndex = i;
+            nMax = pIconDirEntry[i].bHeight * pIconDirEntry[i].bWidth;
+        }
+    if ((pIcon = malloc(pIconDirEntry[nIndex].dwBytesInRes)) == NULL)
+        goto error3;
+    if (fseek(fICOFile, pIconDirEntry[nIndex].dwImageOffset, SEEK_SET))
+        goto error4;
+    if (fread(pIcon, pIconDirEntry[nIndex].dwBytesInRes, 1, fICOFile) != 1)
+        goto error4;
+
+    if(!SaveIconResAsXPM(pIcon, szXPMFileName, szFileName))
+        goto error4;
+
+    free(pIcon);
+    free(pIconDirEntry);
+    fclose(fICOFile);
+
+    return 1;
+
+ error4:
+    free(pIcon);
+ error3:
+    free(pIconDirEntry);
+ error2:
+    fclose(fICOFile);
+ error1:
+    HeapFree(GetProcessHeap(), 0, filename);
+    return 0;
+}
+
+static BOOL create_default_icon( const char *filename, const char* comment )
+{
+    FILE *fXPM;
+    int i;
+
+    if (!(fXPM = fopen(filename, "w"))) return FALSE;
+    if (fprintf(fXPM, "/* XPM */\n/* %s */\nstatic char * icon[] = {", comment) <= 0)
+        goto error;
+    for (i = 0; i < sizeof(wine_xpm)/sizeof(wine_xpm[0]); i++) {
+        if (fprintf( fXPM, "\n\"%s\",", wine_xpm[i]) <= 0)
+            goto error;
+    }
+    if (fprintf( fXPM, "};\n" ) <=0)
+        goto error;
+    fclose( fXPM );
+    return TRUE;
+ error:
+    fclose( fXPM );
+    unlink( filename );
+    return FALSE;
+
+}
+
+static unsigned short crc16(const char* string)
+{
+    unsigned short crc = 0;
+    int i, j, xor_poly;
+
+    for (i = 0; string[i] != 0; i++)
+    {
+        char c = string[i];
+        for (j = 0; j < 8; c >>= 1, j++)
+        {
+            xor_poly = (c ^ crc) & 1;
+            crc >>= 1;
+            if (xor_poly)
+                crc ^= 0xa001;
+        }
+    }
+    return crc;
+}
+
+/* extract an icon from an exe or icon file; helper for IPersistFile_fnSave */
+static char *extract_icon( const char *path, int index)
+{
+    int nodefault = 1;
+    unsigned short crc;
+    char *iconsdir, *ico_path, *ico_name, *xpm_path;
+    char* s;
+    HKEY hkey;
+
+    /* Where should we save the icon? */
+    WINE_TRACE("path=[%s] index=%d\n",path,index);
+    iconsdir=NULL;  /* Default is no icon */
+    if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\Wine", &hkey ))
+    {
+        DWORD size = 0;
+        if (RegQueryValueExA(hkey, "IconsDir", 0, NULL, NULL, &size)==0) {
+            iconsdir = HeapAlloc(GetProcessHeap(), 0, size);
+            RegQueryValueExA(hkey, "IconsDir", 0, NULL, iconsdir, &size);
+
+            s=get_unix_file_name(iconsdir);
+            if (s) {
+                HeapFree(GetProcessHeap(), 0, iconsdir);
+                iconsdir=s;
+            }
+        }
+        RegCloseKey( hkey );
+    }
+    if (iconsdir==NULL || *iconsdir=='\0')
+    {
+        if (iconsdir)
+            HeapFree(GetProcessHeap(), 0, iconsdir);
+        return NULL;  /* No icon created */
+    }
+
+    /* If icon path begins with a '*' then this is a deferred call */
+    if (path[0] == '*')
+    {
+        path++;
+        nodefault = 0;
+    }
+
+    /* Determine the icon base name */
+    ico_path=HeapAlloc(GetProcessHeap(), 0, lstrlenA(path)+1);
+    strcpy(ico_path, path);
+    s=ico_name=ico_path;
+    while (*s!='\0') {
+        if (*s=='/' || *s=='\\') {
+            *s='\\';
+            ico_name=s;
+        } else {
+            *s=tolower(*s);
+        }
+        s++;
+    }
+    if (*ico_name=='\\') *ico_name++='\0';
+    s=strrchr(ico_name,'.');
+    if (s) *s='\0';
+
+    /* Compute the source-path hash */
+    crc=crc16(ico_path);
+
+    /* Try to treat the source file as an exe */
+    xpm_path=HeapAlloc(GetProcessHeap(), 0, strlen(iconsdir)+1+4+1+strlen(ico_name)+1+12+1+3);
+    sprintf(xpm_path,"%s/%04x_%s.%d.xpm",iconsdir,crc,ico_name,index);
+    if (ExtractFromEXEDLL( path, index, xpm_path ))
+        goto end;
+
+    /* Must be something else, ignore the index in that case */
+    sprintf(xpm_path,"%s/%04x_%s.xpm",iconsdir,crc,ico_name);
+    if (ExtractFromICO( path, xpm_path))
+        goto end;
+    if (!nodefault)
+        if (create_default_icon( xpm_path, path ))
+            goto end;
+
+    HeapFree( GetProcessHeap(), 0, xpm_path );
+    xpm_path=NULL;
+
+ end:
+    HeapFree( GetProcessHeap(), 0, ico_path );
+    return xpm_path;
+}
+
+static BOOL DeferToRunOnce(LPWSTR link)
+{
+    HKEY hkey;
+    LONG r, len;
+    const WCHAR szRunOnce[] = {
+        'S','o','f','t','w','a','r','e','\\',
+        'M','i','c','r','o','s','o','f','t','\\',
+        'W','i','n','d','o','w','s','\\',
+        'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
+        'R','u','n','O','n','c','e',0
+    };
+    const WCHAR szFormat[] = { '%','s',' ','"','%','s','"',0 };
+    LPWSTR buffer;
+    WCHAR szExecutable[MAX_PATH];
+
+    WINE_TRACE( "Deferring icon creation to reboot.\n");
+
+    if( !GetModuleFileNameW( 0, szExecutable, MAX_PATH ) )
+        return FALSE;
+
+    len = ( lstrlenW( link ) + lstrlenW( szExecutable ) + 4)*sizeof(WCHAR);
+    buffer = HeapAlloc( GetProcessHeap(), 0, len );
+    if( !buffer )
+        return FALSE;
+
+    wsprintfW( buffer, szFormat, szExecutable, link );
+
+    r = RegCreateKeyExW(HKEY_LOCAL_MACHINE, szRunOnce, 0,
+              NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, NULL);
+    if ( r == ERROR_SUCCESS )
+    {
+        r = RegSetValueExW(hkey, link, 0, REG_SZ,
+                   (LPBYTE) buffer, (lstrlenW(buffer) + 1)*sizeof(WCHAR));
+        RegCloseKey(hkey);
+    }
+    HeapFree(GetProcessHeap(), 0, buffer);
+
+    return ! r;
+}
+
+/* This escapes \ in filenames */
+static LPSTR
+escape(LPCSTR arg) {
+    LPSTR      narg, x;
+
+    narg = HeapAlloc(GetProcessHeap(),0,2*strlen(arg)+2);
+    x = narg;
+    while (*arg) {
+        *x++ = *arg;
+        if (*arg == '\\')
+            *x++='\\'; /* escape \ */
+        arg++;
+    }
+    *x = 0;
+    return narg;
+}
+
+static int fork_and_wait( char *linker, char *link_name, char *path,
+                          int desktop, char *args, char *icon_name,
+                          char *workdir, char *description )
+{
+    int pos = 0;
+    char *argv[20];
+
+    WINE_TRACE( "linker app='%s' link='%s' mode=%s "
+        "path='%s' args='%s' icon='%s' workdir='%s' descr='%s'\n",
+        linker, link_name, desktop ? "desktop" : "menu",
+        path, args, icon_name, workdir, description  );
+
+    argv[pos++] = linker ;
+    argv[pos++] = "--link";
+    argv[pos++] = link_name;
+    argv[pos++] = "--path";
+    argv[pos++] = path;
+    argv[pos++] = desktop ? "--desktop" : "--menu";
+    if (args && strlen(args))
+    {
+        argv[pos++] = "--args";
+        argv[pos++] = args;
+    }
+    if (icon_name)
+    {
+        argv[pos++] = "--icon";
+        argv[pos++] = icon_name;
+    }
+    if (workdir && strlen(workdir))
+    {
+        argv[pos++] = "--workdir";
+        argv[pos++] = workdir;
+    }
+    if (description && strlen(description))
+    {
+        argv[pos++] = "--descr";
+        argv[pos++] = description;
+    }
+    argv[pos] = NULL;
+
+    return spawnvp( _P_WAIT, linker, argv );
+}
+
+/* write the name of the ShellLinker into the buffer provided */
+static BOOL GetLinkerName( LPSTR szLinker, DWORD max )
+{
+    LONG r;
+    DWORD type = 0;
+    HKEY hkey;
+
+    szLinker[0] = 0;
+    r = RegOpenKeyExA( HKEY_LOCAL_MACHINE,
+                        "Software\\Wine\\Wine\\Config\\Wine",
+                        0, KEY_ALL_ACCESS, &hkey );
+    if( r )
+        return FALSE;
+    r = RegQueryValueExA( hkey, "ShellLinker", 0, &type, szLinker, &max );
+    RegCloseKey( hkey );
+    if( r || ( type != REG_SZ ) )
+        return FALSE;
+
+    return TRUE ;
+}
+
+static char *cleanup_link( LPCWSTR link )
+{
+    char  *p, *link_name;
+    int len;
+
+    /* make link name a Unix name -
+       strip leading slashes & remove extension */
+    while ( (*link == '\\') || (*link == '/' ) )
+        link++;
+    len = WideCharToMultiByte( CP_ACP, 0, link, -1, NULL, 0, NULL, NULL);
+    link_name = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
+    if( ! link_name )
+        return link_name;
+    len = WideCharToMultiByte( CP_ACP, 0, link, -1, link_name, len, NULL, NULL);
+    for (p = link_name; *p; p++)
+        if (*p == '\\')
+             *p = '/';
+    p = strrchr( link_name, '.' );
+    if (p)
+        *p = 0;
+    return link_name;
+}
+
+/***********************************************************************
+ *
+ *           GetLinkLocation
+ *
+ * returns TRUE if successful
+ * *loc will contain CS_DESKTOPDIRECTORY, CS_STARTMENU, CS_STARTUP
+ */
+static BOOL GetLinkLocation( LPCWSTR linkfile, DWORD *ofs, DWORD *loc )
+{
+    WCHAR ch, filename[MAX_PATH], buffer[MAX_PATH];
+    DWORD len, i, r;
+    const DWORD locations[] = {
+        CSIDL_STARTUP, CSIDL_DESKTOPDIRECTORY, CSIDL_STARTMENU };
+
+    if( !GetFullPathNameW( linkfile, MAX_PATH, filename, NULL ))
+        return FALSE;
+
+    for( i=0; i<sizeof locations/sizeof locations[0]; i++ )
+    {
+        if (!SHGetSpecialFolderPathW( 0, buffer, locations[i], FALSE ))
+            continue;
+
+        len = lstrlenW(buffer);
+        if( len >= MAX_PATH )
+            continue;
+
+        /* do a lstrcmpinW */
+        ch = filename[len];
+        filename[len] = 0;
+        r = lstrcmpiW( filename, buffer );
+        filename[len] = ch;
+
+        if ( r )
+            continue;
+
+        /* return the remainder of the string and link type */
+        *ofs = len;
+        *loc = locations[i];
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+static BOOL InvokeShellLinker( IShellLinkA *sl, LPCWSTR link )
+{
+    char *link_name, *p, *icon_name = NULL, *work_dir = NULL;
+    char *escaped_path = NULL, *escaped_args = NULL;
+    CHAR szDescription[MAX_PATH], szPath[MAX_PATH], szWorkDir[MAX_PATH];
+    CHAR szArgs[MAX_PATH], szIconPath[MAX_PATH], szLinker[MAX_PATH];
+    int iIconId = 0, r;
+    DWORD ofs=0, csidl= -1;
+
+    if ( !link )
+    {
+        WINE_ERR("Link name is null\n");
+        return FALSE;
+    }
+
+    if( !GetLinkerName( szLinker, MAX_PATH ) )
+    {
+        WINE_ERR("Can't find the name of the linker script\n");
+        return FALSE;
+    }
+
+    if( !GetLinkLocation( link, &ofs, &csidl ) )
+    {
+        WINE_WARN("Unknown link location (%08lx). Ignoring\n", csidl);
+        return TRUE;
+    }
+    if( (csidl != CSIDL_DESKTOPDIRECTORY) && (csidl != CSIDL_STARTMENU) )
+    {
+        WINE_WARN("Not under desktop or start menu. Ignoring.\n");
+        return TRUE;
+    }
+
+    szWorkDir[0]=0;
+    IShellLinkA_GetWorkingDirectory( sl, szWorkDir, sizeof szWorkDir);
+    WINE_TRACE("workdir    : %s\n", szWorkDir);
+
+    szDescription[0] = 0;
+    IShellLinkA_GetDescription( sl, szDescription, sizeof szDescription);
+    WINE_TRACE("description: %s\n", szDescription);
+
+    szPath[0] = 0;
+    IShellLinkA_GetPath( sl, szPath, sizeof szPath, NULL, SLGP_RAWPATH );
+    WINE_TRACE("path       : %s\n", szPath);
+
+    szArgs[0] = 0;
+    IShellLinkA_GetArguments( sl, szArgs, sizeof szArgs );
+    WINE_TRACE("args       : %s\n", szArgs);
+
+    szIconPath[0] = 0;
+    IShellLinkA_GetIconLocation( sl, szIconPath,
+                        sizeof szIconPath, &iIconId );
+    WINE_TRACE("icon file  : %s\n", szIconPath );
+
+    if( !szPath[0] )
+    {
+        LPITEMIDLIST pidl = NULL;
+        IShellLinkA_GetIDList( sl, &pidl );
+        if( pidl && SHGetPathFromIDListA( pidl, szPath ) );
+            WINE_TRACE("pidl path  : %s\n", szPath );
+    }
+
+    /* extract the icon */
+    if( szIconPath[0] )
+        icon_name = extract_icon( szIconPath , iIconId );
+    else
+        icon_name = extract_icon( szPath, iIconId );
+
+    /* fail - try once again at reboot time */
+    if( !icon_name )
+    {
+        WINE_ERR("failed to extract icon.\n");
+        return FALSE;
+    }
+
+    /* check the path */
+    if( szPath[0] )
+    {
+        /* check for .exe extension */
+        if (!(p = strrchr( szPath, '.' ))) return FALSE;
+        if (strchr( p, '\\' ) || strchr( p, '/' )) return FALSE;
+        if (strcasecmp( p, ".exe" )) return FALSE;
+
+        /* convert app working dir */
+        if (szWorkDir[0])
+            work_dir = get_unix_file_name( szWorkDir );
+    }
+    else
+    {
+        /* if there's no path... try run the link itself */
+        WideCharToMultiByte( CP_ACP, 0, link, -1, szArgs, MAX_PATH, NULL, NULL );
+        strcpy(szPath, "C:\\Windows\\System\\start.exe");
+    }
+
+    link_name = cleanup_link( &link[ofs] );
+    if( !link_name )
+    {
+        WINE_ERR("Couldn't clean up link name\n");
+        return FALSE;
+    }
+
+    /* escape the path and parameters */
+    escaped_path = escape(szPath);
+    if (szArgs)
+        escaped_args = escape(szArgs);
+
+    r = fork_and_wait(szLinker, link_name, escaped_path,
+                  (csidl == CSIDL_DESKTOPDIRECTORY), escaped_args, icon_name,
+                   work_dir ? work_dir : "", szDescription );
+
+    HeapFree( GetProcessHeap(), 0, icon_name );
+    HeapFree( GetProcessHeap(), 0, work_dir );
+    HeapFree( GetProcessHeap(), 0, link_name );
+    if (escaped_args)
+        HeapFree( GetProcessHeap(), 0, escaped_args );
+    if (escaped_path)
+        HeapFree( GetProcessHeap(), 0, escaped_path );
+
+    if (r)
+    {
+        WINE_ERR("failed to fork and exec %s\n", szLinker );
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+
+static BOOL Process_Link( LPWSTR linkname, BOOL bAgain )
+{
+    IShellLinkA *sl;
+    IPersistFile *pf;
+    HRESULT r;
+    WCHAR fullname[MAX_PATH];
+ 
+    if( !linkname[0] )
+    {
+        WINE_ERR("link name missing\n");
+        return 1;
+    }
+
+    if( !GetFullPathNameW( linkname, MAX_PATH, fullname, NULL ))
+    {
+        WINE_ERR("couldn't get full path of link file\n");
+        return 1;
+    }
+
+    r = CoInitialize( NULL );
+    if( FAILED( r ) )
+        return 1;
+
+    r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+                      &IID_IShellLink, (LPVOID *) &sl );
+    if( FAILED( r ) )
+    {
+        WINE_ERR("No IID_IShellLink\n");
+        return 1;
+    }
+
+    r = IShellLinkA_QueryInterface( sl, &IID_IPersistFile, (LPVOID*) &pf );
+    if( FAILED( r ) )
+    {
+        WINE_ERR("No IID_IPersistFile\n");
+        return 1;
+    }
+
+    r = IPersistFile_Load( pf, fullname, STGM_READ );
+    if( SUCCEEDED( r ) )
+    {
+        /* If we something fails (eg. Couldn't extract icon)
+         * defer this menu entry to reboot via runonce
+         */
+        if( ! InvokeShellLinker( sl, fullname ) && bAgain )
+            DeferToRunOnce( fullname );
+        else
+            WINE_TRACE("Success.\n");
+    }
+
+    IPersistFile_Release( pf );
+    IShellLinkA_Release( sl );
+
+    CoUninitialize();
+
+    return !r;
+}
+
+
+static CHAR *next_token( LPSTR *p )
+{
+    LPSTR token = NULL, t = *p;
+
+    if( !t )
+        return NULL;
+
+    while( t && !token )
+    {
+        switch( *t )
+        {
+        case ' ':
+            t++;
+            continue;
+        case '"':
+            /* unquote the token */
+            token = ++t;
+            t = strchr( token, '"' );
+            if( t )
+                 *t++ = 0;
+            break;
+        case 0:
+            t = NULL;
+            break;
+        default:
+            token = t;
+            t = strchr( token, ' ' );
+            if( t )
+                 *t++ = 0;
+            break;
+        }
+    }
+    *p = t;
+    return token;
+}
+
+/***********************************************************************
+ *
+ *           WinMain
+ */
+int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show)
+{
+    LPSTR token = NULL, p;
+    BOOL bAgain = FALSE;
+    HANDLE hsem = CreateSemaphoreA( NULL, 1, 1, "winemenubuilder_semaphore");
+    int ret = 0;
+
+    /* running multiple instances of wineshelllink
+       at the same time may be dangerous */
+    if( WAIT_OBJECT_0 != WaitForSingleObject( hsem, INFINITE ) )
+        return FALSE;
+
+    for( p = cmdline; p && *p; )
+    {
+        token = next_token( &p );
+	if( !token )
+	    break;
+        if( !lstrcmpA( token, "-r" ) )
+            bAgain = TRUE;
+	else if( token[0] == '-' )
+	{
+	    WINE_ERR( "unknown option %s\n",token);
+	}
+        else
+        {
+            WCHAR link[MAX_PATH];
+
+            MultiByteToWideChar( CP_ACP, 0, token, -1, link, sizeof link );
+            if( !Process_Link( link, bAgain ) )
+            {
+	        WINE_ERR( "failed to build menu item for %s\n",token);
+	        ret = 1;
+                break;
+            }
+        }
+    }
+
+    ReleaseSemaphore( hsem, 1, NULL );
+    CloseHandle( hsem );
+
+    return ret;
+}