LPWSTR Languages;
}MSISIGNATURE;
-static void ACTION_VerStrToInteger(LPCWSTR verStr, PDWORD ms, PDWORD ls)
+void msi_parse_version_string(LPCWSTR verStr, PDWORD ms, PDWORD ls)
{
const WCHAR *ptr;
int x1 = 0, x2 = 0, x3 = 0, x4 = 0;
'S','i','g','n','a','t','u','r','e',' ',
'w','h','e','r','e',' ','S','i','g','n','a','t','u','r','e',' ','=',' ',
'\'','%','s','\'',0};
- LPWSTR minVersion, maxVersion;
+ LPWSTR minVersion, maxVersion, p;
MSIRECORD *row;
DWORD time;
/* get properties */
sig->File = msi_dup_record_field(row,2);
+ if ((p = strchrW(sig->File, '|')))
+ {
+ p++;
+ memmove(sig->File, p, (strlenW(p) + 1) * sizeof(WCHAR));
+ }
+
minVersion = msi_dup_record_field(row,3);
if (minVersion)
{
- ACTION_VerStrToInteger(minVersion, &sig->MinVersionMS, &sig->MinVersionLS);
+ msi_parse_version_string( minVersion, &sig->MinVersionMS, &sig->MinVersionLS );
msi_free( minVersion );
}
maxVersion = msi_dup_record_field(row,4);
if (maxVersion)
{
- ACTION_VerStrToInteger(maxVersion, &sig->MaxVersionMS, &sig->MaxVersionLS);
+ msi_parse_version_string( maxVersion, &sig->MaxVersionMS, &sig->MaxVersionLS );
msi_free( maxVersion );
}
sig->MinSize = MSI_RecordGetInteger(row,5);
msi_free(sig->Languages);
}
+static LPWSTR app_search_file(LPWSTR path, MSISIGNATURE *sig)
+{
+ VS_FIXEDFILEINFO *info;
+ DWORD attr, handle, size;
+ LPWSTR val = NULL;
+ LPBYTE buffer;
+
+ if (!sig->File)
+ {
+ PathRemoveFileSpecW(path);
+ PathAddBackslashW(path);
+
+ attr = GetFileAttributesW(path);
+ if (attr != INVALID_FILE_ATTRIBUTES &&
+ (attr & FILE_ATTRIBUTE_DIRECTORY))
+ return strdupW(path);
+
+ return NULL;
+ }
+
+ attr = GetFileAttributesW(path);
+ if (attr == INVALID_FILE_ATTRIBUTES ||
+ (attr & FILE_ATTRIBUTE_DIRECTORY))
+ return NULL;
+
+ size = GetFileVersionInfoSizeW(path, &handle);
+ if (!size)
+ return strdupW(path);
+
+ buffer = msi_alloc(size);
+ if (!buffer)
+ return NULL;
+
+ if (!GetFileVersionInfoW(path, 0, size, buffer))
+ goto done;
+
+ if (!VerQueryValueW(buffer, szBackSlash, (LPVOID)&info, &size) || !info)
+ 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;
+}
+
static UINT ACTION_AppSearchComponents(MSIPACKAGE *package, LPWSTR *appValue, MSISIGNATURE *sig)
{
static const WCHAR query[] = {
if (type != msidbLocatorTypeDirectory && sigpresent && !isdir)
{
- *appValue = strdupW(path);
+ *appValue = app_search_file(path, sig);
}
else if (!sigpresent && (type != msidbLocatorTypeDirectory || isdir))
{
*appValue = strdupW(path);
}
+ else if (sigpresent)
+ {
+ PathAddBackslashW(path);
+ lstrcatW(path, MSI_RecordGetString(rec, 2));
+
+ attr = GetFileAttributesW(path);
+ if (attr != INVALID_FILE_ATTRIBUTES &&
+ !(attr & FILE_ATTRIBUTE_DIRECTORY))
+ *appValue = strdupW(path);
+ }
done:
if (rec) msiobj_release(&rec->hdr);
LPWSTR *appValue)
{
static const WCHAR dwordFmt[] = { '#','%','d','\0' };
- static const WCHAR expandSzFmt[] = { '#','%','%','%','s','\0' };
- static const WCHAR binFmt[] = { '#','x','%','x','\0' };
+ static const WCHAR binPre[] = { '#','x','\0' };
+ static const WCHAR binFmt[] = { '%','0','2','X','\0' };
+ LPWSTR ptr;
DWORD i;
switch (regType)
sprintfW(*appValue, dwordFmt, *(const DWORD *)value);
break;
case REG_EXPAND_SZ:
- /* space for extra #% characters in front */
- *appValue = msi_alloc(sz + 2 * sizeof(WCHAR));
- sprintfW(*appValue, expandSzFmt, (LPCWSTR)value);
+ sz = ExpandEnvironmentStringsW((LPCWSTR)value, NULL, 0);
+ *appValue = msi_alloc(sz * sizeof(WCHAR));
+ ExpandEnvironmentStringsW((LPCWSTR)value, *appValue, sz);
break;
case REG_BINARY:
- /* 3 == length of "#x<nibble>" */
- *appValue = msi_alloc((sz * 3 + 1) * sizeof(WCHAR));
- for (i = 0; i < sz; i++)
- sprintfW(*appValue + i * 3, binFmt, value[i]);
+ /* #x<nibbles>\0 */
+ *appValue = msi_alloc((sz * 2 + 3) * sizeof(WCHAR));
+ lstrcpyW(*appValue, binPre);
+ ptr = *appValue + lstrlenW(binPre);
+ for (i = 0; i < sz; i++, ptr += 2)
+ sprintfW(ptr, binFmt, value[i]);
break;
default:
WARN("unimplemented for values of type %d\n", regType);
'S','i','g','n','a','t','u','r','e','_',' ','=',' ', '\'','%','s','\'',0};
LPWSTR keyPath = NULL, valueName = NULL;
LPWSTR deformatted = NULL;
+ LPWSTR ptr = NULL, end;
int root, type;
HKEY rootKey, key = NULL;
DWORD sz = 0, regType;
if (sz == 0)
goto end;
+ if ((regType == REG_SZ || regType == REG_EXPAND_SZ) &&
+ (ptr = strchrW((LPWSTR)value, '"')) && (end = strchrW(++ptr, '"')))
+ *end = '\0';
+ else
+ ptr = (LPWSTR)value;
+
switch (type & 0x0f)
{
case msidbLocatorTypeDirectory:
- rc = ACTION_SearchDirectory(package, sig, (LPWSTR)value, 0, appValue);
+ rc = ACTION_SearchDirectory(package, sig, ptr, 0, appValue);
break;
case msidbLocatorTypeFileName:
- *appValue = strdupW((LPWSTR)value);
+ *appValue = app_search_file(ptr, sig);
break;
case msidbLocatorTypeRawValue:
ACTION_ConvertRegValue(regType, value, sz, appValue);
break;
default:
- FIXME("AppSearch unimplemented for type %d (key path %s, value %s)\n",
+ FIXME("unimplemented for type %d (key path %s, value %s)\n",
type, debugstr_w(keyPath), debugstr_w(valueName));
}
end:
return ERROR_SUCCESS;
}
+static LPWSTR get_ini_field(LPWSTR buf, int field)
+{
+ LPWSTR beg, end;
+ int i = 1;
+
+ if (field == 0)
+ return strdupW(buf);
+
+ beg = buf;
+ while ((end = strchrW(beg, ',')) && i < field)
+ {
+ beg = end + 1;
+ while (*beg && *beg == ' ')
+ beg++;
+
+ i++;
+ }
+
+ end = strchrW(beg, ',');
+ if (!end)
+ end = beg + lstrlenW(beg);
+
+ *end = '\0';
+ return strdupW(beg);
+}
+
static UINT ACTION_AppSearchIni(MSIPACKAGE *package, LPWSTR *appValue,
MSISIGNATURE *sig)
{
switch (type & 0x0f)
{
case msidbLocatorTypeDirectory:
- FIXME("unimplemented for Directory (%s)\n", debugstr_w(buf));
+ ACTION_SearchDirectory(package, sig, buf, 0, appValue);
break;
case msidbLocatorTypeFileName:
- FIXME("unimplemented for File (%s)\n", debugstr_w(buf));
+ *appValue = app_search_file(buf, sig);
break;
case msidbLocatorTypeRawValue:
- *appValue = strdupW(buf);
+ *appValue = get_ini_field(buf, field);
break;
}
}
ptr = src;
deformat_string(package, ptr, &deformatted);
- if (!deformatted || lstrlenW(deformatted) > len - 1)
+ if (!deformatted || strlenW(deformatted) > len - 1)
{
msi_free(deformatted);
return;
if (buf)
{
- static const WCHAR rootW[] = { '\\',0 };
UINT versionLen;
LPVOID subBlock = NULL;
if (GetFileVersionInfoW(filePath, 0, size, buf))
- VerQueryValueW(buf, rootW, &subBlock, &versionLen);
+ VerQueryValueW(buf, szBackSlash, &subBlock, &versionLen);
if (subBlock)
{
- VS_FIXEDFILEINFO *info =
- (VS_FIXEDFILEINFO *)subBlock;
+ VS_FIXEDFILEINFO *info = subBlock;
TRACE("Comparing file version %d.%d.%d.%d:\n",
HIWORD(info->dwFileVersionMS),
HIWORD(sig->MinVersionLS),
LOWORD(sig->MinVersionLS));
}
- else if (info->dwFileVersionMS < sig->MinVersionMS
- || (info->dwFileVersionMS == sig->MinVersionMS &&
- info->dwFileVersionLS < sig->MinVersionLS))
+ else if ((sig->MaxVersionMS || sig->MaxVersionLS) &&
+ (info->dwFileVersionMS > sig->MaxVersionMS ||
+ (info->dwFileVersionMS == sig->MaxVersionMS &&
+ info->dwFileVersionLS > sig->MaxVersionLS)))
{
- TRACE("Greater than minimum version %d.%d.%d.%d\n",
+ TRACE("Greater than maximum version %d.%d.%d.%d\n",
HIWORD(sig->MaxVersionMS),
LOWORD(sig->MaxVersionMS),
HIWORD(sig->MaxVersionLS),
static UINT ACTION_RecurseSearchDirectory(MSIPACKAGE *package, LPWSTR *appValue,
MSISIGNATURE *sig, LPCWSTR dir, int depth)
{
- static const WCHAR starDotStarW[] = { '*','.','*',0 };
+ HANDLE hFind;
+ WIN32_FIND_DATAW findData;
UINT rc = ERROR_SUCCESS;
size_t dirLen = lstrlenW(dir), fileLen = lstrlenW(sig->File);
+ WCHAR subpath[MAX_PATH];
WCHAR *buf;
+ DWORD len;
+
+ static const WCHAR starDotStarW[] = { '*','.','*',0 };
TRACE("Searching directory %s for file %s, depth %d\n", debugstr_w(dir),
- debugstr_w(sig->File), depth);
+ debugstr_w(sig->File), depth);
if (depth < 0)
- return ERROR_INVALID_PARAMETER;
+ return ERROR_SUCCESS;
*appValue = NULL;
/* 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.
*/
- buf = msi_alloc( (dirLen + max(fileLen, lstrlenW(starDotStarW)) + 2) * sizeof(WCHAR));
- if (buf)
- {
- /* a depth of 0 implies we should search dir, so go ahead and search */
- HANDLE hFind;
- WIN32_FIND_DATAW findData;
+ len = dirLen + max(fileLen, strlenW(starDotStarW)) + 2;
+ buf = msi_alloc(len * sizeof(WCHAR));
+ if (!buf)
+ return ERROR_OUTOFMEMORY;
- memcpy(buf, dir, dirLen * sizeof(WCHAR));
- if (buf[dirLen - 1] != '\\')
- buf[dirLen++ - 1] = '\\';
- memcpy(buf + dirLen, sig->File, (fileLen + 1) * sizeof(WCHAR));
- hFind = FindFirstFileW(buf, &findData);
- if (hFind != INVALID_HANDLE_VALUE)
+ lstrcpyW(buf, dir);
+ PathAddBackslashW(buf);
+ lstrcatW(buf, sig->File);
+
+ hFind = FindFirstFileW(buf, &findData);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
BOOL matches;
- /* assuming Signature can't contain wildcards for the file name,
- * so don't bother with FindNextFileW here.
- */
- if (!(rc = ACTION_FileMatchesSig(sig, &findData, buf, &matches))
- && matches)
+ rc = ACTION_FileMatchesSig(sig, &findData, buf, &matches);
+ if (rc == ERROR_SUCCESS && matches)
{
TRACE("found file, returning %s\n", debugstr_w(buf));
*appValue = buf;
}
- FindClose(hFind);
}
- if (rc == ERROR_SUCCESS && !*appValue && depth > 0)
+ FindClose(hFind);
+ }
+
+ if (rc == ERROR_SUCCESS && !*appValue)
+ {
+ lstrcpyW(buf, dir);
+ PathAddBackslashW(buf);
+ lstrcatW(buf, starDotStarW);
+
+ hFind = FindFirstFileW(buf, &findData);
+ if (hFind != INVALID_HANDLE_VALUE)
{
- HANDLE hFind;
- WIN32_FIND_DATAW findData;
-
- memcpy(buf, dir, dirLen * sizeof(WCHAR));
- if (buf[dirLen - 1] != '\\')
- buf[dirLen++ - 1] = '\\';
- lstrcpyW(buf + dirLen, starDotStarW);
- hFind = FindFirstFileW(buf, &findData);
- if (hFind != INVALID_HANDLE_VALUE)
+ if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
+ lstrcmpW(findData.cFileName, szDot) &&
+ lstrcmpW(findData.cFileName, szDotDot))
{
+ lstrcpyW(subpath, dir);
+ PathAppendW(subpath, findData.cFileName);
+ rc = ACTION_RecurseSearchDirectory(package, appValue, sig,
+ subpath, depth - 1);
+ }
+
+ while (rc == ERROR_SUCCESS && !*appValue &&
+ FindNextFileW(hFind, &findData) != 0)
+ {
+ if (!lstrcmpW(findData.cFileName, szDot) ||
+ !lstrcmpW(findData.cFileName, szDotDot))
+ continue;
+
+ lstrcpyW(subpath, dir);
+ PathAppendW(subpath, findData.cFileName);
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- rc = ACTION_RecurseSearchDirectory(package, appValue, sig,
- findData.cFileName, depth - 1);
- while (rc == ERROR_SUCCESS && !*appValue &&
- FindNextFileW(hFind, &findData) != 0)
- {
- if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- rc = ACTION_RecurseSearchDirectory(package, appValue,
- sig, findData.cFileName, depth - 1);
- }
- FindClose(hFind);
+ rc = ACTION_RecurseSearchDirectory(package, appValue,
+ sig, subpath, depth - 1);
}
+
+ FindClose(hFind);
}
- if (!*appValue)
- msi_free(buf);
}
- else
- rc = ERROR_OUTOFMEMORY;
+
+ if (*appValue != buf)
+ msi_free(buf);
return rc;
}
LPCWSTR path, int depth, LPWSTR *appValue)
{
UINT rc;
+ DWORD attr;
+ LPWSTR val = NULL;
TRACE("%p, %p, %s, %d, %p\n", package, sig, debugstr_w(path), depth,
appValue);
+
if (ACTION_IsFullPath(path))
{
if (sig->File)
- rc = ACTION_RecurseSearchDirectory(package, appValue, sig,
- path, depth);
+ rc = ACTION_RecurseSearchDirectory(package, &val, sig, path, depth);
else
{
/* Recursively searching a directory makes no sense when the
* directory to search is the thing you're trying to find.
*/
- rc = ACTION_CheckDirectory(package, path, appValue);
+ rc = ACTION_CheckDirectory(package, path, &val);
}
}
else
int i;
rc = ERROR_SUCCESS;
- *appValue = NULL;
- for (i = 0; rc == ERROR_SUCCESS && !*appValue && i < 26; i++)
- if (drives & (1 << i))
- {
- pathWithDrive[0] = 'A' + i;
- if (GetDriveTypeW(pathWithDrive) == DRIVE_FIXED)
- {
- lstrcpynW(pathWithDrive + 3, path,
- sizeof(pathWithDrive) / sizeof(pathWithDrive[0]) - 3);
- if (sig->File)
- rc = ACTION_RecurseSearchDirectory(package, appValue,
- sig, pathWithDrive, depth);
- else
- rc = ACTION_CheckDirectory(package, pathWithDrive,
- appValue);
- }
- }
+ 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;
+
+ lstrcpynW(pathWithDrive + 3, path,
+ sizeof(pathWithDrive) / sizeof(pathWithDrive[0]) - 3);
+
+ if (sig->File)
+ rc = ACTION_RecurseSearchDirectory(package, &val, sig,
+ pathWithDrive, depth);
+ else
+ rc = ACTION_CheckDirectory(package, pathWithDrive, &val);
+ }
+ }
+
+ attr = GetFileAttributesW(val);
+ if (attr != INVALID_FILE_ATTRIBUTES &&
+ (attr & FILE_ATTRIBUTE_DIRECTORY) &&
+ val && val[lstrlenW(val) - 1] != '\\')
+ {
+ val = msi_realloc(val, (lstrlenW(val) + 2) * sizeof(WCHAR));
+ if (!val)
+ rc = ERROR_OUTOFMEMORY;
+ else
+ PathAddBackslashW(val);
}
+
+ *appValue = val;
+
TRACE("returning %d\n", rc);
return rc;
}
'D','r','L','o','c','a','t','o','r',' ',
'w','h','e','r','e',' ',
'S','i','g','n','a','t','u','r','e','_',' ','=',' ', '\'','%','s','\'',0};
- LPWSTR parentName = NULL, path = NULL, parent = NULL;
+ LPWSTR parent = NULL;
+ LPCWSTR parentName;
+ WCHAR path[MAX_PATH];
WCHAR expanded[MAX_PATH];
MSIRECORD *row;
int depth;
+ DWORD sz, attr;
UINT rc;
TRACE("%s\n", debugstr_w(sig->Name));
- msi_free(sig->File);
- sig->File = NULL;
-
*appValue = NULL;
row = MSI_QueryGetRecord( package->db, query, sig->Name );
}
/* check whether parent is set */
- parentName = msi_dup_record_field(row,2);
+ parentName = MSI_RecordGetString(row, 2);
if (parentName)
{
MSISIGNATURE parentSig;
rc = ACTION_AppSearchSigName(package, parentName, &parentSig, &parent);
ACTION_FreeSignature(&parentSig);
- msi_free(parentName);
+ if (!parent)
+ {
+ msiobj_release(&row->hdr);
+ return ERROR_SUCCESS;
+ }
}
- /* now look for path */
- path = msi_dup_record_field(row,3);
+
+ sz = MAX_PATH;
+ MSI_RecordGetStringW(row, 3, path, &sz);
+
if (MSI_RecordIsNull(row,4))
depth = 0;
else
depth = MSI_RecordGetInteger(row,4);
- ACTION_ExpandAnyPath(package, path, expanded, MAX_PATH);
- msi_free(path);
+
+ if (sz)
+ ACTION_ExpandAnyPath(package, path, expanded, MAX_PATH);
+ else
+ strcpyW(expanded, path);
+
if (parent)
{
- path = msi_alloc((strlenW(parent) + strlenW(expanded) + 1) * sizeof(WCHAR));
- if (!path)
+ attr = GetFileAttributesW(parent);
+ if (attr != INVALID_FILE_ATTRIBUTES &&
+ !(attr & FILE_ATTRIBUTE_DIRECTORY))
{
- rc = ERROR_OUTOFMEMORY;
- goto end;
+ PathRemoveFileSpecW(parent);
+ PathAddBackslashW(parent);
}
+
strcpyW(path, parent);
strcatW(path, expanded);
}
- else
- path = expanded;
+ else if (sz)
+ strcpyW(path, expanded);
+
+ PathAddBackslashW(path);
rc = ACTION_SearchDirectory(package, sig, path, depth, appValue);
-end:
- if (path != expanded)
- msi_free(path);
msi_free(parent);
msiobj_release(&row->hdr);
static UINT iterate_appsearch(MSIRECORD *row, LPVOID param)
{
MSIPACKAGE *package = param;
- LPWSTR propName, sigName, value = NULL;
+ LPCWSTR propName, sigName;
+ LPWSTR value = NULL;
MSISIGNATURE sig;
+ MSIRECORD *uirow;
UINT r;
/* get property and signature */
- propName = msi_dup_record_field(row,1);
- sigName = msi_dup_record_field(row,2);
+ propName = MSI_RecordGetString(row, 1);
+ sigName = MSI_RecordGetString(row, 2);
TRACE("%s %s\n", debugstr_w(propName), debugstr_w(sigName));
r = ACTION_AppSearchSigName(package, sigName, &sig, &value);
if (value)
{
- MSI_SetPropertyW(package, propName, value);
+ r = msi_set_property( package->db, propName, value );
+ if (r == ERROR_SUCCESS && !strcmpW( propName, cszSourceDir ))
+ msi_reset_folders( package, TRUE );
+
msi_free(value);
}
ACTION_FreeSignature(&sig);
- msi_free(propName);
- msi_free(sigName);
+
+ uirow = MSI_CreateRecord( 2 );
+ MSI_RecordSetStringW( uirow, 1, propName );
+ MSI_RecordSetStringW( uirow, 2, sigName );
+ ui_actiondata( package, szAppSearch, uirow );
+ msiobj_release( &uirow->hdr );
return r;
}
MSIQUERY *view = NULL;
UINT r;
+ if (check_unique_action(package, szAppSearch))
+ {
+ TRACE("Skipping AppSearch action: already done in UI sequence\n");
+ return ERROR_SUCCESS;
+ }
+ else
+ register_unique_action(package, szAppSearch);
+
r = MSI_OpenQuery( package->db, &view, query );
if (r != ERROR_SUCCESS)
return ERROR_SUCCESS;
UINT r = ERROR_SUCCESS;
static const WCHAR success[] = {'C','C','P','_','S','u','c','c','e','s','s',0};
- static const WCHAR one[] = {'1',0};
signature = MSI_RecordGetString(row, 1);
if (value)
{
TRACE("Found signature %s\n", debugstr_w(signature));
- MSI_SetPropertyW(package, success, one);
+ msi_set_property(package->db, success, szOne);
msi_free(value);
r = ERROR_NO_MORE_ITEMS;
}
MSIQUERY *view = NULL;
UINT r;
+ if (check_unique_action(package, szCCPSearch))
+ {
+ TRACE("Skipping AppSearch action: already done in UI sequence\n");
+ return ERROR_SUCCESS;
+ }
+ else
+ register_unique_action(package, szCCPSearch);
+
r = MSI_OpenQuery(package->db, &view, query);
if (r != ERROR_SUCCESS)
return ERROR_SUCCESS;