📄 appsearch.c
字号:
case msidbRegistryRootCurrentUser:
rootKey = HKEY_CURRENT_USER;
break;
case msidbRegistryRootLocalMachine:
rootKey = HKEY_LOCAL_MACHINE;
break;
case msidbRegistryRootUsers:
rootKey = HKEY_USERS;
break;
default:
WARN("Unknown root key %d\n", root);
goto end;
}
rc = RegOpenKeyW(rootKey, keyPath, &key);
if (rc)
{
TRACE("RegOpenKeyW returned %d\n", rc);
rc = ERROR_SUCCESS;
goto end;
}
rc = RegQueryValueExW(key, valueName, NULL, NULL, NULL, &sz);
if (rc)
{
TRACE("RegQueryValueExW returned %d\n", rc);
rc = ERROR_SUCCESS;
goto end;
}
/* FIXME: sanity-check sz before allocating (is there an upper-limit
* on the value of a property?)
*/
value = msi_alloc( sz);
rc = RegQueryValueExW(key, valueName, NULL, ®Type, value, &sz);
if (rc)
{
TRACE("RegQueryValueExW returned %d\n", rc);
rc = ERROR_SUCCESS;
goto end;
}
/* bail out if the registry key is empty */
if (sz == 0)
{
rc = ERROR_SUCCESS;
goto end;
}
switch (type & 0x0f)
{
case msidbLocatorTypeDirectory:
rc = ACTION_SearchDirectory(package, sig, (LPCWSTR)value, 0,
appValue);
break;
case msidbLocatorTypeFileName:
*appValue = strdupW((LPCWSTR)value);
break;
case msidbLocatorTypeRawValue:
ACTION_ConvertRegValue(regType, value, sz, appValue);
break;
default:
FIXME("AppSearch unimplemented for type %d (key path %s, value %s)\n",
type, debugstr_w(keyPath), debugstr_w(valueName));
}
end:
msi_free( value);
RegCloseKey(key);
msi_free( keyPath);
msi_free( valueName);
if (row)
msiobj_release(&row->hdr);
MSI_ViewClose(view);
msiobj_release(&view->hdr);
}
else
{
TRACE("MSI_OpenQuery returned %d\n", rc);
rc = ERROR_SUCCESS;
}
TRACE("returning %d\n", rc);
return rc;
}
static UINT ACTION_AppSearchIni(MSIPACKAGE *package, LPWSTR *appValue,
MSISIGNATURE *sig)
{
MSIQUERY *view;
UINT rc;
static const WCHAR ExecSeqQuery[] = {
's','e','l','e','c','t',' ','*',' ',
'f','r','o','m',' ',
'I','n','i','L','o','c','a','t','o','r',' ',
'w','h','e','r','e',' ','S','i','g','n','a','t','u','r','e','_',' ','=',' ',
'\'','%','s','\'',0};
TRACE("(package %p, appValue %p, sig %p)\n", package, appValue, sig);
*appValue = NULL;
rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, sig->Name);
if (rc == ERROR_SUCCESS)
{
MSIRECORD *row = 0;
LPWSTR fileName, section, key;
int field, type;
WCHAR buf[MAX_PATH];
rc = MSI_ViewExecute(view, 0);
if (rc != ERROR_SUCCESS)
{
TRACE("MSI_ViewExecute returned %d\n", rc);
goto end;
}
rc = MSI_ViewFetch(view,&row);
if (rc != ERROR_SUCCESS)
{
TRACE("MSI_ViewFetch returned %d\n", rc);
rc = ERROR_SUCCESS;
goto end;
}
fileName = msi_dup_record_field(row, 2);
section = msi_dup_record_field(row, 3);
key = msi_dup_record_field(row, 4);
if ((field = MSI_RecordGetInteger(row, 5)) == MSI_NULL_INTEGER)
field = 0;
if ((type = MSI_RecordGetInteger(row, 6)) == MSI_NULL_INTEGER)
type = 0;
GetPrivateProfileStringW(section, key, NULL, buf,
sizeof(buf) / sizeof(WCHAR), fileName);
if (buf[0])
{
switch (type & 0x0f)
{
case msidbLocatorTypeDirectory:
FIXME("unimplemented for type Directory (dir: %s)\n",
debugstr_w(buf));
break;
case msidbLocatorTypeFileName:
FIXME("unimplemented for type File (file: %s)\n",
debugstr_w(buf));
break;
case msidbLocatorTypeRawValue:
*appValue = strdupW(buf);
break;
}
}
msi_free(fileName);
msi_free(section);
msi_free(key);
end:
if (row)
msiobj_release(&row->hdr);
MSI_ViewClose(view);
msiobj_release(&view->hdr);
}
else
{
TRACE("MSI_OpenQuery returned %d\n", rc);
rc = ERROR_SUCCESS;
}
TRACE("returning %d\n", rc);
return rc;
}
/* 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?
*/
static void ACTION_ExpandAnyPath(MSIPACKAGE *package, WCHAR *src, WCHAR *dst,
size_t len)
{
WCHAR *ptr;
size_t copied = 0;
if (!src || !dst || !len)
{
if (dst) *dst = '\0';
return;
}
/* Ignore the short portion of the path, don't think we can use it anyway */
if ((ptr = strchrW(src, '|')))
ptr++;
else
ptr = src;
while (*ptr && copied < len - 1)
{
WCHAR *prop = strchrW(ptr, '[');
if (prop)
{
WCHAR *propEnd = strchrW(prop + 1, ']');
if (!propEnd)
{
WARN("Unterminated property name in AnyPath: %s\n",
debugstr_w(prop));
break;
}
else
{
DWORD propLen;
*propEnd = 0;
propLen = len - copied - 1;
MSI_GetPropertyW(package, prop + 1, dst + copied, &propLen);
ptr = propEnd + 1;
copied += propLen;
}
}
else
{
size_t toCopy = min(strlenW(ptr) + 1, len - copied - 1);
memcpy(dst + copied, ptr, toCopy * sizeof(WCHAR));
ptr += toCopy;
copied += toCopy;
}
}
*(dst + copied) = '\0';
}
/* 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.
*/
static UINT ACTION_FileVersionMatches(MSISIGNATURE *sig, LPCWSTR filePath,
BOOL *matches)
{
UINT rc = ERROR_SUCCESS;
*matches = FALSE;
if (sig->Languages)
{
FIXME(": need to check version for languages %s\n",
debugstr_w(sig->Languages));
}
else
{
DWORD zero, size = GetFileVersionInfoSizeW(filePath, &zero);
if (size)
{
LPVOID buf = msi_alloc( size);
if (buf)
{
static WCHAR rootW[] = { '\\',0 };
UINT versionLen;
LPVOID subBlock = NULL;
if (GetFileVersionInfoW(filePath, 0, size, buf))
VerQueryValueW(buf, rootW, &subBlock, &versionLen);
if (subBlock)
{
VS_FIXEDFILEINFO *info =
(VS_FIXEDFILEINFO *)subBlock;
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));
}
else if (info->dwFileVersionMS < sig->MinVersionMS
|| (info->dwFileVersionMS == sig->MinVersionMS &&
info->dwFileVersionLS < sig->MinVersionLS))
{
TRACE("Greater than minimum version %d.%d.%d.%d\n",
HIWORD(sig->MaxVersionMS),
LOWORD(sig->MaxVersionMS),
HIWORD(sig->MaxVersionLS),
LOWORD(sig->MaxVersionLS));
}
else
*matches = TRUE;
}
msi_free( buf);
}
else
rc = ERROR_OUTOFMEMORY;
}
}
return rc;
}
/* 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.
*/
static UINT ACTION_FileMatchesSig(MSISIGNATURE *sig,
LPWIN32_FIND_DATAW findData, LPCWSTR fullFilePath, BOOL *matches)
{
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))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -