sync msi with wine 1.1.11

svn path=/trunk/; revision=38391
This commit is contained in:
Christoph von Wittich 2008-12-27 15:10:14 +00:00
parent 9776114e82
commit 6631d1c7cf
45 changed files with 4903 additions and 2393 deletions

File diff suppressed because it is too large Load diff

View file

@ -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 )

View file

@ -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);

View file

@ -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

View file

@ -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 )
{

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -191,7 +191,8 @@ static const MSIVIEWOPS delete_ops =
NULL,
NULL,
NULL,
NULL
NULL,
NULL,
};
UINT DELETE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )

View file

@ -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;

View file

@ -296,6 +296,7 @@ static const MSIVIEWOPS distinct_ops =
NULL,
NULL,
DISTINCT_sort,
NULL,
};
UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )

View 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;
}

View file

@ -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;

View file

@ -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 */

View file

@ -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;
}

View file

@ -239,6 +239,7 @@ static const MSIVIEWOPS insert_ops =
NULL,
NULL,
NULL,
NULL,
};
static UINT count_column_info( const column_info *ci )

View file

@ -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);

View file

@ -306,6 +306,7 @@ static const MSIVIEWOPS join_ops =
NULL,
NULL,
JOIN_sort,
NULL,
};
UINT JOIN_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR tables )

View 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

View file

@ -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>

View 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

View file

@ -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)

View file

@ -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
{

View 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)

View file

@ -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 );

View file

@ -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 )

View file

@ -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;
}

View file

@ -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 );

View file

@ -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

View file

@ -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 */

View file

@ -363,6 +363,7 @@ static const MSIVIEWOPS select_ops =
NULL,
NULL,
SELECT_sort,
NULL,
};
static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name )

View file

@ -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

View file

@ -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

View file

@ -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
{

View file

@ -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)

View file

@ -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)
{

View file

@ -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;

View file

@ -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] );
}
}
}

View file

@ -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 },

View file

@ -222,6 +222,7 @@ static const MSIVIEWOPS update_ops =
NULL,
NULL,
NULL,
NULL,
};
UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPCWSTR table,

View file

@ -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);

View file

@ -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,