From e2b4efbd02cc18f3e3b586751d83235ead2d3325 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 2 Nov 2000 20:22:07 +0000 Subject: [PATCH] Create Gnome/KDE desktop and menu entries from IShellLink interface. Based on the work of James Thomson and Dusan Lacko. --- dlls/shell32/shelllink.c | 542 ++++++++++++++++++++++++++++++++++++++- include/bitmaps/wine.xpm | 210 +++++++++++++++ tools/Makefile.in | 3 +- tools/wineshelllink | 121 +++++++++ wine.ini | 1 + 5 files changed, 863 insertions(+), 14 deletions(-) create mode 100644 include/bitmaps/wine.xpm create mode 100755 tools/wineshelllink diff --git a/dlls/shell32/shelllink.c b/dlls/shell32/shelllink.c index 25cef1c8469..3acbb72fdd7 100644 --- a/dlls/shell32/shelllink.c +++ b/dlls/shell32/shelllink.c @@ -6,6 +6,12 @@ */ #include +#include +#include +#include +#include +#include + #include "debugtools.h" #include "winerror.h" #include "winbase.h" @@ -14,11 +20,14 @@ #include "shlobj.h" #include "wine/winestring.h" #include "wine/undocshell.h" +#include "bitmaps/wine.xpm" #include "heap.h" #include "pidl.h" #include "shell32_main.h" #include "shlguid.h" +#include "file.h" +#include "options.h" DEFAULT_DEBUG_CHANNEL(shell); @@ -57,8 +66,49 @@ typedef struct _LINK_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" + static ICOM_VTABLE(IShellLinkA) slvt; static ICOM_VTABLE(IShellLinkW) slvtw; static ICOM_VTABLE(IPersistFile) pfvt; @@ -86,6 +136,11 @@ typedef struct SYSTEMTIME time2; SYSTEMTIME time3; + LPSTR sIcoPath; + INT iIcoNdx; + LPSTR sArgs; + LPSTR sWorkDir; + LPSTR sDescription; } IShellLinkImpl; #define _IShellLinkW_Offset ((int)(&(((IShellLinkImpl*)0)->lpvtblw))) @@ -173,12 +228,398 @@ static HRESULT WINAPI IPersistFile_fnLoad(IPersistFile* iface, LPCOLESTR pszFile 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) +{ + *(HRSRC *) lParam = FindResourceA(hModule, lpszName, RT_GROUP_ICONA); + return FALSE; +} + +static int ExtractFromEXEDLL(const char *szFileName, int nIndex, const char *szXPMFileName) +{ + HMODULE hModule; + HRSRC hResInfo; + char *lpName = NULL; + HGLOBAL hResData; + GRPICONDIR *pIconDir; + BITMAPINFO *pIcon; + int nMax = 0; + int i; + + if (!(hModule = LoadLibraryExA(szFileName, 0, LOAD_LIBRARY_AS_DATAFILE))) + goto error1; + + if (nIndex) + hResInfo = FindResourceA(hModule, MAKEINTRESOURCEA(nIndex), RT_GROUP_ICONA); + else + if (EnumResourceNamesA(hModule, RT_GROUP_ICONA, &EnumResNameProc, (LONG) &hResInfo)) + goto error2; + + if (!hResInfo) + goto error2; + + if (!(hResData = LoadResource(hModule, hResInfo))) + goto error2; + if (!(pIconDir = LockResource(hResData))) + goto error3; + + for (i = 0; i < pIconDir->idCount; i++) + 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))) + goto error2; + if (!(hResData = LoadResource(hModule, hResInfo))) + goto error2; + if (!(pIcon = LockResource(hResData))) + goto error3; + + if(!SaveIconResAsXPM(pIcon, szXPMFileName)) + 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 ) +{ + DOS_FULL_NAME path; + + if (!DOSFS_GetFullName( dos, FALSE, &path )) return NULL; + return HEAP_strdupA( GetProcessHeap(), 0, path.long_name ); +} + +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 ) +{ + char *filename = HEAP_strdupA( GetProcessHeap(), 0, tmpnam(NULL) ); + if (ExtractFromEXEDLL( path, index, filename )) return filename; + if (ExtractFromICO( path, filename )) return filename; + if (create_default_icon( filename )) return filename; + HeapFree( GetProcessHeap(), 0, filename ); + return NULL; +} + + static HRESULT WINAPI IPersistFile_fnSave(IPersistFile* iface, LPCOLESTR pszFileName, BOOL fRemember) { - _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface); - FIXME("(%p)->(%s)\n",This,debugstr_w(pszFileName)); - return NOERROR; + HRESULT ret = NOERROR; + int pid, status; + char buffer[MAX_PATH], buff2[MAX_PATH]; + char *filename, *link_name, *p; + char *shell_link_app = NULL; + char *icon_name = NULL; + char *path_name = NULL; + char *work_dir = NULL; + BOOL bDesktop; + + _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface); + + TRACE("(%p)->(%s)\n",This,debugstr_w(pszFileName)); + + ERR("(%p)->(%s),%s,%s,%s\n",This,debugstr_w(pszFileName),This->sPath,This->sArgs,This->sDescription); + + 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 */ + PROFILE_GetWineIniString( "wine", "ShellLinker", "", buffer, sizeof(buffer) ); + if (!*buffer) return NOERROR; + shell_link_app = HEAP_strdupA( GetProcessHeap(), 0, buffer ); + + if (!WideCharToMultiByte( CP_ACP, 0, pszFileName, -1, buffer, sizeof(buffer), NULL, NULL)) + return ERROR_UNKNOWN; + GetFullPathNameA( buffer, sizeof(buff2), buff2, NULL ); + filename = HEAP_strdupA( GetProcessHeap(), 0, 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 path name */ + path_name = get_unix_file_name( This->sPath ); + + /* 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 ? This->sIcoPath : This->sPath, + This->iIcoNdx ))) goto done; + + ERR("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", path_name, + 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++] = path_name; + argv[pos++] = bDesktop ? "--desktop" : "--menu"; + if (This->sArgs) + { + argv[pos++] = "--args"; + argv[pos++] = This->sArgs; + } + if (icon_name) + { + argv[pos++] = "--icon"; + argv[pos++] = icon_name; + } + if (This->sWorkDir) + { + argv[pos++] = "--workdir"; + argv[pos++] = This->sWorkDir; + } + if (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, path_name ); + HeapFree( GetProcessHeap(), 0, work_dir ); + return ret; } + static HRESULT WINAPI IPersistFile_fnSaveCompleted(IPersistFile* iface, LPCOLESTR pszFileName) { _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface); @@ -475,6 +916,18 @@ static ULONG WINAPI IShellLinkA_fnRelease(IShellLinkA * iface) shell32_ObjCount--; 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); @@ -484,6 +937,8 @@ static ULONG WINAPI IShellLinkA_fnRelease(IShellLinkA * iface) if (This->lpFileStream) IStream_Release(This->lpFileStream); + + This->iIcoNdx = 0; HeapFree(GetProcessHeap(),0,This); return 0; @@ -536,7 +991,13 @@ static HRESULT WINAPI IShellLinkA_fnSetDescription(IShellLinkA * iface, LPCSTR p { ICOM_THIS(IShellLinkImpl, iface); - FIXME("(%p)->(desc=%s)\n",This, pszName); + TRACE("(%p)->(pName=%s)\n", This, pszName); + + if (This->sDescription) + HeapFree(GetProcessHeap(), 0, This->sDescription); + if (!(This->sDescription = HEAP_strdupA(GetProcessHeap(), 0, pszName))) + return E_OUTOFMEMORY; + return NOERROR; } static HRESULT WINAPI IShellLinkA_fnGetWorkingDirectory(IShellLinkA * iface, LPSTR pszDir,INT cchMaxPath) @@ -551,7 +1012,13 @@ static HRESULT WINAPI IShellLinkA_fnSetWorkingDirectory(IShellLinkA * iface, LPC { ICOM_THIS(IShellLinkImpl, iface); - FIXME("(%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_strdupA(GetProcessHeap(), 0, pszDir))) + return E_OUTOFMEMORY; + return NOERROR; } static HRESULT WINAPI IShellLinkA_fnGetArguments(IShellLinkA * iface, LPSTR pszArgs,INT cchMaxPath) @@ -566,7 +1033,12 @@ static HRESULT WINAPI IShellLinkA_fnSetArguments(IShellLinkA * iface, LPCSTR psz { ICOM_THIS(IShellLinkImpl, iface); - FIXME("(%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_strdupA(GetProcessHeap(), 0, pszArgs))) + return E_OUTOFMEMORY; return NOERROR; } @@ -618,7 +1090,14 @@ static HRESULT WINAPI IShellLinkA_fnSetIconLocation(IShellLinkA * iface, LPCSTR { ICOM_THIS(IShellLinkImpl, iface); - FIXME("(%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_strdupA(GetProcessHeap(), 0, pszIconPath))) + return E_OUTOFMEMORY; + This->iIcoNdx = iIcon; + return NOERROR; } static HRESULT WINAPI IShellLinkA_fnSetRelativePath(IShellLinkA * iface, LPCSTR pszPathRel, DWORD dwReserved) @@ -639,7 +1118,13 @@ static HRESULT WINAPI IShellLinkA_fnSetPath(IShellLinkA * iface, LPCSTR pszFile) { ICOM_THIS(IShellLinkImpl, iface); - FIXME("(%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_strdupA(GetProcessHeap(), 0, pszFile))) + return E_OUTOFMEMORY; + return NOERROR; } @@ -748,7 +1233,13 @@ static HRESULT WINAPI IShellLinkW_fnSetDescription(IShellLinkW * iface, LPCWSTR { _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); - FIXME("(%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; + return NOERROR; } @@ -765,7 +1256,13 @@ static HRESULT WINAPI IShellLinkW_fnSetWorkingDirectory(IShellLinkW * iface, LPC { _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); - FIXME("(%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; + return NOERROR; } @@ -782,7 +1279,13 @@ static HRESULT WINAPI IShellLinkW_fnSetArguments(IShellLinkW * iface, LPCWSTR ps { _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); - FIXME("(%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; + return NOERROR; } @@ -834,7 +1337,14 @@ static HRESULT WINAPI IShellLinkW_fnSetIconLocation(IShellLinkW * iface, LPCWSTR { _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); - FIXME("(%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; + return NOERROR; } @@ -858,7 +1368,13 @@ static HRESULT WINAPI IShellLinkW_fnSetPath(IShellLinkW * iface, LPCWSTR pszFile { _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface); - FIXME("(%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; + return NOERROR; } diff --git a/include/bitmaps/wine.xpm b/include/bitmaps/wine.xpm new file mode 100644 index 00000000000..613f921d369 --- /dev/null +++ b/include/bitmaps/wine.xpm @@ -0,0 +1,210 @@ +/* XPM */ +static char * wine_xpm[] = { +"48 48 159 2", +" c None", +". c #010101", +"+ c #030303", +"@ c #000000", +"# c #040404", +"$ c #0D0D0D", +"% c #222222", +"& c #090909", +"* c #050505", +"= c #101010", +"- c #0B0B0B", +"; c #131313", +"> c #1C1C1C", +", c #232323", +"' c #161616", +") c #020202", +"! c #2F2F2F", +"~ c #212121", +"{ c #060606", +"] c #292929", +"^ c #0A0A0A", +"/ c #111111", +"( c #252525", +"_ c #0E0E0E", +": c #262626", +"< c #0C0005", +"[ c #100308", +"} c #2D2D2D", +"| c #2A2A2A", +"1 c #360013", +"2 c #59001C", +"3 c #120006", +"4 c #080808", +"5 c #141414", +"6 c #090707", +"7 c #0A0003", +"8 c #0E0003", +"9 c #0B0205", +"0 c #191919", +"a c #6A0022", +"b c #AC0033", +"c c #730024", +"d c #4F0019", +"e c #470016", +"f c #4B0019", +"g c #5D001E", +"h c #690022", +"i c #6E0023", +"j c #660021", +"k c #410012", +"l c #1B080D", +"m c #171717", +"n c #160007", +"o c #8E002E", +"p c #B60038", +"q c #AE0038", +"r c #A90035", +"s c #A60033", +"t c #A60035", +"u c #AF0038", +"v c #B10038", +"w c #B00038", +"x c #A10031", +"y c #6D0020", +"z c #1A0007", +"A c #121212", +"B c #3D0014", +"C c #A70033", +"D c #AE0039", +"E c #B30038", +"F c #B20038", +"G c #B70038", +"H c #98002E", +"I c #2E000F", +"J c #52021A", +"K c #7C0026", +"L c #AC0035", +"M c #AD0038", +"N c #B50038", +"O c #830029", +"P c #1A0008", +"Q c #490017", +"R c #A00033", +"S c #B20039", +"T c #53001B", +"U c #3C0014", +"V c #A20032", +"W c #AD0039", +"X c #B40038", +"Y c #8F002D", +"Z c #1E0008", +"` c #171616", +" . c #51001A", +".. c #A80035", +"+. c #B20037", +"@. c #700025", +"#. c #0A0104", +"$. c #090204", +"%. c #B00039", +"&. c #A40033", +"*. c #32000F", +"=. c #110005", +"-. c #730026", +";. c #AF0039", +">. c #810029", +",. c #0A0002", +"'. c #1D0009", +"). c #820029", +"!. c #410014", +"~. c #21000A", +"{. c #87002A", +"]. c #88002C", +"^. c #8B002A", +"/. c #3C0015", +"(. c #20000A", +"_. c #86002A", +":. c #B50037", +"<. c #710022", +"[. c #080002", +"}. c #130006", +"|. c #790026", +"1. c #7A0128", +"2. c #140007", +"3. c #0D0608", +"4. c #650021", +"5. c #90002E", +"6. c #290310", +"7. c #181818", +"8. c #390013", +"9. c #9A0032", +"0. c #B40039", +"a. c #B10037", +"b. c #91002D", +"c. c #3E0014", +"d. c #0C0407", +"e. c #0A0004", +"f. c #4A001A", +"g. c #92002D", +"h. c #A50034", +"i. c #94002E", +"j. c #6C0122", +"k. c #2E0210", +"l. c #0B0406", +"m. c #070707", +"n. c #090003", +"o. c #26000C", +"p. c #370414", +"q. c #28000C", +"r. c #060303", +"s. c #191818", +"t. c #1F1F1F", +"u. c #0F0F0F", +"v. c #1D1D1D", +"w. c #3E3E3E", +"x. c #2B2B2B", +"y. c #1A1A1A", +"z. c #323232", +"A. c #2E2E2E", +"B. c #1E1E1E", +" . + @ @ # ", +" $ % & . * ", +" & . = & - ", +" @ ; - # ", +" > @ , # ", +" . ' ) ", +" ! # ~ * ", +" { @ # @ ", +" . > . * ", +" ] ^ / ( _ : ", +" $ < [ } + + ", +" | ' 1 2 3 4 5 / 6 7 8 9 $ & 0 ", +" ^ * a b c d e f g h i j k l m & ' ", +" @ n o p q r s t u q v w x y z @ ", +" A B C u D E F v q F u u G H I @ ", +" J K L E D F M v u M E q N O P ", +" Q R E q S u v M F u E q r T + ", +" { U V v F W w v v w F M X Y Z ", +" ` ...F u D F u w v w M +.@.#. ", +" $.a w w v %.v u u w v w &.*.. ", +" =.-.w w v ;.u v u w M G >.,.@ ", +" '.).w v u W v q v u v E !.@ ", +" ~.{.E u F D F u w v X ].7 # ", +" ~.^.F F q S u v M F X /.@ ", +" (._.X u E W u v v :.<.[.@ ", +" }.|.w F q D F v v 1.2.4 ", +" 3.4.w w F %.F X 5.6.. 7. ", +" ^ 8.9.G v 0.a.b.c.d.. ", +" e.f.g.h.i.j.k.l.m. ", +" - n.o.p.q.3 4 ^ ", +" r.@ @ . @ @ ", +" s.@ @ @ ", +" > @ ) ", +" t.. u. ", +" > + ", +" > v. ", +" 5 ' ", +" # ", +" v. ", +" @ ( ", +" w.x.] _ @ ( ", +" @ @ @ @ & / - @ @ @ ( ", +" { & @ @ @ @ @ @ & ( ", +" = / m.@ @ @ @ = 5 ) ", +" y.@ @ @ @ @ @ @ - ", +" z.^ @ @ @ @ m.# ", +" A _ . @ . & ", +" A.B.; "}; diff --git a/tools/Makefile.in b/tools/Makefile.in index 2df43855cd4..486237b21e2 100644 --- a/tools/Makefile.in +++ b/tools/Makefile.in @@ -42,8 +42,9 @@ bin2res: bin2res.o install:: $(PROGRAMS) $(INSTALLSUBDIRS:%=%/__install__) [ -d $(bindir) ] || $(MKDIR) $(bindir) $(INSTALL_PROGRAM) fnt2bdf $(bindir)/fnt2bdf + $(INSTALL_PROGRAM) wineshelllink $(bindir)/wineshelllink uninstall:: $(PROGRAMS) $(INSTALLSUBDIRS:%=%/__uninstall__) - $(RM) $(bindir)/fnt2bdf + $(RM) $(bindir)/fnt2bdf $(bindir)/wineshelllink ### Dependencies: diff --git a/tools/wineshelllink b/tools/wineshelllink new file mode 100755 index 00000000000..dc3d7e839b5 --- /dev/null +++ b/tools/wineshelllink @@ -0,0 +1,121 @@ +#!/bin/sh +# +# Create menu/desktop entries for an application +# This is used by the IShellLink interface +# +# Copyright 2000 Alexandre Julliard +# +mode="" +args="" +menu="" +icon="" +descr="" +link="" +path="" +workdir="" + +usage() +{ + cat < "$HOME/.kde/share/applnk/Wine/$link.kdelnk" + elif [ -d "$HOME/Desktop" ] + then + kde_entry > "$HOME/Desktop/$link.kdelnk" + fi +fi + +# Gnome + +if [ -d "$HOME/.gnome" ] +then + copy_icon "$HOME/.gnome/apps/Wine" + if [ $mode = "menu" ] + then + gnome_entry > "$HOME/.gnome/apps/Wine/$link.desktop" + elif [ -d "$HOME/.gnome-desktop" ] + then + gnome_entry > "$HOME/.gnome-desktop/$link.desktop" + fi +fi + +exit 0 diff --git a/wine.ini b/wine.ini index ebada126a9b..1e851f552f9 100644 --- a/wine.ini +++ b/wine.ini @@ -56,6 +56,7 @@ Temp=e:\ Path=c:\windows;c:\windows\system;e:\;e:\test;f:\ Profile=c:\windows\Profiles\Administrator GraphicsDriver=x11drv +ShellLinker=wineshelllink #