Autosyncing with Wine HEAD

svn path=/trunk/; revision=32849
This commit is contained in:
The Wine Synchronizer 2008-04-04 13:43:40 +00:00
parent 5ef42dd10a
commit e1e678b0f2
25 changed files with 1872 additions and 746 deletions

View file

@ -18,14 +18,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
/*
* Pages I need
*
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
*/
#include <stdarg.h>
#define COBJMACROS
@ -55,6 +47,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi);
static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, UINT* rc, BOOL force);
/*
* consts and values used
@ -241,8 +234,6 @@ struct _actions {
STANDARDACTIONHANDLER handler;
};
static const struct _actions StandardActions[];
/********************************************************
* helper functions
@ -573,7 +564,7 @@ static UINT msi_apply_transforms( MSIPACKAGE *package )
for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
{
if (xforms[i][0] == ':')
r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
r = msi_apply_substorage_transform( package, package->db, xforms[i] );
else
r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
}
@ -584,7 +575,7 @@ static UINT msi_apply_transforms( MSIPACKAGE *package )
return r;
}
BOOL ui_sequence_exists( MSIPACKAGE *package )
static BOOL ui_sequence_exists( MSIPACKAGE *package )
{
MSIQUERY *view;
UINT rc;
@ -973,56 +964,6 @@ static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
/********************************************************
* ACTION helper functions and functions that perform the actions
*******************************************************/
static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
UINT* rc, BOOL force )
{
BOOL ret = FALSE;
BOOL run = force;
int i;
if (!run && !package->script->CurrentlyScripting)
run = TRUE;
if (!run)
{
if (strcmpW(action,szInstallFinalize) == 0 ||
strcmpW(action,szInstallExecute) == 0 ||
strcmpW(action,szInstallExecuteAgain) == 0)
run = TRUE;
}
i = 0;
while (StandardActions[i].action != NULL)
{
if (strcmpW(StandardActions[i].action, action)==0)
{
if (!run)
{
ui_actioninfo(package, action, TRUE, 0);
*rc = schedule_action(package,INSTALL_SCRIPT,action);
ui_actioninfo(package, action, FALSE, *rc);
}
else
{
ui_actionstart(package, action);
if (StandardActions[i].handler)
{
*rc = StandardActions[i].handler(package);
}
else
{
FIXME("unhandled standard action %s\n",debugstr_w(action));
*rc = ERROR_SUCCESS;
}
}
ret = TRUE;
break;
}
i++;
}
return ret;
}
static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
UINT* rc, UINT script, BOOL force )
{
@ -1061,7 +1002,7 @@ UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script,
if (!handled)
{
FIXME("unhandled msi action %s\n",debugstr_w(action));
WARN("unhandled msi action %s\n",debugstr_w(action));
rc = ERROR_FUNCTION_NOT_CALLED;
}
@ -1085,7 +1026,7 @@ UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT scrip
if (!handled)
{
FIXME("unhandled msi action %s\n",debugstr_w(action));
WARN("unhandled msi action %s\n",debugstr_w(action));
rc = ERROR_FUNCTION_NOT_CALLED;
}
@ -2322,7 +2263,6 @@ static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
{
static const WCHAR szMulti[] = {'[','~',']',0};
LPCWSTR ptr;
LPWSTR newdata;
*type=REG_SZ;
if (value[0]=='#')
@ -2350,19 +2290,8 @@ static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
/* add double NULL terminator */
if (*type == REG_MULTI_SZ)
{
*size += sizeof(WCHAR);
newdata = msi_alloc(*size);
if (!newdata)
{
msi_free(data);
return NULL;
}
memcpy(newdata, data, *size - 1);
newdata[*size] = '\0';
msi_free(data);
data = (LPSTR)newdata;
*size += 2 * sizeof(WCHAR); /* two NULL terminators */
data = msi_realloc_zero(data, *size);
}
}
return data;
@ -2503,10 +2432,6 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
deformat_string(package, name, &deformated);
/* get the double nulls to terminate SZ_MULTI */
if (type == REG_MULTI_SZ)
size +=sizeof(WCHAR);
if (!check_first)
{
TRACE("Setting value %s of %s\n",debugstr_w(deformated),
@ -3379,6 +3304,7 @@ static BOOL msi_check_publish(MSIPACKAGE *package)
static UINT ACTION_PublishProduct(MSIPACKAGE *package)
{
UINT rc;
LPWSTR packname;
MSIQUERY * view;
MSISOURCELISTINFO *info;
MSIMEDIADISK *disk;
@ -3389,12 +3315,16 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package)
HKEY hkey=0;
HKEY hukey=0;
HKEY hudkey=0, props=0;
HKEY source;
static const WCHAR szProductLanguage[] =
{'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
static const WCHAR szARPProductIcon[] =
{'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
static const WCHAR szProductVersion[] =
{'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
static const WCHAR szSourceList[] =
{'S','o','u','r','c','e','L','i','s','t',0};
static const WCHAR szEmpty[] = {0};
DWORD langid;
LPWSTR buffer;
DWORD size;
@ -3423,6 +3353,12 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package)
if (rc != ERROR_SUCCESS)
goto end;
rc = RegCreateKeyW(hukey, szSourceList, &source);
if (rc != ERROR_SUCCESS)
goto end;
RegCloseKey(source);
rc = MSIREG_OpenUserDataProductKey(package->ProductCode,&hudkey,TRUE);
if (rc != ERROR_SUCCESS)
goto end;
@ -3436,7 +3372,14 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package)
msi_free(buffer);
langid = msi_get_property_int( package, szProductLanguage, 0 );
msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
msi_reg_set_val_dword( hukey, INSTALLPROPERTY_LANGUAGEW, langid );
packname = strrchrW( package->PackagePath, '\\' ) + 1;
msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGENAMEW, packname );
/* FIXME */
msi_reg_set_val_dword( hukey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0 );
msi_reg_set_val_dword( props, INSTALLPROPERTY_INSTANCETYPEW, 0 );
buffer = msi_dup_property( package, szARPProductIcon );
if (buffer)
@ -3451,10 +3394,29 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package)
if (buffer)
{
DWORD verdword = msi_version_str_to_dword(buffer);
msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
msi_reg_set_val_dword( hukey, INSTALLPROPERTY_VERSIONW, verdword );
}
msi_free(buffer);
buffer = strrchrW( package->PackagePath, '\\') + 1;
rc = MsiSourceListSetInfoW( package->ProductCode, NULL,
MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT,
INSTALLPROPERTY_PACKAGENAMEW, buffer );
if (rc != ERROR_SUCCESS)
goto end;
rc = MsiSourceListSetInfoW( package->ProductCode, NULL,
MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT,
INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty );
if (rc != ERROR_SUCCESS)
goto end;
rc = MsiSourceListSetInfoW( package->ProductCode, NULL,
MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT,
INSTALLPROPERTY_DISKPROMPTW, szEmpty );
if (rc != ERROR_SUCCESS)
goto end;
/* FIXME: Need to write more keys to the user registry */
hDb= alloc_msihandle( &package->db->hdr );
@ -3472,12 +3434,10 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package)
guidbuffer, &size);
if (rc == ERROR_SUCCESS)
{
WCHAR squashed[GUID_SIZE];
/* for now we only care about the first guid */
LPWSTR ptr = strchrW(guidbuffer,';');
if (ptr) *ptr = 0;
squash_guid(guidbuffer,squashed);
msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, guidbuffer );
}
else
{
@ -3495,9 +3455,13 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package)
/* publish the SourceList info */
LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
{
MsiSourceListSetInfoW(package->ProductCode, NULL,
info->context, info->options,
info->property, info->value);
if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
msi_set_last_used_source(package->ProductCode, NULL, info->context,
info->options, info->value);
else
MsiSourceListSetInfoW(package->ProductCode, NULL,
info->context, info->options,
info->property, info->value);
}
LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
@ -4000,6 +3964,14 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
{'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
static const WCHAR szProductVersion[] =
{'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
static const WCHAR szProductName[] =
{'P','r','o','d','u','c','t','N','a','m','e',0};
static const WCHAR szDisplayName[] =
{'D','i','s','p','l','a','y','N','a','m','e',0};
static const WCHAR szDisplayVersion[] =
{'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
static const WCHAR szManufacturer[] =
{'M','a','n','u','f','a','c','t','u','r','e','r',0};
SYSTEMTIME systime;
static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
@ -4014,6 +3986,10 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
if (rc != ERROR_SUCCESS)
return rc;
rc = MSIREG_OpenInstallPropertiesKey(package->ProductCode, &props, TRUE);
if (rc != ERROR_SUCCESS)
return rc;
/* dump all the info i can grab */
/* FIXME: Flesh out more information */
@ -4031,22 +4007,39 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
/* FIXME: Write real Estimated Size when we have it */
msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
buffer = msi_dup_property( package, szProductName );
msi_reg_set_val_str( props, szDisplayName, buffer );
msi_free(buffer);
buffer = msi_dup_property( package, cszSourceDir );
msi_reg_set_val_str( props, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
msi_free(buffer);
buffer = msi_dup_property( package, szManufacturer );
msi_reg_set_val_str( props, INSTALLPROPERTY_PUBLISHERW, buffer);
msi_free(buffer);
GetLocalTime(&systime);
sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
msi_reg_set_val_str( props, INSTALLPROPERTY_INSTALLDATEW, szDate );
langid = msi_get_property_int( package, szProductLanguage, 0 );
msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
buffer = msi_dup_property( package, szProductVersion );
msi_reg_set_val_str( props, szDisplayVersion, buffer );
if (buffer)
{
DWORD verdword = msi_version_str_to_dword(buffer);
msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
msi_reg_set_val_dword( props, INSTALLPROPERTY_VERSIONW, verdword );
msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
msi_reg_set_val_dword( props, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
msi_reg_set_val_dword( props, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
}
msi_free(buffer);
@ -4076,10 +4069,6 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
RegCloseKey(hudkey);
rc = MSIREG_OpenInstallPropertiesKey(package->ProductCode, &props, TRUE);
if (rc != ERROR_SUCCESS)
return rc;
msi_reg_set_val_dword( props, szWindowsInstaller, 1 );
RegCloseKey(props);
@ -4232,13 +4221,13 @@ static UINT ACTION_ResolveSource(MSIPACKAGE* package)
DWORD size = 0;
rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT,
INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
if (rc == ERROR_MORE_DATA)
{
prompt = msi_alloc(size * sizeof(WCHAR));
MsiSourceListGetInfoW(package->ProductCode, NULL,
MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT,
INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
}
else
@ -4287,11 +4276,17 @@ static UINT ACTION_RegisterUser(MSIPACKAGE *package)
{0},
};
if (msi_check_unpublish(package))
{
MSIREG_DeleteUserDataProductKey(package->ProductCode);
return ERROR_SUCCESS;
}
productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
if (!productid)
return ERROR_SUCCESS;
rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
rc = MSIREG_OpenInstallPropertiesKey(package->ProductCode, &hkey, TRUE);
if (rc != ERROR_SUCCESS)
goto end;
@ -4308,7 +4303,7 @@ end:
/* FIXME: call ui_actiondata */
return ERROR_SUCCESS;
return rc;
}
@ -4424,7 +4419,8 @@ static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
MSIRECORD *row;
MSIFILE *file;
SC_HANDLE hscm, service = NULL;
LPCWSTR name, disp, comp, depends, pass;
LPCWSTR comp, depends, pass;
LPWSTR name = NULL, disp = NULL;
LPCWSTR load_order, serv_name, key;
DWORD serv_type, start_type;
DWORD err_control;
@ -4451,8 +4447,8 @@ static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
if (depends && *depends)
FIXME("Dependency list unhandled!\n");
name = MSI_RecordGetString(rec, 2);
disp = MSI_RecordGetString(rec, 3);
deformat_string(package, MSI_RecordGetString(rec, 2), &name);
deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
serv_type = MSI_RecordGetInteger(rec, 4);
err_control = MSI_RecordGetInteger(rec, 6);
load_order = MSI_RecordGetString(rec, 7);
@ -4490,6 +4486,8 @@ static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
done:
CloseServiceHandle(service);
CloseServiceHandle(hscm);
msi_free(name);
msi_free(disp);
return ERROR_SUCCESS;
}
@ -4629,6 +4627,130 @@ static UINT ACTION_StartServices( MSIPACKAGE *package )
return rc;
}
static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
{
DWORD i, needed, count;
ENUM_SERVICE_STATUSW *dependencies;
SERVICE_STATUS ss;
SC_HANDLE depserv;
if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
0, &needed, &count))
return TRUE;
if (GetLastError() != ERROR_MORE_DATA)
return FALSE;
dependencies = msi_alloc(needed);
if (!dependencies)
return FALSE;
if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
needed, &needed, &count))
goto error;
for (i = 0; i < count; i++)
{
depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
SERVICE_STOP | SERVICE_QUERY_STATUS);
if (!depserv)
goto error;
if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
goto error;
}
return TRUE;
error:
msi_free(dependencies);
return FALSE;
}
static UINT ITERATE_StopService(MSIRECORD *rec, LPVOID param)
{
MSIPACKAGE *package = (MSIPACKAGE *)param;
MSICOMPONENT *comp;
SERVICE_STATUS status;
SERVICE_STATUS_PROCESS ssp;
SC_HANDLE scm = NULL, service = NULL;
LPWSTR name, args;
DWORD event, needed;
event = MSI_RecordGetInteger(rec, 3);
if (!(event & msidbServiceControlEventStop))
return ERROR_SUCCESS;
comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
return ERROR_SUCCESS;
deformat_string(package, MSI_RecordGetString(rec, 2), &name);
deformat_string(package, MSI_RecordGetString(rec, 4), &args);
args = strdupW(MSI_RecordGetString(rec, 4));
scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (!scm)
{
WARN("Failed to open the SCM: %d\n", GetLastError());
goto done;
}
service = OpenServiceW(scm, name,
SERVICE_STOP |
SERVICE_QUERY_STATUS |
SERVICE_ENUMERATE_DEPENDENTS);
if (!service)
{
WARN("Failed to open service (%s): %d\n",
debugstr_w(name), GetLastError());
goto done;
}
if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
sizeof(SERVICE_STATUS_PROCESS), &needed))
{
WARN("Failed to query service status (%s): %d\n",
debugstr_w(name), GetLastError());
goto done;
}
if (ssp.dwCurrentState == SERVICE_STOPPED)
goto done;
stop_service_dependents(scm, service);
if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
done:
CloseServiceHandle(service);
CloseServiceHandle(scm);
msi_free(name);
msi_free(args);
return ERROR_SUCCESS;
}
static UINT ACTION_StopServices( MSIPACKAGE *package )
{
UINT rc;
MSIQUERY *view;
static const WCHAR query[] = {
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
msiobj_release(&view->hdr);
return rc;
}
static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
{
MSIFILE *file;
@ -5211,7 +5333,7 @@ static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest)
return TRUE;
}
BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
{
WIN32_FIND_DATAW wfd;
HANDLE hfile;
@ -5240,6 +5362,10 @@ BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
msi_free(path);
}
/* no files match the wildcard */
if (list_empty(&files.entry))
goto done;
/* only the first wildcard match gets renamed to dest */
file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2;
@ -5461,13 +5587,6 @@ static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
}
static UINT ACTION_StopServices( MSIPACKAGE *package )
{
static const WCHAR table[] = {
'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
return msi_unimplemented_action_stub( package, "StopServices", table );
}
static UINT ACTION_DeleteServices( MSIPACKAGE *package )
{
static const WCHAR table[] = {
@ -5682,3 +5801,53 @@ static const struct _actions StandardActions[] = {
{ szWriteRegistryValues, ACTION_WriteRegistryValues },
{ NULL, NULL },
};
static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
UINT* rc, BOOL force )
{
BOOL ret = FALSE;
BOOL run = force;
int i;
if (!run && !package->script->CurrentlyScripting)
run = TRUE;
if (!run)
{
if (strcmpW(action,szInstallFinalize) == 0 ||
strcmpW(action,szInstallExecute) == 0 ||
strcmpW(action,szInstallExecuteAgain) == 0)
run = TRUE;
}
i = 0;
while (StandardActions[i].action != NULL)
{
if (strcmpW(StandardActions[i].action, action)==0)
{
if (!run)
{
ui_actioninfo(package, action, TRUE, 0);
*rc = schedule_action(package,INSTALL_SCRIPT,action);
ui_actioninfo(package, action, FALSE, *rc);
}
else
{
ui_actionstart(package, action);
if (StandardActions[i].handler)
{
*rc = StandardActions[i].handler(package);
}
else
{
FIXME("unhandled standard action %s\n",debugstr_w(action));
*rc = ERROR_SUCCESS;
}
}
ret = TRUE;
break;
}
i++;
}
return ret;
}

View file

@ -901,9 +901,6 @@ static UINT iterate_appsearch(MSIRECORD *row, LPVOID param)
return r;
}
/* http://msdn.microsoft.com/library/en-us/msi/setup/appsearch_table.asp
* is the best reference for the AppSearch table and how it's used.
*/
UINT ACTION_AppSearch(MSIPACKAGE *package)
{
static const WCHAR query[] = {

View file

@ -39,6 +39,9 @@
WINE_DEFAULT_DEBUG_CHANNEL(msi);
#define REG_INDEX_CLASSES_ROOT 0
#define REG_INDEX_DYN_DATA 6
/*
* AutomationObject - "base" class for all automation objects. For each interface, we implement Invoke function
* called from AutomationObject::Invoke, and pass this function to create_automation_object.
@ -150,7 +153,7 @@ HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID
/* Create the automation object, placing the result in the pointer ppObj. The automation object is created
* with the appropriate clsid and invocation function. */
HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOID *ppObj, REFIID clsid,
static HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOID *ppObj, REFIID clsid,
HRESULT (STDMETHODCALLTYPE *funcInvoke)(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,
VARIANT*,EXCEPINFO*,UINT*),
void (STDMETHODCALLTYPE *funcFree)(AutomationObject*),
@ -191,7 +194,7 @@ HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOI
}
/* Create a list enumerator, placing the result in the pointer ppObj. */
HRESULT create_list_enumerator(IUnknown *pUnkOuter, LPVOID *ppObj, AutomationObject *pObj, ULONG ulPos)
static HRESULT create_list_enumerator(IUnknown *pUnkOuter, LPVOID *ppObj, AutomationObject *pObj, ULONG ulPos)
{
ListEnumerator *object;
@ -705,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. */
HRESULT WINAPI DispGetParam_CopyOnly(
static HRESULT WINAPI 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 */
@ -1535,6 +1538,7 @@ static HRESULT WINAPI InstallerImpl_Invoke(
HRESULT hr;
LPWSTR szString = NULL;
DWORD dwSize = 0;
INSTALLUILEVEL ui;
VariantInit(&varg0);
VariantInit(&varg1);
@ -1627,6 +1631,31 @@ static HRESULT WINAPI InstallerImpl_Invoke(
else return DISP_E_MEMBERNOTFOUND;
break;
case DISPID_INSTALLER_UILEVEL:
if (wFlags & DISPATCH_PROPERTYPUT)
{
hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
if (FAILED(hr)) return hr;
if ((ui = MsiSetInternalUI(V_I4(&varg0), NULL) == INSTALLUILEVEL_NOCHANGE))
{
ERR("MsiSetInternalUI failed\n");
return DISP_E_EXCEPTION;
}
}
else if (wFlags & DISPATCH_PROPERTYGET)
{
if ((ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL) == INSTALLUILEVEL_NOCHANGE))
{
ERR("MsiSetInternalUI failed\n");
return DISP_E_EXCEPTION;
}
V_VT(pVarResult) = VT_I4;
V_I4(pVarResult) = ui;
}
else return DISP_E_MEMBERNOTFOUND;
break;
case DISPID_INSTALLER_INSTALLPRODUCT:
if (wFlags & DISPATCH_METHOD)
{
@ -1685,6 +1714,11 @@ static HRESULT WINAPI InstallerImpl_Invoke(
VariantClear(&varg1);
return hr;
}
if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT &&
V_I4(&varg0) <= REG_INDEX_DYN_DATA)
V_I4(&varg0) |= (UINT)HKEY_CLASSES_ROOT;
ret = RegOpenKeyW((HKEY)V_I4(&varg0), V_BSTR(&varg1), &hkey);
/* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */

View file

@ -317,7 +317,11 @@ value_i:
INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
MSI_GetFeatureStateW(cond->package, $2, &install, &action );
$$ = action;
if (action == INSTALLSTATE_UNKNOWN)
$$ = MSICONDITION_FALSE;
else
$$ = action;
msi_free( $2 );
}
| COND_EXCLAM identifier

View file

@ -331,6 +331,9 @@ UINT ACTION_CustomAction(MSIPACKAGE *package, LPCWSTR action, UINT script, BOOL
msi_free(deformated);
break;
case 51: /* Property set with formatted text. */
if (!source)
break;
deformat_string(package,target,&deformated);
rc = MSI_SetPropertyW(package,source,deformated);
msi_free(deformated);
@ -857,12 +860,6 @@ static UINT HANDLE_CustomType23(MSIPACKAGE *package, LPCWSTR source,
lstrcatW(package_path, backslash);
lstrcatW(package_path, source);
if (GetFileAttributesW(package_path) == INVALID_FILE_ATTRIBUTES)
{
ERR("Source package does not exist: %s\n", debugstr_w(package_path));
return ERROR_FUNCTION_FAILED;
}
TRACE("Installing package %s concurrently\n", debugstr_w(package_path));
info = do_msidbCAConcurrentInstall(package, type, package_path, target, action);

View file

@ -317,12 +317,18 @@ static void msi_parse_line(LPWSTR *line, LPWSTR **entries, DWORD *num_entries)
/* store pointers into the data */
for (i = 0, ptr = *line; i < count; i++)
{
while (*ptr && *ptr == '\r') ptr++;
save = ptr;
while (*ptr && *ptr != '\t' && *ptr != '\n') ptr++;
while (*ptr && *ptr != '\t' && *ptr != '\n' && *ptr != '\r') ptr++;
/* NULL-separate the data */
if (*ptr)
if (*ptr == '\n' || *ptr == '\r')
{
while (*ptr == '\n' || *ptr == '\r')
*(ptr++) = '\0';
}
else if (*ptr)
*ptr++ = '\0';
(*entries)[i] = save;
@ -342,7 +348,7 @@ static LPWSTR msi_build_createsql_prelude(LPWSTR table)
static const WCHAR create_fmt[] = {'C','R','E','A','T','E',' ','T','A','B','L','E',' ','`','%','s','`',' ','(',' ',0};
size = sizeof(create_fmt) + lstrlenW(table) - 2;
size = sizeof(create_fmt)/sizeof(create_fmt[0]) + lstrlenW(table) - 2;
prelude = msi_alloc(size * sizeof(WCHAR));
if (!prelude)
return NULL;
@ -509,156 +515,88 @@ static UINT msi_add_table_to_db(MSIDATABASE *db, LPWSTR *columns, LPWSTR *types,
return r;
}
static LPWSTR msi_build_insertsql_prelude(LPWSTR table)
static UINT construct_record(DWORD num_columns, LPWSTR *types,
LPWSTR *data, MSIRECORD **rec)
{
LPWSTR prelude;
DWORD size;
UINT i;
static const WCHAR insert_fmt[] = {'I','N','S','E','R','T',' ','I','N','T','O',' ','`','%','s','`',' ','(',' ',0};
size = sizeof(insert_fmt) + lstrlenW(table) - 2;
prelude = msi_alloc(size * sizeof(WCHAR));
if (!prelude)
return NULL;
sprintfW(prelude, insert_fmt, table);
return prelude;
}
static LPWSTR msi_build_insertsql_columns(LPWSTR *columns_data, LPWSTR *types, DWORD num_columns)
{
LPWSTR columns, p;
DWORD sql_size = 1, i;
WCHAR expanded[128];
static const WCHAR column_fmt[] = {'`','%','s','`',',',' ',0};
columns = msi_alloc_zero(sql_size * sizeof(WCHAR));
if (!columns)
return NULL;
for (i = 0; i < num_columns; i++)
{
sprintfW(expanded, column_fmt, columns_data[i]);
sql_size += lstrlenW(expanded);
if (i == num_columns - 1)
{
sql_size -= 2;
expanded[lstrlenW(expanded) - 2] = '\0';
}
p = msi_realloc(columns, sql_size * sizeof(WCHAR));
if (!p)
{
msi_free(columns);
return NULL;
}
columns = p;
lstrcatW(columns, expanded);
}
return columns;
}
static LPWSTR msi_build_insertsql_data(LPWSTR **records, LPWSTR *types, DWORD num_columns, DWORD irec)
{
LPWSTR columns, temp_columns;
DWORD sql_size = 1, i;
WCHAR expanded[128];
static const WCHAR str_fmt[] = {'\'','%','s','\'',',',' ',0};
static const WCHAR int_fmt[] = {'%','s',',',' ',0};
static const WCHAR empty[] = {'\'','\'',',',' ',0};
columns = msi_alloc_zero(sql_size * sizeof(WCHAR));
if (!columns)
return NULL;
*rec = MSI_CreateRecord(num_columns);
if (!*rec)
return ERROR_OUTOFMEMORY;
for (i = 0; i < num_columns; i++)
{
switch (types[i][0])
{
case 'L': case 'l': case 'S': case 's':
sprintfW(expanded, str_fmt, records[irec][i]);
MSI_RecordSetStringW(*rec, i + 1, data[i]);
break;
case 'I': case 'i':
if (*records[0][i])
sprintfW(expanded, int_fmt, records[irec][i]);
else
lstrcpyW(expanded, empty);
if (*data[i])
MSI_RecordSetInteger(*rec, i + 1, atoiW(data[i]));
break;
default:
HeapFree( GetProcessHeap(), 0, columns );
return NULL;
ERR("Unhandled column type: %c\n", types[i][0]);
msiobj_release(&(*rec)->hdr);
return ERROR_FUNCTION_FAILED;
}
if (i == num_columns - 1)
expanded[lstrlenW(expanded) - 2] = '\0';
sql_size += lstrlenW(expanded);
temp_columns = msi_realloc(columns, sql_size * sizeof(WCHAR));
if (!temp_columns)
{
HeapFree( GetProcessHeap(), 0, columns);
return NULL;
}
columns = temp_columns;
lstrcatW(columns, expanded);
}
return columns;
return ERROR_SUCCESS;
}
static UINT msi_add_records_to_table(MSIDATABASE *db, LPWSTR *columns, LPWSTR *types,
LPWSTR *labels, LPWSTR **records,
int num_columns, int num_records)
{
UINT r;
DWORD i, size;
MSIQUERY *view;
LPWSTR insert_sql;
DWORD size, i;
UINT r = ERROR_SUCCESS;
MSIRECORD *rec;
LPWSTR query;
static const WCHAR mid[] = {' ',')',' ','V','A','L','U','E','S',' ','(',' ',0};
static const WCHAR end[] = {' ',')',0};
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);
if (r != ERROR_SUCCESS)
return r;
while (MSI_ViewFetch(view, &rec) != ERROR_NO_MORE_ITEMS)
{
r = MSI_ViewModify(view, MSIMODIFY_DELETE, rec);
if (r != ERROR_SUCCESS)
goto done;
}
LPWSTR prelude = msi_build_insertsql_prelude(labels[0]);
LPWSTR columns_sql = msi_build_insertsql_columns(columns, types, num_columns);
for (i = 0; i < num_records; i++)
{
LPWSTR data = msi_build_insertsql_data(records, types, num_columns, i);
size = lstrlenW(prelude) + lstrlenW(columns_sql) + sizeof(mid) + lstrlenW(data) + sizeof(end) - 1;
insert_sql = msi_alloc(size * sizeof(WCHAR));
if (!insert_sql)
return ERROR_OUTOFMEMORY;
lstrcpyW(insert_sql, prelude);
lstrcatW(insert_sql, columns_sql);
lstrcatW(insert_sql, mid);
lstrcatW(insert_sql, data);
lstrcatW(insert_sql, end);
msi_free(data);
r = MSI_DatabaseOpenViewW( db, insert_sql, &view );
msi_free(insert_sql);
r = construct_record(num_columns, types, records[i], &rec);
if (r != ERROR_SUCCESS)
goto done;
r = MSI_ViewExecute(view, NULL);
MSI_ViewClose(view);
msiobj_release(&view->hdr);
r = MSI_ViewModify(view, MSIMODIFY_INSERT, rec);
if (r != ERROR_SUCCESS)
{
msiobj_release(&rec->hdr);
goto done;
}
msiobj_release(&rec->hdr);
}
done:
msi_free(prelude);
msi_free(columns_sql);
msiobj_release(&view->hdr);
return r;
}
@ -666,11 +604,11 @@ UINT MSI_DatabaseImport(MSIDATABASE *db, LPCWSTR folder, LPCWSTR file)
{
UINT r;
DWORD len, i;
DWORD num_labels;
DWORD num_labels, num_types;
DWORD num_columns, num_records = 0;
LPWSTR *columns, *types, *labels;
LPWSTR path, ptr, data;
LPWSTR **records;
LPWSTR **records = NULL;
LPWSTR **temp_records;
static const WCHAR backslash[] = {'\\',0};
@ -693,9 +631,15 @@ UINT MSI_DatabaseImport(MSIDATABASE *db, LPCWSTR folder, LPCWSTR file)
ptr = data;
msi_parse_line( &ptr, &columns, &num_columns );
msi_parse_line( &ptr, &types, NULL );
msi_parse_line( &ptr, &types, &num_types );
msi_parse_line( &ptr, &labels, &num_labels );
if (num_columns != num_types)
{
r = ERROR_FUNCTION_FAILED;
goto done;
}
records = msi_alloc(sizeof(LPWSTR *));
if (!records)
{
@ -718,9 +662,15 @@ UINT MSI_DatabaseImport(MSIDATABASE *db, LPCWSTR folder, LPCWSTR file)
records = temp_records;
}
r = msi_add_table_to_db( db, columns, types, labels, num_labels, num_columns );
if (r != ERROR_SUCCESS)
goto done;
if (!TABLE_Exists(db, labels[0]))
{
r = msi_add_table_to_db( db, columns, types, labels, num_labels, num_columns );
if (r != ERROR_SUCCESS)
{
r = ERROR_FUNCTION_FAILED;
goto done;
}
}
r = msi_add_records_to_table( db, columns, types, labels, records, num_columns, num_records );
@ -849,12 +799,29 @@ static UINT msi_export_row( MSIRECORD *row, void *arg )
return msi_export_record( arg, row, 1 );
}
static UINT msi_export_forcecodepage( HANDLE handle )
{
DWORD sz;
static const char data[] = "\r\n\r\n0\t_ForceCodepage\r\n";
FIXME("Read the codepage from the strings table!\n");
sz = lstrlenA(data) + 1;
if (!WriteFile(handle, data, sz, &sz, NULL))
return ERROR_FUNCTION_FAILED;
return ERROR_SUCCESS;
}
UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table,
LPCWSTR folder, LPCWSTR file )
{
static const WCHAR query[] = {
's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','%','s',0 };
static const WCHAR szbs[] = { '\\', 0 };
static const WCHAR forcecodepage[] = {
'_','F','o','r','c','e','C','o','d','e','p','a','g','e',0 };
MSIRECORD *rec = NULL;
MSIQUERY *view = NULL;
LPWSTR filename;
@ -882,6 +849,12 @@ UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table,
if (handle == INVALID_HANDLE_VALUE)
return ERROR_FUNCTION_FAILED;
if (!lstrcmpW( table, forcecodepage ))
{
r = msi_export_forcecodepage( handle );
goto done;
}
r = MSI_OpenQuery( db, &view, query, table );
if (r == ERROR_SUCCESS)
{
@ -915,8 +888,8 @@ UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table,
msiobj_release( &view->hdr );
}
done:
CloseHandle( handle );
return r;
}
@ -1079,32 +1052,32 @@ static ULONG WINAPI mrd_Release( IWineMsiRemoteDatabase *iface )
return r;
}
HRESULT WINAPI mrd_IsTablePersistent( IWineMsiRemoteDatabase *iface,
BSTR table, MSICONDITION *persistent )
static HRESULT WINAPI mrd_IsTablePersistent( IWineMsiRemoteDatabase *iface,
BSTR table, MSICONDITION *persistent )
{
msi_remote_database_impl *This = mrd_from_IWineMsiRemoteDatabase( iface );
*persistent = MsiDatabaseIsTablePersistentW(This->database, (LPWSTR)table);
return S_OK;
}
HRESULT WINAPI mrd_GetPrimaryKeys( IWineMsiRemoteDatabase *iface,
BSTR table, MSIHANDLE *keys )
static HRESULT WINAPI mrd_GetPrimaryKeys( IWineMsiRemoteDatabase *iface,
BSTR table, MSIHANDLE *keys )
{
msi_remote_database_impl *This = mrd_from_IWineMsiRemoteDatabase( iface );
UINT r = MsiDatabaseGetPrimaryKeysW(This->database, (LPWSTR)table, keys);
return HRESULT_FROM_WIN32(r);
}
HRESULT WINAPI mrd_GetSummaryInformation( IWineMsiRemoteDatabase *iface,
UINT updatecount, MSIHANDLE *suminfo )
static HRESULT WINAPI mrd_GetSummaryInformation( IWineMsiRemoteDatabase *iface,
UINT updatecount, MSIHANDLE *suminfo )
{
msi_remote_database_impl *This = mrd_from_IWineMsiRemoteDatabase( iface );
UINT r = MsiGetSummaryInformationW(This->database, NULL, updatecount, suminfo);
return HRESULT_FROM_WIN32(r);
}
HRESULT WINAPI mrd_OpenView( IWineMsiRemoteDatabase *iface,
BSTR query, MSIHANDLE *view )
static HRESULT WINAPI mrd_OpenView( IWineMsiRemoteDatabase *iface,
BSTR query, MSIHANDLE *view )
{
msi_remote_database_impl *This = mrd_from_IWineMsiRemoteDatabase( iface );
UINT r = MsiDatabaseOpenViewW(This->database, (LPWSTR)query, view);

View file

@ -50,12 +50,14 @@ extern HINSTANCE msi_hInstance;
struct msi_control_tag;
typedef struct msi_control_tag msi_control;
typedef UINT (*msi_handler)( msi_dialog *, msi_control *, WPARAM );
typedef void (*msi_update)( msi_dialog *, msi_control * );
struct msi_control_tag
{
struct list entry;
HWND hwnd;
msi_handler handler;
msi_update update;
LPWSTR property;
LPWSTR value;
HBITMAP hBitmap;
@ -564,6 +566,16 @@ static HICON msi_load_icon( MSIDATABASE *db, LPCWSTR text, UINT attributes )
return msi_load_image( db, text, IMAGE_ICON, cx, cy, flags );
}
static void msi_dialog_update_controls( msi_dialog *dialog, LPCWSTR property )
{
msi_control *control;
LIST_FOR_EACH_ENTRY( control, &dialog->controls, msi_control, entry )
{
if ( !lstrcmpW( control->property, property ) && control->update )
control->update( dialog, control );
}
}
/* called from the Control Event subscription code */
void msi_dialog_handle_event( msi_dialog* dialog, LPCWSTR control,
@ -855,6 +867,7 @@ static UINT msi_dialog_checkbox_control( msi_dialog *dialog, MSIRECORD *rec )
control = msi_dialog_add_control( dialog, rec, szButton,
BS_CHECKBOX | BS_MULTILINE | WS_TABSTOP );
control->handler = msi_dialog_checkbox_handler;
control->update = msi_dialog_checkbox_sync_state;
prop = MSI_RecordGetString( rec, 9 );
if( prop )
{
@ -2904,7 +2917,7 @@ static MSIRECORD *msi_get_dialog_record( msi_dialog *dialog )
rec = MSI_QueryGetRecord( package->db, query, dialog->name );
if( !rec )
ERR("query failed for dialog %s\n", debugstr_w(dialog->name));
WARN("query failed for dialog %s\n", debugstr_w(dialog->name));
return rec;
}
@ -3083,6 +3096,7 @@ static UINT msi_dialog_set_property( msi_dialog *dialog, LPCWSTR event, LPCWSTR
if( strcmpW( szNullArg, arg ) )
deformat_string( dialog->package, arg, &arg_fmt );
MSI_SetPropertyW( dialog->package, prop, arg_fmt );
msi_dialog_update_controls( dialog, prop );
msi_free( arg_fmt );
}
else

View file

@ -18,11 +18,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
/*
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/controlevent_overview.asp
*/
#include <stdarg.h>
#include <stdio.h>

View file

@ -59,6 +59,7 @@ static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
struct media_info {
UINT disk_id;
UINT type;
UINT last_sequence;
LPWSTR disk_prompt;
LPWSTR cabinet;
@ -400,10 +401,13 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
}
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))
@ -504,6 +508,8 @@ static UINT load_media_info(MSIPACKAGE *package, MSIFILE *file, struct media_inf
{
MSIRECORD *row;
LPWSTR source_dir;
LPWSTR source;
DWORD options;
UINT r;
static const WCHAR query[] = {
@ -539,6 +545,9 @@ static UINT load_media_info(MSIPACKAGE *package, MSIFILE *file, struct media_inf
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] == '#')
@ -554,17 +563,77 @@ static UINT load_media_info(MSIPACKAGE *package, MSIFILE *file, struct media_inf
lstrcatW(mi->source, mi->cabinet);
}
msi_package_add_media_disk(package, MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
mi->disk_id, mi->volume_label, mi->disk_prompt);
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_info(package, MSIINSTALLCONTEXT_USERMANAGED,
MSICODE_PRODUCT | MSISOURCETYPE_MEDIA,
INSTALLPROPERTY_LASTUSEDSOURCEW, mi->source);
if (mi->type == DRIVE_CDROM || mi->type == DRIVE_REMOVABLE)
msi_package_add_media_disk(package, MSIINSTALLCONTEXT_USERUNMANAGED,
MSICODE_PRODUCT, mi->disk_id,
mi->volume_label, mi->disk_prompt);
msi_package_add_info(package, MSIINSTALLCONTEXT_USERUNMANAGED,
options, INSTALLPROPERTY_LASTUSEDSOURCEW, source);
msi_free(source_dir);
return ERROR_SUCCESS;
}
/* FIXME: search NETWORK and URL sources as well */
static UINT find_published_source(MSIPACKAGE *package, struct media_info *mi)
{
WCHAR source[MAX_PATH];
WCHAR volume[MAX_PATH];
WCHAR prompt[MAX_PATH];
DWORD volumesz, promptsz;
DWORD index, size, id;
UINT r;
r = MsiSourceListGetInfoW(package->ProductCode, NULL,
MSIINSTALLCONTEXT_USERUNMANAGED, 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,
MSIINSTALLCONTEXT_USERUNMANAGED,
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, struct media_info *mi)
{
UINT rc = ERROR_SUCCESS;
@ -602,14 +671,11 @@ static UINT ready_media(MSIPACKAGE *package, MSIFILE *file, struct media_info *m
{
LPWSTR source = msi_dup_property(package, cszSourceDir);
BOOL matches;
UINT type;
PathStripToRootW(source);
type = GetDriveTypeW(source);
matches = source_matches_volume(mi, source);
msi_free(source);
if ((type == DRIVE_CDROM || type == DRIVE_REMOVABLE) && !matches)
if ((mi->type == DRIVE_CDROM || mi->type == DRIVE_REMOVABLE) && !matches)
{
rc = msi_change_media(package, mi);
if (rc != ERROR_SUCCESS)
@ -620,8 +686,13 @@ static UINT ready_media(MSIPACKAGE *package, MSIFILE *file, struct media_info *m
if (file->IsCompressed &&
GetFileAttributesW(mi->source) == INVALID_FILE_ATTRIBUTES)
{
ERR("Cabinet not found: %s\n", debugstr_w(mi->source));
return ERROR_INSTALL_FAILURE;
/* 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;
@ -739,21 +810,11 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
{
struct media_info *mi;
UINT rc = ERROR_SUCCESS;
LPWSTR ptr;
MSIFILE *file;
/* increment progress bar each time action data is sent */
ui_progress(package,1,1,0,0);
/* handle the keys for the SourceList */
ptr = strrchrW(package->PackagePath,'\\');
if (ptr)
{
ptr++;
msi_package_add_info(package, MSIINSTALLCONTEXT_USERMANAGED,
MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, ptr);
}
schedule_install_files(package);
/*

View file

@ -346,7 +346,7 @@ static LPWSTR build_default_format(const MSIRECORD* record)
sprintfW(index, fmt_index, i);
str = MSI_RecordGetString(record, i);
len = (str) ? lstrlenW(str) : 0;
len += (sizeof(fmt_null) - 3) + lstrlenW(index);
len += (sizeof(fmt_null)/sizeof(fmt_null[0]) - 3) + lstrlenW(index);
size += len;
if (len > max_len)
@ -544,6 +544,10 @@ static FORMSTR *format_replace(FORMAT *format, BOOL propfound, BOOL nonprop,
format->deformatted = str;
format->len = size - 1;
/* don't reformat the NULL */
if (replace && !*replace)
format->n++;
if (!replace)
return NULL;
@ -727,9 +731,6 @@ static UINT replace_stack(FORMAT *format, STACK *stack, STACK *values)
msi_free(replaced);
format->n = beg->n + beg->len;
if (type == FORMAT_PROPNULL)
format->n++;
top = stack_peek(stack);
if (top)
{

View file

@ -77,7 +77,7 @@ static UINT JOIN_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *v
break;
}
prev_rows = table->rows;
prev_rows *= table->rows;
cols += table->columns;
}
@ -108,7 +108,7 @@ static UINT JOIN_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStr
break;
}
prev_rows = table->rows;
prev_rows *= table->rows;
cols += table->columns;
}
@ -341,7 +341,8 @@ UINT JOIN_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR tables )
r = TABLE_CreateView( db, tables, &table->view );
if( r != ERROR_SUCCESS )
{
ERR("can't create table\n");
WARN("can't create table: %s\n", debugstr_w(tables));
r = ERROR_BAD_QUERY_SYNTAX;
goto end;
}

View file

@ -365,12 +365,12 @@ UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel,
}
sz = sizeof(sourcepath);
MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath,
&sz);
sz = sizeof(filename);
MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
lstrcatW(sourcepath,filename);
@ -561,114 +561,193 @@ done:
return rc;
}
static LPWSTR msi_reg_get_value(HKEY hkey, LPCWSTR name, DWORD *type)
{
DWORD dval;
LONG res;
WCHAR temp[20];
static const WCHAR format[] = {'%','d',0};
res = RegQueryValueExW(hkey, name, NULL, type, NULL, NULL);
if (res != ERROR_SUCCESS)
return NULL;
if (*type == REG_SZ)
return msi_reg_get_val_str(hkey, name);
if (!msi_reg_get_val_dword(hkey, name, &dval))
return NULL;
sprintfW(temp, format, dval);
return strdupW(temp);
}
static UINT WINAPI MSI_GetProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute,
awstring *szValue, LPDWORD pcchValueBuf)
{
UINT r;
HKEY hkey;
UINT r = ERROR_UNKNOWN_PROPERTY;
HKEY prodkey, userdata, source;
LPWSTR val = NULL;
WCHAR squished_pc[GUID_SIZE];
WCHAR packagecode[GUID_SIZE];
BOOL classes = FALSE;
BOOL badconfig = FALSE;
LONG res;
DWORD save, type = REG_NONE;
static WCHAR empty[] = {0};
static const WCHAR sourcelist[] = {
'S','o','u','r','c','e','L','i','s','t',0};
static const WCHAR display_name[] = {
'D','i','s','p','l','a','y','N','a','m','e',0};
static const WCHAR display_version[] = {
'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
static const WCHAR assignment[] = {
'A','s','s','i','g','n','m','e','n','t',0};
TRACE("%s %s %p %p\n", debugstr_w(szProduct),
debugstr_w(szAttribute), szValue, pcchValueBuf);
/*
* FIXME: Values seem scattered/duplicated in the registry. Is there a system?
*/
if ((szValue->str.w && !pcchValueBuf) || !szProduct || !szProduct[0] || !szAttribute)
if ((szValue->str.w && !pcchValueBuf) || !szProduct || !szAttribute)
return ERROR_INVALID_PARAMETER;
/* check for special properties */
if (!lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGECODEW))
if (!squash_guid(szProduct, squished_pc))
return ERROR_INVALID_PARAMETER;
r = MSIREG_OpenLocalManagedProductKey(szProduct, &prodkey, FALSE);
if (r != ERROR_SUCCESS)
{
LPWSTR regval;
WCHAR packagecode[35];
r = MSIREG_OpenUserProductsKey(szProduct, &hkey, FALSE);
r = MSIREG_OpenUserProductsKey(szProduct, &prodkey, FALSE);
if (r != ERROR_SUCCESS)
return ERROR_UNKNOWN_PRODUCT;
regval = msi_reg_get_val_str( hkey, szAttribute );
if (regval)
{
if (unsquash_guid(regval, packagecode))
val = strdupW(packagecode);
msi_free(regval);
r = MSIREG_OpenLocalClassesProductKey(szProduct, &prodkey, FALSE);
if (r == ERROR_SUCCESS)
classes = TRUE;
}
RegCloseKey(hkey);
}
else if (!lstrcmpW(szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW))
{
static const WCHAR one[] = { '1',0 };
/*
* FIXME: should be in the Product key (user or system?)
* but isn't written yet...
*/
val = strdupW( one );
}
else if (!lstrcmpW(szAttribute, INSTALLPROPERTY_LANGUAGEW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONW))
{
static const WCHAR fmt[] = { '%','u',0 };
WCHAR szVal[16];
DWORD regval;
r = MSIREG_OpenUninstallKey(szProduct, &hkey, FALSE);
if (r != ERROR_SUCCESS)
return ERROR_UNKNOWN_PRODUCT;
if (msi_reg_get_val_dword( hkey, szAttribute, &regval))
{
sprintfW(szVal, fmt, regval);
val = strdupW( szVal );
}
RegCloseKey(hkey);
}
else if (!lstrcmpW(szAttribute, INSTALLPROPERTY_PRODUCTNAMEW))
{
r = MSIREG_OpenUserProductsKey(szProduct, &hkey, FALSE);
if (r != ERROR_SUCCESS)
return ERROR_UNKNOWN_PRODUCT;
val = msi_reg_get_val_str( hkey, szAttribute );
RegCloseKey(hkey);
}
else if (!szAttribute[0])
{
return ERROR_UNKNOWN_PROPERTY;
}
if (classes)
MSIREG_OpenLocalSystemProductKey(szProduct, &userdata, FALSE);
else
MSIREG_OpenInstallPropertiesKey(szProduct, &userdata, FALSE);
if (!lstrcmpW(szAttribute, INSTALLPROPERTY_HELPLINKW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_HELPTELEPHONEW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLDATEW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLLOCATIONW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLSOURCEW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_LOCALPACKAGEW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_PUBLISHERW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_URLINFOABOUTW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_URLUPDATEINFOW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONMINORW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONMAJORW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONSTRINGW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_PRODUCTIDW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_REGCOMPANYW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_REGOWNERW))
{
static const WCHAR szDisplayVersion[] = {
'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0 };
if (!prodkey)
{
r = ERROR_UNKNOWN_PRODUCT;
goto done;
}
FIXME("%s\n", debugstr_w(szAttribute));
/* FIXME: some attribute values not tested... */
if (!userdata)
return ERROR_UNKNOWN_PROPERTY;
if (!lstrcmpW( szAttribute, INSTALLPROPERTY_VERSIONSTRINGW ))
szAttribute = szDisplayVersion;
if (!lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW))
szAttribute = display_name;
else if (!lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONSTRINGW))
szAttribute = display_version;
r = MSIREG_OpenUninstallKey( szProduct, &hkey, FALSE );
if (r != ERROR_SUCCESS)
return ERROR_UNKNOWN_PRODUCT;
val = msi_reg_get_val_str( hkey, szAttribute );
RegCloseKey(hkey);
val = msi_reg_get_value(userdata, szAttribute, &type);
if (!val)
val = empty;
}
else if (!lstrcmpW(szAttribute, INSTALLPROPERTY_INSTANCETYPEW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_TRANSFORMSW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_LANGUAGEW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_PRODUCTNAMEW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGECODEW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_PRODUCTICONW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGENAMEW) ||
!lstrcmpW(szAttribute, INSTALLPROPERTY_AUTHORIZED_LUA_APPW))
{
if (!prodkey)
{
r = ERROR_UNKNOWN_PRODUCT;
goto done;
}
TRACE("returning %s\n", debugstr_w(val));
if (!lstrcmpW(szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW))
szAttribute = assignment;
if (!lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGENAMEW))
{
res = RegOpenKeyW(prodkey, sourcelist, &source);
if (res == ERROR_SUCCESS)
val = msi_reg_get_value(source, szAttribute, &type);
RegCloseKey(source);
}
else
{
val = msi_reg_get_value(prodkey, szAttribute, &type);
if (!val)
val = empty;
}
if (val != empty && type != REG_DWORD &&
!lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGECODEW))
{
if (lstrlenW(val) != SQUISH_GUID_SIZE - 1)
badconfig = TRUE;
else
{
unsquash_guid(val, packagecode);
msi_free(val);
val = strdupW(packagecode);
}
}
}
if (!val)
return ERROR_UNKNOWN_PROPERTY;
{
r = ERROR_UNKNOWN_PROPERTY;
goto done;
}
r = msi_strcpy_to_awstring( val, szValue, pcchValueBuf );
if (pcchValueBuf)
{
save = *pcchValueBuf;
msi_free(val);
if (lstrlenW(val) < *pcchValueBuf)
r = msi_strcpy_to_awstring(val, szValue, pcchValueBuf);
else if (szValue->str.a || szValue->str.w)
r = ERROR_MORE_DATA;
if (!badconfig)
*pcchValueBuf = lstrlenW(val);
else if (r == ERROR_SUCCESS)
{
*pcchValueBuf = save;
r = ERROR_BAD_CONFIGURATION;
}
}
else if (badconfig)
r = ERROR_BAD_CONFIGURATION;
if (val != empty)
msi_free(val);
done:
RegCloseKey(prodkey);
RegCloseKey(userdata);
return r;
}
@ -718,6 +797,292 @@ UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute,
&buffer, pcchValueBuf );
}
UINT WINAPI MsiGetProductInfoExA(LPCSTR szProductCode, LPCSTR szUserSid,
MSIINSTALLCONTEXT dwContext, LPCSTR szProperty,
LPSTR szValue, LPDWORD pcchValue)
{
LPWSTR product = NULL;
LPWSTR usersid = NULL;
LPWSTR property = NULL;
LPWSTR value = NULL;
DWORD len = 0;
UINT r;
TRACE("(%s, %s, %d, %s, %p, %p)\n", debugstr_a(szProductCode),
debugstr_a(szUserSid), dwContext, debugstr_a(szProperty),
szValue, pcchValue);
if (szValue && !pcchValue)
return ERROR_INVALID_PARAMETER;
if (szProductCode) product = strdupAtoW(szProductCode);
if (szUserSid) usersid = strdupAtoW(szUserSid);
if (szProperty) property = strdupAtoW(szProperty);
r = MsiGetProductInfoExW(product, usersid, dwContext, property,
NULL, &len);
if (r != ERROR_SUCCESS)
goto done;
value = msi_alloc(++len * sizeof(WCHAR));
if (!value)
{
r = ERROR_OUTOFMEMORY;
goto done;
}
r = MsiGetProductInfoExW(product, usersid, dwContext, property,
value, &len);
if (r != ERROR_SUCCESS)
goto done;
if (!pcchValue)
goto done;
len = WideCharToMultiByte(CP_ACP, 0, value, -1, NULL, 0, NULL, NULL);
if (*pcchValue >= len)
WideCharToMultiByte(CP_ACP, 0, value, -1, szValue, len, NULL, NULL);
else if (szValue)
{
r = ERROR_MORE_DATA;
if (*pcchValue > 0)
*szValue = '\0';
}
if (*pcchValue <= len || !szValue)
len = len * sizeof(WCHAR) - 1;
*pcchValue = len - 1;
done:
msi_free(product);
msi_free(usersid);
msi_free(property);
msi_free(value);
return r;
}
static UINT msi_copy_outval(LPWSTR val, LPWSTR out, LPDWORD size)
{
UINT r;
if (!val)
return ERROR_UNKNOWN_PROPERTY;
if (out)
{
if (lstrlenW(val) >= *size)
{
r = ERROR_MORE_DATA;
if (*size > 0)
*out = '\0';
}
else
lstrcpyW(out, val);
}
if (size)
*size = lstrlenW(val);
return ERROR_SUCCESS;
}
UINT WINAPI MsiGetProductInfoExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
MSIINSTALLCONTEXT dwContext, LPCWSTR szProperty,
LPWSTR szValue, LPDWORD pcchValue)
{
WCHAR squished_pc[GUID_SIZE];
LPWSTR val = NULL;
LPCWSTR package = NULL;
HKEY props = NULL, prod;
HKEY classes = NULL, managed;
HKEY hkey = NULL;
DWORD type;
UINT r = ERROR_UNKNOWN_PRODUCT;
static const WCHAR one[] = {'1',0};
static const WCHAR five[] = {'5',0};
static const WCHAR empty[] = {0};
static const WCHAR displayname[] = {
'D','i','s','p','l','a','y','N','a','m','e',0};
static const WCHAR displayversion[] = {
'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
static const WCHAR managed_local_package[] = {
'M','a','n','a','g','e','d','L','o','c','a','l',
'P','a','c','k','a','g','e',0};
TRACE("(%s, %s, %d, %s, %p, %p)\n", debugstr_w(szProductCode),
debugstr_w(szUserSid), dwContext, debugstr_w(szProperty),
szValue, pcchValue);
if (!szProductCode || !squash_guid(szProductCode, squished_pc))
return ERROR_INVALID_PARAMETER;
if (szValue && !pcchValue)
return ERROR_INVALID_PARAMETER;
if (dwContext != MSIINSTALLCONTEXT_USERUNMANAGED &&
dwContext != MSIINSTALLCONTEXT_USERMANAGED &&
dwContext != MSIINSTALLCONTEXT_MACHINE)
return ERROR_INVALID_PARAMETER;
if (!szProperty || !*szProperty)
return ERROR_INVALID_PARAMETER;
if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
return ERROR_INVALID_PARAMETER;
MSIREG_OpenLocalManagedProductKey(szProductCode, &managed, FALSE);
MSIREG_OpenUserProductsKey(szProductCode, &prod, FALSE);
if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
{
package = INSTALLPROPERTY_LOCALPACKAGEW;
MSIREG_OpenInstallPropertiesKey(szProductCode, &props, FALSE);
if (!props && !prod)
goto done;
}
else if (dwContext == MSIINSTALLCONTEXT_USERMANAGED)
{
package = managed_local_package;
MSIREG_OpenInstallPropertiesKey(szProductCode, &props, FALSE);
if (!props && !managed)
goto done;
}
else if (dwContext == MSIINSTALLCONTEXT_MACHINE)
{
package = INSTALLPROPERTY_LOCALPACKAGEW;
MSIREG_OpenLocalSystemProductKey(szProductCode, &props, FALSE);
MSIREG_OpenLocalClassesProductKey(szProductCode, &classes, FALSE);
if (!props && !classes)
goto done;
}
if (!lstrcmpW(szProperty, INSTALLPROPERTY_HELPLINKW) ||
!lstrcmpW(szProperty, INSTALLPROPERTY_HELPTELEPHONEW) ||
!lstrcmpW(szProperty, INSTALLPROPERTY_INSTALLDATEW) ||
!lstrcmpW(szProperty, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW) ||
!lstrcmpW(szProperty, INSTALLPROPERTY_INSTALLLOCATIONW) ||
!lstrcmpW(szProperty, INSTALLPROPERTY_INSTALLSOURCEW) ||
!lstrcmpW(szProperty, INSTALLPROPERTY_LOCALPACKAGEW) ||
!lstrcmpW(szProperty, INSTALLPROPERTY_PUBLISHERW) ||
!lstrcmpW(szProperty, INSTALLPROPERTY_URLINFOABOUTW) ||
!lstrcmpW(szProperty, INSTALLPROPERTY_URLUPDATEINFOW) ||
!lstrcmpW(szProperty, INSTALLPROPERTY_VERSIONMINORW) ||
!lstrcmpW(szProperty, INSTALLPROPERTY_VERSIONMAJORW) ||
!lstrcmpW(szProperty, INSTALLPROPERTY_VERSIONSTRINGW) ||
!lstrcmpW(szProperty, INSTALLPROPERTY_PRODUCTIDW) ||
!lstrcmpW(szProperty, INSTALLPROPERTY_REGCOMPANYW) ||
!lstrcmpW(szProperty, INSTALLPROPERTY_REGOWNERW) ||
!lstrcmpW(szProperty, INSTALLPROPERTY_INSTANCETYPEW))
{
val = msi_reg_get_value(props, package, &type);
if (!val)
{
if (prod || classes)
r = ERROR_UNKNOWN_PROPERTY;
goto done;
}
msi_free(val);
if (!lstrcmpW(szProperty, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW))
szProperty = displayname;
else if (!lstrcmpW(szProperty, INSTALLPROPERTY_VERSIONSTRINGW))
szProperty = displayversion;
val = msi_reg_get_value(props, szProperty, &type);
if (!val)
val = strdupW(empty);
r = msi_copy_outval(val, szValue, pcchValue);
}
else if (!lstrcmpW(szProperty, INSTALLPROPERTY_TRANSFORMSW) ||
!lstrcmpW(szProperty, INSTALLPROPERTY_LANGUAGEW) ||
!lstrcmpW(szProperty, INSTALLPROPERTY_PRODUCTNAMEW) ||
!lstrcmpW(szProperty, INSTALLPROPERTY_PACKAGECODEW) ||
!lstrcmpW(szProperty, INSTALLPROPERTY_VERSIONW) ||
!lstrcmpW(szProperty, INSTALLPROPERTY_PRODUCTICONW) ||
!lstrcmpW(szProperty, INSTALLPROPERTY_PACKAGENAMEW) ||
!lstrcmpW(szProperty, INSTALLPROPERTY_AUTHORIZED_LUA_APPW))
{
if (!prod && !classes)
goto done;
if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
hkey = prod;
else if (dwContext == MSIINSTALLCONTEXT_USERMANAGED)
hkey = managed;
else if (dwContext == MSIINSTALLCONTEXT_MACHINE)
hkey = classes;
val = msi_reg_get_value(hkey, szProperty, &type);
if (!val)
val = strdupW(empty);
r = msi_copy_outval(val, szValue, pcchValue);
}
else if (!lstrcmpW(szProperty, INSTALLPROPERTY_PRODUCTSTATEW))
{
if (dwContext == MSIINSTALLCONTEXT_MACHINE)
{
if (props)
{
val = msi_reg_get_value(props, package, &type);
if (!val)
goto done;
msi_free(val);
val = strdupW(five);
}
else
val = strdupW(one);
r = msi_copy_outval(val, szValue, pcchValue);
goto done;
}
else if (props && (val = msi_reg_get_value(props, package, &type)))
{
msi_free(val);
val = strdupW(five);
r = msi_copy_outval(val, szValue, pcchValue);
goto done;
}
if (prod || managed)
val = strdupW(one);
else
goto done;
r = msi_copy_outval(val, szValue, pcchValue);
}
else if (!lstrcmpW(szProperty, INSTALLPROPERTY_ASSIGNMENTTYPEW))
{
if (!prod && !classes)
goto done;
/* FIME */
val = strdupW(empty);
r = msi_copy_outval(val, szValue, pcchValue);
}
else
r = ERROR_UNKNOWN_PROPERTY;
done:
RegCloseKey(props);
RegCloseKey(prod);
RegCloseKey(managed);
RegCloseKey(classes);
msi_free(val);
return r;
}
UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes)
{
LPWSTR szwLogFile = NULL;
@ -849,7 +1214,7 @@ static BOOL msi_comp_find_package(LPCWSTR prodcode, MSIINSTALLCONTEXT context)
return (res == ERROR_SUCCESS);
}
static BOOL msi_comp_find_prodcode(LPCWSTR prodcode, LPWSTR squished_pc,
static BOOL msi_comp_find_prodcode(LPWSTR squished_pc,
MSIINSTALLCONTEXT context,
LPCWSTR comp, DWORD *sz)
{
@ -909,7 +1274,7 @@ UINT WINAPI MsiQueryComponentStateW(LPCWSTR szProductCode,
*pdwState = INSTALLSTATE_UNKNOWN;
if (!msi_comp_find_prodcode(szProductCode, squished_pc, dwContext, szComponent, &sz))
if (!msi_comp_find_prodcode(squished_pc, dwContext, szComponent, &sz))
return ERROR_UNKNOWN_COMPONENT;
if (sz == 0)
@ -1571,11 +1936,15 @@ UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf,
static const WCHAR szVersionResource[] = {'\\',0};
static const WCHAR szVersionFormat[] = {
'%','d','.','%','d','.','%','d','.','%','d',0};
static const WCHAR szLangResource[] = {
'\\','V','a','r','F','i','l','e','I','n','f','o','\\',
'T','r','a','n','s','l','a','t','i','o','n',0};
static const WCHAR szLangFormat[] = {'%','d',0};
UINT ret = 0;
DWORD dwVerLen, gle;
LPVOID lpVer = NULL;
VS_FIXEDFILEINFO *ffi;
USHORT *lang;
UINT puLen;
WCHAR tmp[32];
@ -1636,16 +2005,22 @@ UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf,
if (pcchLangBuf)
{
DWORD lang = GetUserDefaultLangID();
if (VerQueryValueW(lpVer, szLangResource, (LPVOID*)&lang, &puLen) &&
(puLen > 0))
{
wsprintfW(tmp, szLangFormat, *lang);
if (lpLangBuf) lstrcpynW(lpLangBuf, tmp, *pcchLangBuf);
FIXME("Retrieve language from file\n");
wsprintfW(tmp, szLangFormat, lang);
if (lpLangBuf) lstrcpynW(lpLangBuf, tmp, *pcchLangBuf);
if (lstrlenW(tmp) >= *pcchLangBuf)
ret = ERROR_MORE_DATA;
if (lstrlenW(tmp) >= *pcchLangBuf)
ret = ERROR_MORE_DATA;
*pcchLangBuf = lstrlenW(tmp);
*pcchLangBuf = lstrlenW(tmp);
}
else
{
if (lpLangBuf) *lpLangBuf = 0;
*pcchLangBuf = 0;
}
}
end:
@ -2109,11 +2484,11 @@ UINT WINAPI MsiConfigureFeatureW(LPCWSTR szProduct, LPCWSTR szFeature, INSTALLST
return r;
sz = sizeof(sourcepath);
MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
sz = sizeof(filename);
MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
lstrcatW( sourcepath, filename );
@ -2294,11 +2669,11 @@ UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
*ptr = 0;
sz = sizeof(sourcepath);
MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
sz = sizeof(filename);
MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
lstrcatW( sourcepath, filename );
@ -2452,3 +2827,25 @@ UINT WINAPI MsiAdvertiseScriptA( LPCSTR szScriptFile, DWORD dwFlags,
debugstr_a( szScriptFile ), dwFlags, phRegData, fRemoveItems );
return ERROR_CALL_NOT_IMPLEMENTED;
}
/***********************************************************************
* MsiIsProductElevatedW [MSI.@]
*/
UINT WINAPI MsiIsProductElevatedW( LPCWSTR szProduct, BOOL *pfElevated )
{
FIXME("%s %p - stub\n",
debugstr_w( szProduct ), pfElevated );
*pfElevated = TRUE;
return ERROR_SUCCESS;
}
/***********************************************************************
* MsiIsProductElevatedA [MSI.@]
*/
UINT WINAPI MsiIsProductElevatedA( LPCSTR szProduct, BOOL *pfElevated )
{
FIXME("%s %p - stub\n",
debugstr_a( szProduct ), pfElevated );
*pfElevated = TRUE;
return ERROR_SUCCESS;
}

View file

@ -207,8 +207,8 @@
211 stdcall MsiSourceListAddSourceW(wstr wstr long wstr)
212 stub MsiSourceListForceResolutionA
213 stub MsiSourceListForceResolutionW
214 stub MsiIsProductElevatedA
215 stub MsiIsProductElevatedW
214 stdcall MsiIsProductElevatedA(str ptr)
215 stdcall MsiIsProductElevatedW(wstr ptr)
216 stdcall MsiGetShortcutTargetA(str ptr ptr ptr)
217 stdcall MsiGetShortcutTargetW(wstr ptr ptr ptr)
218 stdcall MsiGetFileHashA(str long ptr)
@ -240,8 +240,8 @@
244 stub MsiGetPatchInfoExW
245 stdcall MsiEnumProductsExA(str str long long ptr ptr ptr ptr)
246 stdcall MsiEnumProductsExW(wstr wstr long long ptr ptr ptr ptr)
247 stub MsiGetProductInfoExA
248 stub MsiGetProductInfoExW
247 stdcall MsiGetProductInfoExA(str str long str ptr ptr)
248 stdcall MsiGetProductInfoExW(wstr wstr long wstr ptr ptr)
249 stdcall MsiQueryComponentStateA(str str long str ptr)
250 stdcall MsiQueryComponentStateW(wstr wstr long wstr ptr)
251 stub MsiQueryFeatureStateExA
@ -257,16 +257,16 @@
261 stub MsiSourceListForceResolutionExA
262 stub MsiSourceListForceResolutionExW
263 stdcall MsiSourceListEnumSourcesA(str str long long long ptr ptr)
264 stub MsiSourceListEnumSourcesW
264 stdcall MsiSourceListEnumSourcesW(wstr wstr long long long ptr ptr)
265 stdcall MsiSourceListGetInfoA(str str long long str ptr ptr)
266 stdcall MsiSourceListGetInfoW(wstr wstr long long wstr ptr ptr)
267 stub MsiSourceListSetInfoA
267 stdcall MsiSourceListSetInfoA(str str long long str str)
268 stdcall MsiSourceListSetInfoW(wstr wstr long long wstr wstr)
269 stub MsiEnumPatchesExA
270 stub MsiEnumPatchesExW
271 stub MsiSourceListEnumMediaDisksA
272 stub MsiSourceListEnumMediaDisksW
273 stub MsiSourceListAddMediaDiskA
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

View file

@ -22,10 +22,10 @@ LANGUAGE LANG_KOREAN, SUBLANG_NEUTRAL
STRINGTABLE DISCARDABLE
{
4 " 지정한 설치 패키지를 열 수 없습니다. 파일 경로를 확인하고 다시 시도하십시오."
4 " 지정한 설치 패키지를 열 수 없습니다. 파일 경로를 확인하고 다시 시도하십시오."
5 "%s 경로를 찾을수 없습니다"
9 "디스크 %s 삽입"
10 "못된 매개변수"
10 "못된 매개변수"
11 "%s를 포함하는 폴더를 입력하세여"
12 "빠진 부분(feature)을 위한 설치 원본"
13 "빠진 부분(feature)을 위한 네트워크 드라이브"

View file

@ -568,6 +568,7 @@ typedef struct tagMSISCRIPT
#define MSI_BUILDNUMBER 4000
#define GUID_SIZE 39
#define SQUISH_GUID_SIZE 33
#define MSIHANDLE_MAGIC 0x4d434923
@ -748,12 +749,10 @@ 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_OpenUserPatchesKey(LPCWSTR szPatch, HKEY* key, BOOL create);
extern UINT MSIREG_OpenFeatures(HKEY* key);
extern UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
extern UINT MSIREG_OpenUserDataFeaturesKey(LPCWSTR szProduct, HKEY *key, BOOL create);
extern UINT MSIREG_OpenComponents(HKEY* key);
extern UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create);
extern UINT MSIREG_OpenComponentsKey(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_OpenPatchesKey(LPCWSTR szPatch, HKEY* key, BOOL create);
@ -886,6 +885,8 @@ extern BOOL check_unique_action(const MSIPACKAGE *, LPCWSTR);
extern WCHAR* generate_error_string(MSIPACKAGE *, UINT, DWORD, ... );
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);
/* control event stuff */
extern VOID ControlEvent_FireSubscribedEvent(MSIPACKAGE *package, LPCWSTR event,

View file

@ -126,10 +126,25 @@ library WindowsInstaller
msiOpenDatabaseModePatchFile = 32
} MsiOpenDatabaseMode;
typedef enum {
msiUILevelNoChange = 0,
msiUILevelDefault = 1,
msiUILevelNone = 2,
msiUILevelBasic = 3,
msiUILevelReduced = 4,
msiUILevelFull = 5,
msiUILevelHideCancel = 32,
msiUILevelProgressOnly = 64,
msiUILevelEndDialog = 128,
msiUILevelSourceResOnly = 256
} MsiUILevel;
[ uuid(000C1090-0000-0000-C000-000000000046) ]
dispinterface Installer
{
properties:
[id(DISPID_INSTALLER_UILEVEL)]
MsiUILevel UILevel;
methods:
[id(DISPID_INSTALLER_CREATERECORD)]
Record *CreateRecord([in] long Count);

View file

@ -19,6 +19,7 @@
#define DISPID_INSTALLER_CREATERECORD 1
#define DISPID_INSTALLER_OPENPACKAGE 2
#define DISPID_INSTALLER_OPENDATABASE 4
#define DISPID_INSTALLER_UILEVEL 6
#define DISPID_INSTALLER_INSTALLPRODUCT 8
#define DISPID_INSTALLER_VERSION 9
#define DISPID_INSTALLER_REGISTRYVALUE 11

View file

@ -332,12 +332,6 @@ done:
msi_free(version);
}
/*
* There are a whole slew of these we need to set
*
*
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/properties.asp
*/
static VOID set_installer_properties(MSIPACKAGE *package)
{
WCHAR pth[MAX_PATH];
@ -347,11 +341,11 @@ static VOID set_installer_properties(MSIPACKAGE *package)
DWORD verval;
WCHAR verstr[10], bufstr[20];
HDC dc;
LPWSTR check;
HKEY hkey;
LONG res;
LPWSTR username, companyname;
SYSTEM_INFO sys_info;
SYSTEMTIME systemtime;
LANGID langid;
static const WCHAR cszbs[]={'\\',0};
static const WCHAR CFF[] =
@ -420,9 +414,17 @@ static VOID set_installer_properties(MSIPACKAGE *package)
static const WCHAR szScreenX[] = {'S','c','r','e','e','n','X',0};
static const WCHAR szScreenY[] = {'S','c','r','e','e','n','Y',0};
static const WCHAR szColorBits[] = {'C','o','l','o','r','B','i','t','s',0};
static const WCHAR szScreenFormat[] = {'%','d',0};
static const WCHAR szIntFormat[] = {'%','d',0};
static const WCHAR szIntel[] = { 'I','n','t','e','l',0 };
static const WCHAR szAllUsers[] = { 'A','L','L','U','S','E','R','S',0 };
static const WCHAR szUserInfo[] = {
'S','O','F','T','W','A','R','E','\\',
'M','i','c','r','o','s','o','f','t','\\',
'M','S',' ','S','e','t','u','p',' ','(','A','C','M','E',')','\\',
'U','s','e','r',' ','I','n','f','o',0
};
static const WCHAR szDefName[] = { 'D','e','f','N','a','m','e',0 };
static const WCHAR szDefCompany[] = { 'D','e','f','C','o','m','p','a','n','y',0 };
static const WCHAR szCurrentVersion[] = {
'S','O','F','T','W','A','R','E','\\',
'M','i','c','r','o','s','o','f','t','\\',
@ -437,6 +439,7 @@ static VOID set_installer_properties(MSIPACKAGE *package)
static const WCHAR szCOMPANYNAME[] = {'C','O','M','P','A','N','Y','N','A','M','E',0};
static const WCHAR szDate[] = {'D','a','t','e',0};
static const WCHAR szTime[] = {'T','i','m','e',0};
static const WCHAR szUserLangID[] = {'U','s','e','r','L','a','n','g','u','a','g','e','I','D',0};
/*
* Other things that probably should be set:
@ -523,7 +526,7 @@ static VOID set_installer_properties(MSIPACKAGE *package)
/* Physical Memory is specified in MB. Using total amount. */
msex.dwLength = sizeof(msex);
GlobalMemoryStatusEx( &msex );
sprintfW( bufstr, szScreenFormat, (int)(msex.ullTotalPhys/1024/1024));
sprintfW( bufstr, szIntFormat, (int)(msex.ullTotalPhys/1024/1024));
MSI_SetPropertyW(package, szPhysicalMemory, bufstr);
SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
@ -570,42 +573,48 @@ static VOID set_installer_properties(MSIPACKAGE *package)
GetSystemInfo( &sys_info );
if (sys_info.u.s.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
{
sprintfW( bufstr, szScreenFormat, sys_info.wProcessorLevel );
sprintfW( bufstr, szIntFormat, sys_info.wProcessorLevel );
MSI_SetPropertyW( package, szIntel, bufstr );
}
/* Screen properties. */
dc = GetDC(0);
sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, HORZRES ) );
sprintfW( bufstr, szIntFormat, GetDeviceCaps( dc, HORZRES ) );
MSI_SetPropertyW( package, szScreenX, bufstr );
sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, VERTRES ));
sprintfW( bufstr, szIntFormat, GetDeviceCaps( dc, VERTRES ));
MSI_SetPropertyW( package, szScreenY, bufstr );
sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, BITSPIXEL ));
sprintfW( bufstr, szIntFormat, GetDeviceCaps( dc, BITSPIXEL ));
MSI_SetPropertyW( package, szColorBits, bufstr );
ReleaseDC(0, dc);
/* USERNAME and COMPANYNAME */
res = RegOpenKeyW( HKEY_LOCAL_MACHINE, szCurrentVersion, &hkey );
if (res != ERROR_SUCCESS)
return;
username = msi_dup_property( package, szUSERNAME );
companyname = msi_dup_property( package, szCOMPANYNAME );
check = msi_dup_property( package, szUSERNAME );
if (!check)
if ((!username || !companyname) &&
RegOpenKeyW( HKEY_CURRENT_USER, szUserInfo, &hkey ) == ERROR_SUCCESS)
{
LPWSTR user = msi_reg_get_val_str( hkey, szRegisteredUser );
MSI_SetPropertyW( package, szUSERNAME, user );
msi_free( user );
if (!username &&
(username = msi_reg_get_val_str( hkey, szDefName )))
MSI_SetPropertyW( package, szUSERNAME, username );
if (!companyname &&
(companyname = msi_reg_get_val_str( hkey, szDefCompany )))
MSI_SetPropertyW( package, szCOMPANYNAME, companyname );
CloseHandle( hkey );
}
msi_free( check );
check = msi_dup_property( package, szCOMPANYNAME );
if (!check)
if ((!username || !companyname) &&
RegOpenKeyW( HKEY_LOCAL_MACHINE, szCurrentVersion, &hkey ) == ERROR_SUCCESS)
{
LPWSTR company = msi_reg_get_val_str( hkey, szRegisteredOrg );
MSI_SetPropertyW( package, szCOMPANYNAME, company );
msi_free( company );
if (!username &&
(username = msi_reg_get_val_str( hkey, szRegisteredUser )))
MSI_SetPropertyW( package, szUSERNAME, username );
if (!companyname &&
(companyname = msi_reg_get_val_str( hkey, szRegisteredOrg )))
MSI_SetPropertyW( package, szCOMPANYNAME, companyname );
CloseHandle( hkey );
}
msi_free( username );
msi_free( companyname );
if ( set_user_sid_prop( package ) != ERROR_SUCCESS)
ERR("Failed to set the UserSID property\n");
@ -628,8 +637,10 @@ static VOID set_installer_properties(MSIPACKAGE *package)
set_msi_assembly_prop( package );
msi_free( check );
CloseHandle( hkey );
langid = GetUserDefaultLangID();
sprintfW(bufstr, szIntFormat, langid);
MSI_SetPropertyW( package, szUserLangID, bufstr );
}
static UINT msi_load_summary_properties( MSIPACKAGE *package )
@ -1637,7 +1648,7 @@ static HRESULT WINAPI mrp_SetMsiHandle( IWineMsiRemotePackage *iface, MSIHANDLE
return S_OK;
}
HRESULT WINAPI mrp_GetActiveDatabase( IWineMsiRemotePackage *iface, MSIHANDLE *handle )
static HRESULT WINAPI mrp_GetActiveDatabase( IWineMsiRemotePackage *iface, MSIHANDLE *handle )
{
msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
IWineMsiRemoteDatabase *rdb = NULL;
@ -1664,7 +1675,7 @@ HRESULT WINAPI mrp_GetActiveDatabase( IWineMsiRemotePackage *iface, MSIHANDLE *h
return S_OK;
}
HRESULT WINAPI mrp_GetProperty( IWineMsiRemotePackage *iface, BSTR property, BSTR *value, DWORD *size )
static HRESULT WINAPI mrp_GetProperty( IWineMsiRemotePackage *iface, BSTR property, BSTR *value, DWORD *size )
{
msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
UINT r;
@ -1676,63 +1687,63 @@ HRESULT WINAPI mrp_GetProperty( IWineMsiRemotePackage *iface, BSTR property, BST
return S_OK;
}
HRESULT WINAPI mrp_SetProperty( IWineMsiRemotePackage *iface, BSTR property, BSTR value )
static HRESULT WINAPI mrp_SetProperty( IWineMsiRemotePackage *iface, BSTR property, BSTR value )
{
msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
UINT r = MsiSetPropertyW(This->package, (LPWSTR)property, (LPWSTR)value);
return HRESULT_FROM_WIN32(r);
}
HRESULT WINAPI mrp_ProcessMessage( IWineMsiRemotePackage *iface, INSTALLMESSAGE message, MSIHANDLE record )
static HRESULT WINAPI mrp_ProcessMessage( IWineMsiRemotePackage *iface, INSTALLMESSAGE message, MSIHANDLE record )
{
msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
UINT r = MsiProcessMessage(This->package, message, record);
return HRESULT_FROM_WIN32(r);
}
HRESULT WINAPI mrp_DoAction( IWineMsiRemotePackage *iface, BSTR action )
static HRESULT WINAPI mrp_DoAction( IWineMsiRemotePackage *iface, BSTR action )
{
msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
UINT r = MsiDoActionW(This->package, (LPWSTR)action);
return HRESULT_FROM_WIN32(r);
}
HRESULT WINAPI mrp_Sequence( IWineMsiRemotePackage *iface, BSTR table, int sequence )
static HRESULT WINAPI mrp_Sequence( IWineMsiRemotePackage *iface, BSTR table, int sequence )
{
msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
UINT r = MsiSequenceW(This->package, (LPWSTR)table, sequence);
return HRESULT_FROM_WIN32(r);
}
HRESULT WINAPI mrp_GetTargetPath( IWineMsiRemotePackage *iface, BSTR folder, BSTR *value, DWORD *size )
static HRESULT WINAPI mrp_GetTargetPath( IWineMsiRemotePackage *iface, BSTR folder, BSTR *value, DWORD *size )
{
msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
UINT r = MsiGetTargetPathW(This->package, (LPWSTR)folder, (LPWSTR)value, size);
return HRESULT_FROM_WIN32(r);
}
HRESULT WINAPI mrp_SetTargetPath( IWineMsiRemotePackage *iface, BSTR folder, BSTR value)
static HRESULT WINAPI mrp_SetTargetPath( IWineMsiRemotePackage *iface, BSTR folder, BSTR value)
{
msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
UINT r = MsiSetTargetPathW(This->package, (LPWSTR)folder, (LPWSTR)value);
return HRESULT_FROM_WIN32(r);
}
HRESULT WINAPI mrp_GetSourcePath( IWineMsiRemotePackage *iface, BSTR folder, BSTR *value, DWORD *size )
static HRESULT WINAPI mrp_GetSourcePath( IWineMsiRemotePackage *iface, BSTR folder, BSTR *value, DWORD *size )
{
msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
UINT r = MsiGetSourcePathW(This->package, (LPWSTR)folder, (LPWSTR)value, size);
return HRESULT_FROM_WIN32(r);
}
HRESULT WINAPI mrp_GetMode( IWineMsiRemotePackage *iface, MSIRUNMODE mode, BOOL *ret )
static HRESULT WINAPI mrp_GetMode( IWineMsiRemotePackage *iface, MSIRUNMODE mode, BOOL *ret )
{
msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
*ret = MsiGetMode(This->package, mode);
return S_OK;
}
HRESULT WINAPI mrp_GetFeatureState( IWineMsiRemotePackage *iface, BSTR feature,
static HRESULT WINAPI mrp_GetFeatureState( IWineMsiRemotePackage *iface, BSTR feature,
INSTALLSTATE *installed, INSTALLSTATE *action )
{
msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
@ -1740,14 +1751,14 @@ HRESULT WINAPI mrp_GetFeatureState( IWineMsiRemotePackage *iface, BSTR feature,
return HRESULT_FROM_WIN32(r);
}
HRESULT WINAPI mrp_SetFeatureState( IWineMsiRemotePackage *iface, BSTR feature, INSTALLSTATE state )
static HRESULT WINAPI mrp_SetFeatureState( IWineMsiRemotePackage *iface, BSTR feature, INSTALLSTATE state )
{
msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
UINT r = MsiSetFeatureStateW(This->package, (LPWSTR)feature, state);
return HRESULT_FROM_WIN32(r);
}
HRESULT WINAPI mrp_GetComponentState( IWineMsiRemotePackage *iface, BSTR component,
static HRESULT WINAPI mrp_GetComponentState( IWineMsiRemotePackage *iface, BSTR component,
INSTALLSTATE *installed, INSTALLSTATE *action )
{
msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
@ -1755,28 +1766,28 @@ HRESULT WINAPI mrp_GetComponentState( IWineMsiRemotePackage *iface, BSTR compone
return HRESULT_FROM_WIN32(r);
}
HRESULT WINAPI mrp_SetComponentState( IWineMsiRemotePackage *iface, BSTR component, INSTALLSTATE state )
static HRESULT WINAPI mrp_SetComponentState( IWineMsiRemotePackage *iface, BSTR component, INSTALLSTATE state )
{
msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
UINT r = MsiSetComponentStateW(This->package, (LPWSTR)component, state);
return HRESULT_FROM_WIN32(r);
}
HRESULT WINAPI mrp_GetLanguage( IWineMsiRemotePackage *iface, LANGID *language )
static HRESULT WINAPI mrp_GetLanguage( IWineMsiRemotePackage *iface, LANGID *language )
{
msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
*language = MsiGetLanguage(This->package);
return S_OK;
}
HRESULT WINAPI mrp_SetInstallLevel( IWineMsiRemotePackage *iface, int level )
static HRESULT WINAPI mrp_SetInstallLevel( IWineMsiRemotePackage *iface, int level )
{
msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
UINT r = MsiSetInstallLevel(This->package, level);
return HRESULT_FROM_WIN32(r);
}
HRESULT WINAPI mrp_FormatRecord( IWineMsiRemotePackage *iface, MSIHANDLE record,
static HRESULT WINAPI mrp_FormatRecord( IWineMsiRemotePackage *iface, MSIHANDLE record,
BSTR value, DWORD *size )
{
msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
@ -1784,7 +1795,7 @@ HRESULT WINAPI mrp_FormatRecord( IWineMsiRemotePackage *iface, MSIHANDLE record,
return HRESULT_FROM_WIN32(r);
}
HRESULT WINAPI mrp_EvaluateCondition( IWineMsiRemotePackage *iface, BSTR condition )
static HRESULT WINAPI mrp_EvaluateCondition( IWineMsiRemotePackage *iface, BSTR condition )
{
msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
UINT r = MsiEvaluateConditionW(This->package, (LPWSTR)condition);

View file

@ -338,7 +338,13 @@ UINT MSI_RecordGetStringA(MSIRECORD *rec, UINT iField,
TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
if( iField > rec->count )
return ERROR_INVALID_PARAMETER;
{
if ( szValue && *pcchValue > 0 )
szValue[0] = 0;
*pcchValue = 0;
return ERROR_SUCCESS;
}
ret = ERROR_SUCCESS;
switch( rec->fields[iField].type )
@ -414,7 +420,13 @@ UINT MSI_RecordGetStringW(MSIRECORD *rec, UINT iField,
TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
if( iField > rec->count )
return ERROR_INVALID_PARAMETER;
{
if ( szValue && *pcchValue > 0 )
szValue[0] = 0;
*pcchValue = 0;
return ERROR_SUCCESS;
}
ret = ERROR_SUCCESS;
switch( rec->fields[iField].type )
@ -661,7 +673,7 @@ UINT MSI_RecordSetStream(MSIRECORD *rec, UINT iField, IStream *stream)
return ERROR_SUCCESS;
}
UINT MSI_RecordSetStreamFromFileW(MSIRECORD *rec, UINT iField, LPCWSTR szFilename)
static UINT MSI_RecordSetStreamFromFileW(MSIRECORD *rec, UINT iField, LPCWSTR szFilename)
{
IStream *stm = NULL;
HRESULT r;

View file

@ -52,14 +52,6 @@ static const WCHAR szUserFeatures_fmt[] = {
'F','e','a','t','u','r','e','s','\\',
'%','s',0};
static const WCHAR szInstaller_Features[] = {
'S','o','f','t','w','a','r','e','\\',
'M','i','c','r','o','s','o','f','t','\\',
'W','i','n','d','o','w','s','\\',
'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
'I','n','s','t','a','l','l','e','r','\\',
'F','e','a','t','u','r','e','s',0 };
static const WCHAR szUserDataFeatures_fmt[] = {
'S','o','f','t','w','a','r','e','\\',
'M','i','c','r','o','s','o','f','t','\\',
@ -87,15 +79,6 @@ static const WCHAR szInstaller_Components[] = {
'I','n','s','t','a','l','l','e','r','\\',
'C','o','m','p','o','n','e','n','t','s',0 };
static const WCHAR szInstaller_Components_fmt[] = {
'S','o','f','t','w','a','r','e','\\',
'M','i','c','r','o','s','o','f','t','\\',
'W','i','n','d','o','w','s','\\',
'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
'I','n','s','t','a','l','l','e','r','\\',
'C','o','m','p','o','n','e','n','t','s','\\',
'%','s',0};
static const WCHAR szUser_Components_fmt[] = {
'S','o','f','t','w','a','r','e','\\',
'M','i','c','r','o','s','o','f','t','\\',
@ -231,8 +214,6 @@ static const WCHAR szInstaller_LocalManagedProd_fmt[] = {
'I','n','s','t','a','l','l','e','r','\\',
'P','r','o','d','u','c','t','s','\\','%','s',0};
#define SQUISH_GUID_SIZE 33
BOOL unsquash_guid(LPCWSTR in, LPWSTR out)
{
DWORD i,n=0;
@ -610,11 +591,6 @@ UINT MSIREG_DeleteUserFeaturesKey(LPCWSTR szProduct)
return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
}
UINT MSIREG_OpenFeatures(HKEY* key)
{
return RegCreateKeyW(HKEY_LOCAL_MACHINE,szInstaller_Features,key);
}
UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create)
{
UINT rc;
@ -671,27 +647,6 @@ UINT MSIREG_OpenComponents(HKEY* key)
return RegCreateKeyW(HKEY_LOCAL_MACHINE,szInstaller_Components,key);
}
UINT MSIREG_OpenComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create)
{
UINT rc;
WCHAR squished_cc[GUID_SIZE];
WCHAR keypath[0x200];
TRACE("%s\n",debugstr_w(szComponent));
if (!squash_guid(szComponent,squished_cc))
return ERROR_FUNCTION_FAILED;
TRACE("squished (%s)\n", debugstr_w(squished_cc));
sprintfW(keypath,szInstaller_Components_fmt,squished_cc);
if (create)
rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
else
rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
return rc;
}
UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create)
{
UINT rc;
@ -853,11 +808,6 @@ UINT MSIREG_DeleteUserDataProductKey(LPCWSTR szProduct)
return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
}
UINT MSIREG_OpenProducts(HKEY* key)
{
return RegCreateKeyW(HKEY_LOCAL_MACHINE,szInstaller_Products,key);
}
UINT MSIREG_OpenProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create)
{
UINT rc;
@ -1182,7 +1132,7 @@ UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid)
if (NULL == lpguid)
return ERROR_INVALID_PARAMETER;
r = MSIREG_OpenProducts(&hkeyProducts);
r = RegCreateKeyW(HKEY_LOCAL_MACHINE, szInstaller_Products, &hkeyProducts);
if( r != ERROR_SUCCESS )
return ERROR_NO_MORE_ITEMS;

File diff suppressed because it is too large Load diff

View file

@ -29,6 +29,7 @@
#include "msiquery.h"
#include "objbase.h"
#include "msipriv.h"
#include "query.h"
#include "wine/debug.h"
@ -39,7 +40,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msidb);
typedef struct tabSTREAM
{
int str_index;
UINT str_index;
LPWSTR name;
IStream *stream;
} STREAM;
@ -54,7 +55,7 @@ typedef struct tagMSISTREAMSVIEW
UINT row_size;
} MSISTREAMSVIEW;
static BOOL streams_set_table_size(MSISTREAMSVIEW *sv, int size)
static BOOL streams_set_table_size(MSISTREAMSVIEW *sv, UINT size)
{
if (size >= sv->max_streams)
{
@ -372,7 +373,7 @@ static UINT STREAMS_modify(struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIRE
static UINT STREAMS_delete(struct tagMSIVIEW *view)
{
MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view;
int i;
UINT i;
TRACE("(%p)\n", view);
@ -439,7 +440,7 @@ static const MSIVIEWOPS streams_ops =
NULL,
};
static UINT add_streams_to_table(MSISTREAMSVIEW *sv)
static INT add_streams_to_table(MSISTREAMSVIEW *sv)
{
IEnumSTATSTG *stgenum = NULL;
STATSTG stat;
@ -498,6 +499,7 @@ static UINT add_streams_to_table(MSISTREAMSVIEW *sv)
UINT STREAMS_CreateView(MSIDATABASE *db, MSIVIEW **view)
{
MSISTREAMSVIEW *sv;
INT rows;
TRACE("(%p, %p)\n", db, view);
@ -507,10 +509,10 @@ UINT STREAMS_CreateView(MSIDATABASE *db, MSIVIEW **view)
sv->view.ops = &streams_ops;
sv->db = db;
sv->num_rows = add_streams_to_table(sv);
if (sv->num_rows < 0)
rows = add_streams_to_table(sv);
if (rows < 0)
return ERROR_FUNCTION_FAILED;
sv->num_rows = rows;
*view = (MSIVIEW *)sv;

View file

@ -34,6 +34,7 @@
#include "msidefs.h"
#include "msipriv.h"
#include "objidl.h"
#include "propvarutil.h"
#include "msiserver.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
@ -78,6 +79,10 @@ typedef struct {
#include "poppack.h"
static HRESULT (WINAPI *pPropVariantChangeType)
(PROPVARIANT *ppropvarDest, REFPROPVARIANT propvarSrc,
PROPVAR_CHANGE_FLAGS flags, VARTYPE vt);
#define SECT_HDR_SIZE (sizeof(PROPERTYSECTIONHEADER))
static const WCHAR szSumInfo[] = { 5 ,'S','u','m','m','a','r','y',
@ -144,6 +149,22 @@ static UINT get_property_count( const PROPVARIANT *property )
return n;
}
static UINT propvar_changetype(PROPVARIANT *changed, PROPVARIANT *property, VARTYPE vt)
{
HRESULT hr;
HMODULE propsys = LoadLibraryA("propsys.dll");
pPropVariantChangeType = (void *)GetProcAddress(propsys, "PropVariantChangeType");
if (!pPropVariantChangeType)
{
ERR("PropVariantChangeType function missing!\n");
return ERROR_FUNCTION_FAILED;
}
hr = pPropVariantChangeType(changed, property, 0, vt);
return (hr == S_OK) ? ERROR_SUCCESS : ERROR_FUNCTION_FAILED;
}
/* FIXME: doesn't deal with endian conversion */
static void read_properties_from_data( PROPVARIANT *prop, LPBYTE data, DWORD sz )
{
@ -151,7 +172,8 @@ static void read_properties_from_data( PROPVARIANT *prop, LPBYTE data, DWORD sz
DWORD i;
int size;
PROPERTY_DATA *propdata;
PROPVARIANT *property;
PROPVARIANT property, *ptr;
PROPVARIANT changed;
PROPERTYIDOFFSET *idofs;
PROPERTYSECTIONHEADER *section_hdr;
@ -161,6 +183,12 @@ static void read_properties_from_data( PROPVARIANT *prop, LPBYTE data, DWORD sz
/* now set all the properties */
for( i = 0; i < section_hdr->cProperties; i++ )
{
if( idofs[i].propid >= MSI_MAX_PROPS )
{
ERR("Unknown property ID %d\n", idofs[i].propid );
break;
}
type = get_type( idofs[i].propid );
if( type == VT_EMPTY )
{
@ -170,45 +198,41 @@ static void read_properties_from_data( PROPVARIANT *prop, LPBYTE data, DWORD sz
propdata = (PROPERTY_DATA*) &data[ idofs[i].dwOffset ];
/* check the type is the same as we expect */
if( type != propdata->type )
{
ERR("wrong type %d != %d\n", type, propdata->type);
break;
}
/* check we don't run off the end of the data */
size = sz - idofs[i].dwOffset - sizeof(DWORD);
if( sizeof(DWORD) > size ||
( type == VT_FILETIME && sizeof(FILETIME) > size ) ||
( type == VT_LPSTR && (propdata->u.str.len + sizeof(DWORD)) > size ) )
( propdata->type == VT_FILETIME && sizeof(FILETIME) > size ) ||
( propdata->type == VT_LPSTR && (propdata->u.str.len + sizeof(DWORD)) > size ) )
{
ERR("not enough data\n");
break;
}
if( idofs[i].propid >= MSI_MAX_PROPS )
{
ERR("Unknown property ID %d\n", idofs[i].propid );
break;
}
property = &prop[ idofs[i].propid ];
property->vt = type;
if( type == VT_LPSTR )
property.vt = propdata->type;
if( propdata->type == VT_LPSTR )
{
LPSTR str = msi_alloc( propdata->u.str.len );
memcpy( str, propdata->u.str.str, propdata->u.str.len );
str[ propdata->u.str.len - 1 ] = 0;
property->u.pszVal = str;
property.u.pszVal = str;
}
else if( type == VT_FILETIME )
property->u.filetime = propdata->u.ft;
else if( type == VT_I2 )
property->u.iVal = propdata->u.i2;
else if( type == VT_I4 )
property->u.lVal = propdata->u.i4;
else if( propdata->type == VT_FILETIME )
property.u.filetime = propdata->u.ft;
else if( propdata->type == VT_I2 )
property.u.iVal = propdata->u.i2;
else if( propdata->type == VT_I4 )
property.u.lVal = propdata->u.i4;
/* check the type is the same as we expect */
if( type != propdata->type )
{
propvar_changetype(&changed, &property, type);
ptr = &changed;
}
else
ptr = &property;
prop[ idofs[i].propid ] = *ptr;
}
}
@ -363,7 +387,7 @@ static UINT save_summary_info( const MSISUMMARYINFO * si, IStream *stm )
/* write the format header */
sz = sizeof format_hdr;
memcpy( &format_hdr.fmtid, &FMTID_SummaryInformation, sizeof (FMTID) );
format_hdr.fmtid = FMTID_SummaryInformation;
format_hdr.dwOffset = sizeof format_hdr + sizeof set_hdr;
r = IStream_Write( stm, &format_hdr, sz, &count );
if( FAILED(r) || count != sz )
@ -600,7 +624,7 @@ static UINT get_prop( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType,
break;
case VT_FILETIME:
if( pftValue )
memcpy(pftValue, &prop->u.filetime, sizeof (FILETIME) );
*pftValue = prop->u.filetime;
break;
case VT_EMPTY:
break;
@ -721,7 +745,7 @@ static UINT set_prop( MSIHANDLE handle, UINT uiProperty, UINT uiDataType,
prop->u.iVal = iValue;
break;
case VT_FILETIME:
memcpy( &prop->u.filetime, pftValue, sizeof prop->u.filetime );
prop->u.filetime = *pftValue;
break;
case VT_LPSTR:
if( str->unicode )

View file

@ -923,7 +923,7 @@ static UINT get_defaulttablecolumns( LPCWSTR name, MSICOLUMNINFO *colinfo, UINT
{
if (colinfo && (i < *sz) )
{
memcpy( &colinfo[i], &p[i], sizeof(MSICOLUMNINFO) );
colinfo[i] = p[i];
colinfo[i].tablename = strdupW( p[i].tablename );
colinfo[i].colname = strdupW( p[i].colname );
}
@ -1626,6 +1626,23 @@ static UINT modify_delete_row( struct tagMSIVIEW *view, MSIRECORD *rec )
return TABLE_delete_row(view, row);
}
static UINT msi_refresh_record( struct tagMSIVIEW *view, MSIRECORD *rec, UINT row )
{
MSIRECORD *curr;
UINT r, i, count;
r = TABLE_get_row(view, row - 1, &curr);
if (r != ERROR_SUCCESS)
return r;
count = MSI_RecordGetFieldCount(rec);
for (i = 0; i < count; i++)
MSI_RecordCopyField(curr, i + 1, rec, i + 1);
msiobj_release(&curr->hdr);
return ERROR_SUCCESS;
}
static UINT TABLE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
MSIRECORD *rec, UINT row)
{
@ -1657,11 +1674,14 @@ static UINT TABLE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
r = TABLE_insert_row( view, rec, TRUE );
break;
case MSIMODIFY_REFRESH:
r = msi_refresh_record( view, rec, row );
break;
case MSIMODIFY_UPDATE:
r = msi_table_update( view, rec, row );
break;
case MSIMODIFY_REFRESH:
case MSIMODIFY_ASSIGN:
case MSIMODIFY_REPLACE:
case MSIMODIFY_MERGE:
@ -2034,6 +2054,9 @@ static UINT TABLE_sort(struct tagMSIVIEW *view, column_info *columns)
if (r != ERROR_SUCCESS)
return r;
if (rows == 0)
return ERROR_SUCCESS;
order = msi_alloc_zero(sizeof(MSIORDERINFO) + sizeof(UINT) * cols);
if (!order)
return ERROR_OUTOFMEMORY;

View file

@ -88,7 +88,7 @@ static UINT find_entry_in_hash(MSIHASHENTRY **table, UINT row, UINT *val)
if (!(entry = table[row % MSI_HASH_TABLE_SIZE]))
{
ERR("Row not found in hash table!\n");
WARN("Row not found in hash table!\n");
return ERROR_FUNCTION_FAILED;
}
@ -503,12 +503,15 @@ static UINT WHERE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
MSIRECORD *rec, UINT row )
{
MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
UINT r;
TRACE("%p %d %p\n", wv, eModifyMode, rec );
TRACE("%p %d %p\n", wv, eModifyMode, rec);
if( !wv->table )
return ERROR_FUNCTION_FAILED;
r = WHERE_execute(view, NULL);
if (r != ERROR_SUCCESS)
return r;
find_entry_in_hash(wv->reorder, row - 1, &row);
return wv->table->ops->modify( wv->table, eModifyMode, rec, row );
}