shdocvw, winemenubuilder: Generate fd.o entries for .url files.
diff --git a/dlls/shdocvw/intshcut.c b/dlls/shdocvw/intshcut.c
index e24d56d..01da03e 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 @@
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_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 @@
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 26571f6..4792d0d 100644
--- a/programs/winemenubuilder/winemenubuilder.c
+++ b/programs/winemenubuilder/winemenubuilder.c
@@ -73,6 +73,7 @@
#include <shlguid.h>
#include <appmgmt.h>
#include <tlhelp32.h>
+#include <intshcut.h>
#include "wine/unicode.h"
#include "wine/debug.h"
@@ -1409,6 +1410,82 @@
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 @@
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 @@
{
LPSTR token = NULL, p;
BOOL bWait = FALSE;
+ BOOL bURL = FALSE;
int ret = 0;
init_xdg();
@@ -1607,6 +1749,8 @@
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 @@
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;
}
}
}