msi: Handle descriptors without component in MsiProvideQualifiedComponentEx.
Signed-off-by: Hans Leidekker <hans@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
f6c4f87d32
commit
dea323dcec
|
@ -3363,6 +3363,26 @@ INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature )
|
|||
return MsiUseFeatureExA(szProduct, szFeature, 0, 0);
|
||||
}
|
||||
|
||||
WCHAR *reg_get_multisz( HKEY hkey, const WCHAR *name )
|
||||
{
|
||||
WCHAR *ret;
|
||||
DWORD len, type;
|
||||
if (RegQueryValueExW( hkey, name, NULL, &type, NULL, &len ) || type != REG_MULTI_SZ) return NULL;
|
||||
if ((ret = msi_alloc( len ))) RegQueryValueExW( hkey, name, NULL, NULL, (BYTE *)ret, &len );
|
||||
return ret;
|
||||
}
|
||||
|
||||
WCHAR *reg_get_sz( HKEY hkey, const WCHAR *name )
|
||||
{
|
||||
WCHAR *ret;
|
||||
DWORD len, type;
|
||||
if (RegQueryValueExW( hkey, name, NULL, &type, NULL, &len ) || type != REG_SZ) return NULL;
|
||||
if ((ret = msi_alloc( len ))) RegQueryValueExW( hkey, name, NULL, NULL, (BYTE *)ret, &len );
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define BASE85_SIZE 20
|
||||
|
||||
/***********************************************************************
|
||||
* MSI_ProvideQualifiedComponentEx [internal]
|
||||
*/
|
||||
|
@ -3371,39 +3391,54 @@ static UINT MSI_ProvideQualifiedComponentEx(LPCWSTR szComponent,
|
|||
DWORD Unused1, DWORD Unused2, awstring *lpPathBuf,
|
||||
LPDWORD pcchPathBuf)
|
||||
{
|
||||
WCHAR product[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1],
|
||||
feature[MAX_FEATURE_CHARS+1];
|
||||
LPWSTR info;
|
||||
WCHAR product[MAX_FEATURE_CHARS+1], comp[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1];
|
||||
WCHAR *desc;
|
||||
HKEY hkey;
|
||||
DWORD sz;
|
||||
UINT rc;
|
||||
DWORD size;
|
||||
UINT ret;
|
||||
INSTALLSTATE state;
|
||||
|
||||
rc = MSIREG_OpenUserComponentsKey(szComponent, &hkey, FALSE);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
return ERROR_INDEX_ABSENT;
|
||||
if (MSIREG_OpenUserComponentsKey( szComponent, &hkey, FALSE )) return ERROR_UNKNOWN_COMPONENT;
|
||||
|
||||
info = msi_reg_get_val_str( hkey, szQualifier );
|
||||
desc = reg_get_multisz( hkey, szQualifier );
|
||||
RegCloseKey(hkey);
|
||||
if (!desc) return ERROR_INDEX_ABSENT;
|
||||
|
||||
if (!info)
|
||||
return ERROR_INDEX_ABSENT;
|
||||
/* FIXME: handle multiple descriptors */
|
||||
ret = MsiDecomposeDescriptorW( desc, product, feature, comp, &size );
|
||||
msi_free( desc );
|
||||
if (ret != ERROR_SUCCESS) return ret;
|
||||
|
||||
MsiDecomposeDescriptorW(info, product, feature, component, &sz);
|
||||
if (!szProduct) szProduct = product;
|
||||
if (!comp[0])
|
||||
{
|
||||
MSIINSTALLCONTEXT ctx;
|
||||
WCHAR *components;
|
||||
GUID guid;
|
||||
|
||||
if (!szProduct)
|
||||
state = MSI_GetComponentPath(product, component, lpPathBuf, pcchPathBuf);
|
||||
else
|
||||
state = MSI_GetComponentPath(szProduct, component, lpPathBuf, pcchPathBuf);
|
||||
|
||||
msi_free( info );
|
||||
|
||||
if (state == INSTALLSTATE_MOREDATA)
|
||||
return ERROR_MORE_DATA;
|
||||
|
||||
if (state != INSTALLSTATE_LOCAL)
|
||||
/* use the first component of the feature if the descriptor component is empty */
|
||||
if ((ret = msi_locate_product( szProduct, &ctx ))) return ret;
|
||||
if ((ret = MSIREG_OpenUserDataFeaturesKey( szProduct, NULL, ctx, &hkey, FALSE )))
|
||||
{
|
||||
return ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
components = reg_get_sz( hkey, feature );
|
||||
RegCloseKey( hkey );
|
||||
if (!components) return ERROR_FILE_NOT_FOUND;
|
||||
|
||||
if (strlenW( components ) < BASE85_SIZE || !decode_base85_guid( components, &guid ))
|
||||
{
|
||||
msi_free( components );
|
||||
return ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
msi_free( components );
|
||||
StringFromGUID2( &guid, comp, sizeof(comp)/sizeof(comp[0]) );
|
||||
}
|
||||
|
||||
state = MSI_GetComponentPath( szProduct, comp, lpPathBuf, pcchPathBuf );
|
||||
|
||||
if (state == INSTALLSTATE_MOREDATA) return ERROR_MORE_DATA;
|
||||
if (state != INSTALLSTATE_LOCAL) return ERROR_FILE_NOT_FOUND;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -3523,6 +3523,146 @@ static void test_MsiProvideComponent(void)
|
|||
DeleteFileA(msifile);
|
||||
}
|
||||
|
||||
static void test_MsiProvideQualifiedComponentEx(void)
|
||||
{
|
||||
UINT r;
|
||||
INSTALLSTATE state;
|
||||
char comp[39], comp_squashed[33], comp2[39], comp2_base85[21], comp2_squashed[33];
|
||||
char prod[39], prod_base85[21], prod_squashed[33];
|
||||
char desc[MAX_PATH], buf[MAX_PATH], keypath[MAX_PATH], path[MAX_PATH];
|
||||
DWORD len = sizeof(buf);
|
||||
REGSAM access = KEY_ALL_ACCESS;
|
||||
HKEY hkey, hkey2, hkey3, hkey4, hkey5;
|
||||
LONG res;
|
||||
|
||||
if (is_process_limited())
|
||||
{
|
||||
skip( "process is limited\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
create_test_guid( comp, comp_squashed );
|
||||
compose_base85_guid( comp2, comp2_base85, comp2_squashed );
|
||||
compose_base85_guid( prod, prod_base85, prod_squashed );
|
||||
|
||||
r = MsiProvideQualifiedComponentExA( comp, "qualifier", INSTALLMODE_EXISTING, prod, 0, 0, buf, &len );
|
||||
ok( r == ERROR_UNKNOWN_COMPONENT, "got %u\n", r );
|
||||
|
||||
lstrcpyA( keypath, "Software\\Classes\\Installer\\Components\\" );
|
||||
lstrcatA( keypath, comp_squashed );
|
||||
|
||||
if (is_wow64) access |= KEY_WOW64_64KEY;
|
||||
res = RegCreateKeyExA( HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, &hkey, NULL );
|
||||
ok( res == ERROR_SUCCESS, "got %d\n", res );
|
||||
|
||||
lstrcpyA( desc, prod_base85 );
|
||||
memcpy( desc + lstrlenA(desc), "feature<\0", sizeof("feature<\0") );
|
||||
res = RegSetValueExA( hkey, "qualifier", 0, REG_MULTI_SZ, (const BYTE *)desc,
|
||||
lstrlenA(prod_base85) + sizeof("feature<\0") );
|
||||
ok( res == ERROR_SUCCESS, "got %d\n", res );
|
||||
|
||||
r = MsiProvideQualifiedComponentExA( comp, "qualifier", INSTALLMODE_EXISTING, prod, 0, 0, buf, &len );
|
||||
ok( r == ERROR_UNKNOWN_PRODUCT, "got %u\n", r );
|
||||
|
||||
r = MsiProvideQualifiedComponentExA( comp, "qualifier", INSTALLMODE_EXISTING, NULL, 0, 0, buf, &len );
|
||||
ok( r == ERROR_UNKNOWN_PRODUCT, "got %u\n", r );
|
||||
|
||||
state = MsiQueryProductStateA( prod );
|
||||
ok( state == INSTALLSTATE_UNKNOWN, "got %d\n", state );
|
||||
|
||||
lstrcpyA( keypath, "Software\\Classes\\Installer\\Products\\" );
|
||||
lstrcatA( keypath, prod_squashed );
|
||||
|
||||
res = RegCreateKeyExA( HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, &hkey2, NULL );
|
||||
ok( res == ERROR_SUCCESS, "got %d\n", res );
|
||||
|
||||
state = MsiQueryProductStateA( prod );
|
||||
ok( state == INSTALLSTATE_ADVERTISED, "got %d\n", state );
|
||||
|
||||
r = MsiProvideQualifiedComponentExA( comp, "qualifier", INSTALLMODE_EXISTING, prod, 0, 0, buf, &len );
|
||||
todo_wine ok( r == ERROR_UNKNOWN_FEATURE, "got %u\n", r );
|
||||
|
||||
lstrcpyA( keypath, "Software\\Classes\\Installer\\Features\\" );
|
||||
lstrcatA( keypath, prod_squashed );
|
||||
|
||||
res = RegCreateKeyExA( HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, &hkey3, NULL );
|
||||
ok( res == ERROR_SUCCESS, "got %d\n", res );
|
||||
|
||||
state = MsiQueryFeatureStateA( prod, "feature" );
|
||||
ok( state == INSTALLSTATE_UNKNOWN, "got %d\n", state );
|
||||
|
||||
res = RegSetValueExA( hkey3, "feature", 0, REG_SZ, (const BYTE *)"", 1 );
|
||||
ok( res == ERROR_SUCCESS, "got %d\n", res );
|
||||
|
||||
state = MsiQueryFeatureStateA( prod, "feature" );
|
||||
ok( state == INSTALLSTATE_ADVERTISED, "got %d\n", state );
|
||||
|
||||
r = MsiProvideQualifiedComponentExA( comp, "qualifier", INSTALLMODE_EXISTING, prod, 0, 0, buf, &len );
|
||||
ok( r == ERROR_FILE_NOT_FOUND, "got %u\n", r );
|
||||
|
||||
len = sizeof(buf);
|
||||
r = MsiProvideQualifiedComponentExA( comp, "qualifier", INSTALLMODE_EXISTING, NULL, 0, 0, buf, &len );
|
||||
ok( r == ERROR_FILE_NOT_FOUND, "got %u\n", r );
|
||||
|
||||
lstrcpyA( keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\S-1-5-18\\Products\\" );
|
||||
lstrcatA( keypath, prod_squashed );
|
||||
lstrcatA( keypath, "\\Features" );
|
||||
|
||||
res = RegCreateKeyExA( HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, &hkey4, NULL );
|
||||
ok( res == ERROR_SUCCESS, "got %d\n", res );
|
||||
|
||||
res = RegSetValueExA( hkey4, "feature", 0, REG_SZ, (const BYTE *)comp2_base85, sizeof(comp2_base85) );
|
||||
ok( res == ERROR_SUCCESS, "got %d\n", res );
|
||||
|
||||
state = MsiQueryFeatureStateA( prod, "feature" );
|
||||
ok( state == INSTALLSTATE_ADVERTISED, "got %d\n", state );
|
||||
|
||||
lstrcpyA( keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\S-1-5-18\\Components\\" );
|
||||
lstrcatA( keypath, comp2_squashed );
|
||||
|
||||
res = RegCreateKeyExA( HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, &hkey5, NULL );
|
||||
ok( res == ERROR_SUCCESS, "got %d\n", res );
|
||||
|
||||
res = RegSetValueExA( hkey5, prod_squashed, 0, REG_SZ, (const BYTE *)"c:\\nosuchfile", sizeof("c:\\nosuchfile") );
|
||||
ok( res == ERROR_SUCCESS, "got %d\n", res );
|
||||
|
||||
state = MsiQueryFeatureStateA( prod, "feature" );
|
||||
ok( state == INSTALLSTATE_LOCAL, "got %d\n", state );
|
||||
|
||||
r = MsiProvideQualifiedComponentExA( comp, "qualifier", INSTALLMODE_EXISTING, prod, 0, 0, buf, &len );
|
||||
ok( r == ERROR_FILE_NOT_FOUND, "got %u\n", r );
|
||||
|
||||
GetCurrentDirectoryA( MAX_PATH, path );
|
||||
lstrcatA( path, "\\msitest" );
|
||||
CreateDirectoryA( path, NULL );
|
||||
lstrcatA( path, "\\test.txt" );
|
||||
create_file( path, "test", 100 );
|
||||
|
||||
res = RegSetValueExA( hkey5, prod_squashed, 0, REG_SZ, (const BYTE *)path, lstrlenA(path) + 1 );
|
||||
ok( res == ERROR_SUCCESS, "got %d\n", res );
|
||||
|
||||
buf[0] = 0;
|
||||
len = sizeof(buf);
|
||||
r = MsiProvideQualifiedComponentExA( comp, "qualifier", INSTALLMODE_EXISTING, prod, 0, 0, buf, &len );
|
||||
ok( r == ERROR_SUCCESS, "got %u\n", r );
|
||||
ok( len == lstrlenA(path), "got %u\n", len );
|
||||
ok( !lstrcmpA( path, buf ), "got '%s'\n", buf );
|
||||
|
||||
DeleteFileA( "msitest\\text.txt" );
|
||||
RemoveDirectoryA( "msitest" );
|
||||
|
||||
delete_key( hkey5, "", access & KEY_WOW64_64KEY );
|
||||
RegCloseKey( hkey5 );
|
||||
delete_key( hkey4, "", access & KEY_WOW64_64KEY );
|
||||
RegCloseKey( hkey4 );
|
||||
delete_key( hkey3, "", access & KEY_WOW64_64KEY );
|
||||
RegCloseKey( hkey3 );
|
||||
delete_key( hkey2, "", access & KEY_WOW64_64KEY );
|
||||
RegCloseKey( hkey2 );
|
||||
delete_key( hkey, "", access & KEY_WOW64_64KEY );
|
||||
RegCloseKey( hkey );
|
||||
}
|
||||
|
||||
static void test_MsiGetProductCode(void)
|
||||
{
|
||||
HKEY compkey, prodkey;
|
||||
|
@ -14447,6 +14587,7 @@ START_TEST(msi)
|
|||
if (pMsiGetComponentPathExA)
|
||||
test_concurrentinstall();
|
||||
test_command_line_parsing();
|
||||
test_MsiProvideQualifiedComponentEx();
|
||||
|
||||
SetCurrentDirectoryA(prev_path);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue