diff --git a/dlls/msi/msi.c b/dlls/msi/msi.c index 9b311d7c45d..115f71be10e 100644 --- a/dlls/msi/msi.c +++ b/dlls/msi/msi.c @@ -764,14 +764,53 @@ UINT WINAPI MsiQueryComponentStateW(LPCWSTR szProductCode, LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext, LPCWSTR szComponent, INSTALLSTATE *pdwState) { - FIXME("(%s, %s, %d, %s, %p): stub!\n", debugstr_w(szProductCode), + WCHAR squished_pc[GUID_SIZE]; + HKEY hkey; + LONG res; + DWORD sz; + UINT r; + + TRACE("(%s, %s, %d, %s, %p)\n", debugstr_w(szProductCode), debugstr_w(szUserSid), dwContext, debugstr_w(szComponent), pdwState); if (!pdwState) return ERROR_INVALID_PARAMETER; - *pdwState = INSTALLSTATE_UNKNOWN; - return ERROR_UNKNOWN_PRODUCT; + if (!szProductCode || !*szProductCode || lstrlenW(szProductCode) != GUID_SIZE - 1) + return ERROR_INVALID_PARAMETER; + + if (!squash_guid(szProductCode, squished_pc)) + return ERROR_INVALID_PARAMETER; + + if (dwContext == MSIINSTALLCONTEXT_MACHINE) + { + r = MSIREG_OpenLocalSystemProductKey(szProductCode, &hkey, FALSE); + if (r != ERROR_SUCCESS) + return ERROR_UNKNOWN_PRODUCT; + + RegCloseKey(hkey); + *pdwState = INSTALLSTATE_UNKNOWN; + + r = MSIREG_OpenLocalSystemComponentKey(szComponent, &hkey, FALSE); + if (r != ERROR_SUCCESS) + return ERROR_UNKNOWN_COMPONENT; + + sz = 0; + res = RegQueryValueExW(hkey, squished_pc, NULL, NULL, NULL, &sz); + if (res != ERROR_SUCCESS) + return ERROR_UNKNOWN_COMPONENT; + + RegCloseKey(hkey); + + if (sz == 0) + *pdwState = INSTALLSTATE_NOTUSED; + else + *pdwState = INSTALLSTATE_LOCAL; + + return ERROR_SUCCESS; + } + + return ERROR_UNKNOWN_COMPONENT; } INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct) diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index d4ccd8034fd..799e90a0bca 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -747,6 +747,8 @@ extern UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szProduct, HKEY* key, BOOL cr extern UINT MSIREG_DeleteProductKey(LPCWSTR szProduct); extern UINT MSIREG_DeleteUserProductKey(LPCWSTR szProduct); extern UINT MSIREG_DeleteUserDataProductKey(LPCWSTR szProduct); +extern UINT MSIREG_OpenLocalSystemProductKey(LPCWSTR szProductCode, HKEY *key, BOOL create); +extern UINT MSIREG_OpenLocalSystemComponentKey(LPCWSTR szComponent, HKEY *key, BOOL create); extern LPWSTR msi_reg_get_val_str( HKEY hkey, LPCWSTR name ); extern BOOL msi_reg_get_val_dword( HKEY hkey, LPCWSTR name, DWORD *val); diff --git a/dlls/msi/registry.c b/dlls/msi/registry.c index 6aedc711130..67eae4b5b8c 100644 --- a/dlls/msi/registry.c +++ b/dlls/msi/registry.c @@ -195,6 +195,26 @@ static const WCHAR szInstallProperties_fmt[] = { '%','s','\\','P','r','o','d','u','c','t','s','\\','%','s','\\', 'I','n','s','t','a','l','l','P','r','o','p','e','r','t','i','e','s',0}; +static const WCHAR szInstaller_LocalSystemProductCodes_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','-','1','-','5','-','1','8','\\','P','r','o','d','u','c','t','s','\\', +'%','s','\\','I','n','s','t','a','l','l','P','r','o','p','e','r','t','i','e','s',0}; + +static const WCHAR szInstaller_LocalSystemComponent_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','-','1','-','5','-','1','8','\\', +'C','o','m','p','o','n','e','n','t','s','\\','%','s',0}; + #define SQUISH_GUID_SIZE 33 @@ -869,6 +889,46 @@ UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL creat return rc; } +UINT MSIREG_OpenLocalSystemProductKey(LPCWSTR szProductCode, HKEY *key, BOOL create) +{ + WCHAR squished_pc[GUID_SIZE]; + WCHAR keypath[0x200]; + + TRACE("%s\n", debugstr_w(szProductCode)); + + if (!squash_guid(szProductCode, squished_pc)) + return ERROR_FUNCTION_FAILED; + + TRACE("squished (%s)\n", debugstr_w(squished_pc)); + + sprintfW(keypath, szInstaller_LocalSystemProductCodes_fmt, squished_pc); + + if (create) + return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key); + + return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key); +} + +UINT MSIREG_OpenLocalSystemComponentKey(LPCWSTR szComponent, HKEY *key, BOOL create) +{ + WCHAR squished_pc[GUID_SIZE]; + WCHAR keypath[0x200]; + + TRACE("%s\n", debugstr_w(szComponent)); + + if (!squash_guid(szComponent, squished_pc)) + return ERROR_FUNCTION_FAILED; + + TRACE("squished (%s)\n", debugstr_w(squished_pc)); + + sprintfW(keypath, szInstaller_LocalSystemComponent_fmt, squished_pc); + + if (create) + return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key); + + return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key); +} + /************************************************************************* * MsiDecomposeDescriptorW [MSI.@] diff --git a/dlls/msi/tests/msi.c b/dlls/msi/tests/msi.c index 99be877eec7..5a95ade694b 100644 --- a/dlls/msi/tests/msi.c +++ b/dlls/msi/tests/msi.c @@ -665,56 +665,38 @@ static void test_MsiQueryComponentState(void) /* NULL szProductCode */ state = 0xdeadbeef; r = MsiQueryComponentStateA(NULL, NULL, MSIINSTALLCONTEXT_MACHINE, component, &state); - todo_wine - { - ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); - ok(state == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", state); - } + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(state == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", state); /* empty szProductCode */ state = 0xdeadbeef; r = MsiQueryComponentStateA("", NULL, MSIINSTALLCONTEXT_MACHINE, component, &state);\ - todo_wine - { - ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); - ok(state == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", state); - } + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(state == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", state); /* random szProductCode */ state = 0xdeadbeef; r = MsiQueryComponentStateA("random", NULL, MSIINSTALLCONTEXT_MACHINE, component, &state); - todo_wine - { - ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); - ok(state == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", state); - } + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(state == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", state); /* GUID-length szProductCode */ state = 0xdeadbeef; r = MsiQueryComponentStateA("DJANE93KNDNAS-2KN2NR93KMN3LN13=L1N3KDE", NULL, MSIINSTALLCONTEXT_MACHINE, component, &state); - todo_wine - { - ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); - ok(state == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", state); - } + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(state == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", state); /* GUID-length with brackets */ state = 0xdeadbeef; r = MsiQueryComponentStateA("{JANE93KNDNAS-2KN2NR93KMN3LN13=L1N3KD}", NULL, MSIINSTALLCONTEXT_MACHINE, component, &state); - todo_wine - { - ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); - ok(state == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", state); - } + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(state == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", state); /* actual GUID */ state = 0xdeadbeef; r = MsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, component, &state); ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); - todo_wine - { - ok(state == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", state); - } + ok(state == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", state); /* create local system product key */ lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\S-1-5-18\\Products\\"); @@ -730,10 +712,7 @@ static void test_MsiQueryComponentState(void) /* local system product key exists */ state = 0xdeadbeef; r = MsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, component, &state); - todo_wine - { - ok(r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r); - } + ok(r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r); ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\S-1-5-18\\Components\\"); @@ -745,10 +724,7 @@ static void test_MsiQueryComponentState(void) /* component key exists */ state = 0xdeadbeef; r = MsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, component, &state); - todo_wine - { - ok(r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r); - } + ok(r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r); ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"", 0); @@ -757,22 +733,16 @@ static void test_MsiQueryComponentState(void) /* component\product exists */ state = 0xdeadbeef; r = MsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, component, &state); - todo_wine - { - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - ok(state == INSTALLSTATE_NOTUSED, "Expected INSTALLSTATE_NOTUSED, got %d\n", state); - } + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(state == INSTALLSTATE_NOTUSED, "Expected INSTALLSTATE_NOTUSED, got %d\n", state); res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"hi", 2); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); state = 0xdeadbeef; r = MsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, component, &state); - todo_wine - { - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); - } + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); RegDeleteValueA(prodkey, "LocalPackage"); RegDeleteKeyA(prodkey, ""); @@ -785,11 +755,11 @@ static void test_MsiQueryComponentState(void) state = 0xdeadbeef; r = MsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, component, &state); - ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); todo_wine { - ok(state == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", state); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); } + ok(state == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", state); lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); lstrcatA(keypath, usersid); @@ -805,11 +775,11 @@ static void test_MsiQueryComponentState(void) state = 0xdeadbeef; r = MsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, component, &state); + ok(r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r); todo_wine { - ok(r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); } - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); lstrcatA(keypath, usersid); @@ -822,11 +792,11 @@ static void test_MsiQueryComponentState(void) /* component key exists */ state = 0xdeadbeef; r = MsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, component, &state); + ok(r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r); todo_wine { - ok(r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); } - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"", 0); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); @@ -855,11 +825,11 @@ static void test_MsiQueryComponentState(void) state = 0xdeadbeef; r = MsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERMANAGED, component, &state); - ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); todo_wine { - ok(state == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", state); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); } + ok(state == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", state); res = RegSetValueExA(prodkey, "ManagedLocalPackage", 0, REG_SZ, (const BYTE *)"msitest.msi", 11); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);