diff --git a/dlls/shdocvw/intshcut.c b/dlls/shdocvw/intshcut.c index e24d56dc9ab..01da03e89f9 100644 --- a/dlls/shdocvw/intshcut.c +++ b/dlls/shdocvw/intshcut.c @@ -20,10 +20,8 @@ /* * TODO: - * fd.o desktop and menu integration * Implement the IShellLinkA/W interfaces * Handle the SetURL flags - * Loading .url files * Implement any other interfaces? Does any software actually use them? * * The installer for the Zuma Deluxe Popcap game is good for testing. @@ -67,6 +65,42 @@ static inline InternetShortcut* impl_from_IPersistFile(IPersistFile *iface) return (InternetShortcut*)((char*)iface - FIELD_OFFSET(InternetShortcut, persistFile)); } +static BOOL StartLinkProcessor(LPCOLESTR szLink) +{ + static const WCHAR szFormat[] = { + 'w','i','n','e','m','e','n','u','b','u','i','l','d','e','r','.','e','x','e', + ' ','-','w',' ','-','u',' ','"','%','s','"',0 }; + LONG len; + LPWSTR buffer; + STARTUPINFOW si; + PROCESS_INFORMATION pi; + BOOL ret; + + len = sizeof(szFormat) + lstrlenW( szLink ) * sizeof(WCHAR); + buffer = heap_alloc( len ); + if( !buffer ) + return FALSE; + + wsprintfW( buffer, szFormat, szLink ); + + TRACE("starting %s\n",debugstr_w(buffer)); + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + + ret = CreateProcessW( NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi ); + + HeapFree( GetProcessHeap(), 0, buffer ); + + if (ret) + { + CloseHandle( pi.hProcess ); + CloseHandle( pi.hThread ); + } + + return ret; +} + /* interface functions */ static HRESULT WINAPI Unknown_QueryInterface(InternetShortcut *This, REFIID riid, PVOID *ppvObject) @@ -282,8 +316,54 @@ static HRESULT WINAPI PersistFile_IsDirty(IPersistFile *pFile) static HRESULT WINAPI PersistFile_Load(IPersistFile *pFile, LPCOLESTR pszFileName, DWORD dwMode) { - FIXME("(%p, %p, 0x%x): stub\n", pFile, pszFileName, dwMode); - return E_NOTIMPL; + WCHAR str_header[] = {'I','n','t','e','r','n','e','t','S','h','o','r','t','c','u','t',0}; + WCHAR str_URL[] = {'U','R','L',0}; + WCHAR *filename = NULL; + HRESULT hr; + InternetShortcut *This = impl_from_IPersistFile(pFile); + TRACE("(%p, %s, 0x%x)\n", pFile, debugstr_w(pszFileName), dwMode); + if (dwMode != 0) + FIXME("ignoring unimplemented mode 0x%x\n", dwMode); + filename = co_strdupW(pszFileName); + if (filename != NULL) + { + DWORD len = 128; + DWORD r; + WCHAR *url = CoTaskMemAlloc(len); + if (url != NULL) + { + r = GetPrivateProfileStringW(str_header, str_URL, NULL, url, len, pszFileName); + while (r == len-1) + { + CoTaskMemFree(url); + len *= 2; + url = CoTaskMemAlloc(len); + if (url == NULL) + break; + r = GetPrivateProfileStringW(str_header, str_URL, NULL, url, len, pszFileName); + } + if (r == 0) + hr = E_FAIL; + else if (url != NULL) + { + CoTaskMemFree(This->currentFile); + This->currentFile = filename; + CoTaskMemFree(This->url); + This->url = url; + This->isDirty = FALSE; + return S_OK; + } + else + hr = E_OUTOFMEMORY; + CoTaskMemFree(url); + } + else + hr = E_OUTOFMEMORY; + CoTaskMemFree(filename); + } + else + hr = E_OUTOFMEMORY; + return hr; } static HRESULT WINAPI PersistFile_Save(IPersistFile *pFile, LPCOLESTR pszFileName, BOOL fRemember) @@ -336,6 +416,7 @@ static HRESULT WINAPI PersistFile_Save(IPersistFile *pFile, LPCOLESTR pszFileNam CloseHandle(file); if (pszFileName == NULL || fRemember) This->isDirty = FALSE; + StartLinkProcessor(pszFileName); } else hr = E_FAIL; diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c index 26571f688ae..4792d0d7b65 100644 --- a/programs/winemenubuilder/winemenubuilder.c +++ b/programs/winemenubuilder/winemenubuilder.c @@ -73,6 +73,7 @@ #include #include #include +#include #include "wine/unicode.h" #include "wine/debug.h" @@ -1409,6 +1410,82 @@ cleanup: return ( r == 0 ); } +static BOOL InvokeShellLinkerForURL( IUniformResourceLocatorW *url, LPCWSTR link, BOOL bWait ) +{ + char *link_name = NULL; + DWORD csidl = -1; + LPWSTR urlPath; + char *escaped_urlPath = NULL; + HRESULT hr; + HANDLE hSem = NULL; + BOOL ret = TRUE; + int r = -1; + + if ( !link ) + { + WINE_ERR("Link name is null\n"); + return TRUE; + } + + if( !GetLinkLocation( link, &csidl, &link_name ) ) + { + WINE_WARN("Unknown link location %s. Ignoring.\n",wine_dbgstr_w(link)); + return TRUE; + } + if (!in_desktop_dir(csidl) && !in_startmenu(csidl)) + { + WINE_WARN("Not under desktop or start menu. Ignoring.\n"); + ret = TRUE; + goto cleanup; + } + WINE_TRACE("Link : %s\n", wine_dbgstr_a(link_name)); + + hr = url->lpVtbl->GetURL(url, &urlPath); + if (FAILED(hr)) + { + ret = TRUE; + goto cleanup; + } + WINE_TRACE("path : %s\n", wine_dbgstr_w(urlPath)); + + escaped_urlPath = escape(urlPath); + + hSem = CreateSemaphoreA( NULL, 1, 1, "winemenubuilder_semaphore"); + if( WAIT_OBJECT_0 != MsgWaitForMultipleObjects( 1, &hSem, FALSE, INFINITE, QS_ALLINPUT ) ) + { + WINE_ERR("failed wait for semaphore\n"); + goto cleanup; + } + if (in_desktop_dir(csidl)) + { + char *location; + const char *lastEntry; + lastEntry = strrchr(link_name, '/'); + if (lastEntry == NULL) + lastEntry = link_name; + else + ++lastEntry; + location = heap_printf("%s/Desktop/%s.desktop", getenv("HOME"), lastEntry); + if (location) + { + r = !write_desktop_entry(location, lastEntry, "winebrowser", escaped_urlPath, NULL, NULL, NULL); + HeapFree(GetProcessHeap(), 0, location); + } + } + else + r = !write_menu_entry(link_name, "winebrowser", escaped_urlPath, NULL, NULL, NULL); + ret = (r != 0); + ReleaseSemaphore(hSem, 1, NULL); + +cleanup: + if (hSem) + CloseHandle(hSem); + HeapFree(GetProcessHeap(), 0, link_name); + CoTaskMemFree( urlPath ); + HeapFree(GetProcessHeap(), 0, escaped_urlPath); + return ret; +} + static BOOL WaitForParentProcess( void ) { PROCESSENTRY32 procentry; @@ -1522,6 +1599,70 @@ static BOOL Process_Link( LPCWSTR linkname, BOOL bWait ) return !r; } +static BOOL Process_URL( LPCWSTR urlname, BOOL bWait ) +{ + IUniformResourceLocatorW *url; + IPersistFile *pf; + HRESULT r; + WCHAR fullname[MAX_PATH]; + DWORD len; + + WINE_TRACE("%s, wait %d\n", wine_dbgstr_w(urlname), bWait); + + if( !urlname[0] ) + { + WINE_ERR("URL name missing\n"); + return 1; + } + + len=GetFullPathNameW( urlname, MAX_PATH, fullname, NULL ); + if (len==0 || len>MAX_PATH) + { + WINE_ERR("couldn't get full path of URL file\n"); + return 1; + } + + r = CoInitialize( NULL ); + if( FAILED( r ) ) + { + WINE_ERR("CoInitialize failed\n"); + return 1; + } + + r = CoCreateInstance( &CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER, + &IID_IUniformResourceLocatorW, (LPVOID *) &url ); + if( FAILED( r ) ) + { + WINE_ERR("No IID_IUniformResourceLocatorW\n"); + return 1; + } + + r = url->lpVtbl->QueryInterface( url, &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 something fails (eg. Couldn't extract icon) + * wait for parent process and try again + */ + if( ! InvokeShellLinkerForURL( url, fullname, bWait ) && bWait ) + { + WaitForParentProcess(); + InvokeShellLinkerForURL( url, fullname, FALSE ); + } + } + + IPersistFile_Release( pf ); + url->lpVtbl->Release( url ); + + CoUninitialize(); + + return !r; +} static CHAR *next_token( LPSTR *p ) { @@ -1596,6 +1737,7 @@ int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show { LPSTR token = NULL, p; BOOL bWait = FALSE; + BOOL bURL = FALSE; int ret = 0; init_xdg(); @@ -1607,6 +1749,8 @@ int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show break; if( !lstrcmpA( token, "-w" ) ) bWait = TRUE; + else if ( !lstrcmpA( token, "-u" ) ) + bURL = TRUE; else if( token[0] == '-' ) { WINE_ERR( "unknown option %s\n",token); @@ -1614,12 +1758,17 @@ int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show else { WCHAR link[MAX_PATH]; + BOOL bRet; MultiByteToWideChar( CP_ACP, 0, token, -1, link, sizeof(link)/sizeof(WCHAR) ); - if( !Process_Link( link, bWait ) ) + if (bURL) + bRet = Process_URL( link, bWait ); + else + bRet = Process_Link( link, bWait ); + if (!bRet) { - WINE_ERR( "failed to build menu item for %s\n",token); - ret = 1; + WINE_ERR( "failed to build menu item for %s\n",token); + ret = 1; } } }