ShellExecute again

Duane Clark dclark at akamail.com
Mon Jul 22 22:28:16 CDT 2002


Here is a much improved version (I hope), in case anyone wants to 
comment on it. I did a lot more testing this time, mainly by writing a 
test program where I tried as many combinations as I could think of. 
Tested on WinNT and wine using Word2000, WordPad and wine's notepad. 
Things tested:
  ShellExecute
  ShellExecuteEx with
   SEE_MASK_CLASSNAME with several combinations of fixed and replaced 
parameters
   supplying lpDirectory
   supplying both lpFile and lpParameters
   supplying only lpFile and getting the registry command from the file 
extension. Also tested with the pkzip installer, which uses this method 
to invoke MSI.
   testing of both open and print commands

Some things not yet tested.
   SEE_MASK_IDLIST and SEE_MASK_INVOKEIDLIST, since I have not figured 
out how these IDLists work yet (I don't know how to put that in my test 
program).
   The URL handling, since ..mumble.. I can't install either IE or 
Mozilla in Wine. Same problem as Boris Reisig mentioned a few days ago...

I also plan to try to copy the WinExec16 stuff over, but that is not in 
here yet.


-------------- next part --------------
Index: dlls/shell32/shellord.c
===================================================================
RCS file: /home/wine/wine/dlls/shell32/shellord.c,v
retrieving revision 1.99
diff -u -r1.99 shellord.c
--- dlls/shell32/shellord.c	3 Jul 2002 21:07:36 -0000	1.99
+++ dlls/shell32/shellord.c	23 Jul 2002 02:29:56 -0000
@@ -926,192 +926,6 @@
 {	FIXME("0x%08lx 0x%08lx stub\n",x,z);
 	return 0;
 }
-/*************************************************************************
- * ShellExecuteEx				[SHELL32.291]
- *
- */
-BOOL WINAPI ShellExecuteExAW (LPVOID sei)
-{	if (SHELL_OsIsUnicode())
-	  return ShellExecuteExW (sei);
-	return ShellExecuteExA (sei);
-}
-/*************************************************************************
- * ShellExecuteExA				[SHELL32.292]
- *
- * placeholder in the commandline:
- *	%1 file
- *	%2 printer
- *	%3 driver
- *	%4 port
- *	%I adress of a global item ID (explorer switch /idlist)
- *	%L ??? path/url/current file ???
- *	%S ???
- *	%* all following parameters (see batfile)
- */
-BOOL WINAPI ShellExecuteExA (LPSHELLEXECUTEINFOA sei)
-{ 	CHAR szApplicationName[MAX_PATH],szCommandline[MAX_PATH],szPidl[20];
-	LPSTR pos;
-	int gap, len;
-	STARTUPINFOA  startup;
-	PROCESS_INFORMATION info;
-
-	WARN("mask=0x%08lx hwnd=0x%04x verb=%s file=%s parm=%s dir=%s show=0x%08x class=%s incomplete\n",
-	     sei->fMask, sei->hwnd, debugstr_a(sei->lpVerb),
-	     debugstr_a(sei->lpFile), debugstr_a(sei->lpParameters),
-	     debugstr_a(sei->lpDirectory), sei->nShow,
-	     (sei->fMask & SEE_MASK_CLASSNAME) ? debugstr_a(sei->lpClass) : "not used");
-
-	ZeroMemory(szApplicationName,MAX_PATH);
-	if (sei->lpFile)
-	  strcpy(szApplicationName, sei->lpFile);
-
-	ZeroMemory(szCommandline,MAX_PATH);
-	if (sei->lpParameters)
-	  strcpy(szCommandline, sei->lpParameters);
-
-	if (sei->fMask & (SEE_MASK_CLASSKEY | SEE_MASK_INVOKEIDLIST | SEE_MASK_ICON | SEE_MASK_HOTKEY |
-			  SEE_MASK_CONNECTNETDRV | SEE_MASK_FLAG_DDEWAIT |
-			  SEE_MASK_DOENVSUBST | SEE_MASK_FLAG_NO_UI | SEE_MASK_UNICODE |
-			  SEE_MASK_NO_CONSOLE | SEE_MASK_ASYNCOK | SEE_MASK_HMONITOR ))
-	{
-	  FIXME("flags ignored: 0x%08lx\n", sei->fMask);
-	}
-
-	/* launch a document by fileclass like 'Wordpad.Document.1' */
-	if (sei->fMask & SEE_MASK_CLASSNAME)
-	{
-	  /* FIXME: szCommandline should not be of a fixed size. Plus MAX_PATH is way too short! */
-	  /* the commandline contains 'c:\Path\wordpad.exe "%1"' */
-	  HCR_GetExecuteCommand(sei->lpClass, (sei->lpVerb) ? sei->lpVerb : "open", szCommandline, sizeof(szCommandline));
-	  /* FIXME: get the extension of lpFile, check if it fits to the lpClass */
-	  TRACE("SEE_MASK_CLASSNAME->'%s'\n", szCommandline);
-	}
-
-	/* process the IDList */
-	if ( (sei->fMask & SEE_MASK_INVOKEIDLIST) == SEE_MASK_INVOKEIDLIST) /*0x0c*/
-	{
-	  SHGetPathFromIDListA (sei->lpIDList,szApplicationName);
-	  TRACE("-- idlist=%p (%s)\n", sei->lpIDList, szApplicationName);
-	}
-	else
-	{
-	  if (sei->fMask & SEE_MASK_IDLIST )
-	  {
-	    pos = strstr(szCommandline, "%I");
-	    if (pos)
-	    {
-	      LPVOID pv;
-	      HGLOBAL hmem = SHAllocShared ( sei->lpIDList, ILGetSize(sei->lpIDList), 0);
-	      pv = SHLockShared(hmem,0);
-	      sprintf(szPidl,":%p",pv );
-	      SHUnlockShared(pv);
-
-	      gap = strlen(szPidl);
-	      len = strlen(pos)-2;
-	      memmove(pos+gap,pos+2,len);
-	      memcpy(pos,szPidl,gap);
-
-	    }
-	  }
-	}
-
-	TRACE("execute:'%s','%s'\n",szApplicationName, szCommandline);
-
-	if (szCommandline[0]) {
-	  strcat(szApplicationName, " ");
-	  strcat(szApplicationName, szCommandline);
-	}
-
-	ZeroMemory(&startup,sizeof(STARTUPINFOA));
-	startup.cb = sizeof(STARTUPINFOA);
-
-	if (! CreateProcessA(NULL, szApplicationName,
-			 NULL, NULL, FALSE, 0,
-			 NULL, sei->lpDirectory,
-			 &startup, &info))
-	{
-        BOOL failed = TRUE;
-
-        if ((!sei->lpVerb)||(!strcasecmp(sei->lpVerb,"open")))
-        {
-            LPSTR   ext = PathFindExtensionA(szApplicationName);
-            CHAR    key[1023];
-            CHAR    buffer[1023];
-            CHAR    cmdline[1023];
-            DWORD   size;
-
-            sprintf(key,"Software\\Classes\\%s",ext);
-            size = 1023;
-            if (!RegQueryValueA(HKEY_LOCAL_MACHINE,key,buffer,&size))
-            {
-                sprintf(key,"Software\\Classes\\%s\\shell\\%s\\command", buffer,
-                    (sei->lpVerb)?sei->lpVerb:"open");
-                size = 1023;
-                if (!RegQueryValueA(HKEY_LOCAL_MACHINE,key,buffer,&size))
-                {
-                    sprintf(cmdline,"%s \"%s\"",buffer,szApplicationName);
-                    if (CreateProcessA(NULL,cmdline,  NULL, NULL, FALSE, 0,
-                                   NULL, sei->lpDirectory, &startup, &info))
-                        failed = FALSE;
-                }
-            }
-        }
-
-        if (failed)
-        {
-            sei->hInstApp = GetLastError();
-            return FALSE;
-        }
-	}
-
-        sei->hInstApp = 33;
-
-	if(sei->fMask & SEE_MASK_NOCLOSEPROCESS)
-	  sei->hProcess = info.hProcess;
-        else
-          CloseHandle( info.hProcess );
-        CloseHandle( info.hThread );
-	return TRUE;
-}
-/*************************************************************************
- * ShellExecuteExW				[SHELL32.293]
- *
- */
-BOOL WINAPI ShellExecuteExW (LPSHELLEXECUTEINFOW sei)
-{	SHELLEXECUTEINFOA seiA;
-	DWORD ret;
-
-	TRACE("%p\n", sei);
-
-	memcpy(&seiA, sei, sizeof(SHELLEXECUTEINFOA));
-
-        if (sei->lpVerb)
-	  seiA.lpVerb = HEAP_strdupWtoA( GetProcessHeap(), 0, sei->lpVerb);
-
-        if (sei->lpFile)
-	  seiA.lpFile = HEAP_strdupWtoA( GetProcessHeap(), 0, sei->lpFile);
-
-        if (sei->lpParameters)
-	  seiA.lpParameters = HEAP_strdupWtoA( GetProcessHeap(), 0, sei->lpParameters);
-
-	if (sei->lpDirectory)
-	  seiA.lpDirectory = HEAP_strdupWtoA( GetProcessHeap(), 0, sei->lpDirectory);
-
-        if ((sei->fMask & SEE_MASK_CLASSNAME) && sei->lpClass)
-	  seiA.lpClass = HEAP_strdupWtoA( GetProcessHeap(), 0, sei->lpClass);
-	else
-	  seiA.lpClass = NULL;
-
-	ret = ShellExecuteExA(&seiA);
-
-        if (seiA.lpVerb)	HeapFree( GetProcessHeap(), 0, (LPSTR) seiA.lpVerb );
-	if (seiA.lpFile)	HeapFree( GetProcessHeap(), 0, (LPSTR) seiA.lpFile );
-	if (seiA.lpParameters)	HeapFree( GetProcessHeap(), 0, (LPSTR) seiA.lpParameters );
-	if (seiA.lpDirectory)	HeapFree( GetProcessHeap(), 0, (LPSTR) seiA.lpDirectory );
-	if (seiA.lpClass)	HeapFree( GetProcessHeap(), 0, (LPSTR) seiA.lpClass );
-
- 	return ret;
-}
 
 static LPUNKNOWN SHELL32_IExplorerInterface=0;
 /*************************************************************************
Index: dlls/shell32/shlexec.c
===================================================================
RCS file: /home/wine/wine/dlls/shell32/shlexec.c,v
retrieving revision 1.3
diff -u -r1.3 shlexec.c
--- dlls/shell32/shlexec.c	31 May 2002 23:25:52 -0000	1.3
+++ dlls/shell32/shlexec.c	23 Jul 2002 02:29:56 -0000
@@ -23,6 +23,7 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <stdio.h>
 #include <unistd.h>
 #include <ctype.h>
 #include <assert.h>
@@ -30,6 +31,7 @@
 #include "windef.h"
 #include "winerror.h"
 #include "winreg.h"
+#include "heap.h"
 #include "shellapi.h"
 #include "shlobj.h"
 #include "shlwapi.h"
@@ -37,6 +39,7 @@
 
 #include "wine/winbase16.h"
 #include "shell32_main.h"
+#include "undocshell.h"
 
 #include "wine/debug.h"
 
@@ -45,16 +48,19 @@
 /* this function is supposed to expand the escape sequences found in the registry
  * some diving reported that the following were used:
  * + %1, %2...  seem to report to parameter of index N in ShellExecute pmts
- + + %*         seem to report to all parameter (or all remaining, ie after removing
- *              the already used %1 %2...)
- * + %L         seems to be %1 as long filename followed by the 8+3 variation
- * + %l         unknown
- * + %S         unknown
- * + %I         unknown
+ *	%1 file
+ *	%2 printer
+ *	%3 driver
+ *	%4 port
+ * %I adress of a global item ID (explorer switch /idlist)
+ * %L seems to be %1 as long filename followed by the 8+3 variation
+ * %S ???
+ * %* all following parameters (see batfile)
  */
-static void argify(char* res, int len, const char* fmt, const char* lpFile)
+static BOOL argify(char* res, int len, const char* fmt, const char* lpFile)
 {
     char        xlpFile[1024];
+    BOOL        done = FALSE;
 
     while (*fmt)
     {
@@ -67,25 +73,71 @@
                 *res++ = '%';
                 break;
             case '1':
-                if (SearchPathA(NULL, lpFile, ".exe", sizeof(xlpFile), xlpFile, NULL))
+            case '*':
+                if (!done || (*fmt == '1'))
                 {
-                    strcpy(res, xlpFile);
-                    res += strlen(xlpFile);
-                }
-                else
-                {
-                    strcpy(res, lpFile);
-                    res += strlen(lpFile);
+                    if (SearchPathA(NULL, lpFile, ".exe", sizeof(xlpFile), xlpFile, NULL))
+                    {
+                        strcpy(res, xlpFile);
+                        res += strlen(xlpFile);
+                    }
+                    else
+                    {
+                        strcpy(res, lpFile);
+                        res += strlen(lpFile);
+                    }
                 }
                 break;
             default: FIXME("Unknown escape sequence %%%c\n", *fmt);
             }
             fmt++;
+            done = TRUE;
         }
         else
             *res++ = *fmt++;
     }
     *res = '\0';
+    return done;
+}
+
+/*************************************************************************
+ *	SHELL_ExecuteA [Internal]
+ *
+ */
+static HINSTANCE SHELL_ExecuteA(char *lpCmd, LPSHELLEXECUTEINFOA sei, BOOL is32)
+{
+    STARTUPINFOA  startup;
+    PROCESS_INFORMATION info;
+    HINSTANCE retval = 31;
+    
+    TRACE("Execute %s from directory %s\n", lpCmd, sei->lpDirectory);
+    ZeroMemory(&startup,sizeof(STARTUPINFOA));
+    startup.cb = sizeof(STARTUPINFOA);
+    startup.dwFlags = STARTF_USESHOWWINDOW;
+    startup.wShowWindow = sei->nShow;
+    if (is32)
+    {
+        if (CreateProcessA(NULL, lpCmd, NULL, NULL, FALSE, 0,
+                        NULL, sei->lpDirectory, &startup, &info))
+        {
+            retval = (HINSTANCE)33;
+            if(sei->fMask & SEE_MASK_NOCLOSEPROCESS)
+	        sei->hProcess = info.hProcess;
+            else
+                CloseHandle( info.hProcess );
+            CloseHandle( info.hThread );
+        }
+        else if ((retval = GetLastError()) >= (HINSTANCE)32)
+        {
+            FIXME("Strange error set by CreateProcess: %d\n", retval);
+            retval = (HINSTANCE)ERROR_BAD_FORMAT;
+        }
+    }
+    else
+        retval = WinExec16(lpCmd, sei->nShow);
+    
+    sei->hInstApp = retval;
+    return retval;
 }
 
 /*************************************************************************
@@ -102,7 +154,7 @@
  *              command (it'll be used afterwards for more information
  *              on the operation)
  */
-static HINSTANCE SHELL_FindExecutable(LPCSTR lpFile, LPCSTR lpOperation,
+static HINSTANCE SHELL_FindExecutable(LPCSTR lpPath, LPCSTR lpFile, LPCSTR lpOperation,
                                       LPSTR lpResult, LPSTR key)
 {
     char *extension = NULL; /* pointer to file extension */
@@ -129,7 +181,7 @@
         return 2; /* File not found. Close enough, I guess. */
     }
 
-    if (SearchPathA(NULL, lpFile, ".exe", sizeof(xlpFile), xlpFile, NULL))
+    if (SearchPathA(lpPath, lpFile, ".exe", sizeof(xlpFile), xlpFile, NULL))
     {
         TRACE("SearchPathA returned non-zero\n");
         lpFile = xlpFile;
@@ -287,7 +339,7 @@
  */
 static unsigned dde_connect(char* key, char* start, char* ddeexec,
                             const char* lpFile,
-                            int iCmdShow, BOOL is32)
+                            LPSHELLEXECUTEINFOA sei, BOOL is32)
 {
     char*       endkey = key + strlen(key);
     char        app[256], topic[256], ifexec[256], res[256];
@@ -327,7 +379,7 @@
     if (!hConv)
     {
         TRACE("Launching '%s'\n", start);
-        ret = (is32) ? WinExec(start, iCmdShow) : WinExec16(start, iCmdShow);
+        ret = SHELL_ExecuteA(start, sei, is32);
         if (ret < 32)
         {
             TRACE("Couldn't launch\n");
@@ -358,7 +410,10 @@
     return ret;
 }
 
-static HINSTANCE execute_from_key(LPSTR key, LPCSTR lpFile, INT iShowCmd, BOOL is32)
+/*************************************************************************
+ *	execute_from_key [Internal]
+ */
+static HINSTANCE execute_from_key(LPSTR key, LPCSTR lpFile, LPSHELLEXECUTEINFOA sei, BOOL is32)
 {
     char cmd[1024] = "";
     LONG cmdlen = sizeof(cmd);
@@ -380,15 +435,14 @@
         if (RegQueryValueA(HKEY_CLASSES_ROOT, key, param, &paramlen) == ERROR_SUCCESS)
         {
             TRACE("Got ddeexec %s => %s\n", key, param);
-            retval = dde_connect(key, cmd, param, lpFile, iShowCmd, is32);
+            retval = dde_connect(key, cmd, param, lpFile, sei, is32);
         }
         else
         {
             /* Is there a replace() function anywhere? */
             cmd[cmdlen] = '\0';
             argify(param, sizeof(param), cmd, lpFile);
-
-            retval = (is32) ? WinExec(param, iShowCmd) : WinExec16(param, iShowCmd);
+            retval = SHELL_ExecuteA(param, sei, is32);
         }
     }
     else TRACE("ooch\n");
@@ -396,96 +450,6 @@
     return retval;
 }
 
-static HINSTANCE SHELL_Execute(HWND hWnd, LPCSTR lpOperation, LPCSTR lpFile,
-                               LPCSTR lpParameters, LPCSTR lpDirectory,
-                               INT iShowCmd, BOOL is32)
-{
-    HINSTANCE retval = 31;
-    char old_dir[1024];
-    char cmd[1024];
-
-    TRACE("(%04x,'%s','%s','%s','%s',%x)\n",
-          hWnd, lpOperation ? lpOperation:"<null>", lpFile ? lpFile:"<null>",
-          lpParameters ? lpParameters : "<null>",
-          lpDirectory ? lpDirectory : "<null>", iShowCmd);
-
-    if (lpFile == NULL) return 0; /* should not happen */
-    if (lpOperation == NULL) /* default is open */
-        lpOperation = "open";
-
-    if (lpDirectory)
-    {
-        GetCurrentDirectoryA(sizeof(old_dir), old_dir);
-        SetCurrentDirectoryA(lpDirectory);
-    }
-
-    /* First try to execute lpFile with lpParameters directly */
-    strcpy(cmd, lpFile);
-    if (lpParameters)
-    {
-        strcat(cmd, " ");
-        strcat(cmd, lpParameters);
-    }
-
-    retval = (is32) ? WinExec(cmd, iShowCmd) : WinExec16(cmd, iShowCmd);
-
-    /* Unable to execute lpFile directly
-       Check if we can match an application to lpFile */
-    if (retval < 32)
-    {
-        char lpstrProtocol[256];
-
-        cmd[0] = '\0';
-        retval = SHELL_FindExecutable(lpFile, lpOperation, cmd, lpstrProtocol);
-
-        if (retval > 32)  /* Found */
-        {
-            TRACE("%s/%s => %s/%s\n", lpFile, lpOperation, cmd, lpstrProtocol);
-            if (*lpstrProtocol)
-                retval = execute_from_key(lpstrProtocol, lpFile, iShowCmd, is32);
-            else
-                retval = (is32) ? WinExec(cmd, iShowCmd) : WinExec16(cmd, iShowCmd);
-        }
-        else if (PathIsURLA((LPSTR)lpFile))    /* File not found, check for URL */
-        {
-            LPSTR lpstrRes;
-            INT iSize;
-
-            lpstrRes = strchr(lpFile, ':');
-            iSize = lpstrRes - lpFile;
-
-            TRACE("Got URL: %s\n", lpFile);
-            /* Looking for ...protocol\shell\lpOperation\command */
-            strncpy(lpstrProtocol, lpFile, iSize);
-            lpstrProtocol[iSize] = '\0';
-            strcat(lpstrProtocol, "\\shell\\");
-            strcat(lpstrProtocol, lpOperation);
-            strcat(lpstrProtocol, "\\command");
-
-            /* Remove File Protocol from lpFile */
-            /* In the case file://path/file     */
-            if (!strncasecmp(lpFile, "file", iSize))
-            {
-                lpFile += iSize;
-                while (*lpFile == ':') lpFile++;
-            }
-
-            retval = execute_from_key(lpstrProtocol, lpFile, iShowCmd, is32);
-        }
-        /* Check if file specified is in the form www.??????.*** */
-        else if (!strncasecmp(lpFile, "www", 3))
-        {
-            /* if so, append lpFile http:// and call ShellExecute */
-            char lpstrTmpFile[256] = "http://" ;
-            strcat(lpstrTmpFile, lpFile);
-            retval = ShellExecuteA(hWnd, lpOperation, lpstrTmpFile, NULL, NULL, 0);
-        }
-    }
-    if (lpDirectory)
-        SetCurrentDirectoryA(old_dir);
-    return retval;
-}
-
 /*************************************************************************
  * FindExecutableA			[SHELL32.@]
  */
@@ -512,7 +476,7 @@
         SetCurrentDirectoryA(lpDirectory);
     }
 
-    retval = SHELL_FindExecutable(lpFile, "open", lpResult, NULL);
+    retval = SHELL_FindExecutable(lpDirectory, lpFile, "open", lpResult, NULL);
 
     TRACE("returning %s\n", lpResult);
     if (lpDirectory)
@@ -530,14 +494,204 @@
 }
 
 /*************************************************************************
+ *	ShellExecuteExA32 [Internal]
+ */
+BOOL WINAPI ShellExecuteExA32 (LPSHELLEXECUTEINFOA sei, BOOL is32)
+{
+    CHAR szApplicationName[MAX_PATH],szCommandline[MAX_PATH],szPidl[20],fileName[MAX_PATH];
+    LPSTR pos;
+    int gap, len;
+    char lpstrProtocol[256];
+    LPCSTR lpFile,lpOperation;
+    HINSTANCE retval = 31;
+    char cmd[1024];
+    BOOL done;
+
+    TRACE("mask=0x%08lx hwnd=0x%04x verb=%s file=%s parm=%s dir=%s show=0x%08x class=%s\n",
+            sei->fMask, sei->hwnd, debugstr_a(sei->lpVerb),
+            debugstr_a(sei->lpFile), debugstr_a(sei->lpParameters),
+            debugstr_a(sei->lpDirectory), sei->nShow,
+            (sei->fMask & SEE_MASK_CLASSNAME) ? debugstr_a(sei->lpClass) : "not used");
+    
+    sei->hProcess = (HANDLE)NULL;
+    ZeroMemory(szApplicationName,MAX_PATH);
+    if (sei->lpFile)
+        strcpy(szApplicationName, sei->lpFile);
+
+    ZeroMemory(szCommandline,MAX_PATH);
+    if (sei->lpParameters)
+        strcpy(szCommandline, sei->lpParameters);
+
+    if (sei->fMask & ((SEE_MASK_CLASSKEY & ~SEE_MASK_CLASSNAME) | 
+        SEE_MASK_INVOKEIDLIST | SEE_MASK_ICON | SEE_MASK_HOTKEY |
+        SEE_MASK_CONNECTNETDRV | SEE_MASK_FLAG_DDEWAIT |
+        SEE_MASK_DOENVSUBST | SEE_MASK_FLAG_NO_UI | SEE_MASK_UNICODE |
+        SEE_MASK_NO_CONSOLE | SEE_MASK_ASYNCOK | SEE_MASK_HMONITOR ))
+    {
+        FIXME("flags ignored: 0x%08lx\n", sei->fMask);
+    }
+
+    /* process the IDList */
+    if ( (sei->fMask & SEE_MASK_INVOKEIDLIST) == SEE_MASK_INVOKEIDLIST) /*0x0c*/
+    {
+        SHGetPathFromIDListA (sei->lpIDList,szApplicationName);
+        TRACE("-- idlist=%p (%s)\n", sei->lpIDList, szApplicationName);
+    }
+    else
+    {
+        if (sei->fMask & SEE_MASK_IDLIST )
+        {
+            pos = strstr(szCommandline, "%I");
+            if (pos)
+            {
+                LPVOID pv;
+                HGLOBAL hmem = SHAllocShared ( sei->lpIDList, ILGetSize(sei->lpIDList), 0);
+                pv = SHLockShared(hmem,0);
+                sprintf(szPidl,":%p",pv );
+                SHUnlockShared(pv);
+                
+                gap = strlen(szPidl);
+                len = strlen(pos)-2;
+                memmove(pos+gap,pos+2,len);
+                memcpy(pos,szPidl,gap);
+            }
+        }
+    }
+    
+    if (sei->fMask & SEE_MASK_CLASSNAME)
+    {
+	/* launch a document by fileclass like 'WordPad.Document.1' */
+        /* the Commandline contains 'c:\Path\wordpad.exe "%1"' */
+        /* FIXME: szCommandline should not be of a fixed size. Plus MAX_PATH is way too short! */
+        HCR_GetExecuteCommand(sei->lpClass, (sei->lpVerb) ? sei->lpVerb : "open", szCommandline, sizeof(szCommandline));
+        /* FIXME: get the extension of lpFile, check if it fits to the lpClass */
+        TRACE("SEE_MASK_CLASSNAME->'%s', doc->'%s'\n", szCommandline, szApplicationName);
+        
+        cmd[0] = '\0';
+        done = argify(cmd, sizeof(cmd), szCommandline, szApplicationName);
+        if (!done && szApplicationName[0]) 
+        {
+            strcat(cmd, " ");
+            strcat(cmd, szApplicationName);
+        }
+        retval = SHELL_ExecuteA(cmd, sei, is32);
+        if (retval > 32)
+            return TRUE;
+        else
+            return FALSE;
+    }
+    
+    /* 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->lpVerb == NULL)
+        lpOperation = "open";
+    else
+        lpOperation = sei->lpVerb;
+    
+    /* Else, try to execute the filename */
+    TRACE("execute:'%s','%s'\n",szApplicationName, szCommandline);
+    
+    strcpy(fileName, szApplicationName);
+    lpFile = fileName;
+    if (szCommandline[0]) {
+        strcat(szApplicationName, " ");
+        strcat(szApplicationName, szCommandline);
+    }
+    
+    retval = SHELL_ExecuteA(szApplicationName, sei, is32);
+    if (retval > 32)
+        return TRUE;
+    
+    /* Else, try to find the executable */
+    cmd[0] = '\0';
+    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);
+        if (*lpstrProtocol)
+            retval = execute_from_key(lpstrProtocol, szApplicationName, sei, is32);
+        else 
+            retval = SHELL_ExecuteA(cmd, sei, is32);
+    }
+    else if (PathIsURLA((LPSTR)lpFile))    /* File not found, check for URL */
+    {
+        LPSTR lpstrRes;
+        INT iSize;
+
+        lpstrRes = strchr(lpFile, ':');
+        /* PathIsURLA probably should fail on strings without a ':', but it doesn't */
+        if (lpstrRes)
+            iSize = lpstrRes - lpFile;
+        else
+            iSize = strlen(lpFile);
+
+        TRACE("Got URL: %s\n", lpFile);
+        /* Looking for ...protocol\shell\lpOperation\command */
+        strncpy(lpstrProtocol, lpFile, iSize);
+        lpstrProtocol[iSize] = '\0';
+        strcat(lpstrProtocol, "\\shell\\");
+        strcat(lpstrProtocol, lpOperation);
+        strcat(lpstrProtocol, "\\command");
+
+        /* Remove File Protocol from lpFile */
+        /* In the case file://path/file     */
+        if (!strncasecmp(lpFile, "file", iSize))
+        {
+            lpFile += iSize;
+            while (*lpFile == ':') lpFile++;
+        }
+        retval = execute_from_key(lpstrProtocol, lpFile, sei, is32);
+    }
+    /* Check if file specified is in the form www.??????.*** */
+    else if (!strncasecmp(lpFile, "www", 3))
+    {
+        /* if so, append lpFile http:// and call ShellExecute */
+        char lpstrTmpFile[256] = "http://" ;
+        strcat(lpstrTmpFile, lpFile);
+        retval = ShellExecuteA(sei->hwnd, lpOperation, lpstrTmpFile, NULL, NULL, 0);
+    }
+
+    if (retval <= 32)
+    {
+        sei->hInstApp = retval;
+        return FALSE;
+    }
+
+    sei->hInstApp = 33;
+    return TRUE;
+}
+
+
+/*************************************************************************
  *				ShellExecute		[SHELL.20]
  */
 HINSTANCE16 WINAPI ShellExecute16( HWND16 hWnd, LPCSTR lpOperation,
                                    LPCSTR lpFile, LPCSTR lpParameters,
                                    LPCSTR lpDirectory, INT16 iShowCmd )
 {
-    return (HINSTANCE16)SHELL_Execute(hWnd, lpOperation, lpFile,
-                                      lpParameters, lpDirectory, iShowCmd, FALSE );
+    SHELLEXECUTEINFOA sei;
+    HANDLE hProcess = 0;
+    
+    sei.cbSize = sizeof(sei);
+    sei.fMask = 0;
+    sei.hwnd = hWnd;
+    sei.lpVerb = lpOperation;
+    sei.lpFile = lpFile;
+    sei.lpParameters = lpParameters;
+    sei.lpDirectory = lpDirectory;
+    sei.nShow = iShowCmd;
+    sei.lpIDList = 0;
+    sei.lpClass = 0;
+    sei.hkeyClass = 0;
+    sei.dwHotKey = 0;
+    sei.hProcess = hProcess;
+    
+    ShellExecuteExA32 (&sei, FALSE);
+    return (HINSTANCE16)sei.hInstApp;
 }
 
 /*************************************************************************
@@ -546,9 +700,87 @@
 HINSTANCE WINAPI ShellExecuteA(HWND hWnd, LPCSTR lpOperation,LPCSTR lpFile,
                                LPCSTR lpParameters,LPCSTR lpDirectory, INT iShowCmd)
 {
+    SHELLEXECUTEINFOA sei;
+    HANDLE hProcess = 0;
+    
     TRACE("\n");
-    return SHELL_Execute( hWnd, lpOperation, lpFile, lpParameters,
-                          lpDirectory, iShowCmd, TRUE );
+    sei.cbSize = sizeof(sei);
+    sei.fMask = 0;
+    sei.hwnd = hWnd;
+    sei.lpVerb = lpOperation;
+    sei.lpFile = lpFile;
+    sei.lpParameters = lpParameters;
+    sei.lpDirectory = lpDirectory;
+    sei.nShow = iShowCmd;
+    sei.lpIDList = 0;
+    sei.lpClass = 0;
+    sei.hkeyClass = 0;
+    sei.dwHotKey = 0;
+    sei.hProcess = hProcess;
+    
+    ShellExecuteExA32 (&sei, TRUE);
+    return sei.hInstApp;
+}
+
+/*************************************************************************
+ * ShellExecuteEx				[SHELL32.291]
+ *
+ */
+BOOL WINAPI ShellExecuteExAW (LPVOID sei)
+{	
+    if (SHELL_OsIsUnicode())
+	return ShellExecuteExW (sei);
+    return ShellExecuteExA32 (sei, TRUE);
+}
+
+/*************************************************************************
+ * ShellExecuteExA				[SHELL32.292]
+ *
+ */
+BOOL WINAPI ShellExecuteExA (LPSHELLEXECUTEINFOA sei)
+{
+    return  ShellExecuteExA32 (sei, TRUE);
+}
+
+/*************************************************************************
+ * ShellExecuteExW				[SHELL32.293]
+ *
+ */
+BOOL WINAPI ShellExecuteExW (LPSHELLEXECUTEINFOW sei)
+{	
+    SHELLEXECUTEINFOA seiA;
+    DWORD ret;
+    
+    TRACE("%p\n", sei);
+    
+    memcpy(&seiA, sei, sizeof(SHELLEXECUTEINFOA));
+    
+    if (sei->lpVerb)
+        seiA.lpVerb = HEAP_strdupWtoA( GetProcessHeap(), 0, sei->lpVerb);
+
+    if (sei->lpFile)
+        seiA.lpFile = HEAP_strdupWtoA( GetProcessHeap(), 0, sei->lpFile);
+
+    if (sei->lpParameters)
+        seiA.lpParameters = HEAP_strdupWtoA( GetProcessHeap(), 0, sei->lpParameters);
+
+    if (sei->lpDirectory)
+        seiA.lpDirectory = HEAP_strdupWtoA( GetProcessHeap(), 0, sei->lpDirectory);
+    
+    if ((sei->fMask & SEE_MASK_CLASSNAME) && sei->lpClass)
+        seiA.lpClass = HEAP_strdupWtoA( GetProcessHeap(), 0, sei->lpClass);
+    else
+        seiA.lpClass = NULL;
+    
+    ret = ShellExecuteExA(&seiA);
+    
+    if (seiA.lpVerb)	HeapFree( GetProcessHeap(), 0, (LPSTR) seiA.lpVerb );
+    if (seiA.lpFile)	HeapFree( GetProcessHeap(), 0, (LPSTR) seiA.lpFile );
+    if (seiA.lpParameters)	HeapFree( GetProcessHeap(), 0, (LPSTR) seiA.lpParameters );
+    if (seiA.lpDirectory)	HeapFree( GetProcessHeap(), 0, (LPSTR) seiA.lpDirectory );
+    if (seiA.lpClass)	HeapFree( GetProcessHeap(), 0, (LPSTR) seiA.lpClass );
+    
+    return ret;
 }
 
 /*************************************************************************
@@ -560,7 +792,25 @@
 HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpOperation, LPCWSTR lpFile,
                                LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd)
 {
-       FIXME(": stub\n");
-       return 0;
+    SHELLEXECUTEINFOW sei;
+    HANDLE hProcess = 0;
+    
+    TRACE("\n");
+    sei.cbSize = sizeof(sei);
+    sei.fMask = 0;
+    sei.hwnd = hwnd;
+    sei.lpVerb = lpOperation;
+    sei.lpFile = lpFile;
+    sei.lpParameters = lpParameters;
+    sei.lpDirectory = lpDirectory;
+    sei.nShow = nShowCmd;
+    sei.lpIDList = 0;
+    sei.lpClass = 0;
+    sei.hkeyClass = 0;
+    sei.dwHotKey = 0;
+    sei.hProcess = hProcess;
+    
+    ShellExecuteExW (&sei);
+    return sei.hInstApp;
 }
 


More information about the wine-devel mailing list