diff --git a/reactos/dll/win32/msi/action.c b/reactos/dll/win32/msi/action.c index c8249045943..46249c20813 100644 --- a/reactos/dll/win32/msi/action.c +++ b/reactos/dll/win32/msi/action.c @@ -501,7 +501,7 @@ static UINT msi_apply_substorage_transform( MSIPACKAGE *package, return ERROR_SUCCESS; } -static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si ) +UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si ) { static const WCHAR szProdCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 }; LPWSTR guid_list, *guids, product_code; @@ -789,6 +789,9 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath, static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0}; static const WCHAR szAction[] = {'A','C','T','I','O','N',0}; static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0}; + static const WCHAR szReinstall[] = {'R','E','I','N','S','T','A','L','L',0}; + static const WCHAR szInstalled[] = {'I','n','s','t','a','l','l','e','d',0}; + static const WCHAR szAll[] = {'A','L','L',0}; MSI_SetPropertyW(package, szAction, szInstall); @@ -837,6 +840,12 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath, msi_apply_transforms( package ); msi_apply_patches( package ); + if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 )) + { + TRACE("setting reinstall property\n"); + MSI_SetPropertyW( package, szReinstall, szAll ); + } + /* properties may have been added by a transform */ msi_clone_properties( package ); msi_set_context( package ); @@ -871,6 +880,9 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath, /* finish up running custom actions */ ACTION_FinishCustomActions(package); + if (rc == ERROR_SUCCESS && package->need_reboot) + return ERROR_SUCCESS_REBOOT_REQUIRED; + return rc; } @@ -3378,16 +3390,12 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package) return ERROR_SUCCESS; res = CoInitialize( NULL ); - if (FAILED (res)) - { - ERR("CoInitialize failed\n"); - return ERROR_FUNCTION_FAILED; - } rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package); msiobj_release(&view->hdr); - CoUninitialize(); + if (SUCCEEDED(res)) + CoUninitialize(); return rc; } @@ -5308,8 +5316,7 @@ static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags ) } } - if (!*flags || - check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) || + if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) || check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) || check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) || check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK)) @@ -5318,6 +5325,9 @@ static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags ) return ERROR_FUNCTION_FAILED; } + if (!*flags) + *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE; + return ERROR_SUCCESS; } @@ -5345,6 +5355,8 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param ) name = MSI_RecordGetString(rec, 2); value = MSI_RecordGetString(rec, 3); + TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value)); + res = env_set_flags(&name, &value, &flags); if (res != ERROR_SUCCESS) goto done; diff --git a/reactos/dll/win32/msi/custom.c b/reactos/dll/win32/msi/custom.c index 3476f0d376b..5ac9c1b24d3 100644 --- a/reactos/dll/win32/msi/custom.c +++ b/reactos/dll/win32/msi/custom.c @@ -679,7 +679,7 @@ static DWORD ACTION_CallDllFunction( const GUID *guid ) hModule = LoadLibraryW( dll ); if (!hModule) { - ERR("failed to load dll %s\n", debugstr_w( dll ) ); + ERR("failed to load dll %s (%u)\n", debugstr_w( dll ), GetLastError() ); return r; } @@ -1046,15 +1046,16 @@ static UINT HANDLE_CustomType19(MSIPACKAGE *package, LPCWSTR source, if( row ) { LPCWSTR error = MSI_RecordGetString( row, 1 ); - MessageBoxW( NULL, error, NULL, MB_OK ); + if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE) + MessageBoxW( NULL, error, NULL, MB_OK ); msiobj_release( &row->hdr ); } - else + else if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE) MessageBoxW( NULL, deformated, NULL, MB_OK ); msi_free( deformated ); - return ERROR_FUNCTION_FAILED; + return ERROR_INSTALL_FAILURE; } static UINT HANDLE_CustomType50(MSIPACKAGE *package, LPCWSTR source, diff --git a/reactos/dll/win32/msi/files.c b/reactos/dll/win32/msi/files.c index 01a80b7437c..d9cc0fffb61 100644 --- a/reactos/dll/win32/msi/files.c +++ b/reactos/dll/win32/msi/files.c @@ -139,7 +139,7 @@ static UINT copy_file(MSIFILE *file, LPWSTR source) return ERROR_SUCCESS; } -static UINT copy_install_file(MSIFILE *file, LPWSTR source) +static UINT copy_install_file(MSIPACKAGE *package, MSIFILE *file, LPWSTR source) { UINT gle; @@ -153,7 +153,7 @@ static UINT copy_install_file(MSIFILE *file, LPWSTR source) if (gle == ERROR_ALREADY_EXISTS && file->state == msifs_overwrite) { TRACE("overwriting existing file\n"); - gle = ERROR_SUCCESS; + return ERROR_SUCCESS; } else if (gle == ERROR_ACCESS_DENIED) { @@ -162,6 +162,39 @@ static UINT copy_install_file(MSIFILE *file, LPWSTR source) gle = copy_file(file, source); TRACE("Overwriting existing file: %d\n", gle); } + if (gle == ERROR_SHARING_VIOLATION) + { + static const WCHAR msiW[] = {'m','s','i',0}; + static const WCHAR slashW[] = {'\\',0}; + WCHAR tmpfileW[MAX_PATH], *pathW, *p; + DWORD len; + + TRACE("file in use, scheduling rename operation\n"); + + GetTempFileNameW(slashW, msiW, 0, tmpfileW); + len = strlenW(file->TargetPath) + strlenW(tmpfileW) + 1; + if (!(pathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)))) + return ERROR_OUTOFMEMORY; + + strcpyW(pathW, file->TargetPath); + if ((p = strrchrW(pathW, '\\'))) *p = 0; + strcatW(pathW, tmpfileW); + + if (CopyFileW(source, pathW, FALSE) && + MoveFileExW(file->TargetPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT) && + MoveFileExW(pathW, file->TargetPath, MOVEFILE_DELAY_UNTIL_REBOOT)) + { + file->state = msifs_installed; + package->need_reboot = 1; + gle = ERROR_SUCCESS; + } + else + { + gle = GetLastError(); + WARN("failed to schedule rename operation: %d)\n", gle); + } + HeapFree(GetProcessHeap(), 0, pathW); + } return gle; } @@ -296,7 +329,7 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package) debugstr_w(file->TargetPath)); msi_file_update_ui(package, file, szInstallFiles); - rc = copy_install_file(file, source); + rc = copy_install_file(package, file, source); if (rc != ERROR_SUCCESS) { ERR("Failed to copy %s to %s (%d)\n", debugstr_w(source), diff --git a/reactos/dll/win32/msi/media.c b/reactos/dll/win32/msi/media.c index 2de3252d79d..83f46985ed9 100644 --- a/reactos/dll/win32/msi/media.c +++ b/reactos/dll/win32/msi/media.c @@ -49,11 +49,16 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); #define _O_TEXT 0x4000 #define _O_BINARY 0x8000 -static BOOL source_matches_volume(MSIMEDIAINFO *mi, LPWSTR source_root) +static BOOL source_matches_volume(MSIMEDIAINFO *mi, LPCWSTR source_root) { WCHAR volume_name[MAX_PATH + 1]; + WCHAR root[MAX_PATH + 1]; - if (!GetVolumeInformationW(source_root, volume_name, MAX_PATH + 1, + strcpyW(root, source_root); + PathStripToRootW(root); + PathAddBackslashW(root); + + if (!GetVolumeInformationW(root, volume_name, MAX_PATH + 1, NULL, NULL, NULL, NULL, 0)) { ERR("Failed to get volume information\n"); @@ -80,7 +85,6 @@ static UINT msi_change_media(MSIPACKAGE *package, MSIMEDIAINFO *mi) error = generate_error_string(package, 1302, 1, mi->disk_prompt); error_dialog = msi_dup_property(package, error_prop); source_dir = msi_dup_property(package, cszSourceDir); - PathStripToRootW(source_dir); while (r == ERROR_SUCCESS && !source_matches_volume(mi, source_dir)) @@ -333,11 +337,56 @@ static INT_PTR cabinet_copy_file(FDINOTIFICATIONTYPE fdint, NULL, CREATE_ALWAYS, attrs, NULL); if (handle == INVALID_HANDLE_VALUE) { - if (GetFileAttributesW(path) == INVALID_FILE_ATTRIBUTES) - ERR("failed to create %s (error %d)\n", - debugstr_w(path), GetLastError()); + DWORD err = GetLastError(); + DWORD attrs2 = GetFileAttributesW(path); - goto done; + if (attrs2 == INVALID_FILE_ATTRIBUTES) + { + ERR("failed to create %s (error %d)\n", debugstr_w(path), err); + goto done; + } + else if (err == ERROR_ACCESS_DENIED && (attrs2 & FILE_ATTRIBUTE_READONLY)) + { + TRACE("removing read-only attribute on %s\n", debugstr_w(path)); + SetFileAttributesW( path, attrs2 & ~FILE_ATTRIBUTE_READONLY ); + handle = CreateFileW(path, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, attrs2, NULL); + + if (handle != INVALID_HANDLE_VALUE) goto done; + err = GetLastError(); + } + if (err == ERROR_SHARING_VIOLATION) + { + static const WCHAR msiW[] = {'m','s','i',0}; + static const WCHAR slashW[] = {'\\',0}; + WCHAR tmpfileW[MAX_PATH], *tmppathW, *p; + DWORD len; + + TRACE("file in use, scheduling rename operation\n"); + + GetTempFileNameW(slashW, msiW, 0, tmpfileW); + len = strlenW(path) + strlenW(tmpfileW) + 1; + if (!(tmppathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)))) + return ERROR_OUTOFMEMORY; + + strcpyW(tmppathW, path); + if ((p = strrchrW(tmppathW, '\\'))) *p = 0; + strcatW(tmppathW, tmpfileW); + + handle = CreateFileW(tmppathW, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, attrs, NULL); + + if (handle != INVALID_HANDLE_VALUE && + MoveFileExW(path, NULL, MOVEFILE_DELAY_UNTIL_REBOOT) && + MoveFileExW(tmppathW, path, MOVEFILE_DELAY_UNTIL_REBOOT)) + { + data->package->need_reboot = 1; + } + else + WARN("failed to schedule rename operation %s (error %d)\n", debugstr_w(path), GetLastError()); + + HeapFree(GetProcessHeap(), 0, tmppathW); + } + else + WARN("failed to create %s (error %d)\n", debugstr_w(path), err); } done: @@ -455,6 +504,17 @@ void msi_free_media_info(MSIMEDIAINFO *mi) msi_free(mi); } +static UINT get_drive_type(const WCHAR *path) +{ + WCHAR root[MAX_PATH + 1]; + + strcpyW(root, path); + PathStripToRootW(root); + PathAddBackslashW(root); + + return GetDriveTypeW(root); +} + static UINT msi_load_media_info(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO *mi) { MSIRECORD *row; @@ -494,9 +554,7 @@ static UINT msi_load_media_info(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO source_dir = msi_dup_property(package, cszSourceDir); lstrcpyW(mi->source, source_dir); - - PathStripToRootW(source_dir); - mi->type = GetDriveTypeW(source_dir); + mi->type = get_drive_type(source_dir); if (file->IsCompressed && mi->cabinet) { @@ -576,7 +634,6 @@ static UINT find_published_source(MSIPACKAGE *package, MSIMEDIAINFO *mi) { /* FIXME: what about SourceDir */ lstrcpyW(mi->source, source); - lstrcatW(mi->source, mi->cabinet); return ERROR_SUCCESS; } } diff --git a/reactos/dll/win32/msi/msi.c b/reactos/dll/win32/msi/msi.c index be1ad93bf9f..2a66d601a8e 100644 --- a/reactos/dll/win32/msi/msi.c +++ b/reactos/dll/win32/msi/msi.c @@ -489,13 +489,86 @@ UINT WINAPI MsiDetermineApplicablePatchesA(LPCSTR szProductPackagePath, return ERROR_CALL_NOT_IMPLEMENTED; } +static UINT MSI_ApplicablePatchW( MSIPACKAGE *package, LPCWSTR patch ) +{ + MSISUMMARYINFO *si; + MSIDATABASE *patch_db; + UINT r = ERROR_SUCCESS; + + r = MSI_OpenDatabaseW( patch, MSIDBOPEN_READONLY, &patch_db ); + if (r != ERROR_SUCCESS) + { + WARN("failed to open patch file %s\n", debugstr_w(patch)); + return r; + } + + si = MSI_GetSummaryInformationW( patch_db->storage, 0 ); + if (!si) + { + r = ERROR_FUNCTION_FAILED; + goto done; + } + + r = msi_check_patch_applicable( package, si ); + if (r != ERROR_SUCCESS) + TRACE("patch not applicable\n"); + +done: + msiobj_release( &patch_db->hdr ); + msiobj_release( &si->hdr ); + return r; +} + UINT WINAPI MsiDetermineApplicablePatchesW(LPCWSTR szProductPackagePath, DWORD cPatchInfo, PMSIPATCHSEQUENCEINFOW pPatchInfo) { - FIXME("(%s, %d, %p): stub!\n", debugstr_w(szProductPackagePath), - cPatchInfo, pPatchInfo); + UINT i, r, ret = ERROR_FUNCTION_FAILED; + MSIPACKAGE *package; - return ERROR_CALL_NOT_IMPLEMENTED; + TRACE("(%s, %d, %p)\n", debugstr_w(szProductPackagePath), cPatchInfo, pPatchInfo); + + r = MSI_OpenPackageW( szProductPackagePath, &package ); + if (r != ERROR_SUCCESS) + { + ERR("failed to open package %u\n", r); + return r; + } + + for (i = 0; i < cPatchInfo; i++) + { + switch (pPatchInfo[i].ePatchDataType) + { + case MSIPATCH_DATATYPE_PATCHFILE: + { + FIXME("patch ordering not supported\n"); + r = MSI_ApplicablePatchW( package, pPatchInfo[i].szPatchData ); + if (r != ERROR_SUCCESS) + { + pPatchInfo[i].dwOrder = ~0u; + pPatchInfo[i].uStatus = ERROR_PATCH_TARGET_NOT_FOUND; + } + else + { + pPatchInfo[i].dwOrder = i; + pPatchInfo[i].uStatus = ret = ERROR_SUCCESS; + } + break; + } + default: + { + FIXME("patch data type %u not supported\n", pPatchInfo[i].ePatchDataType); + pPatchInfo[i].dwOrder = ~0u; + pPatchInfo[i].uStatus = ERROR_PATCH_TARGET_NOT_FOUND; + break; + } + } + + TRACE(" szPatchData: %s\n", debugstr_w(pPatchInfo[i].szPatchData)); + TRACE("ePatchDataType: %u\n", pPatchInfo[i].ePatchDataType); + TRACE(" dwOrder: %u\n", pPatchInfo[i].dwOrder); + TRACE(" uStatus: %u\n", pPatchInfo[i].uStatus); + } + return ret; } UINT WINAPI MsiDeterminePatchSequenceA(LPCSTR szProductCode, LPCSTR szUserSid, @@ -620,9 +693,6 @@ UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel, if (szCommandLine) lstrcpyW(commandline,szCommandLine); - if (MsiQueryProductStateW(szProduct) != INSTALLSTATE_UNKNOWN) - lstrcatW(commandline,szInstalled); - if (eInstallState == INSTALLSTATE_ABSENT) lstrcatW(commandline, szRemoveAll); diff --git a/reactos/dll/win32/msi/msipriv.h b/reactos/dll/win32/msi/msipriv.h index b61d7b6f245..71c3b69bfa7 100644 --- a/reactos/dll/win32/msi/msipriv.h +++ b/reactos/dll/win32/msi/msipriv.h @@ -340,6 +340,7 @@ typedef struct tagMSIPACKAGE unsigned char scheduled_action_running : 1; unsigned char commit_action_running : 1; unsigned char rollback_action_running : 1; + unsigned char need_reboot : 1; } MSIPACKAGE; typedef struct tagMSIPREVIEW @@ -683,6 +684,8 @@ extern UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db, LPCWSTR szTransformFile, int iErrorCond ); extern void append_storage_to_db( MSIDATABASE *db, IStorage *stg ); +extern UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si ); + /* action internals */ extern UINT MSI_InstallPackage( MSIPACKAGE *, LPCWSTR, LPCWSTR ); extern void ACTION_free_package_structures( MSIPACKAGE* ); diff --git a/reactos/dll/win32/msi/msiserver.idl b/reactos/dll/win32/msi/msiserver.idl index 546b75821ca..ac442dbd076 100644 --- a/reactos/dll/win32/msi/msiserver.idl +++ b/reactos/dll/win32/msi/msiserver.idl @@ -424,4 +424,4 @@ library WindowsInstaller properties: methods: } -} \ No newline at end of file +} diff --git a/reactos/dll/win32/msi/package.c b/reactos/dll/win32/msi/package.c index 82de944e7a7..f74bf05ab5c 100644 --- a/reactos/dll/win32/msi/package.c +++ b/reactos/dll/win32/msi/package.c @@ -453,13 +453,14 @@ static VOID set_installer_properties(MSIPACKAGE *package) static const WCHAR szTime[] = {'T','i','m','e',0}; static const WCHAR szUserLangID[] = {'U','s','e','r','L','a','n','g','u','a','g','e','I','D',0}; static const WCHAR szSystemLangID[] = {'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0}; + static const WCHAR szProductState[] = {'P','r','o','d','u','c','t','S','t','a','t','e',0}; /* * Other things that probably should be set: * * ComputerName LogonUser VirtualMemory * ShellAdvSupport DefaultUIFont PackagecodeChanging - * ProductState CaptionHeight BorderTop BorderSide TextHeight + * CaptionHeight BorderTop BorderSide TextHeight * RedirectedDllSupport */ @@ -658,6 +659,9 @@ static VOID set_installer_properties(MSIPACKAGE *package) sprintfW(bufstr, szIntFormat, langid); MSI_SetPropertyW( package, szSystemLangID, bufstr ); + + sprintfW(bufstr, szIntFormat, MsiQueryProductStateW(package->ProductCode)); + MSI_SetPropertyW( package, szProductState, bufstr ); } static UINT msi_load_summary_properties( MSIPACKAGE *package ) @@ -804,12 +808,14 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPCWSTR base_url ) create_temp_property_table( package ); msi_clone_properties( package ); - set_installer_properties(package); - sprintfW(uilevel,szpi,gUILevel); - MSI_SetPropertyW(package, szLevel, uilevel); package->ProductCode = msi_dup_property( package, szProductCode ); set_installed_prop( package ); + set_installer_properties( package ); + + sprintfW(uilevel,szpi,gUILevel); + MSI_SetPropertyW(package, szLevel, uilevel); + r = msi_load_summary_properties( package ); if (r != ERROR_SUCCESS) { diff --git a/reactos/dll/win32/msi/suminfo.c b/reactos/dll/win32/msi/suminfo.c index a02f949cb24..ef16665b781 100644 --- a/reactos/dll/win32/msi/suminfo.c +++ b/reactos/dll/win32/msi/suminfo.c @@ -475,7 +475,9 @@ UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase, if( szDatabase ) { - ret = MSI_OpenDatabaseW( szDatabase, NULL, &db ); + LPCWSTR persist = uiUpdateCount ? MSIDBOPEN_TRANSACT : MSIDBOPEN_READONLY; + + ret = MSI_OpenDatabaseW( szDatabase, persist, &db ); if( ret != ERROR_SUCCESS ) return ret; } diff --git a/reactos/dll/win32/msi/table.c b/reactos/dll/win32/msi/table.c index b963a2022fd..86cd4be4a79 100644 --- a/reactos/dll/win32/msi/table.c +++ b/reactos/dll/win32/msi/table.c @@ -2777,7 +2777,7 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg, r = TABLE_insert_row( &tv->view, rec, -1, FALSE ); if (r != ERROR_SUCCESS) - ERR("insert row failed\n"); + WARN("insert row failed\n"); if ( number != MSI_NULL_INTEGER && !lstrcmpW(name, szColumns) ) msi_update_table_columns( db, table ); @@ -2788,7 +2788,7 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg, r = msi_table_find_row( tv, rec, &row ); if (r != ERROR_SUCCESS) - ERR("no matching row to transform\n"); + WARN("no matching row to transform\n"); else if ( mask ) { TRACE("modifying row [%d]:\n", row); diff --git a/reactos/include/psdk/msi.h b/reactos/include/psdk/msi.h index 5e68fdc278c..2c0a37fe43b 100644 --- a/reactos/include/psdk/msi.h +++ b/reactos/include/psdk/msi.h @@ -237,6 +237,8 @@ typedef struct tagMSIPATCHSEQUENCEINFOW #define MAX_FEATURE_CHARS 38 +#define ERROR_PATCH_TARGET_NOT_FOUND 1642 + /* Strings defined in msi.h */ /* Advertised Information */