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