From 4c9c50d86b475f2531f841c0ad1176470e89cc0f Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Fri, 10 Jun 2011 10:13:34 +0200 Subject: [PATCH] msi: Implement and test MsiGetFeatureInfo. --- 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 3f6eae7bf59..437c8d9a38b 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 31ab55876ae..62252817413 100644 --- a/dlls/msi/install.c +++ b/dlls/msi/install.c @@ -1254,6 +1254,126 @@ UINT WINAPI MsiGetFeatureCostW(MSIHANDLE hInstall, LPCWSTR szFeature, return ret; } +/*********************************************************************** +* 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.@) */ diff --git a/dlls/msi/msi.spec b/dlls/msi/msi.spec index 0fe21775b17..10088135641 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 6e9c9599c6f..414b70c09bb 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 d54f9233bbc..267b2bd9537 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 550ce954b62..5b7eff2a329 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)