#include "shlobj.h"
#include "objbase.h"
#include "mscoree.h"
-#include "fusion.h"
#include "shlwapi.h"
#include "wine/unicode.h"
#include "winver.h"
{'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[] =
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[] =
msiobj_release(&row->hdr);
}
+enum parse_state
+{
+ state_whitespace,
+ state_token,
+ state_quote
+};
+
+static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
+{
+ enum parse_state state = state_quote;
+ const WCHAR *p;
+ WCHAR *out = value;
+ int ignore, in_quotes = 0, count = 0, len = 0;
+
+ for (p = str; *p; p++)
+ {
+ ignore = 0;
+ switch (state)
+ {
+ case state_whitespace:
+ switch (*p)
+ {
+ case ' ':
+ if (!count) goto done;
+ in_quotes = 1;
+ ignore = 1;
+ break;
+ case '"':
+ state = state_quote;
+ if (in_quotes) count--;
+ else count++;
+ break;
+ default:
+ state = state_token;
+ if (!count) in_quotes = 0;
+ else in_quotes = 1;
+ len++;
+ break;
+ }
+ break;
+
+ case state_token:
+ switch (*p)
+ {
+ case '"':
+ state = state_quote;
+ if (in_quotes) count--;
+ else count++;
+ break;
+ case ' ':
+ state = state_whitespace;
+ if (!count) goto done;
+ in_quotes = 1;
+ break;
+ default:
+ if (!count) in_quotes = 0;
+ else in_quotes = 1;
+ len++;
+ break;
+ }
+ break;
+
+ case state_quote:
+ switch (*p)
+ {
+ case '"':
+ if (in_quotes) count--;
+ else count++;
+ break;
+ case ' ':
+ state = state_whitespace;
+ if (!count || !len) goto done;
+ in_quotes = 1;
+ break;
+ default:
+ state = state_token;
+ if (!count) in_quotes = 0;
+ else in_quotes = 1;
+ len++;
+ break;
+ }
+ break;
+
+ default: break;
+ }
+ if (!ignore) *out++ = *p;
+ }
+
+done:
+ if (!len) *value = 0;
+ else *out = 0;
+
+ *quotes = count;
+ return p - str;
+}
+
+static void remove_quotes( WCHAR *str )
+{
+ WCHAR *p = str;
+ int len = strlenW( str );
+
+ while ((p = strchrW( p, '"' )))
+ {
+ memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
+ p++;
+ }
+}
+
UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
BOOL preserve_case )
{
- LPCWSTR ptr,ptr2;
- BOOL quote;
+ LPCWSTR ptr, ptr2;
+ int quotes;
DWORD len;
- LPWSTR prop = NULL, val = NULL;
+ WCHAR *prop, *val;
+ UINT r;
if (!szCommandLine)
return ERROR_SUCCESS;
ptr = szCommandLine;
-
while (*ptr)
{
- if (*ptr==' ')
- {
- ptr++;
- continue;
- }
+ while (*ptr == ' ') ptr++;
+ if (!*ptr) break;
- TRACE("Looking at %s\n",debugstr_w(ptr));
-
- ptr2 = strchrW(ptr,'=');
- if (!ptr2)
- {
- ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
- break;
- }
+ ptr2 = strchrW( ptr, '=' );
+ if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
- quote = FALSE;
+ len = ptr2 - ptr;
+ if (!len) return ERROR_INVALID_COMMAND_LINE;
- len = ptr2-ptr;
- prop = msi_alloc((len+1)*sizeof(WCHAR));
- memcpy(prop,ptr,len*sizeof(WCHAR));
- prop[len]=0;
-
- if (!preserve_case)
- struprW(prop);
+ prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
+ memcpy( prop, ptr, len * sizeof(WCHAR) );
+ prop[len] = 0;
+ if (!preserve_case) struprW( prop );
ptr2++;
-
- len = 0;
- ptr = ptr2;
- while (*ptr && (quote || (!quote && *ptr!=' ')))
- {
- if (*ptr == '"')
- quote = !quote;
- ptr++;
- len++;
- }
-
- if (*ptr2=='"')
+ while (*ptr2 == ' ') ptr2++;
+
+ quotes = 0;
+ val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) );
+ len = parse_prop( ptr2, val, "es );
+ if (quotes % 2)
{
- ptr2++;
- len -= 2;
+ WARN("unbalanced quotes\n");
+ msi_free( val );
+ msi_free( prop );
+ return ERROR_INVALID_COMMAND_LINE;
}
- val = msi_alloc((len+1)*sizeof(WCHAR));
- memcpy(val,ptr2,len*sizeof(WCHAR));
- val[len] = 0;
+ remove_quotes( val );
+ TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
- if (lstrlenW(prop) > 0)
- {
- UINT r = msi_set_property( package->db, prop, val );
+ r = msi_set_property( package->db, prop, val );
+ if (r == ERROR_SUCCESS && !strcmpW( prop, cszSourceDir ))
+ msi_reset_folders( package, TRUE );
- TRACE("Found commandline property (%s) = (%s)\n",
- debugstr_w(prop), debugstr_w(val));
+ msi_free( val );
+ msi_free( prop );
- if (r == ERROR_SUCCESS && !strcmpW( prop, cszSourceDir ))
- msi_reset_folders( package, TRUE );
- }
- msi_free(val);
- msi_free(prop);
+ ptr = ptr2 + len;
}
return ERROR_SUCCESS;
}
-
-static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
+WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
{
LPCWSTR pc;
LPWSTR p, *ret = NULL;
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 );
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 );
MSICOMPONENT *comp;
component = MSI_RecordGetString(row, 2);
+ if (!component)
+ return ERROR_SUCCESS;
+
comp = get_loaded_component(package, component);
if (!comp)
return ERROR_SUCCESS;
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));
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;
MSICOMPONENT *comp;
component = MSI_RecordGetString(row, 2);
+ if (!component)
+ return ERROR_SUCCESS;
+
comp = get_loaded_component(package, component);
if (!comp)
return ERROR_SUCCESS;
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));
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;
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;
}
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
{
- if ( !lstrcmpW( feature->Feature, name ) )
+ if ( !strcmpW( feature->Feature, name ) )
return feature;
}
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 );
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)
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)
{
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;
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)
}
}
msi_free(override);
-
return TRUE;
}
{
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;
+ }
}
}
{
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;
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 )
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;
}
}
{
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 )
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",
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;
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;
return size;
}
-static BOOL hash_matches( MSIFILE *file )
+BOOL msi_file_hash_matches( MSIFILE *file )
{
UINT r;
MSIFILEHASHINFO hash;
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);
-
- TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
-
- file->TargetPath = build_directory_name(2, p, file->FileName);
- msi_free(p);
-
- TRACE("file %s resolves to %s\n", debugstr_w(file->File), debugstr_w(file->TargetPath));
+ set_target_path( package, file );
- if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
+ if ((comp->assembly && !comp->assembly->installed) ||
+ GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
{
- file->state = msifs_missing;
comp->Cost += file->FileSize;
continue;
}
- if (file->Version && (file_version = msi_get_disk_file_version( file->TargetPath )))
- {
- TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version),
- HIWORD(file_version->dwFileVersionMS),
- LOWORD(file_version->dwFileVersionMS),
- HIWORD(file_version->dwFileVersionLS),
- LOWORD(file_version->dwFileVersionLS));
+ file_size = msi_get_disk_file_size( file->TargetPath );
- if (msi_compare_file_versions( file_version, file->Version ) < 0)
+ if (file->Version)
+ {
+ if ((file_version = msi_get_disk_file_version( file->TargetPath )))
{
- file->state = msifs_overwrite;
- comp->Cost += file->FileSize;
+ if (msi_compare_file_versions( file_version, file->Version ) < 0)
+ {
+ comp->Cost += file->FileSize - file_size;
+ }
+ msi_free( file_version );
+ continue;
}
- else
+ else if ((font_version = font_version_from_file( file->TargetPath )))
{
- TRACE("Destination file version equal or greater, not overwriting\n");
- file->state = msifs_present;
+ if (msi_compare_font_versions( font_version, file->Version ) < 0)
+ {
+ comp->Cost += file->FileSize - file_size;
+ }
+ msi_free( font_version );
+ continue;
}
- msi_free( file_version );
- continue;
}
- if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize)
+ if (file_size != file->FileSize)
{
- file->state = msifs_overwrite;
comp->Cost += file->FileSize - file_size;
- continue;
- }
- if (file->hash.dwFileHashInfoSize && hash_matches( file ))
- {
- TRACE("File hashes match, not overwriting\n");
- file->state = msifs_present;
- continue;
}
- file->state = msifs_overwrite;
- comp->Cost += file->FileSize - file_size;
}
-
return ERROR_SUCCESS;
}
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");
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 */
else
ptr=value;
- if (strstrW(value,szMulti))
+ if (strstrW(value, szMulti))
*type = REG_MULTI_SZ;
/* remove initial delimiter */
{
ERR("Could not create key %s\n", debugstr_w(keypath));
msi_free(uikey);
+ msi_free(keypath);
return ERROR_SUCCESS;
}
msi_free(value_data);
msi_free(deformated);
msi_free(uikey);
+ msi_free(keypath);
return ERROR_SUCCESS;
}
{
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;
}
{
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));
}
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);
}
{
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)
{
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;
/* only refcount DLLs */
if (comp->KeyPath == NULL ||
+ comp->assembly ||
comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
comp->Attributes & msidbComponentAttributesODBCDataSource)
write = FALSE;
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 );
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;
'>','=',' ','%','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);
}
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 );
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);
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 );
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);
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
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 );
}
return ERROR_FUNCTION_FAILED;
}
- if (!lstrcmpW(features[0], szAll))
+ if (!strcmpW( features[0], szAll ))
full_uninstall = TRUE;
else
{
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);
}
{
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);
rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
if (rc != ERROR_SUCCESS)
goto end;
-
- text = MSI_RecordGetString(rec,4);
- advertise = create_component_advertise_string(package, comp, feature);
-
- sz = strlenW(advertise);
+ advertise = create_component_advertise_string( package, comp, feature );
+ text = MSI_RecordGetString( rec, 4 );
if (text)
- sz += lstrlenW(text);
-
- sz+=3;
- sz *= sizeof(WCHAR);
-
- output = msi_alloc_zero(sz);
- strcpyW(output,advertise);
- msi_free(advertise);
+ {
+ p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
+ strcpyW( p, advertise );
+ strcatW( p, text );
+ msi_free( advertise );
+ advertise = p;
+ }
+ existing = msi_reg_get_val_str( hkey, qualifier );
- if (text)
- strcatW(output,text);
+ sz = strlenW( advertise ) + 1;
+ if (existing)
+ {
+ for (p = existing; *p; p += len)
+ {
+ len = strlenW( p ) + 1;
+ if (strcmpW( advertise, p )) sz += len;
+ }
+ }
+ if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
+ {
+ rc = ERROR_OUTOFMEMORY;
+ goto end;
+ }
+ q = output;
+ if (existing)
+ {
+ for (p = existing; *p; p += len)
+ {
+ len = strlenW( p ) + 1;
+ if (strcmpW( advertise, p ))
+ {
+ memcpy( q, p, len * sizeof(WCHAR) );
+ q += len;
+ }
+ }
+ }
+ strcpyW( q, advertise );
+ q[strlenW( q ) + 1] = 0;
msi_reg_set_val_multi_str( hkey, qualifier, output );
end:
RegCloseKey(hkey);
- msi_free(output);
+ msi_free( output );
+ msi_free( advertise );
+ msi_free( existing );
/* the UI chunk */
uirow = MSI_CreateRecord( 2 );
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',' ',
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);
ERR("Control query failed!\n");
goto done;
}
-
key = MSI_RecordGetString(row, 6);
file = get_loaded_file(package, key);
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;
}
return rc;
}
-static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
-{
- MSIFILE *file;
-
- LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
- {
- if (!lstrcmpW(file->File, filename))
- return file;
- }
-
- return NULL;
-}
-
-static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
+static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
{
MSIPACKAGE *package = param;
LPWSTR driver, driver_path, ptr;
WCHAR outpath[MAX_PATH];
- MSIFILE *driver_file, *setup_file;
+ MSIFILE *driver_file = NULL, *setup_file = NULL;
+ MSICOMPONENT *comp;
MSIRECORD *uirow;
- LPCWSTR desc;
+ LPCWSTR desc, file_key, component;
DWORD len, usage;
UINT r = ERROR_SUCCESS;
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)
{
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;
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)
{
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;
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);
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 ))
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 ))
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;
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 );
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])
{
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);
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;
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 )
{
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 };
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
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 );
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
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);
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);
--- /dev/null
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2010 Hans Leidekker for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "wine/debug.h"
+#include "wine/unicode.h"
+#include "msipriv.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+static HRESULT (WINAPI *pCreateAssemblyCacheNet11)( IAssemblyCache **, DWORD );
+static HRESULT (WINAPI *pCreateAssemblyCacheNet20)( IAssemblyCache **, DWORD );
+static HRESULT (WINAPI *pCreateAssemblyCacheSxs)( IAssemblyCache **, DWORD );
+static HRESULT (WINAPI *pLoadLibraryShim)( LPCWSTR, LPCWSTR, LPVOID, HMODULE * );
+static HRESULT (WINAPI *pGetFileVersion)( LPCWSTR, LPWSTR, DWORD, DWORD * );
+
+static BOOL init_function_pointers( void )
+{
+ static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
+ static const WCHAR szVersion11[] = {'v','1','.','1','.','4','3','2','2',0};
+ static const WCHAR szVersion20[] = {'v','2','.','0','.','5','0','7','2','7',0};
+ HMODULE hfusion11 = NULL, hfusion20 = NULL, hmscoree, hsxs;
+
+ if (pCreateAssemblyCacheNet11 || pCreateAssemblyCacheNet20) return TRUE;
+
+ if (!(hmscoree = LoadLibraryA( "mscoree.dll" ))) return FALSE;
+ if (!(pGetFileVersion = (void *)GetProcAddress( hmscoree, "GetFileVersion" ))) goto error;
+ if (!(pLoadLibraryShim = (void *)GetProcAddress( hmscoree, "LoadLibraryShim" ))) goto error;
+
+ if (!pLoadLibraryShim( szFusion, szVersion11, NULL, &hfusion11 ))
+ pCreateAssemblyCacheNet11 = (void *)GetProcAddress( hfusion11, "CreateAssemblyCache" );
+
+ if (!pLoadLibraryShim( szFusion, szVersion20, NULL, &hfusion20 ))
+ pCreateAssemblyCacheNet20 = (void *)GetProcAddress( hfusion20, "CreateAssemblyCache" );
+
+ if (!pCreateAssemblyCacheNet11 && !pCreateAssemblyCacheNet20) goto error;
+
+ if (!(hsxs = LoadLibraryA( "sxs.dll" ))) goto error;
+ if (!(pCreateAssemblyCacheSxs = (void *)GetProcAddress( hsxs, "CreateAssemblyCache" ))) goto error;
+ return TRUE;
+
+error:
+ pCreateAssemblyCacheNet11 = NULL;
+ pCreateAssemblyCacheNet20 = NULL;
+ FreeLibrary( hfusion11 );
+ FreeLibrary( hfusion20 );
+ FreeLibrary( hmscoree );
+ return FALSE;
+}
+
+static BOOL init_assembly_caches( MSIPACKAGE *package )
+{
+ if (!init_function_pointers()) return FALSE;
+ if (package->cache_net[CLR_VERSION_V11] || package->cache_net[CLR_VERSION_V20]) return TRUE;
+ if (pCreateAssemblyCacheSxs( &package->cache_sxs, 0 ) != S_OK) return FALSE;
+
+ if (pCreateAssemblyCacheNet11) pCreateAssemblyCacheNet11( &package->cache_net[CLR_VERSION_V11], 0 );
+ if (pCreateAssemblyCacheNet20) pCreateAssemblyCacheNet20( &package->cache_net[CLR_VERSION_V20], 0 );
+
+ if (package->cache_net[CLR_VERSION_V11] || package->cache_net[CLR_VERSION_V20])
+ {
+ return TRUE;
+ }
+ if (package->cache_net[CLR_VERSION_V11])
+ {
+ IAssemblyCache_Release( package->cache_net[CLR_VERSION_V11] );
+ package->cache_net[CLR_VERSION_V11] = NULL;
+ }
+ if (package->cache_net[CLR_VERSION_V20])
+ {
+ IAssemblyCache_Release( package->cache_net[CLR_VERSION_V20] );
+ package->cache_net[CLR_VERSION_V20] = NULL;
+ }
+ IAssemblyCache_Release( package->cache_sxs );
+ package->cache_sxs = NULL;
+ return FALSE;
+}
+
+static MSIRECORD *get_assembly_record( MSIPACKAGE *package, const WCHAR *comp )
+{
+ static const WCHAR query[] = {
+ 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','M','s','i','A','s','s','e','m','b','l','y','`',' ',
+ 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
+ ' ','=',' ','\'','%','s','\'',0};
+ MSIQUERY *view;
+ MSIRECORD *rec;
+ UINT r;
+
+ r = MSI_OpenQuery( package->db, &view, query, comp );
+ if (r != ERROR_SUCCESS)
+ return NULL;
+
+ r = MSI_ViewExecute( view, NULL );
+ if (r != ERROR_SUCCESS)
+ {
+ msiobj_release( &view->hdr );
+ return NULL;
+ }
+ r = MSI_ViewFetch( view, &rec );
+ if (r != ERROR_SUCCESS)
+ {
+ msiobj_release( &view->hdr );
+ return NULL;
+ }
+ if (!MSI_RecordGetString( rec, 4 ))
+ TRACE("component is a global assembly\n");
+
+ msiobj_release( &view->hdr );
+ return rec;
+}
+
+struct assembly_name
+{
+ UINT count;
+ UINT index;
+ WCHAR **attrs;
+};
+
+static UINT get_assembly_name_attribute( MSIRECORD *rec, LPVOID param )
+{
+ static const WCHAR fmtW[] = {'%','s','=','"','%','s','"',0};
+ static const WCHAR nameW[] = {'n','a','m','e',0};
+ struct assembly_name *name = param;
+ const WCHAR *attr = MSI_RecordGetString( rec, 2 );
+ const WCHAR *value = MSI_RecordGetString( rec, 3 );
+ int len = strlenW( fmtW ) + strlenW( attr ) + strlenW( value );
+
+ if (!(name->attrs[name->index] = msi_alloc( len * sizeof(WCHAR) )))
+ return ERROR_OUTOFMEMORY;
+
+ if (!strcmpiW( attr, nameW )) strcpyW( name->attrs[name->index++], value );
+ else sprintfW( name->attrs[name->index++], fmtW, attr, value );
+ return ERROR_SUCCESS;
+}
+
+static WCHAR *get_assembly_display_name( MSIDATABASE *db, const WCHAR *comp, MSIASSEMBLY *assembly )
+{
+ static const WCHAR commaW[] = {',',0};
+ static const WCHAR queryW[] = {
+ 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
+ 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
+ ' ','=',' ','\'','%','s','\'',0};
+ struct assembly_name name;
+ WCHAR *display_name = NULL;
+ MSIQUERY *view;
+ UINT i, r;
+ int len;
+
+ r = MSI_OpenQuery( db, &view, queryW, comp );
+ if (r != ERROR_SUCCESS)
+ return NULL;
+
+ name.count = 0;
+ name.index = 0;
+ name.attrs = NULL;
+ MSI_IterateRecords( view, &name.count, NULL, NULL );
+ if (!name.count) goto done;
+
+ name.attrs = msi_alloc( name.count * sizeof(WCHAR *) );
+ if (!name.attrs) goto done;
+
+ MSI_IterateRecords( view, NULL, get_assembly_name_attribute, &name );
+
+ len = 0;
+ for (i = 0; i < name.count; i++) len += strlenW( name.attrs[i] ) + 1;
+
+ display_name = msi_alloc( (len + 1) * sizeof(WCHAR) );
+ if (display_name)
+ {
+ display_name[0] = 0;
+ for (i = 0; i < name.count; i++)
+ {
+ strcatW( display_name, name.attrs[i] );
+ if (i < name.count - 1) strcatW( display_name, commaW );
+ }
+ }
+
+done:
+ msiobj_release( &view->hdr );
+ for (i = 0; i < name.count; i++) msi_free( name.attrs[i] );
+ msi_free( name.attrs );
+ return display_name;
+}
+
+static BOOL is_assembly_installed( IAssemblyCache *cache, const WCHAR *display_name )
+{
+ HRESULT hr;
+ ASSEMBLY_INFO info;
+
+ memset( &info, 0, sizeof(info) );
+ info.cbAssemblyInfo = sizeof(info);
+ hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_GETSIZE, display_name, &info );
+ if (FAILED( hr ))
+ {
+ TRACE("QueryAssemblyInfo returned 0x%08x\n", hr);
+ return FALSE;
+ }
+ return (info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
+}
+
+static const WCHAR clr_version_v11[] = {'v','1','.','1','.','4','3','2','2',0};
+static const WCHAR clr_version_v20[] = {'v','2','.','0','.','5','0','7','2','7',0};
+static const WCHAR clr_version_unknown[] = {'u','n','k','n','o','w','n',0};
+
+static const WCHAR *clr_version[] =
+{
+ clr_version_v11,
+ clr_version_v20
+};
+
+static const WCHAR *get_clr_version_str( enum clr_version version )
+{
+ if (version >= sizeof(clr_version)/sizeof(clr_version[0])) return clr_version_unknown;
+ return clr_version[version];
+}
+
+MSIASSEMBLY *load_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
+{
+ MSIRECORD *rec;
+ MSIASSEMBLY *a;
+
+ if (!(rec = get_assembly_record( package, comp->Component ))) return NULL;
+ if (!init_assembly_caches( package ))
+ {
+ ERR("can't initialize assembly caches\n");
+ msiobj_release( &rec->hdr );
+ return NULL;
+ }
+ if (!(a = msi_alloc_zero( sizeof(MSIASSEMBLY) )))
+ {
+ msiobj_release( &rec->hdr );
+ return NULL;
+ }
+ a->feature = strdupW( MSI_RecordGetString( rec, 2 ) );
+ TRACE("feature %s\n", debugstr_w(a->feature));
+
+ a->manifest = strdupW( MSI_RecordGetString( rec, 3 ) );
+ TRACE("manifest %s\n", debugstr_w(a->manifest));
+
+ a->application = strdupW( MSI_RecordGetString( rec, 4 ) );
+ TRACE("application %s\n", debugstr_w(a->application));
+
+ a->attributes = MSI_RecordGetInteger( rec, 5 );
+ TRACE("attributes %u\n", a->attributes);
+
+ if (!(a->display_name = get_assembly_display_name( package->db, comp->Component, a )))
+ {
+ WARN("can't get display name\n");
+ msiobj_release( &rec->hdr );
+ msi_free( a->feature );
+ msi_free( a->manifest );
+ msi_free( a->application );
+ msi_free( a );
+ return NULL;
+ }
+ TRACE("display name %s\n", debugstr_w(a->display_name));
+
+ if (a->application)
+ {
+ /* We can't check the manifest here because the target path may still change.
+ So we assume that the assembly is not installed and lean on the InstallFiles
+ action to determine which files need to be installed.
+ */
+ a->installed = FALSE;
+ }
+ else
+ {
+ if (a->attributes == msidbAssemblyAttributesWin32)
+ a->installed = is_assembly_installed( package->cache_sxs, a->display_name );
+ else
+ {
+ UINT i;
+ for (i = 0; i < CLR_VERSION_MAX; i++)
+ {
+ a->clr_version[i] = is_assembly_installed( package->cache_net[i], a->display_name );
+ if (a->clr_version[i])
+ {
+ TRACE("runtime version %s\n", debugstr_w(get_clr_version_str( i )));
+ a->installed = TRUE;
+ }
+ }
+ }
+ }
+ TRACE("assembly is %s\n", a->installed ? "installed" : "not installed");
+ msiobj_release( &rec->hdr );
+ return a;
+}
+
+static enum clr_version get_clr_version( const WCHAR *filename )
+{
+ DWORD len;
+ HRESULT hr;
+ enum clr_version version = CLR_VERSION_V11;
+ WCHAR *strW;
+
+ hr = pGetFileVersion( filename, NULL, 0, &len );
+ if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) return CLR_VERSION_V11;
+ if ((strW = msi_alloc( len * sizeof(WCHAR) )))
+ {
+ hr = pGetFileVersion( filename, strW, len, &len );
+ if (hr == S_OK)
+ {
+ UINT i;
+ for (i = 0; i < CLR_VERSION_MAX; i++)
+ if (!strcmpW( strW, clr_version[i] )) version = i;
+ }
+ msi_free( strW );
+ }
+ return version;
+}
+
+UINT install_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
+{
+ HRESULT hr;
+ const WCHAR *manifest;
+ IAssemblyCache *cache;
+ MSIASSEMBLY *assembly = comp->assembly;
+ MSIFEATURE *feature = NULL;
+
+ if (comp->assembly->feature)
+ feature = get_loaded_feature( package, comp->assembly->feature );
+
+ if (assembly->application)
+ {
+ if (feature) feature->Action = INSTALLSTATE_LOCAL;
+ return ERROR_SUCCESS;
+ }
+ if (assembly->attributes == msidbAssemblyAttributesWin32)
+ {
+ if (!assembly->manifest)
+ {
+ WARN("no manifest\n");
+ return ERROR_FUNCTION_FAILED;
+ }
+ manifest = get_loaded_file( package, assembly->manifest )->TargetPath;
+ cache = package->cache_sxs;
+ }
+ else
+ {
+ manifest = get_loaded_file( package, comp->KeyPath )->TargetPath;
+ cache = package->cache_net[get_clr_version( manifest )];
+ }
+ TRACE("installing assembly %s\n", debugstr_w(manifest));
+
+ hr = IAssemblyCache_InstallAssembly( cache, 0, manifest, NULL );
+ if (hr != S_OK)
+ {
+ ERR("Failed to install assembly %s (0x%08x)\n", debugstr_w(manifest), hr);
+ return ERROR_FUNCTION_FAILED;
+ }
+ if (feature) feature->Action = INSTALLSTATE_LOCAL;
+ assembly->installed = TRUE;
+ return ERROR_SUCCESS;
+}
+
+static WCHAR *build_local_assembly_path( const WCHAR *filename )
+{
+ UINT i;
+ WCHAR *ret;
+
+ if (!(ret = msi_alloc( (strlenW( filename ) + 1) * sizeof(WCHAR) )))
+ return NULL;
+
+ for (i = 0; filename[i]; i++)
+ {
+ if (filename[i] == '\\' || filename[i] == '/') ret[i] = '|';
+ else ret[i] = filename[i];
+ }
+ ret[i] = 0;
+ return ret;
+}
+
+static LONG open_assemblies_key( UINT context, BOOL win32, HKEY *hkey )
+{
+ static const WCHAR path_win32[] =
+ {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
+ 'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',0};
+ static const WCHAR path_dotnet[] =
+ {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
+ 'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',0};
+ static const WCHAR classes_path_win32[] =
+ {'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',0};
+ static const WCHAR classes_path_dotnet[] =
+ {'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',0};
+ HKEY root;
+ const WCHAR *path;
+
+ if (context == MSIINSTALLCONTEXT_MACHINE)
+ {
+ root = HKEY_CLASSES_ROOT;
+ if (win32) path = classes_path_win32;
+ else path = classes_path_dotnet;
+ }
+ else
+ {
+ root = HKEY_CURRENT_USER;
+ if (win32) path = path_win32;
+ else path = path_dotnet;
+ }
+ return RegCreateKeyW( root, path, hkey );
+}
+
+static LONG open_local_assembly_key( UINT context, BOOL win32, const WCHAR *filename, HKEY *hkey )
+{
+ LONG res;
+ HKEY root;
+ WCHAR *path;
+
+ if (!(path = build_local_assembly_path( filename )))
+ return ERROR_OUTOFMEMORY;
+
+ if ((res = open_assemblies_key( context, win32, &root )))
+ {
+ msi_free( path );
+ return res;
+ }
+ res = RegCreateKeyW( root, path, hkey );
+ RegCloseKey( root );
+ msi_free( path );
+ return res;
+}
+
+static LONG delete_local_assembly_key( UINT context, BOOL win32, const WCHAR *filename )
+{
+ LONG res;
+ HKEY root;
+ WCHAR *path;
+
+ if (!(path = build_local_assembly_path( filename )))
+ return ERROR_OUTOFMEMORY;
+
+ if ((res = open_assemblies_key( context, win32, &root )))
+ {
+ msi_free( path );
+ return res;
+ }
+ res = RegDeleteKeyW( root, path );
+ RegCloseKey( root );
+ msi_free( path );
+ return res;
+}
+
+static LONG open_global_assembly_key( UINT context, BOOL win32, HKEY *hkey )
+{
+ static const WCHAR path_win32[] =
+ {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
+ 'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',
+ 'G','l','o','b','a','l',0};
+ static const WCHAR path_dotnet[] =
+ {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
+ 'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',
+ 'G','l','o','b','a','l',0};
+ static const WCHAR classes_path_win32[] =
+ {'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',
+ 'G','l','o','b','a','l',0};
+ static const WCHAR classes_path_dotnet[] =
+ {'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\','G','l','o','b','a','l',0};
+ HKEY root;
+ const WCHAR *path;
+
+ if (context == MSIINSTALLCONTEXT_MACHINE)
+ {
+ root = HKEY_CLASSES_ROOT;
+ if (win32) path = classes_path_win32;
+ else path = classes_path_dotnet;
+ }
+ else
+ {
+ root = HKEY_CURRENT_USER;
+ if (win32) path = path_win32;
+ else path = path_dotnet;
+ }
+ return RegCreateKeyW( root, path, hkey );
+}
+
+UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
+{
+ MSICOMPONENT *comp;
+
+ LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
+ {
+ LONG res;
+ HKEY hkey;
+ GUID guid;
+ DWORD size;
+ WCHAR buffer[43];
+ MSIRECORD *uirow;
+ MSIASSEMBLY *assembly = comp->assembly;
+ BOOL win32;
+
+ if (!assembly || !comp->ComponentId) continue;
+
+ if (!comp->Enabled)
+ {
+ TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
+ continue;
+ }
+
+ if (comp->ActionRequest != INSTALLSTATE_LOCAL)
+ {
+ TRACE("Component not scheduled for installation: %s\n", debugstr_w(comp->Component));
+ comp->Action = comp->Installed;
+ continue;
+ }
+ comp->Action = INSTALLSTATE_LOCAL;
+
+ TRACE("publishing %s\n", debugstr_w(comp->Component));
+
+ CLSIDFromString( package->ProductCode, &guid );
+ encode_base85_guid( &guid, buffer );
+ buffer[20] = '>';
+ CLSIDFromString( comp->ComponentId, &guid );
+ encode_base85_guid( &guid, buffer + 21 );
+ buffer[42] = 0;
+
+ win32 = assembly->attributes & msidbAssemblyAttributesWin32;
+ if (assembly->application)
+ {
+ MSIFILE *file = get_loaded_file( package, assembly->application );
+ if ((res = open_local_assembly_key( package->Context, win32, file->TargetPath, &hkey )))
+ {
+ WARN("failed to open local assembly key %d\n", res);
+ return ERROR_FUNCTION_FAILED;
+ }
+ }
+ else
+ {
+ if ((res = open_global_assembly_key( package->Context, win32, &hkey )))
+ {
+ WARN("failed to open global assembly key %d\n", res);
+ return ERROR_FUNCTION_FAILED;
+ }
+ }
+ size = sizeof(buffer);
+ if ((res = RegSetValueExW( hkey, assembly->display_name, 0, REG_MULTI_SZ, (const BYTE *)buffer, size )))
+ {
+ WARN("failed to set assembly value %d\n", res);
+ }
+ RegCloseKey( hkey );
+
+ uirow = MSI_CreateRecord( 2 );
+ MSI_RecordSetStringW( uirow, 2, assembly->display_name );
+ ui_actiondata( package, szMsiPublishAssemblies, uirow );
+ msiobj_release( &uirow->hdr );
+ }
+ return ERROR_SUCCESS;
+}
+
+UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
+{
+ MSICOMPONENT *comp;
+
+ LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
+ {
+ LONG res;
+ MSIRECORD *uirow;
+ MSIASSEMBLY *assembly = comp->assembly;
+ BOOL win32;
+
+ if (!assembly || !comp->ComponentId) continue;
+
+ if (!comp->Enabled)
+ {
+ TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
+ continue;
+ }
+
+ if (comp->ActionRequest != INSTALLSTATE_ABSENT)
+ {
+ TRACE("Component not scheduled for removal: %s\n", debugstr_w(comp->Component));
+ comp->Action = comp->Installed;
+ continue;
+ }
+ comp->Action = INSTALLSTATE_ABSENT;
+
+ TRACE("unpublishing %s\n", debugstr_w(comp->Component));
+
+ win32 = assembly->attributes & msidbAssemblyAttributesWin32;
+ if (assembly->application)
+ {
+ MSIFILE *file = get_loaded_file( package, assembly->application );
+ if ((res = delete_local_assembly_key( package->Context, win32, file->TargetPath )))
+ WARN("failed to delete local assembly key %d\n", res);
+ }
+ else
+ {
+ HKEY hkey;
+ if ((res = open_global_assembly_key( package->Context, win32, &hkey )))
+ WARN("failed to delete global assembly key %d\n", res);
+ else
+ {
+ if ((res = RegDeleteValueW( hkey, assembly->display_name )))
+ WARN("failed to delete global assembly value %d\n", res);
+ RegCloseKey( hkey );
+ }
+ }
+
+ uirow = MSI_CreateRecord( 2 );
+ MSI_RecordSetStringW( uirow, 2, assembly->display_name );
+ ui_actiondata( package, szMsiPublishAssemblies, uirow );
+ msiobj_release( &uirow->hdr );
+ }
+ return ERROR_SUCCESS;
+}
/* 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;
/* 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;
/* 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;
/* 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;
/* 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;
LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry )
{
- if (strcmpiW(extension,ext->Extension))
+ if (strcmpiW(extension, ext->Extension))
continue;
if (comp == ext->Component)
{
}
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;
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");
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;
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");
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;
#include "winbase.h"
#include "winerror.h"
#include "wine/debug.h"
+#include "wine/unicode.h"
#include "msi.h"
#include "msiquery.h"
#include "objbase.h"
/* 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;
}
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
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))
{
return rc;
}
-
-static UINT store_binary_to_temp(MSIPACKAGE *package, LPCWSTR source,
- LPWSTR tmp_file)
+static MSIBINARY *create_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL dll )
{
static const WCHAR query[] = {
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
'`','B','i' ,'n','a','r','y','`',' ','W','H','E','R','E',' ',
'`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0};
- MSIRECORD *row = 0;
+ MSIRECORD *row;
+ MSIBINARY *binary;
HANDLE file;
CHAR buffer[1024];
- WCHAR fmt[MAX_PATH];
- DWORD sz = MAX_PATH;
+ WCHAR fmt[MAX_PATH], tmpfile[MAX_PATH];
+ DWORD sz = MAX_PATH, write;
UINT r;
if (msi_get_property(package->db, cszTempFolder, fmt, &sz) != ERROR_SUCCESS)
GetTempPathW(MAX_PATH, fmt);
- if (GetTempFileNameW(fmt, szMsi, 0, tmp_file) == 0)
+ if (!GetTempFileNameW( fmt, szMsi, 0, tmpfile ))
{
- TRACE("Unable to create file\n");
- return ERROR_FUNCTION_FAILED;
+ TRACE("unable to create temp file %s (%u)\n", debugstr_w(tmpfile), GetLastError());
+ return NULL;
}
- track_tempfile(package, tmp_file);
row = MSI_QueryGetRecord(package->db, query, source);
if (!row)
- return ERROR_FUNCTION_FAILED;
+ return NULL;
- /* write out the file */
- file = CreateFileW(tmp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL, NULL);
+ if (!(binary = msi_alloc_zero( sizeof(MSIBINARY) )))
+ {
+ msiobj_release( &row->hdr );
+ return NULL;
+ }
+ file = CreateFileW( tmpfile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if (file == INVALID_HANDLE_VALUE)
- r = ERROR_FUNCTION_FAILED;
- else
{
- do
+ msiobj_release( &row->hdr );
+ msi_free( binary );
+ return NULL;
+ }
+ do
+ {
+ sz = sizeof(buffer);
+ r = MSI_RecordReadStream( row, 2, buffer, &sz );
+ if (r != ERROR_SUCCESS)
{
- DWORD write;
- sz = sizeof buffer;
- r = MSI_RecordReadStream(row, 2, buffer, &sz);
- if (r != ERROR_SUCCESS)
- {
- ERR("Failed to get stream\n");
- break;
- }
- WriteFile(file, buffer, sz, &write, NULL);
- } while (sz == sizeof buffer);
- CloseHandle(file);
+ ERR("Failed to get stream\n");
+ break;
+ }
+ WriteFile( file, buffer, sz, &write, NULL );
+ } while (sz == sizeof buffer);
+
+ CloseHandle( file );
+ msiobj_release( &row->hdr );
+ if (r != ERROR_SUCCESS)
+ {
+ DeleteFileW( tmpfile );
+ msi_free( binary );
+ return NULL;
}
- msiobj_release(&row->hdr);
+ /* keep a reference to prevent the dll from being unloaded */
+ if (dll && !(binary->module = LoadLibraryW( tmpfile )))
+ {
+ WARN( "failed to load dll %s (%u)\n", debugstr_w( tmpfile ), GetLastError() );
+ }
+ binary->source = strdupW( source );
+ binary->tmpfile = strdupW( tmpfile );
+ list_add_tail( &package->binaries, &binary->entry );
+ return binary;
+}
- return r;
+static MSIBINARY *get_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL dll )
+{
+ MSIBINARY *binary;
+
+ LIST_FOR_EACH_ENTRY( binary, &package->binaries, MSIBINARY, entry )
+ {
+ if (!strcmpW( binary->source, source ))
+ return binary;
+ }
+
+ return create_temp_binary( package, source, dll );
}
static void file_running_action(MSIPACKAGE* package, HANDLE Handle,
if( !GetEnvironmentVariableW( MsiBreak, val, MAX_PATH ))
return;
- if( lstrcmpiW( val, target ))
+ if( strcmpiW( val, target ))
return;
msg = msi_alloc( (lstrlenW(format) + 10) * sizeof(WCHAR) );
IWineMsiRemoteCustomAction *rca = NULL;
HRESULT r;
- r = DllGetClassObject( &CLSID_IWineMsiRemoteCustomAction,
+ r = DllGetClassObject( &CLSID_WineMsiRemoteCustomAction,
&IID_IClassFactory, (LPVOID *)&cf );
if (FAILED(r))
{
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 );
LPCWSTR target, const INT type, LPCWSTR action)
{
msi_custom_action_info *info;
- WCHAR tmp_file[MAX_PATH];
+ MSIBINARY *binary;
UINT r;
- r = store_binary_to_temp(package, source, tmp_file);
- if (r != ERROR_SUCCESS)
- return r;
-
- TRACE("Calling function %s from %s\n",debugstr_w(target),
- debugstr_w(tmp_file));
+ if (!(binary = get_temp_binary( package, source, TRUE )))
+ return ERROR_FUNCTION_FAILED;
- if (!strchrW(tmp_file,'.'))
- strcatW(tmp_file, szDot);
+ TRACE("Calling function %s from %s\n", debugstr_w(target), debugstr_w(binary->tmpfile));
- info = do_msidbCustomActionTypeDll( package, type, tmp_file, target, action );
+ info = do_msidbCustomActionTypeDll( package, type, binary->tmpfile, target, action );
r = wait_thread_handle( info );
release_custom_action_data( info );
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;
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);
}
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;
{
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 ) );
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;
}
}
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,
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 );
if (!This)
return E_OUTOFMEMORY;
- This->lpVtbl = &msi_custom_remote_vtbl;
+ This->IWineMsiRemoteCustomAction_iface.lpVtbl = &msi_custom_remote_vtbl;
This->refs = 1;
*ppObj = This;
*/
#include <stdarg.h>
+#include <stdio.h>
#define COBJMACROS
#define NONAMELESSUNION
continue;
}
- if( !lstrcmpW( name, stat.pwcsName ) )
+ if( !strcmpW( name, stat.pwcsName ) )
{
TRACE("found %s\n", debugstr_w(name));
*stm = stream->stm;
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) );
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;
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))
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;
}
((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)
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;
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;
do
{
str = msi_dup_record_field(colnames, ++i);
- cmp = lstrcmpW(key, str);
+ cmp = strcmpW( key, str );
msi_free(str);
} while (cmp);
}
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,
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 );
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;
}
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);
}
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);
}
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;
}
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;
typedef struct msi_font_tag
{
- struct msi_font_tag *next;
+ struct list entry;
HFONT hfont;
COLORREF color;
WCHAR name[1];
SIZE size;
HWND hwnd;
LPWSTR default_font;
- msi_font *font_list;
+ struct list fonts;
struct list controls;
HWND hWndFocus;
LPWSTR control_default;
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 );
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;
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 );
}
}
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 );
msi_free( font );
msi_dialog_check_messages( NULL );
}
- else if( !lstrcmpW(attribute, szProgress) )
+ else if( !strcmpW( attribute, szProgress ) )
{
DWORD func, val;
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;
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;
}
font = msi_dialog_get_style( font_mask, &mask );
if( !mask )
{
- ERR("mask template is empty\n");
+ WARN("mask template is empty\n");
goto end;
}
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 );
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
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 )
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:
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;
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 );
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));
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 );
void msi_dialog_destroy( msi_dialog *dialog )
{
+ msi_font *font, *next;
+
if( uiThreadId != GetCurrentThreadId() )
{
SendMessageW( hMsiHiddenWindow, WM_MSI_DIALOG_DESTROY, 0, (LPARAM) 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 );
'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 );
}
if ( r != ERROR_SUCCESS)
r = ERROR_SUCCESS;
- if ( !lstrcmpW( result, error_abort ) )
+ if ( !strcmpW( result, error_abort ) )
r = ERROR_FUNCTION_FAILED;
done:
static UINT ControlEvent_EndDialog(MSIPACKAGE* package, LPCWSTR argument,
msi_dialog* dialog)
{
- static const WCHAR szExit[] = {
- 'E','x','i','t',0};
- static const WCHAR szRetry[] = {
- 'R','e','t','r','y',0};
- static const WCHAR szIgnore[] = {
- 'I','g','n','o','r','e',0};
- static const WCHAR szReturn[] = {
- 'R','e','t','u','r','n',0};
-
- if (lstrcmpW(argument,szExit)==0)
+ static const WCHAR szExit[] = {'E','x','i','t',0};
+ static const WCHAR szRetry[] = {'R','e','t','r','y',0};
+ static const WCHAR szIgnore[] = {'I','g','n','o','r','e',0};
+ static const WCHAR szReturn[] = {'R','e','t','u','r','n',0};
+
+ if (!strcmpW( argument, szExit ))
package->CurrentInstallState = ERROR_INSTALL_USEREXIT;
- else if (lstrcmpW(argument, szRetry) == 0)
+ else if (!strcmpW( argument, szRetry ))
package->CurrentInstallState = ERROR_INSTALL_SUSPEND;
- else if (lstrcmpW(argument, szIgnore) == 0)
+ else if (!strcmpW( argument, szIgnore ))
package->CurrentInstallState = ERROR_SUCCESS;
- else if (lstrcmpW(argument, szReturn) == 0)
+ else if (!strcmpW( argument, szReturn ))
{
msi_dialog *parent = msi_dialog_get_parent(dialog);
msi_free(package->next_dialog);
return ERROR_SUCCESS;
}
-static UINT ControlEvent_AddLocal(MSIPACKAGE* package, LPCWSTR argument,
- msi_dialog* dialog)
+static UINT ControlEvent_AddLocal( MSIPACKAGE *package, LPCWSTR argument, msi_dialog *dialog )
{
- MSIFEATURE *feature = NULL;
+ MSIFEATURE *feature;
- if (lstrcmpW(szAll,argument))
- {
- MSI_SetFeatureStateW(package,argument,INSTALLSTATE_LOCAL);
- }
- else
+ LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
{
- LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
- msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
-
- ACTION_UpdateComponentStates(package,argument);
+ if (!strcmpW( argument, feature->Feature ) || !strcmpW( argument, szAll ))
+ {
+ if (feature->ActionRequest != INSTALLSTATE_LOCAL)
+ msi_set_property( package->db, szPreselected, szOne );
+ MSI_SetFeatureStateW( package, feature->Feature, INSTALLSTATE_LOCAL );
+ }
}
return ERROR_SUCCESS;
}
-static UINT ControlEvent_Remove(MSIPACKAGE* package, LPCWSTR argument,
- msi_dialog* dialog)
+static UINT ControlEvent_Remove( MSIPACKAGE *package, LPCWSTR argument, msi_dialog *dialog )
{
- MSIFEATURE *feature = NULL;
+ MSIFEATURE *feature;
- if (lstrcmpW(szAll,argument))
- {
- MSI_SetFeatureStateW(package,argument,INSTALLSTATE_ABSENT);
- }
- else
+ LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
{
- LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
- msi_feature_set_state(package, feature, INSTALLSTATE_ABSENT);
-
- ACTION_UpdateComponentStates(package,argument);
+ if (!strcmpW( argument, feature->Feature ) || !strcmpW( argument, szAll ))
+ {
+ if (feature->ActionRequest != INSTALLSTATE_ABSENT)
+ msi_set_property( package->db, szPreselected, szOne );
+ MSI_SetFeatureStateW( package, feature->Feature, INSTALLSTATE_ABSENT );
+ }
}
return ERROR_SUCCESS;
}
-static UINT ControlEvent_AddSource(MSIPACKAGE* package, LPCWSTR argument,
- msi_dialog* dialog)
+static UINT ControlEvent_AddSource( MSIPACKAGE *package, LPCWSTR argument, msi_dialog *dialog )
{
- MSIFEATURE *feature = NULL;
+ MSIFEATURE *feature;
- if (lstrcmpW(szAll,argument))
+ LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
{
- MSI_SetFeatureStateW(package,argument,INSTALLSTATE_SOURCE);
- }
- else
- {
- LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
- msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
- ACTION_UpdateComponentStates(package,argument);
+ if (!strcmpW( argument, feature->Feature ) || !strcmpW( argument, szAll ))
+ {
+ if (feature->ActionRequest != INSTALLSTATE_SOURCE)
+ msi_set_property( package->db, szPreselected, szOne );
+ MSI_SetFeatureStateW( package, feature->Feature, INSTALLSTATE_SOURCE );
+ }
}
return ERROR_SUCCESS;
}
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 );
}
}
{
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 );
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);
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 );
}
}
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;
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;
}
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;
}
UINT ACTION_InstallFiles(MSIPACKAGE *package)
{
MSIMEDIAINFO *mi;
+ MSICOMPONENT *comp;
UINT rc = ERROR_SUCCESS;
MSIFILE *file;
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;
{
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;
{
ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
rc = ERROR_INSTALL_FAILURE;
- break;
+ goto done;
}
}
{
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)
{
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;
}
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;
{
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 */
{
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;
}
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");
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)
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;
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)
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;
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 );
}
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;
* 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;
/*
* 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;
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);
}
end:
CloseHandle(handle);
+ TRACE("Returning %s\n", debugstr_w(ret));
+ return ret;
+}
+
+static WCHAR *font_name_from_file( const WCHAR *filename )
+{
+ static const WCHAR truetypeW[] = {' ','(','T','r','u','e','T','y','p','e',')',0};
+ WCHAR *name, *ret = NULL;
+
+ if ((name = load_ttf_name_id( filename, NAME_ID_FULL_FONT_NAME )))
+ {
+ ret = msi_alloc( (strlenW( name ) + strlenW( truetypeW ) + 1 ) * sizeof(WCHAR) );
+ strcpyW( ret, name );
+ strcatW( ret, truetypeW );
+ msi_free( name );
+ }
+ return ret;
+}
- TRACE("Returning fontname %s\n",debugstr_w(ret));
+WCHAR *font_version_from_file( const WCHAR *filename )
+{
+ WCHAR *version, *p, *ret = NULL;
+
+ if ((p = version = load_ttf_name_id( filename, NAME_ID_VERSION )))
+ {
+ while (*p && !isdigitW( *p )) p++;
+ ret = msi_alloc( (strlenW( p ) + 1) * sizeof(WCHAR) );
+ strcpyW( ret, p );
+ msi_free( version );
+ }
return ret;
}
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);
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 );
{
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);
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);
LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
{
- if (lstrcmpW(Component,comp->Component)==0)
+ if (!strcmpW( Component, comp->Component ))
return comp;
}
return NULL;
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
{
- if (lstrcmpW( Feature, feature->Feature )==0)
+ if (!strcmpW( Feature, feature->Feature ))
return feature;
}
return NULL;
LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
{
- if (lstrcmpW( key, file->File )==0)
+ if (!strcmpW( key, file->File ))
return file;
}
return NULL;
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) );
LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
{
- if (lstrcmpW( dir, folder->Directory )==0)
+ if (!strcmpW( dir, folder->Directory ))
return folder;
}
return NULL;
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 &&
msi_free(p);
- TRACE("file %s source resolves to %s\n", debugstr_w(file->File),
- debugstr_w(path));
-
+ TRACE("file %s source resolves to %s\n", debugstr_w(file->File), debugstr_w(path));
return path;
}
-LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
- BOOL set_prop, BOOL load_prop, MSIFOLDER **folder)
+LPWSTR resolve_source_folder( MSIPACKAGE *package, LPCWSTR name, MSIFOLDER **folder )
{
MSIFOLDER *f;
LPWSTR p, path = NULL, parent;
- TRACE("Working to resolve %s\n",debugstr_w(name));
+ TRACE("working to resolve %s\n", debugstr_w(name));
+
+ if (!strcmpW( name, cszSourceDir ))
+ name = cszTargetDir;
- if (!name)
+ f = get_loaded_folder( package, name );
+ if (!f)
return NULL;
- if (!lstrcmpW(name,cszSourceDir))
- name = cszTargetDir;
+ /* special resolving for Target and Source root dir */
+ if (!strcmpW( name, cszTargetDir ))
+ {
+ if (!f->ResolvedSource)
+ f->ResolvedSource = get_source_root( package );
+ }
+
+ if (folder)
+ *folder = f;
+
+ if (f->ResolvedSource)
+ {
+ path = strdupW( f->ResolvedSource );
+ TRACE(" already resolved to %s\n", debugstr_w(path));
+ return path;
+ }
+
+ if (!f->Parent)
+ return path;
+
+ parent = f->Parent;
+ TRACE(" ! parent is %s\n", debugstr_w(parent));
+
+ p = resolve_source_folder( package, parent, NULL );
+
+ if (package->WordCount & msidbSumInfoSourceTypeCompressed)
+ path = get_source_root( package );
+ else if (package->WordCount & msidbSumInfoSourceTypeSFN)
+ path = build_directory_name( 3, p, f->SourceShortPath, NULL );
+ else
+ path = build_directory_name( 3, p, f->SourceLongPath, NULL );
+
+ TRACE("-> %s\n", debugstr_w(path));
+ f->ResolvedSource = strdupW( path );
+ msi_free( p );
+
+ return path;
+}
+
+LPWSTR resolve_target_folder( MSIPACKAGE *package, LPCWSTR name, BOOL set_prop, BOOL load_prop,
+ MSIFOLDER **folder )
+{
+ MSIFOLDER *f;
+ LPWSTR p, path = NULL, parent;
+
+ TRACE("working to resolve %s\n", debugstr_w(name));
f = get_loaded_folder( package, name );
if (!f)
return NULL;
/* special resolving for Target and Source root dir */
- if (!strcmpW(name,cszTargetDir))
+ if (!strcmpW( name, cszTargetDir ))
{
if (!f->ResolvedTarget && !f->Property)
{
/* 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));
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;
}
if( ((i+1)!=count) && dir[strlenW(dir)-1]!='\\')
strcatW(dir, szBackSlash);
}
+ va_end(va);
+
return dir;
}
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)
}
/* 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)
{
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;
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 &&
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;
+ }
}
}
}
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;
#include "winbase.h"
#include "winerror.h"
#include "wine/debug.h"
+#include "wine/unicode.h"
#include "msi.h"
#include "msiquery.h"
#include "objbase.h"
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);
if (r != ERROR_SUCCESS)
goto err;
- res = lstrcmpW(a, b);
+ res = strcmpW( a, b );
msi_free(b);
if (res == 0)
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)
}
/***********************************************************************
- * MsiGetSourcePath (internal)
+ * MSI_GetSourcePath (internal)
*/
static UINT MSI_GetSourcePath( MSIHANDLE hInstall, LPCWSTR szFolder,
awstring *szPathBuf, LPDWORD pcchPathBuf )
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;
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
*/
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
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);
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;
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);
}
*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;
}
if (!comp)
return ERROR_UNKNOWN_COMPONENT;
- comp->Installed = iState;
+ if (comp->Enabled)
+ comp->Action = iState;
return ERROR_SUCCESS;
}
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;
}
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)
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;
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;
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;
}
}
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;
/* 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;
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)
}
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])
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)
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[] = {
if (szCommandLine)
sz += lstrlenW(szCommandLine);
+ if (eInstallState != INSTALLSTATE_DEFAULT)
+ sz += lstrlenW(szInstallLevel);
+
if (eInstallState == INSTALLSTATE_ABSENT)
sz += lstrlenW(szRemoveAll);
if (szCommandLine)
lstrcpyW(commandline,szCommandLine);
+ if (eInstallState != INSTALLSTATE_DEFAULT)
+ lstrcatW(commandline, szInstallLevel);
+
if (eInstallState == INSTALLSTATE_ABSENT)
lstrcatW(commandline, szRemoveAll);
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)
{
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)
{
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)
}
if (val != empty && type != REG_DWORD &&
- !lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGECODEW))
+ !strcmpW( szAttribute, INSTALLPROPERTY_PACKAGECODEW ))
{
if (lstrlenW(val) != SQUISH_GUID_SIZE - 1)
badconfig = TRUE;
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)
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);
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;
r = msi_copy_outval(val, szValue, pcchValue);
}
- else if (!lstrcmpW(szProperty, INSTALLPROPERTY_PRODUCTSTATEW))
+ else if (!strcmpW( szProperty, INSTALLPROPERTY_PRODUCTSTATEW ))
{
if (dwContext == MSIINSTALLCONTEXT_MACHINE)
{
r = msi_copy_outval(val, szValue, pcchValue);
}
- else if (!lstrcmpW(szProperty, INSTALLPROPERTY_ASSIGNMENTTYPEW))
+ else if (!strcmpW( szProperty, INSTALLPROPERTY_ASSIGNMENTTYPEW ))
{
if (!prod && !classes)
goto done;
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,
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)
&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;
}
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;
}
*pdwState = INSTALLSTATE_LOCAL;
}
+ TRACE("-> %d\n", *pdwState);
return ERROR_SUCCESS;
}
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,
RegCloseKey(prodkey);
RegCloseKey(userdata);
+ TRACE("-> %d\n", state);
return state;
}
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,
msi_free(path);
}
-
- TRACE("%s %s -> %d\n", debugstr_w(szProduct), debugstr_w(szFeature), r);
msi_free(components);
if (missing)
- return INSTALLSTATE_ADVERTISED;
-
- if (source)
- return INSTALLSTATE_SOURCE;
+ r = INSTALLSTATE_ADVERTISED;
+ else if (source)
+ r = INSTALLSTATE_SOURCE;
+ else
+ r = INSTALLSTATE_LOCAL;
- return INSTALLSTATE_LOCAL;
+ TRACE("-> %d\n", r);
+ return r;
}
/******************************************************************
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;
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 );
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.@]
*/
<file>action.c</file>
<file>alter.c</file>
<file>appsearch.c</file>
+ <file>assembly.c</file>
<file>automation.c</file>
<file>classes.c</file>
<file>cond.tab.c</file>
*/
#include "windef.h"
-#include "winbase.h"
-#include "winuser.h"
-#include "winnls.h"
-LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
-
-#include "version.rc"
-
-#include "msi_Bg.rc"
-#include "msi_Da.rc"
-#include "msi_En.rc"
-#include "msi_Es.rc"
-#include "msi_Fi.rc"
-#include "msi_Hu.rc"
-#include "msi_Ko.rc"
-#include "msi_Nl.rc"
-#include "msi_No.rc"
-#include "msi_Pl.rc"
-#include "msi_Sv.rc"
-#include "msi_Tr.rc"
-#include "msi_Uk.rc"
-#include "msi_Zh.rc"
+LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
-/* UTF-8 */
-#include "msi_De.rc"
-#include "msi_Fr.rc"
-#include "msi_It.rc"
-#include "msi_Lt.rc"
-#include "msi_Pt.rc"
-#include "msi_Ro.rc"
-#include "msi_Ru.rc"
-#include "msi_Si.rc"
-#include "msi_Sr.rc"
+STRINGTABLE
+{
+ 4 "The specified installation package could not be opened. Please check the file path and try again."
+ 5 "path %s not found"
+ 9 "insert disk %s"
+ 10 "Windows Installer %s\n\n" \
+ "Usage:\n" \
+ "msiexec command {required parameter} [optional parameter]\n\n" \
+ "Install a product:\n" \
+ "\t/i {package|product_code} [property]\n" \
+ "\t/package {package|product_code} [property]\n" \
+ "\t/a package [property]\n" \
+ "Repair an installation:\n" \
+ "\t/f[p|o|e|d|c|a|u|m|s|v] {package|product_code}\n" \
+ "Uninstall a product:\n" \
+ "\t/uninstall {package|product_code} [property]\n" \
+ "\t/x {package|product_code} [property]\n" \
+ "Advertise a product:\n" \
+ "\t/j[u|m] package [/t transform] [/g languageid]\n" \
+ "Apply a patch:\n" \
+ "\t/p patch_package [property]\n" \
+ "\t/p patch_package /a package [property]\n" \
+ "Log and UI Modifiers for above commands:\n" \
+ "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \
+ "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+ "Register MSI Service:\n" \
+ "\t/y\n" \
+ "Unregister MSI Service:\n" \
+ "\t/z\n" \
+ "Display this help:\n" \
+ "\t/help\n" \
+ "\t/?\n"
+ 11 "enter which folder contains %s"
+ 12 "install source for feature missing"
+ 13 "network drive for feature missing"
+ 14 "feature from:"
+ 15 "choose which folder contains %s"
+}
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
/* @makedep: msiserver.tlb */
1 TYPELIB msiserver.tlb
+/* @makedep: msiserver.rgs */
+1 WINE_REGISTRY msiserver.rgs
+
/* @makedep: instadvert.bmp */
0x1001 BITMAP instadvert.bmp
/* @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"
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
#include "winreg.h"
#include "shlwapi.h"
#include "oleauto.h"
+#include "rpcproxy.h"
#include "msipriv.h"
+#include "msiserver.h"
#include "wine/debug.h"
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];
if (msi_typelib) ITypeLib_Release( msi_typelib );
msi_dialog_unregister_class();
msi_free_handle_table();
+ msi_free( gszLogFile );
break;
}
return TRUE;
}
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);
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;
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.@]
{
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 ));
}
#include "msidefs.h"
#include "objbase.h"
#include "objidl.h"
+#include "fusion.h"
#include "winnls.h"
#include "winver.h"
#include "wine/list.h"
MSIPATCHSTATE state;
} MSIPATCHINFO;
+typedef struct tagMSIBINARY
+{
+ struct list entry;
+ WCHAR *source;
+ WCHAR *tmpfile;
+ HMODULE module;
+} MSIBINARY;
+
typedef struct _column_info
{
LPCWSTR table;
PLATFORM_X64
};
+enum clr_version
+{
+ CLR_VERSION_V11,
+ CLR_VERSION_V20,
+ CLR_VERSION_MAX
+};
+
typedef struct tagMSIPACKAGE
{
MSIOBJECTHDR hdr;
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;
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;
INT RefCount;
LPWSTR FullKeypath;
LPWSTR AdvertiseString;
+ MSIASSEMBLY *assembly;
unsigned int anyAbsent:1;
unsigned int hasAdvertiseFeature:1;
msifs_present,
msifs_installed,
msifs_skipped,
+ msifs_hashmatch
} msi_file_state;
typedef struct tagMSIFILE
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;
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 );
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);
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 );
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 */
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);
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 );
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 );
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, ... );
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 */
} 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);
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);
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 )
[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
{
properties:
methods:
}
+
+ [
+ helpstring("Microsoft Windows Installer"),
+ threading(apartment),
+ progid("WindowsInstaller.Installer"),
+ uuid(000c1090-0000-0000-c000-000000000046)
+ ]
+ coclass MsiInstaller { interface Installer; }
}
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 );
}
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;
msi_free( comp->Condition );
msi_free( comp->KeyPath );
msi_free( comp->FullKeypath );
+ if (comp->assembly) free_assembly( comp->assembly );
msi_free( comp );
}
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 );
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)
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;
list_init( &package->sourcelist_info );
list_init( &package->sourcelist_media );
list_init( &package->patches );
+ list_init( &package->binaries );
}
return package;
if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
msi_load_admin_properties( package );
+
+ package->log_file = INVALID_HANDLE_VALUE;
}
return 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
{
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)
}
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;
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;
}
{'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;
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 );
}
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,
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 );
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;
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);
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);
}
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);
}
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);
}
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)
{
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);
}
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);
}
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;
{
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;
{
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;
#include "winuser.h"
#include "winerror.h"
#include "wine/debug.h"
+#include "wine/unicode.h"
#include "msi.h"
#include "msiquery.h"
#include "msipriv.h"
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;
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.@]
*
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;
}
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)
/* 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);
else
size = lstrlenW(ptr);
- size = lstrlenW(ptr);
if (size >= *pcchDiskPrompt)
r = ERROR_MORE_DATA;
else if (szDiskPrompt)
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)
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);
return ERROR_SUCCESS;
}
- if (!lstrcmpW(szProperty, INSTALLPROPERTY_LASTUSEDTYPEW))
+ if (!strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDTYPEW ))
{
if (*source != 'n' && *source != 'u' && *source != 'm')
{
*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,
}
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)
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,
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;
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)
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;
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;
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 )
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;
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;
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;
+}
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 )
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;
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);
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 )
if (id > 1 << bytes_per_strref * 8)
{
ERR("string id %u out of range\n", id);
- r = ERROR_FUNCTION_FAILED;
goto err;
}
}
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;
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 );
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;
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 )
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 )
{
LPCWSTR sval = MSI_RecordGetString( rec, i + 1 );
val = msi_addstringW( tv->db->strings, sval, -1, 1,
persistent ? StringPersistent : StringNonPersistent );
-
}
else
{
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;
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);
}
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;
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] ;
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");
! 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
{
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 );
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 );
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 );
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) );
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));
{
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 );
#include "winbase.h"
#include "winerror.h"
#include "wine/debug.h"
+#include "wine/unicode.h"
#include "msi.h"
#include "msiquery.h"
#include "objbase.h"
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 ) );
{
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;