[MSIEXEC] Sync with Wine Staging 3.3. CORE-14434
[reactos.git] / base / system / msiexec / msiexec.c
index fe43efd..8dcd216 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#define WIN32_NO_STATUS
-#define _INC_WINDOWS
-#define COM_NO_WINDOWS_H
-#include <stdarg.h>
-#include <windef.h>
-#include <winbase.h>
-#include <winreg.h>
-#include <winsvc.h>
-#include <winuser.h>
+#define WIN32_LEAN_AND_MEAN
+
+#include <windows.h>
 #include <msi.h>
+#include <winsvc.h>
 #include <objbase.h>
 #include <stdio.h>
 
-#include <wine/debug.h>
-#include <wine/unicode.h>
+#include "wine/debug.h"
+#include "wine/unicode.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(msiexec);
 
@@ -221,14 +216,6 @@ static DWORD msi_atou(LPCWSTR str)
        return ret;
 }
 
-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)
 {
@@ -418,89 +405,103 @@ static INT DoEmbedding( LPWSTR key )
 
 enum chomp_state
 {
-       cs_whitespace,
-       cs_token,
-       cs_quote
+    CS_WHITESPACE,
+    CS_TOKEN,
+    CS_QUOTE
 };
 
-static int chomp( WCHAR *str )
+static int chomp( const WCHAR *in, WCHAR *out )
 {
-       enum chomp_state state = cs_token;
-       WCHAR *p, *out;
-       int count = 1, 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;
+    enum chomp_state state = CS_TOKEN;
+    const WCHAR *p;
+    int count = 1;
+    BOOL ignore;
 
-       return count;
+    for (p = in; *p; p++)
+    {
+        ignore = TRUE;
+        switch (state)
+        {
+        case CS_WHITESPACE:
+            switch (*p)
+            {
+            case ' ':
+                break;
+            case '"':
+                state = CS_QUOTE;
+                count++;
+                break;
+            default:
+                count++;
+                ignore = FALSE;
+                state = CS_TOKEN;
+            }
+            break;
+
+        case CS_TOKEN:
+            switch (*p)
+            {
+            case '"':
+                state = CS_QUOTE;
+                break;
+            case ' ':
+                state = CS_WHITESPACE;
+                if (out) *out++ = 0;
+                break;
+            default:
+                if (p > in && p[-1] == '"')
+                {
+                    if (out) *out++ = 0;
+                    count++;
+                }
+                ignore = FALSE;
+            }
+            break;
+
+        case CS_QUOTE:
+            switch (*p)
+            {
+            case '"':
+                state = CS_TOKEN;
+                break;
+            default:
+                ignore = FALSE;
+            }
+            break;
+        }
+        if (!ignore && out) *out++ = *p;
+    }
+    if (out) *out = 0;
+    return count;
 }
 
 static void process_args( WCHAR *cmdline, int *pargc, WCHAR ***pargv )
 {
-       WCHAR **argv, *p = msi_strdup(cmdline);
-       int i, n;
+    WCHAR **argv, *p;
+    int i, count;
 
-       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 = 0;
+    *pargv = NULL;
+
+    count = chomp( cmdline, NULL );
+    if (!(p = HeapAlloc( GetProcessHeap(), 0, (lstrlenW(cmdline) + count + 1) * sizeof(WCHAR) )))
+        return;
+
+    count = chomp( cmdline, p );
+    if (!(argv = HeapAlloc( GetProcessHeap(), 0, (count + 1) * sizeof(WCHAR *) )))
+    {
+        HeapFree( GetProcessHeap(), 0, p );
+        return;
+    }
+    for (i = 0; i < count; i++)
+    {
+        argv[i] = p;
+        p += lstrlenW( p ) + 1;
+    }
+    argv[i] = NULL;
 
-       *pargc = n;
-       *pargv = argv;
+    *pargc = count;
+    *pargv = argv;
 }
 
 static BOOL process_args_from_reg( const WCHAR *ident, int *pargc, WCHAR ***pargv )
@@ -635,6 +636,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
                        WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
                        PackageName = argvW[i];
                        StringListAppend(&property_list, ActionAdmin);
+                       WINE_FIXME("Administrative installs are not currently supported\n");
                }
                else if(msi_option_prefix(argvW[i], "f"))
                {
@@ -873,7 +875,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
                                ExitProcess(1);
                        }
                }
-               else if(msi_option_equal(argvW[i], "p"))
+               else if(msi_option_equal(argvW[i], "p") || msi_option_equal(argvW[i], "update"))
                {
                        FunctionPatch = TRUE;
                        i++;
@@ -889,10 +891,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
                        {
                                InstallUILevel = INSTALLUILEVEL_NONE;
                        }
-                       else if(msi_strequal(argvW[i]+2, "b"))
-                       {
-                               InstallUILevel = INSTALLUILEVEL_BASIC;
-                       }
                        else if(msi_strequal(argvW[i]+2, "r"))
                        {
                                InstallUILevel = INSTALLUILEVEL_REDUCED;
@@ -905,23 +903,25 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
                        {
                                InstallUILevel = INSTALLUILEVEL_NONE|INSTALLUILEVEL_ENDDIALOG;
                        }
-                       else if(msi_strequal(argvW[i]+2, "b+"))
-                       {
-                               InstallUILevel = INSTALLUILEVEL_BASIC|INSTALLUILEVEL_ENDDIALOG;
-                       }
-                       else if(msi_strequal(argvW[i]+2, "b-"))
-                       {
-                               InstallUILevel = INSTALLUILEVEL_BASIC|INSTALLUILEVEL_PROGRESSONLY;
-                       }
-                       else if(msi_strequal(argvW[i]+2, "b+!"))
-                       {
-                               InstallUILevel = INSTALLUILEVEL_BASIC|INSTALLUILEVEL_ENDDIALOG;
-                               WINE_FIXME("Unknown modifier: !\n");
-                       }
-                       else if(msi_strequal(argvW[i]+2, "b!"))
+                       else if(msi_strprefix(argvW[i]+2, "b"))
                        {
-                               InstallUILevel = INSTALLUILEVEL_BASIC;
-                               WINE_FIXME("Unknown modifier: !\n");
+                const WCHAR *ptr = argvW[i] + 3;
+
+                InstallUILevel = INSTALLUILEVEL_BASIC;
+
+                while (*ptr)
+                {
+                    if (msi_strprefix(ptr, "+"))
+                        InstallUILevel |= INSTALLUILEVEL_ENDDIALOG;
+                    if (msi_strprefix(ptr, "-"))
+                        InstallUILevel |= INSTALLUILEVEL_PROGRESSONLY;
+                    if (msi_strprefix(ptr, "!"))
+                    {
+                        WINE_FIXME("Unhandled modifier: !\n");
+                        InstallUILevel |= INSTALLUILEVEL_HIDECANCEL;
+                    }
+                    ptr++;
+                }
                        }
                        else
                        {
@@ -929,6 +929,14 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
                                         wine_dbgstr_w(argvW[i]+2));
                        }
                }
+                else if(msi_option_equal(argvW[i], "passive"))
+                {
+                    static const WCHAR rebootpromptW[] =
+                        {'R','E','B','O','O','T','P','R','O','M','P','T','=','"','S','"',0};
+
+                    InstallUILevel = INSTALLUILEVEL_BASIC|INSTALLUILEVEL_PROGRESSONLY|INSTALLUILEVEL_HIDECANCEL;
+                    StringListAppend(&property_list, rebootpromptW);
+                }
                else if(msi_option_equal(argvW[i], "y"))
                {
                        FunctionDllRegisterServer = TRUE;