[msi]
authorChristoph von Wittich <christoph_vw@reactos.org>
Sun, 20 Mar 2011 08:47:41 +0000 (08:47 +0000)
committerChristoph von Wittich <christoph_vw@reactos.org>
Sun, 20 Mar 2011 08:47:41 +0000 (08:47 +0000)
-partial sync to wine 1.3.16

svn path=/trunk/; revision=51096

36 files changed:
reactos/dll/win32/msi/action.c
reactos/dll/win32/msi/appsearch.c
reactos/dll/win32/msi/assembly.c [new file with mode: 0644]
reactos/dll/win32/msi/classes.c
reactos/dll/win32/msi/cond.tab.c
reactos/dll/win32/msi/cond.y
reactos/dll/win32/msi/create.c
reactos/dll/win32/msi/custom.c
reactos/dll/win32/msi/database.c
reactos/dll/win32/msi/dialog.c
reactos/dll/win32/msi/events.c
reactos/dll/win32/msi/files.c
reactos/dll/win32/msi/font.c
reactos/dll/win32/msi/format.c
reactos/dll/win32/msi/helpers.c
reactos/dll/win32/msi/insert.c
reactos/dll/win32/msi/install.c
reactos/dll/win32/msi/media.c
reactos/dll/win32/msi/msi.c
reactos/dll/win32/msi/msi.rbuild
reactos/dll/win32/msi/msi.rc
reactos/dll/win32/msi/msi.spec
reactos/dll/win32/msi/msi_main.c
reactos/dll/win32/msi/msipriv.h
reactos/dll/win32/msi/msiquery.c
reactos/dll/win32/msi/msiserver.idl
reactos/dll/win32/msi/package.c
reactos/dll/win32/msi/record.c
reactos/dll/win32/msi/registry.c
reactos/dll/win32/msi/script.c
reactos/dll/win32/msi/source.c
reactos/dll/win32/msi/sql.tab.c
reactos/dll/win32/msi/sql.y
reactos/dll/win32/msi/string.c
reactos/dll/win32/msi/table.c
reactos/dll/win32/msi/where.c

index 808386f..f806f18 100644 (file)
@@ -35,7 +35,6 @@
 #include "shlobj.h"
 #include "objbase.h"
 #include "mscoree.h"
-#include "fusion.h"
 #include "shlwapi.h"
 #include "wine/unicode.h"
 #include "winver.h"
@@ -110,8 +109,6 @@ static const WCHAR szIsolateComponents[] =
     {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
 static const WCHAR szMigrateFeatureStates[] =
     {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
-static const WCHAR szMsiPublishAssemblies[] = 
-    {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
 static const WCHAR szMsiUnpublishAssemblies[] = 
     {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
 static const WCHAR szInstallODBC[] = 
@@ -165,10 +162,6 @@ static const WCHAR szValidateProductID[] =
 static const WCHAR szWriteEnvironmentStrings[] =
     {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
 
-/********************************************************
- * helper functions
- ********************************************************/
-
 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
 {
     static const WCHAR Query_t[] = 
@@ -214,86 +207,173 @@ static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
     msiobj_release(&row->hdr);
 }
 
+enum parse_state
+{
+    state_whitespace,
+    state_token,
+    state_quote
+};
+
+static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
+{
+    enum parse_state state = state_quote;
+    const WCHAR *p;
+    WCHAR *out = value;
+    int ignore, in_quotes = 0, count = 0, len = 0;
+
+    for (p = str; *p; p++)
+    {
+        ignore = 0;
+        switch (state)
+        {
+        case state_whitespace:
+            switch (*p)
+            {
+            case ' ':
+                if (!count) goto done;
+                in_quotes = 1;
+                ignore = 1;
+                break;
+            case '"':
+                state = state_quote;
+                if (in_quotes) count--;
+                else count++;
+                break;
+            default:
+                state = state_token;
+                if (!count) in_quotes = 0;
+                else in_quotes = 1;
+                len++;
+                break;
+            }
+            break;
+
+        case state_token:
+            switch (*p)
+            {
+            case '"':
+                state = state_quote;
+                if (in_quotes) count--;
+                else count++;
+                break;
+            case ' ':
+                state = state_whitespace;
+                if (!count) goto done;
+                in_quotes = 1;
+                break;
+            default:
+                if (!count) in_quotes = 0;
+                else in_quotes = 1;
+                len++;
+                break;
+            }
+            break;
+
+        case state_quote:
+            switch (*p)
+            {
+            case '"':
+                if (in_quotes) count--;
+                else count++;
+                break;
+            case ' ':
+                state = state_whitespace;
+                if (!count || !len) goto done;
+                in_quotes = 1;
+                break;
+            default:
+                state = state_token;
+                if (!count) in_quotes = 0;
+                else in_quotes = 1;
+                len++;
+                break;
+            }
+            break;
+
+        default: break;
+        }
+        if (!ignore) *out++ = *p;
+    }
+
+done:
+    if (!len) *value = 0;
+    else *out = 0;
+
+    *quotes = count;
+    return p - str;
+}
+
+static void remove_quotes( WCHAR *str )
+{
+    WCHAR *p = str;
+    int len = strlenW( str );
+
+    while ((p = strchrW( p, '"' )))
+    {
+        memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
+        p++;
+    }
+}
+
 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
                              BOOL preserve_case )
 {
-    LPCWSTR ptr,ptr2;
-    BOOL quote;
+    LPCWSTR ptr, ptr2;
+    int quotes;
     DWORD len;
-    LPWSTR prop = NULL, val = NULL;
+    WCHAR *prop, *val;
+    UINT r;
 
     if (!szCommandLine)
         return ERROR_SUCCESS;
 
     ptr = szCommandLine;
-       
     while (*ptr)
     {
-        if (*ptr==' ')
-        {
-            ptr++;
-            continue;
-        }
+        while (*ptr == ' ') ptr++;
+        if (!*ptr) break;
 
-        TRACE("Looking at %s\n",debugstr_w(ptr));
-
-        ptr2 = strchrW(ptr,'=');
-        if (!ptr2)
-        {
-            ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
-            break;
-        }
+        ptr2 = strchrW( ptr, '=' );
+        if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
  
-        quote = FALSE;
+        len = ptr2 - ptr;
+        if (!len) return ERROR_INVALID_COMMAND_LINE;
 
-        len = ptr2-ptr;
-        prop = msi_alloc((len+1)*sizeof(WCHAR));
-        memcpy(prop,ptr,len*sizeof(WCHAR));
-        prop[len]=0;
-
-        if (!preserve_case)
-            struprW(prop);
+        prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
+        memcpy( prop, ptr, len * sizeof(WCHAR) );
+        prop[len] = 0;
+        if (!preserve_case) struprW( prop );
 
         ptr2++;
-       
-        len = 0; 
-        ptr = ptr2; 
-        while (*ptr && (quote || (!quote && *ptr!=' ')))
-        {
-            if (*ptr == '"')
-                quote = !quote;
-            ptr++;
-            len++;
-        }
-       
-        if (*ptr2=='"')
+        while (*ptr2 == ' ') ptr2++;
+
+        quotes = 0;
+        val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) );
+        len = parse_prop( ptr2, val, &quotes );
+        if (quotes % 2)
         {
-            ptr2++;
-            len -= 2;
+            WARN("unbalanced quotes\n");
+            msi_free( val );
+            msi_free( prop );
+            return ERROR_INVALID_COMMAND_LINE;
         }
-        val = msi_alloc((len+1)*sizeof(WCHAR));
-        memcpy(val,ptr2,len*sizeof(WCHAR));
-        val[len] = 0;
+        remove_quotes( val );
+        TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
 
-        if (lstrlenW(prop) > 0)
-        {
-            UINT r = msi_set_property( package->db, prop, val );
+        r = msi_set_property( package->db, prop, val );
+        if (r == ERROR_SUCCESS && !strcmpW( prop, cszSourceDir ))
+            msi_reset_folders( package, TRUE );
 
-            TRACE("Found commandline property (%s) = (%s)\n", 
-                   debugstr_w(prop), debugstr_w(val));
+        msi_free( val );
+        msi_free( prop );
 
-            if (r == ERROR_SUCCESS && !strcmpW( prop, cszSourceDir ))
-                msi_reset_folders( package, TRUE );
-        }
-        msi_free(val);
-        msi_free(prop);
+        ptr = ptr2 + len;
     }
 
     return ERROR_SUCCESS;
 }
 
-
-static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
+WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
 {
     LPCWSTR pc;
     LPWSTR p, *ret = NULL;
@@ -445,7 +525,7 @@ UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
     guids = msi_split_string( guid_list, ';' );
     for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
     {
-        if (!lstrcmpW( guids[i], product_code ))
+        if (!strcmpW( guids[i], product_code ))
             ret = ERROR_SUCCESS;
     }
     msi_free( guids );
@@ -679,7 +759,27 @@ static UINT msi_apply_transforms( MSIPACKAGE *package )
         if (xforms[i][0] == ':')
             r = msi_apply_substorage_transform( package, package->db, xforms[i] );
         else
-            r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
+        {
+            WCHAR *transform;
+
+            if (!PathIsRelativeW( xforms[i] )) transform = xforms[i];
+            else
+            {
+                WCHAR *p = strrchrW( package->PackagePath, '\\' );
+                DWORD len = p - package->PackagePath + 1;
+
+                if (!(transform = msi_alloc( (len + strlenW( xforms[i] ) + 1) * sizeof(WCHAR)) ))
+                {
+                    msi_free( xforms );
+                    msi_free( xform_list );
+                    return ERROR_OUTOFMEMORY;
+                }
+                memcpy( transform, package->PackagePath, len * sizeof(WCHAR) );
+                memcpy( transform + len, xforms[i], (strlenW( xforms[i] ) + 1) * sizeof(WCHAR) );
+            }
+            r = MSI_DatabaseApplyTransformW( package->db, transform, 0 );
+            if (transform != xforms[i]) msi_free( transform );
+        }
     }
 
     msi_free( xforms );
@@ -964,6 +1064,9 @@ static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
     MSICOMPONENT *comp;
 
     component = MSI_RecordGetString(row, 2);
+    if (!component)
+        return ERROR_SUCCESS;
+
     comp = get_loaded_component(package, component);
     if (!comp)
         return ERROR_SUCCESS;
@@ -994,7 +1097,7 @@ static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
     ui_actiondata(package, szCreateFolders, uirow);
     msiobj_release(&uirow->hdr);
 
-    full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
+    full_path = resolve_target_folder( package, dir, FALSE, TRUE, &folder );
     if (!full_path)
     {
         ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
@@ -1014,16 +1117,14 @@ static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
 
 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
 {
-    static const WCHAR ExecSeqQuery[] =
-        {'S','E','L','E','C','T',' ',
-         '`','D','i','r','e','c','t','o','r','y','_','`',
-         ' ','F','R','O','M',' ',
-         '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
+    static const WCHAR query[] =
+        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+         '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
     UINT rc;
     MSIQUERY *view;
 
     /* create all the empty folders specified in the CreateFolder table */
-    rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
+    rc = MSI_DatabaseOpenViewW(package->db, query, &view );
     if (rc != ERROR_SUCCESS)
         return ERROR_SUCCESS;
 
@@ -1043,6 +1144,9 @@ static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
     MSICOMPONENT *comp;
 
     component = MSI_RecordGetString(row, 2);
+    if (!component)
+        return ERROR_SUCCESS;
+
     comp = get_loaded_component(package, component);
     if (!comp)
         return ERROR_SUCCESS;
@@ -1068,7 +1172,7 @@ static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
         return ERROR_SUCCESS;
     }
 
-    full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
+    full_path = resolve_target_folder( package, dir, FALSE, TRUE, &folder );
     if (!full_path)
     {
         ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
@@ -1092,8 +1196,8 @@ static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
 {
     static const WCHAR query[] =
-        {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
-         ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
+        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+         '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
 
     MSIQUERY *view;
     UINT rc;
@@ -1131,8 +1235,10 @@ static UINT load_component( MSIRECORD *row, LPVOID param )
     comp->KeyPath = msi_dup_record_field( row, 6 );
 
     comp->Installed = INSTALLSTATE_UNKNOWN;
-    msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
+    comp->Action = INSTALLSTATE_UNKNOWN;
+    comp->ActionRequest = INSTALLSTATE_UNKNOWN;
 
+    comp->assembly = load_assembly( package, comp );
     return ERROR_SUCCESS;
 }
 
@@ -1218,7 +1324,7 @@ static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
 
     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
     {
-        if ( !lstrcmpW( feature->Feature, name ) )
+        if ( !strcmpW( feature->Feature, name ) )
             return feature;
     }
 
@@ -1265,7 +1371,8 @@ static UINT load_feature(MSIRECORD * row, LPVOID param)
     feature->Attributes = MSI_RecordGetInteger(row,8);
 
     feature->Installed = INSTALLSTATE_UNKNOWN;
-    msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
+    feature->Action = INSTALLSTATE_UNKNOWN;
+    feature->ActionRequest = INSTALLSTATE_UNKNOWN;
 
     list_add_tail( &package->features, &feature->entry );
 
@@ -1515,9 +1622,9 @@ static UINT load_folder( MSIRECORD *row, LPVOID param )
     src_long = folder_split_path( src_short, '|' );
 
     /* check for no-op dirs */
-    if (!lstrcmpW(szDot, tgt_short))
+    if (tgt_short && !strcmpW( szDot, tgt_short ))
         tgt_short = szEmpty;
-    if (!lstrcmpW(szDot, src_short))
+    if (src_short && !strcmpW( szDot, src_short ))
         src_short = szEmpty;
 
     if (!tgt_long)
@@ -1636,48 +1743,48 @@ static UINT ACTION_FileCost(MSIPACKAGE *package)
 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
 {
     MSICOMPONENT *comp;
-    INSTALLSTATE state;
     UINT r;
 
-    state = MsiQueryProductStateW(package->ProductCode);
-
     LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
     {
-        if (!comp->ComponentId)
-            continue;
+        if (!comp->ComponentId) continue;
 
-        if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
+        r = MsiQueryComponentStateW( package->ProductCode, NULL,
+                                     MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
+                                     &comp->Installed );
+        if (r != ERROR_SUCCESS)
+            r = MsiQueryComponentStateW( package->ProductCode, NULL,
+                                         MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
+                                         &comp->Installed );
+        if (r != ERROR_SUCCESS)
+            r = MsiQueryComponentStateW( package->ProductCode, NULL,
+                                         MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
+                                         &comp->Installed );
+        if (r != ERROR_SUCCESS)
             comp->Installed = INSTALLSTATE_ABSENT;
-        else
-        {
-            r = MsiQueryComponentStateW(package->ProductCode, NULL,
-                                        package->Context, comp->ComponentId,
-                                        &comp->Installed);
-            if (r != ERROR_SUCCESS)
-                comp->Installed = INSTALLSTATE_ABSENT;
-        }
     }
 }
 
 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
 {
     MSIFEATURE *feature;
-    INSTALLSTATE state;
-
-    state = MsiQueryProductStateW(package->ProductCode);
 
     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
     {
-        if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
+        INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
+
+        if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
             feature->Installed = INSTALLSTATE_ABSENT;
         else
-        {
-            feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
-                                                       feature->Feature);
-        }
+            feature->Installed = state;
     }
 }
 
+static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
+{
+    return (feature->Level > 0 && feature->Level <= level);
+}
+
 static BOOL process_state_property(MSIPACKAGE* package, int level,
                                    LPCWSTR property, INSTALLSTATE state)
 {
@@ -1690,14 +1797,19 @@ static BOOL process_state_property(MSIPACKAGE* package, int level,
 
     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
     {
-        if (lstrcmpW(property, szRemove) &&
-            (feature->Level <= 0 || feature->Level > level))
+        if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
             continue;
 
         if (!strcmpW(property, szReinstall)) state = feature->Installed;
 
-        if (strcmpiW(override, szAll)==0)
-            msi_feature_set_state(package, feature, state);
+        if (!strcmpiW( override, szAll ))
+        {
+            if (feature->Installed != state)
+            {
+                feature->Action = state;
+                feature->ActionRequest = state;
+            }
+        }
         else
         {
             LPWSTR ptr = override;
@@ -1710,7 +1822,11 @@ static BOOL process_state_property(MSIPACKAGE* package, int level,
                 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
                     || (!ptr2 && !strcmpW(ptr, feature->Feature)))
                 {
-                    msi_feature_set_state(package, feature, state);
+                    if (feature->Installed != state)
+                    {
+                        feature->Action = state;
+                        feature->ActionRequest = state;
+                    }
                     break;
                 }
                 if (ptr2)
@@ -1724,7 +1840,6 @@ static BOOL process_state_property(MSIPACKAGE* package, int level,
         }
     }
     msi_free(override);
-
     return TRUE;
 }
 
@@ -1782,17 +1897,25 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
     {
         LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
         {
-            BOOL feature_state = ((feature->Level > 0) &&
-                                  (feature->Level <= level));
+            if (!is_feature_selected( feature, level )) continue;
 
-            if (feature_state && feature->ActionRequest == INSTALLSTATE_UNKNOWN)
+            if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
             {
                 if (feature->Attributes & msidbFeatureAttributesFavorSource)
-                    msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
+                {
+                    feature->Action = INSTALLSTATE_SOURCE;
+                    feature->ActionRequest = INSTALLSTATE_SOURCE;
+                }
                 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
-                    msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
+                {
+                    feature->Action = INSTALLSTATE_ADVERTISED;
+                    feature->ActionRequest = INSTALLSTATE_ADVERTISED;
+                }
                 else
-                    msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
+                {
+                    feature->Action = INSTALLSTATE_LOCAL;
+                    feature->ActionRequest = INSTALLSTATE_LOCAL;
+                }
             }
         }
 
@@ -1801,29 +1924,38 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
         {
             FeatureList *fl;
 
-            if (feature->Level > 0 && feature->Level <= level)
-                continue;
+            if (is_feature_selected( feature, level )) continue;
 
             LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
-                msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
+            {
+                fl->feature->Action = INSTALLSTATE_UNKNOWN;
+                fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
+            }
         }
     }
-    else
+    else /* preselected */
     {
         LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
         {
-            BOOL selected = feature->Level > 0 && feature->Level <= level;
+            if (!is_feature_selected( feature, level )) continue;
 
-            if (selected && feature->ActionRequest == INSTALLSTATE_UNKNOWN)
+            if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
             {
-                 msi_feature_set_state(package, feature, feature->Installed);
+                if (feature->Installed == INSTALLSTATE_ABSENT)
+                {
+                    feature->Action = INSTALLSTATE_UNKNOWN;
+                    feature->ActionRequest = INSTALLSTATE_UNKNOWN;
+                }
+                else
+                {
+                    feature->Action = feature->Installed;
+                    feature->ActionRequest = feature->Installed;
+                }
             }
         }
     }
 
-    /*
-     * now we want to enable or disable components based on feature
-     */
+    /* now we want to set component state based based on feature state */
     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
     {
         ComponentList *cl;
@@ -1832,8 +1964,7 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
               debugstr_w(feature->Feature), feature->Level, feature->Installed,
               feature->ActionRequest, feature->Action);
 
-        if (!feature->Level)
-            continue;
+        if (!is_feature_selected( feature, level )) continue;
 
         /* features with components that have compressed files are made local */
         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
@@ -1841,7 +1972,8 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
             if (cl->component->ForceLocalState &&
                 feature->ActionRequest == INSTALLSTATE_SOURCE)
             {
-                msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
+                feature->Action = INSTALLSTATE_LOCAL;
+                feature->ActionRequest = INSTALLSTATE_LOCAL;
                 break;
             }
         }
@@ -1886,34 +2018,44 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
         {
             if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
                  !component->ForceLocalState)
-                msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
+            {
+                component->Action = INSTALLSTATE_SOURCE;
+                component->ActionRequest = INSTALLSTATE_SOURCE;
+            }
             else
-                msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
+            {
+                component->Action = INSTALLSTATE_LOCAL;
+                component->ActionRequest = INSTALLSTATE_LOCAL;
+            }
             continue;
         }
 
         /* if any feature is local, the component must be local too */
         if (component->hasLocalFeature)
         {
-            msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
+            component->Action = INSTALLSTATE_LOCAL;
+            component->ActionRequest = INSTALLSTATE_LOCAL;
             continue;
         }
-
         if (component->hasSourceFeature)
         {
-            msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
+            component->Action = INSTALLSTATE_SOURCE;
+            component->ActionRequest = INSTALLSTATE_SOURCE;
             continue;
         }
-
         if (component->hasAdvertiseFeature)
         {
-            msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
+            component->Action = INSTALLSTATE_ADVERTISED;
+            component->ActionRequest = INSTALLSTATE_ADVERTISED;
             continue;
         }
-
         TRACE("nobody wants component %s\n", debugstr_w(component->Component));
-        if (component->anyAbsent)
-            msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
+        if (component->anyAbsent &&
+            (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
+        {
+            component->Action = INSTALLSTATE_ABSENT;
+            component->ActionRequest = INSTALLSTATE_ABSENT;
+        }
     }
 
     LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
@@ -1921,7 +2063,16 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
         if (component->ActionRequest == INSTALLSTATE_DEFAULT)
         {
             TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
-            msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
+            component->Action = INSTALLSTATE_LOCAL;
+            component->ActionRequest = INSTALLSTATE_LOCAL;
+        }
+
+        if (component->ActionRequest == INSTALLSTATE_SOURCE &&
+            component->Installed == INSTALLSTATE_SOURCE &&
+            component->hasSourceFeature)
+        {
+            component->Action = INSTALLSTATE_UNKNOWN;
+            component->ActionRequest = INSTALLSTATE_UNKNOWN;
         }
 
         TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
@@ -1947,10 +2098,9 @@ static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
     msi_free(f->ResolvedTarget);
     f->ResolvedTarget = NULL;
 
-    /* This helper function now does ALL the work */
-    TRACE("Dir %s ...\n",debugstr_w(name));
-    path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
-    TRACE("resolves to %s\n",debugstr_w(path));
+    TRACE("directory %s ...\n", debugstr_w(name));
+    path = resolve_target_folder( package, name, TRUE, TRUE, NULL );
+    TRACE("resolves to %s\n", debugstr_w(path));
     msi_free(path);
 
     return ERROR_SUCCESS;
@@ -2028,7 +2178,19 @@ int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
     return 0;
 }
 
-static DWORD get_disk_file_size( LPCWSTR filename )
+int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
+{
+    DWORD ms1, ms2;
+
+    msi_parse_version_string( ver1, &ms1, NULL );
+    msi_parse_version_string( ver2, &ms2, NULL );
+
+    if (ms1 > ms2) return 1;
+    else if (ms1 < ms2) return -1;
+    return 0;
+}
+
+DWORD msi_get_disk_file_size( LPCWSTR filename )
 {
     HANDLE file;
     DWORD size;
@@ -2044,7 +2206,7 @@ static DWORD get_disk_file_size( LPCWSTR filename )
     return size;
 }
 
-static BOOL hash_matches( MSIFILE *file )
+BOOL msi_file_hash_matches( MSIFILE *file )
 {
     UINT r;
     MSIFILEHASHINFO hash;
@@ -2057,77 +2219,95 @@ static BOOL hash_matches( MSIFILE *file )
     return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
 }
 
-static UINT set_file_install_states( MSIPACKAGE *package )
+static WCHAR *get_temp_dir( void )
+{
+    static UINT id;
+    WCHAR tmp[MAX_PATH], dir[MAX_PATH];
+
+    GetTempPathW( MAX_PATH, tmp );
+    for (;;)
+    {
+        if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
+        if (CreateDirectoryW( dir, NULL )) break;
+    }
+    return strdupW( dir );
+}
+
+static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
+{
+    MSIASSEMBLY *assembly = file->Component->assembly;
+
+    TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
+
+    msi_free( file->TargetPath );
+    if (assembly && !assembly->application)
+    {
+        if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
+        file->TargetPath = build_directory_name( 2, assembly->tempdir, file->FileName );
+        track_tempfile( package, file->TargetPath );
+    }
+    else
+    {
+        WCHAR *dir = resolve_target_folder( package, file->Component->Directory, FALSE, TRUE, NULL );
+        file->TargetPath = build_directory_name( 2, dir, file->FileName );
+        msi_free( dir );
+    }
+
+    TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
+}
+
+static UINT calculate_file_cost( MSIPACKAGE *package )
 {
     VS_FIXEDFILEINFO *file_version;
+    WCHAR *font_version;
     MSIFILE *file;
 
     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
     {
-        MSICOMPONENTcomp = file->Component;
+        MSICOMPONENT *comp = file->Component;
         DWORD file_size;
-        LPWSTR p;
 
-        if (!comp)
-            continue;
+        if (!comp->Enabled) continue;
 
         if (file->IsCompressed)
             comp->ForceLocalState = TRUE;
 
-        /* calculate target */
-        p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
-        msi_free(file->TargetPath);
-
-        TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
-
-        file->TargetPath = build_directory_name(2, p, file->FileName);
-        msi_free(p);
-
-        TRACE("file %s resolves to %s\n", debugstr_w(file->File), debugstr_w(file->TargetPath));
+        set_target_path( package, file );
 
-        if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
+        if ((comp->assembly && !comp->assembly->installed) ||
+            GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
         {
-            file->state = msifs_missing;
             comp->Cost += file->FileSize;
             continue;
         }
-        if (file->Version && (file_version = msi_get_disk_file_version( file->TargetPath )))
-        {
-            TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version),
-                  HIWORD(file_version->dwFileVersionMS),
-                  LOWORD(file_version->dwFileVersionMS),
-                  HIWORD(file_version->dwFileVersionLS),
-                  LOWORD(file_version->dwFileVersionLS));
+        file_size = msi_get_disk_file_size( file->TargetPath );
 
-            if (msi_compare_file_versions( file_version, file->Version ) < 0)
+        if (file->Version)
+        {
+            if ((file_version = msi_get_disk_file_version( file->TargetPath )))
             {
-                file->state = msifs_overwrite;
-                comp->Cost += file->FileSize;
+                if (msi_compare_file_versions( file_version, file->Version ) < 0)
+                {
+                    comp->Cost += file->FileSize - file_size;
+                }
+                msi_free( file_version );
+                continue;
             }
-            else
+            else if ((font_version = font_version_from_file( file->TargetPath )))
             {
-                TRACE("Destination file version equal or greater, not overwriting\n");
-                file->state = msifs_present;
+                if (msi_compare_font_versions( font_version, file->Version ) < 0)
+                {
+                    comp->Cost += file->FileSize - file_size;
+                }
+                msi_free( font_version );
+                continue;
             }
-            msi_free( file_version );
-            continue;
         }
-        if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize)
+        if (file_size != file->FileSize)
         {
-            file->state = msifs_overwrite;
             comp->Cost += file->FileSize - file_size;
-            continue;
-        }
-        if (file->hash.dwFileHashInfoSize && hash_matches( file ))
-        {
-            TRACE("File hashes match, not overwriting\n");
-            file->state = msifs_present;
-            continue;
         }
-        file->state = msifs_overwrite;
-        comp->Cost += file->FileSize - file_size;
     }
-
     return ERROR_SUCCESS;
 }
 
@@ -2166,13 +2346,22 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
         msiobj_release(&view->hdr);
     }
 
+    TRACE("Evaluating component conditions\n");
+    LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
+    {
+        if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
+        {
+            TRACE("Disabling component %s\n", debugstr_w(comp->Component));
+            comp->Enabled = FALSE;
+        }
+        else
+            comp->Enabled = TRUE;
+    }
+
     /* read components states from the registry */
     ACTION_GetComponentInstallStates(package);
     ACTION_GetFeatureInstallStates(package);
 
-    TRACE("Calculating file install states\n");
-    set_file_install_states( package );
-
     if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
     {
         TRACE("Evaluating feature conditions\n");
@@ -2184,18 +2373,9 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
             msiobj_release( &view->hdr );
         }
     }
-    TRACE("Evaluating component conditions\n");
 
-    LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
-    {
-        if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
-        {
-            TRACE("Disabling component %s\n", debugstr_w(comp->Component));
-            comp->Enabled = FALSE;
-        }
-        else
-            comp->Enabled = TRUE;
-    }
+    TRACE("Calculating file cost\n");
+    calculate_file_cost( package );
 
     msi_set_property( package->db, szCosting, szOne );
     /* set default run level if not set */
@@ -2313,7 +2493,7 @@ static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
          else
             ptr=value;
 
-        if (strstrW(value,szMulti))
+        if (strstrW(value, szMulti))
             *type = REG_MULTI_SZ;
 
         /* remove initial delimiter */
@@ -2467,6 +2647,7 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
     {
         ERR("Could not create key %s\n", debugstr_w(keypath));
         msi_free(uikey);
+        msi_free(keypath);
         return ERROR_SUCCESS;
     }
 
@@ -2518,6 +2699,7 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
     msi_free(value_data);
     msi_free(deformated);
     msi_free(uikey);
+    msi_free(keypath);
 
     return ERROR_SUCCESS;
 }
@@ -2553,7 +2735,7 @@ static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value,
     {
         if ((res = RegDeleteTreeW( hkey_root, key )))
         {
-            WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
+            TRACE("Failed to delete key %s (%d)\n", debugstr_w(key), res);
         }
         return;
     }
@@ -2562,12 +2744,11 @@ static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value,
     {
         if ((res = RegDeleteValueW( hkey, value )))
         {
-            WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
+            TRACE("Failed to delete value %s (%d)\n", debugstr_w(value), res);
         }
         res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
                                 NULL, NULL, NULL, NULL );
         RegCloseKey( hkey );
-
         if (!res && !num_subkeys && !num_values)
         {
             TRACE("Removing empty key %s\n", debugstr_w(key));
@@ -2575,7 +2756,7 @@ static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value,
         }
         return;
     }
-    WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
+    TRACE("Failed to open key %s (%d)\n", debugstr_w(key), res);
 }
 
 
@@ -2868,7 +3049,7 @@ static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
 {
 
     if (!cmp->KeyPath)
-        return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
+        return resolve_target_folder( package, cmp->Directory, FALSE, TRUE, NULL );
 
     if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
     {
@@ -2970,9 +3151,6 @@ static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
     return count;
 }
 
-/*
- * Return TRUE if the count should be written out and FALSE if not
- */
 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
 {
     MSIFEATURE *feature;
@@ -2981,6 +3159,7 @@ static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
 
     /* only refcount DLLs */
     if (comp->KeyPath == NULL || 
+        comp->assembly ||
         comp->Attributes & msidbComponentAttributesRegistryKeyPath || 
         comp->Attributes & msidbComponentAttributesODBCDataSource)
         write = FALSE;
@@ -3071,7 +3250,19 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
         squash_guid(comp->ComponentId,squished_cc);
 
         msi_free(comp->FullKeypath);
-        comp->FullKeypath = resolve_keypath( package, comp );
+        if (comp->assembly)
+        {
+            const WCHAR prefixW[] = {'<','\\',0};
+            DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
+
+            comp->FullKeypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
+            if (comp->FullKeypath)
+            {
+                strcpyW( comp->FullKeypath, prefixW );
+                strcatW( comp->FullKeypath, comp->assembly->display_name );
+            }
+        }
+        else comp->FullKeypath = resolve_keypath( package, comp );
 
         ACTION_RefCountComponent( package, comp );
 
@@ -3085,15 +3276,10 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
         if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
             comp->ActionRequest == INSTALLSTATE_SOURCE)
         {
-            if (!comp->FullKeypath)
-                continue;
-
             if (package->Context == MSIINSTALLCONTEXT_MACHINE)
-                rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
-                                                     &hkey, TRUE);
+                rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
             else
-                rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
-                                                     &hkey, TRUE);
+                rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
 
             if (rc != ERROR_SUCCESS)
                 continue;
@@ -3127,8 +3313,7 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
                     '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
                     '`','D','i','s','k','I','d','`',0};
 
-                file = get_loaded_file(package, comp->KeyPath);
-                if (!file)
+                if (!comp->KeyPath || !(file = get_loaded_file(package, comp->KeyPath)))
                     continue;
 
                 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
@@ -3260,10 +3445,11 @@ static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
     }
     comp->Action = INSTALLSTATE_LOCAL;
 
-    file = get_loaded_file( package, comp->KeyPath ); 
-    if (!file)
+    if (!comp->KeyPath || !(file = get_loaded_file( package, comp->KeyPath )))
+    {
+        TRACE("component has no key path\n");
         return ERROR_SUCCESS;
-
+    }
     ui_actiondata( package, szRegisterTypeLibraries, row );
 
     module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
@@ -3286,8 +3472,7 @@ static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
 
             helpid = MSI_RecordGetString(row,6);
 
-            if (helpid)
-                help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
+            if (helpid) help = resolve_target_folder( package, helpid, FALSE, TRUE, NULL );
             res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
             msi_free(help);
 
@@ -3421,7 +3606,7 @@ static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
     LPWSTR link_folder, link_file, filename;
 
     directory = MSI_RecordGetString( row, 2 );
-    link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
+    link_folder = resolve_target_folder( package, directory, FALSE, TRUE, NULL );
 
     /* may be needed because of a bug somewhere else */
     create_full_pathW( link_folder );
@@ -3542,7 +3727,7 @@ static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
     if (!MSI_RecordIsNull(row,12))
     {
         LPCWSTR wkdir = MSI_RecordGetString(row, 12);
-        path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
+        path = resolve_target_folder( package, wkdir, FALSE, TRUE, NULL );
         if (path)
             IShellLinkW_SetWorkingDirectory(sl, path);
         msi_free(path);
@@ -3752,7 +3937,7 @@ static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
 
     LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
     {
-        if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
+        if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
             msi_set_last_used_source(package->ProductCode, NULL, info->context,
                                      info->options, info->value);
         else
@@ -4075,7 +4260,7 @@ static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
     dirprop = MSI_RecordGetString( row, 3 );
     if (dirprop)
     {
-        folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
+        folder = resolve_target_folder( package, dirprop, FALSE, TRUE, NULL );
         if (!folder)
             folder = msi_dup_property( package->db, dirprop );
     }
@@ -4855,7 +5040,7 @@ static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
         return ERROR_FUNCTION_FAILED;
     }
 
-    if (!lstrcmpW(features[0], szAll))
+    if (!strcmpW( features[0], szAll ))
         full_uninstall = TRUE;
     else
     {
@@ -4874,21 +5059,16 @@ static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
     MSIREG_DeleteUserDataProductKey(package->ProductCode);
     MSIREG_DeleteUninstallKey(package);
 
-    if (package->Context == MSIINSTALLCONTEXT_MACHINE)
-    {
-        MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
-        MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
-    }
-    else
-    {
-        MSIREG_DeleteUserProductKey(package->ProductCode);
-        MSIREG_DeleteUserFeaturesKey(package->ProductCode);
-    }
+    MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
+    MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
+    MSIREG_DeleteUserProductKey(package->ProductCode);
+    MSIREG_DeleteUserFeaturesKey(package->ProductCode);
 
     upgrade = msi_dup_property(package->db, szUpgradeCode);
     if (upgrade)
     {
         MSIREG_DeleteUserUpgradeCodesKey(upgrade);
+        MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
         msi_free(upgrade);
     }
 
@@ -5100,13 +5280,14 @@ static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
 {
     MSIPACKAGE *package = param;
     LPCWSTR compgroupid, component, feature, qualifier, text;
-    LPWSTR advertise = NULL, output = NULL;
+    LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
     HKEY hkey = NULL;
     UINT rc;
     MSICOMPONENT *comp;
     MSIFEATURE *feat;
     DWORD sz;
     MSIRECORD *uirow;
+    int len;
 
     feature = MSI_RecordGetString(rec, 5);
     feat = get_loaded_feature(package, feature);
@@ -5133,30 +5314,56 @@ static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
     rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
     if (rc != ERROR_SUCCESS)
         goto end;
-    
-    text = MSI_RecordGetString(rec,4);
-    advertise = create_component_advertise_string(package, comp, feature);
-
-    sz = strlenW(advertise);
 
+    advertise = create_component_advertise_string( package, comp, feature );
+    text = MSI_RecordGetString( rec, 4 );
     if (text)
-        sz += lstrlenW(text);
-
-    sz+=3;
-    sz *= sizeof(WCHAR);
-           
-    output = msi_alloc_zero(sz);
-    strcpyW(output,advertise);
-    msi_free(advertise);
+    {
+        p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
+        strcpyW( p, advertise );
+        strcatW( p, text );
+        msi_free( advertise );
+        advertise = p;
+    }
+    existing = msi_reg_get_val_str( hkey, qualifier );
 
-    if (text)
-        strcatW(output,text);
+    sz = strlenW( advertise ) + 1;
+    if (existing)
+    {
+        for (p = existing; *p; p += len)
+        {
+            len = strlenW( p ) + 1;
+            if (strcmpW( advertise, p )) sz += len;
+        }
+    }
+    if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
+    {
+        rc = ERROR_OUTOFMEMORY;
+        goto end;
+    }
+    q = output;
+    if (existing)
+    {
+        for (p = existing; *p; p += len)
+        {
+            len = strlenW( p ) + 1;
+            if (strcmpW( advertise, p ))
+            {
+                memcpy( q, p, len * sizeof(WCHAR) );
+                q += len;
+            }
+        }
+    }
+    strcpyW( q, advertise );
+    q[strlenW( q ) + 1] = 0;
 
     msi_reg_set_val_multi_str( hkey, qualifier, output );
     
 end:
     RegCloseKey(hkey);
-    msi_free(output);
+    msi_free( output );
+    msi_free( advertise );
+    msi_free( existing );
 
     /* the UI chunk */
     uirow = MSI_CreateRecord( 2 );
@@ -5272,11 +5479,11 @@ static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
     MSIRECORD *row;
     MSIFILE *file;
     SC_HANDLE hscm, service = NULL;
-    LPCWSTR comp, depends, pass;
-    LPWSTR name = NULL, disp = NULL;
-    LPCWSTR load_order, serv_name, key;
-    DWORD serv_type, start_type;
-    DWORD err_control;
+    LPCWSTR comp, key;
+    LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
+    LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
+    DWORD serv_type, start_type, err_control;
+    SERVICE_DESCRIPTIONW sd = {NULL};
 
     static const WCHAR query[] =
         {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
@@ -5292,22 +5499,24 @@ static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
         goto done;
     }
 
+    comp = MSI_RecordGetString( rec, 12 );
+    if (!get_loaded_component( package, comp ))
+        goto done;
+
     start_type = MSI_RecordGetInteger(rec, 5);
     if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
         goto done;
 
-    depends = MSI_RecordGetString(rec, 8);
-    if (depends && *depends)
-        FIXME("Dependency list unhandled!\n");
-
     deformat_string(package, MSI_RecordGetString(rec, 2), &name);
     deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
     serv_type = MSI_RecordGetInteger(rec, 4);
     err_control = MSI_RecordGetInteger(rec, 6);
-    load_order = MSI_RecordGetString(rec, 7);
-    serv_name = MSI_RecordGetString(rec, 9);
-    pass = MSI_RecordGetString(rec, 10);
-    comp = MSI_RecordGetString(rec, 12);
+    deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
+    deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
+    deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
+    deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
+    deformat_string(package, MSI_RecordGetString(rec, 11), &args);
+    deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
 
     /* fetch the service path */
     row = MSI_QueryGetRecord(package->db, query, comp);
@@ -5316,7 +5525,6 @@ static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
         ERR("Control query failed!\n");
         goto done;
     }
-
     key = MSI_RecordGetString(row, 6);
 
     file = get_loaded_file(package, key);
@@ -5327,20 +5535,44 @@ static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
         goto done;
     }
 
+    if (!args || !args[0]) image_path = file->TargetPath;
+    else
+    {
+        int len = strlenW(file->TargetPath) + strlenW(args) + 2;
+        if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
+            return ERROR_OUTOFMEMORY;
+
+        strcpyW(image_path, file->TargetPath);
+        strcatW(image_path, szSpace);
+        strcatW(image_path, args);
+    }
     service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
-                             start_type, err_control, file->TargetPath,
-                             load_order, NULL, NULL, serv_name, pass);
+                             start_type, err_control, image_path, load_order,
+                             NULL, depends, serv_name, pass);
+
     if (!service)
     {
         if (GetLastError() != ERROR_SERVICE_EXISTS)
             ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
     }
+    else if (sd.lpDescription)
+    {
+        if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
+            WARN("failed to set service description %u\n", GetLastError());
+    }
 
+    if (image_path != file->TargetPath) msi_free(image_path);
 done:
     CloseServiceHandle(service);
     CloseServiceHandle(hscm);
     msi_free(name);
     msi_free(disp);
+    msi_free(sd.lpDescription);
+    msi_free(load_order);
+    msi_free(serv_name);
+    msi_free(pass);
+    msi_free(depends);
+    msi_free(args);
 
     return ERROR_SUCCESS;
 }
@@ -5780,27 +6012,15 @@ static UINT ACTION_DeleteServices( MSIPACKAGE *package )
     return rc;
 }
 
-static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
-{
-    MSIFILE *file;
-
-    LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
-    {
-        if (!lstrcmpW(file->File, filename))
-            return file;
-    }
-
-    return NULL;
-}
-
-static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
+static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
 {
     MSIPACKAGE *package = param;
     LPWSTR driver, driver_path, ptr;
     WCHAR outpath[MAX_PATH];
-    MSIFILE *driver_file, *setup_file;
+    MSIFILE *driver_file = NULL, *setup_file = NULL;
+    MSICOMPONENT *comp;
     MSIRECORD *uirow;
-    LPCWSTR desc;
+    LPCWSTR desc, file_key, component;
     DWORD len, usage;
     UINT r = ERROR_SUCCESS;
 
@@ -5811,10 +6031,24 @@ static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
     static const WCHAR usage_fmt[] = {
         'F','i','l','e','U','s','a','g','e','=','1',0};
 
+    component = MSI_RecordGetString( rec, 2 );
+    comp = get_loaded_component( package, component );
+    if (!comp)
+        return ERROR_SUCCESS;
+
+    if (!comp->Enabled)
+    {
+        TRACE("component is disabled\n");
+        return ERROR_SUCCESS;
+    }
+
     desc = MSI_RecordGetString(rec, 3);
 
-    driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
-    setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
+    file_key = MSI_RecordGetString( rec, 4 );
+    if (file_key) driver_file = get_loaded_file( package, file_key );
+
+    file_key = MSI_RecordGetString( rec, 5 );
+    if (file_key) setup_file = get_loaded_file( package, file_key );
 
     if (!driver_file)
     {
@@ -5877,9 +6111,10 @@ static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
     MSIPACKAGE *package = param;
     LPWSTR translator, translator_path, ptr;
     WCHAR outpath[MAX_PATH];
-    MSIFILE *translator_file, *setup_file;
+    MSIFILE *translator_file = NULL, *setup_file = NULL;
+    MSICOMPONENT *comp;
     MSIRECORD *uirow;
-    LPCWSTR desc;
+    LPCWSTR desc, file_key, component;
     DWORD len, usage;
     UINT r = ERROR_SUCCESS;
 
@@ -5888,10 +6123,24 @@ static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
     static const WCHAR setup_fmt[] = {
         'S','e','t','u','p','=','%','s',0};
 
+    component = MSI_RecordGetString( rec, 2 );
+    comp = get_loaded_component( package, component );
+    if (!comp)
+        return ERROR_SUCCESS;
+
+    if (!comp->Enabled)
+    {
+        TRACE("component is disabled\n");
+        return ERROR_SUCCESS;
+    }
+
     desc = MSI_RecordGetString(rec, 3);
 
-    translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
-    setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
+    file_key = MSI_RecordGetString( rec, 4 );
+    if (file_key) translator_file = get_loaded_file( package, file_key );
+
+    file_key = MSI_RecordGetString( rec, 5 );
+    if (file_key) setup_file = get_loaded_file( package, file_key );
 
     if (!translator_file)
     {
@@ -5948,8 +6197,9 @@ static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
 {
     MSIPACKAGE *package = param;
+    MSICOMPONENT *comp;
     LPWSTR attrs;
-    LPCWSTR desc, driver;
+    LPCWSTR desc, driver, component;
     WORD request = ODBC_ADD_SYS_DSN;
     INT registration;
     DWORD len;
@@ -5959,6 +6209,17 @@ static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
     static const WCHAR attrs_fmt[] = {
         'D','S','N','=','%','s',0 };
 
+    component = MSI_RecordGetString( rec, 2 );
+    comp = get_loaded_component( package, component );
+    if (!comp)
+        return ERROR_SUCCESS;
+
+    if (!comp->Enabled)
+    {
+        TRACE("component is disabled\n");
+        return ERROR_SUCCESS;
+    }
+
     desc = MSI_RecordGetString(rec, 3);
     driver = MSI_RecordGetString(rec, 4);
     registration = MSI_RecordGetInteger(rec, 5);
@@ -6036,9 +6297,21 @@ static UINT ACTION_InstallODBC( MSIPACKAGE *package )
 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
 {
     MSIPACKAGE *package = param;
+    MSICOMPONENT *comp;
     MSIRECORD *uirow;
     DWORD usage;
-    LPCWSTR desc;
+    LPCWSTR desc, component;
+
+    component = MSI_RecordGetString( rec, 2 );
+    comp = get_loaded_component( package, component );
+    if (!comp)
+        return ERROR_SUCCESS;
+
+    if (!comp->Enabled)
+    {
+        TRACE("component is disabled\n");
+        return ERROR_SUCCESS;
+    }
 
     desc = MSI_RecordGetString( rec, 3 );
     if (!SQLRemoveDriverW( desc, FALSE, &usage ))
@@ -6062,9 +6335,21 @@ static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
 {
     MSIPACKAGE *package = param;
+    MSICOMPONENT *comp;
     MSIRECORD *uirow;
     DWORD usage;
-    LPCWSTR desc;
+    LPCWSTR desc, component;
+
+    component = MSI_RecordGetString( rec, 2 );
+    comp = get_loaded_component( package, component );
+    if (!comp)
+        return ERROR_SUCCESS;
+
+    if (!comp->Enabled)
+    {
+        TRACE("component is disabled\n");
+        return ERROR_SUCCESS;
+    }
 
     desc = MSI_RecordGetString( rec, 3 );
     if (!SQLRemoveTranslatorW( desc, &usage ))
@@ -6088,9 +6373,10 @@ static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
 {
     MSIPACKAGE *package = param;
+    MSICOMPONENT *comp;
     MSIRECORD *uirow;
     LPWSTR attrs;
-    LPCWSTR desc, driver;
+    LPCWSTR desc, driver, component;
     WORD request = ODBC_REMOVE_SYS_DSN;
     INT registration;
     DWORD len;
@@ -6098,6 +6384,17 @@ static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
     static const WCHAR attrs_fmt[] = {
         'D','S','N','=','%','s',0 };
 
+    component = MSI_RecordGetString( rec, 2 );
+    comp = get_loaded_component( package, component );
+    if (!comp)
+        return ERROR_SUCCESS;
+
+    if (!comp->Enabled)
+    {
+        TRACE("component is disabled\n");
+        return ERROR_SUCCESS;
+    }
+
     desc = MSI_RecordGetString( rec, 3 );
     driver = MSI_RecordGetString( rec, 4 );
     registration = MSI_RecordGetInteger( rec, 5 );
@@ -6235,7 +6532,7 @@ static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
         else if (lstrlenW(*value) >= prefix_len)
         {
             ptr += lstrlenW(ptr) - prefix_len;
-            if (!lstrcmpW(ptr, prefix))
+            if (!strcmpW( ptr, prefix ))
             {
                 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
                 {
@@ -6406,7 +6703,7 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
         if (res != ERROR_SUCCESS)
             goto done;
 
-        if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
+        if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
         {
             action = 0x4;
             res = RegDeleteValueW(env, name);
@@ -6590,481 +6887,6 @@ static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
     return rc;
 }
 
-typedef struct tagMSIASSEMBLY
-{
-    struct list entry;
-    MSICOMPONENT *component;
-    MSIFEATURE *feature;
-    MSIFILE *file;
-    LPWSTR manifest;
-    LPWSTR application;
-    LPWSTR display_name;
-    DWORD attributes;
-    BOOL installed;
-} MSIASSEMBLY;
-
-static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
-                                              DWORD dwReserved);
-static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
-                                          LPVOID pvReserved, HMODULE *phModDll);
-
-static BOOL init_functionpointers(void)
-{
-    HRESULT hr;
-    HMODULE hfusion;
-    HMODULE hmscoree;
-
-    static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
-
-    hmscoree = LoadLibraryA("mscoree.dll");
-    if (!hmscoree)
-    {
-        WARN("mscoree.dll not available\n");
-        return FALSE;
-    }
-
-    pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
-    if (!pLoadLibraryShim)
-    {
-        WARN("LoadLibraryShim not available\n");
-        FreeLibrary(hmscoree);
-        return FALSE;
-    }
-
-    hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
-    if (FAILED(hr))
-    {
-        WARN("fusion.dll not available\n");
-        FreeLibrary(hmscoree);
-        return FALSE;
-    }
-
-    pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
-
-    FreeLibrary(hmscoree);
-    return TRUE;
-}
-
-static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
-                             LPWSTR path)
-{
-    IAssemblyCache *cache;
-    MSIRECORD *uirow;
-    HRESULT hr;
-    UINT r = ERROR_FUNCTION_FAILED;
-
-    TRACE("installing assembly: %s\n", debugstr_w(path));
-
-    uirow = MSI_CreateRecord( 2 );
-    MSI_RecordSetStringW( uirow, 2, assembly->display_name );
-    ui_actiondata( package, szMsiPublishAssemblies, uirow );
-    msiobj_release( &uirow->hdr );
-
-    if (assembly->feature)
-        msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
-
-    if (assembly->manifest)
-        FIXME("Manifest unhandled\n");
-
-    if (assembly->application)
-    {
-        FIXME("Assembly should be privately installed\n");
-        return ERROR_SUCCESS;
-    }
-
-    if (assembly->attributes == msidbAssemblyAttributesWin32)
-    {
-        FIXME("Win32 assemblies not handled\n");
-        return ERROR_SUCCESS;
-    }
-
-    hr = pCreateAssemblyCache(&cache, 0);
-    if (FAILED(hr))
-        goto done;
-
-    hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
-    if (FAILED(hr))
-        ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
-
-    r = ERROR_SUCCESS;
-
-done:
-    IAssemblyCache_Release(cache);
-    return r;
-}
-
-typedef struct tagASSEMBLY_LIST
-{
-    MSIPACKAGE *package;
-    IAssemblyCache *cache;
-    struct list *assemblies;
-} ASSEMBLY_LIST;
-
-typedef struct tagASSEMBLY_NAME
-{
-    LPWSTR name;
-    LPWSTR version;
-    LPWSTR culture;
-    LPWSTR pubkeytoken;
-} ASSEMBLY_NAME;
-
-static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
-{
-    ASSEMBLY_NAME *asmname = param;
-    LPCWSTR name = MSI_RecordGetString(rec, 2);
-    LPWSTR val = msi_dup_record_field(rec, 3);
-
-    static const WCHAR Name[] = {'N','a','m','e',0};
-    static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
-    static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
-    static const WCHAR PublicKeyToken[] = {
-        'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
-
-    if (!strcmpiW(name, Name))
-        asmname->name = val;
-    else if (!strcmpiW(name, Version))
-        asmname->version = val;
-    else if (!strcmpiW(name, Culture))
-        asmname->culture = val;
-    else if (!strcmpiW(name, PublicKeyToken))
-        asmname->pubkeytoken = val;
-    else
-        msi_free(val);
-
-    return ERROR_SUCCESS;
-}
-
-static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
-{
-    if (!*str)
-    {
-        *size = lstrlenW(append) + 1;
-        *str = msi_alloc((*size) * sizeof(WCHAR));
-        lstrcpyW(*str, append);
-        return;
-    }
-
-    (*size) += lstrlenW(append);
-    *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
-    lstrcatW(*str, append);
-}
-
-static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
-{
-    static const WCHAR separator[] = {',',' ',0};
-    static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
-    static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
-    static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
-    static const WCHAR query[] = {
-        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
-        '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
-        'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
-        '=','\'','%','s','\'',0};
-    ASSEMBLY_NAME name;
-    MSIQUERY *view;
-    LPWSTR display_name;
-    DWORD size;
-    UINT r;
-
-    display_name = NULL;
-    memset( &name, 0, sizeof(ASSEMBLY_NAME) );
-
-    r = MSI_OpenQuery( db, &view, query, comp->Component );
-    if (r != ERROR_SUCCESS)
-        return NULL;
-
-    MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
-    msiobj_release( &view->hdr );
-
-    if (!name.name)
-    {
-        ERR("No assembly name specified!\n");
-        return NULL;
-    }
-
-    append_str( &display_name, &size, name.name );
-
-    if (name.version)
-    {
-        append_str( &display_name, &size, separator );
-        append_str( &display_name, &size, Version );
-        append_str( &display_name, &size, name.version );
-    }
-    if (name.culture)
-    {
-        append_str( &display_name, &size, separator );
-        append_str( &display_name, &size, Culture );
-        append_str( &display_name, &size, name.culture );
-    }
-    if (name.pubkeytoken)
-    {
-        append_str( &display_name, &size, separator );
-        append_str( &display_name, &size, PublicKeyToken );
-        append_str( &display_name, &size, name.pubkeytoken );
-    }
-
-    msi_free( name.name );
-    msi_free( name.version );
-    msi_free( name.culture );
-    msi_free( name.pubkeytoken );
-
-    return display_name;
-}
-
-static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
-{
-    ASSEMBLY_INFO asminfo;
-    LPWSTR disp;
-    BOOL found = FALSE;
-    HRESULT hr;
-
-    disp = get_assembly_display_name( db, comp );
-    if (!disp)
-        return FALSE;
-
-    memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
-    asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
-
-    hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
-    if (SUCCEEDED(hr))
-        found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
-
-    msi_free( disp );
-    return found;
-}
-
-static UINT load_assembly(MSIRECORD *rec, LPVOID param)
-{
-    ASSEMBLY_LIST *list = param;
-    MSIASSEMBLY *assembly;
-    LPCWSTR component;
-
-    assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
-    if (!assembly)
-        return ERROR_OUTOFMEMORY;
-
-    component = MSI_RecordGetString(rec, 1);
-    assembly->component = get_loaded_component(list->package, component);
-    if (!assembly->component)
-        return ERROR_SUCCESS;
-
-    if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
-        assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
-    {
-        TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
-        assembly->component->Action = assembly->component->Installed;
-        return ERROR_SUCCESS;
-    }
-    assembly->component->Action = assembly->component->ActionRequest;
-
-    assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
-    assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
-
-    if (!assembly->file)
-    {
-        ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
-        return ERROR_FUNCTION_FAILED;
-    }
-
-    assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
-    assembly->application = strdupW(MSI_RecordGetString(rec, 4));
-    assembly->attributes = MSI_RecordGetInteger(rec, 5);
-
-    if (assembly->application)
-    {
-        WCHAR version[24];
-        DWORD size = sizeof(version)/sizeof(WCHAR);
-
-        /* FIXME: we should probably check the manifest file here */
-
-        if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
-            (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
-        {
-            assembly->installed = TRUE;
-        }
-    }
-    else
-        assembly->installed = check_assembly_installed(list->package->db,
-                                                       list->cache,
-                                                       assembly->component);
-
-    list_add_head(list->assemblies, &assembly->entry);
-    return ERROR_SUCCESS;
-}
-
-static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
-{
-    IAssemblyCache *cache = NULL;
-    ASSEMBLY_LIST list;
-    MSIQUERY *view;
-    HRESULT hr;
-    UINT r;
-
-    static const WCHAR query[] =
-        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
-         '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
-
-    r = MSI_DatabaseOpenViewW(package->db, query, &view);
-    if (r != ERROR_SUCCESS)
-        return ERROR_SUCCESS;
-
-    hr = pCreateAssemblyCache(&cache, 0);
-    if (FAILED(hr))
-        return ERROR_FUNCTION_FAILED;
-
-    list.package = package;
-    list.cache = cache;
-    list.assemblies = assemblies;
-
-    r = MSI_IterateRecords(view, NULL, load_assembly, &list);
-    msiobj_release(&view->hdr);
-
-    IAssemblyCache_Release(cache);
-
-    return r;
-}
-
-static void free_assemblies(struct list *assemblies)
-{
-    struct list *item, *cursor;
-
-    LIST_FOR_EACH_SAFE(item, cursor, assemblies)
-    {
-        MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
-
-        list_remove(&assembly->entry);
-        msi_free(assembly->application);
-        msi_free(assembly->manifest);
-        msi_free(assembly->display_name);
-        msi_free(assembly);
-    }
-}
-
-static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
-{
-    MSIASSEMBLY *assembly;
-
-    LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
-    {
-        if (!lstrcmpW(assembly->file->File, file))
-        {
-            *out = assembly;
-            return TRUE;
-        }
-    }
-
-    return FALSE;
-}
-
-static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
-                               LPWSTR *path, DWORD *attrs, PVOID user)
-{
-    MSIASSEMBLY *assembly;
-    WCHAR temppath[MAX_PATH];
-    struct list *assemblies = user;
-    UINT r;
-
-    if (!find_assembly(assemblies, file, &assembly))
-        return FALSE;
-
-    GetTempPathW(MAX_PATH, temppath);
-    PathAddBackslashW(temppath);
-    lstrcatW(temppath, assembly->file->FileName);
-
-    if (action == MSICABEXTRACT_BEGINEXTRACT)
-    {
-        if (assembly->installed)
-            return FALSE;
-
-        *path = strdupW(temppath);
-        *attrs = assembly->file->Attributes;
-    }
-    else if (action == MSICABEXTRACT_FILEEXTRACTED)
-    {
-        assembly->installed = TRUE;
-
-        r = install_assembly(package, assembly, temppath);
-        if (r != ERROR_SUCCESS)
-            ERR("Failed to install assembly\n");
-    }
-
-    return TRUE;
-}
-
-static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
-{
-    UINT r;
-    struct list assemblies = LIST_INIT(assemblies);
-    MSIASSEMBLY *assembly;
-    MSIMEDIAINFO *mi;
-
-    if (!init_functionpointers() || !pCreateAssemblyCache)
-        return ERROR_FUNCTION_FAILED;
-
-    r = load_assemblies(package, &assemblies);
-    if (r != ERROR_SUCCESS)
-        goto done;
-
-    if (list_empty(&assemblies))
-        goto done;
-
-    mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
-    if (!mi)
-    {
-        r = ERROR_OUTOFMEMORY;
-        goto done;
-    }
-
-    LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
-    {
-        if (assembly->installed && !mi->is_continuous)
-            continue;
-
-        if (assembly->file->IsCompressed)
-        {
-            if (assembly->file->disk_id != mi->disk_id || mi->is_continuous)
-            {
-                MSICABDATA data;
-
-                r = ready_media(package, assembly->file, mi);
-                if (r != ERROR_SUCCESS)
-                {
-                    ERR("Failed to ready media\n");
-                    break;
-                }
-
-                data.mi = mi;
-                data.package = package;
-                data.cb = installassembly_cb;
-                data.user = &assemblies;
-
-                if (!msi_cabextract(package, mi, &data))
-                {
-                    ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
-                    r = ERROR_FUNCTION_FAILED;
-                    break;
-                }
-            }
-        }
-        else
-        {
-            LPWSTR source = resolve_file_source(package, assembly->file);
-
-            r = install_assembly(package, assembly, source);
-            if (r != ERROR_SUCCESS)
-                ERR("Failed to install assembly\n");
-
-            msi_free(source);
-        }
-
-        /* FIXME: write Installer assembly reg values */
-    }
-
-done:
-    free_assemblies(&assemblies);
-    return r;
-}
-
 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
 {
     LPWSTR key, template, id;
@@ -7159,6 +6981,101 @@ static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
     return ERROR_SUCCESS;
 }
 
+static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
+{
+    MSIPACKAGE *package = param;
+    const WCHAR *property = MSI_RecordGetString( rec, 1 );
+    WCHAR *value;
+
+    if ((value = msi_dup_property( package->db, property )))
+    {
+        FIXME("remove %s\n", debugstr_w(value));
+        msi_free( value );
+    }
+    return ERROR_SUCCESS;
+}
+
+static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
+{
+    UINT r;
+    MSIQUERY *view;
+
+    static const WCHAR query[] =
+        {'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',
+         ' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
+
+    r = MSI_DatabaseOpenViewW( package->db, query, &view );
+    if (r == ERROR_SUCCESS)
+    {
+        r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
+        msiobj_release( &view->hdr );
+    }
+    return ERROR_SUCCESS;
+}
+
+static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
+{
+    MSIPACKAGE *package = param;
+    int attributes = MSI_RecordGetInteger( rec, 5 );
+
+    if (attributes & msidbUpgradeAttributesMigrateFeatures)
+    {
+        const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
+        const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
+        const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
+        const WCHAR *language = MSI_RecordGetString( rec, 4 );
+        HKEY hkey;
+        UINT r;
+
+        if (package->Context == MSIINSTALLCONTEXT_MACHINE)
+        {
+            r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
+            if (r != ERROR_SUCCESS)
+                return ERROR_SUCCESS;
+        }
+        else
+        {
+            r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
+            if (r != ERROR_SUCCESS)
+                return ERROR_SUCCESS;
+        }
+        RegCloseKey( hkey );
+
+        FIXME("migrate feature states from %s version min %s version max %s language %s\n",
+              debugstr_w(upgrade_code), debugstr_w(version_min),
+              debugstr_w(version_max), debugstr_w(language));
+    }
+    return ERROR_SUCCESS;
+}
+
+static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
+{
+    UINT r;
+    MSIQUERY *view;
+
+    static const WCHAR query[] =
+        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
+
+    if (msi_get_property_int( package->db, szInstalled, 0 ))
+    {
+        TRACE("product is installed, skipping action\n");
+        return ERROR_SUCCESS;
+    }
+    if (msi_get_property_int( package->db, szPreselected, 0 ))
+    {
+        TRACE("Preselected property is set, not migrating feature states\n");
+        return ERROR_SUCCESS;
+    }
+
+    r = MSI_DatabaseOpenViewW( package->db, query, &view );
+    if (r == ERROR_SUCCESS)
+    {
+        r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
+        msiobj_release( &view->hdr );
+    }
+    return ERROR_SUCCESS;
+}
+
 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
                                            LPCSTR action, LPCWSTR table )
 {
@@ -7202,19 +7119,6 @@ static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
     return msi_unimplemented_action_stub( package, "IsolateComponents", table );
 }
 
-static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
-{
-    static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
-    return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
-}
-
-static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
-{
-    static const WCHAR table[] = {
-        'M','s','i','A','s','s','e','m','b','l','y',0 };
-    return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
-}
-
 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
 {
     static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
@@ -7239,12 +7143,6 @@ static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
     return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
 }
 
-static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
-{
-    static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
-    return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
-}
-
 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
 
 static const struct
@@ -7516,7 +7414,9 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
         msi_set_sourcedir_props(package, FALSE);
     }
 
-    msi_parse_command_line( package, szCommandLine, FALSE );
+    rc = msi_parse_command_line( package, szCommandLine, FALSE );
+    if (rc != ERROR_SUCCESS)
+        return rc;
 
     msi_apply_transforms( package );
     msi_apply_patches( package );
index dfab396..c8aea77 100644 (file)
@@ -71,7 +71,7 @@ void msi_parse_version_string(LPCWSTR verStr, PDWORD ms, PDWORD ls)
         x4 = atoiW(ptr + 1);
     /* FIXME: byte-order dependent? */
     *ms = x1 << 16 | x2;
-    *ls = x3 << 16 | x4;
+    if (ls) *ls = x3 << 16 | x4;
 }
 
 /* Fills in sig with the values from the Signature table, where name is the
@@ -796,8 +796,8 @@ static UINT ACTION_RecurseSearchDirectory(MSIPACKAGE *package, LPWSTR *appValue,
         if (hFind != INVALID_HANDLE_VALUE)
         {
             if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
-                lstrcmpW(findData.cFileName, szDot) &&
-                lstrcmpW(findData.cFileName, szDotDot))
+                strcmpW( findData.cFileName, szDot ) &&
+                strcmpW( findData.cFileName, szDotDot ))
             {
                 lstrcpyW(subpath, dir);
                 PathAppendW(subpath, findData.cFileName);
@@ -808,8 +808,8 @@ static UINT ACTION_RecurseSearchDirectory(MSIPACKAGE *package, LPWSTR *appValue,
             while (rc == ERROR_SUCCESS && !*appValue &&
                    FindNextFileW(hFind, &findData) != 0)
             {
-                if (!lstrcmpW(findData.cFileName, szDot) ||
-                    !lstrcmpW(findData.cFileName, szDotDot))
+                if (!strcmpW( findData.cFileName, szDot ) ||
+                    !strcmpW( findData.cFileName, szDotDot ))
                     continue;
 
                 lstrcpyW(subpath, dir);
diff --git a/reactos/dll/win32/msi/assembly.c b/reactos/dll/win32/msi/assembly.c
new file mode 100644 (file)
index 0000000..5199a31
--- /dev/null
@@ -0,0 +1,629 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2010 Hans Leidekker for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "wine/debug.h"
+#include "wine/unicode.h"
+#include "msipriv.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+static HRESULT (WINAPI *pCreateAssemblyCacheNet11)( IAssemblyCache **, DWORD );
+static HRESULT (WINAPI *pCreateAssemblyCacheNet20)( IAssemblyCache **, DWORD );
+static HRESULT (WINAPI *pCreateAssemblyCacheSxs)( IAssemblyCache **, DWORD );
+static HRESULT (WINAPI *pLoadLibraryShim)( LPCWSTR, LPCWSTR, LPVOID, HMODULE * );
+static HRESULT (WINAPI *pGetFileVersion)( LPCWSTR, LPWSTR, DWORD, DWORD * );
+
+static BOOL init_function_pointers( void )
+{
+    static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
+    static const WCHAR szVersion11[] = {'v','1','.','1','.','4','3','2','2',0};
+    static const WCHAR szVersion20[] = {'v','2','.','0','.','5','0','7','2','7',0};
+    HMODULE hfusion11 = NULL, hfusion20 = NULL, hmscoree, hsxs;
+
+    if (pCreateAssemblyCacheNet11 || pCreateAssemblyCacheNet20) return TRUE;
+
+    if (!(hmscoree = LoadLibraryA( "mscoree.dll" ))) return FALSE;
+    if (!(pGetFileVersion = (void *)GetProcAddress( hmscoree, "GetFileVersion" ))) goto error;
+    if (!(pLoadLibraryShim = (void *)GetProcAddress( hmscoree, "LoadLibraryShim" ))) goto error;
+
+    if (!pLoadLibraryShim( szFusion, szVersion11, NULL, &hfusion11 ))
+        pCreateAssemblyCacheNet11 = (void *)GetProcAddress( hfusion11, "CreateAssemblyCache" );
+
+    if (!pLoadLibraryShim( szFusion, szVersion20, NULL, &hfusion20 ))
+        pCreateAssemblyCacheNet20 = (void *)GetProcAddress( hfusion20, "CreateAssemblyCache" );
+
+    if (!pCreateAssemblyCacheNet11 && !pCreateAssemblyCacheNet20) goto error;
+
+    if (!(hsxs = LoadLibraryA( "sxs.dll" ))) goto error;
+    if (!(pCreateAssemblyCacheSxs = (void *)GetProcAddress( hsxs, "CreateAssemblyCache" ))) goto error;
+    return TRUE;
+
+error:
+    pCreateAssemblyCacheNet11 = NULL;
+    pCreateAssemblyCacheNet20 = NULL;
+    FreeLibrary( hfusion11 );
+    FreeLibrary( hfusion20 );
+    FreeLibrary( hmscoree );
+    return FALSE;
+}
+
+static BOOL init_assembly_caches( MSIPACKAGE *package )
+{
+    if (!init_function_pointers()) return FALSE;
+    if (package->cache_net[CLR_VERSION_V11] || package->cache_net[CLR_VERSION_V20]) return TRUE;
+    if (pCreateAssemblyCacheSxs( &package->cache_sxs, 0 ) != S_OK) return FALSE;
+
+    if (pCreateAssemblyCacheNet11) pCreateAssemblyCacheNet11( &package->cache_net[CLR_VERSION_V11], 0 );
+    if (pCreateAssemblyCacheNet20) pCreateAssemblyCacheNet20( &package->cache_net[CLR_VERSION_V20], 0 );
+
+    if (package->cache_net[CLR_VERSION_V11] || package->cache_net[CLR_VERSION_V20])
+    {
+        return TRUE;
+    }
+    if (package->cache_net[CLR_VERSION_V11])
+    {
+        IAssemblyCache_Release( package->cache_net[CLR_VERSION_V11] );
+        package->cache_net[CLR_VERSION_V11] = NULL;
+    }
+    if (package->cache_net[CLR_VERSION_V20])
+    {
+        IAssemblyCache_Release( package->cache_net[CLR_VERSION_V20] );
+        package->cache_net[CLR_VERSION_V20] = NULL;
+    }
+    IAssemblyCache_Release( package->cache_sxs );
+    package->cache_sxs = NULL;
+    return FALSE;
+}
+
+static MSIRECORD *get_assembly_record( MSIPACKAGE *package, const WCHAR *comp )
+{
+    static const WCHAR query[] = {
+        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+         '`','M','s','i','A','s','s','e','m','b','l','y','`',' ',
+         'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
+         ' ','=',' ','\'','%','s','\'',0};
+    MSIQUERY *view;
+    MSIRECORD *rec;
+    UINT r;
+
+    r = MSI_OpenQuery( package->db, &view, query, comp );
+    if (r != ERROR_SUCCESS)
+        return NULL;
+
+    r = MSI_ViewExecute( view, NULL );
+    if (r != ERROR_SUCCESS)
+    {
+        msiobj_release( &view->hdr );
+        return NULL;
+    }
+    r = MSI_ViewFetch( view, &rec );
+    if (r != ERROR_SUCCESS)
+    {
+        msiobj_release( &view->hdr );
+        return NULL;
+    }
+    if (!MSI_RecordGetString( rec, 4 ))
+        TRACE("component is a global assembly\n");
+
+    msiobj_release( &view->hdr );
+    return rec;
+}
+
+struct assembly_name
+{
+    UINT    count;
+    UINT    index;
+    WCHAR **attrs;
+};
+
+static UINT get_assembly_name_attribute( MSIRECORD *rec, LPVOID param )
+{
+    static const WCHAR fmtW[] = {'%','s','=','"','%','s','"',0};
+    static const WCHAR nameW[] = {'n','a','m','e',0};
+    struct assembly_name *name = param;
+    const WCHAR *attr = MSI_RecordGetString( rec, 2 );
+    const WCHAR *value = MSI_RecordGetString( rec, 3 );
+    int len = strlenW( fmtW ) + strlenW( attr ) + strlenW( value );
+
+    if (!(name->attrs[name->index] = msi_alloc( len * sizeof(WCHAR) )))
+        return ERROR_OUTOFMEMORY;
+
+    if (!strcmpiW( attr, nameW )) strcpyW( name->attrs[name->index++], value );
+    else sprintfW( name->attrs[name->index++], fmtW, attr, value );
+    return ERROR_SUCCESS;
+}
+
+static WCHAR *get_assembly_display_name( MSIDATABASE *db, const WCHAR *comp, MSIASSEMBLY *assembly )
+{
+    static const WCHAR commaW[] = {',',0};
+    static const WCHAR queryW[] = {
+        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+        '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
+        'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
+        ' ','=',' ','\'','%','s','\'',0};
+    struct assembly_name name;
+    WCHAR *display_name = NULL;
+    MSIQUERY *view;
+    UINT i, r;
+    int len;
+
+    r = MSI_OpenQuery( db, &view, queryW, comp );
+    if (r != ERROR_SUCCESS)
+        return NULL;
+
+    name.count = 0;
+    name.index = 0;
+    name.attrs = NULL;
+    MSI_IterateRecords( view, &name.count, NULL, NULL );
+    if (!name.count) goto done;
+
+    name.attrs = msi_alloc( name.count * sizeof(WCHAR *) );
+    if (!name.attrs) goto done;
+
+    MSI_IterateRecords( view, NULL, get_assembly_name_attribute, &name );
+
+    len = 0;
+    for (i = 0; i < name.count; i++) len += strlenW( name.attrs[i] ) + 1;
+
+    display_name = msi_alloc( (len + 1) * sizeof(WCHAR) );
+    if (display_name)
+    {
+        display_name[0] = 0;
+        for (i = 0; i < name.count; i++)
+        {
+            strcatW( display_name, name.attrs[i] );
+            if (i < name.count - 1) strcatW( display_name, commaW );
+        }
+    }
+
+done:
+    msiobj_release( &view->hdr );
+    for (i = 0; i < name.count; i++) msi_free( name.attrs[i] );
+    msi_free( name.attrs );
+    return display_name;
+}
+
+static BOOL is_assembly_installed( IAssemblyCache *cache, const WCHAR *display_name )
+{
+    HRESULT hr;
+    ASSEMBLY_INFO info;
+
+    memset( &info, 0, sizeof(info) );
+    info.cbAssemblyInfo = sizeof(info);
+    hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_GETSIZE, display_name, &info );
+    if (FAILED( hr ))
+    {
+        TRACE("QueryAssemblyInfo returned 0x%08x\n", hr);
+        return FALSE;
+    }
+    return (info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
+}
+
+static const WCHAR clr_version_v11[] = {'v','1','.','1','.','4','3','2','2',0};
+static const WCHAR clr_version_v20[] = {'v','2','.','0','.','5','0','7','2','7',0};
+static const WCHAR clr_version_unknown[] = {'u','n','k','n','o','w','n',0};
+
+static const WCHAR *clr_version[] =
+{
+    clr_version_v11,
+    clr_version_v20
+};
+
+static const WCHAR *get_clr_version_str( enum clr_version version )
+{
+    if (version >= sizeof(clr_version)/sizeof(clr_version[0])) return clr_version_unknown;
+    return clr_version[version];
+}
+
+MSIASSEMBLY *load_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
+{
+    MSIRECORD *rec;
+    MSIASSEMBLY *a;
+
+    if (!(rec = get_assembly_record( package, comp->Component ))) return NULL;
+    if (!init_assembly_caches( package ))
+    {
+        ERR("can't initialize assembly caches\n");
+        msiobj_release( &rec->hdr );
+        return NULL;
+    }
+    if (!(a = msi_alloc_zero( sizeof(MSIASSEMBLY) )))
+    {
+        msiobj_release( &rec->hdr );
+        return NULL;
+    }
+    a->feature = strdupW( MSI_RecordGetString( rec, 2 ) );
+    TRACE("feature %s\n", debugstr_w(a->feature));
+
+    a->manifest = strdupW( MSI_RecordGetString( rec, 3 ) );
+    TRACE("manifest %s\n", debugstr_w(a->manifest));
+
+    a->application = strdupW( MSI_RecordGetString( rec, 4 ) );
+    TRACE("application %s\n", debugstr_w(a->application));
+
+    a->attributes = MSI_RecordGetInteger( rec, 5 );
+    TRACE("attributes %u\n", a->attributes);
+
+    if (!(a->display_name = get_assembly_display_name( package->db, comp->Component, a )))
+    {
+        WARN("can't get display name\n");
+        msiobj_release( &rec->hdr );
+        msi_free( a->feature );
+        msi_free( a->manifest );
+        msi_free( a->application );
+        msi_free( a );
+        return NULL;
+    }
+    TRACE("display name %s\n", debugstr_w(a->display_name));
+
+    if (a->application)
+    {
+        /* We can't check the manifest here because the target path may still change.
+           So we assume that the assembly is not installed and lean on the InstallFiles
+           action to determine which files need to be installed.
+         */
+        a->installed = FALSE;
+    }
+    else
+    {
+        if (a->attributes == msidbAssemblyAttributesWin32)
+            a->installed = is_assembly_installed( package->cache_sxs, a->display_name );
+        else
+        {
+            UINT i;
+            for (i = 0; i < CLR_VERSION_MAX; i++)
+            {
+                a->clr_version[i] = is_assembly_installed( package->cache_net[i], a->display_name );
+                if (a->clr_version[i])
+                {
+                    TRACE("runtime version %s\n", debugstr_w(get_clr_version_str( i )));
+                    a->installed = TRUE;
+                }
+            }
+        }
+    }
+    TRACE("assembly is %s\n", a->installed ? "installed" : "not installed");
+    msiobj_release( &rec->hdr );
+    return a;
+}
+
+static enum clr_version get_clr_version( const WCHAR *filename )
+{
+    DWORD len;
+    HRESULT hr;
+    enum clr_version version = CLR_VERSION_V11;
+    WCHAR *strW;
+
+    hr = pGetFileVersion( filename, NULL, 0, &len );
+    if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) return CLR_VERSION_V11;
+    if ((strW = msi_alloc( len * sizeof(WCHAR) )))
+    {
+        hr = pGetFileVersion( filename, strW, len, &len );
+        if (hr == S_OK)
+        {
+            UINT i;
+            for (i = 0; i < CLR_VERSION_MAX; i++)
+                if (!strcmpW( strW, clr_version[i] )) version = i;
+        }
+        msi_free( strW );
+    }
+    return version;
+}
+
+UINT install_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
+{
+    HRESULT hr;
+    const WCHAR *manifest;
+    IAssemblyCache *cache;
+    MSIASSEMBLY *assembly = comp->assembly;
+    MSIFEATURE *feature = NULL;
+
+    if (comp->assembly->feature)
+        feature = get_loaded_feature( package, comp->assembly->feature );
+
+    if (assembly->application)
+    {
+        if (feature) feature->Action = INSTALLSTATE_LOCAL;
+        return ERROR_SUCCESS;
+    }
+    if (assembly->attributes == msidbAssemblyAttributesWin32)
+    {
+        if (!assembly->manifest)
+        {
+            WARN("no manifest\n");
+            return ERROR_FUNCTION_FAILED;
+        }
+        manifest = get_loaded_file( package, assembly->manifest )->TargetPath;
+        cache = package->cache_sxs;
+    }
+    else
+    {
+        manifest = get_loaded_file( package, comp->KeyPath )->TargetPath;
+        cache = package->cache_net[get_clr_version( manifest )];
+    }
+    TRACE("installing assembly %s\n", debugstr_w(manifest));
+
+    hr = IAssemblyCache_InstallAssembly( cache, 0, manifest, NULL );
+    if (hr != S_OK)
+    {
+        ERR("Failed to install assembly %s (0x%08x)\n", debugstr_w(manifest), hr);
+        return ERROR_FUNCTION_FAILED;
+    }
+    if (feature) feature->Action = INSTALLSTATE_LOCAL;
+    assembly->installed = TRUE;
+    return ERROR_SUCCESS;
+}
+
+static WCHAR *build_local_assembly_path( const WCHAR *filename )
+{
+    UINT i;
+    WCHAR *ret;
+
+    if (!(ret = msi_alloc( (strlenW( filename ) + 1) * sizeof(WCHAR) )))
+        return NULL;
+
+    for (i = 0; filename[i]; i++)
+    {
+        if (filename[i] == '\\' || filename[i] == '/') ret[i] = '|';
+        else ret[i] = filename[i];
+    }
+    ret[i] = 0;
+    return ret;
+}
+
+static LONG open_assemblies_key( UINT context, BOOL win32, HKEY *hkey )
+{
+    static const WCHAR path_win32[] =
+        {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
+          'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',0};
+    static const WCHAR path_dotnet[] =
+        {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
+         'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',0};
+    static const WCHAR classes_path_win32[] =
+        {'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',0};
+    static const WCHAR classes_path_dotnet[] =
+        {'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',0};
+    HKEY root;
+    const WCHAR *path;
+
+    if (context == MSIINSTALLCONTEXT_MACHINE)
+    {
+        root = HKEY_CLASSES_ROOT;
+        if (win32) path = classes_path_win32;
+        else path = classes_path_dotnet;
+    }
+    else
+    {
+        root = HKEY_CURRENT_USER;
+        if (win32) path = path_win32;
+        else path = path_dotnet;
+    }
+    return RegCreateKeyW( root, path, hkey );
+}
+
+static LONG open_local_assembly_key( UINT context, BOOL win32, const WCHAR *filename, HKEY *hkey )
+{
+    LONG res;
+    HKEY root;
+    WCHAR *path;
+
+    if (!(path = build_local_assembly_path( filename )))
+        return ERROR_OUTOFMEMORY;
+
+    if ((res = open_assemblies_key( context, win32, &root )))
+    {
+        msi_free( path );
+        return res;
+    }
+    res = RegCreateKeyW( root, path, hkey );
+    RegCloseKey( root );
+    msi_free( path );
+    return res;
+}
+
+static LONG delete_local_assembly_key( UINT context, BOOL win32, const WCHAR *filename )
+{
+    LONG res;
+    HKEY root;
+    WCHAR *path;
+
+    if (!(path = build_local_assembly_path( filename )))
+        return ERROR_OUTOFMEMORY;
+
+    if ((res = open_assemblies_key( context, win32, &root )))
+    {
+        msi_free( path );
+        return res;
+    }
+    res = RegDeleteKeyW( root, path );
+    RegCloseKey( root );
+    msi_free( path );
+    return res;
+}
+
+static LONG open_global_assembly_key( UINT context, BOOL win32, HKEY *hkey )
+{
+    static const WCHAR path_win32[] =
+        {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
+         'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',
+         'G','l','o','b','a','l',0};
+    static const WCHAR path_dotnet[] =
+        {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
+         'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',
+         'G','l','o','b','a','l',0};
+    static const WCHAR classes_path_win32[] =
+        {'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',
+         'G','l','o','b','a','l',0};
+    static const WCHAR classes_path_dotnet[] =
+        {'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\','G','l','o','b','a','l',0};
+    HKEY root;
+    const WCHAR *path;
+
+    if (context == MSIINSTALLCONTEXT_MACHINE)
+    {
+        root = HKEY_CLASSES_ROOT;
+        if (win32) path = classes_path_win32;
+        else path = classes_path_dotnet;
+    }
+    else
+    {
+        root = HKEY_CURRENT_USER;
+        if (win32) path = path_win32;
+        else path = path_dotnet;
+    }
+    return RegCreateKeyW( root, path, hkey );
+}
+
+UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
+{
+    MSICOMPONENT *comp;
+
+    LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
+    {
+        LONG res;
+        HKEY hkey;
+        GUID guid;
+        DWORD size;
+        WCHAR buffer[43];
+        MSIRECORD *uirow;
+        MSIASSEMBLY *assembly = comp->assembly;
+        BOOL win32;
+
+        if (!assembly || !comp->ComponentId) continue;
+
+        if (!comp->Enabled)
+        {
+            TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
+            continue;
+        }
+
+        if (comp->ActionRequest != INSTALLSTATE_LOCAL)
+        {
+            TRACE("Component not scheduled for installation: %s\n", debugstr_w(comp->Component));
+            comp->Action = comp->Installed;
+            continue;
+        }
+        comp->Action = INSTALLSTATE_LOCAL;
+
+        TRACE("publishing %s\n", debugstr_w(comp->Component));
+
+        CLSIDFromString( package->ProductCode, &guid );
+        encode_base85_guid( &guid, buffer );
+        buffer[20] = '>';
+        CLSIDFromString( comp->ComponentId, &guid );
+        encode_base85_guid( &guid, buffer + 21 );
+        buffer[42] = 0;
+
+        win32 = assembly->attributes & msidbAssemblyAttributesWin32;
+        if (assembly->application)
+        {
+            MSIFILE *file = get_loaded_file( package, assembly->application );
+            if ((res = open_local_assembly_key( package->Context, win32, file->TargetPath, &hkey )))
+            {
+                WARN("failed to open local assembly key %d\n", res);
+                return ERROR_FUNCTION_FAILED;
+            }
+        }
+        else
+        {
+            if ((res = open_global_assembly_key( package->Context, win32, &hkey )))
+            {
+                WARN("failed to open global assembly key %d\n", res);
+                return ERROR_FUNCTION_FAILED;
+            }
+        }
+        size = sizeof(buffer);
+        if ((res = RegSetValueExW( hkey, assembly->display_name, 0, REG_MULTI_SZ, (const BYTE *)buffer, size )))
+        {
+            WARN("failed to set assembly value %d\n", res);
+        }
+        RegCloseKey( hkey );
+
+        uirow = MSI_CreateRecord( 2 );
+        MSI_RecordSetStringW( uirow, 2, assembly->display_name );
+        ui_actiondata( package, szMsiPublishAssemblies, uirow );
+        msiobj_release( &uirow->hdr );
+    }
+    return ERROR_SUCCESS;
+}
+
+UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
+{
+    MSICOMPONENT *comp;
+
+    LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
+    {
+        LONG res;
+        MSIRECORD *uirow;
+        MSIASSEMBLY *assembly = comp->assembly;
+        BOOL win32;
+
+        if (!assembly || !comp->ComponentId) continue;
+
+        if (!comp->Enabled)
+        {
+            TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
+            continue;
+        }
+
+        if (comp->ActionRequest != INSTALLSTATE_ABSENT)
+        {
+            TRACE("Component not scheduled for removal: %s\n", debugstr_w(comp->Component));
+            comp->Action = comp->Installed;
+            continue;
+        }
+        comp->Action = INSTALLSTATE_ABSENT;
+
+        TRACE("unpublishing %s\n", debugstr_w(comp->Component));
+
+        win32 = assembly->attributes & msidbAssemblyAttributesWin32;
+        if (assembly->application)
+        {
+            MSIFILE *file = get_loaded_file( package, assembly->application );
+            if ((res = delete_local_assembly_key( package->Context, win32, file->TargetPath )))
+                WARN("failed to delete local assembly key %d\n", res);
+        }
+        else
+        {
+            HKEY hkey;
+            if ((res = open_global_assembly_key( package->Context, win32, &hkey )))
+                WARN("failed to delete global assembly key %d\n", res);
+            else
+            {
+                if ((res = RegDeleteValueW( hkey, assembly->display_name )))
+                    WARN("failed to delete global assembly value %d\n", res);
+                RegCloseKey( hkey );
+            }
+        }
+
+        uirow = MSI_CreateRecord( 2 );
+        MSI_RecordSetStringW( uirow, 2, assembly->display_name );
+        ui_actiondata( package, szMsiPublishAssemblies, uirow );
+        msiobj_release( &uirow->hdr );
+    }
+    return ERROR_SUCCESS;
+}
index beaf1f0..d11f48b 100644 (file)
@@ -87,7 +87,7 @@ static MSIAPPID *load_given_appid( MSIPACKAGE *package, LPCWSTR name )
     /* check for appids already loaded */
     LIST_FOR_EACH_ENTRY( appid, &package->appids, MSIAPPID, entry )
     {
-        if (lstrcmpiW( appid->AppID, name )==0)
+        if (!strcmpiW( appid->AppID, name ))
         {
             TRACE("found appid %s %p\n", debugstr_w(name), appid);
             return appid;
@@ -192,7 +192,7 @@ static MSIPROGID *load_given_progid(MSIPACKAGE *package, LPCWSTR name)
     /* check for progids already loaded */
     LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry )
     {
-        if (strcmpiW( progid->ProgID,name )==0)
+        if (!strcmpiW( progid->ProgID, name ))
         {
             TRACE("found progid %s (%p)\n",debugstr_w(name), progid );
             return progid;
@@ -323,7 +323,7 @@ static MSICLASS *load_given_class(MSIPACKAGE *package, LPCWSTR classid)
     /* check for classes already loaded */
     LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry )
     {
-        if (lstrcmpiW( cls->clsid, classid )==0)
+        if (!strcmpiW( cls->clsid, classid ))
         {
             TRACE("found class %s (%p)\n",debugstr_w(classid), cls);
             return cls;
@@ -384,7 +384,7 @@ static MSIMIME *load_given_mime( MSIPACKAGE *package, LPCWSTR mime )
     /* check for mime already loaded */
     LIST_FOR_EACH_ENTRY( mt, &package->mimes, MSIMIME, entry )
     {
-        if (strcmpiW(mt->ContentType,mime)==0)
+        if (!strcmpiW( mt->ContentType, mime ))
         {
             TRACE("found mime %s (%p)\n",debugstr_w(mime), mt);
             return mt;
@@ -458,7 +458,7 @@ static MSIEXTENSION *load_given_extension( MSIPACKAGE *package, LPCWSTR name )
     /* check for extensions already loaded */
     LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry )
     {
-        if (strcmpiW( ext->Extension, name )==0)
+        if (!strcmpiW( ext->Extension, name ))
         {
             TRACE("extension %s already loaded %p\n", debugstr_w(name), ext);
             return ext;
@@ -578,7 +578,7 @@ static UINT iterate_all_extensions(MSIRECORD *rec, LPVOID param)
 
     LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry )
     {
-        if (strcmpiW(extension,ext->Extension))
+        if (strcmpiW(extension, ext->Extension))
             continue;
         if (comp == ext->Component)
         {
@@ -850,8 +850,7 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
         }
         feature->Action = feature->ActionRequest;
 
-        file = get_loaded_file( package, comp->KeyPath );
-        if (!file)
+        if (!comp->KeyPath || !(file = get_loaded_file( package, comp->KeyPath )))
         {
             TRACE("COM server not provided, skipping class %s\n", debugstr_w(cls->clsid));
             continue;
index e68723d..eff848b 100644 (file)
@@ -2323,26 +2323,36 @@ static INT compare_substring( LPCWSTR a, INT operator, LPCWSTR b )
     switch (operator)
     {
     case COND_SS:
-        return strstrW( a, b ) ? 1 : 0;
+        return strstrW( a, b ) != 0;
     case COND_ISS:
-        return strstriW( a, b ) ? 1 : 0;
+        return strstriW( a, b ) != 0;
     case COND_LHS:
-       return 0 == strncmpW( a, b, lstrlenW( b ) );
+    {
+        int l = strlenW( a );
+        int r = strlenW( b );
+        if (r > l) return 0;
+        return !strncmpW( a, b, r );
+    }
     case COND_RHS:
     {
-        int l = lstrlenW( a );
-        int r = lstrlenW( b );
+        int l = strlenW( a );
+        int r = strlenW( b );
         if (r > l) return 0;
-        return 0 == lstrcmpW( a + (l - r), b );
+        return !strncmpW( a + (l - r), b, r );
     }
     case COND_ILHS:
-       return 0 == strncmpiW( a, b, lstrlenW( b ) );
+    {
+        int l = strlenW( a );
+        int r = strlenW( b );
+        if (r > l) return 0;
+        return !strncmpiW( a, b, r );
+    }
     case COND_IRHS:
     {
-        int l = lstrlenW( a );
-        int r = lstrlenW( b );
+        int l = strlenW( a );
+        int r = strlenW( b );
         if (r > l) return 0;
-        return 0 == lstrcmpiW( a + (l - r), b );
+        return !strncmpiW( a + (l - r), b, r );
     }
     default:
        ERR("invalid substring operator\n");
@@ -2367,29 +2377,29 @@ static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b, BOOL convert )
     switch (operator)
     {
     case COND_LT:
-        return -1 == lstrcmpW( a, b );
+        return strcmpW( a, b ) < 0;
     case COND_GT:
-        return  1 == lstrcmpW( a, b );
+        return strcmpW( a, b ) > 0;
     case COND_EQ:
-        return  0 == lstrcmpW( a, b );
+        return strcmpW( a, b ) == 0;
     case COND_NE:
-        return  0 != lstrcmpW( a, b );
+        return strcmpW( a, b ) != 0;
     case COND_GE:
-        return -1 != lstrcmpW( a, b );
+        return strcmpW( a, b ) >= 0;
     case COND_LE:
-        return  1 != lstrcmpW( a, b );
+        return strcmpW( a, b ) <= 0;
     case COND_ILT:
-        return -1 == lstrcmpiW( a, b );
+        return strcmpiW( a, b ) < 0;
     case COND_IGT:
-        return  1 == lstrcmpiW( a, b );
+        return strcmpiW( a, b ) > 0;
     case COND_IEQ:
-        return  0 == lstrcmpiW( a, b );
+        return strcmpiW( a, b ) == 0;
     case COND_INE:
-        return  0 != lstrcmpiW( a, b );
+        return strcmpiW( a, b ) != 0;
     case COND_IGE:
-        return -1 != lstrcmpiW( a, b );
+        return strcmpiW( a, b ) >= 0;
     case COND_ILE:
-        return  1 != lstrcmpiW( a, b );
+        return strcmpiW( a, b ) <= 0;
     default:
         ERR("invalid string operator\n");
         return 0;
index 03ea493..5bde044 100644 (file)
@@ -456,26 +456,36 @@ static INT compare_substring( LPCWSTR a, INT operator, LPCWSTR b )
     switch (operator)
     {
     case COND_SS:
-        return strstrW( a, b ) ? 1 : 0;
+        return strstrW( a, b ) != 0;
     case COND_ISS:
-        return strstriW( a, b ) ? 1 : 0;
+        return strstriW( a, b ) != 0;
     case COND_LHS:
-       return 0 == strncmpW( a, b, lstrlenW( b ) );
+    {
+        int l = strlenW( a );
+        int r = strlenW( b );
+        if (r > l) return 0;
+        return !strncmpW( a, b, r );
+    }
     case COND_RHS:
     {
-        int l = lstrlenW( a );
-        int r = lstrlenW( b );
+        int l = strlenW( a );
+        int r = strlenW( b );
         if (r > l) return 0;
-        return 0 == lstrcmpW( a + (l - r), b );
+        return !strncmpW( a + (l - r), b, r );
     }
     case COND_ILHS:
-       return 0 == strncmpiW( a, b, lstrlenW( b ) );
+    {
+        int l = strlenW( a );
+        int r = strlenW( b );
+        if (r > l) return 0;
+        return !strncmpiW( a, b, r );
+    }
     case COND_IRHS:
     {
-        int l = lstrlenW( a );
-        int r = lstrlenW( b );
+        int l = strlenW( a );
+        int r = strlenW( b );
         if (r > l) return 0;
-        return 0 == lstrcmpiW( a + (l - r), b );
+        return !strncmpiW( a + (l - r), b, r );
     }
     default:
        ERR("invalid substring operator\n");
@@ -500,29 +510,29 @@ static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b, BOOL convert )
     switch (operator)
     {
     case COND_LT:
-        return -1 == lstrcmpW( a, b );
+        return strcmpW( a, b ) < 0;
     case COND_GT:
-        return  1 == lstrcmpW( a, b );
+        return strcmpW( a, b ) > 0;
     case COND_EQ:
-        return  0 == lstrcmpW( a, b );
+        return strcmpW( a, b ) == 0;
     case COND_NE:
-        return  0 != lstrcmpW( a, b );
+        return strcmpW( a, b ) != 0;
     case COND_GE:
-        return -1 != lstrcmpW( a, b );
+        return strcmpW( a, b ) >= 0;
     case COND_LE:
-        return  1 != lstrcmpW( a, b );
+        return strcmpW( a, b ) <= 0;
     case COND_ILT:
-        return -1 == lstrcmpiW( a, b );
+        return strcmpiW( a, b ) < 0;
     case COND_IGT:
-        return  1 == lstrcmpiW( a, b );
+        return strcmpiW( a, b ) > 0;
     case COND_IEQ:
-        return  0 == lstrcmpiW( a, b );
+        return strcmpiW( a, b ) == 0;
     case COND_INE:
-        return  0 != lstrcmpiW( a, b );
+        return strcmpiW( a, b ) != 0;
     case COND_IGE:
-        return -1 != lstrcmpiW( a, b );
+        return strcmpiW( a, b ) >= 0;
     case COND_ILE:
-        return  1 != lstrcmpiW( a, b );
+        return strcmpiW( a, b ) <= 0;
     default:
         ERR("invalid string operator\n");
         return 0;
index 2e13d59..c55390c 100644 (file)
@@ -24,6 +24,7 @@
 #include "winbase.h"
 #include "winerror.h"
 #include "wine/debug.h"
+#include "wine/unicode.h"
 #include "msi.h"
 #include "msiquery.h"
 #include "objbase.h"
@@ -153,7 +154,7 @@ static UINT check_columns( const column_info *col_info )
     /* check for two columns with the same name */
     for( c1 = col_info; c1; c1 = c1->next )
         for( c2 = c1->next; c2; c2 = c2->next )
-            if (!lstrcmpW(c1->column, c2->column))
+            if (!strcmpW( c1->column, c2->column ))
                 return ERROR_BAD_QUERY_SYNTAX;
 
     return ERROR_SUCCESS;
index b56139f..83a750d 100644 (file)
@@ -236,7 +236,7 @@ UINT ACTION_CustomAction(MSIPACKAGE *package, LPCWSTR action, UINT script, BOOL
             }
             else if (type & msidbCustomActionTypeRollback)
             {
-                FIXME("Deferring rollback only action... rollbacks not supported yet\n");
+                FIXME("Deferring rollback only action\n");
                 schedule_action(package, ROLLBACK_SCRIPT, deferred);
             }
             else
@@ -274,6 +274,12 @@ UINT ACTION_CustomAction(MSIPACKAGE *package, LPCWSTR action, UINT script, BOOL
 
             msi_free(actiondata);
         }
+        if (type & msidbCustomActionTypeRollback)
+        {
+            FIXME("Rollbacks not supported yet\n");
+            rc = ERROR_SUCCESS;
+            goto end;
+        }
     }
     else if (!check_execution_scheduling_options(package,action,type))
     {
@@ -355,60 +361,88 @@ end:
     return rc;
 }
 
-
-static UINT store_binary_to_temp(MSIPACKAGE *package, LPCWSTR source,
-                                LPWSTR tmp_file)
+static MSIBINARY *create_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL dll )
 {
     static const WCHAR query[] = {
         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
         '`','B','i' ,'n','a','r','y','`',' ','W','H','E','R','E',' ',
         '`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0};
-    MSIRECORD *row = 0;
+    MSIRECORD *row;
+    MSIBINARY *binary;
     HANDLE file;
     CHAR buffer[1024];
-    WCHAR fmt[MAX_PATH];
-    DWORD sz = MAX_PATH;
+    WCHAR fmt[MAX_PATH], tmpfile[MAX_PATH];
+    DWORD sz = MAX_PATH, write;
     UINT r;
 
     if (msi_get_property(package->db, cszTempFolder, fmt, &sz) != ERROR_SUCCESS)
         GetTempPathW(MAX_PATH, fmt);
 
-    if (GetTempFileNameW(fmt, szMsi, 0, tmp_file) == 0)
+    if (!GetTempFileNameW( fmt, szMsi, 0, tmpfile ))
     {
-        TRACE("Unable to create file\n");
-        return ERROR_FUNCTION_FAILED;
+        TRACE("unable to create temp file %s (%u)\n", debugstr_w(tmpfile), GetLastError());
+        return NULL;
     }
-    track_tempfile(package, tmp_file);
 
     row = MSI_QueryGetRecord(package->db, query, source);
     if (!row)
-        return ERROR_FUNCTION_FAILED;
+        return NULL;
 
-    /* write out the file */
-    file = CreateFileW(tmp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
-                       FILE_ATTRIBUTE_NORMAL, NULL);
+    if (!(binary = msi_alloc_zero( sizeof(MSIBINARY) )))
+    {
+        msiobj_release( &row->hdr );
+        return NULL;
+    }
+    file = CreateFileW( tmpfile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
     if (file == INVALID_HANDLE_VALUE)
-        r = ERROR_FUNCTION_FAILED;
-    else
     {
-        do
+        msiobj_release( &row->hdr );
+        msi_free( binary );
+        return NULL;
+    }
+    do
+    {
+        sz = sizeof(buffer);
+        r = MSI_RecordReadStream( row, 2, buffer, &sz );
+        if (r != ERROR_SUCCESS)
         {
-            DWORD write;
-            sz = sizeof buffer;
-            r = MSI_RecordReadStream(row, 2, buffer, &sz);
-            if (r != ERROR_SUCCESS)
-            {
-                ERR("Failed to get stream\n");
-                break;
-            }
-            WriteFile(file, buffer, sz, &write, NULL);
-        } while (sz == sizeof buffer);
-        CloseHandle(file);
+            ERR("Failed to get stream\n");
+            break;
+        }
+        WriteFile( file, buffer, sz, &write, NULL );
+    } while (sz == sizeof buffer);
+
+    CloseHandle( file );
+    msiobj_release( &row->hdr );
+    if (r != ERROR_SUCCESS)
+    {
+        DeleteFileW( tmpfile );
+        msi_free( binary );
+        return NULL;
     }
 
-    msiobj_release(&row->hdr);
+    /* keep a reference to prevent the dll from being unloaded */
+    if (dll && !(binary->module = LoadLibraryW( tmpfile )))
+    {
+        WARN( "failed to load dll %s (%u)\n", debugstr_w( tmpfile ), GetLastError() );
+    }
+    binary->source = strdupW( source );
+    binary->tmpfile = strdupW( tmpfile );
+    list_add_tail( &package->binaries, &binary->entry );
+    return binary;
+}
 
-    return r;
+static MSIBINARY *get_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL dll )
+{
+    MSIBINARY *binary;
+
+    LIST_FOR_EACH_ENTRY( binary, &package->binaries, MSIBINARY, entry )
+    {
+        if (!strcmpW( binary->source, source ))
+            return binary;
+    }
+
+    return create_temp_binary( package, source, dll );
 }
 
 static void file_running_action(MSIPACKAGE* package, HANDLE Handle,
@@ -594,7 +628,7 @@ static void handle_msi_break( LPCWSTR target )
     if( !GetEnvironmentVariableW( MsiBreak, val, MAX_PATH ))
         return;
 
-    if( lstrcmpiW( val, target ))
+    if( strcmpiW( val, target ))
         return;
 
     msg = msi_alloc( (lstrlenW(format) + 10) * sizeof(WCHAR) );
@@ -615,7 +649,7 @@ static UINT get_action_info( const GUID *guid, INT *type, MSIHANDLE *handle,
     IWineMsiRemoteCustomAction *rca = NULL;
     HRESULT r;
 
-    r = DllGetClassObject( &CLSID_IWineMsiRemoteCustomAction,
+    r = DllGetClassObject( &CLSID_WineMsiRemoteCustomAction,
                            &IID_IClassFactory, (LPVOID *)&cf );
     if (FAILED(r))
     {
@@ -683,8 +717,8 @@ static DWORD ACTION_CallDllFunction( const GUID *guid )
     hModule = LoadLibraryW( dll );
     if (!hModule)
     {
-        ERR("failed to load dll %s (%u)\n", debugstr_w( dll ), GetLastError() );
-        return r;
+        WARN( "failed to load dll %s (%u)\n", debugstr_w( dll ), GetLastError() );
+        return ERROR_SUCCESS;
     }
 
     proc = strdupWtoA( function );
@@ -875,20 +909,15 @@ static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source,
                                LPCWSTR target, const INT type, LPCWSTR action)
 {
     msi_custom_action_info *info;
-    WCHAR tmp_file[MAX_PATH];
+    MSIBINARY *binary;
     UINT r;
 
-    r = store_binary_to_temp(package, source, tmp_file);
-    if (r != ERROR_SUCCESS)
-        return r;
-
-    TRACE("Calling function %s from %s\n",debugstr_w(target),
-          debugstr_w(tmp_file));
+    if (!(binary = get_temp_binary( package, source, TRUE )))
+        return ERROR_FUNCTION_FAILED;
 
-    if (!strchrW(tmp_file,'.'))
-        strcatW(tmp_file, szDot);
+    TRACE("Calling function %s from %s\n", debugstr_w(target), debugstr_w(binary->tmpfile));
 
-    info = do_msidbCustomActionTypeDll( package, type, tmp_file, target, action );
+    info = do_msidbCustomActionTypeDll( package, type, binary->tmpfile, target, action );
 
     r = wait_thread_handle( info );
     release_custom_action_data( info );
@@ -898,7 +927,6 @@ static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source,
 static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source,
                                LPCWSTR target, const INT type, LPCWSTR action)
 {
-    WCHAR tmp_file[MAX_PATH];
     STARTUPINFOW si;
     PROCESS_INFORMATION info;
     BOOL rc;
@@ -906,29 +934,27 @@ static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source,
     WCHAR *deformated = NULL;
     WCHAR *cmd;
     static const WCHAR spc[] = {' ',0};
+    MSIBINARY *binary;
     UINT r;
 
     memset(&si,0,sizeof(STARTUPINFOW));
 
-    r = store_binary_to_temp(package, source, tmp_file);
-    if (r != ERROR_SUCCESS)
-        return r;
+    if (!(binary = get_temp_binary( package, source, FALSE )))
+        return ERROR_FUNCTION_FAILED;
 
     deformat_string(package,target,&deformated);
 
-    len = strlenW(tmp_file)+2;
-
+    len = strlenW( binary->tmpfile ) + 2;
     if (deformated)
         len += strlenW(deformated);
 
     cmd = msi_alloc(sizeof(WCHAR)*len);
 
-    strcpyW(cmd,tmp_file);
+    strcpyW( cmd, binary->tmpfile );
     if (deformated)
     {
         strcatW(cmd,spc);
         strcatW(cmd,deformated);
-
         msi_free(deformated);
     }
 
@@ -1121,8 +1147,7 @@ static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source,
 
     memset(&si, 0, sizeof(STARTUPINFOW));
 
-    workingdir = resolve_folder(package, source, FALSE, FALSE, TRUE, NULL);
-
+    workingdir = resolve_target_folder( package, source, FALSE, TRUE, NULL );
     if (!workingdir)
         return ERROR_FUNCTION_FAILED;
 
@@ -1161,13 +1186,13 @@ static DWORD ACTION_CallScript( const GUID *guid )
 {
     msi_custom_action_info *info;
     MSIHANDLE hPackage;
-    UINT r = ERROR_FUNCTION_FAILED;
+    UINT r;
 
     info = find_action_by_guid( guid );
     if (!info)
     {
         ERR("failed to find action %s\n", debugstr_guid( guid) );
-        return r;
+        return ERROR_FUNCTION_FAILED;
     }
 
     TRACE("function %s, script %s\n", debugstr_w( info->target ), debugstr_w( info->source ) );
@@ -1176,13 +1201,13 @@ static DWORD ACTION_CallScript( const GUID *guid )
     if (hPackage)
     {
         r = call_script( hPackage, info->type, info->source, info->target, info->action );
+        TRACE("script returned %u\n", r);
         MsiCloseHandle( hPackage );
     }
     else
         ERR("failed to create handle for %p\n", info->package );
 
     release_custom_action_data( info );
-
     return S_OK;
 }
 
@@ -1433,13 +1458,13 @@ void ACTION_FinishCustomActions(const MSIPACKAGE* package)
 }
 
 typedef struct _msi_custom_remote_impl {
-    const IWineMsiRemoteCustomActionVtbl *lpVtbl;
+    IWineMsiRemoteCustomAction IWineMsiRemoteCustomAction_iface;
     LONG refs;
 } msi_custom_remote_impl;
 
-static inline msi_custom_remote_impl* mcr_from_IWineMsiRemoteCustomAction( IWineMsiRemoteCustomAction* iface )
+static inline msi_custom_remote_impl *impl_from_IWineMsiRemoteCustomAction( IWineMsiRemoteCustomAction *iface )
 {
-    return (msi_custom_remote_impl*) iface;
+    return CONTAINING_RECORD(iface, msi_custom_remote_impl, IWineMsiRemoteCustomAction_iface);
 }
 
 static HRESULT WINAPI mcr_QueryInterface( IWineMsiRemoteCustomAction *iface,
@@ -1458,14 +1483,14 @@ static HRESULT WINAPI mcr_QueryInterface( IWineMsiRemoteCustomAction *iface,
 
 static ULONG WINAPI mcr_AddRef( IWineMsiRemoteCustomAction *iface )
 {
-    msi_custom_remote_impl* This = mcr_from_IWineMsiRemoteCustomAction( iface );
+    msi_custom_remote_impl* This = impl_from_IWineMsiRemoteCustomAction( iface );
 
     return InterlockedIncrement( &This->refs );
 }
 
 static ULONG WINAPI mcr_Release( IWineMsiRemoteCustomAction *iface )
 {
-    msi_custom_remote_impl* This = mcr_from_IWineMsiRemoteCustomAction( iface );
+    msi_custom_remote_impl* This = impl_from_IWineMsiRemoteCustomAction( iface );
     ULONG r;
 
     r = InterlockedDecrement( &This->refs );
@@ -1508,7 +1533,7 @@ HRESULT create_msi_custom_remote( IUnknown *pOuter, LPVOID *ppObj )
     if (!This)
         return E_OUTOFMEMORY;
 
-    This->lpVtbl = &msi_custom_remote_vtbl;
+    This->IWineMsiRemoteCustomAction_iface.lpVtbl = &msi_custom_remote_vtbl;
     This->refs = 1;
 
     *ppObj = This;
index 3007d48..598d7a8 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 #include <stdarg.h>
+#include <stdio.h>
 
 #define COBJMACROS
 #define NONAMELESSUNION
@@ -79,7 +80,7 @@ static UINT find_open_stream( MSIDATABASE *db, LPCWSTR name, IStream **stm )
             continue;
         }
 
-        if( !lstrcmpW( name, stat.pwcsName ) )
+        if( !strcmpW( name, stat.pwcsName ) )
         {
             TRACE("found %s\n", debugstr_w(name));
             *stm = stream->stm;
@@ -888,6 +889,8 @@ static UINT MSI_DatabaseImport(MSIDATABASE *db, LPCWSTR folder, LPCWSTR file)
 
     static const WCHAR suminfo[] =
         {'_','S','u','m','m','a','r','y','I','n','f','o','r','m','a','t','i','o','n',0};
+    static const WCHAR forcecodepage[] =
+        {'_','F','o','r','c','e','C','o','d','e','p','a','g','e',0};
 
     TRACE("%p %s %s\n", db, debugstr_w(folder), debugstr_w(file) );
 
@@ -910,6 +913,13 @@ static UINT MSI_DatabaseImport(MSIDATABASE *db, LPCWSTR folder, LPCWSTR file)
     msi_parse_line( &ptr, &types, &num_types );
     msi_parse_line( &ptr, &labels, &num_labels );
 
+    if (num_columns == 1 && !columns[0][0] && num_labels == 1 && !labels[0][0] &&
+        num_types == 2 && !strcmpW( types[1], forcecodepage ))
+    {
+        r = msi_set_string_table_codepage( db->strings, atoiW( types[0] ) );
+        goto done;
+    }
+
     if (num_columns != num_types)
     {
         r = ERROR_FUNCTION_FAILED;
@@ -1087,13 +1097,13 @@ static UINT msi_export_row( MSIRECORD *row, void *arg )
     return msi_export_record( arg, row, 1 );
 }
 
-static UINT msi_export_forcecodepage( HANDLE handle )
+static UINT msi_export_forcecodepage( HANDLE handle, UINT codepage )
 {
+    static const char fmt[] = "\r\n\r\n%u\t_ForceCodepage\r\n";
+    char data[sizeof(fmt) + 10];
     DWORD sz;
 
-    static const char data[] = "\r\n\r\n0\t_ForceCodepage\r\n";
-
-    FIXME("Read the codepage from the strings table!\n");
+    sprintf( data, fmt, codepage );
 
     sz = lstrlenA(data) + 1;
     if (!WriteFile(handle, data, sz, &sz, NULL))
@@ -1136,9 +1146,10 @@ static UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table,
     if (handle == INVALID_HANDLE_VALUE)
         return ERROR_FUNCTION_FAILED;
 
-    if (!lstrcmpW( table, forcecodepage ))
+    if (!strcmpW( table, forcecodepage ))
     {
-        r = msi_export_forcecodepage( handle );
+        UINT codepage = msi_get_string_table_codepage( db->strings );
+        r = msi_export_forcecodepage( handle, codepage );
         goto done;
     }
 
@@ -1319,7 +1330,7 @@ static BOOL merge_type_match(LPCWSTR type1, LPCWSTR type2)
         ((type2[0] == 'L') || (type2[0] == 'S')))
         return TRUE;
 
-    return !lstrcmpW(type1, type2);
+    return !strcmpW( type1, type2 );
 }
 
 static UINT merge_verify_colnames(MSIQUERY *dbview, MSIQUERY *mergeview)
@@ -1341,8 +1352,7 @@ static UINT merge_verify_colnames(MSIQUERY *dbview, MSIQUERY *mergeview)
         if (!MSI_RecordGetString(mergerec, i))
             break;
 
-        if (lstrcmpW(MSI_RecordGetString(dbrec, i),
-                     MSI_RecordGetString(mergerec, i)))
+        if (strcmpW( MSI_RecordGetString( dbrec, i ), MSI_RecordGetString( mergerec, i ) ))
         {
             r = ERROR_DATATYPE_MISMATCH;
             goto done;
@@ -1405,8 +1415,7 @@ static UINT merge_verify_primary_keys(MSIDATABASE *db, MSIDATABASE *mergedb,
 
     for (i = 1; i <= count; i++)
     {
-        if (lstrcmpW(MSI_RecordGetString(dbrec, i),
-                     MSI_RecordGetString(mergerec, i)))
+        if (strcmpW( MSI_RecordGetString( dbrec, i ), MSI_RecordGetString( mergerec, i ) ))
         {
             r = ERROR_DATATYPE_MISMATCH;
             goto done;
@@ -1434,7 +1443,7 @@ static LPWSTR get_key_value(MSIQUERY *view, LPCWSTR key, MSIRECORD *rec)
     do
     {
         str = msi_dup_record_field(colnames, ++i);
-        cmp = lstrcmpW(key, str);
+        cmp = strcmpW( key, str );
         msi_free(str);
     } while (cmp);
 
@@ -2029,14 +2038,14 @@ MSIDBSTATE WINAPI MsiGetDatabaseState( MSIHANDLE handle )
 }
 
 typedef struct _msi_remote_database_impl {
-    const IWineMsiRemoteDatabaseVtbl *lpVtbl;
+    IWineMsiRemoteDatabase IWineMsiRemoteDatabase_iface;
     MSIHANDLE database;
     LONG refs;
 } msi_remote_database_impl;
 
-static inline msi_remote_database_impl* mrd_from_IWineMsiRemoteDatabase( IWineMsiRemoteDatabase* iface )
+static inline msi_remote_database_impl *impl_from_IWineMsiRemoteDatabase( IWineMsiRemoteDatabase *iface )
 {
-    return (msi_remote_database_impl *)iface;
+    return CONTAINING_RECORD(iface, msi_remote_database_impl, IWineMsiRemoteDatabase_iface);
 }
 
 static HRESULT WINAPI mrd_QueryInterface( IWineMsiRemoteDatabase *iface,
@@ -2055,14 +2064,14 @@ static HRESULT WINAPI mrd_QueryInterface( IWineMsiRemoteDatabase *iface,
 
 static ULONG WINAPI mrd_AddRef( IWineMsiRemoteDatabase *iface )
 {
-    msi_remote_database_impl* This = mrd_from_IWineMsiRemoteDatabase( iface );
+    msi_remote_database_impl* This = impl_from_IWineMsiRemoteDatabase( iface );
 
     return InterlockedIncrement( &This->refs );
 }
 
 static ULONG WINAPI mrd_Release( IWineMsiRemoteDatabase *iface )
 {
-    msi_remote_database_impl* This = mrd_from_IWineMsiRemoteDatabase( iface );
+    msi_remote_database_impl* This = impl_from_IWineMsiRemoteDatabase( iface );
     ULONG r;
 
     r = InterlockedDecrement( &This->refs );
@@ -2077,7 +2086,7 @@ static ULONG WINAPI mrd_Release( IWineMsiRemoteDatabase *iface )
 static HRESULT WINAPI mrd_IsTablePersistent( IWineMsiRemoteDatabase *iface,
                                              LPCWSTR table, MSICONDITION *persistent )
 {
-    msi_remote_database_impl *This = mrd_from_IWineMsiRemoteDatabase( iface );
+    msi_remote_database_impl *This = impl_from_IWineMsiRemoteDatabase( iface );
     *persistent = MsiDatabaseIsTablePersistentW(This->database, table);
     return S_OK;
 }
@@ -2085,7 +2094,7 @@ static HRESULT WINAPI mrd_IsTablePersistent( IWineMsiRemoteDatabase *iface,
 static HRESULT WINAPI mrd_GetPrimaryKeys( IWineMsiRemoteDatabase *iface,
                                           LPCWSTR table, MSIHANDLE *keys )
 {
-    msi_remote_database_impl *This = mrd_from_IWineMsiRemoteDatabase( iface );
+    msi_remote_database_impl *This = impl_from_IWineMsiRemoteDatabase( iface );
     UINT r = MsiDatabaseGetPrimaryKeysW(This->database, table, keys);
     return HRESULT_FROM_WIN32(r);
 }
@@ -2093,7 +2102,7 @@ static HRESULT WINAPI mrd_GetPrimaryKeys( IWineMsiRemoteDatabase *iface,
 static HRESULT WINAPI mrd_GetSummaryInformation( IWineMsiRemoteDatabase *iface,
                                                 UINT updatecount, MSIHANDLE *suminfo )
 {
-    msi_remote_database_impl *This = mrd_from_IWineMsiRemoteDatabase( iface );
+    msi_remote_database_impl *This = impl_from_IWineMsiRemoteDatabase( iface );
     UINT r = MsiGetSummaryInformationW(This->database, NULL, updatecount, suminfo);
     return HRESULT_FROM_WIN32(r);
 }
@@ -2101,14 +2110,14 @@ static HRESULT WINAPI mrd_GetSummaryInformation( IWineMsiRemoteDatabase *iface,
 static HRESULT WINAPI mrd_OpenView( IWineMsiRemoteDatabase *iface,
                                     LPCWSTR query, MSIHANDLE *view )
 {
-    msi_remote_database_impl *This = mrd_from_IWineMsiRemoteDatabase( iface );
+    msi_remote_database_impl *This = impl_from_IWineMsiRemoteDatabase( iface );
     UINT r = MsiDatabaseOpenViewW(This->database, query, view);
     return HRESULT_FROM_WIN32(r);
 }
 
 static HRESULT WINAPI mrd_SetMsiHandle( IWineMsiRemoteDatabase *iface, MSIHANDLE handle )
 {
-    msi_remote_database_impl* This = mrd_from_IWineMsiRemoteDatabase( iface );
+    msi_remote_database_impl* This = impl_from_IWineMsiRemoteDatabase( iface );
     This->database = handle;
     return S_OK;
 }
@@ -2133,7 +2142,7 @@ HRESULT create_msi_remote_database( IUnknown *pOuter, LPVOID *ppObj )
     if (!This)
         return E_OUTOFMEMORY;
 
-    This->lpVtbl = &msi_remote_database_vtbl;
+    This->IWineMsiRemoteDatabase_iface.lpVtbl = &msi_remote_database_vtbl;
     This->database = 0;
     This->refs = 1;
 
index e0e27d1..40aa7df 100644 (file)
@@ -73,7 +73,7 @@ struct msi_control_tag
 
 typedef struct msi_font_tag
 {
-    struct msi_font_tag *next;
+    struct list entry;
     HFONT hfont;
     COLORREF color;
     WCHAR name[1];
@@ -90,7 +90,7 @@ struct msi_dialog_tag
     SIZE size;
     HWND hwnd;
     LPWSTR default_font;
-    msi_font *font_list;
+    struct list fonts;
     struct list controls;
     HWND hWndFocus;
     LPWSTR control_default;
@@ -310,8 +310,7 @@ static UINT msi_dialog_add_font( MSIRECORD *rec, LPVOID param )
     name = MSI_RecordGetString( rec, 1 );
     font = msi_alloc( sizeof *font + strlenW( name )*sizeof (WCHAR) );
     strcpyW( font->name, name );
-    font->next = dialog->font_list;
-    dialog->font_list = font;
+    list_add_head( &dialog->fonts, &font->entry );
 
     font->color = MSI_RecordGetInteger( rec, 4 );
 
@@ -346,9 +345,9 @@ static UINT msi_dialog_add_font( MSIRECORD *rec, LPVOID param )
 
 static msi_font *msi_dialog_find_font( msi_dialog *dialog, LPCWSTR name )
 {
-    msi_font *font;
+    msi_font *font = NULL;
 
-    for( font = dialog->font_list; font; font = font->next )
+    LIST_FOR_EACH_ENTRY( font, &dialog->fonts, msi_font, entry )
         if( !strcmpW( font->name, name ) )  /* FIXME: case sensitive? */
             break;
 
@@ -578,7 +577,7 @@ static void msi_dialog_update_controls( msi_dialog *dialog, LPCWSTR property )
 
     LIST_FOR_EACH_ENTRY( control, &dialog->controls, msi_control, entry )
     {
-        if ( !lstrcmpW( control->property, property ) && control->update )
+        if ( control->property && !strcmpW( control->property, property ) && control->update )
             control->update( dialog, control );
     }
 }
@@ -601,7 +600,7 @@ void msi_dialog_handle_event( msi_dialog* dialog, LPCWSTR control,
     ctrl = msi_dialog_find_control( dialog, control );
     if (!ctrl)
         return;
-    if( !lstrcmpW(attribute, szText) )
+    if( !strcmpW( attribute, szText ) )
     {
         font_text = MSI_RecordGetString( rec , 1 );
         font = msi_dialog_get_style( font_text, &text );
@@ -610,7 +609,7 @@ void msi_dialog_handle_event( msi_dialog* dialog, LPCWSTR control,
         msi_free( font );
         msi_dialog_check_messages( NULL );
     }
-    else if( !lstrcmpW(attribute, szProgress) )
+    else if( !strcmpW( attribute, szProgress ) )
     {
         DWORD func, val;
 
@@ -640,12 +639,12 @@ void msi_dialog_handle_event( msi_dialog* dialog, LPCWSTR control,
             break;
         }
     }
-    else if ( !lstrcmpW(attribute, szProperty) )
+    else if ( !strcmpW( attribute, szProperty ) )
     {
         MSIFEATURE *feature = msi_seltree_get_selected_feature( ctrl );
         msi_dialog_set_property( dialog->package, ctrl->property, feature->Directory );
     }
-    else if ( !lstrcmpW(attribute, szSelectionPath) )
+    else if ( !strcmpW( attribute, szSelectionPath ) )
     {
         LPWSTR prop = msi_dialog_dup_property( dialog, ctrl->property, TRUE );
         LPWSTR path;
@@ -1368,7 +1367,7 @@ static void msi_dialog_combobox_update( msi_dialog *dialog,
     for (j = 0; j < info->num_items; j++)
     {
         tmp = (LPWSTR) SendMessageW( control->hwnd, CB_GETITEMDATA, j, 0 );
-        if (!lstrcmpW( value, tmp ))
+        if (!strcmpW( value, tmp ))
             break;
     }
 
@@ -1743,7 +1742,7 @@ static UINT msi_dialog_maskedit_control( msi_dialog *dialog, MSIRECORD *rec )
     font = msi_dialog_get_style( font_mask, &mask );
     if( !mask )
     {
-        ERR("mask template is empty\n");
+        WARN("mask template is empty\n");
         goto end;
     }
 
@@ -1988,7 +1987,7 @@ static UINT msi_dialog_create_radiobutton( MSIRECORD *rec, LPVOID param )
         return ERROR_FUNCTION_FAILED;
     control->handler = msi_dialog_radiogroup_handler;
 
-    if (!lstrcmpW(control->name, group->propval))
+    if (group->propval && !strcmpW( control->name, group->propval ))
         SendMessageW(control->hwnd, BM_SETCHECK, BST_CHECKED, 0);
 
     prop = MSI_RecordGetString( rec, 1 );
@@ -2126,9 +2125,9 @@ static void
 msi_seltree_update_feature_installstate( HWND hwnd, HTREEITEM hItem,
         MSIPACKAGE *package, MSIFEATURE *feature, INSTALLSTATE state )
 {
-    msi_feature_set_state( package, feature, state );
+    feature->ActionRequest = state;
     msi_seltree_sync_item_state( hwnd, feature, hItem );
-    ACTION_UpdateComponentStates( package, feature->Feature );
+    ACTION_UpdateComponentStates( package, feature );
 }
 
 static void
@@ -2258,7 +2257,11 @@ msi_seltree_add_child_features( MSIPACKAGE *package, HWND hwnd,
 
     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
     {
-        if ( lstrcmpW( parent, feature->Feature_Parent ) )
+        if ( parent && feature->Feature_Parent && strcmpW( parent, feature->Feature_Parent ))
+            continue;
+        else if ( parent && !feature->Feature_Parent )
+            continue;
+        else if ( !parent && feature->Feature_Parent )
             continue;
 
         if ( !feature->Title )
@@ -2373,14 +2376,19 @@ static UINT msi_dialog_seltree_handler( msi_dialog *dialog,
     ControlEvent_FireSubscribedEvent( dialog->package, szSelectionDescription, rec );
 
     dir = MSI_RecordGetString( row, 7 );
-    folder = get_loaded_folder( dialog->package, dir );
-    if (!folder)
+    if (dir)
     {
-        r = ERROR_FUNCTION_FAILED;
-        goto done;
+        folder = get_loaded_folder( dialog->package, dir );
+        if (!folder)
+        {
+            r = ERROR_FUNCTION_FAILED;
+            goto done;
+        }
+        MSI_RecordSetStringW( rec, 1, folder->ResolvedTarget );
     }
+    else
+        MSI_RecordSetStringW( rec, 1, NULL );
 
-    MSI_RecordSetStringW( rec, 1, folder->ResolvedTarget );
     ControlEvent_FireSubscribedEvent( dialog->package, szSelectionPath, rec );
 
 done:
@@ -2682,7 +2690,7 @@ static void msi_dialog_update_directory_list( msi_dialog *dialog, msi_control *c
         if ( wfd.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY )
             continue;
 
-        if ( !lstrcmpW( wfd.cFileName, szDot ) || !lstrcmpW( wfd.cFileName, szDotDot ) )
+        if ( !strcmpW( wfd.cFileName, szDot ) || !strcmpW( wfd.cFileName, szDotDot ) )
             continue;
 
         item.mask = LVIF_TEXT;
@@ -2846,7 +2854,7 @@ static void msi_dialog_vcl_add_columns( msi_dialog *dialog, msi_control *control
         begin += end - begin + 1;
 
         /* empty braces or '0' hides the column */ 
-        if ( !num[0] || !lstrcmpW( num, szZero ) )
+        if ( !num[0] || !strcmpW( num, szZero ) )
         {
             count++;
             msi_free( num );
@@ -3151,15 +3159,15 @@ static UINT msi_dialog_set_control_condition( MSIRECORD *rec, LPVOID param )
         TRACE("%s control %s\n", debugstr_w(action), debugstr_w(name));
 
         /* FIXME: case sensitive? */
-        if(!lstrcmpW(action, szHide))
+        if (!strcmpW( action, szHide ))
             ShowWindow(control->hwnd, SW_HIDE);
-        else if(!strcmpW(action, szShow))
+        else if (!strcmpW( action, szShow ))
             ShowWindow(control->hwnd, SW_SHOW);
-        else if(!strcmpW(action, szDisable))
+        else if (!strcmpW( action, szDisable ))
             EnableWindow(control->hwnd, FALSE);
-        else if(!strcmpW(action, szEnable))
+        else if (!strcmpW( action, szEnable ))
             EnableWindow(control->hwnd, TRUE);
-        else if(!strcmpW(action, szDefault))
+        else if (!strcmpW( action, szDefault ))
             SetFocus(control->hwnd);
         else
             FIXME("Unhandled action %s\n", debugstr_w(action));
@@ -3844,6 +3852,7 @@ msi_dialog *msi_dialog_create( MSIPACKAGE* package,
     dialog->event_handler = event_handler;
     dialog->finished = 0;
     list_init( &dialog->controls );
+    list_init( &dialog->fonts );
 
     /* verify that the dialog exists */
     rec = msi_get_dialog_record( dialog );
@@ -3960,6 +3969,8 @@ void msi_dialog_do_preview( msi_dialog *dialog )
 
 void msi_dialog_destroy( msi_dialog *dialog )
 {
+    msi_font *font, *next;
+
     if( uiThreadId != GetCurrentThreadId() )
     {
         SendMessageW( hMsiHiddenWindow, WM_MSI_DIALOG_DESTROY, 0, (LPARAM) dialog );
@@ -3986,12 +3997,11 @@ void msi_dialog_destroy( msi_dialog *dialog )
     }
 
     /* destroy the list of fonts */
-    while( dialog->font_list )
+    LIST_FOR_EACH_ENTRY_SAFE( font, next, &dialog->fonts, msi_font, entry )
     {
-        msi_font *t = dialog->font_list;
-        dialog->font_list = t->next;
-        DeleteObject( t->hfont );
-        msi_free( t );
+        list_remove( &font->entry );
+        DeleteObject( font->hfont );
+        msi_free( font );
     }
     msi_free( dialog->default_font );
 
@@ -4022,11 +4032,11 @@ static UINT error_dialog_handler(MSIPACKAGE *package, LPCWSTR event,
         'M','S','I','E','r','r','o','r','D','i','a','l','o','g','R','e','s','u','l','t',0
     };
 
-    if ( lstrcmpW( event, end_dialog ) )
+    if ( strcmpW( event, end_dialog ) )
         return ERROR_SUCCESS;
 
-    if ( !lstrcmpW( argument, error_abort ) || !lstrcmpW( argument, error_cancel ) ||
-         !lstrcmpW( argument, error_no ) )
+    if ( !strcmpW( argument, error_abort ) || !strcmpW( argument, error_cancel ) ||
+         !strcmpW( argument, error_no ) )
     {
          msi_set_property( package->db, result_prop, error_abort );
     }
@@ -4108,7 +4118,7 @@ UINT msi_spawn_error_dialog( MSIPACKAGE *package, LPWSTR error_dialog, LPWSTR er
     if ( r != ERROR_SUCCESS)
         r = ERROR_SUCCESS;
 
-    if ( !lstrcmpW( result, error_abort ) )
+    if ( !strcmpW( result, error_abort ) )
         r = ERROR_FUNCTION_FAILED;
 
 done:
index 157d185..b888c1c 100644 (file)
@@ -90,22 +90,18 @@ static UINT event_do_dialog( MSIPACKAGE *package, LPCWSTR name, msi_dialog *pare
 static UINT ControlEvent_EndDialog(MSIPACKAGE* package, LPCWSTR argument, 
                                    msi_dialog* dialog)
 {
-    static const WCHAR szExit[] = {
-    'E','x','i','t',0};
-    static const WCHAR szRetry[] = {
-    'R','e','t','r','y',0};
-    static const WCHAR szIgnore[] = {
-    'I','g','n','o','r','e',0};
-    static const WCHAR szReturn[] = {
-    'R','e','t','u','r','n',0};
-
-    if (lstrcmpW(argument,szExit)==0)
+    static const WCHAR szExit[] = {'E','x','i','t',0};
+    static const WCHAR szRetry[] = {'R','e','t','r','y',0};
+    static const WCHAR szIgnore[] = {'I','g','n','o','r','e',0};
+    static const WCHAR szReturn[] = {'R','e','t','u','r','n',0};
+
+    if (!strcmpW( argument, szExit ))
         package->CurrentInstallState = ERROR_INSTALL_USEREXIT;
-    else if (lstrcmpW(argument, szRetry) == 0)
+    else if (!strcmpW( argument, szRetry ))
         package->CurrentInstallState = ERROR_INSTALL_SUSPEND;
-    else if (lstrcmpW(argument, szIgnore) == 0)
+    else if (!strcmpW( argument, szIgnore ))
         package->CurrentInstallState = ERROR_SUCCESS;
-    else if (lstrcmpW(argument, szReturn) == 0)
+    else if (!strcmpW( argument, szReturn ))
     {
         msi_dialog *parent = msi_dialog_get_parent(dialog);
         msi_free(package->next_dialog);
@@ -167,58 +163,50 @@ static UINT ControlEvent_DoAction(MSIPACKAGE* package, LPCWSTR argument,
     return ERROR_SUCCESS;
 }
 
-static UINT ControlEvent_AddLocal(MSIPACKAGE* package, LPCWSTR argument, 
-                                  msi_dialog* dialog)
+static UINT ControlEvent_AddLocal( MSIPACKAGE *package, LPCWSTR argument, msi_dialog *dialog )
 {
-    MSIFEATURE *feature = NULL;
+    MSIFEATURE *feature;
 
-    if (lstrcmpW(szAll,argument))
-    {
-        MSI_SetFeatureStateW(package,argument,INSTALLSTATE_LOCAL);
-    }
-    else
+    LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
     {
-        LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
-            msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
-
-        ACTION_UpdateComponentStates(package,argument);
+        if (!strcmpW( argument, feature->Feature ) || !strcmpW( argument, szAll ))
+        {
+            if (feature->ActionRequest != INSTALLSTATE_LOCAL)
+                msi_set_property( package->db, szPreselected, szOne );
+            MSI_SetFeatureStateW( package, feature->Feature, INSTALLSTATE_LOCAL );
+        }
     }
     return ERROR_SUCCESS;
 }
 
-static UINT ControlEvent_Remove(MSIPACKAGE* package, LPCWSTR argument, 
-                                msi_dialog* dialog)
+static UINT ControlEvent_Remove( MSIPACKAGE *package, LPCWSTR argument, msi_dialog *dialog )
 {
-    MSIFEATURE *feature = NULL;
+    MSIFEATURE *feature;
 
-    if (lstrcmpW(szAll,argument))
-    {
-        MSI_SetFeatureStateW(package,argument,INSTALLSTATE_ABSENT);
-    }
-    else
+    LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
     {
-        LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
-            msi_feature_set_state(package, feature, INSTALLSTATE_ABSENT);
-
-        ACTION_UpdateComponentStates(package,argument);
+        if (!strcmpW( argument, feature->Feature ) || !strcmpW( argument, szAll ))
+        {
+            if (feature->ActionRequest != INSTALLSTATE_ABSENT)
+                msi_set_property( package->db, szPreselected, szOne );
+            MSI_SetFeatureStateW( package, feature->Feature, INSTALLSTATE_ABSENT );
+        }
     }
     return ERROR_SUCCESS;
 }
 
-static UINT ControlEvent_AddSource(MSIPACKAGE* package, LPCWSTR argument, 
-                                   msi_dialog* dialog)
+static UINT ControlEvent_AddSource( MSIPACKAGE *package, LPCWSTR argument, msi_dialog *dialog )
 {
-    MSIFEATURE *feature = NULL;
+    MSIFEATURE *feature;
 
-    if (lstrcmpW(szAll,argument))
+    LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
     {
-        MSI_SetFeatureStateW(package,argument,INSTALLSTATE_SOURCE);
-    }
-    else
-    {
-        LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
-            msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
-        ACTION_UpdateComponentStates(package,argument);
+        if (!strcmpW( argument, feature->Feature ) || !strcmpW( argument, szAll ))
+        {
+            if (feature->ActionRequest != INSTALLSTATE_SOURCE)
+                msi_set_property( package->db, szPreselected, szOne );
+            MSI_SetFeatureStateW( package, feature->Feature, INSTALLSTATE_SOURCE );
+        }
     }
     return ERROR_SUCCESS;
 }
@@ -284,10 +272,9 @@ VOID ControlEvent_FireSubscribedEvent( MSIPACKAGE *package, LPCWSTR event,
 
     LIST_FOR_EACH_ENTRY( sub, &package->subscriptions, struct subscriber, entry )
     {
-        if (lstrcmpiW(sub->event, event))
+        if (strcmpiW( sub->event, event ))
             continue;
-        msi_dialog_handle_event( sub->dialog, sub->control,
-                                 sub->attribute, rec );
+        msi_dialog_handle_event( sub->dialog, sub->control, sub->attribute, rec );
     }
 }
 
@@ -300,7 +287,7 @@ VOID ControlEvent_CleanupDialogSubscriptions(MSIPACKAGE *package, LPWSTR dialog)
     {
         sub = LIST_ENTRY( i, struct subscriber, entry );
 
-        if ( lstrcmpW( msi_dialog_get_name( sub->dialog ), dialog ))
+        if (strcmpW( msi_dialog_get_name( sub->dialog ), dialog ))
             continue;
 
         list_remove( &sub->entry );
@@ -441,7 +428,7 @@ UINT ControlEvent_HandleControlEvent(MSIPACKAGE *package, LPCWSTR event,
     while( Events[i].event != NULL)
     {
         LPWSTR wevent = strdupAtoW(Events[i].event);
-        if (lstrcmpW(wevent,event)==0)
+        if (!strcmpW( wevent, event ))
         {
             msi_free(wevent);
             rc = Events[i].handler(package,argument,dialog);
index 0ed9582..1f61873 100644 (file)
@@ -60,21 +60,98 @@ static void msi_file_update_ui( MSIPACKAGE *package, MSIFILE *f, const WCHAR *ac
     ui_progress( package, 2, f->FileSize, 0, 0 );
 }
 
+static msi_file_state calculate_install_state( MSIFILE *file )
+{
+    MSICOMPONENT *comp = file->Component;
+    VS_FIXEDFILEINFO *file_version;
+    WCHAR *font_version;
+    msi_file_state state;
+    DWORD file_size;
+
+    if (comp->ActionRequest != INSTALLSTATE_LOCAL || !comp->Enabled ||
+        (comp->assembly && comp->assembly->installed))
+    {
+        TRACE("file %s is not scheduled for install\n", debugstr_w(file->File));
+        return msifs_skipped;
+    }
+    if ((comp->assembly && !comp->assembly->application && !comp->assembly->installed) ||
+        GetFileAttributesW( file->TargetPath ) == INVALID_FILE_ATTRIBUTES)
+    {
+        TRACE("file %s is missing\n", debugstr_w(file->File));
+        return msifs_missing;
+    }
+    if (file->Version)
+    {
+        if ((file_version = msi_get_disk_file_version( file->TargetPath )))
+        {
+            TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version),
+                  HIWORD(file_version->dwFileVersionMS),
+                  LOWORD(file_version->dwFileVersionMS),
+                  HIWORD(file_version->dwFileVersionLS),
+                  LOWORD(file_version->dwFileVersionLS));
+
+            if (msi_compare_file_versions( file_version, file->Version ) < 0)
+                state = msifs_overwrite;
+            else
+            {
+                TRACE("destination file version equal or greater, not overwriting\n");
+                state = msifs_present;
+            }
+            msi_free( file_version );
+            return state;
+        }
+        else if ((font_version = font_version_from_file( file->TargetPath )))
+        {
+            TRACE("new %s old %s\n", debugstr_w(file->Version), debugstr_w(font_version));
+
+            if (msi_compare_font_versions( font_version, file->Version ) < 0)
+                state = msifs_overwrite;
+            else
+            {
+                TRACE("destination file version equal or greater, not overwriting\n");
+                state = msifs_present;
+            }
+            msi_free( font_version );
+            return state;
+        }
+    }
+    if ((file_size = msi_get_disk_file_size( file->TargetPath )) != file->FileSize)
+    {
+        return msifs_overwrite;
+    }
+    if (file->hash.dwFileHashInfoSize)
+    {
+        if (msi_file_hash_matches( file ))
+        {
+            TRACE("file hashes match, not overwriting\n");
+            return msifs_hashmatch;
+        }
+        else
+        {
+            TRACE("file hashes do not match, overwriting\n");
+            return msifs_overwrite;
+        }
+    }
+    /* assume present */
+    return msifs_present;
+}
+
 static void schedule_install_files(MSIPACKAGE *package)
 {
     MSIFILE *file;
 
     LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
     {
-        if (file->Component->ActionRequest != INSTALLSTATE_LOCAL || !file->Component->Enabled)
-        {
-            TRACE("File %s is not scheduled for install\n", debugstr_w(file->File));
+        MSICOMPONENT *comp = file->Component;
 
-            ui_progress(package,2,file->FileSize,0,0);
+        file->state = calculate_install_state( file );
+        if (file->state == msifs_overwrite && (comp->Attributes & msidbComponentAttributesNeverOverwrite))
+        {
+            TRACE("not overwriting %s\n", debugstr_w(file->TargetPath));
             file->state = msifs_skipped;
         }
-        else
-            file->Component->Action = INSTALLSTATE_LOCAL;
+        comp->Action = INSTALLSTATE_LOCAL;
+        ui_progress( package, 2, file->FileSize, 0, 0 );
     }
 }
 
@@ -154,7 +231,7 @@ static UINT msi_create_directory( MSIPACKAGE *package, const WCHAR *dir )
     MSIFOLDER *folder;
     WCHAR *install_path;
 
-    install_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
+    install_path = resolve_target_folder( package, dir, FALSE, TRUE, &folder );
     if (!install_path)
         return ERROR_FUNCTION_FAILED;
 
@@ -178,7 +255,7 @@ static BOOL installfiles_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
         f = get_loaded_file(package, file);
         if (!f)
         {
-            WARN("unknown file in cabinet (%s)\n", debugstr_w(file));
+            TRACE("unknown file in cabinet (%s)\n", debugstr_w(file));
             return FALSE;
         }
 
@@ -186,8 +263,10 @@ static BOOL installfiles_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
             return FALSE;
 
         msi_file_update_ui(package, f, szInstallFiles);
-        msi_create_directory(package, f->Component->Directory);
-
+        if (!f->Component->assembly || f->Component->assembly->application)
+        {
+            msi_create_directory(package, f->Component->Directory);
+        }
         *path = strdupW(f->TargetPath);
         *attrs = f->Attributes;
     }
@@ -210,6 +289,7 @@ static BOOL installfiles_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
 UINT ACTION_InstallFiles(MSIPACKAGE *package)
 {
     MSIMEDIAINFO *mi;
+    MSICOMPONENT *comp;
     UINT rc = ERROR_SUCCESS;
     MSIFILE *file;
 
@@ -222,6 +302,20 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
 
     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
     {
+        rc = msi_load_media_info( package, file, mi );
+        if (rc != ERROR_SUCCESS)
+        {
+            ERR("Unable to load media info for %s (%u)\n", debugstr_w(file->File), rc);
+            return ERROR_FUNCTION_FAILED;
+        }
+        if (!file->Component->Enabled) continue;
+
+        if (file->state != msifs_hashmatch && (rc = ready_media( package, file, mi )))
+        {
+            ERR("Failed to ready media for %s\n", debugstr_w(file->File));
+            goto done;
+        }
+
         if (file->state != msifs_missing && !mi->is_continuous && file->state != msifs_overwrite)
             continue;
 
@@ -230,13 +324,6 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
         {
             MSICABDATA data;
 
-            rc = ready_media(package, file, mi);
-            if (rc != ERROR_SUCCESS)
-            {
-                ERR("Failed to ready media for %s\n", debugstr_w(file->File));
-                break;
-            }
-
             data.mi = mi;
             data.package = package;
             data.cb = installfiles_cb;
@@ -247,7 +334,7 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
             {
                 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
                 rc = ERROR_INSTALL_FAILURE;
-                break;
+                goto done;
             }
         }
 
@@ -255,12 +342,13 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
         {
             LPWSTR source = resolve_file_source(package, file);
 
-            TRACE("file paths %s to %s\n", debugstr_w(source),
-                  debugstr_w(file->TargetPath));
+            TRACE("copying %s to %s\n", debugstr_w(source), debugstr_w(file->TargetPath));
 
             msi_file_update_ui(package, file, szInstallFiles);
-            msi_create_directory(package, file->Component->Directory);
-
+            if (!file->Component->assembly || file->Component->assembly->application)
+            {
+                msi_create_directory(package, file->Component->Directory);
+            }
             rc = copy_install_file(package, file, source);
             if (rc != ERROR_SUCCESS)
             {
@@ -268,19 +356,33 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
                     debugstr_w(file->TargetPath), rc);
                 rc = ERROR_INSTALL_FAILURE;
                 msi_free(source);
-                break;
+                goto done;
             }
-
             msi_free(source);
         }
         else if (file->state != msifs_installed)
         {
             ERR("compressed file wasn't installed (%s)\n", debugstr_w(file->TargetPath));
             rc = ERROR_INSTALL_FAILURE;
-            break;
+            goto done;
+        }
+    }
+    LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
+    {
+        if (comp->ActionRequest == INSTALLSTATE_LOCAL && comp->Enabled &&
+            comp->assembly && !comp->assembly->installed)
+        {
+            rc = install_assembly( package, comp );
+            if (rc != ERROR_SUCCESS)
+            {
+                ERR("Failed to install assembly\n");
+                rc = ERROR_INSTALL_FAILURE;
+                break;
+            }
         }
     }
 
+done:
     msi_free_media_info(mi);
     return rc;
 }
@@ -406,7 +508,7 @@ static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest)
 
     LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry)
     {
-        if (lstrcmpW(source, file->source) < 0)
+        if (strcmpW( source, file->source ) < 0)
         {
             list_add_before(&file->entry, &new->entry);
             return TRUE;
@@ -663,7 +765,7 @@ static WCHAR *get_duplicate_filename( MSIPACKAGE *package, MSIRECORD *row, const
     {
         const WCHAR *dst_key = MSI_RecordGetString( row, 5 );
 
-        dst_path = resolve_folder( package, dst_key, FALSE, FALSE, TRUE, NULL );
+        dst_path = resolve_target_folder( package, dst_key, FALSE, TRUE, NULL );
         if (!dst_path)
         {
             /* try a property */
@@ -861,25 +963,25 @@ static BOOL verify_comp_for_removal(MSICOMPONENT *comp, UINT install_mode)
 {
     INSTALLSTATE request = comp->ActionRequest;
 
-    if (request == INSTALLSTATE_UNKNOWN)
-        return FALSE;
+    /* special case */
+    if (request != INSTALLSTATE_SOURCE &&
+        comp->Attributes & msidbComponentAttributesSourceOnly &&
+        (install_mode == msidbRemoveFileInstallModeOnRemove ||
+         install_mode == msidbRemoveFileInstallModeOnBoth)) return TRUE;
 
-    if (install_mode == msidbRemoveFileInstallModeOnInstall &&
-        (request == INSTALLSTATE_LOCAL || request == INSTALLSTATE_SOURCE))
-        return TRUE;
-
-    if (request == INSTALLSTATE_ABSENT)
+    switch (request)
     {
-        if (!comp->ComponentId)
-            return FALSE;
-
-        if (install_mode == msidbRemoveFileInstallModeOnRemove)
-            return TRUE;
+    case INSTALLSTATE_LOCAL:
+    case INSTALLSTATE_SOURCE:
+        if (install_mode == msidbRemoveFileInstallModeOnInstall ||
+            install_mode == msidbRemoveFileInstallModeOnBoth) return TRUE;
+        break;
+    case INSTALLSTATE_ABSENT:
+        if (install_mode == msidbRemoveFileInstallModeOnRemove ||
+            install_mode == msidbRemoveFileInstallModeOnBoth) return TRUE;
+        break;
+    default: break;
     }
-
-    if (install_mode == msidbRemoveFileInstallModeOnBoth)
-        return TRUE;
-
     return FALSE;
 }
 
@@ -888,24 +990,17 @@ static UINT ITERATE_RemoveFiles(MSIRECORD *row, LPVOID param)
     MSIPACKAGE *package = param;
     MSICOMPONENT *comp;
     MSIRECORD *uirow;
-    LPCWSTR component, filename, dirprop;
+    LPCWSTR component, dirprop;
     UINT install_mode;
-    LPWSTR dir = NULL, path = NULL;
+    LPWSTR dir = NULL, path = NULL, filename = NULL;
     DWORD size;
     UINT ret = ERROR_SUCCESS;
 
     component = MSI_RecordGetString(row, 2);
-    filename = MSI_RecordGetString(row, 3);
     dirprop = MSI_RecordGetString(row, 4);
     install_mode = MSI_RecordGetInteger(row, 5);
 
     comp = get_loaded_component(package, component);
-    if (!comp)
-    {
-        ERR("Invalid component: %s\n", debugstr_w(component));
-        return ERROR_FUNCTION_FAILED;
-    }
-
     if (!comp->Enabled)
     {
         TRACE("component is disabled\n");
@@ -914,16 +1009,27 @@ static UINT ITERATE_RemoveFiles(MSIRECORD *row, LPVOID param)
 
     if (!verify_comp_for_removal(comp, install_mode))
     {
-        TRACE("Skipping removal due to missing conditions\n");
+        TRACE("Skipping removal due to install mode\n");
         comp->Action = comp->Installed;
         return ERROR_SUCCESS;
     }
 
+    if (comp->Attributes & msidbComponentAttributesPermanent)
+    {
+        TRACE("permanent component, not removing file\n");
+        return ERROR_SUCCESS;
+    }
+
     dir = msi_dup_property(package->db, dirprop);
     if (!dir)
         return ERROR_OUTOFMEMORY;
 
-    size = (filename != NULL) ? lstrlenW(filename) : 0;
+    size = 0;
+    if ((filename = strdupW( MSI_RecordGetString(row, 3) )))
+    {
+        reduce_to_longfilename( filename );
+        size = lstrlenW( filename );
+    }
     size += lstrlenW(dir) + 2;
     path = msi_alloc(size * sizeof(WCHAR));
     if (!path)
@@ -954,11 +1060,39 @@ done:
     ui_actiondata( package, szRemoveFiles, uirow );
     msiobj_release( &uirow->hdr );
 
+    msi_free(filename);
     msi_free(path);
     msi_free(dir);
     return ret;
 }
 
+static BOOL has_persistent_dir( MSIPACKAGE *package, MSICOMPONENT *comp )
+{
+    MSIQUERY *view;
+    UINT r = ERROR_FUNCTION_FAILED;
+
+    static const WCHAR query[] = {
+        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+        '`','C','r','e','a','t','e','F','o','l','d','e','r','`',' ','W','H','E','R','E',' ',
+        '`','C','o','m','p','o','n','e','n','t','_','`',' ','=','\'','%','s','\'',' ','A','N','D',' ',
+        '`','D','i','r','e','c','t','o','r','y','_','`',' ','=','\'','%','s','\'',0};
+
+    if (!MSI_OpenQuery( package->db, &view, query, comp->Component, comp->Directory ))
+    {
+        if (!MSI_ViewExecute( view, NULL ))
+        {
+            MSIRECORD *rec;
+            if (!(r = MSI_ViewFetch( view, &rec )))
+            {
+                TRACE("directory %s is persistent\n", debugstr_w(comp->Directory));
+                msiobj_release( &rec->hdr );
+            }
+        }
+        msiobj_release( &view->hdr );
+    }
+    return (r == ERROR_SUCCESS);
+}
+
 UINT ACTION_RemoveFiles( MSIPACKAGE *package )
 {
     MSIQUERY *view;
@@ -968,9 +1102,6 @@ UINT ACTION_RemoveFiles( MSIPACKAGE *package )
     static const WCHAR query[] = {
         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
         '`','R','e','m','o','v','e','F','i','l','e','`',0};
-    static const WCHAR folder_query[] = {
-        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
-        '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
 
     r = MSI_DatabaseOpenViewW(package->db, query, &view);
     if (r == ERROR_SUCCESS)
@@ -979,10 +1110,6 @@ UINT ACTION_RemoveFiles( MSIPACKAGE *package )
         msiobj_release(&view->hdr);
     }
 
-    r = MSI_DatabaseOpenViewW(package->db, folder_query, &view);
-    if (r == ERROR_SUCCESS)
-        msiobj_release(&view->hdr);
-
     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
     {
         MSIRECORD *uirow;
@@ -1002,6 +1129,12 @@ UINT ACTION_RemoveFiles( MSIPACKAGE *package )
             continue;
         }
 
+        if (file->Component->Attributes & msidbComponentAttributesPermanent)
+        {
+            TRACE("permanent component, not removing file\n");
+            continue;
+        }
+
         if (file->Version)
         {
             ver = msi_get_disk_file_version( file->TargetPath );
@@ -1015,16 +1148,20 @@ UINT ACTION_RemoveFiles( MSIPACKAGE *package )
         }
 
         TRACE("removing %s\n", debugstr_w(file->File) );
+
+        SetFileAttributesW( file->TargetPath, FILE_ATTRIBUTE_NORMAL );
         if (!DeleteFileW( file->TargetPath ))
         {
-            WARN("failed to delete %s\n",  debugstr_w(file->TargetPath));
+            WARN("failed to delete %s (%u)\n",  debugstr_w(file->TargetPath), GetLastError());
         }
-        /* FIXME: check persistence for each directory */
-        else if (r && (dir = strdupW( file->TargetPath )))
+        else if (!has_persistent_dir( package, file->Component ))
         {
-            if ((p = strrchrW( dir, '\\' ))) *p = 0;
-            RemoveDirectoryW( dir );
-            msi_free( dir );
+            if ((dir = strdupW( file->TargetPath )))
+            {
+                if ((p = strrchrW( dir, '\\' ))) *p = 0;
+                RemoveDirectoryW( dir );
+                msi_free( dir );
+            }
         }
         file->state = msifs_missing;
 
index 2128e92..7a49386 100644 (file)
@@ -52,6 +52,9 @@ typedef struct _tagTT_NAME_TABLE_HEADER {
                             * from start of the table */
 } TT_NAME_TABLE_HEADER;
 
+#define NAME_ID_FULL_FONT_NAME  4
+#define NAME_ID_VERSION         5
+
 typedef struct _tagTT_NAME_RECORD {
     USHORT uPlatformID;
     USHORT uEncodingID;
@@ -80,10 +83,8 @@ static const WCHAR regfont2[] =
 /*
  * Code based off of code located here
  * http://www.codeproject.com/gdi/fontnamefromfile.asp
- *
- * Using string index 4 (full font name) instead of 1 (family name)
  */
-static LPWSTR load_ttfname_from(LPCWSTR filename)
+WCHAR *load_ttf_name_id( const WCHAR *filename, DWORD id )
 {
     TT_TABLE_DIRECTORY tblDir;
     BOOL bFound = FALSE;
@@ -142,30 +143,24 @@ static LPWSTR load_ttfname_from(LPCWSTR filename)
             break;
 
         ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
-        /* 4 is the Full Font Name */
-        if(ttRecord.uNameID == 4)
+        if (ttRecord.uNameID == id)
         {
             int nPos;
             LPSTR buf;
-            static const char tt[] = " (TrueType)";
 
             ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
             ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
             nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
-            SetFilePointer(handle, tblDir.uOffset +
-                            ttRecord.uStringOffset +
-                            ttNTHeader.uStorageOffset,
-                            NULL, FILE_BEGIN);
-            buf = msi_alloc_zero( ttRecord.uStringLength + 1 + strlen(tt) );
+            SetFilePointer(handle, tblDir.uOffset + ttRecord.uStringOffset + ttNTHeader.uStorageOffset,
+                           NULL, FILE_BEGIN);
+            buf = msi_alloc_zero( ttRecord.uStringLength + 1 );
             ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
             if (strlen(buf) > 0)
             {
-                strcat(buf,tt);
                 ret = strdupAtoW(buf);
                 msi_free(buf);
                 break;
             }
-
             msi_free(buf);
             SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
         }
@@ -173,8 +168,36 @@ static LPWSTR load_ttfname_from(LPCWSTR filename)
 
 end:
     CloseHandle(handle);
+    TRACE("Returning %s\n", debugstr_w(ret));
+    return ret;
+}
+
+static WCHAR *font_name_from_file( const WCHAR *filename )
+{
+    static const WCHAR truetypeW[] = {' ','(','T','r','u','e','T','y','p','e',')',0};
+    WCHAR *name, *ret = NULL;
+
+    if ((name = load_ttf_name_id( filename, NAME_ID_FULL_FONT_NAME )))
+    {
+        ret = msi_alloc( (strlenW( name ) + strlenW( truetypeW ) + 1 ) * sizeof(WCHAR) );
+        strcpyW( ret, name );
+        strcatW( ret, truetypeW );
+        msi_free( name );
+    }
+    return ret;
+}
 
-    TRACE("Returning fontname %s\n",debugstr_w(ret));
+WCHAR *font_version_from_file( const WCHAR *filename )
+{
+    WCHAR *version, *p, *ret = NULL;
+
+    if ((p = version = load_ttf_name_id( filename, NAME_ID_VERSION )))
+    {
+        while (*p && !isdigitW( *p )) p++;
+        ret = msi_alloc( (strlenW( p ) + 1) * sizeof(WCHAR) );
+        strcpyW( ret, p );
+        msi_free( version );
+    }
     return ret;
 }
 
@@ -212,7 +235,7 @@ static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
     RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
 
     if (MSI_RecordIsNull(row,2))
-        name = load_ttfname_from( file->TargetPath );
+        name = font_name_from_file( file->TargetPath );
     else
         name = msi_dup_record_field(row,2);
 
@@ -296,7 +319,7 @@ static UINT ITERATE_UnregisterFonts( MSIRECORD *row, LPVOID param )
     RegCreateKeyW( HKEY_LOCAL_MACHINE, regfont2, &hkey2 );
 
     if (MSI_RecordIsNull( row, 2 ))
-        name = load_ttfname_from( file->TargetPath );
+        name = font_name_from_file( file->TargetPath );
     else
         name = msi_dup_record_field( row, 2 );
 
index c4ff30f..b970dc1 100644 (file)
@@ -185,7 +185,6 @@ static LPWSTR deformat_component(FORMAT *format, FORMSTR *str)
 {
     LPWSTR key, ret = NULL;
     MSICOMPONENT *comp;
-    BOOL source;
 
     key = msi_alloc((str->len + 1) * sizeof(WCHAR));
     lstrcpynW(key, get_formstr_data(format, str), str->len + 1);
@@ -194,8 +193,10 @@ static LPWSTR deformat_component(FORMAT *format, FORMSTR *str)
     if (!comp)
         goto done;
 
-    source = (comp->Action == INSTALLSTATE_SOURCE) ? TRUE : FALSE;
-    ret = resolve_folder(format->package, comp->Directory, source, FALSE, TRUE, NULL);
+    if (comp->Action == INSTALLSTATE_SOURCE)
+        ret = resolve_source_folder( format->package, comp->Directory, NULL );
+    else
+        ret = resolve_target_folder( format->package, comp->Directory, FALSE, TRUE, NULL );
 
 done:
     msi_free(key);
index d3f2d90..ffbe58b 100644 (file)
@@ -104,7 +104,7 @@ MSICOMPONENT* get_loaded_component( MSIPACKAGE* package, LPCWSTR Component )
 
     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
     {
-        if (lstrcmpW(Component,comp->Component)==0)
+        if (!strcmpW( Component, comp->Component ))
             return comp;
     }
     return NULL;
@@ -116,7 +116,7 @@ MSIFEATURE* get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature )
 
     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
     {
-        if (lstrcmpW( Feature, feature->Feature )==0)
+        if (!strcmpW( Feature, feature->Feature ))
             return feature;
     }
     return NULL;
@@ -128,7 +128,7 @@ MSIFILE* get_loaded_file( MSIPACKAGE* package, LPCWSTR key )
 
     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
     {
-        if (lstrcmpW( key, file->File )==0)
+        if (!strcmpW( key, file->File ))
             return file;
     }
     return NULL;
@@ -141,7 +141,7 @@ int track_tempfile( MSIPACKAGE *package, LPCWSTR path )
     TRACE("%s\n", debugstr_w(path));
 
     LIST_FOR_EACH_ENTRY( temp, &package->tempfiles, MSITEMPFILE, entry )
-        if (!lstrcmpW( path, temp->Path ))
+        if (!strcmpW( path, temp->Path ))
             return 0;
 
     temp = msi_alloc_zero( sizeof (MSITEMPFILE) );
@@ -160,7 +160,7 @@ MSIFOLDER *get_loaded_folder( MSIPACKAGE *package, LPCWSTR dir )
 
     LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
     {
-        if (lstrcmpW( dir, folder->Directory )==0)
+        if (!strcmpW( dir, folder->Directory ))
             return folder;
     }
     return NULL;
@@ -232,8 +232,7 @@ LPWSTR resolve_file_source(MSIPACKAGE *package, MSIFILE *file)
     if (file->IsCompressed)
         return NULL;
 
-    p = resolve_folder(package, file->Component->Directory,
-                       TRUE, FALSE, TRUE, NULL);
+    p = resolve_source_folder( package, file->Component->Directory, NULL );
     path = build_directory_name(2, p, file->ShortName);
 
     if (file->LongName &&
@@ -245,32 +244,77 @@ LPWSTR resolve_file_source(MSIPACKAGE *package, MSIFILE *file)
 
     msi_free(p);
 
-    TRACE("file %s source resolves to %s\n", debugstr_w(file->File),
-          debugstr_w(path));
-
+    TRACE("file %s source resolves to %s\n", debugstr_w(file->File), debugstr_w(path));
     return path;
 }
 
-LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, 
-                      BOOL set_prop, BOOL load_prop, MSIFOLDER **folder)
+LPWSTR resolve_source_folder( MSIPACKAGE *package, LPCWSTR name, MSIFOLDER **folder )
 {
     MSIFOLDER *f;
     LPWSTR p, path = NULL, parent;
 
-    TRACE("Working to resolve %s\n",debugstr_w(name));
+    TRACE("working to resolve %s\n", debugstr_w(name));
+
+    if (!strcmpW( name, cszSourceDir ))
+        name = cszTargetDir;
 
-    if (!name)
+    f = get_loaded_folder( package, name );
+    if (!f)
         return NULL;
 
-    if (!lstrcmpW(name,cszSourceDir))
-        name = cszTargetDir;
+    /* special resolving for Target and Source root dir */
+    if (!strcmpW( name, cszTargetDir ))
+    {
+        if (!f->ResolvedSource)
+            f->ResolvedSource = get_source_root( package );
+    }
+
+    if (folder)
+        *folder = f;
+
+    if (f->ResolvedSource)
+    {
+        path = strdupW( f->ResolvedSource );
+        TRACE("   already resolved to %s\n", debugstr_w(path));
+        return path;
+    }
+
+    if (!f->Parent)
+        return path;
+
+    parent = f->Parent;
+    TRACE(" ! parent is %s\n", debugstr_w(parent));
+
+    p = resolve_source_folder( package, parent, NULL );
+
+    if (package->WordCount & msidbSumInfoSourceTypeCompressed)
+        path = get_source_root( package );
+    else if (package->WordCount & msidbSumInfoSourceTypeSFN)
+        path = build_directory_name( 3, p, f->SourceShortPath, NULL );
+    else
+        path = build_directory_name( 3, p, f->SourceLongPath, NULL );
+
+    TRACE("-> %s\n", debugstr_w(path));
+    f->ResolvedSource = strdupW( path );
+    msi_free( p );
+
+    return path;
+}
+
+LPWSTR resolve_target_folder( MSIPACKAGE *package, LPCWSTR name, BOOL set_prop, BOOL load_prop,
+                              MSIFOLDER **folder )
+{
+    MSIFOLDER *f;
+    LPWSTR p, path = NULL, parent;
+
+    TRACE("working to resolve %s\n", debugstr_w(name));
 
     f = get_loaded_folder( package, name );
     if (!f)
         return NULL;
 
     /* special resolving for Target and Source root dir */
-    if (!strcmpW(name,cszTargetDir))
+    if (!strcmpW( name, cszTargetDir ))
     {
         if (!f->ResolvedTarget && !f->Property)
         {
@@ -286,45 +330,33 @@ LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
             /* correct misbuilt target dir */
             path = build_directory_name(2, check_path, NULL);
             clean_spaces_from_path( path );
-            if (strcmpiW(path,check_path)!=0)
+            if (strcmpiW( path, check_path ))
                 msi_set_property( package->db, cszTargetDir, path );
             msi_free(check_path);
 
             f->ResolvedTarget = path;
         }
-
-        if (!f->ResolvedSource)
-            f->ResolvedSource = get_source_root( package );
     }
 
     if (folder)
         *folder = f;
 
-    if (!source && f->ResolvedTarget)
+    if (f->ResolvedTarget)
     {
         path = strdupW( f->ResolvedTarget );
-        TRACE("   already resolved to %s\n",debugstr_w(path));
+        TRACE("   already resolved to %s\n", debugstr_w(path));
         return path;
     }
 
-    if (source && f->ResolvedSource)
-    {
-        path = strdupW( f->ResolvedSource );
-        TRACE("   (source)already resolved to %s\n",debugstr_w(path));
-        return path;
-    }
-
-    if (!source && f->Property)
+    if (f->Property)
     {
         path = build_directory_name( 2, f->Property, NULL );
-
-        TRACE("   internally set to %s\n",debugstr_w(path));
-        if (set_prop)
-            msi_set_property( package->db, name, path );
+        TRACE("   internally set to %s\n", debugstr_w(path));
+        if (set_prop) msi_set_property( package->db, name, path );
         return path;
     }
 
-    if (!source && load_prop && (path = msi_dup_property( package->db, name )))
+    if (load_prop && (path = msi_dup_property( package->db, name )))
     {
         f->ResolvedTarget = strdupW( path );
         TRACE("   property set to %s\n", debugstr_w(path));
@@ -336,35 +368,18 @@ LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
 
     parent = f->Parent;
 
-    TRACE(" ! Parent is %s\n", debugstr_w(parent));
+    TRACE(" ! parent is %s\n", debugstr_w(parent));
 
-    p = resolve_folder(package, parent, source, set_prop, load_prop, NULL);
-    if (!source)
-    {
-        TRACE("   TargetDefault = %s\n", debugstr_w(f->TargetDefault));
+    p = resolve_target_folder( package, parent, set_prop, load_prop, NULL );
 
-        path = build_directory_name( 3, p, f->TargetDefault, NULL );
-        clean_spaces_from_path( path );
-        f->ResolvedTarget = strdupW( path );
-        TRACE("target -> %s\n", debugstr_w(path));
-        if (set_prop)
-            msi_set_property( package->db, name, path );
-    }
-    else
-    {
-        path = NULL;
+    TRACE("   TargetDefault = %s\n", debugstr_w(f->TargetDefault));
+    path = build_directory_name( 3, p, f->TargetDefault, NULL );
+    clean_spaces_from_path( path );
+    f->ResolvedTarget = strdupW( path );
 
-        if (package->WordCount & msidbSumInfoSourceTypeCompressed)
-            path = get_source_root( package );
-        else if (package->WordCount & msidbSumInfoSourceTypeSFN)
-            path = build_directory_name( 3, p, f->SourceShortPath, NULL );
-        else
-            path = build_directory_name( 3, p, f->SourceLongPath, NULL );
-
-        TRACE("source -> %s\n", debugstr_w(path));
-        f->ResolvedSource = strdupW( path );
-    }
-    msi_free(p);
+    TRACE("-> %s\n", debugstr_w(path));
+    if (set_prop) msi_set_property( package->db, name, path );
+    msi_free( p );
 
     return path;
 }
@@ -479,6 +494,8 @@ LPWSTR build_directory_name(DWORD count, ...)
         if( ((i+1)!=count) && dir[strlenW(dir)-1]!='\\')
             strcatW(dir, szBackSlash);
     }
+    va_end(va);
+
     return dir;
 }
 
@@ -561,7 +578,7 @@ void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
     MSIRECORD * row = 0;
     DWORD size;
 
-    if (!package->LastAction || strcmpW(package->LastAction,action))
+    if (!package->LastAction || strcmpW(package->LastAction, action))
     {
         row = MSI_QueryGetRecord(package->db, Query_t, action);
         if (!row)
@@ -639,16 +656,11 @@ LPWSTR create_component_advertise_string(MSIPACKAGE* package,
 }
 
 /* update component state based on a feature change */
-void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
+void ACTION_UpdateComponentStates( MSIPACKAGE *package, MSIFEATURE *feature )
 {
     INSTALLSTATE newstate;
-    MSIFEATURE *feature;
     ComponentList *cl;
 
-    feature = get_loaded_feature(package,szFeature);
-    if (!feature)
-        return;
-
     newstate = feature->ActionRequest;
 
     if (newstate == INSTALLSTATE_ABSENT)
@@ -658,15 +670,17 @@ void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
     {
         MSICOMPONENT* component = cl->component;
     
+        if (!component->Enabled) continue;
+
         TRACE("MODIFYING(%i): Component %s (Installed %i, Action %i, Request %i)\n",
             newstate, debugstr_w(component->Component), component->Installed, 
             component->Action, component->ActionRequest);
         
-        if (!component->Enabled)
-            continue;
         if (newstate == INSTALLSTATE_LOCAL)
-            msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
+        {
+            component->Action = INSTALLSTATE_LOCAL;
+            component->ActionRequest = INSTALLSTATE_LOCAL;
+        }
         else 
         {
             ComponentList *clist;
@@ -674,9 +688,10 @@ void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
 
             component->hasLocalFeature = FALSE;
 
-            msi_component_set_state(package, component, newstate);
+            component->Action = newstate;
+            component->ActionRequest = newstate;
 
-            /*if any other feature wants is local we need to set it local*/
+            /* if any other feature wants it local we need to set it local */
             LIST_FOR_EACH_ENTRY( f, &package->features, MSIFEATURE, entry )
             {
                 if ( f->ActionRequest != INSTALLSTATE_LOCAL &&
@@ -697,14 +712,26 @@ void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
                         if (component->Attributes & msidbComponentAttributesOptional)
                         {
                             if (f->Attributes & msidbFeatureAttributesFavorSource)
-                                msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
+                            {
+                                component->Action = INSTALLSTATE_SOURCE;
+                                component->ActionRequest = INSTALLSTATE_SOURCE;
+                            }
                             else
-                                msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
+                            {
+                                component->Action = INSTALLSTATE_LOCAL;
+                                component->ActionRequest = INSTALLSTATE_LOCAL;
+                            }
                         }
                         else if (component->Attributes & msidbComponentAttributesSourceOnly)
-                            msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
+                        {
+                            component->Action = INSTALLSTATE_SOURCE;
+                            component->ActionRequest = INSTALLSTATE_SOURCE;
+                        }
                         else
-                            msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
+                        {
+                            component->Action = INSTALLSTATE_LOCAL;
+                            component->ActionRequest = INSTALLSTATE_LOCAL;
+                        }
                     }
                 }
             }
@@ -747,7 +774,7 @@ BOOL check_unique_action(const MSIPACKAGE *package, LPCWSTR action)
         return FALSE;
 
     for (i = 0; i < package->script->UniqueActionsCount; i++)
-        if (!strcmpW(package->script->UniqueActions[i],action))
+        if (!strcmpW(package->script->UniqueActions[i], action))
             return TRUE;
 
     return FALSE;
index 61807e9..03e1bd9 100644 (file)
@@ -24,6 +24,7 @@
 #include "winbase.h"
 #include "winerror.h"
 #include "wine/debug.h"
+#include "wine/unicode.h"
 #include "msi.h"
 #include "msiquery.h"
 #include "objbase.h"
@@ -117,7 +118,7 @@ static BOOL msi_columns_in_order(MSIINSERTVIEW *iv, UINT col_count)
         iv->sv->ops->get_column_info(iv->sv, i, &a, NULL, NULL, NULL);
         iv->table->ops->get_column_info(iv->table, i, &b, NULL, NULL, NULL);
 
-        res = lstrcmpW(a, b);
+        res = strcmpW( a, b );
         msi_free(a);
         msi_free(b);
 
@@ -168,7 +169,7 @@ static UINT msi_arrange_record(MSIINSERTVIEW *iv, MSIRECORD **values)
             if (r != ERROR_SUCCESS)
                 goto err;
 
-            res = lstrcmpW(a, b);
+            res = strcmpW( a, b );
             msi_free(b);
 
             if (res == 0)
index fa3e4f9..30a63e6 100644 (file)
@@ -282,7 +282,7 @@ done:
         return r;
     }
 
-    path = resolve_folder( package, szFolder, FALSE, FALSE, TRUE, NULL );
+    path = resolve_target_folder( package, szFolder, FALSE, TRUE, NULL );
     msiobj_release( &package->hdr );
 
     if (!path)
@@ -336,7 +336,7 @@ UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder,
 }
 
 /***********************************************************************
- * MsiGetSourcePath   (internal)
+ * MSI_GetSourcePath   (internal)
  */
 static UINT MSI_GetSourcePath( MSIHANDLE hInstall, LPCWSTR szFolder,
                                awstring *szPathBuf, LPDWORD pcchPathBuf )
@@ -413,10 +413,10 @@ done:
         return ERROR_INVALID_PARAMETER;
     }
 
-    path = resolve_folder(package, szFolder, TRUE, FALSE, TRUE, NULL);
+    path = resolve_source_folder( package, szFolder, NULL );
     msiobj_release( &package->hdr );
 
-    TRACE("path = %s\n",debugstr_w(path));
+    TRACE("path = %s\n", debugstr_w(path));
     if (!path)
         return ERROR_DIRECTORY;
 
@@ -512,14 +512,14 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
            attrib & FILE_ATTRIBUTE_READONLY))
         return ERROR_FUNCTION_FAILED;
 
-    path = resolve_folder(package,szFolder,FALSE,FALSE,FALSE,&folder);
+    path = resolve_target_folder( package, szFolder, FALSE, FALSE, &folder );
     if (!path)
         return ERROR_DIRECTORY;
 
     msi_free(folder->Property);
     folder->Property = build_directory_name(2, szFolderPath, NULL);
 
-    if (lstrcmpiW(path, folder->Property) == 0)
+    if (!strcmpiW( path, folder->Property ))
     {
         /*
          *  Resolved Target has not really changed, so just 
@@ -527,7 +527,7 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
          */
         msi_free(folder->ResolvedTarget);
         folder->ResolvedTarget = NULL;
-        path2 = resolve_folder(package,szFolder,FALSE,TRUE,FALSE,NULL);
+        path2 = resolve_target_folder( package, szFolder, TRUE, FALSE, NULL );
         msi_free(path2);
     }
     else
@@ -542,23 +542,23 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
 
         LIST_FOR_EACH_ENTRY( f, &package->folders, MSIFOLDER, entry )
         {
-            path2 = resolve_folder(package, f->Directory, FALSE, TRUE, FALSE, NULL);
+            path2 = resolve_target_folder( package, f->Directory, TRUE, FALSE, NULL );
             msi_free(path2);
         }
 
         LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
         {
             MSICOMPONENT *comp = file->Component;
-            LPWSTR p;
+            LPWSTR dir;
 
-            if (!comp)
+            if (!comp->Enabled || (comp->assembly && !comp->assembly->application))
                 continue;
 
-            p = resolve_folder(package, comp->Directory, FALSE, FALSE, FALSE, NULL);
+            dir = resolve_target_folder( package, comp->Directory, FALSE, FALSE, NULL );
             msi_free(file->TargetPath);
 
-            file->TargetPath = build_directory_name(2, p, file->FileName);
-            msi_free(p);
+            file->TargetPath = build_directory_name(2, dir, file->FileName);
+            msi_free(dir);
         }
     }
     msi_free(path);
@@ -716,6 +716,10 @@ BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
         r = package->need_reboot;
         break;
 
+    case MSIRUNMODE_LOGENABLED:
+        r = (package->log_file != INVALID_HANDLE_VALUE);
+        break;
+
     default:
         FIXME("unimplemented run mode: %d\n", iRunMode);
         r = TRUE;
@@ -821,14 +825,14 @@ UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature,
         feature->Attributes & msidbFeatureAttributesDisallowAdvertise)
         return ERROR_FUNCTION_FAILED;
 
-    msi_feature_set_state(package, feature, iState);
+    feature->ActionRequest = iState;
 
-    ACTION_UpdateComponentStates(package,szFeature);
+    ACTION_UpdateComponentStates( package, feature );
 
     /* update all the features that are children of this feature */
     LIST_FOR_EACH_ENTRY( child, &package->features, MSIFEATURE, entry )
     {
-        if (lstrcmpW(szFeature, child->Feature_Parent) == 0)
+        if (child->Feature_Parent && !strcmpW( szFeature, child->Feature_Parent ))
             MSI_SetFeatureStateW(package, child->Feature, iState);
     }
     
@@ -917,9 +921,9 @@ UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPCWSTR szFeature,
         *piInstalled = feature->Installed;
 
     if (piAction)
-        *piAction = feature->Action;
+        *piAction = feature->ActionRequest;
 
-    TRACE("returning %i %i\n", feature->Installed, feature->Action);
+    TRACE("returning %i %i\n", feature->Installed, feature->ActionRequest);
 
     return ERROR_SUCCESS;
 }
@@ -1158,7 +1162,8 @@ static UINT MSI_SetComponentStateW(MSIPACKAGE *package, LPCWSTR szComponent,
     if (!comp)
         return ERROR_UNKNOWN_COMPONENT;
 
-    comp->Installed = iState;
+    if (comp->Enabled)
+        comp->Action = iState;
 
     return ERROR_SUCCESS;
 }
@@ -1176,13 +1181,22 @@ UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPCWSTR szComponent,
         return ERROR_UNKNOWN_COMPONENT;
 
     if (piInstalled)
-        *piInstalled = comp->Installed;
+    {
+        if (comp->Enabled)
+            *piInstalled = comp->Installed;
+        else
+            *piInstalled = INSTALLSTATE_UNKNOWN;
+    }
 
     if (piAction)
-        *piAction = comp->Action;
+    {
+        if (comp->Enabled)
+            *piAction = comp->Action;
+        else
+            *piAction = INSTALLSTATE_UNKNOWN;
+    }
 
     TRACE("states (%i, %i)\n", comp->Installed, comp->Action );
-
     return ERROR_SUCCESS;
 }
 
index 788528e..37d3530 100644 (file)
@@ -68,7 +68,7 @@ static BOOL source_matches_volume(MSIMEDIAINFO *mi, LPCWSTR source_root)
         return FALSE;
     }
 
-    return !lstrcmpW(mi->volume_label, volume_name);
+    return !strcmpW( mi->volume_label, volume_name );
 }
 
 static UINT msi_change_media(MSIPACKAGE *package, MSIMEDIAINFO *mi)
@@ -331,7 +331,7 @@ static INT_PTR cabinet_next_cabinet(FDINOTIFICATIONTYPE fdint,
         goto done;
     }
 
-    if (lstrcmpiW(mi->cabinet, cab))
+    if (strcmpiW( mi->cabinet, cab ))
     {
         ERR("Continuous cabinet does not match the next cabinet in the Media table\n");
         goto done;
@@ -656,7 +656,7 @@ static UINT get_drive_type(const WCHAR *path)
     return GetDriveTypeW(root);
 }
 
-static UINT msi_load_media_info(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO *mi)
+UINT msi_load_media_info(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO *mi)
 {
     MSIRECORD *row;
     LPWSTR source_dir;
@@ -748,23 +748,44 @@ static UINT find_published_source(MSIPACKAGE *package, MSIMEDIAINFO *mi)
     if (r != ERROR_SUCCESS)
         return r;
 
-    index = 0;
-    volumesz = MAX_PATH;
-    promptsz = MAX_PATH;
-
     if (last_type[0] == 'n')
     {
-        while (MsiSourceListEnumSourcesW(package->ProductCode, NULL,
-                                        package->Context,
-                                        MSISOURCETYPE_NETWORK, index++,
-                                        volume, &volumesz) == ERROR_SUCCESS)
+        WCHAR cabinet_file[MAX_PATH];
+        BOOL check_all = FALSE;
+
+        while(TRUE)
         {
-            if (!strncmpiW(source, volume, strlenW(source)))
+            index = 0;
+            volumesz = MAX_PATH;
+            while (MsiSourceListEnumSourcesW(package->ProductCode, NULL,
+                                             package->Context,
+                                             MSISOURCETYPE_NETWORK, index++,
+                                             volume, &volumesz) == ERROR_SUCCESS)
             {
-                lstrcpyW(mi->sourcedir, source);
-                TRACE("Found network source %s\n", debugstr_w(mi->sourcedir));
-                return ERROR_SUCCESS;
+                if (check_all || !strncmpiW(source, volume, strlenW(source)))
+                {
+                    lstrcpyW(cabinet_file, volume);
+                    PathAddBackslashW(cabinet_file);
+                    lstrcatW(cabinet_file, mi->cabinet);
+
+                    if (GetFileAttributesW(cabinet_file) == INVALID_FILE_ATTRIBUTES)
+                    {
+                        volumesz = MAX_PATH;
+                        if(!check_all)
+                            break;
+                        continue;
+                    }
+
+                    lstrcpyW(mi->sourcedir, volume);
+                    TRACE("Found network source %s\n", debugstr_w(mi->sourcedir));
+                    return ERROR_SUCCESS;
+                }
             }
+
+            if (!check_all)
+                check_all = TRUE;
+            else
+                break;
         }
     }
 
@@ -803,13 +824,6 @@ UINT ready_media(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO *mi)
     if (mi->is_continuous)
         return ERROR_SUCCESS;
 
-    rc = msi_load_media_info(package, file, mi);
-    if (rc != ERROR_SUCCESS)
-    {
-        ERR("Unable to load media info %u\n", rc);
-        return ERROR_FUNCTION_FAILED;
-    }
-
     /* cabinet is internal, no checks needed */
     if (!mi->cabinet || mi->cabinet[0] == '#')
         return ERROR_SUCCESS;
@@ -841,7 +855,7 @@ UINT ready_media(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO *mi)
 
     /* check volume matches, change media if not */
     if (mi->volume_label && mi->disk_id > 1 &&
-        lstrcmpW(mi->first_volume, mi->volume_label))
+        strcmpW( mi->first_volume, mi->volume_label ))
     {
         LPWSTR source = msi_dup_property(package->db, cszSourceDir);
         BOOL matches;
index 7d1b9a5..325a5b0 100644 (file)
@@ -299,13 +299,14 @@ done:
     return r;
 }
 
-static UINT get_patch_product_codes( LPCWSTR szPatchPackage, WCHAR **product_codes )
+
+static UINT get_patch_product_codes( LPCWSTR szPatchPackage, WCHAR ***product_codes )
 {
     MSIHANDLE patch, info = 0;
     UINT r, type;
     DWORD size;
     static WCHAR empty[] = {0};
-    WCHAR *codes;
+    WCHAR *codes = NULL;
 
     r = MsiOpenDatabaseW( szPatchPackage, MSIDBOPEN_READONLY, &patch );
     if (r != ERROR_SUCCESS)
@@ -332,26 +333,25 @@ static UINT get_patch_product_codes( LPCWSTR szPatchPackage, WCHAR **product_cod
     }
 
     r = MsiSummaryInfoGetPropertyW( info, PID_TEMPLATE, &type, NULL, NULL, codes, &size );
-    if (r != ERROR_SUCCESS)
-        msi_free( codes );
-    else
-        *product_codes = codes;
+    if (r == ERROR_SUCCESS)
+        *product_codes = msi_split_string( codes, ';' );
 
 done:
     MsiCloseHandle( info );
     MsiCloseHandle( patch );
+    msi_free( codes );
     return r;
 }
 
 static UINT MSI_ApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szProductCode, LPCWSTR szCommandLine)
 {
-    UINT r;
+    UINT r, i;
     DWORD size;
     LPCWSTR cmd_ptr = szCommandLine;
-    LPWSTR beg, end, cmd, codes = NULL;
+    LPWSTR cmd, *codes = NULL;
     BOOL succeeded = FALSE;
 
-    static const WCHAR patcheq[] = {'P','A','T','C','H','=',0};
+    static const WCHAR fmt[] = {'%','s',' ','P','A','T','C','H','=','"','%','s','"',0};
     static WCHAR empty[] = {0};
 
     if (!szPatchPackage || !szPatchPackage[0])
@@ -363,34 +363,27 @@ static UINT MSI_ApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szProductCode, LPCWS
     if (!szCommandLine)
         cmd_ptr = empty;
 
-    size = lstrlenW(cmd_ptr) + lstrlenW(patcheq) + lstrlenW(szPatchPackage) + 1;
+    size = strlenW(cmd_ptr) + strlenW(fmt) + strlenW(szPatchPackage) + 1;
     cmd = msi_alloc(size * sizeof(WCHAR));
     if (!cmd)
     {
         msi_free(codes);
         return ERROR_OUTOFMEMORY;
     }
-
-    lstrcpyW(cmd, cmd_ptr);
-    if (szCommandLine) lstrcatW(cmd, szSpace);
-    lstrcatW(cmd, patcheq);
-    lstrcatW(cmd, szPatchPackage);
+    sprintfW(cmd, fmt, cmd_ptr, szPatchPackage);
 
     if (szProductCode)
         r = MsiConfigureProductExW(szProductCode, INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, cmd);
     else
     {
-        beg = codes;
-        while ((end = strchrW(beg, '}')))
+        for (i = 0; codes[i]; i++)
         {
-            *(end + 1) = '\0';
-            r = MsiConfigureProductExW(beg, INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, cmd);
+            r = MsiConfigureProductExW(codes[i], INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, cmd);
             if (r == ERROR_SUCCESS)
             {
                 TRACE("patch applied\n");
                 succeeded = TRUE;
             }
-            beg = end + 2;
         }
 
         if (succeeded)
@@ -688,6 +681,8 @@ UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel,
 
     static const WCHAR szInstalled[] = {
         ' ','I','n','s','t','a','l','l','e','d','=','1',0};
+    static const WCHAR szInstallLevel[] = {
+        ' ','I','N','S','T','A','L','L','L','E','V','E','L','=','3','2','7','6','7',0};
     static const WCHAR szRemoveAll[] = {
         ' ','R','E','M','O','V','E','=','A','L','L',0};
     static const WCHAR szMachine[] = {
@@ -719,6 +714,9 @@ UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel,
     if (szCommandLine)
         sz += lstrlenW(szCommandLine);
 
+    if (eInstallState != INSTALLSTATE_DEFAULT)
+        sz += lstrlenW(szInstallLevel);
+
     if (eInstallState == INSTALLSTATE_ABSENT)
         sz += lstrlenW(szRemoveAll);
 
@@ -736,6 +734,9 @@ UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel,
     if (szCommandLine)
         lstrcpyW(commandline,szCommandLine);
 
+    if (eInstallState != INSTALLSTATE_DEFAULT)
+        lstrcatW(commandline, szInstallLevel);
+
     if (eInstallState == INSTALLSTATE_ABSENT)
         lstrcatW(commandline, szRemoveAll);
 
@@ -983,22 +984,22 @@ static UINT MSI_GetProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute,
 
     MSIREG_OpenInstallProps(szProduct, context, NULL, &userdata, FALSE);
 
-    if (!lstrcmpW(szAttribute, INSTALLPROPERTY_HELPLINKW) ||
-        !lstrcmpW(szAttribute, INSTALLPROPERTY_HELPTELEPHONEW) ||
-        !lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLDATEW) ||
-        !lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW) ||
-        !lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLLOCATIONW) ||
-        !lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLSOURCEW) ||
-        !lstrcmpW(szAttribute, INSTALLPROPERTY_LOCALPACKAGEW) ||
-        !lstrcmpW(szAttribute, INSTALLPROPERTY_PUBLISHERW) ||
-        !lstrcmpW(szAttribute, INSTALLPROPERTY_URLINFOABOUTW) ||
-        !lstrcmpW(szAttribute, INSTALLPROPERTY_URLUPDATEINFOW) ||
-        !lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONMINORW) ||
-        !lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONMAJORW) ||
-        !lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONSTRINGW) ||
-        !lstrcmpW(szAttribute, INSTALLPROPERTY_PRODUCTIDW) ||
-        !lstrcmpW(szAttribute, INSTALLPROPERTY_REGCOMPANYW) ||
-        !lstrcmpW(szAttribute, INSTALLPROPERTY_REGOWNERW))
+    if (!strcmpW( szAttribute, INSTALLPROPERTY_HELPLINKW ) ||
+        !strcmpW( szAttribute, INSTALLPROPERTY_HELPTELEPHONEW ) ||
+        !strcmpW( szAttribute, INSTALLPROPERTY_INSTALLDATEW ) ||
+        !strcmpW( szAttribute, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW ) ||
+        !strcmpW( szAttribute, INSTALLPROPERTY_INSTALLLOCATIONW ) ||
+        !strcmpW( szAttribute, INSTALLPROPERTY_INSTALLSOURCEW ) ||
+        !strcmpW( szAttribute, INSTALLPROPERTY_LOCALPACKAGEW ) ||
+        !strcmpW( szAttribute, INSTALLPROPERTY_PUBLISHERW ) ||
+        !strcmpW( szAttribute, INSTALLPROPERTY_URLINFOABOUTW ) ||
+        !strcmpW( szAttribute, INSTALLPROPERTY_URLUPDATEINFOW ) ||
+        !strcmpW( szAttribute, INSTALLPROPERTY_VERSIONMINORW ) ||
+        !strcmpW( szAttribute, INSTALLPROPERTY_VERSIONMAJORW ) ||
+        !strcmpW( szAttribute, INSTALLPROPERTY_VERSIONSTRINGW ) ||
+        !strcmpW( szAttribute, INSTALLPROPERTY_PRODUCTIDW ) ||
+        !strcmpW( szAttribute, INSTALLPROPERTY_REGCOMPANYW ) ||
+        !strcmpW( szAttribute, INSTALLPROPERTY_REGOWNERW ))
     {
         if (!prodkey)
         {
@@ -1009,25 +1010,25 @@ static UINT MSI_GetProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute,
         if (!userdata)
             return ERROR_UNKNOWN_PROPERTY;
 
-        if (!lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW))
+        if (!strcmpW( szAttribute, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW ))
             szAttribute = display_name;
-        else if (!lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONSTRINGW))
+        else if (!strcmpW( szAttribute, INSTALLPROPERTY_VERSIONSTRINGW ))
             szAttribute = display_version;
 
         val = msi_reg_get_value(userdata, szAttribute, &type);
         if (!val)
             val = empty;
     }
-    else if (!lstrcmpW(szAttribute, INSTALLPROPERTY_INSTANCETYPEW) ||
-             !lstrcmpW(szAttribute, INSTALLPROPERTY_TRANSFORMSW) ||
-             !lstrcmpW(szAttribute, INSTALLPROPERTY_LANGUAGEW) ||
-             !lstrcmpW(szAttribute, INSTALLPROPERTY_PRODUCTNAMEW) ||
-             !lstrcmpW(szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW) ||
-             !lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGECODEW) ||
-             !lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONW) ||
-             !lstrcmpW(szAttribute, INSTALLPROPERTY_PRODUCTICONW) ||
-             !lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGENAMEW) ||
-             !lstrcmpW(szAttribute, INSTALLPROPERTY_AUTHORIZED_LUA_APPW))
+    else if (!strcmpW( szAttribute, INSTALLPROPERTY_INSTANCETYPEW ) ||
+             !strcmpW( szAttribute, INSTALLPROPERTY_TRANSFORMSW ) ||
+             !strcmpW( szAttribute, INSTALLPROPERTY_LANGUAGEW ) ||
+             !strcmpW( szAttribute, INSTALLPROPERTY_PRODUCTNAMEW ) ||
+             !strcmpW( szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW ) ||
+             !strcmpW( szAttribute, INSTALLPROPERTY_PACKAGECODEW ) ||
+             !strcmpW( szAttribute, INSTALLPROPERTY_VERSIONW ) ||
+             !strcmpW( szAttribute, INSTALLPROPERTY_PRODUCTICONW ) ||
+             !strcmpW( szAttribute, INSTALLPROPERTY_PACKAGENAMEW ) ||
+             !strcmpW( szAttribute, INSTALLPROPERTY_AUTHORIZED_LUA_APPW ))
     {
         if (!prodkey)
         {
@@ -1035,10 +1036,10 @@ static UINT MSI_GetProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute,
             goto done;
         }
 
-        if (!lstrcmpW(szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW))
+        if (!strcmpW( szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW ))
             szAttribute = assignment;
 
-        if (!lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGENAMEW))
+        if (!strcmpW( szAttribute, INSTALLPROPERTY_PACKAGENAMEW ))
         {
             res = RegOpenKeyW(prodkey, sourcelist, &source);
             if (res != ERROR_SUCCESS)
@@ -1061,7 +1062,7 @@ static UINT MSI_GetProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute,
         }
 
         if (val != empty && type != REG_DWORD &&
-            !lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGECODEW))
+            !strcmpW( szAttribute, INSTALLPROPERTY_PACKAGECODEW ))
         {
             if (lstrlenW(val) != SQUISH_GUID_SIZE - 1)
                 badconfig = TRUE;
@@ -1324,23 +1325,23 @@ UINT WINAPI MsiGetProductInfoExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
             goto done;
     }
 
-    if (!lstrcmpW(szProperty, INSTALLPROPERTY_HELPLINKW) ||
-        !lstrcmpW(szProperty, INSTALLPROPERTY_HELPTELEPHONEW) ||
-        !lstrcmpW(szProperty, INSTALLPROPERTY_INSTALLDATEW) ||
-        !lstrcmpW(szProperty, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW) ||
-        !lstrcmpW(szProperty, INSTALLPROPERTY_INSTALLLOCATIONW) ||
-        !lstrcmpW(szProperty, INSTALLPROPERTY_INSTALLSOURCEW) ||
-        !lstrcmpW(szProperty, INSTALLPROPERTY_LOCALPACKAGEW) ||
-        !lstrcmpW(szProperty, INSTALLPROPERTY_PUBLISHERW) ||
-        !lstrcmpW(szProperty, INSTALLPROPERTY_URLINFOABOUTW) ||
-        !lstrcmpW(szProperty, INSTALLPROPERTY_URLUPDATEINFOW) ||
-        !lstrcmpW(szProperty, INSTALLPROPERTY_VERSIONMINORW) ||
-        !lstrcmpW(szProperty, INSTALLPROPERTY_VERSIONMAJORW) ||
-        !lstrcmpW(szProperty, INSTALLPROPERTY_VERSIONSTRINGW) ||
-        !lstrcmpW(szProperty, INSTALLPROPERTY_PRODUCTIDW) ||
-        !lstrcmpW(szProperty, INSTALLPROPERTY_REGCOMPANYW) ||
-        !lstrcmpW(szProperty, INSTALLPROPERTY_REGOWNERW) ||
-        !lstrcmpW(szProperty, INSTALLPROPERTY_INSTANCETYPEW))
+    if (!strcmpW( szProperty, INSTALLPROPERTY_HELPLINKW ) ||
+        !strcmpW( szProperty, INSTALLPROPERTY_HELPTELEPHONEW ) ||
+        !strcmpW( szProperty, INSTALLPROPERTY_INSTALLDATEW ) ||
+        !strcmpW( szProperty, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW ) ||
+        !strcmpW( szProperty, INSTALLPROPERTY_INSTALLLOCATIONW ) ||
+        !strcmpW( szProperty, INSTALLPROPERTY_INSTALLSOURCEW ) ||
+        !strcmpW( szProperty, INSTALLPROPERTY_LOCALPACKAGEW ) ||
+        !strcmpW( szProperty, INSTALLPROPERTY_PUBLISHERW ) ||
+        !strcmpW( szProperty, INSTALLPROPERTY_URLINFOABOUTW ) ||
+        !strcmpW( szProperty, INSTALLPROPERTY_URLUPDATEINFOW ) ||
+        !strcmpW( szProperty, INSTALLPROPERTY_VERSIONMINORW ) ||
+        !strcmpW( szProperty, INSTALLPROPERTY_VERSIONMAJORW ) ||
+        !strcmpW( szProperty, INSTALLPROPERTY_VERSIONSTRINGW ) ||
+        !strcmpW( szProperty, INSTALLPROPERTY_PRODUCTIDW ) ||
+        !strcmpW( szProperty, INSTALLPROPERTY_REGCOMPANYW ) ||
+        !strcmpW( szProperty, INSTALLPROPERTY_REGOWNERW ) ||
+        !strcmpW( szProperty, INSTALLPROPERTY_INSTANCETYPEW ))
     {
         val = msi_reg_get_value(props, package, &type);
         if (!val)
@@ -1353,9 +1354,9 @@ UINT WINAPI MsiGetProductInfoExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
 
         msi_free(val);
 
-        if (!lstrcmpW(szProperty, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW))
+        if (!strcmpW( szProperty, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW ))
             szProperty = displayname;
-        else if (!lstrcmpW(szProperty, INSTALLPROPERTY_VERSIONSTRINGW))
+        else if (!strcmpW( szProperty, INSTALLPROPERTY_VERSIONSTRINGW ))
             szProperty = displayversion;
 
         val = msi_reg_get_value(props, szProperty, &type);
@@ -1364,14 +1365,14 @@ UINT WINAPI MsiGetProductInfoExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
 
         r = msi_copy_outval(val, szValue, pcchValue);
     }
-    else if (!lstrcmpW(szProperty, INSTALLPROPERTY_TRANSFORMSW) ||
-             !lstrcmpW(szProperty, INSTALLPROPERTY_LANGUAGEW) ||
-             !lstrcmpW(szProperty, INSTALLPROPERTY_PRODUCTNAMEW) ||
-             !lstrcmpW(szProperty, INSTALLPROPERTY_PACKAGECODEW) ||
-             !lstrcmpW(szProperty, INSTALLPROPERTY_VERSIONW) ||
-             !lstrcmpW(szProperty, INSTALLPROPERTY_PRODUCTICONW) ||
-             !lstrcmpW(szProperty, INSTALLPROPERTY_PACKAGENAMEW) ||
-             !lstrcmpW(szProperty, INSTALLPROPERTY_AUTHORIZED_LUA_APPW))
+    else if (!strcmpW( szProperty, INSTALLPROPERTY_TRANSFORMSW ) ||
+             !strcmpW( szProperty, INSTALLPROPERTY_LANGUAGEW ) ||
+             !strcmpW( szProperty, INSTALLPROPERTY_PRODUCTNAMEW ) ||
+             !strcmpW( szProperty, INSTALLPROPERTY_PACKAGECODEW ) ||
+             !strcmpW( szProperty, INSTALLPROPERTY_VERSIONW ) ||
+             !strcmpW( szProperty, INSTALLPROPERTY_PRODUCTICONW ) ||
+             !strcmpW( szProperty, INSTALLPROPERTY_PACKAGENAMEW ) ||
+             !strcmpW( szProperty, INSTALLPROPERTY_AUTHORIZED_LUA_APPW ))
     {
         if (!prod && !classes)
             goto done;
@@ -1389,7 +1390,7 @@ UINT WINAPI MsiGetProductInfoExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
 
         r = msi_copy_outval(val, szValue, pcchValue);
     }
-    else if (!lstrcmpW(szProperty, INSTALLPROPERTY_PRODUCTSTATEW))
+    else if (!strcmpW( szProperty, INSTALLPROPERTY_PRODUCTSTATEW ))
     {
         if (dwContext == MSIINSTALLCONTEXT_MACHINE)
         {
@@ -1423,7 +1424,7 @@ UINT WINAPI MsiGetProductInfoExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
 
         r = msi_copy_outval(val, szValue, pcchValue);
     }
-    else if (!lstrcmpW(szProperty, INSTALLPROPERTY_ASSIGNMENTTYPEW))
+    else if (!strcmpW( szProperty, INSTALLPROPERTY_ASSIGNMENTTYPEW ))
     {
         if (!prod && !classes)
             goto done;
@@ -1554,7 +1555,7 @@ UINT WINAPI MsiGetPatchInfoExW(LPCWSTR szPatchCode, LPCWSTR szProductCode,
     if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
         return ERROR_INVALID_PARAMETER;
 
-    if (!lstrcmpW(szUserSid, szLocalSid))
+    if (szUserSid && !strcmpW( szUserSid, szLocalSid ))
         return ERROR_INVALID_PARAMETER;
 
     if (MSIREG_OpenUserDataProductKey(szProductCode, dwContext, NULL,
@@ -1575,7 +1576,7 @@ UINT WINAPI MsiGetPatchInfoExW(LPCWSTR szPatchCode, LPCWSTR szProductCode,
     if (res != ERROR_SUCCESS)
         goto done;
 
-    if (!lstrcmpW(szProperty, INSTALLPROPERTY_TRANSFORMSW))
+    if (!strcmpW( szProperty, INSTALLPROPERTY_TRANSFORMSW ))
     {
         if (MSIREG_OpenProductKey(szProductCode, NULL, dwContext,
                                   &prod, FALSE) != ERROR_SUCCESS)
@@ -1594,25 +1595,25 @@ UINT WINAPI MsiGetPatchInfoExW(LPCWSTR szPatchCode, LPCWSTR szProductCode,
                                         &udpatch, FALSE) != ERROR_SUCCESS)
             goto done;
 
-        if (!lstrcmpW(szProperty, INSTALLPROPERTY_LOCALPACKAGEW))
+        if (!strcmpW( szProperty, INSTALLPROPERTY_LOCALPACKAGEW ))
         {
             if (dwContext == MSIINSTALLCONTEXT_USERMANAGED)
                 szProperty = szManagedPackage;
             datakey = udpatch;
         }
-        else if (!lstrcmpW(szProperty, INSTALLPROPERTY_INSTALLDATEW))
+        else if (!strcmpW( szProperty, INSTALLPROPERTY_INSTALLDATEW ))
         {
             datakey = patch;
             szProperty = szInstalled;
         }
-        else if (!lstrcmpW(szProperty, INSTALLPROPERTY_LOCALPACKAGEW))
+        else if (!strcmpW( szProperty, INSTALLPROPERTY_LOCALPACKAGEW ))
         {
             datakey = udpatch;
         }
-        else if (!lstrcmpW(szProperty, INSTALLPROPERTY_UNINSTALLABLEW) ||
-                 !lstrcmpW(szProperty, INSTALLPROPERTY_PATCHSTATEW) ||
-                 !lstrcmpW(szProperty, INSTALLPROPERTY_DISPLAYNAMEW) ||
-                 !lstrcmpW(szProperty, INSTALLPROPERTY_MOREINFOURLW))
+        else if (!strcmpW( szProperty, INSTALLPROPERTY_UNINSTALLABLEW ) ||
+                 !strcmpW( szProperty, INSTALLPROPERTY_PATCHSTATEW ) ||
+                 !strcmpW( szProperty, INSTALLPROPERTY_DISPLAYNAMEW ) ||
+                 !strcmpW( szProperty, INSTALLPROPERTY_MOREINFOURLW ))
         {
             datakey = patch;
         }
@@ -1766,24 +1767,26 @@ UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes)
 
 UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes)
 {
-    HANDLE file = INVALID_HANDLE_VALUE;
-
     TRACE("%08x %s %08x\n", dwLogMode, debugstr_w(szLogFile), attributes);
 
+    msi_free(gszLogFile);
+    gszLogFile = NULL;
     if (szLogFile)
     {
-        lstrcpyW(gszLogFile,szLogFile);
+        HANDLE file;
+
         if (!(attributes & INSTALLLOGATTRIBUTES_APPEND))
             DeleteFileW(szLogFile);
-        file = CreateFileW(szLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
-                               FILE_ATTRIBUTE_NORMAL, NULL);
+        file = CreateFileW(szLogFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
+                           FILE_ATTRIBUTE_NORMAL, NULL);
         if (file != INVALID_HANDLE_VALUE)
+        {
+            gszLogFile = strdupW(szLogFile);
             CloseHandle(file);
+        }
         else
-            ERR("Unable to enable log %s\n",debugstr_w(szLogFile));
+            ERR("Unable to enable log %s (%u)\n", debugstr_w(szLogFile), GetLastError());
     }
-    else
-        gszLogFile[0] = '\0';
 
     return ERROR_SUCCESS;
 }
@@ -1944,6 +1947,7 @@ UINT WINAPI MsiQueryComponentStateW(LPCWSTR szProductCode,
             *pdwState = INSTALLSTATE_LOCAL;
     }
 
+    TRACE("-> %d\n", *pdwState);
     return ERROR_SUCCESS;
 }
 
@@ -1982,6 +1986,11 @@ INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
     if (lstrlenW(szProduct) != GUID_SIZE - 1)
         return INSTALLSTATE_INVALIDARG;
 
+    if (szProduct[0] != '{' || szProduct[37] != '}')
+        return INSTALLSTATE_UNKNOWN;
+
+    SetLastError( ERROR_SUCCESS );
+
     if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
                               &prodkey, FALSE) != ERROR_SUCCESS &&
         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
@@ -2015,6 +2024,7 @@ done:
 
     RegCloseKey(prodkey);
     RegCloseKey(userdata);
+    TRACE("-> %d\n", state);
     return state;
 }
 
@@ -2631,6 +2641,8 @@ INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
     if (!squash_guid( szProduct, squishProduct ))
         return INSTALLSTATE_INVALIDARG;
 
+    SetLastError( ERROR_SUCCESS );
+
     if (MSIREG_OpenFeaturesKey(szProduct, MSIINSTALLCONTEXT_USERMANAGED,
                                &hkey, FALSE) != ERROR_SUCCESS &&
         MSIREG_OpenFeaturesKey(szProduct, MSIINSTALLCONTEXT_USERUNMANAGED,
@@ -2711,17 +2723,17 @@ INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
 
         msi_free(path);
     }
-
-    TRACE("%s %s -> %d\n", debugstr_w(szProduct), debugstr_w(szFeature), r);
     msi_free(components);
 
     if (missing)
-        return INSTALLSTATE_ADVERTISED;
-
-    if (source)
-        return INSTALLSTATE_SOURCE;
+        r = INSTALLSTATE_ADVERTISED;
+    else if (source)
+        r = INSTALLSTATE_SOURCE;
+    else
+        r = INSTALLSTATE_LOCAL;
 
-    return INSTALLSTATE_LOCAL;
+    TRACE("-> %d\n", r);
+    return r;
 }
 
 /******************************************************************
@@ -3543,8 +3555,8 @@ UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
     LPWSTR ptr;
     DWORD sz;
 
-    FIXME("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
-                           dwReinstallMode);
+    FIXME("%s %s 0x%08x\n",
+          debugstr_w(szProduct), debugstr_w(szFeature), dwReinstallMode);
 
     ptr = reinstallmode;
 
@@ -3661,8 +3673,10 @@ UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
     handle = CreateFileW( szFilePath, GENERIC_READ,
                           FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL );
     if (handle == INVALID_HANDLE_VALUE)
+    {
+        WARN("can't open file %u\n", GetLastError());
         return ERROR_FILE_NOT_FOUND;
-
+    }
     length = GetFileSize( handle, NULL );
 
     mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, 0, NULL );
@@ -3771,6 +3785,31 @@ UINT WINAPI MsiSetExternalUIRecord( INSTALLUI_HANDLER_RECORD handler,
     return ERROR_SUCCESS;
 }
 
+/***********************************************************************
+ * MsiInstallMissingComponentA     [MSI.@]
+ */
+UINT WINAPI MsiInstallMissingComponentA( LPCSTR product, LPCSTR component, INSTALLSTATE state )
+{
+    UINT r;
+    WCHAR *productW = NULL, *componentW = NULL;
+
+    TRACE("%s, %s, %d\n", debugstr_a(product), debugstr_a(component), state);
+
+    if (product && !(productW = strdupAtoW( product )))
+        return ERROR_OUTOFMEMORY;
+
+    if (component && !(componentW = strdupAtoW( component )))
+    {
+        msi_free( productW );
+        return ERROR_OUTOFMEMORY;
+    }
+
+    r = MsiInstallMissingComponentW( productW, componentW, state );
+    msi_free( productW );
+    msi_free( componentW );
+    return r;
+}
+
 /***********************************************************************
  * MsiInstallMissingComponentW     [MSI.@]
  */
index 8c98a6d..4dd17cc 100644 (file)
@@ -11,6 +11,7 @@
        <file>action.c</file>
        <file>alter.c</file>
        <file>appsearch.c</file>
+       <file>assembly.c</file>
        <file>automation.c</file>
        <file>classes.c</file>
        <file>cond.tab.c</file>
index d81484f..c980fa8 100644 (file)
  */
 
 #include "windef.h"
-#include "winbase.h"
-#include "winuser.h"
-#include "winnls.h"
 
-LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
-
-#include "version.rc"
-
-#include "msi_Bg.rc"
-#include "msi_Da.rc"
-#include "msi_En.rc"
-#include "msi_Es.rc"
-#include "msi_Fi.rc"
-#include "msi_Hu.rc"
-#include "msi_Ko.rc"
-#include "msi_Nl.rc"
-#include "msi_No.rc"
-#include "msi_Pl.rc"
-#include "msi_Sv.rc"
-#include "msi_Tr.rc"
-#include "msi_Uk.rc"
-#include "msi_Zh.rc"
+LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
 
-/* UTF-8 */
-#include "msi_De.rc"
-#include "msi_Fr.rc"
-#include "msi_It.rc"
-#include "msi_Lt.rc"
-#include "msi_Pt.rc"
-#include "msi_Ro.rc"
-#include "msi_Ru.rc"
-#include "msi_Si.rc"
-#include "msi_Sr.rc"
+STRINGTABLE
+{
+       4 "The specified installation package could not be opened.  Please check the file path and try again."
+       5 "path %s not found"
+       9 "insert disk %s"
+       10 "Windows Installer %s\n\n" \
+       "Usage:\n" \
+       "msiexec command {required parameter} [optional parameter]\n\n" \
+       "Install a product:\n" \
+       "\t/i {package|product_code} [property]\n" \
+       "\t/package {package|product_code} [property]\n" \
+       "\t/a package [property]\n" \
+       "Repair an installation:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {package|product_code}\n" \
+       "Uninstall a product:\n" \
+       "\t/uninstall {package|product_code} [property]\n" \
+       "\t/x {package|product_code} [property]\n" \
+       "Advertise a product:\n" \
+       "\t/j[u|m] package [/t transform] [/g languageid]\n" \
+       "Apply a patch:\n" \
+       "\t/p patch_package [property]\n" \
+       "\t/p patch_package /a package [property]\n" \
+       "Log and UI Modifiers for above commands:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Register MSI Service:\n" \
+       "\t/y\n" \
+       "Unregister MSI Service:\n" \
+       "\t/z\n" \
+       "Display this help:\n" \
+       "\t/help\n" \
+       "\t/?\n"
+       11 "enter which folder contains %s"
+       12 "install source for feature missing"
+       13 "network drive for feature missing"
+       14 "feature from:"
+       15 "choose which folder contains %s"
+}
 
 LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
 
 /* @makedep: msiserver.tlb */
 1 TYPELIB msiserver.tlb
 
+/* @makedep: msiserver.rgs */
+1 WINE_REGISTRY msiserver.rgs
+
 /* @makedep: instadvert.bmp */
 0x1001 BITMAP instadvert.bmp
 
@@ -66,3 +77,12 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
 
 /* @makedep: instlocal.bmp */
 0x1003 BITMAP instlocal.bmp
+
+#define WINE_FILEDESCRIPTION_STR "Wine MSI dll"
+#define WINE_FILENAME_STR "msi.dll"
+#define WINE_FILEVERSION 4,5,6001,22159
+#define WINE_FILEVERSION_STR "4.5.6001.22159"
+#define WINE_PRODUCTVERSION 4,5,6001,22159
+#define WINE_PRODUCTVERSION_STR "4.5.6001.22159"
+
+#include "wine/wine_common_ver.rc"
index fd047f8..c1e3553 100644 (file)
@@ -76,7 +76,7 @@
 80 stdcall MsiGetTargetPathW(long wstr ptr ptr)
 81 stdcall MsiGetUserInfoA(str ptr ptr ptr ptr ptr ptr)
 82 stdcall MsiGetUserInfoW(wstr ptr ptr ptr ptr ptr ptr)
-83 stub MsiInstallMissingComponentA
+83 stdcall MsiInstallMissingComponentA(str str long)
 84 stdcall MsiInstallMissingComponentW(wstr wstr long)
 85 stub MsiInstallMissingFileA
 86 stub MsiInstallMissingFileW
index df29184..93f6543 100644 (file)
@@ -28,7 +28,9 @@
 #include "winreg.h"
 #include "shlwapi.h"
 #include "oleauto.h"
+#include "rpcproxy.h"
 #include "msipriv.h"
+#include "msiserver.h"
 
 #include "wine/debug.h"
 
@@ -44,7 +46,7 @@ INSTALLUI_HANDLERW       gUIHandlerW      = NULL;
 INSTALLUI_HANDLER_RECORD gUIHandlerRecord = NULL;
 DWORD                    gUIFilter        = 0;
 LPVOID                   gUIContext       = NULL;
-WCHAR gszLogFile[MAX_PATH];
+WCHAR                   *gszLogFile       = NULL;
 HINSTANCE msi_hInstance;
 
 static WCHAR msi_path[MAX_PATH];
@@ -78,6 +80,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
         if (msi_typelib) ITypeLib_Release( msi_typelib );
         msi_dialog_unregister_class();
         msi_free_handle_table();
+        msi_free( gszLogFile );
         break;
     }
     return TRUE;
@@ -117,14 +120,19 @@ ITypeLib *get_msi_typelib( LPWSTR *path )
 }
 
 typedef struct tagIClassFactoryImpl {
-    const IClassFactoryVtbl *lpVtbl;
+    IClassFactory IClassFactory_iface;
     HRESULT (*create_object)( IUnknown*, LPVOID* );
 } IClassFactoryImpl;
 
+static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
+{
+    return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
+}
+
 static HRESULT WINAPI MsiCF_QueryInterface(LPCLASSFACTORY iface,
                 REFIID riid,LPVOID *ppobj)
 {
-    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+    IClassFactoryImpl *This = impl_from_IClassFactory(iface);
 
     TRACE("%p %s %p\n",This,debugstr_guid(riid),ppobj);
 
@@ -153,7 +161,7 @@ static ULONG WINAPI MsiCF_Release(LPCLASSFACTORY iface)
 static HRESULT WINAPI MsiCF_CreateInstance(LPCLASSFACTORY iface,
     LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj)
 {
-    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+    IClassFactoryImpl *This = impl_from_IClassFactory(iface);
     IUnknown *unk = NULL;
     HRESULT r;
 
@@ -189,9 +197,9 @@ static const IClassFactoryVtbl MsiCF_Vtbl =
     MsiCF_LockServer
 };
 
-static IClassFactoryImpl MsiServer_CF = { &MsiCF_Vtbl, create_msiserver };
-static IClassFactoryImpl WineMsiCustomRemote_CF = { &MsiCF_Vtbl, create_msi_custom_remote };
-static IClassFactoryImpl WineMsiRemotePackage_CF = { &MsiCF_Vtbl, create_msi_remote_package };
+static IClassFactoryImpl MsiServer_CF = { { &MsiCF_Vtbl }, create_msiserver };
+static IClassFactoryImpl WineMsiCustomRemote_CF = { { &MsiCF_Vtbl }, create_msi_custom_remote };
+static IClassFactoryImpl WineMsiRemotePackage_CF = { { &MsiCF_Vtbl }, create_msi_remote_package };
 
 /******************************************************************
  * DllGetClassObject          [MSI.@]
@@ -200,28 +208,28 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
 {
     TRACE("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
 
-    if ( IsEqualCLSID (rclsid, &CLSID_IMsiServerX2) )
+    if ( IsEqualCLSID (rclsid, &CLSID_MsiInstaller) )
     {
         *ppv = &MsiServer_CF;
         return S_OK;
     }
 
-    if ( IsEqualCLSID (rclsid, &CLSID_IWineMsiRemoteCustomAction) )
+    if ( IsEqualCLSID (rclsid, &CLSID_WineMsiRemoteCustomAction) )
     {
         *ppv = &WineMsiCustomRemote_CF;
         return S_OK;
     }
 
-    if ( IsEqualCLSID (rclsid, &CLSID_IWineMsiRemotePackage) )
+    if ( IsEqualCLSID (rclsid, &CLSID_WineMsiRemotePackage) )
     {
         *ppv = &WineMsiRemotePackage_CF;
         return S_OK;
     }
 
-    if( IsEqualCLSID (rclsid, &CLSID_IMsiServerMessage) ||
-        IsEqualCLSID (rclsid, &CLSID_IMsiServer) ||
-        IsEqualCLSID (rclsid, &CLSID_IMsiServerX1) ||
-        IsEqualCLSID (rclsid, &CLSID_IMsiServerX3) )
+    if( IsEqualCLSID (rclsid, &CLSID_MsiServerMessage) ||
+        IsEqualCLSID (rclsid, &CLSID_MsiServer) ||
+        IsEqualCLSID (rclsid, &CLSID_PSFactoryBuffer) ||
+        IsEqualCLSID (rclsid, &CLSID_MsiServerX3) )
     {
         FIXME("create %s object\n", debugstr_guid( rclsid ));
     }
index 0361ff4..56a8a93 100644 (file)
@@ -32,6 +32,7 @@
 #include "msidefs.h"
 #include "objbase.h"
 #include "objidl.h"
+#include "fusion.h"
 #include "winnls.h"
 #include "winver.h"
 #include "wine/list.h"
@@ -162,6 +163,14 @@ typedef struct tagMSIPATCHINFO
     MSIPATCHSTATE state;
 } MSIPATCHINFO;
 
+typedef struct tagMSIBINARY
+{
+    struct list entry;
+    WCHAR *source;
+    WCHAR *tmpfile;
+    HMODULE module;
+} MSIBINARY;
+
 typedef struct _column_info
 {
     LPCWSTR table;
@@ -315,6 +324,13 @@ enum platform
     PLATFORM_X64
 };
 
+enum clr_version
+{
+    CLR_VERSION_V11,
+    CLR_VERSION_V20,
+    CLR_VERSION_MAX
+};
+
 typedef struct tagMSIPACKAGE
 {
     MSIOBJECTHDR hdr;
@@ -329,8 +345,12 @@ typedef struct tagMSIPACKAGE
     struct list files;
     struct list tempfiles;
     struct list folders;
+    struct list binaries;
     LPWSTR ActionFormat;
     LPWSTR LastAction;
+    HANDLE log_file;
+    IAssemblyCache *cache_net[CLR_VERSION_MAX];
+    IAssemblyCache *cache_sxs;
 
     struct list classes;
     struct list extensions;
@@ -401,6 +421,18 @@ typedef struct tagMSIFEATURE
     struct list Components;
 } MSIFEATURE;
 
+typedef struct tagMSIASSEMBLY
+{
+    LPWSTR feature;
+    LPWSTR manifest;
+    LPWSTR application;
+    DWORD attributes;
+    LPWSTR display_name;
+    LPWSTR tempdir;
+    BOOL installed;
+    BOOL clr_version[CLR_VERSION_MAX];
+} MSIASSEMBLY;
+
 typedef struct tagMSICOMPONENT
 {
     struct list entry;
@@ -419,6 +451,7 @@ typedef struct tagMSICOMPONENT
     INT  RefCount;
     LPWSTR FullKeypath;
     LPWSTR AdvertiseString;
+    MSIASSEMBLY *assembly;
 
     unsigned int anyAbsent:1;
     unsigned int hasAdvertiseFeature:1;
@@ -466,6 +499,7 @@ typedef enum _msi_file_state {
     msifs_present,
     msifs_installed,
     msifs_skipped,
+    msifs_hashmatch
 } msi_file_state;
 
 typedef struct tagMSIFILE
@@ -625,14 +659,6 @@ DEFINE_GUID(CLSID_IMsiServerX2, 0x000C1090,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x0
 DEFINE_GUID(CLSID_IMsiServerX3, 0x000C1094,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
 
 DEFINE_GUID(CLSID_IMsiServerMessage, 0x000C101D,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
-
-DEFINE_GUID(CLSID_IWineMsiRemoteCustomAction,0xBA26E6FA,0x4F27,0x4f56,0x95,0x3A,0x3F,0x90,0x27,0x20,0x18,0xAA);
-DEFINE_GUID(CLSID_IWineMsiRemotePackage,0x902b3592,0x9d08,0x4dfd,0xa5,0x93,0xd0,0x7c,0x52,0x54,0x64,0x21);
-
-DEFINE_GUID(CLSID_MsiTransform, 0x000c1082,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
-DEFINE_GUID(CLSID_MsiDatabase,  0x000c1084,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
-DEFINE_GUID(CLSID_MsiPatch,     0x000c1086,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
-
 /* handle unicode/ascii output in the Msi* API functions */
 typedef struct {
     BOOL unicode;
@@ -688,6 +714,8 @@ extern const WCHAR *msi_string_lookup_id( const string_table *st, UINT id );
 extern HRESULT msi_init_string_table( IStorage *stg );
 extern string_table *msi_load_string_table( IStorage *stg, UINT *bytes_per_strref );
 extern UINT msi_save_string_table( const string_table *st, IStorage *storage, UINT *bytes_per_strref );
+extern UINT msi_get_string_table_codepage( const string_table *st );
+extern UINT msi_set_string_table_codepage( string_table *st, UINT codepage );
 
 extern BOOL TABLE_Exists( MSIDATABASE *db, LPCWSTR name );
 extern MSICONDITION MSI_DatabaseIsTablePersistent( MSIDATABASE *db, LPCWSTR table );
@@ -823,6 +851,7 @@ extern UINT MSIREG_DeleteUserDataProductKey(LPCWSTR szProduct);
 extern UINT MSIREG_DeleteUserFeaturesKey(LPCWSTR szProduct);
 extern UINT MSIREG_DeleteUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid);
 extern UINT MSIREG_DeleteUserUpgradeCodesKey(LPCWSTR szUpgradeCode);
+extern UINT MSIREG_DeleteClassesUpgradeCodesKey(LPCWSTR szUpgradeCode);
 extern UINT MSIREG_OpenClassesUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create);
 extern UINT MSIREG_DeleteLocalClassesProductKey(LPCWSTR szProductCode);
 extern UINT MSIREG_DeleteLocalClassesFeaturesKey(LPCWSTR szProductCode);
@@ -834,7 +863,9 @@ extern DWORD msi_version_str_to_dword(LPCWSTR p);
 extern void msi_parse_version_string(LPCWSTR, PDWORD, PDWORD);
 extern VS_FIXEDFILEINFO *msi_get_disk_file_version(LPCWSTR);
 extern int msi_compare_file_versions(VS_FIXEDFILEINFO *, const WCHAR *);
-
+extern int msi_compare_font_versions(const WCHAR *, const WCHAR *);
+extern DWORD msi_get_disk_file_size(LPCWSTR);
+extern BOOL msi_file_hash_matches(MSIFILE *);
 
 extern LONG msi_reg_set_val_str( HKEY hkey, LPCWSTR name, LPCWSTR value );
 extern LONG msi_reg_set_val_multi_str( HKEY hkey, LPCWSTR name, LPCWSTR value );
@@ -879,7 +910,7 @@ extern INSTALLUI_HANDLERW gUIHandlerW;
 extern INSTALLUI_HANDLER_RECORD gUIHandlerRecord;
 extern DWORD gUIFilter;
 extern LPVOID gUIContext;
-extern WCHAR gszLogFile[MAX_PATH];
+extern WCHAR *gszLogFile;
 extern HINSTANCE msi_hInstance;
 
 /* action related functions */
@@ -888,102 +919,6 @@ extern UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UIN
 extern void ACTION_FinishCustomActions( const MSIPACKAGE* package);
 extern UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action, UINT script, BOOL execute);
 
-static inline void msi_feature_set_state(MSIPACKAGE *package,
-                                         MSIFEATURE *feature,
-                                         INSTALLSTATE state)
-{
-    if (!package->ProductCode)
-    {
-        feature->ActionRequest = state;
-        feature->Action = state;
-    }
-    else if (state == INSTALLSTATE_ABSENT)
-    {
-        switch (feature->Installed)
-        {
-            case INSTALLSTATE_ABSENT:
-                feature->ActionRequest = INSTALLSTATE_UNKNOWN;
-                feature->Action = INSTALLSTATE_UNKNOWN;
-                break;
-            default:
-                feature->ActionRequest = state;
-                feature->Action = state;
-        }
-    }
-    else if (state == INSTALLSTATE_SOURCE)
-    {
-        switch (feature->Installed)
-        {
-            case INSTALLSTATE_ABSENT:
-            case INSTALLSTATE_SOURCE:
-                feature->ActionRequest = state;
-                feature->Action = state;
-                break;
-            case INSTALLSTATE_LOCAL:
-                feature->ActionRequest = INSTALLSTATE_LOCAL;
-                feature->Action = INSTALLSTATE_LOCAL;
-                break;
-            default:
-                feature->ActionRequest = INSTALLSTATE_UNKNOWN;
-                feature->Action = INSTALLSTATE_UNKNOWN;
-        }
-    }
-    else
-    {
-        feature->ActionRequest = state;
-        feature->Action = state;
-    }
-    if (feature->Attributes & msidbFeatureAttributesUIDisallowAbsent)
-    {
-        feature->Action = INSTALLSTATE_UNKNOWN;
-    }
-}
-
-static inline void msi_component_set_state(MSIPACKAGE *package,
-                                           MSICOMPONENT *comp,
-                                           INSTALLSTATE state)
-{
-    if (!package->ProductCode)
-    {
-        comp->ActionRequest = state;
-        comp->Action = state;
-    }
-    else if (state == INSTALLSTATE_ABSENT)
-    {
-        switch (comp->Installed)
-        {
-            case INSTALLSTATE_LOCAL:
-            case INSTALLSTATE_SOURCE:
-            case INSTALLSTATE_DEFAULT:
-                comp->ActionRequest = state;
-                comp->Action = state;
-                break;
-            default:
-                comp->ActionRequest = INSTALLSTATE_UNKNOWN;
-                comp->Action = INSTALLSTATE_UNKNOWN;
-        }
-    }
-    else if (state == INSTALLSTATE_SOURCE)
-    {
-        if (comp->Installed == INSTALLSTATE_ABSENT ||
-            (comp->Installed == INSTALLSTATE_SOURCE && comp->hasLocalFeature))
-        {
-            comp->ActionRequest = state;
-            comp->Action = state;
-        }
-        else
-        {
-            comp->ActionRequest = INSTALLSTATE_UNKNOWN;
-            comp->Action = INSTALLSTATE_UNKNOWN;
-        }
-    }
-    else
-    {
-        comp->ActionRequest = state;
-        comp->Action = state;
-    }
-}
-
 /* actions in other modules */
 extern UINT ACTION_AppSearch(MSIPACKAGE *package);
 extern UINT ACTION_CCPSearch(MSIPACKAGE *package);
@@ -1003,6 +938,8 @@ extern UINT ACTION_UnregisterExtensionInfo(MSIPACKAGE *package);
 extern UINT ACTION_UnregisterFonts(MSIPACKAGE *package);
 extern UINT ACTION_UnregisterMIMEInfo(MSIPACKAGE *package);
 extern UINT ACTION_UnregisterProgIdInfo(MSIPACKAGE *package);
+extern UINT ACTION_MsiPublishAssemblies(MSIPACKAGE *package);
+extern UINT ACTION_MsiUnpublishAssemblies(MSIPACKAGE *package);
 
 /* Helpers */
 extern DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data );
@@ -1011,8 +948,8 @@ extern LPWSTR msi_dup_property( MSIDATABASE *db, LPCWSTR prop );
 extern UINT msi_set_property( MSIDATABASE *, LPCWSTR, LPCWSTR );
 extern UINT msi_get_property( MSIDATABASE *, LPCWSTR, LPWSTR, LPDWORD );
 extern int msi_get_property_int( MSIDATABASE *package, LPCWSTR prop, int def );
-extern LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
-                      BOOL set_prop, BOOL load_prop, MSIFOLDER **folder);
+extern LPWSTR resolve_source_folder(MSIPACKAGE *package, LPCWSTR name, MSIFOLDER **folder);
+extern LPWSTR resolve_target_folder(MSIPACKAGE *package, LPCWSTR name, BOOL set_prop, BOOL load_prop, MSIFOLDER **folder);
 extern LPWSTR resolve_file_source(MSIPACKAGE *package, MSIFILE *file);
 extern void msi_reset_folders( MSIPACKAGE *package, BOOL source );
 extern MSICOMPONENT *get_loaded_component( MSIPACKAGE* package, LPCWSTR Component );
@@ -1027,7 +964,7 @@ extern LPWSTR build_directory_name(DWORD , ...);
 extern BOOL create_full_pathW(const WCHAR *path);
 extern void reduce_to_longfilename(WCHAR*);
 extern LPWSTR create_component_advertise_string(MSIPACKAGE*, MSICOMPONENT*, LPCWSTR);
-extern void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature);
+extern void ACTION_UpdateComponentStates(MSIPACKAGE *package, MSIFEATURE *feature);
 extern UINT register_unique_action(MSIPACKAGE *, LPCWSTR);
 extern BOOL check_unique_action(const MSIPACKAGE *, LPCWSTR);
 extern WCHAR* generate_error_string(MSIPACKAGE *, UINT, DWORD, ... );
@@ -1035,6 +972,10 @@ extern UINT msi_set_last_used_source(LPCWSTR product, LPCWSTR usersid,
                         MSIINSTALLCONTEXT context, DWORD options, LPCWSTR value);
 extern UINT msi_get_local_package_name(LPWSTR path, LPCWSTR suffix);
 extern UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace);
+extern MSIASSEMBLY *load_assembly(MSIPACKAGE *, MSICOMPONENT *);
+extern UINT install_assembly(MSIPACKAGE *, MSICOMPONENT *);
+extern WCHAR *font_version_from_file(const WCHAR *);
+extern WCHAR **msi_split_string(const WCHAR *, WCHAR);
 
 /* media */
 
@@ -1053,6 +994,7 @@ typedef struct
 } MSICABDATA;
 
 extern UINT ready_media(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO *mi);
+extern UINT msi_load_media_info(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO *mi);
 extern void msi_free_media_info(MSIMEDIAINFO *mi);
 extern BOOL msi_cabextract(MSIPACKAGE* package, MSIMEDIAINFO *mi, LPVOID data);
 
@@ -1149,8 +1091,12 @@ static const WCHAR szAdminUser[] = {'A','d','m','i','n','U','s','e','r',0};
 static const WCHAR szIntel[] = {'I','n','t','e','l',0};
 static const WCHAR szIntel64[] = {'I','n','t','e','l','6','4',0};
 static const WCHAR szX64[] = {'x','6','4',0};
+static const WCHAR szAMD64[] = {'A','M','D','6','4',0};
 static const WCHAR szWow6432NodeCLSID[] = {'W','o','w','6','4','3','2','N','o','d','e','\\','C','L','S','I','D',0};
 static const WCHAR szWow6432Node[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
+static const WCHAR szStreams[] = {'_','S','t','r','e','a','m','s',0};
+static const WCHAR szStorages[] = {'_','S','t','o','r','a','g','e','s',0};
+static const WCHAR szMsiPublishAssemblies[] = {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
 
 /* memory allocation macro functions */
 static void *msi_alloc( size_t len ) __WINE_ALLOC_SIZE(1);
index cf69593..4ccf5f6 100644 (file)
@@ -75,9 +75,9 @@ UINT VIEW_find_column( MSIVIEW *table, LPCWSTR name, LPCWSTR table_name, UINT *n
                                          NULL, &haystack_table_name );
         if( r != ERROR_SUCCESS )
             return r;
-        x = lstrcmpW( name, col_name );
+        x = strcmpW( name, col_name );
         if( table_name )
-            x |= lstrcmpW( table_name, haystack_table_name );
+            x |= strcmpW( table_name, haystack_table_name );
         msi_free( col_name );
         msi_free( haystack_table_name );
         if( !x )
index e74c22c..58c5b3c 100644 (file)
@@ -86,6 +86,99 @@ interface IWineMsiRemoteCustomAction : IUnknown
                            [out] BSTR *function, [out] IWineMsiRemotePackage **package );
 }
 
+[
+    uuid(000c101c-0000-0000-c000-000000000046),
+    oleautomation,
+    object
+]
+interface IMsiServer : IUnknown
+{
+    /* FIXME: methods */
+}
+
+[
+    uuid(000c101d-0000-0000-c000-000000000046),
+    oleautomation,
+    object
+]
+interface IMsiMessage : IUnknown
+{
+    /* FIXME: methods */
+}
+
+[
+    uuid(000c1025-0000-0000-c000-000000000046),
+    oleautomation,
+    object
+]
+interface IMsiCustomAction : IUnknown
+{
+    /* FIXME: methods */
+}
+
+[
+    uuid(000c1033-0000-0000-c000-000000000046),
+    oleautomation,
+    object
+]
+interface IMsiRemoteAPI : IUnknown
+{
+    /* FIXME: methods */
+}
+
+[
+    helpstring("Msi install server"),
+    progid("IMsiServer"),
+    uuid(000c101c-0000-0000-c000-000000000046)
+]
+coclass MsiServer { interface IMsiServer; }
+
+[
+    helpstring("Microsoft Windows Installer Message RPC"),
+    progid("WindowsInstaller.Message"),
+    uuid(000c101d-0000-0000-c000-000000000046)
+]
+coclass MsiServerMessage { interface IMsiMessage; }
+
+[
+    threading(both),
+    uuid(000c103e-0000-0000-c000-000000000046)
+]
+coclass PSFactoryBuffer { interface IPSFactoryBuffer; }
+
+[
+    uuid(000c1082-0000-0000-c000-000000000046)
+]
+coclass MsiTransform { }
+
+[
+    uuid(000c1084-0000-0000-c000-000000000046)
+]
+coclass MsiDatabase { }
+
+[
+    uuid(000c1086-0000-0000-c000-000000000046)
+]
+coclass MsiPatch { }
+
+[
+    threading(apartment),
+    uuid(000c1094-0000-0000-c000-000000000046)
+]
+/* FIXME: unidentified class */
+coclass MsiServerX3 { interface IMsiServer; }
+
+[
+    uuid(ba26e6fa-4f27-4f56-953a-3f90272018aa)
+]
+coclass WineMsiRemoteCustomAction { interface WineMsiRemoteCustomAction; }
+
+[
+    uuid(902b3592-9d08-4dfd-a593-d07c52546421)
+]
+coclass WineMsiRemotePackage { interface WineMsiRemotePackage; }
+
+
 [ uuid(000C1092-0000-0000-C000-000000000046), version(1.0) ]
 library WindowsInstaller
 {
@@ -452,4 +545,12 @@ library WindowsInstaller
         properties:
         methods:
     }
+
+    [
+       helpstring("Microsoft Windows Installer"),
+       threading(apartment),
+       progid("WindowsInstaller.Installer"),
+       uuid(000c1090-0000-0000-c000-000000000046)
+    ]
+    coclass MsiInstaller { interface Installer; }
 }
index 32576a0..c84c28a 100644 (file)
@@ -59,8 +59,7 @@ static void remove_tracked_tempfiles( MSIPACKAGE *package )
 
         list_remove( &temp->entry );
         TRACE("deleting temp file %s\n", debugstr_w( temp->Path ));
-        if (!DeleteFileW( temp->Path ))
-            ERR("failed to delete %s\n", debugstr_w( temp->Path ));
+        DeleteFileW( temp->Path );
         msi_free( temp->Path );
         msi_free( temp );
     }
@@ -111,6 +110,17 @@ static void free_extension( MSIEXTENSION *ext )
     msi_free( ext );
 }
 
+static void free_assembly( MSIASSEMBLY *assembly )
+{
+    msi_free( assembly->feature );
+    msi_free( assembly->manifest );
+    msi_free( assembly->application );
+    msi_free( assembly->display_name );
+    if (assembly->tempdir) RemoveDirectoryW( assembly->tempdir );
+    msi_free( assembly->tempdir );
+    msi_free( assembly );
+}
+
 static void free_package_structures( MSIPACKAGE *package )
 {
     INT i;
@@ -154,6 +164,7 @@ static void free_package_structures( MSIPACKAGE *package )
         msi_free( comp->Condition );
         msi_free( comp->KeyPath );
         msi_free( comp->FullKeypath );
+        if (comp->assembly) free_assembly( comp->assembly );
         msi_free( comp );
     }
 
@@ -275,6 +286,20 @@ static void free_package_structures( MSIPACKAGE *package )
         msi_free( patch );
     }
 
+    LIST_FOR_EACH_SAFE( item, cursor, &package->binaries )
+    {
+        MSIBINARY *binary = LIST_ENTRY( item, MSIBINARY, entry );
+
+        list_remove( &binary->entry );
+        if (binary->module)
+            FreeLibrary( binary->module );
+        if (!DeleteFileW( binary->tmpfile ))
+            ERR("failed to delete %s (%u)\n", debugstr_w(binary->tmpfile), GetLastError());
+        msi_free( binary->source );
+        msi_free( binary->tmpfile );
+        msi_free( binary );
+    }
+
     msi_free( package->BaseURL );
     msi_free( package->PackagePath );
     msi_free( package->ProductCode );
@@ -288,13 +313,19 @@ static void free_package_structures( MSIPACKAGE *package )
 
 static void MSI_FreePackage( MSIOBJECTHDR *arg)
 {
-    MSIPACKAGE *package= (MSIPACKAGE*) arg;
+    UINT i;
+    MSIPACKAGE *package = (MSIPACKAGE *)arg;
 
     if( package->dialog )
         msi_dialog_destroy( package->dialog );
 
     msiobj_release( &package->db->hdr );
     free_package_structures(package);
+    CloseHandle( package->log_file );
+
+    for (i = 0; i < CLR_VERSION_MAX; i++)
+        if (package->cache_net[i]) IAssemblyCache_Release( package->cache_net[i] );
+    if (package->cache_sxs) IAssemblyCache_Release( package->cache_sxs );
 }
 
 static UINT create_temp_property_table(MSIPACKAGE *package)
@@ -511,7 +542,7 @@ static LPWSTR get_fusion_filename(MSIPACKAGE *package)
         index++;
 
         /* verify existence of fusion.dll .Net 3.0 does not install a new one */
-        if (lstrcmpW(ver, name) < 0)
+        if (strcmpW( ver, name ) < 0)
         {
             LPWSTR check;
             size = lstrlenW(windir) + lstrlenW(subdir) + lstrlenW(name) +lstrlenW(fusion) + 3;
@@ -1046,6 +1077,7 @@ static MSIPACKAGE *msi_alloc_package( void )
         list_init( &package->sourcelist_info );
         list_init( &package->sourcelist_media );
         list_init( &package->patches );
+        list_init( &package->binaries );
     }
 
     return package;
@@ -1121,6 +1153,8 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPCWSTR base_url )
 
         if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
             msi_load_admin_properties( package );
+
+        package->log_file = INVALID_HANDLE_VALUE;
     }
 
     return package;
@@ -1313,7 +1347,7 @@ static UINT msi_parse_summary( MSISUMMARYINFO *si, MSIPACKAGE *package )
         package->platform = PLATFORM_INTEL;
     else if (!strcmpW( template, szIntel64 ))
         package->platform = PLATFORM_INTEL64;
-    else if (!strcmpW( template, szX64 ))
+    else if (!strcmpW( template, szX64 ) || !strcmpW( template, szAMD64 ))
         package->platform = PLATFORM_X64;
     else
     {
@@ -1321,9 +1355,14 @@ static UINT msi_parse_summary( MSISUMMARYINFO *si, MSIPACKAGE *package )
         msi_free( template );
         return ERROR_INSTALL_PLATFORM_UNSUPPORTED;
     }
-
+    p++;
+    if (!*p)
+    {
+        msi_free( template );
+        return ERROR_SUCCESS;
+    }
     count = 1;
-    for (q = ++p; (q = strchrW( q, ',' )); q++) count++;
+    for (q = p; (q = strchrW( q, ',' )); q++) count++;
 
     package->langids = msi_alloc( count * sizeof(LANGID) );
     if (!package->langids)
@@ -1367,7 +1406,17 @@ static UINT validate_package( MSIPACKAGE *package )
     }
     for (i = 0; i < package->num_langids; i++)
     {
-        if (!package->langids[i] || IsValidLocale( package->langids[i], LCID_INSTALLED ))
+        LANGID langid = package->langids[i];
+
+        if (PRIMARYLANGID( langid ) == LANG_NEUTRAL)
+        {
+            langid = MAKELANGID( PRIMARYLANGID( GetSystemDefaultLangID() ), SUBLANGID( langid ) );
+        }
+        if (SUBLANGID( langid ) == SUBLANG_NEUTRAL)
+        {
+            langid = MAKELANGID( PRIMARYLANGID( langid ), SUBLANGID( GetSystemDefaultLangID() ) );
+        }
+        if (IsValidLocale( langid, LCID_INSTALLED ))
             return ERROR_SUCCESS;
     }
     return ERROR_INSTALL_LANGUAGE_UNSUPPORTED;
@@ -1551,6 +1600,10 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
         msi_adjust_privilege_properties( package );
     }
 
+    if (gszLogFile)
+        package->log_file = CreateFileW( gszLogFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
+                                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
+
     *pPackage = package;
     return ERROR_SUCCESS;
 }
@@ -1657,17 +1710,13 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
         {'S','e','t','P','r','o','g','r','e','s','s',0};
     static const WCHAR szActionText[] =
         {'A','c','t','i','o','n','T','e','x','t',0};
-    DWORD log_type = 0;
     LPWSTR message;
-    DWORD sz;
-    DWORD total_size = 0;
-    INT i;
-    INT rc;
+    DWORD sz, total_size = 0, log_type = 0;
+    INT i, rc = 0;
     char *msg;
     int len;
 
     TRACE("%x\n", eMessageType);
-    rc = 0;
 
     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR)
         log_type |= INSTALLLOGMODE_ERROR;
@@ -1773,20 +1822,12 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
         MsiCloseHandle( rec );
     }
 
-    if ((!rc) && (gszLogFile[0]) && !((eMessageType & 0xff000000) ==
-                                      INSTALLMESSAGE_PROGRESS))
+    if (!rc && package->log_file != INVALID_HANDLE_VALUE &&
+        (eMessageType & 0xff000000) != INSTALLMESSAGE_PROGRESS)
     {
-        DWORD write;
-        HANDLE log_file = CreateFileW(gszLogFile,GENERIC_WRITE, 0, NULL,
-                                  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-
-        if (log_file != INVALID_HANDLE_VALUE)
-        {
-            SetFilePointer(log_file,0, NULL, FILE_END);
-            WriteFile(log_file,msg,strlen(msg),&write,NULL);
-            WriteFile(log_file,"\n",1,&write,NULL);
-            CloseHandle(log_file);
-        }
+        DWORD written;
+        WriteFile( package->log_file, msg, len - 1, &written, NULL );
+        WriteFile( package->log_file, "\n", 1, &written, NULL );
     }
     msi_free( msg );
     msi_free( message );
@@ -2248,14 +2289,14 @@ UINT WINAPI MsiGetPropertyW( MSIHANDLE hInstall, LPCWSTR szName,
 }
 
 typedef struct _msi_remote_package_impl {
-    const IWineMsiRemotePackageVtbl *lpVtbl;
+    IWineMsiRemotePackage IWineMsiRemotePackage_iface;
     MSIHANDLE package;
     LONG refs;
 } msi_remote_package_impl;
 
-static inline msi_remote_package_impl* mrp_from_IWineMsiRemotePackage( IWineMsiRemotePackage* iface )
+static inline msi_remote_package_impl *impl_from_IWineMsiRemotePackage( IWineMsiRemotePackage *iface )
 {
-    return (msi_remote_package_impl*) iface;
+    return CONTAINING_RECORD(iface, msi_remote_package_impl, IWineMsiRemotePackage_iface);
 }
 
 static HRESULT WINAPI mrp_QueryInterface( IWineMsiRemotePackage *iface,
@@ -2274,14 +2315,14 @@ static HRESULT WINAPI mrp_QueryInterface( IWineMsiRemotePackage *iface,
 
 static ULONG WINAPI mrp_AddRef( IWineMsiRemotePackage *iface )
 {
-    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
 
     return InterlockedIncrement( &This->refs );
 }
 
 static ULONG WINAPI mrp_Release( IWineMsiRemotePackage *iface )
 {
-    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
     ULONG r;
 
     r = InterlockedDecrement( &This->refs );
@@ -2295,14 +2336,14 @@ static ULONG WINAPI mrp_Release( IWineMsiRemotePackage *iface )
 
 static HRESULT WINAPI mrp_SetMsiHandle( IWineMsiRemotePackage *iface, MSIHANDLE handle )
 {
-    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
     This->package = handle;
     return S_OK;
 }
 
 static HRESULT WINAPI mrp_GetActiveDatabase( IWineMsiRemotePackage *iface, MSIHANDLE *handle )
 {
-    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
     IWineMsiRemoteDatabase *rdb = NULL;
     HRESULT hr;
     MSIHANDLE hdb;
@@ -2329,7 +2370,7 @@ static HRESULT WINAPI mrp_GetActiveDatabase( IWineMsiRemotePackage *iface, MSIHA
 
 static HRESULT WINAPI mrp_GetProperty( IWineMsiRemotePackage *iface, BSTR property, BSTR *value, DWORD *size )
 {
-    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
     UINT r;
 
     r = MsiGetPropertyW(This->package, (LPWSTR)property, (LPWSTR)value, size);
@@ -2341,63 +2382,63 @@ static HRESULT WINAPI mrp_GetProperty( IWineMsiRemotePackage *iface, BSTR proper
 
 static HRESULT WINAPI mrp_SetProperty( IWineMsiRemotePackage *iface, BSTR property, BSTR value )
 {
-    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
     UINT r = MsiSetPropertyW(This->package, property, value);
     return HRESULT_FROM_WIN32(r);
 }
 
 static HRESULT WINAPI mrp_ProcessMessage( IWineMsiRemotePackage *iface, INSTALLMESSAGE message, MSIHANDLE record )
 {
-    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
     UINT r = MsiProcessMessage(This->package, message, record);
     return HRESULT_FROM_WIN32(r);
 }
 
 static HRESULT WINAPI mrp_DoAction( IWineMsiRemotePackage *iface, BSTR action )
 {
-    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
     UINT r = MsiDoActionW(This->package, action);
     return HRESULT_FROM_WIN32(r);
 }
 
 static HRESULT WINAPI mrp_Sequence( IWineMsiRemotePackage *iface, BSTR table, int sequence )
 {
-    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
     UINT r = MsiSequenceW(This->package, table, sequence);
     return HRESULT_FROM_WIN32(r);
 }
 
 static HRESULT WINAPI mrp_GetTargetPath( IWineMsiRemotePackage *iface, BSTR folder, BSTR *value, DWORD *size )
 {
-    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
     UINT r = MsiGetTargetPathW(This->package, (LPWSTR)folder, (LPWSTR)value, size);
     return HRESULT_FROM_WIN32(r);
 }
 
 static HRESULT WINAPI mrp_SetTargetPath( IWineMsiRemotePackage *iface, BSTR folder, BSTR value)
 {
-    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
     UINT r = MsiSetTargetPathW(This->package, folder, value);
     return HRESULT_FROM_WIN32(r);
 }
 
 static HRESULT WINAPI mrp_GetSourcePath( IWineMsiRemotePackage *iface, BSTR folder, BSTR *value, DWORD *size )
 {
-    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
     UINT r = MsiGetSourcePathW(This->package, (LPWSTR)folder, (LPWSTR)value, size);
     return HRESULT_FROM_WIN32(r);
 }
 
 static HRESULT WINAPI mrp_GetMode( IWineMsiRemotePackage *iface, MSIRUNMODE mode, BOOL *ret )
 {
-    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
     *ret = MsiGetMode(This->package, mode);
     return S_OK;
 }
 
 static HRESULT WINAPI mrp_SetMode( IWineMsiRemotePackage *iface, MSIRUNMODE mode, BOOL state )
 {
-    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
     UINT r = MsiSetMode(This->package, mode, state);
     return HRESULT_FROM_WIN32(r);
 }
@@ -2405,14 +2446,14 @@ static HRESULT WINAPI mrp_SetMode( IWineMsiRemotePackage *iface, MSIRUNMODE mode
 static HRESULT WINAPI mrp_GetFeatureState( IWineMsiRemotePackage *iface, BSTR feature,
                                     INSTALLSTATE *installed, INSTALLSTATE *action )
 {
-    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
     UINT r = MsiGetFeatureStateW(This->package, feature, installed, action);
     return HRESULT_FROM_WIN32(r);
 }
 
 static HRESULT WINAPI mrp_SetFeatureState( IWineMsiRemotePackage *iface, BSTR feature, INSTALLSTATE state )
 {
-    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
     UINT r = MsiSetFeatureStateW(This->package, feature, state);
     return HRESULT_FROM_WIN32(r);
 }
@@ -2420,28 +2461,28 @@ static HRESULT WINAPI mrp_SetFeatureState( IWineMsiRemotePackage *iface, BSTR fe
 static HRESULT WINAPI mrp_GetComponentState( IWineMsiRemotePackage *iface, BSTR component,
                                       INSTALLSTATE *installed, INSTALLSTATE *action )
 {
-    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
     UINT r = MsiGetComponentStateW(This->package, component, installed, action);
     return HRESULT_FROM_WIN32(r);
 }
 
 static HRESULT WINAPI mrp_SetComponentState( IWineMsiRemotePackage *iface, BSTR component, INSTALLSTATE state )
 {
-    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
     UINT r = MsiSetComponentStateW(This->package, component, state);
     return HRESULT_FROM_WIN32(r);
 }
 
 static HRESULT WINAPI mrp_GetLanguage( IWineMsiRemotePackage *iface, LANGID *language )
 {
-    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
     *language = MsiGetLanguage(This->package);
     return S_OK;
 }
 
 static HRESULT WINAPI mrp_SetInstallLevel( IWineMsiRemotePackage *iface, int level )
 {
-    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
     UINT r = MsiSetInstallLevel(This->package, level);
     return HRESULT_FROM_WIN32(r);
 }
@@ -2450,7 +2491,7 @@ static HRESULT WINAPI mrp_FormatRecord( IWineMsiRemotePackage *iface, MSIHANDLE
                                         BSTR *value)
 {
     DWORD size = 0;
-    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
     UINT r = MsiFormatRecordW(This->package, record, NULL, &size);
     if (r == ERROR_SUCCESS)
     {
@@ -2465,7 +2506,7 @@ static HRESULT WINAPI mrp_FormatRecord( IWineMsiRemotePackage *iface, MSIHANDLE
 
 static HRESULT WINAPI mrp_EvaluateCondition( IWineMsiRemotePackage *iface, BSTR condition )
 {
-    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
     UINT r = MsiEvaluateConditionW(This->package, condition);
     return HRESULT_FROM_WIN32(r);
 }
@@ -2473,7 +2514,7 @@ static HRESULT WINAPI mrp_EvaluateCondition( IWineMsiRemotePackage *iface, BSTR
 static HRESULT WINAPI mrp_GetFeatureCost( IWineMsiRemotePackage *iface, BSTR feature,
                                           INT cost_tree, INSTALLSTATE state, INT *cost )
 {
-    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
     UINT r = MsiGetFeatureCostW(This->package, feature, cost_tree, state, cost);
     return HRESULT_FROM_WIN32(r);
 }
@@ -2514,7 +2555,7 @@ HRESULT create_msi_remote_package( IUnknown *pOuter, LPVOID *ppObj )
     if (!This)
         return E_OUTOFMEMORY;
 
-    This->lpVtbl = &msi_remote_package_vtbl;
+    This->IWineMsiRemotePackage_iface.lpVtbl = &msi_remote_package_vtbl;
     This->package = 0;
     This->refs = 1;
 
@@ -2528,6 +2569,11 @@ UINT msi_package_add_info(MSIPACKAGE *package, DWORD context, DWORD options,
 {
     MSISOURCELISTINFO *info;
 
+    LIST_FOR_EACH_ENTRY( info, &package->sourcelist_info, MSISOURCELISTINFO, entry )
+    {
+        if (!strcmpW( info->value, value )) return ERROR_SUCCESS;
+    }
+
     info = msi_alloc(sizeof(MSISOURCELISTINFO));
     if (!info)
         return ERROR_OUTOFMEMORY;
@@ -2546,6 +2592,11 @@ UINT msi_package_add_media_disk(MSIPACKAGE *package, DWORD context, DWORD option
 {
     MSIMEDIADISK *disk;
 
+    LIST_FOR_EACH_ENTRY( disk, &package->sourcelist_media, MSIMEDIADISK, entry )
+    {
+        if (disk->disk_id == disk_id) return ERROR_SUCCESS;
+    }
+
     disk = msi_alloc(sizeof(MSIMEDIADISK));
     if (!disk)
         return ERROR_OUTOFMEMORY;
index 7bc8281..fc30f79 100644 (file)
@@ -27,6 +27,7 @@
 #include "winuser.h"
 #include "winerror.h"
 #include "wine/debug.h"
+#include "wine/unicode.h"
 #include "msi.h"
 #include "msiquery.h"
 #include "msipriv.h"
@@ -1016,7 +1017,7 @@ BOOL MSI_RecordsAreEqual(MSIRECORD *a, MSIRECORD *b)
                 break;
 
             case MSIFIELD_WSTR:
-                if (lstrcmpW(a->fields[i].u.szwVal, b->fields[i].u.szwVal))
+                if (strcmpW(a->fields[i].u.szwVal, b->fields[i].u.szwVal))
                     return FALSE;
                 break;
 
index e83490f..017aa24 100644 (file)
@@ -1182,6 +1182,21 @@ UINT MSIREG_OpenClassesUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL cr
     return RegOpenKeyW(HKEY_CLASSES_ROOT, keypath, key);
 }
 
+UINT MSIREG_DeleteClassesUpgradeCodesKey(LPCWSTR szUpgradeCode)
+{
+    WCHAR squished_pc[GUID_SIZE];
+    WCHAR keypath[0x200];
+
+    TRACE("%s\n", debugstr_w(szUpgradeCode));
+    if (!squash_guid(szUpgradeCode, squished_pc))
+        return ERROR_FUNCTION_FAILED;
+    TRACE("squished (%s)\n", debugstr_w(squished_pc));
+
+    sprintfW(keypath, szInstaller_ClassesUpgrade_fmt, squished_pc);
+
+    return RegDeleteTreeW(HKEY_CLASSES_ROOT, keypath);
+}
+
 /*************************************************************************
  *  MsiDecomposeDescriptorW   [MSI.@]
  *
@@ -1549,10 +1564,11 @@ UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct)
     sz = SQUISH_GUID_SIZE;
     r = RegEnumValueW(hkeyComp, index, szValName, &sz, NULL, NULL, NULL, NULL);
     if( r == ERROR_SUCCESS )
+    {
         unsquash_guid(szValName, szProduct);
-
+        TRACE("-> %s\n", debugstr_w(szProduct));
+    }
     RegCloseKey(hkeyComp);
-
     return r;
 }
 
@@ -2140,7 +2156,7 @@ UINT WINAPI MsiEnumPatchesExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
     if (!szProductCode || !squash_guid(szProductCode, squished_pc))
         return ERROR_INVALID_PARAMETER;
 
-    if (!lstrcmpW(szUserSid, szLocalSid))
+    if (szUserSid && !strcmpW( szUserSid, szLocalSid ))
         return ERROR_INVALID_PARAMETER;
 
     if (dwContext & MSIINSTALLCONTEXT_MACHINE && szUserSid)
index 4f223da..27bbee1 100644 (file)
@@ -143,6 +143,7 @@ DWORD call_script(MSIHANDLE hPackage, INT type, LPCWSTR script, LPCWSTR function
 
     /* Add the session object */
     hr = IActiveScript_AddNamedItem(pActiveScript, szSession, SCRIPTITEM_ISVISIBLE);
+    if (FAILED(hr)) goto done;
 
     /* Pass the script to the engine */
     hr = IActiveScriptParse64_ParseScriptText(pActiveScriptParse, script, NULL, NULL, NULL, 0, 0, 0L, NULL, NULL);
index 8e4323a..881f3d2 100644 (file)
@@ -330,7 +330,6 @@ UINT WINAPI MsiSourceListEnumMediaDisksW(LPCWSTR szProductCodeOrPatchCode,
         else
             size = lstrlenW(ptr);
 
-        size = lstrlenW(ptr);
         if (size >= *pcchDiskPrompt)
             r = ERROR_MORE_DATA;
         else if (szDiskPrompt)
@@ -592,8 +591,8 @@ UINT WINAPI MsiSourceListGetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
     if (rc != ERROR_SUCCESS)
         return rc;
 
-    if (!lstrcmpW(szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW) ||
-        !lstrcmpW(szProperty, INSTALLPROPERTY_DISKPROMPTW))
+    if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ) ||
+        !strcmpW( szProperty, INSTALLPROPERTY_DISKPROMPTW ))
     {
         rc = OpenMediaSubkey(sourcekey, &media, FALSE);
         if (rc != ERROR_SUCCESS)
@@ -602,14 +601,14 @@ UINT WINAPI MsiSourceListGetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
             return ERROR_SUCCESS;
         }
 
-        if (!lstrcmpW(szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW))
+        if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ))
             szProperty = mediapack;
 
         RegQueryValueExW(media, szProperty, 0, 0, (LPBYTE)szValue, pcchValue);
         RegCloseKey(media);
     }
-    else if (!lstrcmpW(szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW) ||
-             !lstrcmpW(szProperty, INSTALLPROPERTY_LASTUSEDTYPEW))
+    else if (!strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ) ||
+             !strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDTYPEW ))
     {
         rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
                               0, 0, NULL, &size);
@@ -630,7 +629,7 @@ UINT WINAPI MsiSourceListGetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
             return ERROR_SUCCESS;
         }
 
-        if (!lstrcmpW(szProperty, INSTALLPROPERTY_LASTUSEDTYPEW))
+        if (!strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDTYPEW ))
         {
             if (*source != 'n' && *source != 'u' && *source != 'm')
             {
@@ -662,7 +661,7 @@ UINT WINAPI MsiSourceListGetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
         *pcchValue = lstrlenW(ptr);
         msi_free(source);
     }
-    else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW, szProperty)==0)
+    else if (!strcmpW( szProperty, INSTALLPROPERTY_PACKAGENAMEW ))
     {
         *pcchValue = *pcchValue * sizeof(WCHAR);
         rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0, 0,
@@ -815,22 +814,22 @@ UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
     }
 
     property = szProperty;
-    if (!lstrcmpW(szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW))
+    if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ))
         property = media_package;
 
     rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
     if (rc != ERROR_SUCCESS)
         return rc;
 
-    if (lstrcmpW(szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW) &&
+    if (strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ) &&
         dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL))
     {
         RegCloseKey(sourcekey);
         return ERROR_INVALID_PARAMETER;
     }
 
-    if (!lstrcmpW(szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW) ||
-        !lstrcmpW(szProperty, INSTALLPROPERTY_DISKPROMPTW))
+    if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ) ||
+        !strcmpW( szProperty, INSTALLPROPERTY_DISKPROMPTW ))
     {
         rc = OpenMediaSubkey(sourcekey, &media, TRUE);
         if (rc == ERROR_SUCCESS)
@@ -839,7 +838,7 @@ UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
             RegCloseKey(media);
         }
     }
-    else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW, szProperty)==0)
+    else if (!strcmpW( szProperty, INSTALLPROPERTY_PACKAGENAMEW ))
     {
         DWORD size = (lstrlenW(szValue) + 1) * sizeof(WCHAR);
         rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0,
@@ -847,7 +846,7 @@ UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
         if (rc != ERROR_SUCCESS)
             rc = ERROR_UNKNOWN_PROPERTY;
     }
-    else if (!lstrcmpW(szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW))
+    else if (!strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ))
     {
         if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
             rc = ERROR_INVALID_PARAMETER;
@@ -1130,6 +1129,12 @@ UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid,
         RegCloseKey(sourcekey);
         return ERROR_FUNCTION_FAILED;
     }
+    if (rc != ERROR_SUCCESS)
+    {
+        ERR("can't open subkey %u\n", rc);
+        RegCloseKey(sourcekey);
+        return rc;
+    }
 
     postfix = (dwOptions & MSISOURCETYPE_NETWORK) ? szBackSlash : szForwardSlash;
     if (szSource[lstrlenW(szSource) - 1] == *postfix)
index 72e230c..f707602 100644 (file)
@@ -2872,7 +2872,7 @@ static BOOL SQL_MarkPrimaryKeys( column_info **cols,
         found = FALSE;
         for( c = *cols, idx = 0; c && !found; c = c->next, idx++ )
         {
-            if( lstrcmpW( k->column, c->column ) )
+            if( strcmpW( k->column, c->column ) )
                 continue;
             c->type |= MSITYPE_KEY;
             found = TRUE;
index 548a878..0121737 100644 (file)
@@ -950,7 +950,7 @@ static BOOL SQL_MarkPrimaryKeys( column_info **cols,
         found = FALSE;
         for( c = *cols, idx = 0; c && !found; c = c->next, idx++ )
         {
-            if( lstrcmpW( k->column, c->column ) )
+            if( strcmpW( k->column, c->column ) )
                 continue;
             c->type |= MSITYPE_KEY;
             found = TRUE;
index 5644749..4068033 100644 (file)
@@ -58,15 +58,22 @@ struct string_table
     UINT *sorted;       /* index */
 };
 
+static BOOL validate_codepage( UINT codepage )
+{
+    if (codepage != CP_ACP && !IsValidCodePage( codepage ))
+    {
+        WARN("invalid codepage %u\n", codepage);
+        return FALSE;
+    }
+    return TRUE;
+}
+
 static string_table *init_stringtable( int entries, UINT codepage )
 {
     string_table *st;
 
-    if (codepage != CP_ACP && !IsValidCodePage(codepage))
-    {
-        ERR("invalid codepage %d\n", codepage);
+    if (!validate_codepage( codepage ))
         return NULL;
-    }
 
     st = msi_alloc( sizeof (string_table) );
     if( !st )
@@ -162,7 +169,7 @@ static int find_insert_index( const string_table *st, UINT string_id )
     while (low <= high)
     {
         i = (low + high) / 2;
-        c = lstrcmpW( st->strings[string_id].str, st->strings[st->sorted[i]].str );
+        c = strcmpW( st->strings[string_id].str, st->strings[st->sorted[i]].str );
 
         if (c < 0)
             high = i - 1;
@@ -402,7 +409,7 @@ UINT msi_string2idW( const string_table *st, LPCWSTR str, UINT *id )
     while (low <= high)
     {
         i = (low + high) / 2;
-        c = lstrcmpW( str, st->strings[st->sorted[i]].str );
+        c = strcmpW( str, st->strings[st->sorted[i]].str );
 
         if (c < 0)
             high = i - 1;
@@ -671,3 +678,18 @@ err:
 
     return ret;
 }
+
+UINT msi_get_string_table_codepage( const string_table *st )
+{
+    return st->codepage;
+}
+
+UINT msi_set_string_table_codepage( string_table *st, UINT codepage )
+{
+    if (validate_codepage( codepage ))
+    {
+        st->codepage = codepage;
+        return ERROR_SUCCESS;
+    }
+    return ERROR_FUNCTION_FAILED;
+}
index 3e456ed..14f4d30 100644 (file)
@@ -156,7 +156,7 @@ LPWSTR encode_streamname(BOOL bTable, LPCWSTR in)
 
     if( !bTable )
         count = lstrlenW( in )+2;
-    out = msi_alloc( count*sizeof(WCHAR) );
+    if (!(out = msi_alloc( count*sizeof(WCHAR) ))) return NULL;
     p = out;
 
     if( bTable )
@@ -512,7 +512,7 @@ static MSITABLE *find_cached_table( MSIDATABASE *db, LPCWSTR name )
     MSITABLE *t;
 
     LIST_FOR_EACH_ENTRY( t, &db->tables, MSITABLE, entry )
-        if( !lstrcmpW( name, t->name ) )
+        if( !strcmpW( name, t->name ) )
             return t;
 
     return NULL;
@@ -731,7 +731,7 @@ static UINT get_table( MSIDATABASE *db, LPCWSTR name, MSITABLE **table_ret )
     table->persistent = MSICONDITION_TRUE;
     lstrcpyW( table->name, name );
 
-    if ( !lstrcmpW(name, szTables) || !lstrcmpW(name, szColumns) )
+    if ( !strcmpW( name, szTables ) || !strcmpW( name, szColumns ) )
         table->persistent = MSICONDITION_NONE;
 
     r = table_get_column_info( db, name, &table->colinfo, &table->col_count);
@@ -766,7 +766,8 @@ static UINT read_table_int(BYTE *const *data, UINT row, UINT col, UINT bytes)
 static UINT save_table( MSIDATABASE *db, const MSITABLE *t, UINT bytes_per_strref )
 {
     BYTE *rawdata = NULL;
-    UINT rawsize, r, i, j, row_size, row_count;
+    UINT rawsize, i, j, row_size, row_count;
+    UINT r = ERROR_FUNCTION_FAILED;
 
     /* Nothing to do for non-persistent tables */
     if( t->persistent == MSICONDITION_FALSE )
@@ -816,7 +817,6 @@ static UINT save_table( MSIDATABASE *db, const MSITABLE *t, UINT bytes_per_strre
                 if (id > 1 << bytes_per_strref * 8)
                 {
                     ERR("string id %u out of range\n", id);
-                    r = ERROR_FUNCTION_FAILED;
                     goto err;
                 }
             }
@@ -864,12 +864,12 @@ static UINT get_defaulttablecolumns( MSIDATABASE *db, LPCWSTR name,
 
     TRACE("%s\n", debugstr_w(name));
 
-    if (!lstrcmpW( name, szTables ))
+    if (!strcmpW( name, szTables ))
     {
         p = _Tables_cols;
         n = 1;
     }
-    else if (!lstrcmpW( name, szColumns ))
+    else if (!strcmpW( name, szColumns ))
     {
         p = _Columns_cols;
         n = 4;
@@ -1037,11 +1037,8 @@ BOOL TABLE_Exists( MSIDATABASE *db, LPCWSTR name )
     UINT r, table_id, i;
     MSITABLE *table;
 
-    static const WCHAR szStreams[] = {'_','S','t','r','e','a','m','s',0};
-    static const WCHAR szStorages[] = {'_','S','t','o','r','a','g','e','s',0};
-
-    if( !lstrcmpW( name, szTables ) || !lstrcmpW( name, szColumns ) ||
-        !lstrcmpW( name, szStreams ) || !lstrcmpW( name, szStorages ) )
+    if( !strcmpW( name, szTables ) || !strcmpW( name, szColumns ) ||
+        !strcmpW( name, szStreams ) || !strcmpW( name, szStorages ) )
         return TRUE;
 
     r = msi_string2idW( db->strings, name, &table_id );
@@ -1146,6 +1143,8 @@ static UINT msi_stream_name( const MSITABLEVIEW *tv, UINT row, LPWSTR *pstname )
         type = tv->columns[i].type;
         if ( type & MSITYPE_KEY )
         {
+            WCHAR number[0x20];
+
             r = TABLE_fetch_int( view, row, i+1, &ival );
             if ( r != ERROR_SUCCESS )
                 goto err;
@@ -1162,7 +1161,6 @@ static UINT msi_stream_name( const MSITABLEVIEW *tv, UINT row, LPWSTR *pstname )
             else
             {
                 static const WCHAR fmt[] = { '%','d',0 };
-                WCHAR number[0x20];
                 UINT n = bytes_per_column( tv->db, &tv->columns[i], LONG_STR_BYTES );
 
                 switch( n )
@@ -1346,10 +1344,13 @@ static UINT get_table_value_from_record( MSITABLEVIEW *tv, MSIRECORD *rec, UINT
     else if ( columninfo.type & MSITYPE_STRING )
     {
         LPCWSTR sval = MSI_RecordGetString( rec, iField );
-
-        r = msi_string2idW(tv->db->strings, sval, pvalue);
-        if (r != ERROR_SUCCESS)
-           return ERROR_NOT_FOUND;
+        if (sval)
+        {
+            r = msi_string2idW(tv->db->strings, sval, pvalue);
+            if (r != ERROR_SUCCESS)
+                return ERROR_NOT_FOUND;
+        }
+        else *pvalue = 0;
     }
     else if ( bytes_per_column( tv->db, &columninfo, LONG_STR_BYTES ) == 2 )
     {
@@ -1432,7 +1433,6 @@ static UINT TABLE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UI
                     LPCWSTR sval = MSI_RecordGetString( rec, i + 1 );
                     val = msi_addstringW( tv->db->strings, sval, -1, 1,
                       persistent ? StringPersistent : StringNonPersistent );
-
                 }
                 else
                 {
@@ -1630,6 +1630,8 @@ static int compare_record( MSITABLEVIEW *tv, UINT row, MSIRECORD *rec )
 
     for (i = 0; i < tv->num_cols; i++ )
     {
+        if (!(tv->columns[i].type & MSITYPE_KEY)) continue;
+
         r = get_table_value_from_record( tv, rec, i + 1, &ivalue );
         if (r != ERROR_SUCCESS)
             return 1;
@@ -1774,6 +1776,9 @@ static UINT msi_table_update(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row)
     if (row != new_row + 1)
         return ERROR_FUNCTION_FAILED;
 
+    if(tv->order)
+        new_row = tv->order->reorder[new_row];
+
     return TABLE_set_row(view, new_row, rec, (1 << tv->num_cols) - 1);
 }
 
@@ -2099,7 +2104,7 @@ static UINT TABLE_add_column(struct tagMSIVIEW *view, LPCWSTR table, UINT number
     msitable = find_cached_table(tv->db, table);
     for (i = 0; i < msitable->col_count; i++)
     {
-        if (!lstrcmpW(msitable->colinfo[i].colname, column))
+        if (!strcmpW( msitable->colinfo[i].colname, column ))
         {
             InterlockedIncrement(&msitable->colinfo[i].ref_count);
             break;
@@ -2340,14 +2345,11 @@ UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view )
     MSITABLEVIEW *tv ;
     UINT r, sz;
 
-    static const WCHAR Streams[] = {'_','S','t','r','e','a','m','s',0};
-    static const WCHAR Storages[] = {'_','S','t','o','r','a','g','e','s',0};
-
     TRACE("%p %s %p\n", db, debugstr_w(name), view );
 
-    if ( !lstrcmpW( name, Streams ) )
+    if ( !strcmpW( name, szStreams ) )
         return STREAMS_CreateView( db, view );
-    else if ( !lstrcmpW( name, Storages ) )
+    else if ( !strcmpW( name, szStorages ) )
         return STORAGES_CreateView( db, view );
 
     sz = sizeof *tv + lstrlenW(name)*sizeof name[0] ;
@@ -2593,7 +2595,7 @@ static void dump_record( MSIRECORD *rec )
     n = MSI_RecordGetFieldCount( rec );
     for( i=1; i<=n; i++ )
     {
-        LPCWSTR sval = MSI_RecordGetString( rec, i );
+        LPCWSTR sval;
 
         if( MSI_RecordIsNull( rec, i ) )
             TRACE("row -> []\n");
@@ -2634,15 +2636,19 @@ static UINT* msi_record_to_row( const MSITABLEVIEW *tv, MSIRECORD *rec )
              ! MSITYPE_IS_BINARY(tv->columns[i].type) )
         {
             str = MSI_RecordGetString( rec, i+1 );
-            r = msi_string2idW( tv->db->strings, str, &data[i] );
-
-            /* if there's no matching string in the string table,
-               these keys can't match any record, so fail now. */
-            if( ERROR_SUCCESS != r )
+            if (str)
             {
-                msi_free( data );
-                return NULL;
+                r = msi_string2idW( tv->db->strings, str, &data[i] );
+
+                /* if there's no matching string in the string table,
+                   these keys can't match any record, so fail now. */
+                if (r != ERROR_SUCCESS)
+                {
+                    msi_free( data );
+                    return NULL;
+                }
             }
+            else data[i] = 0;
         }
         else
         {
@@ -2818,7 +2824,7 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
             UINT number = MSI_NULL_INTEGER;
             UINT row = 0;
 
-            if (!lstrcmpW( name, szColumns ))
+            if (!strcmpW( name, szColumns ))
             {
                 MSI_RecordGetStringW( rec, 1, table, &sz );
                 number = MSI_RecordGetInteger( rec, 2 );
@@ -2830,7 +2836,7 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
                 if ( number == MSI_NULL_INTEGER )
                 {
                     /* reset the column number on a new table */
-                    if (lstrcmpW( coltable, table ))
+                    if (strcmpW( coltable, table ))
                     {
                         colcol = 0;
                         lstrcpyW( coltable, table );
@@ -2876,7 +2882,7 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
                     WARN("failed to insert row %u\n", r);
             }
 
-            if (number != MSI_NULL_INTEGER && !lstrcmpW( name, szColumns ))
+            if (number != MSI_NULL_INTEGER && !strcmpW( name, szColumns ))
                 msi_update_table_columns( db, table );
 
             msiobj_release( &rec->hdr );
@@ -2938,8 +2944,8 @@ UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg )
         if ( name[0] != 0x4840 )
             continue;
 
-        if ( !lstrcmpW( name+1, szStringPool ) ||
-             !lstrcmpW( name+1, szStringData ) )
+        if ( !strcmpW( name+1, szStringPool ) ||
+             !strcmpW( name+1, szStringData ) )
             continue;
 
         transform = msi_alloc_zero( sizeof(TRANSFORMDATA) );
@@ -2950,9 +2956,9 @@ UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg )
 
         transform->name = strdupW( name + 1 );
 
-        if ( !lstrcmpW( transform->name, szTables ) )
+        if ( !strcmpW( transform->name, szTables ) )
             tables = transform;
-        else if (!lstrcmpW( transform->name, szColumns ) )
+        else if (!strcmpW( transform->name, szColumns ) )
             columns = transform;
 
         TRACE("transform contains stream %s\n", debugstr_w(name));
@@ -2990,8 +2996,8 @@ UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg )
     {
         transform = LIST_ENTRY( list_head( &transforms ), TRANSFORMDATA, entry );
 
-        if ( lstrcmpW( transform->name, szColumns ) &&
-             lstrcmpW( transform->name, szTables ) &&
+        if ( strcmpW( transform->name, szColumns ) &&
+             strcmpW( transform->name, szTables ) &&
              ret == ERROR_SUCCESS )
         {
             ret = msi_table_load_transform( db, stg, strings, transform, bytes_per_strref );
index 4c4db49..35a6074 100644 (file)
@@ -24,6 +24,7 @@
 #include "winbase.h"
 #include "winerror.h"
 #include "wine/debug.h"
+#include "wine/unicode.h"
 #include "msi.h"
 #include "msiquery.h"
 #include "objbase.h"
@@ -306,7 +307,7 @@ static UINT STRCMP_Evaluate( MSIWHEREVIEW *wv, UINT row, const struct expr *cond
     else if( r_str && ! l_str )
         sr = -1;
     else
-        sr = lstrcmpW( l_str, r_str );
+        sr = strcmpW( l_str, r_str );
 
     *val = ( cond->u.expr.op == OP_EQ && ( sr == 0 ) ) ||
            ( cond->u.expr.op == OP_NE && ( sr != 0 ) );
@@ -327,11 +328,15 @@ static UINT WHERE_evaluate( MSIWHEREVIEW *wv, UINT row,
     {
     case EXPR_COL_NUMBER:
         r = wv->table->ops->fetch_int( wv->table, row, cond->u.col_number, &tval );
+        if( r != ERROR_SUCCESS )
+            return r;
         *val = tval - 0x8000;
         return ERROR_SUCCESS;
 
     case EXPR_COL_NUMBER32:
         r = wv->table->ops->fetch_int( wv->table, row, cond->u.col_number, &tval );
+        if( r != ERROR_SUCCESS )
+            return r;
         *val = tval - 0x80000000;
         return r;