From 88090b47a6cd474670350a73a78cc7ade6b93e60 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Wed, 21 May 2003 18:50:53 +0000 Subject: [PATCH] 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. --- configure | 3 +- configure.ac | 1 + dlls/shell32/Makefile.in | 7 - dlls/shell32/memorystream.c | 123 +- dlls/shell32/shell32_main.h | 4 +- dlls/shell32/shelllink.c | 1547 +++++++++----------- include/wine/obj_shelllink.h | 3 +- programs/Makefile.in | 7 + programs/winemenubuilder/.cvsignore | 3 + programs/winemenubuilder/Makefile.in | 22 + programs/winemenubuilder/winemenubuilder.c | 980 +++++++++++++ 11 files changed, 1785 insertions(+), 915 deletions(-) create mode 100644 programs/winemenubuilder/.cvsignore create mode 100644 programs/winemenubuilder/Makefile.in create mode 100644 programs/winemenubuilder/winemenubuilder.c diff --git a/configure b/configure index 43131c7ed58..be413791f36 100755 --- a/configure +++ b/configure @@ -16038,7 +16038,7 @@ MAKE_LIB_RULES=libs/Makelib.rules 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 @@ do "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 2590fcebc4e..9342ccaeae4 100644 --- a/configure.ac +++ b/configure.ac @@ -1525,6 +1525,7 @@ programs/winecfg/Makefile 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 65d9ef67e8d..f132e52ff49 100644 --- a/dlls/shell32/Makefile.in +++ b/dlls/shell32/Makefile.in @@ -58,13 +58,6 @@ SUBDIRS = tests @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 9b225af6566..0bcd5f8e1ff 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 @@ static ICOM_VTABLE(IStream) stvt = typedef struct { ICOM_VTABLE(IStream) *lpvtst; DWORD ref; - LPBYTE pImage; - HANDLE hMapping; - DWORD dwLength; - DWORD dwPos; + HANDLE handle; } ISHFileStream; /************************************************************************** @@ -84,40 +82,42 @@ typedef struct * * 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 @@ static ULONG WINAPI IStream_fnRelease(IStream *iface) 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 @@ static HRESULT WINAPI IStream_fnRead (IStream * iface, void* pv, ULONG cb, ULONG { 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 b3544500f2d..0f64d97836e 100644 --- a/dlls/shell32/shell32_main.h +++ b/dlls/shell32/shell32_main.h @@ -101,14 +101,12 @@ LPENUMIDLIST IEnumIDList_Constructor(LPCSTR,DWORD,DWORD); 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 423a8204601..dfcc2be9c75 100644 --- a/dlls/shell32/shelllink.c +++ b/dlls/shell32/shelllink.c @@ -20,12 +20,14 @@ #include "config.h" +#include #include #include #ifdef HAVE_UNISTD_H # include #endif #include +#include #ifdef HAVE_SYS_WAIT_H # include #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 @@ WINE_DEFAULT_DEBUG_CHANNEL(shell); /* 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 @@ typedef struct 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 @@ static HRESULT WINAPI IPersistFile_fnQueryInterface( 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 HRESULT WINAPI IPersistFile_fnQueryInterface( */ 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_fnAddRef(IPersistFile* iface) */ 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 ULONG WINAPI IPersistFile_fnRelease(IPersistFile* iface) 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 @@ static HRESULT WINAPI IPersistStream_fnIsDirty( 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 @@ HRESULT WINAPI IShellLink_Constructor ( 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_fnAddRef(IShellLinkA * iface) */ 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 @@ static HRESULT WINAPI IShellLinkA_fnGetIDList(IShellLinkA * iface, LPITEMIDLIST 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 @@ static HRESULT WINAPI IShellLinkA_fnSetIDList(IShellLinkA * iface, LPCITEMIDLIST 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 @@ static HRESULT WINAPI IShellLinkA_fnGetHotkey(IShellLinkA * iface, WORD *pwHotke *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 @@ static HRESULT WINAPI IShellLinkA_fnSetHotkey(IShellLinkA * iface, WORD wHotkey) 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 ULONG WINAPI IShellLinkW_fnRelease(IShellLinkW * iface) 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 55d5fdc08f0..61b65c56b2b 100644 --- a/include/wine/obj_shelllink.h +++ b/include/wine/obj_shelllink.h @@ -49,7 +49,8 @@ typedef enum */ 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 762fb3014e7..5a6e5c88759 100644 --- a/programs/Makefile.in +++ b/programs/Makefile.in @@ -28,6 +28,7 @@ SUBDIRS = \ wineconsole \ winedbg \ winefile \ + winemenubuilder \ winemine \ winepath \ winevdm \ @@ -54,6 +55,7 @@ INSTALLSUBDIRS = \ wineconsole \ winedbg \ winefile \ + winemenubuilder \ winemine \ winepath \ winevdm \ @@ -84,6 +86,7 @@ SYMLINKS = \ wcmd.exe \ wineconsole.exe \ winedbg.exe \ + winemenubuilder.exe \ winevdm.exe \ winhelp.exe @@ -142,6 +145,9 @@ wineconsole.exe$(DLLEXT): wineconsole/wineconsole.exe$(DLLEXT) 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 @@ winhelp.exe$(DLLEXT): winhelp/winhelp.exe$(DLLEXT) 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 00000000000..fef4f8eb610 --- /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 00000000000..aa586d8f84a --- /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 00000000000..7c7a6a53857 --- /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 ] + * + * 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 +#include +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#ifdef HAVE_SYS_WAIT_H +#include +#endif +#include +#ifdef HAVE_SYS_SIGNAL_H +#include +#endif + +#include +#include +#include +#include + +#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= 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; +}