* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
-#define WIN32_LEAN_AND_MEAN
+#include "precomp.h"
-#include <windows.h>
+#include <winreg.h>
+#include <winuser.h>
#include <msi.h>
#include <objbase.h>
-#include <stdio.h>
-#include "wine/debug.h"
-#include "wine/unicode.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(msiexec);
+#include <wine/unicode.h>
typedef HRESULT (WINAPI *DLLREGISTERSERVER)(void);
typedef HRESULT (WINAPI *DLLUNREGISTERSERVER)(void);
static VOID StringListAppend(struct string_list **list, LPCWSTR str)
{
struct string_list *entry;
- DWORD size;
- size = sizeof *entry + lstrlenW(str) * sizeof (WCHAR);
- entry = HeapAlloc(GetProcessHeap(), 0, size);
+ entry = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(struct string_list, str[lstrlenW(str) + 1]));
if(!entry)
{
WINE_ERR("Out of memory!\n");
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)
{
static DWORD DoRegServer(void)
{
+ static const WCHAR msiserverW[] = {'M','S','I','S','e','r','v','e','r',0};
+ static const WCHAR msiexecW[] = {'\\','m','s','i','e','x','e','c',' ','/','V',0};
SC_HANDLE scm, service;
- CHAR path[MAX_PATH+12];
- DWORD ret = 0;
+ WCHAR path[MAX_PATH+12];
+ DWORD len, ret = 0;
- scm = OpenSCManagerA(NULL, SERVICES_ACTIVE_DATABASEA, SC_MANAGER_CREATE_SERVICE);
- if (!scm)
+ if (!(scm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, SC_MANAGER_CREATE_SERVICE)))
{
fprintf(stderr, "Failed to open the service control manager.\n");
return 1;
}
-
- GetSystemDirectoryA(path, MAX_PATH);
- lstrcatA(path, "\\msiexec.exe /V");
-
- service = CreateServiceA(scm, "MSIServer", "MSIServer", GENERIC_ALL,
- SERVICE_WIN32_SHARE_PROCESS, SERVICE_DEMAND_START,
- SERVICE_ERROR_NORMAL, path, NULL, NULL,
- NULL, NULL, NULL);
-
- if (service) CloseServiceHandle(service);
+ len = GetSystemDirectoryW(path, MAX_PATH);
+ lstrcpyW(path + len, msiexecW);
+ if ((service = CreateServiceW(scm, msiserverW, msiserverW, GENERIC_ALL,
+ SERVICE_WIN32_SHARE_PROCESS, SERVICE_DEMAND_START,
+ SERVICE_ERROR_NORMAL, path, NULL, NULL, NULL, NULL, NULL)))
+ {
+ CloseServiceHandle(service);
+ }
else if (GetLastError() != ERROR_SERVICE_EXISTS)
{
fprintf(stderr, "Failed to create MSI service\n");
return ret;
}
+static DWORD DoUnregServer(void)
+{
+ static const WCHAR msiserverW[] = {'M','S','I','S','e','r','v','e','r',0};
+ SC_HANDLE scm, service;
+ DWORD ret = 0;
+
+ if (!(scm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, SC_MANAGER_CONNECT)))
+ {
+ fprintf(stderr, "Failed to open service control manager\n");
+ return 1;
+ }
+ if ((service = OpenServiceW(scm, msiserverW, DELETE)))
+ {
+ if (!DeleteService(service))
+ {
+ fprintf(stderr, "Failed to delete MSI service\n");
+ ret = 1;
+ }
+ CloseServiceHandle(service);
+ }
+ else if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
+ {
+ fprintf(stderr, "Failed to open MSI service\n");
+ ret = 1;
+ }
+ CloseServiceHandle(scm);
+ return ret;
+}
+
static INT DoEmbedding( LPWSTR key )
{
printf("Remote custom actions are not supported yet\n");
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;
+ enum chomp_state state = CS_TOKEN;
+ const WCHAR *p;
+ int count = 1;
+ BOOL 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;
+ 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;
- *pargc = n;
- *pargv = argv;
+ 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 = count;
+ *pargv = argv;
}
-static BOOL process_args_from_reg( LPWSTR ident, int *pargc, WCHAR ***pargv )
+static BOOL process_args_from_reg( const WCHAR *ident, int *pargc, WCHAR ***pargv )
{
LONG r;
- HKEY hkey = 0, hkeyArgs = 0;
+ HKEY hkey;
DWORD sz = 0, type = 0;
- LPWSTR buf = NULL;
+ WCHAR *buf;
BOOL ret = FALSE;
r = RegOpenKeyW(HKEY_LOCAL_MACHINE, InstallRunOnce, &hkey);
r = RegQueryValueExW(hkey, ident, 0, &type, 0, &sz);
if(r == ERROR_SUCCESS && type == REG_SZ)
{
- buf = HeapAlloc(GetProcessHeap(), 0, sz);
- r = RegQueryValueExW(hkey, ident, 0, &type, (LPBYTE)buf, &sz);
+ int len = lstrlenW( *pargv[0] );
+ if (!(buf = HeapAlloc( GetProcessHeap(), 0, sz + (len + 1) * sizeof(WCHAR) )))
+ {
+ RegCloseKey( hkey );
+ return FALSE;
+ }
+ memcpy( buf, *pargv[0], len * sizeof(WCHAR) );
+ buf[len++] = ' ';
+ r = RegQueryValueExW(hkey, ident, 0, &type, (LPBYTE)(buf + len), &sz);
if( r == ERROR_SUCCESS )
{
process_args(buf, pargc, pargv);
}
HeapFree(GetProcessHeap(), 0, buf);
}
- RegCloseKey(hkeyArgs);
+ RegCloseKey(hkey);
return ret;
}
{
FunctionRegServer = TRUE;
}
- else if (msi_option_equal(argvW[i], "unregserver") || msi_option_equal(argvW[i], "unregister"))
+ else if (msi_option_equal(argvW[i], "unregserver") || msi_option_equal(argvW[i], "unregister")
+ || msi_option_equal(argvW[i], "unreg"))
{
FunctionUnregServer = TRUE;
}
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"))
{
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++;
{
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;
{
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+!"))
+ else if(msi_strprefix(argvW[i]+2, "b"))
{
- InstallUILevel = INSTALLUILEVEL_BASIC|INSTALLUILEVEL_ENDDIALOG;
- 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
{
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;
}
else if (FunctionUnregServer)
{
- WINE_FIXME( "/unregserver not implemented yet, ignoring\n" );
+ ReturnCode = DoUnregServer();
}
else if (FunctionServer)
{