2006-02-17 00:04:10 +00:00
|
|
|
/*
|
|
|
|
* Implementation of the Microsoft Installer (msi.dll)
|
|
|
|
*
|
|
|
|
* Copyright 2005 Mike McCormack for CodeWeavers
|
|
|
|
* Copyright 2005 Aric Stewart for CodeWeavers
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
2006-08-01 23:12:11 +00:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
2006-02-17 00:04:10 +00:00
|
|
|
*/
|
|
|
|
|
2018-03-04 23:30:58 +00:00
|
|
|
#include <stdarg.h>
|
|
|
|
|
|
|
|
#define COBJMACROS
|
|
|
|
|
|
|
|
#include "windef.h"
|
|
|
|
#include "winbase.h"
|
|
|
|
#include "winreg.h"
|
|
|
|
#include "winnls.h"
|
|
|
|
#include "shlwapi.h"
|
|
|
|
#include "wine/debug.h"
|
|
|
|
#include "msi.h"
|
2006-02-17 00:04:10 +00:00
|
|
|
#include "msipriv.h"
|
2018-03-04 23:30:58 +00:00
|
|
|
#include "wincrypt.h"
|
|
|
|
#include "wine/unicode.h"
|
|
|
|
#include "winver.h"
|
|
|
|
#include "winuser.h"
|
|
|
|
#include "sddl.h"
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
/*
|
2006-02-17 00:04:10 +00:00
|
|
|
* This module will be all the helper functions for registry access by the
|
2008-01-16 10:11:22 +00:00
|
|
|
* installer bits.
|
2006-02-17 00:04:10 +00:00
|
|
|
*/
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szUserDataFeatures_fmt[] = {
|
2012-01-21 17:19:12 +00:00
|
|
|
'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','\\','F','e','a','t','u','r','e','s',0};
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szUserDataComp_fmt[] = {
|
2012-01-21 17:19:12 +00:00
|
|
|
'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','\\','C','o','m','p','o','n','e','n','t','s','\\','%','s',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR szUserDataComponents_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','\\','C','o','m','p','o','n','e','n','t','s',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
|
|
|
|
static const WCHAR szUserDataProd_fmt[] = {
|
2012-01-21 17:19:12 +00:00
|
|
|
'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};
|
|
|
|
|
|
|
|
static const WCHAR szUserDataProducts_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',0};
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
static const WCHAR szUserDataPatch_fmt[] = {
|
2012-01-21 17:19:12 +00:00
|
|
|
'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 szUserDataPatches_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',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
static const WCHAR szUserDataProductPatches_fmt[] = {
|
2012-01-21 17:19:12 +00:00
|
|
|
'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','\\','P','a','t','c','h','e','s',0};
|
2010-05-29 08:55:43 +00:00
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
static const WCHAR szInstallProperties_fmt[] = {
|
2012-01-21 17:19:12 +00:00
|
|
|
'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','\\',
|
|
|
|
'I','n','s','t','a','l','l','P','r','o','p','e','r','t','i','e','s',0};
|
2008-07-08 20:52:29 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szInstaller_LocalManagedProd_fmt[] = {
|
2012-01-21 17:19:12 +00:00
|
|
|
'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','\\','%','s','\\',
|
|
|
|
'I','n','s','t','a','l','l','e','r','\\','P','r','o','d','u','c','t','s','\\','%','s',0};
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-07-08 20:52:29 +00:00
|
|
|
static const WCHAR szInstaller_LocalManagedFeat_fmt[] = {
|
2012-01-21 17:19:12 +00:00
|
|
|
'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','\\','%','s','\\',
|
|
|
|
'I','n','s','t','a','l','l','e','r','\\','F','e','a','t','u','r','e','s','\\','%','s',0};
|
|
|
|
|
|
|
|
static const WCHAR szInstaller_Products[] = {
|
|
|
|
'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','\\','P','r','o','d','u','c','t','s',0};
|
|
|
|
|
|
|
|
static const WCHAR szInstaller_Patches[] = {
|
|
|
|
'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','\\','P','a','t','c','h','e','s',0};
|
|
|
|
|
|
|
|
static const WCHAR szInstaller_LocalClassesProducts[] = {
|
|
|
|
'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};
|
|
|
|
|
|
|
|
static const WCHAR szInstaller_LocalClassesFeatures[] = {
|
|
|
|
'S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s','\\',
|
|
|
|
'I','n','s','t','a','l','l','e','r','\\','F','e','a','t','u','r','e','s',0};
|
|
|
|
|
|
|
|
static const WCHAR szInstaller_LocalClassesProd[] = {
|
|
|
|
'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};
|
|
|
|
|
|
|
|
static const WCHAR szInstaller_LocalClassesFeat[] = {
|
|
|
|
'S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s','\\',
|
|
|
|
'I','n','s','t','a','l','l','e','r','\\','F','e','a','t','u','r','e','s','\\',0};
|
|
|
|
|
|
|
|
static const WCHAR szInstaller_ClassesUpgradeCode[] = {
|
|
|
|
'S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s','\\',
|
|
|
|
'I','n','s','t','a','l','l','e','r','\\','U','p','g','r','a','d','e','C','o','d','e','s','\\',0};
|
|
|
|
|
|
|
|
static const WCHAR szInstaller_ClassesUpgradeCodes[] = {
|
|
|
|
'S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s','\\',
|
|
|
|
'I','n','s','t','a','l','l','e','r','\\','U','p','g','r','a','d','e','C','o','d','e','s',0};
|
|
|
|
|
|
|
|
static const WCHAR szInstaller_Features[] = {
|
|
|
|
'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','\\','F','e','a','t','u','r','e','s','\\',0};
|
|
|
|
|
|
|
|
static const WCHAR szInstaller_UpgradeCodes[] = {
|
|
|
|
'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','p','g','r','a','d','e','C','o','d','e','s','\\',0};
|
|
|
|
|
|
|
|
static const WCHAR szInstaller_UserUpgradeCodes[] = {
|
|
|
|
'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','\\','U','p','g','r','a','d','e','C','o','d','e','s','\\',0};
|
|
|
|
|
|
|
|
static const WCHAR szUninstall[] = {
|
|
|
|
'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','\\',
|
|
|
|
'U','n','i','n','s','t','a','l','l','\\',0};
|
|
|
|
|
|
|
|
static const WCHAR szUninstall_32node[] = {
|
|
|
|
'S','o','f','t','w','a','r','e','\\','W','o','w','6','4','3','2','N','o','d','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','\\','U','n','i','n','s','t','a','l','l','\\',0};
|
|
|
|
|
|
|
|
static const WCHAR szUserComponents[] = {
|
|
|
|
'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','\\','C','o','m','p','o','n','e','n','t','s','\\',0};
|
|
|
|
|
2015-11-21 16:44:38 +00:00
|
|
|
static const WCHAR szInstaller_Components[] = {
|
|
|
|
'S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s','\\',
|
|
|
|
'I','n','s','t','a','l','l','e','r','\\','C','o','m','p','o','n','e','n','t','s','\\',0};
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR szUserFeatures[] = {
|
|
|
|
'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','\\','F','e','a','t','u','r','e','s','\\',0};
|
|
|
|
|
|
|
|
static const WCHAR szUserProducts[] = {
|
|
|
|
'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};
|
|
|
|
|
|
|
|
static const WCHAR szUserPatches[] = {
|
|
|
|
'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','a','t','c','h','e','s','\\',0};
|
2008-07-08 20:52:29 +00:00
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
BOOL unsquash_guid(LPCWSTR in, LPWSTR out)
|
|
|
|
{
|
|
|
|
DWORD i,n=0;
|
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
if (lstrlenW(in) != 32)
|
|
|
|
return FALSE;
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
out[n++]='{';
|
|
|
|
for(i=0; i<8; i++)
|
|
|
|
out[n++] = in[7-i];
|
|
|
|
out[n++]='-';
|
|
|
|
for(i=0; i<4; i++)
|
|
|
|
out[n++] = in[11-i];
|
|
|
|
out[n++]='-';
|
|
|
|
for(i=0; i<4; i++)
|
|
|
|
out[n++] = in[15-i];
|
|
|
|
out[n++]='-';
|
|
|
|
for(i=0; i<2; i++)
|
|
|
|
{
|
|
|
|
out[n++] = in[17+i*2];
|
|
|
|
out[n++] = in[16+i*2];
|
|
|
|
}
|
|
|
|
out[n++]='-';
|
|
|
|
for( ; i<8; i++)
|
|
|
|
{
|
|
|
|
out[n++] = in[17+i*2];
|
|
|
|
out[n++] = in[16+i*2];
|
|
|
|
}
|
|
|
|
out[n++]='}';
|
|
|
|
out[n]=0;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL squash_guid(LPCWSTR in, LPWSTR out)
|
|
|
|
{
|
2006-08-01 23:12:11 +00:00
|
|
|
DWORD i,n=1;
|
|
|
|
GUID guid;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
out[0] = 0;
|
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
if (FAILED(CLSIDFromString((LPCOLESTR)in, &guid)))
|
2006-02-17 00:04:10 +00:00
|
|
|
return FALSE;
|
2006-08-01 23:12:11 +00:00
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
for(i=0; i<8; i++)
|
|
|
|
out[7-i] = in[n++];
|
2006-08-01 23:12:11 +00:00
|
|
|
n++;
|
2006-02-17 00:04:10 +00:00
|
|
|
for(i=0; i<4; i++)
|
|
|
|
out[11-i] = in[n++];
|
2006-08-01 23:12:11 +00:00
|
|
|
n++;
|
2006-02-17 00:04:10 +00:00
|
|
|
for(i=0; i<4; i++)
|
|
|
|
out[15-i] = in[n++];
|
2006-08-01 23:12:11 +00:00
|
|
|
n++;
|
2006-02-17 00:04:10 +00:00
|
|
|
for(i=0; i<2; i++)
|
|
|
|
{
|
|
|
|
out[17+i*2] = in[n++];
|
|
|
|
out[16+i*2] = in[n++];
|
|
|
|
}
|
2006-08-01 23:12:11 +00:00
|
|
|
n++;
|
2006-02-17 00:04:10 +00:00
|
|
|
for( ; i<8; i++)
|
|
|
|
{
|
|
|
|
out[17+i*2] = in[n++];
|
|
|
|
out[16+i*2] = in[n++];
|
|
|
|
}
|
|
|
|
out[32]=0;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* tables for encoding and decoding base85 */
|
|
|
|
static const unsigned char table_dec85[0x80] = {
|
|
|
|
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
|
|
|
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
|
|
|
0xff,0x00,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0xff,
|
|
|
|
0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0xff,0xff,0xff,0x16,0xff,0x17,
|
|
|
|
0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
|
|
|
|
0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0x34,0x35,0x36,
|
|
|
|
0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,
|
|
|
|
0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0xff,0x53,0x54,0xff,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char table_enc85[] =
|
|
|
|
"!$%&'()*+,-.0123456789=?@ABCDEFGHIJKLMNO"
|
|
|
|
"PQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwx"
|
|
|
|
"yz{}~";
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Converts a base85 encoded guid into a GUID pointer
|
|
|
|
* Base85 encoded GUIDs should be 20 characters long.
|
|
|
|
*
|
|
|
|
* returns TRUE if successful, FALSE if not
|
|
|
|
*/
|
|
|
|
BOOL decode_base85_guid( LPCWSTR str, GUID *guid )
|
|
|
|
{
|
|
|
|
DWORD i, val = 0, base = 1, *p;
|
|
|
|
|
|
|
|
if (!str)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
p = (DWORD*) guid;
|
|
|
|
for( i=0; i<20; i++ )
|
|
|
|
{
|
|
|
|
if( (i%5) == 0 )
|
|
|
|
{
|
|
|
|
val = 0;
|
|
|
|
base = 1;
|
|
|
|
}
|
|
|
|
val += table_dec85[str[i]] * base;
|
|
|
|
if( str[i] >= 0x80 )
|
|
|
|
return FALSE;
|
|
|
|
if( table_dec85[str[i]] == 0xff )
|
|
|
|
return FALSE;
|
|
|
|
if( (i%5) == 4 )
|
|
|
|
p[i/5] = val;
|
|
|
|
base *= 85;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Encodes a base85 guid given a GUID pointer
|
|
|
|
* Caller should provide a 21 character buffer for the encoded string.
|
|
|
|
*
|
|
|
|
* returns TRUE if successful, FALSE if not
|
|
|
|
*/
|
|
|
|
BOOL encode_base85_guid( GUID *guid, LPWSTR str )
|
|
|
|
{
|
|
|
|
unsigned int x, *p, i;
|
|
|
|
|
|
|
|
p = (unsigned int*) guid;
|
|
|
|
for( i=0; i<4; i++ )
|
|
|
|
{
|
|
|
|
x = p[i];
|
|
|
|
*str++ = table_enc85[x%85];
|
|
|
|
x = x/85;
|
|
|
|
*str++ = table_enc85[x%85];
|
|
|
|
x = x/85;
|
|
|
|
*str++ = table_enc85[x%85];
|
|
|
|
x = x/85;
|
|
|
|
*str++ = table_enc85[x%85];
|
|
|
|
x = x/85;
|
|
|
|
*str++ = table_enc85[x%85];
|
|
|
|
}
|
|
|
|
*str = 0;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2006-08-01 23:12:11 +00:00
|
|
|
DWORD msi_version_str_to_dword(LPCWSTR p)
|
|
|
|
{
|
|
|
|
DWORD major, minor = 0, build = 0, version = 0;
|
|
|
|
|
|
|
|
if (!p)
|
|
|
|
return version;
|
|
|
|
|
|
|
|
major = atoiW(p);
|
|
|
|
|
|
|
|
p = strchrW(p, '.');
|
|
|
|
if (p)
|
|
|
|
{
|
|
|
|
minor = atoiW(p+1);
|
|
|
|
p = strchrW(p+1, '.');
|
|
|
|
if (p)
|
|
|
|
build = atoiW(p+1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return MAKELONG(build, MAKEWORD(minor, major));
|
|
|
|
}
|
|
|
|
|
|
|
|
LONG msi_reg_set_val_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
|
|
|
|
{
|
2008-05-17 19:46:01 +00:00
|
|
|
DWORD len;
|
2009-10-25 11:06:09 +00:00
|
|
|
if (!value) value = szEmpty;
|
2008-05-17 19:46:01 +00:00
|
|
|
len = (lstrlenW(value) + 1) * sizeof (WCHAR);
|
2006-10-22 20:23:59 +00:00
|
|
|
return RegSetValueExW( hkey, name, 0, REG_SZ, (const BYTE *)value, len );
|
2006-08-01 23:12:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
LONG msi_reg_set_val_multi_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
|
|
|
|
{
|
|
|
|
LPCWSTR p = value;
|
|
|
|
while (*p) p += lstrlenW(p) + 1;
|
|
|
|
return RegSetValueExW( hkey, name, 0, REG_MULTI_SZ,
|
2006-10-22 20:23:59 +00:00
|
|
|
(const BYTE *)value, (p + 1 - value) * sizeof(WCHAR) );
|
2006-08-01 23:12:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
LONG msi_reg_set_val_dword( HKEY hkey, LPCWSTR name, DWORD val )
|
|
|
|
{
|
|
|
|
return RegSetValueExW( hkey, name, 0, REG_DWORD, (LPBYTE)&val, sizeof (DWORD) );
|
|
|
|
}
|
|
|
|
|
|
|
|
LONG msi_reg_set_subkey_val( HKEY hkey, LPCWSTR path, LPCWSTR name, LPCWSTR val )
|
|
|
|
{
|
|
|
|
HKEY hsubkey = 0;
|
|
|
|
LONG r;
|
|
|
|
|
|
|
|
r = RegCreateKeyW( hkey, path, &hsubkey );
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return r;
|
|
|
|
r = msi_reg_set_val_str( hsubkey, name, val );
|
|
|
|
RegCloseKey( hsubkey );
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
LPWSTR msi_reg_get_val_str( HKEY hkey, LPCWSTR name )
|
|
|
|
{
|
|
|
|
DWORD len = 0;
|
|
|
|
LPWSTR val;
|
|
|
|
LONG r;
|
|
|
|
|
|
|
|
r = RegQueryValueExW(hkey, name, NULL, NULL, NULL, &len);
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
len += sizeof (WCHAR);
|
|
|
|
val = msi_alloc( len );
|
|
|
|
if (!val)
|
|
|
|
return NULL;
|
|
|
|
val[0] = 0;
|
|
|
|
RegQueryValueExW(hkey, name, NULL, NULL, (LPBYTE) val, &len);
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL msi_reg_get_val_dword( HKEY hkey, LPCWSTR name, DWORD *val)
|
|
|
|
{
|
|
|
|
DWORD type, len = sizeof (DWORD);
|
|
|
|
LONG r = RegQueryValueExW(hkey, name, NULL, &type, (LPBYTE) val, &len);
|
|
|
|
return r == ERROR_SUCCESS && type == REG_DWORD;
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
static WCHAR *get_user_sid(void)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
|
|
|
HANDLE token;
|
2012-01-21 17:19:12 +00:00
|
|
|
DWORD size = 256;
|
|
|
|
TOKEN_USER *user;
|
|
|
|
WCHAR *ret;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &token )) return NULL;
|
|
|
|
if (!(user = msi_alloc( size )))
|
|
|
|
{
|
|
|
|
CloseHandle( token );
|
|
|
|
return NULL;
|
2008-01-20 17:01:42 +00:00
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
if (!GetTokenInformation( token, TokenUser, user, size, &size ))
|
|
|
|
{
|
|
|
|
msi_free( user );
|
|
|
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER || !(user = msi_alloc( size )))
|
|
|
|
{
|
|
|
|
CloseHandle( token );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
GetTokenInformation( token, TokenUser, user, size, &size );
|
2008-01-20 17:01:42 +00:00
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
CloseHandle( token );
|
|
|
|
if (!ConvertSidToStringSidW( user->User.Sid, &ret ))
|
|
|
|
{
|
|
|
|
msi_free( user );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
msi_free( user );
|
|
|
|
return ret;
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT MSIREG_OpenUninstallKey(const WCHAR *product, enum platform platform, HKEY *key, BOOL create)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
WCHAR keypath[0x200];
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("%s\n", debugstr_w(product));
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (is_64bit && platform == PLATFORM_INTEL)
|
|
|
|
{
|
|
|
|
strcpyW(keypath, szUninstall_32node);
|
|
|
|
strcatW(keypath, product);
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
else
|
2012-01-21 17:19:12 +00:00
|
|
|
{
|
|
|
|
strcpyW(keypath, szUninstall);
|
|
|
|
strcatW(keypath, product);
|
|
|
|
}
|
|
|
|
if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, KEY_ALL_ACCESS, NULL, key, NULL);
|
|
|
|
return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, KEY_ALL_ACCESS, key);
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT MSIREG_DeleteUninstallKey(const WCHAR *product, enum platform platform)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
|
|
|
WCHAR keypath[0x200];
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("%s\n", debugstr_w(product));
|
2010-10-22 13:18:11 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (is_64bit && platform == PLATFORM_INTEL)
|
|
|
|
{
|
|
|
|
strcpyW(keypath, szUninstall_32node);
|
|
|
|
strcatW(keypath, product);
|
|
|
|
}
|
2010-10-22 13:18:11 +00:00
|
|
|
else
|
2012-01-21 17:19:12 +00:00
|
|
|
{
|
|
|
|
strcpyW(keypath, szUninstall);
|
|
|
|
strcatW(keypath, product);
|
|
|
|
}
|
2015-11-21 16:44:38 +00:00
|
|
|
return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT MSIREG_OpenProductKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context, HKEY *key, BOOL create)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2008-12-27 15:10:14 +00:00
|
|
|
HKEY root = HKEY_LOCAL_MACHINE;
|
2012-01-21 17:19:12 +00:00
|
|
|
REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR *usersid = NULL, squashed_pc[SQUASHED_GUID_SIZE], keypath[MAX_PATH];
|
2008-12-27 15:10:14 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
if (context == MSIINSTALLCONTEXT_MACHINE)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
strcpyW(keypath, szInstaller_LocalClassesProd);
|
2016-11-22 12:25:27 +00:00
|
|
|
strcatW( keypath, squashed_pc );
|
2008-12-27 15:10:14 +00:00
|
|
|
}
|
|
|
|
else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
|
|
|
|
{
|
|
|
|
root = HKEY_CURRENT_USER;
|
2012-01-21 17:19:12 +00:00
|
|
|
strcpyW(keypath, szUserProducts);
|
2016-11-22 12:25:27 +00:00
|
|
|
strcatW( keypath, squashed_pc );
|
2008-12-27 15:10:14 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-05-20 12:59:23 +00:00
|
|
|
if (!szUserSid)
|
2008-12-27 15:10:14 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
if (!(usersid = get_user_sid()))
|
2009-05-20 12:59:23 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
ERR("Failed to retrieve user SID\n");
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
2009-05-20 12:59:23 +00:00
|
|
|
}
|
|
|
|
szUserSid = usersid;
|
2008-12-27 15:10:14 +00:00
|
|
|
}
|
2016-11-22 12:25:27 +00:00
|
|
|
sprintfW( keypath, szInstaller_LocalManagedProd_fmt, szUserSid, squashed_pc );
|
2008-12-27 15:10:14 +00:00
|
|
|
LocalFree(usersid);
|
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
if (create) return RegCreateKeyExW(root, keypath, 0, NULL, 0, access, NULL, key, NULL);
|
|
|
|
return RegOpenKeyExW(root, keypath, 0, access, key);
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
UINT MSIREG_DeleteUserProductKey(LPCWSTR szProduct)
|
|
|
|
{
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
strcpyW(keypath, szUserProducts);
|
2016-11-22 12:25:27 +00:00
|
|
|
strcatW( keypath, squashed_pc );
|
2015-11-21 16:44:38 +00:00
|
|
|
return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT MSIREG_OpenUserPatchesKey(LPCWSTR szPatch, HKEY *key, BOOL create)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( szPatch, squashed_pc )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(szPatch), debugstr_w(squashed_pc));
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
strcpyW(keypath, szUserPatches);
|
2016-11-22 12:25:27 +00:00
|
|
|
strcatW( keypath, squashed_pc );
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (create) return RegCreateKeyW(HKEY_CURRENT_USER, keypath, key);
|
|
|
|
return RegOpenKeyW(HKEY_CURRENT_USER, keypath, key);
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
|
2013-04-03 21:58:03 +00:00
|
|
|
UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context,
|
|
|
|
HKEY *key, BOOL create)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2008-12-27 15:10:14 +00:00
|
|
|
HKEY root = HKEY_LOCAL_MACHINE;
|
2012-01-21 17:19:12 +00:00
|
|
|
REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[MAX_PATH], *usersid = NULL;
|
2008-12-27 15:10:14 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
if (context == MSIINSTALLCONTEXT_MACHINE)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
strcpyW(keypath, szInstaller_LocalClassesFeat);
|
2016-11-22 12:25:27 +00:00
|
|
|
strcatW( keypath, squashed_pc );
|
2008-12-27 15:10:14 +00:00
|
|
|
}
|
|
|
|
else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
|
|
|
|
{
|
|
|
|
root = HKEY_CURRENT_USER;
|
2012-01-21 17:19:12 +00:00
|
|
|
strcpyW(keypath, szUserFeatures);
|
2016-11-22 12:25:27 +00:00
|
|
|
strcatW( keypath, squashed_pc );
|
2008-12-27 15:10:14 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-04-03 21:58:03 +00:00
|
|
|
if (!szUserSid)
|
2008-12-27 15:10:14 +00:00
|
|
|
{
|
2013-04-03 21:58:03 +00:00
|
|
|
if (!(usersid = get_user_sid()))
|
|
|
|
{
|
|
|
|
ERR("Failed to retrieve user SID\n");
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
szUserSid = usersid;
|
2008-12-27 15:10:14 +00:00
|
|
|
}
|
2016-11-22 12:25:27 +00:00
|
|
|
sprintfW( keypath, szInstaller_LocalManagedFeat_fmt, szUserSid, squashed_pc );
|
2008-12-27 15:10:14 +00:00
|
|
|
LocalFree(usersid);
|
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
if (create) return RegCreateKeyExW(root, keypath, 0, NULL, 0, access, NULL, key, NULL);
|
|
|
|
return RegOpenKeyExW(root, keypath, 0, access, key);
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
UINT MSIREG_DeleteUserFeaturesKey(LPCWSTR szProduct)
|
|
|
|
{
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
strcpyW(keypath, szUserFeatures);
|
2016-11-22 12:25:27 +00:00
|
|
|
strcatW( keypath, squashed_pc );
|
2015-11-21 16:44:38 +00:00
|
|
|
return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
static UINT MSIREG_OpenInstallerFeaturesKey(LPCWSTR szProduct, HKEY *key, BOOL create)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
strcpyW(keypath, szInstaller_Features);
|
2016-11-22 12:25:27 +00:00
|
|
|
strcatW( keypath, squashed_pc );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
|
|
|
|
return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2013-04-03 21:58:03 +00:00
|
|
|
UINT MSIREG_OpenUserDataFeaturesKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context,
|
|
|
|
HKEY *key, BOOL create)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200], *usersid = NULL;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
if (context == MSIINSTALLCONTEXT_MACHINE)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2016-11-22 12:25:27 +00:00
|
|
|
sprintfW( keypath, szUserDataFeatures_fmt, szLocalSid, squashed_pc );
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
else
|
2008-12-27 15:10:14 +00:00
|
|
|
{
|
2013-04-03 21:58:03 +00:00
|
|
|
if (!szUserSid)
|
2008-12-27 15:10:14 +00:00
|
|
|
{
|
2013-04-03 21:58:03 +00:00
|
|
|
if (!(usersid = get_user_sid()))
|
|
|
|
{
|
|
|
|
ERR("Failed to retrieve user SID\n");
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
szUserSid = usersid;
|
2008-12-27 15:10:14 +00:00
|
|
|
}
|
2016-11-22 12:25:27 +00:00
|
|
|
sprintfW( keypath, szUserDataFeatures_fmt, szUserSid, squashed_pc );
|
2008-12-27 15:10:14 +00:00
|
|
|
LocalFree(usersid);
|
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
|
|
|
|
return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY *key, BOOL create)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR squashed_cc[SQUASHED_GUID_SIZE], keypath[0x200];
|
2017-03-05 20:45:25 +00:00
|
|
|
REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
|
2015-11-21 16:44:38 +00:00
|
|
|
UINT ret;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( szComponent, squashed_cc)) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(szComponent), debugstr_w(squashed_cc));
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
strcpyW(keypath, szUserComponents);
|
2016-11-22 12:25:27 +00:00
|
|
|
strcatW( keypath, squashed_cc );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (create) return RegCreateKeyW(HKEY_CURRENT_USER, keypath, key);
|
2015-11-21 16:44:38 +00:00
|
|
|
ret = RegOpenKeyW(HKEY_CURRENT_USER, keypath, key);
|
|
|
|
if (ret != ERROR_FILE_NOT_FOUND) return ret;
|
|
|
|
|
|
|
|
strcpyW(keypath, szInstaller_Components);
|
2016-11-22 12:25:27 +00:00
|
|
|
strcatW( keypath, squashed_cc );
|
2017-03-05 20:45:25 +00:00
|
|
|
return RegOpenKeyExW( HKEY_LOCAL_MACHINE, keypath, 0, access, key );
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT MSIREG_OpenUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid, HKEY *key, BOOL create)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR *usersid, squashed_comp[SQUASHED_GUID_SIZE], keypath[0x200];
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( szComponent, squashed_comp )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(szComponent), debugstr_w(squashed_comp));
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
if (!szUserSid)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
if (!(usersid = get_user_sid()))
|
2008-12-27 15:10:14 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
ERR("Failed to retrieve user SID\n");
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
2008-12-27 15:10:14 +00:00
|
|
|
}
|
2016-11-22 12:25:27 +00:00
|
|
|
sprintfW( keypath, szUserDataComp_fmt, usersid, squashed_comp );
|
2008-12-27 15:10:14 +00:00
|
|
|
LocalFree(usersid);
|
|
|
|
}
|
|
|
|
else
|
2016-11-22 12:25:27 +00:00
|
|
|
sprintfW( keypath, szUserDataComp_fmt, szUserSid, squashed_comp );
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
|
|
|
|
return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
UINT MSIREG_DeleteUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR *usersid, squashed_comp[SQUASHED_GUID_SIZE], keypath[0x200];
|
2012-01-21 17:19:12 +00:00
|
|
|
HKEY hkey;
|
|
|
|
LONG r;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( szComponent, squashed_comp )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(szComponent), debugstr_w(squashed_comp));
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
if (!szUserSid)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
if (!(usersid = get_user_sid()))
|
2008-12-27 15:10:14 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
ERR("Failed to retrieve user SID\n");
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
2008-12-27 15:10:14 +00:00
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
sprintfW(keypath, szUserDataComponents_fmt, usersid);
|
2008-12-27 15:10:14 +00:00
|
|
|
LocalFree(usersid);
|
|
|
|
}
|
|
|
|
else
|
2012-01-21 17:19:12 +00:00
|
|
|
sprintfW(keypath, szUserDataComponents_fmt, szUserSid);
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, &hkey)) return ERROR_SUCCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
r = RegDeleteTreeW( hkey, squashed_comp );
|
2012-01-21 17:19:12 +00:00
|
|
|
RegCloseKey(hkey);
|
|
|
|
return r;
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT MSIREG_OpenUserDataProductKey(LPCWSTR szProduct, MSIINSTALLCONTEXT dwContext, LPCWSTR szUserSid, HKEY *key, BOOL create)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR *usersid, squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
if (dwContext == MSIINSTALLCONTEXT_MACHINE)
|
2016-11-22 12:25:27 +00:00
|
|
|
sprintfW( keypath, szUserDataProd_fmt, szLocalSid, squashed_pc );
|
2008-12-27 15:10:14 +00:00
|
|
|
else if (szUserSid)
|
2016-11-22 12:25:27 +00:00
|
|
|
sprintfW( keypath, szUserDataProd_fmt, szUserSid, squashed_pc );
|
2008-12-27 15:10:14 +00:00
|
|
|
else
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
if (!(usersid = get_user_sid()))
|
2008-12-27 15:10:14 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
ERR("Failed to retrieve user SID\n");
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
2008-12-27 15:10:14 +00:00
|
|
|
}
|
2016-11-22 12:25:27 +00:00
|
|
|
sprintfW( keypath, szUserDataProd_fmt, usersid, squashed_pc );
|
2008-12-27 15:10:14 +00:00
|
|
|
LocalFree(usersid);
|
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
|
|
|
|
return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT MSIREG_OpenUserDataPatchKey(LPCWSTR szPatch, MSIINSTALLCONTEXT dwContext, HKEY *key, BOOL create)
|
2008-07-08 20:52:29 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR *usersid, squashed_patch[SQUASHED_GUID_SIZE], keypath[0x200];
|
2008-07-08 20:52:29 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( szPatch, squashed_patch )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(szPatch), debugstr_w(squashed_patch));
|
2008-07-08 20:52:29 +00:00
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
if (dwContext == MSIINSTALLCONTEXT_MACHINE)
|
2016-11-22 12:25:27 +00:00
|
|
|
sprintfW( keypath, szUserDataPatch_fmt, szLocalSid, squashed_patch );
|
2008-12-27 15:10:14 +00:00
|
|
|
else
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
if (!(usersid = get_user_sid()))
|
2008-12-27 15:10:14 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
ERR("Failed to retrieve user SID\n");
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
2008-12-27 15:10:14 +00:00
|
|
|
}
|
2016-11-22 12:25:27 +00:00
|
|
|
sprintfW( keypath, szUserDataPatch_fmt, usersid, squashed_patch );
|
2008-12-27 15:10:14 +00:00
|
|
|
LocalFree(usersid);
|
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
|
|
|
|
return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
|
2008-07-08 20:52:29 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
UINT MSIREG_DeleteUserDataPatchKey(LPCWSTR patch, MSIINSTALLCONTEXT context)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR *usersid, squashed_patch[SQUASHED_GUID_SIZE], keypath[0x200];
|
2012-01-21 17:19:12 +00:00
|
|
|
HKEY hkey;
|
|
|
|
LONG r;
|
2010-05-29 08:55:43 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( patch, squashed_patch )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(patch), debugstr_w(squashed_patch));
|
2010-05-29 08:55:43 +00:00
|
|
|
|
|
|
|
if (context == MSIINSTALLCONTEXT_MACHINE)
|
2012-01-21 17:19:12 +00:00
|
|
|
sprintfW(keypath, szUserDataPatches_fmt, szLocalSid);
|
2010-05-29 08:55:43 +00:00
|
|
|
else
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
if (!(usersid = get_user_sid()))
|
2010-05-29 08:55:43 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
ERR("Failed to retrieve user SID\n");
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
2010-05-29 08:55:43 +00:00
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
sprintfW(keypath, szUserDataPatches_fmt, usersid);
|
2010-05-29 08:55:43 +00:00
|
|
|
LocalFree(usersid);
|
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, &hkey)) return ERROR_SUCCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
r = RegDeleteTreeW( hkey, squashed_patch );
|
2012-01-21 17:19:12 +00:00
|
|
|
RegCloseKey(hkey);
|
|
|
|
return r;
|
2010-05-29 08:55:43 +00:00
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT MSIREG_OpenUserDataProductPatchesKey(LPCWSTR product, MSIINSTALLCONTEXT context, HKEY *key, BOOL create)
|
2010-05-29 08:55:43 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR *usersid, squashed_product[SQUASHED_GUID_SIZE], keypath[0x200];
|
2010-05-29 08:55:43 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( product, squashed_product )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(product), debugstr_w(squashed_product));
|
2010-05-29 08:55:43 +00:00
|
|
|
|
|
|
|
if (context == MSIINSTALLCONTEXT_MACHINE)
|
2016-11-22 12:25:27 +00:00
|
|
|
sprintfW( keypath, szUserDataProductPatches_fmt, szLocalSid, squashed_product );
|
2010-05-29 08:55:43 +00:00
|
|
|
else
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
if (!(usersid = get_user_sid()))
|
2010-05-29 08:55:43 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
ERR("Failed to retrieve user SID\n");
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
2010-05-29 08:55:43 +00:00
|
|
|
}
|
2016-11-22 12:25:27 +00:00
|
|
|
sprintfW( keypath, szUserDataProductPatches_fmt, usersid, squashed_product );
|
2010-05-29 08:55:43 +00:00
|
|
|
LocalFree(usersid);
|
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
|
|
|
|
return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
|
2010-05-29 08:55:43 +00:00
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT MSIREG_OpenInstallProps(LPCWSTR szProduct, MSIINSTALLCONTEXT dwContext, LPCWSTR szUserSid, HKEY *key, BOOL create)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR *usersid, squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
if (dwContext == MSIINSTALLCONTEXT_MACHINE)
|
2016-11-22 12:25:27 +00:00
|
|
|
sprintfW( keypath, szInstallProperties_fmt, szLocalSid, squashed_pc );
|
2008-12-27 15:10:14 +00:00
|
|
|
else if (szUserSid)
|
2016-11-22 12:25:27 +00:00
|
|
|
sprintfW( keypath, szInstallProperties_fmt, szUserSid, squashed_pc );
|
2008-05-17 19:46:01 +00:00
|
|
|
else
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
if (!(usersid = get_user_sid()))
|
2008-12-27 15:10:14 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
ERR("Failed to retrieve user SID\n");
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
2008-12-27 15:10:14 +00:00
|
|
|
}
|
2016-11-22 12:25:27 +00:00
|
|
|
sprintfW( keypath, szInstallProperties_fmt, usersid, squashed_pc );
|
2008-12-27 15:10:14 +00:00
|
|
|
LocalFree(usersid);
|
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
|
|
|
|
return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
|
2008-05-17 19:46:01 +00:00
|
|
|
}
|
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
UINT MSIREG_DeleteUserDataProductKey(LPCWSTR szProduct, MSIINSTALLCONTEXT context)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR *usersid, squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
|
2012-01-21 17:19:12 +00:00
|
|
|
HKEY hkey;
|
|
|
|
LONG r;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (context == MSIINSTALLCONTEXT_MACHINE)
|
|
|
|
sprintfW(keypath, szUserDataProducts_fmt, szLocalSid);
|
|
|
|
else
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!(usersid = get_user_sid()))
|
|
|
|
{
|
|
|
|
ERR("Failed to retrieve user SID\n");
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
sprintfW(keypath, szUserDataProducts_fmt, usersid);
|
|
|
|
LocalFree(usersid);
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
|
|
|
|
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, &hkey)) return ERROR_SUCCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
r = RegDeleteTreeW( hkey, squashed_pc );
|
2012-01-21 17:19:12 +00:00
|
|
|
RegCloseKey(hkey);
|
|
|
|
return r;
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
UINT MSIREG_DeleteProductKey(LPCWSTR szProduct)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR squashed_pc[SQUASHED_GUID_SIZE];
|
2012-01-21 17:19:12 +00:00
|
|
|
HKEY hkey;
|
|
|
|
LONG r;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szInstaller_Products, 0, access, &hkey)) return ERROR_SUCCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
r = RegDeleteTreeW( hkey, squashed_pc );
|
2012-01-21 17:19:12 +00:00
|
|
|
RegCloseKey(hkey);
|
|
|
|
return r;
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT MSIREG_OpenPatchesKey(LPCWSTR szPatch, HKEY *key, BOOL create)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( szPatch, squashed_pc )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(szPatch), debugstr_w(squashed_pc));
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
sprintfW( keypath, szInstaller_Patches, squashed_pc );
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
|
|
|
|
return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY *key, BOOL create)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
strcpyW(keypath, szInstaller_UpgradeCodes);
|
2016-11-22 12:25:27 +00:00
|
|
|
strcatW( keypath, squashed_uc );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
|
|
|
|
return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
|
|
|
|
{
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
strcpyW(keypath, szInstaller_UserUpgradeCodes);
|
2016-11-22 12:25:27 +00:00
|
|
|
strcatW( keypath, squashed_uc );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (create) return RegCreateKeyW(HKEY_CURRENT_USER, keypath, key);
|
|
|
|
return RegOpenKeyW(HKEY_CURRENT_USER, keypath, key);
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
UINT MSIREG_DeleteUpgradeCodesKey( const WCHAR *code )
|
|
|
|
{
|
2017-03-05 20:45:25 +00:00
|
|
|
WCHAR squashed_code[SQUASHED_GUID_SIZE];
|
|
|
|
REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
|
|
|
|
HKEY hkey;
|
|
|
|
LONG ret;
|
2016-11-22 12:25:27 +00:00
|
|
|
|
|
|
|
if (!squash_guid( code, squashed_code )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE( "%s squashed %s\n", debugstr_w(code), debugstr_w(squashed_code) );
|
|
|
|
|
2017-03-05 20:45:25 +00:00
|
|
|
if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, szInstaller_UpgradeCodes, 0, access, &hkey )) return ERROR_SUCCESS;
|
|
|
|
ret = RegDeleteTreeW( hkey, squashed_code );
|
|
|
|
RegCloseKey( hkey );
|
|
|
|
return ret;
|
2016-11-22 12:25:27 +00:00
|
|
|
}
|
|
|
|
|
2008-07-08 20:52:29 +00:00
|
|
|
UINT MSIREG_DeleteUserUpgradeCodesKey(LPCWSTR szUpgradeCode)
|
|
|
|
{
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
|
2008-07-08 20:52:29 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
|
2008-07-08 20:52:29 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
strcpyW(keypath, szInstaller_UserUpgradeCodes);
|
2016-11-22 12:25:27 +00:00
|
|
|
strcatW( keypath, squashed_uc );
|
2015-11-21 16:44:38 +00:00
|
|
|
return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
|
2008-07-08 20:52:29 +00:00
|
|
|
}
|
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
UINT MSIREG_DeleteLocalClassesProductKey(LPCWSTR szProductCode)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR squashed_pc[SQUASHED_GUID_SIZE];
|
2012-01-21 17:19:12 +00:00
|
|
|
HKEY hkey;
|
|
|
|
LONG r;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( szProductCode, squashed_pc )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(szProductCode), debugstr_w(squashed_pc));
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szInstaller_LocalClassesProducts, 0, access, &hkey)) return ERROR_SUCCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
r = RegDeleteTreeW( hkey, squashed_pc );
|
2012-01-21 17:19:12 +00:00
|
|
|
RegCloseKey(hkey);
|
|
|
|
return r;
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
UINT MSIREG_DeleteLocalClassesFeaturesKey(LPCWSTR szProductCode)
|
2008-07-08 20:52:29 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR squashed_pc[SQUASHED_GUID_SIZE];
|
2012-01-21 17:19:12 +00:00
|
|
|
HKEY hkey;
|
|
|
|
LONG r;
|
2008-07-08 20:52:29 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( szProductCode, squashed_pc )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(szProductCode), debugstr_w(squashed_pc));
|
2008-07-08 20:52:29 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szInstaller_LocalClassesFeatures, 0, access, &hkey)) return ERROR_SUCCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
r = RegDeleteTreeW( hkey, squashed_pc );
|
2012-01-21 17:19:12 +00:00
|
|
|
RegCloseKey(hkey);
|
|
|
|
return r;
|
2008-07-08 20:52:29 +00:00
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT MSIREG_OpenClassesUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY *key, BOOL create)
|
2008-07-08 20:52:29 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
|
2008-07-08 20:52:29 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
|
2008-07-08 20:52:29 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
strcpyW(keypath, szInstaller_ClassesUpgradeCode);
|
2016-11-22 12:25:27 +00:00
|
|
|
strcatW( keypath, squashed_uc );
|
2008-07-08 20:52:29 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
|
|
|
|
return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
|
2008-07-08 20:52:29 +00:00
|
|
|
}
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
UINT MSIREG_DeleteClassesUpgradeCodesKey(LPCWSTR szUpgradeCode)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR squashed_uc[SQUASHED_GUID_SIZE];
|
2012-01-21 17:19:12 +00:00
|
|
|
HKEY hkey;
|
|
|
|
LONG r;
|
2011-03-20 08:47:41 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
|
|
|
|
TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
|
2011-03-20 08:47:41 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szInstaller_ClassesUpgradeCodes, 0, access, &hkey)) return ERROR_SUCCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
r = RegDeleteTreeW( hkey, squashed_uc );
|
2012-01-21 17:19:12 +00:00
|
|
|
RegCloseKey(hkey);
|
|
|
|
return r;
|
2011-03-20 08:47:41 +00:00
|
|
|
}
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
/*************************************************************************
|
|
|
|
* MsiDecomposeDescriptorW [MSI.@]
|
|
|
|
*
|
|
|
|
* Decomposes an MSI descriptor into product, feature and component parts.
|
|
|
|
* An MSI descriptor is a string of the form:
|
2016-11-22 12:25:27 +00:00
|
|
|
* [base 85 guid] [feature code] '>' [base 85 guid] or
|
|
|
|
* [base 85 guid] [feature code] '<'
|
2006-02-17 00:04:10 +00:00
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* szDescriptor [I] the descriptor to decompose
|
|
|
|
* szProduct [O] buffer of MAX_FEATURE_CHARS+1 for the product guid
|
|
|
|
* szFeature [O] buffer of MAX_FEATURE_CHARS+1 for the feature code
|
|
|
|
* szComponent [O] buffer of MAX_FEATURE_CHARS+1 for the component guid
|
|
|
|
* pUsed [O] the length of the descriptor
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* ERROR_SUCCESS if everything worked correctly
|
|
|
|
* ERROR_INVALID_PARAMETER if the descriptor was invalid
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct,
|
2008-01-16 10:11:22 +00:00
|
|
|
LPWSTR szFeature, LPWSTR szComponent, LPDWORD pUsed )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2016-11-22 12:25:27 +00:00
|
|
|
UINT len;
|
|
|
|
const WCHAR *p;
|
2006-02-17 00:04:10 +00:00
|
|
|
GUID product, component;
|
|
|
|
|
|
|
|
TRACE("%s %p %p %p %p\n", debugstr_w(szDescriptor), szProduct,
|
|
|
|
szFeature, szComponent, pUsed);
|
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!decode_base85_guid( szDescriptor, &product ))
|
2006-02-17 00:04:10 +00:00
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
TRACE("product %s\n", debugstr_guid( &product ));
|
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!(p = strchrW( &szDescriptor[20], '>' )))
|
|
|
|
p = strchrW( &szDescriptor[20], '<' );
|
|
|
|
if (!p)
|
2006-02-17 00:04:10 +00:00
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
len = (p - &szDescriptor[20]);
|
|
|
|
if( len > MAX_FEATURE_CHARS )
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2006-11-28 11:21:39 +00:00
|
|
|
TRACE("feature %s\n", debugstr_wn( &szDescriptor[20], len ));
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (*p == '>')
|
|
|
|
{
|
|
|
|
if (!decode_base85_guid( p+1, &component ))
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
TRACE( "component %s\n", debugstr_guid(&component) );
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
if (szProduct)
|
|
|
|
StringFromGUID2( &product, szProduct, MAX_FEATURE_CHARS+1 );
|
|
|
|
if (szComponent)
|
2016-11-22 12:25:27 +00:00
|
|
|
{
|
|
|
|
if (*p == '>')
|
|
|
|
StringFromGUID2( &component, szComponent, MAX_FEATURE_CHARS+1 );
|
|
|
|
else
|
|
|
|
szComponent[0] = 0;
|
|
|
|
}
|
2006-11-28 11:21:39 +00:00
|
|
|
if (szFeature)
|
|
|
|
{
|
|
|
|
memcpy( szFeature, &szDescriptor[20], len*sizeof(WCHAR) );
|
|
|
|
szFeature[len] = 0;
|
|
|
|
}
|
2016-11-22 12:25:27 +00:00
|
|
|
|
|
|
|
len = p - szDescriptor + 1;
|
|
|
|
if (*p == '>') len += 20;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
TRACE("length = %d\n", len);
|
2010-05-29 08:55:43 +00:00
|
|
|
if (pUsed) *pUsed = len;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT WINAPI MsiDecomposeDescriptorA( LPCSTR szDescriptor, LPSTR szProduct,
|
2008-01-16 10:11:22 +00:00
|
|
|
LPSTR szFeature, LPSTR szComponent, LPDWORD pUsed )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
WCHAR product[MAX_FEATURE_CHARS+1];
|
|
|
|
WCHAR feature[MAX_FEATURE_CHARS+1];
|
|
|
|
WCHAR component[MAX_FEATURE_CHARS+1];
|
|
|
|
LPWSTR str = NULL, p = NULL, f = NULL, c = NULL;
|
|
|
|
UINT r;
|
|
|
|
|
|
|
|
TRACE("%s %p %p %p %p\n", debugstr_a(szDescriptor), szProduct,
|
|
|
|
szFeature, szComponent, pUsed);
|
|
|
|
|
|
|
|
str = strdupAtoW( szDescriptor );
|
|
|
|
if( szDescriptor && !str )
|
|
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
|
|
|
|
if (szProduct)
|
|
|
|
p = product;
|
|
|
|
if (szFeature)
|
|
|
|
f = feature;
|
|
|
|
if (szComponent)
|
|
|
|
c = component;
|
|
|
|
|
|
|
|
r = MsiDecomposeDescriptorW( str, p, f, c, pUsed );
|
|
|
|
|
2006-11-28 11:21:39 +00:00
|
|
|
if (r == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
WideCharToMultiByte( CP_ACP, 0, p, -1,
|
|
|
|
szProduct, MAX_FEATURE_CHARS+1, NULL, NULL );
|
|
|
|
WideCharToMultiByte( CP_ACP, 0, f, -1,
|
|
|
|
szFeature, MAX_FEATURE_CHARS+1, NULL, NULL );
|
|
|
|
WideCharToMultiByte( CP_ACP, 0, c, -1,
|
|
|
|
szComponent, MAX_FEATURE_CHARS+1, NULL, NULL );
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
msi_free( str );
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid)
|
|
|
|
{
|
|
|
|
DWORD r;
|
|
|
|
WCHAR szwGuid[GUID_SIZE];
|
|
|
|
|
2006-10-22 20:23:59 +00:00
|
|
|
TRACE("%d %p\n", index, lpguid);
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
if (NULL == lpguid)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
r = MsiEnumProductsW(index, szwGuid);
|
|
|
|
if( r == ERROR_SUCCESS )
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid)
|
|
|
|
{
|
2006-10-22 20:23:59 +00:00
|
|
|
TRACE("%d %p\n", index, lpguid);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
if (NULL == lpguid)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2012-05-14 21:41:31 +00:00
|
|
|
return MsiEnumProductsExW( NULL, szAllSid, MSIINSTALLCONTEXT_ALL, index, lpguid,
|
|
|
|
NULL, NULL, NULL );
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
UINT WINAPI MsiEnumFeaturesA(LPCSTR szProduct, DWORD index,
|
2006-02-17 00:04:10 +00:00
|
|
|
LPSTR szFeature, LPSTR szParent)
|
|
|
|
{
|
|
|
|
DWORD r;
|
|
|
|
WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE];
|
|
|
|
LPWSTR szwProduct = NULL;
|
|
|
|
|
2006-10-22 20:23:59 +00:00
|
|
|
TRACE("%s %d %p %p\n", debugstr_a(szProduct), index, szFeature, szParent);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
if( szProduct )
|
|
|
|
{
|
|
|
|
szwProduct = strdupAtoW( szProduct );
|
|
|
|
if( !szwProduct )
|
|
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = MsiEnumFeaturesW(szwProduct, index, szwFeature, szwParent);
|
|
|
|
if( r == ERROR_SUCCESS )
|
|
|
|
{
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, szwFeature, -1,
|
|
|
|
szFeature, GUID_SIZE, NULL, NULL);
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, szwParent, -1,
|
|
|
|
szParent, GUID_SIZE, NULL, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
msi_free( szwProduct);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index,
|
2006-02-17 00:04:10 +00:00
|
|
|
LPWSTR szFeature, LPWSTR szParent)
|
|
|
|
{
|
|
|
|
HKEY hkeyProduct = 0;
|
|
|
|
DWORD r, sz;
|
|
|
|
|
2006-10-22 20:23:59 +00:00
|
|
|
TRACE("%s %d %p %p\n", debugstr_w(szProduct), index, szFeature, szParent);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2006-08-01 23:12:11 +00:00
|
|
|
if( !szProduct )
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
r = MSIREG_OpenInstallerFeaturesKey(szProduct,&hkeyProduct,FALSE);
|
2006-02-17 00:04:10 +00:00
|
|
|
if( r != ERROR_SUCCESS )
|
|
|
|
return ERROR_NO_MORE_ITEMS;
|
|
|
|
|
|
|
|
sz = GUID_SIZE;
|
|
|
|
r = RegEnumValueW(hkeyProduct, index, szFeature, &sz, NULL, NULL, NULL, NULL);
|
|
|
|
RegCloseKey(hkeyProduct);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT WINAPI MsiEnumComponentsA(DWORD index, LPSTR lpguid)
|
|
|
|
{
|
|
|
|
DWORD r;
|
|
|
|
WCHAR szwGuid[GUID_SIZE];
|
|
|
|
|
2012-05-14 21:41:31 +00:00
|
|
|
TRACE("%u, %p\n", index, lpguid);
|
|
|
|
|
|
|
|
if (!lpguid) return ERROR_INVALID_PARAMETER;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
r = MsiEnumComponentsW(index, szwGuid);
|
|
|
|
if( r == ERROR_SUCCESS )
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT WINAPI MsiEnumComponentsW(DWORD index, LPWSTR lpguid)
|
|
|
|
{
|
2012-05-14 21:41:31 +00:00
|
|
|
TRACE("%u, %p\n", index, lpguid);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-05-14 21:41:31 +00:00
|
|
|
if (!lpguid) return ERROR_INVALID_PARAMETER;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-05-14 21:41:31 +00:00
|
|
|
return MsiEnumComponentsExW( szAllSid, MSIINSTALLCONTEXT_ALL, index, lpguid, NULL, NULL, NULL );
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT WINAPI MsiEnumComponentsExA( LPCSTR user_sid, DWORD ctx, DWORD index, CHAR guid[39],
|
|
|
|
MSIINSTALLCONTEXT *installed_ctx, LPSTR sid, LPDWORD sid_len )
|
|
|
|
{
|
|
|
|
UINT r;
|
|
|
|
WCHAR *user_sidW = NULL, *sidW = NULL, guidW[GUID_SIZE];
|
|
|
|
|
|
|
|
TRACE("%s, %u, %u, %p, %p, %p, %p\n", debugstr_a(user_sid), ctx, index, guid, installed_ctx,
|
|
|
|
sid, sid_len);
|
|
|
|
|
|
|
|
if (sid && !sid_len) return ERROR_INVALID_PARAMETER;
|
|
|
|
if (user_sid && !(user_sidW = strdupAtoW( user_sid ))) return ERROR_OUTOFMEMORY;
|
|
|
|
if (sid && !(sidW = msi_alloc( *sid_len * sizeof(WCHAR) )))
|
|
|
|
{
|
|
|
|
msi_free( user_sidW );
|
|
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
r = MsiEnumComponentsExW( user_sidW, ctx, index, guidW, installed_ctx, sidW, sid_len );
|
|
|
|
if (r == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
if (guid) WideCharToMultiByte( CP_ACP, 0, guidW, GUID_SIZE, guid, GUID_SIZE, NULL, NULL );
|
|
|
|
if (sid) WideCharToMultiByte( CP_ACP, 0, sidW, *sid_len + 1, sid, *sid_len + 1, NULL, NULL );
|
|
|
|
}
|
|
|
|
msi_free( user_sidW );
|
|
|
|
msi_free( sidW );
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT fetch_machine_component( DWORD ctx, DWORD index, DWORD *idx, WCHAR guid[39],
|
|
|
|
MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len )
|
|
|
|
{
|
|
|
|
static const WCHAR componentsW[] =
|
|
|
|
{'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',0};
|
|
|
|
UINT r = ERROR_SUCCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR component[SQUASHED_GUID_SIZE];
|
2012-05-14 21:41:31 +00:00
|
|
|
DWORD i = 0, len_component;
|
|
|
|
REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
|
|
|
|
HKEY key_components;
|
|
|
|
|
|
|
|
if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, componentsW, 0, access, &key_components ))
|
2006-02-17 00:04:10 +00:00
|
|
|
return ERROR_NO_MORE_ITEMS;
|
|
|
|
|
2012-05-14 21:41:31 +00:00
|
|
|
len_component = sizeof(component)/sizeof(component[0]);
|
|
|
|
while (!RegEnumKeyExW( key_components, i, component, &len_component, NULL, NULL, NULL, NULL ))
|
|
|
|
{
|
|
|
|
if (*idx == index) goto found;
|
|
|
|
(*idx)++;
|
|
|
|
len_component = sizeof(component)/sizeof(component[0]);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
RegCloseKey( key_components );
|
|
|
|
return ERROR_NO_MORE_ITEMS;
|
|
|
|
|
|
|
|
found:
|
|
|
|
if (sid_len)
|
|
|
|
{
|
|
|
|
if (*sid_len < 1)
|
|
|
|
{
|
|
|
|
*sid_len = 1;
|
|
|
|
r = ERROR_MORE_DATA;
|
|
|
|
}
|
|
|
|
else if (sid)
|
|
|
|
{
|
|
|
|
*sid_len = 0;
|
|
|
|
sid[0] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (guid) unsquash_guid( component, guid );
|
|
|
|
if (installed_ctx) *installed_ctx = MSIINSTALLCONTEXT_MACHINE;
|
|
|
|
RegCloseKey( key_components );
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT fetch_user_component( const WCHAR *usersid, DWORD ctx, DWORD index, DWORD *idx,
|
|
|
|
WCHAR guid[39], MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid,
|
|
|
|
LPDWORD sid_len )
|
|
|
|
{
|
|
|
|
static const WCHAR userdataW[] =
|
|
|
|
{'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',0};
|
|
|
|
static const WCHAR componentsW[] = {'\\','C','o','m','p','o','n','e','n','t','s',0};
|
|
|
|
UINT r = ERROR_SUCCESS;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR path[MAX_PATH], component[SQUASHED_GUID_SIZE], user[128];
|
2012-05-14 21:41:31 +00:00
|
|
|
DWORD i = 0, j = 0, len_component, len_user;
|
|
|
|
REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
|
|
|
|
HKEY key_users, key_components;
|
|
|
|
|
2016-03-03 14:28:37 +00:00
|
|
|
if (ctx == MSIINSTALLCONTEXT_USERMANAGED) /* FIXME: where to find these? */
|
2012-05-14 21:41:31 +00:00
|
|
|
return ERROR_NO_MORE_ITEMS;
|
|
|
|
|
|
|
|
if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, userdataW, 0, access, &key_users ))
|
|
|
|
return ERROR_NO_MORE_ITEMS;
|
|
|
|
|
|
|
|
len_user = sizeof(user)/sizeof(user[0]);
|
|
|
|
while (!RegEnumKeyExW( key_users, i, user, &len_user, NULL, NULL, NULL, NULL ))
|
|
|
|
{
|
|
|
|
if ((strcmpW( usersid, szAllSid ) && strcmpW( usersid, user )) ||
|
|
|
|
!strcmpW( szLocalSid, user ))
|
|
|
|
{
|
|
|
|
i++;
|
|
|
|
len_user = sizeof(user)/sizeof(user[0]);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
strcpyW( path, user );
|
|
|
|
strcatW( path, componentsW );
|
|
|
|
if (RegOpenKeyExW( key_users, path, 0, access, &key_components ))
|
|
|
|
{
|
|
|
|
i++;
|
|
|
|
len_user = sizeof(user)/sizeof(user[0]);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
len_component = sizeof(component)/sizeof(component[0]);
|
|
|
|
while (!RegEnumKeyExW( key_components, j, component, &len_component, NULL, NULL, NULL, NULL ))
|
|
|
|
{
|
|
|
|
if (*idx == index) goto found;
|
|
|
|
(*idx)++;
|
|
|
|
len_component = sizeof(component)/sizeof(component[0]);
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
RegCloseKey( key_components );
|
|
|
|
len_user = sizeof(user)/sizeof(user[0]);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
RegCloseKey( key_users );
|
|
|
|
return ERROR_NO_MORE_ITEMS;
|
|
|
|
|
|
|
|
found:
|
|
|
|
if (sid_len)
|
|
|
|
{
|
|
|
|
if (*sid_len < len_user + 1)
|
|
|
|
{
|
|
|
|
*sid_len = len_user + 1;
|
|
|
|
r = ERROR_MORE_DATA;
|
|
|
|
}
|
|
|
|
else if (sid)
|
|
|
|
{
|
|
|
|
*sid_len = len_user;
|
|
|
|
strcpyW( sid, user );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (guid) unsquash_guid( component, guid );
|
|
|
|
if (installed_ctx) *installed_ctx = ctx;
|
|
|
|
RegCloseKey( key_components );
|
|
|
|
RegCloseKey( key_users );
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT enum_components( const WCHAR *usersid, DWORD ctx, DWORD index, DWORD *idx, WCHAR guid[39],
|
|
|
|
MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD 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_USERMANAGED)
|
|
|
|
{
|
|
|
|
r = fetch_user_component( usersid, MSIINSTALLCONTEXT_USERMANAGED, index, idx, guid,
|
|
|
|
installed_ctx, sid, sid_len );
|
|
|
|
if (r != ERROR_NO_MORE_ITEMS) goto done;
|
|
|
|
}
|
|
|
|
if (ctx & MSIINSTALLCONTEXT_USERUNMANAGED)
|
|
|
|
{
|
|
|
|
r = fetch_user_component( usersid, MSIINSTALLCONTEXT_USERUNMANAGED, index, idx, guid,
|
|
|
|
installed_ctx, sid, sid_len );
|
|
|
|
if (r != ERROR_NO_MORE_ITEMS) goto done;
|
|
|
|
}
|
|
|
|
if (ctx & MSIINSTALLCONTEXT_MACHINE)
|
|
|
|
{
|
|
|
|
r = fetch_machine_component( MSIINSTALLCONTEXT_MACHINE, index, idx, guid, installed_ctx,
|
|
|
|
sid, sid_len );
|
|
|
|
if (r != ERROR_NO_MORE_ITEMS) goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
LocalFree( user );
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT WINAPI MsiEnumComponentsExW( LPCWSTR user_sid, DWORD ctx, DWORD index, WCHAR guid[39],
|
|
|
|
MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len )
|
|
|
|
{
|
|
|
|
UINT r;
|
|
|
|
DWORD idx = 0;
|
|
|
|
static DWORD last_index;
|
|
|
|
|
|
|
|
TRACE("%s, %u, %u, %p, %p, %p, %p\n", debugstr_w(user_sid), ctx, index, guid, installed_ctx,
|
|
|
|
sid, sid_len);
|
|
|
|
|
|
|
|
if ((sid && !sid_len) || !ctx || (user_sid && ctx == MSIINSTALLCONTEXT_MACHINE))
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
if (index && index - last_index != 1)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
if (!index) last_index = 0;
|
|
|
|
|
|
|
|
r = enum_components( user_sid, ctx, index, &idx, guid, installed_ctx, sid, sid_len );
|
|
|
|
if (r == ERROR_SUCCESS)
|
|
|
|
last_index = index;
|
|
|
|
else
|
|
|
|
last_index = 0;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT WINAPI MsiEnumClientsA(LPCSTR szComponent, DWORD index, LPSTR szProduct)
|
|
|
|
{
|
|
|
|
DWORD r;
|
|
|
|
WCHAR szwProduct[GUID_SIZE];
|
|
|
|
LPWSTR szwComponent = NULL;
|
|
|
|
|
2006-10-22 20:23:59 +00:00
|
|
|
TRACE("%s %d %p\n", debugstr_a(szComponent), index, szProduct);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
if ( !szProduct )
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
if( szComponent )
|
|
|
|
{
|
|
|
|
szwComponent = strdupAtoW( szComponent );
|
|
|
|
if( !szwComponent )
|
|
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = MsiEnumClientsW(szComponent?szwComponent:NULL, index, szwProduct);
|
|
|
|
if( r == ERROR_SUCCESS )
|
|
|
|
{
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, szwProduct, -1,
|
|
|
|
szProduct, GUID_SIZE, NULL, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
msi_free( szwComponent);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct)
|
|
|
|
{
|
|
|
|
HKEY hkeyComp = 0;
|
|
|
|
DWORD r, sz;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR szValName[SQUASHED_GUID_SIZE];
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2006-10-22 20:23:59 +00:00
|
|
|
TRACE("%s %d %p\n", debugstr_w(szComponent), index, szProduct);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
if (!szComponent || !*szComponent || !szProduct)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
if (MSIREG_OpenUserDataComponentKey(szComponent, NULL, &hkeyComp, FALSE) != ERROR_SUCCESS &&
|
|
|
|
MSIREG_OpenUserDataComponentKey(szComponent, szLocalSid, &hkeyComp, FALSE) != ERROR_SUCCESS)
|
2008-01-16 10:11:22 +00:00
|
|
|
return ERROR_UNKNOWN_COMPONENT;
|
|
|
|
|
|
|
|
/* see if there are any products at all */
|
2016-11-22 12:25:27 +00:00
|
|
|
sz = SQUASHED_GUID_SIZE;
|
2008-01-16 10:11:22 +00:00
|
|
|
r = RegEnumValueW(hkeyComp, 0, szValName, &sz, NULL, NULL, NULL, NULL);
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
RegCloseKey(hkeyComp);
|
|
|
|
|
|
|
|
if (index != 0)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
return ERROR_UNKNOWN_COMPONENT;
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
sz = SQUASHED_GUID_SIZE;
|
2006-02-17 00:04:10 +00:00
|
|
|
r = RegEnumValueW(hkeyComp, index, szValName, &sz, NULL, NULL, NULL, NULL);
|
|
|
|
if( r == ERROR_SUCCESS )
|
2011-03-20 08:47:41 +00:00
|
|
|
{
|
2006-02-17 00:04:10 +00:00
|
|
|
unsquash_guid(szValName, szProduct);
|
2011-03-20 08:47:41 +00:00
|
|
|
TRACE("-> %s\n", debugstr_w(szProduct));
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
RegCloseKey(hkeyComp);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2015-03-09 20:28:19 +00:00
|
|
|
UINT WINAPI MsiEnumClientsExA(LPCSTR component, LPCSTR usersid, DWORD ctx, DWORD index,
|
|
|
|
CHAR installed_product[GUID_SIZE],
|
|
|
|
MSIINSTALLCONTEXT *installed_ctx, LPSTR sid, LPDWORD sid_len)
|
|
|
|
{
|
|
|
|
FIXME("%s, %s, %u, %u, %p, %p, %p, %p\n", debugstr_a(component), debugstr_a(usersid),
|
|
|
|
ctx, index, installed_product, installed_ctx, sid, sid_len);
|
|
|
|
return ERROR_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT WINAPI MsiEnumClientsExW(LPCWSTR component, LPCWSTR usersid, DWORD ctx, DWORD index,
|
|
|
|
WCHAR installed_product[GUID_SIZE],
|
|
|
|
MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len)
|
|
|
|
{
|
|
|
|
FIXME("%s, %s, %u, %u, %p, %p, %p, %p\n", debugstr_w(component), debugstr_w(usersid),
|
|
|
|
ctx, index, installed_product, installed_ctx, sid, sid_len);
|
|
|
|
return ERROR_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
static UINT MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex,
|
2008-01-16 10:11:22 +00:00
|
|
|
awstring *lpQualBuf, LPDWORD pcchQual,
|
|
|
|
awstring *lpAppBuf, LPDWORD pcchAppBuf )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
DWORD name_sz, val_sz, name_max, val_max, type, ofs;
|
|
|
|
LPWSTR name = NULL, val = NULL;
|
|
|
|
UINT r, r2;
|
|
|
|
HKEY key;
|
|
|
|
|
2006-10-22 20:23:59 +00:00
|
|
|
TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex,
|
2006-02-17 00:04:10 +00:00
|
|
|
lpQualBuf, pcchQual, lpAppBuf, pcchAppBuf);
|
|
|
|
|
|
|
|
if (!szComponent)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
r = MSIREG_OpenUserComponentsKey( szComponent, &key, FALSE );
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return ERROR_UNKNOWN_COMPONENT;
|
|
|
|
|
|
|
|
/* figure out how big the name is we want to return */
|
|
|
|
name_max = 0x10;
|
|
|
|
r = ERROR_OUTOFMEMORY;
|
|
|
|
name = msi_alloc( name_max * sizeof(WCHAR) );
|
|
|
|
if (!name)
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
val_max = 0x10;
|
|
|
|
r = ERROR_OUTOFMEMORY;
|
|
|
|
val = msi_alloc( val_max );
|
|
|
|
if (!val)
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
/* loop until we allocate enough memory */
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
name_sz = name_max;
|
|
|
|
val_sz = val_max;
|
|
|
|
r = RegEnumValueW( key, iIndex, name, &name_sz,
|
|
|
|
NULL, &type, (LPBYTE)val, &val_sz );
|
|
|
|
if (r == ERROR_SUCCESS)
|
|
|
|
break;
|
|
|
|
if (r != ERROR_MORE_DATA)
|
|
|
|
goto end;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
if (type != REG_MULTI_SZ)
|
|
|
|
{
|
2006-10-22 20:23:59 +00:00
|
|
|
ERR("component data has wrong type (%d)\n", type);
|
2006-02-17 00:04:10 +00:00
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = ERROR_OUTOFMEMORY;
|
2012-12-09 19:43:59 +00:00
|
|
|
if (name_sz + 1 >= name_max)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
name_max *= 2;
|
|
|
|
msi_free( name );
|
|
|
|
name = msi_alloc( name_max * sizeof (WCHAR) );
|
|
|
|
if (!name)
|
|
|
|
goto end;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (val_sz > val_max)
|
|
|
|
{
|
|
|
|
val_max = val_sz + sizeof (WCHAR);
|
2006-08-30 19:24:26 +00:00
|
|
|
msi_free( val );
|
2006-02-17 00:04:10 +00:00
|
|
|
val = msi_alloc( val_max * sizeof (WCHAR) );
|
|
|
|
if (!val)
|
|
|
|
goto end;
|
|
|
|
continue;
|
|
|
|
}
|
2006-10-22 20:23:59 +00:00
|
|
|
ERR("should be enough data, but isn't %d %d\n", name_sz, val_sz );
|
2006-02-17 00:04:10 +00:00
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
ofs = 0;
|
|
|
|
r = MsiDecomposeDescriptorW( val, NULL, NULL, NULL, &ofs );
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
TRACE("Providing %s and %s\n", debugstr_w(name), debugstr_w(val+ofs));
|
|
|
|
|
2012-12-09 19:43:59 +00:00
|
|
|
r = msi_strcpy_to_awstring( name, -1, lpQualBuf, pcchQual );
|
|
|
|
r2 = msi_strcpy_to_awstring( val+ofs, -1, lpAppBuf, pcchAppBuf );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
if (r2 != ERROR_SUCCESS)
|
|
|
|
r = r2;
|
|
|
|
|
|
|
|
end:
|
|
|
|
msi_free(val);
|
|
|
|
msi_free(name);
|
|
|
|
RegCloseKey(key);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* MsiEnumComponentQualifiersA [MSI.@]
|
|
|
|
*/
|
|
|
|
UINT WINAPI MsiEnumComponentQualifiersA( LPCSTR szComponent, DWORD iIndex,
|
2008-01-16 10:11:22 +00:00
|
|
|
LPSTR lpQualifierBuf, LPDWORD pcchQualifierBuf,
|
|
|
|
LPSTR lpApplicationDataBuf, LPDWORD pcchApplicationDataBuf )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
awstring qual, appdata;
|
|
|
|
LPWSTR comp;
|
|
|
|
UINT r;
|
|
|
|
|
2006-10-22 20:23:59 +00:00
|
|
|
TRACE("%s %08x %p %p %p %p\n", debugstr_a(szComponent), iIndex,
|
2006-02-17 00:04:10 +00:00
|
|
|
lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
|
|
|
|
pcchApplicationDataBuf);
|
|
|
|
|
|
|
|
comp = strdupAtoW( szComponent );
|
|
|
|
if (szComponent && !comp)
|
|
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
|
|
|
|
qual.unicode = FALSE;
|
|
|
|
qual.str.a = lpQualifierBuf;
|
|
|
|
|
|
|
|
appdata.unicode = FALSE;
|
|
|
|
appdata.str.a = lpApplicationDataBuf;
|
|
|
|
|
|
|
|
r = MSI_EnumComponentQualifiers( comp, iIndex,
|
|
|
|
&qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
|
|
|
|
msi_free( comp );
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* MsiEnumComponentQualifiersW [MSI.@]
|
|
|
|
*/
|
|
|
|
UINT WINAPI MsiEnumComponentQualifiersW( LPCWSTR szComponent, DWORD iIndex,
|
2008-01-16 10:11:22 +00:00
|
|
|
LPWSTR lpQualifierBuf, LPDWORD pcchQualifierBuf,
|
|
|
|
LPWSTR lpApplicationDataBuf, LPDWORD pcchApplicationDataBuf )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
awstring qual, appdata;
|
|
|
|
|
2006-10-22 20:23:59 +00:00
|
|
|
TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex,
|
2006-02-17 00:04:10 +00:00
|
|
|
lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
|
|
|
|
pcchApplicationDataBuf);
|
|
|
|
|
|
|
|
qual.unicode = TRUE;
|
|
|
|
qual.str.w = lpQualifierBuf;
|
|
|
|
|
|
|
|
appdata.unicode = TRUE;
|
|
|
|
appdata.str.w = lpApplicationDataBuf;
|
|
|
|
|
|
|
|
return MSI_EnumComponentQualifiers( szComponent, iIndex,
|
|
|
|
&qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* MsiEnumRelatedProductsW [MSI.@]
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR szUpgradeCode, DWORD dwReserved,
|
|
|
|
DWORD iProductIndex, LPWSTR lpProductBuf)
|
|
|
|
{
|
|
|
|
UINT r;
|
|
|
|
HKEY hkey;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR szKeyName[SQUASHED_GUID_SIZE];
|
|
|
|
DWORD dwSize = sizeof(szKeyName)/sizeof(szKeyName[0]);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2006-10-22 20:23:59 +00:00
|
|
|
TRACE("%s %u %u %p\n", debugstr_w(szUpgradeCode), dwReserved,
|
2006-02-17 00:04:10 +00:00
|
|
|
iProductIndex, lpProductBuf);
|
|
|
|
|
|
|
|
if (NULL == szUpgradeCode)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
if (NULL == lpProductBuf)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
r = MSIREG_OpenUpgradeCodesKey(szUpgradeCode, &hkey, FALSE);
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return ERROR_NO_MORE_ITEMS;
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
r = RegEnumValueW(hkey, iProductIndex, szKeyName, &dwSize, NULL, NULL, NULL, NULL);
|
2006-02-17 00:04:10 +00:00
|
|
|
if( r == ERROR_SUCCESS )
|
|
|
|
unsquash_guid(szKeyName, lpProductBuf);
|
|
|
|
RegCloseKey(hkey);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* MsiEnumRelatedProductsA [MSI.@]
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
UINT WINAPI MsiEnumRelatedProductsA(LPCSTR szUpgradeCode, DWORD dwReserved,
|
|
|
|
DWORD iProductIndex, LPSTR lpProductBuf)
|
|
|
|
{
|
|
|
|
LPWSTR szwUpgradeCode = NULL;
|
|
|
|
WCHAR productW[GUID_SIZE];
|
|
|
|
UINT r;
|
|
|
|
|
2006-10-22 20:23:59 +00:00
|
|
|
TRACE("%s %u %u %p\n", debugstr_a(szUpgradeCode), dwReserved,
|
2006-02-17 00:04:10 +00:00
|
|
|
iProductIndex, lpProductBuf);
|
|
|
|
|
|
|
|
if (szUpgradeCode)
|
|
|
|
{
|
|
|
|
szwUpgradeCode = strdupAtoW( szUpgradeCode );
|
|
|
|
if( !szwUpgradeCode )
|
|
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = MsiEnumRelatedProductsW( szwUpgradeCode, dwReserved,
|
|
|
|
iProductIndex, productW );
|
|
|
|
if (r == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
WideCharToMultiByte( CP_ACP, 0, productW, GUID_SIZE,
|
|
|
|
lpProductBuf, GUID_SIZE, NULL, NULL );
|
|
|
|
}
|
|
|
|
msi_free( szwUpgradeCode);
|
|
|
|
return r;
|
|
|
|
}
|
2006-08-01 23:12:11 +00:00
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
/***********************************************************************
|
|
|
|
* MsiEnumPatchesExA [MSI.@]
|
|
|
|
*/
|
|
|
|
UINT WINAPI MsiEnumPatchesExA(LPCSTR szProductCode, LPCSTR szUserSid,
|
|
|
|
DWORD dwContext, DWORD dwFilter, DWORD dwIndex, LPSTR szPatchCode,
|
|
|
|
LPSTR szTargetProductCode, MSIINSTALLCONTEXT *pdwTargetProductContext,
|
|
|
|
LPSTR szTargetUserSid, LPDWORD pcchTargetUserSid)
|
|
|
|
{
|
|
|
|
LPWSTR prodcode = NULL;
|
|
|
|
LPWSTR usersid = NULL;
|
|
|
|
LPWSTR targsid = NULL;
|
|
|
|
WCHAR patch[GUID_SIZE];
|
|
|
|
WCHAR targprod[GUID_SIZE];
|
|
|
|
DWORD len;
|
|
|
|
UINT r;
|
|
|
|
|
|
|
|
TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p, %p)\n",
|
|
|
|
debugstr_a(szProductCode), debugstr_a(szUserSid), dwContext, dwFilter,
|
|
|
|
dwIndex, szPatchCode, szTargetProductCode, pdwTargetProductContext,
|
|
|
|
szTargetUserSid, pcchTargetUserSid);
|
|
|
|
|
|
|
|
if (szTargetUserSid && !pcchTargetUserSid)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
if (szProductCode) prodcode = strdupAtoW(szProductCode);
|
|
|
|
if (szUserSid) usersid = strdupAtoW(szUserSid);
|
|
|
|
|
|
|
|
r = MsiEnumPatchesExW(prodcode, usersid, dwContext, dwFilter, dwIndex,
|
|
|
|
patch, targprod, pdwTargetProductContext,
|
|
|
|
NULL, &len);
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, patch, -1, szPatchCode,
|
|
|
|
GUID_SIZE, NULL, NULL);
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, targprod, -1, szTargetProductCode,
|
|
|
|
GUID_SIZE, NULL, NULL);
|
|
|
|
|
|
|
|
if (!szTargetUserSid)
|
|
|
|
{
|
|
|
|
if (pcchTargetUserSid)
|
|
|
|
*pcchTargetUserSid = len;
|
|
|
|
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
targsid = msi_alloc(++len * sizeof(WCHAR));
|
|
|
|
if (!targsid)
|
|
|
|
{
|
|
|
|
r = ERROR_OUTOFMEMORY;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = MsiEnumPatchesExW(prodcode, usersid, dwContext, dwFilter, dwIndex,
|
|
|
|
patch, targprod, pdwTargetProductContext,
|
|
|
|
targsid, &len);
|
|
|
|
if (r != ERROR_SUCCESS || !szTargetUserSid)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, targsid, -1, szTargetUserSid,
|
|
|
|
*pcchTargetUserSid, NULL, NULL);
|
|
|
|
|
|
|
|
len = lstrlenW(targsid);
|
|
|
|
if (*pcchTargetUserSid < len + 1)
|
|
|
|
{
|
|
|
|
r = ERROR_MORE_DATA;
|
|
|
|
*pcchTargetUserSid = len * sizeof(WCHAR);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*pcchTargetUserSid = len;
|
|
|
|
|
|
|
|
done:
|
|
|
|
msi_free(prodcode);
|
|
|
|
msi_free(usersid);
|
|
|
|
msi_free(targsid);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT msi_get_patch_state(LPCWSTR prodcode, LPCWSTR usersid,
|
2009-05-20 12:59:23 +00:00
|
|
|
MSIINSTALLCONTEXT context,
|
2008-12-27 15:10:14 +00:00
|
|
|
LPWSTR patch, MSIPATCHSTATE *state)
|
|
|
|
{
|
|
|
|
DWORD type, val, size;
|
|
|
|
HKEY prod, hkey = 0;
|
|
|
|
HKEY udpatch = 0;
|
|
|
|
LONG res;
|
|
|
|
UINT r = ERROR_NO_MORE_ITEMS;
|
|
|
|
|
|
|
|
*state = MSIPATCHSTATE_INVALID;
|
|
|
|
|
2009-05-20 12:59:23 +00:00
|
|
|
r = MSIREG_OpenUserDataProductKey(prodcode, context,
|
|
|
|
usersid, &prod, FALSE);
|
2008-12-27 15:10:14 +00:00
|
|
|
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, LPWSTR *transforms)
|
|
|
|
{
|
2009-06-06 15:59:47 +00:00
|
|
|
MSIPATCHSTATE state = MSIPATCHSTATE_INVALID;
|
2008-12-27 15:10:14 +00:00
|
|
|
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;
|
|
|
|
|
2009-05-20 12:59:23 +00:00
|
|
|
if (MSIREG_OpenProductKey(prodcode, usersid, context,
|
|
|
|
&prod, FALSE) != ERROR_SUCCESS)
|
2008-12-27 15:10:14 +00:00
|
|
|
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;
|
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
for (ptr = patches; *ptr && r == ERROR_NO_MORE_ITEMS; ptr += lstrlenW(ptr) + 1)
|
2008-12-27 15:10:14 +00:00
|
|
|
{
|
|
|
|
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 (transforms)
|
|
|
|
{
|
|
|
|
*transforms = msi_alloc(size);
|
|
|
|
if (!*transforms)
|
|
|
|
{
|
|
|
|
r = ERROR_OUTOFMEMORY;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = RegGetValueW(prod, szPatches, ptr, RRF_RT_REG_SZ,
|
|
|
|
&type, *transforms, &size);
|
|
|
|
if (res != ERROR_SUCCESS)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (context == MSIINSTALLCONTEXT_USERMANAGED)
|
|
|
|
{
|
|
|
|
if (!(filter & MSIPATCHSTATE_APPLIED))
|
|
|
|
{
|
2009-05-20 12:59:23 +00:00
|
|
|
temp = msi_get_patch_state(prodcode, usersid, context,
|
|
|
|
ptr, &state);
|
2008-12-27 15:10:14 +00:00
|
|
|
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))
|
|
|
|
{
|
2009-05-20 12:59:23 +00:00
|
|
|
temp = msi_get_patch_state(prodcode, usersid, context,
|
|
|
|
ptr, &state);
|
2008-12-27 15:10:14 +00:00
|
|
|
if (temp == ERROR_BAD_CONFIGURATION)
|
|
|
|
{
|
|
|
|
r = ERROR_BAD_CONFIGURATION;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (temp != ERROR_SUCCESS || !(filter & state))
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
temp = MSIREG_OpenUserDataPatchKey(patch, context,
|
|
|
|
&patchkey, FALSE);
|
|
|
|
RegCloseKey(patchkey);
|
|
|
|
if (temp != ERROR_SUCCESS)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (context == MSIINSTALLCONTEXT_MACHINE)
|
|
|
|
{
|
|
|
|
usersid = szEmpty;
|
|
|
|
|
|
|
|
if (MSIREG_OpenUserDataProductKey(prodcode, context, NULL, &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;
|
|
|
|
if (targetprod)
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT msi_enum_patches(LPCWSTR szProductCode, LPCWSTR szUserSid,
|
|
|
|
DWORD dwContext, DWORD dwFilter, DWORD dwIndex, DWORD *idx,
|
|
|
|
LPWSTR szPatchCode, LPWSTR szTargetProductCode,
|
|
|
|
MSIINSTALLCONTEXT *pdwTargetProductContext, LPWSTR szTargetUserSid,
|
|
|
|
LPDWORD pcchTargetUserSid, LPWSTR *szTransforms)
|
|
|
|
{
|
2009-05-20 12:59:23 +00:00
|
|
|
LPWSTR usersid = NULL;
|
2009-01-31 14:13:20 +00:00
|
|
|
UINT r = ERROR_INVALID_PARAMETER;
|
2008-12-27 15:10:14 +00:00
|
|
|
|
2009-05-20 12:59:23 +00:00
|
|
|
if (!szUserSid)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
szUserSid = usersid = get_user_sid();
|
|
|
|
if (!usersid) return ERROR_FUNCTION_FAILED;
|
2009-05-20 12:59:23 +00:00
|
|
|
}
|
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
if (dwContext & MSIINSTALLCONTEXT_USERMANAGED)
|
|
|
|
{
|
|
|
|
r = msi_check_product_patches(szProductCode, szUserSid,
|
|
|
|
MSIINSTALLCONTEXT_USERMANAGED, dwFilter,
|
|
|
|
dwIndex, idx, szPatchCode,
|
|
|
|
szTargetProductCode,
|
|
|
|
pdwTargetProductContext, szTargetUserSid,
|
|
|
|
pcchTargetUserSid, szTransforms);
|
|
|
|
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, szTransforms);
|
|
|
|
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, szTransforms);
|
|
|
|
if (r != ERROR_NO_MORE_ITEMS)
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
2009-05-20 12:59:23 +00:00
|
|
|
LocalFree(usersid);
|
2008-12-27 15:10:14 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* MsiEnumPatchesExW [MSI.@]
|
|
|
|
*/
|
|
|
|
UINT WINAPI MsiEnumPatchesExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
|
|
|
|
DWORD dwContext, DWORD dwFilter, DWORD dwIndex, LPWSTR szPatchCode,
|
|
|
|
LPWSTR szTargetProductCode, MSIINSTALLCONTEXT *pdwTargetProductContext,
|
|
|
|
LPWSTR szTargetUserSid, LPDWORD pcchTargetUserSid)
|
|
|
|
{
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR squashed_pc[SQUASHED_GUID_SIZE];
|
2008-12-27 15:10:14 +00:00
|
|
|
DWORD idx = 0;
|
|
|
|
UINT r;
|
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
static DWORD last_index;
|
2008-12-27 15:10:14 +00:00
|
|
|
|
|
|
|
TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p, %p)\n",
|
|
|
|
debugstr_w(szProductCode), debugstr_w(szUserSid), dwContext, dwFilter,
|
|
|
|
dwIndex, szPatchCode, szTargetProductCode, pdwTargetProductContext,
|
|
|
|
szTargetUserSid, pcchTargetUserSid);
|
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!szProductCode || !squash_guid( szProductCode, squashed_pc ))
|
2008-12-27 15:10:14 +00:00
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
if (szUserSid && !strcmpW( szUserSid, szLocalSid ))
|
2008-12-27 15:10:14 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
r = msi_enum_patches(szProductCode, szUserSid, dwContext, dwFilter,
|
|
|
|
dwIndex, &idx, szPatchCode, szTargetProductCode,
|
|
|
|
pdwTargetProductContext, szTargetUserSid,
|
|
|
|
pcchTargetUserSid, NULL);
|
|
|
|
|
|
|
|
if (r == ERROR_SUCCESS)
|
|
|
|
last_index = dwIndex;
|
2010-05-29 08:55:43 +00:00
|
|
|
else
|
|
|
|
last_index = 0;
|
2008-12-27 15:10:14 +00:00
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2006-08-01 23:12:11 +00:00
|
|
|
/***********************************************************************
|
|
|
|
* MsiEnumPatchesA [MSI.@]
|
|
|
|
*/
|
2008-12-27 15:10:14 +00:00
|
|
|
UINT WINAPI MsiEnumPatchesA(LPCSTR szProduct, DWORD iPatchIndex,
|
2008-01-16 10:11:22 +00:00
|
|
|
LPSTR lpPatchBuf, LPSTR lpTransformsBuf, LPDWORD pcchTransformsBuf)
|
2006-08-01 23:12:11 +00:00
|
|
|
{
|
2009-05-20 12:59:23 +00:00
|
|
|
LPWSTR product, transforms;
|
2008-12-27 15:10:14 +00:00
|
|
|
WCHAR patch[GUID_SIZE];
|
|
|
|
DWORD len;
|
|
|
|
UINT r;
|
|
|
|
|
|
|
|
TRACE("(%s %d %p %p %p)\n", debugstr_a(szProduct), iPatchIndex,
|
|
|
|
lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
|
|
|
|
|
|
|
|
if (!szProduct || !lpPatchBuf || !lpTransformsBuf || !pcchTransformsBuf)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
product = strdupAtoW(szProduct);
|
|
|
|
if (!product)
|
|
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
|
2009-05-20 12:59:23 +00:00
|
|
|
len = *pcchTransformsBuf;
|
|
|
|
transforms = msi_alloc( len * sizeof(WCHAR) );
|
2008-12-27 15:10:14 +00:00
|
|
|
if (!transforms)
|
|
|
|
{
|
|
|
|
r = ERROR_OUTOFMEMORY;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = MsiEnumPatchesW(product, iPatchIndex, patch, transforms, &len);
|
2009-05-20 12:59:23 +00:00
|
|
|
if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
|
2008-12-27 15:10:14 +00:00
|
|
|
goto done;
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, patch, -1, lpPatchBuf,
|
|
|
|
GUID_SIZE, NULL, NULL);
|
|
|
|
|
2009-05-20 12:59:23 +00:00
|
|
|
if (!WideCharToMultiByte(CP_ACP, 0, transforms, -1, lpTransformsBuf,
|
|
|
|
*pcchTransformsBuf, NULL, NULL))
|
|
|
|
r = ERROR_MORE_DATA;
|
2008-12-27 15:10:14 +00:00
|
|
|
|
2009-05-20 12:59:23 +00:00
|
|
|
if (r == ERROR_MORE_DATA)
|
2008-12-27 15:10:14 +00:00
|
|
|
{
|
|
|
|
lpTransformsBuf[*pcchTransformsBuf - 1] = '\0';
|
2009-05-20 12:59:23 +00:00
|
|
|
*pcchTransformsBuf = len * 2;
|
2008-12-27 15:10:14 +00:00
|
|
|
}
|
|
|
|
else
|
2009-05-20 12:59:23 +00:00
|
|
|
*pcchTransformsBuf = strlen( lpTransformsBuf );
|
2008-12-27 15:10:14 +00:00
|
|
|
|
|
|
|
done:
|
|
|
|
msi_free(transforms);
|
|
|
|
msi_free(product);
|
|
|
|
|
|
|
|
return r;
|
2006-08-01 23:12:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* MsiEnumPatchesW [MSI.@]
|
|
|
|
*/
|
2008-12-27 15:10:14 +00:00
|
|
|
UINT WINAPI MsiEnumPatchesW(LPCWSTR szProduct, DWORD iPatchIndex,
|
2008-01-16 10:11:22 +00:00
|
|
|
LPWSTR lpPatchBuf, LPWSTR lpTransformsBuf, LPDWORD pcchTransformsBuf)
|
2006-08-01 23:12:11 +00:00
|
|
|
{
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR *transforms = NULL, squashed_pc[SQUASHED_GUID_SIZE];
|
2008-12-27 15:10:14 +00:00
|
|
|
HKEY prod;
|
|
|
|
DWORD idx = 0;
|
|
|
|
UINT r;
|
|
|
|
|
|
|
|
TRACE("(%s %d %p %p %p)\n", debugstr_w(szProduct), iPatchIndex,
|
|
|
|
lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
|
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!szProduct || !squash_guid( szProduct, squashed_pc ))
|
2008-12-27 15:10:14 +00:00
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
if (!lpPatchBuf || !lpTransformsBuf || !pcchTransformsBuf)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2009-05-20 12:59:23 +00:00
|
|
|
if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
|
2008-12-27 15:10:14 +00:00
|
|
|
&prod, FALSE) != ERROR_SUCCESS &&
|
2009-05-20 12:59:23 +00:00
|
|
|
MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
|
2008-12-27 15:10:14 +00:00
|
|
|
&prod, FALSE) != ERROR_SUCCESS &&
|
2009-05-20 12:59:23 +00:00
|
|
|
MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
|
2008-12-27 15:10:14 +00:00
|
|
|
&prod, FALSE) != ERROR_SUCCESS)
|
|
|
|
return ERROR_UNKNOWN_PRODUCT;
|
|
|
|
|
|
|
|
RegCloseKey(prod);
|
|
|
|
|
|
|
|
r = msi_enum_patches(szProduct, NULL, MSIINSTALLCONTEXT_ALL,
|
|
|
|
MSIPATCHSTATE_ALL, iPatchIndex, &idx, lpPatchBuf,
|
|
|
|
NULL, NULL, NULL, NULL, &transforms);
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
lstrcpynW(lpTransformsBuf, transforms, *pcchTransformsBuf);
|
|
|
|
if (*pcchTransformsBuf <= lstrlenW(transforms))
|
|
|
|
{
|
|
|
|
r = ERROR_MORE_DATA;
|
2009-05-20 12:59:23 +00:00
|
|
|
*pcchTransformsBuf = lstrlenW(transforms);
|
2008-12-27 15:10:14 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
*pcchTransformsBuf = lstrlenW(transforms);
|
|
|
|
|
|
|
|
done:
|
|
|
|
msi_free(transforms);
|
|
|
|
return r;
|
2006-08-01 23:12:11 +00:00
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2012-05-14 21:41:31 +00:00
|
|
|
UINT WINAPI MsiEnumProductsExA( LPCSTR product, LPCSTR usersid, DWORD ctx, DWORD index,
|
|
|
|
CHAR installed_product[GUID_SIZE],
|
|
|
|
MSIINSTALLCONTEXT *installed_ctx, LPSTR sid, LPDWORD sid_len )
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2012-05-14 21:41:31 +00:00
|
|
|
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;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR product[SQUASHED_GUID_SIZE];
|
2012-05-14 21:41:31 +00:00
|
|
|
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 );
|
2008-01-16 10:11:22 +00:00
|
|
|
return ERROR_NO_MORE_ITEMS;
|
2012-05-14 21:41:31 +00:00
|
|
|
|
|
|
|
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;
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
|
2012-05-14 21:41:31 +00:00
|
|
|
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 )
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2012-05-14 21:41:31 +00:00
|
|
|
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;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR path[MAX_PATH], product[SQUASHED_GUID_SIZE], user[128];
|
2012-05-14 21:41:31 +00:00
|
|
|
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 (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 );
|
2008-01-16 10:11:22 +00:00
|
|
|
return ERROR_NO_MORE_ITEMS;
|
2012-05-14 21:41:31 +00:00
|
|
|
|
|
|
|
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;
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|