mirror of
https://github.com/reactos/reactos.git
synced 2025-02-23 00:45:24 +00:00
- 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:
parent
5e15912284
commit
6193e2092b
59 changed files with 3842 additions and 1740 deletions
|
@ -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:
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 }
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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 },
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
472
reactos/dll/win32/msi/join.c
Normal file
472
reactos/dll/win32/msi/join.c
Normal 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
|
@ -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>
|
||||
|
|
|
@ -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'
|
||||
} */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
33
reactos/dll/win32/msi/msi_Eo.rc
Normal file
33
reactos/dll/win32/msi/msi_Eo.rc
Normal 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"
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
33
reactos/dll/win32/msi/msi_It.rc
Normal file
33
reactos/dll/win32/msi/msi_It.rc
Normal 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"
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
33
reactos/dll/win32/msi/msi_Tr.rc
Normal file
33
reactos/dll/win32/msi/msi_Tr.rc
Normal 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"
|
||||
}
|
180
reactos/dll/win32/msi/msi_main.c
Normal file
180
reactos/dll/win32/msi/msi_main.c
Normal 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;
|
||||
}
|
|
@ -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 )
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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( !$$ )
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue