shell32: Fix computation of default verb

Francois Gouget fgouget at codeweavers.com
Fri Jun 23 11:32:38 CDT 2006


Changelog:
  * dlls/shell32/classes.c
    dlls/shell32/shell32_main.h
    dlls/shell32/shlexec.c

    Francois Gouget <fgouget at codeweavers.com>
    Compute the default verb as documented on MSDN instead of blindly 
assuming it is 'open'. This fixes the WordViewer association in some cases.

-- 
Francois Gouget
fgouget at codeweavers.com

-------------- next part --------------
Index: dlls/shell32/classes.c
===================================================================
RCS file: /home/wine/wine/dlls/shell32/classes.c,v
retrieving revision 1.45
diff -u -p -r1.45 classes.c
--- dlls/shell32/classes.c	23 May 2006 12:48:39 -0000	1.45
+++ dlls/shell32/classes.c	23 Jun 2006 15:56:06 -0000
@@ -117,30 +117,86 @@ BOOL HCR_MapTypeToValueA(LPCSTR szExtens
 	return TRUE;
 }
 
+static const WCHAR swShell[] = {'s','h','e','l','l','\\',0};
+static const WCHAR swOpen[] = {'o','p','e','n',0};
+static const WCHAR swCommand[] = {'\\','c','o','m','m','a','n','d',0};
+
+BOOL HCR_GetDefaultVerbW( HKEY hkeyClass, LPCWSTR szVerb, LPWSTR szDest, DWORD len )
+{
+        WCHAR sTemp[MAX_PATH];
+        LONG size;
+        HKEY hkey;
+
+	TRACE("%p %s %p\n", hkeyClass, debugstr_w(szVerb), szDest);
+
+        if (szVerb)
+        {
+            lstrcpynW(szDest, szVerb, len);
+            return TRUE;
+        }
+
+        size=len;
+        *szDest='\0';
+        if (!RegQueryValueW(hkeyClass, swShell, szDest, &size) && *szDest)
+        {
+            /* The MSDN says to first try the default verb */
+            lstrcpyW(sTemp, swShell);
+            lstrcatW(sTemp, szDest);
+            lstrcatW(sTemp, swCommand);
+            if (!RegOpenKeyExW(hkeyClass, sTemp, 0, 0, &hkey))
+            {
+                RegCloseKey(hkey);
+                TRACE("default verb=%s\n", debugstr_w(szDest));
+                return TRUE;
+            }
+        }
+
+        /* then fallback to 'open' */
+        lstrcpyW(sTemp, swShell);
+        lstrcatW(sTemp, swOpen);
+        lstrcatW(sTemp, swCommand);
+        if (!RegOpenKeyExW(hkeyClass, sTemp, 0, 0, &hkey))
+        {
+            RegCloseKey(hkey);
+            lstrcpynW(szDest, swOpen, len);
+            TRACE("default verb=open\n");
+            return TRUE;
+        }
+
+        /* and then just use the first verb on Windows >= 2000 */
+        if (!RegEnumKeyW(hkeyClass, 0, szDest, len) && *szDest)
+        {
+            TRACE("default verb=first verb=%s\n", debugstr_w(szDest));
+            return TRUE;
+        }
+
+        TRACE("no default verb!\n");
+	return FALSE;
+}
 
 BOOL HCR_GetExecuteCommandW( HKEY hkeyClass, LPCWSTR szClass, LPCWSTR szVerb, LPWSTR szDest, DWORD len )
 {
-        static const WCHAR swShell[] = {'s','h','e','l','l','\\',0};
-        static const WCHAR swCommand[] = {'\\','c','o','m','m','a','n','d',0};
-	BOOL	ret = FALSE;
+	WCHAR sTempVerb[MAX_PATH];
+	BOOL ret;
 
 	TRACE("%p %s %s %p\n", hkeyClass, debugstr_w(szClass), debugstr_w(szVerb), szDest);
 
 	if (szClass)
             RegOpenKeyExW(HKEY_CLASSES_ROOT, szClass, 0, 0x02000000, &hkeyClass);
+        if (!hkeyClass)
+            return FALSE;
+        ret = FALSE;
 
-        if (hkeyClass)
-	{
-	    WCHAR sTemp[MAX_PATH];
-	    lstrcpyW(sTemp, swShell);
-	    lstrcatW(sTemp, szVerb);
-	    lstrcatW(sTemp, swCommand);
-
-	    ret = (ERROR_SUCCESS == SHGetValueW(hkeyClass, sTemp, NULL, NULL, szDest, &len));
-
-	    if (szClass)
-	       RegCloseKey(hkeyClass);
-	}
+        if (HCR_GetDefaultVerbW(hkeyClass, szVerb, sTempVerb, sizeof(sTempVerb)))
+        {
+            WCHAR sTemp[MAX_PATH];
+            lstrcpyW(sTemp, swShell);
+            lstrcatW(sTemp, sTempVerb);
+            lstrcatW(sTemp, swCommand);
+            ret = (ERROR_SUCCESS == SHGetValueW(hkeyClass, sTemp, NULL, NULL, szDest, &len));
+        }
+        if (szClass)
+            RegCloseKey(hkeyClass);
 
 	TRACE("-- %s\n", debugstr_w(szDest) );
 	return ret;
Index: dlls/shell32/shell32_main.h
===================================================================
RCS file: /home/wine/wine/dlls/shell32/shell32_main.h,v
retrieving revision 1.116
diff -u -p -r1.116 shell32_main.h
--- dlls/shell32/shell32_main.h	20 Jun 2006 10:25:22 -0000	1.116
+++ dlls/shell32/shell32_main.h	23 Jun 2006 15:56:06 -0000
@@ -57,6 +57,7 @@ INT SIC_GetIconIndex (LPCWSTR sSourceFil
 
 /* Classes Root */
 BOOL HCR_MapTypeToValueW(LPCWSTR szExtension, LPWSTR szFileType, LONG len, BOOL bPrependDot);
+BOOL HCR_GetDefaultVerbW( HKEY hkeyClass, LPCWSTR szVerb, LPWSTR szDest, DWORD len );
 BOOL HCR_GetExecuteCommandW( HKEY hkeyClass, LPCWSTR szClass, LPCWSTR szVerb, LPWSTR szDest, DWORD len );
 BOOL HCR_GetDefaultIconW(LPCWSTR szClass, LPWSTR szDest, DWORD len, int* picon_idx);
 BOOL HCR_GetDefaultIconFromGUIDW(REFIID riid, LPWSTR szDest, DWORD len, int* picon_idx);
Index: dlls/shell32/shlexec.c
===================================================================
RCS file: /home/wine/wine/dlls/shell32/shlexec.c,v
retrieving revision 1.86
diff -u -p -r1.86 shlexec.c
--- dlls/shell32/shlexec.c	16 Jun 2006 13:20:15 -0000	1.86
+++ dlls/shell32/shlexec.c	23 Jun 2006 16:07:19 -0000
@@ -426,10 +426,18 @@ end:
 static UINT SHELL_FindExecutableByOperation(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOperation, LPWSTR key, LPWSTR filetype, LPWSTR command, LONG commandlen)
 {
     static const WCHAR wCommand[] = {'\\','c','o','m','m','a','n','d',0};
+    HKEY hkeyClass;
+    WCHAR verb[MAX_PATH];
+
+    if (RegOpenKeyExW(HKEY_CLASSES_ROOT, filetype, 0, 0x02000000, &hkeyClass))
+        return 31; /* default - 'No association was found' */
+    if (!HCR_GetDefaultVerbW(hkeyClass, lpOperation, verb, sizeof(verb)))
+        return 31; /* default - 'No association was found' */
+    RegCloseKey(hkeyClass);
 
     /* Looking for ...buffer\shell\<verb>\command */
     strcatW(filetype, wszShell);
-    strcatW(filetype, lpOperation);
+    strcatW(filetype, verb);
     strcatW(filetype, wCommand);
 
     if (RegQueryValueW(HKEY_CLASSES_ROOT, filetype, command,
@@ -508,10 +516,10 @@ UINT SHELL_FindExecutable(LPCWSTR lpPath
     if (key) *key = '\0';
 
     /* trap NULL parameters on entry */
-    if ((lpFile == NULL) || (lpResult == NULL) || (lpOperation == NULL))
+    if ((lpFile == NULL) || (lpResult == NULL))
     {
-        WARN("(lpFile=%s,lpResult=%s,lpOperation=%s): NULL parameter\n",
-             debugstr_w(lpFile), debugstr_w(lpOperation), debugstr_w(lpResult));
+        WARN("(lpFile=%s,lpResult=%s): NULL parameter\n",
+             debugstr_w(lpFile), debugstr_w(lpResult));
         return 2; /* File not found. Close enough, I guess. */
     }
 
@@ -1292,7 +1309,7 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW 
         ULONG cmask=(sei_tmp.fMask & SEE_MASK_CLASSALL);
         HCR_GetExecuteCommandW((cmask == SEE_MASK_CLASSKEY) ? sei_tmp.hkeyClass : NULL,
                                (cmask == SEE_MASK_CLASSNAME) ? sei_tmp.lpClass: NULL,
-                               (sei_tmp.lpVerb) ? sei_tmp.lpVerb : wszOpen,
+                               sei_tmp.lpVerb,
                                wszParameters, sizeof(wszParameters)/sizeof(WCHAR));
 
         /* FIXME: get the extension of lpFile, check if it fits to the lpClass */
@@ -1332,7 +1351,7 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW 
 		if (attribs != INVALID_FILE_ATTRIBUTES &&
 		    (attribs & FILE_ATTRIBUTE_DIRECTORY) &&
 		    HCR_GetExecuteCommandW(0, wszFolder,
-		                           sei_tmp.lpVerb?sei_tmp.lpVerb:wszOpen,
+		                           sei_tmp.lpVerb,
 		                           buffer, sizeof(buffer))) {
 		    SHELL_ArgifyW(wszApplicationName, dwApplicationNameLen,
 		                  buffer, target, sei_tmp.lpIDList, NULL);
@@ -1427,11 +1446,6 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW 
         strcatW(wcmd, wszParameters);
     }
 
-    /* We set the default to open, and that should generally work.
-       But that is not really the way the MS docs say to do it. */
-    if (!sei_tmp.lpVerb)
-        sei_tmp.lpVerb = wszOpen;
-
     retval = execfunc(wcmd, NULL, FALSE, &sei_tmp, sei);
     if (retval > 32) {
         HeapFree(GetProcessHeap(), 0, wszApplicationName);


More information about the wine-patches mailing list