Implement missing App Paths search in ShellExecute

Dan Kegel dank at kegel.com
Sun Dec 29 16:58:08 CST 2002


With this patch applied, if you have wordpad.exe installed properly,
msvc4.0's setup.exe's "Standard Template Library"
button will properly start up wordpad.  (That is, if
you switch current drive and directory to the CD-ROM first.
Still fails if you don't, but that's another bug.
And the document still looks wrong, but that's yet another bug...)

Changelog:
	* shell32/shlexec.c: ShellExecute(NULL, "wordpad.exe",) now
           correctly finds wordpad.exe in App Paths

Copyright 2002, dank at kegel.com.  LGPL.

-- 
Dan Kegel
Linux User #78045
http://www.kegel.com
-------------- next part --------------
Index: dlls/shell32/shlexec.c
===================================================================
RCS file: /home/wine/wine/dlls/shell32/shlexec.c,v
retrieving revision 1.15
diff -d -u -r1.15 shlexec.c
--- dlls/shell32/shlexec.c	16 Dec 2002 22:40:34 -0000	1.15
+++ dlls/shell32/shlexec.c	29 Dec 2002 22:37:16 -0000
@@ -145,6 +145,43 @@
     return retval;
 }
 
+/***********************************************************************
+ *           SHELL_TryAppPath
+ *
+ * Helper function for SHELL_FindExecutable
+ * @param lpResult - pointer to a buffer of size MAX_PATH
+ * On entry: szName is a filename (probably without path separators).
+ * On exit: if szName found in "App Path", place full path in lpResult, and return true
+ */
+static BOOL SHELL_TryAppPath( LPCSTR szName, LPSTR lpResult)
+{
+    HKEY hkApp = 0;
+    char szAppKey[256];
+    LONG len;
+    LONG res; 
+    BOOL found = FALSE;
+
+    sprintf(szAppKey, "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\%s", szName);
+    res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, szAppKey, 0, KEY_READ, &hkApp);
+    if (res) {
+        /*TRACE("RegOpenKeyExA(HKEY_LOCAL_MACHINE, %s,) returns %ld\n", szAppKey, res);*/
+        goto end;
+    }
+
+    len = MAX_PATH;
+    res = RegQueryValueA(hkApp, NULL, lpResult, &len);
+    if (res) {
+        /*TRACE("RegQueryValueA(hkApp, NULL,) returns %ld\n", res);*/
+        goto end;
+    }
+    /*TRACE("%s -> %s\n", szName, lpResult);*/
+    found = TRUE;
+
+end:
+    if (hkApp) RegCloseKey(hkApp);
+    return found;
+}
+
 /*************************************************************************
  *	SHELL_FindExecutable [Internal]
  *
@@ -176,6 +213,7 @@
     TRACE("%s\n", (lpFile != NULL) ? lpFile : "-");
 
     lpResult[0] = '\0'; /* Start off with an empty return string */
+    if (key) *key = '\0';
 
     /* trap NULL parameters on entry */
     if ((lpFile == NULL) || (lpResult == NULL) || (lpOperation == NULL))
@@ -185,10 +223,17 @@
         return 2; /* File not found. Close enough, I guess. */
     }
 
+    if (SHELL_TryAppPath( lpFile, lpResult ))
+    {
+        TRACE("found %s via App Paths\n", lpResult);
+        return 33;
+    }
+
     if (SearchPathA(lpPath, lpFile, ".exe", sizeof(xlpFile), xlpFile, NULL))
     {
         TRACE("SearchPathA returned non-zero\n");
         lpFile = xlpFile;
+        /* Hey, isn't this value ignored?  Why make this call?  Shouldn't we return here?  --dank*/
     }
 
     /* First thing we need is the file's extension */
@@ -216,8 +261,6 @@
     /* extensions; however, it'd make sense to check the programs */
     /* section first, so that's what happens here. */
 
-    if (key) *key = '\0';
-
     /* See if it's a program - if GetProfileString fails, we skip this
      * section. Actually, if GetProfileString fails, we've probably
      * got a lot more to worry about than running a program... */
@@ -614,15 +657,19 @@
     retval = SHELL_FindExecutable(sei->lpDirectory, lpFile, lpOperation, cmd, lpstrProtocol);
     if (retval > 32)  /* Found */
     {
-        if (szCommandline[0]) {
-            strcat(cmd, " ");
-            strcat(cmd, szCommandline);
-        }
-        TRACE("%s/%s => %s/%s\n", szApplicationName, lpOperation, cmd, lpstrProtocol);
+        CHAR szQuotedCmd[MAX_PATH+2];
+        /* Must quote to handle case where cmd contains spaces, 
+         * else security hole if malicious user creates executable file "C:\\Program"
+         */
+        if (szCommandline[0])
+            sprintf(szQuotedCmd, "\"%s\" %s", cmd, szCommandline);
+        else
+            sprintf(szQuotedCmd, "\"%s\"", cmd);
+        TRACE("%s/%s => %s/%s\n", szApplicationName, lpOperation, szQuotedCmd, lpstrProtocol);
         if (*lpstrProtocol)
             retval = execute_from_key(lpstrProtocol, szApplicationName, sei, execfunc);
         else
-            retval = execfunc(cmd, sei, FALSE);
+            retval = execfunc(szQuotedCmd, sei, FALSE);
     }
     else if (PathIsURLA((LPSTR)lpFile))    /* File not found, check for URL */
     {


More information about the wine-patches mailing list