Revert 7c35db000b26852fc2bf4a7a7e349953f60d183f

Aric Stewart aric at codeweavers.com
Thu Mar 22 08:20:16 CDT 2007


The previous command line processing is not identical to 
CommandLineToArgvW and CommandLineToArgvW breaks msi command line 
processing for things such as Excel Viewer 2003

specifically the command line created by the Excel Viewer 2003 and 
passed to msiexec.exe is "c:\windows\system32\msiexec.exe"  /I 
C:\windows\temp\IXP000.TMP\XLVIEW.MSI CDCACHE="2" LAUNCHEDFROMSETUP="1" 
SETUPEXEPATH="C:\windows\temp\IXP000.TMP\" SETUPEXENAME="SETUP.EXE" 
/lpiwaeo "C:\windows\temp\Microsoft Office Excel Viewer 2003 
Setup(0001)_Task(0001).txt" CDCACH"...

Notice for SETUPEXEPATH there is a " and then a \" at the end as the \ 
is the end of the path.  I have confirmed this command line on windows 
(in the setup log that is created).  Native msiexec.exe does not call 
CommandLineToArgvW and parses the path. However CommandLineToArgvW sees 
the \" and thus sets SETUPEXEPATH to equal "C:\windows\temp\IXP000.TMP\" 
SETUPEXENAME=SETUP.EXE   /lpiwaeo C:\\windows\\temp\\Microsoft"

This is correct behavior for CommandLineToArgvW but incorrect behavior 
for msiexec.exe command line processing.
---
  programs/msiexec/Makefile.in |    2 +-
  programs/msiexec/msiexec.c   |  104 
++++++++++++++++++++++++++++++++++++++++-
  2 files changed, 102 insertions(+), 4 deletions(-)
-------------- next part --------------
diff --git a/programs/msiexec/Makefile.in b/programs/msiexec/Makefile.in
index 10e1cc4..c2bd981 100644
--- a/programs/msiexec/Makefile.in
+++ b/programs/msiexec/Makefile.in
@@ -4,7 +4,7 @@ SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = msiexec.exe
 APPMODE   = -mconsole
-IMPORTS   = msi shell32 ole32 advapi32 user32 kernel32
+IMPORTS   = msi ole32 advapi32 user32 kernel32
 
 C_SRCS = \
 	msiexec.c
diff --git a/programs/msiexec/msiexec.c b/programs/msiexec/msiexec.c
index 2d2728c..810dd70 100644
--- a/programs/msiexec/msiexec.c
+++ b/programs/msiexec/msiexec.c
@@ -25,7 +25,6 @@
 #include <msi.h>
 #include <objbase.h>
 #include <stdio.h>
-#include <shellapi.h>
 
 #include "wine/debug.h"
 #include "wine/unicode.h"
@@ -211,6 +210,14 @@ static DWORD msi_atou(LPCWSTR str)
 	return 0;
 }
 
+static LPWSTR msi_strdup(LPCWSTR str)
+{
+	DWORD len = lstrlenW(str)+1;
+	LPWSTR ret = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len);
+	lstrcpyW(ret, str);
+	return ret;
+}
+
 /* str1 is the same as str2, ignoring case */
 static BOOL msi_strequal(LPCWSTR str1, LPCSTR str2)
 {
@@ -366,6 +373,97 @@ static INT DoEmbedding( LPWSTR key )
 	return 1;
 }
 
+/*
+ * state machine to break up the command line properly
+ */
+
+enum chomp_state
+{
+	cs_whitespace,
+	cs_token,
+	cs_quote
+};
+
+static int chomp( WCHAR *str )
+{
+	enum chomp_state state = cs_whitespace;
+	WCHAR *p, *out;
+	int count = 0, ignore;
+
+	for( p = str, out = str; *p; p++ )
+	{
+		ignore = 1;
+		switch( state )
+		{
+		case cs_whitespace:
+			switch( *p )
+			{
+			case ' ':
+				break;
+			case '"':
+				state = cs_quote;
+				count++;
+				break;
+			default:
+				count++;
+				ignore = 0;
+				state = cs_token;
+			}
+			break;
+
+		case cs_token:
+			switch( *p )
+			{
+			case '"':
+				state = cs_quote;
+				break;
+			case ' ':
+				state = cs_whitespace;
+				*out++ = 0;
+				break;
+			default:
+				ignore = 0;
+			}
+			break;
+
+		case cs_quote:
+			switch( *p )
+			{
+			case '"':
+				state = cs_token;
+				break;
+			default:
+				ignore = 0;
+			}
+			break;
+		}
+		if( !ignore )
+			*out++ = *p;
+	}
+
+	*out = 0;
+
+	return count;
+}
+
+static void process_args( WCHAR *cmdline, int *pargc, WCHAR ***pargv )
+{
+	WCHAR **argv, *p = msi_strdup(cmdline);
+	int i, n;
+
+	n = chomp( p );
+	argv = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR*)*(n+1));
+	for( i=0; i<n; i++ )
+	{
+		argv[i] = p;
+		p += lstrlenW(p) + 1;
+	}
+	argv[i] = NULL;
+
+	*pargc = n;
+	*pargv = argv;
+}
+
 static BOOL process_args_from_reg( LPWSTR ident, int *pargc, WCHAR ***pargv )
 {
 	LONG r;
@@ -384,7 +482,7 @@ static BOOL process_args_from_reg( LPWST
 		r = RegQueryValueExW(hkey, ident, 0, &type, (LPBYTE)buf, &sz);
 		if( r == ERROR_SUCCESS )
 		{
-			*pargv = CommandLineToArgvW(buf, pargc);
+			process_args(buf, pargc, pargv);
 			ret = TRUE;
 		}
 	}
@@ -430,7 +528,7 @@ int main(int argc, char **argv)
 	LPWSTR *argvW = NULL;
 
 	/* overwrite the command line */
-	argvW = CommandLineToArgvW( GetCommandLineW(), &argc );
+	process_args( GetCommandLineW(), &argc, &argvW );
 
 	/*
 	 * If the args begin with /@ IDENT then we need to load the real


More information about the wine-patches mailing list