James Hawkins : msi: Fixed the WriteEnvironmentStrings action.
Alexandre Julliard
julliard at wine.codeweavers.com
Thu Jun 14 07:47:05 CDT 2007
Module: wine
Branch: master
Commit: 881f59254a1d2e1fc0b8661c3f0f14d709e80007
URL: http://source.winehq.org/git/wine.git/?a=commit;h=881f59254a1d2e1fc0b8661c3f0f14d709e80007
Author: James Hawkins <truiken at gmail.com>
Date: Wed Jun 13 17:46:09 2007 -0700
msi: Fixed the WriteEnvironmentStrings action.
---
dlls/msi/action.c | 179 +++++++++++++++++++++++++++++++++++++++++------------
1 files changed, 140 insertions(+), 39 deletions(-)
diff --git a/dlls/msi/action.c b/dlls/msi/action.c
index d6f53d7..00ed572 100644
--- a/dlls/msi/action.c
+++ b/dlls/msi/action.c
@@ -4570,15 +4570,92 @@ static UINT ACTION_InstallODBC( MSIPACKAGE *package )
#define ENV_ACT_SETALWAYS 0x1
#define ENV_ACT_SETABSENT 0x2
#define ENV_ACT_REMOVE 0x4
+#define ENV_ACT_REMOVEMATCH 0x8
#define ENV_MOD_MACHINE 0x20000000
#define ENV_MOD_APPEND 0x40000000
#define ENV_MOD_PREFIX 0x80000000
+#define ENV_MOD_MASK 0xC0000000
+
+#define check_flag_combo(x, y) ((x) & ~(y)) == (y)
+
+static LONG env_set_flags( LPCWSTR *name, LPWSTR *value, DWORD *flags )
+{
+ LPCWSTR cptr = *name;
+ LPWSTR ptr = *value;
+
+ static const WCHAR prefix[] = {'[','~',']',0};
+
+ *flags = 0;
+ while (*cptr && (*cptr == '=' || *cptr == '+' ||
+ *cptr == '-' || *cptr == '!' || *cptr == '*'))
+ {
+ switch (*cptr)
+ {
+ case '=':
+ *flags |= ENV_ACT_SETALWAYS;
+ break;
+ case '+':
+ *flags |= ENV_ACT_SETABSENT;
+ break;
+ case '-':
+ *flags |= ENV_ACT_REMOVE;
+ break;
+ case '!':
+ *flags |= ENV_ACT_REMOVEMATCH;
+ break;
+ case '*':
+ *flags |= ENV_MOD_MACHINE;
+ break;
+ default:
+ ERR("Unknown Environment flag: %c\n", *cptr);
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ cptr++;
+ (*name)++;
+ }
+
+ if (!*cptr)
+ {
+ ERR("Missing environment variable\n");
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ if (!strncmpW(ptr, prefix, lstrlenW(prefix)))
+ {
+ *flags |= ENV_MOD_PREFIX;
+ *value += lstrlenW(prefix);
+ }
+ else
+ {
+ ptr += lstrlenW(ptr) - lstrlenW(prefix) - 1;
+ if (!lstrcmpW(ptr, prefix))
+ {
+ *flags |= ENV_MOD_APPEND;
+ *ptr = '\0';
+ }
+ }
+
+ if (!*flags ||
+ check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
+ check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
+ check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
+ check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
+ {
+ ERR("Invalid flags: %08x\n", *flags);
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ return ERROR_SUCCESS;
+}
static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
{
- LPCWSTR var, value;
- LPWSTR val = NULL, ptr;
+ MSIPACKAGE *package = param;
+ LPCWSTR name, value, comp;
+ LPWSTR data = NULL, newval = NULL;
+ LPWSTR deformatted, ptr;
DWORD flags, type, size;
LONG res;
HKEY env, root = HKEY_CURRENT_USER;
@@ -4591,33 +4668,35 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
'E','n','v','i','r','o','n','m','e','n','t',0};
static const WCHAR semicolon[] = {';',0};
- var = MSI_RecordGetString(rec, 1);
- value = MSI_RecordGetString(rec, 2);
- flags = MSI_RecordGetInteger(rec, 3);
+ name = MSI_RecordGetString(rec, 2);
+ value = MSI_RecordGetString(rec, 3);
+ comp = MSI_RecordGetString(rec, 4);
+
+ deformat_string(package, value, &deformatted);
+ if (!deformatted)
+ return ERROR_OUTOFMEMORY;
+
+ res = env_set_flags(&name, &deformatted, &flags);
+ if (res != ERROR_SUCCESS)
+ goto done;
- TRACE("(%s, %s, %08x)\n", debugstr_w(var), debugstr_w(value), flags);
+ value = deformatted;
if (flags & ENV_MOD_MACHINE)
root = HKEY_LOCAL_MACHINE;
res = RegOpenKeyExW(root, environment, 0, KEY_ALL_ACCESS, &env);
if (res != ERROR_SUCCESS)
- return res;
+ goto done;
if (flags & ENV_ACT_REMOVE)
- {
- res = RegDeleteKeyW(env, var);
- RegCloseKey(env);
- return res;
- }
+ FIXME("Not removing environment variable on uninstall!\n");
size = 0;
- res = RegQueryValueExW(env, var, NULL, &type, NULL, &size);
- if ((res != ERROR_MORE_DATA && res != ERROR_FILE_NOT_FOUND) || type != REG_SZ)
- {
- RegCloseKey(env);
- return res;
- }
+ res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
+ if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
+ (res == ERROR_SUCCESS && type != REG_SZ))
+ goto done;
if (res != ERROR_FILE_NOT_FOUND)
{
@@ -4627,51 +4706,73 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
goto done;
}
- /* oldvals;newval */
- size = (lstrlenW(value) + 1 + size) * sizeof(WCHAR);
- val = msi_alloc(size);
- ptr = val;
- if (!val)
+ data = msi_alloc(size);
+ if (!data)
{
- res = ERROR_OUTOFMEMORY;
- goto done;
+ RegCloseKey(env);
+ return ERROR_OUTOFMEMORY;
}
- if (flags & ENV_MOD_PREFIX)
+ res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
+ if (res != ERROR_SUCCESS)
+ goto done;
+
+ if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
{
- lstrcpyW(val, value);
- lstrcatW(val, semicolon);
- ptr = val + lstrlenW(value) + 1;
+ res = RegDeleteKeyW(env, name);
+ goto done;
}
- res = RegQueryValueExW(env, var, NULL, &type, (LPVOID)ptr, &size);
- if (res != ERROR_SUCCESS)
+ size = (lstrlenW(value) + 1 + size) * sizeof(WCHAR);
+ newval = msi_alloc(size);
+ ptr = newval;
+ if (!newval)
+ {
+ res = ERROR_OUTOFMEMORY;
goto done;
+ }
- if (!flags || flags & ENV_MOD_APPEND)
+ if (!(flags & ENV_MOD_MASK))
+ lstrcpyW(newval, value);
+ else
{
- lstrcatW(val, semicolon);
- lstrcatW(val, value);
+ if (flags & ENV_MOD_PREFIX)
+ {
+ lstrcpyW(newval, value);
+ lstrcatW(newval, semicolon);
+ ptr = newval + lstrlenW(value) + 1;
+ }
+
+ lstrcpyW(ptr, data);
+
+ if (flags & ENV_MOD_APPEND)
+ {
+ lstrcatW(newval, semicolon);
+ lstrcatW(newval, value);
+ }
}
}
else
{
size = (lstrlenW(value) + 1) * sizeof(WCHAR);
- val = msi_alloc(size);
- if (!val)
+ newval = msi_alloc(size);
+ if (!newval)
{
res = ERROR_OUTOFMEMORY;
goto done;
}
- lstrcpyW(val, value);
+ lstrcpyW(newval, value);
}
- res = RegSetValueExW(env, var, 0, type, (LPVOID)val, size);
+ TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
+ res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
done:
RegCloseKey(env);
- msi_free(val);
+ msi_free(deformatted);
+ msi_free(data);
+ msi_free(newval);
return res;
}
More information about the wine-cvs
mailing list