[2/4] msi: Implement MsiEnumProductsEx.
Hans Leidekker
hans at codeweavers.com
Mon Mar 12 06:25:50 CDT 2012
---
dlls/msi/msipriv.h | 1 +
dlls/msi/registry.c | 254 +++++++++++++++++++++++++++++++++++++++++++++++---
dlls/msi/tests/msi.c | 162 +++++++++++++++++++++++++++++++-
3 files changed, 403 insertions(+), 14 deletions(-)
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index 2c9385a..0591050 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -1077,6 +1077,7 @@ static const WCHAR szSOURCEDIR[] = {'S','O','U','R','C','E','D','I','R',0};
static const WCHAR szRootDrive[] = {'R','O','O','T','D','R','I','V','E',0};
static const WCHAR szTargetDir[] = {'T','A','R','G','E','T','D','I','R',0};
static const WCHAR szLocalSid[] = {'S','-','1','-','5','-','1','8',0};
+static const WCHAR szAllSid[] = {'S','-','1','-','1','-','0',0};
static const WCHAR szEmpty[] = {0};
static const WCHAR szAll[] = {'A','L','L',0};
static const WCHAR szOne[] = {'1',0};
diff --git a/dlls/msi/registry.c b/dlls/msi/registry.c
index e5d2c51..53b51f6 100644
--- a/dlls/msi/registry.c
+++ b/dlls/msi/registry.c
@@ -2113,22 +2113,252 @@ done:
return r;
}
-UINT WINAPI MsiEnumProductsExA( LPCSTR szProductCode, LPCSTR szUserSid,
- DWORD dwContext, DWORD dwIndex, CHAR szInstalledProductCode[39],
- MSIINSTALLCONTEXT* pdwInstalledContext, LPSTR szSid, LPDWORD pcchSid)
+UINT WINAPI MsiEnumProductsExA( LPCSTR product, LPCSTR usersid, DWORD ctx, DWORD index,
+ CHAR installed_product[GUID_SIZE],
+ MSIINSTALLCONTEXT *installed_ctx, LPSTR sid, LPDWORD sid_len )
{
- FIXME("%s %s %d %d %p %p %p %p\n", debugstr_a(szProductCode), debugstr_a(szUserSid),
- dwContext, dwIndex, szInstalledProductCode, pdwInstalledContext,
- szSid, pcchSid);
+ UINT r;
+ WCHAR installed_productW[GUID_SIZE], *productW = NULL, *usersidW = NULL, *sidW = NULL;
+
+ TRACE("%s, %s, %u, %u, %p, %p, %p, %p\n", debugstr_a(product), debugstr_a(usersid),
+ ctx, index, installed_product, installed_ctx, sid, sid_len);
+
+ if (sid && !sid_len) return ERROR_INVALID_PARAMETER;
+ if (product && !(productW = strdupAtoW( product ))) return ERROR_OUTOFMEMORY;
+ if (usersid && !(usersidW = strdupAtoW( usersid )))
+ {
+ msi_free( productW );
+ return ERROR_OUTOFMEMORY;
+ }
+ if (sid && !(sidW = msi_alloc( *sid_len * sizeof(WCHAR) )))
+ {
+ msi_free( usersidW );
+ msi_free( productW );
+ return ERROR_OUTOFMEMORY;
+ }
+ r = MsiEnumProductsExW( productW, usersidW, ctx, index, installed_productW,
+ installed_ctx, sidW, sid_len );
+ if (r == ERROR_SUCCESS)
+ {
+ if (installed_product) WideCharToMultiByte( CP_ACP, 0, installed_productW, GUID_SIZE,
+ installed_product, GUID_SIZE, NULL, NULL );
+ if (sid) WideCharToMultiByte( CP_ACP, 0, sidW, *sid_len + 1, sid, *sid_len + 1, NULL, NULL );
+ }
+ msi_free( productW );
+ msi_free( usersidW );
+ msi_free( sidW );
+ return r;
+}
+
+static UINT fetch_machine_product( const WCHAR *match, DWORD index, DWORD *idx,
+ WCHAR installed_product[GUID_SIZE],
+ MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
+{
+ static const WCHAR productsW[] =
+ {'S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s','\\',
+ 'I','n','s','t','a','l','l','e','r','\\','P','r','o','d','u','c','t','s',0};
+ UINT r;
+ WCHAR product[GUID_SIZE];
+ DWORD i = 0, len;
+ REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
+ HKEY key;
+
+ if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, productsW, 0, access, &key ))
+ return ERROR_NO_MORE_ITEMS;
+
+ len = sizeof(product)/sizeof(product[0]);
+ while (!RegEnumKeyExW( key, i, product, &len, NULL, NULL, NULL, NULL ))
+ {
+ if (match && strcmpW( match, product ))
+ {
+ i++;
+ len = sizeof(product)/sizeof(product[0]);
+ continue;
+ }
+ if (*idx == index) goto found;
+ (*idx)++;
+ len = sizeof(product)/sizeof(product[0]);
+ i++;
+ }
+ RegCloseKey( key );
return ERROR_NO_MORE_ITEMS;
+
+found:
+ if (sid_len && *sid_len < 1)
+ {
+ *sid_len = 1;
+ r = ERROR_MORE_DATA;
+ }
+ else
+ {
+ if (installed_product) unsquash_guid( product, installed_product );
+ if (installed_ctx) *installed_ctx = MSIINSTALLCONTEXT_MACHINE;
+ if (sid)
+ {
+ sid[0] = 0;
+ *sid_len = 0;
+ }
+ r = ERROR_SUCCESS;
+ }
+ RegCloseKey( key );
+ return r;
}
-UINT WINAPI MsiEnumProductsExW( LPCWSTR szProductCode, LPCWSTR szUserSid,
- DWORD dwContext, DWORD dwIndex, WCHAR szInstalledProductCode[39],
- MSIINSTALLCONTEXT* pdwInstalledContext, LPWSTR szSid, LPDWORD pcchSid)
+static UINT fetch_user_product( const WCHAR *match, const WCHAR *usersid, DWORD ctx, DWORD index,
+ DWORD *idx, WCHAR installed_product[GUID_SIZE],
+ MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
{
- FIXME("%s %s %d %d %p %p %p %p\n", debugstr_w(szProductCode), debugstr_w(szUserSid),
- dwContext, dwIndex, szInstalledProductCode, pdwInstalledContext,
- szSid, pcchSid);
+ static const WCHAR managedW[] =
+ {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
+ 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s',
+ 'i','o','n','\\','I','n','s','t','a','l','l','e','r','\\','M','a','n','a','g','e','d',0};
+ static const WCHAR managed_productsW[] =
+ {'\\','I','n','s','t','a','l','l','e','r','\\','P','r','o','d','u','c','t','s',0};
+ static const WCHAR unmanaged_productsW[] =
+ {'\\','S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
+ 'I','n','s','t','a','l','l','e','r','\\','P','r','o','d','u','c','t','s',0};
+ UINT r;
+ const WCHAR *subkey;
+ WCHAR path[MAX_PATH], product[GUID_SIZE], user[128];
+ DWORD i = 0, j = 0, len_product, len_user;
+ REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
+ HKEY key_users, key_products;
+
+ if (ctx == MSIINSTALLCONTEXT_USERMANAGED)
+ {
+ subkey = managed_productsW;
+ if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, managedW, 0, access, &key_users ))
+ return ERROR_NO_MORE_ITEMS;
+ }
+ else if (ctx == MSIINSTALLCONTEXT_USERUNMANAGED)
+ {
+ subkey = unmanaged_productsW;
+ if (RegOpenKeyExW( HKEY_USERS, NULL, 0, access, &key_users ))
+ return ERROR_NO_MORE_ITEMS;
+ }
+ else return ERROR_INVALID_PARAMETER;
+
+ len_user = sizeof(user)/sizeof(user[0]);
+ while (!RegEnumKeyExW( key_users, i, user, &len_user, NULL, NULL, NULL, NULL ))
+ {
+ if (strcmpW( usersid, user ) && strcmpW( usersid, szAllSid ))
+ {
+ i++;
+ len_user = sizeof(user)/sizeof(user[0]);
+ continue;
+ }
+ strcpyW( path, user );
+ strcatW( path, subkey );
+ if ((r = RegOpenKeyExW( key_users, path, 0, access, &key_products )))
+ {
+ i++;
+ len_user = sizeof(user)/sizeof(user[0]);
+ continue;
+ }
+ len_product = sizeof(product)/sizeof(product[0]);
+ while (!RegEnumKeyExW( key_products, j, product, &len_product, NULL, NULL, NULL, NULL ))
+ {
+ if (match && strcmpW( match, product ))
+ {
+ j++;
+ len_product = sizeof(product)/sizeof(product[0]);
+ continue;
+ }
+ if (*idx == index) goto found;
+ (*idx)++;
+ len_product = sizeof(product)/sizeof(product[0]);
+ j++;
+ }
+ RegCloseKey( key_products );
+ len_user = sizeof(user)/sizeof(user[0]);
+ i++;
+ }
+ RegCloseKey( key_users );
return ERROR_NO_MORE_ITEMS;
+
+found:
+ if (sid_len && *sid_len <= len_user)
+ {
+ *sid_len = len_user;
+ r = ERROR_MORE_DATA;
+ }
+ else
+ {
+ if (installed_product) unsquash_guid( product, installed_product );
+ if (installed_ctx) *installed_ctx = ctx;
+ if (sid)
+ {
+ strcpyW( sid, user );
+ *sid_len = len_user;
+ }
+ r = ERROR_SUCCESS;
+ }
+ RegCloseKey( key_products );
+ RegCloseKey( key_users );
+ return r;
+}
+
+static UINT enum_products( const WCHAR *product, const WCHAR *usersid, DWORD ctx, DWORD index,
+ DWORD *idx, WCHAR installed_product[GUID_SIZE],
+ MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
+{
+ UINT r = ERROR_NO_MORE_ITEMS;
+ WCHAR *user = NULL;
+
+ if (!usersid)
+ {
+ usersid = user = get_user_sid();
+ if (!user) return ERROR_FUNCTION_FAILED;
+ }
+ if (ctx & MSIINSTALLCONTEXT_MACHINE)
+ {
+ r = fetch_machine_product( product, index, idx, installed_product, installed_ctx,
+ sid, sid_len );
+ if (r != ERROR_NO_MORE_ITEMS) goto done;
+ }
+ if (ctx & MSIINSTALLCONTEXT_USERUNMANAGED)
+ {
+ r = fetch_user_product( product, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, index,
+ idx, installed_product, installed_ctx, sid, sid_len );
+ if (r != ERROR_NO_MORE_ITEMS) goto done;
+ }
+ if (ctx & MSIINSTALLCONTEXT_USERMANAGED)
+ {
+ r = fetch_user_product( product, usersid, MSIINSTALLCONTEXT_USERMANAGED, index,
+ idx, installed_product, installed_ctx, sid, sid_len );
+ if (r != ERROR_NO_MORE_ITEMS) goto done;
+ }
+
+done:
+ LocalFree( user );
+ return r;
+}
+
+UINT WINAPI MsiEnumProductsExW( LPCWSTR product, LPCWSTR usersid, DWORD ctx, DWORD index,
+ WCHAR installed_product[GUID_SIZE],
+ MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len )
+{
+ UINT r;
+ DWORD idx = 0;
+ static DWORD last_index;
+
+ TRACE("%s, %s, %u, %u, %p, %p, %p, %p\n", debugstr_w(product), debugstr_w(usersid),
+ ctx, index, installed_product, installed_ctx, sid, sid_len);
+
+ if ((sid && !sid_len) || !ctx || (usersid && ctx == MSIINSTALLCONTEXT_MACHINE))
+ return ERROR_INVALID_PARAMETER;
+
+ if (index && index - last_index != 1)
+ return ERROR_INVALID_PARAMETER;
+
+ if (!index) last_index = 0;
+
+ r = enum_products( product, usersid, ctx, index, &idx, installed_product, installed_ctx,
+ sid, sid_len );
+ if (r == ERROR_SUCCESS)
+ last_index = index;
+ else
+ last_index = 0;
+
+ return r;
}
diff --git a/dlls/msi/tests/msi.c b/dlls/msi/tests/msi.c
index ec8e2f1..b86946e 100644
--- a/dlls/msi/tests/msi.c
+++ b/dlls/msi/tests/msi.c
@@ -55,6 +55,8 @@ static INSTALLSTATE (WINAPI *pMsiUseFeatureExA)
(LPCSTR, LPCSTR ,DWORD, DWORD);
static UINT (WINAPI *pMsiGetPatchInfoExA)
(LPCSTR, LPCSTR, LPCSTR, MSIINSTALLCONTEXT, LPCSTR, LPSTR, DWORD *);
+static UINT (WINAPI *pMsiEnumProductsExA)
+ (LPCSTR, LPCSTR, DWORD, DWORD, CHAR[39], MSIINSTALLCONTEXT *, LPSTR, LPDWORD);
static void init_functionpointers(void)
{
@@ -76,6 +78,7 @@ static void init_functionpointers(void)
GET_PROC(hmsi, MsiQueryComponentStateA)
GET_PROC(hmsi, MsiUseFeatureExA)
GET_PROC(hmsi, MsiGetPatchInfoExA)
+ GET_PROC(hmsi, MsiEnumProductsExA)
GET_PROC(hadvapi32, ConvertSidToStringSidA)
GET_PROC(hadvapi32, RegDeleteKeyExA)
@@ -538,8 +541,11 @@ static void create_test_guid(LPSTR prodcode, LPSTR squashed)
ok(size == 39, "Expected 39, got %d\n", hr);
WideCharToMultiByte(CP_ACP, 0, guidW, size, prodcode, MAX_PATH, NULL, NULL);
- squash_guid(guidW, squashedW);
- WideCharToMultiByte(CP_ACP, 0, squashedW, -1, squashed, MAX_PATH, NULL, NULL);
+ if (squashed)
+ {
+ squash_guid(guidW, squashedW);
+ WideCharToMultiByte(CP_ACP, 0, squashedW, -1, squashed, MAX_PATH, NULL, NULL);
+ }
}
static char *get_user_sid(void)
@@ -11850,6 +11856,157 @@ static void test_MsiGetFileSignatureInformation(void)
DeleteFileA( "signature.bin" );
}
+static void test_MsiEnumProductsEx(void)
+{
+ UINT r;
+ DWORD len, index;
+ MSIINSTALLCONTEXT context;
+ char product0[39], product1[39], product2[39], product3[39], guid[39], sid[128];
+ char product_squashed1[33], product_squashed2[33], product_squashed3[33];
+ char keypath1[MAX_PATH], keypath2[MAX_PATH], keypath3[MAX_PATH];
+ HKEY key1, key2, key3;
+ REGSAM access = KEY_ALL_ACCESS;
+ char *usersid = get_user_sid();
+
+ create_test_guid( product0, NULL );
+ create_test_guid( product1, product_squashed1 );
+ create_test_guid( product2, product_squashed2 );
+ create_test_guid( product3, product_squashed3 );
+
+ if (is_wow64) access |= KEY_WOW64_64KEY;
+
+ strcpy( keypath1, "Software\\Classes\\Installer\\Products\\" );
+ strcat( keypath1, product_squashed1 );
+
+ r = RegCreateKeyExA( HKEY_LOCAL_MACHINE, keypath1, 0, NULL, 0, access, NULL, &key1, NULL );
+ if (r == ERROR_ACCESS_DENIED)
+ {
+ skip( "insufficient rights\n" );
+ LocalFree( usersid );
+ return;
+ }
+ ok( r == ERROR_SUCCESS, "got %u\n", r );
+
+ strcpy( keypath2, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\" );
+ strcat( keypath2, usersid );
+ strcat( keypath2, "\\Installer\\Products\\" );
+ strcat( keypath2, product_squashed2 );
+
+ r = RegCreateKeyExA( HKEY_LOCAL_MACHINE, keypath2, 0, NULL, 0, access, NULL, &key2, NULL );
+ ok( r == ERROR_SUCCESS, "got %u\n", r );
+
+ strcpy( keypath3, usersid );
+ strcat( keypath3, "\\Software\\Microsoft\\Installer\\Products\\" );
+ strcat( keypath3, product_squashed3 );
+
+ r = RegCreateKeyExA( HKEY_USERS, keypath3, 0, NULL, 0, access, NULL, &key3, NULL );
+ ok( r == ERROR_SUCCESS, "got %u\n", r );
+
+ r = pMsiEnumProductsExA( NULL, NULL, 0, 0, NULL, NULL, NULL, NULL );
+ ok( r == ERROR_INVALID_PARAMETER, "got %u\n", r );
+
+ len = sizeof(sid);
+ r = pMsiEnumProductsExA( NULL, NULL, 0, 0, NULL, NULL, NULL, &len );
+ ok( r == ERROR_INVALID_PARAMETER, "got %u\n", r );
+ ok( len == sizeof(sid), "got %u\n", len );
+
+ r = pMsiEnumProductsExA( NULL, NULL, MSIINSTALLCONTEXT_ALL, 0, NULL, NULL, NULL, NULL );
+ ok( r == ERROR_SUCCESS, "got %u\n", r );
+
+ sid[0] = 0;
+ len = sizeof(sid);
+ r = pMsiEnumProductsExA( product0, NULL, MSIINSTALLCONTEXT_ALL, 0, NULL, NULL, sid, &len );
+ ok( r == ERROR_NO_MORE_ITEMS, "got %u\n", r );
+ ok( len == sizeof(sid), "got %u\n", len );
+ ok( !sid[0], "got %s\n", sid );
+
+ sid[0] = 0;
+ len = sizeof(sid);
+ r = pMsiEnumProductsExA( product0, usersid, MSIINSTALLCONTEXT_ALL, 0, NULL, NULL, sid, &len );
+ ok( r == ERROR_NO_MORE_ITEMS, "got %u\n", r );
+ ok( len == sizeof(sid), "got %u\n", len );
+ ok( !sid[0], "got %s\n", sid );
+
+ guid[0] = 0;
+ context = 0xdeadbeef;
+ sid[0] = 0;
+ len = sizeof(sid);
+ r = pMsiEnumProductsExA( NULL, NULL, MSIINSTALLCONTEXT_ALL, 0, guid, &context, sid, &len );
+ ok( r == ERROR_SUCCESS, "got %u\n", r );
+ ok( guid[0], "empty guid\n" );
+ ok( context != 0xdeadbeef, "context unchanged\n" );
+ ok( !len, "got %u\n", len );
+ ok( !sid[0], "got %s\n", sid );
+
+ guid[0] = 0;
+ context = 0xdeadbeef;
+ sid[0] = 0;
+ len = sizeof(sid);
+ r = pMsiEnumProductsExA( NULL, usersid, MSIINSTALLCONTEXT_ALL, 0, guid, &context, sid, &len );
+ ok( r == ERROR_SUCCESS, "got %u\n", r );
+ ok( guid[0], "empty guid\n" );
+ ok( context != 0xdeadbeef, "context unchanged\n" );
+ ok( !len, "got %u\n", len );
+ ok( !sid[0], "got %s\n", sid );
+
+ guid[0] = 0;
+ context = 0xdeadbeef;
+ sid[0] = 0;
+ len = sizeof(sid);
+ r = pMsiEnumProductsExA( NULL, "S-1-1-0", MSIINSTALLCONTEXT_ALL, 0, guid, &context, sid, &len );
+ if (r == ERROR_ACCESS_DENIED)
+ {
+ skip( "insufficient rights\n" );
+ LocalFree( usersid );
+ return;
+ }
+ ok( r == ERROR_SUCCESS, "got %u\n", r );
+ ok( guid[0], "empty guid\n" );
+ ok( context != 0xdeadbeef, "context unchanged\n" );
+ ok( !len, "got %u\n", len );
+ ok( !sid[0], "got %s\n", sid );
+
+ index = 0;
+ guid[0] = 0;
+ context = 0xdeadbeef;
+ sid[0] = 0;
+ len = sizeof(sid);
+ while (!pMsiEnumProductsExA( NULL, "S-1-1-0", MSIINSTALLCONTEXT_ALL, index, guid, &context, sid, &len ))
+ {
+ if (!strcmp( product1, guid ))
+ {
+ ok( context == MSIINSTALLCONTEXT_MACHINE, "got %u\n", context );
+ ok( !sid[0], "got \"%s\"\n", sid );
+ ok( !len, "unexpected length %u\n", len );
+ }
+ if (!strcmp( product2, guid ))
+ {
+ ok( context == MSIINSTALLCONTEXT_USERMANAGED, "got %u\n", context );
+ ok( sid[0], "empty sid\n" );
+ ok( len == strlen(sid), "unexpected length %u\n", len );
+ }
+ if (!strcmp( product3, guid ))
+ {
+ ok( context == MSIINSTALLCONTEXT_USERUNMANAGED, "got %u\n", context );
+ ok( sid[0], "empty sid\n" );
+ ok( len == strlen(sid), "unexpected length %u\n", len );
+ }
+ index++;
+ guid[0] = 0;
+ context = 0xdeadbeef;
+ sid[0] = 0;
+ len = sizeof(sid);
+ }
+
+ delete_key( key1, "", access );
+ delete_key( key2, "", access );
+ delete_key( key3, "", access );
+ RegCloseKey( key1 );
+ RegCloseKey( key2 );
+ RegCloseKey( key3 );
+ LocalFree( usersid );
+}
+
START_TEST(msi)
{
init_functionpointers();
@@ -11882,6 +12039,7 @@ START_TEST(msi)
test_MsiGetPatchInfoEx();
test_MsiGetPatchInfo();
test_MsiEnumProducts();
+ test_MsiEnumProductsEx();
}
test_MsiGetFileVersion();
test_MsiGetFileSignatureInformation();
--
1.7.9.1
More information about the wine-patches
mailing list