diff --git a/dlls/msi/msi.c b/dlls/msi/msi.c index 7240ea4fd64..fce1bc51842 100644 --- a/dlls/msi/msi.c +++ b/dlls/msi/msi.c @@ -763,10 +763,13 @@ INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct) { UINT rc; INSTALLSTATE state = INSTALLSTATE_UNKNOWN; - HKEY hkey = 0; + HKEY hkey = 0, props = 0; DWORD sz; static const int GUID_LEN = 38; + static const WCHAR szInstallProperties[] = { + 'I','n','s','t','a','l','l','P','r','o','p','e','r','t','i','e','s',0 + }; static const WCHAR szWindowsInstaller[] = { 'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0 }; @@ -783,12 +786,16 @@ INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct) state = INSTALLSTATE_ADVERTISED; RegCloseKey(hkey); - rc = MSIREG_OpenUninstallKey(szProduct,&hkey,FALSE); + rc = MSIREG_OpenUserDataProductKey(szProduct,&hkey,FALSE); + if (rc != ERROR_SUCCESS) + goto end; + + rc = RegOpenKeyW(hkey, szInstallProperties, &props); if (rc != ERROR_SUCCESS) goto end; sz = sizeof(state); - rc = RegQueryValueExW(hkey,szWindowsInstaller,NULL,NULL,(LPVOID)&state, &sz); + rc = RegQueryValueExW(props,szWindowsInstaller,NULL,NULL,(LPVOID)&state, &sz); if (rc != ERROR_SUCCESS) goto end; @@ -804,6 +811,7 @@ INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct) break; } end: + RegCloseKey(props); RegCloseKey(hkey); return state; } diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index d9c76150e1b..be5f2b1ebbb 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -675,6 +675,7 @@ extern UINT MSIREG_OpenComponents(HKEY* key); extern UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create); extern UINT MSIREG_OpenComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create); extern UINT MSIREG_OpenProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create); +extern UINT MSIREG_OpenUserDataProductKey(LPCWSTR szProduct, HKEY* key, BOOL create); extern UINT MSIREG_OpenUserFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create); extern UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create); extern UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szProduct, HKEY* key, BOOL create); diff --git a/dlls/msi/registry.c b/dlls/msi/registry.c index 14a475451c6..21e0804ecc6 100644 --- a/dlls/msi/registry.c +++ b/dlls/msi/registry.c @@ -36,6 +36,7 @@ #include "wine/unicode.h" #include "winver.h" #include "winuser.h" +#include "sddl.h" WINE_DEFAULT_DEBUG_CHANNEL(msi); @@ -140,6 +141,15 @@ static const WCHAR szInstaller_UserUpgradeCodes_fmt[] = { 'U','p','g','r','a','d','e','C','o','d','e','s','\\', '%','s',0}; +static const WCHAR szUserDataProd_fmt[] = { +'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','\\', +'U','s','e','r','D','a','t','a','\\', +'%','s','\\','P','r','o','d','u','c','t','s','\\','%','s',0}; + #define SQUISH_GUID_SIZE 33 @@ -501,6 +511,55 @@ UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create) return rc; } +static UINT get_user_sid(LPWSTR *usersid) +{ + HANDLE token; + BYTE buf[1024]; + DWORD size; + PTOKEN_USER user; + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) + return ERROR_FUNCTION_FAILED; + + size = sizeof(buf); + if (!GetTokenInformation(token, TokenUser, (void *)buf, size, &size)) + return ERROR_FUNCTION_FAILED; + + user = (PTOKEN_USER)buf; + if (!ConvertSidToStringSidW(user->User.Sid, usersid)) + return ERROR_FUNCTION_FAILED; + + return ERROR_SUCCESS; +} + +UINT MSIREG_OpenUserDataProductKey(LPCWSTR szProduct, HKEY *key, BOOL create) +{ + UINT rc; + WCHAR squished_pc[GUID_SIZE]; + WCHAR keypath[0x200]; + LPWSTR usersid; + + TRACE("%s\n", debugstr_w(szProduct)); + squash_guid(szProduct, squished_pc); + TRACE("squished (%s)\n", debugstr_w(squished_pc)); + + rc = get_user_sid(&usersid); + if (rc != ERROR_SUCCESS || !usersid) + { + ERR("Failed to retrieve user SID: %d\n", rc); + return rc; + } + + sprintfW(keypath, szUserDataProd_fmt, usersid, squished_pc); + + if (create) + rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key); + else + rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key); + + return rc; +} + UINT MSIREG_OpenProducts(HKEY* key) { return RegCreateKeyW(HKEY_LOCAL_MACHINE,szInstaller_Products,key); diff --git a/dlls/msi/tests/automation.c b/dlls/msi/tests/automation.c index 7308671c16c..84c362726b4 100644 --- a/dlls/msi/tests/automation.c +++ b/dlls/msi/tests/automation.c @@ -2110,7 +2110,10 @@ static void test_Installer_InstallProduct(LPCWSTR szPath) /* Installer::ProductState for our product code, which has been installed */ hr = Installer_ProductState(szProductCode, &iValue); ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr); - ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT); + todo_wine + { + ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT); + } /* Installer::ProductInfo for our product code */ diff --git a/dlls/msi/tests/msi.c b/dlls/msi/tests/msi.c index 9afa5769329..4e42feaa389 100644 --- a/dlls/msi/tests/msi.c +++ b/dlls/msi/tests/msi.c @@ -379,6 +379,27 @@ static void test_MsiQueryProductState(void) state = MsiQueryProductStateA(prodcode); ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"); + lstrcatA(keypath, prodcode); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &localkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* local uninstall key exists */ + state = MsiQueryProductStateA(prodcode); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + data = 1; + res = RegSetValueExA(localkey, "WindowsInstaller", 0, REG_DWORD, (const BYTE *)&data, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* WindowsInstaller value exists */ + state = MsiQueryProductStateA(prodcode); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + RegDeleteValueA(localkey, "WindowsInstaller"); + RegDeleteKeyA(localkey, ""); + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); lstrcatA(keypath, usersid); lstrcatA(keypath, "\\Products\\"); @@ -404,10 +425,7 @@ static void test_MsiQueryProductState(void) /* WindowsInstaller value exists */ state = MsiQueryProductStateA(prodcode); - todo_wine - { - ok(state == INSTALLSTATE_DEFAULT, "Expected INSTALLSTATE_DEFAULT, got %d\n", state); - } + ok(state == INSTALLSTATE_DEFAULT, "Expected INSTALLSTATE_DEFAULT, got %d\n", state); RegDeleteKeyA(userkey, "");