2006-02-17 00:04:10 +00:00
|
|
|
/*
|
|
|
|
* Implementation of the AppSearch action of the Microsoft Installer (msi.dll)
|
|
|
|
*
|
|
|
|
* Copyright 2005 Juan Lang
|
|
|
|
*
|
|
|
|
* 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>
|
2013-01-24 23:00:42 +00:00
|
|
|
|
2018-03-04 23:30:58 +00:00
|
|
|
#define COBJMACROS
|
|
|
|
|
|
|
|
#include "windef.h"
|
|
|
|
#include "winbase.h"
|
|
|
|
#include "winreg.h"
|
|
|
|
#include "msi.h"
|
|
|
|
#include "msiquery.h"
|
|
|
|
#include "msidefs.h"
|
|
|
|
#include "winver.h"
|
|
|
|
#include "shlwapi.h"
|
|
|
|
#include "wine/debug.h"
|
2006-02-17 00:04:10 +00:00
|
|
|
#include "msipriv.h"
|
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
|
|
|
|
|
|
|
typedef struct tagMSISIGNATURE
|
|
|
|
{
|
2006-08-01 23:12:11 +00:00
|
|
|
LPCWSTR Name; /* NOT owned by this structure */
|
2006-02-17 00:04:10 +00:00
|
|
|
LPWSTR File;
|
|
|
|
DWORD MinVersionMS;
|
|
|
|
DWORD MinVersionLS;
|
|
|
|
DWORD MaxVersionMS;
|
|
|
|
DWORD MaxVersionLS;
|
|
|
|
DWORD MinSize;
|
|
|
|
DWORD MaxSize;
|
|
|
|
FILETIME MinTime;
|
|
|
|
FILETIME MaxTime;
|
|
|
|
LPWSTR Languages;
|
|
|
|
}MSISIGNATURE;
|
|
|
|
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
void msi_parse_version_string(LPCWSTR verStr, PDWORD ms, PDWORD ls)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
const WCHAR *ptr;
|
|
|
|
int x1 = 0, x2 = 0, x3 = 0, x4 = 0;
|
|
|
|
|
2022-03-13 00:35:24 +00:00
|
|
|
x1 = wcstol(verStr, NULL, 10);
|
|
|
|
ptr = wcschr(verStr, '.');
|
2006-02-17 00:04:10 +00:00
|
|
|
if (ptr)
|
|
|
|
{
|
2022-03-13 00:35:24 +00:00
|
|
|
x2 = wcstol(ptr + 1, NULL, 10);
|
|
|
|
ptr = wcschr(ptr + 1, '.');
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
if (ptr)
|
|
|
|
{
|
2022-03-13 00:35:24 +00:00
|
|
|
x3 = wcstol(ptr + 1, NULL, 10);
|
|
|
|
ptr = wcschr(ptr + 1, '.');
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
if (ptr)
|
2022-03-13 00:35:24 +00:00
|
|
|
x4 = wcstol(ptr + 1, NULL, 10);
|
2006-02-17 00:04:10 +00:00
|
|
|
/* FIXME: byte-order dependent? */
|
|
|
|
*ms = x1 << 16 | x2;
|
2011-03-20 08:47:41 +00:00
|
|
|
if (ls) *ls = x3 << 16 | x4;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
/* Fills in sig with the values from the Signature table, where name is the
|
2006-02-17 00:04:10 +00:00
|
|
|
* signature to find. Upon return, sig->File will be NULL if the record is not
|
|
|
|
* found, and not NULL if it is found.
|
|
|
|
* Warning: clears all fields in sig!
|
|
|
|
* Returns ERROR_SUCCESS upon success (where not finding the record counts as
|
|
|
|
* success), something else on error.
|
|
|
|
*/
|
2022-03-13 00:17:50 +00:00
|
|
|
static UINT get_signature( MSIPACKAGE *package, MSISIGNATURE *sig, const WCHAR *name )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2022-03-13 20:31:42 +00:00
|
|
|
WCHAR *minVersion, *maxVersion, *p;
|
2008-01-16 10:11:22 +00:00
|
|
|
MSIRECORD *row;
|
|
|
|
DWORD time;
|
|
|
|
|
|
|
|
TRACE("package %p, sig %p\n", package, sig);
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
memset(sig, 0, sizeof(*sig));
|
2006-08-01 23:12:11 +00:00
|
|
|
sig->Name = name;
|
2022-03-13 20:31:42 +00:00
|
|
|
row = MSI_QueryGetRecord( package->db, L"SELECT * FROM `Signature` WHERE `Signature` = '%s'", name );
|
2008-01-16 10:11:22 +00:00
|
|
|
if (!row)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2008-01-16 10:11:22 +00:00
|
|
|
TRACE("failed to query signature for %s\n", debugstr_w(name));
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
/* get properties */
|
|
|
|
sig->File = msi_dup_record_field(row,2);
|
2022-03-13 00:35:24 +00:00
|
|
|
if ((p = wcschr(sig->File, '|')))
|
2010-10-22 13:18:11 +00:00
|
|
|
{
|
|
|
|
p++;
|
2022-03-13 00:35:24 +00:00
|
|
|
memmove(sig->File, p, (lstrlenW(p) + 1) * sizeof(WCHAR));
|
2010-10-22 13:18:11 +00:00
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
minVersion = msi_dup_record_field(row,3);
|
|
|
|
if (minVersion)
|
|
|
|
{
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
msi_parse_version_string( minVersion, &sig->MinVersionMS, &sig->MinVersionLS );
|
2008-01-16 10:11:22 +00:00
|
|
|
msi_free( minVersion );
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
maxVersion = msi_dup_record_field(row,4);
|
|
|
|
if (maxVersion)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
msi_parse_version_string( maxVersion, &sig->MaxVersionMS, &sig->MaxVersionLS );
|
2008-01-16 10:11:22 +00:00
|
|
|
msi_free( maxVersion );
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
sig->MinSize = MSI_RecordGetInteger(row,5);
|
|
|
|
if (sig->MinSize == MSI_NULL_INTEGER)
|
|
|
|
sig->MinSize = 0;
|
|
|
|
sig->MaxSize = MSI_RecordGetInteger(row,6);
|
|
|
|
if (sig->MaxSize == MSI_NULL_INTEGER)
|
|
|
|
sig->MaxSize = 0;
|
|
|
|
sig->Languages = msi_dup_record_field(row,9);
|
|
|
|
time = MSI_RecordGetInteger(row,7);
|
|
|
|
if (time != MSI_NULL_INTEGER)
|
|
|
|
DosDateTimeToFileTime(HIWORD(time), LOWORD(time), &sig->MinTime);
|
|
|
|
time = MSI_RecordGetInteger(row,8);
|
|
|
|
if (time != MSI_NULL_INTEGER)
|
|
|
|
DosDateTimeToFileTime(HIWORD(time), LOWORD(time), &sig->MaxTime);
|
|
|
|
|
|
|
|
TRACE("Found file name %s for Signature_ %s;\n",
|
|
|
|
debugstr_w(sig->File), debugstr_w(name));
|
|
|
|
TRACE("MinVersion is %d.%d.%d.%d\n", HIWORD(sig->MinVersionMS),
|
|
|
|
LOWORD(sig->MinVersionMS), HIWORD(sig->MinVersionLS),
|
|
|
|
LOWORD(sig->MinVersionLS));
|
|
|
|
TRACE("MaxVersion is %d.%d.%d.%d\n", HIWORD(sig->MaxVersionMS),
|
|
|
|
LOWORD(sig->MaxVersionMS), HIWORD(sig->MaxVersionLS),
|
|
|
|
LOWORD(sig->MaxVersionLS));
|
2022-03-14 20:20:29 +00:00
|
|
|
TRACE("MinSize is %lu, MaxSize is %lu\n", sig->MinSize, sig->MaxSize);
|
2008-01-16 10:11:22 +00:00
|
|
|
TRACE("Languages is %s\n", debugstr_w(sig->Languages));
|
|
|
|
|
|
|
|
msiobj_release( &row->hdr );
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2006-08-01 23:12:11 +00:00
|
|
|
/* Frees any memory allocated in sig */
|
2022-03-13 00:17:50 +00:00
|
|
|
static void free_signature( MSISIGNATURE *sig )
|
2006-08-01 23:12:11 +00:00
|
|
|
{
|
|
|
|
msi_free(sig->File);
|
|
|
|
msi_free(sig->Languages);
|
|
|
|
}
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
static WCHAR *search_file( MSIPACKAGE *package, WCHAR *path, MSISIGNATURE *sig )
|
2008-12-27 15:10:14 +00:00
|
|
|
{
|
|
|
|
VS_FIXEDFILEINFO *info;
|
2022-03-14 20:20:24 +00:00
|
|
|
DWORD attr;
|
|
|
|
UINT size;
|
2008-12-27 15:10:14 +00:00
|
|
|
LPWSTR val = NULL;
|
|
|
|
LPBYTE buffer;
|
|
|
|
|
|
|
|
if (!sig->File)
|
|
|
|
{
|
|
|
|
PathRemoveFileSpecW(path);
|
|
|
|
PathAddBackslashW(path);
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
attr = msi_get_file_attributes( package, path );
|
|
|
|
if (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
|
2008-12-27 15:10:14 +00:00
|
|
|
return strdupW(path);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
attr = msi_get_file_attributes( package, path );
|
|
|
|
if (attr == INVALID_FILE_ATTRIBUTES || (attr & FILE_ATTRIBUTE_DIRECTORY))
|
2008-12-27 15:10:14 +00:00
|
|
|
return NULL;
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
size = msi_get_file_version_info( package, path, 0, NULL );
|
2008-12-27 15:10:14 +00:00
|
|
|
if (!size)
|
|
|
|
return strdupW(path);
|
|
|
|
|
|
|
|
buffer = msi_alloc(size);
|
|
|
|
if (!buffer)
|
|
|
|
return NULL;
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
size = msi_get_file_version_info( package, path, size, buffer );
|
|
|
|
if (!size)
|
2008-12-27 15:10:14 +00:00
|
|
|
goto done;
|
|
|
|
|
2022-03-13 20:31:42 +00:00
|
|
|
if (!VerQueryValueW(buffer, L"\\", (LPVOID)&info, &size) || !info)
|
2008-12-27 15:10:14 +00:00
|
|
|
goto done;
|
|
|
|
|
|
|
|
if (sig->MinVersionLS || sig->MinVersionMS)
|
|
|
|
{
|
|
|
|
if (info->dwFileVersionMS < sig->MinVersionMS)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
if (info->dwFileVersionMS == sig->MinVersionMS &&
|
|
|
|
info->dwFileVersionLS < sig->MinVersionLS)
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sig->MaxVersionLS || sig->MaxVersionMS)
|
|
|
|
{
|
|
|
|
if (info->dwFileVersionMS > sig->MaxVersionMS)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
if (info->dwFileVersionMS == sig->MaxVersionMS &&
|
|
|
|
info->dwFileVersionLS > sig->MaxVersionLS)
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
val = strdupW(path);
|
|
|
|
|
|
|
|
done:
|
|
|
|
msi_free(buffer);
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
static UINT search_components( MSIPACKAGE *package, WCHAR **appValue, MSISIGNATURE *sig )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2008-01-16 10:11:22 +00:00
|
|
|
MSIRECORD *row, *rec;
|
|
|
|
LPCWSTR signature, guid;
|
|
|
|
BOOL sigpresent = TRUE;
|
|
|
|
BOOL isdir;
|
|
|
|
UINT type;
|
|
|
|
WCHAR path[MAX_PATH];
|
|
|
|
DWORD size = MAX_PATH;
|
|
|
|
LPWSTR ptr;
|
|
|
|
DWORD attr;
|
|
|
|
|
|
|
|
TRACE("%s\n", debugstr_w(sig->Name));
|
|
|
|
|
2006-08-01 23:12:11 +00:00
|
|
|
*appValue = NULL;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2022-03-13 20:31:42 +00:00
|
|
|
row = MSI_QueryGetRecord(package->db, L"SELECT * FROM `CompLocator` WHERE `Signature_` = '%s'", sig->Name);
|
2008-01-16 10:11:22 +00:00
|
|
|
if (!row)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2008-01-16 10:11:22 +00:00
|
|
|
TRACE("failed to query CompLocator for %s\n", debugstr_w(sig->Name));
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
signature = MSI_RecordGetString(row, 1);
|
|
|
|
guid = MSI_RecordGetString(row, 2);
|
|
|
|
type = MSI_RecordGetInteger(row, 3);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2022-03-13 20:31:42 +00:00
|
|
|
rec = MSI_QueryGetRecord(package->db, L"SELECT * FROM `Signature` WHERE `Signature` = '%s'", signature);
|
2008-01-16 10:11:22 +00:00
|
|
|
if (!rec)
|
|
|
|
sigpresent = FALSE;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
*path = '\0';
|
|
|
|
MsiLocateComponentW(guid, path, &size);
|
|
|
|
if (!*path)
|
|
|
|
goto done;
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
attr = msi_get_file_attributes( package, path );
|
2008-01-16 10:11:22 +00:00
|
|
|
if (attr == INVALID_FILE_ATTRIBUTES)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
isdir = (attr & FILE_ATTRIBUTE_DIRECTORY);
|
|
|
|
|
|
|
|
if (type != msidbLocatorTypeDirectory && sigpresent && !isdir)
|
|
|
|
{
|
2022-03-13 00:17:50 +00:00
|
|
|
*appValue = search_file( package, path, sig );
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
else if (!sigpresent && (type != msidbLocatorTypeDirectory || isdir))
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2008-01-16 10:11:22 +00:00
|
|
|
if (type == msidbLocatorTypeFileName)
|
|
|
|
{
|
2022-03-13 00:35:24 +00:00
|
|
|
ptr = wcsrchr(path, '\\');
|
2008-01-16 10:11:22 +00:00
|
|
|
*(ptr + 1) = '\0';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
PathAddBackslashW(path);
|
|
|
|
|
|
|
|
*appValue = strdupW(path);
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2008-12-27 15:10:14 +00:00
|
|
|
else if (sigpresent)
|
|
|
|
{
|
|
|
|
PathAddBackslashW(path);
|
|
|
|
lstrcatW(path, MSI_RecordGetString(rec, 2));
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
attr = msi_get_file_attributes( package, path );
|
|
|
|
if (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY))
|
2008-12-27 15:10:14 +00:00
|
|
|
*appValue = strdupW(path);
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
done:
|
|
|
|
if (rec) msiobj_release(&rec->hdr);
|
|
|
|
msiobj_release(&row->hdr);
|
|
|
|
return ERROR_SUCCESS;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
static void convert_reg_value( DWORD regType, const BYTE *value, DWORD sz, WCHAR **appValue )
|
2006-08-01 23:12:11 +00:00
|
|
|
{
|
2008-12-27 15:10:14 +00:00
|
|
|
LPWSTR ptr;
|
2006-08-01 23:12:11 +00:00
|
|
|
DWORD i;
|
|
|
|
|
|
|
|
switch (regType)
|
|
|
|
{
|
|
|
|
case REG_SZ:
|
2006-10-22 20:23:59 +00:00
|
|
|
if (*(LPCWSTR)value == '#')
|
2006-08-01 23:12:11 +00:00
|
|
|
{
|
|
|
|
/* escape leading pound with another */
|
|
|
|
*appValue = msi_alloc(sz + sizeof(WCHAR));
|
|
|
|
(*appValue)[0] = '#';
|
2022-03-13 00:35:24 +00:00
|
|
|
lstrcpyW(*appValue + 1, (LPCWSTR)value);
|
2006-08-01 23:12:11 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*appValue = msi_alloc(sz);
|
2022-03-13 00:35:24 +00:00
|
|
|
lstrcpyW(*appValue, (LPCWSTR)value);
|
2006-08-01 23:12:11 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case REG_DWORD:
|
|
|
|
/* 7 chars for digits, 1 for NULL, 1 for #, and 1 for sign
|
|
|
|
* char if needed
|
|
|
|
*/
|
|
|
|
*appValue = msi_alloc(10 * sizeof(WCHAR));
|
2022-03-13 20:31:42 +00:00
|
|
|
swprintf(*appValue, 10, L"#%d", *(const DWORD *)value);
|
2006-08-01 23:12:11 +00:00
|
|
|
break;
|
|
|
|
case REG_EXPAND_SZ:
|
2008-12-27 15:10:14 +00:00
|
|
|
sz = ExpandEnvironmentStringsW((LPCWSTR)value, NULL, 0);
|
|
|
|
*appValue = msi_alloc(sz * sizeof(WCHAR));
|
|
|
|
ExpandEnvironmentStringsW((LPCWSTR)value, *appValue, sz);
|
2006-08-01 23:12:11 +00:00
|
|
|
break;
|
|
|
|
case REG_BINARY:
|
2008-12-27 15:10:14 +00:00
|
|
|
/* #x<nibbles>\0 */
|
|
|
|
*appValue = msi_alloc((sz * 2 + 3) * sizeof(WCHAR));
|
2022-03-13 20:31:42 +00:00
|
|
|
lstrcpyW(*appValue, L"#x");
|
|
|
|
ptr = *appValue + lstrlenW(L"#x");
|
2008-12-27 15:10:14 +00:00
|
|
|
for (i = 0; i < sz; i++, ptr += 2)
|
2022-03-13 20:31:42 +00:00
|
|
|
swprintf(ptr, 3, L"%02X", value[i]);
|
2006-08-01 23:12:11 +00:00
|
|
|
break;
|
|
|
|
default:
|
2022-03-14 20:20:29 +00:00
|
|
|
WARN( "unimplemented for values of type %lu\n", regType );
|
2006-08-01 23:12:11 +00:00
|
|
|
*appValue = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
static UINT search_directory( MSIPACKAGE *, MSISIGNATURE *, const WCHAR *, int, WCHAR ** );
|
2006-08-01 23:12:11 +00:00
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
static UINT search_reg( MSIPACKAGE *package, WCHAR **appValue, MSISIGNATURE *sig )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
const WCHAR *keyPath, *valueName;
|
|
|
|
WCHAR *deformatted = NULL, *ptr = NULL, *end;
|
2008-01-16 10:11:22 +00:00
|
|
|
int root, type;
|
2022-03-13 00:23:59 +00:00
|
|
|
REGSAM access = KEY_READ;
|
2008-01-16 10:11:22 +00:00
|
|
|
HKEY rootKey, key = NULL;
|
|
|
|
DWORD sz = 0, regType;
|
|
|
|
LPBYTE value = NULL;
|
|
|
|
MSIRECORD *row;
|
2006-02-17 00:04:10 +00:00
|
|
|
UINT rc;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
|
|
|
TRACE("%s\n", debugstr_w(sig->Name));
|
|
|
|
|
2006-08-01 23:12:11 +00:00
|
|
|
*appValue = NULL;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2022-03-13 20:31:42 +00:00
|
|
|
row = MSI_QueryGetRecord( package->db, L"SELECT * FROM `RegLocator` WHERE `Signature_` = '%s'", sig->Name );
|
2008-01-16 10:11:22 +00:00
|
|
|
if (!row)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2008-01-16 10:11:22 +00:00
|
|
|
TRACE("failed to query RegLocator for %s\n", debugstr_w(sig->Name));
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
root = MSI_RecordGetInteger(row, 2);
|
|
|
|
keyPath = MSI_RecordGetString(row, 3);
|
|
|
|
valueName = MSI_RecordGetString(row, 4);
|
|
|
|
type = MSI_RecordGetInteger(row, 5);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
deformat_string(package, keyPath, &deformatted);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
switch (root)
|
|
|
|
{
|
|
|
|
case msidbRegistryRootClassesRoot:
|
|
|
|
rootKey = HKEY_CLASSES_ROOT;
|
|
|
|
break;
|
|
|
|
case msidbRegistryRootCurrentUser:
|
|
|
|
rootKey = HKEY_CURRENT_USER;
|
|
|
|
break;
|
|
|
|
case msidbRegistryRootLocalMachine:
|
|
|
|
rootKey = HKEY_LOCAL_MACHINE;
|
2022-03-13 00:23:59 +00:00
|
|
|
if (type & msidbLocatorType64bit) access |= KEY_WOW64_64KEY;
|
|
|
|
else access |= KEY_WOW64_32KEY;
|
2008-01-16 10:11:22 +00:00
|
|
|
break;
|
|
|
|
case msidbRegistryRootUsers:
|
|
|
|
rootKey = HKEY_USERS;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
WARN("Unknown root key %d\n", root);
|
|
|
|
goto end;
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2022-03-13 00:23:59 +00:00
|
|
|
rc = RegOpenKeyExW( rootKey, deformatted, 0, access, &key );
|
2008-01-16 10:11:22 +00:00
|
|
|
if (rc)
|
|
|
|
{
|
2022-03-13 00:23:59 +00:00
|
|
|
TRACE("RegOpenKeyExW returned %d\n", rc);
|
2008-01-16 10:11:22 +00:00
|
|
|
goto end;
|
|
|
|
}
|
2006-08-01 23:12:11 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
msi_free(deformatted);
|
|
|
|
deformat_string(package, valueName, &deformatted);
|
|
|
|
|
|
|
|
rc = RegQueryValueExW(key, deformatted, NULL, NULL, NULL, &sz);
|
2008-01-16 10:11:22 +00:00
|
|
|
if (rc)
|
|
|
|
{
|
|
|
|
TRACE("RegQueryValueExW returned %d\n", rc);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
/* FIXME: sanity-check sz before allocating (is there an upper-limit
|
|
|
|
* on the value of a property?)
|
|
|
|
*/
|
|
|
|
value = msi_alloc( sz );
|
2012-01-21 17:19:12 +00:00
|
|
|
rc = RegQueryValueExW(key, deformatted, NULL, ®Type, value, &sz);
|
2008-01-16 10:11:22 +00:00
|
|
|
if (rc)
|
|
|
|
{
|
|
|
|
TRACE("RegQueryValueExW returned %d\n", rc);
|
|
|
|
goto end;
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
/* bail out if the registry key is empty */
|
|
|
|
if (sz == 0)
|
|
|
|
goto end;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2014-09-23 18:32:48 +00:00
|
|
|
/* expand if needed */
|
|
|
|
if (regType == REG_EXPAND_SZ)
|
|
|
|
{
|
|
|
|
sz = ExpandEnvironmentStringsW((LPCWSTR)value, NULL, 0);
|
|
|
|
if (sz)
|
|
|
|
{
|
|
|
|
LPWSTR buf = msi_alloc(sz * sizeof(WCHAR));
|
|
|
|
ExpandEnvironmentStringsW((LPCWSTR)value, buf, sz);
|
|
|
|
msi_free(value);
|
|
|
|
value = (LPBYTE)buf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-16 01:13:42 +00:00
|
|
|
if ((regType == REG_SZ || regType == REG_EXPAND_SZ) &&
|
2022-03-13 00:35:24 +00:00
|
|
|
(ptr = wcschr((LPWSTR)value, '"')) && (end = wcschr(++ptr, '"')))
|
2008-12-27 15:10:14 +00:00
|
|
|
*end = '\0';
|
|
|
|
else
|
|
|
|
ptr = (LPWSTR)value;
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
switch (type & 0x0f)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2008-01-16 10:11:22 +00:00
|
|
|
case msidbLocatorTypeDirectory:
|
2022-03-13 00:17:50 +00:00
|
|
|
search_directory( package, sig, ptr, 0, appValue );
|
2008-01-16 10:11:22 +00:00
|
|
|
break;
|
|
|
|
case msidbLocatorTypeFileName:
|
2022-03-13 00:17:50 +00:00
|
|
|
*appValue = search_file( package, ptr, sig );
|
2008-01-16 10:11:22 +00:00
|
|
|
break;
|
|
|
|
case msidbLocatorTypeRawValue:
|
2022-03-13 00:17:50 +00:00
|
|
|
convert_reg_value( regType, value, sz, appValue );
|
2008-01-16 10:11:22 +00:00
|
|
|
break;
|
|
|
|
default:
|
2010-02-06 21:28:28 +00:00
|
|
|
FIXME("unimplemented for type %d (key path %s, value %s)\n",
|
2008-01-16 10:11:22 +00:00
|
|
|
type, debugstr_w(keyPath), debugstr_w(valueName));
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
end:
|
|
|
|
msi_free( value );
|
|
|
|
RegCloseKey( key );
|
|
|
|
msi_free( deformatted );
|
|
|
|
|
|
|
|
msiobj_release(&row->hdr);
|
|
|
|
return ERROR_SUCCESS;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
static LPWSTR get_ini_field(LPWSTR buf, int field)
|
|
|
|
{
|
|
|
|
LPWSTR beg, end;
|
|
|
|
int i = 1;
|
|
|
|
|
|
|
|
if (field == 0)
|
|
|
|
return strdupW(buf);
|
|
|
|
|
|
|
|
beg = buf;
|
2022-03-13 00:35:24 +00:00
|
|
|
while ((end = wcschr(beg, ',')) && i < field)
|
2008-12-27 15:10:14 +00:00
|
|
|
{
|
|
|
|
beg = end + 1;
|
2018-01-20 11:29:30 +00:00
|
|
|
while (*beg == ' ')
|
2008-12-27 15:10:14 +00:00
|
|
|
beg++;
|
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
2022-03-13 00:35:24 +00:00
|
|
|
end = wcschr(beg, ',');
|
2008-12-27 15:10:14 +00:00
|
|
|
if (!end)
|
|
|
|
end = beg + lstrlenW(beg);
|
|
|
|
|
|
|
|
*end = '\0';
|
|
|
|
return strdupW(beg);
|
|
|
|
}
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
static UINT search_ini( MSIPACKAGE *package, WCHAR **appValue, MSISIGNATURE *sig )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2008-01-16 10:11:22 +00:00
|
|
|
MSIRECORD *row;
|
|
|
|
LPWSTR fileName, section, key;
|
|
|
|
int field, type;
|
|
|
|
WCHAR buf[MAX_PATH];
|
|
|
|
|
|
|
|
TRACE("%s\n", debugstr_w(sig->Name));
|
|
|
|
|
2006-08-01 23:12:11 +00:00
|
|
|
*appValue = NULL;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2022-03-13 20:31:42 +00:00
|
|
|
row = MSI_QueryGetRecord( package->db, L"SELECT * FROM `IniLocator` WHERE `Signature_` = '%s'", sig->Name );
|
2008-01-16 10:11:22 +00:00
|
|
|
if (!row)
|
|
|
|
{
|
|
|
|
TRACE("failed to query IniLocator for %s\n", debugstr_w(sig->Name));
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
fileName = msi_dup_record_field(row, 2);
|
|
|
|
section = msi_dup_record_field(row, 3);
|
|
|
|
key = msi_dup_record_field(row, 4);
|
|
|
|
field = MSI_RecordGetInteger(row, 5);
|
|
|
|
type = MSI_RecordGetInteger(row, 6);
|
|
|
|
if (field == MSI_NULL_INTEGER)
|
|
|
|
field = 0;
|
|
|
|
if (type == MSI_NULL_INTEGER)
|
|
|
|
type = 0;
|
|
|
|
|
|
|
|
GetPrivateProfileStringW(section, key, NULL, buf, MAX_PATH, fileName);
|
|
|
|
if (buf[0])
|
|
|
|
{
|
|
|
|
switch (type & 0x0f)
|
2006-08-01 23:12:11 +00:00
|
|
|
{
|
2008-01-16 10:11:22 +00:00
|
|
|
case msidbLocatorTypeDirectory:
|
2022-03-13 00:17:50 +00:00
|
|
|
search_directory( package, sig, buf, 0, appValue );
|
2008-01-16 10:11:22 +00:00
|
|
|
break;
|
|
|
|
case msidbLocatorTypeFileName:
|
2022-03-13 00:17:50 +00:00
|
|
|
*appValue = search_file( package, buf, sig );
|
2008-01-16 10:11:22 +00:00
|
|
|
break;
|
|
|
|
case msidbLocatorTypeRawValue:
|
2008-12-27 15:10:14 +00:00
|
|
|
*appValue = get_ini_field(buf, field);
|
2008-01-16 10:11:22 +00:00
|
|
|
break;
|
2006-08-01 23:12:11 +00:00
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
msi_free(fileName);
|
|
|
|
msi_free(section);
|
|
|
|
msi_free(key);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
msiobj_release(&row->hdr);
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Expands the value in src into a path without property names and only
|
|
|
|
* containing long path names into dst. Replaces at most len characters of dst,
|
|
|
|
* and always NULL-terminates dst if dst is not NULL and len >= 1.
|
|
|
|
* May modify src.
|
|
|
|
* Assumes src and dst are non-overlapping.
|
|
|
|
* FIXME: return code probably needed:
|
|
|
|
* - what does AppSearch return if the table values are invalid?
|
|
|
|
* - what if dst is too small?
|
|
|
|
*/
|
2022-03-13 00:17:50 +00:00
|
|
|
static void expand_any_path( MSIPACKAGE *package, WCHAR *src, WCHAR *dst, size_t len )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2008-01-16 10:11:22 +00:00
|
|
|
WCHAR *ptr, *deformatted;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
if (!src || !dst || !len)
|
2006-10-22 20:23:59 +00:00
|
|
|
{
|
|
|
|
if (dst) *dst = '\0';
|
2006-02-17 00:04:10 +00:00
|
|
|
return;
|
2006-10-22 20:23:59 +00:00
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
dst[0] = '\0';
|
|
|
|
|
|
|
|
/* Ignore the short portion of the path */
|
2022-03-13 00:35:24 +00:00
|
|
|
if ((ptr = wcschr(src, '|')))
|
2006-02-17 00:04:10 +00:00
|
|
|
ptr++;
|
|
|
|
else
|
|
|
|
ptr = src;
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
deformat_string(package, ptr, &deformatted);
|
2022-03-13 00:35:24 +00:00
|
|
|
if (!deformatted || lstrlenW(deformatted) > len - 1)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
|
|
|
msi_free(deformatted);
|
|
|
|
return;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
|
|
|
|
lstrcpyW(dst, deformatted);
|
|
|
|
dst[lstrlenW(deformatted)] = '\0';
|
|
|
|
msi_free(deformatted);
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2012-05-14 21:41:31 +00:00
|
|
|
static LANGID *parse_languages( const WCHAR *languages, DWORD *num_ids )
|
|
|
|
{
|
|
|
|
UINT i, count = 1;
|
|
|
|
WCHAR *str = strdupW( languages ), *p, *q;
|
|
|
|
LANGID *ret;
|
|
|
|
|
|
|
|
if (!str) return NULL;
|
2022-03-13 00:35:24 +00:00
|
|
|
for (p = q = str; (q = wcschr( q, ',' )); q++) count++;
|
2012-05-14 21:41:31 +00:00
|
|
|
|
|
|
|
if (!(ret = msi_alloc( count * sizeof(LANGID) )))
|
|
|
|
{
|
|
|
|
msi_free( str );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
i = 0;
|
|
|
|
while (*p)
|
|
|
|
{
|
2022-03-13 00:35:24 +00:00
|
|
|
q = wcschr( p, ',' );
|
2012-05-14 21:41:31 +00:00
|
|
|
if (q) *q = 0;
|
2022-03-13 00:35:24 +00:00
|
|
|
ret[i] = wcstol( p, NULL, 10 );
|
2012-05-14 21:41:31 +00:00
|
|
|
if (!q) break;
|
|
|
|
p = q + 1;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
msi_free( str );
|
|
|
|
*num_ids = count;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL match_languages( const void *version, const WCHAR *languages )
|
|
|
|
{
|
|
|
|
struct lang
|
|
|
|
{
|
|
|
|
USHORT id;
|
|
|
|
USHORT codepage;
|
|
|
|
} *lang;
|
2022-03-14 20:20:24 +00:00
|
|
|
UINT len, j;
|
|
|
|
DWORD num_ids, i;
|
2012-05-14 21:41:31 +00:00
|
|
|
BOOL found = FALSE;
|
|
|
|
LANGID *ids;
|
|
|
|
|
|
|
|
if (!languages || !languages[0]) return TRUE;
|
2022-03-13 20:31:42 +00:00
|
|
|
if (!VerQueryValueW( version, L"\\VarFileInfo\\Translation", (void **)&lang, &len )) return FALSE;
|
2012-05-14 21:41:31 +00:00
|
|
|
if (!(ids = parse_languages( languages, &num_ids ))) return FALSE;
|
|
|
|
|
|
|
|
for (i = 0; i < num_ids; i++)
|
|
|
|
{
|
|
|
|
found = FALSE;
|
|
|
|
for (j = 0; j < len / sizeof(struct lang); j++)
|
|
|
|
{
|
|
|
|
if (!ids[i] || ids[i] == lang[j].id) found = TRUE;
|
|
|
|
}
|
|
|
|
if (!found) goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
msi_free( ids );
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
/* Sets *matches to whether the file (whose path is filePath) matches the
|
|
|
|
* versions set in sig.
|
|
|
|
* Return ERROR_SUCCESS in case of success (whether or not the file matches),
|
|
|
|
* something else if an install-halting error occurs.
|
|
|
|
*/
|
2022-03-13 00:17:50 +00:00
|
|
|
static UINT file_version_matches( MSIPACKAGE *package, const MSISIGNATURE *sig, const WCHAR *filePath,
|
|
|
|
BOOL *matches )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2012-05-14 21:41:31 +00:00
|
|
|
UINT len;
|
|
|
|
void *version;
|
|
|
|
VS_FIXEDFILEINFO *info = NULL;
|
2022-03-13 00:17:50 +00:00
|
|
|
DWORD size = msi_get_file_version_info( package, filePath, 0, NULL );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
*matches = FALSE;
|
|
|
|
|
2012-05-14 21:41:31 +00:00
|
|
|
if (!size) return ERROR_SUCCESS;
|
|
|
|
if (!(version = msi_alloc( size ))) return ERROR_OUTOFMEMORY;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
if (msi_get_file_version_info( package, filePath, size, version ))
|
2022-03-13 20:31:42 +00:00
|
|
|
VerQueryValueW( version, L"\\", (void **)&info, &len );
|
2012-05-14 21:41:31 +00:00
|
|
|
|
|
|
|
if (info)
|
|
|
|
{
|
|
|
|
TRACE("comparing file version %d.%d.%d.%d:\n",
|
|
|
|
HIWORD(info->dwFileVersionMS),
|
|
|
|
LOWORD(info->dwFileVersionMS),
|
|
|
|
HIWORD(info->dwFileVersionLS),
|
|
|
|
LOWORD(info->dwFileVersionLS));
|
|
|
|
if (info->dwFileVersionMS < sig->MinVersionMS
|
|
|
|
|| (info->dwFileVersionMS == sig->MinVersionMS &&
|
|
|
|
info->dwFileVersionLS < sig->MinVersionLS))
|
|
|
|
{
|
|
|
|
TRACE("less than minimum version %d.%d.%d.%d\n",
|
|
|
|
HIWORD(sig->MinVersionMS),
|
|
|
|
LOWORD(sig->MinVersionMS),
|
|
|
|
HIWORD(sig->MinVersionLS),
|
|
|
|
LOWORD(sig->MinVersionLS));
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2012-05-14 21:41:31 +00:00
|
|
|
else if ((sig->MaxVersionMS || sig->MaxVersionLS) &&
|
|
|
|
(info->dwFileVersionMS > sig->MaxVersionMS ||
|
|
|
|
(info->dwFileVersionMS == sig->MaxVersionMS &&
|
|
|
|
info->dwFileVersionLS > sig->MaxVersionLS)))
|
|
|
|
{
|
|
|
|
TRACE("greater than maximum version %d.%d.%d.%d\n",
|
|
|
|
HIWORD(sig->MaxVersionMS),
|
|
|
|
LOWORD(sig->MaxVersionMS),
|
|
|
|
HIWORD(sig->MaxVersionLS),
|
|
|
|
LOWORD(sig->MaxVersionLS));
|
|
|
|
}
|
|
|
|
else if (!match_languages( version, sig->Languages ))
|
|
|
|
{
|
|
|
|
TRACE("languages %s not supported\n", debugstr_w( sig->Languages ));
|
|
|
|
}
|
|
|
|
else *matches = TRUE;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2012-05-14 21:41:31 +00:00
|
|
|
msi_free( version );
|
|
|
|
return ERROR_SUCCESS;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Sets *matches to whether the file in findData matches that in sig.
|
|
|
|
* fullFilePath is assumed to be the full path of the file specified in
|
|
|
|
* findData, which may be necessary to compare the version.
|
|
|
|
* Return ERROR_SUCCESS in case of success (whether or not the file matches),
|
|
|
|
* something else if an install-halting error occurs.
|
|
|
|
*/
|
2022-03-13 00:17:50 +00:00
|
|
|
static UINT file_matches_sig( MSIPACKAGE *package, const MSISIGNATURE *sig, const WIN32_FIND_DATAW *findData,
|
|
|
|
const WCHAR *fullFilePath, BOOL *matches )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
UINT rc = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
*matches = TRUE;
|
|
|
|
/* assumes the caller has already ensured the filenames match, so check
|
|
|
|
* the other fields..
|
|
|
|
*/
|
|
|
|
if (sig->MinTime.dwLowDateTime || sig->MinTime.dwHighDateTime)
|
|
|
|
{
|
|
|
|
if (findData->ftCreationTime.dwHighDateTime <
|
|
|
|
sig->MinTime.dwHighDateTime ||
|
|
|
|
(findData->ftCreationTime.dwHighDateTime == sig->MinTime.dwHighDateTime
|
|
|
|
&& findData->ftCreationTime.dwLowDateTime <
|
|
|
|
sig->MinTime.dwLowDateTime))
|
|
|
|
*matches = FALSE;
|
|
|
|
}
|
|
|
|
if (*matches && (sig->MaxTime.dwLowDateTime || sig->MaxTime.dwHighDateTime))
|
|
|
|
{
|
|
|
|
if (findData->ftCreationTime.dwHighDateTime >
|
|
|
|
sig->MaxTime.dwHighDateTime ||
|
|
|
|
(findData->ftCreationTime.dwHighDateTime == sig->MaxTime.dwHighDateTime
|
|
|
|
&& findData->ftCreationTime.dwLowDateTime >
|
|
|
|
sig->MaxTime.dwLowDateTime))
|
|
|
|
*matches = FALSE;
|
|
|
|
}
|
|
|
|
if (*matches && sig->MinSize && findData->nFileSizeLow < sig->MinSize)
|
|
|
|
*matches = FALSE;
|
|
|
|
if (*matches && sig->MaxSize && findData->nFileSizeLow > sig->MaxSize)
|
|
|
|
*matches = FALSE;
|
|
|
|
if (*matches && (sig->MinVersionMS || sig->MinVersionLS ||
|
|
|
|
sig->MaxVersionMS || sig->MaxVersionLS))
|
2022-03-13 00:17:50 +00:00
|
|
|
rc = file_version_matches( package, sig, fullFilePath, matches );
|
2006-02-17 00:04:10 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Recursively searches the directory dir for files that match the signature
|
|
|
|
* sig, up to (depth + 1) levels deep. That is, if depth is 0, it searches dir
|
|
|
|
* (and only dir). If depth is 1, searches dir and its immediate
|
|
|
|
* subdirectories.
|
|
|
|
* Assumes sig->File is not NULL.
|
|
|
|
* Returns ERROR_SUCCESS on success (which may include non-critical errors),
|
|
|
|
* something else on failures which should halt the install.
|
|
|
|
*/
|
2022-03-13 00:17:50 +00:00
|
|
|
static UINT recurse_search_directory( MSIPACKAGE *package, WCHAR **appValue, MSISIGNATURE *sig, const WCHAR *dir,
|
|
|
|
int depth )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2008-12-27 15:10:14 +00:00
|
|
|
HANDLE hFind;
|
|
|
|
WIN32_FIND_DATAW findData;
|
2006-02-17 00:04:10 +00:00
|
|
|
UINT rc = ERROR_SUCCESS;
|
|
|
|
size_t dirLen = lstrlenW(dir), fileLen = lstrlenW(sig->File);
|
2008-12-27 15:10:14 +00:00
|
|
|
WCHAR subpath[MAX_PATH];
|
2006-02-17 00:04:10 +00:00
|
|
|
WCHAR *buf;
|
2009-12-22 09:28:03 +00:00
|
|
|
DWORD len;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
TRACE("Searching directory %s for file %s, depth %d\n", debugstr_w(dir), debugstr_w(sig->File), depth);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
if (depth < 0)
|
2008-12-27 15:10:14 +00:00
|
|
|
return ERROR_SUCCESS;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2006-08-01 23:12:11 +00:00
|
|
|
*appValue = NULL;
|
2006-02-17 00:04:10 +00:00
|
|
|
/* We need the buffer in both paths below, so go ahead and allocate it
|
|
|
|
* here. Add two because we might need to add a backslash if the dir name
|
|
|
|
* isn't backslash-terminated.
|
|
|
|
*/
|
2022-03-13 20:31:42 +00:00
|
|
|
len = dirLen + max(fileLen, lstrlenW(L"*.*")) + 2;
|
2009-12-22 09:28:03 +00:00
|
|
|
buf = msi_alloc(len * sizeof(WCHAR));
|
2008-12-27 15:10:14 +00:00
|
|
|
if (!buf)
|
|
|
|
return ERROR_OUTOFMEMORY;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
lstrcpyW(buf, dir);
|
|
|
|
PathAddBackslashW(buf);
|
|
|
|
lstrcatW(buf, sig->File);
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
hFind = msi_find_first_file( package, buf, &findData );
|
2008-12-27 15:10:14 +00:00
|
|
|
if (hFind != INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
BOOL matches;
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
rc = file_matches_sig( package, sig, &findData, buf, &matches );
|
2008-12-27 15:10:14 +00:00
|
|
|
if (rc == ERROR_SUCCESS && matches)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2006-08-01 23:12:11 +00:00
|
|
|
TRACE("found file, returning %s\n", debugstr_w(buf));
|
|
|
|
*appValue = buf;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
}
|
2008-12-27 15:10:14 +00:00
|
|
|
FindClose(hFind);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc == ERROR_SUCCESS && !*appValue)
|
|
|
|
{
|
|
|
|
lstrcpyW(buf, dir);
|
|
|
|
PathAddBackslashW(buf);
|
2022-03-13 20:31:42 +00:00
|
|
|
lstrcatW(buf, L"*.*");
|
2008-12-27 15:10:14 +00:00
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
hFind = msi_find_first_file( package, buf, &findData );
|
2008-12-27 15:10:14 +00:00
|
|
|
if (hFind != INVALID_HANDLE_VALUE)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2008-12-27 15:10:14 +00:00
|
|
|
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
|
2022-03-13 20:31:42 +00:00
|
|
|
wcscmp( findData.cFileName, L"." ) &&
|
|
|
|
wcscmp( findData.cFileName, L".." ))
|
2008-12-27 15:10:14 +00:00
|
|
|
{
|
|
|
|
lstrcpyW(subpath, dir);
|
|
|
|
PathAppendW(subpath, findData.cFileName);
|
2022-03-13 00:17:50 +00:00
|
|
|
rc = recurse_search_directory( package, appValue, sig, subpath, depth - 1 );
|
2008-12-27 15:10:14 +00:00
|
|
|
}
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
while (rc == ERROR_SUCCESS && !*appValue && msi_find_next_file( package, hFind, &findData ))
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2022-03-13 20:31:42 +00:00
|
|
|
if (!wcscmp( findData.cFileName, L"." ) ||
|
|
|
|
!wcscmp( findData.cFileName, L".." ))
|
2008-12-27 15:10:14 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
lstrcpyW(subpath, dir);
|
|
|
|
PathAppendW(subpath, findData.cFileName);
|
2006-02-17 00:04:10 +00:00
|
|
|
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
2022-03-13 00:17:50 +00:00
|
|
|
rc = recurse_search_directory( package, appValue, sig, subpath, depth - 1 );
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2008-12-27 15:10:14 +00:00
|
|
|
|
|
|
|
FindClose(hFind);
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
}
|
2008-12-27 15:10:14 +00:00
|
|
|
|
2009-12-22 09:28:03 +00:00
|
|
|
if (*appValue != buf)
|
2008-12-27 15:10:14 +00:00
|
|
|
msi_free(buf);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
static UINT check_directory( MSIPACKAGE *package, const WCHAR *dir, WCHAR **appValue )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2022-03-13 00:17:50 +00:00
|
|
|
DWORD attr = msi_get_file_attributes( package, dir );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
if (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2006-08-01 23:12:11 +00:00
|
|
|
TRACE("directory exists, returning %s\n", debugstr_w(dir));
|
|
|
|
*appValue = strdupW(dir);
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
static BOOL is_full_path( const WCHAR *path )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2022-03-13 00:35:24 +00:00
|
|
|
WCHAR first = towupper(path[0]);
|
2006-02-17 00:04:10 +00:00
|
|
|
BOOL ret;
|
|
|
|
|
|
|
|
if (first >= 'A' && first <= 'Z' && path[1] == ':')
|
|
|
|
ret = TRUE;
|
|
|
|
else if (path[0] == '\\' && path[1] == '\\')
|
|
|
|
ret = TRUE;
|
|
|
|
else
|
|
|
|
ret = FALSE;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
static UINT search_directory( MSIPACKAGE *package, MSISIGNATURE *sig, const WCHAR *path, int depth, WCHAR **appValue )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
UINT rc;
|
2008-12-27 15:10:14 +00:00
|
|
|
DWORD attr;
|
|
|
|
LPWSTR val = NULL;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
TRACE("%p, %p, %s, %d, %p\n", package, sig, debugstr_w(path), depth, appValue);
|
2008-12-27 15:10:14 +00:00
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
if (is_full_path( path ))
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
if (sig->File)
|
2022-03-13 00:17:50 +00:00
|
|
|
rc = recurse_search_directory( package, &val, sig, path, depth );
|
2006-02-17 00:04:10 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Recursively searching a directory makes no sense when the
|
|
|
|
* directory to search is the thing you're trying to find.
|
|
|
|
*/
|
2022-03-13 00:17:50 +00:00
|
|
|
rc = check_directory( package, path, &val );
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
WCHAR pathWithDrive[MAX_PATH] = { 'C',':','\\',0 };
|
|
|
|
DWORD drives = GetLogicalDrives();
|
|
|
|
int i;
|
|
|
|
|
|
|
|
rc = ERROR_SUCCESS;
|
2008-12-27 15:10:14 +00:00
|
|
|
for (i = 0; rc == ERROR_SUCCESS && !val && i < 26; i++)
|
|
|
|
{
|
|
|
|
if (!(drives & (1 << i)))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
pathWithDrive[0] = 'A' + i;
|
|
|
|
if (GetDriveTypeW(pathWithDrive) != DRIVE_FIXED)
|
|
|
|
continue;
|
|
|
|
|
2022-03-12 22:54:36 +00:00
|
|
|
lstrcpynW(pathWithDrive + 3, path, ARRAY_SIZE(pathWithDrive) - 3);
|
2008-12-27 15:10:14 +00:00
|
|
|
|
|
|
|
if (sig->File)
|
2022-03-13 00:17:50 +00:00
|
|
|
rc = recurse_search_directory( package, &val, sig, pathWithDrive, depth );
|
2008-12-27 15:10:14 +00:00
|
|
|
else
|
2022-03-13 00:17:50 +00:00
|
|
|
rc = check_directory( package, pathWithDrive, &val );
|
2008-12-27 15:10:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
attr = msi_get_file_attributes( package, val );
|
|
|
|
if (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY) &&
|
2008-12-27 15:10:14 +00:00
|
|
|
val && val[lstrlenW(val) - 1] != '\\')
|
|
|
|
{
|
|
|
|
val = msi_realloc(val, (lstrlenW(val) + 2) * sizeof(WCHAR));
|
|
|
|
if (!val)
|
|
|
|
rc = ERROR_OUTOFMEMORY;
|
|
|
|
else
|
|
|
|
PathAddBackslashW(val);
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2008-12-27 15:10:14 +00:00
|
|
|
|
|
|
|
*appValue = val;
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
TRACE("returning %d\n", rc);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
static UINT search_sig_name( MSIPACKAGE *, const WCHAR *, MSISIGNATURE *, WCHAR ** );
|
2006-08-01 23:12:11 +00:00
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
static UINT search_dr( MSIPACKAGE *package, WCHAR **appValue, MSISIGNATURE *sig )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2010-05-29 08:55:43 +00:00
|
|
|
LPWSTR parent = NULL;
|
|
|
|
LPCWSTR parentName;
|
2008-12-27 15:10:14 +00:00
|
|
|
WCHAR path[MAX_PATH];
|
2008-01-16 10:11:22 +00:00
|
|
|
WCHAR expanded[MAX_PATH];
|
|
|
|
MSIRECORD *row;
|
|
|
|
int depth;
|
2009-05-20 12:59:23 +00:00
|
|
|
DWORD sz, attr;
|
2006-02-17 00:04:10 +00:00
|
|
|
UINT rc;
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
TRACE("%s\n", debugstr_w(sig->Name));
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
*appValue = NULL;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2022-03-13 20:31:42 +00:00
|
|
|
row = MSI_QueryGetRecord( package->db, L"SELECT * FROM `DrLocator` WHERE `Signature_` = '%s'", sig->Name );
|
2008-01-16 10:11:22 +00:00
|
|
|
if (!row)
|
|
|
|
{
|
|
|
|
TRACE("failed to query DrLocator for %s\n", debugstr_w(sig->Name));
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check whether parent is set */
|
2010-05-29 08:55:43 +00:00
|
|
|
parentName = MSI_RecordGetString(row, 2);
|
2008-01-16 10:11:22 +00:00
|
|
|
if (parentName)
|
|
|
|
{
|
|
|
|
MSISIGNATURE parentSig;
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
search_sig_name( package, parentName, &parentSig, &parent );
|
|
|
|
free_signature( &parentSig );
|
2010-05-29 08:55:43 +00:00
|
|
|
if (!parent)
|
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
|
|
|
{
|
|
|
|
msiobj_release(&row->hdr);
|
2010-05-29 08:55:43 +00:00
|
|
|
return ERROR_SUCCESS;
|
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
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2008-12-27 15:10:14 +00:00
|
|
|
|
|
|
|
sz = MAX_PATH;
|
|
|
|
MSI_RecordGetStringW(row, 3, path, &sz);
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
if (MSI_RecordIsNull(row,4))
|
|
|
|
depth = 0;
|
2006-02-17 00:04:10 +00:00
|
|
|
else
|
2008-01-16 10:11:22 +00:00
|
|
|
depth = MSI_RecordGetInteger(row,4);
|
2008-12-27 15:10:14 +00:00
|
|
|
|
2009-05-20 12:59:23 +00:00
|
|
|
if (sz)
|
2022-03-13 00:17:50 +00:00
|
|
|
expand_any_path( package, path, expanded, MAX_PATH );
|
2009-05-20 12:59:23 +00:00
|
|
|
else
|
2022-03-13 00:35:24 +00:00
|
|
|
lstrcpyW(expanded, path);
|
2008-12-27 15:10:14 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
if (parent)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2022-03-13 00:17:50 +00:00
|
|
|
attr = msi_get_file_attributes( package, parent );
|
2009-05-20 12:59:23 +00:00
|
|
|
if (attr != INVALID_FILE_ATTRIBUTES &&
|
|
|
|
!(attr & FILE_ATTRIBUTE_DIRECTORY))
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2008-12-27 15:10:14 +00:00
|
|
|
PathRemoveFileSpecW(parent);
|
|
|
|
PathAddBackslashW(parent);
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
2008-12-27 15:10:14 +00:00
|
|
|
|
2022-03-13 00:35:24 +00:00
|
|
|
lstrcpyW(path, parent);
|
|
|
|
lstrcatW(path, expanded);
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2022-03-13 00:35:24 +00:00
|
|
|
else if (sz) lstrcpyW(path, expanded);
|
2008-12-27 15:10:14 +00:00
|
|
|
|
|
|
|
PathAddBackslashW(path);
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
rc = search_directory( package, sig, path, depth, appValue );
|
2008-01-16 10:11:22 +00:00
|
|
|
|
|
|
|
msi_free(parent);
|
|
|
|
msiobj_release(&row->hdr);
|
2006-02-17 00:04:10 +00:00
|
|
|
TRACE("returning %d\n", rc);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
static UINT search_sig_name( MSIPACKAGE *package, const WCHAR *sigName, MSISIGNATURE *sig, WCHAR **appValue )
|
2006-08-01 23:12:11 +00:00
|
|
|
{
|
|
|
|
UINT rc;
|
|
|
|
|
|
|
|
*appValue = NULL;
|
2022-03-13 00:17:50 +00:00
|
|
|
rc = get_signature( package, sig, sigName );
|
2006-08-01 23:12:11 +00:00
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
{
|
2022-03-13 00:17:50 +00:00
|
|
|
rc = search_components( package, appValue, sig );
|
2006-08-01 23:12:11 +00:00
|
|
|
if (rc == ERROR_SUCCESS && !*appValue)
|
|
|
|
{
|
2022-03-13 00:17:50 +00:00
|
|
|
rc = search_reg( package, appValue, sig );
|
2006-08-01 23:12:11 +00:00
|
|
|
if (rc == ERROR_SUCCESS && !*appValue)
|
|
|
|
{
|
2022-03-13 00:17:50 +00:00
|
|
|
rc = search_ini( package, appValue, sig );
|
2006-08-01 23:12:11 +00:00
|
|
|
if (rc == ERROR_SUCCESS && !*appValue)
|
2022-03-13 00:17:50 +00:00
|
|
|
rc = search_dr( package, appValue, sig );
|
2006-08-01 23:12:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
static UINT ITERATE_AppSearch(MSIRECORD *row, LPVOID param)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
|
|
|
MSIPACKAGE *package = param;
|
2010-03-06 09:05:09 +00:00
|
|
|
LPCWSTR propName, sigName;
|
|
|
|
LPWSTR value = NULL;
|
2008-01-16 10:11:22 +00:00
|
|
|
MSISIGNATURE sig;
|
2010-03-06 09:05:09 +00:00
|
|
|
MSIRECORD *uirow;
|
2008-01-16 10:11:22 +00:00
|
|
|
UINT r;
|
|
|
|
|
|
|
|
/* get property and signature */
|
2010-03-06 09:05:09 +00:00
|
|
|
propName = MSI_RecordGetString(row, 1);
|
|
|
|
sigName = MSI_RecordGetString(row, 2);
|
2008-01-16 10:11:22 +00:00
|
|
|
|
|
|
|
TRACE("%s %s\n", debugstr_w(propName), debugstr_w(sigName));
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
r = search_sig_name( package, sigName, &sig, &value );
|
2008-01-16 10:11:22 +00:00
|
|
|
if (value)
|
|
|
|
{
|
2012-12-09 19:43:59 +00:00
|
|
|
r = msi_set_property( package->db, propName, value, -1 );
|
2022-03-13 20:31:42 +00:00
|
|
|
if (r == ERROR_SUCCESS && !wcscmp( propName, L"SourceDir" ))
|
2022-03-12 23:08:16 +00:00
|
|
|
msi_reset_source_folders( package );
|
2010-05-29 08:55:43 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
msi_free(value);
|
|
|
|
}
|
2022-03-13 00:17:50 +00:00
|
|
|
free_signature( &sig );
|
2010-03-06 09:05:09 +00:00
|
|
|
|
|
|
|
uirow = MSI_CreateRecord( 2 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, propName );
|
|
|
|
MSI_RecordSetStringW( uirow, 2, sigName );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-03-06 09:05:09 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
2008-01-16 10:11:22 +00:00
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
UINT ACTION_AppSearch(MSIPACKAGE *package)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
MSIQUERY *view;
|
2008-01-16 10:11:22 +00:00
|
|
|
UINT r;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2022-03-13 20:31:42 +00:00
|
|
|
if (msi_action_is_unique(package, L"AppSearch"))
|
2010-05-29 08:55:43 +00:00
|
|
|
{
|
|
|
|
TRACE("Skipping AppSearch action: already done in UI sequence\n");
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
else
|
2022-03-13 20:31:42 +00:00
|
|
|
msi_register_unique_action(package, L"AppSearch");
|
2010-05-29 08:55:43 +00:00
|
|
|
|
2022-03-13 20:31:42 +00:00
|
|
|
r = MSI_OpenQuery( package->db, &view, L"SELECT * FROM `AppSearch`" );
|
2008-01-16 10:11:22 +00:00
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
r = MSI_IterateRecords( view, NULL, ITERATE_AppSearch, package );
|
2008-01-16 10:11:22 +00:00
|
|
|
msiobj_release( &view->hdr );
|
|
|
|
return r;
|
|
|
|
}
|
2006-08-01 23:12:11 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
static UINT ITERATE_CCPSearch(MSIRECORD *row, LPVOID param)
|
|
|
|
{
|
|
|
|
MSIPACKAGE *package = param;
|
|
|
|
LPCWSTR signature;
|
|
|
|
LPWSTR value = NULL;
|
|
|
|
MSISIGNATURE sig;
|
|
|
|
UINT r = ERROR_SUCCESS;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
signature = MSI_RecordGetString(row, 1);
|
2006-08-01 23:12:11 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
TRACE("%s\n", debugstr_w(signature));
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
search_sig_name( package, signature, &sig, &value );
|
2008-01-16 10:11:22 +00:00
|
|
|
if (value)
|
|
|
|
{
|
|
|
|
TRACE("Found signature %s\n", debugstr_w(signature));
|
2022-03-13 20:31:42 +00:00
|
|
|
msi_set_property( package->db, L"CCP_Success", L"1", -1 );
|
2008-01-16 10:11:22 +00:00
|
|
|
msi_free(value);
|
|
|
|
r = ERROR_NO_MORE_ITEMS;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2022-03-13 00:17:50 +00:00
|
|
|
free_signature(&sig);
|
2008-01-16 10:11:22 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT ACTION_CCPSearch(MSIPACKAGE *package)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
MSIQUERY *view;
|
2008-01-16 10:11:22 +00:00
|
|
|
UINT r;
|
|
|
|
|
2022-03-13 20:31:42 +00:00
|
|
|
if (msi_action_is_unique(package, L"CCPSearch"))
|
2010-05-29 08:55:43 +00:00
|
|
|
{
|
|
|
|
TRACE("Skipping AppSearch action: already done in UI sequence\n");
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
else
|
2022-03-13 20:31:42 +00:00
|
|
|
msi_register_unique_action(package, L"CCPSearch");
|
2010-05-29 08:55:43 +00:00
|
|
|
|
2022-03-13 20:31:42 +00:00
|
|
|
r = MSI_OpenQuery(package->db, &view, L"SELECT * FROM `CCPSearch`");
|
2008-01-16 10:11:22 +00:00
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
r = MSI_IterateRecords(view, NULL, ITERATE_CCPSearch, package);
|
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
return r;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|