- sync MSI to Wine 0.9.18

- note, it still has the swprintf warnings which I'll fix tomorrow (if someone reminds me ;) )
- MSI Wine test is now in trunk, if anyone has chance to do a before and after test ...

svn path=/trunk/; revision=23414
This commit is contained in:
Ged Murphy 2006-08-01 23:12:11 +00:00
parent 5e15912284
commit 6193e2092b
59 changed files with 3842 additions and 1740 deletions

View file

@ -1,68 +1,75 @@
TOPSRCDIR = @top_srcdir@
TOPOBJDIR = ../..
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = msi.dll
IMPORTLIB = libmsi.$(IMPLIBEXT)
IMPORTS = shell32 shlwapi cabinet oleaut32 ole32 version user32 gdi32 advapi32 kernel32
EXTRALIBS = -luuid $(LIBUNICODE)
C_SRCS = \
action.c \
appsearch.c \
classes.c \
create.c \
custom.c \
database.c \
delete.c \
dialog.c \
distinct.c \
events.c \
files.c \
format.c \
handle.c \
helpers.c \
insert.c \
install.c \
msi.c \
msiquery.c \
order.c \
package.c \
preview.c \
record.c \
registry.c \
regsvr.c \
select.c \
source.c \
string.c \
suminfo.c \
table.c \
tokenize.c \
update.c \
upgrade.c \
where.c
RC_SRCS = msi.rc
EXTRA_SRCS = sql.y cond.y
EXTRA_OBJS = sql.tab.o cond.tab.o
SUBDIRS = tests
@MAKE_DLL_RULES@
sql.tab.c sql.tab.h: sql.y
$(BISON) -p SQL_ -d $(SRCDIR)/sql.y -o sql.tab.c
cond.tab.c cond.tab.h: cond.y
$(BISON) -p COND_ -d $(SRCDIR)/cond.y -o cond.tab.c
# hack to allow parallel make
sql.tab.h: sql.tab.c
sql.tab.o: sql.tab.h
cond.tab.h: cond.tab.c
cond.tab.o: cond.tab.h
tokenize.o: sql.tab.h
### Dependencies:
TOPSRCDIR = @top_srcdir@
TOPOBJDIR = ../..
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = msi.dll
IMPORTLIB = libmsi.$(IMPLIBEXT)
IMPORTS = urlmon wininet comctl32 shell32 shlwapi cabinet oleaut32 ole32 version user32 gdi32 advapi32 kernel32
EXTRALIBS = -luuid
C_SRCS = \
action.c \
appsearch.c \
classes.c \
create.c \
custom.c \
database.c \
delete.c \
dialog.c \
distinct.c \
events.c \
files.c \
format.c \
handle.c \
helpers.c \
insert.c \
install.c \
join.c \
msi.c \
msi_main.c \
msiquery.c \
order.c \
package.c \
preview.c \
record.c \
registry.c \
regsvr.c \
select.c \
source.c \
string.c \
suminfo.c \
table.c \
tokenize.c \
update.c \
upgrade.c \
where.c
RC_SRCS = msi.rc
RC_BINSRC = msi.rc
RC_BINARIES = \
instabsent.bmp \
instadvert.bmp \
instlocal.bmp
EXTRA_SRCS = sql.y cond.y
EXTRA_OBJS = sql.tab.o cond.tab.o
SUBDIRS = tests
@MAKE_DLL_RULES@
sql.tab.c sql.tab.h: sql.y
$(BISON) -p SQL_ -d $(SRCDIR)/sql.y -o sql.tab.c
cond.tab.c cond.tab.h: cond.y
$(BISON) -p COND_ -d $(SRCDIR)/cond.y -o cond.tab.c
# hack to allow parallel make
sql.tab.h: sql.tab.c
sql.tab.o: sql.tab.h
cond.tab.h: cond.tab.c
cond.tab.o: cond.tab.h
tokenize.o: sql.tab.h
### Dependencies:

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
/*
@ -113,7 +113,7 @@ static const WCHAR szForceReboot[] =
{'F','o','r','c','e','R','e','b','o','o','t',0};
static const WCHAR szResolveSource[] =
{'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
const WCHAR szAppSearch[] =
static const WCHAR szAppSearch[] =
{'A','p','p','S','e','a','r','c','h',0};
static const WCHAR szAllocateRegistrySpace[] =
{'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
@ -154,8 +154,6 @@ static const WCHAR szInstallODBC[] =
{'I','n','s','t','a','l','l','O','D','B','C',0};
static const WCHAR szInstallServices[] =
{'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
static const WCHAR szISInitAllUsers[] =
{'I','S','I','n','i','t','A','l','l','U','s','e','r','s',0};
const WCHAR szPatchFiles[] =
{'P','a','t','c','h','F','i','l','e','s',0};
static const WCHAR szPublishComponents[] =
@ -249,55 +247,20 @@ static struct _actions StandardActions[];
* helper functions
********************************************************/
static void ce_actiontext(MSIPACKAGE* package, LPCWSTR action)
{
static const WCHAR szActionText[] =
{'A','c','t','i','o','n','T','e','x','t',0};
MSIRECORD *row;
row = MSI_CreateRecord(1);
MSI_RecordSetStringW(row,1,action);
ControlEvent_FireSubscribedEvent(package,szActionText, row);
msiobj_release(&row->hdr);
}
static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
{
static const WCHAR template_s[]=
{'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ', '%','s',
'.',0};
static const WCHAR format[] =
{'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
static const WCHAR Query_t[] =
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
'`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
' ','\'','%','s','\'',0};
WCHAR message[1024];
WCHAR timet[0x100];
MSIRECORD * row = 0;
LPCWSTR ActionText;
LPWSTR deformated;
GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
MSIRECORD * row;
row = MSI_QueryGetRecord( package->db, Query_t, action );
if (!row)
return;
ActionText = MSI_RecordGetString(row,2);
deformat_string(package, ActionText, &deformated);
sprintfW(message,template_s,timet,action,deformated);
ce_actiontext(package, deformated);
msiobj_release(&row->hdr);
row = MSI_CreateRecord(1);
MSI_RecordSetStringW(row,1,message);
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
msiobj_release(&row->hdr);
msi_free(deformated);
}
static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
@ -329,14 +292,6 @@ static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
msiobj_release(&row->hdr);
}
static int msi_get_property_int( MSIPACKAGE *package, LPCWSTR prop, int def )
{
LPWSTR str = msi_dup_property( package, prop );
int val = str ? atoiW( str ) : def;
msi_free( str );
return val;
}
static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
{
LPCWSTR ptr,ptr2;
@ -610,8 +565,7 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
MSI_SetPropertyW(package, szAction, szInstall);
package->script = msi_alloc(sizeof(MSISCRIPT));
memset(package->script,0,sizeof(MSISCRIPT));
package->script = msi_alloc_zero(sizeof(MSISCRIPT));
package->script->InWhatSequence = SEQUENCE_INSTALL;
@ -921,12 +875,6 @@ static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
BOOL run = force;
int i;
if (!package)
{
ERR("package was null!\n");
return FALSE;
}
if (!run && !package->script->CurrentlyScripting)
run = TRUE;
@ -1147,13 +1095,16 @@ static UINT ACTION_CreateFolders(MSIPACKAGE *package)
return rc;
}
static MSICOMPONENT* load_component( MSIRECORD * row )
static UINT load_component( MSIRECORD *row, LPVOID param )
{
MSIPACKAGE *package = param;
MSICOMPONENT *comp;
comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
if (!comp)
return comp;
return ERROR_FUNCTION_FAILED;
list_add_tail( &package->components, &comp->entry );
/* fill in the data */
comp->Component = msi_dup_record_field( row, 1 );
@ -1167,12 +1118,44 @@ static MSICOMPONENT* load_component( MSIRECORD * row )
comp->KeyPath = msi_dup_record_field( row, 6 );
comp->Installed = INSTALLSTATE_ABSENT;
comp->Action = INSTALLSTATE_UNKNOWN;
comp->ActionRequest = INSTALLSTATE_UNKNOWN;
comp->Enabled = TRUE;
switch (comp->Attributes)
{
case msidbComponentAttributesLocalOnly:
case msidbComponentAttributesOptional:
comp->Action = INSTALLSTATE_LOCAL;
comp->ActionRequest = INSTALLSTATE_LOCAL;
break;
case msidbComponentAttributesSourceOnly:
comp->Action = INSTALLSTATE_SOURCE;
comp->ActionRequest = INSTALLSTATE_SOURCE;
break;
default:
comp->Action = INSTALLSTATE_UNKNOWN;
comp->ActionRequest = INSTALLSTATE_UNKNOWN;
}
return comp;
return ERROR_SUCCESS;
}
static UINT load_all_components( MSIPACKAGE *package )
{
static const WCHAR query[] = {
'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
'`','C','o','m','p','o','n','e','n','t','`',0 };
MSIQUERY *view;
UINT r;
if (!list_empty(&package->components))
return ERROR_SUCCESS;
r = MSI_DatabaseOpenViewW( package->db, query, &view );
if (r != ERROR_SUCCESS)
return r;
r = MSI_IterateRecords(view, NULL, load_component, package);
msiobj_release(&view->hdr);
return r;
}
typedef struct {
@ -1193,56 +1176,24 @@ static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
return ERROR_SUCCESS;
}
static UINT iterate_component_check( MSIRECORD *row, LPVOID param )
{
_ilfs* ilfs= (_ilfs*)param;
MSIPACKAGE *package = ilfs->package;
MSIFEATURE *feature = ilfs->feature;
MSICOMPONENT *comp;
comp = load_component( row );
if (!comp)
return ERROR_FUNCTION_FAILED;
list_add_tail( &package->components, &comp->entry );
add_feature_component( feature, comp );
TRACE("Loaded new component %p\n", comp);
return ERROR_SUCCESS;
}
static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
{
_ilfs* ilfs= (_ilfs*)param;
LPCWSTR component;
DWORD rc;
MSICOMPONENT *comp;
MSIQUERY * view;
static const WCHAR Query[] =
{'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
'`','C','o','m','p','o','n','e','n','t','`',' ',
'W','H','E','R','E',' ',
'`','C','o','m','p','o','n','e','n','t','`',' ',
'=','\'','%','s','\'',0};
component = MSI_RecordGetString(row,1);
/* check to see if the component is already loaded */
comp = get_loaded_component( ilfs->package, component );
if (comp)
if (!comp)
{
TRACE("Component %s already loaded\n", debugstr_w(component) );
add_feature_component( ilfs->feature, comp );
return ERROR_SUCCESS;
ERR("unknown component %s\n", debugstr_w(component));
return ERROR_FUNCTION_FAILED;
}
rc = MSI_OpenQuery(ilfs->package->db, &view, Query, component);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
rc = MSI_IterateRecords(view, NULL, iterate_component_check, ilfs);
msiobj_release( &view->hdr );
add_feature_component( ilfs->feature, comp );
comp->Enabled = TRUE;
return ERROR_SUCCESS;
}
@ -1306,6 +1257,38 @@ static UINT load_feature(MSIRECORD * row, LPVOID param)
return ERROR_SUCCESS;
}
static UINT load_all_features( MSIPACKAGE *package )
{
static const WCHAR query[] = {
'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
'`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
MSIQUERY *view;
UINT r;
if (!list_empty(&package->features))
return ERROR_SUCCESS;
r = MSI_DatabaseOpenViewW( package->db, query, &view );
if (r != ERROR_SUCCESS)
return r;
r = MSI_IterateRecords( view, NULL, load_feature, package );
msiobj_release( &view->hdr );
return r;
}
static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
{
if (!p)
return p;
p = strchrW(p, ch);
if (!p)
return p;
*p = 0;
return p+1;
}
static UINT load_file(MSIRECORD *row, LPVOID param)
{
MSIPACKAGE* package = (MSIPACKAGE*)param;
@ -1330,7 +1313,7 @@ static UINT load_file(MSIRECORD *row, LPVOID param)
reduce_to_longfilename( file->FileName );
file->ShortName = msi_dup_record_field( row, 3 );
reduce_to_shortfilename( file->ShortName );
file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
file->FileSize = MSI_RecordGetInteger( row, 4 );
file->Version = msi_dup_record_field( row, 5 );
@ -1356,8 +1339,8 @@ static UINT load_all_files(MSIPACKAGE *package)
'`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
'`','S','e','q','u','e','n','c','e','`', 0};
if (!package)
return ERROR_INVALID_HANDLE;
if (!list_empty(&package->files))
return ERROR_SUCCESS;
rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
if (rc != ERROR_SUCCESS)
@ -1371,43 +1354,33 @@ static UINT load_all_files(MSIPACKAGE *package)
/*
* I am not doing any of the costing functionality yet.
* I am not doing any of the costing functionality yet.
* Mostly looking at doing the Component and Feature loading
*
* The native MSI does A LOT of modification to tables here. Mostly adding
* a lot of temporary columns to the Feature and Component tables.
* a lot of temporary columns to the Feature and Component tables.
*
* note: Native msi also tracks the short filename. But I am only going to
* track the long ones. Also looking at this directory table
* it appears that the directory table does not get the parents
* resolved base on property only based on their entries in the
* resolved base on property only based on their entries in the
* directory table.
*/
static UINT ACTION_CostInitialize(MSIPACKAGE *package)
{
MSIQUERY * view;
UINT rc;
static const WCHAR Query_all[] =
{'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
'`','F','e','a','t','u','r','e','`',0};
static const WCHAR szCosting[] =
{'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
static const WCHAR szZero[] = { '0', 0 };
if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
return ERROR_SUCCESS;
MSI_SetPropertyW(package, szCosting, szZero);
MSI_SetPropertyW(package, cszRootDrive , c_colon);
MSI_SetPropertyW(package, cszRootDrive, c_colon);
rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
if (rc != ERROR_SUCCESS)
return rc;
rc = MSI_IterateRecords(view, NULL, load_feature, package);
msiobj_release(&view->hdr);
load_all_files(package);
load_all_components( package );
load_all_features( package );
load_all_files( package );
return ERROR_SUCCESS;
}
@ -1419,6 +1392,12 @@ static UINT execute_script(MSIPACKAGE *package, UINT script )
TRACE("Executing Script %i\n",script);
if (!package->script)
{
ERR("no script!\n");
return ERROR_FUNCTION_FAILED;
}
for (i = 0; i < package->script->ActionCount[script]; i++)
{
LPWSTR action;
@ -1442,7 +1421,6 @@ static UINT ACTION_FileCost(MSIPACKAGE *package)
return ERROR_SUCCESS;
}
static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
{
static const WCHAR Query[] =
@ -1451,10 +1429,11 @@ static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
' ','=',' ','\'','%','s','\'',
0};
LPWSTR ptargetdir, targetdir, srcdir;
static const WCHAR szDot[] = { '.',0 };
static WCHAR szEmpty[] = { 0 };
LPWSTR p, tgt_short, tgt_long, src_short, src_long;
LPCWSTR parent;
LPWSTR shortname = NULL;
MSIRECORD * row = 0;
MSIRECORD *row;
MSIFOLDER *folder;
TRACE("Looking for dir %s\n",debugstr_w(dir));
@ -1475,54 +1454,44 @@ static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
if (!row)
return NULL;
ptargetdir = targetdir = msi_dup_record_field(row,3);
p = msi_dup_record_field(row, 3);
/* split src and target dir */
if (strchrW(targetdir,':'))
{
srcdir=strchrW(targetdir,':');
*srcdir=0;
srcdir ++;
}
else
srcdir=NULL;
tgt_short = p;
src_short = folder_split_path( p, ':' );
/* for now only pick long filename versions */
if (strchrW(targetdir,'|'))
{
shortname = targetdir;
targetdir = strchrW(targetdir,'|');
*targetdir = 0;
targetdir ++;
}
/* for the sourcedir pick the short filename */
if (srcdir && strchrW(srcdir,'|'))
{
LPWSTR p = strchrW(srcdir,'|');
*p = 0;
}
/* split the long and short paths */
tgt_long = folder_split_path( tgt_short, '|' );
src_long = folder_split_path( src_short, '|' );
/* now check for root dirs */
if (targetdir[0] == '.' && targetdir[1] == 0)
targetdir = NULL;
if (targetdir)
{
TRACE(" TargetDefault = %s\n",debugstr_w(targetdir));
msi_free( folder->TargetDefault);
folder->TargetDefault = strdupW(targetdir);
/* check for no-op dirs */
if (!lstrcmpW(szDot, tgt_short))
tgt_short = szEmpty;
if (!lstrcmpW(szDot, src_short))
src_short = szEmpty;
if (!tgt_long)
tgt_long = tgt_short;
if (!src_short) {
src_short = tgt_short;
src_long = tgt_long;
}
if (!src_long)
src_long = src_short;
if (srcdir)
folder->SourceDefault = strdupW(srcdir);
else if (shortname)
folder->SourceDefault = strdupW(shortname);
else if (targetdir)
folder->SourceDefault = strdupW(targetdir);
msi_free(ptargetdir);
TRACE(" SourceDefault = %s\n", debugstr_w( folder->SourceDefault ));
/* FIXME: use the target short path too */
folder->TargetDefault = strdupW(tgt_long);
folder->SourceShortPath = strdupW(src_short);
folder->SourceLongPath = strdupW(src_long);
msi_free(p);
parent = MSI_RecordGetString(row,2);
TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
parent = MSI_RecordGetString(row, 2);
if (parent)
{
folder->Parent = load_folder( package, parent );
@ -1631,7 +1600,7 @@ static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
return TRUE;
}
static UINT SetFeatureStates(MSIPACKAGE *package)
UINT MSI_SetFeatureStates(MSIPACKAGE *package)
{
int install_level;
static const WCHAR szlevel[] =
@ -1919,7 +1888,7 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
version = msi_alloc(versize);
GetFileVersionInfoW(file->TargetPath, 0, versize, version);
VerQueryValueW(version, (LPWSTR)name, (LPVOID*)&lpVer, &sz);
VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
sprintfW(filever,name_fmt,
HIWORD(lpVer->dwFileVersionMS),
@ -1976,7 +1945,7 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
ACTION_UpdateInstallStates(package);
return SetFeatureStates(package);
return MSI_SetFeatureStates(package);
}
/* OK this value is "interpreted" and then formatted based on the
@ -2280,9 +2249,6 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
'`','R','e','g','i','s','t','r','y','`',0 };
if (!package)
return ERROR_INVALID_HANDLE;
rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
@ -2588,92 +2554,91 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
rc = MSIREG_OpenComponents(&hkey);
if (rc != ERROR_SUCCESS)
goto end;
return rc;
squash_guid(package->ProductCode,squished_pc);
ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
{
MSIRECORD * uirow;
ui_progress(package,2,0,0,0);
if (comp->ComponentId)
{
MSIRECORD * uirow;
if (!comp->ComponentId)
continue;
squash_guid(comp->ComponentId,squished_cc);
squash_guid(comp->ComponentId,squished_cc);
msi_free(comp->FullKeypath);
comp->FullKeypath = resolve_keypath( package, comp );
msi_free(comp->FullKeypath);
comp->FullKeypath = resolve_keypath( package, comp );
/* do the refcounting */
ACTION_RefCountComponent( package, comp );
/* do the refcounting */
ACTION_RefCountComponent( package, comp );
TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
debugstr_w(comp->Component),
debugstr_w(squished_cc),
debugstr_w(comp->FullKeypath),
debugstr_w(comp->FullKeypath),
comp->RefCount);
/*
* Write the keypath out if the component is to be registered
* and delete the key if the component is to be deregistered
*/
if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
/*
* Write the keypath out if the component is to be registered
* and delete the key if the component is to be deregistered
*/
if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
{
rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
if (rc != ERROR_SUCCESS)
continue;
if (!comp->FullKeypath)
continue;
msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
if (comp->Attributes & msidbComponentAttributesPermanent)
{
rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
if (rc != ERROR_SUCCESS)
continue;
static const WCHAR szPermKey[] =
{ '0','0','0','0','0','0','0','0','0','0','0','0',
'0','0','0','0','0','0','0','0','0','0','0','0',
'0','0','0','0','0','0','0','0',0 };
if (comp->FullKeypath)
{
msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
if (comp->Attributes & msidbComponentAttributesPermanent)
{
static const WCHAR szPermKey[] =
{ '0','0','0','0','0','0','0','0','0','0','0','0',
'0','0','0','0','0','0','0','0','0','0','0','0',
'0','0','0','0','0','0','0','0',0};
msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
}
RegCloseKey(hkey2);
/* UI stuff */
uirow = MSI_CreateRecord(3);
MSI_RecordSetStringW(uirow,1,package->ProductCode);
MSI_RecordSetStringW(uirow,2,comp->ComponentId);
MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
ui_actiondata(package,szProcessComponents,uirow);
msiobj_release( &uirow->hdr );
}
msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
}
else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
{
DWORD res;
rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
if (rc != ERROR_SUCCESS)
continue;
RegCloseKey(hkey2);
RegDeleteValueW(hkey2,squished_pc);
/* UI stuff */
uirow = MSI_CreateRecord(3);
MSI_RecordSetStringW(uirow,1,package->ProductCode);
MSI_RecordSetStringW(uirow,2,comp->ComponentId);
MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
ui_actiondata(package,szProcessComponents,uirow);
msiobj_release( &uirow->hdr );
}
else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
{
DWORD res;
/* if the key is empty delete it */
res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
RegCloseKey(hkey2);
if (res == ERROR_NO_MORE_ITEMS)
RegDeleteKeyW(hkey,squished_cc);
/* UI stuff */
uirow = MSI_CreateRecord(2);
MSI_RecordSetStringW(uirow,1,package->ProductCode);
MSI_RecordSetStringW(uirow,2,comp->ComponentId);
ui_actiondata(package,szProcessComponents,uirow);
msiobj_release( &uirow->hdr );
}
rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
if (rc != ERROR_SUCCESS)
continue;
RegDeleteValueW(hkey2,squished_pc);
/* if the key is empty delete it */
res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
RegCloseKey(hkey2);
if (res == ERROR_NO_MORE_ITEMS)
RegDeleteKeyW(hkey,squished_cc);
/* UI stuff */
uirow = MSI_CreateRecord(2);
MSI_RecordSetStringW(uirow,1,package->ProductCode);
MSI_RecordSetStringW(uirow,2,comp->ComponentId);
ui_actiondata(package,szProcessComponents,uirow);
msiobj_release( &uirow->hdr );
}
}
end:
RegCloseKey(hkey);
return rc;
}
@ -2704,7 +2669,7 @@ static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
sz = strlenW(tl_struct->source)+4;
sz *= sizeof(WCHAR);
if ((INT)lpszName == 1)
if ((INT_PTR)lpszName == 1)
tl_struct->path = strdupW(tl_struct->source);
else
{
@ -2845,14 +2810,12 @@ static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
{
MSIPACKAGE *package = (MSIPACKAGE*)param;
LPWSTR target_file, target_folder;
LPCWSTR buffer;
WCHAR filename[0x100];
DWORD sz;
LPWSTR target_file, target_folder, filename;
LPCWSTR buffer, extension;
MSICOMPONENT *comp;
static const WCHAR szlnk[]={'.','l','n','k',0};
IShellLinkW *sl;
IPersistFile *pf;
IShellLinkW *sl = NULL;
IPersistFile *pf = NULL;
HRESULT res;
buffer = MSI_RecordGetString(row,4);
@ -2876,17 +2839,17 @@ static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
&IID_IShellLinkW, (LPVOID *) &sl );
if (FAILED(res))
if (FAILED( res ))
{
ERR("Is IID_IShellLink\n");
return ERROR_SUCCESS;
ERR("CLSID_ShellLink not available\n");
goto err;
}
res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
if( FAILED( res ) )
if (FAILED( res ))
{
ERR("Is IID_IPersistFile\n");
return ERROR_SUCCESS;
ERR("QueryInterface(IID_IPersistFile) failed\n");
goto err;
}
buffer = MSI_RecordGetString(row,2);
@ -2895,13 +2858,19 @@ static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
/* may be needed because of a bug somehwere else */
create_full_pathW(target_folder);
sz = 0x100;
MSI_RecordGetStringW(row,3,filename,&sz);
filename = msi_dup_record_field( row, 3 );
reduce_to_longfilename(filename);
if (!strchrW(filename,'.') || strcmpiW(strchrW(filename,'.'),szlnk))
strcatW(filename,szlnk);
extension = strchrW(filename,'.');
if (!extension || strcmpiW(extension,szlnk))
{
int len = strlenW(filename);
filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
memcpy(filename + len, szlnk, sizeof(szlnk));
}
target_file = build_directory_name(2, target_folder, filename);
msi_free(target_folder);
msi_free(filename);
buffer = MSI_RecordGetString(row,5);
if (strchrW(buffer,'['))
@ -2966,8 +2935,11 @@ static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
msi_free(target_file);
IPersistFile_Release( pf );
IShellLinkW_Release( sl );
err:
if (pf)
IPersistFile_Release( pf );
if (sl)
IShellLinkW_Release( sl );
return ERROR_SUCCESS;
}
@ -3009,6 +2981,7 @@ static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
CHAR buffer[1024];
DWORD sz;
UINT rc;
MSIRECORD *uirow;
FileName = MSI_RecordGetString(row,1);
if (!FileName)
@ -3049,6 +3022,12 @@ static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
msi_free(FilePath);
CloseHandle(the_file);
uirow = MSI_CreateRecord(1);
MSI_RecordSetStringW(uirow,1,FileName);
ui_actiondata(package,szPublishProduct,uirow);
msiobj_release( &uirow->hdr );
return ERROR_SUCCESS;
}
@ -3118,7 +3097,7 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package)
buffer = msi_dup_property( package, szProductVersion );
if (buffer)
{
DWORD verdword = build_version_dword(buffer);
DWORD verdword = msi_version_str_to_dword(buffer);
msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
}
msi_free(buffer);
@ -3295,6 +3274,8 @@ static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
STARTUPINFOW si;
PROCESS_INFORMATION info;
BOOL brc;
MSIRECORD *uirow;
LPWSTR uipath, p;
memset(&si,0,sizeof(STARTUPINFOW));
@ -3322,6 +3303,20 @@ static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
msi_dialog_check_messages(info.hProcess);
msi_free(FullName);
/* the UI chunk */
uirow = MSI_CreateRecord( 2 );
uipath = strdupW( file->TargetPath );
p = strrchrW(uipath,'\\');
if (p)
p[1]=0;
MSI_RecordSetStringW( uirow, 1, &p[2] );
MSI_RecordSetStringW( uirow, 2, uipath);
ui_actiondata( package, szSelfRegModules, uirow);
msiobj_release( &uirow->hdr );
msi_free( uipath );
/* FIXME: call ui_progress? */
return ERROR_SUCCESS;
}
@ -3369,6 +3364,7 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
GUID clsid;
INT size;
BOOL absent = FALSE;
MSIRECORD *uirow;
if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
@ -3391,7 +3387,7 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
MSICOMPONENT* component = cl->component;
WCHAR buf[21];
memset(buf,0,sizeof(buf));
buf[0] = 0;
if (component->ComponentId)
{
TRACE("From %s\n",debugstr_w(component->ComponentId));
@ -3431,6 +3427,13 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
(LPBYTE)data,size);
msi_free(data);
}
/* the UI chunk */
uirow = MSI_CreateRecord( 1 );
MSI_RecordSetStringW( uirow, 1, feature->Feature );
ui_actiondata( package, szPublishFeatures, uirow);
msiobj_release( &uirow->hdr );
/* FIXME: call ui_progress? */
}
end:
@ -3594,7 +3597,7 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
buffer = msi_dup_property( package, szProductVersion );
if (buffer)
{
DWORD verdword = build_version_dword(buffer);
DWORD verdword = msi_version_str_to_dword(buffer);
msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
@ -3622,6 +3625,8 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
RegCloseKey(hkey);
/* FIXME: call ui_actiondata */
return ERROR_SUCCESS;
}
@ -3790,6 +3795,8 @@ end:
msi_free(productid);
RegCloseKey(hkey);
/* FIXME: call ui_actiondata */
return ERROR_SUCCESS;
}
@ -3911,8 +3918,7 @@ static LPWSTR load_ttfname_from(LPCWSTR filename)
ttRecord.uStringOffset +
ttNTHeader.uStorageOffset,
NULL, FILE_BEGIN);
buf = msi_alloc( ttRecord.uStringLength + 1 + strlen(tt) );
memset(buf, 0, ttRecord.uStringLength + 1 + strlen(tt));
buf = msi_alloc_zero( ttRecord.uStringLength + 1 + strlen(tt) );
ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
if (strlen(buf) > 0)
{
@ -3956,6 +3962,8 @@ static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
'F','o','n','t','s',0};
HKEY hkey1;
HKEY hkey2;
MSIRECORD *uirow;
LPWSTR uipath, p;
filename = MSI_RecordGetString( row, 1 );
file = get_loaded_file( package, filename );
@ -3989,6 +3997,19 @@ static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
msi_free(name);
RegCloseKey(hkey1);
RegCloseKey(hkey2);
/* the UI chunk */
uirow = MSI_CreateRecord( 1 );
uipath = strdupW( file->TargetPath );
p = strrchrW(uipath,'\\');
if (p) p++;
else p = uipath;
MSI_RecordSetStringW( uirow, 1, p );
ui_actiondata( package, szRegisterFonts, uirow);
msiobj_release( &uirow->hdr );
msi_free( uipath );
/* FIXME: call ui_progress? */
return ERROR_SUCCESS;
}
@ -4027,6 +4048,7 @@ static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
UINT rc = ERROR_SUCCESS;
MSICOMPONENT *comp;
DWORD sz = 0;
MSIRECORD *uirow;
component = MSI_RecordGetString(rec,3);
comp = get_loaded_component(package,component);
@ -4042,13 +4064,13 @@ static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
}
compgroupid = MSI_RecordGetString(rec,1);
qualifier = MSI_RecordGetString(rec,2);
rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
if (rc != ERROR_SUCCESS)
goto end;
text = MSI_RecordGetString(rec,4);
qualifier = MSI_RecordGetString(rec,2);
feature = MSI_RecordGetString(rec,5);
advertise = create_component_advertise_string(package, comp, feature);
@ -4061,8 +4083,7 @@ static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
sz+=3;
sz *= sizeof(WCHAR);
output = msi_alloc(sz);
memset(output,0,sz);
output = msi_alloc_zero(sz);
strcpyW(output,advertise);
msi_free(advertise);
@ -4074,7 +4095,15 @@ static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
end:
RegCloseKey(hkey);
msi_free(output);
/* the UI chunk */
uirow = MSI_CreateRecord( 2 );
MSI_RecordSetStringW( uirow, 1, compgroupid );
MSI_RecordSetStringW( uirow, 2, qualifier);
ui_actiondata( package, szPublishComponents, uirow);
msiobj_release( &uirow->hdr );
/* FIXME: call ui_progress? */
return rc;
}
@ -4249,6 +4278,18 @@ static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
}
static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
{
static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
}
static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
{
static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
}
static struct _actions StandardActions[] = {
{ szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
{ szAppSearch, ACTION_AppSearch },
@ -4279,7 +4320,6 @@ static struct _actions StandardActions[] = {
{ szMoveFiles, ACTION_MoveFiles },
{ szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
{ szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
{ szISInitAllUsers, NULL },
{ szInstallODBC, NULL},
{ szInstallServices, ACTION_InstallServices },
{ szPatchFiles, ACTION_PatchFiles },
@ -4288,7 +4328,7 @@ static struct _actions StandardActions[] = {
{ szPublishFeatures, ACTION_PublishFeatures },
{ szPublishProduct, ACTION_PublishProduct },
{ szRegisterClassInfo, ACTION_RegisterClassInfo },
{ szRegisterComPlus, NULL},
{ szRegisterComPlus, ACTION_RegisterComPlus},
{ szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
{ szRegisterFonts, ACTION_RegisterFonts },
{ szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
@ -4316,7 +4356,7 @@ static struct _actions StandardActions[] = {
{ szUnpublishComponents, NULL},
{ szUnpublishFeatures, NULL},
{ szUnregisterClassInfo, NULL},
{ szUnregisterComPlus, NULL},
{ szUnregisterComPlus, ACTION_UnregisterComPlus},
{ szUnregisterExtensionInfo, NULL},
{ szUnregisterFonts, ACTION_UnregisterFonts },
{ szUnregisterMIMEInfo, NULL},

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef __MSI_ACTION_H__
@ -78,7 +78,8 @@ typedef struct tagMSIFOLDER
struct list entry;
LPWSTR Directory;
LPWSTR TargetDefault;
LPWSTR SourceDefault;
LPWSTR SourceLongPath;
LPWSTR SourceShortPath;
LPWSTR ResolvedTarget;
LPWSTR ResolvedSource;
@ -109,6 +110,7 @@ typedef struct tagMSIFILE
MSICOMPONENT *Component;
LPWSTR FileName;
LPWSTR ShortName;
LPWSTR LongName;
INT FileSize;
LPWSTR Version;
LPWSTR Language;
@ -255,6 +257,7 @@ extern UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package);
extern DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data );
extern LPWSTR msi_dup_record_field(MSIRECORD *row, INT index);
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, MSIFOLDER **folder);
extern MSICOMPONENT *get_loaded_component( MSIPACKAGE* package, LPCWSTR Component );
@ -264,7 +267,6 @@ extern MSIFOLDER *get_loaded_folder( MSIPACKAGE *package, LPCWSTR dir );
extern int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path);
extern UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action);
extern LPWSTR build_icon_path(MSIPACKAGE *, LPCWSTR);
extern DWORD build_version_dword(LPCWSTR);
extern LPWSTR build_directory_name(DWORD , ...);
extern BOOL create_full_pathW(const WCHAR *path);
extern BOOL ACTION_VerifyComponentForAction(MSICOMPONENT*, INSTALLSTATE);

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
@ -37,8 +37,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi);
typedef struct tagMSISIGNATURE
{
LPWSTR Name; /* NOT owned by this structure */
LPWSTR Property; /* NOT owned by this structure */
LPCWSTR Name; /* NOT owned by this structure */
LPWSTR File;
DWORD MinVersionMS;
DWORD MinVersionLS;
@ -96,6 +95,7 @@ static UINT ACTION_AppSearchGetSignature(MSIPACKAGE *package, MSISIGNATURE *sig,
TRACE("(package %p, sig %p)\n", package, sig);
memset(sig, 0, sizeof(*sig));
sig->Name = name;
rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, name);
if (rc == ERROR_SUCCESS)
{
@ -158,7 +158,8 @@ static UINT ACTION_AppSearchGetSignature(MSIPACKAGE *package, MSISIGNATURE *sig,
TRACE("Languages is %s\n", debugstr_w(sig->Languages));
end:
msiobj_release(&row->hdr);
if (row)
msiobj_release(&row->hdr);
MSI_ViewClose(view);
msiobj_release(&view->hdr);
}
@ -172,7 +173,14 @@ end:
return rc;
}
static UINT ACTION_AppSearchComponents(MSIPACKAGE *package, BOOL *appFound,
/* Frees any memory allocated in sig */
static void ACTION_FreeSignature(MSISIGNATURE *sig)
{
msi_free(sig->File);
msi_free(sig->Languages);
}
static UINT ACTION_AppSearchComponents(MSIPACKAGE *package, LPWSTR *appValue,
MSISIGNATURE *sig)
{
MSIQUERY *view;
@ -184,8 +192,8 @@ static UINT ACTION_AppSearchComponents(MSIPACKAGE *package, BOOL *appFound,
'w','h','e','r','e',' ','S','i','g','n','a','t','u','r','e','_',' ','=',' ',
'\'','%','s','\'',0};
TRACE("(package %p, appFound %p, sig %p)\n", package, appFound, sig);
*appFound = FALSE;
TRACE("(package %p, appValue %p, sig %p)\n", package, appValue, sig);
*appValue = NULL;
rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, sig->Name);
if (rc == ERROR_SUCCESS)
{
@ -220,7 +228,8 @@ static UINT ACTION_AppSearchComponents(MSIPACKAGE *package, BOOL *appFound,
debugstr_w(guid));
end:
msiobj_release(&row->hdr);
if (row)
msiobj_release(&row->hdr);
MSI_ViewClose(view);
msiobj_release(&view->hdr);
}
@ -234,7 +243,58 @@ end:
return rc;
}
static UINT ACTION_AppSearchReg(MSIPACKAGE *package, BOOL *appFound,
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' };
DWORD i;
switch (regType)
{
case REG_SZ:
if (*(LPWSTR)value == '#')
{
/* escape leading pound with another */
*appValue = msi_alloc(sz + sizeof(WCHAR));
(*appValue)[0] = '#';
strcpyW(*appValue + 1, (LPCWSTR)value);
}
else
{
*appValue = msi_alloc(sz);
strcpyW(*appValue, (LPCWSTR)value);
}
break;
case REG_DWORD:
/* 7 chars for digits, 1 for NULL, 1 for #, and 1 for sign
* char if needed
*/
*appValue = msi_alloc(10 * sizeof(WCHAR));
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);
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]);
break;
default:
WARN("unimplemented for values of type %ld\n", regType);
*appValue = NULL;
}
}
static UINT ACTION_SearchDirectory(MSIPACKAGE *package, MSISIGNATURE *sig,
LPCWSTR path, int depth, LPWSTR *appValue);
static UINT ACTION_AppSearchReg(MSIPACKAGE *package, LPWSTR *appValue,
MSISIGNATURE *sig)
{
MSIQUERY *view;
@ -245,20 +305,17 @@ static UINT ACTION_AppSearchReg(MSIPACKAGE *package, BOOL *appFound,
'R','e','g','L','o','c','a','t','o','r',' ',
'w','h','e','r','e',' ','S','i','g','n','a','t','u','r','e','_',' ','=',' ',
'\'','%','s','\'',0};
static const WCHAR dwordFmt[] = { '#','%','d','\0' };
static const WCHAR expandSzFmt[] = { '#','%','%','%','s','\0' };
static const WCHAR binFmt[] = { '#','x','%','x','\0' };
TRACE("(package %p, appFound %p, sig %p)\n", package, appFound, sig);
*appFound = FALSE;
TRACE("(package %p, appValue %p, sig %p)\n", package, appValue, sig);
*appValue = NULL;
rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, sig->Name);
if (rc == ERROR_SUCCESS)
{
MSIRECORD *row = 0;
LPWSTR keyPath = NULL, valueName = NULL, propertyValue = NULL;
LPWSTR keyPath = NULL, valueName = NULL;
int root, type;
HKEY rootKey, key = NULL;
DWORD sz = 0, regType, i;
DWORD sz = 0, regType;
LPBYTE value = NULL;
rc = MSI_ViewExecute(view, 0);
@ -282,13 +339,6 @@ static UINT ACTION_AppSearchReg(MSIPACKAGE *package, BOOL *appFound,
/* FIXME: valueName probably does too */
type = MSI_RecordGetInteger(row,5);
if ((type & 0x0f) != msidbLocatorTypeRawValue)
{
FIXME("AppSearch unimplemented for type %d (key path %s, value %s)\n",
type, debugstr_w(keyPath), debugstr_w(valueName));
goto end;
}
switch (root)
{
case msidbRegistryRootClassesRoot:
@ -308,10 +358,10 @@ static UINT ACTION_AppSearchReg(MSIPACKAGE *package, BOOL *appFound,
goto end;
}
rc = RegCreateKeyW(rootKey, keyPath, &key);
rc = RegOpenKeyW(rootKey, keyPath, &key);
if (rc)
{
TRACE("RegCreateKeyW returned %d\n", rc);
TRACE("RegOpenKeyW returned %d\n", rc);
rc = ERROR_SUCCESS;
goto end;
}
@ -340,60 +390,29 @@ static UINT ACTION_AppSearchReg(MSIPACKAGE *package, BOOL *appFound,
rc = ERROR_SUCCESS;
goto end;
}
switch (regType)
switch (type & 0x0f)
{
case REG_SZ:
if (*(LPWSTR)value == '#')
{
/* escape leading pound with another */
propertyValue = msi_alloc( sz + sizeof(WCHAR));
propertyValue[0] = '#';
strcpyW(propertyValue + 1, (LPWSTR)value);
}
else
{
propertyValue = msi_alloc( sz);
strcpyW(propertyValue, (LPWSTR)value);
}
break;
case REG_DWORD:
/* 7 chars for digits, 1 for NULL, 1 for #, and 1 for sign
* char if needed
*/
propertyValue = msi_alloc( 10 * sizeof(WCHAR));
sprintfW(propertyValue, dwordFmt, *(DWORD *)value);
break;
case REG_EXPAND_SZ:
/* space for extra #% characters in front */
propertyValue = msi_alloc( sz + 2 * sizeof(WCHAR));
sprintfW(propertyValue, expandSzFmt, (LPWSTR)value);
break;
case REG_BINARY:
/* 3 == length of "#x<nibble>" */
propertyValue = msi_alloc( (sz * 3 + 1) * sizeof(WCHAR));
for (i = 0; i < sz; i++)
sprintfW(propertyValue + i * 3, binFmt, value[i]);
break;
default:
WARN("unimplemented for values of type %ld\n", regType);
goto end;
case msidbLocatorTypeDirectory:
rc = ACTION_SearchDirectory(package, sig, (LPCWSTR)value, 0,
appValue);
break;
case msidbLocatorTypeRawValue:
ACTION_ConvertRegValue(regType, value, sz, appValue);
break;
default:
FIXME("AppSearch unimplemented for type %d (key path %s, value %s)\n",
type, debugstr_w(keyPath), debugstr_w(valueName));
}
TRACE("found registry value, setting %s to %s\n",
debugstr_w(sig->Property), debugstr_w(propertyValue));
rc = MSI_SetPropertyW(package, sig->Property, propertyValue);
*appFound = TRUE;
end:
msi_free( propertyValue);
msi_free( value);
RegCloseKey(key);
msi_free( keyPath);
msi_free( valueName);
msiobj_release(&row->hdr);
if (row)
msiobj_release(&row->hdr);
MSI_ViewClose(view);
msiobj_release(&view->hdr);
}
@ -407,7 +426,7 @@ end:
return rc;
}
static UINT ACTION_AppSearchIni(MSIPACKAGE *package, BOOL *appFound,
static UINT ACTION_AppSearchIni(MSIPACKAGE *package, LPWSTR *appValue,
MSISIGNATURE *sig)
{
MSIQUERY *view;
@ -419,13 +438,15 @@ static UINT ACTION_AppSearchIni(MSIPACKAGE *package, BOOL *appFound,
'w','h','e','r','e',' ','S','i','g','n','a','t','u','r','e','_',' ','=',' ',
'\'','%','s','\'',0};
TRACE("(package %p, appFound %p, sig %p)\n", package, appFound, sig);
*appFound = FALSE;
TRACE("(package %p, appValue %p, sig %p)\n", package, appValue, sig);
*appValue = NULL;
rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, sig->Name);
if (rc == ERROR_SUCCESS)
{
MSIRECORD *row = 0;
LPWSTR fileName;
LPWSTR fileName, section, key;
int field, type;
WCHAR buf[MAX_PATH];
rc = MSI_ViewExecute(view, 0);
if (rc != ERROR_SUCCESS)
@ -441,14 +462,41 @@ static UINT ACTION_AppSearchIni(MSIPACKAGE *package, BOOL *appFound,
goto end;
}
/* get file name */
fileName = msi_dup_record_field(row,2);
FIXME("AppSearch unimplemented for IniLocator (ini file name %s)\n",
debugstr_w(fileName));
msi_free( fileName);
fileName = msi_dup_record_field(row, 2);
section = msi_dup_record_field(row, 3);
key = msi_dup_record_field(row, 4);
if ((field = MSI_RecordGetInteger(row, 5)) == MSI_NULL_INTEGER)
field = 0;
if ((type = MSI_RecordGetInteger(row, 6)) == MSI_NULL_INTEGER)
type = 0;
GetPrivateProfileStringW(section, key, NULL, buf,
sizeof(buf) / sizeof(WCHAR), fileName);
if (buf[0])
{
switch (type & 0x0f)
{
case msidbLocatorTypeDirectory:
FIXME("unimplemented for type Directory (dir: %s)\n",
debugstr_w(buf));
break;
case msidbLocatorTypeFileName:
FIXME("unimplemented for type File (file: %s)\n",
debugstr_w(buf));
break;
case msidbLocatorTypeRawValue:
*appValue = strdupW(buf);
break;
}
}
msi_free(fileName);
msi_free(section);
msi_free(key);
end:
msiobj_release(&row->hdr);
if (row)
msiobj_release(&row->hdr);
MSI_ViewClose(view);
msiobj_release(&view->hdr);
}
@ -541,7 +589,7 @@ static UINT ACTION_FileVersionMatches(MSISIGNATURE *sig, LPCWSTR filePath,
}
else
{
DWORD zero, size = GetFileVersionInfoSizeW((LPWSTR)filePath, &zero);
DWORD zero, size = GetFileVersionInfoSizeW(filePath, &zero);
if (size)
{
@ -553,8 +601,8 @@ static UINT ACTION_FileVersionMatches(MSISIGNATURE *sig, LPCWSTR filePath,
UINT versionLen;
LPVOID subBlock = NULL;
if (GetFileVersionInfoW((LPWSTR)filePath, 0, size, buf))
VerQueryValueW(buf, (LPWSTR)rootW, &subBlock, &versionLen);
if (GetFileVersionInfoW(filePath, 0, size, buf))
VerQueryValueW(buf, rootW, &subBlock, &versionLen);
if (subBlock)
{
VS_FIXEDFILEINFO *info =
@ -648,7 +696,7 @@ static UINT ACTION_FileMatchesSig(MSISIGNATURE *sig,
* Returns ERROR_SUCCESS on success (which may include non-critical errors),
* something else on failures which should halt the install.
*/
static UINT ACTION_RecurseSearchDirectory(MSIPACKAGE *package, BOOL *appFound,
static UINT ACTION_RecurseSearchDirectory(MSIPACKAGE *package, LPWSTR *appValue,
MSISIGNATURE *sig, LPCWSTR dir, int depth)
{
static const WCHAR starDotStarW[] = { '*','.','*',0 };
@ -662,7 +710,7 @@ static UINT ACTION_RecurseSearchDirectory(MSIPACKAGE *package, BOOL *appFound,
if (depth < 0)
return ERROR_INVALID_PARAMETER;
*appFound = FALSE;
*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.
@ -689,14 +737,12 @@ static UINT ACTION_RecurseSearchDirectory(MSIPACKAGE *package, BOOL *appFound,
if (!(rc = ACTION_FileMatchesSig(sig, &findData, buf, &matches))
&& matches)
{
TRACE("found file, setting %s to %s\n",
debugstr_w(sig->Property), debugstr_w(buf));
rc = MSI_SetPropertyW(package, sig->Property, buf);
*appFound = TRUE;
TRACE("found file, returning %s\n", debugstr_w(buf));
*appValue = buf;
}
FindClose(hFind);
}
if (rc == ERROR_SUCCESS && !*appFound && depth > 0)
if (rc == ERROR_SUCCESS && !*appValue && depth > 0)
{
HANDLE hFind;
WIN32_FIND_DATAW findData;
@ -709,19 +755,20 @@ static UINT ACTION_RecurseSearchDirectory(MSIPACKAGE *package, BOOL *appFound,
if (hFind != INVALID_HANDLE_VALUE)
{
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
rc = ACTION_RecurseSearchDirectory(package, appFound,
sig, findData.cFileName, depth - 1);
while (rc == ERROR_SUCCESS && !*appFound &&
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, appFound,
rc = ACTION_RecurseSearchDirectory(package, appValue,
sig, findData.cFileName, depth - 1);
}
FindClose(hFind);
}
}
msi_free(buf);
if (!*appValue)
msi_free(buf);
}
else
rc = ERROR_OUTOFMEMORY;
@ -729,16 +776,15 @@ static UINT ACTION_RecurseSearchDirectory(MSIPACKAGE *package, BOOL *appFound,
return rc;
}
static UINT ACTION_CheckDirectory(MSIPACKAGE *package, MSISIGNATURE *sig,
LPCWSTR dir)
static UINT ACTION_CheckDirectory(MSIPACKAGE *package, LPCWSTR dir,
LPWSTR *appValue)
{
UINT rc = ERROR_SUCCESS;
if (GetFileAttributesW(dir) & FILE_ATTRIBUTE_DIRECTORY)
{
TRACE("directory exists, setting %s to %s\n",
debugstr_w(sig->Property), debugstr_w(dir));
rc = MSI_SetPropertyW(package, sig->Property, dir);
TRACE("directory exists, returning %s\n", debugstr_w(dir));
*appValue = strdupW(dir);
}
return rc;
}
@ -758,23 +804,23 @@ static BOOL ACTION_IsFullPath(LPCWSTR path)
}
static UINT ACTION_SearchDirectory(MSIPACKAGE *package, MSISIGNATURE *sig,
LPCWSTR expanded, int depth)
LPCWSTR path, int depth, LPWSTR *appValue)
{
UINT rc;
BOOL found;
TRACE("%p, %p, %s, %d\n", package, sig, debugstr_w(expanded), depth);
if (ACTION_IsFullPath(expanded))
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, &found, sig,
expanded, depth);
rc = ACTION_RecurseSearchDirectory(package, appValue, 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, sig, expanded);
rc = ACTION_CheckDirectory(package, path, appValue);
}
}
else
@ -784,20 +830,21 @@ static UINT ACTION_SearchDirectory(MSIPACKAGE *package, MSISIGNATURE *sig,
int i;
rc = ERROR_SUCCESS;
found = FALSE;
for (i = 0; rc == ERROR_SUCCESS && !found && i < 26; i++)
*appValue = NULL;
for (i = 0; rc == ERROR_SUCCESS && !*appValue && i < 26; i++)
if (drives & (1 << drives))
{
pathWithDrive[0] = 'A' + i;
if (GetDriveTypeW(pathWithDrive) == DRIVE_FIXED)
{
lstrcpynW(pathWithDrive + 3, expanded,
lstrcpynW(pathWithDrive + 3, path,
sizeof(pathWithDrive) / sizeof(pathWithDrive[0]) - 3);
if (sig->File)
rc = ACTION_RecurseSearchDirectory(package, &found, sig,
pathWithDrive, depth);
rc = ACTION_RecurseSearchDirectory(package, appValue,
sig, pathWithDrive, depth);
else
rc = ACTION_CheckDirectory(package, sig, pathWithDrive);
rc = ACTION_CheckDirectory(package, pathWithDrive,
appValue);
}
}
}
@ -805,7 +852,11 @@ static UINT ACTION_SearchDirectory(MSIPACKAGE *package, MSISIGNATURE *sig,
return rc;
}
static UINT ACTION_AppSearchDr(MSIPACKAGE *package, MSISIGNATURE *sig)
static UINT ACTION_AppSearchSigName(MSIPACKAGE *package, LPCWSTR sigName,
MSISIGNATURE *sig, LPWSTR *appValue);
static UINT ACTION_AppSearchDr(MSIPACKAGE *package, LPWSTR *appValue,
MSISIGNATURE *sig)
{
MSIQUERY *view;
UINT rc;
@ -821,8 +872,8 @@ static UINT ACTION_AppSearchDr(MSIPACKAGE *package, MSISIGNATURE *sig)
if (rc == ERROR_SUCCESS)
{
MSIRECORD *row = 0;
WCHAR buffer[MAX_PATH], expanded[MAX_PATH];
DWORD sz;
WCHAR expanded[MAX_PATH];
LPWSTR parentName = NULL, path = NULL, parent = NULL;
int depth;
rc = MSI_ViewExecute(view, 0);
@ -840,39 +891,43 @@ static UINT ACTION_AppSearchDr(MSIPACKAGE *package, MSISIGNATURE *sig)
}
/* check whether parent is set */
buffer[0] = 0;
sz=sizeof(buffer)/sizeof(buffer[0]);
rc = MSI_RecordGetStringW(row,2,buffer,&sz);
if (rc != ERROR_SUCCESS)
parentName = msi_dup_record_field(row,2);
if (parentName)
{
ERR("Error is %x\n",rc);
goto end;
}
else if (buffer[0])
{
FIXME(": searching parent (%s) unimplemented\n",
debugstr_w(buffer));
goto end;
}
/* no parent, now look for path */
buffer[0] = 0;
sz=sizeof(buffer)/sizeof(buffer[0]);
rc = MSI_RecordGetStringW(row,3,buffer,&sz);
if (rc != ERROR_SUCCESS)
{
ERR("Error is %x\n",rc);
goto end;
MSISIGNATURE parentSig;
rc = ACTION_AppSearchSigName(package, parentName, &parentSig,
&parent);
ACTION_FreeSignature(&parentSig);
msi_free(parentName);
}
/* now look for path */
path = msi_dup_record_field(row,3);
if (MSI_RecordIsNull(row,4))
depth = 0;
else
depth = MSI_RecordGetInteger(row,4);
ACTION_ExpandAnyPath(package, buffer, expanded,
ACTION_ExpandAnyPath(package, path, expanded,
sizeof(expanded) / sizeof(expanded[0]));
rc = ACTION_SearchDirectory(package, sig, expanded, depth);
msi_free(path);
if (parent)
{
path = msi_alloc(strlenW(parent) + strlenW(expanded) + 1);
if (!path)
goto end;
strcpyW(path, parent);
strcatW(path, expanded);
}
else
path = expanded;
rc = ACTION_SearchDirectory(package, sig, path, depth, appValue);
end:
msiobj_release(&row->hdr);
if (path != expanded)
msi_free(path);
msi_free(parent);
if (row)
msiobj_release(&row->hdr);
MSI_ViewClose(view);
msiobj_release(&view->hdr);
}
@ -882,11 +937,34 @@ end:
rc = ERROR_SUCCESS;
}
TRACE("returning %d\n", rc);
return rc;
}
static UINT ACTION_AppSearchSigName(MSIPACKAGE *package, LPCWSTR sigName,
MSISIGNATURE *sig, LPWSTR *appValue)
{
UINT rc;
*appValue = NULL;
rc = ACTION_AppSearchGetSignature(package, sig, sigName);
if (rc == ERROR_SUCCESS)
{
rc = ACTION_AppSearchComponents(package, appValue, sig);
if (rc == ERROR_SUCCESS && !*appValue)
{
rc = ACTION_AppSearchReg(package, appValue, sig);
if (rc == ERROR_SUCCESS && !*appValue)
{
rc = ACTION_AppSearchIni(package, appValue, sig);
if (rc == ERROR_SUCCESS && !*appValue)
rc = ACTION_AppSearchDr(package, appValue, sig);
}
}
}
return rc;
}
/* 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.
*/
@ -903,10 +981,7 @@ UINT ACTION_AppSearch(MSIPACKAGE *package)
if (rc == ERROR_SUCCESS)
{
MSIRECORD *row = 0;
WCHAR propBuf[0x100], sigBuf[0x100];
DWORD sz;
MSISIGNATURE sig;
BOOL appFound = FALSE;
LPWSTR propName, sigName;
rc = MSI_ViewExecute(view, 0);
if (rc != ERROR_SUCCESS)
@ -914,6 +989,9 @@ UINT ACTION_AppSearch(MSIPACKAGE *package)
while (!rc)
{
MSISIGNATURE sig;
LPWSTR value;
rc = MSI_ViewFetch(view,&row);
if (rc != ERROR_SUCCESS)
{
@ -922,46 +1000,21 @@ UINT ACTION_AppSearch(MSIPACKAGE *package)
}
/* get property and signature */
propBuf[0] = 0;
sz=sizeof(propBuf)/sizeof(propBuf[0]);
rc = MSI_RecordGetStringW(row,1,propBuf,&sz);
if (rc != ERROR_SUCCESS)
{
ERR("Error is %x\n",rc);
msiobj_release(&row->hdr);
break;
}
sigBuf[0] = 0;
sz=sizeof(sigBuf)/sizeof(sigBuf[0]);
rc = MSI_RecordGetStringW(row,2,sigBuf,&sz);
if (rc != ERROR_SUCCESS)
{
ERR("Error is %x\n",rc);
msiobj_release(&row->hdr);
break;
}
propName = msi_dup_record_field(row,1);
sigName = msi_dup_record_field(row,2);
TRACE("Searching for Property %s, Signature_ %s\n",
debugstr_w(propBuf), debugstr_w(sigBuf));
/* This clears all the fields, so set Name and Property afterward */
rc = ACTION_AppSearchGetSignature(package, &sig, sigBuf);
sig.Name = sigBuf;
sig.Property = propBuf;
if (rc == ERROR_SUCCESS)
debugstr_w(propName), debugstr_w(sigName));
rc = ACTION_AppSearchSigName(package, sigName, &sig, &value);
if (value)
{
rc = ACTION_AppSearchComponents(package, &appFound, &sig);
if (rc == ERROR_SUCCESS && !appFound)
{
rc = ACTION_AppSearchReg(package, &appFound, &sig);
if (rc == ERROR_SUCCESS && !appFound)
{
rc = ACTION_AppSearchIni(package, &appFound, &sig);
if (rc == ERROR_SUCCESS && !appFound)
rc = ACTION_AppSearchDr(package, &sig);
}
}
MSI_SetPropertyW(package, propName, value);
msi_free(value);
}
msi_free( sig.File);
msi_free( sig.Languages);
ACTION_FreeSignature(&sig);
msi_free(propName);
msi_free(sigName);
msiobj_release(&row->hdr);
}

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
/* actions handled in this module
@ -716,7 +716,7 @@ static void mark_progid_for_install( MSIPACKAGE* package, MSIPROGID *progid )
if (!progid)
return;
if (progid->InstallMe == TRUE)
if (progid->InstallMe)
return;
progid->InstallMe = TRUE;
@ -736,38 +736,6 @@ static void mark_mime_for_install( MSIMIME *mime )
mime->InstallMe = TRUE;
}
LONG msi_reg_set_val_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
{
DWORD len = value ? (lstrlenW(value) + 1) * sizeof (WCHAR) : 0;
return RegSetValueExW( hkey, name, 0, REG_SZ, (LPBYTE)value, len );
}
LONG msi_reg_set_val_multi_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
{
LPCWSTR p = value;
while (*p) p += lstrlenW(p) + 1;
return RegSetValueExW( hkey, name, 0, REG_MULTI_SZ,
(LPBYTE)value, (p + 1 - value) * sizeof(WCHAR) );
}
LONG msi_reg_set_val_dword( HKEY hkey, LPCWSTR name, DWORD val )
{
return RegSetValueExW( hkey, name, 0, REG_DWORD, (LPBYTE)&val, sizeof (DWORD) );
}
LONG msi_reg_set_subkey_val( HKEY hkey, LPCWSTR path, LPCWSTR name, LPCWSTR val )
{
HKEY hsubkey = 0;
LONG r;
r = RegCreateKeyW( hkey, path, &hsubkey );
if (r != ERROR_SUCCESS)
return r;
r = msi_reg_set_val_str( hsubkey, name, val );
RegCloseKey( hsubkey );
return r;
}
static UINT register_appid(MSIAPPID *appid, LPCWSTR app )
{
static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
@ -832,7 +800,6 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
static const WCHAR szInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
static const WCHAR szFileType_fmt[] = {'F','i','l','e','T','y','p','e','\\','%','s','\\','%','i',0};
HKEY hkey,hkey2,hkey3;
BOOL install_on_demand = FALSE;
MSICLASS *cls;
load_classes_and_such(package);
@ -863,9 +830,9 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
* yes. MSDN says that these are based on _Feature_ not on
* Component. So verify the feature is to be installed
*/
if ((!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL )) &&
!(install_on_demand &&
ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED )))
if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
/* && !(install_on_demand &&
ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))) */
{
TRACE("Skipping class %s reg due to disabled feature %s\n",
debugstr_w(cls->clsid),
@ -1161,8 +1128,7 @@ static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid,
size += strlenW(verb->Argument);
size += 4;
command = msi_alloc(size * sizeof (WCHAR));
memset(command,0,size*sizeof(WCHAR));
command = msi_alloc_zero(size * sizeof (WCHAR));
strcpyW(command,advertise);
if (verb->Argument)

View file

@ -17,7 +17,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
@ -110,7 +110,7 @@ static BOOL num_from_prop( LPCWSTR p, INT *val )
INT value;
}
%token COND_SPACE COND_EOF COND_SPACE
%token COND_SPACE COND_EOF
%token COND_OR COND_AND COND_NOT COND_XOR COND_IMP COND_EQV
%token COND_LT COND_GT COND_EQ COND_NE COND_GE COND_LE
%token COND_ILT COND_IGT COND_IEQ COND_INE COND_IGE COND_ILE
@ -186,6 +186,7 @@ boolean_factor:
| value_s
{
$$ = ($1 && $1[0]) ? 1 : 0;
msi_free($1);
}
| value_i operator value_i
{
@ -198,6 +199,7 @@ boolean_factor:
$$ = compare_int( num, $2, $3 );
else
$$ = ($2 == COND_NE || $2 == COND_INE );
msi_free($1);
}
| value_i operator symbol_s
{
@ -206,6 +208,7 @@ boolean_factor:
$$ = compare_int( $1, $2, num );
else
$$ = ($2 == COND_NE || $2 == COND_INE );
msi_free($3);
}
| symbol_s operator symbol_s
{
@ -226,10 +229,12 @@ boolean_factor:
| literal operator value_i
{
$$ = 0;
msi_free($1);
}
| value_i operator literal
{
$$ = 0;
msi_free($3);
}
| COND_LPAR expression COND_RPAR
{
@ -463,7 +468,7 @@ static INT compare_int( INT a, INT operator, INT b )
return a >= b;
case COND_LE:
case COND_ILE:
return a >= b;
return a <= b;
case COND_SS:
case COND_ISS:
return ( a & b ) ? 1 : 0;
@ -492,21 +497,21 @@ static int COND_GetOperator( COND_input *cond )
int id;
} table[] = {
{ {'~','=',0}, COND_IEQ },
{ {'~','>','=',0}, COND_ILE },
{ {'~','<','=',0}, COND_ILE },
{ {'~','>','<',0}, COND_ISS },
{ {'~','>','>',0}, COND_IRHS },
{ {'~','>',0}, COND_ILT },
{ {'~','<','>',0}, COND_INE },
{ {'~','<','=',0}, COND_IGE },
{ {'~','<',0}, COND_ILT },
{ {'~','>','=',0}, COND_IGE },
{ {'~','<','<',0}, COND_ILHS },
{ {'~','<',0}, COND_IGT },
{ {'~','>',0}, COND_IGT },
{ {'>','=',0}, COND_GE },
{ {'>','<',0}, COND_SS },
{ {'>','>',0}, COND_LHS },
{ {'<','<',0}, COND_LHS },
{ {'>',0}, COND_GT },
{ {'<','>',0}, COND_NE },
{ {'<','=',0}, COND_LE },
{ {'<','<',0}, COND_RHS },
{ {'>','>',0}, COND_RHS },
{ {'<',0}, COND_LT },
{ {0}, 0 }
};

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
@ -207,7 +207,7 @@ static UINT CREATE_delete( struct tagMSIVIEW *view )
}
MSIVIEWOPS create_ops =
static const MSIVIEWOPS create_ops =
{
CREATE_fetch_int,
NULL,

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
/*
@ -38,7 +38,7 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/summa
#include "msi.h"
#include "msidefs.h"
#include "msiquery.h"
#include "fcntl.h"
#include "msvcrt/fcntl.h"
#include "objbase.h"
#include "objidl.h"
#include "msipriv.h"
@ -67,6 +67,8 @@ static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source,
LPCWSTR target, const INT type, LPCWSTR action);
static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source,
LPCWSTR target, const INT type, LPCWSTR action);
static UINT HANDLE_CustomType17(MSIPACKAGE *package, LPCWSTR source,
LPCWSTR target, const INT type, LPCWSTR action);
static UINT HANDLE_CustomType18(MSIPACKAGE *package, LPCWSTR source,
LPCWSTR target, const INT type, LPCWSTR action);
static UINT HANDLE_CustomType19(MSIPACKAGE *package, LPCWSTR source,
@ -207,6 +209,9 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute)
case 19: /* Error that halts install */
rc = HANDLE_CustomType19(package,source,target,type,action);
break;
case 17:
rc = HANDLE_CustomType17(package,source,target,type,action);
break;
case 50: /*EXE file specified by a property value */
rc = HANDLE_CustomType50(package,source,target,type,action);
break;
@ -437,13 +442,13 @@ static DWORD WINAPI ACTION_CallDllFunction(thread_struct *stuff)
ERR("Handle for object %p not found\n", package );
}
else
ERR("Cannot load functon\n");
ERR("failed to resolve functon %s\n", debugstr_a(proc));
msi_free(proc);
FreeLibrary(hModule);
}
else
ERR("Unable to load library\n");
ERR("failed to load dll %s\n", debugstr_w(stuff->source));
msiobj_release( &stuff->package->hdr );
msi_free(stuff->source);
msi_free(stuff->target);
@ -468,15 +473,26 @@ static DWORD WINAPI DllThread(LPVOID info)
return rc;
}
static HANDLE do_msidbCustomActionTypeDll(MSIPACKAGE *package, LPCWSTR dll, LPCWSTR target)
{
thread_struct *info;
info = msi_alloc( sizeof(*info) );
msiobj_addref( &package->hdr );
info->package = package;
info->target = strdupW(target);
info->source = strdupW(dll);
return CreateThread(NULL, 0, DllThread, info, 0, NULL);
}
static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source,
LPCWSTR target, const INT type, LPCWSTR action)
{
WCHAR tmp_file[MAX_PATH];
thread_struct *info;
DWORD ThreadId;
HANDLE ThreadHandle;
UINT rc = ERROR_SUCCESS;
BOOL finished = FALSE;
HANDLE ThreadHandle;
store_binary_to_temp(package, source, tmp_file);
@ -489,13 +505,7 @@ static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source,
strcatW(tmp_file,dot);
}
info = msi_alloc( sizeof(*info) );
msiobj_addref( &package->hdr );
info->package = package;
info->target = strdupW(target);
info->source = strdupW(tmp_file);
ThreadHandle = CreateThread(NULL,0,DllThread,(LPVOID)info,0,&ThreadId);
ThreadHandle = do_msidbCustomActionTypeDll( package, tmp_file, target );
rc = process_handle(package, type, ThreadHandle, NULL, action, &finished );
@ -503,7 +513,7 @@ static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source,
track_tempfile(package, tmp_file, tmp_file);
else
DeleteFileW(tmp_file);
return rc;
}
@ -568,6 +578,26 @@ static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source,
return prc;
}
static UINT HANDLE_CustomType17(MSIPACKAGE *package, LPCWSTR source,
LPCWSTR target, const INT type, LPCWSTR action)
{
HANDLE hThread;
MSIFILE *file;
TRACE("%s %s\n", debugstr_w(source), debugstr_w(target));
file = get_loaded_file( package, source );
if (!file)
{
ERR("invalid file key %s\n", debugstr_w( source ));
return ERROR_FUNCTION_FAILED;
}
hThread = do_msidbCustomActionTypeDll( package, file->TargetPath, target );
return process_handle(package, type, hThread, NULL, action, NULL );
}
static UINT HANDLE_CustomType18(MSIPACKAGE *package, LPCWSTR source,
LPCWSTR target, const INT type, LPCWSTR action)
{

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
@ -208,7 +208,7 @@ UINT WINAPI MsiOpenDatabaseA(LPCSTR szDBPath, LPCSTR szPersist, MSIHANDLE *phDB)
goto end;
}
else
szwPersist = (LPWSTR)(DWORD)szPersist;
szwPersist = (LPWSTR)(DWORD_PTR)szPersist;
r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB );
@ -344,3 +344,20 @@ end:
return r;
}
MSIDBSTATE WINAPI MsiGetDatabaseState( MSIHANDLE handle )
{
MSIDBSTATE ret = MSIDBSTATE_READ;
MSIDATABASE *db;
TRACE("%ld\n", handle);
db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
if (!db)
return MSIDBSTATE_ERROR;
if (db->mode != MSIDBOPEN_READONLY )
ret = MSIDBSTATE_WRITE;
msiobj_release( &db->hdr );
return ret;
}

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
@ -182,8 +182,16 @@ static UINT DELETE_delete( struct tagMSIVIEW *view )
return ERROR_SUCCESS;
}
static UINT DELETE_find_matching_rows( struct tagMSIVIEW *view, UINT col,
UINT val, UINT *row, MSIITERHANDLE *handle )
{
TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
MSIVIEWOPS delete_ops =
return ERROR_FUNCTION_FAILED;
}
static const MSIVIEWOPS delete_ops =
{
DELETE_fetch_int,
DELETE_fetch_stream,
@ -194,7 +202,8 @@ MSIVIEWOPS delete_ops =
DELETE_get_dimensions,
DELETE_get_column_info,
DELETE_modify,
DELETE_delete
DELETE_delete,
DELETE_find_matching_rows
};
UINT DELETE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define COBJMACROS
@ -45,6 +45,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(msi);
extern HINSTANCE msi_hInstance;
struct msi_control_tag;
typedef struct msi_control_tag msi_control;
typedef UINT (*msi_handler)( msi_dialog *, msi_control *, WPARAM );
@ -59,6 +61,9 @@ struct msi_control_tag
HBITMAP hBitmap;
HICON hIcon;
LPWSTR tabnext;
HMODULE hDll;
float progress_current;
float progress_max;
WCHAR name[1];
};
@ -66,6 +71,7 @@ typedef struct msi_font_tag
{
struct msi_font_tag *next;
HFONT hfont;
COLORREF color;
WCHAR name[1];
} msi_font;
@ -98,16 +104,18 @@ typedef struct
msi_dialog* dialog;
msi_control *parent;
DWORD attributes;
LPWSTR propval;
} radio_button_group_descr;
const WCHAR szMsiDialogClass[] = {
static const WCHAR szMsiDialogClass[] = {
'M','s','i','D','i','a','l','o','g','C','l','o','s','e','C','l','a','s','s',0
};
const WCHAR szMsiHiddenWindow[] = {
static const WCHAR szMsiHiddenWindow[] = {
'M','s','i','H','i','d','d','e','n','W','i','n','d','o','w',0 };
static const WCHAR szStatic[] = { 'S','t','a','t','i','c',0 };
static const WCHAR szButton[] = { 'B','U','T','T','O','N', 0 };
static const WCHAR szButtonData[] = { 'M','S','I','D','A','T','A',0 };
static const WCHAR szProgress[] = { 'P','r','o','g','r','e','s','s',0 };
static const WCHAR szText[] = { 'T','e','x','t',0 };
static const WCHAR szPushButton[] = { 'P','u','s','h','B','u','t','t','o','n',0 };
static const WCHAR szLine[] = { 'L','i','n','e',0 };
@ -126,6 +134,8 @@ static const WCHAR szRadioButtonGroup[] = {
static const WCHAR szIcon[] = { 'I','c','o','n',0 };
static const WCHAR szSelectionTree[] = {
'S','e','l','e','c','t','i','o','n','T','r','e','e',0 };
static const WCHAR szGroupBox[] = { 'G','r','o','u','p','B','o','x',0 };
static const WCHAR szListBox[] = { 'L','i','s','t','B','o','x',0 };
static UINT msi_dialog_checkbox_handler( msi_dialog *, msi_control *, WPARAM );
static void msi_dialog_checkbox_sync_state( msi_dialog *, msi_control * );
@ -236,6 +246,8 @@ static UINT msi_dialog_add_font( MSIRECORD *rec, LPVOID param )
font->next = dialog->font_list;
dialog->font_list = font;
font->color = MSI_RecordGetInteger( rec, 4 );
memset( &lf, 0, sizeof lf );
face = MSI_RecordGetString( rec, 2 );
lf.lfHeight = MSI_RecordGetInteger( rec, 3 );
@ -310,7 +322,7 @@ static UINT msi_dialog_build_font_list( msi_dialog *dialog )
}
static msi_control *msi_dialog_create_window( msi_dialog *dialog,
MSIRECORD *rec, LPCWSTR szCls, LPCWSTR name, LPCWSTR text,
MSIRECORD *rec, DWORD exstyle, LPCWSTR szCls, LPCWSTR name, LPCWSTR text,
DWORD style, HWND parent )
{
DWORD x, y, width, height;
@ -328,7 +340,10 @@ static msi_control *msi_dialog_create_window( msi_dialog *dialog,
control->value = NULL;
control->hBitmap = NULL;
control->hIcon = NULL;
control->hDll = NULL;
control->tabnext = strdupW( MSI_RecordGetString( rec, 11) );
control->progress_current = 0;
control->progress_max = 100;
x = MSI_RecordGetInteger( rec, 4 );
y = MSI_RecordGetInteger( rec, 5 );
@ -346,7 +361,7 @@ static msi_control *msi_dialog_create_window( msi_dialog *dialog,
font = msi_dialog_get_style( title_font, &title );
}
control->hwnd = CreateWindowW( szCls, title, style,
control->hwnd = CreateWindowExW( exstyle, szCls, title, style,
x, y, width, height, parent, NULL, NULL, NULL );
TRACE("Dialog %s control %s hwnd %p\n",
@ -457,24 +472,56 @@ void msi_dialog_handle_event( msi_dialog* dialog, LPCWSTR control,
LPCWSTR attribute, MSIRECORD *rec )
{
msi_control* ctrl;
LPCWSTR text;
LPCWSTR font_text, text = NULL;
LPWSTR font;
ctrl = msi_dialog_find_control( dialog, control );
if (!ctrl)
return;
if( lstrcmpW(attribute, szText) )
if( !lstrcmpW(attribute, szText) )
{
ERR("Attribute %s\n", debugstr_w(attribute));
font_text = MSI_RecordGetString( rec , 1 );
font = msi_dialog_get_style( font_text, &text );
SetWindowTextW( ctrl->hwnd, text );
msi_free( font );
msi_dialog_check_messages( NULL );
}
else if( !lstrcmpW(attribute, szProgress) )
{
DWORD func, val;
func = MSI_RecordGetInteger( rec , 1 );
val = MSI_RecordGetInteger( rec , 2 );
switch (func)
{
case 0: /* init */
ctrl->progress_max = val;
ctrl->progress_current = 0;
SendMessageW(ctrl->hwnd, PBM_SETRANGE, 0, MAKELPARAM(0,100));
SendMessageW(ctrl->hwnd, PBM_SETPOS, 0, 0);
break;
case 1: /* FIXME: not sure what this is supposed to do */
break;
case 2: /* move */
ctrl->progress_current += val;
SendMessageW(ctrl->hwnd, PBM_SETPOS, 100*(ctrl->progress_current/ctrl->progress_max), 0);
break;
default:
ERR("Unknown progress message %ld\n", func);
break;
}
}
else
{
FIXME("Attribute %s not being set\n", debugstr_w(attribute));
return;
}
text = MSI_RecordGetString( rec , 1 );
SetWindowTextW( ctrl->hwnd, text );
msi_dialog_check_messages( NULL );
}
static void msi_dialog_map_events(msi_dialog* dialog, LPCWSTR control)
{
static WCHAR Query[] = {
static const WCHAR Query[] = {
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
'`','E','v','e','n','t','M','a','p','p','i','n','g','`',' ',
'W','H','E','R','E',' ',
@ -501,6 +548,7 @@ static msi_control *msi_dialog_add_control( msi_dialog *dialog,
{
DWORD attributes;
LPCWSTR text, name;
DWORD exstyle = 0;
name = MSI_RecordGetString( rec, 2 );
attributes = MSI_RecordGetInteger( rec, 8 );
@ -509,15 +557,18 @@ static msi_control *msi_dialog_add_control( msi_dialog *dialog,
style |= WS_VISIBLE;
if( ~attributes & msidbControlAttributesEnabled )
style |= WS_DISABLED;
if( attributes & msidbControlAttributesSunken )
exstyle |= WS_EX_CLIENTEDGE;
msi_dialog_map_events(dialog, name);
return msi_dialog_create_window( dialog, rec, szCls, name, text,
style, dialog->hwnd );
return msi_dialog_create_window( dialog, rec, exstyle, szCls, name,
text, style, dialog->hwnd );
}
struct msi_text_info
{
msi_font *font;
WNDPROC oldproc;
DWORD attributes;
};
@ -547,6 +598,9 @@ MSIText_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
info = GetPropW(hWnd, szButtonData);
if ( info->font )
SetTextColor( (HDC)wParam, info->font->color );
if( msg == WM_CTLCOLORSTATIC &&
( info->attributes & msidbControlAttributesTransparent ) )
{
@ -574,6 +628,8 @@ static UINT msi_dialog_text_control( msi_dialog *dialog, MSIRECORD *rec )
{
msi_control *control;
struct msi_text_info *info;
LPCWSTR text, ptr;
LPWSTR font_name;
TRACE("%p %p\n", dialog, rec);
@ -585,6 +641,11 @@ static UINT msi_dialog_text_control( msi_dialog *dialog, MSIRECORD *rec )
if( !info )
return ERROR_SUCCESS;
text = MSI_RecordGetString( rec, 10 );
font_name = msi_dialog_get_style( text, &ptr );
info->font = ( font_name ) ? msi_dialog_find_font( dialog, font_name ) : NULL;
msi_free( font_name );
info->attributes = MSI_RecordGetInteger( rec, 8 );
if( info->attributes & msidbControlAttributesTransparent )
SetWindowLongPtrW( control->hwnd, GWL_EXSTYLE, WS_EX_TRANSPARENT );
@ -700,7 +761,6 @@ struct msi_scrolltext_info
msi_dialog *dialog;
msi_control *control;
WNDPROC oldproc;
HMODULE hRichedit;
};
static LRESULT WINAPI
@ -718,11 +778,11 @@ MSIScrollText_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
switch( msg )
{
case WM_NCDESTROY:
FreeLibrary( info->hRichedit );
msi_free( info );
RemovePropW( hWnd, szButtonData );
break;
case WM_VSCROLL:
case WM_PAINT:
/* native MSI sets a wait cursor here */
msi_dialog_button_handler( info->dialog, info->control, BN_CLICKED );
break;
}
@ -777,24 +837,27 @@ static UINT msi_dialog_scrolltext_control( msi_dialog *dialog, MSIRECORD *rec )
};
struct msi_scrolltext_info *info;
msi_control *control;
HMODULE hRichedit;
DWORD style;
info = msi_alloc( sizeof *info );
if (!info)
return ERROR_FUNCTION_FAILED;
info->hRichedit = LoadLibraryA("riched20");
hRichedit = LoadLibraryA("riched20");
style = WS_BORDER | ES_MULTILINE | WS_VSCROLL |
ES_READONLY | ES_AUTOVSCROLL | WS_TABSTOP;
control = msi_dialog_add_control( dialog, rec, szRichEdit20W, style );
if (!control)
{
FreeLibrary( info->hRichedit );
FreeLibrary( hRichedit );
msi_free( info );
return ERROR_FUNCTION_FAILED;
}
control->hDll = hRichedit;
info->dialog = dialog;
info->control = control;
@ -1314,12 +1377,15 @@ static UINT msi_dialog_create_radiobutton( MSIRECORD *rec, LPVOID param )
if( ~attributes & 2 )
style |= WS_DISABLED;
control = msi_dialog_create_window( dialog, rec, szButton, name, text,
control = msi_dialog_create_window( dialog, rec, 0, szButton, name, text,
style, group->parent->hwnd );
if (!control)
return ERROR_FUNCTION_FAILED;
control->handler = msi_dialog_radiogroup_handler;
if (!lstrcmpW(control->name, group->propval))
SendMessageW(control->hwnd, BM_SETCHECK, BST_CHECKED, 0);
prop = MSI_RecordGetString( rec, 1 );
if( prop )
control->property = strdupW( prop );
@ -1371,18 +1437,164 @@ static UINT msi_dialog_radiogroup_control( msi_dialog *dialog, MSIRECORD *rec )
group.dialog = dialog;
group.parent = control;
group.attributes = MSI_RecordGetInteger( rec, 8 );
group.propval = msi_dup_property( dialog->package, control->property );
r = MSI_IterateRecords( view, 0, msi_dialog_create_radiobutton, &group );
msiobj_release( &view->hdr );
msi_free( group.propval );
return r;
}
/******************** Selection Tree ***************************************/
struct msi_selection_tree_info
{
msi_dialog *dialog;
HWND hwnd;
WNDPROC oldproc;
};
static void
msi_dialog_tv_add_child_features( MSIPACKAGE *package, HWND hwnd,
LPCWSTR parent, HTREEITEM hParent )
msi_seltree_sync_item_state( HWND hwnd, MSIFEATURE *feature, HTREEITEM hItem )
{
TVITEMW tvi;
TRACE("Feature %s -> %d %d %d\n", debugstr_w(feature->Title),
feature->Installed, feature->Action, feature->ActionRequest);
tvi.mask = TVIF_STATE;
tvi.hItem = hItem;
tvi.state = INDEXTOSTATEIMAGEMASK( feature->Action );
tvi.stateMask = TVIS_STATEIMAGEMASK;
SendMessageW( hwnd, TVM_SETITEMW, 0, (LPARAM) &tvi );
}
static UINT
msi_seltree_popup_menu( HWND hwnd, INT x, INT y )
{
HMENU hMenu;
INT r;
/* create a menu to display */
hMenu = CreatePopupMenu();
/* FIXME: load strings from resources */
AppendMenuA( hMenu, MF_ENABLED, INSTALLSTATE_LOCAL, "Install feature locally");
AppendMenuA( hMenu, MF_GRAYED, 0x1000, "Install entire feature");
AppendMenuA( hMenu, MF_ENABLED, INSTALLSTATE_ADVERTISED, "Install on demand");
AppendMenuA( hMenu, MF_ENABLED, INSTALLSTATE_ABSENT, "Don't install");
r = TrackPopupMenu( hMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD,
x, y, 0, hwnd, NULL );
DestroyMenu( hMenu );
return r;
}
static MSIFEATURE *
msi_seltree_feature_from_item( HWND hwnd, HTREEITEM hItem )
{
TVITEMW tvi;
/* get the feature from the item */
memset( &tvi, 0, sizeof tvi );
tvi.hItem = hItem;
tvi.mask = TVIF_PARAM | TVIF_HANDLE;
SendMessageW( hwnd, TVM_GETITEMW, 0, (LPARAM) &tvi );
return (MSIFEATURE*) tvi.lParam;
}
static LRESULT
msi_seltree_menu( HWND hwnd, HTREEITEM hItem )
{
MSIFEATURE *feature;
ComponentList *cl;
union {
RECT rc;
POINT pt[2];
HTREEITEM hItem;
} u;
UINT r;
feature = msi_seltree_feature_from_item( hwnd, hItem );
if (!feature)
{
ERR("item %p feature was NULL\n", hItem);
return 0;
}
/* get the item's rectangle to put the menu just below it */
u.hItem = hItem;
SendMessageW( hwnd, TVM_GETITEMRECT, 0, (LPARAM) &u.rc );
MapWindowPoints( hwnd, NULL, u.pt, 2 );
r = msi_seltree_popup_menu( hwnd, u.rc.left, u.rc.top );
switch (r)
{
case INSTALLSTATE_LOCAL:
case INSTALLSTATE_ADVERTISED:
case INSTALLSTATE_ABSENT:
feature->ActionRequest = r;
feature->Action = r;
break;
default:
FIXME("select feature and all children\n");
}
/* update */
msi_seltree_sync_item_state( hwnd, feature, hItem );
/* update the feature's components */
LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
{
cl->component->Action = feature->Action;
cl->component->ActionRequest = feature->ActionRequest;
}
return 0;
}
static LRESULT WINAPI
MSISelectionTree_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
struct msi_selection_tree_info *info;
TVHITTESTINFO tvhti;
HRESULT r;
TRACE("%p %04x %08x %08lx\n", hWnd, msg, wParam, lParam);
info = GetPropW(hWnd, szButtonData);
switch( msg )
{
case WM_LBUTTONDOWN:
tvhti.pt.x = LOWORD( lParam );
tvhti.pt.y = HIWORD( lParam );
tvhti.flags = 0;
tvhti.hItem = 0;
r = CallWindowProcW(info->oldproc, hWnd, TVM_HITTEST, 0, (LPARAM) &tvhti );
if (tvhti.flags & TVHT_ONITEMSTATEICON)
return msi_seltree_menu( hWnd, tvhti.hItem );
break;
}
r = CallWindowProcW(info->oldproc, hWnd, msg, wParam, lParam);
switch( msg )
{
case WM_NCDESTROY:
msi_free( info );
RemovePropW( hWnd, szButtonData );
break;
}
return r;
}
static void
msi_seltree_add_child_features( MSIPACKAGE *package, HWND hwnd,
LPCWSTR parent, HTREEITEM hParent )
{
MSIFEATURE *feature;
TVINSERTSTRUCTW tvis;
@ -1396,46 +1608,265 @@ msi_dialog_tv_add_child_features( MSIPACKAGE *package, HWND hwnd,
if ( !feature->Title )
continue;
if ( !feature->Display )
continue;
memset( &tvis, 0, sizeof tvis );
tvis.hParent = hParent;
tvis.hInsertAfter = TVI_SORT;
if (feature->Title)
{
tvis.u.item.mask = TVIF_TEXT;
tvis.u.item.pszText = feature->Title;
}
tvis.hInsertAfter = TVI_LAST;
tvis.u.item.mask = TVIF_TEXT | TVIF_PARAM;
tvis.u.item.pszText = feature->Title;
tvis.u.item.lParam = (LPARAM) feature;
hitem = (HTREEITEM) SendMessageW( hwnd, TVM_INSERTITEMW, 0, (LPARAM) &tvis );
if (!hitem)
continue;
msi_dialog_tv_add_child_features( package, hwnd,
feature->Feature, hitem );
msi_seltree_sync_item_state( hwnd, feature, hitem );
msi_seltree_add_child_features( package, hwnd,
feature->Feature, hitem );
/* the node is expanded if Display is odd */
if ( feature->Display % 2 != 0 )
SendMessageW( hwnd, TVM_EXPAND, TVE_EXPAND, (LPARAM) hitem );
}
}
static void msi_seltree_create_imagelist( HWND hwnd )
{
const int bm_width = 32, bm_height = 16, bm_count = 3;
const int bm_resource = 0x1001;
HIMAGELIST himl;
int i;
HBITMAP hbmp;
himl = ImageList_Create( bm_width, bm_height, FALSE, 4, 0 );
if (!himl)
{
ERR("failed to create image list\n");
return;
}
for (i=0; i<bm_count; i++)
{
hbmp = LoadBitmapW( msi_hInstance, MAKEINTRESOURCEW(i+bm_resource) );
if (!hbmp)
{
ERR("failed to load bitmap %d\n", i);
break;
}
/*
* Add a dummy bitmap at offset zero because the treeview
* can't use it as a state mask (zero means no user state).
*/
if (!i)
ImageList_Add( himl, hbmp, NULL );
ImageList_Add( himl, hbmp, NULL );
}
SendMessageW( hwnd, TVM_SETIMAGELIST, TVSIL_STATE, (LPARAM)himl );
}
static UINT msi_dialog_selection_tree( msi_dialog *dialog, MSIRECORD *rec )
{
msi_control *control;
LPCWSTR prop;
LPWSTR val;
MSIPACKAGE *package = dialog->package;
DWORD style;
struct msi_selection_tree_info *info;
prop = MSI_RecordGetString( rec, 9 );
val = msi_dup_property( package, prop );
control = msi_dialog_add_control( dialog, rec, WC_TREEVIEWW,
TVS_HASBUTTONS | WS_GROUP | WS_VSCROLL );
if (!control)
info = msi_alloc( sizeof *info );
if (!info)
return ERROR_FUNCTION_FAILED;
msi_dialog_tv_add_child_features( package, control->hwnd, NULL, NULL );
/* create the treeview control */
prop = MSI_RecordGetString( rec, 9 );
style = TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT;
style |= WS_GROUP | WS_VSCROLL;
control = msi_dialog_add_control( dialog, rec, WC_TREEVIEWW, style );
if (!control)
{
msi_free(info);
return ERROR_FUNCTION_FAILED;
}
msi_free( val );
/* subclass */
info->dialog = dialog;
info->hwnd = control->hwnd;
info->oldproc = (WNDPROC) SetWindowLongPtrW( control->hwnd, GWLP_WNDPROC,
(LONG_PTR)MSISelectionTree_WndProc );
SetPropW( control->hwnd, szButtonData, info );
/* initialize it */
msi_seltree_create_imagelist( control->hwnd );
msi_seltree_add_child_features( package, control->hwnd, NULL, NULL );
return ERROR_SUCCESS;
}
struct control_handler msi_dialog_handler[] =
/******************** Group Box ***************************************/
static UINT msi_dialog_group_box( msi_dialog *dialog, MSIRECORD *rec )
{
msi_control *control;
DWORD style;
style = BS_GROUPBOX | WS_CHILD | WS_GROUP;
control = msi_dialog_add_control( dialog, rec, WC_BUTTONW, style );
if (!control)
return ERROR_FUNCTION_FAILED;
return ERROR_SUCCESS;
}
/******************** List Box ***************************************/
struct msi_listbox_item
{
LPWSTR property;
LPWSTR value;
};
struct msi_listbox_info
{
msi_dialog *dialog;
HWND hwnd;
WNDPROC oldproc;
DWORD num_items;
struct msi_listbox_item *items;
};
static LRESULT WINAPI MSIListBox_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
struct msi_listbox_info *info;
LRESULT r;
DWORD j;
TRACE("%p %04x %08x %08lx\n", hWnd, msg, wParam, lParam);
info = GetPropW( hWnd, szButtonData );
if (!info)
return 0;
r = CallWindowProcW( info->oldproc, hWnd, msg, wParam, lParam );
switch( msg )
{
case WM_NCDESTROY:
for (j = 0; j < info->num_items; j++)
{
msi_free( info->items[j].property );
msi_free( info->items[j].value );
}
msi_free( info->items );
msi_free( info );
RemovePropW( hWnd, szButtonData );
break;
}
return r;
}
static UINT msi_listbox_add_item( MSIRECORD *rec, LPVOID param )
{
struct msi_listbox_info *info = param;
struct msi_listbox_item *item;
LPCWSTR property, value, text;
static int index = 0;
item = &info->items[index++];
property = MSI_RecordGetString( rec, 1 );
value = MSI_RecordGetString( rec, 3 );
text = MSI_RecordGetString( rec, 4 );
item->property = strdupW( property );
item->value = strdupW( value );
SendMessageW( info->hwnd, LB_ADDSTRING, 0, (LPARAM)text );
return ERROR_SUCCESS;
}
static UINT msi_listbox_add_items( struct msi_listbox_info *info )
{
UINT r;
MSIQUERY *view = NULL;
DWORD count;
static const WCHAR query[] = {
'S','E','L','E','C','T',' ','*',' ',
'F','R','O','M',' ','`','L','i','s','t','B','o','x','`',' ',
'O','R','D','E','R',' ','B','Y',' ','`','O','r','d','e','r','`',0
};
r = MSI_OpenQuery( info->dialog->package->db, &view, query );
if ( r != ERROR_SUCCESS )
return r;
/* just get the number of records */
r = MSI_IterateRecords( view, &count, NULL, NULL );
info->num_items = count;
info->items = msi_alloc( sizeof(*info->items) * count );
r = MSI_IterateRecords( view, NULL, msi_listbox_add_item, info );
msiobj_release( &view->hdr );
return r;
}
static UINT msi_dialog_listbox_handler( msi_dialog *dialog,
msi_control *control, WPARAM param )
{
struct msi_listbox_info *info;
int index;
if( HIWORD(param) != LBN_SELCHANGE )
return ERROR_SUCCESS;
info = GetPropW( control->hwnd, szButtonData );
index = SendMessageW( control->hwnd, LB_GETCURSEL, 0, 0 );
MSI_SetPropertyW( info->dialog->package,
info->items[index].property, info->items[index].value );
msi_dialog_evaluate_control_conditions( info->dialog );
return ERROR_SUCCESS;
}
static UINT msi_dialog_list_box( msi_dialog *dialog, MSIRECORD *rec )
{
struct msi_listbox_info *info;
msi_control *control;
DWORD style;
info = msi_alloc( sizeof *info );
if (!info)
return ERROR_FUNCTION_FAILED;
style = WS_TABSTOP | WS_GROUP | WS_CHILD | LBS_STANDARD;
control = msi_dialog_add_control( dialog, rec, WC_LISTBOXW, style );
if (!control)
return ERROR_FUNCTION_FAILED;
control->handler = msi_dialog_listbox_handler;
/* subclass */
info->dialog = dialog;
info->hwnd = control->hwnd;
info->items = NULL;
info->oldproc = (WNDPROC)SetWindowLongPtrW( control->hwnd, GWLP_WNDPROC,
(LONG_PTR)MSIListBox_WndProc );
SetPropW( control->hwnd, szButtonData, info );
msi_listbox_add_items( info );
return ERROR_SUCCESS;
}
static const struct control_handler msi_dialog_handler[] =
{
{ szText, msi_dialog_text_control },
{ szPushButton, msi_dialog_button_control },
@ -1451,6 +1882,8 @@ struct control_handler msi_dialog_handler[] =
{ szRadioButtonGroup, msi_dialog_radiogroup_control },
{ szIcon, msi_dialog_icon_control },
{ szSelectionTree, msi_dialog_selection_tree },
{ szGroupBox, msi_dialog_group_box },
{ szListBox, msi_dialog_list_box },
};
#define NUM_CONTROL_TYPES (sizeof msi_dialog_handler/sizeof msi_dialog_handler[0])
@ -1719,7 +2152,6 @@ static LRESULT msi_dialog_oncreate( HWND hwnd, LPCREATESTRUCTW cs )
SetWindowPos( hwnd, 0, 0, 0, size.cx, size.cy,
SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW );
msi_dialog_build_font_list( dialog );
msi_dialog_fill_controls( dialog );
msi_dialog_evaluate_control_conditions( dialog );
@ -1779,7 +2211,7 @@ static UINT msi_dialog_control_event( MSIRECORD *rec, LPVOID param )
condition = MSI_RecordGetString( rec, 5 );
r = MSI_EvaluateConditionW( dialog->package, condition );
if( r == MSICONDITION_TRUE )
if( r == MSICONDITION_TRUE || r == MSICONDITION_NONE )
{
event = MSI_RecordGetString( rec, 3 );
arg = MSI_RecordGetString( rec, 4 );
@ -2007,16 +2439,29 @@ static LRESULT WINAPI MSIDialog_WndProc( HWND hwnd, UINT msg,
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
static BOOL CALLBACK msi_radioground_child_enum( HWND hWnd, LPARAM lParam )
{
EnableWindow( hWnd, lParam );
return TRUE;
}
static LRESULT WINAPI MSIRadioGroup_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
WNDPROC oldproc = (WNDPROC) GetPropW(hWnd, szButtonData);
LRESULT r;
TRACE("hWnd %p msg %04x wParam 0x%08x lParam 0x%08lx\n", hWnd, msg, wParam, lParam);
if (msg == WM_COMMAND) /* Forward notifications to dialog */
SendMessageW(GetParent(hWnd), msg, wParam, lParam);
return CallWindowProcW(oldproc, hWnd, msg, wParam, lParam);
r = CallWindowProcW(oldproc, hWnd, msg, wParam, lParam);
/* make sure the radio buttons show as disabled if the parent is disabled */
if (msg == WM_ENABLE)
EnumChildWindows( hWnd, msi_radioground_child_enum, wParam );
return r;
}
static LRESULT WINAPI MSIHiddenWindowProc( HWND hwnd, UINT msg,
@ -2126,16 +2571,18 @@ void msi_dialog_check_messages( HANDLE handle )
UINT msi_dialog_run_message_loop( msi_dialog *dialog )
{
DWORD style;
HWND hwnd;
if( !(dialog->attributes & msidbDialogAttributesVisible) )
return ERROR_SUCCESS;
if( uiThreadId != GetCurrentThreadId() )
return SendMessageW( hMsiHiddenWindow, WM_MSI_DIALOG_CREATE, 0, (LPARAM) dialog );
/* create the dialog window, don't show it yet */
hwnd = CreateWindowW( szMsiDialogClass, dialog->name, WS_OVERLAPPEDWINDOW,
style = WS_OVERLAPPED;
if( dialog->attributes & msidbDialogAttributesVisible )
style |= WS_VISIBLE;
hwnd = CreateWindowW( szMsiDialogClass, dialog->name, style,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, NULL, dialog );
if( !hwnd )
@ -2198,6 +2645,8 @@ void msi_dialog_destroy( msi_dialog *dialog )
DestroyIcon( t->hIcon );
msi_free( t->tabnext );
msi_free( t );
if (t->hDll)
FreeLibrary( t->hDll );
}
/* destroy the list of fonts */

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
@ -246,8 +246,29 @@ static UINT DISTINCT_delete( struct tagMSIVIEW *view )
return ERROR_SUCCESS;
}
static UINT DISTINCT_find_matching_rows( struct tagMSIVIEW *view, UINT col,
UINT val, UINT *row, MSIITERHANDLE *handle )
{
MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
UINT r;
MSIVIEWOPS distinct_ops =
TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
if( !dv->table )
return ERROR_FUNCTION_FAILED;
r = dv->table->ops->find_matching_rows( dv->table, col, val, row, handle );
if( *row > dv->row_count )
return ERROR_NO_MORE_ITEMS;
*row = dv->translation[ *row ];
return r;
}
static const MSIVIEWOPS distinct_ops =
{
DISTINCT_fetch_int,
NULL,
@ -258,7 +279,8 @@ MSIVIEWOPS distinct_ops =
DISTINCT_get_dimensions,
DISTINCT_get_column_info,
DISTINCT_modify,
DISTINCT_delete
DISTINCT_delete,
DISTINCT_find_matching_rows,
};
UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
@ -35,6 +35,7 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/contr
#include "action.h"
#include "wine/debug.h"
#include "wine/unicode.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
@ -368,7 +369,17 @@ UINT ACTION_DialogBox( MSIPACKAGE* package, LPCWSTR szDialogName )
return r;
}
struct _events Events[] = {
static UINT ControlEvent_SetInstallLevel(MSIPACKAGE* package, LPCWSTR argument,
msi_dialog* dialog)
{
int iInstallLevel = atolW(argument);
TRACE("Setting install level: %i\n", iInstallLevel);
return MSI_SetInstallLevel( package, iInstallLevel );
}
static const struct _events Events[] = {
{ "EndDialog",ControlEvent_EndDialog },
{ "NewDialog",ControlEvent_NewDialog },
{ "SpawnDialog",ControlEvent_SpawnDialog },
@ -379,6 +390,7 @@ struct _events Events[] = {
{ "AddSource",ControlEvent_AddSource },
{ "SetTargetPath",ControlEvent_SetTargetPath },
{ "Reset",ControlEvent_Reset },
{ "SetInstallLevel",ControlEvent_SetInstallLevel },
{ NULL,NULL },
};

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
@ -180,7 +180,7 @@ static long cabinet_seek(INT_PTR hf, long dist, int seektype)
return SetFilePointer(handle, dist, NULL, seektype);
}
static void msi_file_update_ui( MSIPACKAGE *package, MSIFILE *f )
static void msi_file_update_ui( MSIPACKAGE *package, MSIFILE *f, const WCHAR *action )
{
MSIRECORD *uirow;
LPWSTR uipath, p;
@ -194,7 +194,7 @@ static void msi_file_update_ui( MSIPACKAGE *package, MSIFILE *f )
p[1]=0;
MSI_RecordSetStringW( uirow, 9, uipath);
MSI_RecordSetInteger( uirow, 6, f->FileSize );
ui_actiondata( package, szInstallFiles, uirow);
ui_actiondata( package, action, uirow);
msiobj_release( &uirow->hdr );
msi_free( uipath );
ui_progress( package, 2, f->FileSize, 0, 0);
@ -210,6 +210,7 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
HANDLE handle;
LPWSTR file;
MSIFILE *f;
DWORD attrs;
file = strdupAtoW(pfdin->psz1);
f = get_loaded_file(data->package, file);
@ -227,12 +228,15 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
return 0;
}
msi_file_update_ui( data->package, f );
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_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
NULL, CREATE_ALWAYS, attrs, NULL );
if ( handle == INVALID_HANDLE_VALUE )
{
ERR("failed to create %s (error %ld)\n",
@ -328,90 +332,21 @@ static VOID set_file_source(MSIPACKAGE* package, MSIFILE* file, MSICOMPONENT*
{
if (file->Attributes & msidbFileAttributesNoncompressed)
{
LPWSTR p;
LPWSTR p, path;
p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
file->SourcePath = build_directory_name(2, p, file->ShortName);
path = build_directory_name(2, p, file->ShortName);
if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW( path ))
{
msi_free(path);
path = build_directory_name(2, p, file->LongName);
}
file->SourcePath = path;
msi_free(p);
}
else
file->SourcePath = build_directory_name(2, path, file->File);
}
static BOOL check_volume(LPCWSTR path, LPCWSTR want_volume, LPWSTR volume,
UINT *intype)
{
WCHAR drive[4];
WCHAR name[MAX_PATH];
UINT type;
if (!(path[0] && path[1] == ':'))
return TRUE;
drive[0] = path[0];
drive[1] = path[1];
drive[2] = '\\';
drive[3] = 0;
TRACE("Checking volume %s .. (%s)\n",debugstr_w(drive), debugstr_w(want_volume));
type = GetDriveTypeW(drive);
TRACE("drive is of type %x\n",type);
if (type == DRIVE_UNKNOWN || type == DRIVE_NO_ROOT_DIR ||
type == DRIVE_FIXED || type == DRIVE_RAMDISK)
return TRUE;
GetVolumeInformationW(drive, name, MAX_PATH, NULL, NULL, NULL, NULL, 0);
TRACE("Drive contains %s\n", debugstr_w(name));
volume = strdupW(name);
if (*intype)
*intype=type;
return (strcmpiW(want_volume,name)==0);
}
static BOOL check_for_sourcefile(LPCWSTR source)
{
DWORD attrib = GetFileAttributesW(source);
return (!(attrib == INVALID_FILE_ATTRIBUTES));
}
static UINT ready_volume(MSIPACKAGE* package, LPCWSTR path, LPWSTR last_volume,
MSIRECORD *row,UINT *type )
{
LPWSTR volume = NULL;
LPCWSTR want_volume = MSI_RecordGetString(row, 5);
BOOL ok = check_volume(path, want_volume, volume, type);
TRACE("Readying Volume for %s (%s, %s)\n", debugstr_w(path),
debugstr_w(want_volume), debugstr_w(last_volume));
if (check_for_sourcefile(path) && !ok)
{
FIXME("Found the Sourcefile but not on the correct volume.(%s,%s,%s)\n",
debugstr_w(path),debugstr_w(want_volume), debugstr_w(volume));
return ERROR_SUCCESS;
}
while (!ok)
{
INT rc;
LPCWSTR prompt;
LPWSTR msg;
prompt = MSI_RecordGetString(row,3);
msg = generate_error_string(package, 1302, 1, prompt);
rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
msi_free(volume);
msi_free(msg);
if (rc == IDOK)
ok = check_for_sourcefile(path);
else
return ERROR_INSTALL_USEREXIT;
}
msi_free(last_volume);
last_volume = strdupW(volume);
return ERROR_SUCCESS;
}
struct media_info {
UINT last_sequence;
LPWSTR last_volume;
@ -457,7 +392,6 @@ static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi,
LPCWSTR cab, volume;
DWORD sz;
INT seq;
UINT type;
LPCWSTR prompt;
MSICOMPONENT *comp = file->Component;
@ -489,23 +423,15 @@ static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi,
{
mi->last_path = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
set_file_source(package,file,comp,mi->last_path);
rc = ready_volume(package, file->SourcePath, mi->last_volume, row,&type);
MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT, mi->count, volume,
prompt);
if (type == DRIVE_REMOVABLE || type == DRIVE_CDROM ||
type == DRIVE_RAMDISK)
MsiSourceListSetInfoW(package->ProductCode, NULL,
MsiSourceListSetInfoW(package->ProductCode, NULL,
MSIINSTALLCONTEXT_USERMANAGED,
MSICODE_PRODUCT|MSISOURCETYPE_MEDIA,
INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path);
else
MsiSourceListSetInfoW(package->ProductCode, NULL,
MSIINSTALLCONTEXT_USERMANAGED,
MSICODE_PRODUCT|MSISOURCETYPE_NETWORK,
INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path);
msiobj_release(&row->hdr);
return rc;
}
@ -550,18 +476,10 @@ static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi,
strcpyW(mi->last_path,mi->source);
strcatW(mi->source,cab);
rc = ready_volume(package, mi->source, mi->last_volume, row, &type);
if (type == DRIVE_REMOVABLE || type == DRIVE_CDROM ||
type == DRIVE_RAMDISK)
MsiSourceListSetInfoW(package->ProductCode, NULL,
MsiSourceListSetInfoW(package->ProductCode, NULL,
MSIINSTALLCONTEXT_USERMANAGED,
MSICODE_PRODUCT|MSISOURCETYPE_MEDIA,
INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path);
else
MsiSourceListSetInfoW(package->ProductCode, NULL,
MSIINSTALLCONTEXT_USERMANAGED,
MSICODE_PRODUCT|MSISOURCETYPE_NETWORK,
INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path);
/* extract the cab file into a folder in the temp folder */
sz = MAX_PATH;
@ -578,19 +496,11 @@ static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi,
mi->last_path = msi_alloc(MAX_PATH*sizeof(WCHAR));
MSI_GetPropertyW(package,cszSourceDir,mi->source,&sz);
strcpyW(mi->last_path,mi->source);
rc = ready_volume(package, mi->last_path, mi->last_volume, row, &type);
if (type == DRIVE_REMOVABLE || type == DRIVE_CDROM ||
type == DRIVE_RAMDISK)
MsiSourceListSetInfoW(package->ProductCode, NULL,
MsiSourceListSetInfoW(package->ProductCode, NULL,
MSIINSTALLCONTEXT_USERMANAGED,
MSICODE_PRODUCT|MSISOURCETYPE_MEDIA,
INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path);
else
MsiSourceListSetInfoW(package->ProductCode, NULL,
MSIINSTALLCONTEXT_USERMANAGED,
MSICODE_PRODUCT|MSISOURCETYPE_NETWORK,
INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path);
}
set_file_source(package, file, comp, mi->last_path);
@ -604,19 +514,14 @@ static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi,
}
static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
LPWSTR* file_source)
MSIFILE** file)
{
MSIFILE *file;
LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
LIST_FOR_EACH_ENTRY( *file, &package->files, MSIFILE, entry )
{
if (lstrcmpW( file_key, file->File )==0)
if (lstrcmpW( file_key, (*file)->File )==0)
{
if (file->state >= msifs_overwrite)
{
*file_source = strdupW( file->TargetPath );
if ((*file)->state >= msifs_overwrite)
return ERROR_SUCCESS;
}
else
return ERROR_FILE_NOT_FOUND;
}
@ -744,13 +649,13 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
{
MSIPACKAGE *package = (MSIPACKAGE*)param;
WCHAR *file_source = NULL;
WCHAR dest_name[0x100];
LPWSTR dest_path, dest;
LPCWSTR file_key, component;
DWORD sz;
DWORD rc;
MSICOMPONENT *comp;
MSIFILE *file;
component = MSI_RecordGetString(row,2);
comp = get_loaded_component(package,component);
@ -775,17 +680,16 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
return ERROR_FUNCTION_FAILED;
}
rc = get_file_target(package,file_key,&file_source);
rc = get_file_target(package,file_key,&file);
if (rc != ERROR_SUCCESS)
{
ERR("Original file unknown %s\n",debugstr_w(file_key));
msi_free(file_source);
return ERROR_SUCCESS;
}
if (MSI_RecordIsNull(row,4))
strcpyW(dest_name,strrchrW(file_source,'\\')+1);
strcpyW(dest_name,strrchrW(file->TargetPath,'\\')+1);
else
{
sz=0x100;
@ -796,7 +700,7 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
if (MSI_RecordIsNull(row,5))
{
LPWSTR p;
dest_path = strdupW(file_source);
dest_path = strdupW(file->TargetPath);
p = strrchrW(dest_path,'\\');
if (p)
*p=0;
@ -813,7 +717,6 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
if (!dest_path)
{
FIXME("Unable to get destination folder, try AppSearch properties\n");
msi_free(file_source);
return ERROR_SUCCESS;
}
}
@ -821,23 +724,24 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
dest = build_directory_name(2, dest_path, dest_name);
TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),
TRACE("Duplicating file %s to %s\n",debugstr_w(file->TargetPath),
debugstr_w(dest));
if (strcmpW(file_source,dest))
rc = !CopyFileW(file_source,dest,TRUE);
if (strcmpW(file->TargetPath,dest))
rc = !CopyFileW(file->TargetPath,dest,TRUE);
else
rc = ERROR_SUCCESS;
if (rc != ERROR_SUCCESS)
ERR("Failed to copy file %s -> %s, last error %ld\n",
debugstr_w(file_source), debugstr_w(dest_path), GetLastError());
debugstr_w(file->TargetPath), debugstr_w(dest_path), GetLastError());
FIXME("We should track these duplicate files as well\n");
msi_free(dest_path);
msi_free(dest);
msi_free(file_source);
msi_file_update_ui(package, file, szDuplicateFiles);
return ERROR_SUCCESS;
}
@ -866,6 +770,9 @@ UINT ACTION_RemoveFiles( MSIPACKAGE *package )
LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
{
MSIRECORD *uirow;
LPWSTR uipath, p;
if ( !file->Component )
continue;
if ( file->Component->Installed == INSTALLSTATE_LOCAL )
@ -881,6 +788,19 @@ UINT ACTION_RemoveFiles( MSIPACKAGE *package )
if ( !DeleteFileW( file->TargetPath ) )
ERR("failed to delete %s\n", debugstr_w(file->TargetPath) );
file->state = msifs_missing;
/* the UI chunk */
uirow = MSI_CreateRecord( 9 );
MSI_RecordSetStringW( uirow, 1, file->FileName );
uipath = strdupW( file->TargetPath );
p = strrchrW(uipath,'\\');
if (p)
p[1]=0;
MSI_RecordSetStringW( uirow, 9, uipath);
ui_actiondata( package, szRemoveFiles, uirow);
msiobj_release( &uirow->hdr );
msi_free( uipath );
/* FIXME: call ui_progress here? */
}
return ERROR_SUCCESS;

View file

@ -16,7 +16,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
/*

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
@ -188,6 +188,9 @@ UINT WINAPI MsiCloseHandle(MSIHANDLE handle)
TRACE("%lx\n",handle);
if (!handle)
return ERROR_SUCCESS;
EnterCriticalSection( &MSI_handle_cs );
info = msihandle2msiinfo(handle, 0);

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
/*
@ -43,47 +43,6 @@ 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};
DWORD build_version_dword(LPCWSTR version_string)
{
SHORT major,minor;
WORD build;
DWORD rc = 0x00000000;
LPCWSTR ptr1;
ptr1 = version_string;
if (!ptr1)
return rc;
else
major = atoiW(ptr1);
if(ptr1)
ptr1 = strchrW(ptr1,'.');
if (ptr1)
{
ptr1++;
minor = atoiW(ptr1);
}
else
minor = 0;
if (ptr1)
ptr1 = strchrW(ptr1,'.');
if (ptr1)
{
ptr1++;
build = atoiW(ptr1);
}
else
build = 0;
rc = MAKELONG(build,MAKEWORD(minor,major));
TRACE("%s -> 0x%lx\n",debugstr_w(version_string),rc);
return rc;
}
LPWSTR build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name )
{
LPWSTR SystemFolder, dest, FilePath;
@ -133,6 +92,14 @@ LPWSTR msi_dup_property(MSIPACKAGE *package, LPCWSTR prop)
return str;
}
int msi_get_property_int( MSIPACKAGE *package, LPCWSTR prop, int def )
{
LPWSTR str = msi_dup_property( package, prop );
int val = str ? atoiW( str ) : def;
msi_free( str );
return val;
}
MSICOMPONENT* get_loaded_component( MSIPACKAGE* package, LPCWSTR Component )
{
MSICOMPONENT *comp;
@ -228,6 +195,45 @@ static LPWSTR get_source_root( MSIPACKAGE *package )
return path;
}
/*
* clean_spaces_from_path()
*
* removes spaces from the beginning and end of path segments
* removes multiple \\ characters
*/
static void clean_spaces_from_path( LPWSTR p )
{
LPWSTR q = p;
int n, len = 0;
while (1)
{
/* copy until the end of the string or a space */
while (*p != ' ' && (*q = *p))
{
p++, len++;
/* reduce many backslashes to one */
if (*p != '\\' || *q != '\\')
q++;
}
/* quit at the end of the string */
if (!*p)
break;
/* count the number of spaces */
n = 0;
while (p[n] == ' ')
n++;
/* if it's leading or trailing space, skip it */
if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
p += n;
else /* copy n spaces */
while (n && (*q++ = *p++)) n--;
}
}
LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
BOOL set_prop, MSIFOLDER **folder)
{
@ -255,6 +261,7 @@ LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
/* correct misbuilt target dir */
path = build_directory_name(2, check_path, NULL);
clean_spaces_from_path( path );
if (strcmpiW(path,check_path)!=0)
MSI_SetPropertyW(package,cszTargetDir,path);
msi_free(check_path);
@ -307,6 +314,7 @@ LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
TRACE(" TargetDefault = %s\n", debugstr_w(f->TargetDefault));
path = build_directory_name( 3, p, f->TargetDefault, NULL );
clean_spaces_from_path( path );
f->ResolvedTarget = strdupW( path );
TRACE("target -> %s\n", debugstr_w(path));
if (set_prop)
@ -314,21 +322,37 @@ LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
}
else
{
if (f->SourceDefault && f->SourceDefault[0]!='.')
path = build_directory_name( 3, p, f->SourceDefault, NULL );
else
path = strdupW(p);
TRACE("source -> %s\n", debugstr_w(path));
/* source may be in a few different places ... check each of them */
path = NULL;
/* if the directory doesn't exist, use the root */
if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW( path ))
/* try the long path directory */
if (f->SourceLongPath)
{
msi_free( path );
path = get_source_root( package );
TRACE("defaulting to %s\n", debugstr_w(path));
path = build_directory_name( 3, p, f->SourceLongPath, NULL );
if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW( path ))
{
msi_free( path );
path = NULL;
}
}
else
f->ResolvedSource = strdupW( path );
/* try the short path directory */
if (!path && f->SourceShortPath)
{
path = build_directory_name( 3, p, f->SourceShortPath, NULL );
if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW( path ))
{
msi_free( path );
path = NULL;
}
}
/* try the root of the install */
if (!path)
path = get_source_root( package );
TRACE("source -> %s\n", debugstr_w(path));
f->ResolvedSource = strdupW( path );
}
msi_free(p);
}
@ -467,7 +491,8 @@ void ACTION_free_package_structures( MSIPACKAGE* package)
list_remove( &folder->entry );
msi_free( folder->Directory );
msi_free( folder->TargetDefault );
msi_free( folder->SourceDefault );
msi_free( folder->SourceLongPath );
msi_free( folder->SourceShortPath );
msi_free( folder->ResolvedTarget );
msi_free( folder->ResolvedSource );
msi_free( folder->Property );
@ -496,6 +521,7 @@ void ACTION_free_package_structures( MSIPACKAGE* package)
msi_free( file->File );
msi_free( file->FileName );
msi_free( file->ShortName );
msi_free( file->LongName );
msi_free( file->Version );
msi_free( file->Language );
msi_free( file->SourcePath );
@ -719,8 +745,6 @@ void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
WCHAR message[1024];
MSIRECORD * row = 0;
DWORD size;
static const WCHAR szActionData[] =
{'A','c','t','i','o','n','D','a','t','a',0};
if (!package->LastAction || strcmpW(package->LastAction,action))
{
@ -753,8 +777,6 @@ void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
ControlEvent_FireSubscribedEvent(package,szActionData, row);
msiobj_release(&row->hdr);
}
@ -803,49 +825,35 @@ void reduce_to_shortfilename(WCHAR* filename)
LPWSTR create_component_advertise_string(MSIPACKAGE* package,
MSICOMPONENT* component, LPCWSTR feature)
{
GUID clsid;
WCHAR productid_85[21];
WCHAR component_85[21];
/*
* I have a fair bit of confusion as to when a < is used and when a > is
* used. I do not think i have it right...
*
* Ok it appears that the > is used if there is a guid for the compoenent
* and the < is used if not.
*/
static WCHAR fmt1[] = {'%','s','%','s','<',0,0};
static WCHAR fmt2[] = {'%','s','%','s','>','%','s',0,0};
static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
WCHAR productid_85[21], component_85[21];
LPWSTR output = NULL;
DWORD sz = 0;
GUID clsid;
memset(productid_85,0,sizeof(productid_85));
memset(component_85,0,sizeof(component_85));
/* > is used if there is a component GUID and < if not. */
productid_85[0] = 0;
component_85[0] = 0;
CLSIDFromString(package->ProductCode, &clsid);
encode_base85_guid(&clsid,productid_85);
encode_base85_guid(&clsid, productid_85);
CLSIDFromString(component->ComponentId, &clsid);
encode_base85_guid(&clsid,component_85);
if (component)
{
CLSIDFromString(component->ComponentId, &clsid);
encode_base85_guid(&clsid, component_85);
}
TRACE("Doing something with this... %s %s %s\n",
debugstr_w(productid_85), debugstr_w(feature),
debugstr_w(component_85));
TRACE("prod=%s feat=%s comp=%s\n", debugstr_w(productid_85),
debugstr_w(feature), debugstr_w(component_85));
sz = lstrlenW(productid_85) + lstrlenW(feature);
if (component)
sz += lstrlenW(component_85);
sz = 20 + lstrlenW(feature) + 20 + 3;
sz+=3;
sz *= sizeof(WCHAR);
output = msi_alloc(sz);
memset(output,0,sz);
output = msi_alloc_zero(sz*sizeof(WCHAR));
if (component)
sprintfW(output,fmt2,productid_85,feature,component_85);
else
sprintfW(output,fmt1,productid_85,feature);
sprintfW(output, fmt, productid_85, feature,
component?'>':'<', component_85);
return output;
}

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
@ -214,8 +214,16 @@ static UINT INSERT_delete( struct tagMSIVIEW *view )
return ERROR_SUCCESS;
}
static UINT INSERT_find_matching_rows( struct tagMSIVIEW *view, UINT col,
UINT val, UINT *row, MSIITERHANDLE *handle )
{
TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
MSIVIEWOPS insert_ops =
return ERROR_FUNCTION_FAILED;
}
static const MSIVIEWOPS insert_ops =
{
INSERT_fetch_int,
NULL,
@ -226,7 +234,8 @@ MSIVIEWOPS insert_ops =
INSERT_get_dimensions,
INSERT_get_column_info,
INSERT_modify,
INSERT_delete
INSERT_delete,
INSERT_find_matching_rows
};
UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
/* Msi top level apis directly related to installs */
@ -29,9 +29,8 @@
#include "msi.h"
#include "msidefs.h"
#include "msipriv.h"
#include "winuser.h"
#include "wine/unicode.h"
#include "action.h"
#include "wine/unicode.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
@ -331,13 +330,14 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
LPWSTR path = NULL;
LPWSTR path2 = NULL;
MSIFOLDER *folder;
MSIFILE *file;
TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
TRACE("%p %s %s\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
attrib = GetFileAttributesW(szFolderPath);
/* native MSI tests writeability by making temporary files at each drive */
if ( attrib != INVALID_FILE_ATTRIBUTES &&
(!(attrib & FILE_ATTRIBUTE_DIRECTORY) ||
attrib & FILE_ATTRIBUTE_OFFLINE ||
(attrib & FILE_ATTRIBUTE_OFFLINE ||
attrib & FILE_ATTRIBUTE_READONLY))
return ERROR_FUNCTION_FAILED;
@ -345,16 +345,6 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
if (!path)
return ERROR_DIRECTORY;
if (attrib == INVALID_FILE_ATTRIBUTES)
{
if (!CreateDirectoryW(szFolderPath,NULL))
{
msi_free( path );
return ERROR_FUNCTION_FAILED;
}
RemoveDirectoryW(szFolderPath);
}
msi_free(folder->Property);
folder->Property = build_directory_name(2, szFolderPath, NULL);
@ -384,6 +374,21 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
path2 = resolve_folder(package, f->Directory, FALSE, TRUE, NULL);
msi_free(path2);
}
LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
{
MSICOMPONENT *comp = file->Component;
LPWSTR p;
if (!comp)
continue;
p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
msi_free(file->TargetPath);
file->TargetPath = build_directory_name(2, p, file->FileName);
msi_free(p);
}
}
msi_free(path);
@ -399,7 +404,7 @@ UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder,
MSIPACKAGE *package;
UINT ret;
TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
TRACE("%s %s\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
if ( !szFolder || !szFolderPath )
return ERROR_INVALID_PARAMETER;
@ -446,7 +451,6 @@ UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder,
* Not in the state: FALSE
*
*/
BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
{
BOOL r = FALSE;
@ -526,7 +530,7 @@ UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature,
UINT rc = ERROR_SUCCESS;
MSIFEATURE *feature, *child;
TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
TRACE("%s %i\n", debugstr_w(szFeature), iState);
feature = get_loaded_feature(package,szFeature);
if (!feature)
@ -560,7 +564,7 @@ UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
MSIPACKAGE* package;
UINT rc = ERROR_SUCCESS;
TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
TRACE("%s %i\n",debugstr_w(szFeature), iState);
package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
if (!package)
@ -619,8 +623,7 @@ UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPWSTR szFeature,
MSIPACKAGE* package;
UINT ret;
TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled,
piAction);
TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled, piAction);
package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
if (!package)
@ -747,7 +750,6 @@ LANGID WINAPI MsiGetLanguage(MSIHANDLE hInstall)
{
MSIPACKAGE* package;
LANGID langid;
LPWSTR buffer;
static const WCHAR szProductLanguage[] =
{'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
@ -755,10 +757,51 @@ LANGID WINAPI MsiGetLanguage(MSIHANDLE hInstall)
if (!package)
return ERROR_INVALID_HANDLE;
buffer = msi_dup_property( package, szProductLanguage );
langid = atoiW(buffer);
msi_free(buffer);
msiobj_release (&package->hdr);
langid = msi_get_property_int( package, szProductLanguage, 0 );
msiobj_release( &package->hdr );
return langid;
}
UINT MSI_SetInstallLevel( MSIPACKAGE *package, int iInstallLevel )
{
static const WCHAR szInstallLevel[] = {
'I','N','S','T','A','L','L','L','E','V','E','L',0 };
static const WCHAR fmt[] = { '%','d',0 };
WCHAR level[6];
UINT r;
TRACE("%p %i\n", package, iInstallLevel);
if (iInstallLevel<1 || iInstallLevel>32767)
return ERROR_INVALID_PARAMETER;
sprintfW( level, fmt, iInstallLevel );
r = MSI_SetPropertyW( package, szInstallLevel, level );
if ( r == ERROR_SUCCESS )
{
r = MSI_SetFeatureStates( package );
}
return r;
}
/***********************************************************************
* MsiSetInstallLevel (MSI.@)
*/
UINT WINAPI MsiSetInstallLevel(MSIHANDLE hInstall, int iInstallLevel)
{
MSIPACKAGE* package;
UINT r;
TRACE("%ld %i\n", hInstall, iInstallLevel);
package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
if ( !package )
return ERROR_INVALID_HANDLE;
r = MSI_SetInstallLevel( package, iInstallLevel );
msiobj_release( &package->hdr );
return r;
}

View file

@ -0,0 +1,472 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2006 Mike McCormack for CodeWeavers
*
* 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 tagMSIJOINVIEW
{
MSIVIEW view;
MSIDATABASE *db;
MSIVIEW *left, *right;
UINT left_count, right_count;
UINT left_key, right_key;
UINT *pairs;
UINT pair_count;
} MSIJOINVIEW;
static UINT JOIN_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
{
MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
MSIVIEW *table;
TRACE("%p %d %d %p\n", jv, row, col, val );
if( !jv->left || !jv->right )
return ERROR_FUNCTION_FAILED;
if( (col==0) || (col>(jv->left_count + jv->right_count)) )
return ERROR_FUNCTION_FAILED;
if( row >= jv->pair_count )
return ERROR_FUNCTION_FAILED;
if( col <= jv->left_count )
{
table = jv->left;
row = jv->pairs[ row*2 ];
}
else
{
table = jv->right;
row = jv->pairs[ row*2 + 1 ];
col -= jv->left_count;
}
return table->ops->fetch_int( table, row, col, val );
}
static UINT JOIN_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm)
{
MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
MSIVIEW *table;
TRACE("%p %d %d %p\n", jv, row, col, stm );
if( !jv->left || !jv->right )
return ERROR_FUNCTION_FAILED;
if( (col==0) || (col>(jv->left_count + jv->right_count)) )
return ERROR_FUNCTION_FAILED;
if( row <= jv->left_count )
{
table = jv->left;
row = jv->pairs[ row*2 ];
}
else
{
table = jv->right;
row = jv->pairs[ row*2 + 1 ];
col -= jv->left_count;
}
return table->ops->fetch_stream( table, row, col, stm );
}
static UINT JOIN_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val )
{
MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
TRACE("%p %d %d %04x\n", jv, row, col, val );
return ERROR_FUNCTION_FAILED;
}
static UINT JOIN_insert_row( struct tagMSIVIEW *view, MSIRECORD *record )
{
MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
TRACE("%p %p\n", jv, record );
return ERROR_FUNCTION_FAILED;
}
static int join_key_compare(const void *l, const void *r)
{
const UINT *left = l, *right = r;
if (left[1] < right[1])
return -1;
if (left[1] == right[1])
return 0;
return 1;
}
static UINT join_load_key_column( MSIJOINVIEW *jv, MSIVIEW *table, UINT column,
UINT **pdata, UINT *pcount )
{
UINT r, i, count = 0, *data = NULL;
r = table->ops->get_dimensions( table, &count, NULL );
if( r != ERROR_SUCCESS )
return r;
if (!count)
goto end;
data = msi_alloc( count * 2 * sizeof (UINT) );
if (!data)
return ERROR_SUCCESS;
for (i=0; i<count; i++)
{
data[i*2] = i;
r = table->ops->fetch_int( table, i, column, &data[i*2+1] );
if (r != ERROR_SUCCESS)
ERR("fetch data (%u,%u) failed\n", i, column);
}
qsort( data, count, 2 * sizeof (UINT), join_key_compare );
end:
*pdata = data;
*pcount = count;
return ERROR_SUCCESS;
}
static UINT join_match( UINT *ldata, UINT lcount,
UINT *rdata, UINT rcount,
UINT **ppairs, UINT *ppair_count )
{
UINT *pairs;
UINT n, i, j;
TRACE("left %u right %u\n", rcount, lcount);
/* there can be at most max(lcount, rcount) matches */
if (lcount > rcount)
n = lcount;
else
n = rcount;
pairs = msi_alloc( n * 2 * sizeof(UINT) );
if (!pairs)
return ERROR_OUTOFMEMORY;
for (n=0, i=0, j=0; i<lcount && j<rcount; )
{
/* values match... store the row numbers */
if (ldata[i*2+1] == rdata[j*2+1])
{
pairs[n*2] = ldata[i*2];
pairs[n*2+1] = rdata[j*2];
i++; /* FIXME: assumes primary key on the right */
n++;
continue;
}
/* values differ... move along */
if (ldata[i*2+1] < rdata[j*2+1])
i++;
else
j++;
}
*ppairs = pairs;
*ppair_count = n;
return ERROR_SUCCESS;
}
static UINT JOIN_execute( struct tagMSIVIEW *view, MSIRECORD *record )
{
MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
UINT r, *ldata = NULL, *rdata = NULL, lcount = 0, rcount = 0;
TRACE("%p %p\n", jv, record);
if( !jv->left || !jv->right )
return ERROR_FUNCTION_FAILED;
r = jv->left->ops->execute( jv->left, NULL );
if (r != ERROR_SUCCESS)
return r;
r = jv->right->ops->execute( jv->right, NULL );
if (r != ERROR_SUCCESS)
return r;
r = join_load_key_column( jv, jv->left, jv->left_key, &ldata, &lcount );
if (r != ERROR_SUCCESS)
return r;
r = join_load_key_column( jv, jv->right, jv->right_key, &rdata, &rcount );
if (r != ERROR_SUCCESS)
goto end;
r = join_match( ldata, lcount, rdata, rcount, &jv->pairs, &jv->pair_count );
end:
msi_free( ldata );
msi_free( rdata );
return r;
}
static UINT JOIN_close( struct tagMSIVIEW *view )
{
MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
TRACE("%p\n", jv );
if( !jv->left || !jv->right )
return ERROR_FUNCTION_FAILED;
jv->left->ops->close( jv->left );
jv->right->ops->close( jv->right );
return ERROR_SUCCESS;
}
static UINT JOIN_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
{
MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
TRACE("%p %p %p\n", jv, rows, cols );
if( cols )
*cols = jv->left_count + jv->right_count;
if( rows )
{
if( !jv->left || !jv->right )
return ERROR_FUNCTION_FAILED;
*rows = jv->pair_count;
}
return ERROR_SUCCESS;
}
static UINT JOIN_get_column_info( struct tagMSIVIEW *view,
UINT n, LPWSTR *name, UINT *type )
{
MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
TRACE("%p %d %p %p\n", jv, n, name, type );
if( !jv->left || !jv->right )
return ERROR_FUNCTION_FAILED;
if( (n==0) || (n>(jv->left_count + jv->right_count)) )
return ERROR_FUNCTION_FAILED;
if( n <= jv->left_count )
return jv->left->ops->get_column_info( jv->left, n, name, type );
n = n - jv->left_count;
return jv->right->ops->get_column_info( jv->right, n, name, type );
}
static UINT JOIN_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
MSIRECORD *rec )
{
MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
TRACE("%p %d %p\n", jv, eModifyMode, rec );
return ERROR_FUNCTION_FAILED;
}
static UINT JOIN_delete( struct tagMSIVIEW *view )
{
MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
TRACE("%p\n", jv );
if( jv->left )
jv->left->ops->delete( jv->left );
jv->left = NULL;
if( jv->right )
jv->right->ops->delete( jv->right );
jv->right = NULL;
msi_free( jv->pairs );
jv->pairs = NULL;
return ERROR_SUCCESS;
}
static UINT JOIN_find_matching_rows( struct tagMSIVIEW *view, UINT col,
UINT val, UINT *row, MSIITERHANDLE *handle )
{
MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
FIXME("%p, %d, %u, %p\n", jv, col, val, *handle);
return ERROR_FUNCTION_FAILED;
}
static const MSIVIEWOPS join_ops =
{
JOIN_fetch_int,
JOIN_fetch_stream,
JOIN_set_int,
JOIN_insert_row,
JOIN_execute,
JOIN_close,
JOIN_get_dimensions,
JOIN_get_column_info,
JOIN_modify,
JOIN_delete,
JOIN_find_matching_rows
};
/*
* join_check_condition
*
* This is probably overly strict about what kind of condition we need
* for a join query.
*/
static UINT join_check_condition(MSIJOINVIEW *jv, struct expr *cond)
{
UINT r, type = 0;
/* assume that we have `KeyColumn` = `SubkeyColumn` */
if ( cond->type != EXPR_COMPLEX )
return ERROR_FUNCTION_FAILED;
if ( cond->u.expr.op != OP_EQ )
return ERROR_FUNCTION_FAILED;
if ( cond->u.expr.left->type != EXPR_COLUMN )
return ERROR_FUNCTION_FAILED;
if ( cond->u.expr.right->type != EXPR_COLUMN )
return ERROR_FUNCTION_FAILED;
/* make sure both columns exist */
r = VIEW_find_column( jv->left, cond->u.expr.left->u.column, &jv->left_key );
if (r != ERROR_SUCCESS)
return ERROR_FUNCTION_FAILED;
r = VIEW_find_column( jv->right, cond->u.expr.right->u.column, &jv->right_key );
if (r != ERROR_SUCCESS)
return ERROR_FUNCTION_FAILED;
/* make sure both columns are keys */
r = jv->left->ops->get_column_info( jv->left, jv->left_key, NULL, &type );
if (r != ERROR_SUCCESS)
return ERROR_FUNCTION_FAILED;
if (!(type & MSITYPE_KEY))
return ERROR_FUNCTION_FAILED;
r = jv->right->ops->get_column_info( jv->right, jv->right_key, NULL, &type );
if (r != ERROR_SUCCESS)
return ERROR_FUNCTION_FAILED;
if (!(type & MSITYPE_KEY))
return ERROR_FUNCTION_FAILED;
TRACE("left %s (%u) right %s (%u)\n",
debugstr_w(cond->u.expr.left->u.column), jv->left_key,
debugstr_w(cond->u.expr.right->u.column), jv->right_key);
return ERROR_SUCCESS;
}
UINT JOIN_CreateView( MSIDATABASE *db, MSIVIEW **view,
LPCWSTR left, LPCWSTR right,
struct expr *cond )
{
MSIJOINVIEW *jv = NULL;
UINT r = ERROR_SUCCESS;
TRACE("%p (%s,%s)\n", jv, debugstr_w(left), debugstr_w(right) );
jv = msi_alloc_zero( sizeof *jv );
if( !jv )
return ERROR_FUNCTION_FAILED;
/* fill the structure */
jv->view.ops = &join_ops;
jv->db = db;
/* create the tables to join */
r = TABLE_CreateView( db, left, &jv->left );
if( r != ERROR_SUCCESS )
{
ERR("can't create left table\n");
goto end;
}
r = TABLE_CreateView( db, right, &jv->right );
if( r != ERROR_SUCCESS )
{
ERR("can't create right table\n");
goto end;
}
/* get the number of columns in each table */
r = jv->left->ops->get_dimensions( jv->left, NULL, &jv->left_count );
if( r != ERROR_SUCCESS )
{
ERR("can't get left table dimensions\n");
goto end;
}
r = jv->right->ops->get_dimensions( jv->right, NULL, &jv->right_count );
if( r != ERROR_SUCCESS )
{
ERR("can't get right table dimensions\n");
goto end;
}
r = join_check_condition( jv, cond );
if( r != ERROR_SUCCESS )
{
ERR("can't get join condition\n");
goto end;
}
*view = &jv->view;
return ERROR_SUCCESS;
end:
jv->view.ops->delete( &jv->view );
return r;
}

File diff suppressed because it is too large Load diff

View file

@ -19,9 +19,12 @@
<library>shlwapi</library>
<library>winmm</library>
<library>cabinet</library>
<library>comctl32</library>
<library>ole32</library>
<library>oleaut32</library>
<library>version</library>
<library>wininet</library>
<library>urlmon</library>
<file>action.c</file>
<file>appsearch.c</file>
<file>classes.c</file>
@ -39,7 +42,9 @@
<file>helpers.c</file>
<file>insert.c</file>
<file>install.c</file>
<file>join.c</file>
<file>msi.c</file>
<file>msi_main.c</file>
<file>msiquery.c</file>
<file>order.c</file>
<file>package.c</file>

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "windef.h"
@ -30,13 +30,102 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
#include "msi_Bg.rc"
#include "msi_De.rc"
#include "msi_En.rc"
#include "msi_Ja.rc"
#include "msi_Eo.rc"
#include "msi_Es.rc"
#include "msi_Fi.rc"
#include "msi_Fr.rc"
#include "msi_Hu.rc"
#include "msi_It.rc"
#include "msi_Ko.rc"
#include "msi_Nl.rc"
#include "msi_No.rc"
#include "msi_Pt.rc"
#include "msi_Ru.rc"
#include "msi_Hu.rc"
#include "msi_Tr.rc"
/* BINRES instadvert.bmp */
0x1001 BITMAP instadvert.bmp
/* {
'42 4D 76 01 00 00 00 00 00 00 76 00 00 00 28 00'
'00 00 20 00 00 00 10 00 00 00 01 00 04 00 00 00'
'00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80'
'00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80'
'00 00 C0 C0 C0 00 80 80 80 00 00 00 FF 00 00 FF'
'00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF'
'00 00 FF FF FF 00 77 77 77 77 77 77 77 77 77 77'
'77 77 77 77 77 77 77 77 77 77 77 77 77 77 77 77'
'77 77 77 77 77 77 77 77 70 00 00 07 77 77 77 77'
'77 77 77 77 77 77 77 70 03 33 B3 30 07 77 77 77'
'77 77 77 77 77 77 77 00 B3 33 33 33 00 77 77 77'
'77 77 77 77 77 77 77 03 33 B3 A3 B3 30 77 77 77'
'77 77 07 77 77 77 70 33 33 33 33 33 B3 07 77 77'
'77 70 00 77 77 77 70 33 B3 30 03 33 33 07 77 77'
'77 00 00 07 77 77 70 33 33 00 00 3B 33 07 77 77'
'70 00 00 00 77 77 70 33 B3 30 0B 33 3B 07 77 77'
'00 00 00 00 07 77 70 3B 3A 33 33 33 33 07 77 70'
'00 00 00 00 00 77 77 03 3B 3B 3A 3B 30 77 77 77'
'77 77 77 77 77 77 77 00 33 33 3B 33 00 77 77 77'
'77 77 77 77 77 77 77 70 03 B3 33 30 07 77 77 77'
'77 77 77 77 77 77 77 77 70 00 00 07 77 77 77 77'
'77 77 77 77 77 77 77 77 77 77 77 77 77 77 77 77'
'77 77 77 77 77 77'
} */
/* BINRES instabsent.bmp */
0x1002 BITMAP instabsent.bmp
/* {
'42 4D 76 01 00 00 00 00 00 00 76 00 00 00 28 00'
'00 00 20 00 00 00 10 00 00 00 01 00 04 00 00 00'
'00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80'
'00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80'
'00 00 C0 C0 C0 00 80 80 80 00 00 00 FF 00 00 FF'
'00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF'
'00 00 FF FF FF 00 77 77 77 77 77 77 77 77 77 77'
'77 77 77 77 77 77 70 07 77 77 77 77 70 07 77 77'
'77 77 77 77 77 77 70 00 77 77 77 77 00 07 77 77'
'77 77 77 77 77 77 77 00 07 77 77 70 00 77 77 77'
'77 77 77 77 77 77 77 70 00 77 77 00 07 77 77 77'
'77 77 77 77 77 77 77 77 00 07 70 00 77 77 77 77'
'77 77 07 77 77 77 77 77 70 00 00 07 77 77 77 77'
'77 70 00 77 77 77 77 77 77 00 00 77 77 77 77 77'
'77 00 00 07 77 77 77 77 77 00 00 77 77 77 77 77'
'70 00 00 00 77 77 77 77 70 00 00 07 77 77 77 77'
'00 00 00 00 07 77 77 77 00 07 70 00 77 77 77 70'
'00 00 00 00 00 77 77 70 00 77 77 00 07 77 77 77'
'77 77 77 77 77 77 77 00 07 77 77 70 00 77 77 77'
'77 77 77 77 77 77 70 00 77 77 77 77 00 07 77 77'
'77 77 77 77 77 77 70 07 77 77 77 77 70 07 77 77'
'77 77 77 77 77 77 77 77 77 77 77 77 77 77 77 77'
'77 77 77 77 77 77'
} */
/* BINRES instlocal.bmp */
0x1003 BITMAP instlocal.bmp
/* {
'42 4D 76 01 00 00 00 00 00 00 76 00 00 00 28 00'
'00 00 20 00 00 00 10 00 00 00 01 00 04 00 00 00'
'00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80'
'00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80'
'00 00 C0 C0 C0 00 80 80 80 00 00 00 FF 00 00 FF'
'00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF'
'00 00 FF FF FF 00 77 77 77 77 77 77 77 77 77 77'
'77 77 77 77 77 77 77 77 77 77 77 77 77 77 77 77'
'77 77 77 77 77 77 77 77 77 77 77 77 77 77 77 77'
'77 77 77 77 77 77 77 77 70 07 77 77 77 77 77 77'
'77 77 77 77 77 77 77 77 0F F0 77 77 77 77 77 77'
'77 77 77 77 77 77 77 70 FF FF 07 77 77 77 77 77'
'77 77 07 77 77 77 77 0F F0 0F F0 77 77 77 77 77'
'77 70 00 77 77 77 77 0F 07 70 FF 07 77 77 77 77'
'77 00 00 07 77 77 77 70 77 77 0F F0 77 77 77 77'
'70 00 00 00 77 77 77 77 77 77 70 FF 07 77 77 77'
'00 00 00 00 07 77 77 77 77 77 77 0F F0 77 77 70'
'00 00 00 00 00 77 77 77 77 77 77 70 FF 07 77 77'
'77 77 77 77 77 77 77 77 77 77 77 77 0F F0 77 77'
'77 77 77 77 77 77 77 77 77 77 77 77 70 F0 77 77'
'77 77 77 77 77 77 77 77 77 77 77 77 77 07 77 77'
'77 77 77 77 77 77 77 77 77 77 77 77 77 77 77 77'
'77 77 77 77 77 77'
} */

View file

@ -45,7 +45,7 @@
49 stdcall MsiGetActiveDatabase(long)
50 stdcall MsiGetComponentStateA(long str ptr ptr)
51 stdcall MsiGetComponentStateW(long wstr ptr ptr)
52 stub MsiGetDatabaseState
52 stdcall MsiGetDatabaseState(long)
53 stub MsiGetFeatureCostA
54 stub MsiGetFeatureCostW
55 stub MsiGetFeatureInfoA
@ -133,7 +133,7 @@
137 stdcall MsiSetExternalUIW(ptr long ptr)
138 stdcall MsiSetFeatureStateA(long str long)
139 stdcall MsiSetFeatureStateW(long wstr long)
140 stub MsiSetInstallLevel
140 stdcall MsiSetInstallLevel(long long)
141 stdcall MsiSetInternalUI(long ptr)
142 stub MsiVerifyDiskSpace
143 stdcall MsiSetMode(long long long)
@ -195,16 +195,16 @@
199 stdcall MsiMessageBoxW(long long long long long long)
200 stdcall MsiDecomposeDescriptorA(str ptr ptr ptr ptr)
201 stdcall MsiDecomposeDescriptorW(wstr ptr ptr ptr ptr)
202 stub MsiProvideQualifiedComponentExA
202 stdcall MsiProvideQualifiedComponentExA(str str long str long long ptr ptr)
203 stdcall MsiProvideQualifiedComponentExW(wstr wstr long wstr long long ptr ptr)
204 stdcall MsiEnumRelatedProductsA(str long long ptr)
205 stdcall MsiEnumRelatedProductsW(wstr long long ptr)
206 stub MsiSetFeatureAttributesA
207 stub MsiSetFeatureAttributesW
208 stub MsiSourceListClearAllA
209 stub MsiSourceListClearAllW
210 stub MsiSourceListAddSourceA
211 stub MsiSourceListAddSourceW
208 stdcall MsiSourceListClearAllA(str str long)
209 stdcall MsiSourceListClearAllW(wstr wstr long)
210 stdcall MsiSourceListAddSourceA(str str long str)
211 stdcall MsiSourceListAddSourceW(wstr wstr long wstr)
212 stub MsiSourceListForceResolutionA
213 stub MsiSourceListForceResolutionW
214 stub MsiIsProductElevatedA

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
LANGUAGE LANG_BULGARIAN, SUBLANG_DEFAULT

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
LANGUAGE LANG_GERMAN, SUBLANG_DEFAULT

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT

View file

@ -0,0 +1,33 @@
/*
* Esperanto resources for MSI
*
* Copyright 2006 Antonio Codazzi
*
* 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
*/
LANGUAGE LANG_ESPERANTO, SUBLANG_DEFAULT
STRINGTABLE DISCARDABLE
{
5 "Mi ne trovis la vojon %s"
9 "enþovu la diskon %s"
10 "nekorektaj parametroj"
11 "enigu la nomon de dosierujo kiu enhavas %s"
12 "instalad-fonto por mankanta taýgeco"
13 "retdrajvo por mankanta taýgeco"
14 "taýgeco el:"
15 "elektu la dosierujo kiu enhavas %s"
}

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
LANGUAGE LANG_FINNISH, SUBLANG_DEFAULT

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL

View file

@ -1,34 +1,33 @@
/*
* Hungarian resources for MSI
*
* Copyright 2005 Mike McCormack
* Copyright 2005 Gergely Risko
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
LANGUAGE LANG_HUNGARIAN, SUBLANG_NEUTRAL
STRINGTABLE DISCARDABLE
{
5 "Az elérési út: %s nem található"
9 "Tedd be a következõ lemezt: %s"
10 "Rossz paraméterek"
11 "Add meg melyik mappa tartalmazza a következõt: %s"
12 "Az összetevõ forrása hiányzik"
13 "Hiányzik a hálózati meghajtó az össszetevõhöz"
/* NOT TRANSLATED */ 14 "feature from:"
15 "Válaszd ki melyik mappa tartalmazza a következõt: %s"
}
/*
* Hungarian resources for MSI
*
* Copyright 2006 Andras Kovacs
*
* 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
*/
LANGUAGE LANG_HUNGARIAN, SUBLANG_DEFAULT
STRINGTABLE DISCARDABLE
{
5 "%s útvonal nem található"
9 "helyezze be a lemezt: %s"
10 "rossz paraméterek"
11 "adja meg melyik mappa tartalmazza ezt: %s"
12 "hiányzó tulajdonság a telepítési forráshoz"
13 "hiányzó tulajdonság a hálózati meghajtóhoz"
14 "tulajdonság innen:"
15 "válassza ki, melyik mappa tartalmazza ezt: %s"
}

View file

@ -0,0 +1,33 @@
/*
* Italian resources for MSI
*
* Copyright 2006 Antonio Codazzi
*
* 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
*/
LANGUAGE LANG_ITALIAN, SUBLANG_DEFAULT
STRINGTABLE DISCARDABLE
{
5 "percorso %s non trovato"
9 "inserire disco %s"
10 "parametri incorretti"
11 "immettere il nome della cartella che contiene %s"
12 "sorgente di installazione per la funzionalità mancante"
13 "periferica di rete per la funzionalità mancante"
14 "funzionalità da:"
15 "selezionare la cartella che contiene %s"
}

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
LANGUAGE LANG_DUTCH, SUBLANG_DEFAULT

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
LANGUAGE LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
LANGUAGE LANG_PORTUGUESE, SUBLANG_DEFAULT

View file

@ -1,8 +1,7 @@
/*
* Russian resources for MSI
*
* Copyright 2005 Mikhail Y. Zvyozdochkin
* Aleksey Bragin
* Copyright 2006 Vitaly Lipatov
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -16,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
@ -26,9 +25,9 @@ STRINGTABLE DISCARDABLE
5 "ïóòü %s íå íàéäåí"
9 "âñòàâüòå äèñê %s"
10 "íåâåðíûå ïàðàìåòðû"
11 "введите, какая папка содержит %s"
12 "недоступен источник установки (съемный или компакт-диск не вставлен в дисковод)"
13 "недоступен сетевой диск, содержащий необходимый файл"
14 "функциональность из:"
15 "выберите, какая папка содержит %s"
11 "укажите каталог, содержащий %s"
12 "источник установки данной возможности не указан"
13 "сетевой диск для данной возможности не указан"
14 "возможность из:"
15 "выберите каталог, содержащий %s"
}

View file

@ -0,0 +1,33 @@
/*
* Turkish resources for MSI
*
* Copyright 2006 Fatih Aþýcý
*
* 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
*/
LANGUAGE LANG_TURKISH, SUBLANG_DEFAULT
STRINGTABLE DISCARDABLE
{
5 "%s yolu bulunamadý"
9 "%s nolu diski yerleþtirin"
10 "bozuk parametreler"
11 "%s öðesini içeren dizini girin"
12 "eksik özellik için kurulum kaynaðý"
13 "eksik özellik için að sürücüsü"
14 "özellik buradan:"
15 "%s öðesini içeren dizini seçin"
}

View file

@ -0,0 +1,180 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2006 Mike McCormack for CodeWeavers
*
* 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>
#define COBJMACROS
#define NONAMELESSUNION
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "shlwapi.h"
#include "msipriv.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
static LONG dll_count;
/* the UI level */
INSTALLUILEVEL gUILevel = INSTALLUILEVEL_BASIC;
HWND gUIhwnd = 0;
INSTALLUI_HANDLERA gUIHandlerA = NULL;
INSTALLUI_HANDLERW gUIHandlerW = NULL;
DWORD gUIFilter = 0;
LPVOID gUIContext = NULL;
WCHAR gszLogFile[MAX_PATH];
HINSTANCE msi_hInstance;
/*
* Dll lifetime tracking declaration
*/
static void LockModule(void)
{
InterlockedIncrement(&dll_count);
}
static void UnlockModule(void)
{
InterlockedDecrement(&dll_count);
}
/******************************************************************
* DllMain
*/
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
msi_hInstance = hinstDLL;
DisableThreadLibraryCalls(hinstDLL);
msi_dialog_register_class();
break;
case DLL_PROCESS_DETACH:
msi_dialog_unregister_class();
break;
}
return TRUE;
}
typedef struct tagIClassFactoryImpl
{
const IClassFactoryVtbl *lpVtbl;
} IClassFactoryImpl;
static HRESULT WINAPI MsiCF_QueryInterface(LPCLASSFACTORY iface,
REFIID riid,LPVOID *ppobj)
{
IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
FIXME("%p %s %p\n",This,debugstr_guid(riid),ppobj);
return E_NOINTERFACE;
}
static ULONG WINAPI MsiCF_AddRef(LPCLASSFACTORY iface)
{
LockModule();
return 2;
}
static ULONG WINAPI MsiCF_Release(LPCLASSFACTORY iface)
{
UnlockModule();
return 1;
}
static HRESULT WINAPI MsiCF_CreateInstance(LPCLASSFACTORY iface,
LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj)
{
IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
FIXME("%p %p %s %p\n", This, pOuter, debugstr_guid(riid), ppobj);
return E_FAIL;
}
static HRESULT WINAPI MsiCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
{
TRACE("%p %d\n", iface, dolock);
if (dolock)
LockModule();
else
UnlockModule();
return S_OK;
}
static const IClassFactoryVtbl MsiCF_Vtbl =
{
MsiCF_QueryInterface,
MsiCF_AddRef,
MsiCF_Release,
MsiCF_CreateInstance,
MsiCF_LockServer
};
static IClassFactoryImpl Msi_CF = { &MsiCF_Vtbl };
/******************************************************************
* DllGetClassObject [MSI.@]
*/
HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
{
TRACE("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
if( IsEqualCLSID (rclsid, &CLSID_IMsiServer) ||
IsEqualCLSID (rclsid, &CLSID_IMsiServerMessage) ||
IsEqualCLSID (rclsid, &CLSID_IMsiServerX1) ||
IsEqualCLSID (rclsid, &CLSID_IMsiServerX2) ||
IsEqualCLSID (rclsid, &CLSID_IMsiServerX3) )
{
*ppv = (LPVOID) &Msi_CF;
return S_OK;
}
return CLASS_E_CLASSNOTAVAILABLE;
}
/******************************************************************
* DllGetVersion [MSI.@]
*/
HRESULT WINAPI DllGetVersion(DLLVERSIONINFO *pdvi)
{
TRACE("%p\n",pdvi);
if (pdvi->cbSize != sizeof(DLLVERSIONINFO))
return E_INVALIDARG;
pdvi->dwMajorVersion = MSI_MAJORVERSION;
pdvi->dwMinorVersion = MSI_MINORVERSION;
pdvi->dwBuildNumber = MSI_BUILDNUMBER;
pdvi->dwPlatformID = 1;
return S_OK;
}
/******************************************************************
* DllCanUnloadNow [MSI.@]
*/
HRESULT WINAPI DllCanUnloadNow(void)
{
return dll_count == 0 ? S_OK : S_FALSE;
}

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef __WINE_MSI_PRIVATE__
@ -100,6 +100,8 @@ typedef struct tagMSIRECORD
MSIFIELD fields[1]; /* nb. array size is count+1 */
} MSIRECORD;
typedef void *MSIITERHANDLE;
typedef struct tagMSIVIEWOPS
{
/*
@ -114,7 +116,7 @@ typedef struct tagMSIVIEWOPS
UINT (*fetch_int)( struct tagMSIVIEW *, UINT row, UINT col, UINT *val );
/*
* fetch_int - reads one integer from {row,col} in the table
* fetch_stream - gets a stream from {row,col} in the table
*
* This function is similar to fetch_int, except fetches a
* stream instead of an integer.
@ -170,12 +172,24 @@ typedef struct tagMSIVIEWOPS
*/
UINT (*delete)( struct tagMSIVIEW * );
/*
* find_matching_rows - iterates through rows that match a value
*
* If the column type is a string then a string ID should be passed in.
* If the value to be looked up is an integer then no transformation of
* the input value is required, except if the column is a string, in which
* case a string ID should be passed in.
* The handle is an input/output parameter that keeps track of the current
* position in the iteration. It must be initialised to zero before the
* first call and continued to be passed in to subsequent calls.
*/
UINT (*find_matching_rows)( struct tagMSIVIEW *, UINT col, UINT val, UINT *row, MSIITERHANDLE *handle );
} MSIVIEWOPS;
struct tagMSIVIEW
{
MSIOBJECTHDR hdr;
MSIVIEWOPS *ops;
const MSIVIEWOPS *ops;
};
struct msi_dialog_tag;
@ -325,6 +339,7 @@ extern UINT MSI_InstallPackage( MSIPACKAGE *, LPCWSTR, LPCWSTR );
extern void ACTION_free_package_structures( MSIPACKAGE* );
extern UINT ACTION_DialogBox( MSIPACKAGE*, LPCWSTR);
extern UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode );
extern UINT MSI_SetFeatureStates( MSIPACKAGE *package );
/* record internals */
extern UINT MSI_RecordSetIStream( MSIRECORD *, unsigned int, IStream *);
@ -366,6 +381,9 @@ extern UINT MSI_ViewExecute( MSIQUERY*, MSIRECORD * );
extern UINT MSI_ViewFetch( MSIQUERY*, MSIRECORD ** );
extern UINT MSI_ViewClose( MSIQUERY* );
/* install internals */
extern UINT MSI_SetInstallLevel( MSIPACKAGE *package, int iInstallLevel );
/* package internals */
extern MSIPACKAGE *MSI_CreatePackage( MSIDATABASE * );
extern UINT MSI_OpenPackageW( LPCWSTR szPackage, MSIPACKAGE ** );
@ -401,9 +419,16 @@ extern UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL cr
extern UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
extern UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
extern LPWSTR msi_reg_get_val_str( HKEY hkey, LPCWSTR name );
extern BOOL msi_reg_get_val_dword( HKEY hkey, LPCWSTR name, DWORD *val);
extern DWORD msi_version_str_to_dword(LPCWSTR p);
extern LPWSTR msi_version_dword_to_str(DWORD version);
extern LONG msi_reg_set_val_str( HKEY hkey, LPCWSTR name, LPCWSTR value );
extern LONG msi_reg_set_val_multi_str( HKEY hkey, LPCWSTR name, LPCWSTR value );
extern LONG msi_reg_set_val_dword( HKEY hkey, LPCWSTR name, DWORD val );
extern LONG msi_reg_set_subkey_val( HKEY hkey, LPCWSTR path, LPCWSTR name, LPCWSTR val );
/* msi dialog interface */
typedef UINT (*msi_dialog_event_handler)( MSIPACKAGE*, LPCWSTR, LPCWSTR, msi_dialog* );
@ -441,6 +466,7 @@ extern INSTALLUI_HANDLERW gUIHandlerW;
extern DWORD gUIFilter;
extern LPVOID gUIContext;
extern WCHAR gszLogFile[MAX_PATH];
extern HINSTANCE msi_hInstance;
/* memory allocation macro functions */
static inline void *msi_alloc( size_t len )

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
@ -354,6 +354,10 @@ UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record)
TRACE("%ld %p\n", hView, record);
if( !record )
return ERROR_INVALID_PARAMETER;
*record = 0;
query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
if( !query )
return ERROR_INVALID_HANDLE;
@ -853,16 +857,29 @@ UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb,
return r;
}
UINT WINAPI MsiDatabaseIsTablePersistentA(
MSICONDITION WINAPI MsiDatabaseIsTablePersistentA(
MSIHANDLE hDatabase, LPSTR szTableName)
{
FIXME("%lx %s\n", hDatabase, debugstr_a(szTableName));
return ERROR_CALL_NOT_IMPLEMENTED;
LPWSTR szwTableName = NULL;
MSICONDITION r;
TRACE("%lx %s\n", hDatabase, debugstr_a(szTableName));
if( szTableName )
{
szwTableName = strdupAtoW( szTableName );
if( !szwTableName )
return MSICONDITION_ERROR;
}
r = MsiDatabaseIsTablePersistentW( hDatabase, szwTableName );
msi_free( szwTableName );
return r;
}
UINT WINAPI MsiDatabaseIsTablePersistentW(
MSICONDITION WINAPI MsiDatabaseIsTablePersistentW(
MSIHANDLE hDatabase, LPWSTR szTableName)
{
FIXME("%lx %s\n", hDatabase, debugstr_w(szTableName));
return ERROR_CALL_NOT_IMPLEMENTED;
return MSICONDITION_FALSE;
}

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
@ -249,8 +249,26 @@ static UINT ORDER_delete( struct tagMSIVIEW *view )
return ERROR_SUCCESS;
}
static UINT ORDER_find_matching_rows( struct tagMSIVIEW *view, UINT col,
UINT val, UINT *row, MSIITERHANDLE *handle )
{
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
UINT r;
MSIVIEWOPS order_ops =
TRACE("%p, %d, %u, %p\n", ov, col, val, *handle);
if( !ov->table )
return ERROR_FUNCTION_FAILED;
r = ov->table->ops->find_matching_rows( ov->table, col, val, row, handle );
*row = ov->reorder[ *row ];
return r;
}
static const MSIVIEWOPS order_ops =
{
ORDER_fetch_int,
NULL,
@ -261,7 +279,8 @@ MSIVIEWOPS order_ops =
ORDER_get_dimensions,
ORDER_get_column_info,
ORDER_modify,
ORDER_delete
ORDER_delete,
ORDER_find_matching_rows
};
static UINT ORDER_AddColumn( MSIORDERVIEW *ov, LPCWSTR name )

View file

@ -15,10 +15,11 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include <stdarg.h>
#include <stdio.h>
@ -34,6 +35,8 @@
#include "objidl.h"
#include "wincrypt.h"
#include "winuser.h"
#include "wininet.h"
#include "urlmon.h"
#include "shlobj.h"
#include "wine/unicode.h"
#include "objbase.h"
@ -443,7 +446,7 @@ static LPCWSTR copy_package_to_temp( LPCWSTR szPackage, LPWSTR filename )
if( !CopyFileW( szPackage, filename, FALSE ) )
{
ERR("failed to copy package to temp path %s\n", debugstr_w(filename) );
ERR("failed to copy package %s\n", debugstr_w(szPackage) );
return szPackage;
}
@ -451,6 +454,38 @@ static LPCWSTR copy_package_to_temp( LPCWSTR szPackage, LPWSTR filename )
return filename;
}
static LPCWSTR msi_download_package( LPCWSTR szUrl, LPWSTR filename )
{
LPINTERNET_CACHE_ENTRY_INFOW cache_entry;
DWORD size = 0;
HRESULT hr;
/* call will always fail, becase size is 0,
* but will return ERROR_FILE_NOT_FOUND first
* if the file doesn't exist
*/
GetUrlCacheEntryInfoW( szUrl, NULL, &size );
if ( GetLastError() != ERROR_FILE_NOT_FOUND )
{
cache_entry = HeapAlloc( GetProcessHeap(), 0, size );
if ( !GetUrlCacheEntryInfoW( szUrl, cache_entry, &size ) )
{
HeapFree( GetProcessHeap(), 0, cache_entry );
return szUrl;
}
lstrcpyW( filename, cache_entry->lpszLocalFileName );
HeapFree( GetProcessHeap(), 0, cache_entry );
return filename;
}
hr = URLDownloadToCacheFileW( NULL, szUrl, filename, MAX_PATH, 0, NULL );
if ( FAILED(hr) )
return szUrl;
return filename;
}
UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
{
MSIDATABASE *db = NULL;
@ -470,7 +505,12 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
else
{
WCHAR temppath[MAX_PATH];
LPCWSTR file = copy_package_to_temp( szPackage, temppath );
LPCWSTR file;
if ( UrlIsW( szPackage, URLIS_URL ) )
file = msi_download_package( szPackage, temppath );
else
file = copy_package_to_temp( szPackage, temppath );
r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &db );
@ -513,6 +553,9 @@ UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phP
TRACE("%s %08lx %p\n", debugstr_w(szPackage), dwOptions, phPackage );
if( szPackage == NULL )
return ERROR_INVALID_PARAMETER;
if( dwOptions )
FIXME("dwOptions %08lx not supported\n", dwOptions);
@ -575,11 +618,16 @@ MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
MSIRECORD *record)
{
static const WCHAR szActionData[] =
{'A','c','t','i','o','n','D','a','t','a',0};
static const WCHAR szSetProgress[] =
{'S','e','t','P','r','o','g','r','e','s','s',0};
static const WCHAR szActionText[] =
{'A','c','t','i','o','n','T','e','x','t',0};
DWORD log_type = 0;
LPWSTR message;
DWORD sz;
DWORD total_size = 0;
INT msg_field=1;
INT i;
INT rc;
char *msg;
@ -606,34 +654,63 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS)
log_type |= 0x800;
message = msi_alloc(1*sizeof (WCHAR));
message[0]=0;
msg_field = MSI_RecordGetFieldCount(record);
for (i = 1; i <= msg_field; i++)
if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
{
LPWSTR tmp;
WCHAR number[3];
static const WCHAR format[] = { '%','i',':',' ',0};
static const WCHAR space[] = { ' ',0};
sz = 0;
MSI_RecordGetStringW(record,i,NULL,&sz);
sz+=4;
total_size+=sz*sizeof(WCHAR);
tmp = msi_alloc(sz*sizeof(WCHAR));
message = msi_realloc(message,total_size*sizeof (WCHAR));
static const WCHAR template_s[]=
{'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ',0};
static const WCHAR format[] =
{'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
WCHAR timet[0x100];
LPCWSTR action_text, action;
LPWSTR deformatted = NULL;
MSI_RecordGetStringW(record,i,tmp,&sz);
GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
if (msg_field > 1)
action = MSI_RecordGetString(record, 1);
action_text = MSI_RecordGetString(record, 2);
deformat_string(package, action_text, &deformatted);
len = strlenW(timet) + strlenW(action) + strlenW(template_s);
if (deformatted)
len += strlenW(deformatted);
message = msi_alloc(len*sizeof(WCHAR));
sprintfW(message, template_s, timet, action);
if (deformatted)
strcatW(message, deformatted);
msi_free(deformatted);
}
else
{
INT msg_field=1;
message = msi_alloc(1*sizeof (WCHAR));
message[0]=0;
msg_field = MSI_RecordGetFieldCount(record);
for (i = 1; i <= msg_field; i++)
{
sprintfW(number,format,i);
strcatW(message,number);
}
strcatW(message,tmp);
if (msg_field > 1)
strcatW(message,space);
LPWSTR tmp;
WCHAR number[3];
static const WCHAR format[] = { '%','i',':',' ',0};
static const WCHAR space[] = { ' ',0};
sz = 0;
MSI_RecordGetStringW(record,i,NULL,&sz);
sz+=4;
total_size+=sz*sizeof(WCHAR);
tmp = msi_alloc(sz*sizeof(WCHAR));
message = msi_realloc(message,total_size*sizeof (WCHAR));
msi_free(tmp);
MSI_RecordGetStringW(record,i,tmp,&sz);
if (msg_field > 1)
{
sprintfW(number,format,i);
strcatW(message,number);
}
strcatW(message,tmp);
if (msg_field > 1)
strcatW(message,space);
msi_free(tmp);
}
}
TRACE("(%p %lx %lx %s)\n",gUIHandlerA, gUIFilter, log_type,
@ -667,8 +744,38 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
}
}
msi_free( msg );
msi_free( message);
switch (eMessageType & 0xff000000)
{
case INSTALLMESSAGE_ACTIONDATA:
/* FIXME: format record here instead of in ui_actiondata to get the
* correct action data for external scripts */
ControlEvent_FireSubscribedEvent(package, szActionData, record);
break;
case INSTALLMESSAGE_ACTIONSTART:
{
MSIRECORD *uirow;
LPWSTR deformated;
LPCWSTR action_text = MSI_RecordGetString(record, 2);
deformat_string(package, action_text, &deformated);
uirow = MSI_CreateRecord(1);
MSI_RecordSetStringW(uirow, 1, deformated);
TRACE("INSTALLMESSAGE_ACTIONSTART: %s\n", debugstr_w(deformated));
msi_free(deformated);
ControlEvent_FireSubscribedEvent(package, szActionText, uirow);
msiobj_release(&uirow->hdr);
break;
}
case INSTALLMESSAGE_PROGRESS:
ControlEvent_FireSubscribedEvent(package, szSetProgress, record);
break;
}
return ERROR_SUCCESS;
}

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef __WINE_MSI_QUERY_H
@ -53,6 +53,7 @@
#define EXPR_STRCMP 7
#define EXPR_WILDCARD 9
#define EXPR_COL_NUMBER_STRING 10
#define EXPR_COL_NUMBER32 11
struct sql_str {
LPCWSTR data;
@ -116,6 +117,10 @@ UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **, LPWSTR table,
UINT DELETE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table );
UINT JOIN_CreateView( MSIDATABASE *db, MSIVIEW **view,
LPCWSTR left, LPCWSTR right,
struct expr *cond );
int sqliteGetToken(const WCHAR *z, int *tokenType);
#endif /* __WINE_MSI_QUERY_H */

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
@ -100,8 +100,10 @@ MSIHANDLE WINAPI MsiCreateRecord( unsigned int cParams )
rec = MSI_CreateRecord( cParams );
if( rec )
{
ret = alloc_msihandle( &rec->hdr );
msiobj_release( &rec->hdr );
msiobj_release( &rec->hdr );
}
return ret;
}
@ -319,7 +321,7 @@ UINT MSI_RecordGetStringA(MSIRECORD *rec, unsigned int iField,
break;
}
if( *pcchValue < len )
if( *pcchValue <= len )
ret = ERROR_MORE_DATA;
*pcchValue = len;
@ -387,7 +389,7 @@ UINT MSI_RecordGetStringW(MSIRECORD *rec, unsigned int iField,
break;
}
if( *pcchValue < len )
if( *pcchValue <= len )
ret = ERROR_MORE_DATA;
*pcchValue = len;

View file

@ -16,7 +16,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
@ -189,39 +189,33 @@ BOOL unsquash_guid(LPCWSTR in, LPWSTR out)
BOOL squash_guid(LPCWSTR in, LPWSTR out)
{
DWORD i,n=0;
DWORD i,n=1;
GUID guid;
if(in[n++] != '{')
if (FAILED(CLSIDFromString((LPOLESTR)in, &guid)))
return FALSE;
for(i=0; i<8; i++)
out[7-i] = in[n++];
if(in[n++] != '-')
return FALSE;
n++;
for(i=0; i<4; i++)
out[11-i] = in[n++];
if(in[n++] != '-')
return FALSE;
n++;
for(i=0; i<4; i++)
out[15-i] = in[n++];
if(in[n++] != '-')
return FALSE;
n++;
for(i=0; i<2; i++)
{
out[17+i*2] = in[n++];
out[16+i*2] = in[n++];
}
if(in[n++] != '-')
return FALSE;
n++;
for( ; i<8; i++)
{
out[17+i*2] = in[n++];
out[16+i*2] = in[n++];
}
out[32]=0;
if(in[n++] != '}')
return FALSE;
if(in[n])
return FALSE;
return TRUE;
}
@ -305,6 +299,95 @@ BOOL encode_base85_guid( GUID *guid, LPWSTR str )
return TRUE;
}
DWORD msi_version_str_to_dword(LPCWSTR p)
{
DWORD major, minor = 0, build = 0, version = 0;
if (!p)
return version;
major = atoiW(p);
p = strchrW(p, '.');
if (p)
{
minor = atoiW(p+1);
p = strchrW(p+1, '.');
if (p)
build = atoiW(p+1);
}
return MAKELONG(build, MAKEWORD(minor, major));
}
LPWSTR msi_version_dword_to_str(DWORD version)
{
const WCHAR fmt[] = { '%','u','.','%','u','.','%','u',0 };
LPWSTR str = msi_alloc(20);
sprintfW(str, fmt,
(version&0xff000000)>>24,
(version&0x00ff0000)>>16,
version&0x0000ffff);
return str;
}
LONG msi_reg_set_val_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
{
DWORD len = value ? (lstrlenW(value) + 1) * sizeof (WCHAR) : 0;
return RegSetValueExW( hkey, name, 0, REG_SZ, (LPBYTE)value, len );
}
LONG msi_reg_set_val_multi_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
{
LPCWSTR p = value;
while (*p) p += lstrlenW(p) + 1;
return RegSetValueExW( hkey, name, 0, REG_MULTI_SZ,
(LPBYTE)value, (p + 1 - value) * sizeof(WCHAR) );
}
LONG msi_reg_set_val_dword( HKEY hkey, LPCWSTR name, DWORD val )
{
return RegSetValueExW( hkey, name, 0, REG_DWORD, (LPBYTE)&val, sizeof (DWORD) );
}
LONG msi_reg_set_subkey_val( HKEY hkey, LPCWSTR path, LPCWSTR name, LPCWSTR val )
{
HKEY hsubkey = 0;
LONG r;
r = RegCreateKeyW( hkey, path, &hsubkey );
if (r != ERROR_SUCCESS)
return r;
r = msi_reg_set_val_str( hsubkey, name, val );
RegCloseKey( hsubkey );
return r;
}
LPWSTR msi_reg_get_val_str( HKEY hkey, LPCWSTR name )
{
DWORD len = 0;
LPWSTR val;
LONG r;
r = RegQueryValueExW(hkey, name, NULL, NULL, NULL, &len);
if (r != ERROR_SUCCESS)
return NULL;
len += sizeof (WCHAR);
val = msi_alloc( len );
if (!val)
return NULL;
val[0] = 0;
RegQueryValueExW(hkey, name, NULL, NULL, (LPBYTE) val, &len);
return val;
}
BOOL msi_reg_get_val_dword( HKEY hkey, LPCWSTR name, DWORD *val)
{
DWORD type, len = sizeof (DWORD);
LONG r = RegQueryValueExW(hkey, name, NULL, &type, (LPBYTE) val, &len);
return r == ERROR_SUCCESS && type == REG_DWORD;
}
UINT MSIREG_OpenUninstallKey(LPCWSTR szProduct, HKEY* key, BOOL create)
{
@ -675,6 +758,9 @@ UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index,
TRACE("%s %ld %p %p\n",debugstr_w(szProduct),index,szFeature,szParent);
if( !szProduct )
return ERROR_INVALID_PARAMETER;
r = MSIREG_OpenFeaturesKey(szProduct,&hkeyProduct,FALSE);
if( r != ERROR_SUCCESS )
return ERROR_NO_MORE_ITEMS;
@ -978,3 +1064,25 @@ UINT WINAPI MsiEnumRelatedProductsA(LPCSTR szUpgradeCode, DWORD dwReserved,
msi_free( szwUpgradeCode);
return r;
}
/***********************************************************************
* MsiEnumPatchesA [MSI.@]
*/
UINT WINAPI MsiEnumPatchesA( LPCSTR szProduct, DWORD iPatchIndex,
LPSTR lpPatchBuf, LPSTR lpTransformsBuf, DWORD* pcchTransformsBuf)
{
FIXME("%s %ld %p %p %p\n", debugstr_a(szProduct),
iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
return ERROR_NO_MORE_ITEMS;
}
/***********************************************************************
* MsiEnumPatchesW [MSI.@]
*/
UINT WINAPI MsiEnumPatchesW( LPCWSTR szProduct, DWORD iPatchIndex,
LPWSTR lpPatchBuf, LPWSTR lpTransformsBuf, DWORD* pcchTransformsBuf)
{
FIXME("%s %ld %p %p %p\n", debugstr_w(szProduct),
iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
return ERROR_NO_MORE_ITEMS;
}

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
@ -160,7 +160,7 @@ static HRESULT register_interfaces(struct regsvr_interface const *list) {
}
if (list->base_iid) {
register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
res = register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
if (res != ERROR_SUCCESS) goto error_close_iid_key;
}
@ -182,12 +182,12 @@ static HRESULT register_interfaces(struct regsvr_interface const *list) {
}
if (list->ps_clsid) {
register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
res = register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
if (res != ERROR_SUCCESS) goto error_close_iid_key;
}
if (list->ps_clsid32) {
register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
res = register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
if (res != ERROR_SUCCESS) goto error_close_iid_key;
}
@ -595,6 +595,39 @@ static struct regsvr_interface const interface_list[] = {
{ NULL } /* list terminator */
};
static HRESULT register_msiexec(void)
{
static const WCHAR key[] = {
'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',0 };
static const WCHAR val[] = {
'I','n','s','t','a','l','l','e','r','L','o','c','a','t','i','o','n',0 };
WCHAR path[MAX_PATH];
HKEY hkey;
LONG res;
INT len;
len = GetSystemDirectoryW(path, MAX_PATH);
if (!len || len > MAX_PATH)
return E_FAIL;
res = RegCreateKeyExW(HKEY_LOCAL_MACHINE, key, 0,
NULL, 0, KEY_READ | KEY_WRITE, NULL,
&hkey, NULL);
if (res != ERROR_SUCCESS)
return E_FAIL;
res = RegSetValueExW(hkey, val, 0, REG_SZ,
(BYTE*)path, (len + 1)*sizeof(WCHAR));
RegCloseKey(hkey);
return (res == ERROR_SUCCESS) ? S_OK : E_FAIL;
}
/***********************************************************************
* DllRegisterServer (MSI.@)
*/
@ -607,6 +640,8 @@ HRESULT WINAPI DllRegisterServer(void)
hr = register_coclasses(coclass_list);
if (SUCCEEDED(hr))
hr = register_interfaces(interface_list);
if (SUCCEEDED(hr))
hr = register_msiexec();
return hr;
}

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
@ -196,8 +196,26 @@ static UINT SELECT_delete( struct tagMSIVIEW *view )
return ERROR_SUCCESS;
}
static UINT SELECT_find_matching_rows( struct tagMSIVIEW *view, UINT col,
UINT val, UINT *row, MSIITERHANDLE *handle )
{
MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
MSIVIEWOPS select_ops =
TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
if( !sv->table )
return ERROR_FUNCTION_FAILED;
if( (col==0) || (col>sv->num_cols) )
return ERROR_FUNCTION_FAILED;
col = sv->cols[ col - 1 ];
return sv->table->ops->find_matching_rows( sv->table, col, val, row, handle );
}
static const MSIVIEWOPS select_ops =
{
SELECT_fetch_int,
SELECT_fetch_stream,
@ -208,7 +226,8 @@ MSIVIEWOPS select_ops =
SELECT_get_dimensions,
SELECT_get_column_info,
SELECT_modify,
SELECT_delete
SELECT_delete,
SELECT_find_matching_rows
};
static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name )
@ -245,20 +264,23 @@ static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name )
return ERROR_SUCCESS;
}
int select_count_columns( column_info *col )
{
int n;
for (n = 0; col; col = col->next)
n++;
return n;
}
UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
column_info *columns )
{
MSISELECTVIEW *sv = NULL;
UINT count = 0, r;
UINT count = 0, r = ERROR_SUCCESS;
TRACE("%p\n", sv );
r = table->ops->get_dimensions( table, NULL, &count );
if( r != ERROR_SUCCESS )
{
ERR("can't get table dimensions\n");
return r;
}
count = select_count_columns( columns );
sv = msi_alloc_zero( sizeof *sv + count*sizeof (UINT) );
if( !sv )

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
@ -37,6 +37,7 @@
#include "winuser.h"
#include "wine/unicode.h"
#include "action.h"
#include "sddl.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
@ -126,6 +127,7 @@ static UINT find_given_source(HKEY key, LPCWSTR szSource, media_info *ss)
{
val = NULL;
val_size = 0;
size = sizeof(szIndex)/sizeof(szIndex[0]);
rc = RegEnumValueW(key, index, szIndex, &size, NULL, NULL, NULL, &val_size);
if (rc != ERROR_NO_MORE_ITEMS)
{
@ -396,6 +398,61 @@ UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
}
/******************************************************************
* MsiSourceListAddSourceW (MSI.@)
*/
UINT WINAPI MsiSourceListAddSourceW( LPCWSTR szProduct, LPCWSTR szUserName,
DWORD dwReserved, LPCWSTR szSource)
{
INT ret;
LPWSTR sidstr = NULL;
DWORD sidsize = 0;
TRACE("%s %s %s\n", debugstr_w(szProduct), debugstr_w(szUserName), debugstr_w(szSource));
if (LookupAccountNameW(NULL, szUserName, NULL, &sidsize, NULL, NULL, NULL))
{
PSID psid = msi_alloc(sidsize);
if (LookupAccountNameW(NULL, szUserName, psid, &sidsize, NULL, NULL, NULL))
ConvertSidToStringSidW(psid, &sidstr);
msi_free(psid);
}
ret = MsiSourceListAddSourceExW(szProduct, sidstr,
MSIINSTALLCONTEXT_USERMANAGED, MSISOURCETYPE_NETWORK, szSource, 0);
if (sidstr)
LocalFree(sidstr);
return ret;
}
/******************************************************************
* MsiSourceListAddSourceA (MSI.@)
*/
UINT WINAPI MsiSourceListAddSourceA( LPCSTR szProduct, LPCSTR szUserName,
DWORD dwReserved, LPCSTR szSource)
{
INT ret;
LPWSTR szwproduct;
LPWSTR szwusername;
LPWSTR szwsource;
szwproduct = strdupAtoW( szProduct );
szwusername = strdupAtoW( szUserName );
szwsource = strdupAtoW( szSource );
ret = MsiSourceListAddSourceW(szwproduct, szwusername, 0, szwsource);
msi_free(szwproduct);
msi_free(szwusername);
msi_free(szwsource);
return ret;
}
/******************************************************************
* MsiSourceListAddSourceExW (MSI.@)
*/
@ -442,6 +499,8 @@ UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid,
rc = OpenNetworkSubkey(sourcekey, &typekey, TRUE);
else if (dwOptions & MSISOURCETYPE_URL)
rc = OpenURLSubkey(sourcekey, &typekey, TRUE);
else if (dwOptions & MSISOURCETYPE_MEDIA)
rc = OpenMediaSubkey(sourcekey, &typekey, TRUE);
else
{
ERR("unknown media type: %08lx\n", dwOptions);
@ -558,3 +617,21 @@ UINT WINAPI MsiSourceListAddMediaDiskW(LPCWSTR szProduct, LPCWSTR szUserSid,
return ERROR_SUCCESS;
}
/******************************************************************
* MsiSourceListAddSourceExA (MSI.@)
*/
UINT WINAPI MsiSourceListClearAllA( LPCSTR szProduct, LPCSTR szUserName, DWORD dwReserved )
{
FIXME("(%s %s %ld) stub\n", debugstr_a(szProduct), debugstr_a(szUserName), dwReserved);
return ERROR_SUCCESS;
}
/******************************************************************
* MsiSourceListAddSourceExW (MSI.@)
*/
UINT WINAPI MsiSourceListClearAllW( LPCWSTR szProduct, LPCWSTR szUserName, DWORD dwReserved )
{
FIXME("(%s %s %ld) stub\n", debugstr_w(szProduct), debugstr_w(szUserName), dwReserved);
return ERROR_SUCCESS;
}

View file

@ -17,7 +17,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
@ -126,12 +126,20 @@ static struct expr * EXPR_wildcard( void *info );
%type <string> table id
%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> query multifrom from fromtable selectfrom unorderedsel
%type <query> oneupdate onedelete oneselect onequery onecreate oneinsert
%type <expr> expr val column_val const_val
%type <column_type> column_type data_type data_type_l data_count
%type <integer> number
/* Reference: http://mates.ms.mff.cuni.cz/oracle/doc/ora815nt/server.815/a67779/operator.htm */
%left TK_OR
%left TK_AND
%left TK_NOT
%left TK_EQ TK_NE TK_LT TK_GT TK_LE TK_GE TK_ISNULL TK_LIKE TK_BETWEEN TK_IN
%left TK_PLUS TK_MINUS TK_CONCAT
%right TK_NEGATION
%%
query:
@ -361,7 +369,7 @@ unorderedsel:
;
selectfrom:
selcollist from
selcollist multifrom
{
SQL_input* sql = (SQL_input*) info;
UINT r;
@ -393,6 +401,20 @@ selcollist:
}
;
multifrom:
from
| TK_FROM table TK_COMMA table TK_WHERE expr
{
SQL_input* sql = (SQL_input*) info;
UINT r;
/* only support inner joins on two tables */
r = JOIN_CreateView( sql->db, &$$, $2, $4, $6 );
if( r != ERROR_SUCCESS )
YYABORT;
}
;
from:
fromtable
| fromtable TK_WHERE expr
@ -430,12 +452,6 @@ expr:
if( !$$ )
YYABORT;
}
| column_val TK_EQ column_val
{
$$ = EXPR_complex( info, $1, OP_EQ, $3 );
if( !$$ )
YYABORT;
}
| expr TK_AND expr
{
$$ = EXPR_complex( info, $1, OP_AND, $3 );
@ -545,7 +561,7 @@ const_val:
if( !$$ )
YYABORT;
}
| TK_MINUS number
| TK_MINUS number %prec TK_NEGATION
{
$$ = EXPR_ival( info, -$2 );
if( !$$ )

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
@ -37,9 +37,11 @@
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
#define HASH_SIZE 67
typedef struct _msistring
{
UINT hash;
int hash_next;
UINT refcount;
LPWSTR str;
} msistring;
@ -49,6 +51,7 @@ struct string_table
UINT maxcount; /* the number of strings */
UINT freeslot;
UINT codepage;
int hash[HASH_SIZE];
msistring *strings; /* an array of strings (in the tree) */
};
@ -65,12 +68,13 @@ static UINT msistring_makehash( const WCHAR *str )
hash *= 53;
hash = (hash<<5) | (hash>>27);
}
return hash;
return hash % HASH_SIZE;
}
string_table *msi_init_stringtable( int entries, UINT codepage )
{
string_table *st;
int i;
st = msi_alloc( sizeof (string_table) );
if( !st )
@ -78,7 +82,7 @@ string_table *msi_init_stringtable( int entries, UINT codepage )
if( entries < 1 )
entries = 1;
st->strings = msi_alloc_zero( sizeof (msistring) * entries );
if( !st )
if( !st->strings )
{
msi_free( st );
return NULL;
@ -87,6 +91,9 @@ string_table *msi_init_stringtable( int entries, UINT codepage )
st->freeslot = 1;
st->codepage = codepage;
for( i=0; i<HASH_SIZE; i++ )
st->hash[i] = -1;
return st;
}
@ -133,15 +140,23 @@ static int st_find_free_entry( string_table *st )
return st->freeslot;
}
static void st_mark_entry_used( string_table *st, UINT n )
static void set_st_entry( string_table *st, UINT n, LPWSTR str )
{
if( n >= st->maxcount )
return;
st->freeslot = n + 1;
UINT hash = msistring_makehash( str );
st->strings[n].refcount = 1;
st->strings[n].str = str;
st->strings[n].hash_next = st->hash[hash];
st->hash[hash] = n;
if( n < st->maxcount )
st->freeslot = n + 1;
}
int msi_addstring( string_table *st, UINT n, const CHAR *data, int len, UINT refcount )
{
LPWSTR str;
int sz;
if( !data )
@ -175,21 +190,21 @@ int msi_addstring( string_table *st, UINT n, const CHAR *data, int len, UINT ref
if( len < 0 )
len = strlen(data);
sz = MultiByteToWideChar( st->codepage, 0, data, len, NULL, 0 );
st->strings[n].str = msi_alloc( (sz+1)*sizeof(WCHAR) );
if( !st->strings[n].str )
str = msi_alloc( (sz+1)*sizeof(WCHAR) );
if( !str )
return -1;
MultiByteToWideChar( st->codepage, 0, data, len, st->strings[n].str, sz );
st->strings[n].str[sz] = 0;
st->strings[n].refcount = 1;
st->strings[n].hash = msistring_makehash( st->strings[n].str );
MultiByteToWideChar( st->codepage, 0, data, len, str, sz );
str[sz] = 0;
st_mark_entry_used( st, n );
set_st_entry( st, n, str );
return n;
}
int msi_addstringW( string_table *st, UINT n, const WCHAR *data, int len, UINT refcount )
{
LPWSTR str;
/* TRACE("[%2d] = %s\n", string_no, debugstr_an(data,len) ); */
if( !data )
@ -224,16 +239,14 @@ int msi_addstringW( string_table *st, UINT n, const WCHAR *data, int len, UINT r
len = strlenW(data);
TRACE("%s, n = %d len = %d\n", debugstr_w(data), n, len );
st->strings[n].str = msi_alloc( (len+1)*sizeof(WCHAR) );
if( !st->strings[n].str )
str = msi_alloc( (len+1)*sizeof(WCHAR) );
if( !str )
return -1;
TRACE("%d\n",__LINE__);
memcpy( st->strings[n].str, data, len*sizeof(WCHAR) );
st->strings[n].str[len] = 0;
st->strings[n].refcount = 1;
st->strings[n].hash = msistring_makehash( st->strings[n].str );
memcpy( str, data, len*sizeof(WCHAR) );
str[len] = 0;
st_mark_entry_used( st, n );
set_st_entry( st, n, str );
return n;
}
@ -349,23 +362,19 @@ UINT msi_id2stringA( string_table *st, UINT id, LPSTR buffer, UINT *sz )
*/
UINT msi_string2idW( string_table *st, LPCWSTR str, UINT *id )
{
UINT hash;
UINT i, r = ERROR_INVALID_PARAMETER;
UINT n, hash = msistring_makehash( str );
msistring *se = st->strings;
hash = msistring_makehash( str );
for( i=0; i<st->maxcount; i++ )
for (n = st->hash[hash]; n != -1; n = st->strings[n].hash_next )
{
if ( (str == NULL && st->strings[i].str == NULL) ||
( ( st->strings[i].hash == hash ) &&
!strcmpW( st->strings[i].str, str ) ))
if ((str == se[n].str) || !lstrcmpW(str, se[n].str))
{
r = ERROR_SUCCESS;
*id = i;
break;
*id = n;
return ERROR_SUCCESS;
}
}
return r;
return ERROR_INVALID_PARAMETER;
}
UINT msi_string2idA( string_table *st, LPCSTR buffer, UINT *id )

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
@ -23,8 +23,6 @@
#define COBJMACROS
#define NONAMELESSUNION
#define PRSPEC_PROPID (1)
#include "windef.h"
#include "winbase.h"
#include "winreg.h"

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
@ -39,6 +39,15 @@
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
#define MSITABLE_HASH_TABLE_SIZE 37
typedef struct tagMSICOLUMNHASHENTRY
{
struct tagMSICOLUMNHASHENTRY *next;
UINT value;
UINT row;
} MSICOLUMNHASHENTRY;
typedef struct tagMSICOLUMNINFO
{
LPCWSTR tablename;
@ -46,6 +55,7 @@ typedef struct tagMSICOLUMNINFO
LPCWSTR colname;
UINT type;
UINT offset;
MSICOLUMNHASHENTRY **hash_table;
} MSICOLUMNINFO;
struct tagMSITABLE
@ -467,7 +477,7 @@ static MSITABLE *read_table_from_storage( IStorage *stg, LPCWSTR name,
goto err;
/* transpose all the data */
TRACE("Transposing data from %d columns\n", t->row_count );
TRACE("Transposing data from %d rows\n", t->row_count );
for( i=0; i<t->row_count; i++ )
{
t->data[i] = msi_alloc( row_size );
@ -673,8 +683,8 @@ HRESULT init_string_table( IStorage *stg )
string_table *load_string_table( IStorage *stg )
{
string_table *st = NULL;
CHAR *data;
USHORT *pool;
CHAR *data = NULL;
USHORT *pool = NULL;
UINT r, datasize = 0, poolsize = 0, codepage;
DWORD i, count, offset, len, n;
static const WCHAR szStringData[] = {
@ -707,8 +717,8 @@ string_table *load_string_table( IStorage *stg )
* and its the high word of the length is inserted in the null string's
* reference count field.
*/
if( pool[i*2-2] == 0 )
len += pool[i*2-1] * 0x10000;
if( pool[i*2-2] == 0 && pool[i*2-1] )
len += pool[i*2+1] * 0x10000;
if( (offset + len) > datasize )
{
@ -755,7 +765,7 @@ static UINT save_string_table( MSIDATABASE *db )
/* construct the new table in memory first */
datasize = msi_string_totalsize( db->strings, &count );
poolsize = count*2*sizeof(USHORT);
poolsize = (count + 1)*2*sizeof(USHORT);
pool = msi_alloc( poolsize );
if( ! pool )
@ -884,6 +894,7 @@ static void msi_free_colinfo( MSICOLUMNINFO *colinfo, UINT count )
{
msi_free( (LPWSTR) colinfo[i].tablename );
msi_free( (LPWSTR) colinfo[i].colname );
msi_free( colinfo[i].hash_table );
}
}
@ -931,7 +942,7 @@ static UINT get_tablecolumns( MSIDATABASE *db,
return r;
}
TRACE("Table id is %d\n", table_id);
TRACE("Table id is %d, row count is %d\n", table_id, table->row_count);
count = table->row_count;
for( i=0; i<count; i++ )
@ -945,6 +956,7 @@ static UINT get_tablecolumns( MSIDATABASE *db,
colinfo[n].number = table->data[ i ][ 1 ] - (1<<15);
colinfo[n].colname = MSI_makestring( db, id );
colinfo[n].type = table->data[ i ] [ 3 ] ^ 0x8000;
colinfo[n].hash_table = NULL;
/* this assumes that columns are in order in the table */
if( n )
colinfo[n].offset = colinfo[n-1].offset
@ -1296,6 +1308,8 @@ static UINT msi_table_modify_row( MSITABLEVIEW *tv, MSIRECORD *rec,
val = MSI_RecordGetInteger( rec, i+1 );
if ( 2 == bytes_per_column( &tv->columns[i] ) )
val ^= 0x8000;
else
val ^= 0x80000000;
}
r = TABLE_set_int( &tv->view, row, i+1, val );
if( r )
@ -1389,8 +1403,100 @@ static UINT TABLE_delete( struct tagMSIVIEW *view )
return ERROR_SUCCESS;
}
static UINT TABLE_find_matching_rows( struct tagMSIVIEW *view, UINT col,
UINT val, UINT *row, MSIITERHANDLE *handle )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
const MSICOLUMNHASHENTRY *entry;
MSIVIEWOPS table_ops =
TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
if( !tv->table )
return ERROR_INVALID_PARAMETER;
if( (col==0) || (col > tv->num_cols) )
return ERROR_INVALID_PARAMETER;
if( !tv->columns[col-1].hash_table )
{
UINT i;
UINT num_rows = tv->table->row_count;
MSICOLUMNHASHENTRY **hash_table;
MSICOLUMNHASHENTRY *new_entry;
if( tv->columns[col-1].offset >= tv->row_size )
{
ERR("Stuffed up %d >= %d\n", tv->columns[col-1].offset, tv->row_size );
ERR("%p %p\n", tv, tv->columns );
return ERROR_FUNCTION_FAILED;
}
/* allocate contiguous memory for the table and its entries so we
* don't have to do an expensive cleanup */
hash_table = msi_alloc(MSITABLE_HASH_TABLE_SIZE * sizeof(MSICOLUMNHASHENTRY*) +
num_rows * sizeof(MSICOLUMNHASHENTRY));
if (!hash_table)
return ERROR_OUTOFMEMORY;
memset(hash_table, 0, MSITABLE_HASH_TABLE_SIZE * sizeof(MSICOLUMNHASHENTRY*));
tv->columns[col-1].hash_table = hash_table;
new_entry = (MSICOLUMNHASHENTRY *)(hash_table + MSITABLE_HASH_TABLE_SIZE);
for (i = 0; i < num_rows; i++, new_entry++)
{
UINT row_value, n;
UINT offset = i + (tv->columns[col-1].offset/2) * num_rows;
n = bytes_per_column( &tv->columns[col-1] );
switch( n )
{
case 4:
offset = tv->columns[col-1].offset/2;
row_value = tv->table->data[i][offset] +
(tv->table->data[i][offset + 1] << 16);
break;
case 2:
offset = tv->columns[col-1].offset/2;
row_value = tv->table->data[i][offset];
break;
default:
ERR("oops! what is %d bytes per column?\n", n );
continue;
}
new_entry->next = NULL;
new_entry->value = row_value;
new_entry->row = i;
if (hash_table[row_value % MSITABLE_HASH_TABLE_SIZE])
{
MSICOLUMNHASHENTRY *prev_entry = hash_table[row_value % MSITABLE_HASH_TABLE_SIZE];
while (prev_entry->next)
prev_entry = prev_entry->next;
prev_entry->next = new_entry;
}
else
hash_table[row_value % MSITABLE_HASH_TABLE_SIZE] = new_entry;
}
}
if( !*handle )
entry = tv->columns[col-1].hash_table[val % MSITABLE_HASH_TABLE_SIZE];
else
entry = ((const MSICOLUMNHASHENTRY *)*handle)->next;
while (entry && entry->value != val)
entry = entry->next;
*handle = (MSIITERHANDLE)entry;
if (!entry)
return ERROR_NO_MORE_ITEMS;
*row = entry->row;
return ERROR_SUCCESS;
}
static const MSIVIEWOPS table_ops =
{
TABLE_fetch_int,
TABLE_fetch_stream,
@ -1401,7 +1507,8 @@ MSIVIEWOPS table_ops =
TABLE_get_dimensions,
TABLE_get_column_info,
TABLE_modify,
TABLE_delete
TABLE_delete,
TABLE_find_matching_rows
};
UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view )
@ -1499,13 +1606,12 @@ static MSIRECORD *msi_get_transform_record( MSITABLEVIEW *tv, string_table *st,
USHORT mask = *rawdata++;
MSICOLUMNINFO *columns = tv->columns;
MSIRECORD *rec;
const int debug_transform = 0;
rec = MSI_CreateRecord( tv->num_cols );
if( !rec )
return rec;
if( debug_transform ) MESSAGE("row -> ");
TRACE("row -> ");
for( i=0; i<tv->num_cols; i++ )
{
UINT n = bytes_per_column( &columns[i] );
@ -1525,20 +1631,20 @@ static MSIRECORD *msi_get_transform_record( MSITABLEVIEW *tv, string_table *st,
{
LPCWSTR sval = msi_string_lookup_id( st, val );
MSI_RecordSetStringW( rec, i+1, sval );
if( debug_transform ) MESSAGE("[%s]", debugstr_w(sval));
TRACE("[%s]", debugstr_w(sval));
}
else
{
val ^= 0x8000;
MSI_RecordSetInteger( rec, i+1, val );
if( debug_transform) MESSAGE("[0x%04x]", val );
TRACE("[0x%04x]", val );
}
break;
case 4:
val = rawdata[ofs] + (rawdata[ofs + 1]<<16);
/* val ^= 0x80000000; */
MSI_RecordSetInteger( rec, i+1, val );
if( debug_transform ) MESSAGE("[0x%08x]", val );
TRACE("[0x%08x]", val );
break;
default:
ERR("oops - unknown column width %d\n", n);
@ -1546,7 +1652,7 @@ static MSIRECORD *msi_get_transform_record( MSITABLEVIEW *tv, string_table *st,
}
ofs += n/2;
}
if( debug_transform) MESSAGE("\n");
TRACE("\n");
return rec;
}
@ -1554,20 +1660,18 @@ static void dump_record( MSIRECORD *rec )
{
UINT i, n;
MESSAGE("row -> ");
n = MSI_RecordGetFieldCount( rec );
for( i=1; i<=n; i++ )
{
LPCWSTR sval = MSI_RecordGetString( rec, i );
if( MSI_RecordIsNull( rec, i ) )
MESSAGE("[]");
TRACE("row -> []\n");
else if( (sval = MSI_RecordGetString( rec, i )) )
MESSAGE("[%s]", debugstr_w(sval));
TRACE("row -> [%s]\n", debugstr_w(sval));
else
MESSAGE("[0x%08x]", MSI_RecordGetInteger( rec, i ) );
TRACE("row -> [0x%08x]\n", MSI_RecordGetInteger( rec, i ) );
}
MESSAGE("\n");
}
static void dump_table( string_table *st, USHORT *rawdata, UINT rawsize )
@ -1578,7 +1682,6 @@ static void dump_table( string_table *st, USHORT *rawdata, UINT rawsize )
for( i=0; i<(rawsize/2); i++ )
{
sval = msi_string_lookup_id( st, rawdata[i] );
if( !sval ) sval = (WCHAR[]) {0};
MESSAGE(" %04x %s\n", rawdata[i], debugstr_w(sval) );
}
}
@ -1683,7 +1786,6 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
MSITABLEVIEW *tv = NULL;
UINT r, n, sz, i, mask;
MSIRECORD *rec = NULL;
const int debug_transform = 0;
TRACE("%p %p %p %s\n", db, stg, st, debugstr_w(name) );
@ -1757,20 +1859,20 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
if( rawdata[n] & 1)
{
if( debug_transform ) MESSAGE("insert [%d]: ", row);
TRACE("insert [%d]: ", row);
TABLE_insert_row( &tv->view, rec );
}
else if( mask & 0xff )
{
if( debug_transform ) MESSAGE("modify [%d]: ", row);
TRACE("modify [%d]: ", row);
msi_table_modify_row( tv, rec, row, mask );
}
else
{
if( debug_transform ) MESSAGE("delete [%d]: ", row);
TRACE("delete [%d]: ", row);
msi_delete_row( tv, row );
}
if( debug_transform ) dump_record( rec );
if( TRACE_ON(msidb) ) dump_record( rec );
msiobj_release( &rec->hdr );
}

View file

@ -15,7 +15,7 @@
*
* You should have receuved a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
@ -177,6 +177,13 @@ static UINT UPDATE_delete( struct tagMSIVIEW *view )
return ERROR_SUCCESS;
}
static UINT UPDATE_find_matching_rows( struct tagMSIVIEW *view, UINT col, UINT val, UINT *row, MSIITERHANDLE *handle )
{
TRACE("%p %d %d %p\n", view, col, val, *handle );
return ERROR_FUNCTION_FAILED;
}
static MSIVIEWOPS update_ops =
{
@ -189,7 +196,8 @@ static MSIVIEWOPS update_ops =
UPDATE_get_dimensions,
UPDATE_get_column_info,
UPDATE_modify,
UPDATE_delete
UPDATE_delete,
UPDATE_find_matching_rows
};
UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
/*
@ -151,7 +151,7 @@ static UINT ITERATE_FindRelatedProducts(MSIRECORD *rec, LPVOID param)
(LPBYTE)&check, &sz);
/* check min */
ver = MSI_RecordGetString(rec,2);
comp_ver = build_version_dword(ver);
comp_ver = msi_version_str_to_dword(ver);
r = check - comp_ver;
if (r < 0 || (r == 0 && !(attributes &
msidbUpgradeAttributesVersionMinInclusive)))
@ -163,7 +163,7 @@ static UINT ITERATE_FindRelatedProducts(MSIRECORD *rec, LPVOID param)
/* check max */
ver = MSI_RecordGetString(rec,3);
comp_ver = build_version_dword(ver);
comp_ver = msi_version_str_to_dword(ver);
r = check - comp_ver;
if (r > 0 || (r == 0 && !(attributes &
msidbUpgradeAttributesVersionMaxInclusive)))

View file

@ -13,7 +13,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define WINE_FILEDESCRIPTION_STR "Wine MSI dll"

View file

@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
@ -99,7 +99,7 @@ static UINT WHERE_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val
return wv->table->ops->set_int( wv->table, row, col, val );
}
static UINT INT_evaluate( UINT lval, UINT op, UINT rval )
static INT INT_evaluate( INT lval, UINT op, INT rval )
{
switch( op )
{
@ -156,7 +156,7 @@ static const WCHAR *STRING_evaluate( string_table *st,
}
static UINT STRCMP_Evaluate( string_table *st, MSIVIEW *table, UINT row,
struct expr *cond, UINT *val, MSIRECORD *record )
struct expr *cond, INT *val, MSIRECORD *record )
{
int sr;
const WCHAR *l_str, *r_str;
@ -180,18 +180,25 @@ static UINT STRCMP_Evaluate( string_table *st, MSIVIEW *table, UINT row,
}
static UINT WHERE_evaluate( MSIDATABASE *db, MSIVIEW *table, UINT row,
struct expr *cond, UINT *val, MSIRECORD *record )
struct expr *cond, INT *val, MSIRECORD *record )
{
UINT r, lval, rval;
UINT r, tval;
INT lval, rval;
if( !cond )
return ERROR_SUCCESS;
switch( cond->type )
{
case EXPR_COL_NUMBER_STRING:
case EXPR_COL_NUMBER:
return table->ops->fetch_int( table, row, cond->u.col_number, val );
r = table->ops->fetch_int( table, row, cond->u.col_number, &tval );
*val = tval - 0x8000;
return ERROR_SUCCESS;
case EXPR_COL_NUMBER32:
r = table->ops->fetch_int( table, row, cond->u.col_number, &tval );
*val = tval - 0x80000000;
return r;
case EXPR_UVAL:
*val = cond->u.uval;
@ -226,7 +233,8 @@ static UINT WHERE_evaluate( MSIDATABASE *db, MSIVIEW *table, UINT row,
static UINT WHERE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
{
MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
UINT count = 0, r, val, i;
UINT count = 0, r, i;
INT val;
MSIVIEW *table = wv->table;
TRACE("%p %p\n", wv, record);
@ -248,6 +256,51 @@ static UINT WHERE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
return ERROR_FUNCTION_FAILED;
wv->row_count = 0;
if (wv->cond->type == EXPR_STRCMP)
{
MSIITERHANDLE handle = NULL;
UINT row, value, col;
struct expr *col_cond = wv->cond->u.expr.left;
struct expr *val_cond = wv->cond->u.expr.right;
/* swap conditionals */
if (col_cond->type != EXPR_COL_NUMBER_STRING)
{
val_cond = wv->cond->u.expr.left;
col_cond = wv->cond->u.expr.right;
}
if ((col_cond->type == EXPR_COL_NUMBER_STRING) && (val_cond->type == EXPR_SVAL))
{
col = col_cond->u.col_number;
/* special case for "" - translate it into nil */
if (!val_cond->u.sval[0])
value = 0;
else
{
r = msi_string2idW(wv->db->strings, val_cond->u.sval, &value);
if (r != ERROR_SUCCESS)
{
TRACE("no id for %s, assuming it doesn't exist in the table\n", debugstr_w(wv->cond->u.expr.right->u.sval));
return ERROR_SUCCESS;
}
}
do
{
r = table->ops->find_matching_rows(table, col, value, &row, &handle);
if (r == ERROR_SUCCESS)
wv->reorder[ wv->row_count ++ ] = row;
} while (r == ERROR_SUCCESS);
if (r == ERROR_NO_MORE_ITEMS)
return ERROR_SUCCESS;
else
return r;
}
/* else fallback to slow case */
}
for( i=0; i<count; i++ )
{
val = 0;
@ -341,8 +394,29 @@ static UINT WHERE_delete( struct tagMSIVIEW *view )
return ERROR_SUCCESS;
}
static UINT WHERE_find_matching_rows( struct tagMSIVIEW *view, UINT col,
UINT val, UINT *row, MSIITERHANDLE *handle )
{
MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
UINT r;
MSIVIEWOPS where_ops =
TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
if( !wv->table )
return ERROR_FUNCTION_FAILED;
r = wv->table->ops->find_matching_rows( wv->table, col, val, row, handle );
if( *row > wv->row_count )
return ERROR_NO_MORE_ITEMS;
*row = wv->reorder[ *row ];
return r;
}
static const MSIVIEWOPS where_ops =
{
WHERE_fetch_int,
WHERE_fetch_stream,
@ -353,7 +427,8 @@ MSIVIEWOPS where_ops =
WHERE_get_dimensions,
WHERE_get_column_info,
WHERE_modify,
WHERE_delete
WHERE_delete,
WHERE_find_matching_rows
};
static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr *cond,
@ -373,6 +448,8 @@ static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr
{
if (type&MSITYPE_STRING)
cond->type = EXPR_COL_NUMBER_STRING;
else if ((type&0xff) == 4)
cond->type = EXPR_COL_NUMBER32;
else
cond->type = EXPR_COL_NUMBER;
cond->u.col_number = val;
@ -423,7 +500,7 @@ static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr
case EXPR_IVAL:
*valid = 1;
cond->type = EXPR_UVAL;
cond->u.uval = cond->u.ival + (1<<15);
cond->u.uval = cond->u.ival;
break;
case EXPR_WILDCARD:
*valid = 1;