[4/5] msi: Implement and test MsiGetFeatureInfo.

Hans Leidekker hans at codeweavers.com
Fri Jun 10 03:13:34 CDT 2011


---
 dlls/msi/action.c        |    8 ++--
 dlls/msi/install.c       |  120 ++++++++++++++++++++++++++++++++++++++++++++++
 dlls/msi/msi.spec        |    4 +-
 dlls/msi/msipriv.h       |    2 +
 dlls/msi/tests/install.c |   84 ++++++++++++++++++++++++++++++++
 include/msi.h            |   14 +++++
 6 files changed, 226 insertions(+), 6 deletions(-)

diff --git a/dlls/msi/action.c b/dlls/msi/action.c
index 3f6eae7..437c8d9 100644
--- a/dlls/msi/action.c
+++ b/dlls/msi/action.c
@@ -999,7 +999,7 @@ static UINT load_component( MSIRECORD *row, LPVOID param )
     return ERROR_SUCCESS;
 }
 
-static UINT load_all_components( MSIPACKAGE *package )
+UINT msi_load_all_components( MSIPACKAGE *package )
 {
     static const WCHAR query[] = {
         'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ', 
@@ -1161,7 +1161,7 @@ static UINT find_feature_children(MSIRECORD * row, LPVOID param)
     return ERROR_SUCCESS;
 }
 
-static UINT load_all_features( MSIPACKAGE *package )
+UINT msi_load_all_features( MSIPACKAGE *package )
 {
     static const WCHAR query[] = {
         'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
@@ -1550,8 +1550,8 @@ static UINT ACTION_CostInitialize(MSIPACKAGE *package)
     msi_set_property( package->db, szRootDrive, szCRoot );
 
     load_all_folders( package );
-    load_all_components( package );
-    load_all_features( package );
+    msi_load_all_components( package );
+    msi_load_all_features( package );
     load_all_files( package );
     load_all_patches( package );
     load_all_media( package );
diff --git a/dlls/msi/install.c b/dlls/msi/install.c
index 31ab558..6225281 100644
--- a/dlls/msi/install.c
+++ b/dlls/msi/install.c
@@ -1255,6 +1255,126 @@ UINT WINAPI MsiGetFeatureCostW(MSIHANDLE hInstall, LPCWSTR szFeature,
 }
 
 /***********************************************************************
+* MsiGetFeatureInfoA   (MSI.@)
+*/
+UINT WINAPI MsiGetFeatureInfoA( MSIHANDLE handle, LPCSTR feature, LPDWORD attrs,
+                                LPSTR title, LPDWORD title_len, LPSTR help, LPDWORD help_len )
+{
+    UINT r;
+    WCHAR *titleW = NULL, *helpW = NULL, *featureW = NULL;
+
+    TRACE("%u, %s, %p, %p, %p, %p, %p\n", handle, debugstr_a(feature), attrs, title,
+          title_len, help, help_len);
+
+    if (feature && !(featureW = strdupAtoW( feature ))) return ERROR_OUTOFMEMORY;
+
+    if (title && title_len && !(titleW = msi_alloc( *title_len * sizeof(WCHAR) )))
+    {
+        msi_free( featureW );
+        return ERROR_OUTOFMEMORY;
+    }
+    if (help && help_len && !(helpW = msi_alloc( *help_len * sizeof(WCHAR) )))
+    {
+        msi_free( featureW );
+        msi_free( titleW );
+        return ERROR_OUTOFMEMORY;
+    }
+    r = MsiGetFeatureInfoW( handle, featureW, attrs, titleW, title_len, helpW, help_len );
+    if (r == ERROR_SUCCESS)
+    {
+        if (titleW) WideCharToMultiByte( CP_ACP, 0, titleW, -1, title, *title_len + 1, NULL, NULL );
+        if (helpW) WideCharToMultiByte( CP_ACP, 0, helpW, -1, help, *help_len + 1, NULL, NULL );
+    }
+    msi_free( titleW );
+    msi_free( helpW );
+    msi_free( featureW );
+    return r;
+}
+
+static DWORD map_feature_attributes( DWORD attrs )
+{
+    DWORD ret = 0;
+
+    if (attrs == msidbFeatureAttributesFavorLocal)            ret |= INSTALLFEATUREATTRIBUTE_FAVORLOCAL;
+    if (attrs & msidbFeatureAttributesFavorSource)            ret |= INSTALLFEATUREATTRIBUTE_FAVORSOURCE;
+    if (attrs & msidbFeatureAttributesFollowParent)           ret |= INSTALLFEATUREATTRIBUTE_FOLLOWPARENT;
+    if (attrs & msidbFeatureAttributesFavorAdvertise)         ret |= INSTALLFEATUREATTRIBUTE_FAVORADVERTISE;
+    if (attrs & msidbFeatureAttributesDisallowAdvertise)      ret |= INSTALLFEATUREATTRIBUTE_DISALLOWADVERTISE;
+    if (attrs & msidbFeatureAttributesNoUnsupportedAdvertise) ret |= INSTALLFEATUREATTRIBUTE_NOUNSUPPORTEDADVERTISE;
+    return ret;
+}
+
+static UINT MSI_GetFeatureInfo( MSIPACKAGE *package, LPCWSTR name, LPDWORD attrs,
+                                LPWSTR title, LPDWORD title_len, LPWSTR help, LPDWORD help_len )
+{
+    UINT r = ERROR_SUCCESS;
+    MSIFEATURE *feature = msi_get_loaded_feature( package, name );
+    int len;
+
+    if (!feature) return ERROR_UNKNOWN_FEATURE;
+    if (attrs) *attrs = map_feature_attributes( feature->Attributes );
+    if (title_len)
+    {
+        if (feature->Title) len = strlenW( feature->Title );
+        else len = 0;
+        if (*title_len <= len)
+        {
+            *title_len = len;
+            if (title) r = ERROR_MORE_DATA;
+        }
+        else if (title)
+        {
+            if (feature->Title) strcpyW( title, feature->Title );
+            else *title = 0;
+            *title_len = len;
+        }
+    }
+    if (help_len)
+    {
+        if (feature->Description) len = strlenW( feature->Description );
+        else len = 0;
+        if (*help_len <= len)
+        {
+            *help_len = len;
+            if (help) r = ERROR_MORE_DATA;
+        }
+        else if (help)
+        {
+            if (feature->Description) strcpyW( help, feature->Description );
+            else *help = 0;
+            *help_len = len;
+        }
+    }
+    return r;
+}
+
+/***********************************************************************
+* MsiGetFeatureInfoW   (MSI.@)
+*/
+UINT WINAPI MsiGetFeatureInfoW( MSIHANDLE handle, LPCWSTR feature, LPDWORD attrs,
+                                LPWSTR title, LPDWORD title_len, LPWSTR help, LPDWORD help_len )
+{
+    UINT r;
+    MSIPACKAGE *package;
+
+    TRACE("%u, %s, %p, %p, %p, %p, %p\n", handle, debugstr_w(feature), attrs, title,
+          title_len, help, help_len);
+
+    if (!feature) return ERROR_INVALID_PARAMETER;
+
+    if (!(package = msihandle2msiinfo( handle, MSIHANDLETYPE_PACKAGE )))
+        return ERROR_INVALID_HANDLE;
+
+    /* features may not have been loaded yet */
+    msi_load_all_components( package );
+    msi_load_all_features( package );
+
+    r = MSI_GetFeatureInfo( package, feature, attrs, title, title_len, help, help_len );
+    msiobj_release( &package->hdr );
+    return r;
+}
+
+/***********************************************************************
  * MsiSetComponentStateA (MSI.@)
  */
 UINT WINAPI MsiSetComponentStateA(MSIHANDLE hInstall, LPCSTR szComponent,
diff --git a/dlls/msi/msi.spec b/dlls/msi/msi.spec
index 0fe2177..1008813 100644
--- a/dlls/msi/msi.spec
+++ b/dlls/msi/msi.spec
@@ -48,8 +48,8 @@
 52 stdcall MsiGetDatabaseState(long)
 53 stdcall MsiGetFeatureCostA(long str long long ptr)
 54 stdcall MsiGetFeatureCostW(long wstr long long ptr)
-55 stub MsiGetFeatureInfoA
-56 stub MsiGetFeatureInfoW
+55 stdcall MsiGetFeatureInfoA(long str ptr ptr ptr ptr ptr)
+56 stdcall MsiGetFeatureInfoW(long wstr ptr ptr ptr ptr ptr)
 57 stdcall MsiGetFeatureStateA(long str ptr ptr)
 58 stdcall MsiGetFeatureStateW(long wstr ptr ptr)
 59 stdcall MsiGetFeatureUsageA(str str ptr ptr)
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index 6e9c959..414b70c 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -776,6 +776,8 @@ extern UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
 extern UINT msi_schedule_action( MSIPACKAGE *package, UINT script, const WCHAR *action ) DECLSPEC_HIDDEN;
 extern INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp ) DECLSPEC_HIDDEN;
 extern INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature ) DECLSPEC_HIDDEN;
+extern UINT msi_load_all_components( MSIPACKAGE *package ) DECLSPEC_HIDDEN;
+extern UINT msi_load_all_features( MSIPACKAGE *package ) DECLSPEC_HIDDEN;
 
 /* record internals */
 extern void MSI_CloseRecord( MSIOBJECTHDR * ) DECLSPEC_HIDDEN;
diff --git a/dlls/msi/tests/install.c b/dlls/msi/tests/install.c
index d54f923..81e1c1e 100644
--- a/dlls/msi/tests/install.c
+++ b/dlls/msi/tests/install.c
@@ -6386,6 +6386,89 @@ static void test_upgrade_code(void)
     DeleteFile(msifile);
 }
 
+static void test_MsiGetFeatureInfo(void)
+{
+    UINT r;
+    MSIHANDLE package;
+    char title[32], help[32], path[MAX_PATH];
+    DWORD attrs, title_len, help_len;
+
+    if (is_process_limited())
+    {
+        skip("process is limited\n");
+        return;
+    }
+    create_database( msifile, tables, sizeof(tables) / sizeof(tables[0]) );
+
+    strcpy( path, CURR_DIR );
+    strcat( path, "\\" );
+    strcat( path, msifile );
+
+    r = MsiOpenPackage( path, &package );
+    if (r == ERROR_INSTALL_PACKAGE_REJECTED)
+    {
+        skip("Not enough rights to perform tests\n");
+        DeleteFileA( msifile );
+        return;
+    }
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    r = MsiGetFeatureInfoA( 0, NULL, NULL, NULL, NULL, NULL, NULL );
+    ok(r == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", r); 
+
+    r = MsiGetFeatureInfoA( package, NULL, NULL, NULL, NULL, NULL, NULL );
+    ok(r == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", r); 
+
+    r = MsiGetFeatureInfoA( package, "", NULL, NULL, NULL, NULL, NULL );
+    ok(r == ERROR_UNKNOWN_FEATURE, "expected ERROR_UNKNOWN_FEATURE, got %u\n", r); 
+
+    r = MsiGetFeatureInfoA( package, "One", NULL, NULL, NULL, NULL, NULL );
+    ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r); 
+
+    r = MsiGetFeatureInfoA( 0, "One", NULL, NULL, NULL, NULL, NULL );
+    ok(r == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %u\n", r); 
+
+    title_len = help_len = 0;
+    r = MsiGetFeatureInfoA( package, "One", NULL, NULL, &title_len, NULL, &help_len );
+    ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r); 
+    ok(title_len == 3, "expected 3, got %u\n", title_len);
+    ok(help_len == 15, "expected 15, got %u\n", help_len);
+
+    title[0] = help[0] = 0;
+    title_len = help_len = 0;
+    r = MsiGetFeatureInfoA( package, "One", NULL, title, &title_len, help, &help_len );
+    ok(r == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %u\n", r); 
+    ok(title_len == 3, "expected 3, got %u\n", title_len);
+    ok(help_len == 15, "expected 15, got %u\n", help_len);
+
+    attrs = 0;
+    title[0] = help[0] = 0;
+    title_len = sizeof(title);
+    help_len = sizeof(help);
+    r = MsiGetFeatureInfoA( package, "One", &attrs, title, &title_len, help, &help_len );
+    ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r); 
+    ok(attrs == INSTALLFEATUREATTRIBUTE_FAVORLOCAL, "expected INSTALLFEATUREATTRIBUTE_FAVORLOCAL, got %u\n", attrs);
+    ok(title_len == 3, "expected 3, got %u\n", title_len);
+    ok(help_len == 15, "expected 15, got %u\n", help_len);
+    ok(!strcmp(title, "One"), "expected \"One\", got \"%s\"\n", title);
+    ok(!strcmp(help, "The One Feature"), "expected \"The One Feature\", got \"%s\"\n", help);
+
+    attrs = 0;
+    title[0] = help[0] = 0;
+    title_len = sizeof(title);
+    help_len = sizeof(help);
+    r = MsiGetFeatureInfoA( package, "feature", &attrs, title, &title_len, help, &help_len );
+    ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
+    ok(attrs == INSTALLFEATUREATTRIBUTE_FAVORLOCAL, "expected INSTALLFEATUREATTRIBUTE_FAVORLOCAL, got %u\n", attrs);
+    ok(!title_len, "expected 0, got %u\n", title_len);
+    ok(!help_len, "expected 0, got %u\n", help_len);
+    ok(!title[0], "expected \"\", got \"%s\"\n", title);
+    ok(!help[0], "expected \"\", got \"%s\"\n", help);
+
+    MsiCloseHandle( package );
+    DeleteFileA( msifile );
+}
+
 START_TEST(install)
 {
     DWORD len;
@@ -6475,6 +6558,7 @@ START_TEST(install)
     test_package_validation();
     test_command_line_parsing();
     test_upgrade_code();
+    test_MsiGetFeatureInfo();
 
     DeleteFileA(log_file);
 
diff --git a/include/msi.h b/include/msi.h
index 550ce95..5b7eff2 100644
--- a/include/msi.h
+++ b/include/msi.h
@@ -207,6 +207,16 @@ typedef enum tagMSICODE
     MSICODE_PATCH = 0x40000000L
 } MSICODE;
 
+typedef enum tagINSTALLFEATUREATTRIBUTE
+{
+    INSTALLFEATUREATTRIBUTE_FAVORLOCAL             = 1 << 0,
+    INSTALLFEATUREATTRIBUTE_FAVORSOURCE            = 1 << 1,
+    INSTALLFEATUREATTRIBUTE_FOLLOWPARENT           = 1 << 2,
+    INSTALLFEATUREATTRIBUTE_FAVORADVERTISE         = 1 << 3,
+    INSTALLFEATUREATTRIBUTE_DISALLOWADVERTISE      = 1 << 4,
+    INSTALLFEATUREATTRIBUTE_NOUNSUPPORTEDADVERTISE = 1 << 5
+} INSTALLFEATUREATTRIBUTE;
+
 typedef struct _MSIFILEHASHINFO {
     ULONG dwFileHashInfoSize;
     ULONG dwData[4];
@@ -523,6 +533,10 @@ INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR, LPCSTR);
 INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR, LPCWSTR);
 #define MsiQueryFeatureState WINELIB_NAME_AW(MsiQueryFeatureState)
 
+UINT WINAPI MsiGetFeatureInfoA(MSIHANDLE, LPCSTR, LPDWORD, LPSTR, LPDWORD, LPSTR, LPDWORD);
+UINT WINAPI MsiGetFeatureInfoW(MSIHANDLE, LPCWSTR, LPDWORD, LPWSTR, LPDWORD, LPWSTR, LPDWORD);
+#define MsiGetFeatureInfo WINELIB_NAME_AW(MsiGetFeatureInfo)
+
 UINT WINAPI MsiGetFeatureUsageA(LPCSTR, LPCSTR, LPDWORD, LPWORD);
 UINT WINAPI MsiGetFeatureUsageW(LPCWSTR, LPCWSTR, LPDWORD, LPWORD);
 #define MsiGetFeatureUsage WINELIB_NAME_AW(MsiGetFeatureUsage)
-- 
1.7.4.1







More information about the wine-patches mailing list