msi: Implement MsiEnumPatchesExW.
This commit is contained in:
parent
a32fcfa9b1
commit
87fef9fd22
|
@ -168,6 +168,15 @@ static const WCHAR szUserDataProd_fmt[] = {
|
||||||
'U','s','e','r','D','a','t','a','\\',
|
'U','s','e','r','D','a','t','a','\\',
|
||||||
'%','s','\\','P','r','o','d','u','c','t','s','\\','%','s',0};
|
'%','s','\\','P','r','o','d','u','c','t','s','\\','%','s',0};
|
||||||
|
|
||||||
|
static const WCHAR szUserDataPatch_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','a','t','c','h','e','s','\\','%','s',0};
|
||||||
|
|
||||||
static const WCHAR szInstallProperties_fmt[] = {
|
static const WCHAR szInstallProperties_fmt[] = {
|
||||||
'S','o','f','t','w','a','r','e','\\',
|
'S','o','f','t','w','a','r','e','\\',
|
||||||
'M','i','c','r','o','s','o','f','t','\\',
|
'M','i','c','r','o','s','o','f','t','\\',
|
||||||
|
@ -241,6 +250,9 @@ BOOL unsquash_guid(LPCWSTR in, LPWSTR out)
|
||||||
{
|
{
|
||||||
DWORD i,n=0;
|
DWORD i,n=0;
|
||||||
|
|
||||||
|
if (lstrlenW(in) != 32)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
out[n++]='{';
|
out[n++]='{';
|
||||||
for(i=0; i<8; i++)
|
for(i=0; i<8; i++)
|
||||||
out[n++] = in[7-i];
|
out[n++] = in[7-i];
|
||||||
|
@ -860,6 +872,32 @@ UINT MSIREG_OpenUserDataProductKey(LPCWSTR szProduct, HKEY *key, BOOL create)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UINT MSIREG_OpenUserDataPatchKey(LPWSTR patch, HKEY *key, BOOL create)
|
||||||
|
{
|
||||||
|
UINT rc;
|
||||||
|
WCHAR keypath[0x200];
|
||||||
|
LPWSTR usersid;
|
||||||
|
|
||||||
|
TRACE("\n");
|
||||||
|
|
||||||
|
rc = get_user_sid(&usersid);
|
||||||
|
if (rc != ERROR_SUCCESS || !usersid)
|
||||||
|
{
|
||||||
|
ERR("Failed to retrieve user SID: %d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintfW(keypath, szUserDataPatch_fmt, usersid, patch);
|
||||||
|
|
||||||
|
if (create)
|
||||||
|
rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
|
||||||
|
else
|
||||||
|
rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
|
||||||
|
|
||||||
|
LocalFree(usersid);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
UINT MSIREG_OpenLocalUserDataProductKey(LPCWSTR szProduct, HKEY *key, BOOL create)
|
UINT MSIREG_OpenLocalUserDataProductKey(LPCWSTR szProduct, HKEY *key, BOOL create)
|
||||||
{
|
{
|
||||||
WCHAR squished_pc[GUID_SIZE];
|
WCHAR squished_pc[GUID_SIZE];
|
||||||
|
@ -1727,19 +1765,287 @@ done:
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static UINT msi_get_patch_state(LPCWSTR prodcode, LPCWSTR usersid,
|
||||||
|
LPWSTR patch, MSIPATCHSTATE *state)
|
||||||
|
{
|
||||||
|
DWORD type, val, size;
|
||||||
|
HKEY prod, hkey = 0;
|
||||||
|
HKEY udpatch = 0;
|
||||||
|
LONG res;
|
||||||
|
UINT r = ERROR_NO_MORE_ITEMS;
|
||||||
|
|
||||||
|
static const WCHAR szPatches[] = {'P','a','t','c','h','e','s',0};
|
||||||
|
static const WCHAR szState[] = {'S','t','a','t','e',0};
|
||||||
|
|
||||||
|
/* FIXME: usersid might not be current user */
|
||||||
|
r = MSIREG_OpenUserDataProductKey(prodcode, &prod, FALSE);
|
||||||
|
if (r != ERROR_SUCCESS)
|
||||||
|
return ERROR_NO_MORE_ITEMS;
|
||||||
|
|
||||||
|
res = RegOpenKeyExW(prod, szPatches, 0, KEY_READ, &hkey);
|
||||||
|
if (res != ERROR_SUCCESS)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
res = RegOpenKeyExW(hkey, patch, 0, KEY_READ, &udpatch);
|
||||||
|
if (res != ERROR_SUCCESS)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
size = sizeof(DWORD);
|
||||||
|
res = RegGetValueW(udpatch, NULL, szState, RRF_RT_DWORD, &type, &val, &size);
|
||||||
|
if (res != ERROR_SUCCESS ||
|
||||||
|
val < MSIPATCHSTATE_APPLIED || val > MSIPATCHSTATE_REGISTERED)
|
||||||
|
{
|
||||||
|
r = ERROR_BAD_CONFIGURATION;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
*state = val;
|
||||||
|
r = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
done:
|
||||||
|
RegCloseKey(udpatch);
|
||||||
|
RegCloseKey(hkey);
|
||||||
|
RegCloseKey(prod);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static UINT msi_check_product_patches(LPCWSTR prodcode, LPCWSTR usersid,
|
||||||
|
MSIINSTALLCONTEXT context, DWORD filter, DWORD index, DWORD *idx,
|
||||||
|
LPWSTR patch, LPWSTR targetprod, MSIINSTALLCONTEXT *targetctx,
|
||||||
|
LPWSTR targetsid, DWORD *sidsize)
|
||||||
|
{
|
||||||
|
MSIPATCHSTATE state;
|
||||||
|
LPWSTR ptr, patches = NULL;
|
||||||
|
HKEY prod, patchkey = 0;
|
||||||
|
HKEY localprod = 0, localpatch = 0;
|
||||||
|
DWORD type, size;
|
||||||
|
LONG res;
|
||||||
|
UINT temp, r = ERROR_NO_MORE_ITEMS;
|
||||||
|
|
||||||
|
static const WCHAR szPatches[] = {'P','a','t','c','h','e','s',0};
|
||||||
|
static const WCHAR szState[] = {'S','t','a','t','e',0};
|
||||||
|
static const WCHAR szEmpty[] = {0};
|
||||||
|
|
||||||
|
if (MSIREG_OpenProductKey(prodcode, context, &prod, FALSE) != ERROR_SUCCESS)
|
||||||
|
return ERROR_NO_MORE_ITEMS;
|
||||||
|
|
||||||
|
size = 0;
|
||||||
|
res = RegGetValueW(prod, szPatches, szPatches, RRF_RT_ANY, &type, NULL,
|
||||||
|
&size);
|
||||||
|
if (res != ERROR_SUCCESS)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if (type != REG_MULTI_SZ)
|
||||||
|
{
|
||||||
|
r = ERROR_BAD_CONFIGURATION;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
patches = msi_alloc(size);
|
||||||
|
if (!patches)
|
||||||
|
{
|
||||||
|
r = ERROR_OUTOFMEMORY;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = RegGetValueW(prod, szPatches, szPatches, RRF_RT_ANY, &type,
|
||||||
|
patches, &size);
|
||||||
|
if (res != ERROR_SUCCESS)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
ptr = patches;
|
||||||
|
for (ptr = patches; *ptr && r == ERROR_NO_MORE_ITEMS; ptr += lstrlenW(ptr))
|
||||||
|
{
|
||||||
|
if (!unsquash_guid(ptr, patch))
|
||||||
|
{
|
||||||
|
r = ERROR_BAD_CONFIGURATION;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = 0;
|
||||||
|
res = RegGetValueW(prod, szPatches, ptr, RRF_RT_REG_SZ,
|
||||||
|
&type, NULL, &size);
|
||||||
|
if (res != ERROR_SUCCESS)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (context == MSIINSTALLCONTEXT_USERMANAGED)
|
||||||
|
{
|
||||||
|
if (!(filter & MSIPATCHSTATE_APPLIED))
|
||||||
|
{
|
||||||
|
temp = msi_get_patch_state(prodcode, usersid, ptr, &state);
|
||||||
|
if (temp == ERROR_BAD_CONFIGURATION)
|
||||||
|
{
|
||||||
|
r = ERROR_BAD_CONFIGURATION;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (temp != ERROR_SUCCESS || !(filter & state))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
|
||||||
|
{
|
||||||
|
if (!(filter & MSIPATCHSTATE_APPLIED))
|
||||||
|
{
|
||||||
|
temp = msi_get_patch_state(prodcode, usersid, ptr, &state);
|
||||||
|
if (temp == ERROR_BAD_CONFIGURATION)
|
||||||
|
{
|
||||||
|
r = ERROR_BAD_CONFIGURATION;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (temp != ERROR_SUCCESS || !(filter & state))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
temp = MSIREG_OpenUserDataPatchKey(ptr, &patchkey, FALSE);
|
||||||
|
RegCloseKey(patchkey);
|
||||||
|
if (temp != ERROR_SUCCESS)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (context == MSIINSTALLCONTEXT_MACHINE)
|
||||||
|
{
|
||||||
|
usersid = szEmpty;
|
||||||
|
|
||||||
|
if (MSIREG_OpenLocalUserDataProductKey(prodcode, &localprod, FALSE) == ERROR_SUCCESS &&
|
||||||
|
RegOpenKeyExW(localprod, szPatches, 0, KEY_READ, &localpatch) == ERROR_SUCCESS &&
|
||||||
|
RegOpenKeyExW(localpatch, ptr, 0, KEY_READ, &patchkey) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
res = RegGetValueW(patchkey, NULL, szState, RRF_RT_REG_DWORD,
|
||||||
|
&type, &state, &size);
|
||||||
|
|
||||||
|
if (!(filter & state))
|
||||||
|
res = ERROR_NO_MORE_ITEMS;
|
||||||
|
|
||||||
|
RegCloseKey(patchkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
RegCloseKey(localpatch);
|
||||||
|
RegCloseKey(localprod);
|
||||||
|
|
||||||
|
if (res != ERROR_SUCCESS)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*idx < index)
|
||||||
|
{
|
||||||
|
(*idx)++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = ERROR_SUCCESS;
|
||||||
|
lstrcpyW(targetprod, prodcode);
|
||||||
|
|
||||||
|
if (targetctx)
|
||||||
|
*targetctx = context;
|
||||||
|
|
||||||
|
if (targetsid)
|
||||||
|
{
|
||||||
|
lstrcpynW(targetsid, usersid, *sidsize);
|
||||||
|
if (lstrlenW(usersid) >= *sidsize)
|
||||||
|
r = ERROR_MORE_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sidsize)
|
||||||
|
{
|
||||||
|
*sidsize = lstrlenW(usersid);
|
||||||
|
if (!targetsid)
|
||||||
|
*sidsize *= sizeof(WCHAR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
RegCloseKey(prod);
|
||||||
|
msi_free(patches);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* MsiEnumPatchesW [MSI.@]
|
* MsiEnumPatchesExW [MSI.@]
|
||||||
*/
|
*/
|
||||||
UINT WINAPI MsiEnumPatchesExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
|
UINT WINAPI MsiEnumPatchesExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
|
||||||
DWORD dwContext, DWORD dwFilter, DWORD dwIndex, LPWSTR szPatchCode,
|
DWORD dwContext, DWORD dwFilter, DWORD dwIndex, LPWSTR szPatchCode,
|
||||||
LPWSTR szTargetProductCode, MSIINSTALLCONTEXT *pdwTargetProductContext,
|
LPWSTR szTargetProductCode, MSIINSTALLCONTEXT *pdwTargetProductContext,
|
||||||
LPWSTR szTargetUserSid, LPDWORD pcchTargetUserSid)
|
LPWSTR szTargetUserSid, LPDWORD pcchTargetUserSid)
|
||||||
{
|
{
|
||||||
FIXME("(%s, %s, %d, %d, %d, %p, %p, %p, %p, %p) stub!\n",
|
WCHAR squished_pc[GUID_SIZE];
|
||||||
|
DWORD idx = 0;
|
||||||
|
UINT r;
|
||||||
|
|
||||||
|
static int last_index = 0;
|
||||||
|
|
||||||
|
TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p, %p)\n",
|
||||||
debugstr_w(szProductCode), debugstr_w(szUserSid), dwContext, dwFilter,
|
debugstr_w(szProductCode), debugstr_w(szUserSid), dwContext, dwFilter,
|
||||||
dwIndex, szPatchCode, szTargetProductCode, pdwTargetProductContext,
|
dwIndex, szPatchCode, szTargetProductCode, pdwTargetProductContext,
|
||||||
szTargetUserSid, pcchTargetUserSid);
|
szTargetUserSid, pcchTargetUserSid);
|
||||||
return ERROR_NO_MORE_ITEMS;
|
|
||||||
|
if (!szProductCode || !squash_guid(szProductCode, squished_pc))
|
||||||
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
if (!lstrcmpW(szUserSid, localsid))
|
||||||
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
if (dwContext & MSIINSTALLCONTEXT_MACHINE && szUserSid)
|
||||||
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
if (dwContext <= MSIINSTALLCONTEXT_NONE ||
|
||||||
|
dwContext > MSIINSTALLCONTEXT_ALL)
|
||||||
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
if (dwFilter <= MSIPATCHSTATE_INVALID || dwFilter > MSIPATCHSTATE_ALL)
|
||||||
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
if (dwIndex && dwIndex - last_index != 1)
|
||||||
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
if (dwIndex == 0)
|
||||||
|
last_index = 0;
|
||||||
|
|
||||||
|
if (dwContext & MSIINSTALLCONTEXT_USERMANAGED)
|
||||||
|
{
|
||||||
|
r = msi_check_product_patches(szProductCode, szUserSid,
|
||||||
|
MSIINSTALLCONTEXT_USERMANAGED, dwFilter,
|
||||||
|
dwIndex, &idx, szPatchCode,
|
||||||
|
szTargetProductCode,
|
||||||
|
pdwTargetProductContext,
|
||||||
|
szTargetUserSid, pcchTargetUserSid);
|
||||||
|
if (r != ERROR_NO_MORE_ITEMS)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dwContext & MSIINSTALLCONTEXT_USERUNMANAGED)
|
||||||
|
{
|
||||||
|
r = msi_check_product_patches(szProductCode, szUserSid,
|
||||||
|
MSIINSTALLCONTEXT_USERUNMANAGED, dwFilter,
|
||||||
|
dwIndex, &idx, szPatchCode,
|
||||||
|
szTargetProductCode,
|
||||||
|
pdwTargetProductContext,
|
||||||
|
szTargetUserSid, pcchTargetUserSid);
|
||||||
|
if (r != ERROR_NO_MORE_ITEMS)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dwContext & MSIINSTALLCONTEXT_MACHINE)
|
||||||
|
{
|
||||||
|
r = msi_check_product_patches(szProductCode, szUserSid,
|
||||||
|
MSIINSTALLCONTEXT_MACHINE, dwFilter,
|
||||||
|
dwIndex, &idx, szPatchCode,
|
||||||
|
szTargetProductCode,
|
||||||
|
pdwTargetProductContext,
|
||||||
|
szTargetUserSid, pcchTargetUserSid);
|
||||||
|
if (r != ERROR_NO_MORE_ITEMS)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (r == ERROR_SUCCESS)
|
||||||
|
last_index = dwIndex;
|
||||||
|
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
|
|
Loading…
Reference in New Issue