mirror of
https://github.com/reactos/reactos.git
synced 2025-02-23 00:45:24 +00:00
sync msi with wine 1.1.11
svn path=/trunk/; revision=38391
This commit is contained in:
parent
9776114e82
commit
6631d1c7cf
45 changed files with 4903 additions and 2393 deletions
File diff suppressed because it is too large
Load diff
|
@ -242,6 +242,7 @@ static const MSIVIEWOPS alter_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
UINT ALTER_CreateView( MSIDATABASE *db, MSIVIEW **view, LPCWSTR name, column_info *colinfo, int hold )
|
||||
|
|
|
@ -155,6 +155,73 @@ static void ACTION_FreeSignature(MSISIGNATURE *sig)
|
|||
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;
|
||||
|
||||
static const WCHAR root[] = {'\\',0};
|
||||
|
||||
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, root, (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[] = {
|
||||
|
@ -211,7 +278,7 @@ static UINT ACTION_AppSearchComponents(MSIPACKAGE *package, LPWSTR *appValue, MS
|
|||
|
||||
if (type != msidbLocatorTypeDirectory && sigpresent && !isdir)
|
||||
{
|
||||
*appValue = strdupW(path);
|
||||
*appValue = app_search_file(path, sig);
|
||||
}
|
||||
else if (!sigpresent && (type != msidbLocatorTypeDirectory || isdir))
|
||||
{
|
||||
|
@ -225,6 +292,15 @@ static UINT ACTION_AppSearchComponents(MSIPACKAGE *package, LPWSTR *appValue, MS
|
|||
|
||||
*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);
|
||||
|
@ -236,8 +312,9 @@ static void ACTION_ConvertRegValue(DWORD regType, const BYTE *value, DWORD sz,
|
|||
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)
|
||||
|
@ -264,15 +341,17 @@ static void ACTION_ConvertRegValue(DWORD regType, const BYTE *value, DWORD sz,
|
|||
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);
|
||||
|
@ -293,6 +372,7 @@ static UINT ACTION_AppSearchReg(MSIPACKAGE *package, LPWSTR *appValue, MSISIGNAT
|
|||
'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;
|
||||
|
@ -365,13 +445,18 @@ static UINT ACTION_AppSearchReg(MSIPACKAGE *package, LPWSTR *appValue, MSISIGNAT
|
|||
if (sz == 0)
|
||||
goto end;
|
||||
|
||||
if ((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);
|
||||
|
@ -393,6 +478,32 @@ 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)
|
||||
{
|
||||
|
@ -434,13 +545,13 @@ static UINT ACTION_AppSearchIni(MSIPACKAGE *package, LPWSTR *appValue,
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
@ -483,7 +594,7 @@ static void ACTION_ExpandAnyPath(MSIPACKAGE *package, WCHAR *src, WCHAR *dst,
|
|||
ptr = src;
|
||||
|
||||
deformat_string(package, ptr, &deformatted);
|
||||
if (!deformatted || lstrlenW(deformatted) > len - 1)
|
||||
if (!deformatted || strlenW(deformatted) > len - 1)
|
||||
{
|
||||
msi_free(deformatted);
|
||||
return;
|
||||
|
@ -546,11 +657,12 @@ static UINT ACTION_FileVersionMatches(const MSISIGNATURE *sig, LPCWSTR filePath,
|
|||
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),
|
||||
|
@ -622,79 +734,92 @@ static UINT ACTION_FileMatchesSig(const MSISIGNATURE *sig,
|
|||
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;
|
||||
|
||||
static const WCHAR dot[] = {'.',0};
|
||||
static const WCHAR dotdot[] = {'.','.',0};
|
||||
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;
|
||||
buf = msi_alloc( (dirLen + max(fileLen, strlenW(starDotStarW)) + 2) * 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)
|
||||
{
|
||||
lstrcpyW(buf, dir);
|
||||
PathAddBackslashW(buf);
|
||||
lstrcatW(buf, starDotStarW);
|
||||
|
||||
hFind = FindFirstFileW(buf, &findData);
|
||||
if (hFind != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
|
||||
lstrcmpW(findData.cFileName, dot) &&
|
||||
lstrcmpW(findData.cFileName, dotdot))
|
||||
{
|
||||
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, dot) ||
|
||||
!lstrcmpW(findData.cFileName, dotdot))
|
||||
continue;
|
||||
|
||||
lstrcpyW(subpath, dir);
|
||||
PathAppendW(subpath, findData.cFileName);
|
||||
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
rc = ACTION_RecurseSearchDirectory(package, appValue,
|
||||
sig, subpath, depth - 1);
|
||||
}
|
||||
|
||||
FindClose(hFind);
|
||||
}
|
||||
if (rc == ERROR_SUCCESS && !*appValue && depth > 0)
|
||||
{
|
||||
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)
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (!*appValue)
|
||||
msi_free(buf);
|
||||
}
|
||||
else
|
||||
rc = ERROR_OUTOFMEMORY;
|
||||
|
||||
if (!*appValue)
|
||||
msi_free(buf);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -731,20 +856,22 @@ static UINT ACTION_SearchDirectory(MSIPACKAGE *package, MSISIGNATURE *sig,
|
|||
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
|
||||
|
@ -754,24 +881,39 @@ static UINT ACTION_SearchDirectory(MSIPACKAGE *package, MSISIGNATURE *sig,
|
|||
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 & 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;
|
||||
}
|
||||
|
@ -787,17 +929,16 @@ static UINT ACTION_AppSearchDr(MSIPACKAGE *package, LPWSTR *appValue, MSISIGNATU
|
|||
'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 parentName = NULL, parent = NULL;
|
||||
WCHAR path[MAX_PATH];
|
||||
WCHAR expanded[MAX_PATH];
|
||||
MSIRECORD *row;
|
||||
int depth;
|
||||
DWORD sz;
|
||||
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 );
|
||||
|
@ -817,33 +958,35 @@ static UINT ACTION_AppSearchDr(MSIPACKAGE *package, LPWSTR *appValue, MSISIGNATU
|
|||
ACTION_FreeSignature(&parentSig);
|
||||
msi_free(parentName);
|
||||
}
|
||||
/* 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 (parent)
|
||||
{
|
||||
path = msi_alloc((strlenW(parent) + strlenW(expanded) + 1) * sizeof(WCHAR));
|
||||
if (!path)
|
||||
if (!(GetFileAttributesW(parent) & FILE_ATTRIBUTE_DIRECTORY))
|
||||
{
|
||||
rc = ERROR_OUTOFMEMORY;
|
||||
goto end;
|
||||
PathRemoveFileSpecW(parent);
|
||||
PathAddBackslashW(parent);
|
||||
}
|
||||
|
||||
strcpyW(path, parent);
|
||||
strcatW(path, expanded);
|
||||
}
|
||||
else
|
||||
path = expanded;
|
||||
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);
|
||||
|
||||
|
|
|
@ -336,7 +336,7 @@ static HRESULT WINAPI AutomationObject_GetIDsOfNames(
|
|||
hr = ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId);
|
||||
if (hr == DISP_E_UNKNOWNNAME)
|
||||
{
|
||||
int idx;
|
||||
UINT idx;
|
||||
for (idx=0; idx<cNames; idx++)
|
||||
{
|
||||
if (rgDispId[idx] == DISPID_UNKNOWN)
|
||||
|
@ -441,7 +441,7 @@ static HRESULT WINAPI AutomationObject_Invoke(
|
|||
if (pVarResult == &varResultDummy) VariantClear(pVarResult);
|
||||
|
||||
/* Free function name if we retrieved it */
|
||||
if (bstrName) SysFreeString(bstrName);
|
||||
SysFreeString(bstrName);
|
||||
|
||||
TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
|
||||
|
||||
|
@ -618,7 +618,7 @@ static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
|
|||
static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
|
||||
{
|
||||
ListEnumerator *This = (ListEnumerator *)iface;
|
||||
ListData *data = (ListData *)private_data(This->pObj);
|
||||
ListData *data = private_data(This->pObj);
|
||||
ULONG idx, local;
|
||||
|
||||
TRACE("(%p,%uld,%p,%p)\n", iface, celt, rgVar, pCeltFetched);
|
||||
|
@ -645,7 +645,7 @@ static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIA
|
|||
static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt)
|
||||
{
|
||||
ListEnumerator *This = (ListEnumerator *)iface;
|
||||
ListData *data = (ListData *)private_data(This->pObj);
|
||||
ListData *data = private_data(This->pObj);
|
||||
|
||||
TRACE("(%p,%uld)\n", iface, celt);
|
||||
|
||||
|
@ -708,7 +708,7 @@ static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl =
|
|||
/* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
|
||||
This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
|
||||
using DispGetParam/VariantChangeType. */
|
||||
static HRESULT WINAPI DispGetParam_CopyOnly(
|
||||
static HRESULT DispGetParam_CopyOnly(
|
||||
DISPPARAMS *pdispparams, /* [in] Parameter list */
|
||||
UINT *position, /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
|
||||
VARIANT *pvarResult) /* [out] Destination for resulting variant */
|
||||
|
@ -988,7 +988,7 @@ static HRESULT WINAPI ListImpl_Invoke(
|
|||
EXCEPINFO* pExcepInfo,
|
||||
UINT* puArgErr)
|
||||
{
|
||||
ListData *data = (ListData *)private_data(This);
|
||||
ListData *data = private_data(This);
|
||||
HRESULT hr;
|
||||
VARIANTARG varg0;
|
||||
IUnknown *pUnk = NULL;
|
||||
|
@ -1868,7 +1868,7 @@ static HRESULT WINAPI InstallerImpl_Invoke(
|
|||
V_DISPATCH(pVarResult) = pDispatch;
|
||||
|
||||
/* Save product strings */
|
||||
ldata = (ListData *)private_data((AutomationObject *)pDispatch);
|
||||
ldata = private_data((AutomationObject *)pDispatch);
|
||||
if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx)))
|
||||
ERR("Out of memory\n");
|
||||
else
|
||||
|
@ -1914,7 +1914,7 @@ static HRESULT WINAPI InstallerImpl_Invoke(
|
|||
V_DISPATCH(pVarResult) = pDispatch;
|
||||
|
||||
/* Save product strings */
|
||||
ldata = (ListData *)private_data((AutomationObject *)pDispatch);
|
||||
ldata = private_data((AutomationObject *)pDispatch);
|
||||
if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx)))
|
||||
ERR("Out of memory\n");
|
||||
else
|
||||
|
|
|
@ -461,6 +461,9 @@ static MSIEXTENSION *load_given_extension( MSIPACKAGE *package, LPCWSTR name )
|
|||
if (!name)
|
||||
return NULL;
|
||||
|
||||
if (name[0] == '.')
|
||||
name++;
|
||||
|
||||
/* check for extensions already loaded */
|
||||
LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry )
|
||||
{
|
||||
|
|
|
@ -137,6 +137,7 @@ static const MSIVIEWOPS create_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static UINT check_columns( column_info *col_info )
|
||||
|
@ -157,7 +158,7 @@ UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
|
|||
{
|
||||
MSICREATEVIEW *cv = NULL;
|
||||
UINT r;
|
||||
const column_info *col;
|
||||
column_info *col;
|
||||
BOOL temp = TRUE;
|
||||
|
||||
TRACE("%p\n", cv );
|
||||
|
@ -171,11 +172,13 @@ UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
|
|||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
for( col = col_info; col; col = col->next )
|
||||
{
|
||||
if (!col->table)
|
||||
col->table = strdupW(table);
|
||||
|
||||
if( !col->temporary )
|
||||
{
|
||||
temp = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* fill the structure */
|
||||
cv->view.ops = &create_ops;
|
||||
|
|
|
@ -659,7 +659,7 @@ static UINT get_action_info( const GUID *guid, INT *type, MSIHANDLE *handle,
|
|||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static DWORD WINAPI ACTION_CallDllFunction( const GUID *guid )
|
||||
static DWORD ACTION_CallDllFunction( const GUID *guid )
|
||||
{
|
||||
MsiCustomActionEntryPoint fn;
|
||||
MSIHANDLE hPackage, handle;
|
||||
|
@ -744,7 +744,7 @@ static DWORD WINAPI DllThread( LPVOID arg )
|
|||
return rc;
|
||||
}
|
||||
|
||||
static DWORD WINAPI ACTION_CAInstallPackage(const GUID *guid)
|
||||
static DWORD ACTION_CAInstallPackage(const GUID *guid)
|
||||
{
|
||||
msi_custom_action_info *info;
|
||||
UINT r = ERROR_FUNCTION_FAILED;
|
||||
|
@ -1147,7 +1147,7 @@ static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source,
|
|||
return wait_process_handle(package, type, info.hProcess, action);
|
||||
}
|
||||
|
||||
static DWORD WINAPI ACTION_CallScript( const GUID *guid )
|
||||
static DWORD ACTION_CallScript( const GUID *guid )
|
||||
{
|
||||
msi_custom_action_info *info;
|
||||
MSIHANDLE hPackage;
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "objidl.h"
|
||||
#include "objbase.h"
|
||||
#include "msiserver.h"
|
||||
#include "query.h"
|
||||
|
||||
#include "initguid.h"
|
||||
|
||||
|
@ -125,7 +126,7 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
|
|||
IStorage_SetClass( stg, &CLSID_MsiDatabase );
|
||||
/* create the _Tables stream */
|
||||
r = write_stream_data(stg, szTables, NULL, 0, TRUE);
|
||||
if (!FAILED(r))
|
||||
if (SUCCEEDED(r))
|
||||
r = msi_init_string_table( stg );
|
||||
}
|
||||
created = TRUE;
|
||||
|
@ -204,7 +205,6 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
|
|||
if( !db->strings )
|
||||
goto end;
|
||||
|
||||
msi_table_set_strref( db->bytes_per_strref );
|
||||
ret = ERROR_SUCCESS;
|
||||
|
||||
msiobj_addref( &db->hdr );
|
||||
|
@ -557,25 +557,16 @@ static UINT msi_add_records_to_table(MSIDATABASE *db, LPWSTR *columns, LPWSTR *t
|
|||
int num_columns, int num_records)
|
||||
{
|
||||
UINT r;
|
||||
DWORD i, size;
|
||||
int i;
|
||||
MSIQUERY *view;
|
||||
MSIRECORD *rec;
|
||||
LPWSTR query;
|
||||
|
||||
static const WCHAR select[] = {
|
||||
'S','E','L','E','C','T',' ','*',' ',
|
||||
'F','R','O','M',' ','`','%','s','`',0
|
||||
};
|
||||
|
||||
size = lstrlenW(select) + lstrlenW(labels[0]) - 1;
|
||||
query = msi_alloc(size * sizeof(WCHAR));
|
||||
if (!query)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
sprintfW(query, select, labels[0]);
|
||||
|
||||
r = MSI_DatabaseOpenViewW(db, query, &view);
|
||||
msi_free(query);
|
||||
r = MSI_OpenQuery(db, &view, select, labels[0]);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
|
@ -984,6 +975,514 @@ end:
|
|||
return r;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiDatabaseMergeA(MSIHANDLE hDatabase, MSIHANDLE hDatabaseMerge,
|
||||
LPCSTR szTableName)
|
||||
{
|
||||
UINT r;
|
||||
LPWSTR table;
|
||||
|
||||
TRACE("(%ld, %ld, %s)\n", hDatabase, hDatabaseMerge,
|
||||
debugstr_a(szTableName));
|
||||
|
||||
table = strdupAtoW(szTableName);
|
||||
r = MsiDatabaseMergeW(hDatabase, hDatabaseMerge, table);
|
||||
|
||||
msi_free(table);
|
||||
return r;
|
||||
}
|
||||
|
||||
typedef struct _tagMERGETABLE
|
||||
{
|
||||
struct list entry;
|
||||
struct list rows;
|
||||
LPWSTR name;
|
||||
DWORD numconflicts;
|
||||
} MERGETABLE;
|
||||
|
||||
typedef struct _tagMERGEROW
|
||||
{
|
||||
struct list entry;
|
||||
MSIRECORD *data;
|
||||
} MERGEROW;
|
||||
|
||||
typedef struct _tagMERGEDATA
|
||||
{
|
||||
MSIDATABASE *db;
|
||||
MSIDATABASE *merge;
|
||||
MERGETABLE *curtable;
|
||||
MSIQUERY *curview;
|
||||
struct list *tabledata;
|
||||
} MERGEDATA;
|
||||
|
||||
static UINT merge_verify_colnames(MSIQUERY *dbview, MSIQUERY *mergeview)
|
||||
{
|
||||
MSIRECORD *dbrec, *mergerec;
|
||||
UINT r, i, count;
|
||||
|
||||
r = MSI_ViewGetColumnInfo(dbview, MSICOLINFO_NAMES, &dbrec);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
r = MSI_ViewGetColumnInfo(mergeview, MSICOLINFO_NAMES, &mergerec);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
count = MSI_RecordGetFieldCount(dbrec);
|
||||
for (i = 1; i <= count; i++)
|
||||
{
|
||||
if (!MSI_RecordGetString(mergerec, i))
|
||||
break;
|
||||
|
||||
if (lstrcmpW(MSI_RecordGetString(dbrec, i),
|
||||
MSI_RecordGetString(mergerec, i)))
|
||||
{
|
||||
r = ERROR_DATATYPE_MISMATCH;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
msiobj_release(&dbrec->hdr);
|
||||
msiobj_release(&mergerec->hdr);
|
||||
dbrec = mergerec = NULL;
|
||||
|
||||
r = MSI_ViewGetColumnInfo(dbview, MSICOLINFO_TYPES, &dbrec);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
r = MSI_ViewGetColumnInfo(mergeview, MSICOLINFO_TYPES, &mergerec);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
count = MSI_RecordGetFieldCount(dbrec);
|
||||
for (i = 1; i <= count; i++)
|
||||
{
|
||||
if (!MSI_RecordGetString(mergerec, i))
|
||||
break;
|
||||
|
||||
if (lstrcmpW(MSI_RecordGetString(dbrec, i),
|
||||
MSI_RecordGetString(mergerec, i)))
|
||||
{
|
||||
r = ERROR_DATATYPE_MISMATCH;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
msiobj_release(&dbrec->hdr);
|
||||
msiobj_release(&mergerec->hdr);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static UINT merge_verify_primary_keys(MSIDATABASE *db, MSIDATABASE *mergedb,
|
||||
LPCWSTR table)
|
||||
{
|
||||
MSIRECORD *dbrec, *mergerec = NULL;
|
||||
UINT r, i, count;
|
||||
|
||||
r = MSI_DatabaseGetPrimaryKeys(db, table, &dbrec);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
r = MSI_DatabaseGetPrimaryKeys(mergedb, table, &mergerec);
|
||||
if (r != ERROR_SUCCESS)
|
||||
goto done;
|
||||
|
||||
count = MSI_RecordGetFieldCount(dbrec);
|
||||
if (count != MSI_RecordGetFieldCount(mergerec))
|
||||
{
|
||||
r = ERROR_DATATYPE_MISMATCH;
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i = 1; i <= count; i++)
|
||||
{
|
||||
if (lstrcmpW(MSI_RecordGetString(dbrec, i),
|
||||
MSI_RecordGetString(mergerec, i)))
|
||||
{
|
||||
r = ERROR_DATATYPE_MISMATCH;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
msiobj_release(&dbrec->hdr);
|
||||
msiobj_release(&mergerec->hdr);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static LPWSTR get_key_value(MSIQUERY *view, LPCWSTR key, MSIRECORD *rec)
|
||||
{
|
||||
MSIRECORD *colnames;
|
||||
LPWSTR str;
|
||||
UINT r, i = 0;
|
||||
int cmp;
|
||||
|
||||
r = MSI_ViewGetColumnInfo(view, MSICOLINFO_NAMES, &colnames);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return NULL;
|
||||
|
||||
do
|
||||
{
|
||||
str = msi_dup_record_field(colnames, ++i);
|
||||
cmp = lstrcmpW(key, str);
|
||||
msi_free(str);
|
||||
} while (cmp);
|
||||
|
||||
msiobj_release(&colnames->hdr);
|
||||
return msi_dup_record_field(rec, i);
|
||||
}
|
||||
|
||||
static LPWSTR create_diff_row_query(MSIDATABASE *merge, MSIQUERY *view,
|
||||
LPWSTR table, MSIRECORD *rec)
|
||||
{
|
||||
LPWSTR query = NULL, clause = NULL;
|
||||
LPWSTR ptr = NULL, val;
|
||||
LPCWSTR setptr;
|
||||
DWORD size = 1, oldsize;
|
||||
LPCWSTR key;
|
||||
MSIRECORD *keys;
|
||||
UINT r, i, count;
|
||||
|
||||
static const WCHAR keyset[] = {
|
||||
'`','%','s','`',' ','=',' ','%','s',' ','A','N','D',' ',0};
|
||||
static const WCHAR lastkeyset[] = {
|
||||
'`','%','s','`',' ','=',' ','%','s',' ',0};
|
||||
static const WCHAR fmt[] = {'S','E','L','E','C','T',' ','*',' ',
|
||||
'F','R','O','M',' ','`','%','s','`',' ',
|
||||
'W','H','E','R','E',' ','%','s',0};
|
||||
|
||||
r = MSI_DatabaseGetPrimaryKeys(merge, table, &keys);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return NULL;
|
||||
|
||||
clause = msi_alloc_zero(size * sizeof(WCHAR));
|
||||
if (!clause)
|
||||
goto done;
|
||||
|
||||
ptr = clause;
|
||||
count = MSI_RecordGetFieldCount(keys);
|
||||
for (i = 1; i <= count; i++)
|
||||
{
|
||||
key = MSI_RecordGetString(keys, i);
|
||||
val = get_key_value(view, key, rec);
|
||||
|
||||
if (i == count)
|
||||
setptr = lastkeyset;
|
||||
else
|
||||
setptr = keyset;
|
||||
|
||||
oldsize = size;
|
||||
size += lstrlenW(setptr) + lstrlenW(key) + lstrlenW(val) - 4;
|
||||
clause = msi_realloc(clause, size * sizeof (WCHAR));
|
||||
if (!clause)
|
||||
{
|
||||
msi_free(val);
|
||||
goto done;
|
||||
}
|
||||
|
||||
ptr = clause + oldsize - 1;
|
||||
sprintfW(ptr, setptr, key, val);
|
||||
msi_free(val);
|
||||
}
|
||||
|
||||
size = lstrlenW(fmt) + lstrlenW(table) + lstrlenW(clause) + 1;
|
||||
query = msi_alloc(size * sizeof(WCHAR));
|
||||
if (!query)
|
||||
goto done;
|
||||
|
||||
sprintfW(query, fmt, table, clause);
|
||||
|
||||
done:
|
||||
msi_free(clause);
|
||||
msiobj_release(&keys->hdr);
|
||||
return query;
|
||||
}
|
||||
|
||||
static UINT merge_diff_row(MSIRECORD *rec, LPVOID param)
|
||||
{
|
||||
MERGEDATA *data = (MERGEDATA *)param;
|
||||
MERGETABLE *table = data->curtable;
|
||||
MERGEROW *mergerow;
|
||||
MSIQUERY *dbview;
|
||||
MSIRECORD *row;
|
||||
LPWSTR query;
|
||||
UINT r;
|
||||
|
||||
query = create_diff_row_query(data->merge, data->curview, table->name, rec);
|
||||
if (!query)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
r = MSI_DatabaseOpenViewW(data->db, query, &dbview);
|
||||
if (r != ERROR_SUCCESS)
|
||||
goto done;
|
||||
|
||||
r = MSI_ViewExecute(dbview, NULL);
|
||||
if (r != ERROR_SUCCESS)
|
||||
goto done;
|
||||
|
||||
r = MSI_ViewFetch(dbview, &row);
|
||||
if (r == ERROR_SUCCESS && !MSI_RecordsAreEqual(rec, row))
|
||||
{
|
||||
table->numconflicts++;
|
||||
goto done;
|
||||
}
|
||||
else if (r != ERROR_NO_MORE_ITEMS)
|
||||
goto done;
|
||||
|
||||
mergerow = msi_alloc(sizeof(MERGEROW));
|
||||
if (!mergerow)
|
||||
{
|
||||
r = ERROR_OUTOFMEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
mergerow->data = MSI_CloneRecord(rec);
|
||||
if (!mergerow->data)
|
||||
{
|
||||
r = ERROR_OUTOFMEMORY;
|
||||
msi_free(mergerow);
|
||||
goto done;
|
||||
}
|
||||
|
||||
list_add_tail(&table->rows, &mergerow->entry);
|
||||
|
||||
done:
|
||||
msi_free(query);
|
||||
msiobj_release(&row->hdr);
|
||||
msiobj_release(&dbview->hdr);
|
||||
return r;
|
||||
}
|
||||
|
||||
static UINT merge_diff_tables(MSIRECORD *rec, LPVOID param)
|
||||
{
|
||||
MERGEDATA *data = (MERGEDATA *)param;
|
||||
MERGETABLE *table;
|
||||
MSIQUERY *dbview;
|
||||
MSIQUERY *mergeview = NULL;
|
||||
LPCWSTR name;
|
||||
UINT r;
|
||||
|
||||
static const WCHAR query[] = {'S','E','L','E','C','T',' ','*',' ',
|
||||
'F','R','O','M',' ','`','%','s','`',0};
|
||||
|
||||
name = MSI_RecordGetString(rec, 1);
|
||||
|
||||
r = MSI_OpenQuery(data->db, &dbview, query, name);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
r = MSI_OpenQuery(data->merge, &mergeview, query, name);
|
||||
if (r != ERROR_SUCCESS)
|
||||
goto done;
|
||||
|
||||
r = merge_verify_colnames(dbview, mergeview);
|
||||
if (r != ERROR_SUCCESS)
|
||||
goto done;
|
||||
|
||||
r = merge_verify_primary_keys(data->db, data->merge, name);
|
||||
if (r != ERROR_SUCCESS)
|
||||
goto done;
|
||||
|
||||
table = msi_alloc(sizeof(MERGETABLE));
|
||||
if (!table)
|
||||
{
|
||||
r = ERROR_OUTOFMEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
list_init(&table->rows);
|
||||
table->name = strdupW(name);
|
||||
table->numconflicts = 0;
|
||||
data->curtable = table;
|
||||
data->curview = mergeview;
|
||||
|
||||
r = MSI_IterateRecords(mergeview, NULL, merge_diff_row, data);
|
||||
if (r != ERROR_SUCCESS)
|
||||
{
|
||||
msi_free(table->name);
|
||||
msi_free(table);
|
||||
goto done;
|
||||
}
|
||||
|
||||
list_add_tail(data->tabledata, &table->entry);
|
||||
|
||||
done:
|
||||
msiobj_release(&dbview->hdr);
|
||||
msiobj_release(&mergeview->hdr);
|
||||
return r;
|
||||
}
|
||||
|
||||
static UINT gather_merge_data(MSIDATABASE *db, MSIDATABASE *merge,
|
||||
struct list *tabledata)
|
||||
{
|
||||
UINT r;
|
||||
MSIQUERY *view;
|
||||
MERGEDATA data;
|
||||
|
||||
static const WCHAR query[] = {'S','E','L','E','C','T',' ','*',' ',
|
||||
'F','R','O','M',' ','`','_','T','a','b','l','e','s','`',0};
|
||||
|
||||
r = MSI_DatabaseOpenViewW(merge, query, &view);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
data.db = db;
|
||||
data.merge = merge;
|
||||
data.tabledata = tabledata;
|
||||
r = MSI_IterateRecords(view, NULL, merge_diff_tables, &data);
|
||||
|
||||
msiobj_release(&view->hdr);
|
||||
return r;
|
||||
}
|
||||
|
||||
static UINT merge_table(MSIDATABASE *db, MERGETABLE *table)
|
||||
{
|
||||
UINT r;
|
||||
MERGEROW *row;
|
||||
MSIVIEW *tv;
|
||||
|
||||
LIST_FOR_EACH_ENTRY(row, &table->rows, MERGEROW, entry)
|
||||
{
|
||||
r = TABLE_CreateView(db, table->name, &tv);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
r = tv->ops->insert_row(tv, row->data, FALSE);
|
||||
tv->ops->delete(tv);
|
||||
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT update_merge_errors(MSIDATABASE *db, LPCWSTR error,
|
||||
LPWSTR table, DWORD numconflicts)
|
||||
{
|
||||
UINT r;
|
||||
MSIQUERY *view;
|
||||
|
||||
static const WCHAR create[] = {
|
||||
'C','R','E','A','T','E',' ','T','A','B','L','E',' ',
|
||||
'`','%','s','`',' ','(','`','T','a','b','l','e','`',' ',
|
||||
'C','H','A','R','(','2','5','5',')',' ','N','O','T',' ',
|
||||
'N','U','L','L',',',' ','`','N','u','m','R','o','w','M','e','r','g','e',
|
||||
'C','o','n','f','l','i','c','t','s','`',' ','S','H','O','R','T',' ',
|
||||
'N','O','T',' ','N','U','L','L',' ','P','R','I','M','A','R','Y',' ',
|
||||
'K','E','Y',' ','`','T','a','b','l','e','`',')',0};
|
||||
static const WCHAR insert[] = {
|
||||
'I','N','S','E','R','T',' ','I','N','T','O',' ',
|
||||
'`','%','s','`',' ','(','`','T','a','b','l','e','`',',',' ',
|
||||
'`','N','u','m','R','o','w','M','e','r','g','e',
|
||||
'C','o','n','f','l','i','c','t','s','`',')',' ','V','A','L','U','E','S',
|
||||
' ','(','\'','%','s','\'',',',' ','%','d',')',0};
|
||||
|
||||
if (!TABLE_Exists(db, error))
|
||||
{
|
||||
r = MSI_OpenQuery(db, &view, create, error);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
r = MSI_ViewExecute(view, NULL);
|
||||
msiobj_release(&view->hdr);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = MSI_OpenQuery(db, &view, insert, error, table, numconflicts);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
r = MSI_ViewExecute(view, NULL);
|
||||
msiobj_release(&view->hdr);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void merge_free_rows(MERGETABLE *table)
|
||||
{
|
||||
struct list *item, *cursor;
|
||||
|
||||
LIST_FOR_EACH_SAFE(item, cursor, &table->rows)
|
||||
{
|
||||
MERGEROW *row = LIST_ENTRY(item, MERGEROW, entry);
|
||||
|
||||
list_remove(&row->entry);
|
||||
merge_free_rows(table);
|
||||
msiobj_release(&row->data->hdr);
|
||||
msi_free(row);
|
||||
}
|
||||
}
|
||||
|
||||
UINT WINAPI MsiDatabaseMergeW(MSIHANDLE hDatabase, MSIHANDLE hDatabaseMerge,
|
||||
LPCWSTR szTableName)
|
||||
{
|
||||
struct list tabledata = LIST_INIT(tabledata);
|
||||
struct list *item, *cursor;
|
||||
MSIDATABASE *db, *merge;
|
||||
MERGETABLE *table;
|
||||
BOOL conflicts;
|
||||
UINT r;
|
||||
|
||||
TRACE("(%ld, %ld, %s)\n", hDatabase, hDatabaseMerge,
|
||||
debugstr_w(szTableName));
|
||||
|
||||
if (szTableName && !*szTableName)
|
||||
return ERROR_INVALID_TABLE;
|
||||
|
||||
db = msihandle2msiinfo(hDatabase, MSIHANDLETYPE_DATABASE);
|
||||
merge = msihandle2msiinfo(hDatabaseMerge, MSIHANDLETYPE_DATABASE);
|
||||
if (!db || !merge)
|
||||
{
|
||||
r = ERROR_INVALID_HANDLE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
r = gather_merge_data(db, merge, &tabledata);
|
||||
if (r != ERROR_SUCCESS)
|
||||
goto done;
|
||||
|
||||
conflicts = FALSE;
|
||||
LIST_FOR_EACH_ENTRY(table, &tabledata, MERGETABLE, entry)
|
||||
{
|
||||
if (table->numconflicts)
|
||||
{
|
||||
conflicts = TRUE;
|
||||
|
||||
r = update_merge_errors(db, szTableName, table->name,
|
||||
table->numconflicts);
|
||||
if (r != ERROR_SUCCESS)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = merge_table(db, table);
|
||||
if (r != ERROR_SUCCESS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LIST_FOR_EACH_SAFE(item, cursor, &tabledata)
|
||||
{
|
||||
MERGETABLE *table = LIST_ENTRY(item, MERGETABLE, entry);
|
||||
|
||||
list_remove(&table->entry);
|
||||
merge_free_rows(table);
|
||||
msi_free(table->name);
|
||||
msi_free(table);
|
||||
}
|
||||
|
||||
if (conflicts)
|
||||
r = ERROR_FUNCTION_FAILED;
|
||||
|
||||
done:
|
||||
msiobj_release(&db->hdr);
|
||||
msiobj_release(&merge->hdr);
|
||||
return r;
|
||||
}
|
||||
|
||||
MSIDBSTATE WINAPI MsiGetDatabaseState( MSIHANDLE handle )
|
||||
{
|
||||
MSIDBSTATE ret = MSIDBSTATE_READ;
|
||||
|
|
|
@ -191,7 +191,8 @@ static const MSIVIEWOPS delete_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
UINT DELETE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )
|
||||
|
|
|
@ -1204,12 +1204,15 @@ static UINT msi_dialog_combo_control( msi_dialog *dialog, MSIRECORD *rec )
|
|||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/* length of 2^32 + 1 */
|
||||
#define MAX_NUM_DIGITS 11
|
||||
|
||||
static UINT msi_dialog_edit_control( msi_dialog *dialog, MSIRECORD *rec )
|
||||
{
|
||||
msi_control *control;
|
||||
LPCWSTR prop, text;
|
||||
LPWSTR val, begin, end;
|
||||
WCHAR num[10];
|
||||
WCHAR num[MAX_NUM_DIGITS];
|
||||
DWORD limit;
|
||||
|
||||
control = msi_dialog_add_control( dialog, rec, szEdit,
|
||||
|
@ -1222,7 +1225,9 @@ static UINT msi_dialog_edit_control( msi_dialog *dialog, MSIRECORD *rec )
|
|||
begin = strchrW( text, '{' );
|
||||
end = strchrW( text, '}' );
|
||||
|
||||
if ( begin && end && end > begin )
|
||||
if ( begin && end && end > begin &&
|
||||
begin[0] >= '0' && begin[0] <= '9' &&
|
||||
end - begin < MAX_NUM_DIGITS)
|
||||
{
|
||||
lstrcpynW( num, begin + 1, end - begin );
|
||||
limit = atolW( num );
|
||||
|
@ -1383,7 +1388,7 @@ msi_maskedit_set_text( struct msi_maskedit_info *info, LPCWSTR text )
|
|||
p = text;
|
||||
for( i = 0; i < info->num_groups; i++ )
|
||||
{
|
||||
if( info->group[i].len < lstrlenW( p ) )
|
||||
if( info->group[i].len < strlenW( p ) )
|
||||
{
|
||||
LPWSTR chunk = strdupW( p );
|
||||
chunk[ info->group[i].len ] = 0;
|
||||
|
@ -1909,7 +1914,7 @@ msi_seltree_menu( HWND hwnd, HTREEITEM hItem )
|
|||
case INSTALLSTATE_LOCAL:
|
||||
case INSTALLSTATE_ADVERTISED:
|
||||
case INSTALLSTATE_ABSENT:
|
||||
msi_feature_set_state( feature, r );
|
||||
msi_feature_set_state(package, feature, r);
|
||||
break;
|
||||
default:
|
||||
FIXME("select feature and all children\n");
|
||||
|
@ -2242,6 +2247,7 @@ static UINT msi_listbox_add_items( struct msi_listbox_info *info, LPCWSTR proper
|
|||
return r;
|
||||
|
||||
/* just get the number of records */
|
||||
count = 0;
|
||||
r = MSI_IterateRecords( view, &count, NULL, NULL );
|
||||
|
||||
info->num_items = count;
|
||||
|
|
|
@ -296,6 +296,7 @@ static const MSIVIEWOPS distinct_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
DISTINCT_sort,
|
||||
NULL,
|
||||
};
|
||||
|
||||
UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )
|
||||
|
|
125
reactos/dll/win32/msi/drop.c
Normal file
125
reactos/dll/win32/msi/drop.c
Normal file
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Implementation of the Microsoft Installer (msi.dll)
|
||||
*
|
||||
* Copyright 2008 James Hawkins
|
||||
*
|
||||
* 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
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
#include "wine/debug.h"
|
||||
#include "msi.h"
|
||||
#include "msiquery.h"
|
||||
#include "objbase.h"
|
||||
#include "objidl.h"
|
||||
#include "msipriv.h"
|
||||
|
||||
#include "query.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
||||
|
||||
typedef struct tagMSIDROPVIEW
|
||||
{
|
||||
MSIVIEW view;
|
||||
MSIDATABASE *db;
|
||||
MSIVIEW *table;
|
||||
column_info *colinfo;
|
||||
INT hold;
|
||||
} MSIDROPVIEW;
|
||||
|
||||
static UINT DROP_execute(struct tagMSIVIEW *view, MSIRECORD *record)
|
||||
{
|
||||
MSIDROPVIEW *dv = (MSIDROPVIEW*)view;
|
||||
UINT r;
|
||||
|
||||
TRACE("%p %p\n", dv, record);
|
||||
|
||||
if( !dv->table )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
r = dv->table->ops->execute(dv->table, record);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
return dv->table->ops->drop(dv->table);
|
||||
}
|
||||
|
||||
static UINT DROP_close(struct tagMSIVIEW *view)
|
||||
{
|
||||
MSIDROPVIEW *dv = (MSIDROPVIEW*)view;
|
||||
|
||||
TRACE("%p\n", dv);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT DROP_get_dimensions(struct tagMSIVIEW *view, UINT *rows, UINT *cols)
|
||||
{
|
||||
MSIDROPVIEW *dv = (MSIDROPVIEW*)view;
|
||||
|
||||
TRACE("%p %p %p\n", dv, rows, cols);
|
||||
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
static const MSIVIEWOPS drop_ops =
|
||||
{
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
DROP_execute,
|
||||
DROP_close,
|
||||
DROP_get_dimensions,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
UINT DROP_CreateView(MSIDATABASE *db, MSIVIEW **view, LPCWSTR name)
|
||||
{
|
||||
MSIDROPVIEW *dv;
|
||||
UINT r;
|
||||
|
||||
TRACE("%p %s\n", view, debugstr_w(name));
|
||||
|
||||
dv = msi_alloc_zero(sizeof *dv);
|
||||
if(!dv)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
r = TABLE_CreateView(db, name, &dv->table);
|
||||
if (r != ERROR_SUCCESS || !dv->table)
|
||||
return r;
|
||||
|
||||
dv->view.ops = &drop_ops;
|
||||
dv->db = db;
|
||||
|
||||
*view = (MSIVIEW *)dv;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
|
@ -104,7 +104,7 @@ static UINT ControlEvent_EndDialog(MSIPACKAGE* package, LPCWSTR argument,
|
|||
else if (lstrcmpW(argument, szRetry) == 0)
|
||||
package->CurrentInstallState = ERROR_INSTALL_SUSPEND;
|
||||
else if (lstrcmpW(argument, szIgnore) == 0)
|
||||
package->CurrentInstallState = -1;
|
||||
package->CurrentInstallState = ERROR_SUCCESS;
|
||||
else if (lstrcmpW(argument, szReturn) == 0)
|
||||
{
|
||||
msi_dialog *parent = msi_dialog_get_parent(dialog);
|
||||
|
@ -180,7 +180,7 @@ static UINT ControlEvent_AddLocal(MSIPACKAGE* package, LPCWSTR argument,
|
|||
else
|
||||
{
|
||||
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
|
||||
msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
|
||||
msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
|
||||
|
||||
ACTION_UpdateComponentStates(package,argument);
|
||||
}
|
||||
|
@ -200,7 +200,7 @@ static UINT ControlEvent_Remove(MSIPACKAGE* package, LPCWSTR argument,
|
|||
else
|
||||
{
|
||||
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
|
||||
msi_feature_set_state( feature, INSTALLSTATE_ABSENT );
|
||||
msi_feature_set_state(package, feature, INSTALLSTATE_ABSENT);
|
||||
|
||||
ACTION_UpdateComponentStates(package,argument);
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ static UINT ControlEvent_AddSource(MSIPACKAGE* package, LPCWSTR argument,
|
|||
else
|
||||
{
|
||||
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
|
||||
msi_feature_set_state( feature, INSTALLSTATE_SOURCE );
|
||||
msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
|
||||
ACTION_UpdateComponentStates(package,argument);
|
||||
}
|
||||
return ERROR_SUCCESS;
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
#include "fdi.h"
|
||||
#include "msi.h"
|
||||
#include "msidefs.h"
|
||||
#include "msvcrt/fcntl.h"
|
||||
#include "msipriv.h"
|
||||
#include "winuser.h"
|
||||
#include "winreg.h"
|
||||
|
@ -55,183 +54,6 @@ extern const WCHAR szPatchFiles[];
|
|||
extern const WCHAR szRemoveDuplicateFiles[];
|
||||
extern const WCHAR szRemoveFiles[];
|
||||
|
||||
static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
|
||||
|
||||
static BOOL source_matches_volume(MSIMEDIAINFO *mi, LPWSTR source_root)
|
||||
{
|
||||
WCHAR volume_name[MAX_PATH + 1];
|
||||
|
||||
if (!GetVolumeInformationW(source_root, volume_name, MAX_PATH + 1,
|
||||
NULL, NULL, NULL, NULL, 0))
|
||||
{
|
||||
ERR("Failed to get volume information\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return !lstrcmpW(mi->volume_label, volume_name);
|
||||
}
|
||||
|
||||
static UINT msi_change_media( MSIPACKAGE *package, MSIMEDIAINFO *mi )
|
||||
{
|
||||
LPSTR msg;
|
||||
LPWSTR error, error_dialog;
|
||||
LPWSTR source_dir;
|
||||
UINT r = ERROR_SUCCESS;
|
||||
|
||||
static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
|
||||
static const WCHAR error_prop[] = {'E','r','r','o','r','D','i','a','l','o','g',0};
|
||||
|
||||
if ( (msi_get_property_int(package, szUILevel, 0) & INSTALLUILEVEL_MASK) == INSTALLUILEVEL_NONE && !gUIHandlerA )
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
error = generate_error_string( package, 1302, 1, mi->disk_prompt );
|
||||
error_dialog = msi_dup_property( package, error_prop );
|
||||
source_dir = msi_dup_property( package, cszSourceDir );
|
||||
PathStripToRootW(source_dir);
|
||||
|
||||
while ( r == ERROR_SUCCESS &&
|
||||
!source_matches_volume(mi, source_dir) )
|
||||
{
|
||||
r = msi_spawn_error_dialog( package, error_dialog, error );
|
||||
|
||||
if (gUIHandlerA)
|
||||
{
|
||||
msg = strdupWtoA( error );
|
||||
gUIHandlerA( gUIContext, MB_RETRYCANCEL | INSTALLMESSAGE_ERROR, msg );
|
||||
msi_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
msi_free( error );
|
||||
msi_free( error_dialog );
|
||||
msi_free( source_dir );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a helper function for handling embedded cabinet media
|
||||
*/
|
||||
static UINT writeout_cabinet_stream(MSIPACKAGE *package, LPCWSTR stream_name,
|
||||
WCHAR* source)
|
||||
{
|
||||
UINT rc;
|
||||
USHORT* data;
|
||||
UINT size;
|
||||
DWORD write;
|
||||
HANDLE the_file;
|
||||
WCHAR tmp[MAX_PATH];
|
||||
|
||||
rc = read_raw_stream_data(package->db,stream_name,&data,&size);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
return rc;
|
||||
|
||||
write = MAX_PATH;
|
||||
if (MSI_GetPropertyW(package, cszTempFolder, tmp, &write))
|
||||
GetTempPathW(MAX_PATH,tmp);
|
||||
|
||||
GetTempFileNameW(tmp,stream_name,0,source);
|
||||
|
||||
track_tempfile(package, source);
|
||||
the_file = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (the_file == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ERR("Unable to create file %s\n",debugstr_w(source));
|
||||
rc = ERROR_FUNCTION_FAILED;
|
||||
goto end;
|
||||
}
|
||||
|
||||
WriteFile(the_file,data,size,&write,NULL);
|
||||
CloseHandle(the_file);
|
||||
TRACE("wrote %i bytes to %s\n",write,debugstr_w(source));
|
||||
end:
|
||||
msi_free(data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Support functions for FDI functions */
|
||||
typedef struct
|
||||
{
|
||||
MSIPACKAGE* package;
|
||||
MSIMEDIAINFO *mi;
|
||||
} CabData;
|
||||
|
||||
static void * cabinet_alloc(ULONG cb)
|
||||
{
|
||||
return msi_alloc(cb);
|
||||
}
|
||||
|
||||
static void cabinet_free(void *pv)
|
||||
{
|
||||
msi_free(pv);
|
||||
}
|
||||
|
||||
static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode)
|
||||
{
|
||||
HANDLE handle;
|
||||
DWORD dwAccess = 0;
|
||||
DWORD dwShareMode = 0;
|
||||
DWORD dwCreateDisposition = OPEN_EXISTING;
|
||||
switch (oflag & _O_ACCMODE)
|
||||
{
|
||||
case _O_RDONLY:
|
||||
dwAccess = GENERIC_READ;
|
||||
dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;
|
||||
break;
|
||||
case _O_WRONLY:
|
||||
dwAccess = GENERIC_WRITE;
|
||||
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||
break;
|
||||
case _O_RDWR:
|
||||
dwAccess = GENERIC_READ | GENERIC_WRITE;
|
||||
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||
break;
|
||||
}
|
||||
if ((oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))
|
||||
dwCreateDisposition = CREATE_NEW;
|
||||
else if (oflag & _O_CREAT)
|
||||
dwCreateDisposition = CREATE_ALWAYS;
|
||||
handle = CreateFileA( pszFile, dwAccess, dwShareMode, NULL,
|
||||
dwCreateDisposition, 0, NULL );
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
return (INT_PTR) handle;
|
||||
}
|
||||
|
||||
static UINT cabinet_read(INT_PTR hf, void *pv, UINT cb)
|
||||
{
|
||||
HANDLE handle = (HANDLE) hf;
|
||||
DWORD dwRead;
|
||||
if (ReadFile(handle, pv, cb, &dwRead, NULL))
|
||||
return dwRead;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb)
|
||||
{
|
||||
HANDLE handle = (HANDLE) hf;
|
||||
DWORD dwWritten;
|
||||
if (WriteFile(handle, pv, cb, &dwWritten, NULL))
|
||||
return dwWritten;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cabinet_close(INT_PTR hf)
|
||||
{
|
||||
HANDLE handle = (HANDLE) hf;
|
||||
return CloseHandle(handle) ? 0 : -1;
|
||||
}
|
||||
|
||||
static long cabinet_seek(INT_PTR hf, long dist, int seektype)
|
||||
{
|
||||
HANDLE handle = (HANDLE) hf;
|
||||
/* flags are compatible and so are passed straight through */
|
||||
return SetFilePointer(handle, dist, NULL, seektype);
|
||||
}
|
||||
|
||||
static void msi_file_update_ui( MSIPACKAGE *package, MSIFILE *f, const WCHAR *action )
|
||||
{
|
||||
MSIRECORD *uirow;
|
||||
|
@ -252,213 +74,6 @@ static void msi_file_update_ui( MSIPACKAGE *package, MSIFILE *f, const WCHAR *ac
|
|||
ui_progress( package, 2, f->FileSize, 0, 0);
|
||||
}
|
||||
|
||||
static UINT msi_media_get_disk_info( MSIPACKAGE *package, MSIMEDIAINFO *mi )
|
||||
{
|
||||
MSIRECORD *row;
|
||||
LPWSTR ptr;
|
||||
|
||||
static const WCHAR query[] =
|
||||
{'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
|
||||
'`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
|
||||
'`','D','i','s','k','I','d','`',' ','=',' ','%','i',0};
|
||||
|
||||
row = MSI_QueryGetRecord(package->db, query, mi->disk_id);
|
||||
if (!row)
|
||||
{
|
||||
TRACE("Unable to query row\n");
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
mi->disk_prompt = strdupW(MSI_RecordGetString(row, 3));
|
||||
mi->cabinet = strdupW(MSI_RecordGetString(row, 4));
|
||||
mi->volume_label = strdupW(MSI_RecordGetString(row, 5));
|
||||
|
||||
if (!mi->first_volume)
|
||||
mi->first_volume = strdupW(mi->volume_label);
|
||||
|
||||
ptr = strrchrW(mi->source, '\\') + 1;
|
||||
lstrcpyW(ptr, mi->cabinet);
|
||||
msiobj_release(&row->hdr);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
|
||||
{
|
||||
TRACE("(%d)\n", fdint);
|
||||
|
||||
switch (fdint)
|
||||
{
|
||||
case fdintPARTIAL_FILE:
|
||||
{
|
||||
CabData *data = (CabData *)pfdin->pv;
|
||||
data->mi->is_continuous = FALSE;
|
||||
return 0;
|
||||
}
|
||||
case fdintNEXT_CABINET:
|
||||
{
|
||||
CabData *data = (CabData *)pfdin->pv;
|
||||
MSIMEDIAINFO *mi = data->mi;
|
||||
LPWSTR cab = strdupAtoW(pfdin->psz1);
|
||||
UINT rc;
|
||||
|
||||
msi_free(mi->disk_prompt);
|
||||
msi_free(mi->cabinet);
|
||||
msi_free(mi->volume_label);
|
||||
mi->disk_prompt = NULL;
|
||||
mi->cabinet = NULL;
|
||||
mi->volume_label = NULL;
|
||||
|
||||
mi->disk_id++;
|
||||
mi->is_continuous = TRUE;
|
||||
|
||||
rc = msi_media_get_disk_info(data->package, mi);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
msi_free(cab);
|
||||
ERR("Failed to get next cabinet information: %d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lstrcmpiW(mi->cabinet, cab))
|
||||
{
|
||||
msi_free(cab);
|
||||
ERR("Continuous cabinet does not match the next cabinet in the Media table\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
msi_free(cab);
|
||||
|
||||
TRACE("Searching for %s\n", debugstr_w(mi->source));
|
||||
|
||||
if (GetFileAttributesW(mi->source) == INVALID_FILE_ATTRIBUTES)
|
||||
rc = msi_change_media(data->package, mi);
|
||||
|
||||
if (rc != ERROR_SUCCESS)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case fdintCOPY_FILE:
|
||||
{
|
||||
CabData *data = (CabData*) pfdin->pv;
|
||||
HANDLE handle;
|
||||
LPWSTR file;
|
||||
MSIFILE *f;
|
||||
DWORD attrs;
|
||||
|
||||
file = strdupAtoW(pfdin->psz1);
|
||||
f = get_loaded_file(data->package, file);
|
||||
msi_free(file);
|
||||
|
||||
if (!f)
|
||||
{
|
||||
WARN("unknown file in cabinet (%s)\n",debugstr_a(pfdin->psz1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (f->state != msifs_missing && f->state != msifs_overwrite)
|
||||
{
|
||||
TRACE("Skipping extraction of %s\n",debugstr_a(pfdin->psz1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
msi_file_update_ui( data->package, f, szInstallFiles );
|
||||
|
||||
TRACE("extracting %s\n", debugstr_w(f->TargetPath) );
|
||||
|
||||
attrs = f->Attributes & (FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
|
||||
if (!attrs) attrs = FILE_ATTRIBUTE_NORMAL;
|
||||
|
||||
handle = CreateFileW( f->TargetPath, GENERIC_READ | GENERIC_WRITE, 0,
|
||||
NULL, CREATE_ALWAYS, attrs, NULL );
|
||||
if ( handle == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
if ( GetFileAttributesW( f->TargetPath ) != INVALID_FILE_ATTRIBUTES )
|
||||
f->state = msifs_installed;
|
||||
else
|
||||
ERR("failed to create %s (error %d)\n",
|
||||
debugstr_w( f->TargetPath ), GetLastError() );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
f->state = msifs_installed;
|
||||
return (INT_PTR) handle;
|
||||
}
|
||||
case fdintCLOSE_FILE_INFO:
|
||||
{
|
||||
CabData *data = (CabData*) pfdin->pv;
|
||||
FILETIME ft;
|
||||
FILETIME ftLocal;
|
||||
HANDLE handle = (HANDLE) pfdin->hf;
|
||||
|
||||
data->mi->is_continuous = FALSE;
|
||||
|
||||
if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
|
||||
return -1;
|
||||
if (!LocalFileTimeToFileTime(&ft, &ftLocal))
|
||||
return -1;
|
||||
if (!SetFileTime(handle, &ftLocal, 0, &ftLocal))
|
||||
return -1;
|
||||
CloseHandle(handle);
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* msi_cabextract
|
||||
*
|
||||
* Extract files from a cab file.
|
||||
*/
|
||||
BOOL msi_cabextract(MSIPACKAGE* package, MSIMEDIAINFO *mi,
|
||||
PFNFDINOTIFY notify, LPVOID data)
|
||||
{
|
||||
LPSTR cabinet, cab_path = NULL;
|
||||
LPWSTR ptr;
|
||||
HFDI hfdi;
|
||||
ERF erf;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
TRACE("Extracting %s\n", debugstr_w(mi->source));
|
||||
|
||||
hfdi = FDICreate(cabinet_alloc, cabinet_free, cabinet_open, cabinet_read,
|
||||
cabinet_write, cabinet_close, cabinet_seek, 0, &erf);
|
||||
if (!hfdi)
|
||||
{
|
||||
ERR("FDICreate failed\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ptr = strrchrW(mi->source, '\\') + 1;
|
||||
cabinet = strdupWtoA(ptr);
|
||||
if (!cabinet)
|
||||
goto done;
|
||||
|
||||
cab_path = strdupWtoA(mi->source);
|
||||
if (!cab_path)
|
||||
goto done;
|
||||
|
||||
cab_path[ptr - mi->source] = '\0';
|
||||
|
||||
ret = FDICopy(hfdi, cabinet, cab_path, 0, notify, NULL, data);
|
||||
if (!ret)
|
||||
ERR("FDICopy failed\n");
|
||||
|
||||
done:
|
||||
FDIDestroy(hfdi);
|
||||
msi_free(cabinet);
|
||||
msi_free(cab_path);
|
||||
|
||||
if (ret)
|
||||
mi->is_extracted = TRUE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* compares the version of a file read from the filesystem and
|
||||
* the version specified in the File table
|
||||
*/
|
||||
|
@ -477,209 +92,6 @@ static int msi_compare_file_version(MSIFILE *file)
|
|||
return lstrcmpW(version, file->Version);
|
||||
}
|
||||
|
||||
void msi_free_media_info( MSIMEDIAINFO *mi )
|
||||
{
|
||||
msi_free( mi->disk_prompt );
|
||||
msi_free( mi->cabinet );
|
||||
msi_free( mi->volume_label );
|
||||
msi_free( mi->first_volume );
|
||||
msi_free( mi );
|
||||
}
|
||||
|
||||
UINT msi_load_media_info(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO *mi)
|
||||
{
|
||||
MSIRECORD *row;
|
||||
LPWSTR source_dir;
|
||||
LPWSTR source;
|
||||
DWORD options;
|
||||
UINT r;
|
||||
|
||||
static const WCHAR query[] = {
|
||||
'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
|
||||
'`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
|
||||
'`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',
|
||||
' ','%','i',' ','A','N','D',' ','`','D','i','s','k','I','d','`',' ','>','=',
|
||||
' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
|
||||
'`','D','i','s','k','I','d','`',0
|
||||
};
|
||||
|
||||
row = MSI_QueryGetRecord(package->db, query, file->Sequence, mi->disk_id);
|
||||
if (!row)
|
||||
{
|
||||
TRACE("Unable to query row\n");
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
mi->is_extracted = FALSE;
|
||||
mi->disk_id = MSI_RecordGetInteger(row, 1);
|
||||
mi->last_sequence = MSI_RecordGetInteger(row, 2);
|
||||
msi_free(mi->disk_prompt);
|
||||
mi->disk_prompt = strdupW(MSI_RecordGetString(row, 3));
|
||||
msi_free(mi->cabinet);
|
||||
mi->cabinet = strdupW(MSI_RecordGetString(row, 4));
|
||||
msi_free(mi->volume_label);
|
||||
mi->volume_label = strdupW(MSI_RecordGetString(row, 5));
|
||||
msiobj_release(&row->hdr);
|
||||
|
||||
if (!mi->first_volume)
|
||||
mi->first_volume = strdupW(mi->volume_label);
|
||||
|
||||
source_dir = msi_dup_property(package, cszSourceDir);
|
||||
lstrcpyW(mi->source, source_dir);
|
||||
|
||||
PathStripToRootW(source_dir);
|
||||
mi->type = GetDriveTypeW(source_dir);
|
||||
|
||||
if (file->IsCompressed && mi->cabinet)
|
||||
{
|
||||
if (mi->cabinet[0] == '#')
|
||||
{
|
||||
r = writeout_cabinet_stream(package, &mi->cabinet[1], mi->source);
|
||||
if (r != ERROR_SUCCESS)
|
||||
{
|
||||
ERR("Failed to extract cabinet stream\n");
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
}
|
||||
else
|
||||
lstrcatW(mi->source, mi->cabinet);
|
||||
}
|
||||
|
||||
options = MSICODE_PRODUCT;
|
||||
if (mi->type == DRIVE_CDROM || mi->type == DRIVE_REMOVABLE)
|
||||
{
|
||||
source = source_dir;
|
||||
options |= MSISOURCETYPE_MEDIA;
|
||||
}
|
||||
else if (package->BaseURL && UrlIsW(package->BaseURL, URLIS_URL))
|
||||
{
|
||||
source = package->BaseURL;
|
||||
options |= MSISOURCETYPE_URL;
|
||||
}
|
||||
else
|
||||
{
|
||||
source = mi->source;
|
||||
options |= MSISOURCETYPE_NETWORK;
|
||||
}
|
||||
|
||||
msi_package_add_media_disk(package, package->Context,
|
||||
MSICODE_PRODUCT, mi->disk_id,
|
||||
mi->volume_label, mi->disk_prompt);
|
||||
|
||||
msi_package_add_info(package, package->Context,
|
||||
options, INSTALLPROPERTY_LASTUSEDSOURCEW, source);
|
||||
|
||||
msi_free(source_dir);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/* FIXME: search NETWORK and URL sources as well */
|
||||
UINT find_published_source(MSIPACKAGE *package, MSIMEDIAINFO *mi)
|
||||
{
|
||||
WCHAR source[MAX_PATH];
|
||||
WCHAR volume[MAX_PATH];
|
||||
WCHAR prompt[MAX_PATH];
|
||||
DWORD volumesz, promptsz;
|
||||
DWORD index, size, id;
|
||||
UINT r;
|
||||
|
||||
size = MAX_PATH;
|
||||
r = MsiSourceListGetInfoW(package->ProductCode, NULL,
|
||||
package->Context, MSICODE_PRODUCT,
|
||||
INSTALLPROPERTY_LASTUSEDSOURCEW, source, &size);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
index = 0;
|
||||
volumesz = MAX_PATH;
|
||||
promptsz = MAX_PATH;
|
||||
while (MsiSourceListEnumMediaDisksW(package->ProductCode, NULL,
|
||||
package->Context,
|
||||
MSICODE_PRODUCT, index++, &id,
|
||||
volume, &volumesz, prompt, &promptsz) == ERROR_SUCCESS)
|
||||
{
|
||||
mi->disk_id = id;
|
||||
mi->volume_label = msi_realloc(mi->volume_label, ++volumesz * sizeof(WCHAR));
|
||||
lstrcpyW(mi->volume_label, volume);
|
||||
mi->disk_prompt = msi_realloc(mi->disk_prompt, ++promptsz * sizeof(WCHAR));
|
||||
lstrcpyW(mi->disk_prompt, prompt);
|
||||
|
||||
if (source_matches_volume(mi, source))
|
||||
{
|
||||
/* FIXME: what about SourceDir */
|
||||
lstrcpyW(mi->source, source);
|
||||
lstrcatW(mi->source, mi->cabinet);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
static UINT ready_media(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO *mi)
|
||||
{
|
||||
UINT rc = ERROR_SUCCESS;
|
||||
|
||||
/* media info for continuous cabinet is already loaded */
|
||||
if (mi->is_continuous)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
rc = msi_load_media_info(package, file, mi);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
ERR("Unable to load media info\n");
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
/* cabinet is internal, no checks needed */
|
||||
if (!mi->cabinet || mi->cabinet[0] == '#')
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
/* package should be downloaded */
|
||||
if (file->IsCompressed &&
|
||||
GetFileAttributesW(mi->source) == INVALID_FILE_ATTRIBUTES &&
|
||||
package->BaseURL && UrlIsW(package->BaseURL, URLIS_URL))
|
||||
{
|
||||
WCHAR temppath[MAX_PATH];
|
||||
|
||||
msi_download_file(mi->source, temppath);
|
||||
lstrcpyW(mi->source, temppath);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/* check volume matches, change media if not */
|
||||
if (mi->volume_label && mi->disk_id > 1 &&
|
||||
lstrcmpW(mi->first_volume, mi->volume_label))
|
||||
{
|
||||
LPWSTR source = msi_dup_property(package, cszSourceDir);
|
||||
BOOL matches;
|
||||
|
||||
matches = source_matches_volume(mi, source);
|
||||
msi_free(source);
|
||||
|
||||
if ((mi->type == DRIVE_CDROM || mi->type == DRIVE_REMOVABLE) && !matches)
|
||||
{
|
||||
rc = msi_change_media(package, mi);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
if (file->IsCompressed &&
|
||||
GetFileAttributesW(mi->source) == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
/* FIXME: this might be done earlier in the install process */
|
||||
rc = find_published_source(package, mi);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
ERR("Cabinet not found: %s\n", debugstr_w(mi->source));
|
||||
return ERROR_INSTALL_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
|
||||
MSIFILE** file)
|
||||
{
|
||||
|
@ -713,28 +125,28 @@ static void schedule_install_files(MSIPACKAGE *package)
|
|||
}
|
||||
}
|
||||
|
||||
static UINT copy_file(MSIFILE *file)
|
||||
static UINT copy_file(MSIFILE *file, LPWSTR source)
|
||||
{
|
||||
BOOL ret;
|
||||
|
||||
ret = CopyFileW(file->SourcePath, file->TargetPath, FALSE);
|
||||
if (ret)
|
||||
{
|
||||
file->state = msifs_installed;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
ret = CopyFileW(source, file->TargetPath, FALSE);
|
||||
if (!ret)
|
||||
return GetLastError();
|
||||
|
||||
return GetLastError();
|
||||
SetFileAttributesW(file->TargetPath, FILE_ATTRIBUTE_NORMAL);
|
||||
|
||||
file->state = msifs_installed;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT copy_install_file(MSIFILE *file)
|
||||
static UINT copy_install_file(MSIFILE *file, LPWSTR source)
|
||||
{
|
||||
UINT gle;
|
||||
|
||||
TRACE("Copying %s to %s\n", debugstr_w(file->SourcePath),
|
||||
TRACE("Copying %s to %s\n", debugstr_w(source),
|
||||
debugstr_w(file->TargetPath));
|
||||
|
||||
gle = copy_file(file);
|
||||
gle = copy_file(file, source);
|
||||
if (gle == ERROR_SUCCESS)
|
||||
return gle;
|
||||
|
||||
|
@ -747,7 +159,7 @@ static UINT copy_install_file(MSIFILE *file)
|
|||
{
|
||||
SetFileAttributesW(file->TargetPath, FILE_ATTRIBUTE_NORMAL);
|
||||
|
||||
gle = copy_file(file);
|
||||
gle = copy_file(file, source);
|
||||
TRACE("Overwriting existing file: %d\n", gle);
|
||||
}
|
||||
|
||||
|
@ -770,6 +182,40 @@ static BOOL check_dest_hash_matches(MSIFILE *file)
|
|||
return !memcmp(&hash, &file->hash, sizeof(MSIFILEHASHINFO));
|
||||
}
|
||||
|
||||
static BOOL installfiles_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
|
||||
LPWSTR *path, DWORD *attrs, PVOID user)
|
||||
{
|
||||
static MSIFILE *f = NULL;
|
||||
|
||||
if (action == MSICABEXTRACT_BEGINEXTRACT)
|
||||
{
|
||||
f = get_loaded_file(package, file);
|
||||
if (!f)
|
||||
{
|
||||
WARN("unknown file in cabinet (%s)\n", debugstr_w(file));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (f->state != msifs_missing && f->state != msifs_overwrite)
|
||||
{
|
||||
TRACE("Skipping extraction of %s\n", debugstr_w(file));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
msi_file_update_ui(package, f, szInstallFiles);
|
||||
|
||||
*path = strdupW(f->TargetPath);
|
||||
*attrs = f->Attributes;
|
||||
}
|
||||
else if (action == MSICABEXTRACT_FILEEXTRACTED)
|
||||
{
|
||||
f->state = msifs_installed;
|
||||
f = NULL;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* ACTION_InstallFiles()
|
||||
*
|
||||
|
@ -819,7 +265,7 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
|
|||
if (file->Sequence > mi->last_sequence || mi->is_continuous ||
|
||||
(file->IsCompressed && !mi->is_extracted))
|
||||
{
|
||||
CabData data;
|
||||
MSICABDATA data;
|
||||
|
||||
rc = ready_media(package, file, mi);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
|
@ -830,9 +276,11 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
|
|||
|
||||
data.mi = mi;
|
||||
data.package = package;
|
||||
data.cb = installfiles_cb;
|
||||
data.user = NULL;
|
||||
|
||||
if (file->IsCompressed &&
|
||||
!msi_cabextract(package, mi, cabinet_notify, &data))
|
||||
!msi_cabextract(package, mi, &data))
|
||||
{
|
||||
ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
|
||||
rc = ERROR_FUNCTION_FAILED;
|
||||
|
@ -842,28 +290,34 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
|
|||
|
||||
if (!file->IsCompressed)
|
||||
{
|
||||
TRACE("file paths %s to %s\n", debugstr_w(file->SourcePath),
|
||||
LPWSTR source = resolve_file_source(package, file);
|
||||
|
||||
TRACE("file paths %s to %s\n", debugstr_w(source),
|
||||
debugstr_w(file->TargetPath));
|
||||
|
||||
msi_file_update_ui(package, file, szInstallFiles);
|
||||
rc = copy_install_file(file);
|
||||
rc = copy_install_file(file, source);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
ERR("Failed to copy %s to %s (%d)\n", debugstr_w(file->SourcePath),
|
||||
ERR("Failed to copy %s to %s (%d)\n", debugstr_w(source),
|
||||
debugstr_w(file->TargetPath), rc);
|
||||
rc = ERROR_INSTALL_FAILURE;
|
||||
msi_free(source);
|
||||
break;
|
||||
}
|
||||
|
||||
msi_free(source);
|
||||
}
|
||||
else if (file->state != msifs_installed)
|
||||
{
|
||||
ERR("compressed file wasn't extracted (%s)\n", debugstr_w(file->TargetPath));
|
||||
ERR("compressed file wasn't extracted (%s)\n",
|
||||
debugstr_w(file->TargetPath));
|
||||
rc = ERROR_INSTALL_FAILURE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
msi_free_media_info( mi );
|
||||
msi_free_media_info(mi);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -986,35 +440,134 @@ UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static BOOL verify_comp_for_removal(MSICOMPONENT *comp, UINT install_mode)
|
||||
{
|
||||
INSTALLSTATE request = comp->ActionRequest;
|
||||
|
||||
if (request == INSTALLSTATE_UNKNOWN)
|
||||
return FALSE;
|
||||
|
||||
if (install_mode == msidbRemoveFileInstallModeOnInstall &&
|
||||
(request == INSTALLSTATE_LOCAL || request == INSTALLSTATE_SOURCE))
|
||||
return TRUE;
|
||||
|
||||
if (request == INSTALLSTATE_ABSENT)
|
||||
{
|
||||
if (!comp->ComponentId)
|
||||
return FALSE;
|
||||
|
||||
if (install_mode == msidbRemoveFileInstallModeOnRemove)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (install_mode == msidbRemoveFileInstallModeOnBoth)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static UINT ITERATE_RemoveFiles(MSIRECORD *row, LPVOID param)
|
||||
{
|
||||
MSIPACKAGE *package = (MSIPACKAGE*)param;
|
||||
MSICOMPONENT *comp;
|
||||
LPCWSTR component, filename, dirprop;
|
||||
UINT install_mode;
|
||||
LPWSTR dir = NULL, path = NULL;
|
||||
DWORD size;
|
||||
UINT r;
|
||||
|
||||
component = MSI_RecordGetString(row, 2);
|
||||
filename = MSI_RecordGetString(row, 3);
|
||||
dirprop = MSI_RecordGetString(row, 4);
|
||||
install_mode = MSI_RecordGetInteger(row, 5);
|
||||
|
||||
comp = get_loaded_component(package, component);
|
||||
if (!comp)
|
||||
{
|
||||
ERR("Invalid component: %s\n", debugstr_w(component));
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
if (!verify_comp_for_removal(comp, install_mode))
|
||||
{
|
||||
TRACE("Skipping removal due to missing conditions\n");
|
||||
comp->Action = comp->Installed;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
dir = msi_dup_property(package, dirprop);
|
||||
if (!dir)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
size = (filename != NULL) ? lstrlenW(filename) : 0;
|
||||
size += lstrlenW(dir) + 2;
|
||||
path = msi_alloc(size * sizeof(WCHAR));
|
||||
if (!path)
|
||||
{
|
||||
r = ERROR_OUTOFMEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
lstrcpyW(path, dir);
|
||||
PathAddBackslashW(path);
|
||||
|
||||
if (filename)
|
||||
{
|
||||
lstrcatW(path, filename);
|
||||
|
||||
TRACE("Deleting misc file: %s\n", debugstr_w(path));
|
||||
DeleteFileW(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE("Removing misc directory: %s\n", debugstr_w(path));
|
||||
RemoveDirectoryW(path);
|
||||
}
|
||||
|
||||
done:
|
||||
msi_free(path);
|
||||
msi_free(dir);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
UINT ACTION_RemoveFiles( MSIPACKAGE *package )
|
||||
{
|
||||
MSIQUERY *view;
|
||||
MSIFILE *file;
|
||||
UINT r;
|
||||
|
||||
static const WCHAR query[] = {
|
||||
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
||||
'`','R','e','m','o','v','e','F','i','l','e','`',0};
|
||||
|
||||
r = MSI_DatabaseOpenViewW(package->db, query, &view);
|
||||
if (r == ERROR_SUCCESS)
|
||||
{
|
||||
MSI_IterateRecords(view, NULL, ITERATE_RemoveFiles, package);
|
||||
msiobj_release(&view->hdr);
|
||||
}
|
||||
|
||||
LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
|
||||
{
|
||||
MSIRECORD *uirow;
|
||||
LPWSTR uipath, p;
|
||||
|
||||
if ( !file->Component )
|
||||
continue;
|
||||
if ( file->Component->Installed == INSTALLSTATE_LOCAL )
|
||||
continue;
|
||||
|
||||
if ( file->state == msifs_installed )
|
||||
ERR("removing installed file %s\n", debugstr_w(file->TargetPath));
|
||||
|
||||
if ( file->state != msifs_present )
|
||||
if ( file->Component->ActionRequest != INSTALLSTATE_ABSENT ||
|
||||
file->Component->Installed == INSTALLSTATE_SOURCE )
|
||||
continue;
|
||||
|
||||
/* only remove a file if the version to be installed
|
||||
* is strictly newer than the old file
|
||||
/* don't remove a file if the old file
|
||||
* is strictly newer than the version to be installed
|
||||
*/
|
||||
if ( msi_compare_file_version( file ) >= 0 )
|
||||
if ( msi_compare_file_version( file ) < 0 )
|
||||
continue;
|
||||
|
||||
TRACE("removing %s\n", debugstr_w(file->File) );
|
||||
if ( !DeleteFileW( file->TargetPath ) )
|
||||
ERR("failed to delete %s\n", debugstr_w(file->TargetPath) );
|
||||
TRACE("failed to delete %s\n", debugstr_w(file->TargetPath));
|
||||
file->state = msifs_missing;
|
||||
|
||||
/* the UI chunk */
|
||||
|
|
|
@ -26,13 +26,9 @@
|
|||
#include <stdarg.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
#include "wine/debug.h"
|
||||
#include "msipriv.h"
|
||||
#include "winuser.h"
|
||||
#include "winreg.h"
|
||||
#include "shlwapi.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "msidefs.h"
|
||||
|
||||
|
@ -45,6 +41,7 @@ const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0};
|
|||
const WCHAR cszSOURCEDIR[] = {'S','O','U','R','C','E','D','I','R',0};
|
||||
const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0};
|
||||
const WCHAR cszbs[]={'\\',0};
|
||||
const WCHAR szLocalSid[] = {'S','-','1','-','5','-','1','8',0};
|
||||
|
||||
LPWSTR build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name )
|
||||
{
|
||||
|
@ -165,6 +162,25 @@ MSIFOLDER *get_loaded_folder( MSIPACKAGE *package, LPCWSTR dir )
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void msi_reset_folders( MSIPACKAGE *package, BOOL source )
|
||||
{
|
||||
MSIFOLDER *folder;
|
||||
|
||||
LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
|
||||
{
|
||||
if ( source )
|
||||
{
|
||||
msi_free( folder->ResolvedSource );
|
||||
folder->ResolvedSource = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
msi_free( folder->ResolvedTarget );
|
||||
folder->ResolvedTarget = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static LPWSTR get_source_root( MSIPACKAGE *package )
|
||||
{
|
||||
LPWSTR path, p;
|
||||
|
@ -222,6 +238,34 @@ static void clean_spaces_from_path( LPWSTR p )
|
|||
}
|
||||
}
|
||||
|
||||
LPWSTR resolve_file_source(MSIPACKAGE *package, MSIFILE *file)
|
||||
{
|
||||
LPWSTR p, path;
|
||||
|
||||
TRACE("Working to resolve source of file %s\n", debugstr_w(file->File));
|
||||
|
||||
if (file->IsCompressed)
|
||||
return NULL;
|
||||
|
||||
p = resolve_folder(package, file->Component->Directory,
|
||||
TRUE, FALSE, TRUE, NULL);
|
||||
path = build_directory_name(2, p, file->ShortName);
|
||||
|
||||
if (file->LongName &&
|
||||
GetFileAttributesW(path) == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
msi_free(path);
|
||||
path = build_directory_name(2, p, file->LongName);
|
||||
}
|
||||
|
||||
msi_free(p);
|
||||
|
||||
TRACE("file %s source resolves to %s\n", debugstr_w(file->File),
|
||||
debugstr_w(path));
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
|
||||
BOOL set_prop, BOOL load_prop, MSIFOLDER **folder)
|
||||
{
|
||||
|
@ -393,7 +437,7 @@ UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action)
|
|||
|
||||
void msi_free_action_script(MSIPACKAGE *package, UINT script)
|
||||
{
|
||||
int i;
|
||||
UINT i;
|
||||
for (i = 0; i < package->script->ActionCount[script]; i++)
|
||||
msi_free(package->script->Actions[script][i]);
|
||||
|
||||
|
@ -522,7 +566,6 @@ void ACTION_free_package_structures( MSIPACKAGE* package)
|
|||
msi_free( file->LongName );
|
||||
msi_free( file->Version );
|
||||
msi_free( file->Language );
|
||||
msi_free( file->SourcePath );
|
||||
msi_free( file->TargetPath );
|
||||
msi_free( file );
|
||||
}
|
||||
|
@ -618,6 +661,13 @@ void ACTION_free_package_structures( MSIPACKAGE* package)
|
|||
msi_free(package->script);
|
||||
}
|
||||
|
||||
if (package->patch)
|
||||
{
|
||||
msi_free(package->patch->patchcode);
|
||||
msi_free(package->patch->transforms);
|
||||
msi_free(package->patch);
|
||||
}
|
||||
|
||||
msi_free(package->BaseURL);
|
||||
msi_free(package->PackagePath);
|
||||
msi_free(package->ProductCode);
|
||||
|
@ -797,9 +847,6 @@ BOOL ACTION_VerifyComponentForAction( const MSICOMPONENT* comp, INSTALLSTATE che
|
|||
if (!comp)
|
||||
return FALSE;
|
||||
|
||||
if (comp->Installed == check)
|
||||
return FALSE;
|
||||
|
||||
if (comp->ActionRequest == check)
|
||||
return TRUE;
|
||||
else
|
||||
|
@ -895,7 +942,7 @@ void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
|
|||
continue;
|
||||
|
||||
if (newstate == INSTALLSTATE_LOCAL)
|
||||
msi_component_set_state( component, INSTALLSTATE_LOCAL );
|
||||
msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
|
||||
else
|
||||
{
|
||||
ComponentList *clist;
|
||||
|
@ -903,7 +950,7 @@ void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
|
|||
|
||||
component->hasLocalFeature = FALSE;
|
||||
|
||||
msi_component_set_state( component, newstate );
|
||||
msi_component_set_state(package, component, newstate);
|
||||
|
||||
/*if any other feature wants is local we need to set it local*/
|
||||
LIST_FOR_EACH_ENTRY( f, &package->features, MSIFEATURE, entry )
|
||||
|
@ -926,14 +973,14 @@ void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
|
|||
if (component->Attributes & msidbComponentAttributesOptional)
|
||||
{
|
||||
if (f->Attributes & msidbFeatureAttributesFavorSource)
|
||||
msi_component_set_state( component, INSTALLSTATE_SOURCE );
|
||||
msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
|
||||
else
|
||||
msi_component_set_state( component, INSTALLSTATE_LOCAL );
|
||||
msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
|
||||
}
|
||||
else if (component->Attributes & msidbComponentAttributesSourceOnly)
|
||||
msi_component_set_state( component, INSTALLSTATE_SOURCE );
|
||||
msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
|
||||
else
|
||||
msi_component_set_state( component, INSTALLSTATE_LOCAL );
|
||||
msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -970,7 +1017,7 @@ UINT register_unique_action(MSIPACKAGE *package, LPCWSTR action)
|
|||
|
||||
BOOL check_unique_action(const MSIPACKAGE *package, LPCWSTR action)
|
||||
{
|
||||
INT i;
|
||||
UINT i;
|
||||
|
||||
if (!package->script)
|
||||
return FALSE;
|
||||
|
@ -1039,132 +1086,3 @@ void msi_ui_error( DWORD msg_id, DWORD type )
|
|||
|
||||
MessageBoxW( NULL, text, title, type );
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MSIPACKAGE *package;
|
||||
MSIMEDIAINFO *mi;
|
||||
MSIFILE *file;
|
||||
LPWSTR destination;
|
||||
} CabData;
|
||||
|
||||
static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
|
||||
{
|
||||
TRACE("(%d)\n", fdint);
|
||||
|
||||
switch (fdint)
|
||||
{
|
||||
case fdintNEXT_CABINET:
|
||||
{
|
||||
ERR("continuous cabinets not handled\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
case fdintCOPY_FILE:
|
||||
{
|
||||
CabData *data = (CabData*) pfdin->pv;
|
||||
LPWSTR file, path;
|
||||
DWORD attrs, size;
|
||||
HANDLE handle;
|
||||
MSIFILE *f;
|
||||
|
||||
file = strdupAtoW(pfdin->psz1);
|
||||
f = get_loaded_file(data->package, file);
|
||||
msi_free(file);
|
||||
|
||||
if (!f)
|
||||
{
|
||||
WARN("unknown file in cabinet (%s)\n",debugstr_a(pfdin->psz1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lstrcmpW(f->File, data->file->File))
|
||||
return 0;
|
||||
|
||||
size = lstrlenW(data->destination) + lstrlenW(data->file->FileName) + 2;
|
||||
path = msi_alloc(size * sizeof(WCHAR));
|
||||
lstrcpyW(path, data->destination);
|
||||
PathAddBackslashW(path);
|
||||
lstrcatW(path, data->file->FileName);
|
||||
|
||||
TRACE("extracting %s\n", debugstr_w(path));
|
||||
|
||||
attrs = f->Attributes & (FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
|
||||
if (!attrs) attrs = FILE_ATTRIBUTE_NORMAL;
|
||||
|
||||
handle = CreateFileW(path, GENERIC_READ | GENERIC_WRITE, 0,
|
||||
NULL, CREATE_ALWAYS, attrs, NULL);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (GetFileAttributesW(path) == INVALID_FILE_ATTRIBUTES)
|
||||
ERR("failed to create %s (error %d)\n",
|
||||
debugstr_w(path), GetLastError());
|
||||
|
||||
msi_free(path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
msi_free(path);
|
||||
return (INT_PTR)handle;
|
||||
}
|
||||
|
||||
case fdintCLOSE_FILE_INFO:
|
||||
{
|
||||
FILETIME ft;
|
||||
FILETIME ftLocal;
|
||||
HANDLE handle = (HANDLE)pfdin->hf;
|
||||
|
||||
if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
|
||||
return -1;
|
||||
if (!LocalFileTimeToFileTime(&ft, &ftLocal))
|
||||
return -1;
|
||||
if (!SetFileTime(handle, &ftLocal, 0, &ftLocal))
|
||||
return -1;
|
||||
CloseHandle(handle);
|
||||
return 1;
|
||||
}
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
UINT msi_extract_file(MSIPACKAGE *package, MSIFILE *file, LPWSTR destdir)
|
||||
{
|
||||
MSIMEDIAINFO *mi;
|
||||
CabData data;
|
||||
UINT r;
|
||||
|
||||
mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
|
||||
if (!mi)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
r = msi_load_media_info(package, file, mi);
|
||||
if (r != ERROR_SUCCESS)
|
||||
goto done;
|
||||
|
||||
if (GetFileAttributesW(mi->source) == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
r = find_published_source(package, mi);
|
||||
if (r != ERROR_SUCCESS)
|
||||
{
|
||||
ERR("Cabinet not found: %s\n", debugstr_w(mi->source));
|
||||
return ERROR_INSTALL_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
data.package = package;
|
||||
data.mi = mi;
|
||||
data.file = file;
|
||||
data.destination = destdir;
|
||||
|
||||
if (!msi_cabextract(package, mi, cabinet_notify, &data))
|
||||
{
|
||||
ERR("Failed to extract cabinet file\n");
|
||||
r = ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
done:
|
||||
msi_free_media_info(mi);
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -239,6 +239,7 @@ static const MSIVIEWOPS insert_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static UINT count_column_info( const column_info *ci )
|
||||
|
|
|
@ -215,8 +215,8 @@ UINT msi_strcpy_to_awstring( LPCWSTR str, awstring *awbuf, DWORD *sz )
|
|||
/***********************************************************************
|
||||
* MsiGetTargetPath (internal)
|
||||
*/
|
||||
static UINT WINAPI MSI_GetTargetPath( MSIHANDLE hInstall, LPCWSTR szFolder,
|
||||
awstring *szPathBuf, LPDWORD pcchPathBuf )
|
||||
static UINT MSI_GetTargetPath( MSIHANDLE hInstall, LPCWSTR szFolder,
|
||||
awstring *szPathBuf, LPDWORD pcchPathBuf )
|
||||
{
|
||||
MSIPACKAGE *package;
|
||||
LPWSTR path;
|
||||
|
@ -774,7 +774,7 @@ UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature,
|
|||
feature->Attributes & msidbFeatureAttributesDisallowAdvertise)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
msi_feature_set_state( feature, iState );
|
||||
msi_feature_set_state(package, feature, iState);
|
||||
|
||||
ACTION_UpdateComponentStates(package,szFeature);
|
||||
|
||||
|
|
|
@ -306,6 +306,7 @@ static const MSIVIEWOPS join_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
JOIN_sort,
|
||||
NULL,
|
||||
};
|
||||
|
||||
UINT JOIN_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR tables )
|
||||
|
|
648
reactos/dll/win32/msi/media.c
Normal file
648
reactos/dll/win32/msi/media.c
Normal file
|
@ -0,0 +1,648 @@
|
|||
/*
|
||||
* Implementation of the Microsoft Installer (msi.dll)
|
||||
*
|
||||
* Copyright 2008 James Hawkins
|
||||
*
|
||||
* 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
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winerror.h"
|
||||
#include "wine/debug.h"
|
||||
#include "fdi.h"
|
||||
#include "msipriv.h"
|
||||
#include "winuser.h"
|
||||
#include "winreg.h"
|
||||
#include "shlwapi.h"
|
||||
#include "wine/unicode.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
|
||||
/* from msvcrt/fcntl.h */
|
||||
#define _O_RDONLY 0
|
||||
#define _O_WRONLY 1
|
||||
#define _O_RDWR 2
|
||||
#define _O_ACCMODE (_O_RDONLY|_O_WRONLY|_O_RDWR)
|
||||
#define _O_APPEND 0x0008
|
||||
#define _O_RANDOM 0x0010
|
||||
#define _O_SEQUENTIAL 0x0020
|
||||
#define _O_TEMPORARY 0x0040
|
||||
#define _O_NOINHERIT 0x0080
|
||||
#define _O_CREAT 0x0100
|
||||
#define _O_TRUNC 0x0200
|
||||
#define _O_EXCL 0x0400
|
||||
#define _O_SHORT_LIVED 0x1000
|
||||
#define _O_TEXT 0x4000
|
||||
#define _O_BINARY 0x8000
|
||||
|
||||
static BOOL source_matches_volume(MSIMEDIAINFO *mi, LPWSTR source_root)
|
||||
{
|
||||
WCHAR volume_name[MAX_PATH + 1];
|
||||
|
||||
if (!GetVolumeInformationW(source_root, volume_name, MAX_PATH + 1,
|
||||
NULL, NULL, NULL, NULL, 0))
|
||||
{
|
||||
ERR("Failed to get volume information\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return !lstrcmpW(mi->volume_label, volume_name);
|
||||
}
|
||||
|
||||
static UINT msi_change_media(MSIPACKAGE *package, MSIMEDIAINFO *mi)
|
||||
{
|
||||
LPSTR msg;
|
||||
LPWSTR error, error_dialog;
|
||||
LPWSTR source_dir;
|
||||
UINT r = ERROR_SUCCESS;
|
||||
|
||||
static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
|
||||
static const WCHAR error_prop[] = {'E','r','r','o','r','D','i','a','l','o','g',0};
|
||||
|
||||
if ((msi_get_property_int(package, szUILevel, 0) & INSTALLUILEVEL_MASK) ==
|
||||
INSTALLUILEVEL_NONE && !gUIHandlerA)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
error = generate_error_string(package, 1302, 1, mi->disk_prompt);
|
||||
error_dialog = msi_dup_property(package, error_prop);
|
||||
source_dir = msi_dup_property(package, cszSourceDir);
|
||||
PathStripToRootW(source_dir);
|
||||
|
||||
while (r == ERROR_SUCCESS &&
|
||||
!source_matches_volume(mi, source_dir))
|
||||
{
|
||||
r = msi_spawn_error_dialog(package, error_dialog, error);
|
||||
|
||||
if (gUIHandlerA)
|
||||
{
|
||||
msg = strdupWtoA(error);
|
||||
gUIHandlerA(gUIContext, MB_RETRYCANCEL | INSTALLMESSAGE_ERROR, msg);
|
||||
msi_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
msi_free(error);
|
||||
msi_free(error_dialog);
|
||||
msi_free(source_dir);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static UINT writeout_cabinet_stream(MSIPACKAGE *package, LPCWSTR stream,
|
||||
WCHAR* source)
|
||||
{
|
||||
UINT rc;
|
||||
USHORT* data;
|
||||
UINT size;
|
||||
DWORD write;
|
||||
HANDLE hfile;
|
||||
WCHAR tmp[MAX_PATH];
|
||||
|
||||
static const WCHAR cszTempFolder[]= {
|
||||
'T','e','m','p','F','o','l','d','e','r',0};
|
||||
|
||||
rc = read_raw_stream_data(package->db, stream, &data, &size);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
return rc;
|
||||
|
||||
write = MAX_PATH;
|
||||
if (MSI_GetPropertyW(package, cszTempFolder, tmp, &write))
|
||||
GetTempPathW(MAX_PATH, tmp);
|
||||
|
||||
GetTempFileNameW(tmp, stream, 0, source);
|
||||
|
||||
track_tempfile(package, source);
|
||||
hfile = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (hfile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ERR("Unable to create file %s\n", debugstr_w(source));
|
||||
rc = ERROR_FUNCTION_FAILED;
|
||||
goto end;
|
||||
}
|
||||
|
||||
WriteFile(hfile, data, size, &write, NULL);
|
||||
CloseHandle(hfile);
|
||||
TRACE("wrote %i bytes to %s\n", write, debugstr_w(source));
|
||||
|
||||
end:
|
||||
msi_free(data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void *cabinet_alloc(ULONG cb)
|
||||
{
|
||||
return msi_alloc(cb);
|
||||
}
|
||||
|
||||
static void cabinet_free(void *pv)
|
||||
{
|
||||
msi_free(pv);
|
||||
}
|
||||
|
||||
static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode)
|
||||
{
|
||||
HANDLE handle;
|
||||
DWORD dwAccess = 0;
|
||||
DWORD dwShareMode = 0;
|
||||
DWORD dwCreateDisposition = OPEN_EXISTING;
|
||||
|
||||
switch (oflag & _O_ACCMODE)
|
||||
{
|
||||
case _O_RDONLY:
|
||||
dwAccess = GENERIC_READ;
|
||||
dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;
|
||||
break;
|
||||
case _O_WRONLY:
|
||||
dwAccess = GENERIC_WRITE;
|
||||
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||
break;
|
||||
case _O_RDWR:
|
||||
dwAccess = GENERIC_READ | GENERIC_WRITE;
|
||||
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))
|
||||
dwCreateDisposition = CREATE_NEW;
|
||||
else if (oflag & _O_CREAT)
|
||||
dwCreateDisposition = CREATE_ALWAYS;
|
||||
|
||||
handle = CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
|
||||
dwCreateDisposition, 0, NULL);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
return (INT_PTR)handle;
|
||||
}
|
||||
|
||||
static UINT cabinet_read(INT_PTR hf, void *pv, UINT cb)
|
||||
{
|
||||
HANDLE handle = (HANDLE)hf;
|
||||
DWORD read;
|
||||
|
||||
if (ReadFile(handle, pv, cb, &read, NULL))
|
||||
return read;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb)
|
||||
{
|
||||
HANDLE handle = (HANDLE)hf;
|
||||
DWORD written;
|
||||
|
||||
if (WriteFile(handle, pv, cb, &written, NULL))
|
||||
return written;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cabinet_close(INT_PTR hf)
|
||||
{
|
||||
HANDLE handle = (HANDLE)hf;
|
||||
return CloseHandle(handle) ? 0 : -1;
|
||||
}
|
||||
|
||||
static long cabinet_seek(INT_PTR hf, long dist, int seektype)
|
||||
{
|
||||
HANDLE handle = (HANDLE)hf;
|
||||
/* flags are compatible and so are passed straight through */
|
||||
return SetFilePointer(handle, dist, NULL, seektype);
|
||||
}
|
||||
|
||||
static UINT msi_media_get_disk_info(MSIPACKAGE *package, MSIMEDIAINFO *mi)
|
||||
{
|
||||
MSIRECORD *row;
|
||||
LPWSTR ptr;
|
||||
|
||||
static const WCHAR query[] = {
|
||||
'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
|
||||
'`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
|
||||
'`','D','i','s','k','I','d','`',' ','=',' ','%','i',0};
|
||||
|
||||
row = MSI_QueryGetRecord(package->db, query, mi->disk_id);
|
||||
if (!row)
|
||||
{
|
||||
TRACE("Unable to query row\n");
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
mi->disk_prompt = strdupW(MSI_RecordGetString(row, 3));
|
||||
mi->cabinet = strdupW(MSI_RecordGetString(row, 4));
|
||||
mi->volume_label = strdupW(MSI_RecordGetString(row, 5));
|
||||
|
||||
if (!mi->first_volume)
|
||||
mi->first_volume = strdupW(mi->volume_label);
|
||||
|
||||
ptr = strrchrW(mi->source, '\\') + 1;
|
||||
lstrcpyW(ptr, mi->cabinet);
|
||||
msiobj_release(&row->hdr);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static INT_PTR cabinet_partial_file(FDINOTIFICATIONTYPE fdint,
|
||||
PFDINOTIFICATION pfdin)
|
||||
{
|
||||
MSICABDATA *data = (MSICABDATA *)pfdin->pv;
|
||||
data->mi->is_continuous = FALSE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INT_PTR cabinet_next_cabinet(FDINOTIFICATIONTYPE fdint,
|
||||
PFDINOTIFICATION pfdin)
|
||||
{
|
||||
MSICABDATA *data = (MSICABDATA *)pfdin->pv;
|
||||
MSIMEDIAINFO *mi = data->mi;
|
||||
LPWSTR cab = strdupAtoW(pfdin->psz1);
|
||||
INT_PTR res = -1;
|
||||
UINT rc;
|
||||
|
||||
msi_free(mi->disk_prompt);
|
||||
msi_free(mi->cabinet);
|
||||
msi_free(mi->volume_label);
|
||||
mi->disk_prompt = NULL;
|
||||
mi->cabinet = NULL;
|
||||
mi->volume_label = NULL;
|
||||
|
||||
mi->disk_id++;
|
||||
mi->is_continuous = TRUE;
|
||||
|
||||
rc = msi_media_get_disk_info(data->package, mi);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
ERR("Failed to get next cabinet information: %d\n", rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (lstrcmpiW(mi->cabinet, cab))
|
||||
{
|
||||
ERR("Continuous cabinet does not match the next cabinet in the Media table\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
TRACE("Searching for %s\n", debugstr_w(mi->source));
|
||||
|
||||
res = 0;
|
||||
if (GetFileAttributesW(mi->source) == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
if (msi_change_media(data->package, mi) != ERROR_SUCCESS)
|
||||
res = -1;
|
||||
}
|
||||
|
||||
done:
|
||||
msi_free(cab);
|
||||
return res;
|
||||
}
|
||||
|
||||
static INT_PTR cabinet_copy_file(FDINOTIFICATIONTYPE fdint,
|
||||
PFDINOTIFICATION pfdin)
|
||||
{
|
||||
MSICABDATA *data = (MSICABDATA*)pfdin->pv;
|
||||
HANDLE handle = 0;
|
||||
LPWSTR path = NULL;
|
||||
DWORD attrs;
|
||||
|
||||
data->curfile = strdupAtoW(pfdin->psz1);
|
||||
if (!data->cb(data->package, data->curfile, MSICABEXTRACT_BEGINEXTRACT, &path,
|
||||
&attrs, data->user))
|
||||
goto done;
|
||||
|
||||
TRACE("extracting %s\n", debugstr_w(path));
|
||||
|
||||
attrs = attrs & (FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
|
||||
if (!attrs) attrs = FILE_ATTRIBUTE_NORMAL;
|
||||
|
||||
handle = CreateFileW(path, GENERIC_READ | GENERIC_WRITE, 0,
|
||||
NULL, CREATE_ALWAYS, attrs, NULL);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (GetFileAttributesW(path) == INVALID_FILE_ATTRIBUTES)
|
||||
ERR("failed to create %s (error %d)\n",
|
||||
debugstr_w(path), GetLastError());
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
msi_free(path);
|
||||
|
||||
return (INT_PTR)handle;
|
||||
}
|
||||
|
||||
static INT_PTR cabinet_close_file_info(FDINOTIFICATIONTYPE fdint,
|
||||
PFDINOTIFICATION pfdin)
|
||||
{
|
||||
MSICABDATA *data = (MSICABDATA*)pfdin->pv;
|
||||
FILETIME ft;
|
||||
FILETIME ftLocal;
|
||||
HANDLE handle = (HANDLE)pfdin->hf;
|
||||
|
||||
data->mi->is_continuous = FALSE;
|
||||
|
||||
if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
|
||||
return -1;
|
||||
if (!LocalFileTimeToFileTime(&ft, &ftLocal))
|
||||
return -1;
|
||||
if (!SetFileTime(handle, &ftLocal, 0, &ftLocal))
|
||||
return -1;
|
||||
|
||||
CloseHandle(handle);
|
||||
|
||||
data->cb(data->package, data->curfile, MSICABEXTRACT_FILEEXTRACTED, NULL, NULL,
|
||||
data->user);
|
||||
|
||||
msi_free(data->curfile);
|
||||
data->curfile = NULL;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
|
||||
{
|
||||
TRACE("(%d)\n", fdint);
|
||||
|
||||
switch (fdint)
|
||||
{
|
||||
case fdintPARTIAL_FILE:
|
||||
return cabinet_partial_file(fdint, pfdin);
|
||||
|
||||
case fdintNEXT_CABINET:
|
||||
return cabinet_next_cabinet(fdint, pfdin);
|
||||
|
||||
case fdintCOPY_FILE:
|
||||
return cabinet_copy_file(fdint, pfdin);
|
||||
|
||||
case fdintCLOSE_FILE_INFO:
|
||||
return cabinet_close_file_info(fdint, pfdin);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* msi_cabextract
|
||||
*
|
||||
* Extract files from a cab file.
|
||||
*/
|
||||
BOOL msi_cabextract(MSIPACKAGE* package, MSIMEDIAINFO *mi, LPVOID data)
|
||||
{
|
||||
LPSTR cabinet, cab_path = NULL;
|
||||
LPWSTR ptr;
|
||||
HFDI hfdi;
|
||||
ERF erf;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
TRACE("Extracting %s\n", debugstr_w(mi->source));
|
||||
|
||||
hfdi = FDICreate(cabinet_alloc, cabinet_free, cabinet_open, cabinet_read,
|
||||
cabinet_write, cabinet_close, cabinet_seek, 0, &erf);
|
||||
if (!hfdi)
|
||||
{
|
||||
ERR("FDICreate failed\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ptr = strrchrW(mi->source, '\\') + 1;
|
||||
cabinet = strdupWtoA(ptr);
|
||||
if (!cabinet)
|
||||
goto done;
|
||||
|
||||
cab_path = strdupWtoA(mi->source);
|
||||
if (!cab_path)
|
||||
goto done;
|
||||
|
||||
cab_path[ptr - mi->source] = '\0';
|
||||
|
||||
ret = FDICopy(hfdi, cabinet, cab_path, 0, cabinet_notify, NULL, data);
|
||||
if (!ret)
|
||||
ERR("FDICopy failed\n");
|
||||
|
||||
done:
|
||||
FDIDestroy(hfdi);
|
||||
msi_free(cabinet);
|
||||
msi_free(cab_path);
|
||||
|
||||
if (ret)
|
||||
mi->is_extracted = TRUE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void msi_free_media_info(MSIMEDIAINFO *mi)
|
||||
{
|
||||
msi_free(mi->disk_prompt);
|
||||
msi_free(mi->cabinet);
|
||||
msi_free(mi->volume_label);
|
||||
msi_free(mi->first_volume);
|
||||
msi_free(mi);
|
||||
}
|
||||
|
||||
UINT msi_load_media_info(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO *mi)
|
||||
{
|
||||
MSIRECORD *row;
|
||||
LPWSTR source_dir;
|
||||
LPWSTR source;
|
||||
DWORD options;
|
||||
UINT r;
|
||||
|
||||
static const WCHAR query[] = {
|
||||
'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
|
||||
'`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
|
||||
'`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',
|
||||
' ','%','i',' ','A','N','D',' ','`','D','i','s','k','I','d','`',' ','>','=',
|
||||
' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
|
||||
'`','D','i','s','k','I','d','`',0};
|
||||
|
||||
row = MSI_QueryGetRecord(package->db, query, file->Sequence, mi->disk_id);
|
||||
if (!row)
|
||||
{
|
||||
TRACE("Unable to query row\n");
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
mi->is_extracted = FALSE;
|
||||
mi->disk_id = MSI_RecordGetInteger(row, 1);
|
||||
mi->last_sequence = MSI_RecordGetInteger(row, 2);
|
||||
msi_free(mi->disk_prompt);
|
||||
mi->disk_prompt = strdupW(MSI_RecordGetString(row, 3));
|
||||
msi_free(mi->cabinet);
|
||||
mi->cabinet = strdupW(MSI_RecordGetString(row, 4));
|
||||
msi_free(mi->volume_label);
|
||||
mi->volume_label = strdupW(MSI_RecordGetString(row, 5));
|
||||
msiobj_release(&row->hdr);
|
||||
|
||||
if (!mi->first_volume)
|
||||
mi->first_volume = strdupW(mi->volume_label);
|
||||
|
||||
source_dir = msi_dup_property(package, cszSourceDir);
|
||||
lstrcpyW(mi->source, source_dir);
|
||||
|
||||
PathStripToRootW(source_dir);
|
||||
mi->type = GetDriveTypeW(source_dir);
|
||||
|
||||
if (file->IsCompressed && mi->cabinet)
|
||||
{
|
||||
if (mi->cabinet[0] == '#')
|
||||
{
|
||||
r = writeout_cabinet_stream(package, &mi->cabinet[1], mi->source);
|
||||
if (r != ERROR_SUCCESS)
|
||||
{
|
||||
ERR("Failed to extract cabinet stream\n");
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
}
|
||||
else
|
||||
lstrcatW(mi->source, mi->cabinet);
|
||||
}
|
||||
|
||||
options = MSICODE_PRODUCT;
|
||||
if (mi->type == DRIVE_CDROM || mi->type == DRIVE_REMOVABLE)
|
||||
{
|
||||
source = source_dir;
|
||||
options |= MSISOURCETYPE_MEDIA;
|
||||
}
|
||||
else if (package->BaseURL && UrlIsW(package->BaseURL, URLIS_URL))
|
||||
{
|
||||
source = package->BaseURL;
|
||||
options |= MSISOURCETYPE_URL;
|
||||
}
|
||||
else
|
||||
{
|
||||
source = mi->source;
|
||||
options |= MSISOURCETYPE_NETWORK;
|
||||
}
|
||||
|
||||
msi_package_add_media_disk(package, package->Context,
|
||||
MSICODE_PRODUCT, mi->disk_id,
|
||||
mi->volume_label, mi->disk_prompt);
|
||||
|
||||
msi_package_add_info(package, package->Context,
|
||||
options, INSTALLPROPERTY_LASTUSEDSOURCEW, source);
|
||||
|
||||
msi_free(source_dir);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/* FIXME: search NETWORK and URL sources as well */
|
||||
UINT find_published_source(MSIPACKAGE *package, MSIMEDIAINFO *mi)
|
||||
{
|
||||
WCHAR source[MAX_PATH];
|
||||
WCHAR volume[MAX_PATH];
|
||||
WCHAR prompt[MAX_PATH];
|
||||
DWORD volumesz, promptsz;
|
||||
DWORD index, size, id;
|
||||
UINT r;
|
||||
|
||||
size = MAX_PATH;
|
||||
r = MsiSourceListGetInfoW(package->ProductCode, NULL,
|
||||
package->Context, MSICODE_PRODUCT,
|
||||
INSTALLPROPERTY_LASTUSEDSOURCEW, source, &size);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
index = 0;
|
||||
volumesz = MAX_PATH;
|
||||
promptsz = MAX_PATH;
|
||||
while (MsiSourceListEnumMediaDisksW(package->ProductCode, NULL,
|
||||
package->Context,
|
||||
MSICODE_PRODUCT, index++, &id,
|
||||
volume, &volumesz, prompt, &promptsz) == ERROR_SUCCESS)
|
||||
{
|
||||
mi->disk_id = id;
|
||||
mi->volume_label = msi_realloc(mi->volume_label, ++volumesz * sizeof(WCHAR));
|
||||
lstrcpyW(mi->volume_label, volume);
|
||||
mi->disk_prompt = msi_realloc(mi->disk_prompt, ++promptsz * sizeof(WCHAR));
|
||||
lstrcpyW(mi->disk_prompt, prompt);
|
||||
|
||||
if (source_matches_volume(mi, source))
|
||||
{
|
||||
/* FIXME: what about SourceDir */
|
||||
lstrcpyW(mi->source, source);
|
||||
lstrcatW(mi->source, mi->cabinet);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
UINT ready_media(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO *mi)
|
||||
{
|
||||
UINT rc = ERROR_SUCCESS;
|
||||
|
||||
/* media info for continuous cabinet is already loaded */
|
||||
if (mi->is_continuous)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
rc = msi_load_media_info(package, file, mi);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
ERR("Unable to load media info\n");
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
/* cabinet is internal, no checks needed */
|
||||
if (!mi->cabinet || mi->cabinet[0] == '#')
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
/* package should be downloaded */
|
||||
if (file->IsCompressed &&
|
||||
GetFileAttributesW(mi->source) == INVALID_FILE_ATTRIBUTES &&
|
||||
package->BaseURL && UrlIsW(package->BaseURL, URLIS_URL))
|
||||
{
|
||||
WCHAR temppath[MAX_PATH];
|
||||
|
||||
msi_download_file(mi->source, temppath);
|
||||
lstrcpyW(mi->source, temppath);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/* check volume matches, change media if not */
|
||||
if (mi->volume_label && mi->disk_id > 1 &&
|
||||
lstrcmpW(mi->first_volume, mi->volume_label))
|
||||
{
|
||||
LPWSTR source = msi_dup_property(package, cszSourceDir);
|
||||
BOOL matches;
|
||||
|
||||
matches = source_matches_volume(mi, source);
|
||||
msi_free(source);
|
||||
|
||||
if ((mi->type == DRIVE_CDROM || mi->type == DRIVE_REMOVABLE) && !matches)
|
||||
{
|
||||
rc = msi_change_media(package, mi);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
if (file->IsCompressed &&
|
||||
GetFileAttributesW(mi->source) == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
rc = find_published_source(package, mi);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
ERR("Cabinet not found: %s\n", debugstr_w(mi->source));
|
||||
return ERROR_INSTALL_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -20,6 +20,7 @@
|
|||
<file>delete.c</file>
|
||||
<file>dialog.c</file>
|
||||
<file>distinct.c</file>
|
||||
<file>drop.c</file>
|
||||
<file>events.c</file>
|
||||
<file>files.c</file>
|
||||
<file>font.c</file>
|
||||
|
@ -29,6 +30,7 @@
|
|||
<file>insert.c</file>
|
||||
<file>install.c</file>
|
||||
<file>join.c</file>
|
||||
<file>media.c</file>
|
||||
<file>msi.c</file>
|
||||
<file>msi_main.c</file>
|
||||
<file>msiquery.c</file>
|
||||
|
|
|
@ -46,6 +46,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
|||
#include "msi_Si.rc"
|
||||
#include "msi_Sv.rc"
|
||||
#include "msi_Tr.rc"
|
||||
#include "msi_Zh.rc"
|
||||
|
||||
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
||||
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
26 stdcall MsiDatabaseGetPrimaryKeysW(long wstr ptr)
|
||||
27 stdcall MsiDatabaseImportA(str str long)
|
||||
28 stdcall MsiDatabaseImportW(wstr wstr long)
|
||||
29 stub MsiDatabaseMergeA
|
||||
30 stub MsiDatabaseMergeW
|
||||
29 stdcall MsiDatabaseMergeA(long long str)
|
||||
30 stdcall MsiDatabaseMergeW(long long wstr)
|
||||
31 stdcall MsiDatabaseOpenViewA(long str ptr)
|
||||
32 stdcall MsiDatabaseOpenViewW(long wstr ptr)
|
||||
33 stdcall MsiDoActionA(long str)
|
||||
|
@ -77,7 +77,7 @@
|
|||
81 stdcall MsiGetUserInfoA(str ptr ptr ptr ptr ptr ptr)
|
||||
82 stdcall MsiGetUserInfoW(wstr ptr ptr ptr ptr ptr ptr)
|
||||
83 stub MsiInstallMissingComponentA
|
||||
84 stub MsiInstallMissingComponentW
|
||||
84 stdcall MsiInstallMissingComponentW(wstr wstr long)
|
||||
85 stub MsiInstallMissingFileA
|
||||
86 stub MsiInstallMissingFileW
|
||||
87 stdcall MsiInstallProductA(str str)
|
||||
|
@ -236,8 +236,8 @@
|
|||
240 stub MsiApplyMultiplePatchesW
|
||||
241 stub MsiExtractPatchXMLDataA
|
||||
242 stub MsiExtractPatchXMLDataW
|
||||
243 stub MsiGetPatchInfoExA
|
||||
244 stub MsiGetPatchInfoExW
|
||||
243 stdcall MsiGetPatchInfoExA(str str str long str ptr ptr)
|
||||
244 stdcall MsiGetPatchInfoExW(wstr wstr wstr long wstr ptr ptr)
|
||||
245 stdcall MsiEnumProductsExA(str str long long ptr ptr ptr ptr)
|
||||
246 stdcall MsiEnumProductsExW(wstr wstr long long ptr ptr ptr ptr)
|
||||
247 stdcall MsiGetProductInfoExA(str str long str ptr ptr)
|
||||
|
@ -262,19 +262,19 @@
|
|||
266 stdcall MsiSourceListGetInfoW(wstr wstr long long wstr ptr ptr)
|
||||
267 stdcall MsiSourceListSetInfoA(str str long long str str)
|
||||
268 stdcall MsiSourceListSetInfoW(wstr wstr long long wstr wstr)
|
||||
269 stub MsiEnumPatchesExA
|
||||
270 stub MsiEnumPatchesExW
|
||||
269 stdcall MsiEnumPatchesExA(str str long long long ptr ptr ptr ptr ptr)
|
||||
270 stdcall MsiEnumPatchesExW(wstr wstr long long long ptr ptr ptr ptr ptr)
|
||||
271 stdcall MsiSourceListEnumMediaDisksA(str str long long long ptr ptr ptr ptr ptr)
|
||||
272 stdcall MsiSourceListEnumMediaDisksW(wstr wstr long long long ptr ptr ptr ptr ptr)
|
||||
273 stdcall MsiSourceListAddMediaDiskA(str str long long long str str)
|
||||
274 stdcall MsiSourceListAddMediaDiskW(wstr wstr long long long wstr wstr)
|
||||
275 stub MsiSourceListClearMediaDiskA
|
||||
276 stub MsiSourceListClearMediaDiskW
|
||||
277 stub MsiDetermineApplicablePatchesA
|
||||
278 stub MsiDetermineApplicablePatchesW
|
||||
277 stdcall MsiDetermineApplicablePatchesA(str long ptr)
|
||||
278 stdcall MsiDetermineApplicablePatchesW(wstr long ptr)
|
||||
279 stub MsiMessageBoxExA
|
||||
280 stub MsiMessageBoxExW
|
||||
281 stub MsiSetExternalUIRecord
|
||||
281 stdcall MsiSetExternalUIRecord(ptr long ptr ptr)
|
||||
|
||||
@ stdcall -private DllCanUnloadNow()
|
||||
@ stdcall -private DllGetClassObject(ptr ptr ptr)
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
LANGUAGE LANG_KOREAN, SUBLANG_NEUTRAL
|
||||
LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT
|
||||
|
||||
STRINGTABLE DISCARDABLE
|
||||
{
|
||||
|
|
54
reactos/dll/win32/msi/msi_Zh.rc
Normal file
54
reactos/dll/win32/msi/msi_Zh.rc
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* MSI (Simplified and Traditional Chinese Resources)
|
||||
*
|
||||
* Copyright 2008 Hongbo Ni <hongbo.at.njstar.com>
|
||||
*
|
||||
* 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
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/* Chinese text is encoded in UTF-8 */
|
||||
#pragma code_page(65001)
|
||||
|
||||
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
|
||||
|
||||
STRINGTABLE DISCARDABLE
|
||||
{
|
||||
4 "不能打开所指定的安装软件包. 请检查文件路径后再试."
|
||||
5 "路径 %s 没找到"
|
||||
9 "插入软盘 %s"
|
||||
10 "错误参数"
|
||||
11 "输入包含 %s 的文件夹"
|
||||
12 "本功能的安装源不存在"
|
||||
13 "本功能的网络驱动器不存在"
|
||||
14 "功能来自:"
|
||||
15 "选择包含 %s 的文件夹"
|
||||
}
|
||||
|
||||
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL
|
||||
|
||||
STRINGTABLE DISCARDABLE
|
||||
{
|
||||
4 "不能開啟所指定的安裝軟件包. 請檢查檔案路徑後再試."
|
||||
5 "路徑 %s 沒找到"
|
||||
9 "插入軟碟 %s"
|
||||
10 "錯誤參數"
|
||||
11 "輸入包含 %s 的檔案夾"
|
||||
12 "本功能的安裝源不存在"
|
||||
13 "本功能的網路儲存槽不存在"
|
||||
14 "功能來自:"
|
||||
15 "選擇包含 %s 的檔案夾"
|
||||
}
|
||||
|
||||
#pragma code_page(default)
|
|
@ -33,6 +33,7 @@
|
|||
#include "objidl.h"
|
||||
#include "winnls.h"
|
||||
#include "wine/list.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
#define MSI_DATASIZEMASK 0x00ff
|
||||
#define MSITYPE_VALID 0x0100
|
||||
|
@ -143,6 +144,12 @@ typedef struct tagMSIMEDIAINFO
|
|||
WCHAR source[MAX_PATH];
|
||||
} MSIMEDIAINFO;
|
||||
|
||||
typedef struct tagMSIPATCHINFO
|
||||
{
|
||||
LPWSTR patchcode;
|
||||
LPWSTR transforms;
|
||||
} MSIPATCHINFO;
|
||||
|
||||
typedef struct _column_info
|
||||
{
|
||||
LPCWSTR table;
|
||||
|
@ -273,6 +280,11 @@ typedef struct tagMSIVIEWOPS
|
|||
* sort - orders the table by columns
|
||||
*/
|
||||
UINT (*sort)( struct tagMSIVIEW *view, column_info *columns );
|
||||
|
||||
/*
|
||||
* drop - drops the table from the database
|
||||
*/
|
||||
UINT (*drop)( struct tagMSIVIEW *view );
|
||||
} MSIVIEWOPS;
|
||||
|
||||
struct tagMSIVIEW
|
||||
|
@ -288,6 +300,7 @@ typedef struct tagMSIPACKAGE
|
|||
{
|
||||
MSIOBJECTHDR hdr;
|
||||
MSIDATABASE *db;
|
||||
MSIPATCHINFO *patch;
|
||||
struct list components;
|
||||
struct list features;
|
||||
struct list files;
|
||||
|
@ -447,7 +460,6 @@ typedef struct tagMSIFILE
|
|||
INT Attributes;
|
||||
INT Sequence;
|
||||
msi_file_state state;
|
||||
LPWSTR SourcePath;
|
||||
LPWSTR TargetPath;
|
||||
BOOL IsCompressed;
|
||||
MSIFILEHASHINFO hash;
|
||||
|
@ -655,8 +667,6 @@ extern HRESULT msi_init_string_table( IStorage *stg );
|
|||
extern string_table *msi_load_string_table( IStorage *stg, UINT *bytes_per_strref );
|
||||
extern UINT msi_save_string_table( const string_table *st, IStorage *storage );
|
||||
|
||||
|
||||
extern void msi_table_set_strref(UINT bytes_per_strref);
|
||||
extern BOOL TABLE_Exists( MSIDATABASE *db, LPCWSTR name );
|
||||
extern MSICONDITION MSI_DatabaseIsTablePersistent( MSIDATABASE *db, LPCWSTR table );
|
||||
|
||||
|
@ -680,7 +690,8 @@ extern UINT ACTION_DialogBox( MSIPACKAGE*, LPCWSTR);
|
|||
extern UINT ACTION_ForceReboot(MSIPACKAGE *package);
|
||||
extern UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode );
|
||||
extern UINT MSI_SetFeatureStates( MSIPACKAGE *package );
|
||||
extern UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine );
|
||||
extern UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
|
||||
BOOL preserve_case );
|
||||
|
||||
/* record internals */
|
||||
extern UINT MSI_RecordSetIStream( MSIRECORD *, UINT, IStream *);
|
||||
|
@ -700,6 +711,8 @@ extern UINT MSI_RecordSetStream( MSIRECORD *, UINT, IStream * );
|
|||
extern UINT MSI_RecordDataSize( MSIRECORD *, UINT );
|
||||
extern UINT MSI_RecordStreamToFile( MSIRECORD *, UINT, LPCWSTR );
|
||||
extern UINT MSI_RecordCopyField( MSIRECORD *, UINT, MSIRECORD *, UINT );
|
||||
extern MSIRECORD *MSI_CloneRecord( MSIRECORD * );
|
||||
extern BOOL MSI_RecordsAreEqual( MSIRECORD *, MSIRECORD * );
|
||||
|
||||
/* stream internals */
|
||||
extern UINT get_raw_stream( MSIHANDLE hdb, LPCWSTR stname, IStream **stm );
|
||||
|
@ -758,38 +771,35 @@ extern BOOL encode_base85_guid(GUID *,LPWSTR);
|
|||
extern BOOL decode_base85_guid(LPCWSTR,GUID*);
|
||||
extern UINT MSIREG_OpenUninstallKey(LPCWSTR szProduct, HKEY* key, BOOL create);
|
||||
extern UINT MSIREG_DeleteUninstallKey(LPCWSTR szProduct);
|
||||
extern UINT MSIREG_OpenUserProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create);
|
||||
extern UINT MSIREG_OpenProductKey(LPCWSTR szProduct, MSIINSTALLCONTEXT context,
|
||||
HKEY* key, BOOL create);
|
||||
extern UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, MSIINSTALLCONTEXT context,
|
||||
HKEY *key, BOOL create);
|
||||
extern UINT MSIREG_OpenUserPatchesKey(LPCWSTR szPatch, HKEY* key, BOOL create);
|
||||
extern UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
|
||||
extern UINT MSIREG_OpenUserDataFeaturesKey(LPCWSTR szProduct, HKEY *key, BOOL create);
|
||||
extern UINT MSIREG_OpenInstallerFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
|
||||
UINT MSIREG_OpenUserDataFeaturesKey(LPCWSTR szProduct, MSIINSTALLCONTEXT context,
|
||||
HKEY *key, BOOL create);
|
||||
extern UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create);
|
||||
extern UINT MSIREG_OpenLocalUserDataComponentKey(LPCWSTR szComponent, HKEY *key, BOOL create);
|
||||
extern UINT MSIREG_OpenUserDataComponentKey(LPCWSTR szComponent, HKEY *key, BOOL create);
|
||||
extern UINT MSIREG_OpenProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create);
|
||||
extern UINT MSIREG_OpenUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid,
|
||||
HKEY *key, BOOL create);
|
||||
extern UINT MSIREG_OpenPatchesKey(LPCWSTR szPatch, HKEY* key, BOOL create);
|
||||
extern UINT MSIREG_OpenUserDataProductKey(LPCWSTR szProduct, HKEY* key, BOOL create);
|
||||
extern UINT MSIREG_OpenLocalUserDataProductKey(LPCWSTR szProduct, HKEY* key, BOOL create);
|
||||
extern UINT MSIREG_OpenCurrentUserInstallProps(LPCWSTR szProduct, HKEY* key, BOOL create);
|
||||
extern UINT MSIREG_OpenLocalSystemInstallProps(LPCWSTR szProduct, HKEY* key, BOOL create);
|
||||
extern UINT MSIREG_OpenUserFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
|
||||
extern UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create);
|
||||
extern UINT MSIREG_OpenUserDataProductKey(LPCWSTR szProduct, MSIINSTALLCONTEXT dwContext,
|
||||
LPCWSTR szUserSid, HKEY *key, BOOL create);
|
||||
extern UINT MSIREG_OpenUserDataPatchKey(LPCWSTR szPatch, MSIINSTALLCONTEXT dwContext,
|
||||
HKEY *key, BOOL create);
|
||||
extern UINT MSIREG_OpenInstallProps(LPCWSTR szProduct, MSIINSTALLCONTEXT dwContext,
|
||||
LPCWSTR szUserSid, HKEY *key, BOOL create);
|
||||
extern UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
|
||||
extern UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
|
||||
extern UINT MSIREG_DeleteProductKey(LPCWSTR szProduct);
|
||||
extern UINT MSIREG_DeleteUserProductKey(LPCWSTR szProduct);
|
||||
extern UINT MSIREG_DeleteUserDataProductKey(LPCWSTR szProduct);
|
||||
extern UINT MSIREG_OpenLocalSystemProductKey(LPCWSTR szProductCode, HKEY *key, BOOL create);
|
||||
extern UINT MSIREG_OpenLocalSystemComponentKey(LPCWSTR szComponent, HKEY *key, BOOL create);
|
||||
extern UINT MSIREG_OpenLocalClassesProductKey(LPCWSTR szProductCode, HKEY *key, BOOL create);
|
||||
extern UINT MSIREG_OpenLocalClassesFeaturesKey(LPCWSTR szProductCode, HKEY *key, BOOL create);
|
||||
extern UINT MSIREG_OpenLocalManagedProductKey(LPCWSTR szProductCode, HKEY *key, BOOL create);
|
||||
extern UINT MSIREG_OpenManagedFeaturesKey(LPCWSTR szProductCode, HKEY *key, BOOL create);
|
||||
extern UINT MSIREG_OpenLocalUserDataFeaturesKey(LPCWSTR szProduct, HKEY *key, BOOL create);
|
||||
extern UINT MSIREG_DeleteUserFeaturesKey(LPCWSTR szProduct);
|
||||
extern UINT MSIREG_DeleteLocalUserDataComponentKey(LPCWSTR szComponent);
|
||||
extern UINT MSIREG_DeleteUserDataComponentKey(LPCWSTR szComponent);
|
||||
extern UINT MSIREG_DeleteUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid);
|
||||
extern UINT MSIREG_DeleteUserUpgradeCodesKey(LPCWSTR szUpgradeCode);
|
||||
extern UINT MSIREG_OpenClassesUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create);
|
||||
extern UINT MSIREG_DeleteLocalClassesProductKey(LPCWSTR szProductCode);
|
||||
extern UINT MSIREG_DeleteLocalClassesFeaturesKey(LPCWSTR szProductCode);
|
||||
|
||||
extern LPWSTR msi_reg_get_val_str( HKEY hkey, LPCWSTR name );
|
||||
extern BOOL msi_reg_get_val_dword( HKEY hkey, LPCWSTR name, DWORD *val);
|
||||
|
@ -851,16 +861,96 @@ extern UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UIN
|
|||
extern void ACTION_FinishCustomActions( const MSIPACKAGE* package);
|
||||
extern UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action, UINT script, BOOL execute);
|
||||
|
||||
static inline void msi_feature_set_state( MSIFEATURE *feature, INSTALLSTATE state )
|
||||
static inline void msi_feature_set_state(MSIPACKAGE *package,
|
||||
MSIFEATURE *feature,
|
||||
INSTALLSTATE state)
|
||||
{
|
||||
feature->ActionRequest = state;
|
||||
feature->Action = state;
|
||||
if (!package->ProductCode)
|
||||
{
|
||||
feature->ActionRequest = state;
|
||||
feature->Action = state;
|
||||
}
|
||||
else if (state == INSTALLSTATE_ABSENT)
|
||||
{
|
||||
switch (feature->Installed)
|
||||
{
|
||||
case INSTALLSTATE_ABSENT:
|
||||
feature->ActionRequest = INSTALLSTATE_UNKNOWN;
|
||||
feature->Action = INSTALLSTATE_UNKNOWN;
|
||||
break;
|
||||
default:
|
||||
feature->ActionRequest = state;
|
||||
feature->Action = state;
|
||||
}
|
||||
}
|
||||
else if (state == INSTALLSTATE_SOURCE)
|
||||
{
|
||||
switch (feature->Installed)
|
||||
{
|
||||
case INSTALLSTATE_ABSENT:
|
||||
case INSTALLSTATE_SOURCE:
|
||||
feature->ActionRequest = state;
|
||||
feature->Action = state;
|
||||
break;
|
||||
case INSTALLSTATE_LOCAL:
|
||||
feature->ActionRequest = INSTALLSTATE_LOCAL;
|
||||
feature->Action = INSTALLSTATE_LOCAL;
|
||||
break;
|
||||
default:
|
||||
feature->ActionRequest = INSTALLSTATE_UNKNOWN;
|
||||
feature->Action = INSTALLSTATE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
feature->ActionRequest = state;
|
||||
feature->Action = state;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void msi_component_set_state( MSICOMPONENT *comp, INSTALLSTATE state )
|
||||
static inline void msi_component_set_state(MSIPACKAGE *package,
|
||||
MSICOMPONENT *comp,
|
||||
INSTALLSTATE state)
|
||||
{
|
||||
comp->ActionRequest = state;
|
||||
comp->Action = state;
|
||||
if (!package->ProductCode)
|
||||
{
|
||||
comp->ActionRequest = state;
|
||||
comp->Action = state;
|
||||
}
|
||||
else if (state == INSTALLSTATE_ABSENT)
|
||||
{
|
||||
switch (comp->Installed)
|
||||
{
|
||||
case INSTALLSTATE_LOCAL:
|
||||
case INSTALLSTATE_SOURCE:
|
||||
case INSTALLSTATE_DEFAULT:
|
||||
comp->ActionRequest = state;
|
||||
comp->Action = state;
|
||||
break;
|
||||
default:
|
||||
comp->ActionRequest = INSTALLSTATE_UNKNOWN;
|
||||
comp->Action = INSTALLSTATE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
else if (state == INSTALLSTATE_SOURCE)
|
||||
{
|
||||
if (comp->Installed == INSTALLSTATE_ABSENT ||
|
||||
(comp->Installed == INSTALLSTATE_SOURCE && comp->hasLocalFeature))
|
||||
{
|
||||
comp->ActionRequest = state;
|
||||
comp->Action = state;
|
||||
}
|
||||
else
|
||||
{
|
||||
comp->ActionRequest = INSTALLSTATE_UNKNOWN;
|
||||
comp->Action = INSTALLSTATE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
comp->ActionRequest = state;
|
||||
comp->Action = state;
|
||||
}
|
||||
}
|
||||
|
||||
/* actions in other modules */
|
||||
|
@ -883,10 +973,12 @@ extern LPWSTR msi_dup_property(MSIPACKAGE *package, LPCWSTR prop);
|
|||
extern int msi_get_property_int( MSIPACKAGE *package, LPCWSTR prop, int def );
|
||||
extern LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
|
||||
BOOL set_prop, BOOL load_prop, MSIFOLDER **folder);
|
||||
extern LPWSTR resolve_file_source(MSIPACKAGE *package, MSIFILE *file);
|
||||
extern MSICOMPONENT *get_loaded_component( MSIPACKAGE* package, LPCWSTR Component );
|
||||
extern MSIFEATURE *get_loaded_feature( MSIPACKAGE* package, LPCWSTR Feature );
|
||||
extern MSIFILE *get_loaded_file( MSIPACKAGE* package, LPCWSTR file );
|
||||
extern MSIFOLDER *get_loaded_folder( MSIPACKAGE *package, LPCWSTR dir );
|
||||
extern void msi_reset_folders( MSIPACKAGE *package, BOOL source );
|
||||
extern int track_tempfile(MSIPACKAGE *package, LPCWSTR path);
|
||||
extern UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action);
|
||||
extern void msi_free_action_script(MSIPACKAGE *package, UINT script);
|
||||
|
@ -906,10 +998,27 @@ extern UINT msi_create_component_directories( MSIPACKAGE *package );
|
|||
extern void msi_ui_error( DWORD msg_id, DWORD type );
|
||||
extern UINT msi_set_last_used_source(LPCWSTR product, LPCWSTR usersid,
|
||||
MSIINSTALLCONTEXT context, DWORD options, LPCWSTR value);
|
||||
|
||||
/* media */
|
||||
|
||||
typedef BOOL (*PMSICABEXTRACTCB)(MSIPACKAGE *, LPCWSTR, DWORD, LPWSTR *, DWORD *, PVOID);
|
||||
|
||||
#define MSICABEXTRACT_BEGINEXTRACT 0x01
|
||||
#define MSICABEXTRACT_FILEEXTRACTED 0x02
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MSIPACKAGE* package;
|
||||
MSIMEDIAINFO *mi;
|
||||
PMSICABEXTRACTCB cb;
|
||||
LPWSTR curfile;
|
||||
PVOID user;
|
||||
} MSICABDATA;
|
||||
|
||||
extern UINT ready_media(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO *mi);
|
||||
extern UINT msi_load_media_info(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO *mi);
|
||||
extern void msi_free_media_info(MSIMEDIAINFO *mi);
|
||||
extern BOOL msi_cabextract(MSIPACKAGE* package, MSIMEDIAINFO *mi, PFNFDINOTIFY notify, LPVOID data);
|
||||
extern UINT msi_extract_file(MSIPACKAGE *package, MSIFILE *file, LPWSTR destdir);
|
||||
extern BOOL msi_cabextract(MSIPACKAGE* package, MSIMEDIAINFO *mi, LPVOID data);
|
||||
extern UINT find_published_source(MSIPACKAGE *package, MSIMEDIAINFO *mi);
|
||||
|
||||
/* control event stuff */
|
||||
|
@ -937,26 +1046,30 @@ extern void ui_actiondata(MSIPACKAGE *, LPCWSTR, MSIRECORD *);
|
|||
/* string consts use a number of places and defined in helpers.c*/
|
||||
extern const WCHAR cszSourceDir[];
|
||||
extern const WCHAR cszSOURCEDIR[];
|
||||
extern const WCHAR szProductCode[];
|
||||
extern const WCHAR cszRootDrive[];
|
||||
extern const WCHAR cszbs[];
|
||||
extern const WCHAR szLocalSid[];
|
||||
|
||||
/* memory allocation macro functions */
|
||||
static void *msi_alloc( size_t len ) __WINE_ALLOC_SIZE(1);
|
||||
static inline void *msi_alloc( size_t len )
|
||||
{
|
||||
return HeapAlloc( GetProcessHeap(), 0, len );
|
||||
}
|
||||
|
||||
static void *msi_alloc_zero( size_t len ) __WINE_ALLOC_SIZE(1);
|
||||
static inline void *msi_alloc_zero( size_t len )
|
||||
{
|
||||
return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len );
|
||||
}
|
||||
|
||||
static void *msi_realloc( void *mem, size_t len ) __WINE_ALLOC_SIZE(2);
|
||||
static inline void *msi_realloc( void *mem, size_t len )
|
||||
{
|
||||
return HeapReAlloc( GetProcessHeap(), 0, mem, len );
|
||||
}
|
||||
|
||||
static void *msi_realloc_zero( void *mem, size_t len ) __WINE_ALLOC_SIZE(2);
|
||||
static inline void *msi_realloc_zero( void *mem, size_t len )
|
||||
{
|
||||
return HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, mem, len );
|
||||
|
|
|
@ -633,7 +633,7 @@ MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, LPWSTR szColumnNameBuffer,
|
|||
MSIQUERY *query = NULL;
|
||||
static const WCHAR szError[] = { 0 };
|
||||
MSIDBERROR r = MSIDBERROR_NOERROR;
|
||||
int len;
|
||||
DWORD len;
|
||||
|
||||
FIXME("%ld %p %p - returns empty error string\n",
|
||||
handle, szColumnNameBuffer, pcchBuf );
|
||||
|
@ -645,7 +645,7 @@ MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, LPWSTR szColumnNameBuffer,
|
|||
if( !query )
|
||||
return MSIDBERROR_INVALIDARG;
|
||||
|
||||
len = lstrlenW( szError );
|
||||
len = strlenW( szError );
|
||||
if( szColumnNameBuffer )
|
||||
{
|
||||
if( *pcchBuf > len )
|
||||
|
@ -665,7 +665,7 @@ MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR szColumnNameBuffer,
|
|||
static const CHAR szError[] = { 0 };
|
||||
MSIQUERY *query = NULL;
|
||||
MSIDBERROR r = MSIDBERROR_NOERROR;
|
||||
int len;
|
||||
DWORD len;
|
||||
|
||||
FIXME("%ld %p %p - returns empty error string\n",
|
||||
handle, szColumnNameBuffer, pcchBuf );
|
||||
|
@ -677,7 +677,7 @@ MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR szColumnNameBuffer,
|
|||
if( !query )
|
||||
return MSIDBERROR_INVALIDARG;
|
||||
|
||||
len = lstrlenA( szError );
|
||||
len = strlen( szError );
|
||||
if( szColumnNameBuffer )
|
||||
{
|
||||
if( *pcchBuf > len )
|
||||
|
|
|
@ -731,6 +731,7 @@ static MSIPACKAGE *msi_alloc_package( void )
|
|||
list_init( &package->sourcelist_info );
|
||||
list_init( &package->sourcelist_media );
|
||||
|
||||
package->patch = NULL;
|
||||
package->ActionFormat = NULL;
|
||||
package->LastAction = NULL;
|
||||
package->dialog = NULL;
|
||||
|
@ -754,7 +755,7 @@ static UINT msi_load_admin_properties(MSIPACKAGE *package)
|
|||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
r = msi_parse_command_line(package, (WCHAR *)data);
|
||||
r = msi_parse_command_line(package, (WCHAR *)data, TRUE);
|
||||
|
||||
msi_free(data);
|
||||
return r;
|
||||
|
@ -1345,6 +1346,9 @@ UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
|
|||
|
||||
msiobj_release(&row->hdr);
|
||||
|
||||
if (rc == ERROR_SUCCESS && (!lstrcmpW(szName, cszSourceDir)))
|
||||
msi_reset_folders(package, TRUE);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -117,6 +117,8 @@ UINT STREAMS_CreateView( MSIDATABASE *db, MSIVIEW **view );
|
|||
|
||||
UINT STORAGES_CreateView( MSIDATABASE *db, MSIVIEW **view );
|
||||
|
||||
UINT DROP_CreateView( MSIDATABASE *db, MSIVIEW **view, LPCWSTR name );
|
||||
|
||||
int sqliteGetToken(const WCHAR *z, int *tokenType);
|
||||
|
||||
MSIRECORD *msi_query_merge_record( UINT fields, const column_info *vl, MSIRECORD *rec );
|
||||
|
|
|
@ -358,15 +358,16 @@ UINT MSI_RecordGetStringA(MSIRECORD *rec, UINT iField,
|
|||
case MSIFIELD_WSTR:
|
||||
len = WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1,
|
||||
NULL, 0 , NULL, NULL);
|
||||
WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1,
|
||||
szValue, *pcchValue, NULL, NULL);
|
||||
if (szValue)
|
||||
WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1,
|
||||
szValue, *pcchValue, NULL, NULL);
|
||||
if( szValue && *pcchValue && len>*pcchValue )
|
||||
szValue[*pcchValue-1] = 0;
|
||||
if( len )
|
||||
len--;
|
||||
break;
|
||||
case MSIFIELD_NULL:
|
||||
if( *pcchValue > 0 )
|
||||
if( szValue && *pcchValue > 0 )
|
||||
szValue[0] = 0;
|
||||
break;
|
||||
default:
|
||||
|
@ -903,3 +904,74 @@ UINT MSI_RecordStreamToFile( MSIRECORD *rec, UINT iField, LPCWSTR name )
|
|||
|
||||
return r;
|
||||
}
|
||||
|
||||
MSIRECORD *MSI_CloneRecord(MSIRECORD *rec)
|
||||
{
|
||||
MSIRECORD *clone;
|
||||
UINT r, i, count;
|
||||
|
||||
count = MSI_RecordGetFieldCount(rec);
|
||||
clone = MSI_CreateRecord(count);
|
||||
if (!clone)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i <= count; i++)
|
||||
{
|
||||
if (rec->fields[i].type == MSIFIELD_STREAM)
|
||||
{
|
||||
if (FAILED(IStream_Clone(rec->fields[i].u.stream,
|
||||
&clone->fields[i].u.stream)))
|
||||
{
|
||||
msiobj_release(&clone->hdr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
r = MSI_RecordCopyField(rec, i, clone, i);
|
||||
if (r != ERROR_SUCCESS)
|
||||
{
|
||||
msiobj_release(&clone->hdr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
BOOL MSI_RecordsAreEqual(MSIRECORD *a, MSIRECORD *b)
|
||||
{
|
||||
UINT i;
|
||||
|
||||
if (a->count != b->count)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i <= a->count; i++)
|
||||
{
|
||||
if (a->fields[i].type != b->fields[i].type)
|
||||
return FALSE;
|
||||
|
||||
switch (a->fields[i].type)
|
||||
{
|
||||
case MSIFIELD_NULL:
|
||||
break;
|
||||
|
||||
case MSIFIELD_INT:
|
||||
if (a->fields[i].u.iVal != b->fields[i].u.iVal)
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
case MSIFIELD_WSTR:
|
||||
if (lstrcmpW(a->fields[i].u.szwVal, b->fields[i].u.szwVal))
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
case MSIFIELD_STREAM:
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -36,6 +36,7 @@
|
|||
#include "oleauto.h"
|
||||
|
||||
#include "wine/debug.h"
|
||||
#include "wine/unicode.h"
|
||||
|
||||
#include "msi.h"
|
||||
#include "initguid.h"
|
||||
|
@ -80,6 +81,7 @@ struct regsvr_coclass {
|
|||
LPCSTR progid; /* can be NULL to omit */
|
||||
LPCSTR viprogid; /* can be NULL to omit */
|
||||
LPCSTR progid_extra; /* can be NULL to omit */
|
||||
LPCSTR dllversion; /* can be NULL to omit */
|
||||
};
|
||||
|
||||
/* flags for regsvr_coclass.flags */
|
||||
|
@ -123,6 +125,8 @@ static WCHAR const viprogid_keyname[25] = {
|
|||
'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
|
||||
'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
|
||||
0 };
|
||||
static WCHAR const dllversion_keyname[11] = {
|
||||
'D', 'l', 'l', 'V', 'e', 'r', 's', 'i', 'o', 'n', 0 };
|
||||
static char const tmodel_valuename[] = "ThreadingModel";
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -177,7 +181,7 @@ static HRESULT register_interfaces(struct regsvr_interface const *list) {
|
|||
KEY_READ | KEY_WRITE, NULL, &key, NULL);
|
||||
if (res != ERROR_SUCCESS) goto error_close_iid_key;
|
||||
|
||||
wsprintfW(buf, fmt, list->num_methods);
|
||||
sprintfW(buf, fmt, list->num_methods);
|
||||
res = RegSetValueExW(key, NULL, 0, REG_SZ,
|
||||
(CONST BYTE*)buf,
|
||||
(lstrlenW(buf) + 1) * sizeof(WCHAR));
|
||||
|
@ -319,6 +323,22 @@ static HRESULT register_coclasses(struct regsvr_coclass const *list) {
|
|||
if (res != ERROR_SUCCESS) goto error_close_clsid_key;
|
||||
}
|
||||
|
||||
if (list->dllversion) {
|
||||
HKEY dllver_key;
|
||||
|
||||
res = RegCreateKeyExW(clsid_key, dllversion_keyname, 0, NULL, 0,
|
||||
KEY_READ | KEY_WRITE, NULL,
|
||||
&dllver_key, NULL);
|
||||
if (res != ERROR_SUCCESS) goto error_close_clsid_key;
|
||||
|
||||
res = RegSetValueExA(dllver_key, NULL, 0, REG_SZ,
|
||||
(CONST BYTE*)list->dllversion,
|
||||
lstrlenA(list->dllversion) + 1);
|
||||
RegCloseKey(dllver_key);
|
||||
if (res != ERROR_SUCCESS) goto error_close_clsid_key;
|
||||
}
|
||||
|
||||
|
||||
error_close_clsid_key:
|
||||
RegCloseKey(clsid_key);
|
||||
}
|
||||
|
@ -478,6 +498,8 @@ static struct regsvr_coclass const coclass_list[] = {
|
|||
"Apartment",
|
||||
PROGID_CLSID,
|
||||
"IMsiServer",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
},
|
||||
{
|
||||
|
@ -489,7 +511,9 @@ static struct regsvr_coclass const coclass_list[] = {
|
|||
NULL,
|
||||
PROGID_CLSID,
|
||||
"WindowsInstaller.Message",
|
||||
NULL
|
||||
NULL,
|
||||
NULL,
|
||||
"3.1.4000"
|
||||
},
|
||||
{
|
||||
&CLSID_IMsiServerX1,
|
||||
|
@ -500,6 +524,8 @@ static struct regsvr_coclass const coclass_list[] = {
|
|||
"Apartment",
|
||||
0,
|
||||
"WindowsInstaller.Installer",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
},
|
||||
{
|
||||
|
@ -511,6 +537,8 @@ static struct regsvr_coclass const coclass_list[] = {
|
|||
"Apartment",
|
||||
PROGID_CLSID,
|
||||
"WindowsInstaller.Installer",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
},
|
||||
{
|
||||
|
@ -522,6 +550,8 @@ static struct regsvr_coclass const coclass_list[] = {
|
|||
"Apartment",
|
||||
0,
|
||||
"WindowsInstaller.Installer",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
},
|
||||
{ NULL } /* list terminator */
|
||||
|
|
|
@ -363,6 +363,7 @@ static const MSIVIEWOPS select_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
SELECT_sort,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name )
|
||||
|
|
|
@ -64,21 +64,21 @@ static UINT OpenSourceKey(LPCWSTR szProduct, HKEY* key, DWORD dwOptions,
|
|||
if (dwOptions & MSICODE_PATCH)
|
||||
rc = MSIREG_OpenUserPatchesKey(szProduct, &rootkey, create);
|
||||
else
|
||||
rc = MSIREG_OpenUserProductsKey(szProduct, &rootkey, create);
|
||||
rc = MSIREG_OpenProductKey(szProduct, context, &rootkey, create);
|
||||
}
|
||||
else if (context == MSIINSTALLCONTEXT_USERMANAGED)
|
||||
{
|
||||
if (dwOptions & MSICODE_PATCH)
|
||||
rc = MSIREG_OpenUserPatchesKey(szProduct, &rootkey, create);
|
||||
else
|
||||
rc = MSIREG_OpenLocalManagedProductKey(szProduct, &rootkey, create);
|
||||
rc = MSIREG_OpenProductKey(szProduct, context, &rootkey, create);
|
||||
}
|
||||
else if (context == MSIINSTALLCONTEXT_MACHINE)
|
||||
{
|
||||
if (dwOptions & MSICODE_PATCH)
|
||||
rc = MSIREG_OpenPatchesKey(szProduct, &rootkey, create);
|
||||
else
|
||||
rc = MSIREG_OpenLocalClassesProductKey(szProduct, &rootkey, create);
|
||||
rc = MSIREG_OpenProductKey(szProduct, context, &rootkey, create);
|
||||
}
|
||||
|
||||
if (rc != ERROR_SUCCESS)
|
||||
|
@ -208,16 +208,19 @@ UINT WINAPI MsiSourceListEnumMediaDisksW(LPCWSTR szProductCodeOrPatchCode,
|
|||
LPWSTR szDiskPrompt, LPDWORD pcchDiskPrompt)
|
||||
{
|
||||
WCHAR squished_pc[GUID_SIZE];
|
||||
WCHAR convert[11];
|
||||
LPWSTR value = NULL;
|
||||
LPWSTR data = NULL;
|
||||
LPWSTR ptr;
|
||||
LPWSTR ptr, ptr2;
|
||||
HKEY source, media;
|
||||
DWORD valuesz, datasz = 0;
|
||||
DWORD type;
|
||||
DWORD numvals, size;
|
||||
LONG res;
|
||||
UINT r;
|
||||
static int index = 0;
|
||||
static DWORD index = 0;
|
||||
|
||||
static const WCHAR fmt[] = {'#','%','d',0};
|
||||
|
||||
TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p)\n", debugstr_w(szProductCodeOrPatchCode),
|
||||
debugstr_w(szUserSid), dwContext, dwOptions, dwIndex, szVolumeLabel,
|
||||
|
@ -285,6 +288,7 @@ UINT WINAPI MsiSourceListEnumMediaDisksW(LPCWSTR szProductCodeOrPatchCode,
|
|||
if (pdwDiskId)
|
||||
*pdwDiskId = atolW(value);
|
||||
|
||||
ptr2 = data;
|
||||
ptr = strchrW(data, ';');
|
||||
if (!ptr)
|
||||
ptr = data;
|
||||
|
@ -293,11 +297,19 @@ UINT WINAPI MsiSourceListEnumMediaDisksW(LPCWSTR szProductCodeOrPatchCode,
|
|||
|
||||
if (pcchVolumeLabel)
|
||||
{
|
||||
size = lstrlenW(data);
|
||||
if (type == REG_DWORD)
|
||||
{
|
||||
sprintfW(convert, fmt, *data);
|
||||
size = lstrlenW(convert);
|
||||
ptr2 = convert;
|
||||
}
|
||||
else
|
||||
size = lstrlenW(data);
|
||||
|
||||
if (size >= *pcchVolumeLabel)
|
||||
r = ERROR_MORE_DATA;
|
||||
else if (szVolumeLabel)
|
||||
lstrcpyW(szVolumeLabel, data);
|
||||
lstrcpyW(szVolumeLabel, ptr2);
|
||||
|
||||
*pcchVolumeLabel = size;
|
||||
}
|
||||
|
@ -307,6 +319,15 @@ UINT WINAPI MsiSourceListEnumMediaDisksW(LPCWSTR szProductCodeOrPatchCode,
|
|||
if (!*ptr)
|
||||
ptr++;
|
||||
|
||||
if (type == REG_DWORD)
|
||||
{
|
||||
sprintfW(convert, fmt, *ptr);
|
||||
size = lstrlenW(convert);
|
||||
ptr = convert;
|
||||
}
|
||||
else
|
||||
size = lstrlenW(ptr);
|
||||
|
||||
size = lstrlenW(ptr);
|
||||
if (size >= *pcchDiskPrompt)
|
||||
r = ERROR_MORE_DATA;
|
||||
|
@ -339,7 +360,7 @@ UINT WINAPI MsiSourceListEnumSourcesA(LPCSTR szProductCodeOrPatch, LPCSTR szUser
|
|||
LPWSTR source = NULL;
|
||||
DWORD len = 0;
|
||||
UINT r = ERROR_INVALID_PARAMETER;
|
||||
static int index = 0;
|
||||
static DWORD index = 0;
|
||||
|
||||
TRACE("(%s, %s, %d, %d, %d, %p, %p)\n", debugstr_a(szProductCodeOrPatch),
|
||||
debugstr_a(szUserSid), dwContext, dwOptions, dwIndex, szSource, pcchSource);
|
||||
|
@ -412,7 +433,7 @@ UINT WINAPI MsiSourceListEnumSourcesW(LPCWSTR szProductCodeOrPatch, LPCWSTR szUs
|
|||
HKEY subkey = NULL;
|
||||
LONG res;
|
||||
UINT r = ERROR_INVALID_PARAMETER;
|
||||
static int index = 0;
|
||||
static DWORD index = 0;
|
||||
|
||||
static const WCHAR format[] = {'%','d',0};
|
||||
|
||||
|
@ -633,7 +654,7 @@ UINT WINAPI MsiSourceListGetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
|
|||
|
||||
if (szValue)
|
||||
{
|
||||
if (lstrlenW(ptr) < *pcchValue)
|
||||
if (strlenW(ptr) < *pcchValue)
|
||||
lstrcpyW(szValue, ptr);
|
||||
else
|
||||
rc = ERROR_MORE_DATA;
|
||||
|
@ -882,12 +903,14 @@ UINT WINAPI MsiSourceListAddSourceW( LPCWSTR szProduct, LPCWSTR szUserName,
|
|||
msi_free(psid);
|
||||
}
|
||||
|
||||
r = MSIREG_OpenLocalManagedProductKey(szProduct, &hkey, FALSE);
|
||||
r = MSIREG_OpenProductKey(szProduct, MSIINSTALLCONTEXT_USERMANAGED,
|
||||
&hkey, FALSE);
|
||||
if (r == ERROR_SUCCESS)
|
||||
context = MSIINSTALLCONTEXT_USERMANAGED;
|
||||
else
|
||||
{
|
||||
r = MSIREG_OpenUserProductsKey(szProduct, &hkey, FALSE);
|
||||
r = MSIREG_OpenProductKey(szProduct, MSIINSTALLCONTEXT_USERUNMANAGED,
|
||||
&hkey, FALSE);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return ERROR_UNKNOWN_PRODUCT;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -36,59 +36,60 @@
|
|||
TK_COMMA = 262,
|
||||
TK_CREATE = 263,
|
||||
TK_DELETE = 264,
|
||||
TK_DISTINCT = 265,
|
||||
TK_DOT = 266,
|
||||
TK_EQ = 267,
|
||||
TK_FREE = 268,
|
||||
TK_FROM = 269,
|
||||
TK_GE = 270,
|
||||
TK_GT = 271,
|
||||
TK_HOLD = 272,
|
||||
TK_ADD = 273,
|
||||
TK_ID = 274,
|
||||
TK_ILLEGAL = 275,
|
||||
TK_INSERT = 276,
|
||||
TK_INT = 277,
|
||||
TK_INTEGER = 278,
|
||||
TK_INTO = 279,
|
||||
TK_IS = 280,
|
||||
TK_KEY = 281,
|
||||
TK_LE = 282,
|
||||
TK_LONG = 283,
|
||||
TK_LONGCHAR = 284,
|
||||
TK_LP = 285,
|
||||
TK_LT = 286,
|
||||
TK_LOCALIZABLE = 287,
|
||||
TK_MINUS = 288,
|
||||
TK_NE = 289,
|
||||
TK_NOT = 290,
|
||||
TK_NULL = 291,
|
||||
TK_OBJECT = 292,
|
||||
TK_OR = 293,
|
||||
TK_ORDER = 294,
|
||||
TK_PRIMARY = 295,
|
||||
TK_RP = 296,
|
||||
TK_SELECT = 297,
|
||||
TK_SET = 298,
|
||||
TK_SHORT = 299,
|
||||
TK_SPACE = 300,
|
||||
TK_STAR = 301,
|
||||
TK_STRING = 302,
|
||||
TK_TABLE = 303,
|
||||
TK_TEMPORARY = 304,
|
||||
TK_UPDATE = 305,
|
||||
TK_VALUES = 306,
|
||||
TK_WHERE = 307,
|
||||
TK_WILDCARD = 308,
|
||||
COLUMN = 310,
|
||||
FUNCTION = 311,
|
||||
COMMENT = 312,
|
||||
UNCLOSED_STRING = 313,
|
||||
SPACE = 314,
|
||||
ILLEGAL = 315,
|
||||
END_OF_FILE = 316,
|
||||
TK_LIKE = 317,
|
||||
TK_NEGATION = 318
|
||||
TK_DROP = 265,
|
||||
TK_DISTINCT = 266,
|
||||
TK_DOT = 267,
|
||||
TK_EQ = 268,
|
||||
TK_FREE = 269,
|
||||
TK_FROM = 270,
|
||||
TK_GE = 271,
|
||||
TK_GT = 272,
|
||||
TK_HOLD = 273,
|
||||
TK_ADD = 274,
|
||||
TK_ID = 275,
|
||||
TK_ILLEGAL = 276,
|
||||
TK_INSERT = 277,
|
||||
TK_INT = 278,
|
||||
TK_INTEGER = 279,
|
||||
TK_INTO = 280,
|
||||
TK_IS = 281,
|
||||
TK_KEY = 282,
|
||||
TK_LE = 283,
|
||||
TK_LONG = 284,
|
||||
TK_LONGCHAR = 285,
|
||||
TK_LP = 286,
|
||||
TK_LT = 287,
|
||||
TK_LOCALIZABLE = 288,
|
||||
TK_MINUS = 289,
|
||||
TK_NE = 290,
|
||||
TK_NOT = 291,
|
||||
TK_NULL = 292,
|
||||
TK_OBJECT = 293,
|
||||
TK_OR = 294,
|
||||
TK_ORDER = 295,
|
||||
TK_PRIMARY = 296,
|
||||
TK_RP = 297,
|
||||
TK_SELECT = 298,
|
||||
TK_SET = 299,
|
||||
TK_SHORT = 300,
|
||||
TK_SPACE = 301,
|
||||
TK_STAR = 302,
|
||||
TK_STRING = 303,
|
||||
TK_TABLE = 304,
|
||||
TK_TEMPORARY = 305,
|
||||
TK_UPDATE = 306,
|
||||
TK_VALUES = 307,
|
||||
TK_WHERE = 308,
|
||||
TK_WILDCARD = 309,
|
||||
COLUMN = 311,
|
||||
FUNCTION = 312,
|
||||
COMMENT = 313,
|
||||
UNCLOSED_STRING = 314,
|
||||
SPACE = 315,
|
||||
ILLEGAL = 316,
|
||||
END_OF_FILE = 317,
|
||||
TK_LIKE = 318,
|
||||
TK_NEGATION = 319
|
||||
};
|
||||
#endif
|
||||
/* Tokens. */
|
||||
|
@ -99,59 +100,60 @@
|
|||
#define TK_COMMA 262
|
||||
#define TK_CREATE 263
|
||||
#define TK_DELETE 264
|
||||
#define TK_DISTINCT 265
|
||||
#define TK_DOT 266
|
||||
#define TK_EQ 267
|
||||
#define TK_FREE 268
|
||||
#define TK_FROM 269
|
||||
#define TK_GE 270
|
||||
#define TK_GT 271
|
||||
#define TK_HOLD 272
|
||||
#define TK_ADD 273
|
||||
#define TK_ID 274
|
||||
#define TK_ILLEGAL 275
|
||||
#define TK_INSERT 276
|
||||
#define TK_INT 277
|
||||
#define TK_INTEGER 278
|
||||
#define TK_INTO 279
|
||||
#define TK_IS 280
|
||||
#define TK_KEY 281
|
||||
#define TK_LE 282
|
||||
#define TK_LONG 283
|
||||
#define TK_LONGCHAR 284
|
||||
#define TK_LP 285
|
||||
#define TK_LT 286
|
||||
#define TK_LOCALIZABLE 287
|
||||
#define TK_MINUS 288
|
||||
#define TK_NE 289
|
||||
#define TK_NOT 290
|
||||
#define TK_NULL 291
|
||||
#define TK_OBJECT 292
|
||||
#define TK_OR 293
|
||||
#define TK_ORDER 294
|
||||
#define TK_PRIMARY 295
|
||||
#define TK_RP 296
|
||||
#define TK_SELECT 297
|
||||
#define TK_SET 298
|
||||
#define TK_SHORT 299
|
||||
#define TK_SPACE 300
|
||||
#define TK_STAR 301
|
||||
#define TK_STRING 302
|
||||
#define TK_TABLE 303
|
||||
#define TK_TEMPORARY 304
|
||||
#define TK_UPDATE 305
|
||||
#define TK_VALUES 306
|
||||
#define TK_WHERE 307
|
||||
#define TK_WILDCARD 308
|
||||
#define COLUMN 310
|
||||
#define FUNCTION 311
|
||||
#define COMMENT 312
|
||||
#define UNCLOSED_STRING 313
|
||||
#define SPACE 314
|
||||
#define ILLEGAL 315
|
||||
#define END_OF_FILE 316
|
||||
#define TK_LIKE 317
|
||||
#define TK_NEGATION 318
|
||||
#define TK_DROP 265
|
||||
#define TK_DISTINCT 266
|
||||
#define TK_DOT 267
|
||||
#define TK_EQ 268
|
||||
#define TK_FREE 269
|
||||
#define TK_FROM 270
|
||||
#define TK_GE 271
|
||||
#define TK_GT 272
|
||||
#define TK_HOLD 273
|
||||
#define TK_ADD 274
|
||||
#define TK_ID 275
|
||||
#define TK_ILLEGAL 276
|
||||
#define TK_INSERT 277
|
||||
#define TK_INT 278
|
||||
#define TK_INTEGER 279
|
||||
#define TK_INTO 280
|
||||
#define TK_IS 281
|
||||
#define TK_KEY 282
|
||||
#define TK_LE 283
|
||||
#define TK_LONG 284
|
||||
#define TK_LONGCHAR 285
|
||||
#define TK_LP 286
|
||||
#define TK_LT 287
|
||||
#define TK_LOCALIZABLE 288
|
||||
#define TK_MINUS 289
|
||||
#define TK_NE 290
|
||||
#define TK_NOT 291
|
||||
#define TK_NULL 292
|
||||
#define TK_OBJECT 293
|
||||
#define TK_OR 294
|
||||
#define TK_ORDER 295
|
||||
#define TK_PRIMARY 296
|
||||
#define TK_RP 297
|
||||
#define TK_SELECT 298
|
||||
#define TK_SET 299
|
||||
#define TK_SHORT 300
|
||||
#define TK_SPACE 301
|
||||
#define TK_STAR 302
|
||||
#define TK_STRING 303
|
||||
#define TK_TABLE 304
|
||||
#define TK_TEMPORARY 305
|
||||
#define TK_UPDATE 306
|
||||
#define TK_VALUES 307
|
||||
#define TK_WHERE 308
|
||||
#define TK_WILDCARD 309
|
||||
#define COLUMN 311
|
||||
#define FUNCTION 312
|
||||
#define COMMENT 313
|
||||
#define UNCLOSED_STRING 314
|
||||
#define SPACE 315
|
||||
#define ILLEGAL 316
|
||||
#define END_OF_FILE 317
|
||||
#define TK_LIKE 318
|
||||
#define TK_NEGATION 319
|
||||
|
||||
|
||||
|
||||
|
@ -168,7 +170,7 @@ typedef union YYSTYPE {
|
|||
int integer;
|
||||
} YYSTYPE;
|
||||
/* Line 1447 of yacc.c. */
|
||||
#line 172 "sql.tab.h"
|
||||
#line 174 "sql.tab.h"
|
||||
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
|
||||
# define YYSTYPE_IS_DECLARED 1
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
|
|
|
@ -81,7 +81,7 @@ static struct expr * EXPR_wildcard( void *info );
|
|||
int integer;
|
||||
}
|
||||
|
||||
%token TK_ALTER TK_AND TK_BY TK_CHAR TK_COMMA TK_CREATE TK_DELETE
|
||||
%token TK_ALTER TK_AND TK_BY TK_CHAR TK_COMMA TK_CREATE TK_DELETE TK_DROP
|
||||
%token TK_DISTINCT TK_DOT TK_EQ TK_FREE TK_FROM TK_GE TK_GT TK_HOLD TK_ADD
|
||||
%token <str> TK_ID
|
||||
%token TK_ILLEGAL TK_INSERT TK_INT
|
||||
|
@ -106,7 +106,7 @@ static struct expr * EXPR_wildcard( void *info );
|
|||
%type <column_list> selcollist column column_and_type column_def table_def
|
||||
%type <column_list> column_assignment update_assign_list constlist
|
||||
%type <query> query from fromtable selectfrom unorderedsel
|
||||
%type <query> oneupdate onedelete oneselect onequery onecreate oneinsert onealter
|
||||
%type <query> oneupdate onedelete oneselect onequery onecreate oneinsert onealter onedrop
|
||||
%type <expr> expr val column_val const_val
|
||||
%type <column_type> column_type data_type data_type_l data_count
|
||||
%type <integer> number alterop
|
||||
|
@ -135,6 +135,7 @@ onequery:
|
|||
| oneupdate
|
||||
| onedelete
|
||||
| onealter
|
||||
| onedrop
|
||||
;
|
||||
|
||||
oneinsert:
|
||||
|
@ -267,6 +268,19 @@ alterop:
|
|||
}
|
||||
;
|
||||
|
||||
onedrop:
|
||||
TK_DROP TK_TABLE table
|
||||
{
|
||||
SQL_input* sql = (SQL_input*) info;
|
||||
UINT r;
|
||||
|
||||
$$ = NULL;
|
||||
r = DROP_CreateView( sql->db, &$$, $3 );
|
||||
if( r != ERROR_SUCCESS || !$$ )
|
||||
YYABORT;
|
||||
}
|
||||
;
|
||||
|
||||
table_def:
|
||||
column_def TK_PRIMARY TK_KEY selcollist
|
||||
{
|
||||
|
|
|
@ -184,7 +184,7 @@ done:
|
|||
static UINT STORAGES_set_row(struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask)
|
||||
{
|
||||
MSISTORAGESVIEW *sv = (MSISTORAGESVIEW *)view;
|
||||
IStorage *stg, *substg;
|
||||
IStorage *stg, *substg = NULL;
|
||||
IStream *stm;
|
||||
LPWSTR name = NULL;
|
||||
HRESULT hr;
|
||||
|
@ -236,7 +236,7 @@ static UINT STORAGES_set_row(struct tagMSIVIEW *view, UINT row, MSIRECORD *rec,
|
|||
done:
|
||||
msi_free(name);
|
||||
|
||||
IStorage_Release(substg);
|
||||
if (substg) IStorage_Release(substg);
|
||||
IStorage_Release(stg);
|
||||
IStream_Release(stm);
|
||||
|
||||
|
@ -474,6 +474,7 @@ static const MSIVIEWOPS storages_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static INT add_storages_to_table(MSISTORAGESVIEW *sv)
|
||||
|
|
|
@ -438,6 +438,7 @@ static const MSIVIEWOPS streams_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static INT add_streams_to_table(MSISTREAMSVIEW *sv)
|
||||
|
@ -464,6 +465,9 @@ static INT add_streams_to_table(MSISTREAMSVIEW *sv)
|
|||
if (FAILED(hr) || !size)
|
||||
break;
|
||||
|
||||
if (stat.type != STGTY_STREAM)
|
||||
continue;
|
||||
|
||||
/* table streams are not in the _Streams table */
|
||||
if (*stat.pwcsName == 0x4840)
|
||||
{
|
||||
|
|
|
@ -169,8 +169,7 @@ static UINT propvar_changetype(PROPVARIANT *changed, PROPVARIANT *property, VART
|
|||
static void read_properties_from_data( PROPVARIANT *prop, LPBYTE data, DWORD sz )
|
||||
{
|
||||
UINT type;
|
||||
DWORD i;
|
||||
int size;
|
||||
DWORD i, size;
|
||||
PROPERTY_DATA *propdata;
|
||||
PROPVARIANT property, *ptr;
|
||||
PROPVARIANT changed;
|
||||
|
|
|
@ -101,43 +101,33 @@ static WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 };
|
|||
static WCHAR szNumber[] = { 'N','u','m','b','e','r',0 };
|
||||
static WCHAR szType[] = { 'T','y','p','e',0 };
|
||||
|
||||
/* These tables are written into (the .hash_table part).
|
||||
* Do not mark them const.
|
||||
*/
|
||||
static MSICOLUMNINFO _Columns_cols[4] = {
|
||||
static const MSICOLUMNINFO _Columns_cols[4] = {
|
||||
{ szColumns, 1, szTable, MSITYPE_VALID | MSITYPE_STRING | MSITYPE_KEY | 64, 0, 0, NULL },
|
||||
{ szColumns, 2, szNumber, MSITYPE_VALID | MSITYPE_KEY | 2, 2, 0, NULL },
|
||||
{ szColumns, 3, szName, MSITYPE_VALID | MSITYPE_STRING | 64, 4, 0, NULL },
|
||||
{ szColumns, 4, szType, MSITYPE_VALID | 2, 6, 0, NULL },
|
||||
};
|
||||
static MSICOLUMNINFO _Tables_cols[1] = {
|
||||
{ szTables, 1, szName, MSITYPE_VALID | MSITYPE_STRING | 64, 0, 0, NULL },
|
||||
|
||||
static const MSICOLUMNINFO _Tables_cols[1] = {
|
||||
{ szTables, 1, szName, MSITYPE_VALID | MSITYPE_STRING | MSITYPE_KEY | 64, 0, 0, NULL },
|
||||
};
|
||||
|
||||
#define MAX_STREAM_NAME 0x1f
|
||||
|
||||
static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name,
|
||||
MSICOLUMNINFO **pcols, UINT *pcount );
|
||||
static void table_calc_column_offsets( MSICOLUMNINFO *colinfo, DWORD count );
|
||||
static void table_calc_column_offsets( MSIDATABASE *db, MSICOLUMNINFO *colinfo,
|
||||
DWORD count );
|
||||
static UINT get_tablecolumns( MSIDATABASE *db,
|
||||
LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz);
|
||||
static void msi_free_colinfo( MSICOLUMNINFO *colinfo, UINT count );
|
||||
|
||||
|
||||
void msi_table_set_strref(UINT bytes_per_strref)
|
||||
{
|
||||
_Columns_cols[0].offset = 0;
|
||||
_Columns_cols[1].offset = bytes_per_strref;
|
||||
_Columns_cols[2].offset = _Columns_cols[1].offset + sizeof(USHORT);
|
||||
_Columns_cols[3].offset = _Columns_cols[2].offset + bytes_per_strref;
|
||||
}
|
||||
|
||||
static inline UINT bytes_per_column( const MSICOLUMNINFO *col )
|
||||
static inline UINT bytes_per_column( MSIDATABASE *db, const MSICOLUMNINFO *col )
|
||||
{
|
||||
if( MSITYPE_IS_BINARY(col->type) )
|
||||
return 2;
|
||||
if( col->type & MSITYPE_STRING )
|
||||
return _Columns_cols[1].offset;
|
||||
return db->bytes_per_strref;
|
||||
if( (col->type & 0xff) > 4 )
|
||||
ERR("Invalid column size!\n");
|
||||
return col->type & 0xff;
|
||||
|
@ -488,32 +478,29 @@ static void free_table( MSITABLE *table )
|
|||
for( i=0; i<table->nonpersistent_row_count; i++ )
|
||||
msi_free( table->nonpersistent_data[i] );
|
||||
msi_free( table->nonpersistent_data );
|
||||
if( (table->colinfo != _Tables_cols) &&
|
||||
(table->colinfo != _Columns_cols) )
|
||||
{
|
||||
msi_free_colinfo( table->colinfo, table->col_count );
|
||||
msi_free( table->colinfo );
|
||||
}
|
||||
msi_free_colinfo( table->colinfo, table->col_count );
|
||||
msi_free( table->colinfo );
|
||||
msi_free( table );
|
||||
}
|
||||
|
||||
static UINT msi_table_get_row_size( const MSICOLUMNINFO *cols, UINT count )
|
||||
static UINT msi_table_get_row_size( MSIDATABASE *db,const MSICOLUMNINFO *cols,
|
||||
UINT count )
|
||||
{
|
||||
const MSICOLUMNINFO *last_col = &cols[count-1];
|
||||
if (!count)
|
||||
return 0;
|
||||
return last_col->offset + bytes_per_column( last_col );
|
||||
return last_col->offset + bytes_per_column( db, last_col );
|
||||
}
|
||||
|
||||
/* add this table to the list of cached tables in the database */
|
||||
static UINT read_table_from_storage( MSITABLE *t, IStorage *stg )
|
||||
static UINT read_table_from_storage( MSIDATABASE *db, MSITABLE *t, IStorage *stg )
|
||||
{
|
||||
BYTE *rawdata = NULL;
|
||||
UINT rawsize = 0, i, j, row_size = 0;
|
||||
|
||||
TRACE("%s\n",debugstr_w(t->name));
|
||||
|
||||
row_size = msi_table_get_row_size( t->colinfo, t->col_count );
|
||||
row_size = msi_table_get_row_size( db, t->colinfo, t->col_count );
|
||||
|
||||
/* if we can't read the table, just assume that it's empty */
|
||||
read_stream_data( stg, t->name, TRUE, &rawdata, &rawsize );
|
||||
|
@ -544,7 +531,7 @@ static UINT read_table_from_storage( MSITABLE *t, IStorage *stg )
|
|||
for( j=0; j<t->col_count; j++ )
|
||||
{
|
||||
UINT ofs = t->colinfo[j].offset;
|
||||
UINT n = bytes_per_column( &t->colinfo[j] );
|
||||
UINT n = bytes_per_column( db, &t->colinfo[j] );
|
||||
UINT k;
|
||||
|
||||
if ( n != 2 && n != 3 && n != 4 )
|
||||
|
@ -598,6 +585,8 @@ static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO
|
|||
if( r != ERROR_SUCCESS )
|
||||
return r;
|
||||
|
||||
*pcount = column_count;
|
||||
|
||||
/* if there's no columns, there's no table */
|
||||
if( column_count == 0 )
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
@ -616,7 +605,6 @@ static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO
|
|||
}
|
||||
|
||||
*pcols = columns;
|
||||
*pcount = column_count;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
@ -672,7 +660,7 @@ UINT msi_create_table( MSIDATABASE *db, LPCWSTR name, column_info *col_info,
|
|||
table->colinfo[ i ].ref_count = 0;
|
||||
table->colinfo[ i ].hash_table = NULL;
|
||||
}
|
||||
table_calc_column_offsets( table->colinfo, table->col_count);
|
||||
table_calc_column_offsets( db, table->colinfo, table->col_count);
|
||||
|
||||
r = TABLE_CreateView( db, szTables, &tv );
|
||||
TRACE("CreateView returned %x\n", r);
|
||||
|
@ -800,28 +788,14 @@ static UINT get_table( MSIDATABASE *db, LPCWSTR name, MSITABLE **table_ret )
|
|||
table->persistent = TRUE;
|
||||
lstrcpyW( table->name, name );
|
||||
|
||||
/* these two tables are special - we know the column types already */
|
||||
if( !lstrcmpW( name, szColumns ) )
|
||||
r = table_get_column_info( db, name, &table->colinfo, &table->col_count);
|
||||
if (r != ERROR_SUCCESS)
|
||||
{
|
||||
table->colinfo = _Columns_cols;
|
||||
table->col_count = sizeof(_Columns_cols)/sizeof(_Columns_cols[0]);
|
||||
}
|
||||
else if( !lstrcmpW( name, szTables ) )
|
||||
{
|
||||
table->colinfo = _Tables_cols;
|
||||
table->col_count = sizeof(_Tables_cols)/sizeof(_Tables_cols[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
r = table_get_column_info( db, name, &table->colinfo, &table->col_count);
|
||||
if (r != ERROR_SUCCESS)
|
||||
{
|
||||
free_table ( table );
|
||||
return r;
|
||||
}
|
||||
free_table ( table );
|
||||
return r;
|
||||
}
|
||||
|
||||
r = read_table_from_storage( table, db->storage );
|
||||
r = read_table_from_storage( db, table, db->storage );
|
||||
if( r != ERROR_SUCCESS )
|
||||
{
|
||||
free_table( table );
|
||||
|
@ -844,7 +818,7 @@ static UINT save_table( MSIDATABASE *db, const MSITABLE *t )
|
|||
|
||||
TRACE("Saving %s\n", debugstr_w( t->name ) );
|
||||
|
||||
row_size = msi_table_get_row_size( t->colinfo, t->col_count );
|
||||
row_size = msi_table_get_row_size( db, t->colinfo, t->col_count );
|
||||
|
||||
rawsize = t->row_count * row_size;
|
||||
rawdata = msi_alloc_zero( rawsize );
|
||||
|
@ -863,7 +837,7 @@ static UINT save_table( MSIDATABASE *db, const MSITABLE *t )
|
|||
|
||||
*p++ = t->data[j][offset];
|
||||
*p++ = t->data[j][offset + 1];
|
||||
if( 4 == bytes_per_column( &t->colinfo[i] ) )
|
||||
if( 4 == bytes_per_column( db, &t->colinfo[i] ) )
|
||||
{
|
||||
*p++ = t->data[j][offset + 2];
|
||||
*p++ = t->data[j][offset + 3];
|
||||
|
@ -880,7 +854,8 @@ err:
|
|||
return r;
|
||||
}
|
||||
|
||||
static void table_calc_column_offsets( MSICOLUMNINFO *colinfo, DWORD count )
|
||||
static void table_calc_column_offsets( MSIDATABASE *db, MSICOLUMNINFO *colinfo,
|
||||
DWORD count )
|
||||
{
|
||||
DWORD i;
|
||||
|
||||
|
@ -889,7 +864,7 @@ static void table_calc_column_offsets( MSICOLUMNINFO *colinfo, DWORD count )
|
|||
assert( (i+1) == colinfo[ i ].number );
|
||||
if (i)
|
||||
colinfo[i].offset = colinfo[ i - 1 ].offset
|
||||
+ bytes_per_column( &colinfo[ i - 1 ] );
|
||||
+ bytes_per_column( db, &colinfo[ i - 1 ] );
|
||||
else
|
||||
colinfo[i].offset = 0;
|
||||
TRACE("column %d is [%s] with type %08x ofs %d\n",
|
||||
|
@ -898,7 +873,8 @@ static void table_calc_column_offsets( MSICOLUMNINFO *colinfo, DWORD count )
|
|||
}
|
||||
}
|
||||
|
||||
static UINT get_defaulttablecolumns( LPCWSTR name, MSICOLUMNINFO *colinfo, UINT *sz)
|
||||
static UINT get_defaulttablecolumns( MSIDATABASE *db, LPCWSTR name,
|
||||
MSICOLUMNINFO *colinfo, UINT *sz)
|
||||
{
|
||||
const MSICOLUMNINFO *p;
|
||||
DWORD i, n;
|
||||
|
@ -930,7 +906,7 @@ static UINT get_defaulttablecolumns( LPCWSTR name, MSICOLUMNINFO *colinfo, UINT
|
|||
if( colinfo && (i >= *sz) )
|
||||
break;
|
||||
}
|
||||
table_calc_column_offsets( colinfo, n );
|
||||
table_calc_column_offsets( db, colinfo, n );
|
||||
*sz = n;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
@ -971,7 +947,7 @@ static UINT get_tablecolumns( MSIDATABASE *db,
|
|||
TRACE("%s\n", debugstr_w(szTableName));
|
||||
|
||||
/* first check if there is a default table with that name */
|
||||
r = get_defaulttablecolumns( szTableName, colinfo, sz );
|
||||
r = get_defaulttablecolumns( db, szTableName, colinfo, sz );
|
||||
if( ( r == ERROR_SUCCESS ) && *sz )
|
||||
return r;
|
||||
|
||||
|
@ -1003,8 +979,8 @@ static UINT get_tablecolumns( MSIDATABASE *db,
|
|||
continue;
|
||||
if( colinfo )
|
||||
{
|
||||
UINT id = read_table_int(table->data, i, _Columns_cols[2].offset, db->bytes_per_strref);
|
||||
UINT col = read_table_int(table->data, i, _Columns_cols[1].offset, sizeof(USHORT)) - (1<<15);
|
||||
UINT id = read_table_int(table->data, i, table->colinfo[2].offset, db->bytes_per_strref);
|
||||
UINT col = read_table_int(table->data, i, table->colinfo[1].offset, sizeof(USHORT)) - (1<<15);
|
||||
|
||||
/* check the column number is in range */
|
||||
if (col<1 || col>maxcount)
|
||||
|
@ -1023,7 +999,9 @@ static UINT get_tablecolumns( MSIDATABASE *db,
|
|||
colinfo[ col - 1 ].tablename = msi_makestring( db, table_id );
|
||||
colinfo[ col - 1 ].number = col;
|
||||
colinfo[ col - 1 ].colname = msi_makestring( db, id );
|
||||
colinfo[ col - 1 ].type = read_table_int(table->data, i, _Columns_cols[3].offset, sizeof(USHORT)) - (1<<15);
|
||||
colinfo[ col - 1 ].type = read_table_int(table->data, i,
|
||||
table->colinfo[3].offset,
|
||||
sizeof(USHORT)) - (1<<15);
|
||||
colinfo[ col - 1 ].offset = 0;
|
||||
colinfo[ col - 1 ].ref_count = 0;
|
||||
colinfo[ col - 1 ].hash_table = NULL;
|
||||
|
@ -1040,7 +1018,7 @@ static UINT get_tablecolumns( MSIDATABASE *db,
|
|||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
table_calc_column_offsets( colinfo, n );
|
||||
table_calc_column_offsets( db, colinfo, n );
|
||||
*sz = n;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
|
@ -1057,7 +1035,10 @@ static void msi_update_table_columns( MSIDATABASE *db, LPCWSTR name )
|
|||
msi_free( table->colinfo );
|
||||
table_get_column_info( db, name, &table->colinfo, &table->col_count );
|
||||
|
||||
size = msi_table_get_row_size( table->colinfo, table->col_count );
|
||||
if (!table->col_count)
|
||||
return;
|
||||
|
||||
size = msi_table_get_row_size( db, table->colinfo, table->col_count );
|
||||
offset = table->colinfo[table->col_count - 1].offset;
|
||||
|
||||
for ( n = 0; n < table->row_count; n++ )
|
||||
|
@ -1096,20 +1077,12 @@ BOOL TABLE_Exists( MSIDATABASE *db, LPCWSTR name )
|
|||
count = table->row_count;
|
||||
for( i=0; i<count; i++ )
|
||||
if( table->data[ i ][ 0 ] == table_id )
|
||||
break;
|
||||
|
||||
if (i!=count)
|
||||
return TRUE;
|
||||
return TRUE;
|
||||
|
||||
count = table->nonpersistent_row_count;
|
||||
for( i=0; i<count; i++ )
|
||||
if( table->nonpersistent_data[ i ][ 0 ] == table_id )
|
||||
break;
|
||||
|
||||
if (i!=count)
|
||||
return TRUE;
|
||||
|
||||
TRACE("Searched %d tables, but %d was not found\n", count, table_id );
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -1162,7 +1135,7 @@ static UINT TABLE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *
|
|||
else
|
||||
data = tv->table->data;
|
||||
|
||||
n = bytes_per_column( &tv->columns[col-1] );
|
||||
n = bytes_per_column( tv->db, &tv->columns[col-1] );
|
||||
if (n != 2 && n != 3 && n != 4)
|
||||
{
|
||||
ERR("oops! what is %d bytes per column?\n", n );
|
||||
|
@ -1277,7 +1250,7 @@ static UINT TABLE_set_int( MSITABLEVIEW *tv, UINT row, UINT col, UINT val )
|
|||
else
|
||||
data = tv->table->data;
|
||||
|
||||
n = bytes_per_column( &tv->columns[col-1] );
|
||||
n = bytes_per_column( tv->db, &tv->columns[col-1] );
|
||||
if ( n != 2 && n != 3 && n != 4 )
|
||||
{
|
||||
ERR("oops! what is %d bytes per column?\n", n );
|
||||
|
@ -1351,7 +1324,7 @@ static UINT TABLE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UI
|
|||
val = msi_addstringW( tv->db->strings, 0, sval, -1, 1,
|
||||
persistent ? StringPersistent : StringNonPersistent );
|
||||
}
|
||||
else if ( 2 == bytes_per_column( &tv->columns[ i ] ) )
|
||||
else if ( 2 == bytes_per_column( tv->db, &tv->columns[ i ] ) )
|
||||
{
|
||||
val = 0x8000 + MSI_RecordGetInteger( rec, i + 1 );
|
||||
if ( val & 0xffff0000 )
|
||||
|
@ -2081,6 +2054,53 @@ static UINT TABLE_sort(struct tagMSIVIEW *view, column_info *columns)
|
|||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT TABLE_drop(struct tagMSIVIEW *view)
|
||||
{
|
||||
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
|
||||
MSIVIEW *tables = NULL;
|
||||
MSIRECORD *rec = NULL;
|
||||
UINT r, row;
|
||||
INT i;
|
||||
|
||||
TRACE("dropping table %s\n", debugstr_w(tv->name));
|
||||
|
||||
for (i = tv->table->col_count - 1; i >= 0; i--)
|
||||
{
|
||||
r = TABLE_remove_column(view, tv->table->colinfo[i].tablename,
|
||||
tv->table->colinfo[i].number);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
}
|
||||
|
||||
rec = MSI_CreateRecord(1);
|
||||
if (!rec)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
MSI_RecordSetStringW(rec, 1, tv->name);
|
||||
|
||||
r = TABLE_CreateView(tv->db, szTables, &tables);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
r = msi_table_find_row((MSITABLEVIEW *)tables, rec, &row);
|
||||
if (r != ERROR_SUCCESS)
|
||||
goto done;
|
||||
|
||||
r = TABLE_delete_row(tables, row);
|
||||
if (r != ERROR_SUCCESS)
|
||||
goto done;
|
||||
|
||||
list_remove(&tv->table->entry);
|
||||
free_table(tv->table);
|
||||
TABLE_delete(view);
|
||||
|
||||
done:
|
||||
msiobj_release(&rec->hdr);
|
||||
tables->ops->delete(tables);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static const MSIVIEWOPS table_ops =
|
||||
{
|
||||
TABLE_fetch_int,
|
||||
|
@ -2101,6 +2121,7 @@ static const MSIVIEWOPS table_ops =
|
|||
TABLE_add_column,
|
||||
TABLE_remove_column,
|
||||
TABLE_sort,
|
||||
TABLE_drop,
|
||||
};
|
||||
|
||||
UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view )
|
||||
|
@ -2138,7 +2159,7 @@ UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view )
|
|||
tv->db = db;
|
||||
tv->columns = tv->table->colinfo;
|
||||
tv->num_cols = tv->table->col_count;
|
||||
tv->row_size = msi_table_get_row_size( tv->table->colinfo, tv->table->col_count );
|
||||
tv->row_size = msi_table_get_row_size( db, tv->table->colinfo, tv->table->col_count );
|
||||
|
||||
TRACE("%s one row is %d bytes\n", debugstr_w(name), tv->row_size );
|
||||
|
||||
|
@ -2246,7 +2267,7 @@ static MSIRECORD *msi_get_transform_record( const MSITABLEVIEW *tv, const string
|
|||
}
|
||||
else
|
||||
{
|
||||
UINT n = bytes_per_column( &columns[i] );
|
||||
UINT n = bytes_per_column( tv->db, &columns[i] );
|
||||
switch( n )
|
||||
{
|
||||
case 2:
|
||||
|
@ -2457,7 +2478,7 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
|
|||
! MSITYPE_IS_BINARY(tv->columns[i].type) )
|
||||
sz += bytes_per_strref;
|
||||
else
|
||||
sz += bytes_per_column( &tv->columns[i] );
|
||||
sz += bytes_per_column( tv->db, &tv->columns[i] );
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -2479,7 +2500,7 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
|
|||
! MSITYPE_IS_BINARY(tv->columns[i].type) )
|
||||
sz += bytes_per_strref;
|
||||
else
|
||||
sz += bytes_per_column( &tv->columns[i] );
|
||||
sz += bytes_per_column( tv->db, &tv->columns[i] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ static const WCHAR CHARACTER_W[] = { 'C','H','A','R','A','C','T','E','R',0 };
|
|||
static const WCHAR CREATE_W[] = { 'C','R','E','A','T','E',0 };
|
||||
static const WCHAR DELETE_W[] = { 'D','E','L','E','T','E',0 };
|
||||
static const WCHAR DISTINCT_W[] = { 'D','I','S','T','I','N','C','T',0 };
|
||||
static const WCHAR DROP_W[] = { 'D','R','O','P',0 };
|
||||
static const WCHAR FREE_W[] = { 'F','R','E','E',0 };
|
||||
static const WCHAR FROM_W[] = { 'F','R','O','M',0 };
|
||||
static const WCHAR HOLD_W[] = { 'H','O','L','D',0 };
|
||||
|
@ -89,6 +90,7 @@ static const Keyword aKeywordTable[] = {
|
|||
{ CREATE_W, TK_CREATE },
|
||||
{ DELETE_W, TK_DELETE },
|
||||
{ DISTINCT_W, TK_DISTINCT },
|
||||
{ DROP_W, TK_DROP },
|
||||
{ FREE_W, TK_FREE },
|
||||
{ FROM_W, TK_FROM },
|
||||
{ HOLD_W, TK_HOLD },
|
||||
|
|
|
@ -222,6 +222,7 @@ static const MSIVIEWOPS update_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPCWSTR table,
|
||||
|
|
|
@ -136,15 +136,16 @@ static UINT ITERATE_FindRelatedProducts(MSIRECORD *rec, LPVOID param)
|
|||
HKEY hukey;
|
||||
INT r;
|
||||
|
||||
unsquash_guid(product,productid);
|
||||
rc = MSIREG_OpenUserProductsKey(productid, &hukey, FALSE);
|
||||
unsquash_guid(product, productid);
|
||||
rc = MSIREG_OpenProductKey(productid, package->Context,
|
||||
&hukey, FALSE);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
rc = ERROR_SUCCESS;
|
||||
index ++;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
sz = sizeof(DWORD);
|
||||
RegQueryValueExW(hukey, INSTALLPROPERTY_VERSIONW, NULL, NULL,
|
||||
(LPBYTE)&check, &sz);
|
||||
|
|
|
@ -180,7 +180,7 @@ static UINT WHERE_get_row( struct tagMSIVIEW *view, UINT row, MSIRECORD **rec )
|
|||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
return wv->table->ops->get_row(view, row, rec);
|
||||
return wv->table->ops->get_row(wv->table, row, rec);
|
||||
}
|
||||
|
||||
static UINT WHERE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask )
|
||||
|
@ -585,6 +585,7 @@ static const MSIVIEWOPS where_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
WHERE_sort,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr *cond,
|
||||
|
|
Loading…
Reference in a new issue