[PATCH v2 15/15] winemenubuilder: Save AppUserModelID as StartupWMClass

Jonas Kümmerlin rgcjonas at gmail.com
Sat Jul 18 11:26:54 CDT 2015


---
 programs/winemenubuilder/winemenubuilder.c | 123 ++++++++++++++++++++++++++---
 1 file changed, 113 insertions(+), 10 deletions(-)

diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c
index 76d8f3a..2e258a9 100644
--- a/programs/winemenubuilder/winemenubuilder.c
+++ b/programs/winemenubuilder/winemenubuilder.c
@@ -90,6 +90,8 @@
 #include <shlwapi.h>
 #include <initguid.h>
 #include <wincodec.h>
+#include <propsys.h>
+#include <propvarutil.h>
 
 #include "wine/unicode.h"
 #include "wine/debug.h"
@@ -97,6 +99,9 @@
 #include "wine/list.h"
 #include "wine/rbtree.h"
 
+#include <initguid.h>
+#include <propkey.h>
+
 WINE_DEFAULT_DEBUG_CHANNEL(menubuilder);
 
 #define in_desktop_dir(csidl) ((csidl)==CSIDL_DESKTOPDIRECTORY || \
@@ -1474,7 +1479,7 @@ static DWORD register_menus_entry(const char *unix_file, const char *windows_fil
 
 static BOOL write_desktop_entry(const char *unix_link, const char *location, const char *linkname,
                                 const char *path, const char *args, const char *descr,
-                                const char *workdir, const char *icon)
+                                const char *workdir, const char *icon, const char *appusermodelid)
 {
     FILE *file;
 
@@ -1498,6 +1503,8 @@ static BOOL write_desktop_entry(const char *unix_link, const char *location, con
         fprintf(file, "Path=%s\n", workdir);
     if (icon && lstrlenA(icon))
         fprintf(file, "Icon=%s\n", icon);
+    if (appusermodelid && lstrlenA(appusermodelid))
+        fprintf(file, "StartupWMClass=%s\n", appusermodelid);
 
     fclose(file);
 
@@ -1643,7 +1650,7 @@ end:
 }
 
 static BOOL write_menu_entry(const char *unix_link, const char *link, const char *path, const char *args,
-                             const char *descr, const char *workdir, const char *icon)
+                             const char *descr, const char *workdir, const char *icon, const char *appusermodelid)
 {
     const char *linkname;
     char *desktopPath = NULL;
@@ -1651,9 +1658,9 @@ static BOOL write_menu_entry(const char *unix_link, const char *link, const char
     char *filename = NULL;
     BOOL ret = TRUE;
 
-    WINE_TRACE("(%s, %s, %s, %s, %s, %s, %s)\n", wine_dbgstr_a(unix_link), wine_dbgstr_a(link),
+    WINE_TRACE("(%s, %s, %s, %s, %s, %s, %s, %s)\n", wine_dbgstr_a(unix_link), wine_dbgstr_a(link),
                wine_dbgstr_a(path), wine_dbgstr_a(args), wine_dbgstr_a(descr),
-               wine_dbgstr_a(workdir), wine_dbgstr_a(icon));
+               wine_dbgstr_a(workdir), wine_dbgstr_a(icon), wine_dbgstr_a(appusermodelid));
 
     linkname = strrchr(link, '/');
     if (linkname == NULL)
@@ -1677,7 +1684,7 @@ static BOOL write_menu_entry(const char *unix_link, const char *link, const char
         goto end;
     }
     *desktopDir = '/';
-    if (!write_desktop_entry(unix_link, desktopPath, linkname, path, args, descr, workdir, icon))
+    if (!write_desktop_entry(unix_link, desktopPath, linkname, path, args, descr, workdir, icon, appusermodelid))
     {
         WINE_WARN("couldn't make desktop entry %s\n", wine_dbgstr_a(desktopPath));
         ret = FALSE;
@@ -1756,6 +1763,45 @@ end:
     return utf8_string;
 }
 
+/* escapes strings for normal keys (i.e. everything but Exec */
+static char *escape_string(const char *source)
+{
+    char *dst = HeapAlloc(GetProcessHeap(), 0, lstrlenA(source)*2+1);
+    char *d = dst;
+    const char *s = source;
+
+    if (!dst)
+        return NULL;
+
+    for (; *s; ++s)
+    {
+        switch (*s)
+        {
+            case '\r':
+                *d++ = '\\';
+                *d++ = 'r';
+                break;
+            case '\n':
+                *d++ = '\\';
+                *d++ = 'n';
+                break;
+            case '\t':
+                *d++ = '\\';
+                *d++ = 't';
+                break;
+            case '\\':
+                *d++ = '\\';
+                *d++ = '\\';
+                break;
+            default:
+                *d++ = *s;
+        }
+    }
+    *d = 0;
+
+    return dst;
+}
+
 /* Return a heap-allocated copy of the unix format difference between the two
  * Windows-format paths.
  * locn is the owning location
@@ -2811,6 +2857,58 @@ static char* escape_unix_link_arg(LPCSTR unix_link)
     return ret;
 }
 
+static char *get_appusermodel_id( IShellLinkW *link )
+{
+    char *id = NULL;
+    IPropertyStore *store = NULL;
+    WCHAR buffer[MAX_PATH];
+    HRESULT hr;
+
+    /* search an explicit id */
+    hr = IShellLinkW_QueryInterface(link, &IID_IPropertyStore, (void**)&store);
+    if (SUCCEEDED(hr))
+    {
+        PROPVARIANT v;
+        PropVariantInit(&v);
+
+        hr = IPropertyStore_GetValue(store, &PKEY_AppUserModel_ID, &v);
+        if (SUCCEEDED(hr) && v.vt == VT_LPWSTR)
+        {
+            DWORD u8len = WideCharToMultiByte(CP_UTF8, 0, v.u.pwszVal, -1, NULL, 0, NULL, NULL);
+            if (u8len && (id = HeapAlloc(GetProcessHeap(), 0, u8len)))
+            {
+                WideCharToMultiByte(CP_UTF8, 0, v.u.pwszVal, -1, id, u8len, NULL, NULL);
+            }
+        }
+
+        PropVariantClear(&v);
+        IPropertyStore_Release(store);
+    }
+
+    /* use the link target */
+    if (!id)
+    {
+        hr = IShellLinkW_GetPath(link, buffer, MAX_PATH, NULL, 0);
+        if (SUCCEEDED(hr))
+        {
+            DWORD u8len = WideCharToMultiByte(CP_UTF8, 0, buffer, -1, NULL, 0, NULL, NULL);
+            if (u8len && (id = HeapAlloc(GetProcessHeap(), 0, u8len)))
+            {
+                WideCharToMultiByte(CP_UTF8, 0, buffer, -1, id, u8len, NULL, NULL);
+            }
+        }
+    }
+
+    if (id)
+    {
+        char *tmp = escape_string(id);
+        HeapFree(GetProcessHeap(), 0, id);
+        return tmp;
+    }
+
+    return NULL;
+}
+
 static BOOL InvokeShellLinker( IShellLinkW *sl, LPCWSTR link, BOOL bWait )
 {
     static const WCHAR startW[] = {'\\','c','o','m','m','a','n','d',
@@ -2825,6 +2923,7 @@ static BOOL InvokeShellLinker( IShellLinkW *sl, LPCWSTR link, BOOL bWait )
     HANDLE hsem = NULL;
     char *unix_link = NULL;
     char *start_path = NULL;
+    char *appusermodelid = NULL;
 
     if ( !link )
     {
@@ -2864,6 +2963,9 @@ static BOOL InvokeShellLinker( IShellLinkW *sl, LPCWSTR link, BOOL bWait )
     ExpandEnvironmentStringsW(szTmp, szIconPath, MAX_PATH);
     WINE_TRACE("icon file  : %s\n", wine_dbgstr_w(szIconPath) );
 
+    appusermodelid = get_appusermodel_id( sl );
+    WINE_TRACE("AppUserModelID : %s\n", wine_dbgstr_a(appusermodelid));
+
     if( !szPath[0] )
     {
         LPITEMIDLIST pidl = NULL;
@@ -2982,12 +3084,12 @@ static BOOL InvokeShellLinker( IShellLinkW *sl, LPCWSTR link, BOOL bWait )
                 if (link_arg)
                 {
                     r = !write_desktop_entry(unix_link, location, lastEntry,
-                        start_path, link_arg, description, work_dir, icon_name);
+                        start_path, link_arg, description, work_dir, icon_name, appusermodelid);
                     HeapFree(GetProcessHeap(), 0, link_arg);
                 }
             }
             else
-                r = !write_desktop_entry(NULL, location, lastEntry, escaped_path, escaped_args, description, work_dir, icon_name);
+                r = !write_desktop_entry(NULL, location, lastEntry, escaped_path, escaped_args, description, work_dir, icon_name, appusermodelid);
             if (r == 0)
                 chmod(location, 0755);
             HeapFree(GetProcessHeap(), 0, location);
@@ -2998,7 +3100,7 @@ static BOOL InvokeShellLinker( IShellLinkW *sl, LPCWSTR link, BOOL bWait )
         char *link_arg = escape_unix_link_arg(unix_link);
         if (link_arg)
         {
-            r = !write_menu_entry(unix_link, link_name, start_path, link_arg, description, work_dir, icon_name);
+            r = !write_menu_entry(unix_link, link_name, start_path, link_arg, description, work_dir, icon_name, appusermodelid);
             HeapFree(GetProcessHeap(), 0, link_arg);
         }
     }
@@ -3015,6 +3117,7 @@ cleanup:
     HeapFree( GetProcessHeap(), 0, description );
     HeapFree( GetProcessHeap(), 0, unix_link );
     HeapFree( GetProcessHeap(), 0, start_path );
+    HeapFree( GetProcessHeap(), 0, appusermodelid );
 
     if (r && !bWait)
         WINE_ERR("failed to build the menu\n" );
@@ -3148,14 +3251,14 @@ static BOOL InvokeShellLinkerForURL( IUniformResourceLocatorW *url, LPCWSTR link
         location = heap_printf("%s/%s.desktop", xdg_desktop_dir, lastEntry);
         if (location)
         {
-            r = !write_desktop_entry(NULL, location, lastEntry, start_path, escaped_urlPath, NULL, NULL, icon_name);
+            r = !write_desktop_entry(NULL, location, lastEntry, start_path, escaped_urlPath, NULL, NULL, icon_name, NULL);
             if (r == 0)
                 chmod(location, 0755);
             HeapFree(GetProcessHeap(), 0, location);
         }
     }
     else
-        r = !write_menu_entry(unix_link, link_name, start_path, escaped_urlPath, NULL, NULL, icon_name);
+        r = !write_menu_entry(unix_link, link_name, start_path, escaped_urlPath, NULL, NULL, icon_name, NULL);
     ret = (r == 0);
     ReleaseSemaphore(hSem, 1, NULL);
 
-- 
2.4.3




More information about the wine-devel mailing list