diff --git a/reactos/dll/win32/msi/action.c b/reactos/dll/win32/msi/action.c index 808386f96e9..f806f18cb34 100644 --- a/reactos/dll/win32/msi/action.c +++ b/reactos/dll/win32/msi/action.c @@ -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=='"') - { - ptr2++; - len -= 2; - } - val = msi_alloc((len+1)*sizeof(WCHAR)); - memcpy(val,ptr2,len*sizeof(WCHAR)); - val[len] = 0; + while (*ptr2 == ' ') ptr2++; - if (lstrlenW(prop) > 0) + quotes = 0; + val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) ); + len = parse_prop( ptr2, val, "es ); + if (quotes % 2) { - UINT r = msi_set_property( package->db, prop, val ); - - TRACE("Found commandline property (%s) = (%s)\n", - debugstr_w(prop), debugstr_w(val)); - - if (r == ERROR_SUCCESS && !strcmpW( prop, cszSourceDir )) - msi_reset_folders( package, TRUE ); + WARN("unbalanced quotes\n"); + msi_free( val ); + msi_free( prop ); + return ERROR_INVALID_COMMAND_LINE; } - msi_free(val); - msi_free(prop); + remove_quotes( val ); + TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val)); + + r = msi_set_property( package->db, prop, val ); + 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 ) { - MSICOMPONENT* comp = 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); + set_target_path( package, file ); - 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)); - - 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) - { - file->state = msifs_overwrite; - comp->Cost += file->FileSize; - } - else - { - TRACE("Destination file version equal or greater, not overwriting\n"); - file->state = msifs_present; - } - msi_free( file_version ); - continue; - } - if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize) + if (file->Version) + { + if ((file_version = msi_get_disk_file_version( file->TargetPath ))) + { + if (msi_compare_file_versions( file_version, file->Version ) < 0) + { + comp->Cost += file->FileSize - file_size; + } + msi_free( file_version ); + continue; + } + else if ((font_version = font_version_from_file( file->TargetPath ))) + { + if (msi_compare_font_versions( font_version, file->Version ) < 0) + { + comp->Cost += file->FileSize - file_size; + } + msi_free( font_version ); + continue; + } + } + 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); + { + 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 ); - sz+=3; - sz *= sizeof(WCHAR); - - output = msi_alloc_zero(sz); - strcpyW(output,advertise); - msi_free(advertise); - - 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 ) { 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 ); diff --git a/reactos/dll/win32/msi/appsearch.c b/reactos/dll/win32/msi/appsearch.c index dfab3960b01..c8aea77fd35 100644 --- a/reactos/dll/win32/msi/appsearch.c +++ b/reactos/dll/win32/msi/appsearch.c @@ -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 index 00000000000..5199a31fc70 --- /dev/null +++ b/reactos/dll/win32/msi/assembly.c @@ -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 + +#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; +} diff --git a/reactos/dll/win32/msi/classes.c b/reactos/dll/win32/msi/classes.c index beaf1f0ff93..d11f48b4eab 100644 --- a/reactos/dll/win32/msi/classes.c +++ b/reactos/dll/win32/msi/classes.c @@ -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; diff --git a/reactos/dll/win32/msi/cond.tab.c b/reactos/dll/win32/msi/cond.tab.c index e68723db89b..eff848b5507 100644 --- a/reactos/dll/win32/msi/cond.tab.c +++ b/reactos/dll/win32/msi/cond.tab.c @@ -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; diff --git a/reactos/dll/win32/msi/cond.y b/reactos/dll/win32/msi/cond.y index 03ea4938ade..5bde044d8c2 100644 --- a/reactos/dll/win32/msi/cond.y +++ b/reactos/dll/win32/msi/cond.y @@ -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; diff --git a/reactos/dll/win32/msi/create.c b/reactos/dll/win32/msi/create.c index 2e13d592552..c55390c8f7a 100644 --- a/reactos/dll/win32/msi/create.c +++ b/reactos/dll/win32/msi/create.c @@ -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; diff --git a/reactos/dll/win32/msi/custom.c b/reactos/dll/win32/msi/custom.c index b56139fb665..83a750dd578 100644 --- a/reactos/dll/win32/msi/custom.c +++ b/reactos/dll/win32/msi/custom.c @@ -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 (file == INVALID_HANDLE_VALUE) - r = ERROR_FUNCTION_FAILED; - else + if (!(binary = msi_alloc_zero( sizeof(MSIBINARY) ))) { - do + msiobj_release( &row->hdr ); + return NULL; + } + file = CreateFileW( tmpfile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); + if (file == INVALID_HANDLE_VALUE) + { + 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; + if (!(binary = get_temp_binary( package, source, TRUE ))) + return ERROR_FUNCTION_FAILED; - TRACE("Calling function %s from %s\n",debugstr_w(target), - debugstr_w(tmp_file)); + TRACE("Calling function %s from %s\n", debugstr_w(target), debugstr_w(binary->tmpfile)); - if (!strchrW(tmp_file,'.')) - strcatW(tmp_file, szDot); - - 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; diff --git a/reactos/dll/win32/msi/database.c b/reactos/dll/win32/msi/database.c index 3007d485b2b..598d7a8a022 100644 --- a/reactos/dll/win32/msi/database.c +++ b/reactos/dll/win32/msi/database.c @@ -19,6 +19,7 @@ */ #include +#include #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; diff --git a/reactos/dll/win32/msi/dialog.c b/reactos/dll/win32/msi/dialog.c index e0e27d129f4..40aa7dff692 100644 --- a/reactos/dll/win32/msi/dialog.c +++ b/reactos/dll/win32/msi/dialog.c @@ -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: diff --git a/reactos/dll/win32/msi/events.c b/reactos/dll/win32/msi/events.c index 157d18575f4..b888c1cada9 100644 --- a/reactos/dll/win32/msi/events.c +++ b/reactos/dll/win32/msi/events.c @@ -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}; + 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) + 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)) + LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) { - MSI_SetFeatureStateW(package,argument,INSTALLSTATE_LOCAL); - } - else - { - 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)) + LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) { - MSI_SetFeatureStateW(package,argument,INSTALLSTATE_ABSENT); - } - else - { - 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); diff --git a/reactos/dll/win32/msi/files.c b/reactos/dll/win32/msi/files.c index 0ed9582c179..1f6187356e1 100644 --- a/reactos/dll/win32/msi/files.c +++ b/reactos/dll/win32/msi/files.c @@ -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; diff --git a/reactos/dll/win32/msi/font.c b/reactos/dll/win32/msi/font.c index 2128e922a56..7a493867c6a 100644 --- a/reactos/dll/win32/msi/font.c +++ b/reactos/dll/win32/msi/font.c @@ -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; +} - TRACE("Returning fontname %s\n",debugstr_w(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; +} + +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 ); diff --git a/reactos/dll/win32/msi/format.c b/reactos/dll/win32/msi/format.c index c4ff30f4111..b970dc1479f 100644 --- a/reactos/dll/win32/msi/format.c +++ b/reactos/dll/win32/msi/format.c @@ -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); diff --git a/reactos/dll/win32/msi/helpers.c b/reactos/dll/win32/msi/helpers.c index d3f2d9074a5..ffbe58b40e0 100644 --- a/reactos/dll/win32/msi/helpers.c +++ b/reactos/dll/win32/msi/helpers.c @@ -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,24 +244,18 @@ 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 (!name) - return NULL; - - if (!lstrcmpW(name,cszSourceDir)) + if (!strcmpW( name, cszSourceDir )) name = cszTargetDir; f = get_loaded_folder( package, name ); @@ -270,7 +263,58 @@ LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, return NULL; /* special resolving for Target and Source root dir */ - if (!strcmpW(name,cszTargetDir)) + 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 (!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; diff --git a/reactos/dll/win32/msi/insert.c b/reactos/dll/win32/msi/insert.c index 61807e9534e..03e1bd99795 100644 --- a/reactos/dll/win32/msi/insert.c +++ b/reactos/dll/win32/msi/insert.c @@ -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) diff --git a/reactos/dll/win32/msi/install.c b/reactos/dll/win32/msi/install.c index fa3e4f9e382..30a63e6d8bb 100644 --- a/reactos/dll/win32/msi/install.c +++ b/reactos/dll/win32/msi/install.c @@ -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; } diff --git a/reactos/dll/win32/msi/media.c b/reactos/dll/win32/msi/media.c index 788528e9b37..37d353017e1 100644 --- a/reactos/dll/win32/msi/media.c +++ b/reactos/dll/win32/msi/media.c @@ -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; diff --git a/reactos/dll/win32/msi/msi.c b/reactos/dll/win32/msi/msi.c index 7d1b9a55095..325a5b04634 100644 --- a/reactos/dll/win32/msi/msi.c +++ b/reactos/dll/win32/msi/msi.c @@ -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; + r = INSTALLSTATE_ADVERTISED; + else if (source) + r = INSTALLSTATE_SOURCE; + else + r = INSTALLSTATE_LOCAL; - if (source) - return INSTALLSTATE_SOURCE; - - 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.@] */ diff --git a/reactos/dll/win32/msi/msi.rbuild b/reactos/dll/win32/msi/msi.rbuild index 8c98a6d5c46..4dd17cc0655 100644 --- a/reactos/dll/win32/msi/msi.rbuild +++ b/reactos/dll/win32/msi/msi.rbuild @@ -11,6 +11,7 @@ action.c alter.c appsearch.c + assembly.c automation.c classes.c cond.tab.c diff --git a/reactos/dll/win32/msi/msi.rc b/reactos/dll/win32/msi/msi.rc index d81484f66bb..c980fa891d2 100644 --- a/reactos/dll/win32/msi/msi.rc +++ b/reactos/dll/win32/msi/msi.rc @@ -19,45 +19,56 @@ */ #include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "winnls.h" -LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT -#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" - -/* 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" diff --git a/reactos/dll/win32/msi/msi.spec b/reactos/dll/win32/msi/msi.spec index fd047f8a652..c1e35530782 100644 --- a/reactos/dll/win32/msi/msi.spec +++ b/reactos/dll/win32/msi/msi.spec @@ -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 diff --git a/reactos/dll/win32/msi/msi_main.c b/reactos/dll/win32/msi/msi_main.c index df29184ab92..93f65430545 100644 --- a/reactos/dll/win32/msi/msi_main.c +++ b/reactos/dll/win32/msi/msi_main.c @@ -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 )); } diff --git a/reactos/dll/win32/msi/msipriv.h b/reactos/dll/win32/msi/msipriv.h index 0361ff42c6e..56a8a93c807 100644 --- a/reactos/dll/win32/msi/msipriv.h +++ b/reactos/dll/win32/msi/msipriv.h @@ -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); diff --git a/reactos/dll/win32/msi/msiquery.c b/reactos/dll/win32/msi/msiquery.c index cf6959391d3..4ccf5f65f8f 100644 --- a/reactos/dll/win32/msi/msiquery.c +++ b/reactos/dll/win32/msi/msiquery.c @@ -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 ) diff --git a/reactos/dll/win32/msi/msiserver.idl b/reactos/dll/win32/msi/msiserver.idl index e74c22c0b19..58c5b3cf99f 100644 --- a/reactos/dll/win32/msi/msiserver.idl +++ b/reactos/dll/win32/msi/msiserver.idl @@ -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; } } diff --git a/reactos/dll/win32/msi/package.c b/reactos/dll/win32/msi/package.c index 32576a0362c..c84c28a7516 100644 --- a/reactos/dll/win32/msi/package.c +++ b/reactos/dll/win32/msi/package.c @@ -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; diff --git a/reactos/dll/win32/msi/record.c b/reactos/dll/win32/msi/record.c index 7bc82814b2e..fc30f793436 100644 --- a/reactos/dll/win32/msi/record.c +++ b/reactos/dll/win32/msi/record.c @@ -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; diff --git a/reactos/dll/win32/msi/registry.c b/reactos/dll/win32/msi/registry.c index e83490f5e36..017aa2405c9 100644 --- a/reactos/dll/win32/msi/registry.c +++ b/reactos/dll/win32/msi/registry.c @@ -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) diff --git a/reactos/dll/win32/msi/script.c b/reactos/dll/win32/msi/script.c index 4f223daa8b0..27bbee1afda 100644 --- a/reactos/dll/win32/msi/script.c +++ b/reactos/dll/win32/msi/script.c @@ -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); diff --git a/reactos/dll/win32/msi/source.c b/reactos/dll/win32/msi/source.c index 8e4323a4711..881f3d26bf2 100644 --- a/reactos/dll/win32/msi/source.c +++ b/reactos/dll/win32/msi/source.c @@ -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) diff --git a/reactos/dll/win32/msi/sql.tab.c b/reactos/dll/win32/msi/sql.tab.c index 72e230ca837..f70760278e5 100644 --- a/reactos/dll/win32/msi/sql.tab.c +++ b/reactos/dll/win32/msi/sql.tab.c @@ -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; diff --git a/reactos/dll/win32/msi/sql.y b/reactos/dll/win32/msi/sql.y index 548a8782444..01217378534 100644 --- a/reactos/dll/win32/msi/sql.y +++ b/reactos/dll/win32/msi/sql.y @@ -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; diff --git a/reactos/dll/win32/msi/string.c b/reactos/dll/win32/msi/string.c index 5644749392f..406803337f4 100644 --- a/reactos/dll/win32/msi/string.c +++ b/reactos/dll/win32/msi/string.c @@ -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; +} diff --git a/reactos/dll/win32/msi/table.c b/reactos/dll/win32/msi/table.c index 3e456ed56c4..14f4d307ddd 100644 --- a/reactos/dll/win32/msi/table.c +++ b/reactos/dll/win32/msi/table.c @@ -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 ); diff --git a/reactos/dll/win32/msi/where.c b/reactos/dll/win32/msi/where.c index 4c4db491474..35a6074a650 100644 --- a/reactos/dll/win32/msi/where.c +++ b/reactos/dll/win32/msi/where.c @@ -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;