| /* |
| * |
| * Copyright 1997 Marcus Meissner |
| * Copyright 1998 Juergen Schmied |
| * |
| * 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 |
| */ |
| |
| #include "config.h" |
| |
| #include <string.h> |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <errno.h> |
| #ifdef HAVE_SYS_WAIT_H |
| # include <sys/wait.h> |
| #endif |
| #include "wine/debug.h" |
| #include "wine/port.h" |
| #include "winerror.h" |
| #include "winbase.h" |
| #include "winnls.h" |
| #include "winreg.h" |
| |
| #include "shlobj.h" |
| #include "undocshell.h" |
| #include "bitmaps/wine.xpm" |
| |
| #include "heap.h" |
| #include "pidl.h" |
| #include "shell32_main.h" |
| #include "shlguid.h" |
| |
| 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 |
| |
| /* 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 */ |
| FILETIME Time1; /* 0x1c */ |
| FILETIME Time2; /* 0x24 */ |
| FILETIME Time3; /* 0x2c */ |
| DWORD Unknown1; /* 0x34 */ |
| DWORD Unknown2; /* 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; |
| |
| 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; |
| |
| static ICOM_VTABLE(IShellLinkA) slvt; |
| static ICOM_VTABLE(IShellLinkW) slvtw; |
| static ICOM_VTABLE(IPersistFile) pfvt; |
| static ICOM_VTABLE(IPersistStream) psvt; |
| |
| /* IShellLink Implementation */ |
| |
| typedef struct |
| { |
| ICOM_VFIELD(IShellLinkA); |
| DWORD ref; |
| |
| ICOM_VTABLE(IShellLinkW)* lpvtblw; |
| 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; |
| } IShellLinkImpl; |
| |
| #define _IShellLinkW_Offset ((int)(&(((IShellLinkImpl*)0)->lpvtblw))) |
| #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 _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); |
| |
| |
| /* strdup on the process heap */ |
| inline static LPSTR heap_strdup( LPCSTR str ) |
| { |
| INT len = strlen(str) + 1; |
| LPSTR p = HeapAlloc( GetProcessHeap(), 0, len ); |
| if (p) memcpy( p, str, len ); |
| return p; |
| } |
| |
| |
| /************************************************************************** |
| * IPersistFile_QueryInterface |
| */ |
| static HRESULT WINAPI IPersistFile_fnQueryInterface( |
| IPersistFile* iface, |
| REFIID riid, |
| LPVOID *ppvObj) |
| { |
| _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface) |
| |
| TRACE("(%p)\n",This); |
| |
| return IShellLinkA_QueryInterface((IShellLinkA*)This, riid, ppvObj); |
| } |
| |
| /****************************************************************************** |
| * IPersistFile_AddRef |
| */ |
| static ULONG WINAPI IPersistFile_fnAddRef(IPersistFile* iface) |
| { |
| _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface) |
| |
| TRACE("(%p)->(count=%lu)\n",This,This->ref); |
| |
| return IShellLinkA_AddRef((IShellLinkA*)This); |
| } |
| /****************************************************************************** |
| * IPersistFile_Release |
| */ |
| static ULONG WINAPI IPersistFile_fnRelease(IPersistFile* iface) |
| { |
| _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface) |
| |
| TRACE("(%p)->(count=%lu)\n",This,This->ref); |
| |
| return IShellLinkA_Release((IShellLinkA*)This); |
| } |
| |
| static HRESULT WINAPI IPersistFile_fnGetClassID(IPersistFile* iface, CLSID *pClassID) |
| { |
| _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) |
| 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 0x%x, error %ld\n", szFileName, hResInfo, GetLastError()); |
| } |
| else |
| { |
| sEnumRes.pResInfo = &hResInfo; |
| sEnumRes.nIndex = nIndex; |
| if (EnumResourceNamesA(hModule, RT_GROUP_ICONA, &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; |
| } |
| } |
| |
| 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; |
| } |
| |
| 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; |
| |
| if (!(fICOFile = fopen(szFileName, "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)) |
| goto error4; |
| |
| free(pIcon); |
| free(pIconDirEntry); |
| fclose(fICOFile); |
| |
| return 1; |
| |
| error4: |
| free(pIcon); |
| error3: |
| free(pIconDirEntry); |
| error2: |
| fclose(fICOFile); |
| error1: |
| return 0; |
| } |
| |
| /* 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]; |
| |
| if (!wine_get_unix_file_name( dos, buffer, sizeof(buffer) )) return NULL; |
| return heap_strdup( buffer ); |
| } |
| |
| 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"); |
| fd = mkstemp( tmpfn ); |
| 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; |
| } |
| |
| |
| 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; |
| BOOL bDesktop; |
| HKEY hkey; |
| |
| _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface); |
| |
| 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 )) |
| { |
| 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 ); |
| |
| 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) )) |
| { |
| 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->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; |
| 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++] = This->sPath; |
| argv[pos++] = bDesktop ? "--desktop" : "--menu"; |
| if (This->sArgs && strlen(This->sArgs)) |
| { |
| argv[pos++] = "--args"; |
| argv[pos++] = This->sArgs; |
| } |
| if (icon_name) |
| { |
| argv[pos++] = "--icon"; |
| argv[pos++] = icon_name; |
| } |
| if (This->sWorkDir && strlen(This->sWorkDir)) |
| { |
| argv[pos++] = "--workdir"; |
| argv[pos++] = This->sWorkDir; |
| } |
| 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 ); |
| return ret; |
| } |
| |
| static HRESULT WINAPI IPersistFile_fnSaveCompleted(IPersistFile* iface, LPCOLESTR pszFileName) |
| { |
| _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface); |
| FIXME("(%p)->(%s)\n",This,debugstr_w(pszFileName)); |
| return NOERROR; |
| } |
| static HRESULT WINAPI IPersistFile_fnGetCurFile(IPersistFile* iface, LPOLESTR *ppszFileName) |
| { |
| _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface); |
| FIXME("(%p)\n",This); |
| return NOERROR; |
| } |
| |
| static ICOM_VTABLE(IPersistFile) pfvt = |
| { |
| ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE |
| IPersistFile_fnQueryInterface, |
| IPersistFile_fnAddRef, |
| IPersistFile_fnRelease, |
| IPersistFile_fnGetClassID, |
| IPersistFile_fnIsDirty, |
| IPersistFile_fnLoad, |
| IPersistFile_fnSave, |
| IPersistFile_fnSaveCompleted, |
| IPersistFile_fnGetCurFile |
| }; |
| |
| /************************************************************************ |
| * IPersistStream_QueryInterface |
| */ |
| static HRESULT WINAPI IPersistStream_fnQueryInterface( |
| IPersistStream* iface, |
| REFIID riid, |
| VOID** ppvoid) |
| { |
| _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface); |
| |
| TRACE("(%p)\n",This); |
| |
| return IShellLinkA_QueryInterface((IShellLinkA*)This, riid, ppvoid); |
| } |
| |
| /************************************************************************ |
| * IPersistStream_Release |
| */ |
| static ULONG WINAPI IPersistStream_fnRelease( |
| IPersistStream* iface) |
| { |
| _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface); |
| |
| TRACE("(%p)\n",This); |
| |
| return IShellLinkA_Release((IShellLinkA*)This); |
| } |
| |
| /************************************************************************ |
| * IPersistStream_AddRef |
| */ |
| static ULONG WINAPI IPersistStream_fnAddRef( |
| IPersistStream* iface) |
| { |
| _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface); |
| |
| TRACE("(%p)\n",This); |
| |
| return IShellLinkA_AddRef((IShellLinkA*)This); |
| } |
| |
| /************************************************************************ |
| * IPersistStream_GetClassID |
| * |
| */ |
| static HRESULT WINAPI IPersistStream_fnGetClassID( |
| IPersistStream* iface, |
| CLSID* pClassID) |
| { |
| _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface); |
| |
| TRACE("(%p)\n", This); |
| |
| if (pClassID==0) |
| return E_POINTER; |
| |
| /* memcpy(pClassID, &CLSID_???, sizeof(CLSID_???)); */ |
| |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * IPersistStream_IsDirty (IPersistStream) |
| */ |
| static HRESULT WINAPI IPersistStream_fnIsDirty( |
| IPersistStream* iface) |
| { |
| _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface); |
| |
| TRACE("(%p)\n", This); |
| |
| return S_OK; |
| } |
| /************************************************************************ |
| * IPersistStream_Load (IPersistStream) |
| */ |
| |
| static HRESULT WINAPI IPersistStream_fnLoad( |
| IPersistStream* iface, |
| IStream* pLoadStream) |
| { |
| PLINK_HEADER lpLinkHeader = HeapAlloc(GetProcessHeap(), 0, LINK_HEADER_SIZE); |
| ULONG dwBytesRead; |
| DWORD ret = E_FAIL; |
| char sTemp[MAX_PATH]; |
| |
| _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface); |
| |
| TRACE("(%p)(%p)\n", This, pLoadStream); |
| |
| if ( ! pLoadStream) |
| { |
| return STG_E_INVALIDPOINTER; |
| } |
| |
| IStream_AddRef (pLoadStream); |
| if(!lpLinkHeader) |
| goto end; |
| |
| dwBytesRead = 0; |
| if (!(SUCCEEDED(IStream_Read(pLoadStream, lpLinkHeader, LINK_HEADER_SIZE, &dwBytesRead)))) |
| goto end; |
| |
| 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 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; |
| |
| end: |
| IStream_Release (pLoadStream); |
| |
| pdump(This->pPidl); |
| |
| HeapFree(GetProcessHeap(), 0, lpLinkHeader); |
| |
| return ret; |
| } |
| |
| /************************************************************************ |
| * IPersistStream_Save (IPersistStream) |
| */ |
| static HRESULT WINAPI IPersistStream_fnSave( |
| IPersistStream* iface, |
| IStream* pOutStream, |
| BOOL fClearDirty) |
| { |
| _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface); |
| |
| TRACE("(%p) %p %x\n", This, pOutStream, fClearDirty); |
| |
| return E_NOTIMPL; |
| } |
| |
| /************************************************************************ |
| * IPersistStream_GetSizeMax (IPersistStream) |
| */ |
| static HRESULT WINAPI IPersistStream_fnGetSizeMax( |
| IPersistStream* iface, |
| ULARGE_INTEGER* pcbSize) |
| { |
| _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface); |
| |
| TRACE("(%p)\n", This); |
| |
| return E_NOTIMPL; |
| } |
| |
| static ICOM_VTABLE(IPersistStream) psvt = |
| { |
| ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE |
| IPersistStream_fnQueryInterface, |
| IPersistStream_fnAddRef, |
| IPersistStream_fnRelease, |
| IPersistStream_fnGetClassID, |
| IPersistStream_fnIsDirty, |
| IPersistStream_fnLoad, |
| IPersistStream_fnSave, |
| IPersistStream_fnGetSizeMax |
| }; |
| |
| /************************************************************************** |
| * IShellLink_Constructor |
| */ |
| HRESULT WINAPI IShellLink_Constructor ( |
| IUnknown * pUnkOuter, |
| REFIID riid, |
| LPVOID * ppv) |
| { |
| IShellLinkImpl * sl; |
| |
| TRACE("unkOut=%p riid=%s\n",pUnkOuter, debugstr_guid(riid)); |
| |
| *ppv = NULL; |
| |
| if(pUnkOuter) return CLASS_E_NOAGGREGATION; |
| sl = (IShellLinkImpl *) LocalAlloc(GMEM_ZEROINIT,sizeof(IShellLinkImpl)); |
| if (!sl) return E_OUTOFMEMORY; |
| |
| sl->ref = 1; |
| ICOM_VTBL(sl) = &slvt; |
| sl->lpvtblw = &slvtw; |
| sl->lpvtblPersistFile = &pfvt; |
| sl->lpvtblPersistStream = &psvt; |
| |
| TRACE("(%p)->()\n",sl); |
| |
| if (IsEqualIID(riid, &IID_IShellLinkA)) |
| *ppv = sl; |
| else if (IsEqualIID(riid, &IID_IShellLinkW)) |
| *ppv = &(sl->lpvtblw); |
| else { |
| LocalFree((HLOCAL)sl); |
| ERR("E_NOINTERFACE\n"); |
| return E_NOINTERFACE; |
| } |
| |
| return S_OK; |
| } |
| |
| /************************************************************************** |
| * IShellLinkA_QueryInterface |
| */ |
| static HRESULT WINAPI IShellLinkA_fnQueryInterface( IShellLinkA * iface, REFIID riid, LPVOID *ppvObj) |
| { |
| ICOM_THIS(IShellLinkImpl, iface); |
| |
| TRACE("(%p)->(\n\tIID:\t%s)\n",This,debugstr_guid(riid)); |
| |
| *ppvObj = NULL; |
| |
| if(IsEqualIID(riid, &IID_IUnknown) || |
| IsEqualIID(riid, &IID_IShellLinkA)) |
| { |
| *ppvObj = This; |
| } |
| else if(IsEqualIID(riid, &IID_IShellLinkW)) |
| { |
| *ppvObj = (IShellLinkW *)&(This->lpvtblw); |
| } |
| else if(IsEqualIID(riid, &IID_IPersistFile)) |
| { |
| *ppvObj = (IPersistFile *)&(This->lpvtblPersistFile); |
| } |
| else if(IsEqualIID(riid, &IID_IPersistStream)) |
| { |
| *ppvObj = (IPersistStream *)&(This->lpvtblPersistStream); |
| } |
| |
| if(*ppvObj) |
| { |
| IUnknown_AddRef((IUnknown*)(*ppvObj)); |
| TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj); |
| return S_OK; |
| } |
| TRACE("-- Interface: E_NOINTERFACE\n"); |
| return E_NOINTERFACE; |
| } |
| /****************************************************************************** |
| * IShellLinkA_AddRef |
| */ |
| static ULONG WINAPI IShellLinkA_fnAddRef(IShellLinkA * iface) |
| { |
| ICOM_THIS(IShellLinkImpl, iface); |
| |
| TRACE("(%p)->(count=%lu)\n",This,This->ref); |
| |
| return ++(This->ref); |
| } |
| /****************************************************************************** |
| * IShellLinkA_Release |
| */ |
| static ULONG WINAPI IShellLinkA_fnRelease(IShellLinkA * iface) |
| { |
| ICOM_THIS(IShellLinkImpl, iface); |
| |
| TRACE("(%p)->(count=%lu)\n",This,This->ref); |
| |
| if (!--(This->ref)) |
| { TRACE("-- destroying IShellLink(%p)\n",This); |
| |
| if (This->sIcoPath) |
| HeapFree(GetProcessHeap(), 0, This->sIcoPath); |
| |
| if (This->sArgs) |
| HeapFree(GetProcessHeap(), 0, This->sArgs); |
| |
| if (This->sWorkDir) |
| HeapFree(GetProcessHeap(), 0, This->sWorkDir); |
| |
| if (This->sDescription) |
| HeapFree(GetProcessHeap(), 0, This->sDescription); |
| |
| if (This->sPath) |
| HeapFree(GetProcessHeap(),0,This->sPath); |
| |
| if (This->pPidl) |
| SHFree(This->pPidl); |
| |
| if (This->lpFileStream) |
| IStream_Release(This->lpFileStream); |
| |
| This->iIcoNdx = 0; |
| |
| LocalFree((HANDLE)This); |
| return 0; |
| } |
| return This->ref; |
| } |
| |
| static HRESULT WINAPI IShellLinkA_fnGetPath(IShellLinkA * iface, LPSTR pszFile,INT cchMaxPath, WIN32_FIND_DATAA *pfd, DWORD fFlags) |
| { |
| 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)); |
| |
| if (This->sPath) |
| lstrcpynA(pszFile,This->sPath, cchMaxPath); |
| else |
| return E_FAIL; |
| |
| return NOERROR; |
| } |
| static HRESULT WINAPI IShellLinkA_fnGetIDList(IShellLinkA * iface, LPITEMIDLIST * ppidl) |
| { |
| ICOM_THIS(IShellLinkImpl, iface); |
| |
| 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); |
| |
| TRACE("(%p)->(pidl=%p)\n",This, pidl); |
| |
| if (This->pPidl) |
| SHFree(This->pPidl); |
| This->pPidl = ILClone (pidl); |
| return NOERROR; |
| } |
| static HRESULT WINAPI IShellLinkA_fnGetDescription(IShellLinkA * iface, LPSTR pszName,INT cchMaxName) |
| { |
| ICOM_THIS(IShellLinkImpl, iface); |
| |
| FIXME("(%p)->(%p len=%u)\n",This, pszName, cchMaxName); |
| lstrcpynA(pszName,"Description, FIXME",cchMaxName); |
| return NOERROR; |
| } |
| static HRESULT WINAPI IShellLinkA_fnSetDescription(IShellLinkA * iface, LPCSTR pszName) |
| { |
| ICOM_THIS(IShellLinkImpl, iface); |
| |
| TRACE("(%p)->(pName=%s)\n", This, pszName); |
| |
| if (This->sDescription) |
| HeapFree(GetProcessHeap(), 0, This->sDescription); |
| if (!(This->sDescription = heap_strdup(pszName))) |
| return E_OUTOFMEMORY; |
| |
| return NOERROR; |
| } |
| static HRESULT WINAPI IShellLinkA_fnGetWorkingDirectory(IShellLinkA * iface, LPSTR pszDir,INT cchMaxPath) |
| { |
| ICOM_THIS(IShellLinkImpl, iface); |
| |
| TRACE("(%p)->(%p len=%u)\n", This, pszDir, cchMaxPath); |
| |
| lstrcpynA( pszDir, This->sWorkDir ? This->sWorkDir : "", cchMaxPath ); |
| |
| return NOERROR; |
| } |
| static HRESULT WINAPI IShellLinkA_fnSetWorkingDirectory(IShellLinkA * iface, LPCSTR pszDir) |
| { |
| ICOM_THIS(IShellLinkImpl, iface); |
| |
| TRACE("(%p)->(dir=%s)\n",This, pszDir); |
| |
| if (This->sWorkDir) |
| HeapFree(GetProcessHeap(), 0, This->sWorkDir); |
| if (!(This->sWorkDir = heap_strdup(pszDir))) |
| return E_OUTOFMEMORY; |
| |
| return NOERROR; |
| } |
| static HRESULT WINAPI IShellLinkA_fnGetArguments(IShellLinkA * iface, LPSTR pszArgs,INT cchMaxPath) |
| { |
| ICOM_THIS(IShellLinkImpl, iface); |
| |
| TRACE("(%p)->(%p len=%u)\n", This, pszArgs, cchMaxPath); |
| |
| lstrcpynA( pszArgs, This->sArgs ? This->sArgs : "", cchMaxPath ); |
| |
| return NOERROR; |
| } |
| static HRESULT WINAPI IShellLinkA_fnSetArguments(IShellLinkA * iface, LPCSTR pszArgs) |
| { |
| ICOM_THIS(IShellLinkImpl, iface); |
| |
| TRACE("(%p)->(args=%s)\n",This, pszArgs); |
| |
| if (This->sArgs) |
| HeapFree(GetProcessHeap(), 0, This->sArgs); |
| if (!(This->sArgs = heap_strdup(pszArgs))) |
| return E_OUTOFMEMORY; |
| |
| return NOERROR; |
| } |
| static HRESULT WINAPI IShellLinkA_fnGetHotkey(IShellLinkA * iface, WORD *pwHotkey) |
| { |
| ICOM_THIS(IShellLinkImpl, iface); |
| |
| TRACE("(%p)->(%p)(0x%08x)\n",This, pwHotkey, This->wHotKey); |
| |
| *pwHotkey = This->wHotKey; |
| |
| return NOERROR; |
| } |
| static HRESULT WINAPI IShellLinkA_fnSetHotkey(IShellLinkA * iface, WORD wHotkey) |
| { |
| ICOM_THIS(IShellLinkImpl, iface); |
| |
| TRACE("(%p)->(hotkey=%x)\n",This, wHotkey); |
| |
| This->wHotKey = wHotkey; |
| |
| return NOERROR; |
| } |
| static HRESULT WINAPI IShellLinkA_fnGetShowCmd(IShellLinkA * iface, INT *piShowCmd) |
| { |
| ICOM_THIS(IShellLinkImpl, iface); |
| |
| FIXME("(%p)->(%p)\n",This, piShowCmd); |
| *piShowCmd=0; |
| return NOERROR; |
| } |
| static HRESULT WINAPI IShellLinkA_fnSetShowCmd(IShellLinkA * iface, INT iShowCmd) |
| { |
| ICOM_THIS(IShellLinkImpl, iface); |
| |
| FIXME("(%p)->(showcmd=%x)\n",This, iShowCmd); |
| return NOERROR; |
| } |
| static HRESULT WINAPI IShellLinkA_fnGetIconLocation(IShellLinkA * iface, LPSTR pszIconPath,INT cchIconPath,INT *piIcon) |
| { |
| ICOM_THIS(IShellLinkImpl, iface); |
| |
| TRACE("(%p)->(%p len=%u iicon=%p)\n", This, pszIconPath, cchIconPath, piIcon); |
| |
| lstrcpynA( pszIconPath, This->sIcoPath ? This->sIcoPath : "", cchIconPath ); |
| *piIcon = This->iIcoNdx; |
| |
| return NOERROR; |
| } |
| static HRESULT WINAPI IShellLinkA_fnSetIconLocation(IShellLinkA * iface, LPCSTR pszIconPath,INT iIcon) |
| { |
| ICOM_THIS(IShellLinkImpl, iface); |
| |
| 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; |
| |
| return NOERROR; |
| } |
| static HRESULT WINAPI IShellLinkA_fnSetRelativePath(IShellLinkA * iface, LPCSTR pszPathRel, DWORD dwReserved) |
| { |
| ICOM_THIS(IShellLinkImpl, iface); |
| |
| FIXME("(%p)->(path=%s %lx)\n",This, pszPathRel, dwReserved); |
| return NOERROR; |
| } |
| static HRESULT WINAPI IShellLinkA_fnResolve(IShellLinkA * iface, HWND hwnd, DWORD fFlags) |
| { |
| ICOM_THIS(IShellLinkImpl, iface); |
| |
| FIXME("(%p)->(hwnd=%x flags=%lx)\n",This, hwnd, fFlags); |
| return NOERROR; |
| } |
| static HRESULT WINAPI IShellLinkA_fnSetPath(IShellLinkA * iface, LPCSTR pszFile) |
| { |
| ICOM_THIS(IShellLinkImpl, iface); |
| |
| TRACE("(%p)->(path=%s)\n",This, pszFile); |
| |
| if (This->sPath) |
| HeapFree(GetProcessHeap(), 0, This->sPath); |
| if (!(This->sPath = heap_strdup(pszFile))) |
| return E_OUTOFMEMORY; |
| |
| return NOERROR; |
| } |
| |
| /************************************************************************** |
| * IShellLink Implementation |
| */ |
| |
| static ICOM_VTABLE(IShellLinkA) slvt = |
| { |
| ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE |
| IShellLinkA_fnQueryInterface, |
| IShellLinkA_fnAddRef, |
| IShellLinkA_fnRelease, |
| IShellLinkA_fnGetPath, |
| IShellLinkA_fnGetIDList, |
| IShellLinkA_fnSetIDList, |
| IShellLinkA_fnGetDescription, |
| IShellLinkA_fnSetDescription, |
| IShellLinkA_fnGetWorkingDirectory, |
| IShellLinkA_fnSetWorkingDirectory, |
| IShellLinkA_fnGetArguments, |
| IShellLinkA_fnSetArguments, |
| IShellLinkA_fnGetHotkey, |
| IShellLinkA_fnSetHotkey, |
| IShellLinkA_fnGetShowCmd, |
| IShellLinkA_fnSetShowCmd, |
| IShellLinkA_fnGetIconLocation, |
| IShellLinkA_fnSetIconLocation, |
| IShellLinkA_fnSetRelativePath, |
| IShellLinkA_fnResolve, |
| IShellLinkA_fnSetPath |
| }; |
| |
| |
| /************************************************************************** |
| * IShellLinkW_fnQueryInterface |
| */ |
| static HRESULT WINAPI IShellLinkW_fnQueryInterface( |
| IShellLinkW * iface, REFIID riid, LPVOID *ppvObj) |
| { |
| _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); |
| |
| return IShellLinkA_QueryInterface((IShellLinkA*)This, riid, ppvObj); |
| } |
| |
| /****************************************************************************** |
| * IShellLinkW_fnAddRef |
| */ |
| static ULONG WINAPI IShellLinkW_fnAddRef(IShellLinkW * iface) |
| { |
| _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); |
| |
| TRACE("(%p)->(count=%lu)\n",This,This->ref); |
| |
| return IShellLinkA_AddRef((IShellLinkA*)This); |
| } |
| /****************************************************************************** |
| * IShellLinkW_fnRelease |
| */ |
| |
| static ULONG WINAPI IShellLinkW_fnRelease(IShellLinkW * iface) |
| { |
| _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); |
| |
| TRACE("(%p)->(count=%lu)\n",This,This->ref); |
| |
| return IShellLinkA_Release((IShellLinkA*)This); |
| } |
| |
| static HRESULT WINAPI IShellLinkW_fnGetPath(IShellLinkW * iface, LPWSTR pszFile,INT cchMaxPath, WIN32_FIND_DATAA *pfd, DWORD fFlags) |
| { |
| _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; |
| } |
| |
| static HRESULT WINAPI IShellLinkW_fnGetIDList(IShellLinkW * iface, LPITEMIDLIST * ppidl) |
| { |
| _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); |
| |
| FIXME("(%p)->(ppidl=%p)\n",This, ppidl); |
| *ppidl = _ILCreateDesktop(); |
| return NOERROR; |
| } |
| |
| static HRESULT WINAPI IShellLinkW_fnSetIDList(IShellLinkW * iface, LPCITEMIDLIST pidl) |
| { |
| _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); |
| |
| FIXME("(%p)->(pidl=%p)\n",This, pidl); |
| return NOERROR; |
| } |
| |
| static HRESULT WINAPI IShellLinkW_fnGetDescription(IShellLinkW * iface, LPWSTR pszName,INT cchMaxName) |
| { |
| _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; |
| } |
| |
| static HRESULT WINAPI IShellLinkW_fnSetDescription(IShellLinkW * iface, LPCWSTR pszName) |
| { |
| _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); |
| |
| 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; |
| |
| return NOERROR; |
| } |
| |
| static HRESULT WINAPI IShellLinkW_fnGetWorkingDirectory(IShellLinkW * iface, LPWSTR pszDir,INT cchMaxPath) |
| { |
| _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); |
| |
| TRACE("(%p)->(%p len %u)\n", This, pszDir, cchMaxPath); |
| |
| MultiByteToWideChar( CP_ACP, 0, This->sWorkDir ? This->sWorkDir : "", -1, pszDir, cchMaxPath ); |
| |
| return NOERROR; |
| } |
| |
| static HRESULT WINAPI IShellLinkW_fnSetWorkingDirectory(IShellLinkW * iface, LPCWSTR pszDir) |
| { |
| _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); |
| |
| 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; |
| |
| return NOERROR; |
| } |
| |
| static HRESULT WINAPI IShellLinkW_fnGetArguments(IShellLinkW * iface, LPWSTR pszArgs,INT cchMaxPath) |
| { |
| _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); |
| |
| TRACE("(%p)->(%p len=%u)\n", This, pszArgs, cchMaxPath); |
| |
| MultiByteToWideChar( CP_ACP, 0, This->sArgs ? This->sArgs : "", -1, pszArgs, cchMaxPath ); |
| |
| return NOERROR; |
| } |
| |
| static HRESULT WINAPI IShellLinkW_fnSetArguments(IShellLinkW * iface, LPCWSTR pszArgs) |
| { |
| _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); |
| |
| 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; |
| |
| return NOERROR; |
| } |
| |
| static HRESULT WINAPI IShellLinkW_fnGetHotkey(IShellLinkW * iface, WORD *pwHotkey) |
| { |
| _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); |
| |
| FIXME("(%p)->(%p)\n",This, pwHotkey); |
| *pwHotkey=0x0; |
| return NOERROR; |
| } |
| |
| static HRESULT WINAPI IShellLinkW_fnSetHotkey(IShellLinkW * iface, WORD wHotkey) |
| { |
| _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); |
| |
| FIXME("(%p)->(hotkey=%x)\n",This, wHotkey); |
| return NOERROR; |
| } |
| |
| static HRESULT WINAPI IShellLinkW_fnGetShowCmd(IShellLinkW * iface, INT *piShowCmd) |
| { |
| _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); |
| |
| FIXME("(%p)->(%p)\n",This, piShowCmd); |
| *piShowCmd=0; |
| return NOERROR; |
| } |
| |
| static HRESULT WINAPI IShellLinkW_fnSetShowCmd(IShellLinkW * iface, INT iShowCmd) |
| { |
| _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); |
| |
| FIXME("(%p)->(showcmd=%x)\n",This, iShowCmd); |
| return NOERROR; |
| } |
| |
| static HRESULT WINAPI IShellLinkW_fnGetIconLocation(IShellLinkW * iface, LPWSTR pszIconPath,INT cchIconPath,INT *piIcon) |
| { |
| _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); |
| |
| 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; |
| |
| return NOERROR; |
| } |
| |
| static HRESULT WINAPI IShellLinkW_fnSetIconLocation(IShellLinkW * iface, LPCWSTR pszIconPath,INT iIcon) |
| { |
| _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); |
| |
| 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; |
| |
| return NOERROR; |
| } |
| |
| static HRESULT WINAPI IShellLinkW_fnSetRelativePath(IShellLinkW * iface, LPCWSTR pszPathRel, DWORD dwReserved) |
| { |
| _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); |
| |
| FIXME("(%p)->(path=%s %lx)\n",This, debugstr_w(pszPathRel), dwReserved); |
| return NOERROR; |
| } |
| |
| static HRESULT WINAPI IShellLinkW_fnResolve(IShellLinkW * iface, HWND hwnd, DWORD fFlags) |
| { |
| _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); |
| |
| FIXME("(%p)->(hwnd=%x flags=%lx)\n",This, hwnd, fFlags); |
| return NOERROR; |
| } |
| |
| static HRESULT WINAPI IShellLinkW_fnSetPath(IShellLinkW * iface, LPCWSTR pszFile) |
| { |
| _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); |
| |
| 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; |
| |
| return NOERROR; |
| } |
| |
| /************************************************************************** |
| * IShellLinkW Implementation |
| */ |
| |
| static ICOM_VTABLE(IShellLinkW) slvtw = |
| { |
| ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE |
| IShellLinkW_fnQueryInterface, |
| IShellLinkW_fnAddRef, |
| IShellLinkW_fnRelease, |
| IShellLinkW_fnGetPath, |
| IShellLinkW_fnGetIDList, |
| IShellLinkW_fnSetIDList, |
| IShellLinkW_fnGetDescription, |
| IShellLinkW_fnSetDescription, |
| IShellLinkW_fnGetWorkingDirectory, |
| IShellLinkW_fnSetWorkingDirectory, |
| IShellLinkW_fnGetArguments, |
| IShellLinkW_fnSetArguments, |
| IShellLinkW_fnGetHotkey, |
| IShellLinkW_fnSetHotkey, |
| IShellLinkW_fnGetShowCmd, |
| IShellLinkW_fnSetShowCmd, |
| IShellLinkW_fnGetIconLocation, |
| IShellLinkW_fnSetIconLocation, |
| IShellLinkW_fnSetRelativePath, |
| IShellLinkW_fnResolve, |
| IShellLinkW_fnSetPath |
| }; |