Commit 88090b47 authored by Mike McCormack's avatar Mike McCormack Committed by Alexandre Julliard

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.
parent fa9af1d0
......@@ -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" ;;
......
......@@ -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
......
......@@ -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
......
......@@ -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));
fstr->lpvtst=&stvt;
fstr->ref = 1;
fstr->dwLength = GetFileSize ((HANDLE)hFile, NULL);
if( grfMode & STGM_TRANSACTED )
return E_INVALIDARG;
if (!(fstr->hMapping = CreateFileMappingA((HANDLE)hFile,NULL,PAGE_READONLY|SEC_COMMIT,0,0,NULL)))
{
WARN("failed to create filemap.\n");
goto end_2;
}
if( grfMode & STGM_WRITE )
access |= GENERIC_WRITE;
if( grfMode & STGM_READWRITE )
access = GENERIC_WRITE | GENERIC_READ;
if (!(fstr->pImage = MapViewOfFile(fstr->hMapping,FILE_MAP_READ,0,0,0)))
{
WARN("failed to mmap filemap.\n");
goto end_3;
}
if( grfMode & STGM_CREATE )
creat = CREATE_ALWAYS;
else
creat = OPEN_EXISTING;
TRACE("Opening %s\n", debugstr_w(pszFilename) );
ret = S_OK;
goto end_1;
handle = CreateFileW( pszFilename, access, 0, NULL, creat, 0, NULL );
if( handle == INVALID_HANDLE_VALUE )
return E_FAIL;
end_3: CloseHandle(fstr->hMapping);
end_2: HeapFree(GetProcessHeap(), 0, fstr);
fstr = NULL;
fstr = (ISHFileStream*)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,sizeof(ISHFileStream));
if( !fstr )
return E_FAIL;
fstr->lpvtst=&stvt;
fstr->ref = 1;
fstr->handle = handle;
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;
dwBytesLeft = This->dwLength - This->dwPos;
if ( 0 >= dwBytesLeft ) /* end of buffer */
return S_FALSE;
dwBytesToRead = ( cb > dwBytesLeft) ? dwBytesLeft : cb;
return STG_E_INVALIDPOINTER;
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)
{
......
......@@ -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
......
......@@ -20,12 +20,14 @@
#include "config.h"
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <errno.h>
#include <limits.h>
#ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
......@@ -38,7 +40,6 @@
#include "shlobj.h"
#include "undocshell.h"
#include "bitmaps/wine.xpm"
#include "heap.h"
#include "pidl.h"
......@@ -49,87 +50,60 @@ WINE_DEFAULT_DEBUG_CHANNEL(shell);
/* link file formats */
#include "pshpack1.h"
/* flag1: lnk elements: simple link has 0x0B */
#define WORKDIR 0x10
#define ARGUMENT 0x20
#define ICON 0x40
#define UNC 0x80
#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
/* fStartup */
#define NORMAL 0x01
#define MAXIMIZED 0x03
#define MINIMIZED 0x07
#include "pshpack1.h"
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))
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;
#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;
DWORD dwImageOffset;
} ICONDIRENTRY;
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;
} 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)
LPSTR sFile = HEAP_strdupWtoA ( GetProcessHeap(), 0, pszFileName);
HRESULT hRet = E_FAIL;
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++)
{
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;
}
_ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
_IPersistStream_From_ICOM_THIS(IPersistStream, This);
HRESULT r;
IStream *stm;
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;
}
TRACE("(%p, %s)\n",This, debugstr_w(pszFileName));
for (i = 0; i < pIconDir->idCount; i++)
if ((pIconDir->idEntries[i].wBitCount >= nMaxBits) && (pIconDir->idEntries[i].wBitCount <= 8))
r = CreateStreamOnFile(pszFileName, dwMode, &stm);
if( SUCCEEDED( r ) )
{
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 );
}
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;
len = sizeof(szFormat) + lstrlenW( szLink ) * sizeof(WCHAR);
buffer = HeapAlloc( GetProcessHeap(), 0, len );
if( !buffer )
return FALSE;
filename = get_unix_file_name(szFileName);
if (!(fICOFile = fopen(filename, "r")))
goto error1;
wsprintfW( buffer, szFormat, szLink );
if (fread(&iconDir, sizeof (ICONDIR), 1, fICOFile) != 1)
goto error2;
if ((iconDir.idReserved != 0) || (iconDir.idType != 1))
goto error2;
TRACE("starting %s\n",debugstr_w(buffer));
if ((pIconDirEntry = malloc(iconDir.idCount * sizeof (ICONDIRENTRY))) == NULL)
goto error2;
if (fread(pIconDirEntry, sizeof (ICONDIRENTRY), iconDir.idCount, fICOFile) != iconDir.idCount)
goto error3;
memset(&si, 0, sizeof si);
si.cb = sizeof si;
if (!CreateProcessW( NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) return FALSE;
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))
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;
}
/* 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");
static BOOL create_default_icon( const char *filename )
{
FILE *fXPM;
int i;
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
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 );
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 );
r = IPersistStream_Save(StreamThis, stm, FALSE);
IStream_Release( stm );
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) ))
{
link_name = filename + strlen(buffer);
bDesktop = TRUE;
goto found;
}
}
if (SHGetSpecialFolderPathA( 0, buffer, CSIDL_STARTMENU, FALSE ))
{
if (!strncasecmp( filename, buffer, strlen(buffer) ))
if( SUCCEEDED( r ) )
StartLinkProcessor( pszFileName );
else
{
link_name = filename + strlen(buffer);
bDesktop = FALSE;
goto found;
DeleteFileW( pszFileName );
WARN("Failed to create shortcut %s\n", debugstr_w(pszFileName) );
}
}
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( 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
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
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 ( (lpLinkHeader->MagicStr != 0x0000004CL) || !IsEqualIID(&lpLinkHeader->MagicGuid, &CLSID_ShellLink) )
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(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))
if( hdr.dwFlags & SCF_WORKDIR )
{
This->pPidl = ILClone (&lpLinkHeader->Pidl);
r = Stream_LoadString( stm, unicode, &This->sWorkDir );
TRACE("Working Dir -> %s\n",debugstr_w(This->sWorkDir));
}
if( FAILED( r ) )
goto end;
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 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);
#endif
ret = S_OK;
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;
}
/************************************************************************
* 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;
r = IStream_Write( stm, &len, sizeof len, &count );
if( FAILED( r ) )
return r;
len *= sizeof(WCHAR);
r = IStream_Write( stm, str, len, &count );
if( FAILED( r ) )
return r;
return S_OK;
}
pdump(This->pPidl);
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;
HeapFree(GetProcessHeap(), 0, lpLinkHeader);
/* FIXME: fill this in */
return ret;
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;
}
/**************************************************************************
......
......@@ -49,7 +49,8 @@ typedef enum
*/
typedef enum
{ SLGP_SHORTPATH = 0x0001,
SLGP_UNCPRIORITY = 0x0002
SLGP_UNCPRIORITY = 0x0002,
SLGP_RAWPATH = 0x0004
} SLGP_FLAGS;
/*****************************************************************************
* IShellLink interface
......
......@@ -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
......
Makefile
winemenubuilder.exe.dbg.c
winemenubuilder.exe.spec.c
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:
/*
* Helper program to build unix menu entries
*
* Copyright 1997 Marcus Meissner
* Copyright 1998 Juergen Schmied
* Copyright 2003 Mike McCormack for Codeweavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* This program will read a Windows shortcut file using the IShellLink
* interface, then invoke wineshelllink with the appropriate arguments
* to create a KDE/Gnome menu entry for the shortcut.
*
* winemenubuilder [ -r ] <shortcut.lnk>
*
* If the -r parameter is passed, and the shortcut cannot be created,
* this program will add RunOnce entry to invoke itself at the next
* reboot. This covers the case when a ShortCut is created before the
* executable containing its icon.
*
*/
#include "config.h"
#include "wine/port.h"
#include <ctype.h>
#include <stdio.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <errno.h>
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#include <stdarg.h>
#ifdef HAVE_SYS_SIGNAL_H
#include <signal.h>
#endif
#include <windows.h>
#include <shlobj.h>
#include <objidl.h>
#include <shlguid.h>
#include "bitmaps/wine.xpm"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(menubuilder);
/* link file formats */
#include "pshpack1.h"
typedef struct
{
BYTE bWidth;
BYTE bHeight;
BYTE bColorCount;
BYTE bReserved;
WORD wPlanes;
WORD wBitCount;
DWORD dwBytesInRes;
WORD nID;
} GRPICONDIRENTRY;
typedef struct
{
WORD idReserved;
WORD idType;
WORD idCount;
GRPICONDIRENTRY idEntries[1];
} GRPICONDIR;
typedef struct
{
BYTE bWidth;
BYTE bHeight;
BYTE bColorCount;
BYTE bReserved;
WORD wPlanes;
WORD wBitCount;
DWORD dwBytesInRes;
DWORD dwImageOffset;
} ICONDIRENTRY;
typedef struct
{
WORD idReserved;
WORD idType;
WORD idCount;
} ICONDIR;
#include "poppack.h"
typedef struct
{
HRSRC *pResInfo;
int nIndex;
} ENUMRESSTRUCT;
/* Icon extraction routines
*
* FIXME: should use PrivateExtractIcons and friends
* FIXME: should not use stdio
*/
static BOOL SaveIconResAsXPM(const BITMAPINFO *pIcon, const char *szXPMFileName, const char *comment)
{
FILE *fXPMFile;
int nHeight;
int nXORWidthBytes;
int nANDWidthBytes;
BOOL b8BitColors;
int nColors;
BYTE *pXOR;
BYTE *pAND;
BOOL aColorUsed[256] = {0};
int nColorsUsed = 0;
int i,j;
if (!((pIcon->bmiHeader.biBitCount == 4) || (pIcon->bmiHeader.biBitCount == 8)))
return FALSE;
if (!(fXPMFile = fopen(szXPMFileName, "w")))
return FALSE;
nHeight = pIcon->bmiHeader.biHeight / 2;
nXORWidthBytes = 4 * ((pIcon->bmiHeader.biWidth * pIcon->bmiHeader.biBitCount / 32)
+ ((pIcon->bmiHeader.biWidth * pIcon->bmiHeader.biBitCount % 32) > 0));
nANDWidthBytes = 4 * ((pIcon->bmiHeader.biWidth / 32)
+ ((pIcon->bmiHeader.biWidth % 32) > 0));
b8BitColors = pIcon->bmiHeader.biBitCount == 8;
nColors = pIcon->bmiHeader.biClrUsed ? pIcon->bmiHeader.biClrUsed
: 1 << pIcon->bmiHeader.biBitCount;
pXOR = (BYTE*) pIcon + sizeof (BITMAPINFOHEADER) + (nColors * sizeof (RGBQUAD));
pAND = pXOR + nHeight * nXORWidthBytes;
#define MASK(x,y) (pAND[(x) / 8 + (nHeight - (y) - 1) * nANDWidthBytes] & (1 << (7 - (x) % 8)))
#define COLOR(x,y) (b8BitColors ? pXOR[(x) + (nHeight - (y) - 1) * nXORWidthBytes] : (x) % 2 ? pXOR[(x) / 2 + (nHeight - (y) - 1) * nXORWidthBytes] & 0xF : (pXOR[(x) / 2 + (nHeight - (y) - 1) * nXORWidthBytes] & 0xF0) >> 4)
for (i = 0; i < nHeight; i++) {
for (j = 0; j < pIcon->bmiHeader.biWidth; j++) {
if (!aColorUsed[COLOR(j,i)] && !MASK(j,i))
{
aColorUsed[COLOR(j,i)] = TRUE;
nColorsUsed++;
}
}
}
if (fprintf(fXPMFile, "/* XPM */\n/* %s */\nstatic char *icon[] = {\n", comment) <= 0)
goto error;
if (fprintf(fXPMFile, "\"%d %d %d %d\",\n",
(int) pIcon->bmiHeader.biWidth, nHeight, nColorsUsed + 1, 2) <=0)
goto error;
for (i = 0; i < nColors; i++) {
if (aColorUsed[i])
if (fprintf(fXPMFile, "\"%.2X c #%.2X%.2X%.2X\",\n", i, pIcon->bmiColors[i].rgbRed,
pIcon->bmiColors[i].rgbGreen, pIcon->bmiColors[i].rgbBlue) <= 0)
goto error;
}
if (fprintf(fXPMFile, "\" c None\"") <= 0)
goto error;
for (i = 0; i < nHeight; i++)
{
if (fprintf(fXPMFile, ",\n\"") <= 0)
goto error;
for (j = 0; j < pIcon->bmiHeader.biWidth; j++)
{
if MASK(j,i)
{
if (fprintf(fXPMFile, " ") <= 0)
goto error;
}
else
if (fprintf(fXPMFile, "%.2X", COLOR(j,i)) <= 0)
goto error;
}
if (fprintf(fXPMFile, "\"") <= 0)
goto error;
}
if (fprintf(fXPMFile, "};\n") <= 0)
goto error;
#undef MASK
#undef COLOR
fclose(fXPMFile);
return TRUE;
error:
fclose(fXPMFile);
unlink( szXPMFileName );
return FALSE;
}
static BOOL CALLBACK EnumResNameProc(HMODULE hModule, LPCSTR lpszType, LPSTR lpszName, LONG lParam)
{
ENUMRESSTRUCT *sEnumRes = (ENUMRESSTRUCT *) lParam;
if (!sEnumRes->nIndex--)
{
*sEnumRes->pResInfo = FindResourceA(hModule, lpszName, RT_GROUP_ICONA);
return FALSE;
}
else
return TRUE;
}
static BOOL ExtractFromEXEDLL(const char *szFileName, int nIndex, const char *szXPMFileName)
{
HMODULE hModule;
HRSRC hResInfo;
char *lpName = NULL;
HGLOBAL hResData;
GRPICONDIR *pIconDir;
BITMAPINFO *pIcon;
ENUMRESSTRUCT sEnumRes;
int nMax = 0;
int nMaxBits = 0;
int i;
if (!(hModule = LoadLibraryExA(szFileName, 0, LOAD_LIBRARY_AS_DATAFILE)))
{
WINE_ERR("LoadLibraryExA (%s) failed, error %ld\n", szFileName, GetLastError());
goto error1;
}
if (nIndex < 0)
{
hResInfo = FindResourceA(hModule, MAKEINTRESOURCEA(-nIndex), RT_GROUP_ICONA);
WINE_ERR("FindResourceA (%s) called, return %p, error %ld\n", szFileName, hResInfo, GetLastError());
}
else
{
hResInfo=(HRSRC)NULL;
sEnumRes.pResInfo = &hResInfo;
sEnumRes.nIndex = nIndex;
EnumResourceNamesA(hModule, RT_GROUP_ICONA, &EnumResNameProc, (LONG) &sEnumRes);
}
if (!hResInfo)
{
WINE_ERR("ExtractFromEXEDLL failed, error %ld\n", GetLastError());
goto error2;
}
if (!(hResData = LoadResource(hModule, hResInfo)))
{
WINE_ERR("LoadResource failed, error %ld\n", GetLastError());
goto error2;
}
if (!(pIconDir = LockResource(hResData)))
{
WINE_ERR("LockResource failed, error %ld\n", GetLastError());
goto error3;
}
for (i = 0; i < pIconDir->idCount; i++)
if ((pIconDir->idEntries[i].wBitCount >= nMaxBits) && (pIconDir->idEntries[i].wBitCount <= 8))
{
if (pIconDir->idEntries[i].wBitCount > nMaxBits)
{
nMaxBits = pIconDir->idEntries[i].wBitCount;
nMax = 0;
}
if ((pIconDir->idEntries[i].bHeight * pIconDir->idEntries[i].bWidth) > nMax)
{
lpName = MAKEINTRESOURCEA(pIconDir->idEntries[i].nID);
nMax = pIconDir->idEntries[i].bHeight * pIconDir->idEntries[i].bWidth;
}
}
FreeResource(hResData);
if (!(hResInfo = FindResourceA(hModule, lpName, RT_ICONA)))
{
WINE_ERR("Second FindResourceA failed, error %ld\n", GetLastError());
goto error2;
}
if (!(hResData = LoadResource(hModule, hResInfo)))
{
WINE_ERR("Second LoadResource failed, error %ld\n", GetLastError());
goto error2;
}
if (!(pIcon = LockResource(hResData)))
{
WINE_ERR("Second LockResource failed, error %ld\n", GetLastError());
goto error3;
}
if(!SaveIconResAsXPM(pIcon, szXPMFileName, szFileName))
{
WINE_ERR("Failed saving icon as XPM, error %ld\n", GetLastError());
goto error3;
}
FreeResource(hResData);
FreeLibrary(hModule);
return TRUE;
error3:
FreeResource(hResData);
error2:
FreeLibrary(hModule);
error1:
return FALSE;
}
/* get the Unix file name for a given path, allocating the string */
inline static char *get_unix_file_name( const char *dos )
{
char buffer[MAX_PATH], *ret;
if (!wine_get_unix_file_name( dos, buffer, sizeof(buffer) )) return NULL;
ret = HeapAlloc( GetProcessHeap(), 0, lstrlenA( buffer ) + 1 );
lstrcpyA( ret, buffer );
return ret;
}
static int ExtractFromICO(const char *szFileName, const char *szXPMFileName)
{
FILE *fICOFile;
ICONDIR iconDir;
ICONDIRENTRY *pIconDirEntry;
int nMax = 0;
int nIndex = 0;
void *pIcon;
int i;
char *filename;
filename = get_unix_file_name(szFileName);
if (!(fICOFile = fopen(filename, "r")))
goto error1;
if (fread(&iconDir, sizeof (ICONDIR), 1, fICOFile) != 1)
goto error2;
if ((iconDir.idReserved != 0) || (iconDir.idType != 1))
goto error2;
if ((pIconDirEntry = malloc(iconDir.idCount * sizeof (ICONDIRENTRY))) == NULL)
goto error2;
if (fread(pIconDirEntry, sizeof (ICONDIRENTRY), iconDir.idCount, fICOFile) != iconDir.idCount)
goto error3;
for (i = 0; i < iconDir.idCount; i++)
if ((pIconDirEntry[i].bHeight * pIconDirEntry[i].bWidth) > nMax)
{
nIndex = i;
nMax = pIconDirEntry[i].bHeight * pIconDirEntry[i].bWidth;
}
if ((pIcon = malloc(pIconDirEntry[nIndex].dwBytesInRes)) == NULL)
goto error3;
if (fseek(fICOFile, pIconDirEntry[nIndex].dwImageOffset, SEEK_SET))
goto error4;
if (fread(pIcon, pIconDirEntry[nIndex].dwBytesInRes, 1, fICOFile) != 1)
goto error4;
if(!SaveIconResAsXPM(pIcon, szXPMFileName, szFileName))
goto error4;
free(pIcon);
free(pIconDirEntry);
fclose(fICOFile);
return 1;
error4:
free(pIcon);
error3:
free(pIconDirEntry);
error2:
fclose(fICOFile);
error1:
HeapFree(GetProcessHeap(), 0, filename);
return 0;
}
static BOOL create_default_icon( const char *filename, const char* comment )
{
FILE *fXPM;
int i;
if (!(fXPM = fopen(filename, "w"))) return FALSE;
if (fprintf(fXPM, "/* XPM */\n/* %s */\nstatic char * icon[] = {", comment) <= 0)
goto error;
for (i = 0; i < sizeof(wine_xpm)/sizeof(wine_xpm[0]); i++) {
if (fprintf( fXPM, "\n\"%s\",", wine_xpm[i]) <= 0)
goto error;
}
if (fprintf( fXPM, "};\n" ) <=0)
goto error;
fclose( fXPM );
return TRUE;
error:
fclose( fXPM );
unlink( filename );
return FALSE;
}
static unsigned short crc16(const char* string)
{
unsigned short crc = 0;
int i, j, xor_poly;
for (i = 0; string[i] != 0; i++)
{
char c = string[i];
for (j = 0; j < 8; c >>= 1, j++)
{
xor_poly = (c ^ crc) & 1;
crc >>= 1;
if (xor_poly)
crc ^= 0xa001;
}
}
return crc;
}
/* extract an icon from an exe or icon file; helper for IPersistFile_fnSave */
static char *extract_icon( const char *path, int index)
{
int nodefault = 1;
unsigned short crc;
char *iconsdir, *ico_path, *ico_name, *xpm_path;
char* s;
HKEY hkey;
/* Where should we save the icon? */
WINE_TRACE("path=[%s] index=%d\n",path,index);
iconsdir=NULL; /* Default is no icon */
if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\Wine", &hkey ))
{
DWORD size = 0;
if (RegQueryValueExA(hkey, "IconsDir", 0, NULL, NULL, &size)==0) {
iconsdir = HeapAlloc(GetProcessHeap(), 0, size);
RegQueryValueExA(hkey, "IconsDir", 0, NULL, iconsdir, &size);
s=get_unix_file_name(iconsdir);
if (s) {
HeapFree(GetProcessHeap(), 0, iconsdir);
iconsdir=s;
}
}
RegCloseKey( hkey );
}
if (iconsdir==NULL || *iconsdir=='\0')
{
if (iconsdir)
HeapFree(GetProcessHeap(), 0, iconsdir);
return NULL; /* No icon created */
}
/* If icon path begins with a '*' then this is a deferred call */
if (path[0] == '*')
{
path++;
nodefault = 0;
}
/* Determine the icon base name */
ico_path=HeapAlloc(GetProcessHeap(), 0, lstrlenA(path)+1);
strcpy(ico_path, path);
s=ico_name=ico_path;
while (*s!='\0') {
if (*s=='/' || *s=='\\') {
*s='\\';
ico_name=s;
} else {
*s=tolower(*s);
}
s++;
}
if (*ico_name=='\\') *ico_name++='\0';
s=strrchr(ico_name,'.');
if (s) *s='\0';
/* Compute the source-path hash */
crc=crc16(ico_path);
/* Try to treat the source file as an exe */
xpm_path=HeapAlloc(GetProcessHeap(), 0, strlen(iconsdir)+1+4+1+strlen(ico_name)+1+12+1+3);
sprintf(xpm_path,"%s/%04x_%s.%d.xpm",iconsdir,crc,ico_name,index);
if (ExtractFromEXEDLL( path, index, xpm_path ))
goto end;
/* Must be something else, ignore the index in that case */
sprintf(xpm_path,"%s/%04x_%s.xpm",iconsdir,crc,ico_name);
if (ExtractFromICO( path, xpm_path))
goto end;
if (!nodefault)
if (create_default_icon( xpm_path, path ))
goto end;
HeapFree( GetProcessHeap(), 0, xpm_path );
xpm_path=NULL;
end:
HeapFree( GetProcessHeap(), 0, ico_path );
return xpm_path;
}
static BOOL DeferToRunOnce(LPWSTR link)
{
HKEY hkey;
LONG r, len;
const WCHAR szRunOnce[] = {
'S','o','f','t','w','a','r','e','\\',
'M','i','c','r','o','s','o','f','t','\\',
'W','i','n','d','o','w','s','\\',
'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
'R','u','n','O','n','c','e',0
};
const WCHAR szFormat[] = { '%','s',' ','"','%','s','"',0 };
LPWSTR buffer;
WCHAR szExecutable[MAX_PATH];
WINE_TRACE( "Deferring icon creation to reboot.\n");
if( !GetModuleFileNameW( 0, szExecutable, MAX_PATH ) )
return FALSE;
len = ( lstrlenW( link ) + lstrlenW( szExecutable ) + 4)*sizeof(WCHAR);
buffer = HeapAlloc( GetProcessHeap(), 0, len );
if( !buffer )
return FALSE;
wsprintfW( buffer, szFormat, szExecutable, link );
r = RegCreateKeyExW(HKEY_LOCAL_MACHINE, szRunOnce, 0,
NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, NULL);
if ( r == ERROR_SUCCESS )
{
r = RegSetValueExW(hkey, link, 0, REG_SZ,
(LPBYTE) buffer, (lstrlenW(buffer) + 1)*sizeof(WCHAR));
RegCloseKey(hkey);
}
HeapFree(GetProcessHeap(), 0, buffer);
return ! r;
}
/* This escapes \ in filenames */
static LPSTR
escape(LPCSTR arg) {
LPSTR narg, x;
narg = HeapAlloc(GetProcessHeap(),0,2*strlen(arg)+2);
x = narg;
while (*arg) {
*x++ = *arg;
if (*arg == '\\')
*x++='\\'; /* escape \ */
arg++;
}
*x = 0;
return narg;
}
static int fork_and_wait( char *linker, char *link_name, char *path,
int desktop, char *args, char *icon_name,
char *workdir, char *description )
{
int pos = 0;
char *argv[20];
WINE_TRACE( "linker app='%s' link='%s' mode=%s "
"path='%s' args='%s' icon='%s' workdir='%s' descr='%s'\n",
linker, link_name, desktop ? "desktop" : "menu",
path, args, icon_name, workdir, description );
argv[pos++] = linker ;
argv[pos++] = "--link";
argv[pos++] = link_name;
argv[pos++] = "--path";
argv[pos++] = path;
argv[pos++] = desktop ? "--desktop" : "--menu";
if (args && strlen(args))
{
argv[pos++] = "--args";
argv[pos++] = args;
}
if (icon_name)
{
argv[pos++] = "--icon";
argv[pos++] = icon_name;
}
if (workdir && strlen(workdir))
{
argv[pos++] = "--workdir";
argv[pos++] = workdir;
}
if (description && strlen(description))
{
argv[pos++] = "--descr";
argv[pos++] = description;
}
argv[pos] = NULL;
return spawnvp( _P_WAIT, linker, argv );
}
/* write the name of the ShellLinker into the buffer provided */
static BOOL GetLinkerName( LPSTR szLinker, DWORD max )
{
LONG r;
DWORD type = 0;
HKEY hkey;
szLinker[0] = 0;
r = RegOpenKeyExA( HKEY_LOCAL_MACHINE,
"Software\\Wine\\Wine\\Config\\Wine",
0, KEY_ALL_ACCESS, &hkey );
if( r )
return FALSE;
r = RegQueryValueExA( hkey, "ShellLinker", 0, &type, szLinker, &max );
RegCloseKey( hkey );
if( r || ( type != REG_SZ ) )
return FALSE;
return TRUE ;
}
static char *cleanup_link( LPCWSTR link )
{
char *p, *link_name;
int len;
/* make link name a Unix name -
strip leading slashes & remove extension */
while ( (*link == '\\') || (*link == '/' ) )
link++;
len = WideCharToMultiByte( CP_ACP, 0, link, -1, NULL, 0, NULL, NULL);
link_name = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
if( ! link_name )
return link_name;
len = WideCharToMultiByte( CP_ACP, 0, link, -1, link_name, len, NULL, NULL);
for (p = link_name; *p; p++)
if (*p == '\\')
*p = '/';
p = strrchr( link_name, '.' );
if (p)
*p = 0;
return link_name;
}
/***********************************************************************
*
* GetLinkLocation
*
* returns TRUE if successful
* *loc will contain CS_DESKTOPDIRECTORY, CS_STARTMENU, CS_STARTUP
*/
static BOOL GetLinkLocation( LPCWSTR linkfile, DWORD *ofs, DWORD *loc )
{
WCHAR ch, filename[MAX_PATH], buffer[MAX_PATH];
DWORD len, i, r;
const DWORD locations[] = {
CSIDL_STARTUP, CSIDL_DESKTOPDIRECTORY, CSIDL_STARTMENU };
if( !GetFullPathNameW( linkfile, MAX_PATH, filename, NULL ))
return FALSE;
for( i=0; i<sizeof locations/sizeof locations[0]; i++ )
{
if (!SHGetSpecialFolderPathW( 0, buffer, locations[i], FALSE ))
continue;
len = lstrlenW(buffer);
if( len >= MAX_PATH )
continue;
/* do a lstrcmpinW */
ch = filename[len];
filename[len] = 0;
r = lstrcmpiW( filename, buffer );
filename[len] = ch;
if ( r )
continue;
/* return the remainder of the string and link type */
*ofs = len;
*loc = locations[i];
return TRUE;
}
return FALSE;
}
static BOOL InvokeShellLinker( IShellLinkA *sl, LPCWSTR link )
{
char *link_name, *p, *icon_name = NULL, *work_dir = NULL;
char *escaped_path = NULL, *escaped_args = NULL;
CHAR szDescription[MAX_PATH], szPath[MAX_PATH], szWorkDir[MAX_PATH];
CHAR szArgs[MAX_PATH], szIconPath[MAX_PATH], szLinker[MAX_PATH];
int iIconId = 0, r;
DWORD ofs=0, csidl= -1;
if ( !link )
{
WINE_ERR("Link name is null\n");
return FALSE;
}
if( !GetLinkerName( szLinker, MAX_PATH ) )
{
WINE_ERR("Can't find the name of the linker script\n");
return FALSE;
}
if( !GetLinkLocation( link, &ofs, &csidl ) )
{
WINE_WARN("Unknown link location (%08lx). Ignoring\n", csidl);
return TRUE;
}
if( (csidl != CSIDL_DESKTOPDIRECTORY) && (csidl != CSIDL_STARTMENU) )
{
WINE_WARN("Not under desktop or start menu. Ignoring.\n");
return TRUE;
}
szWorkDir[0]=0;
IShellLinkA_GetWorkingDirectory( sl, szWorkDir, sizeof szWorkDir);
WINE_TRACE("workdir : %s\n", szWorkDir);
szDescription[0] = 0;
IShellLinkA_GetDescription( sl, szDescription, sizeof szDescription);
WINE_TRACE("description: %s\n", szDescription);
szPath[0] = 0;
IShellLinkA_GetPath( sl, szPath, sizeof szPath, NULL, SLGP_RAWPATH );
WINE_TRACE("path : %s\n", szPath);
szArgs[0] = 0;
IShellLinkA_GetArguments( sl, szArgs, sizeof szArgs );
WINE_TRACE("args : %s\n", szArgs);
szIconPath[0] = 0;
IShellLinkA_GetIconLocation( sl, szIconPath,
sizeof szIconPath, &iIconId );
WINE_TRACE("icon file : %s\n", szIconPath );
if( !szPath[0] )
{
LPITEMIDLIST pidl = NULL;
IShellLinkA_GetIDList( sl, &pidl );
if( pidl && SHGetPathFromIDListA( pidl, szPath ) );
WINE_TRACE("pidl path : %s\n", szPath );
}
/* extract the icon */
if( szIconPath[0] )
icon_name = extract_icon( szIconPath , iIconId );
else
icon_name = extract_icon( szPath, iIconId );
/* fail - try once again at reboot time */
if( !icon_name )
{
WINE_ERR("failed to extract icon.\n");
return FALSE;
}
/* check the path */
if( szPath[0] )
{
/* check for .exe extension */
if (!(p = strrchr( szPath, '.' ))) return FALSE;
if (strchr( p, '\\' ) || strchr( p, '/' )) return FALSE;
if (strcasecmp( p, ".exe" )) return FALSE;
/* convert app working dir */
if (szWorkDir[0])
work_dir = get_unix_file_name( szWorkDir );
}
else
{
/* if there's no path... try run the link itself */
WideCharToMultiByte( CP_ACP, 0, link, -1, szArgs, MAX_PATH, NULL, NULL );
strcpy(szPath, "C:\\Windows\\System\\start.exe");
}
link_name = cleanup_link( &link[ofs] );
if( !link_name )
{
WINE_ERR("Couldn't clean up link name\n");
return FALSE;
}
/* escape the path and parameters */
escaped_path = escape(szPath);
if (szArgs)
escaped_args = escape(szArgs);
r = fork_and_wait(szLinker, link_name, escaped_path,
(csidl == CSIDL_DESKTOPDIRECTORY), escaped_args, icon_name,
work_dir ? work_dir : "", szDescription );
HeapFree( GetProcessHeap(), 0, icon_name );
HeapFree( GetProcessHeap(), 0, work_dir );
HeapFree( GetProcessHeap(), 0, link_name );
if (escaped_args)
HeapFree( GetProcessHeap(), 0, escaped_args );
if (escaped_path)
HeapFree( GetProcessHeap(), 0, escaped_path );
if (r)
{
WINE_ERR("failed to fork and exec %s\n", szLinker );
return FALSE;
}
return TRUE;
}
static BOOL Process_Link( LPWSTR linkname, BOOL bAgain )
{
IShellLinkA *sl;
IPersistFile *pf;
HRESULT r;
WCHAR fullname[MAX_PATH];
if( !linkname[0] )
{
WINE_ERR("link name missing\n");
return 1;
}
if( !GetFullPathNameW( linkname, MAX_PATH, fullname, NULL ))
{
WINE_ERR("couldn't get full path of link file\n");
return 1;
}
r = CoInitialize( NULL );
if( FAILED( r ) )
return 1;
r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
&IID_IShellLink, (LPVOID *) &sl );
if( FAILED( r ) )
{
WINE_ERR("No IID_IShellLink\n");
return 1;
}
r = IShellLinkA_QueryInterface( sl, &IID_IPersistFile, (LPVOID*) &pf );
if( FAILED( r ) )
{
WINE_ERR("No IID_IPersistFile\n");
return 1;
}
r = IPersistFile_Load( pf, fullname, STGM_READ );
if( SUCCEEDED( r ) )
{
/* If we something fails (eg. Couldn't extract icon)
* defer this menu entry to reboot via runonce
*/
if( ! InvokeShellLinker( sl, fullname ) && bAgain )
DeferToRunOnce( fullname );
else
WINE_TRACE("Success.\n");
}
IPersistFile_Release( pf );
IShellLinkA_Release( sl );
CoUninitialize();
return !r;
}
static CHAR *next_token( LPSTR *p )
{
LPSTR token = NULL, t = *p;
if( !t )
return NULL;
while( t && !token )
{
switch( *t )
{
case ' ':
t++;
continue;
case '"':
/* unquote the token */
token = ++t;
t = strchr( token, '"' );
if( t )
*t++ = 0;
break;
case 0:
t = NULL;
break;
default:
token = t;
t = strchr( token, ' ' );
if( t )
*t++ = 0;
break;
}
}
*p = t;
return token;
}
/***********************************************************************
*
* WinMain
*/
int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show)
{
LPSTR token = NULL, p;
BOOL bAgain = FALSE;
HANDLE hsem = CreateSemaphoreA( NULL, 1, 1, "winemenubuilder_semaphore");
int ret = 0;
/* running multiple instances of wineshelllink
at the same time may be dangerous */
if( WAIT_OBJECT_0 != WaitForSingleObject( hsem, INFINITE ) )
return FALSE;
for( p = cmdline; p && *p; )
{
token = next_token( &p );
if( !token )
break;
if( !lstrcmpA( token, "-r" ) )
bAgain = TRUE;
else if( token[0] == '-' )
{
WINE_ERR( "unknown option %s\n",token);
}
else
{
WCHAR link[MAX_PATH];
MultiByteToWideChar( CP_ACP, 0, token, -1, link, sizeof link );
if( !Process_Link( link, bAgain ) )
{
WINE_ERR( "failed to build menu item for %s\n",token);
ret = 1;
break;
}
}
}
ReleaseSemaphore( hsem, 1, NULL );
CloseHandle( hsem );
return ret;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment