- 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
-TOPSRCDIR = @top_srcdir@\r
-TOPOBJDIR = ../..\r
-SRCDIR = @srcdir@\r
-VPATH = @srcdir@\r
-MODULE = msi.dll\r
-IMPORTLIB = libmsi.$(IMPLIBEXT)\r
-IMPORTS = shell32 shlwapi cabinet oleaut32 ole32 version user32 gdi32 advapi32 kernel32\r
-EXTRALIBS = -luuid $(LIBUNICODE)\r
-\r
-C_SRCS = \\r
- action.c \\r
- appsearch.c \\r
- classes.c \\r
- create.c \\r
- custom.c \\r
- database.c \\r
- delete.c \\r
- dialog.c \\r
- distinct.c \\r
- events.c \\r
- files.c \\r
- format.c \\r
- handle.c \\r
- helpers.c \\r
- insert.c \\r
- install.c \\r
- msi.c \\r
- msiquery.c \\r
- order.c \\r
- package.c \\r
- preview.c \\r
- record.c \\r
- registry.c \\r
- regsvr.c \\r
- select.c \\r
- source.c \\r
- string.c \\r
- suminfo.c \\r
- table.c \\r
- tokenize.c \\r
- update.c \\r
- upgrade.c \\r
- where.c\r
-\r
-RC_SRCS = msi.rc\r
-\r
-EXTRA_SRCS = sql.y cond.y\r
-EXTRA_OBJS = sql.tab.o cond.tab.o\r
-\r
-SUBDIRS = tests\r
-\r
-@MAKE_DLL_RULES@\r
-\r
-sql.tab.c sql.tab.h: sql.y\r
- $(BISON) -p SQL_ -d $(SRCDIR)/sql.y -o sql.tab.c\r
-\r
-cond.tab.c cond.tab.h: cond.y\r
- $(BISON) -p COND_ -d $(SRCDIR)/cond.y -o cond.tab.c\r
-\r
-# hack to allow parallel make\r
-sql.tab.h: sql.tab.c\r
-sql.tab.o: sql.tab.h\r
-cond.tab.h: cond.tab.c\r
-cond.tab.o: cond.tab.h\r
-\r
-tokenize.o: sql.tab.h\r
-\r
-### Dependencies:\r
+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:
*
* 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
*/
/*
{'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',
{'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[] =
* 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,
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;
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;
BOOL run = force;
int i;
- if (!package)
- {
- ERR("package was null!\n");
- return FALSE;
- }
-
if (!run && !package->script->CurrentlyScripting)
run = TRUE;
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 );
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 {
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;
}
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;
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 );
'`','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)
/*
- * 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);
-
- 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);
+ MSI_SetPropertyW(package, szCosting, szZero);
+ MSI_SetPropertyW(package, cszRootDrive, c_colon);
- load_all_files(package);
+ load_all_components( package );
+ load_all_features( package );
+ load_all_files( package );
return ERROR_SUCCESS;
}
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;
return ERROR_SUCCESS;
}
-
static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
{
static const WCHAR Query[] =
'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));
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;
-
- /* 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;
+ tgt_short = p;
+ src_short = folder_split_path( p, ':' );
+
+ /* split the long and short paths */
+ tgt_long = folder_split_path( tgt_short, '|' );
+ src_long = folder_split_path( src_short, '|' );
+
+ /* 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;
- /* 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);
- }
+ /* 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);
- 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 ));
+ 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);
+ parent = MSI_RecordGetString(row, 2);
if (parent)
{
folder->Parent = load_folder( package, parent );
return TRUE;
}
-static UINT SetFeatureStates(MSIPACKAGE *package)
+UINT MSI_SetFeatureStates(MSIPACKAGE *package)
{
int install_level;
static const WCHAR szlevel[] =
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),
ACTION_UpdateInstallStates(package);
- return SetFeatureStates(package);
+ return MSI_SetFeatureStates(package);
}
/* OK this value is "interpreted" and then formatted based on the
{'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;
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))
- {
- rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
- if (rc != ERROR_SUCCESS)
- continue;
+ /*
+ * 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)
- {
- msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
+ if (!comp->FullKeypath)
+ continue;
- 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, squished_pc, comp->FullKeypath );
- 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 );
- }
- }
- else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
+ if (comp->Attributes & msidbComponentAttributesPermanent)
{
- DWORD res;
+ 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 };
- rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
- if (rc != ERROR_SUCCESS)
- continue;
+ msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
+ }
- RegDeleteValueW(hkey2,squished_pc);
+ RegCloseKey(hkey2);
- /* 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 );
- }
+ /* 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;
+
+ 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;
}
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
{
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);
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);
/* 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,'['))
msi_free(target_file);
- IPersistFile_Release( pf );
- IShellLinkW_Release( sl );
+err:
+ if (pf)
+ IPersistFile_Release( pf );
+ if (sl)
+ IShellLinkW_Release( sl );
return ERROR_SUCCESS;
}
CHAR buffer[1024];
DWORD sz;
UINT rc;
+ MSIRECORD *uirow;
FileName = MSI_RecordGetString(row,1);
if (!FileName)
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;
}
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);
STARTUPINFOW si;
PROCESS_INFORMATION info;
BOOL brc;
+ MSIRECORD *uirow;
+ LPWSTR uipath, p;
memset(&si,0,sizeof(STARTUPINFOW));
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;
}
GUID clsid;
INT size;
BOOL absent = FALSE;
+ MSIRECORD *uirow;
if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
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));
(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:
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 );
RegCloseKey(hkey);
+ /* FIXME: call ui_actiondata */
+
return ERROR_SUCCESS;
}
msi_free(productid);
RegCloseKey(hkey);
+ /* FIXME: call ui_actiondata */
+
return ERROR_SUCCESS;
}
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)
{
'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 );
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;
}
UINT rc = ERROR_SUCCESS;
MSICOMPONENT *comp;
DWORD sz = 0;
+ MSIRECORD *uirow;
component = MSI_RecordGetString(rec,3);
comp = get_loaded_component(package,component);
}
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);
sz+=3;
sz *= sizeof(WCHAR);
- output = msi_alloc(sz);
- memset(output,0,sz);
+ output = msi_alloc_zero(sz);
strcpyW(output,advertise);
msi_free(advertise);
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;
}
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 },
{ szMoveFiles, ACTION_MoveFiles },
{ szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
{ szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
- { szISInitAllUsers, NULL },
{ szInstallODBC, NULL},
{ szInstallServices, ACTION_InstallServices },
{ szPatchFiles, ACTION_PatchFiles },
{ szPublishFeatures, ACTION_PublishFeatures },
{ szPublishProduct, ACTION_PublishProduct },
{ szRegisterClassInfo, ACTION_RegisterClassInfo },
- { szRegisterComPlus, NULL},
+ { szRegisterComPlus, ACTION_RegisterComPlus},
{ szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
{ szRegisterFonts, ACTION_RegisterFonts },
{ szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
{ szUnpublishComponents, NULL},
{ szUnpublishFeatures, NULL},
{ szUnregisterClassInfo, NULL},
- { szUnregisterComPlus, NULL},
+ { szUnregisterComPlus, ACTION_UnregisterComPlus},
{ szUnregisterExtensionInfo, NULL},
{ szUnregisterFonts, ACTION_UnregisterFonts },
{ szUnregisterMIMEInfo, NULL},
*
* 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__
struct list entry;
LPWSTR Directory;
LPWSTR TargetDefault;
- LPWSTR SourceDefault;
+ LPWSTR SourceLongPath;
+ LPWSTR SourceShortPath;
LPWSTR ResolvedTarget;
LPWSTR ResolvedSource;
MSICOMPONENT *Component;
LPWSTR FileName;
LPWSTR ShortName;
+ LPWSTR LongName;
INT FileSize;
LPWSTR Version;
LPWSTR Language;
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 );
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);
*
* 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>
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;
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)
{
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);
}
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;
'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)
{
debugstr_w(guid));
end:
- msiobj_release(&row->hdr);
+ if (row)
+ msiobj_release(&row->hdr);
MSI_ViewClose(view);
msiobj_release(&view->hdr);
}
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;
'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);
/* 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:
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;
}
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);
}
return rc;
}
-static UINT ACTION_AppSearchIni(MSIPACKAGE *package, BOOL *appFound,
+static UINT ACTION_AppSearchIni(MSIPACKAGE *package, LPWSTR *appValue,
MSISIGNATURE *sig)
{
MSIQUERY *view;
'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)
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);
}
}
else
{
- DWORD zero, size = GetFileVersionInfoSizeW((LPWSTR)filePath, &zero);
+ DWORD zero, size = GetFileVersionInfoSizeW(filePath, &zero);
if (size)
{
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 =
* 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 };
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.
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;
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;
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;
}
}
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
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);
}
}
}
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;
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);
}
/* 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);
}
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.
*/
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)
while (!rc)
{
+ MSISIGNATURE sig;
+ LPWSTR value;
+
rc = MSI_ViewFetch(view,&row);
if (rc != ERROR_SUCCESS)
{
}
/* 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);
}
*
* 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
if (!progid)
return;
- if (progid->InstallMe == TRUE)
+ if (progid->InstallMe)
return;
progid->InstallMe = TRUE;
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 };
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);
* 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),
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)
*
* 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"
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
| value_s
{
$$ = ($1 && $1[0]) ? 1 : 0;
+ msi_free($1);
}
| value_i operator value_i
{
$$ = compare_int( num, $2, $3 );
else
$$ = ($2 == COND_NE || $2 == COND_INE );
+ msi_free($1);
}
| value_i operator symbol_s
{
$$ = compare_int( $1, $2, num );
else
$$ = ($2 == COND_NE || $2 == COND_INE );
+ msi_free($3);
}
| symbol_s operator symbol_s
{
| literal operator value_i
{
$$ = 0;
+ msi_free($1);
}
| value_i operator literal
{
$$ = 0;
+ msi_free($3);
}
| COND_LPAR expression COND_RPAR
{
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;
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 }
};
*
* 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>
}
-MSIVIEWOPS create_ops =
+static const MSIVIEWOPS create_ops =
{
CREATE_fetch_int,
NULL,
*
* 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 "msi.h"
#include "msidefs.h"
#include "msiquery.h"
-#include "fcntl.h"
+#include "msvcrt/fcntl.h"
#include "objbase.h"
#include "objidl.h"
#include "msipriv.h"
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,
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;
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);
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);
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 );
track_tempfile(package, tmp_file, tmp_file);
else
DeleteFileW(tmp_file);
-
+
return rc;
}
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)
{
*
* 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>
goto end;
}
else
- szwPersist = (LPWSTR)(DWORD)szPersist;
+ szwPersist = (LPWSTR)(DWORD_PTR)szPersist;
r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB );
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;
+}
*
* 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>
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);
+
+ return ERROR_FUNCTION_FAILED;
+}
+
-MSIVIEWOPS delete_ops =
+static const MSIVIEWOPS delete_ops =
{
DELETE_fetch_int,
DELETE_fetch_stream,
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 )
*
* 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
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 );
HBITMAP hBitmap;
HICON hIcon;
LPWSTR tabnext;
+ HMODULE hDll;
+ float progress_current;
+ float progress_max;
WCHAR name[1];
};
{
struct msi_font_tag *next;
HFONT hfont;
+ COLORREF color;
WCHAR name[1];
} msi_font;
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 };
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 * );
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 );
}
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;
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 );
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",
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) )
+ {
+ 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
{
- ERR("Attribute %s\n", debugstr_w(attribute));
+ 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',' ',
{
DWORD attributes;
LPCWSTR text, name;
+ DWORD exstyle = 0;
name = MSI_RecordGetString( rec, 2 );
attributes = MSI_RecordGetInteger( rec, 8 );
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;
};
info = GetPropW(hWnd, szButtonData);
+ if ( info->font )
+ SetTextColor( (HDC)wParam, info->font->color );
+
if( msg == WM_CTLCOLORSTATIC &&
( info->attributes & msidbControlAttributesTransparent ) )
{
{
msi_control *control;
struct msi_text_info *info;
+ LPCWSTR text, ptr;
+ LPWSTR font_name;
TRACE("%p %p\n", dialog, 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 );
msi_dialog *dialog;
msi_control *control;
WNDPROC oldproc;
- HMODULE hRichedit;
};
static LRESULT WINAPI
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;
}
};
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;
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 );
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_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_dialog_tv_add_child_features( MSIPACKAGE *package, HWND hwnd,
- LPCWSTR parent, HTREEITEM hParent )
+msi_seltree_add_child_features( MSIPACKAGE *package, HWND hwnd,
+ LPCWSTR parent, HTREEITEM hParent )
{
MSIFEATURE *feature;
TVINSERTSTRUCTW tvis;
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;
+ info = msi_alloc( sizeof *info );
+ if (!info)
+ return ERROR_FUNCTION_FAILED;
+
+ /* create the treeview control */
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 );
+ 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_dialog_tv_add_child_features( package, control->hwnd, NULL, NULL );
+ /* 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 );
- msi_free( val );
+ /* 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 },
{ 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])
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 );
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 );
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,
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 )
DestroyIcon( t->hIcon );
msi_free( t->tabnext );
msi_free( t );
+ if (t->hDll)
+ FreeLibrary( t->hDll );
}
/* destroy the list of fonts */
*
* 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>
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;
+
+ 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;
+}
+
-MSIVIEWOPS distinct_ops =
+static const MSIVIEWOPS distinct_ops =
{
DISTINCT_fetch_int,
NULL,
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 )
*
* 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 "action.h"
#include "wine/debug.h"
+#include "wine/unicode.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
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 },
{ "AddSource",ControlEvent_AddSource },
{ "SetTargetPath",ControlEvent_SetTargetPath },
{ "Reset",ControlEvent_Reset },
+ { "SetInstallLevel",ControlEvent_SetInstallLevel },
{ NULL,NULL },
};
*
* 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
*/
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;
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);
HANDLE handle;
LPWSTR file;
MSIFILE *f;
+ DWORD attrs;
file = strdupAtoW(pfdin->psz1);
f = get_loaded_file(data->package, file);
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",
{
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;
LPCWSTR cab, volume;
DWORD sz;
INT seq;
- UINT type;
LPCWSTR prompt;
MSICOMPONENT *comp = file->Component;
{
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;
}
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;
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);
}
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;
}
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);
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;
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;
if (!dest_path)
{
FIXME("Unable to get destination folder, try AppSearch properties\n");
- msi_free(file_source);
return ERROR_SUCCESS;
}
}
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;
}
LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
{
+ MSIRECORD *uirow;
+ LPWSTR uipath, p;
+
if ( !file->Component )
continue;
if ( file->Component->Installed == INSTALLSTATE_LOCAL )
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;
*
* 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
*/
/*
*
* 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>
TRACE("%lx\n",handle);
+ if (!handle)
+ return ERROR_SUCCESS;
+
EnterCriticalSection( &MSI_handle_cs );
info = msihandle2msiinfo(handle, 0);
*
* 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
*/
/*
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;
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;
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)
{
/* 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);
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)
}
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);
}
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 );
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 );
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))
{
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
- ControlEvent_FireSubscribedEvent(package,szActionData, row);
-
msiobj_release(&row->hdr);
}
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;
+
+ /* > is used if there is a component GUID and < if not. */
- memset(productid_85,0,sizeof(productid_85));
- memset(component_85,0,sizeof(component_85));
+ 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;
}
*
* 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>
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);
+
+ return ERROR_FUNCTION_FAILED;
+}
+
-MSIVIEWOPS insert_ops =
+static const MSIVIEWOPS insert_ops =
{
INSERT_fetch_int,
NULL,
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,
*
* 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 */
#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);
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;
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);
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);
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;
* Not in the state: FALSE
*
*/
-
BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
{
BOOL r = FALSE;
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)
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)
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)
{
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};
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;
+}
--- /dev/null
+/*
+ * 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;
+}
*
* 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>
WINE_DEFAULT_DEBUG_CHANNEL(msi);
-/* 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;
-
-static LONG dll_count;
-
static const WCHAR installerW[] = {'\\','I','n','s','t','a','l','l','e','r',0};
-/*
- * Dll lifetime tracking declaration
- */
-static void LockModule(void)
-{
- InterlockedIncrement(&dll_count);
-}
-
-static void UnlockModule(void)
-{
- InterlockedDecrement(&dll_count);
-}
-
-
UINT WINAPI MsiOpenProductA(LPCSTR szProduct, MSIHANDLE *phProduct)
{
UINT r;
MSIPACKAGE *package = NULL;
UINT r;
- FIXME("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine));
+ TRACE("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine));
r = MSI_OpenPackageW( szPackagePath, &package );
if (r == ERROR_SUCCESS)
' ','I','n','s','t','a','l','l','e','d','=','1',0};
LPWSTR commandline;
- FIXME("%s %d %d %s\n",debugstr_w(szProduct), iInstallLevel, eInstallState,
+ TRACE("%s %d %d %s\n",debugstr_w(szProduct), iInstallLevel, eInstallState,
debugstr_w(szCommandLine));
if (eInstallState != INSTALLSTATE_LOCAL &&
UINT WINAPI MsiConfigureProductW(LPCWSTR szProduct, int iInstallLevel,
INSTALLSTATE eInstallState)
{
- FIXME("%s %d %d\n", debugstr_w(szProduct), iInstallLevel, eInstallState);
-
return MsiConfigureProductExW(szProduct, iInstallLevel, eInstallState, NULL);
}
return ERROR_SUCCESS;
}
-UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute,
- LPSTR szBuffer, DWORD *pcchValueBuf)
-{
- LPWSTR szwProduct = NULL, szwAttribute = NULL, szwBuffer = NULL;
- UINT r = ERROR_OUTOFMEMORY;
- DWORD pcchwValueBuf = 0;
-
- TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szAttribute),
- szBuffer, pcchValueBuf);
-
- if( szProduct )
- {
- szwProduct = strdupAtoW( szProduct );
- if( !szwProduct )
- goto end;
- }
-
- if( szAttribute )
- {
- szwAttribute = strdupAtoW( szAttribute );
- if( !szwAttribute )
- goto end;
- }
-
- if( szBuffer )
- {
- szwBuffer = msi_alloc( (*pcchValueBuf) * sizeof(WCHAR) );
- pcchwValueBuf = *pcchValueBuf;
- if( !szwBuffer )
- goto end;
- }
-
- r = MsiGetProductInfoW( szwProduct, szwAttribute, szwBuffer,
- &pcchwValueBuf );
-
- if( ERROR_SUCCESS == r )
- {
- INT old_len = *pcchValueBuf;
- *pcchValueBuf = WideCharToMultiByte(CP_ACP, 0, szwBuffer, pcchwValueBuf,
- szBuffer, *pcchValueBuf, NULL, NULL);
- if (old_len > *pcchValueBuf)
- szBuffer[*pcchValueBuf]=0;
- }
-
-end:
- msi_free( szwProduct );
- msi_free( szwAttribute );
- msi_free( szwBuffer );
-
- return r;
-}
-
-UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute,
- LPWSTR szBuffer, DWORD *pcchValueBuf)
+UINT WINAPI MSI_GetProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute,
+ awstring *szValue, DWORD *pcchValueBuf)
{
- MSIHANDLE hProduct;
UINT r;
- static const WCHAR szProductVersion[] =
- {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
- static const WCHAR szProductLanguage[] =
- {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
+ HKEY hkey;
+ LPWSTR val = NULL;
- FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szAttribute),
- szBuffer, pcchValueBuf);
+ TRACE("%s %s %p %p\n", debugstr_w(szProduct),
+ debugstr_w(szAttribute), szValue, pcchValueBuf);
- if (NULL != szBuffer && NULL == pcchValueBuf)
- return ERROR_INVALID_PARAMETER;
- if (NULL == szProduct || NULL == szAttribute)
+ /*
+ * FIXME: Values seem scattered/duplicated in the registry. Is there a system?
+ */
+
+ if ((szValue->str.w && !pcchValueBuf) || !szProduct || !szAttribute)
return ERROR_INVALID_PARAMETER;
-
+
/* check for special properties */
- if (strcmpW(szAttribute, INSTALLPROPERTY_PACKAGECODEW)==0)
+ if (!lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGECODEW))
{
- HKEY hkey;
- WCHAR squished[GUID_SIZE];
- WCHAR package[200];
- DWORD sz = sizeof(squished);
+ LPWSTR regval;
+ WCHAR packagecode[35];
r = MSIREG_OpenUserProductsKey(szProduct, &hkey, FALSE);
if (r != ERROR_SUCCESS)
return ERROR_UNKNOWN_PRODUCT;
- r = RegQueryValueExW(hkey, INSTALLPROPERTY_PACKAGECODEW, NULL, NULL,
- (LPBYTE)squished, &sz);
- if (r != ERROR_SUCCESS)
- {
- RegCloseKey(hkey);
- return ERROR_UNKNOWN_PRODUCT;
- }
-
- unsquash_guid(squished, package);
- *pcchValueBuf = strlenW(package);
- if (strlenW(package) > *pcchValueBuf)
+ regval = msi_reg_get_val_str( hkey, szAttribute );
+ if (regval)
{
- RegCloseKey(hkey);
- return ERROR_MORE_DATA;
+ if (unsquash_guid(regval, packagecode))
+ val = strdupW(packagecode);
+ msi_free(regval);
}
- else
- strcpyW(szBuffer, package);
RegCloseKey(hkey);
- r = ERROR_SUCCESS;
}
- else if (strcmpW(szAttribute, INSTALLPROPERTY_VERSIONSTRINGW)==0)
+ else if (!lstrcmpW(szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW))
{
- r = MsiOpenProductW(szProduct, &hProduct);
- if (ERROR_SUCCESS != r)
- return r;
-
- r = MsiGetPropertyW(hProduct, szProductVersion, szBuffer, pcchValueBuf);
- MsiCloseHandle(hProduct);
+ static const WCHAR one[] = { '1',0 };
+ /*
+ * FIXME: should be in the Product key (user or system?)
+ * but isn't written yet...
+ */
+ val = strdupW( one );
}
- else if (strcmpW(szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW)==0)
+ else if (!lstrcmpW(szAttribute, INSTALLPROPERTY_LANGUAGEW) ||
+ !lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONW))
{
- FIXME("0 (zero) if advertised or per user , 1(one) if per machine.\n");
- if (szBuffer)
+ static const WCHAR fmt[] = { '%','u',0 };
+ WCHAR szVal[16];
+ DWORD regval;
+
+ r = MSIREG_OpenUninstallKey(szProduct, &hkey, FALSE);
+ if (r != ERROR_SUCCESS)
+ return ERROR_UNKNOWN_PRODUCT;
+
+ if (msi_reg_get_val_dword( hkey, szAttribute, ®val))
{
- szBuffer[0] = '1';
- szBuffer[1] = 0;
+ sprintfW(szVal, fmt, regval);
+ val = strdupW( szVal );
}
- if (pcchValueBuf)
- *pcchValueBuf = 1;
- r = ERROR_SUCCESS;
+
+ RegCloseKey(hkey);
}
- else if (strcmpW(szAttribute, INSTALLPROPERTY_LANGUAGEW)==0)
+ else if (!lstrcmpW(szAttribute, INSTALLPROPERTY_PRODUCTNAMEW))
{
- r = MsiOpenProductW(szProduct, &hProduct);
- if (ERROR_SUCCESS != r)
- return r;
+ r = MSIREG_OpenUserProductsKey(szProduct, &hkey, FALSE);
+ if (r != ERROR_SUCCESS)
+ return ERROR_UNKNOWN_PRODUCT;
- r = MsiGetPropertyW(hProduct, szProductLanguage, szBuffer, pcchValueBuf);
- MsiCloseHandle(hProduct);
+ val = msi_reg_get_val_str( hkey, szAttribute );
+
+ RegCloseKey(hkey);
}
else
{
- r = MsiOpenProductW(szProduct, &hProduct);
- if (ERROR_SUCCESS != r)
- return r;
+ static const WCHAR szDisplayVersion[] = {
+ 'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0 };
+
+ FIXME("%s\n", debugstr_w(szAttribute));
+ /* FIXME: some attribute values not tested... */
+
+ if (!lstrcmpW( szAttribute, INSTALLPROPERTY_VERSIONSTRINGW ))
+ szAttribute = szDisplayVersion;
+
+ r = MSIREG_OpenUninstallKey( szProduct, &hkey, FALSE );
+ if (r != ERROR_SUCCESS)
+ return ERROR_UNKNOWN_PRODUCT;
+
+ val = msi_reg_get_val_str( hkey, szAttribute );
- r = MsiGetPropertyW(hProduct, szAttribute, szBuffer, pcchValueBuf);
- MsiCloseHandle(hProduct);
+ RegCloseKey(hkey);
}
+ TRACE("returning %s\n", debugstr_w(val));
+
+ if (!val)
+ return ERROR_UNKNOWN_PROPERTY;
+
+ r = msi_strcpy_to_awstring( val, szValue, pcchValueBuf );
+
+ msi_free(val);
+
+ return r;
+}
+
+UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute,
+ LPSTR szBuffer, DWORD *pcchValueBuf)
+{
+ LPWSTR szwProduct, szwAttribute = NULL;
+ UINT r = ERROR_OUTOFMEMORY;
+ awstring buffer;
+
+ TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szAttribute),
+ szBuffer, pcchValueBuf);
+
+ szwProduct = strdupAtoW( szProduct );
+ if( szProduct && !szwProduct )
+ goto end;
+
+ szwAttribute = strdupAtoW( szAttribute );
+ if( szAttribute && !szwAttribute )
+ goto end;
+
+ buffer.unicode = FALSE;
+ buffer.str.a = szBuffer;
+
+ r = MSI_GetProductInfo( szwProduct, szwAttribute,
+ &buffer, pcchValueBuf );
+
+end:
+ msi_free( szwProduct );
+ msi_free( szwAttribute );
+
return r;
}
+UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute,
+ LPWSTR szBuffer, DWORD *pcchValueBuf)
+{
+ awstring buffer;
+
+ TRACE("%s %s %p %p\n", debugstr_w(szProduct), debugstr_w(szAttribute),
+ szBuffer, pcchValueBuf);
+
+ buffer.unicode = TRUE;
+ buffer.str.w = szBuffer;
+
+ return MSI_GetProductInfo( szProduct, szAttribute,
+ &buffer, pcchValueBuf );
+}
+
UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes)
{
LPWSTR szwLogFile = NULL;
TRACE("%08lx %s %08lx\n", dwLogMode, debugstr_w(szLogFile), attributes);
- lstrcpyW(gszLogFile,szLogFile);
- if (!(attributes & INSTALLLOGATTRIBUTES_APPEND))
- DeleteFileW(szLogFile);
- file = CreateFileW(szLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
- FILE_ATTRIBUTE_NORMAL, NULL);
- if (file != INVALID_HANDLE_VALUE)
- CloseHandle(file);
+ if (szLogFile)
+ {
+ lstrcpyW(gszLogFile,szLogFile);
+ if (!(attributes & INSTALLLOGATTRIBUTES_APPEND))
+ DeleteFileW(szLogFile);
+ file = CreateFileW(szLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ if (file != INVALID_HANDLE_VALUE)
+ CloseHandle(file);
+ else
+ ERR("Unable to enable log %s\n",debugstr_w(szLogFile));
+ }
else
- ERR("Unable to enable log %s\n",debugstr_w(szLogFile));
+ gszLogFile[0] = '\0';
return ERROR_SUCCESS;
}
TRACE("%s\n", debugstr_w(szProduct));
+ if (!szProduct)
+ return INSTALLSTATE_INVALIDARG;
+
rc = MSIREG_OpenUserProductsKey(szProduct,&hkey,FALSE);
if (rc != ERROR_SUCCESS)
goto end;
INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf,
DWORD *pcchBuf)
{
- /* This FIXME will crash some installer
- * FIXME("%s %p %p\n", debugstr_a(szComponent), lpPathBuf, pcchBuf);
- */
- return INSTALLSTATE_UNKNOWN;
+ char szProduct[GUID_SIZE];
+
+ TRACE("%s %p %p\n", debugstr_a(szComponent), lpPathBuf, pcchBuf);
+
+ if (MsiGetProductCodeA( szComponent, szProduct ) != ERROR_SUCCESS)
+ return INSTALLSTATE_UNKNOWN;
+
+ return MsiGetComponentPathA( szProduct, szComponent, lpPathBuf, pcchBuf );
}
INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf,
DWORD *pcchBuf)
{
- FIXME("%s %p %p\n", debugstr_w(szComponent), lpPathBuf, pcchBuf);
- return INSTALLSTATE_UNKNOWN;
+ WCHAR szProduct[GUID_SIZE];
+
+ TRACE("%s %p %p\n", debugstr_w(szComponent), lpPathBuf, pcchBuf);
+
+ if (MsiGetProductCodeW( szComponent, szProduct ) != ERROR_SUCCESS)
+ return INSTALLSTATE_UNKNOWN;
+
+ return MsiGetComponentPathW( szProduct, szComponent, lpPathBuf, pcchBuf );
}
UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType,
return r;
}
-INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent,
- LPSTR lpPathBuf, DWORD* pcchBuf)
-{
- LPWSTR szwProduct = NULL, szwComponent = NULL, lpwPathBuf= NULL;
- INSTALLSTATE rc;
- UINT incoming_len;
-
- if( szProduct )
- {
- szwProduct = strdupAtoW( szProduct );
- if( !szwProduct)
- return ERROR_OUTOFMEMORY;
- }
-
- if( szComponent )
- {
- szwComponent = strdupAtoW( szComponent );
- if( !szwComponent )
- {
- msi_free( szwProduct);
- return ERROR_OUTOFMEMORY;
- }
- }
-
- if( pcchBuf && *pcchBuf > 0 )
- {
- lpwPathBuf = msi_alloc( *pcchBuf * sizeof(WCHAR));
- incoming_len = *pcchBuf;
- }
- else
- {
- lpwPathBuf = NULL;
- incoming_len = 0;
- }
-
- rc = MsiGetComponentPathW(szwProduct, szwComponent, lpwPathBuf, pcchBuf);
-
- msi_free( szwProduct);
- msi_free( szwComponent);
- if (lpwPathBuf)
- {
- if (rc != INSTALLSTATE_UNKNOWN)
- WideCharToMultiByte(CP_ACP, 0, lpwPathBuf, incoming_len,
- lpPathBuf, incoming_len, NULL, NULL);
- msi_free( lpwPathBuf);
- }
-
- return rc;
-}
-
-INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent,
- LPWSTR lpPathBuf, DWORD* pcchBuf)
+INSTALLSTATE WINAPI MSI_GetComponentPath(LPCWSTR szProduct, LPCWSTR szComponent,
+ awstring* lpPathBuf, DWORD* pcchBuf)
{
- WCHAR squished_pc[GUID_SIZE];
+ WCHAR squished_pc[GUID_SIZE], squished_comp[GUID_SIZE];
UINT rc;
- INSTALLSTATE rrc = INSTALLSTATE_UNKNOWN;
HKEY hkey = 0;
LPWSTR path = NULL;
- DWORD sz, type;
+ INSTALLSTATE r;
TRACE("%s %s %p %p\n", debugstr_w(szProduct),
- debugstr_w(szComponent), lpPathBuf, pcchBuf);
+ debugstr_w(szComponent), lpPathBuf->str.w, pcchBuf);
- if( !szComponent )
+ if( !szProduct || !szComponent )
return INSTALLSTATE_INVALIDARG;
- if( lpPathBuf && !pcchBuf )
+ if( lpPathBuf->str.w && !pcchBuf )
return INSTALLSTATE_INVALIDARG;
- squash_guid(szProduct,squished_pc);
+ if (!squash_guid( szProduct, squished_pc ) ||
+ !squash_guid( szComponent, squished_comp ))
+ return INSTALLSTATE_INVALIDARG;
rc = MSIREG_OpenProductsKey( szProduct, &hkey, FALSE);
if( rc != ERROR_SUCCESS )
- goto end;
+ return INSTALLSTATE_UNKNOWN;
RegCloseKey(hkey);
rc = MSIREG_OpenComponentsKey( szComponent, &hkey, FALSE);
if( rc != ERROR_SUCCESS )
- goto end;
-
- sz = 0;
- type = 0;
- rc = RegQueryValueExW( hkey, squished_pc, NULL, &type, NULL, &sz );
- if( rc != ERROR_SUCCESS )
- goto end;
- if( type != REG_SZ )
- goto end;
-
- sz += sizeof(WCHAR);
- path = msi_alloc( sz );
- if( !path )
- goto end;
+ return INSTALLSTATE_UNKNOWN;
- rc = RegQueryValueExW( hkey, squished_pc, NULL, NULL, (LPVOID) path, &sz );
- if( rc != ERROR_SUCCESS )
- goto end;
+ path = msi_reg_get_val_str( hkey, squished_pc );
+ RegCloseKey(hkey);
TRACE("found path of (%s:%s)(%s)\n", debugstr_w(szComponent),
debugstr_w(szProduct), debugstr_w(path));
- if (path[0]=='0')
- {
- FIXME("Registry entry.. check entry\n");
- rrc = INSTALLSTATE_LOCAL;
- }
+ if (!path)
+ return INSTALLSTATE_UNKNOWN;
+
+ if (path[0])
+ r = INSTALLSTATE_LOCAL;
else
- {
- /* PROBABLY a file */
- if ( GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES )
- rrc = INSTALLSTATE_LOCAL;
- else
- rrc = INSTALLSTATE_ABSENT;
- }
+ r = INSTALLSTATE_NOTUSED;
- if( pcchBuf )
- {
- sz = sz / sizeof(WCHAR);
- if( *pcchBuf >= sz )
- lstrcpyW( lpPathBuf, path );
- *pcchBuf = sz;
- }
+ msi_strcpy_to_awstring( path, lpPathBuf, pcchBuf );
+
+ msi_free( path );
+ return r;
+}
+
+/******************************************************************
+ * MsiGetComponentPathW [MSI.@]
+ */
+INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent,
+ LPWSTR lpPathBuf, DWORD* pcchBuf)
+{
+ awstring path;
+
+ path.unicode = TRUE;
+ path.str.w = lpPathBuf;
+
+ return MSI_GetComponentPath( szProduct, szComponent, &path, pcchBuf );
+}
+
+/******************************************************************
+ * MsiGetComponentPathA [MSI.@]
+ */
+INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent,
+ LPSTR lpPathBuf, DWORD* pcchBuf)
+{
+ LPWSTR szwProduct, szwComponent = NULL;
+ INSTALLSTATE r = INSTALLSTATE_UNKNOWN;
+ awstring path;
+
+ szwProduct = strdupAtoW( szProduct );
+ if( szProduct && !szwProduct)
+ goto end;
+
+ szwComponent = strdupAtoW( szComponent );
+ if( szComponent && !szwComponent )
+ goto end;
+
+ path.unicode = FALSE;
+ path.str.a = lpPathBuf;
+
+ r = MSI_GetComponentPath( szwProduct, szwComponent, &path, pcchBuf );
end:
- msi_free(path );
- RegCloseKey(hkey);
- return rrc;
+ msi_free( szwProduct );
+ msi_free( szwComponent );
+
+ return r;
}
/******************************************************************
/******************************************************************
* MsiQueryFeatureStateW [MSI.@]
*
- * This does not verify that the Feature is functional. So i am only going to
- * check the existence of the key in the registry. This should tell me if it is
- * installed.
+ * Checks the state of a feature
+ *
+ * PARAMS
+ * szProduct [I] Product's GUID string
+ * szFeature [I] Feature's GUID string
+ *
+ * RETURNS
+ * INSTALLSTATE_LOCAL Feature is installed and useable
+ * INSTALLSTATE_ABSENT Feature is absent
+ * INSTALLSTATE_ADVERTISED Feature should be installed on demand
+ * INSTALLSTATE_UNKNOWN An error occured
+ * INSTALLSTATE_INVALIDARG One of the GUIDs was invalid
+ *
*/
INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
{
- WCHAR squishProduct[GUID_SIZE];
+ WCHAR squishProduct[33], comp[GUID_SIZE];
+ GUID guid;
+ LPWSTR components, p, parent_feature;
UINT rc;
- DWORD sz = 0;
HKEY hkey;
+ INSTALLSTATE r;
+ BOOL missing = FALSE;
TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
if (!squash_guid( szProduct, squishProduct ))
return INSTALLSTATE_INVALIDARG;
+ /* check that it's installed at all */
+ rc = MSIREG_OpenUserFeaturesKey(szProduct, &hkey, FALSE);
+ if (rc != ERROR_SUCCESS)
+ return INSTALLSTATE_UNKNOWN;
+
+ parent_feature = msi_reg_get_val_str( hkey, szFeature );
+ RegCloseKey(hkey);
+
+ if (!parent_feature)
+ return INSTALLSTATE_UNKNOWN;
+
+ r = (parent_feature[0] == 6) ? INSTALLSTATE_ABSENT : INSTALLSTATE_LOCAL;
+ msi_free(parent_feature);
+ if (r == INSTALLSTATE_ABSENT)
+ return r;
+
+ /* now check if it's complete or advertised */
rc = MSIREG_OpenFeaturesKey(szProduct, &hkey, FALSE);
if (rc != ERROR_SUCCESS)
return INSTALLSTATE_UNKNOWN;
- rc = RegQueryValueExW( hkey, szFeature, NULL, NULL, NULL, &sz);
+ components = msi_reg_get_val_str( hkey, szFeature );
RegCloseKey(hkey);
- if (rc == ERROR_SUCCESS)
- return INSTALLSTATE_LOCAL;
+ TRACE("rc = %d buffer = %s\n", rc, debugstr_w(components));
+
+ if (!components)
+ {
+ ERR("components missing %s %s\n",
+ debugstr_w(szProduct), debugstr_w(szFeature));
+ return INSTALLSTATE_UNKNOWN;
+ }
+
+ for( p = components; *p != 2 ; p += 20)
+ {
+ if (!decode_base85_guid( p, &guid ))
+ {
+ ERR("%s\n", debugstr_w(p));
+ break;
+ }
+ StringFromGUID2(&guid, comp, GUID_SIZE);
+ r = MsiGetComponentPathW(szProduct, comp, NULL, 0);
+ TRACE("component %s state %d\n", debugstr_guid(&guid), r);
+ switch (r)
+ {
+ case INSTALLSTATE_NOTUSED:
+ case INSTALLSTATE_LOCAL:
+ case INSTALLSTATE_SOURCE:
+ break;
+ default:
+ missing = TRUE;
+ }
+ }
+
+ TRACE("%s %s -> %d\n", debugstr_w(szProduct), debugstr_w(szFeature), r);
+ msi_free(components);
- return INSTALLSTATE_UNKNOWN;
+ if (missing)
+ return INSTALLSTATE_ADVERTISED;
+
+ return INSTALLSTATE_LOCAL;
}
/******************************************************************
return ret;
}
-
-/******************************************************************
- * DllMain
+/***********************************************************************
+ * MsiGetFeatureUsageW [MSI.@]
*/
-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();
- /* FIXME: Cleanup */
- 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;
-}
-
-/***********************************************************************
- * MsiGetFeatureUsageW [MSI.@]
- */
-UINT WINAPI MsiGetFeatureUsageW( LPCWSTR szProduct, LPCWSTR szFeature,
- DWORD* pdwUseCount, WORD* pwDateUsed )
+UINT WINAPI MsiGetFeatureUsageW( LPCWSTR szProduct, LPCWSTR szFeature,
+ DWORD* pdwUseCount, WORD* pwDateUsed )
{
FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),
pdwUseCount, pwDateUsed);
return ret;
}
+/***********************************************************************
+ * MsiUseFeatureW [MSI.@]
+ */
INSTALLSTATE WINAPI MsiUseFeatureW( LPCWSTR szProduct, LPCWSTR szFeature )
{
- FIXME("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
-
- return INSTALLSTATE_LOCAL;
+ return MsiUseFeatureExW(szProduct, szFeature, 0, 0);
}
+/***********************************************************************
+ * MsiUseFeatureA [MSI.@]
+ */
INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature )
{
- INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
- LPWSTR prod = NULL, feat = NULL;
-
- TRACE("%s %s\n", debugstr_a(szProduct), debugstr_a(szFeature) );
-
- prod = strdupAtoW( szProduct );
- if (szProduct && !prod)
- goto end;
-
- feat = strdupAtoW( szFeature );
- if (szFeature && !feat)
- goto end;
-
- ret = MsiUseFeatureW( prod, feat );
-
-end:
- msi_free( prod );
- msi_free( feat );
-
- return ret;
+ return MsiUseFeatureExA(szProduct, szFeature, 0, 0);
}
/***********************************************************************
- * MsiProvideQualifiedComponentExW [MSI.@]
+ * MSI_ProvideQualifiedComponentEx [internal]
*/
-UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
+UINT WINAPI MSI_ProvideQualifiedComponentEx(LPCWSTR szComponent,
LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR szProduct,
- DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf,
+ DWORD Unused1, DWORD Unused2, awstring *lpPathBuf,
DWORD* pcchPathBuf)
{
- HKEY hkey;
- UINT rc;
+ WCHAR product[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1],
+ feature[MAX_FEATURE_CHARS+1];
LPWSTR info;
+ HKEY hkey;
DWORD sz;
- WCHAR product[MAX_FEATURE_CHARS+1];
- WCHAR component[MAX_FEATURE_CHARS+1];
- WCHAR feature[MAX_FEATURE_CHARS+1];
+ UINT rc;
TRACE("%s %s %li %s %li %li %p %p\n", debugstr_w(szComponent),
debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct),
Unused1, Unused2, lpPathBuf, pcchPathBuf);
-
+
rc = MSIREG_OpenUserComponentsKey(szComponent, &hkey, FALSE);
if (rc != ERROR_SUCCESS)
return ERROR_INDEX_ABSENT;
- sz = 0;
- rc = RegQueryValueExW( hkey, szQualifier, NULL, NULL, NULL, &sz);
- if (sz <= 0)
- {
- RegCloseKey(hkey);
- return ERROR_INDEX_ABSENT;
- }
+ info = msi_reg_get_val_str( hkey, szQualifier );
+ RegCloseKey(hkey);
- info = msi_alloc(sz);
- rc = RegQueryValueExW( hkey, szQualifier, NULL, NULL, (LPBYTE)info, &sz);
- if (rc != ERROR_SUCCESS)
- {
- RegCloseKey(hkey);
- msi_free(info);
+ if (!info)
return ERROR_INDEX_ABSENT;
- }
MsiDecomposeDescriptorW(info, product, feature, component, &sz);
-
+
if (!szProduct)
- rc = MsiGetComponentPathW(product, component, lpPathBuf, pcchPathBuf);
+ rc = MSI_GetComponentPath(product, component, lpPathBuf, pcchPathBuf);
else
- rc = MsiGetComponentPathW(szProduct, component, lpPathBuf, pcchPathBuf);
-
- RegCloseKey(hkey);
- msi_free(info);
+ rc = MSI_GetComponentPath(szProduct, component, lpPathBuf, pcchPathBuf);
- if (rc == INSTALLSTATE_LOCAL)
- return ERROR_SUCCESS;
- else
+
+ if (rc != INSTALLSTATE_LOCAL)
return ERROR_FILE_NOT_FOUND;
+
+ return ERROR_SUCCESS;
}
/***********************************************************************
- * MsiProvideQualifiedComponentW [MSI.@]
+ * MsiProvideQualifiedComponentExW [MSI.@]
*/
-UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent,
- LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf,
+UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
+ LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR szProduct,
+ DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf,
DWORD* pcchPathBuf)
{
- return MsiProvideQualifiedComponentExW(szComponent, szQualifier,
- dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
+ awstring path;
+
+ path.unicode = TRUE;
+ path.str.w = lpPathBuf;
+
+ return MSI_ProvideQualifiedComponentEx(szComponent, szQualifier,
+ dwInstallMode, szProduct, Unused1, Unused2, &path, pcchPathBuf);
}
/***********************************************************************
- * MsiProvideQualifiedComponentA [MSI.@]
+ * MsiProvideQualifiedComponentExA [MSI.@]
*/
-UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent,
- LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf,
+UINT WINAPI MsiProvideQualifiedComponentExA(LPCSTR szComponent,
+ LPCSTR szQualifier, DWORD dwInstallMode, LPSTR szProduct,
+ DWORD Unused1, DWORD Unused2, LPSTR lpPathBuf,
DWORD* pcchPathBuf)
{
- LPWSTR szwComponent, szwQualifier, lpwPathBuf;
- DWORD pcchwPathBuf;
- UINT rc;
+ LPWSTR szwComponent, szwQualifier = NULL, szwProduct = NULL;
+ UINT r = ERROR_OUTOFMEMORY;
+ awstring path;
- TRACE("%s %s %li %p %p\n",szComponent, szQualifier,
- dwInstallMode, lpPathBuf, pcchPathBuf);
+ TRACE("%s %s %lu %s %lu %lu %p %p\n", debugstr_a(szComponent),
+ debugstr_a(szQualifier), dwInstallMode, debugstr_a(szProduct),
+ Unused1, Unused2, lpPathBuf, pcchPathBuf);
- szwComponent= strdupAtoW( szComponent);
- szwQualifier= strdupAtoW( szQualifier);
+ szwComponent = strdupAtoW( szComponent );
+ if (szComponent && !szwComponent)
+ goto end;
- lpwPathBuf = msi_alloc(*pcchPathBuf * sizeof(WCHAR));
+ szwQualifier = strdupAtoW( szQualifier );
+ if (szQualifier && !szwQualifier)
+ goto end;
- pcchwPathBuf = *pcchPathBuf;
+ szwProduct = strdupAtoW( szProduct );
+ if (szProduct && !szwProduct)
+ goto end;
- rc = MsiProvideQualifiedComponentW(szwComponent, szwQualifier,
- dwInstallMode, lpwPathBuf, &pcchwPathBuf);
+ path.unicode = FALSE;
+ path.str.a = lpPathBuf;
+ r = MSI_ProvideQualifiedComponentEx(szwComponent, szwQualifier,
+ dwInstallMode, szwProduct, Unused1,
+ Unused2, &path, pcchPathBuf);
+end:
+ msi_free(szwProduct);
msi_free(szwComponent);
msi_free(szwQualifier);
- *pcchPathBuf = WideCharToMultiByte(CP_ACP, 0, lpwPathBuf, pcchwPathBuf,
- lpPathBuf, *pcchPathBuf, NULL, NULL);
- msi_free(lpwPathBuf);
- return rc;
+ return r;
+}
+
+/***********************************************************************
+ * MsiProvideQualifiedComponentW [MSI.@]
+ */
+UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent,
+ LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf,
+ DWORD* pcchPathBuf)
+{
+ return MsiProvideQualifiedComponentExW(szComponent, szQualifier,
+ dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
}
-USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct, LPWSTR lpUserNameBuf,
- DWORD* pcchUserNameBuf, LPWSTR lpOrgNameBuf,
- DWORD* pcchOrgNameBuf, LPWSTR lpSerialBuf, DWORD* pcchSerialBuf)
+/***********************************************************************
+ * MsiProvideQualifiedComponentA [MSI.@]
+ */
+UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent,
+ LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf,
+ DWORD* pcchPathBuf)
+{
+ return MsiProvideQualifiedComponentExA(szComponent, szQualifier,
+ dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
+}
+
+/***********************************************************************
+ * MSI_GetUserInfo [internal]
+ */
+USERINFOSTATE WINAPI MSI_GetUserInfo(LPCWSTR szProduct,
+ awstring *lpUserNameBuf, DWORD* pcchUserNameBuf,
+ awstring *lpOrgNameBuf, DWORD* pcchOrgNameBuf,
+ awstring *lpSerialBuf, DWORD* pcchSerialBuf)
{
HKEY hkey;
- DWORD sz;
- UINT rc = ERROR_SUCCESS,rc2 = ERROR_SUCCESS;
+ LPWSTR user, org, serial;
+ UINT r;
+ USERINFOSTATE state;
TRACE("%s %p %p %p %p %p %p\n",debugstr_w(szProduct), lpUserNameBuf,
pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
pcchSerialBuf);
- rc = MSIREG_OpenUninstallKey(szProduct, &hkey, FALSE);
- if (rc != ERROR_SUCCESS)
+ if (!szProduct)
+ return USERINFOSTATE_INVALIDARG;
+
+ r = MSIREG_OpenUninstallKey(szProduct, &hkey, FALSE);
+ if (r != ERROR_SUCCESS)
return USERINFOSTATE_UNKNOWN;
- if (lpUserNameBuf)
- {
- sz = *lpUserNameBuf * sizeof(WCHAR);
- rc = RegQueryValueExW( hkey, INSTALLPROPERTY_REGOWNERW, NULL,
- NULL, (LPBYTE)lpUserNameBuf,
- &sz);
- }
- if (!lpUserNameBuf && pcchUserNameBuf)
- {
- sz = 0;
- rc = RegQueryValueExW( hkey, INSTALLPROPERTY_REGOWNERW, NULL,
- NULL, NULL, &sz);
- }
+ user = msi_reg_get_val_str( hkey, INSTALLPROPERTY_REGOWNERW );
+ org = msi_reg_get_val_str( hkey, INSTALLPROPERTY_REGCOMPANYW );
+ serial = msi_reg_get_val_str( hkey, INSTALLPROPERTY_PRODUCTIDW );
- if (pcchUserNameBuf)
- *pcchUserNameBuf = sz / sizeof(WCHAR);
+ RegCloseKey(hkey);
- if (lpOrgNameBuf)
- {
- sz = *pcchOrgNameBuf * sizeof(WCHAR);
- rc2 = RegQueryValueExW( hkey, INSTALLPROPERTY_REGCOMPANYW, NULL,
- NULL, (LPBYTE)lpOrgNameBuf, &sz);
- }
- if (!lpOrgNameBuf && pcchOrgNameBuf)
- {
- sz = 0;
- rc2 = RegQueryValueExW( hkey, INSTALLPROPERTY_REGCOMPANYW, NULL,
- NULL, NULL, &sz);
- }
+ state = USERINFOSTATE_PRESENT;
- if (pcchOrgNameBuf)
- *pcchOrgNameBuf = sz / sizeof(WCHAR);
+ r = msi_strcpy_to_awstring( user, lpUserNameBuf, pcchUserNameBuf );
+ if (r == ERROR_MORE_DATA)
+ state = USERINFOSTATE_MOREDATA;
+ r = msi_strcpy_to_awstring( org, lpOrgNameBuf, pcchOrgNameBuf );
+ if (r == ERROR_MORE_DATA)
+ state = USERINFOSTATE_MOREDATA;
+ r = msi_strcpy_to_awstring( serial, lpSerialBuf, pcchSerialBuf );
+ if (r == ERROR_MORE_DATA)
+ state = USERINFOSTATE_MOREDATA;
- if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA &&
- rc2 != ERROR_SUCCESS && rc2 != ERROR_MORE_DATA)
- {
- RegCloseKey(hkey);
- return USERINFOSTATE_ABSENT;
- }
+ msi_free( user );
+ msi_free( org );
+ msi_free( serial );
- if (lpSerialBuf)
- {
- sz = *pcchSerialBuf * sizeof(WCHAR);
- RegQueryValueExW( hkey, INSTALLPROPERTY_PRODUCTIDW, NULL, NULL,
- (LPBYTE)lpSerialBuf, &sz);
- }
- if (!lpSerialBuf && pcchSerialBuf)
- {
- sz = 0;
- rc = RegQueryValueExW( hkey, INSTALLPROPERTY_PRODUCTIDW, NULL,
- NULL, NULL, &sz);
- }
- if (pcchSerialBuf)
- *pcchSerialBuf = sz / sizeof(WCHAR);
-
- RegCloseKey(hkey);
- return USERINFOSTATE_PRESENT;
+ return state;
}
-USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct, LPSTR lpUserNameBuf,
- DWORD* pcchUserNameBuf, LPSTR lpOrgNameBuf,
- DWORD* pcchOrgNameBuf, LPSTR lpSerialBuf, DWORD* pcchSerialBuf)
+/***********************************************************************
+ * MsiGetUserInfoW [MSI.@]
+ */
+USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct,
+ LPWSTR lpUserNameBuf, DWORD* pcchUserNameBuf,
+ LPWSTR lpOrgNameBuf, DWORD* pcchOrgNameBuf,
+ LPWSTR lpSerialBuf, DWORD* pcchSerialBuf)
{
- FIXME("%s %p %p %p %p %p %p\n",debugstr_a(szProduct), lpUserNameBuf,
- pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
- pcchSerialBuf);
+ awstring user, org, serial;
+
+ user.unicode = TRUE;
+ user.str.w = lpUserNameBuf;
+ org.unicode = TRUE;
+ org.str.w = lpOrgNameBuf;
+ serial.unicode = TRUE;
+ serial.str.w = lpSerialBuf;
+
+ return MSI_GetUserInfo( szProduct, &user, pcchUserNameBuf,
+ &org, pcchOrgNameBuf,
+ &serial, pcchSerialBuf );
+}
+
+USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct,
+ LPSTR lpUserNameBuf, DWORD* pcchUserNameBuf,
+ LPSTR lpOrgNameBuf, DWORD* pcchOrgNameBuf,
+ LPSTR lpSerialBuf, DWORD* pcchSerialBuf)
+{
+ awstring user, org, serial;
+ LPWSTR prod;
+ UINT r;
+
+ prod = strdupAtoW( szProduct );
+ if (szProduct && !prod)
+ return ERROR_OUTOFMEMORY;
+
+ user.unicode = FALSE;
+ user.str.a = lpUserNameBuf;
+ org.unicode = FALSE;
+ org.str.a = lpOrgNameBuf;
+ serial.unicode = FALSE;
+ serial.str.a = lpSerialBuf;
+
+ r = MSI_GetUserInfo( prod, &user, pcchUserNameBuf,
+ &org, pcchOrgNameBuf,
+ &serial, pcchSerialBuf );
- return USERINFOSTATE_UNKNOWN;
+ msi_free( prod );
+
+ return r;
}
UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct)
*/
UINT WINAPI MsiConfigureFeatureA(LPCSTR szProduct, LPCSTR szFeature, INSTALLSTATE eInstallState)
{
- FIXME("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), eInstallState);
- return ERROR_SUCCESS;
+ LPWSTR prod, feat = NULL;
+ UINT r = ERROR_OUTOFMEMORY;
+
+ TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), eInstallState);
+
+ prod = strdupAtoW( szProduct );
+ if (szProduct && !prod)
+ goto end;
+
+ feat = strdupAtoW( szFeature );
+ if (szFeature && !feat)
+ goto end;
+
+ r = MsiConfigureFeatureW(prod, feat, eInstallState);
+
+end:
+ msi_free(feat);
+ msi_free(prod);
+
+ return r;
}
/***********************************************************************
*/
UINT WINAPI MsiConfigureFeatureW(LPCWSTR szProduct, LPCWSTR szFeature, INSTALLSTATE eInstallState)
{
- FIXME("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature), eInstallState);
- return ERROR_SUCCESS;
+ static const WCHAR szCostInit[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
+ MSIPACKAGE *package = NULL;
+ UINT r;
+ WCHAR sourcepath[MAX_PATH], filename[MAX_PATH];
+ DWORD sz;
+
+ TRACE("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature), eInstallState);
+
+ if (!szProduct || !szFeature)
+ return ERROR_INVALID_PARAMETER;
+
+ switch (eInstallState)
+ {
+ case INSTALLSTATE_DEFAULT:
+ /* FIXME: how do we figure out the default location? */
+ eInstallState = INSTALLSTATE_LOCAL;
+ break;
+ case INSTALLSTATE_LOCAL:
+ case INSTALLSTATE_SOURCE:
+ case INSTALLSTATE_ABSENT:
+ case INSTALLSTATE_ADVERTISED:
+ break;
+ default:
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ r = MSI_OpenProductW( szProduct, &package );
+ if (r != ERROR_SUCCESS)
+ return r;
+
+ sz = sizeof(sourcepath);
+ MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
+ MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
+
+ sz = sizeof(filename);
+ MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
+ MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
+
+ lstrcatW( sourcepath, filename );
+
+ MsiSetInternalUI( INSTALLUILEVEL_BASIC, NULL );
+
+ r = ACTION_PerformUIAction( package, szCostInit );
+ if (r != ERROR_SUCCESS)
+ goto end;
+
+ r = MSI_SetFeatureStateW( package, szFeature, eInstallState);
+ if (r != ERROR_SUCCESS)
+ goto end;
+
+ r = MSI_InstallPackage( package, sourcepath, NULL );
+
+end:
+ msiobj_release( &package->hdr );
+
+ return r;
}
+/***********************************************************************
+ * MsiCreateAndVerifyInstallerDirectory [MSI.@]
+ *
+ * Notes: undocumented
+ */
UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)
{
WCHAR path[MAX_PATH];
- if(dwReserved) {
- FIXME("Don't know how to handle argument %ld\n", dwReserved);
- return ERROR_CALL_NOT_IMPLEMENTED;
+ TRACE("%ld\n", dwReserved);
+
+ if (dwReserved)
+ {
+ FIXME("dwReserved=%ld\n", dwReserved);
+ return ERROR_INVALID_PARAMETER;
}
- if(!GetWindowsDirectoryW(path, MAX_PATH)) {
- FIXME("GetWindowsDirectory failed unexpected! Error %ld\n",
- GetLastError());
- return ERROR_CALL_NOT_IMPLEMENTED;
- }
+ if (!GetWindowsDirectoryW(path, MAX_PATH))
+ return ERROR_FUNCTION_FAILED;
- strcatW(path, installerW);
+ lstrcatW(path, installerW);
- CreateDirectoryW(path, NULL);
+ if (!CreateDirectoryW(path, NULL))
+ return ERROR_FUNCTION_FAILED;
- return 0;
+ return ERROR_SUCCESS;
}
/***********************************************************************
{
MSIPACKAGE* package = NULL;
UINT r;
- DWORD sz;
WCHAR sourcepath[MAX_PATH];
WCHAR filename[MAX_PATH];
- static const WCHAR szInstalled[] = {
- ' ','L','O','G','V','E','R','B','O','S','E','=','1',' ','I','n','s','t','a','l','l','e','d','=','1',0};
- static const WCHAR fmt[] = {'R','E','I','N','S','T','A','L','L','=','%','s',0};
- static const WCHAR REINSTALLMODE[] = {'R','E','I','N','S','T','A','L','L','M','O','D','E',0};
+ static const WCHAR szLogVerbose[] = {
+ ' ','L','O','G','V','E','R','B','O','S','E',0 };
+ static const WCHAR szInstalled[] = { 'I','n','s','t','a','l','l','e','d',0};
+ static const WCHAR szReinstall[] = {'R','E','I','N','S','T','A','L','L',0};
+ static const WCHAR szReinstallMode[] = {'R','E','I','N','S','T','A','L','L','M','O','D','E',0};
+ static const WCHAR szOne[] = {'1',0};
WCHAR reinstallmode[11];
LPWSTR ptr;
- LPWSTR commandline;
+ DWORD sz;
FIXME("%s %s %li\n", debugstr_w(szProduct), debugstr_w(szFeature),
dwReinstallMode);
- memset(reinstallmode,0,sizeof(reinstallmode));
ptr = reinstallmode;
if (dwReinstallMode & REINSTALLMODE_FILEMISSING)
- { *ptr = 'p'; ptr++; }
+ *ptr++ = 'p';
if (dwReinstallMode & REINSTALLMODE_FILEOLDERVERSION)
- { *ptr = 'o'; ptr++; }
+ *ptr++ = 'o';
if (dwReinstallMode & REINSTALLMODE_FILEEQUALVERSION)
- { *ptr = 'w'; ptr++; }
+ *ptr++ = 'w';
if (dwReinstallMode & REINSTALLMODE_FILEEXACT)
- { *ptr = 'd'; ptr++; }
+ *ptr++ = 'd';
if (dwReinstallMode & REINSTALLMODE_FILEVERIFY)
- { *ptr = 'c'; ptr++; }
+ *ptr++ = 'c';
if (dwReinstallMode & REINSTALLMODE_FILEREPLACE)
- { *ptr = 'a'; ptr++; }
+ *ptr++ = 'a';
if (dwReinstallMode & REINSTALLMODE_USERDATA)
- { *ptr = 'u'; ptr++; }
+ *ptr++ = 'u';
if (dwReinstallMode & REINSTALLMODE_MACHINEDATA)
- { *ptr = 'm'; ptr++; }
+ *ptr++ = 'm';
if (dwReinstallMode & REINSTALLMODE_SHORTCUT)
- { *ptr = 's'; ptr++; }
+ *ptr++ = 's';
if (dwReinstallMode & REINSTALLMODE_PACKAGE)
- { *ptr = 'v'; ptr++; }
+ *ptr++ = 'v';
+ *ptr = 0;
sz = sizeof(sourcepath);
MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
- MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath,
- &sz);
+ MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
sz = sizeof(filename);
MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
- strcatW(sourcepath,filename);
+ lstrcatW( sourcepath, filename );
if (dwReinstallMode & REINSTALLMODE_PACKAGE)
r = MSI_OpenPackageW( sourcepath, &package );
if (r != ERROR_SUCCESS)
return r;
- MSI_SetPropertyW(package,REINSTALLMODE,reinstallmode);
-
- sz = lstrlenW(szInstalled);
- sz += lstrlenW(fmt);
- sz += lstrlenW(szFeature);
-
- commandline = msi_alloc(sz * sizeof(WCHAR));
-
- sprintfW(commandline,fmt,szFeature);
- lstrcatW(commandline,szInstalled);
+ MSI_SetPropertyW( package, szReinstallMode, reinstallmode );
+ MSI_SetPropertyW( package, szInstalled, szOne );
+ MSI_SetPropertyW( package, szLogVerbose, szOne );
+ MSI_SetPropertyW( package, szReinstall, szFeature );
- r = MSI_InstallPackage( package, sourcepath, commandline );
+ r = MSI_InstallPackage( package, sourcepath, NULL );
msiobj_release( &package->hdr );
- msi_free(commandline);
-
return r;
}
wszFeature = strdupAtoW(szFeature);
rc = MsiReinstallFeatureW(wszProduct, wszFeature, dwReinstallMode);
-
+
msi_free(wszProduct);
msi_free(wszFeature);
return rc;
}
-/***********************************************************************
- * MsiEnumPatchesA [MSI.@]
- */
-UINT WINAPI MsiEnumPatchesA( LPCSTR szProduct, DWORD iPatchIndex,
- LPSTR lpPatchBuf, LPSTR lpTransformsBuf, DWORD* pcchTransformsBuf)
+typedef struct
{
- FIXME("%s %ld %p %p %p\n", debugstr_a(szProduct),
- iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
- return ERROR_NO_MORE_ITEMS;
-}
+ unsigned int i[2];
+ unsigned int buf[4];
+ unsigned char in[64];
+ unsigned char digest[16];
+} MD5_CTX;
-/***********************************************************************
- * 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;
-}
+extern VOID WINAPI MD5Init( MD5_CTX *);
+extern VOID WINAPI MD5Update( MD5_CTX *, const unsigned char *, unsigned int );
+extern VOID WINAPI MD5Final( MD5_CTX *);
/***********************************************************************
* MsiGetFileHashW [MSI.@]
UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
PMSIFILEHASHINFO pHash )
{
- FIXME("%s %08lx %p\n", debugstr_w(szFilePath), dwOptions, pHash );
- return ERROR_CALL_NOT_IMPLEMENTED;
+ HANDLE handle, mapping;
+ void *p;
+ DWORD length;
+ UINT r = ERROR_FUNCTION_FAILED;
+
+ TRACE("%s %08lx %p\n", debugstr_w(szFilePath), dwOptions, pHash );
+
+ if (dwOptions)
+ return ERROR_INVALID_PARAMETER;
+ if (!pHash)
+ return ERROR_INVALID_PARAMETER;
+ if (pHash->dwFileHashInfoSize < sizeof *pHash)
+ return ERROR_INVALID_PARAMETER;
+
+ handle = CreateFileW( szFilePath, GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL );
+ if (handle == INVALID_HANDLE_VALUE)
+ return ERROR_FILE_NOT_FOUND;
+
+ length = GetFileSize( handle, NULL );
+
+ mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, 0, NULL );
+ if (mapping)
+ {
+ p = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, length );
+ if (p)
+ {
+ MD5_CTX ctx;
+
+ MD5Init( &ctx );
+ MD5Update( &ctx, p, length );
+ MD5Final( &ctx );
+ UnmapViewOfFile( p );
+
+ memcpy( pHash->dwData, &ctx.digest, sizeof pHash->dwData );
+ r = ERROR_SUCCESS;
+ }
+ CloseHandle( mapping );
+ }
+ CloseHandle( handle );
+
+ return r;
}
/***********************************************************************
UINT WINAPI MsiGetFileHashA( LPCSTR szFilePath, DWORD dwOptions,
PMSIFILEHASHINFO pHash )
{
- FIXME("%s %08lx %p\n", debugstr_a(szFilePath), dwOptions, pHash );
- return ERROR_CALL_NOT_IMPLEMENTED;
+ LPWSTR file;
+ UINT r;
+
+ TRACE("%s %08lx %p\n", debugstr_a(szFilePath), dwOptions, pHash );
+
+ file = strdupAtoW( szFilePath );
+ if (szFilePath && !file)
+ return ERROR_OUTOFMEMORY;
+
+ r = MsiGetFileHashW( file, dwOptions, pHash );
+ msi_free( file );
+ return r;
}
/***********************************************************************
<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>
<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>
*
* 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"
#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'
+} */
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
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)
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
*
* 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
*
* 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
*
* 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
--- /dev/null
+/*
+ * 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"
+}
*
* 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
*
* 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
*
* 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
-/*\r
- * Hungarian resources for MSI\r
- *\r
- * Copyright 2005 Mike McCormack\r
- * Copyright 2005 Gergely Risko\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
- */\r
-\r
-LANGUAGE LANG_HUNGARIAN, SUBLANG_NEUTRAL\r
-\r
-STRINGTABLE DISCARDABLE\r
-{\r
- 5 "Az elérési út: %s nem található"\r
- 9 "Tedd be a következõ lemezt: %s"\r
- 10 "Rossz paraméterek"\r
- 11 "Add meg melyik mappa tartalmazza a következõt: %s"\r
- 12 "Az összetevõ forrása hiányzik"\r
- 13 "Hiányzik a hálózati meghajtó az össszetevõhöz"\r
-/* NOT TRANSLATED */ 14 "feature from:"\r
- 15 "Válaszd ki melyik mappa tartalmazza a következõt: %s"\r
-}\r
+/*
+ * 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"
+}
--- /dev/null
+/*
+ * 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"
+}
*
* 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
*
* 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
*
* 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
*
* 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
/*
* 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
*
* 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
5 "ïóòü %s ÃÃ¥ Ãà éäåÃ"
9 "âñòà âüòå äèñê %s"
10 "ÃåâåðÃûå ïà ðà ìåòðû"
- 11 "ââåäèòå, êà êà ÿ ïà ïêà ñîäåðæèò %s"
- 12 "Ãåäîñòóïåà èñòî÷Ãèê óñòà Ãîâêè (ñúåìÃûé èëè êîìïà êò-äèñê ÃÃ¥ âñòà âëåà â äèñêîâîä)"
- 13 "Ãåäîñòóïåà ñåòåâîé äèñê, ñîäåðæà ùèé Ãåîáõîäèìûé ôà éë"
- 14 "ôóÃêöèîÃà ëüÃîñòü èç:"
- 15 "âûáåðèòå, êà êà ÿ ïà ïêà ñîäåðæèò %s"
+ 11 "óêà æèòå êà òà ëîã, ñîäåðæà ùèé %s"
+ 12 "èñòî÷Ãèê óñòà Ãîâêè äà ÃÃîé âîçìîæÃîñòè ÃÃ¥ óêà çà Ã"
+ 13 "ñåòåâîé äèñê äëÿ äà ÃÃîé âîçìîæÃîñòè ÃÃ¥ óêà çà Ã"
+ 14 "âîçìîæÃîñòü èç:"
+ 15 "âûáåðèòå êà òà ëîã, ñîäåðæà ùèé %s"
}
--- /dev/null
+/*
+ * 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"
+}
--- /dev/null
+/*
+ * 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;
+}
*
* 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__
MSIFIELD fields[1]; /* nb. array size is count+1 */
} MSIRECORD;
+typedef void *MSIITERHANDLE;
+
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.
*/
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;
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 *);
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 ** );
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* );
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 )
*
* 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>
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;
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;
}
*
* 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>
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;
+
+ 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;
+}
+
-MSIVIEWOPS order_ops =
+static const MSIVIEWOPS order_ops =
{
ORDER_fetch_int,
NULL,
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 )
*
* 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>
#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"
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;
}
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;
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 );
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);
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;
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)
+ {
+ 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;
+
+ GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
+
+ 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
{
- 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_RecordGetStringW(record,i,tmp,&sz);
-
- if (msg_field > 1)
+ 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);
+ 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_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);
}
- strcatW(message,tmp);
- if (msg_field > 1)
- strcatW(message,space);
-
- msi_free(tmp);
}
TRACE("(%p %lx %lx %s)\n",gUIHandlerA, gUIFilter, log_type,
}
}
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;
}
*
* 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>
*
* 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
#define EXPR_STRCMP 7
#define EXPR_WILDCARD 9
#define EXPR_COL_NUMBER_STRING 10
+#define EXPR_COL_NUMBER32 11
struct sql_str {
LPCWSTR data;
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 */
*
* 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>
rec = MSI_CreateRecord( cParams );
if( rec )
+ {
ret = alloc_msihandle( &rec->hdr );
- msiobj_release( &rec->hdr );
+ msiobj_release( &rec->hdr );
+ }
return ret;
}
break;
}
- if( *pcchValue < len )
+ if( *pcchValue <= len )
ret = ERROR_MORE_DATA;
*pcchValue = len;
break;
}
- if( *pcchValue < len )
+ if( *pcchValue <= len )
ret = ERROR_MORE_DATA;
*pcchValue = len;
*
* 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>
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;
}
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)
{
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;
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;
+}
*
* 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"
}
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;
}
}
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;
}
{ 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.@)
*/
hr = register_coclasses(coclass_list);
if (SUCCEEDED(hr))
hr = register_interfaces(interface_list);
+ if (SUCCEEDED(hr))
+ hr = register_msiexec();
return hr;
}
*
* 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>
return ERROR_SUCCESS;
}
+static UINT SELECT_find_matching_rows( struct tagMSIVIEW *view, UINT col,
+ UINT val, UINT *row, MSIITERHANDLE *handle )
+{
+ MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
+
+ 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 ];
-MSIVIEWOPS select_ops =
+ return sv->table->ops->find_matching_rows( sv->table, col, val, row, handle );
+}
+
+
+static const MSIVIEWOPS select_ops =
{
SELECT_fetch_int,
SELECT_fetch_stream,
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 )
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 )
*
* 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>
#include "winuser.h"
#include "wine/unicode.h"
#include "action.h"
+#include "sddl.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
{
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)
{
}
+/******************************************************************
+ * 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.@)
*/
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);
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;
+}
*
* 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
*/
%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:
;
selectfrom:
- selcollist from
+ selcollist multifrom
{
SQL_input* sql = (SQL_input*) info;
UINT r;
}
;
+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
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 );
if( !$$ )
YYABORT;
}
- | TK_MINUS number
+ | TK_MINUS number %prec TK_NEGATION
{
$$ = EXPR_ival( info, -$2 );
if( !$$ )
*
* 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>
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
+#define HASH_SIZE 67
+
typedef struct _msistring
{
- UINT hash;
+ int hash_next;
UINT refcount;
LPWSTR str;
} msistring;
UINT maxcount; /* the number of strings */
UINT freeslot;
UINT codepage;
+ int hash[HASH_SIZE];
msistring *strings; /* an array of strings (in the tree) */
};
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 )
if( entries < 1 )
entries = 1;
st->strings = msi_alloc_zero( sizeof (msistring) * entries );
- if( !st )
+ if( !st->strings )
{
msi_free( st );
return NULL;
st->freeslot = 1;
st->codepage = codepage;
+ for( i=0; i<HASH_SIZE; i++ )
+ st->hash[i] = -1;
+
return 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 )
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 )
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;
}
*/
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 )
*
* 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>
#define COBJMACROS
#define NONAMELESSUNION
-#define PRSPEC_PROPID (1)
-
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
*
* 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>
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;
LPCWSTR colname;
UINT type;
UINT offset;
+ MSICOLUMNHASHENTRY **hash_table;
} MSICOLUMNINFO;
struct tagMSITABLE
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 );
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[] = {
* 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 )
{
/* 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 )
{
msi_free( (LPWSTR) colinfo[i].tablename );
msi_free( (LPWSTR) colinfo[i].colname );
+ msi_free( colinfo[i].hash_table );
}
}
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++ )
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
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 )
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;
+
+ TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
+
+ if( !tv->table )
+ return ERROR_INVALID_PARAMETER;
-MSIVIEWOPS table_ops =
+ 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,
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 )
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] );
{
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);
}
ofs += n/2;
}
- if( debug_transform) MESSAGE("\n");
+ TRACE("\n");
return 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 )
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) );
}
}
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) );
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 );
}
*
* 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>
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 =
{
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,
*
* 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
*/
/*
(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)))
/* 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)))
*
* 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"
*
* 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>
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 )
{
}
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;
}
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;
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);
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;
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;
+
+ 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;
+}
+
-MSIVIEWOPS where_ops =
+static const MSIVIEWOPS where_ops =
{
WHERE_fetch_int,
WHERE_fetch_stream,
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,
{
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;
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;