msi: Implement and test MsiEnumComponentCostsA/W.

Hans Leidekker hans at codeweavers.com
Fri Apr 1 07:54:12 CDT 2011


See http://bugs.winehq.org/show_bug.cgi?id=26615
---
 dlls/msi/action.c        |    9 +--
 dlls/msi/msi.c           |  101 +++++++++++++++++++--
 dlls/msi/msi.spec        |    2 +-
 dlls/msi/msipriv.h       |    1 +
 dlls/msi/tests/package.c |  219 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 316 insertions(+), 16 deletions(-)

diff --git a/dlls/msi/action.c b/dlls/msi/action.c
index 73d6d1b..79d12d6 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 890132a..44a4e21 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 c1e3553..273e5dc 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 19e9be8..2dd2c9b 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 f74659e..d7161d1 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)
     {
-- 
1.7.1






More information about the wine-patches mailing list