diff --git a/reactos/dll/win32/msi/action.c b/reactos/dll/win32/msi/action.c index fec14a4f4ef..252f1ba55ba 100644 --- a/reactos/dll/win32/msi/action.c +++ b/reactos/dll/win32/msi/action.c @@ -35,6 +35,7 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/stand #include "winbase.h" #include "winerror.h" #include "winreg.h" +#include "winsvc.h" #include "wine/debug.h" #include "msidefs.h" #include "msipriv.h" @@ -42,7 +43,6 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/stand #include "shlobj.h" #include "wine/unicode.h" #include "winver.h" -#include "action.h" #define REG_PROGRESS_VALUE 13200 #define COMPONENT_PROGRESS_VALUE 24000 @@ -365,6 +365,7 @@ static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine ) static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep ) { + LPCWSTR pc; LPWSTR p, *ret = NULL; UINT count = 0; @@ -372,11 +373,11 @@ static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep ) return ret; /* count the number of substrings */ - for ( p = (LPWSTR)str, count = 0; p; count++ ) + for ( pc = str, count = 0; pc; count++ ) { - p = strchrW( p, sep ); - if (p) - p++; + pc = strchrW( pc, sep ); + if (pc) + pc++; } /* allocate space for an array of substring pointers and the substrings */ @@ -574,7 +575,6 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath, { LPWSTR p, check, path; - package->PackagePath = strdupW(szPackagePath); path = strdupW(szPackagePath); p = strrchrW(path,'\\'); if (p) @@ -593,8 +593,15 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath, check = msi_dup_property( package, cszSourceDir ); if (!check) MSI_SetPropertyW(package, cszSourceDir, path); + + check = msi_dup_property( package, cszSOURCEDIR ); + if (!check) + MSI_SetPropertyW(package, cszSOURCEDIR, path); + + msi_free( package->PackagePath ); + package->PackagePath = path; + msi_free(check); - msi_free(path); } msi_parse_command_line( package, szCommandLine ); @@ -1118,26 +1125,9 @@ static UINT load_component( MSIRECORD *row, LPVOID param ) comp->Condition = msi_dup_record_field( row, 5 ); comp->KeyPath = msi_dup_record_field( row, 6 ); - comp->Installed = INSTALLSTATE_ABSENT; - - switch (comp->Attributes) - { - case msidbComponentAttributesLocalOnly: - comp->Action = INSTALLSTATE_LOCAL; - comp->ActionRequest = INSTALLSTATE_LOCAL; - break; - case msidbComponentAttributesSourceOnly: - comp->Action = INSTALLSTATE_SOURCE; - comp->ActionRequest = INSTALLSTATE_SOURCE; - break; - case msidbComponentAttributesOptional: - comp->Action = INSTALLSTATE_DEFAULT; - comp->ActionRequest = INSTALLSTATE_DEFAULT; - break; - default: - comp->Action = INSTALLSTATE_LOCAL; - comp->ActionRequest = INSTALLSTATE_LOCAL; - } + comp->Installed = INSTALLSTATE_UNKNOWN; + comp->Action = INSTALLSTATE_UNKNOWN; + comp->ActionRequest = INSTALLSTATE_UNKNOWN; return ERROR_SUCCESS; } @@ -1180,6 +1170,19 @@ static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp ) return ERROR_SUCCESS; } +static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child ) +{ + FeatureList *fl; + + fl = msi_alloc( sizeof(*fl) ); + if ( !fl ) + return ERROR_NOT_ENOUGH_MEMORY; + fl->feature = child; + list_add_tail( &parent->Children, &fl->entry ); + + return ERROR_SUCCESS; +} + static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param) { _ilfs* ilfs= (_ilfs*)param; @@ -1202,6 +1205,19 @@ static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param) return ERROR_SUCCESS; } +static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name ) +{ + MSIFEATURE *feature; + + LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) + { + if ( !lstrcmpW( feature->Feature, name ) ) + return feature; + } + + return NULL; +} + static UINT load_feature(MSIRECORD * row, LPVOID param) { MSIPACKAGE* package = (MSIPACKAGE*)param; @@ -1223,6 +1239,7 @@ static UINT load_feature(MSIRECORD * row, LPVOID param) if (!feature) return ERROR_NOT_ENOUGH_MEMORY; + list_init( &feature->Children ); list_init( &feature->Components ); feature->Feature = msi_dup_record_field( row, 1 ); @@ -1240,7 +1257,7 @@ static UINT load_feature(MSIRECORD * row, LPVOID param) feature->Directory = msi_dup_record_field( row, 7 ); feature->Attributes = MSI_RecordGetInteger(row,8); - feature->Installed = INSTALLSTATE_ABSENT; + feature->Installed = INSTALLSTATE_UNKNOWN; feature->Action = INSTALLSTATE_UNKNOWN; feature->ActionRequest = INSTALLSTATE_UNKNOWN; @@ -1261,6 +1278,26 @@ static UINT load_feature(MSIRECORD * row, LPVOID param) return ERROR_SUCCESS; } +static UINT find_feature_children(MSIRECORD * row, LPVOID param) +{ + MSIPACKAGE* package = (MSIPACKAGE*)param; + MSIFEATURE *parent, *child; + + child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) ); + if (!child) + return ERROR_FUNCTION_FAILED; + + if (!child->Feature_Parent) + return ERROR_SUCCESS; + + parent = find_feature_by_name( package, child->Feature_Parent ); + if (!parent) + return ERROR_FUNCTION_FAILED; + + add_feature_child( parent, child ); + return ERROR_SUCCESS; +} + static UINT load_all_features( MSIPACKAGE *package ) { static const WCHAR query[] = { @@ -1278,7 +1315,12 @@ static UINT load_all_features( MSIPACKAGE *package ) return r; r = MSI_IterateRecords( view, NULL, load_feature, package ); + if (r != ERROR_SUCCESS) + return r; + + r = MSI_IterateRecords( view, NULL, find_feature_children, package ); msiobj_release( &view->hdr ); + return r; } @@ -1343,13 +1385,6 @@ static UINT load_file(MSIRECORD *row, LPVOID param) file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED; } - if (file->IsCompressed) - { - file->Component->ForceLocalState = TRUE; - file->Component->Action = INSTALLSTATE_LOCAL; - file->Component->ActionRequest = INSTALLSTATE_LOCAL; - } - TRACE("File Loaded (%s)\n",debugstr_w(file->File)); list_add_tail( &package->files, &file->entry ); @@ -1546,9 +1581,16 @@ static void ACTION_UpdateInstallStates(MSIPACKAGE *package) MSICOMPONENT *comp; MSIFEATURE *feature; + /* FIXME: component's installed state should be determined + * by the component's registration + */ LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) { INSTALLSTATE res; + + if (!comp->ComponentId) + continue; + res = MsiGetComponentPathW( package->ProductCode, comp->ComponentId, NULL, NULL); if (res < 0) @@ -1559,21 +1601,30 @@ static void ACTION_UpdateInstallStates(MSIPACKAGE *package) LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) { ComponentList *cl; - INSTALLSTATE res = -10; + INSTALLSTATE res = INSTALLSTATE_ABSENT; LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) { comp= cl->component; - if (res == -10) + if (!comp->ComponentId) + { + res = INSTALLSTATE_ABSENT; + break; + } + + if (res == INSTALLSTATE_ABSENT) res = comp->Installed; else { if (res == comp->Installed) continue; - if (res != comp->Installed) - res = INSTALLSTATE_INCOMPLETE; + if (res != INSTALLSTATE_DEFAULT || res != INSTALLSTATE_LOCAL || + res != INSTALLSTATE_SOURCE) + { + res = INSTALLSTATE_INCOMPLETE; + } } } feature->Installed = res; @@ -1649,7 +1700,7 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package) install_level = msi_get_property_int( package, szlevel, 1 ); - /* ok hereis the _real_ rub + /* ok here is the _real_ rub * all these activation/deactivation things happen in order and things * later on the list override things earlier on the list. * 1) INSTALLLEVEL processing @@ -1701,6 +1752,21 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package) } } } + + /* disable child features of unselected parent features */ + LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) + { + FeatureList *fl; + + if (feature->Level > 0 && feature->Level <= install_level) + continue; + + LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry ) + { + fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN; + fl->feature->Action = INSTALLSTATE_UNKNOWN; + } + } } else { @@ -1727,6 +1793,31 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package) { component = cl->component; + switch (component->Attributes) + { + case msidbComponentAttributesLocalOnly: + component->Action = INSTALLSTATE_LOCAL; + component->ActionRequest = INSTALLSTATE_LOCAL; + break; + case msidbComponentAttributesSourceOnly: + component->Action = INSTALLSTATE_SOURCE; + component->ActionRequest = INSTALLSTATE_SOURCE; + break; + case msidbComponentAttributesOptional: + component->Action = INSTALLSTATE_DEFAULT; + component->ActionRequest = INSTALLSTATE_DEFAULT; + break; + default: + component->Action = INSTALLSTATE_LOCAL; + component->ActionRequest = INSTALLSTATE_LOCAL; + } + + if (component->ForceLocalState) + { + component->Action = INSTALLSTATE_LOCAL; + component->ActionRequest = INSTALLSTATE_LOCAL; + } + if (!component->Enabled) { component->Action = INSTALLSTATE_UNKNOWN; @@ -1772,9 +1863,14 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package) component->ActionRequest = INSTALLSTATE_ABSENT; } } + else if (feature->ActionRequest == INSTALLSTATE_UNKNOWN) + { + component->Action = INSTALLSTATE_UNKNOWN; + component->ActionRequest = INSTALLSTATE_UNKNOWN; + } } - if (component->ForceLocalState) + if (component->ForceLocalState && feature->Action == INSTALLSTATE_SOURCE) { feature->Action = INSTALLSTATE_LOCAL; feature->ActionRequest = INSTALLSTATE_LOCAL; @@ -1837,7 +1933,6 @@ static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param) return ERROR_SUCCESS; } - /* * A lot is done in this function aside from just the costing. * The costing needs to be implemented at some point but for now I am going @@ -1886,6 +1981,9 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) if (!comp) continue; + if (file->IsCompressed) + comp->ForceLocalState = TRUE; + /* calculate target */ p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL); @@ -2037,7 +2135,7 @@ static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type, } msi_free(deformated); - TRACE("Data %li bytes(%i)\n",*size,count); + TRACE("Data %i bytes(%i)\n",*size,count); } else { @@ -2063,7 +2161,7 @@ static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type, if (deformated[0] == '-') d = -d; *(LPDWORD)data = d; - TRACE("DWORD %li\n",*(LPDWORD)data); + TRACE("DWORD %i\n",*(LPDWORD)data); msi_free(deformated); } @@ -3540,7 +3638,7 @@ static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey ) if (!r) { - ERR("Unable to copy package (%s -> %s) (error %ld)\n", + ERR("Unable to copy package (%s -> %s) (error %d)\n", debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError()); return ERROR_FUNCTION_FAILED; } @@ -3751,10 +3849,12 @@ static UINT ACTION_ForceReboot(MSIPACKAGE *package) return ERROR_INSTALL_SUSPEND; } -UINT ACTION_ResolveSource(MSIPACKAGE* package) +static UINT ACTION_ResolveSource(MSIPACKAGE* package) { - DWORD attrib; + DWORD attrib, len; + LPWSTR ptr, source; UINT rc; + /* * we are currently doing what should be done here in the top level Install * however for Adminastrative and uninstalls this step will be needed @@ -3762,6 +3862,19 @@ UINT ACTION_ResolveSource(MSIPACKAGE* package) if (!package->PackagePath) return ERROR_SUCCESS; + ptr = strrchrW(package->PackagePath, '\\'); + if (!ptr) + return ERROR_SUCCESS; + + len = ptr - package->PackagePath + 2; + source = msi_alloc(len * sizeof(WCHAR)); + lstrcpynW(source, package->PackagePath, len); + + MSI_SetPropertyW(package, cszSourceDir, source); + MSI_SetPropertyW(package, cszSOURCEDIR, source); + + msi_free(source); + attrib = GetFileAttributesW(package->PackagePath); if (attrib == INVALID_FILE_ATTRIBUTES) { @@ -3956,6 +4069,100 @@ static UINT ACTION_PublishComponents(MSIPACKAGE *package) return rc; } +static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param) +{ + MSIPACKAGE *package = (MSIPACKAGE*)param; + MSIRECORD *row; + MSIFILE *file; + SC_HANDLE hscm, service = NULL; + LPCWSTR name, disp, comp, depends, pass; + LPCWSTR load_order, serv_name, key; + DWORD serv_type, start_type; + DWORD err_control; + + static const WCHAR query[] = + {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ', + '`','C','o','m','p','o','n','e','n','t','`',' ', + 'W','H','E','R','E',' ', + '`','C','o','m','p','o','n','e','n','t','`',' ', + '=','\'','%','s','\'',0}; + + hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE); + if (!hscm) + { + ERR("Failed to open the SC Manager!\n"); + 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"); + + name = MSI_RecordGetString(rec, 2); + disp = MSI_RecordGetString(rec, 3); + 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); + + /* fetch the service path */ + row = MSI_QueryGetRecord(package->db, query, comp); + if (!row) + { + ERR("Control query failed!\n"); + goto done; + } + + key = MSI_RecordGetString(row, 6); + msiobj_release(&row->hdr); + + file = get_loaded_file(package, key); + if (!file) + { + ERR("Failed to load the service file\n"); + goto done; + } + + service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type, + start_type, err_control, file->TargetPath, + load_order, NULL, NULL, serv_name, pass); + if (!service) + { + if (GetLastError() != ERROR_SERVICE_EXISTS) + ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError()); + } + +done: + CloseServiceHandle(service); + CloseServiceHandle(hscm); + + return ERROR_SUCCESS; +} + +static UINT ACTION_InstallServices( MSIPACKAGE *package ) +{ + UINT rc; + MSIQUERY * view; + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0}; + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + return ERROR_SUCCESS; + + rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package); + msiobj_release(&view->hdr); + + return rc; +} + static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table ) { @@ -3974,7 +4181,7 @@ static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, } if (count) - FIXME("%s -> %lu ignored %s table values\n", + FIXME("%s -> %u ignored %s table values\n", action, count, debugstr_w(table)); return ERROR_SUCCESS; @@ -4030,13 +4237,6 @@ static UINT ACTION_SelfUnregModules( MSIPACKAGE *package ) return msi_unimplemented_action_stub( package, "SelfUnregModules", table ); } -static UINT ACTION_InstallServices( MSIPACKAGE *package ) -{ - static const WCHAR table[] = { - 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 }; - return msi_unimplemented_action_stub( package, "InstallServices", table ); -} - static UINT ACTION_StartServices( MSIPACKAGE *package ) { static const WCHAR table[] = { diff --git a/reactos/dll/win32/msi/action.h b/reactos/dll/win32/msi/action.h deleted file mode 100644 index 785c4e3fda2..00000000000 --- a/reactos/dll/win32/msi/action.h +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Common prototypes for Action handlers - * - * Copyright 2005 Aric Stewart 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 - */ - -#ifndef __MSI_ACTION_H__ -#define __MSI_ACTION_H__ - -#include "wine/list.h" - -typedef struct tagMSIFEATURE -{ - struct list entry; - LPWSTR Feature; - LPWSTR Feature_Parent; - LPWSTR Title; - LPWSTR Description; - INT Display; - INT Level; - LPWSTR Directory; - INT Attributes; - - INSTALLSTATE Installed; - INSTALLSTATE ActionRequest; - INSTALLSTATE Action; - - struct list Components; - - INT Cost; -} MSIFEATURE; - -typedef struct tagMSICOMPONENT -{ - struct list entry; - DWORD magic; - LPWSTR Component; - LPWSTR ComponentId; - LPWSTR Directory; - INT Attributes; - LPWSTR Condition; - LPWSTR KeyPath; - - INSTALLSTATE Installed; - INSTALLSTATE ActionRequest; - INSTALLSTATE Action; - - BOOL ForceLocalState; - BOOL Enabled; - INT Cost; - INT RefCount; - - LPWSTR FullKeypath; - LPWSTR AdvertiseString; -} MSICOMPONENT; - -typedef struct tagComponentList -{ - struct list entry; - MSICOMPONENT *component; -} ComponentList; - -typedef struct tagMSIFOLDER -{ - struct list entry; - LPWSTR Directory; - LPWSTR TargetDefault; - LPWSTR SourceLongPath; - LPWSTR SourceShortPath; - - LPWSTR ResolvedTarget; - LPWSTR ResolvedSource; - LPWSTR Property; /* initially set property */ - struct tagMSIFOLDER *Parent; - INT State; - /* 0 = uninitialized */ - /* 1 = existing */ - /* 2 = created remove if empty */ - /* 3 = created persist if empty */ - INT Cost; - INT Space; -} MSIFOLDER; - -typedef enum _msi_file_state { - msifs_invalid, - msifs_missing, - msifs_overwrite, - msifs_present, - msifs_installed, - msifs_skipped, -} msi_file_state; - -typedef struct tagMSIFILE -{ - struct list entry; - LPWSTR File; - MSICOMPONENT *Component; - LPWSTR FileName; - LPWSTR ShortName; - LPWSTR LongName; - INT FileSize; - LPWSTR Version; - LPWSTR Language; - INT Attributes; - INT Sequence; - msi_file_state state; - LPWSTR SourcePath; - LPWSTR TargetPath; - BOOL IsCompressed; -} MSIFILE; - -typedef struct tagMSITEMPFILE -{ - struct list entry; - LPWSTR File; - LPWSTR Path; -} MSITEMPFILE; - -typedef struct tagMSIAPPID -{ - struct list entry; - LPWSTR AppID; /* Primary key */ - LPWSTR RemoteServerName; - LPWSTR LocalServer; - LPWSTR ServiceParameters; - LPWSTR DllSurrogate; - BOOL ActivateAtStorage; - BOOL RunAsInteractiveUser; -} MSIAPPID; - -typedef struct tagMSIPROGID MSIPROGID; - -typedef struct tagMSICLASS -{ - struct list entry; - LPWSTR clsid; /* Primary Key */ - LPWSTR Context; /* Primary Key */ - MSICOMPONENT *Component; - MSIPROGID *ProgID; - LPWSTR ProgIDText; - LPWSTR Description; - MSIAPPID *AppID; - LPWSTR FileTypeMask; - LPWSTR IconPath; - LPWSTR DefInprocHandler; - LPWSTR DefInprocHandler32; - LPWSTR Argument; - MSIFEATURE *Feature; - INT Attributes; - /* not in the table, set during installation */ - BOOL Installed; -} MSICLASS; - -typedef struct tagMSIMIME MSIMIME; - -typedef struct tagMSIEXTENSION -{ - struct list entry; - LPWSTR Extension; /* Primary Key */ - MSICOMPONENT *Component; - MSIPROGID *ProgID; - LPWSTR ProgIDText; - MSIMIME *Mime; - MSIFEATURE *Feature; - /* not in the table, set during installation */ - BOOL Installed; - struct list verbs; -} MSIEXTENSION; - -struct tagMSIPROGID -{ - struct list entry; - LPWSTR ProgID; /* Primary Key */ - MSIPROGID *Parent; - MSICLASS *Class; - LPWSTR Description; - LPWSTR IconPath; - /* not in the table, set during installation */ - BOOL InstallMe; - MSIPROGID *CurVer; - MSIPROGID *VersionInd; -}; - -typedef struct tagMSIVERB -{ - struct list entry; - LPWSTR Verb; - INT Sequence; - LPWSTR Command; - LPWSTR Argument; -} MSIVERB; - -struct tagMSIMIME -{ - struct list entry; - LPWSTR ContentType; /* Primary Key */ - MSIEXTENSION *Extension; - LPWSTR clsid; - MSICLASS *Class; - /* not in the table, set during installation */ - BOOL InstallMe; -}; - -enum SCRIPTS { - INSTALL_SCRIPT = 0, - COMMIT_SCRIPT = 1, - ROLLBACK_SCRIPT = 2, - TOTAL_SCRIPTS = 3 -}; - -#define SEQUENCE_UI 0x1 -#define SEQUENCE_EXEC 0x2 -#define SEQUENCE_INSTALL 0x10 - -typedef struct tagMSISCRIPT -{ - LPWSTR *Actions[TOTAL_SCRIPTS]; - UINT ActionCount[TOTAL_SCRIPTS]; - BOOL ExecuteSequenceRun; - BOOL CurrentlyScripting; - UINT InWhatSequence; - LPWSTR *UniqueActions; - UINT UniqueActionsCount; -} MSISCRIPT; - - -extern UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force); -extern UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action); -extern void ACTION_FinishCustomActions( MSIPACKAGE* package); -extern UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action, BOOL execute); - -/* actions in other modules */ -extern UINT ACTION_AppSearch(MSIPACKAGE *package); -extern UINT ACTION_FindRelatedProducts(MSIPACKAGE *package); -extern UINT ACTION_InstallFiles(MSIPACKAGE *package); -extern UINT ACTION_RemoveFiles(MSIPACKAGE *package); -extern UINT ACTION_DuplicateFiles(MSIPACKAGE *package); -extern UINT ACTION_RegisterClassInfo(MSIPACKAGE *package); -extern UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package); -extern UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package); -extern UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package); -extern UINT ACTION_RegisterFonts(MSIPACKAGE *package); - - -/* Helpers */ -extern DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data ); -extern LPWSTR msi_dup_record_field(MSIRECORD *row, INT index); -extern LPWSTR msi_dup_property(MSIPACKAGE *package, LPCWSTR prop); -extern int msi_get_property_int( MSIPACKAGE *package, LPCWSTR prop, int def ); -extern LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, - BOOL set_prop, MSIFOLDER **folder); -extern MSICOMPONENT *get_loaded_component( MSIPACKAGE* package, LPCWSTR Component ); -extern MSIFEATURE *get_loaded_feature( MSIPACKAGE* package, LPCWSTR Feature ); -extern MSIFILE *get_loaded_file( MSIPACKAGE* package, LPCWSTR file ); -extern MSIFOLDER *get_loaded_folder( MSIPACKAGE *package, LPCWSTR dir ); -extern int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path); -extern UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action); -extern LPWSTR build_icon_path(MSIPACKAGE *, LPCWSTR); -extern LPWSTR build_directory_name(DWORD , ...); -extern BOOL create_full_pathW(const WCHAR *path); -extern BOOL ACTION_VerifyComponentForAction(MSICOMPONENT*, INSTALLSTATE); -extern BOOL ACTION_VerifyFeatureForAction(MSIFEATURE*, INSTALLSTATE); -extern void reduce_to_longfilename(WCHAR*); -extern void reduce_to_shortfilename(WCHAR*); -extern LPWSTR create_component_advertise_string(MSIPACKAGE*, MSICOMPONENT*, LPCWSTR); -extern void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature); -extern UINT register_unique_action(MSIPACKAGE *, LPCWSTR); -extern BOOL check_unique_action(MSIPACKAGE *, LPCWSTR); -extern WCHAR* generate_error_string(MSIPACKAGE *, UINT, DWORD, ... ); -extern UINT msi_create_component_directories( MSIPACKAGE *package ); - - -/* control event stuff */ -extern VOID ControlEvent_FireSubscribedEvent(MSIPACKAGE *package, LPCWSTR event, - MSIRECORD *data); -extern VOID ControlEvent_CleanupSubscriptions(MSIPACKAGE *package); -extern VOID ControlEvent_SubscribeToEvent(MSIPACKAGE *package, LPCWSTR event, - LPCWSTR control, LPCWSTR attribute); -extern VOID ControlEvent_UnSubscribeToEvent( MSIPACKAGE *package, LPCWSTR event, - LPCWSTR control, LPCWSTR attribute ); - -/* User Interface messages from the actions */ -extern void ui_progress(MSIPACKAGE *, int, int, int, int); -extern void ui_actiondata(MSIPACKAGE *, LPCWSTR, MSIRECORD *); - - -/* string consts use a number of places and defined in helpers.c*/ -extern const WCHAR cszSourceDir[]; -extern const WCHAR szProductCode[]; -extern const WCHAR cszRootDrive[]; -extern const WCHAR cszbs[]; - -#endif /* __MSI_ACTION_H__ */ diff --git a/reactos/dll/win32/msi/appsearch.c b/reactos/dll/win32/msi/appsearch.c index fa750f52c78..674169f3107 100644 --- a/reactos/dll/win32/msi/appsearch.c +++ b/reactos/dll/win32/msi/appsearch.c @@ -32,7 +32,6 @@ #include "wine/unicode.h" #include "wine/debug.h" #include "msipriv.h" -#include "action.h" WINE_DEFAULT_DEBUG_CHANNEL(msi); @@ -155,7 +154,7 @@ static UINT ACTION_AppSearchGetSignature(MSIPACKAGE *package, MSISIGNATURE *sig, TRACE("MaxVersion is %d.%d.%d.%d\n", HIWORD(sig->MaxVersionMS), LOWORD(sig->MaxVersionMS), HIWORD(sig->MaxVersionLS), LOWORD(sig->MaxVersionLS)); - TRACE("MinSize is %ld, MaxSize is %ld;\n", sig->MinSize, sig->MaxSize); + TRACE("MinSize is %d, MaxSize is %d;\n", sig->MinSize, sig->MaxSize); TRACE("Languages is %s\n", debugstr_w(sig->Languages)); end: @@ -255,7 +254,7 @@ static void ACTION_ConvertRegValue(DWORD regType, const BYTE *value, DWORD sz, switch (regType) { case REG_SZ: - if (*(LPWSTR)value == '#') + if (*(LPCWSTR)value == '#') { /* escape leading pound with another */ *appValue = msi_alloc(sz + sizeof(WCHAR)); @@ -287,7 +286,7 @@ static void ACTION_ConvertRegValue(DWORD regType, const BYTE *value, DWORD sz, sprintfW(*appValue + i * 3, binFmt, value[i]); break; default: - WARN("unimplemented for values of type %ld\n", regType); + WARN("unimplemented for values of type %d\n", regType); *appValue = NULL; } } @@ -398,6 +397,9 @@ static UINT ACTION_AppSearchReg(MSIPACKAGE *package, LPWSTR *appValue, rc = ACTION_SearchDirectory(package, sig, (LPCWSTR)value, 0, appValue); break; + case msidbLocatorTypeFileName: + *appValue = strdupW((LPCWSTR)value); + break; case msidbLocatorTypeRawValue: ACTION_ConvertRegValue(regType, value, sz, appValue); break; @@ -528,7 +530,10 @@ static void ACTION_ExpandAnyPath(MSIPACKAGE *package, WCHAR *src, WCHAR *dst, size_t copied = 0; if (!src || !dst || !len) + { + if (dst) *dst = '\0'; return; + } /* Ignore the short portion of the path, don't think we can use it anyway */ if ((ptr = strchrW(src, '|'))) @@ -913,7 +918,7 @@ static UINT ACTION_AppSearchDr(MSIPACKAGE *package, LPWSTR *appValue, msi_free(path); if (parent) { - path = msi_alloc(strlenW(parent) + strlenW(expanded) + 1); + path = msi_alloc((strlenW(parent) + strlenW(expanded) + 1) * sizeof(WCHAR)); if (!path) goto end; strcpyW(path, parent); @@ -991,7 +996,7 @@ UINT ACTION_AppSearch(MSIPACKAGE *package) while (!rc) { MSISIGNATURE sig; - LPWSTR value; + LPWSTR value = NULL; rc = MSI_ViewFetch(view,&row); if (rc != ERROR_SUCCESS) diff --git a/reactos/dll/win32/msi/classes.c b/reactos/dll/win32/msi/classes.c index 43e89579a86..d34534f9777 100644 --- a/reactos/dll/win32/msi/classes.c +++ b/reactos/dll/win32/msi/classes.c @@ -40,7 +40,6 @@ #include "msipriv.h" #include "winuser.h" #include "wine/unicode.h" -#include "action.h" WINE_DEFAULT_DEBUG_CHANNEL(msi); diff --git a/reactos/dll/win32/msi/cond.y b/reactos/dll/win32/msi/cond.y index dd8252ad171..9cfb00114fa 100644 --- a/reactos/dll/win32/msi/cond.y +++ b/reactos/dll/win32/msi/cond.y @@ -35,7 +35,6 @@ #include "msi.h" #include "msiquery.h" #include "msipriv.h" -#include "action.h" #define YYLEX_PARAM info #define YYPARSE_PARAM info diff --git a/reactos/dll/win32/msi/custom.c b/reactos/dll/win32/msi/custom.c index dad67a22824..a464dfede10 100644 --- a/reactos/dll/win32/msi/custom.c +++ b/reactos/dll/win32/msi/custom.c @@ -47,7 +47,6 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/summa #include "shlobj.h" #include "wine/unicode.h" #include "winver.h" -#include "action.h" WINE_DEFAULT_DEBUG_CHANNEL(msi); @@ -120,7 +119,7 @@ static BOOL check_execution_scheduling_options(MSIPACKAGE *package, LPCWSTR acti /* stores the CustomActionData before the action: * [CustomActionData]Action */ -LPWSTR msi_get_deferred_action(LPCWSTR action, LPWSTR actiondata) +static LPWSTR msi_get_deferred_action(LPCWSTR action, LPWSTR actiondata) { LPWSTR deferred; DWORD len; @@ -167,7 +166,10 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute) row = MSI_QueryGetRecord( package->db, ExecSeqQuery, action ); if (!row) + { + msi_free(action_copy); return ERROR_CALL_NOT_IMPLEMENTED; + } type = MSI_RecordGetInteger(row,2); @@ -382,7 +384,7 @@ static UINT process_action_return_value(UINT type, HANDLE ThreadHandle) case ERROR_NO_MORE_ITEMS: return ERROR_SUCCESS; default: - ERR("Invalid Return Code %ld\n",rc); + ERR("Invalid Return Code %d\n",rc); return ERROR_INSTALL_FAILURE; } } @@ -502,14 +504,13 @@ static DWORD WINAPI DllThread(LPVOID info) { thread_struct *stuff; DWORD rc = 0; - - TRACE("MSI Thread (0x%lx) started for custom action\n", - GetCurrentThreadId()); - + + TRACE("MSI Thread (%x) started for custom action\n", GetCurrentThreadId()); + stuff = (thread_struct*)info; rc = ACTION_CallDllFunction(stuff); - TRACE("MSI Thread (0x%lx) finished (rc %li)\n",GetCurrentThreadId(), rc); + TRACE("MSI Thread (%x) finished (rc %i)\n",GetCurrentThreadId(), rc); /* clse all handles for this thread */ MsiCloseAllHandles(); return rc; diff --git a/reactos/dll/win32/msi/database.c b/reactos/dll/win32/msi/database.c index d98461355a4..c36139e705a 100644 --- a/reactos/dll/win32/msi/database.c +++ b/reactos/dll/win32/msi/database.c @@ -28,6 +28,7 @@ #include "winreg.h" #include "winnls.h" #include "wine/debug.h" +#include "wine/unicode.h" #include "msi.h" #include "msiquery.h" #include "msipriv.h" @@ -58,12 +59,13 @@ static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg ) MSIDATABASE *db = (MSIDATABASE *) arg; DWORD r; + msi_free(db->path); free_cached_tables( db ); msi_free_transforms( db ); msi_destroy_stringtable( db->strings ); r = IStorage_Release( db->storage ); if( r ) - ERR("database reference count was not zero (%ld)\n", r); + ERR("database reference count was not zero (%d)\n", r); if (db->deletefile) { DeleteFileW( db->deletefile ); @@ -77,15 +79,19 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb) HRESULT r; MSIDATABASE *db = NULL; UINT ret = ERROR_FUNCTION_FAILED; - LPCWSTR szMode; + LPCWSTR szMode, save_path; STATSTG stat; BOOL created = FALSE; + WCHAR path[MAX_PATH]; + + static const WCHAR backslash[] = {'\\',0}; TRACE("%s %s\n",debugstr_w(szDBPath),debugstr_w(szPersist) ); if( !pdb ) return ERROR_INVALID_PARAMETER; + save_path = szDBPath; szMode = szPersist; if( HIWORD( szPersist ) ) { @@ -135,7 +141,7 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb) if( FAILED( r ) ) { - FIXME("open failed r = %08lx!\n",r); + FIXME("open failed r = %08x!\n",r); return ERROR_FUNCTION_FAILED; } @@ -162,6 +168,17 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb) goto end; } + if (!strchrW( save_path, '\\' )) + { + GetCurrentDirectoryW( MAX_PATH, path ); + lstrcatW( path, backslash ); + lstrcatW( path, save_path ); + } + else + lstrcpyW( path, save_path ); + + db->path = strdupW( path ); + if( TRACE_ON( msi ) ) enum_stream_names( stg ); @@ -245,14 +262,444 @@ end: return r; } -UINT MSI_DatabaseImport( MSIDATABASE *db, LPCWSTR folder, LPCWSTR file ) +static LPWSTR msi_read_text_archive(LPCWSTR path) { - FIXME("%p %s %s\n", db, debugstr_w(folder), debugstr_w(file) ); + HANDLE file; + LPSTR data = NULL; + LPWSTR wdata = NULL; + DWORD read, size = 0; + + file = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); + if (file == INVALID_HANDLE_VALUE) + return NULL; + + size = GetFileSize( file, NULL ); + data = msi_alloc( size + 1 ); + if (!data) + goto done; + + if (!ReadFile( file, data, size, &read, NULL )) + goto done; + + data[size] = '\0'; + wdata = strdupAtoW( data ); + +done: + CloseHandle( file ); + msi_free( data ); + return wdata; +} + +static void msi_parse_line(LPWSTR *line, LPWSTR **entries, DWORD *num_entries) +{ + LPWSTR ptr = *line, save; + DWORD i, count = 1; + + *entries = NULL; + + /* stay on this line */ + while (*ptr && *ptr != '\n') + { + /* entries are separated by tabs */ + if (*ptr == '\t') + count++; + + ptr++; + } + + *entries = msi_alloc(count * sizeof(LPWSTR)); + if (!*entries) + return; + + /* store pointers into the data */ + for (i = 0, ptr = *line; i < count; i++) + { + save = ptr; + + while (*ptr && *ptr != '\t' && *ptr != '\n') ptr++; + + /* NULL-separate the data */ + if (*ptr) + *ptr++ = '\0'; + + (*entries)[i] = save; + } + + /* move to the next line if there's more, else EOF */ + *line = ptr; + + if (num_entries) + *num_entries = count; +} + +static LPWSTR msi_build_createsql_prelude(LPWSTR table) +{ + LPWSTR prelude; + DWORD size; + + static const WCHAR create_fmt[] = {'C','R','E','A','T','E',' ','T','A','B','L','E',' ','`','%','s','`',' ','(',' ',0}; + + size = sizeof(create_fmt) + lstrlenW(table) - 2; + prelude = msi_alloc(size * sizeof(WCHAR)); + if (!prelude) + return NULL; + + sprintfW(prelude, create_fmt, table); + return prelude; +} + +static LPWSTR msi_build_createsql_columns(LPWSTR *columns_data, LPWSTR *types, DWORD num_columns) +{ + LPWSTR columns; + LPCWSTR type; + DWORD sql_size = 1, i, len; + WCHAR expanded[128], *ptr; + WCHAR size[10], comma[2], extra[10]; + + static const WCHAR column_fmt[] = {'`','%','s','`',' ','%','s','%','s','%','s','%','s',' ',0}; + static const WCHAR size_fmt[] = {'(','%','s',')',0}; + static const WCHAR type_char[] = {'C','H','A','R',0}; + static const WCHAR type_int[] = {'I','N','T',0}; + static const WCHAR type_long[] = {'L','O','N','G',0}; + static const WCHAR type_notnull[] = {' ','N','O','T',' ','N','U','L','L',0}; + + columns = msi_alloc_zero(sql_size * sizeof(WCHAR)); + if (!columns) + return NULL; + + for (i = 0; i < num_columns; i++) + { + type = NULL; + comma[1] = size[0] = extra[0] = '\0'; + + if (i == num_columns - 1) + comma[0] = '\0'; + else + comma[0] = ','; + + ptr = &types[i][1]; + len = atolW(ptr); + + switch (types[i][0]) + { + case 'l': case 's': + lstrcpyW(extra, type_notnull); + case 'L': case 'S': + type = type_char; + sprintfW(size, size_fmt, ptr); + break; + case 'i': + lstrcpyW(extra, type_notnull); + case 'I': + if (len == 2) + type = type_int; + else + type = type_long; + break; + } + + sprintfW(expanded, column_fmt, columns_data[i], type, size, extra, comma); + sql_size += lstrlenW(expanded); + + columns = msi_realloc(columns, sql_size * sizeof(WCHAR)); + if (!columns) + return NULL; + + lstrcatW(columns, expanded); + } + + return columns; +} + +static LPWSTR msi_build_createsql_postlude(LPWSTR *primary_keys, DWORD num_keys) +{ + LPWSTR postlude, keys, ptr; + DWORD size, key_size, i; + + static const WCHAR key_fmt[] = {'`','%','s','`',',',' ',0}; + static const WCHAR postlude_fmt[] = {'P','R','I','M','A','R','Y',' ','K','E','Y',' ','%','s',')',' ','H','O','L','D',0}; + + for (i = 0, size = 1; i < num_keys; i++) + size += lstrlenW(key_fmt) + lstrlenW(primary_keys[i]) - 2; + + keys = msi_alloc(size * sizeof(WCHAR)); + if (!keys) + return NULL; + + for (i = 0, ptr = keys; i < num_keys; i++) + { + key_size = lstrlenW(key_fmt) + lstrlenW(primary_keys[i]) -2; + sprintfW(ptr, key_fmt, primary_keys[i]); + ptr += key_size; + } + + /* remove final ', ' */ + *(ptr - 2) = '\0'; + + size = lstrlenW(postlude_fmt) + size - 1; + postlude = msi_alloc(size * sizeof(WCHAR)); + if (!postlude) + goto done; + + sprintfW(postlude, postlude_fmt, keys); + +done: + msi_free(keys); + return postlude; +} + +static UINT msi_add_table_to_db(MSIDATABASE *db, LPWSTR *columns, LPWSTR *types, LPWSTR *labels, DWORD num_labels, DWORD num_columns) +{ + UINT r; + DWORD size; + MSIQUERY *view; + LPWSTR create_sql; + LPWSTR prelude, columns_sql, postlude; + + prelude = msi_build_createsql_prelude(labels[0]); + columns_sql = msi_build_createsql_columns(columns, types, num_columns); + postlude = msi_build_createsql_postlude(labels + 1, num_labels - 1); /* skip over table name */ + + if (!prelude || !columns_sql || !postlude) + return ERROR_OUTOFMEMORY; + + size = lstrlenW(prelude) + lstrlenW(columns_sql) + lstrlenW(postlude) + 1; + create_sql = msi_alloc(size * sizeof(WCHAR)); + if (!create_sql) + return ERROR_OUTOFMEMORY; + + lstrcpyW(create_sql, prelude); + lstrcatW(create_sql, columns_sql); + lstrcatW(create_sql, postlude); + + msi_free(prelude); + msi_free(columns_sql); + msi_free(postlude); + + r = MSI_DatabaseOpenViewW( db, create_sql, &view ); + msi_free(create_sql); + + if (r != ERROR_SUCCESS) + return r; + + r = MSI_ViewExecute(view, NULL); + MSI_ViewClose(view); + msiobj_release(&view->hdr); + + return r; +} + +static LPWSTR msi_build_insertsql_prelude(LPWSTR table) +{ + LPWSTR prelude; + DWORD size; + + static const WCHAR insert_fmt[] = {'I','N','S','E','R','T',' ','I','N','T','O',' ','`','%','s','`',' ','(',' ',0}; + + size = sizeof(insert_fmt) + lstrlenW(table) - 2; + prelude = msi_alloc(size * sizeof(WCHAR)); + if (!prelude) + return NULL; + + sprintfW(prelude, insert_fmt, table); + return prelude; +} + +static LPWSTR msi_build_insertsql_columns(LPWSTR *columns_data, LPWSTR *types, DWORD num_columns) +{ + LPWSTR columns; + DWORD sql_size = 1, i; + WCHAR expanded[128]; + + static const WCHAR column_fmt[] = {'`','%','s','`',',',' ',0}; + + columns = msi_alloc_zero(sql_size * sizeof(WCHAR)); + if (!columns) + return NULL; + + for (i = 0; i < num_columns; i++) + { + sprintfW(expanded, column_fmt, columns_data[i]); + sql_size += lstrlenW(expanded); + + if (i == num_columns - 1) + { + sql_size -= 2; + expanded[lstrlenW(expanded) - 2] = '\0'; + } + + columns = msi_realloc(columns, sql_size * sizeof(WCHAR)); + if (!columns) + return NULL; + + lstrcatW(columns, expanded); + } + + return columns; +} + +static LPWSTR msi_build_insertsql_data(LPWSTR **records, LPWSTR *types, DWORD num_columns, DWORD irec) +{ + LPWSTR columns; + DWORD sql_size = 1, i; + WCHAR expanded[128]; + + static const WCHAR str_fmt[] = {'\'','%','s','\'',',',' ',0}; + static const WCHAR int_fmt[] = {'%','s',',',' ',0}; + static const WCHAR empty[] = {'\'','\'',',',' ',0}; + + columns = msi_alloc_zero(sql_size * sizeof(WCHAR)); + if (!columns) + return NULL; + + for (i = 0; i < num_columns; i++) + { + switch (types[i][0]) + { + case 'L': case 'l': case 'S': case 's': + sprintfW(expanded, str_fmt, records[irec][i]); + break; + case 'I': case 'i': + if (*records[0][i]) + sprintfW(expanded, int_fmt, records[irec][i]); + else + lstrcpyW(expanded, empty); + break; + default: + return NULL; + } + + if (i == num_columns - 1) + expanded[lstrlenW(expanded) - 2] = '\0'; + + sql_size += lstrlenW(expanded); + columns = msi_realloc(columns, sql_size * sizeof(WCHAR)); + if (!columns) + return NULL; + + lstrcatW(columns, expanded); + } + + return columns; +} + +static UINT msi_add_records_to_table(MSIDATABASE *db, LPWSTR *columns, LPWSTR *types, + LPWSTR *labels, LPWSTR **records, + int num_columns, int num_records) +{ + MSIQUERY *view; + LPWSTR insert_sql; + DWORD size, i; + UINT r = ERROR_SUCCESS; + + static const WCHAR mid[] = {' ',')',' ','V','A','L','U','E','S',' ','(',' ',0}; + static const WCHAR end[] = {' ',')',0}; + + LPWSTR prelude = msi_build_insertsql_prelude(labels[0]); + LPWSTR columns_sql = msi_build_insertsql_columns(columns, types, num_columns); + + for (i = 0; i < num_records; i++) + { + LPWSTR data = msi_build_insertsql_data(records, types, num_columns, i); + + size = lstrlenW(prelude) + lstrlenW(columns_sql) + sizeof(mid) + lstrlenW(data) + sizeof(end) - 1; + insert_sql = msi_alloc(size * sizeof(WCHAR)); + if (!insert_sql) + return ERROR_OUTOFMEMORY; + + lstrcpyW(insert_sql, prelude); + lstrcatW(insert_sql, columns_sql); + lstrcatW(insert_sql, mid); + lstrcatW(insert_sql, data); + lstrcatW(insert_sql, end); + + msi_free(data); + + r = MSI_DatabaseOpenViewW( db, insert_sql, &view ); + msi_free(insert_sql); + + if (r != ERROR_SUCCESS) + goto done; + + r = MSI_ViewExecute(view, NULL); + MSI_ViewClose(view); + msiobj_release(&view->hdr); + } + +done: + msi_free(prelude); + msi_free(columns_sql); + + return r; +} + +UINT MSI_DatabaseImport(MSIDATABASE *db, LPCWSTR folder, LPCWSTR file) +{ + UINT r; + DWORD len, i; + DWORD num_labels; + DWORD num_columns, num_records = 0; + LPWSTR *columns, *types, *labels; + LPWSTR path, ptr, data; + LPWSTR **records; + + static const WCHAR backslash[] = {'\\',0}; + + TRACE("%p %s %s\n", db, debugstr_w(folder), debugstr_w(file) ); if( folder == NULL || file == NULL ) return ERROR_INVALID_PARAMETER; - - return ERROR_CALL_NOT_IMPLEMENTED; + + len = lstrlenW(folder) + lstrlenW(backslash) + lstrlenW(file) + 1; + path = msi_alloc( len * sizeof(WCHAR) ); + if (!path) + return ERROR_OUTOFMEMORY; + + lstrcpyW( path, folder ); + lstrcatW( path, backslash ); + lstrcatW( path, file ); + + data = msi_read_text_archive( path ); + + ptr = data; + msi_parse_line( &ptr, &columns, &num_columns ); + msi_parse_line( &ptr, &types, NULL ); + msi_parse_line( &ptr, &labels, &num_labels ); + + records = msi_alloc(sizeof(LPWSTR *)); + if (!records) + return ERROR_OUTOFMEMORY; + + /* read in the table records */ + while (*ptr) + { + msi_parse_line( &ptr, &records[num_records], NULL ); + + num_records++; + records = msi_realloc(records, (num_records + 1) * sizeof(LPWSTR *)); + if (!records) + return ERROR_OUTOFMEMORY; + } + + r = msi_add_table_to_db( db, columns, types, labels, num_labels, num_columns ); + if (r != ERROR_SUCCESS) + goto done; + + r = msi_add_records_to_table( db, columns, types, labels, records, num_columns, num_records ); + +done: + msi_free(path); + msi_free(data); + msi_free(columns); + msi_free(types); + msi_free(labels); + + for (i = 0; i < num_records; i++) + msi_free(records[i]); + + msi_free(records); + + return r; } UINT WINAPI MsiDatabaseImportW(MSIHANDLE handle, LPCWSTR szFolder, LPCWSTR szFilename) diff --git a/reactos/dll/win32/msi/dialog.c b/reactos/dll/win32/msi/dialog.c index 0b63966435f..5c4ca26af69 100644 --- a/reactos/dll/win32/msi/dialog.c +++ b/reactos/dll/win32/msi/dialog.c @@ -42,8 +42,6 @@ #include "wine/debug.h" #include "wine/unicode.h" -#include "action.h" - WINE_DEFAULT_DEBUG_CHANNEL(msi); @@ -82,6 +80,7 @@ typedef struct msi_font_tag struct msi_dialog_tag { MSIPACKAGE *package; + msi_dialog *parent; msi_dialog_event_handler event_handler; BOOL finished; INT scale; @@ -144,6 +143,9 @@ static const WCHAR szListBox[] = { 'L','i','s','t','B','o','x',0 }; static const WCHAR szDirectoryCombo[] = { 'D','i','r','e','c','t','o','r','y','C','o','m','b','o',0 }; static const WCHAR szDirectoryList[] = { 'D','i','r','e','c','t','o','r','y','L','i','s','t',0 }; static const WCHAR szVolumeCostList[] = { 'V','o','l','u','m','e','C','o','s','t','L','i','s','t',0 }; +static const WCHAR szSelectionDescription[] = {'S','e','l','e','c','t','i','o','n','D','e','s','c','r','i','p','t','i','o','n',0}; +static const WCHAR szSelectionPath[] = {'S','e','l','e','c','t','i','o','n','P','a','t','h',0}; +static const WCHAR szProperty[] = {'P','r','o','p','e','r','t','y',0}; static UINT msi_dialog_checkbox_handler( msi_dialog *, msi_control *, WPARAM ); static void msi_dialog_checkbox_sync_state( msi_dialog *, msi_control * ); @@ -152,7 +154,7 @@ static UINT msi_dialog_edit_handler( msi_dialog *, msi_control *, WPARAM ); static UINT msi_dialog_radiogroup_handler( msi_dialog *, msi_control *, WPARAM param ); static UINT msi_dialog_evaluate_control_conditions( msi_dialog *dialog ); static LRESULT WINAPI MSIRadioGroup_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - +static MSIFEATURE *msi_seltree_get_selected_feature( msi_control *control ); /* dialog sequencing */ @@ -213,43 +215,62 @@ static LPWSTR msi_get_deformatted_field( MSIPACKAGE *package, MSIRECORD *rec, in static LPWSTR msi_dialog_dup_property( msi_dialog *dialog, LPCWSTR property, BOOL indirect ) { + LPWSTR prop = NULL; + if (!property) return NULL; if (indirect) - return msi_dup_property( dialog->package, property ); + prop = msi_dup_property( dialog->package, property ); - return strdupW( property ); + if (!prop) + prop = strdupW( property ); + + return prop; +} + +msi_dialog *msi_dialog_get_parent( msi_dialog *dialog ) +{ + return dialog->parent; +} + +LPWSTR msi_dialog_get_name( msi_dialog *dialog ) +{ + return dialog->name; } /* * msi_dialog_get_style * * Extract the {\style} string from the front of the text to display and - * update the pointer. + * update the pointer. Only the last style in a list is applied. */ static LPWSTR msi_dialog_get_style( LPCWSTR p, LPCWSTR *rest ) { - LPWSTR ret = NULL; - LPCWSTR q, i; + LPWSTR ret; + LPCWSTR q, i, first; DWORD len; + q = NULL; *rest = p; if( !p ) - return ret; - if( *p++ != '{' ) - return ret; - q = strchrW( p, '}' ); - if( !q ) - return ret; - if( *p == '\\' || *p == '&' ) - p++; + return NULL; + + while ((first = strchrW( p, '{' )) && (q = strchrW( first + 1, '}' ))) + { + p = first + 1; + if( *p == '\\' || *p == '&' ) + p++; + + /* little bit of sanity checking to stop us getting confused with RTF */ + for( i=p; ihwnd, text ); msi_free( font ); msi_dialog_check_messages( NULL ); @@ -558,10 +582,15 @@ void msi_dialog_handle_event( msi_dialog* dialog, LPCWSTR control, SendMessageW(ctrl->hwnd, PBM_SETPOS, 100*(ctrl->progress_current/ctrl->progress_max), 0); break; default: - ERR("Unknown progress message %ld\n", func); + ERR("Unknown progress message %d\n", func); break; } } + else if ( !lstrcmpW(attribute, szProperty) ) + { + MSIFEATURE *feature = msi_seltree_get_selected_feature( ctrl ); + MSI_SetPropertyW( dialog->package, ctrl->property, feature->Directory ); + } else { FIXME("Attribute %s not being set\n", debugstr_w(attribute)); @@ -588,7 +617,7 @@ static void msi_dialog_map_events(msi_dialog* dialog, LPCWSTR control) event = MSI_RecordGetString( row, 3 ); attribute = MSI_RecordGetString( row, 4 ); - ControlEvent_SubscribeToEvent( dialog->package, event, control, attribute ); + ControlEvent_SubscribeToEvent( dialog->package, dialog, event, control, attribute ); msiobj_release( &row->hdr ); } @@ -860,7 +889,7 @@ msi_richedit_stream_in( DWORD_PTR arg, LPBYTE buffer, LONG count, LONG *pcb ) *pcb = count; info->offset += count; - TRACE("%ld/%ld\n", info->offset, info->length); + TRACE("%d/%d\n", info->offset, info->length); return 0; } @@ -1078,7 +1107,7 @@ static UINT msi_dialog_edit_control( msi_dialog *dialog, MSIRECORD *rec ) /******************** Masked Edit ********************************************/ -#define MASK_MAX_GROUPS 10 +#define MASK_MAX_GROUPS 20 struct msi_mask_group { @@ -1443,8 +1472,8 @@ static void msi_dialog_update_pathedit( msi_dialog *dialog, msi_control *control indirect = control->attributes & msidbControlAttributesIndirect; prop = msi_dialog_dup_property( dialog, control->property, indirect ); + path = msi_dialog_dup_property( dialog, prop, TRUE ); - path = msi_dup_property( dialog->package, prop ); SetWindowTextW( control->hwnd, path ); SendMessageW( control->hwnd, EM_SETSEL, 0, -1 ); @@ -1645,19 +1674,24 @@ struct msi_selection_tree_info msi_dialog *dialog; HWND hwnd; WNDPROC oldproc; + HTREEITEM selected; }; static void msi_seltree_sync_item_state( HWND hwnd, MSIFEATURE *feature, HTREEITEM hItem ) { TVITEMW tvi; + DWORD index = feature->Action; TRACE("Feature %s -> %d %d %d\n", debugstr_w(feature->Title), feature->Installed, feature->Action, feature->ActionRequest); + if (index == INSTALLSTATE_UNKNOWN) + index = INSTALLSTATE_ABSENT; + tvi.mask = TVIF_STATE; tvi.hItem = hItem; - tvi.state = INDEXTOSTATEIMAGEMASK( feature->Action ); + tvi.state = INDEXTOSTATEIMAGEMASK( index ); tvi.stateMask = TVIS_STATEIMAGEMASK; SendMessageW( hwnd, TVM_SETITEMW, 0, (LPARAM) &tvi ); @@ -1700,8 +1734,9 @@ msi_seltree_feature_from_item( HWND hwnd, HTREEITEM hItem ) static LRESULT msi_seltree_menu( HWND hwnd, HTREEITEM hItem ) { + struct msi_selection_tree_info *info; MSIFEATURE *feature; - ComponentList *cl; + MSIPACKAGE *package; union { RECT rc; POINT pt[2]; @@ -1709,6 +1744,9 @@ msi_seltree_menu( HWND hwnd, HTREEITEM hItem ) } u; UINT r; + info = GetPropW(hwnd, szButtonData); + package = info->dialog->package; + feature = msi_seltree_feature_from_item( hwnd, hItem ); if (!feature) { @@ -1737,17 +1775,17 @@ msi_seltree_menu( HWND hwnd, HTREEITEM hItem ) /* update */ msi_seltree_sync_item_state( hwnd, feature, hItem ); - - /* update the feature's components */ - LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) - { - cl->component->Action = feature->Action; - cl->component->ActionRequest = feature->ActionRequest; - } + ACTION_UpdateComponentStates( package, feature->Feature ); return 0; } +static MSIFEATURE *msi_seltree_get_selected_feature( msi_control *control ) +{ + struct msi_selection_tree_info *info = GetPropW(control->hwnd, szButtonData); + return msi_seltree_feature_from_item( control->hwnd, info->selected ); +} + static LRESULT WINAPI MSISelectionTree_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { @@ -1788,9 +1826,10 @@ static void msi_seltree_add_child_features( MSIPACKAGE *package, HWND hwnd, LPCWSTR parent, HTREEITEM hParent ) { + struct msi_selection_tree_info *info = GetPropW( hwnd, szButtonData ); MSIFEATURE *feature; TVINSERTSTRUCTW tvis; - HTREEITEM hitem; + HTREEITEM hitem, hfirst = NULL; LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) { @@ -1814,6 +1853,9 @@ msi_seltree_add_child_features( MSIPACKAGE *package, HWND hwnd, if (!hitem) continue; + if (!hfirst) + hfirst = hitem; + msi_seltree_sync_item_state( hwnd, feature, hitem ); msi_seltree_add_child_features( package, hwnd, feature->Feature, hitem ); @@ -1822,6 +1864,10 @@ msi_seltree_add_child_features( MSIPACKAGE *package, HWND hwnd, if ( feature->Display % 2 != 0 ) SendMessageW( hwnd, TVM_EXPAND, TVE_EXPAND, (LPARAM) hitem ); } + + /* select the first item */ + SendMessageW( hwnd, TVM_SELECTITEM, TVGN_CARET | TVGN_DROPHILITE, (LPARAM) hfirst ); + info->selected = hfirst; } static void msi_seltree_create_imagelist( HWND hwnd ) @@ -1861,6 +1907,54 @@ static void msi_seltree_create_imagelist( HWND hwnd ) SendMessageW( hwnd, TVM_SETIMAGELIST, TVSIL_STATE, (LPARAM)himl ); } +static UINT msi_dialog_seltree_handler( msi_dialog *dialog, + msi_control *control, WPARAM param ) +{ + struct msi_selection_tree_info *info = GetPropW( control->hwnd, szButtonData ); + LPNMTREEVIEWW tv = (LPNMTREEVIEWW)param; + MSIRECORD *row, *rec; + MSIFOLDER *folder; + LPCWSTR dir; + UINT r = ERROR_SUCCESS; + + static const WCHAR select[] = { + 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','F','e','a','t','u','r','e','`',' ','W','H','E','R','E',' ', + '`','T','i','t','l','e','`',' ','=',' ','\'','%','s','\'',0 + }; + + if (tv->hdr.code != TVN_SELCHANGINGW) + return ERROR_SUCCESS; + + info->selected = tv->itemNew.hItem; + + row = MSI_QueryGetRecord( dialog->package->db, select, tv->itemNew.pszText ); + if (!row) + return ERROR_FUNCTION_FAILED; + + rec = MSI_CreateRecord( 1 ); + + MSI_RecordSetStringW( rec, 1, MSI_RecordGetString( row, 4 ) ); + ControlEvent_FireSubscribedEvent( dialog->package, szSelectionDescription, rec ); + + dir = MSI_RecordGetString( row, 7 ); + folder = get_loaded_folder( dialog->package, dir ); + if (!folder) + { + r = ERROR_FUNCTION_FAILED; + goto done; + } + + MSI_RecordSetStringW( rec, 1, folder->ResolvedTarget ); + ControlEvent_FireSubscribedEvent( dialog->package, szSelectionPath, rec ); + +done: + msiobj_release(&row->hdr); + msiobj_release(&rec->hdr); + + return r; +} + static UINT msi_dialog_selection_tree( msi_dialog *dialog, MSIRECORD *rec ) { msi_control *control; @@ -1874,7 +1968,6 @@ static UINT msi_dialog_selection_tree( msi_dialog *dialog, MSIRECORD *rec ) return ERROR_FUNCTION_FAILED; /* create the treeview control */ - prop = MSI_RecordGetString( rec, 9 ); style = TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT; style |= WS_GROUP | WS_VSCROLL; control = msi_dialog_add_control( dialog, rec, WC_TREEVIEWW, style ); @@ -1884,6 +1977,11 @@ static UINT msi_dialog_selection_tree( msi_dialog *dialog, MSIRECORD *rec ) return ERROR_FUNCTION_FAILED; } + control->handler = msi_dialog_seltree_handler; + control->attributes = MSI_RecordGetInteger( rec, 8 ); + prop = MSI_RecordGetString( rec, 9 ); + control->property = msi_dialog_dup_property( dialog, prop, FALSE ); + /* subclass */ info->dialog = dialog; info->hwnd = control->hwnd; @@ -1891,6 +1989,9 @@ static UINT msi_dialog_selection_tree( msi_dialog *dialog, MSIRECORD *rec ) (LONG_PTR)MSISelectionTree_WndProc ); SetPropW( control->hwnd, szButtonData, info ); + ControlEvent_SubscribeToEvent( dialog->package, dialog, + szSelectionPath, control->name, szProperty ); + /* initialize it */ msi_seltree_create_imagelist( control->hwnd ); msi_seltree_add_child_features( package, control->hwnd, NULL, NULL ); @@ -2070,7 +2171,7 @@ static void msi_dialog_update_directory_combo( msi_dialog *dialog, msi_control * indirect = control->attributes & msidbControlAttributesIndirect; prop = msi_dialog_dup_property( dialog, control->property, indirect ); - path = msi_dup_property( dialog->package, prop ); + path = msi_dialog_dup_property( dialog, prop, TRUE ); PathStripPathW( path ); PathRemoveBackslashW( path ); @@ -2127,7 +2228,7 @@ static void msi_dialog_update_directory_list( msi_dialog *dialog, msi_control *c indirect = control->attributes & msidbControlAttributesIndirect; prop = msi_dialog_dup_property( dialog, control->property, indirect ); - path = msi_dup_property( dialog->package, prop ); + path = msi_dialog_dup_property( dialog, prop, TRUE ); lstrcpyW( dir_spec, path ); lstrcatW( dir_spec, asterisk ); @@ -2167,8 +2268,7 @@ UINT msi_dialog_directorylist_up( msi_dialog *dialog ) control = msi_dialog_find_control_by_type( dialog, szDirectoryList ); indirect = control->attributes & msidbControlAttributesIndirect; prop = msi_dialog_dup_property( dialog, control->property, indirect ); - - path = msi_dup_property( dialog->package, prop ); + path = msi_dialog_dup_property( dialog, prop, TRUE ); /* strip off the last directory */ ptr = PathFindFileNameW( path ); @@ -2217,7 +2317,7 @@ static UINT msi_dialog_dirlist_handler( msi_dialog *dialog, indirect = control->attributes & msidbControlAttributesIndirect; prop = msi_dialog_dup_property( dialog, control->property, indirect ); - path = msi_dup_property( dialog->package, prop ); + path = msi_dialog_dup_property( dialog, prop, TRUE ); lstrcpyW( new_path, path ); lstrcatW( new_path, text ); @@ -2290,7 +2390,6 @@ static void msi_dialog_vcl_add_columns( msi_dialog *dialog, msi_control *control WCHAR num[10]; LVCOLUMNW lvc; DWORD count = 0; - LRESULT r; static const WCHAR zero[] = {'0',0}; static const WCHAR negative[] = {'-',0}; @@ -2316,20 +2415,20 @@ static void msi_dialog_vcl_add_columns( msi_dialog *dialog, msi_control *control if ( !strncmpW( num, negative, 1 ) || !str_is_number( num ) ) return; - lvc.mask = LVCF_FMT | LVCF_ORDER | LVCF_WIDTH | LVCF_TEXT; - lvc.iOrder = count; - lvc.pszText = msi_dialog_get_uitext( dialog, column_keys[count++] ); + ZeroMemory( &lvc, sizeof(lvc) ); + lvc.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM; lvc.cx = atolW( num ); - lvc.fmt = LVCFMT_LEFT; + lvc.pszText = msi_dialog_get_uitext( dialog, column_keys[count] ); - r = SendMessageW( control->hwnd, LVM_INSERTCOLUMNW, 0, (LPARAM)&lvc ); + SendMessageW( control->hwnd, LVM_INSERTCOLUMNW, count++, (LPARAM)&lvc ); msi_free( lvc.pszText ); - if ( r ) return; } } static void msi_dialog_vcl_add_drives( msi_dialog *dialog, msi_control *control ) { + ULARGE_INTEGER total, free; + WCHAR size_text[MAX_PATH]; LPWSTR drives, ptr; LVITEMW lvitem; DWORD size; @@ -2353,6 +2452,20 @@ static void msi_dialog_vcl_add_drives( msi_dialog *dialog, msi_control *control lvitem.cchTextMax = lstrlenW(ptr) + 1; SendMessageW( control->hwnd, LVM_INSERTITEMW, 0, (LPARAM)&lvitem ); + GetDiskFreeSpaceExW(ptr, &free, &total, NULL); + + StrFormatByteSizeW(total.QuadPart, size_text, MAX_PATH); + lvitem.iSubItem = 1; + lvitem.pszText = size_text; + lvitem.cchTextMax = lstrlenW(size_text) + 1; + SendMessageW( control->hwnd, LVM_SETITEMW, 0, (LPARAM)&lvitem ); + + StrFormatByteSizeW(free.QuadPart, size_text, MAX_PATH); + lvitem.iSubItem = 2; + lvitem.pszText = size_text; + lvitem.cchTextMax = lstrlenW(size_text) + 1; + SendMessageW( control->hwnd, LVM_SETITEMW, 0, (LPARAM)&lvitem ); + ptr += lstrlenW(ptr) + 1; i++; } @@ -2503,10 +2616,7 @@ static UINT msi_dialog_evaluate_control_conditions( msi_dialog *dialog ) /* query the Control table for all the elements of the control */ r = MSI_OpenQuery( package->db, &view, query, dialog->name ); if( r != ERROR_SUCCESS ) - { - ERR("query failed for dialog %s\n", debugstr_w(dialog->name)); - return ERROR_INVALID_PARAMETER; - } + return ERROR_SUCCESS; r = MSI_IterateRecords( view, 0, msi_dialog_set_control_condition, dialog ); msiobj_release( &view->hdr ); @@ -2621,7 +2731,7 @@ static void msi_dialog_adjust_dialog_pos( msi_dialog *dialog, MSIRECORD *rec, LP dialog->size.cx = sz.cx; dialog->size.cy = sz.cy; - TRACE("%lu %lu %lu %lu\n", pos->left, pos->top, pos->right, pos->bottom); + TRACE("%u %u %u %u\n", pos->left, pos->top, pos->right, pos->bottom); style = GetWindowLongPtrW( dialog->hwnd, GWL_STYLE ); AdjustWindowRect( pos, style, FALSE ); @@ -2776,6 +2886,38 @@ static UINT msi_dialog_control_event( MSIRECORD *rec, LPVOID param ) return ERROR_SUCCESS; } +struct rec_list +{ + struct list entry; + MSIRECORD *rec; +}; + +static UINT add_rec_to_list( MSIRECORD *rec, LPVOID param ) +{ + struct rec_list *add_rec; + struct list *records = (struct list *)param; + + msiobj_addref( &rec->hdr ); + + add_rec = msi_alloc( sizeof( *add_rec ) ); + if (!add_rec) + { + msiobj_release( &rec->hdr ); + return ERROR_OUTOFMEMORY; + } + + add_rec->rec = rec; + list_add_tail( records, &add_rec->entry ); + return ERROR_SUCCESS; +} + +static inline void remove_rec_from_list( struct rec_list *rec_entry ) +{ + msiobj_release( &rec_entry->rec->hdr ); + list_remove( &rec_entry->entry ); + msi_free( rec_entry ); +} + static UINT msi_dialog_button_handler( msi_dialog *dialog, msi_control *control, WPARAM param ) { @@ -2789,11 +2931,15 @@ static UINT msi_dialog_button_handler( msi_dialog *dialog, 'O','R','D','E','R',' ','B','Y',' ','`','O','r','d','e','r','i','n','g','`',0 }; MSIQUERY *view = NULL; + struct rec_list *rec_entry, *next; + struct list events; UINT r; if( HIWORD(param) != BN_CLICKED ) return ERROR_SUCCESS; + list_init( &events ); + r = MSI_OpenQuery( dialog->package->db, &view, query, dialog->name, control->name ); if( r != ERROR_SUCCESS ) @@ -2802,8 +2948,41 @@ static UINT msi_dialog_button_handler( msi_dialog *dialog, return 0; } - r = MSI_IterateRecords( view, 0, msi_dialog_control_event, dialog ); + r = MSI_IterateRecords( view, 0, add_rec_to_list, &events ); msiobj_release( &view->hdr ); + if (r != ERROR_SUCCESS) + goto done; + + /* handle all SetProperty events first */ + LIST_FOR_EACH_ENTRY_SAFE( rec_entry, next, &events, struct rec_list, entry ) + { + LPCWSTR event = MSI_RecordGetString( rec_entry->rec, 3 ); + + if ( event[0] != '[' ) + continue; + + r = msi_dialog_control_event( rec_entry->rec, dialog ); + remove_rec_from_list( rec_entry ); + + if ( r != ERROR_SUCCESS ) + goto done; + } + + /* handle all other events */ + LIST_FOR_EACH_ENTRY_SAFE( rec_entry, next, &events, struct rec_list, entry ) + { + r = msi_dialog_control_event( rec_entry->rec, dialog ); + remove_rec_from_list( rec_entry ); + + if ( r != ERROR_SUCCESS ) + goto done; + } + +done: + LIST_FOR_EACH_ENTRY_SAFE( rec_entry, next, &events, struct rec_list, entry ) + { + remove_rec_from_list( rec_entry ); + } return r; } @@ -2938,7 +3117,7 @@ static LRESULT msi_dialog_onnotify( msi_dialog *dialog, LPARAM param ) LPNMHDR nmhdr = (LPNMHDR) param; msi_control *control = msi_dialog_find_control_by_hwnd( dialog, nmhdr->hwndFrom ); - TRACE("%p %p", dialog, nmhdr->hwndFrom); + TRACE("%p %p\n", dialog, nmhdr->hwndFrom); if ( control && control->handler ) control->handler( dialog, control, param ); @@ -3045,8 +3224,9 @@ static LRESULT WINAPI MSIHiddenWindowProc( HWND hwnd, UINT msg, /* functions that interface to other modules within MSI */ -msi_dialog *msi_dialog_create( MSIPACKAGE* package, LPCWSTR szDialogName, - msi_dialog_event_handler event_handler ) +msi_dialog *msi_dialog_create( MSIPACKAGE* package, + LPCWSTR szDialogName, msi_dialog *parent, + msi_dialog_event_handler event_handler ) { MSIRECORD *rec = NULL; msi_dialog *dialog; @@ -3058,6 +3238,7 @@ msi_dialog *msi_dialog_create( MSIPACKAGE* package, LPCWSTR szDialogName, if( !dialog ) return NULL; strcpyW( dialog->name, szDialogName ); + dialog->parent = parent; msiobj_addref( &package->hdr ); dialog->package = package; dialog->event_handler = event_handler; diff --git a/reactos/dll/win32/msi/events.c b/reactos/dll/win32/msi/events.c index 72e521760dd..2b0397bf73c 100644 --- a/reactos/dll/win32/msi/events.c +++ b/reactos/dll/win32/msi/events.c @@ -32,7 +32,6 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/contr #include "winreg.h" #include "msi.h" #include "msipriv.h" -#include "action.h" #include "wine/debug.h" #include "wine/unicode.h" @@ -48,6 +47,7 @@ struct _events { struct subscriber { struct list entry; + msi_dialog *dialog; LPWSTR event; LPWSTR control; LPWSTR attribute; @@ -58,13 +58,13 @@ UINT ControlEvent_HandleControlEvent(MSIPACKAGE *, LPCWSTR, LPCWSTR, msi_dialog* /* * Create a dialog box and run it if it's modal */ -static UINT event_do_dialog( MSIPACKAGE *package, LPCWSTR name, BOOL destroy_modeless ) +static UINT event_do_dialog( MSIPACKAGE *package, LPCWSTR name, msi_dialog *parent, BOOL destroy_modeless ) { msi_dialog *dialog; UINT r; /* create a new dialog */ - dialog = msi_dialog_create( package, name, + dialog = msi_dialog_create( package, name, parent, ControlEvent_HandleControlEvent ); if( dialog ) { @@ -111,7 +111,12 @@ static UINT ControlEvent_EndDialog(MSIPACKAGE* package, LPCWSTR argument, else if (lstrcmpW(argument, szIgnore) == 0) package->CurrentInstallState = -1; else if (lstrcmpW(argument, szReturn) == 0) + { + msi_dialog *parent = msi_dialog_get_parent(dialog); + msi_free(package->next_dialog); + package->next_dialog = (parent) ? strdupW(msi_dialog_get_name(parent)) : NULL; package->CurrentInstallState = ERROR_SUCCESS; + } else { ERR("Unknown argument string %s\n",debugstr_w(argument)); @@ -143,7 +148,7 @@ static UINT ControlEvent_SpawnDialog(MSIPACKAGE* package, LPCWSTR argument, msi_dialog *dialog) { /* don't destroy a modeless dialogs that might be our parent */ - event_do_dialog( package, argument, FALSE ); + event_do_dialog( package, argument, dialog, FALSE ); if( package->CurrentInstallState != ERROR_SUCCESS ) msi_dialog_end_dialog( dialog ); return ERROR_SUCCESS; @@ -237,10 +242,18 @@ static UINT ControlEvent_SetTargetPath(MSIPACKAGE* package, LPCWSTR argument, msi_dialog* dialog) { LPWSTR path = msi_dup_property( package, argument ); + MSIRECORD *rec = MSI_CreateRecord( 1 ); UINT r; + + static const WCHAR szSelectionPath[] = {'S','e','l','e','c','t','i','o','n','P','a','t','h',0}; + + MSI_RecordSetStringW( rec, 1, path ); + ControlEvent_FireSubscribedEvent( package, szSelectionPath, rec ); + /* failure to set the path halts the executing of control events */ r = MSI_SetTargetPathW(package, argument, path); msi_free(path); + msi_free(&rec->hdr); return r; } @@ -262,14 +275,15 @@ static void free_subscriber( struct subscriber *sub ) msi_free(sub); } -VOID ControlEvent_SubscribeToEvent( MSIPACKAGE *package, LPCWSTR event, - LPCWSTR control, LPCWSTR attribute ) +VOID ControlEvent_SubscribeToEvent( MSIPACKAGE *package, msi_dialog *dialog, + LPCWSTR event, LPCWSTR control, LPCWSTR attribute ) { struct subscriber *sub; sub = msi_alloc(sizeof (*sub)); if( !sub ) return; + sub->dialog = dialog; sub->event = strdupW(event); sub->control = strdupW(control); sub->attribute = strdupW(attribute); @@ -304,14 +318,11 @@ VOID ControlEvent_FireSubscribedEvent( MSIPACKAGE *package, LPCWSTR event, TRACE("Firing Event %s\n",debugstr_w(event)); - if (!package->dialog) - return; - LIST_FOR_EACH_ENTRY( sub, &package->subscriptions, struct subscriber, entry ) { if (lstrcmpiW(sub->event, event)) continue; - msi_dialog_handle_event( package->dialog, sub->control, + msi_dialog_handle_event( sub->dialog, sub->control, sub->attribute, rec ); } } @@ -353,13 +364,13 @@ UINT ACTION_DialogBox( MSIPACKAGE* package, LPCWSTR szDialogName ) * dialog, as it returns ERROR_IO_PENDING when we try to run * its message loop. */ - r = event_do_dialog( package, szDialogName, TRUE ); + r = event_do_dialog( package, szDialogName, NULL, TRUE ); while( r == ERROR_SUCCESS && package->next_dialog ) { LPWSTR name = package->next_dialog; package->next_dialog = NULL; - r = event_do_dialog( package, name, TRUE ); + r = event_do_dialog( package, name, NULL, TRUE ); msi_free( name ); } @@ -398,6 +409,7 @@ static const struct _events Events[] = { { "Reset",ControlEvent_Reset }, { "SetInstallLevel",ControlEvent_SetInstallLevel }, { "DirectoryListUp",ControlEvent_DirectoryListUp }, + { "SelectionBrowse",ControlEvent_SpawnDialog }, { NULL,NULL }, }; diff --git a/reactos/dll/win32/msi/files.c b/reactos/dll/win32/msi/files.c index 81c5ac44bf1..99cc6b5565d 100644 --- a/reactos/dll/win32/msi/files.c +++ b/reactos/dll/win32/msi/files.c @@ -45,7 +45,6 @@ #include "winreg.h" #include "shlwapi.h" #include "wine/unicode.h" -#include "action.h" WINE_DEFAULT_DEBUG_CHANNEL(msi); @@ -58,8 +57,6 @@ extern const WCHAR szRemoveFiles[]; static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0}; -extern LPCWSTR msi_download_file( LPCWSTR szUrl, LPWSTR filename ); - /* * This is a helper function for handling embedded cabinet media */ @@ -96,7 +93,7 @@ static UINT writeout_cabinet_stream(MSIPACKAGE *package, LPCWSTR stream_name, WriteFile(the_file,data,size,&write,NULL); CloseHandle(the_file); - TRACE("wrote %li bytes to %s\n",write,debugstr_w(source)); + TRACE("wrote %i bytes to %s\n",write,debugstr_w(source)); end: msi_free(data); return rc; @@ -242,7 +239,7 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) NULL, CREATE_ALWAYS, attrs, NULL ); if ( handle == INVALID_HANDLE_VALUE ) { - ERR("failed to create %s (error %ld)\n", + ERR("failed to create %s (error %d)\n", debugstr_w( f->TargetPath ), GetLastError() ); return 0; } @@ -793,7 +790,7 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param) rc = ERROR_SUCCESS; if (rc != ERROR_SUCCESS) - ERR("Failed to copy file %s -> %s, last error %ld\n", + ERR("Failed to copy file %s -> %s, last error %d\n", debugstr_w(file->TargetPath), debugstr_w(dest_path), GetLastError()); FIXME("We should track these duplicate files as well\n"); diff --git a/reactos/dll/win32/msi/font.c b/reactos/dll/win32/msi/font.c index ce75520ddec..32dbbbe9687 100644 --- a/reactos/dll/win32/msi/font.c +++ b/reactos/dll/win32/msi/font.c @@ -26,7 +26,6 @@ #include "wine/debug.h" #include "msipriv.h" #include "wine/unicode.h" -#include "action.h" WINE_DEFAULT_DEBUG_CHANNEL(msi); diff --git a/reactos/dll/win32/msi/format.c b/reactos/dll/win32/msi/format.c index 290908947de..4cb802e2135 100644 --- a/reactos/dll/win32/msi/format.c +++ b/reactos/dll/win32/msi/format.c @@ -36,7 +36,6 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msifo #include "msipriv.h" #include "winnls.h" #include "wine/unicode.h" -#include "action.h" WINE_DEFAULT_DEBUG_CHANNEL(msi); @@ -471,7 +470,7 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, TRACE("after value %s\n", debugstr_wn((LPWSTR)newdata, size/sizeof(WCHAR))); chunk = (len - (progress - ptr)) * sizeof(WCHAR); - TRACE("after chunk is %li + %li\n",size,chunk); + TRACE("after chunk is %i + %i\n",size,chunk); if (size) nd2 = msi_realloc(newdata,(size+chunk)); else @@ -583,7 +582,7 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, if (value!=NULL) { LPBYTE nd2; - TRACE("value %s, chunk %li size %li\n",debugstr_w((LPWSTR)value), + TRACE("value %s, chunk %i size %i\n",debugstr_w((LPWSTR)value), chunk, size); if (size) nd2= msi_realloc(newdata,(size + chunk)); @@ -616,7 +615,7 @@ UINT MSI_FormatRecordW( MSIPACKAGE* package, MSIRECORD* record, LPWSTR buffer, DWORD len; UINT rc = ERROR_INVALID_PARAMETER; - TRACE("%p %p %p %li\n",package, record ,buffer, *size); + TRACE("%p %p %p %i\n", package, record ,buffer, *size); rec = msi_dup_record_field(record,0); if (!rec) @@ -663,7 +662,7 @@ UINT MSI_FormatRecordA( MSIPACKAGE* package, MSIRECORD* record, LPSTR buffer, DWORD len,lenA; UINT rc = ERROR_INVALID_PARAMETER; - TRACE("%p %p %p %li\n",package, record ,buffer, *size); + TRACE("%p %p %p %i\n", package, record ,buffer, *size); rec = msi_dup_record_field(record,0); if (!rec) diff --git a/reactos/dll/win32/msi/helpers.c b/reactos/dll/win32/msi/helpers.c index 9cf96ea476b..314b53ec00a 100644 --- a/reactos/dll/win32/msi/helpers.c +++ b/reactos/dll/win32/msi/helpers.c @@ -33,7 +33,7 @@ #include "msipriv.h" #include "winuser.h" #include "wine/unicode.h" -#include "action.h" +#include "msidefs.h" WINE_DEFAULT_DEBUG_CHANNEL(msi); @@ -41,6 +41,7 @@ static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0}; static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0}; const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0}; +const WCHAR cszSOURCEDIR[] = {'S','O','U','R','C','E','D','I','R',0}; const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0}; const WCHAR cszbs[]={'\\',0}; @@ -217,10 +218,14 @@ LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, if (!name) return NULL; + f = get_loaded_folder( package, name ); + if (!f) + return NULL; + /* special resolving for Target and Source root dir */ if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0) { - if (!source) + if (!f->ResolvedTarget && !f->Property) { LPWSTR check_path; check_path = msi_dup_property( package, cszTargetDir ); @@ -237,17 +242,13 @@ LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, if (strcmpiW(path,check_path)!=0) MSI_SetPropertyW(package,cszTargetDir,path); msi_free(check_path); - } - else - path = get_source_root( package ); - if (folder) - *folder = get_loaded_folder( package, name ); - return path; - } - f = get_loaded_folder( package, name ); - if (!f) - return NULL; + f->ResolvedTarget = path; + } + + if (!f->ResolvedSource) + f->ResolvedSource = get_source_root( package ); + } if (folder) *folder = f; @@ -405,6 +406,13 @@ static void free_feature( MSIFEATURE *feature ) { struct list *item, *cursor; + LIST_FOR_EACH_SAFE( item, cursor, &feature->Children ) + { + FeatureList *fl = LIST_ENTRY( item, FeatureList, entry ); + list_remove( &fl->entry ); + msi_free( fl ); + } + LIST_FOR_EACH_SAFE( item, cursor, &feature->Components ) { ComponentList *cl = LIST_ENTRY( item, ComponentList, entry ); @@ -419,7 +427,7 @@ static void free_feature( MSIFEATURE *feature ) msi_free( feature ); } -void free_extension( MSIEXTENSION *ext ) +static void free_extension( MSIEXTENSION *ext ) { struct list *item, *cursor; @@ -843,6 +851,9 @@ void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature) newstate = feature->ActionRequest; + if (newstate == INSTALLSTATE_ABSENT) + newstate = INSTALLSTATE_UNKNOWN; + LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) { MSICOMPONENT* component = cl->component; @@ -870,20 +881,43 @@ void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature) /*if any other feature wants is local we need to set it local*/ LIST_FOR_EACH_ENTRY( f, &package->features, MSIFEATURE, entry ) { - if ( component->ActionRequest != INSTALLSTATE_LOCAL ) - break; + if ( f->ActionRequest != INSTALLSTATE_LOCAL && + f->ActionRequest != INSTALLSTATE_SOURCE ) + { + continue; + } LIST_FOR_EACH_ENTRY( clist, &f->Components, ComponentList, entry ) { - if ( clist->component == component ) + if ( clist->component == component && + (f->ActionRequest == INSTALLSTATE_LOCAL || + f->ActionRequest == INSTALLSTATE_SOURCE) ) { - if (f->ActionRequest == INSTALLSTATE_LOCAL) + TRACE("Saved by %s\n", debugstr_w(f->Feature)); + + if (component->Attributes & msidbComponentAttributesOptional) { - TRACE("Saved by %s\n", debugstr_w(f->Feature)); - component->ActionRequest = INSTALLSTATE_LOCAL; - component->Action = INSTALLSTATE_LOCAL; + if (f->Attributes & msidbFeatureAttributesFavorSource) + { + component->Action = INSTALLSTATE_SOURCE; + component->ActionRequest = INSTALLSTATE_SOURCE; + } + else + { + component->Action = INSTALLSTATE_LOCAL; + component->ActionRequest = INSTALLSTATE_LOCAL; + } } - break; + else if (component->Attributes & msidbComponentAttributesSourceOnly) + { + component->Action = INSTALLSTATE_SOURCE; + component->ActionRequest = INSTALLSTATE_SOURCE; + } + else + { + component->Action = INSTALLSTATE_LOCAL; + component->ActionRequest = INSTALLSTATE_LOCAL; + } } } } diff --git a/reactos/dll/win32/msi/insert.c b/reactos/dll/win32/msi/insert.c index 2b0f68a70ca..33c915fe2de 100644 --- a/reactos/dll/win32/msi/insert.c +++ b/reactos/dll/win32/msi/insert.c @@ -78,7 +78,7 @@ static MSIRECORD *INSERT_merge_record( UINT fields, column_info *vl, MSIRECORD * switch( vl->val->type ) { case EXPR_SVAL: - TRACE("field %ld -> %s\n", i, debugstr_w(vl->val->u.sval)); + TRACE("field %d -> %s\n", i, debugstr_w(vl->val->u.sval)); MSI_RecordSetStringW( merged, i, vl->val->u.sval ); break; case EXPR_IVAL: diff --git a/reactos/dll/win32/msi/install.c b/reactos/dll/win32/msi/install.c index e02c307bd56..63b1d64d71e 100644 --- a/reactos/dll/win32/msi/install.c +++ b/reactos/dll/win32/msi/install.c @@ -30,7 +30,6 @@ #include "msi.h" #include "msidefs.h" #include "msipriv.h" -#include "action.h" #include "wine/unicode.h" WINE_DEFAULT_DEBUG_CHANNEL(msi); @@ -138,7 +137,7 @@ UINT msi_strcpy_to_awstring( LPCWSTR str, awstring *awbuf, DWORD *sz ) if (len) len--; WideCharToMultiByte( CP_ACP, 0, str, -1, awbuf->str.a, *sz, NULL, NULL ); - if ( *sz && (len >= *sz) ) + if ( awbuf->str.a && *sz && (len >= *sz) ) awbuf->str.a[*sz - 1] = 0; } @@ -151,8 +150,8 @@ UINT msi_strcpy_to_awstring( LPCWSTR str, awstring *awbuf, DWORD *sz ) /*********************************************************************** * MsiGetTargetPath (internal) */ -UINT WINAPI MSI_GetTargetPath( MSIHANDLE hInstall, LPCWSTR szFolder, - awstring *szPathBuf, DWORD* pcchPathBuf ) +static UINT WINAPI MSI_GetTargetPath( MSIHANDLE hInstall, LPCWSTR szFolder, + awstring *szPathBuf, DWORD* pcchPathBuf ) { MSIPACKAGE *package; LPWSTR path; diff --git a/reactos/dll/win32/msi/msi.c b/reactos/dll/win32/msi/msi.c index 11bc415bf33..d7185096ad3 100644 --- a/reactos/dll/win32/msi/msi.c +++ b/reactos/dll/win32/msi/msi.c @@ -40,7 +40,6 @@ #include "shobjidl.h" #include "objidl.h" #include "wine/unicode.h" -#include "action.h" WINE_DEFAULT_DEBUG_CHANNEL(msi); @@ -151,7 +150,7 @@ UINT WINAPI MsiAdvertiseProductW(LPCWSTR szPackagePath, LPCWSTR szScriptfilePath UINT WINAPI MsiAdvertiseProductExA(LPCSTR szPackagePath, LPCSTR szScriptfilePath, LPCSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions) { - FIXME("%s %s %s %08x %08lx %08lx\n", debugstr_a(szPackagePath), + FIXME("%s %s %s %08x %08x %08x\n", debugstr_a(szPackagePath), debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage, dwPlatform, dwOptions); return ERROR_CALL_NOT_IMPLEMENTED; @@ -160,7 +159,7 @@ UINT WINAPI MsiAdvertiseProductExA(LPCSTR szPackagePath, LPCSTR szScriptfilePath UINT WINAPI MsiAdvertiseProductExW( LPCWSTR szPackagePath, LPCWSTR szScriptfilePath, LPCWSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions) { - FIXME("%s %s %s %08x %08lx %08lx\n", debugstr_w(szPackagePath), + FIXME("%s %s %s %08x %08x %08x\n", debugstr_w(szPackagePath), debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage, dwPlatform, dwOptions); return ERROR_CALL_NOT_IMPLEMENTED; @@ -215,13 +214,13 @@ UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine) UINT WINAPI MsiReinstallProductA(LPCSTR szProduct, DWORD dwReinstallMode) { - FIXME("%s %08lx\n", debugstr_a(szProduct), dwReinstallMode); + FIXME("%s %08x\n", debugstr_a(szProduct), dwReinstallMode); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiReinstallProductW(LPCWSTR szProduct, DWORD dwReinstallMode) { - FIXME("%s %08lx\n", debugstr_w(szProduct), dwReinstallMode); + FIXME("%s %08x\n", debugstr_w(szProduct), dwReinstallMode); return ERROR_CALL_NOT_IMPLEMENTED; } @@ -432,8 +431,8 @@ UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer) return ERROR_SUCCESS; } -UINT WINAPI MSI_GetProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, - awstring *szValue, DWORD *pcchValueBuf) +static UINT WINAPI MSI_GetProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, + awstring *szValue, DWORD *pcchValueBuf) { UINT r; HKEY hkey; @@ -590,7 +589,7 @@ UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes) LPWSTR szwLogFile = NULL; UINT r; - TRACE("%08lx %s %08lx\n", dwLogMode, debugstr_a(szLogFile), attributes); + TRACE("%08x %s %08x\n", dwLogMode, debugstr_a(szLogFile), attributes); if( szLogFile ) { @@ -607,7 +606,7 @@ UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes) { HANDLE file = INVALID_HANDLE_VALUE; - TRACE("%08lx %s %08lx\n", dwLogMode, debugstr_w(szLogFile), attributes); + TRACE("%08x %s %08x\n", dwLogMode, debugstr_w(szLogFile), attributes); if (szLogFile) { @@ -709,7 +708,7 @@ INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler, { INSTALLUI_HANDLERA prev = gUIHandlerA; - TRACE("%p %lx %p\n",puiHandler, dwMessageFilter,pvContext); + TRACE("%p %x %p\n",puiHandler, dwMessageFilter,pvContext); gUIHandlerA = puiHandler; gUIFilter = dwMessageFilter; gUIContext = pvContext; @@ -722,7 +721,7 @@ INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler, { INSTALLUI_HANDLERW prev = gUIHandlerW; - TRACE("%p %lx %p\n",puiHandler,dwMessageFilter,pvContext); + TRACE("%p %x %p\n",puiHandler,dwMessageFilter,pvContext); gUIHandlerW = puiHandler; gUIFilter = dwMessageFilter; gUIContext = pvContext; @@ -848,16 +847,16 @@ INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf, UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType, WORD wLanguageId, DWORD f) { - FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_a(lpText),debugstr_a(lpCaption), - uType,wLanguageId,f); + FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_a(lpText), debugstr_a(lpCaption), + uType, wLanguageId, f); return MessageBoxExA(hWnd,lpText,lpCaption,uType,wLanguageId); } UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType, WORD wLanguageId, DWORD f) { - FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_w(lpText),debugstr_w(lpCaption), - uType,wLanguageId,f); + FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_w(lpText), debugstr_w(lpCaption), + uType, wLanguageId, f); return MessageBoxExW(hWnd,lpText,lpCaption,uType,wLanguageId); } @@ -865,7 +864,7 @@ UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext, DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf, DWORD* pcchPathBuf ) { - FIXME("%s %s %08lx %08lx %p %p\n", debugstr_a(szAssemblyName), + FIXME("%s %s %08x %08x %p %p\n", debugstr_a(szAssemblyName), debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf, pcchPathBuf); return ERROR_CALL_NOT_IMPLEMENTED; @@ -875,7 +874,7 @@ UINT WINAPI MsiProvideAssemblyW( LPCWSTR szAssemblyName, LPCWSTR szAppContext, DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf, DWORD* pcchPathBuf ) { - FIXME("%s %s %08lx %08lx %p %p\n", debugstr_w(szAssemblyName), + FIXME("%s %s %08x %08x %p %p\n", debugstr_w(szAssemblyName), debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf, pcchPathBuf); return ERROR_CALL_NOT_IMPLEMENTED; @@ -899,7 +898,7 @@ HRESULT WINAPI MsiGetFileSignatureInformationA( LPCSTR szSignedObjectPath, DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData, DWORD* pcbHashData) { - FIXME("%s %08lx %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags, + FIXME("%s %08x %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags, ppcCertContext, pbHashData, pcbHashData); return ERROR_CALL_NOT_IMPLEMENTED; } @@ -908,7 +907,7 @@ HRESULT WINAPI MsiGetFileSignatureInformationW( LPCWSTR szSignedObjectPath, DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData, DWORD* pcbHashData) { - FIXME("%s %08lx %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags, + FIXME("%s %08x %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags, ppcCertContext, pbHashData, pcbHashData); return ERROR_CALL_NOT_IMPLEMENTED; } @@ -961,8 +960,8 @@ UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage ) return r; } -INSTALLSTATE WINAPI MSI_GetComponentPath(LPCWSTR szProduct, LPCWSTR szComponent, - awstring* lpPathBuf, DWORD* pcchBuf) +static INSTALLSTATE WINAPI MSI_GetComponentPath(LPCWSTR szProduct, LPCWSTR szComponent, + awstring* lpPathBuf, DWORD* pcchBuf) { WCHAR squished_pc[GUID_SIZE], squished_comp[GUID_SIZE]; UINT rc; @@ -1244,7 +1243,7 @@ UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf, UINT puLen; WCHAR tmp[32]; - TRACE("%s %p %ld %p %ld\n", debugstr_w(szFilePath), + TRACE("%s %p %d %p %d\n", debugstr_w(szFilePath), lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0, lpLangBuf, pcchLangBuf?*pcchLangBuf:0); @@ -1345,7 +1344,7 @@ INSTALLSTATE WINAPI MsiUseFeatureExW( LPCWSTR szProduct, LPCWSTR szFeature, { INSTALLSTATE state; - TRACE("%s %s %li %li\n", debugstr_w(szProduct), debugstr_w(szFeature), + TRACE("%s %s %i %i\n", debugstr_w(szProduct), debugstr_w(szFeature), dwInstallMode, dwReserved); state = MsiQueryFeatureStateW( szProduct, szFeature ); @@ -1371,7 +1370,7 @@ INSTALLSTATE WINAPI MsiUseFeatureExA( LPCSTR szProduct, LPCSTR szFeature, INSTALLSTATE ret = INSTALLSTATE_UNKNOWN; LPWSTR prod = NULL, feat = NULL; - TRACE("%s %s %li %li\n", debugstr_a(szProduct), debugstr_a(szFeature), + TRACE("%s %s %i %i\n", debugstr_a(szProduct), debugstr_a(szFeature), dwInstallMode, dwReserved); prod = strdupAtoW( szProduct ); @@ -1410,7 +1409,7 @@ INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature ) /*********************************************************************** * MSI_ProvideQualifiedComponentEx [internal] */ -UINT WINAPI MSI_ProvideQualifiedComponentEx(LPCWSTR szComponent, +static UINT WINAPI MSI_ProvideQualifiedComponentEx(LPCWSTR szComponent, LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR szProduct, DWORD Unused1, DWORD Unused2, awstring *lpPathBuf, DWORD* pcchPathBuf) @@ -1422,7 +1421,7 @@ UINT WINAPI MSI_ProvideQualifiedComponentEx(LPCWSTR szComponent, DWORD sz; UINT rc; - TRACE("%s %s %li %s %li %li %p %p\n", debugstr_w(szComponent), + TRACE("%s %s %i %s %i %i %p %p\n", debugstr_w(szComponent), debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct), Unused1, Unused2, lpPathBuf, pcchPathBuf); @@ -1480,7 +1479,7 @@ UINT WINAPI MsiProvideQualifiedComponentExA(LPCSTR szComponent, UINT r = ERROR_OUTOFMEMORY; awstring path; - TRACE("%s %s %lu %s %lu %lu %p %p\n", debugstr_a(szComponent), + TRACE("%s %s %u %s %u %u %p %p\n", debugstr_a(szComponent), debugstr_a(szQualifier), dwInstallMode, debugstr_a(szProduct), Unused1, Unused2, lpPathBuf, pcchPathBuf); @@ -1535,7 +1534,7 @@ UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent, /*********************************************************************** * MSI_GetUserInfo [internal] */ -USERINFOSTATE WINAPI MSI_GetUserInfo(LPCWSTR szProduct, +static USERINFOSTATE WINAPI MSI_GetUserInfo(LPCWSTR szProduct, awstring *lpUserNameBuf, DWORD* pcchUserNameBuf, awstring *lpOrgNameBuf, DWORD* pcchOrgNameBuf, awstring *lpSerialBuf, DWORD* pcchSerialBuf) @@ -1775,11 +1774,11 @@ UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved) { WCHAR path[MAX_PATH]; - TRACE("%ld\n", dwReserved); + TRACE("%d\n", dwReserved); if (dwReserved) { - FIXME("dwReserved=%ld\n", dwReserved); + FIXME("dwReserved=%d\n", dwReserved); return ERROR_INVALID_PARAMETER; } @@ -1896,7 +1895,7 @@ UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature, LPWSTR ptr; DWORD sz; - FIXME("%s %s %li\n", debugstr_w(szProduct), debugstr_w(szFeature), + FIXME("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature), dwReinstallMode); ptr = reinstallmode; @@ -1960,7 +1959,7 @@ UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature, LPWSTR wszFeature; UINT rc; - TRACE("%s %s %li\n", debugstr_a(szProduct), debugstr_a(szFeature), + TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), dwReinstallMode); wszProduct = strdupAtoW(szProduct); @@ -1996,7 +1995,7 @@ UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions, DWORD length; UINT r = ERROR_FUNCTION_FAILED; - TRACE("%s %08lx %p\n", debugstr_w(szFilePath), dwOptions, pHash ); + TRACE("%s %08x %p\n", debugstr_w(szFilePath), dwOptions, pHash ); if (dwOptions) return ERROR_INVALID_PARAMETER; @@ -2044,7 +2043,7 @@ UINT WINAPI MsiGetFileHashA( LPCSTR szFilePath, DWORD dwOptions, LPWSTR file; UINT r; - TRACE("%s %08lx %p\n", debugstr_a(szFilePath), dwOptions, pHash ); + TRACE("%s %08x %p\n", debugstr_a(szFilePath), dwOptions, pHash ); file = strdupAtoW( szFilePath ); if (szFilePath && !file) @@ -2061,7 +2060,7 @@ UINT WINAPI MsiGetFileHashA( LPCSTR szFilePath, DWORD dwOptions, UINT WINAPI MsiAdvertiseScriptW( LPCWSTR szScriptFile, DWORD dwFlags, PHKEY phRegData, BOOL fRemoveItems ) { - FIXME("%s %08lx %p %d\n", + FIXME("%s %08x %p %d\n", debugstr_w( szScriptFile ), dwFlags, phRegData, fRemoveItems ); return ERROR_CALL_NOT_IMPLEMENTED; } @@ -2072,7 +2071,7 @@ UINT WINAPI MsiAdvertiseScriptW( LPCWSTR szScriptFile, DWORD dwFlags, UINT WINAPI MsiAdvertiseScriptA( LPCSTR szScriptFile, DWORD dwFlags, PHKEY phRegData, BOOL fRemoveItems ) { - FIXME("%s %08lx %p %d\n", + FIXME("%s %08x %p %d\n", debugstr_a( szScriptFile ), dwFlags, phRegData, fRemoveItems ); return ERROR_CALL_NOT_IMPLEMENTED; } diff --git a/reactos/dll/win32/msi/msi.rc b/reactos/dll/win32/msi/msi.rc index 9199accb31a..822a531e446 100644 --- a/reactos/dll/win32/msi/msi.rc +++ b/reactos/dll/win32/msi/msi.rc @@ -43,6 +43,8 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL #include "msi_Ru.rc" #include "msi_Tr.rc" +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL + /* BINRES instadvert.bmp */ 0x1001 BITMAP instadvert.bmp /* { diff --git a/reactos/dll/win32/msi/msi_Es.rc b/reactos/dll/win32/msi/msi_Es.rc index 3f33ea38218..94bfaf55e00 100644 --- a/reactos/dll/win32/msi/msi_Es.rc +++ b/reactos/dll/win32/msi/msi_Es.rc @@ -1,7 +1,7 @@ /* * Spanish resources for MSI * - * Copyright 2005 José Manuel Ferrer Ortiz + * Copyright 2005, 2006 José Manuel Ferrer Ortiz * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,7 +22,7 @@ LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL STRINGTABLE DISCARDABLE { - 4 "The specified installation package could not be opened. Please check the file path and try again." + 4 "No se ha podido abrir el paquete de instalación especificado. Por favor, compruebe la ruta del archivo y vuelva a intentarlo." 5 "ruta %s no encontrada" 9 "inserte el disco %s" 10 "parámetros incorrectos" diff --git a/reactos/dll/win32/msi/msi_Ko.rc b/reactos/dll/win32/msi/msi_Ko.rc index 3628e45a44e..100a98e8caf 100644 --- a/reactos/dll/win32/msi/msi_Ko.rc +++ b/reactos/dll/win32/msi/msi_Ko.rc @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT +LANGUAGE LANG_KOREAN, SUBLANG_NEUTRAL STRINGTABLE DISCARDABLE { diff --git a/reactos/dll/win32/msi/msipriv.h b/reactos/dll/win32/msi/msipriv.h index a10be59e955..94edb234020 100644 --- a/reactos/dll/win32/msi/msipriv.h +++ b/reactos/dll/win32/msi/msipriv.h @@ -2,6 +2,7 @@ * Implementation of the Microsoft Installer (msi.dll) * * Copyright 2002-2005 Mike McCormack for CodeWeavers + * Copyright 2005 Aric Stewart for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -71,6 +72,7 @@ typedef struct tagMSIDATABASE MSIOBJECTHDR hdr; IStorage *storage; string_table *strings; + LPWSTR path; LPWSTR deletefile; LPCWSTR mode; struct list tables; @@ -115,7 +117,7 @@ typedef struct tagMSIVIEWOPS * fetch_int - reads one integer from {row,col} in the table * * This function should be called after the execute method. - * Data returned by the function should not change until + * Data returned by the function should not change until * close or delete is called. * To get a string value, query the database's string table with * the integer value returned from this function. @@ -182,7 +184,7 @@ typedef struct tagMSIVIEWOPS /* * find_matching_rows - iterates through rows that match a value * - * If the column type is a string then a string ID should be passed in. + * If the column type is a string then a string ID should be passed in. * If the value to be looked up is an integer then no transformation of * the input value is required, except if the column is a string, in which * case a string ID should be passed in. @@ -259,6 +261,221 @@ typedef struct tagMSISUMMARYINFO PROPVARIANT property[MSI_MAX_PROPS]; } MSISUMMARYINFO; +typedef struct tagMSIFEATURE +{ + struct list entry; + LPWSTR Feature; + LPWSTR Feature_Parent; + LPWSTR Title; + LPWSTR Description; + INT Display; + INT Level; + LPWSTR Directory; + INT Attributes; + INSTALLSTATE Installed; + INSTALLSTATE ActionRequest; + INSTALLSTATE Action; + struct list Children; + struct list Components; + INT Cost; +} MSIFEATURE; + +typedef struct tagMSICOMPONENT +{ + struct list entry; + DWORD magic; + LPWSTR Component; + LPWSTR ComponentId; + LPWSTR Directory; + INT Attributes; + LPWSTR Condition; + LPWSTR KeyPath; + INSTALLSTATE Installed; + INSTALLSTATE ActionRequest; + INSTALLSTATE Action; + BOOL ForceLocalState; + BOOL Enabled; + INT Cost; + INT RefCount; + LPWSTR FullKeypath; + LPWSTR AdvertiseString; +} MSICOMPONENT; + +typedef struct tagComponentList +{ + struct list entry; + MSICOMPONENT *component; +} ComponentList; + +typedef struct tagFeatureList +{ + struct list entry; + MSIFEATURE *feature; +} FeatureList; + +typedef struct tagMSIFOLDER +{ + struct list entry; + LPWSTR Directory; + LPWSTR TargetDefault; + LPWSTR SourceLongPath; + LPWSTR SourceShortPath; + + LPWSTR ResolvedTarget; + LPWSTR ResolvedSource; + LPWSTR Property; /* initially set property */ + struct tagMSIFOLDER *Parent; + INT State; + /* 0 = uninitialized */ + /* 1 = existing */ + /* 2 = created remove if empty */ + /* 3 = created persist if empty */ + INT Cost; + INT Space; +} MSIFOLDER; + +typedef enum _msi_file_state { + msifs_invalid, + msifs_missing, + msifs_overwrite, + msifs_present, + msifs_installed, + msifs_skipped, +} msi_file_state; + +typedef struct tagMSIFILE +{ + struct list entry; + LPWSTR File; + MSICOMPONENT *Component; + LPWSTR FileName; + LPWSTR ShortName; + LPWSTR LongName; + INT FileSize; + LPWSTR Version; + LPWSTR Language; + INT Attributes; + INT Sequence; + msi_file_state state; + LPWSTR SourcePath; + LPWSTR TargetPath; + BOOL IsCompressed; +} MSIFILE; + +typedef struct tagMSITEMPFILE +{ + struct list entry; + LPWSTR File; + LPWSTR Path; +} MSITEMPFILE; + +typedef struct tagMSIAPPID +{ + struct list entry; + LPWSTR AppID; /* Primary key */ + LPWSTR RemoteServerName; + LPWSTR LocalServer; + LPWSTR ServiceParameters; + LPWSTR DllSurrogate; + BOOL ActivateAtStorage; + BOOL RunAsInteractiveUser; +} MSIAPPID; + +typedef struct tagMSIPROGID MSIPROGID; + +typedef struct tagMSICLASS +{ + struct list entry; + LPWSTR clsid; /* Primary Key */ + LPWSTR Context; /* Primary Key */ + MSICOMPONENT *Component; + MSIPROGID *ProgID; + LPWSTR ProgIDText; + LPWSTR Description; + MSIAPPID *AppID; + LPWSTR FileTypeMask; + LPWSTR IconPath; + LPWSTR DefInprocHandler; + LPWSTR DefInprocHandler32; + LPWSTR Argument; + MSIFEATURE *Feature; + INT Attributes; + /* not in the table, set during installation */ + BOOL Installed; +} MSICLASS; + +typedef struct tagMSIMIME MSIMIME; + +typedef struct tagMSIEXTENSION +{ + struct list entry; + LPWSTR Extension; /* Primary Key */ + MSICOMPONENT *Component; + MSIPROGID *ProgID; + LPWSTR ProgIDText; + MSIMIME *Mime; + MSIFEATURE *Feature; + /* not in the table, set during installation */ + BOOL Installed; + struct list verbs; +} MSIEXTENSION; + +struct tagMSIPROGID +{ + struct list entry; + LPWSTR ProgID; /* Primary Key */ + MSIPROGID *Parent; + MSICLASS *Class; + LPWSTR Description; + LPWSTR IconPath; + /* not in the table, set during installation */ + BOOL InstallMe; + MSIPROGID *CurVer; + MSIPROGID *VersionInd; +}; + +typedef struct tagMSIVERB +{ + struct list entry; + LPWSTR Verb; + INT Sequence; + LPWSTR Command; + LPWSTR Argument; +} MSIVERB; + +struct tagMSIMIME +{ + struct list entry; + LPWSTR ContentType; /* Primary Key */ + MSIEXTENSION *Extension; + LPWSTR clsid; + MSICLASS *Class; + /* not in the table, set during installation */ + BOOL InstallMe; +}; + +enum SCRIPTS { + INSTALL_SCRIPT = 0, + COMMIT_SCRIPT = 1, + ROLLBACK_SCRIPT = 2, + TOTAL_SCRIPTS = 3 +}; + +#define SEQUENCE_UI 0x1 +#define SEQUENCE_EXEC 0x2 +#define SEQUENCE_INSTALL 0x10 + +typedef struct tagMSISCRIPT +{ + LPWSTR *Actions[TOTAL_SCRIPTS]; + UINT ActionCount[TOTAL_SCRIPTS]; + BOOL ExecuteSequenceRun; + BOOL CurrentlyScripting; + UINT InWhatSequence; + LPWSTR *UniqueActions; + UINT UniqueActionsCount; +} MSISCRIPT; + #define MSIHANDLETYPE_ANY 0 #define MSIHANDLETYPE_DATABASE 1 #define MSIHANDLETYPE_SUMMARYINFO 2 @@ -324,7 +541,6 @@ extern BOOL msi_addstringW( string_table *st, UINT string_no, const WCHAR *data, extern UINT msi_id2stringW( string_table *st, UINT string_no, LPWSTR buffer, UINT *sz ); extern UINT msi_id2stringA( string_table *st, UINT string_no, LPSTR buffer, UINT *sz ); -extern LPWSTR MSI_makestring( MSIDATABASE *db, UINT stringid); extern UINT msi_string2idW( string_table *st, LPCWSTR buffer, UINT *id ); extern UINT msi_string2idA( string_table *st, LPCSTR str, UINT *id ); extern string_table *msi_init_stringtable( int entries, UINT codepage ); @@ -345,7 +561,7 @@ extern UINT read_raw_stream_data( MSIDATABASE*, LPCWSTR stname, /* transform functions */ extern UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg ); -extern UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db, +extern UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db, LPCWSTR szTransformFile, int iErrorCond ); /* action internals */ @@ -414,11 +630,12 @@ extern MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *, LPCWSTR ); extern UINT MSI_GetComponentStateW( MSIPACKAGE *, LPCWSTR, INSTALLSTATE *, INSTALLSTATE * ); extern UINT MSI_GetFeatureStateW( MSIPACKAGE *, LPCWSTR, INSTALLSTATE *, INSTALLSTATE * ); extern UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE*, LPCWSTR, INSTALLSTATE ); +extern LPCWSTR msi_download_file( LPCWSTR szUrl, LPWSTR filename ); /* for deformating */ extern UINT MSI_FormatRecordW( MSIPACKAGE *, MSIRECORD *, LPWSTR, DWORD * ); extern UINT MSI_FormatRecordA( MSIPACKAGE *, MSIRECORD *, LPSTR, DWORD * ); - + /* registry data encoding/decoding functions */ extern BOOL unsquash_guid(LPCWSTR in, LPWSTR out); extern BOOL squash_guid(LPCWSTR in, LPWSTR out); @@ -450,7 +667,7 @@ extern LONG msi_reg_set_subkey_val( HKEY hkey, LPCWSTR path, LPCWSTR name, LPCWS /* msi dialog interface */ typedef UINT (*msi_dialog_event_handler)( MSIPACKAGE*, LPCWSTR, LPCWSTR, msi_dialog* ); -extern msi_dialog *msi_dialog_create( MSIPACKAGE*, LPCWSTR, msi_dialog_event_handler ); +extern msi_dialog *msi_dialog_create( MSIPACKAGE*, LPCWSTR, msi_dialog*, msi_dialog_event_handler ); extern UINT msi_dialog_run_message_loop( msi_dialog* ); extern void msi_dialog_end_dialog( msi_dialog* ); extern void msi_dialog_check_messages( HANDLE ); @@ -461,6 +678,8 @@ extern void msi_dialog_unregister_class( void ); extern void msi_dialog_handle_event( msi_dialog*, LPCWSTR, LPCWSTR, MSIRECORD * ); extern UINT msi_dialog_reset( msi_dialog *dialog ); extern UINT msi_dialog_directorylist_up( msi_dialog *dialog ); +extern msi_dialog *msi_dialog_get_parent( msi_dialog *dialog ); +extern LPWSTR msi_dialog_get_name( msi_dialog *dialog ); /* preview */ extern MSIPREVIEW *MSI_EnableUIPreview( MSIDATABASE * ); @@ -487,6 +706,72 @@ extern LPVOID gUIContext; extern WCHAR gszLogFile[MAX_PATH]; extern HINSTANCE msi_hInstance; +/* action related functions */ +extern UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force); +extern UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action); +extern void ACTION_FinishCustomActions( MSIPACKAGE* package); +extern UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action, BOOL execute); + +/* actions in other modules */ +extern UINT ACTION_AppSearch(MSIPACKAGE *package); +extern UINT ACTION_FindRelatedProducts(MSIPACKAGE *package); +extern UINT ACTION_InstallFiles(MSIPACKAGE *package); +extern UINT ACTION_RemoveFiles(MSIPACKAGE *package); +extern UINT ACTION_DuplicateFiles(MSIPACKAGE *package); +extern UINT ACTION_RegisterClassInfo(MSIPACKAGE *package); +extern UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package); +extern UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package); +extern UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package); +extern UINT ACTION_RegisterFonts(MSIPACKAGE *package); + +/* Helpers */ +extern DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data ); +extern LPWSTR msi_dup_record_field(MSIRECORD *row, INT index); +extern LPWSTR msi_dup_property(MSIPACKAGE *package, LPCWSTR prop); +extern int msi_get_property_int( MSIPACKAGE *package, LPCWSTR prop, int def ); +extern LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, + BOOL set_prop, MSIFOLDER **folder); +extern MSICOMPONENT *get_loaded_component( MSIPACKAGE* package, LPCWSTR Component ); +extern MSIFEATURE *get_loaded_feature( MSIPACKAGE* package, LPCWSTR Feature ); +extern MSIFILE *get_loaded_file( MSIPACKAGE* package, LPCWSTR file ); +extern MSIFOLDER *get_loaded_folder( MSIPACKAGE *package, LPCWSTR dir ); +extern int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path); +extern UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action); +extern LPWSTR build_icon_path(MSIPACKAGE *, LPCWSTR); +extern LPWSTR build_directory_name(DWORD , ...); +extern BOOL create_full_pathW(const WCHAR *path); +extern BOOL ACTION_VerifyComponentForAction(MSICOMPONENT*, INSTALLSTATE); +extern BOOL ACTION_VerifyFeatureForAction(MSIFEATURE*, INSTALLSTATE); +extern void reduce_to_longfilename(WCHAR*); +extern void reduce_to_shortfilename(WCHAR*); +extern LPWSTR create_component_advertise_string(MSIPACKAGE*, MSICOMPONENT*, LPCWSTR); +extern void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature); +extern UINT register_unique_action(MSIPACKAGE *, LPCWSTR); +extern BOOL check_unique_action(MSIPACKAGE *, LPCWSTR); +extern WCHAR* generate_error_string(MSIPACKAGE *, UINT, DWORD, ... ); +extern UINT msi_create_component_directories( MSIPACKAGE *package ); +extern void msi_ui_error( DWORD msg_id, DWORD type ); + +/* control event stuff */ +extern VOID ControlEvent_FireSubscribedEvent(MSIPACKAGE *package, LPCWSTR event, + MSIRECORD *data); +extern VOID ControlEvent_CleanupSubscriptions(MSIPACKAGE *package); +extern VOID ControlEvent_SubscribeToEvent(MSIPACKAGE *package, msi_dialog *dialog, + LPCWSTR event, LPCWSTR control, LPCWSTR attribute); +extern VOID ControlEvent_UnSubscribeToEvent( MSIPACKAGE *package, LPCWSTR event, + LPCWSTR control, LPCWSTR attribute ); + +/* User Interface messages from the actions */ +extern void ui_progress(MSIPACKAGE *, int, int, int, int); +extern void ui_actiondata(MSIPACKAGE *, LPCWSTR, MSIRECORD *); + +/* string consts use a number of places and defined in helpers.c*/ +extern const WCHAR cszSourceDir[]; +extern const WCHAR cszSOURCEDIR[]; +extern const WCHAR szProductCode[]; +extern const WCHAR cszRootDrive[]; +extern const WCHAR cszbs[]; + /* memory allocation macro functions */ static inline void *msi_alloc( size_t len ) { diff --git a/reactos/dll/win32/msi/msiquery.c b/reactos/dll/win32/msi/msiquery.c index f063ac0578f..cd13a66ff39 100644 --- a/reactos/dll/win32/msi/msiquery.c +++ b/reactos/dll/win32/msi/msiquery.c @@ -37,6 +37,8 @@ #include "query.h" +#include "initguid.h" + WINE_DEFAULT_DEBUG_CHANNEL(msi); static void MSI_CloseView( MSIOBJECTHDR *arg ) @@ -314,11 +316,10 @@ UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec) if( type & MSITYPE_STRING ) { - LPWSTR sval; + LPCWSTR sval; - sval = MSI_makestring( query->db, ival ); + sval = msi_string_lookup_id( query->db->strings, ival ); MSI_RecordSetStringW( rec, i, sval ); - msi_free( sval ); } else { @@ -662,30 +663,40 @@ MSIHANDLE WINAPI MsiGetLastErrorRecord( void ) DEFINE_GUID( CLSID_MsiTransform, 0x000c1082, 0x0000, 0x0000, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); -UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db, +UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db, LPCWSTR szTransformFile, int iErrorCond ) { - UINT r; + HRESULT r; + UINT ret = ERROR_FUNCTION_FAILED; IStorage *stg = NULL; - + STATSTG stat; + TRACE("%p %s %d\n", db, debugstr_w(szTransformFile), iErrorCond); r = StgOpenStorage( szTransformFile, NULL, STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg); - if( r ) - return r; + if ( FAILED(r) ) + return ret; + + r = IStorage_Stat( stg, &stat, STATFLAG_NONAME ); + if ( FAILED( r ) ) + goto end; + + if ( !IsEqualGUID( &stat.clsid, &CLSID_MsiTransform ) ) + goto end; if( TRACE_ON( msi ) ) enum_stream_names( stg ); - r = msi_table_apply_transform( db, stg ); + ret = msi_table_apply_transform( db, stg ); +end: IStorage_Release( stg ); - return r; + return ret; } -UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb, +UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb, LPCWSTR szTransformFile, int iErrorCond) { MSIDATABASE *db; @@ -814,7 +825,7 @@ UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db, r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info ); if( r == ERROR_SUCCESS ) { - TRACE("Found %ld primary keys\n", info.n ); + TRACE("Found %d primary keys\n", info.n ); /* allocate a record and fill in the names of the tables */ info.rec = MSI_CreateRecord( info.n ); diff --git a/reactos/dll/win32/msi/package.c b/reactos/dll/win32/msi/package.c index c700bbfd867..3aaad690955 100644 --- a/reactos/dll/win32/msi/package.c +++ b/reactos/dll/win32/msi/package.c @@ -43,12 +43,9 @@ #include "msidefs.h" #include "msipriv.h" -#include "action.h" WINE_DEFAULT_DEBUG_CHANNEL(msi); -extern void msi_ui_error( DWORD msg_id, DWORD type ); - static void msi_free_properties( MSIPACKAGE *package ); static void MSI_FreePackage( MSIOBJECTHDR *arg) @@ -144,6 +141,9 @@ static VOID set_installer_properties(MSIPACKAGE *package) DWORD verval; WCHAR verstr[10], bufstr[20]; HDC dc; + LPWSTR check; + HKEY hkey; + LONG res; static const WCHAR cszbs[]={'\\',0}; static const WCHAR CFF[] = @@ -213,6 +213,18 @@ static VOID set_installer_properties(MSIPACKAGE *package) static const WCHAR szScreenFormat[] = {'%','d',0}; static const WCHAR szIntel[] = { 'I','n','t','e','l',0 }; static const WCHAR szAllUsers[] = { 'A','L','L','U','S','E','R','S',0 }; + static const WCHAR szCurrentVersion[] = { + 'S','O','F','T','W','A','R','E','\\', + 'M','i','c','r','o','s','o','f','t','\\', + 'W','i','n','d','o','w','s',' ','N','T','\\', + 'C','u','r','r','e','n','t','V','e','r','s','i','o','n',0 + }; + static const WCHAR szRegisteredUser[] = {'R','e','g','i','s','t','e','r','e','d','O','w','n','e','r',0}; + static const WCHAR szRegisteredOrg[] = { + 'R','e','g','i','s','t','e','r','e','d','O','r','g','a','n','i','z','a','t','i','o','n',0 + }; + static const WCHAR szUSERNAME[] = {'U','S','E','R','N','A','M','E',0}; + static const WCHAR szCOMPANYNAME[] = {'C','O','M','P','A','N','Y','N','A','M','E',0}; SYSTEM_INFO sys_info; /* @@ -356,6 +368,32 @@ static VOID set_installer_properties(MSIPACKAGE *package) sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, BITSPIXEL )); MSI_SetPropertyW( package, szColorBits, bufstr ); ReleaseDC(0, dc); + + /* USERNAME and COMPANYNAME */ + res = RegOpenKeyW( HKEY_LOCAL_MACHINE, szCurrentVersion, &hkey ); + if (res != ERROR_SUCCESS) + return; + + check = msi_dup_property( package, szUSERNAME ); + if (!check) + { + LPWSTR user = msi_reg_get_val_str( hkey, szRegisteredUser ); + MSI_SetPropertyW( package, szUSERNAME, user ); + msi_free( user ); + } + + msi_free( check ); + + check = msi_dup_property( package, szCOMPANYNAME ); + if (!check) + { + LPWSTR company = msi_reg_get_val_str( hkey, szRegisteredOrg ); + MSI_SetPropertyW( package, szCOMPANYNAME, company ); + msi_free( company ); + } + + msi_free( check ); + CloseHandle( hkey ); } static UINT msi_get_word_count( MSIPACKAGE *package ) @@ -427,6 +465,7 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db ) list_init( &package->RunningActions ); package->WordCount = msi_get_word_count( package ); + package->PackagePath = strdupW( db->path ); /* OK, here is where we do a slew of things to the database to * prep for all that is to come as a package */ @@ -513,6 +552,10 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage) MSIHANDLE handle; UINT r; + static const WCHAR OriginalDatabase[] = + {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0}; + static const WCHAR Database[] = {'D','A','T','A','B','A','S','E',0}; + TRACE("%s %p\n", debugstr_w(szPackage), pPackage); if( szPackage[0] == '#' ) @@ -551,20 +594,16 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage) if( !package ) return ERROR_FUNCTION_FAILED; - /* - * FIXME: I don't think this is right. Maybe we should be storing the - * name of the database in the MSIDATABASE structure and fetching this - * info from there, or maybe this is only relevant to cached databases. - */ if( szPackage[0] != '#' ) { - static const WCHAR OriginalDatabase[] = - {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0}; - static const WCHAR Database[] = {'D','A','T','A','B','A','S','E',0}; - MSI_SetPropertyW( package, OriginalDatabase, szPackage ); MSI_SetPropertyW( package, Database, szPackage ); } + else + { + MSI_SetPropertyW( package, OriginalDatabase, db->path ); + MSI_SetPropertyW( package, Database, db->path ); + } *pPackage = package; @@ -576,13 +615,13 @@ UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phP MSIPACKAGE *package = NULL; UINT ret; - TRACE("%s %08lx %p\n", debugstr_w(szPackage), dwOptions, phPackage ); + TRACE("%s %08x %p\n", debugstr_w(szPackage), dwOptions, phPackage ); if( szPackage == NULL ) return ERROR_INVALID_PARAMETER; if( dwOptions ) - FIXME("dwOptions %08lx not supported\n", dwOptions); + FIXME("dwOptions %08x not supported\n", dwOptions); ret = MSI_OpenPackageW( szPackage, &package ); if( ret == ERROR_SUCCESS ) @@ -744,7 +783,7 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType, } } - TRACE("(%p %lx %lx %s)\n",gUIHandlerA, gUIFilter, log_type, + TRACE("(%p %x %x %s)\n", gUIHandlerA, gUIFilter, log_type, debugstr_w(message)); /* convert it to ASCII */ @@ -1009,7 +1048,7 @@ UINT MSI_GetPropertyW( MSIPACKAGE *package, LPCWSTR szName, if ( *pchValueBuf <= len ) { - TRACE("have %lu, need %u -> ERROR_MORE_DATA\n", *pchValueBuf, len); + TRACE("have %u, need %u -> ERROR_MORE_DATA\n", *pchValueBuf, len); r = ERROR_MORE_DATA; } else diff --git a/reactos/dll/win32/msi/preview.c b/reactos/dll/win32/msi/preview.c index 161bcc75f51..4f4cc5c2b7b 100644 --- a/reactos/dll/win32/msi/preview.c +++ b/reactos/dll/win32/msi/preview.c @@ -103,7 +103,7 @@ UINT MSI_PreviewDialogW( MSIPREVIEW *preview, LPCWSTR szDialogName ) /* an empty name means we should just destroy the current preview dialog */ if( szDialogName ) { - dialog = msi_dialog_create( preview->package, szDialogName, + dialog = msi_dialog_create( preview->package, szDialogName, NULL, preview_event_handler ); if( dialog ) msi_dialog_do_preview( dialog ); diff --git a/reactos/dll/win32/msi/record.c b/reactos/dll/win32/msi/record.c index 8bc3871d3d8..6705a03a475 100644 --- a/reactos/dll/win32/msi/record.c +++ b/reactos/dll/win32/msi/record.c @@ -641,7 +641,7 @@ static UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm) ulSize.QuadPart = sz; IStream_SetSize(*pstm, ulSize); - TRACE("read %s, %ld bytes into IStream %p\n", debugstr_w(szFile), sz, *pstm); + TRACE("read %s, %d bytes into IStream %p\n", debugstr_w(szFile), sz, *pstm); return ERROR_SUCCESS; } diff --git a/reactos/dll/win32/msi/registry.c b/reactos/dll/win32/msi/registry.c index 75b9d23a0f7..6ea57b4bb98 100644 --- a/reactos/dll/win32/msi/registry.c +++ b/reactos/dll/win32/msi/registry.c @@ -335,7 +335,7 @@ LPWSTR msi_version_dword_to_str(DWORD version) LONG msi_reg_set_val_str( HKEY hkey, LPCWSTR name, LPCWSTR value ) { DWORD len = value ? (lstrlenW(value) + 1) * sizeof (WCHAR) : 0; - return RegSetValueExW( hkey, name, 0, REG_SZ, (LPBYTE)value, len ); + return RegSetValueExW( hkey, name, 0, REG_SZ, (const BYTE *)value, len ); } LONG msi_reg_set_val_multi_str( HKEY hkey, LPCWSTR name, LPCWSTR value ) @@ -343,7 +343,7 @@ LONG msi_reg_set_val_multi_str( HKEY hkey, LPCWSTR name, LPCWSTR value ) LPCWSTR p = value; while (*p) p += lstrlenW(p) + 1; return RegSetValueExW( hkey, name, 0, REG_MULTI_SZ, - (LPBYTE)value, (p + 1 - value) * sizeof(WCHAR) ); + (const BYTE *)value, (p + 1 - value) * sizeof(WCHAR) ); } LONG msi_reg_set_val_dword( HKEY hkey, LPCWSTR name, DWORD val ) @@ -687,8 +687,8 @@ UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid) DWORD r; WCHAR szwGuid[GUID_SIZE]; - TRACE("%ld %p\n",index,lpguid); - + TRACE("%d %p\n", index, lpguid); + if (NULL == lpguid) return ERROR_INVALID_PARAMETER; r = MsiEnumProductsW(index, szwGuid); @@ -704,7 +704,7 @@ UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid) DWORD r; WCHAR szKeyName[SQUISH_GUID_SIZE]; - TRACE("%ld %p\n",index,lpguid); + TRACE("%d %p\n", index, lpguid); if (NULL == lpguid) return ERROR_INVALID_PARAMETER; @@ -728,7 +728,7 @@ UINT WINAPI MsiEnumFeaturesA(LPCSTR szProduct, DWORD index, WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE]; LPWSTR szwProduct = NULL; - TRACE("%s %ld %p %p\n",debugstr_a(szProduct),index,szFeature,szParent); + TRACE("%s %d %p %p\n", debugstr_a(szProduct), index, szFeature, szParent); if( szProduct ) { @@ -757,7 +757,7 @@ UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index, HKEY hkeyProduct = 0; DWORD r, sz; - TRACE("%s %ld %p %p\n",debugstr_w(szProduct),index,szFeature,szParent); + TRACE("%s %d %p %p\n", debugstr_w(szProduct), index, szFeature, szParent); if( !szProduct ) return ERROR_INVALID_PARAMETER; @@ -778,7 +778,7 @@ UINT WINAPI MsiEnumComponentsA(DWORD index, LPSTR lpguid) DWORD r; WCHAR szwGuid[GUID_SIZE]; - TRACE("%ld %p\n",index,lpguid); + TRACE("%d %p\n", index, lpguid); r = MsiEnumComponentsW(index, szwGuid); if( r == ERROR_SUCCESS ) @@ -793,7 +793,7 @@ UINT WINAPI MsiEnumComponentsW(DWORD index, LPWSTR lpguid) DWORD r; WCHAR szKeyName[SQUISH_GUID_SIZE]; - TRACE("%ld %p\n",index,lpguid); + TRACE("%d %p\n", index, lpguid); r = MSIREG_OpenComponents(&hkeyComponents); if( r != ERROR_SUCCESS ) @@ -813,7 +813,7 @@ UINT WINAPI MsiEnumClientsA(LPCSTR szComponent, DWORD index, LPSTR szProduct) WCHAR szwProduct[GUID_SIZE]; LPWSTR szwComponent = NULL; - TRACE("%s %ld %p\n",debugstr_a(szComponent),index,szProduct); + TRACE("%s %d %p\n", debugstr_a(szComponent), index, szProduct); if( szComponent ) { @@ -840,7 +840,7 @@ UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct) DWORD r, sz; WCHAR szValName[SQUISH_GUID_SIZE]; - TRACE("%s %ld %p\n",debugstr_w(szComponent),index,szProduct); + TRACE("%s %d %p\n", debugstr_w(szComponent), index, szProduct); r = MSIREG_OpenComponentsKey(szComponent,&hkeyComp,FALSE); if( r != ERROR_SUCCESS ) @@ -856,7 +856,7 @@ UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct) return r; } -UINT WINAPI MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex, +static UINT WINAPI MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex, awstring *lpQualBuf, DWORD* pcchQual, awstring *lpAppBuf, DWORD* pcchAppBuf ) { @@ -865,7 +865,7 @@ UINT WINAPI MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex, UINT r, r2; HKEY key; - TRACE("%s %08lx %p %p %p %p\n", debugstr_w(szComponent), iIndex, + TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex, lpQualBuf, pcchQual, lpAppBuf, pcchAppBuf); if (!szComponent) @@ -902,7 +902,7 @@ UINT WINAPI MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex, if (type != REG_MULTI_SZ) { - ERR("component data has wrong type (%ld)\n", type); + ERR("component data has wrong type (%d)\n", type); goto end; } @@ -925,7 +925,7 @@ UINT WINAPI MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex, goto end; continue; } - ERR("should be enough data, but isn't %ld %ld\n", name_sz, val_sz ); + ERR("should be enough data, but isn't %d %d\n", name_sz, val_sz ); goto end; } @@ -961,7 +961,7 @@ UINT WINAPI MsiEnumComponentQualifiersA( LPCSTR szComponent, DWORD iIndex, LPWSTR comp; UINT r; - TRACE("%s %08lx %p %p %p %p\n", debugstr_a(szComponent), iIndex, + TRACE("%s %08x %p %p %p %p\n", debugstr_a(szComponent), iIndex, lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, pcchApplicationDataBuf); @@ -990,7 +990,7 @@ UINT WINAPI MsiEnumComponentQualifiersW( LPCWSTR szComponent, DWORD iIndex, { awstring qual, appdata; - TRACE("%s %08lx %p %p %p %p\n", debugstr_w(szComponent), iIndex, + TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex, lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, pcchApplicationDataBuf); @@ -1015,7 +1015,7 @@ UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR szUpgradeCode, DWORD dwReserved, HKEY hkey; WCHAR szKeyName[SQUISH_GUID_SIZE]; - TRACE("%s %lu %lu %p\n", debugstr_w(szUpgradeCode), dwReserved, + TRACE("%s %u %u %p\n", debugstr_w(szUpgradeCode), dwReserved, iProductIndex, lpProductBuf); if (NULL == szUpgradeCode) @@ -1046,7 +1046,7 @@ UINT WINAPI MsiEnumRelatedProductsA(LPCSTR szUpgradeCode, DWORD dwReserved, WCHAR productW[GUID_SIZE]; UINT r; - TRACE("%s %lu %lu %p\n", debugstr_a(szUpgradeCode), dwReserved, + TRACE("%s %u %u %p\n", debugstr_a(szUpgradeCode), dwReserved, iProductIndex, lpProductBuf); if (szUpgradeCode) @@ -1070,10 +1070,10 @@ UINT WINAPI MsiEnumRelatedProductsA(LPCSTR szUpgradeCode, DWORD dwReserved, /*********************************************************************** * MsiEnumPatchesA [MSI.@] */ -UINT WINAPI MsiEnumPatchesA( LPCSTR szProduct, DWORD iPatchIndex, +UINT WINAPI MsiEnumPatchesA( LPCSTR szProduct, DWORD iPatchIndex, LPSTR lpPatchBuf, LPSTR lpTransformsBuf, DWORD* pcchTransformsBuf) { - FIXME("%s %ld %p %p %p\n", debugstr_a(szProduct), + FIXME("%s %d %p %p %p\n", debugstr_a(szProduct), iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf); return ERROR_NO_MORE_ITEMS; } @@ -1081,10 +1081,10 @@ UINT WINAPI MsiEnumPatchesA( LPCSTR szProduct, DWORD iPatchIndex, /*********************************************************************** * MsiEnumPatchesW [MSI.@] */ -UINT WINAPI MsiEnumPatchesW( LPCWSTR szProduct, DWORD iPatchIndex, +UINT WINAPI MsiEnumPatchesW( LPCWSTR szProduct, DWORD iPatchIndex, LPWSTR lpPatchBuf, LPWSTR lpTransformsBuf, DWORD* pcchTransformsBuf) { - FIXME("%s %ld %p %p %p\n", debugstr_w(szProduct), + FIXME("%s %d %p %p %p\n", debugstr_w(szProduct), iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf); return ERROR_NO_MORE_ITEMS; } diff --git a/reactos/dll/win32/msi/select.c b/reactos/dll/win32/msi/select.c index d47792b225f..c9611305fb0 100644 --- a/reactos/dll/win32/msi/select.c +++ b/reactos/dll/win32/msi/select.c @@ -285,7 +285,7 @@ static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name ) return ERROR_SUCCESS; } -int select_count_columns( column_info *col ) +static int select_count_columns( column_info *col ) { int n; for (n = 0; col; col = col->next) diff --git a/reactos/dll/win32/msi/source.c b/reactos/dll/win32/msi/source.c index f8c5a1024f7..98796a29d04 100644 --- a/reactos/dll/win32/msi/source.c +++ b/reactos/dll/win32/msi/source.c @@ -37,7 +37,6 @@ #include "winver.h" #include "winuser.h" #include "wine/unicode.h" -#include "action.h" #include "sddl.h" WINE_DEFAULT_DEBUG_CHANNEL(msi); @@ -300,7 +299,7 @@ UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid, HKEY sourcekey; UINT rc; - TRACE("%s %s %x %lx %s %s\n", debugstr_w(szProduct), debugstr_w(szUserSid), + TRACE("%s %s %x %x %s %s\n", debugstr_w(szProduct), debugstr_w(szUserSid), dwContext, dwOptions, debugstr_w(szProperty), debugstr_w(szValue)); if (!szProduct || lstrlenW(szProduct) > 39) @@ -334,7 +333,7 @@ UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid, rc = OpenMediaSubkey(sourcekey, &key, FALSE); if (rc == ERROR_SUCCESS) rc = RegSetValueExW(key, INSTALLPROPERTY_MEDIAPACKAGEPATHW, 0, - REG_SZ, (LPBYTE)szValue, size); + REG_SZ, (const BYTE *)szValue, size); if (rc != ERROR_SUCCESS) rc = ERROR_UNKNOWN_PROPERTY; RegCloseKey(key); @@ -346,7 +345,7 @@ UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid, rc = OpenMediaSubkey(sourcekey, &key, FALSE); if (rc == ERROR_SUCCESS) rc = RegSetValueExW(key, INSTALLPROPERTY_DISKPROMPTW, 0, - REG_SZ, (LPBYTE)szValue, size); + REG_SZ, (const BYTE *)szValue, size); if (rc != ERROR_SUCCESS) rc = ERROR_UNKNOWN_PROPERTY; RegCloseKey(key); @@ -368,9 +367,9 @@ UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid, typechar = 'u'; else if (dwOptions & MSISOURCETYPE_MEDIA) typechar = 'm'; - else - ERR("Unknown source type! 0x%lx\n",dwOptions); - + else + ERR("Unknown source type! %x\n", dwOptions); + size = (lstrlenW(szValue)+5)*sizeof(WCHAR); buffer = msi_alloc(size); sprintfW(buffer, LastUsedSource_Fmt, typechar, 1, szValue); @@ -384,7 +383,7 @@ UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid, { DWORD size = lstrlenW(szValue)*sizeof(WCHAR); rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0, - REG_SZ, (LPBYTE)szValue, size); + REG_SZ, (const BYTE *)szValue, size); if (rc != ERROR_SUCCESS) rc = ERROR_UNKNOWN_PROPERTY; } @@ -466,11 +465,10 @@ UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid, HKEY typekey; UINT rc; media_info source_struct; - - TRACE("%s, %s, %x, %lx, %s, %li\n", debugstr_w(szProduct), - debugstr_w(szUserSid), dwContext, dwOptions, debugstr_w(szSource), - dwIndex); - + + TRACE("%s %s %x %x %s %i\n", debugstr_w(szProduct), debugstr_w(szUserSid), + dwContext, dwOptions, debugstr_w(szSource), dwIndex); + if (!szProduct) return ERROR_INVALID_PARAMETER; @@ -505,7 +503,7 @@ UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid, rc = OpenMediaSubkey(sourcekey, &typekey, TRUE); else { - ERR("unknown media type: %08lx\n", dwOptions); + ERR("unknown media type: %08x\n", dwOptions); RegCloseKey(sourcekey); return ERROR_FUNCTION_FAILED; } @@ -533,7 +531,7 @@ UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid, current_index ++; sprintfW(source_struct.szIndex,fmt,current_index); rc = RegSetValueExW(typekey, source_struct.szIndex, 0, REG_EXPAND_SZ, - (LPBYTE)szSource, size); + (const BYTE *)szSource, size); } RegCloseKey(typekey); @@ -559,9 +557,9 @@ UINT WINAPI MsiSourceListAddMediaDiskW(LPCWSTR szProduct, LPCWSTR szUserSid, LPWSTR buffer; DWORD size; - TRACE("%s %s %x %lx %li %s %s\n", debugstr_w(szProduct), - debugstr_w(szUserSid), dwContext, dwOptions, dwDiskId, - debugstr_w(szVolumeLabel), debugstr_w(szDiskPrompt)); + TRACE("%s %s %x %x %i %s %s\n", debugstr_w(szProduct), + debugstr_w(szUserSid), dwContext, dwOptions, dwDiskId, + debugstr_w(szVolumeLabel), debugstr_w(szDiskPrompt)); if (!szProduct || lstrlenW(szProduct) > 39) return ERROR_INVALID_PARAMETER; @@ -625,7 +623,7 @@ UINT WINAPI MsiSourceListAddMediaDiskW(LPCWSTR szProduct, LPCWSTR szUserSid, */ UINT WINAPI MsiSourceListClearAllA( LPCSTR szProduct, LPCSTR szUserName, DWORD dwReserved ) { - FIXME("(%s %s %ld) stub\n", debugstr_a(szProduct), debugstr_a(szUserName), dwReserved); + FIXME("(%s %s %d)\n", debugstr_a(szProduct), debugstr_a(szUserName), dwReserved); return ERROR_SUCCESS; } @@ -634,6 +632,6 @@ UINT WINAPI MsiSourceListClearAllA( LPCSTR szProduct, LPCSTR szUserName, DWORD d */ UINT WINAPI MsiSourceListClearAllW( LPCWSTR szProduct, LPCWSTR szUserName, DWORD dwReserved ) { - FIXME("(%s %s %ld) stub\n", debugstr_w(szProduct), debugstr_w(szUserName), dwReserved); + FIXME("(%s %s %d)\n", debugstr_w(szProduct), debugstr_w(szUserName), dwReserved); return ERROR_SUCCESS; } diff --git a/reactos/dll/win32/msi/suminfo.c b/reactos/dll/win32/msi/suminfo.c index 7b547521d58..5d51e4f4562 100644 --- a/reactos/dll/win32/msi/suminfo.c +++ b/reactos/dll/win32/msi/suminfo.c @@ -163,7 +163,7 @@ static void read_properties_from_data( PROPVARIANT *prop, LPBYTE data, DWORD sz type = get_type( idofs[i].propid ); if( type == VT_EMPTY ) { - ERR("propid %ld has unknown type\n", idofs[i].propid); + ERR("propid %d has unknown type\n", idofs[i].propid); break; } @@ -172,7 +172,7 @@ static void read_properties_from_data( PROPVARIANT *prop, LPBYTE data, DWORD sz /* check the type is the same as we expect */ if( type != propdata->type ) { - ERR("wrong type %d != %ld\n", type, propdata->type); + ERR("wrong type %d != %d\n", type, propdata->type); break; } @@ -188,7 +188,7 @@ static void read_properties_from_data( PROPVARIANT *prop, LPBYTE data, DWORD sz if( idofs[i].propid >= MSI_MAX_PROPS ) { - ERR("Unknown property ID %ld\n", idofs[i].propid ); + ERR("Unknown property ID %d\n", idofs[i].propid ); break; } @@ -259,7 +259,7 @@ static UINT load_summary_info( MSISUMMARYINFO *si, IStream *stm ) if( section_hdr.cProperties > MSI_MAX_PROPS ) { - ERR("too many properties %ld\n", section_hdr.cProperties); + ERR("too many properties %d\n", section_hdr.cProperties); return ret; } @@ -275,7 +275,7 @@ static UINT load_summary_info( MSISUMMARYINFO *si, IStream *stm ) if( SUCCEEDED(r) && count == sz ) read_properties_from_data( si->property, data, sz + SECT_HDR_SIZE ); else - ERR("failed to read properties %ld %ld\n", count, sz); + ERR("failed to read properties %d %d\n", count, sz); msi_free( data ); return ret; @@ -506,7 +506,7 @@ UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo, UINT *pCount) { MSISUMMARYINFO *si; - TRACE("%ld %p\n",hSummaryInfo, pCount); + TRACE("%ld %p\n", hSummaryInfo, pCount); si = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO ); if( !si ) diff --git a/reactos/dll/win32/msi/table.c b/reactos/dll/win32/msi/table.c index 4eb3f523437..8d416f2910e 100644 --- a/reactos/dll/win32/msi/table.c +++ b/reactos/dll/win32/msi/table.c @@ -27,15 +27,17 @@ #include "windef.h" #include "winbase.h" #include "winerror.h" -#include "wine/debug.h" #include "msi.h" #include "msiquery.h" #include "objbase.h" #include "objidl.h" -#include "msipriv.h" #include "winnls.h" - +#include "msipriv.h" #include "query.h" +#include "assert.h" + +#include "wine/debug.h" +#include "wine/unicode.h" WINE_DEFAULT_DEBUG_CHANNEL(msidb); @@ -71,11 +73,16 @@ typedef struct tagMSITRANSFORM { IStorage *stg; } MSITRANSFORM; +static const WCHAR szStringData[] = { + '_','S','t','r','i','n','g','D','a','t','a',0 }; +static const WCHAR szStringPool[] = { + '_','S','t','r','i','n','g','P','o','o','l',0 }; + #define MAX_STREAM_NAME 0x1f static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO **pcols, UINT *pcount ); -static UINT get_tablecolumns( MSIDATABASE *db, +static UINT get_tablecolumns( MSIDATABASE *db, LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz); static void msi_free_colinfo( MSICOLUMNINFO *colinfo, UINT count ); @@ -208,7 +215,7 @@ void enum_stream_names( IStorage *stg ) if( FAILED( r ) || !count ) break; decode_streamname( stat.pwcsName, name ); - TRACE("stream %2ld -> %s %s\n", n, + TRACE("stream %2d -> %s %s\n", n, debugstr_w(stat.pwcsName), debugstr_w(name) ); n++; } @@ -236,14 +243,14 @@ static UINT read_stream_data( IStorage *stg, LPCWSTR stname, msi_free( encname ); if( FAILED( r ) ) { - WARN("open stream failed r = %08lx - empty table?\n",r); + WARN("open stream failed r = %08x - empty table?\n", r); return ret; } r = IStream_Stat(stm, &stat, STATFLAG_NONAME ); if( FAILED( r ) ) { - WARN("open stream failed r = %08lx!\n",r); + WARN("open stream failed r = %08x!\n", r); goto end; } @@ -257,7 +264,7 @@ static UINT read_stream_data( IStorage *stg, LPCWSTR stname, data = msi_alloc( sz ); if( !data ) { - WARN("couldn't allocate memory r=%08lx!\n",r); + WARN("couldn't allocate memory r=%08x!\n", r); ret = ERROR_NOT_ENOUGH_MEMORY; goto end; } @@ -266,7 +273,7 @@ static UINT read_stream_data( IStorage *stg, LPCWSTR stname, if( FAILED( r ) || ( count != sz ) ) { msi_free( data ); - WARN("read stream failed r = %08lx!\n",r); + WARN("read stream failed r = %08x!\n", r); goto end; } @@ -326,7 +333,7 @@ UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname, r = IStream_Stat(stm, &stat, STATFLAG_NONAME ); if( FAILED( r ) ) { - WARN("open stream failed r = %08lx!\n",r); + WARN("open stream failed r = %08x!\n", r); goto end; } @@ -340,7 +347,7 @@ UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname, data = msi_alloc( sz ); if( !data ) { - WARN("couldn't allocate memory r=%08lx!\n",r); + WARN("couldn't allocate memory r=%08x!\n", r); ret = ERROR_NOT_ENOUGH_MEMORY; goto end; } @@ -349,7 +356,7 @@ UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname, if( FAILED( r ) || ( count != sz ) ) { msi_free( data ); - WARN("read stream failed r = %08lx!\n",r); + WARN("read stream failed r = %08x!\n", r); goto end; } @@ -385,7 +392,7 @@ static UINT write_stream_data( IStorage *stg, LPCWSTR stname, msi_free( encname ); if( FAILED( r ) ) { - WARN("open stream failed r = %08lx\n",r); + WARN("open stream failed r = %08x\n", r); return ret; } @@ -635,10 +642,6 @@ err: HRESULT init_string_table( IStorage *stg ) { HRESULT r; - static const WCHAR szStringData[] = { - '_','S','t','r','i','n','g','D','a','t','a',0 }; - static const WCHAR szStringPool[] = { - '_','S','t','r','i','n','g','P','o','o','l',0 }; USHORT zero[2] = { 0, 0 }; ULONG count = 0; IStream *stm = NULL; @@ -687,10 +690,6 @@ string_table *load_string_table( IStorage *stg ) USHORT *pool = NULL; UINT r, datasize = 0, poolsize = 0, codepage; DWORD i, count, offset, len, n, refs; - static const WCHAR szStringData[] = { - '_','S','t','r','i','n','g','D','a','t','a',0 }; - static const WCHAR szStringPool[] = { - '_','S','t','r','i','n','g','P','o','o','l',0 }; r = read_stream_data( stg, szStringPool, &pool, &poolsize ); if( r != ERROR_SUCCESS) @@ -746,15 +745,15 @@ string_table *load_string_table( IStorage *stg ) r = msi_addstring( st, n, data+offset, len, refs ); if( r != n ) - ERR("Failed to add string %ld\n", n ); + ERR("Failed to add string %d\n", n ); n++; offset += len; } if ( datasize != offset ) - ERR("string table load failed! (%08x != %08lx), please report\n", datasize, offset ); + ERR("string table load failed! (%08x != %08x), please report\n", datasize, offset ); - TRACE("Loaded %ld strings\n", count); + TRACE("Loaded %d strings\n", count); end: msi_free( pool ); @@ -767,10 +766,6 @@ static UINT save_string_table( MSIDATABASE *db ) { UINT i, count, datasize = 0, poolsize = 0, sz, used, r, codepage, n; UINT ret = ERROR_FUNCTION_FAILED; - static const WCHAR szStringData[] = { - '_','S','t','r','i','n','g','D','a','t','a',0 }; - static const WCHAR szStringPool[] = { - '_','S','t','r','i','n','g','P','o','o','l',0 }; CHAR *data = NULL; USHORT *pool = NULL; @@ -811,7 +806,10 @@ static UINT save_string_table( MSIDATABASE *db ) if( sz && (sz < (datasize - used ) ) ) sz--; - pool[ n*2 + 1 ] = msi_id_refcount( db->strings, i ); + if (sz) + pool[ n*2 + 1 ] = msi_id_refcount( db->strings, i ); + else + pool[ n*2 + 1 ] = 0; if (sz < 0x10000) { pool[ n*2 ] = sz; @@ -924,17 +922,19 @@ static void msi_free_colinfo( MSICOLUMNINFO *colinfo, UINT count ) } } -LPWSTR MSI_makestring( MSIDATABASE *db, UINT stringid) +static LPWSTR msi_makestring( MSIDATABASE *db, UINT stringid) { return strdupW(msi_string_lookup_id( db->strings, stringid )); } -static UINT get_tablecolumns( MSIDATABASE *db, +static UINT get_tablecolumns( MSIDATABASE *db, LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz) { UINT r, i, n=0, table_id, count, maxcount = *sz; MSITABLE *table = NULL; + TRACE("%s\n", debugstr_w(szTableName)); + /* first check if there is a default table with that name */ r = get_defaulttablecolumns( szTableName, colinfo, sz ); if( ( r == ERROR_SUCCESS ) && *sz ) @@ -957,6 +957,8 @@ static UINT get_tablecolumns( MSIDATABASE *db, TRACE("Table id is %d, row count is %d\n", table_id, table->row_count); + /* if maxcount is non-zero, assume it's exactly right for this table */ + memset( colinfo, 0, maxcount*sizeof(*colinfo) ); count = table->row_count; for( i=0; idata[ i ] [ 2 ]; - colinfo[n].tablename = MSI_makestring( db, table_id ); - colinfo[n].number = table->data[ i ][ 1 ] - (1<<15); - colinfo[n].colname = MSI_makestring( db, id ); - colinfo[n].type = table->data[ i ] [ 3 ] ^ 0x8000; - colinfo[n].hash_table = NULL; - /* this assumes that columns are in order in the table */ - if( n ) - colinfo[n].offset = colinfo[n-1].offset - + bytes_per_column( &colinfo[n-1] ); - else - colinfo[n].offset = 0; - TRACE("table %s column %d is [%s] (%d) with type %08x " - "offset %d at row %d\n", debugstr_w(szTableName), - colinfo[n].number, debugstr_w(colinfo[n].colname), - id, colinfo[n].type, colinfo[n].offset, i); - if( n != (colinfo[n].number-1) ) + UINT col = table->data[ i ][ 1 ] - (1<<15); + + /* check the column number is in range */ + if (col<1 || col>maxcount) { - ERR("oops. data in the _Columns table isn't in the right " - "order for table %s\n", debugstr_w(szTableName)); - return ERROR_FUNCTION_FAILED; + ERR("column %d out of range\n", col); + continue; } + + /* check if this column was already set */ + if (colinfo[ col - 1 ].number) + { + ERR("duplicate column %d\n", col); + continue; + } + + colinfo[ col - 1 ].tablename = msi_makestring( db, table_id ); + colinfo[ col - 1 ].number = col; + colinfo[ col - 1 ].colname = msi_makestring( db, id ); + colinfo[ col - 1 ].type = table->data[ i ] [ 3 ] - (1<<15); + colinfo[ col - 1 ].offset = 0; + colinfo[ col - 1 ].hash_table = NULL; } n++; - if( colinfo && ( n >= maxcount ) ) - break; + } + + TRACE("%s has %d columns\n", debugstr_w(szTableName), n); + + if (maxcount && n != maxcount) + { + ERR("missing column in table %s\n", debugstr_w(szTableName)); + msi_free_colinfo(colinfo, maxcount ); + return ERROR_FUNCTION_FAILED; + } + + /* calculate the offsets */ + for( i=0; maxcount && (iops->fetch_int ) return ERROR_INVALID_PARAMETER; @@ -1121,15 +1146,31 @@ static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, ISt if( r != ERROR_SUCCESS ) return r; - /* now get the column with the name of the stream */ - r = view->ops->fetch_int( view, row, ival, &refcol ); - if( r != ERROR_SUCCESS ) - return r; + /* check the column value is in range */ + if (ival < 0 || ival > tv->num_cols || ival == col) + { + ERR("bad column ref (%u) for stream\n", ival); + return ERROR_FUNCTION_FAILED; + } - /* lookup the string value from the string table */ - sval = msi_string_lookup_id( tv->db->strings, refcol ); - if( !sval ) - return ERROR_INVALID_PARAMETER; + if ( tv->columns[ival - 1].type & MSITYPE_STRING ) + { + /* now get the column with the name of the stream */ + r = view->ops->fetch_int( view, row, ival, &refcol ); + if ( r != ERROR_SUCCESS ) + return r; + + /* lookup the string value from the string table */ + sval = msi_string_lookup_id( tv->db->strings, refcol ); + if ( !sval ) + return ERROR_INVALID_PARAMETER; + } + else + { + static const WCHAR fmt[] = { '%','d',0 }; + sprintfW( number, fmt, ival ); + sval = number; + } len = lstrlenW( tv->name ) + 2 + lstrlenW( sval ); full_name = msi_alloc( len*sizeof(WCHAR) ); @@ -1296,7 +1337,9 @@ static UINT table_validate_new( MSITABLEVIEW *tv, MSIRECORD *rec ) if ( tv->columns[i].type & MSITYPE_NULLABLE ) continue; - if ( tv->columns[i].type & MSITYPE_STRING ) + if ( MSITYPE_IS_BINARY(tv->columns[i].type) ) + TRACE("skipping binary column\n"); + else if ( tv->columns[i].type & MSITYPE_STRING ) { LPCWSTR str; @@ -1662,7 +1705,7 @@ static MSIRECORD *msi_get_transform_record( MSITABLEVIEW *tv, string_table *st, if( !rec ) return rec; - TRACE("row -> "); + TRACE("row ->\n"); for( i=0; inum_cols; i++ ) { UINT n = bytes_per_column( &columns[i] ); @@ -1682,20 +1725,20 @@ static MSIRECORD *msi_get_transform_record( MSITABLEVIEW *tv, string_table *st, { LPCWSTR sval = msi_string_lookup_id( st, val ); MSI_RecordSetStringW( rec, i+1, sval ); - TRACE("[%s]", debugstr_w(sval)); + TRACE(" field %d [%s]\n", i+1, debugstr_w(sval)); } else { - val ^= 0x8000; - MSI_RecordSetInteger( rec, i+1, val ); - TRACE("[0x%04x]", val ); + if (val) + MSI_RecordSetInteger( rec, i+1, val^0x8000 ); + TRACE(" field %d [0x%04x]\n", i+1, val ); } break; case 4: - val = rawdata[ofs] + (rawdata[ofs + 1]<<16); - /* val ^= 0x80000000; */ - MSI_RecordSetInteger( rec, i+1, val ); - TRACE("[0x%08x]", val ); + val = (rawdata[ofs] + (rawdata[ofs + 1]<<16)); + if (val) + MSI_RecordSetInteger( rec, i+1, val^0x80000000 ); + TRACE(" field %d [0x%08x]\n", i+1, val ); break; default: ERR("oops - unknown column width %d\n", n); @@ -1703,7 +1746,6 @@ static MSIRECORD *msi_get_transform_record( MSITABLEVIEW *tv, string_table *st, } ofs += n/2; } - TRACE("\n"); return rec; } @@ -1766,7 +1808,13 @@ static UINT* msi_record_to_row( MSITABLEVIEW *tv, MSIRECORD *rec ) } } else + { data[i] = MSI_RecordGetInteger( rec, i+1 ); + if ((tv->columns[i].type&0xff) == 2) + data[i] += 0x8000; + else + data[i] += 0x80000000; + } } return data; } @@ -1837,9 +1885,20 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg, MSITABLEVIEW *tv = NULL; UINT r, n, sz, i, mask; MSIRECORD *rec = NULL; + UINT colcol = 0; + WCHAR coltable[32]; + coltable[0] = 0; TRACE("%p %p %p %s\n", db, stg, st, debugstr_w(name) ); + /* read the transform data */ + read_stream_data( stg, name, &rawdata, &rawsize ); + if ( !rawdata ) + { + TRACE("table %s empty\n", debugstr_w(name) ); + return ERROR_INVALID_TABLE; + } + /* create a table view */ r = TABLE_CreateView( db, name, (MSIVIEW**) &tv ); if( r != ERROR_SUCCESS ) @@ -1849,15 +1908,6 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg, if( r != ERROR_SUCCESS ) goto err; - /* read the transform data */ - r = ERROR_FUNCTION_FAILED; - read_stream_data( stg, name, &rawdata, &rawsize ); - if( !rawdata || (rawsize < 2) ) - { - ERR("odd sized transform for table %s\n", debugstr_w(name)); - goto err; - } - TRACE("name = %s columns = %u row_size = %u raw size = %u\n", debugstr_w(name), tv->num_cols, tv->row_size, rawsize ); @@ -1904,31 +1954,60 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg, rec = msi_get_transform_record( tv, st, &rawdata[n] ); if (rec) { - UINT row = 0; - - r = msi_table_find_row( tv, rec, &row ); - - if( rawdata[n] & 1) + if ( mask & 1 ) { - TRACE("insert [%d]: ", row); - TABLE_insert_row( &tv->view, rec ); - } - else if( mask & 0xff ) - { - TRACE("modify [%d]: ", row); - msi_table_modify_row( tv, rec, row, mask ); + TRACE("inserting record\n"); + + /* + * Native msi seems writes nul into the + * Number (2nd) column of the _Columns table. + * Not sure that it's deliberate... + */ + if (!lstrcmpW(name, szColumns)) + { + WCHAR table[32]; + DWORD sz = 32; + + MSI_RecordGetStringW( rec, 1, table, &sz ); + + /* reset the column number on a new table */ + if ( lstrcmpW(coltable, table) ) + { + colcol = 0; + lstrcpyW( coltable, table ); + } + + /* fix nul column numbers */ + MSI_RecordSetInteger( rec, 2, ++colcol ); + } + + r = TABLE_insert_row( &tv->view, rec ); + if (r != ERROR_SUCCESS) + ERR("insert row failed\n"); } else { - TRACE("delete [%d]: ", row); - msi_delete_row( tv, row ); + UINT row = 0; + + r = msi_table_find_row( tv, rec, &row ); + if (r != ERROR_SUCCESS) + ERR("no matching row to transform\n"); + else if ( mask ) + { + TRACE("modifying row [%d]:\n", row); + msi_table_modify_row( tv, rec, row, mask ); + } + else + { + TRACE("deleting row [%d]:\n", row); + msi_delete_row( tv, row ); + } } if( TRACE_ON(msidb) ) dump_record( rec ); msiobj_release( &rec->hdr ); } n += sz/2; - } err: @@ -1950,7 +2029,7 @@ UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg ) IEnumSTATSTG *stgenum = NULL; HRESULT r; STATSTG stat; - ULONG n, count; + ULONG count; WCHAR name[0x40]; string_table *strings; UINT ret = ERROR_FUNCTION_FAILED; @@ -1965,7 +2044,18 @@ UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg ) if( FAILED( r ) ) goto end; - n = 0; + /* + * Apply _Tables and _Coluimns transforms first so that + * the table metadata is correct, and empty tables exist. + */ + ret = msi_table_load_transform( db, stg, strings, szTables ); + if (ret != ERROR_SUCCESS && ret != ERROR_INVALID_TABLE) + goto end; + + ret = msi_table_load_transform( db, stg, strings, szColumns ); + if (ret != ERROR_SUCCESS && ret != ERROR_INVALID_TABLE) + goto end; + ret = ERROR_SUCCESS; while( r == ERROR_SUCCESS ) @@ -1974,12 +2064,20 @@ UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg ) r = IEnumSTATSTG_Next( stgenum, 1, &stat, &count ); if( FAILED( r ) || !count ) break; + decode_streamname( stat.pwcsName, name ); - if( ( name[0] == 0x4840 ) && ( name[1] != '_' ) ) - ret = msi_table_load_transform( db, stg, strings, name+1 ); - else - TRACE("transform contains stream %s\n", debugstr_w(name)); - n++; + if ( name[0] != 0x4840 ) + continue; + + TRACE("transform contains stream %s\n", debugstr_w(name)); + + if ( !lstrcmpW( name+1, szStringPool ) || + !lstrcmpW( name+1, szStringData ) || + !lstrcmpW( name+1, szColumns ) || + !lstrcmpW( name+1, szTables ) ) + continue; + + ret = msi_table_load_transform( db, stg, strings, name+1 ); } if ( ret == ERROR_SUCCESS ) diff --git a/reactos/dll/win32/msi/upgrade.c b/reactos/dll/win32/msi/upgrade.c index 63b1d99c309..da954997bb9 100644 --- a/reactos/dll/win32/msi/upgrade.c +++ b/reactos/dll/win32/msi/upgrade.c @@ -36,7 +36,6 @@ #include "msidefs.h" #include "msipriv.h" #include "winuser.h" -#include "action.h" #include "wine/unicode.h" WINE_DEFAULT_DEBUG_CHANNEL(msi); @@ -124,7 +123,7 @@ static UINT ITERATE_FindRelatedProducts(MSIRECORD *rec, LPVOID param) while (rc == ERROR_SUCCESS) { rc = RegEnumValueW(hkey, index, product, &sz, NULL, NULL, NULL, NULL); - TRACE("Looking at (%li) %s\n",index,debugstr_w(product)); + TRACE("Looking at (%i) %s\n",index,debugstr_w(product)); if (rc == ERROR_SUCCESS) { WCHAR productid[GUID_SIZE]; @@ -179,7 +178,7 @@ static UINT ITERATE_FindRelatedProducts(MSIRECORD *rec, LPVOID param) (LPBYTE)&check, &sz); RegCloseKey(hukey); language = MSI_RecordGetString(rec,4); - TRACE("Checking languages 0x%lx and %s\n", check, + TRACE("Checking languages %x and %s\n", check, debugstr_w(language)); if (!check_language(check, language, attributes)) {