diff --git a/dlls/msi/action.c b/dlls/msi/action.c index 73d6d1bdb741edc67f5d281ef36ae303f9686062..79d12d65bb27200a8d8aca96c477459728c4a95c 100644 --- a/dlls/msi/action.c +++ b/dlls/msi/action.c @@ -2007,10 +2007,7 @@ static UINT load_all_folders( MSIPACKAGE *package ) */ static UINT ACTION_CostInitialize(MSIPACKAGE *package) { - static const WCHAR szCosting[] = - {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 }; - - msi_set_property( package->db, szCosting, szZero ); + msi_set_property( package->db, szCostingComplete, szZero ); msi_set_property( package->db, cszRootDrive, c_colon ); load_all_folders( package ); @@ -2639,8 +2636,6 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) static const WCHAR ConditionQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', '`','C','o','n','d','i','t','i','o','n','`',0}; - static const WCHAR szCosting[] = - {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 }; static const WCHAR szlevel[] = {'I','N','S','T','A','L','L','L','E','V','E','L',0}; static const WCHAR szOutOfDiskSpace[] = @@ -2691,7 +2686,7 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) TRACE("Calculating file cost\n"); calculate_file_cost( package ); - msi_set_property( package->db, szCosting, szOne ); + msi_set_property( package->db, szCostingComplete, szOne ); /* set default run level if not set */ level = msi_dup_property( package->db, szlevel ); if (!level) diff --git a/dlls/msi/msi.c b/dlls/msi/msi.c index 890132aa6cca29e147b701981409faebf2531050..44a4e210466da4fc8e2d4d4e83003f78eee4f9d1 100644 --- a/dlls/msi/msi.c +++ b/dlls/msi/msi.c @@ -1794,16 +1794,101 @@ UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes) return ERROR_SUCCESS; } -UINT WINAPI MsiEnumComponentCostsW(MSIHANDLE hInstall, LPCWSTR szComponent, - DWORD dwIndex, INSTALLSTATE iState, - LPWSTR lpDriveBuf, DWORD *pcchDriveBuf, - int *piCost, int *pTempCost) +UINT WINAPI MsiEnumComponentCostsA( MSIHANDLE handle, LPCSTR component, DWORD index, + INSTALLSTATE state, LPSTR drive, DWORD *buflen, + int *cost, int *temp ) { - FIXME("(%d, %s, %d, %d, %p, %p, %p %p): stub!\n", hInstall, - debugstr_w(szComponent), dwIndex, iState, lpDriveBuf, - pcchDriveBuf, piCost, pTempCost); + UINT r; + DWORD len; + WCHAR *driveW, *componentW = NULL; + + TRACE("%d, %s, %u, %d, %p, %p, %p %p\n", handle, debugstr_a(component), index, + state, drive, buflen, cost, temp); + + if (!drive || !buflen) return ERROR_INVALID_PARAMETER; + if (component && !(componentW = strdupAtoW( component ))) return ERROR_OUTOFMEMORY; + + len = *buflen; + if (!(driveW = msi_alloc( len * sizeof(WCHAR) ))) + { + msi_free( componentW ); + return ERROR_OUTOFMEMORY; + } + r = MsiEnumComponentCostsW( handle, componentW, index, state, driveW, buflen, cost, temp ); + if (!r) + { + WideCharToMultiByte( CP_ACP, 0, driveW, -1, drive, len, NULL, NULL ); + } + msi_free( componentW ); + msi_free( driveW ); + return r; +} + +UINT WINAPI MsiEnumComponentCostsW( MSIHANDLE handle, LPCWSTR component, DWORD index, + INSTALLSTATE state, LPWSTR drive, DWORD *buflen, + int *cost, int *temp ) +{ + UINT r = ERROR_NO_MORE_ITEMS; + MSICOMPONENT *comp = NULL; + MSIPACKAGE *package; + MSIFILE *file; + STATSTG stat = {0}; + WCHAR path[MAX_PATH]; + + TRACE("%d, %s, %u, %d, %p, %p, %p %p\n", handle, debugstr_w(component), index, + state, drive, buflen, cost, temp); + + if (!drive || !buflen || !cost || !temp) return ERROR_INVALID_PARAMETER; + if (!(package = msihandle2msiinfo( handle, MSIHANDLETYPE_PACKAGE ))) return ERROR_INVALID_HANDLE; + if (!msi_get_property_int( package->db, szCostingComplete, 0 )) + { + msiobj_release( &package->hdr ); + return ERROR_FUNCTION_NOT_CALLED; + } + if (component && component[0] && !(comp = get_loaded_component( package, component ))) + { + msiobj_release( &package->hdr ); + return ERROR_UNKNOWN_COMPONENT; + } + if (*buflen < 3) + { + *buflen = 2; + msiobj_release( &package->hdr ); + return ERROR_MORE_DATA; + } + if (index) + { + msiobj_release( &package->hdr ); + return ERROR_NO_MORE_ITEMS; + } - return ERROR_NO_MORE_ITEMS; + drive[0] = 0; + *cost = *temp = 0; + if (component && component[0]) + { + *cost = max( 8, comp->Cost / 512 ); + if (comp->assembly && !comp->assembly->application) *temp = comp->Cost; + if ((file = get_loaded_file( package, comp->KeyPath ))) + { + drive[0] = file->TargetPath[0]; + drive[1] = ':'; + drive[2] = 0; + *buflen = 2; + r = ERROR_SUCCESS; + } + } + else if (IStorage_Stat( package->db->storage, &stat, STATFLAG_NONAME ) == S_OK) + { + *temp = max( 8, stat.cbSize.QuadPart / 512 ); + GetWindowsDirectoryW( path, MAX_PATH ); + drive[0] = path[0]; + drive[1] = ':'; + drive[2] = 0; + *buflen = 2; + r = ERROR_SUCCESS; + } + msiobj_release( &package->hdr ); + return r; } UINT WINAPI MsiQueryComponentStateA(LPCSTR szProductCode, diff --git a/dlls/msi/msi.spec b/dlls/msi/msi.spec index c1e35530782541e3a292609590abf5da62792240..273e5dcb39506e2487c78d28d9e650c5fe18eef8 100644 --- a/dlls/msi/msi.spec +++ b/dlls/msi/msi.spec @@ -213,7 +213,7 @@ 217 stdcall MsiGetShortcutTargetW(wstr ptr ptr ptr) 218 stdcall MsiGetFileHashA(str long ptr) 219 stdcall MsiGetFileHashW(wstr long ptr) -220 stub MsiEnumComponentCostsA +220 stdcall MsiEnumComponentCostsA(long str long long ptr ptr ptr ptr) 221 stdcall MsiEnumComponentCostsW(long wstr long long ptr ptr ptr ptr) 222 stdcall MsiCreateAndVerifyInstallerDirectory(long) 223 stdcall MsiGetFileSignatureInformationA(str long ptr ptr ptr) diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index 19e9be899e1cee3794a716c71efd7e8c04ffc17b..2dd2c9b9a7e2361d5cf8cabca8100f32891dc24c 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -1108,6 +1108,7 @@ static const WCHAR szWow6432Node[] = {'W','o','w','6','4','3','2','N','o','d','e static const WCHAR szStreams[] = {'_','S','t','r','e','a','m','s',0}; static const WCHAR szStorages[] = {'_','S','t','o','r','a','g','e','s',0}; static const WCHAR szMsiPublishAssemblies[] = {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0}; +static const WCHAR szCostingComplete[] = {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0}; /* memory allocation macro functions */ static void *msi_alloc( size_t len ) __WINE_ALLOC_SIZE(1); diff --git a/dlls/msi/tests/package.c b/dlls/msi/tests/package.c index f74659e5c9f28a11c3362c2e442770a1a8f35996..d7161d17f78276f400b272383526f129cbeeb20c 100644 --- a/dlls/msi/tests/package.c +++ b/dlls/msi/tests/package.c @@ -12907,6 +12907,224 @@ static void test_MsiApplyPatch(void) ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", r); } +static void test_MsiEnumComponentCosts(void) +{ + MSIHANDLE hdb, hpkg; + char package[12], drive[3]; + DWORD len; + UINT r; + int cost, temp; + + hdb = create_package_db(); + ok( hdb, "failed to create database\n" ); + + r = create_property_table( hdb ); + ok( r == ERROR_SUCCESS, "cannot create Property table %u\n", r ); + + r = add_property_entry( hdb, "'ProductCode', '{379B1C47-40C1-42FA-A9BB-BEBB6F1B0172}'" ); + ok( r == ERROR_SUCCESS, "cannot add property entry %u\n", r ); + + r = add_property_entry( hdb, "'MSIFASTINSTALL', '1'" ); + ok( r == ERROR_SUCCESS, "cannot add property entry %u\n", r ); + + r = add_directory_entry( hdb, "'TARGETDIR', '', 'SourceDir'" ); + ok( r == ERROR_SUCCESS, "failed to add directory entry %u\n" , r ); + + r = create_media_table( hdb ); + ok( r == ERROR_SUCCESS, "cannot create Media table %u\n", r ); + + r = add_media_entry( hdb, "'1', '2', 'cabinet', '', '', ''"); + ok( r == ERROR_SUCCESS, "cannot add media entry %u\n", r ); + + r = create_file_table( hdb ); + ok( r == ERROR_SUCCESS, "cannot create File table %u\n", r ); + + r = add_file_entry( hdb, "'one.txt', 'one', 'one.txt', 4096, '', '', 8192, 1" ); + ok( r == ERROR_SUCCESS, "cannot add file %u\n", r ); + + r = add_file_entry( hdb, "'two.txt', 'two', 'two.txt', 8192, '', '', 8192, 2" ); + ok( r == ERROR_SUCCESS, "cannot add file %u\n", r ); + + r = create_component_table( hdb ); + ok( r == ERROR_SUCCESS, "cannot create Component table %u\n", r ); + + r = add_component_entry( hdb, "'one', '{B2F86B9D-8447-4BC5-8883-750C45AA31CA}', 'TARGETDIR', 0, '', 'one.txt'" ); + ok( r == ERROR_SUCCESS, "cannot add component %u\n", r ); + + r = add_component_entry( hdb, "'two', '{62A09F6E-0B74-4829-BDB7-CAB66F42CCE8}', 'TARGETDIR', 0, '', 'two.txt'" ); + ok( r == ERROR_SUCCESS, "cannot add component %u\n", r ); + + r = create_feature_table( hdb ); + ok( r == ERROR_SUCCESS, "cannot create Feature table %u\n", r ); + + r = add_feature_entry( hdb, "'one', '', '', '', 0, 1, '', 0" ); + ok( r == ERROR_SUCCESS, "cannot add feature %u\n", r ); + + r = add_feature_entry( hdb, "'two', '', '', '', 0, 1, '', 0" ); + ok( r == ERROR_SUCCESS, "cannot add feature %u\n", r ); + + r = create_feature_components_table( hdb ); + ok( r == ERROR_SUCCESS, "cannot create FeatureComponents table %u\n", r ); + + r = add_feature_components_entry( hdb, "'one', 'one'" ); + ok( r == ERROR_SUCCESS, "cannot add feature/component pair %u\n", r ); + + r = add_feature_components_entry( hdb, "'two', 'two'" ); + ok( r == ERROR_SUCCESS, "cannot add feature/component pair %u\n", r ); + + r = create_install_execute_sequence_table( hdb ); + ok( r == ERROR_SUCCESS, "cannot create InstallExecuteSequence table %u\n", r ); + + r = add_install_execute_sequence_entry( hdb, "'CostInitialize', '', '800'" ); + ok( r == ERROR_SUCCESS, "cannot add install execute sequence entry %u\n", r ); + + r = add_install_execute_sequence_entry( hdb, "'FileCost', '', '900'" ); + ok( r == ERROR_SUCCESS, "cannot add install execute sequence entry %u\n", r ); + + r = add_install_execute_sequence_entry( hdb, "'CostFinalize', '', '1000'" ); + ok( r == ERROR_SUCCESS, "cannot add install execute sequence entry %u\n", r ); + + r = add_install_execute_sequence_entry( hdb, "'InstallValidate', '', '1100'" ); + ok( r == ERROR_SUCCESS, "cannot add install execute sequence entry %u\n", r ); + + MsiDatabaseCommit( hdb ); + + sprintf( package, "#%u", hdb ); + r = MsiOpenPackageA( package, &hpkg ); + if (r == ERROR_INSTALL_PACKAGE_REJECTED) + { + skip("Not enough rights to perform tests\n"); + goto error; + } + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r ); + + r = MsiEnumComponentCostsA( 0, NULL, 0, INSTALLSTATE_UNKNOWN, NULL, NULL, NULL, NULL ); + ok( r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", r ); + + r = MsiEnumComponentCostsA( hpkg, NULL, 0, INSTALLSTATE_UNKNOWN, NULL, NULL, NULL, NULL ); + ok( r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", r ); + + r = MsiEnumComponentCostsA( hpkg, NULL, 0, INSTALLSTATE_UNKNOWN, NULL, NULL, NULL, NULL ); + ok( r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", r ); + + r = MsiEnumComponentCostsA( hpkg, "", 0, INSTALLSTATE_UNKNOWN, NULL, NULL, NULL, NULL ); + ok( r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", r ); + + r = MsiEnumComponentCostsA( hpkg, "one", 0, INSTALLSTATE_UNKNOWN, NULL, NULL, NULL, NULL ); + ok( r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", r ); + + r = MsiEnumComponentCostsA( hpkg, "one", 0, INSTALLSTATE_LOCAL, NULL, NULL, NULL, NULL ); + ok( r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", r ); + + r = MsiEnumComponentCostsA( hpkg, "one", 0, INSTALLSTATE_LOCAL, drive, NULL, NULL, NULL ); + ok( r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", r ); + + len = sizeof(drive); + r = MsiEnumComponentCostsA( hpkg, "one", 0, INSTALLSTATE_LOCAL, drive, &len, NULL, NULL ); + ok( r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", r ); + + len = sizeof(drive); + r = MsiEnumComponentCostsA( hpkg, "one", 0, INSTALLSTATE_LOCAL, drive, &len, &cost, NULL ); + ok( r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", r ); + + len = sizeof(drive); + r = MsiEnumComponentCostsA( hpkg, "one", 0, INSTALLSTATE_LOCAL, drive, &len, &cost, &temp ); + todo_wine ok( r == ERROR_INVALID_HANDLE_STATE, "Expected ERROR_INVALID_HANDLE_STATE, got %u\n", r ); + + len = sizeof(drive); + r = MsiEnumComponentCostsA( hpkg, "one", 0, INSTALLSTATE_LOCAL, NULL, &len, &cost, &temp ); + ok( r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", r ); + + MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL ); + + r = MsiDoAction( hpkg, "CostInitialize" ); + ok( r == ERROR_SUCCESS, "CostInitialize failed %u\n", r ); + + r = MsiDoAction( hpkg, "FileCost" ); + ok( r == ERROR_SUCCESS, "FileCost failed %u\n", r ); + + len = sizeof(drive); + r = MsiEnumComponentCostsA( hpkg, "one", 0, INSTALLSTATE_LOCAL, drive, &len, &cost, &temp ); + ok( r == ERROR_FUNCTION_NOT_CALLED, "Expected ERROR_FUNCTION_NOT_CALLED, got %u\n", r ); + + r = MsiDoAction( hpkg, "CostFinalize" ); + ok( r == ERROR_SUCCESS, "CostFinalize failed %u\n", r ); + + /* contrary to what msdn says InstallValidate must be called too */ + len = sizeof(drive); + r = MsiEnumComponentCostsA( hpkg, "one", 0, INSTALLSTATE_LOCAL, drive, &len, &cost, &temp ); + todo_wine ok( r == ERROR_FUNCTION_NOT_CALLED, "Expected ERROR_FUNCTION_NOT_CALLED, got %u\n", r ); + + r = MsiDoAction( hpkg, "InstallValidate" ); + ok( r == ERROR_SUCCESS, "InstallValidate failed %u\n", r ); + + len = 0; + r = MsiEnumComponentCostsA( hpkg, "three", 0, INSTALLSTATE_LOCAL, drive, &len, &cost, &temp ); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %u\n", r ); + + len = 0; + r = MsiEnumComponentCostsA( hpkg, "one", 0, INSTALLSTATE_LOCAL, drive, &len, &cost, &temp ); + ok( r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %u\n", r ); + ok( len == 2, "expected len == 2, got %u\n", len ); + + len = 2; + r = MsiEnumComponentCostsA( hpkg, "one", 0, INSTALLSTATE_LOCAL, drive, &len, &cost, &temp ); + ok( r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %u\n", r ); + ok( len == 2, "expected len == 2, got %u\n", len ); + + len = 2; + r = MsiEnumComponentCostsA( hpkg, "one", 0, INSTALLSTATE_UNKNOWN, drive, &len, &cost, &temp ); + ok( r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %u\n", r ); + ok( len == 2, "expected len == 2, got %u\n", len ); + + /* install state doesn't seem to matter */ + len = sizeof(drive); + r = MsiEnumComponentCostsA( hpkg, "one", 0, INSTALLSTATE_UNKNOWN, drive, &len, &cost, &temp ); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r ); + + len = sizeof(drive); + r = MsiEnumComponentCostsA( hpkg, "one", 0, INSTALLSTATE_ABSENT, drive, &len, &cost, &temp ); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r ); + + len = sizeof(drive); + r = MsiEnumComponentCostsA( hpkg, "one", 0, INSTALLSTATE_SOURCE, drive, &len, &cost, &temp ); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r ); + + len = sizeof(drive); + drive[0] = 0; + cost = temp = 0xdead; + r = MsiEnumComponentCostsA( hpkg, "one", 0, INSTALLSTATE_LOCAL, drive, &len, &cost, &temp ); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r ); + ok( len == 2, "expected len == 2, got %u\n", len ); + ok( drive[0], "expected a drive\n" ); + ok( cost && cost != 0xdead, "expected cost > 0, got %d\n", cost ); + ok( !temp, "expected temp == 0, got %d\n", temp ); + + len = sizeof(drive); + drive[0] = 0; + cost = temp = 0xdead; + r = MsiEnumComponentCostsA( hpkg, "", 0, INSTALLSTATE_UNKNOWN, drive, &len, &cost, &temp ); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r ); + ok( len == 2, "expected len == 2, got %u\n", len ); + ok( drive[0], "expected a drive\n" ); + ok( !cost, "expected cost == 0, got %d\n", cost ); + ok( temp && temp != 0xdead, "expected temp > 0, got %d\n", temp ); + + /* increased index */ + len = sizeof(drive); + r = MsiEnumComponentCostsA( hpkg, "one", 1, INSTALLSTATE_LOCAL, drive, &len, &cost, &temp ); + ok( r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %u\n", r ); + + len = sizeof(drive); + r = MsiEnumComponentCostsA( hpkg, "", 1, INSTALLSTATE_UNKNOWN, drive, &len, &cost, &temp ); + ok( r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %u\n", r ); + + MsiCloseHandle( hpkg ); +error: + MsiCloseHandle( hdb ); + DeleteFileA( msifile ); +} + START_TEST(package) { STATEMGRSTATUS status; @@ -12962,6 +13180,7 @@ START_TEST(package) test_MsiSetProperty(); test_MsiApplyMultiplePatches(); test_MsiApplyPatch(); + test_MsiEnumComponentCosts(); if (pSRSetRestorePointA && !pMsiGetComponentPathExA && ret) {