Damjan Jovanovic : shdocvw, winemenubuilder: Generate fd.o entries for . url files.

Alexandre Julliard julliard at winehq.org
Fri Nov 14 07:55:03 CST 2008


Module: wine
Branch: master
Commit: 9ff230dcaa0f18c3bf1af58bf37b5d29a31edd75
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=9ff230dcaa0f18c3bf1af58bf37b5d29a31edd75

Author: Damjan Jovanovic <damjan.jov at gmail.com>
Date:   Thu Nov 13 08:19:25 2008 +0200

shdocvw, winemenubuilder: Generate fd.o entries for .url files.

---

 dlls/shdocvw/intshcut.c                    |   89 +++++++++++++++-
 programs/winemenubuilder/winemenubuilder.c |  155 +++++++++++++++++++++++++++-
 2 files changed, 237 insertions(+), 7 deletions(-)

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 @@ 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 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 @@ 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;
             }
         }
     }




More information about the wine-cvs mailing list