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;
+}