- sync MSI to Wine 0.9.18
authorGed Murphy <gedmurphy@reactos.org>
Tue, 1 Aug 2006 23:12:11 +0000 (23:12 +0000)
committerGed Murphy <gedmurphy@reactos.org>
Tue, 1 Aug 2006 23:12:11 +0000 (23:12 +0000)
- 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

59 files changed:
reactos/dll/win32/msi/Makefile.in
reactos/dll/win32/msi/action.c
reactos/dll/win32/msi/action.h
reactos/dll/win32/msi/appsearch.c
reactos/dll/win32/msi/classes.c
reactos/dll/win32/msi/cond.y
reactos/dll/win32/msi/create.c
reactos/dll/win32/msi/custom.c
reactos/dll/win32/msi/database.c
reactos/dll/win32/msi/delete.c
reactos/dll/win32/msi/dialog.c
reactos/dll/win32/msi/distinct.c
reactos/dll/win32/msi/events.c
reactos/dll/win32/msi/files.c
reactos/dll/win32/msi/format.c
reactos/dll/win32/msi/handle.c
reactos/dll/win32/msi/helpers.c
reactos/dll/win32/msi/insert.c
reactos/dll/win32/msi/install.c
reactos/dll/win32/msi/join.c [new file with mode: 0644]
reactos/dll/win32/msi/msi.c
reactos/dll/win32/msi/msi.rbuild
reactos/dll/win32/msi/msi.rc
reactos/dll/win32/msi/msi.spec
reactos/dll/win32/msi/msi_Bg.rc
reactos/dll/win32/msi/msi_De.rc
reactos/dll/win32/msi/msi_En.rc
reactos/dll/win32/msi/msi_Eo.rc [new file with mode: 0644]
reactos/dll/win32/msi/msi_Es.rc
reactos/dll/win32/msi/msi_Fi.rc
reactos/dll/win32/msi/msi_Fr.rc
reactos/dll/win32/msi/msi_Hu.rc
reactos/dll/win32/msi/msi_It.rc [new file with mode: 0644]
reactos/dll/win32/msi/msi_Ko.rc
reactos/dll/win32/msi/msi_Nl.rc
reactos/dll/win32/msi/msi_No.rc
reactos/dll/win32/msi/msi_Pt.rc
reactos/dll/win32/msi/msi_Ru.rc
reactos/dll/win32/msi/msi_Tr.rc [new file with mode: 0644]
reactos/dll/win32/msi/msi_main.c [new file with mode: 0644]
reactos/dll/win32/msi/msipriv.h
reactos/dll/win32/msi/msiquery.c
reactos/dll/win32/msi/order.c
reactos/dll/win32/msi/package.c
reactos/dll/win32/msi/preview.c
reactos/dll/win32/msi/query.h
reactos/dll/win32/msi/record.c
reactos/dll/win32/msi/registry.c
reactos/dll/win32/msi/regsvr.c
reactos/dll/win32/msi/select.c
reactos/dll/win32/msi/source.c
reactos/dll/win32/msi/sql.y
reactos/dll/win32/msi/string.c
reactos/dll/win32/msi/suminfo.c
reactos/dll/win32/msi/table.c
reactos/dll/win32/msi/update.c
reactos/dll/win32/msi/upgrade.c
reactos/dll/win32/msi/version.rc
reactos/dll/win32/msi/where.c

index e1216ae..fe12586 100644 (file)
@@ -1,68 +1,75 @@
-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:
index 1017e57..f7454c2 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 /*
@@ -113,7 +113,7 @@ static const WCHAR szForceReboot[] =
     {'F','o','r','c','e','R','e','b','o','o','t',0};
 static const WCHAR szResolveSource[] =
     {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
-const WCHAR szAppSearch[] = 
+static const WCHAR szAppSearch[] = 
     {'A','p','p','S','e','a','r','c','h',0};
 static const WCHAR szAllocateRegistrySpace[] = 
     {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
@@ -154,8 +154,6 @@ static const WCHAR szInstallODBC[] =
     {'I','n','s','t','a','l','l','O','D','B','C',0};
 static const WCHAR szInstallServices[] = 
     {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
-static const WCHAR szISInitAllUsers[] = 
-    {'I','S','I','n','i','t','A','l','l','U','s','e','r','s',0};
 const WCHAR szPatchFiles[] = 
     {'P','a','t','c','h','F','i','l','e','s',0};
 static const WCHAR szPublishComponents[] = 
@@ -249,55 +247,20 @@ static struct _actions StandardActions[];
  * helper functions
  ********************************************************/
 
-static void ce_actiontext(MSIPACKAGE* package, LPCWSTR action)
-{
-    static const WCHAR szActionText[] = 
-        {'A','c','t','i','o','n','T','e','x','t',0};
-    MSIRECORD *row;
-
-    row = MSI_CreateRecord(1);
-    MSI_RecordSetStringW(row,1,action);
-    ControlEvent_FireSubscribedEvent(package,szActionText, row);
-    msiobj_release(&row->hdr);
-}
-
 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
 {
-    static const WCHAR template_s[]=
-        {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ', '%','s',
-         '.',0};
-    static const WCHAR format[] = 
-        {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
     static const WCHAR Query_t[] = 
         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
          '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
          'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=', 
          ' ','\'','%','s','\'',0};
-    WCHAR message[1024];
-    WCHAR timet[0x100];
-    MSIRECORD * row = 0;
-    LPCWSTR ActionText;
-    LPWSTR deformated;
-
-    GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
+    MSIRECORD * row;
 
     row = MSI_QueryGetRecord( package->db, Query_t, action );
     if (!row)
         return;
-
-    ActionText = MSI_RecordGetString(row,2);
-    deformat_string(package, ActionText, &deformated);
-
-    sprintfW(message,template_s,timet,action,deformated);
-    ce_actiontext(package, deformated);
-    msiobj_release(&row->hdr);
-
-    row = MSI_CreateRecord(1);
-    MSI_RecordSetStringW(row,1,message);
     MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
     msiobj_release(&row->hdr);
-    msi_free(deformated);
 }
 
 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start, 
@@ -329,14 +292,6 @@ static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
     msiobj_release(&row->hdr);
 }
 
-static int msi_get_property_int( MSIPACKAGE *package, LPCWSTR prop, int def )
-{
-    LPWSTR str = msi_dup_property( package, prop );
-    int val = str ? atoiW( str ) : def;
-    msi_free( str );
-    return val;
-}
-
 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
 {
     LPCWSTR ptr,ptr2;
@@ -610,8 +565,7 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
 
     MSI_SetPropertyW(package, szAction, szInstall);
 
-    package->script = msi_alloc(sizeof(MSISCRIPT));
-    memset(package->script,0,sizeof(MSISCRIPT));
+    package->script = msi_alloc_zero(sizeof(MSISCRIPT));
 
     package->script->InWhatSequence = SEQUENCE_INSTALL;
 
@@ -921,12 +875,6 @@ static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
     BOOL run = force;
     int i;
 
-    if (!package)
-    {
-        ERR("package was null!\n");
-        return FALSE;
-    }
-
     if (!run && !package->script->CurrentlyScripting)
         run = TRUE;
    
@@ -1147,13 +1095,16 @@ static UINT ACTION_CreateFolders(MSIPACKAGE *package)
     return rc;
 }
 
-static MSICOMPONENT* load_component( MSIRECORD * row )
+static UINT load_component( MSIRECORD *row, LPVOID param )
 {
+    MSIPACKAGE *package = param;
     MSICOMPONENT *comp;
 
     comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
     if (!comp)
-        return comp;
+        return ERROR_FUNCTION_FAILED;
+
+    list_add_tail( &package->components, &comp->entry );
 
     /* fill in the data */
     comp->Component = msi_dup_record_field( row, 1 );
@@ -1167,12 +1118,44 @@ static MSICOMPONENT* load_component( MSIRECORD * row )
     comp->KeyPath = msi_dup_record_field( row, 6 );
 
     comp->Installed = INSTALLSTATE_ABSENT;
-    comp->Action = INSTALLSTATE_UNKNOWN;
-    comp->ActionRequest = INSTALLSTATE_UNKNOWN;
 
-    comp->Enabled = TRUE;
+    switch (comp->Attributes)
+    {
+    case msidbComponentAttributesLocalOnly:
+    case msidbComponentAttributesOptional:
+        comp->Action = INSTALLSTATE_LOCAL;
+        comp->ActionRequest = INSTALLSTATE_LOCAL;
+        break;
+    case msidbComponentAttributesSourceOnly:
+        comp->Action = INSTALLSTATE_SOURCE;
+        comp->ActionRequest = INSTALLSTATE_SOURCE;
+        break;
+    default:
+        comp->Action = INSTALLSTATE_UNKNOWN;
+        comp->ActionRequest = INSTALLSTATE_UNKNOWN;
+    }
 
-    return comp;
+    return ERROR_SUCCESS;
+}
+
+static UINT load_all_components( MSIPACKAGE *package )
+{
+    static const WCHAR query[] = {
+        'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ', 
+         '`','C','o','m','p','o','n','e','n','t','`',0 };
+    MSIQUERY *view;
+    UINT r;
+
+    if (!list_empty(&package->components))
+        return ERROR_SUCCESS;
+
+    r = MSI_DatabaseOpenViewW( package->db, query, &view );
+    if (r != ERROR_SUCCESS)
+        return r;
+
+    r = MSI_IterateRecords(view, NULL, load_component, package);
+    msiobj_release(&view->hdr);
+    return r;
 }
 
 typedef struct {
@@ -1193,56 +1176,24 @@ static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
     return ERROR_SUCCESS;
 }
 
-static UINT iterate_component_check( MSIRECORD *row, LPVOID param )
-{
-    _ilfs* ilfs= (_ilfs*)param;
-    MSIPACKAGE *package = ilfs->package;
-    MSIFEATURE *feature = ilfs->feature;
-    MSICOMPONENT *comp;
-
-    comp = load_component( row );
-    if (!comp)
-        return ERROR_FUNCTION_FAILED;
-
-    list_add_tail( &package->components, &comp->entry );
-    add_feature_component( feature, comp );
-
-    TRACE("Loaded new component %p\n", comp);
-
-    return ERROR_SUCCESS;
-}
-
 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
 {
     _ilfs* ilfs= (_ilfs*)param;
     LPCWSTR component;
-    DWORD rc;
     MSICOMPONENT *comp;
-    MSIQUERY * view;
-    static const WCHAR Query[] = 
-        {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ', 
-         '`','C','o','m','p','o','n','e','n','t','`',' ',
-         'W','H','E','R','E',' ', 
-         '`','C','o','m','p','o','n','e','n','t','`',' ',
-         '=','\'','%','s','\'',0};
 
     component = MSI_RecordGetString(row,1);
 
     /* check to see if the component is already loaded */
     comp = get_loaded_component( ilfs->package, component );
-    if (comp)
+    if (!comp)
     {
-        TRACE("Component %s already loaded\n", debugstr_w(component) );
-        add_feature_component( ilfs->feature, comp );
-        return ERROR_SUCCESS;
+        ERR("unknown component %s\n", debugstr_w(component));
+        return ERROR_FUNCTION_FAILED;
     }
 
-    rc = MSI_OpenQuery(ilfs->package->db, &view, Query, component);
-    if (rc != ERROR_SUCCESS)
-        return ERROR_SUCCESS;
-
-    rc = MSI_IterateRecords(view, NULL, iterate_component_check, ilfs);
-    msiobj_release( &view->hdr );
+    add_feature_component( ilfs->feature, comp );
+    comp->Enabled = TRUE;
 
     return ERROR_SUCCESS;
 }
@@ -1306,6 +1257,38 @@ static UINT load_feature(MSIRECORD * row, LPVOID param)
     return ERROR_SUCCESS;
 }
 
+static UINT load_all_features( MSIPACKAGE *package )
+{
+    static const WCHAR query[] = {
+        'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
+        '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
+        ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
+    MSIQUERY *view;
+    UINT r;
+
+    if (!list_empty(&package->features))
+        return ERROR_SUCCESS;
+    r = MSI_DatabaseOpenViewW( package->db, query, &view );
+    if (r != ERROR_SUCCESS)
+        return r;
+
+    r = MSI_IterateRecords( view, NULL, load_feature, package );
+    msiobj_release( &view->hdr );
+    return r;
+}
+
+static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
+{
+    if (!p)
+        return p;
+    p = strchrW(p, ch);
+    if (!p)
+        return p;
+    *p = 0;
+    return p+1;
+}
+
 static UINT load_file(MSIRECORD *row, LPVOID param)
 {
     MSIPACKAGE* package = (MSIPACKAGE*)param;
@@ -1330,7 +1313,7 @@ static UINT load_file(MSIRECORD *row, LPVOID param)
     reduce_to_longfilename( file->FileName );
 
     file->ShortName = msi_dup_record_field( row, 3 );
-    reduce_to_shortfilename( file->ShortName );
+    file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
     
     file->FileSize = MSI_RecordGetInteger( row, 4 );
     file->Version = msi_dup_record_field( row, 5 );
@@ -1356,8 +1339,8 @@ static UINT load_all_files(MSIPACKAGE *package)
          '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
          '`','S','e','q','u','e','n','c','e','`', 0};
 
-    if (!package)
-        return ERROR_INVALID_HANDLE;
+    if (!list_empty(&package->files))
+        return ERROR_SUCCESS;
 
     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
     if (rc != ERROR_SUCCESS)
@@ -1371,43 +1354,33 @@ static UINT load_all_files(MSIPACKAGE *package)
 
 
 /*
- * I am not doing any of the costing functionality yet. 
+ * I am not doing any of the costing functionality yet.
  * Mostly looking at doing the Component and Feature loading
  *
  * The native MSI does A LOT of modification to tables here. Mostly adding
- * a lot of temporary columns to the Feature and Component tables. 
+ * a lot of temporary columns to the Feature and Component tables.
  *
  *    note: Native msi also tracks the short filename. But I am only going to
  *          track the long ones.  Also looking at this directory table
  *          it appears that the directory table does not get the parents
- *          resolved base on property only based on their entries in the 
+ *          resolved base on property only based on their entries in the
  *          directory table.
  */
 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
 {
-    MSIQUERY * view;
-    UINT rc;
-    static const WCHAR Query_all[] =
-        {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
-         '`','F','e','a','t','u','r','e','`',0};
     static const WCHAR szCosting[] =
         {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
     static const WCHAR szZero[] = { '0', 0 };
 
     if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
         return ERROR_SUCCESS;
-    
-    MSI_SetPropertyW(package, szCosting, szZero);
-    MSI_SetPropertyW(package, cszRootDrive , c_colon);
-
-    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;
 }
@@ -1419,6 +1392,12 @@ static UINT execute_script(MSIPACKAGE *package, UINT script )
 
     TRACE("Executing Script %i\n",script);
 
+    if (!package->script)
+    {
+        ERR("no script!\n");
+        return ERROR_FUNCTION_FAILED;
+    }
+
     for (i = 0; i < package->script->ActionCount[script]; i++)
     {
         LPWSTR action;
@@ -1442,7 +1421,6 @@ static UINT ACTION_FileCost(MSIPACKAGE *package)
     return ERROR_SUCCESS;
 }
 
-
 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
 {
     static const WCHAR Query[] =
@@ -1451,10 +1429,11 @@ static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
          'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
          ' ','=',' ','\'','%','s','\'',
          0};
-    LPWSTR ptargetdir, targetdir, srcdir;
+    static const WCHAR szDot[] = { '.',0 };
+    static WCHAR szEmpty[] = { 0 };
+    LPWSTR p, tgt_short, tgt_long, src_short, src_long;
     LPCWSTR parent;
-    LPWSTR shortname = NULL;
-    MSIRECORD * row = 0;
+    MSIRECORD *row;
     MSIFOLDER *folder;
 
     TRACE("Looking for dir %s\n",debugstr_w(dir));
@@ -1475,54 +1454,44 @@ static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
     if (!row)
         return NULL;
 
-    ptargetdir = targetdir = msi_dup_record_field(row,3);
+    p = msi_dup_record_field(row, 3);
 
     /* split src and target dir */
-    if (strchrW(targetdir,':'))
-    {
-        srcdir=strchrW(targetdir,':');
-        *srcdir=0;
-        srcdir ++;
-    }
-    else
-        srcdir=NULL;
-
-    /* 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 );
@@ -1631,7 +1600,7 @@ static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
     return TRUE;
 }
 
-static UINT SetFeatureStates(MSIPACKAGE *package)
+UINT MSI_SetFeatureStates(MSIPACKAGE *package)
 {
     int install_level;
     static const WCHAR szlevel[] =
@@ -1919,7 +1888,7 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
             version = msi_alloc(versize);
             GetFileVersionInfoW(file->TargetPath, 0, versize, version);
 
-            VerQueryValueW(version, (LPWSTR)name, (LPVOID*)&lpVer, &sz);
+            VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
 
             sprintfW(filever,name_fmt,
                 HIWORD(lpVer->dwFileVersionMS),
@@ -1976,7 +1945,7 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
 
     ACTION_UpdateInstallStates(package);
 
-    return SetFeatureStates(package);
+    return MSI_SetFeatureStates(package);
 }
 
 /* OK this value is "interpreted" and then formatted based on the 
@@ -2280,9 +2249,6 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
          '`','R','e','g','i','s','t','r','y','`',0 };
 
-    if (!package)
-        return ERROR_INVALID_HANDLE;
-
     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
     if (rc != ERROR_SUCCESS)
         return ERROR_SUCCESS;
@@ -2588,92 +2554,91 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
 
     rc = MSIREG_OpenComponents(&hkey);
     if (rc != ERROR_SUCCESS)
-        goto end;
-      
+        return rc;
+
     squash_guid(package->ProductCode,squished_pc);
     ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
 
     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
     {
+        MSIRECORD * uirow;
+
         ui_progress(package,2,0,0,0);
-        if (comp->ComponentId)
-        {
-            MSIRECORD * uirow;
+        if (!comp->ComponentId)
+            continue;
 
-            squash_guid(comp->ComponentId,squished_cc);
+        squash_guid(comp->ComponentId,squished_cc);
            
-            msi_free(comp->FullKeypath);
-            comp->FullKeypath = resolve_keypath( package, comp );
+        msi_free(comp->FullKeypath);
+        comp->FullKeypath = resolve_keypath( package, comp );
 
-            /* do the refcounting */
-            ACTION_RefCountComponent( package, comp );
+        /* do the refcounting */
+        ACTION_RefCountComponent( package, comp );
 
-            TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n", 
+        TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
                             debugstr_w(comp->Component),
                             debugstr_w(squished_cc),
-                            debugstr_w(comp->FullKeypath), 
+                            debugstr_w(comp->FullKeypath),
                             comp->RefCount);
-            /*
-            * Write the keypath out if the component is to be registered
-            * and delete the key if the component is to be deregistered
-            */
-            if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
-            {
-                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;
 }
@@ -2704,7 +2669,7 @@ static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
     sz = strlenW(tl_struct->source)+4;
     sz *= sizeof(WCHAR);
 
-    if ((INT)lpszName == 1)
+    if ((INT_PTR)lpszName == 1)
         tl_struct->path = strdupW(tl_struct->source);
     else
     {
@@ -2845,14 +2810,12 @@ static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
 {
     MSIPACKAGE *package = (MSIPACKAGE*)param;
-    LPWSTR target_file, target_folder;
-    LPCWSTR buffer;
-    WCHAR filename[0x100];
-    DWORD sz;
+    LPWSTR target_file, target_folder, filename;
+    LPCWSTR buffer, extension;
     MSICOMPONENT *comp;
     static const WCHAR szlnk[]={'.','l','n','k',0};
-    IShellLinkW *sl;
-    IPersistFile *pf;
+    IShellLinkW *sl = NULL;
+    IPersistFile *pf = NULL;
     HRESULT res;
 
     buffer = MSI_RecordGetString(row,4);
@@ -2876,17 +2839,17 @@ static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
     res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
                     &IID_IShellLinkW, (LPVOID *) &sl );
 
-    if (FAILED(res))
+    if (FAILED( res ))
     {
-        ERR("Is IID_IShellLink\n");
-        return ERROR_SUCCESS;
+        ERR("CLSID_ShellLink not available\n");
+        goto err;
     }
 
     res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
-    if( FAILED( res ) )
+    if (FAILED( res ))
     {
-        ERR("Is IID_IPersistFile\n");
-        return ERROR_SUCCESS;
+        ERR("QueryInterface(IID_IPersistFile) failed\n");
+        goto err;
     }
 
     buffer = MSI_RecordGetString(row,2);
@@ -2895,13 +2858,19 @@ static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
     /* may be needed because of a bug somehwere else */
     create_full_pathW(target_folder);
 
-    sz = 0x100;
-    MSI_RecordGetStringW(row,3,filename,&sz);
+    filename = msi_dup_record_field( row, 3 );
     reduce_to_longfilename(filename);
-    if (!strchrW(filename,'.') || strcmpiW(strchrW(filename,'.'),szlnk))
-        strcatW(filename,szlnk);
+
+    extension = strchrW(filename,'.');
+    if (!extension || strcmpiW(extension,szlnk))
+    {
+        int len = strlenW(filename);
+        filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
+        memcpy(filename + len, szlnk, sizeof(szlnk));
+    }
     target_file = build_directory_name(2, target_folder, filename);
     msi_free(target_folder);
+    msi_free(filename);
 
     buffer = MSI_RecordGetString(row,5);
     if (strchrW(buffer,'['))
@@ -2966,8 +2935,11 @@ static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
 
     msi_free(target_file);    
 
-    IPersistFile_Release( pf );
-    IShellLinkW_Release( sl );
+err:
+    if (pf)
+        IPersistFile_Release( pf );
+    if (sl)
+        IShellLinkW_Release( sl );
 
     return ERROR_SUCCESS;
 }
@@ -3009,6 +2981,7 @@ static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
     CHAR buffer[1024];
     DWORD sz;
     UINT rc;
+    MSIRECORD *uirow;
 
     FileName = MSI_RecordGetString(row,1);
     if (!FileName)
@@ -3049,6 +3022,12 @@ static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
     msi_free(FilePath);
 
     CloseHandle(the_file);
+
+    uirow = MSI_CreateRecord(1);
+    MSI_RecordSetStringW(uirow,1,FileName);
+    ui_actiondata(package,szPublishProduct,uirow);
+    msiobj_release( &uirow->hdr );
+
     return ERROR_SUCCESS;
 }
 
@@ -3118,7 +3097,7 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package)
     buffer = msi_dup_property( package, szProductVersion );
     if (buffer)
     {
-        DWORD verdword = build_version_dword(buffer);
+        DWORD verdword = msi_version_str_to_dword(buffer);
         msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
     }
     msi_free(buffer);
@@ -3295,6 +3274,8 @@ static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
     STARTUPINFOW si;
     PROCESS_INFORMATION info;
     BOOL brc;
+    MSIRECORD *uirow;
+    LPWSTR uipath, p;
 
     memset(&si,0,sizeof(STARTUPINFOW));
 
@@ -3322,6 +3303,20 @@ static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
         msi_dialog_check_messages(info.hProcess);
 
     msi_free(FullName);
+
+    /* the UI chunk */
+    uirow = MSI_CreateRecord( 2 );
+    uipath = strdupW( file->TargetPath );
+    p = strrchrW(uipath,'\\');
+    if (p)
+        p[1]=0;
+    MSI_RecordSetStringW( uirow, 1, &p[2] );
+    MSI_RecordSetStringW( uirow, 2, uipath);
+    ui_actiondata( package, szSelfRegModules, uirow);
+    msiobj_release( &uirow->hdr );
+    msi_free( uipath );
+    /* FIXME: call ui_progress? */
+
     return ERROR_SUCCESS;
 }
 
@@ -3369,6 +3364,7 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
         GUID clsid;
         INT size;
         BOOL absent = FALSE;
+        MSIRECORD *uirow;
 
         if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
             !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
@@ -3391,7 +3387,7 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
             MSICOMPONENT* component = cl->component;
             WCHAR buf[21];
 
-            memset(buf,0,sizeof(buf));
+            buf[0] = 0;
             if (component->ComponentId)
             {
                 TRACE("From %s\n",debugstr_w(component->ComponentId));
@@ -3431,6 +3427,13 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
                        (LPBYTE)data,size);
             msi_free(data);
         }
+
+        /* the UI chunk */
+        uirow = MSI_CreateRecord( 1 );
+        MSI_RecordSetStringW( uirow, 1, feature->Feature );
+        ui_actiondata( package, szPublishFeatures, uirow);
+        msiobj_release( &uirow->hdr );
+        /* FIXME: call ui_progress? */
     }
 
 end:
@@ -3594,7 +3597,7 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
     buffer = msi_dup_property( package, szProductVersion );
     if (buffer)
     {
-        DWORD verdword = build_version_dword(buffer);
+        DWORD verdword = msi_version_str_to_dword(buffer);
 
         msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
         msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
@@ -3622,6 +3625,8 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
     
     RegCloseKey(hkey);
 
+    /* FIXME: call ui_actiondata */
+
     return ERROR_SUCCESS;
 }
 
@@ -3790,6 +3795,8 @@ end:
     msi_free(productid);
     RegCloseKey(hkey);
 
+    /* FIXME: call ui_actiondata */
+
     return ERROR_SUCCESS;
 }
 
@@ -3911,8 +3918,7 @@ static LPWSTR load_ttfname_from(LPCWSTR filename)
                                     ttRecord.uStringOffset + 
                                     ttNTHeader.uStorageOffset,
                                     NULL, FILE_BEGIN);
-                    buf = msi_alloc( ttRecord.uStringLength + 1 + strlen(tt) );
-                    memset(buf, 0, ttRecord.uStringLength + 1 + strlen(tt));
+                    buf = msi_alloc_zero( ttRecord.uStringLength + 1 + strlen(tt) );
                     ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
                     if (strlen(buf) > 0)
                     {
@@ -3956,6 +3962,8 @@ static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
          'F','o','n','t','s',0};
     HKEY hkey1;
     HKEY hkey2;
+    MSIRECORD *uirow;
+    LPWSTR uipath, p;
 
     filename = MSI_RecordGetString( row, 1 );
     file = get_loaded_file( package, filename );
@@ -3989,6 +3997,19 @@ static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
     msi_free(name);
     RegCloseKey(hkey1);
     RegCloseKey(hkey2);
+
+    /* the UI chunk */
+    uirow = MSI_CreateRecord( 1 );
+    uipath = strdupW( file->TargetPath );
+    p = strrchrW(uipath,'\\');
+    if (p) p++;
+    else p = uipath;
+    MSI_RecordSetStringW( uirow, 1, p );
+    ui_actiondata( package, szRegisterFonts, uirow);
+    msiobj_release( &uirow->hdr );
+    msi_free( uipath );
+    /* FIXME: call ui_progress? */
+
     return ERROR_SUCCESS;
 }
 
@@ -4027,6 +4048,7 @@ static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
     UINT rc = ERROR_SUCCESS;
     MSICOMPONENT *comp;
     DWORD sz = 0;
+    MSIRECORD *uirow;
 
     component = MSI_RecordGetString(rec,3);
     comp = get_loaded_component(package,component);
@@ -4042,13 +4064,13 @@ static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
     }
 
     compgroupid = MSI_RecordGetString(rec,1);
+    qualifier = MSI_RecordGetString(rec,2);
 
     rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
     if (rc != ERROR_SUCCESS)
         goto end;
     
     text = MSI_RecordGetString(rec,4);
-    qualifier = MSI_RecordGetString(rec,2);
     feature = MSI_RecordGetString(rec,5);
   
     advertise = create_component_advertise_string(package, comp, feature);
@@ -4061,8 +4083,7 @@ static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
     sz+=3;
     sz *= sizeof(WCHAR);
            
-    output = msi_alloc(sz);
-    memset(output,0,sz);
+    output = msi_alloc_zero(sz);
     strcpyW(output,advertise);
     msi_free(advertise);
 
@@ -4074,7 +4095,15 @@ static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
 end:
     RegCloseKey(hkey);
     msi_free(output);
-    
+
+    /* the UI chunk */
+    uirow = MSI_CreateRecord( 2 );
+    MSI_RecordSetStringW( uirow, 1, compgroupid );
+    MSI_RecordSetStringW( uirow, 2, qualifier);
+    ui_actiondata( package, szPublishComponents, uirow);
+    msiobj_release( &uirow->hdr );
+    /* FIXME: call ui_progress? */
+
     return rc;
 }
 
@@ -4249,6 +4278,18 @@ static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
     return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
 }
 
+static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
+{
+    static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
+    return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
+}
+
+static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
+{
+    static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
+    return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
+}
+
 static struct _actions StandardActions[] = {
     { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
     { szAppSearch, ACTION_AppSearch },
@@ -4279,7 +4320,6 @@ static struct _actions StandardActions[] = {
     { szMoveFiles, ACTION_MoveFiles },
     { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
     { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
-    { szISInitAllUsers, NULL },
     { szInstallODBC, NULL},
     { szInstallServices, ACTION_InstallServices },
     { szPatchFiles, ACTION_PatchFiles },
@@ -4288,7 +4328,7 @@ static struct _actions StandardActions[] = {
     { szPublishFeatures, ACTION_PublishFeatures },
     { szPublishProduct, ACTION_PublishProduct },
     { szRegisterClassInfo, ACTION_RegisterClassInfo },
-    { szRegisterComPlus, NULL},
+    { szRegisterComPlus, ACTION_RegisterComPlus},
     { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
     { szRegisterFonts, ACTION_RegisterFonts },
     { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
@@ -4316,7 +4356,7 @@ static struct _actions StandardActions[] = {
     { szUnpublishComponents, NULL},
     { szUnpublishFeatures, NULL},
     { szUnregisterClassInfo, NULL},
-    { szUnregisterComPlus, NULL},
+    { szUnregisterComPlus, ACTION_UnregisterComPlus},
     { szUnregisterExtensionInfo, NULL},
     { szUnregisterFonts, ACTION_UnregisterFonts },
     { szUnregisterMIMEInfo, NULL},
index 9b3e58d..8edfbb0 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #ifndef __MSI_ACTION_H__
@@ -78,7 +78,8 @@ typedef struct tagMSIFOLDER
     struct list entry;
     LPWSTR Directory;
     LPWSTR TargetDefault;
-    LPWSTR SourceDefault;
+    LPWSTR SourceLongPath;
+    LPWSTR SourceShortPath;
 
     LPWSTR ResolvedTarget;
     LPWSTR ResolvedSource;
@@ -109,6 +110,7 @@ typedef struct tagMSIFILE
     MSICOMPONENT *Component;
     LPWSTR FileName;
     LPWSTR ShortName;
+    LPWSTR LongName;
     INT FileSize;
     LPWSTR Version;
     LPWSTR Language;
@@ -255,6 +257,7 @@ extern UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package);
 extern DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data );
 extern LPWSTR msi_dup_record_field(MSIRECORD *row, INT index);
 extern LPWSTR msi_dup_property(MSIPACKAGE *package, LPCWSTR prop);
+extern int msi_get_property_int( MSIPACKAGE *package, LPCWSTR prop, int def );
 extern LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, 
                       BOOL set_prop, MSIFOLDER **folder);
 extern MSICOMPONENT *get_loaded_component( MSIPACKAGE* package, LPCWSTR Component );
@@ -264,7 +267,6 @@ extern MSIFOLDER *get_loaded_folder( MSIPACKAGE *package, LPCWSTR dir );
 extern int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path);
 extern UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action);
 extern LPWSTR build_icon_path(MSIPACKAGE *, LPCWSTR);
-extern DWORD build_version_dword(LPCWSTR);
 extern LPWSTR build_directory_name(DWORD , ...);
 extern BOOL create_full_pathW(const WCHAR *path);
 extern BOOL ACTION_VerifyComponentForAction(MSICOMPONENT*, INSTALLSTATE);
index 4c59c1a..b47ecec 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 #include <stdarg.h>
 
@@ -37,8 +37,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
 typedef struct tagMSISIGNATURE
 {
-    LPWSTR   Name;     /* NOT owned by this structure */
-    LPWSTR   Property; /* NOT owned by this structure */
+    LPCWSTR  Name;     /* NOT owned by this structure */
     LPWSTR   File;
     DWORD    MinVersionMS;
     DWORD    MinVersionLS;
@@ -96,6 +95,7 @@ static UINT ACTION_AppSearchGetSignature(MSIPACKAGE *package, MSISIGNATURE *sig,
 
     TRACE("(package %p, sig %p)\n", package, sig);
     memset(sig, 0, sizeof(*sig));
+    sig->Name = name;
     rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, name);
     if (rc == ERROR_SUCCESS)
     {
@@ -158,7 +158,8 @@ static UINT ACTION_AppSearchGetSignature(MSIPACKAGE *package, MSISIGNATURE *sig,
         TRACE("Languages is %s\n", debugstr_w(sig->Languages));
 
 end:
-        msiobj_release(&row->hdr);
+        if (row)
+            msiobj_release(&row->hdr);
         MSI_ViewClose(view);
         msiobj_release(&view->hdr);
     }
@@ -172,7 +173,14 @@ end:
     return rc;
 }
 
-static UINT ACTION_AppSearchComponents(MSIPACKAGE *package, BOOL *appFound,
+/* Frees any memory allocated in sig */
+static void ACTION_FreeSignature(MSISIGNATURE *sig)
+{
+    msi_free(sig->File);
+    msi_free(sig->Languages);
+}
+
+static UINT ACTION_AppSearchComponents(MSIPACKAGE *package, LPWSTR *appValue,
  MSISIGNATURE *sig)
 {
     MSIQUERY *view;
@@ -184,8 +192,8 @@ static UINT ACTION_AppSearchComponents(MSIPACKAGE *package, BOOL *appFound,
    'w','h','e','r','e',' ','S','i','g','n','a','t','u','r','e','_',' ','=',' ',
    '\'','%','s','\'',0};
 
-    TRACE("(package %p, appFound %p, sig %p)\n", package, appFound, sig);
-    *appFound = FALSE;
+    TRACE("(package %p, appValue %p, sig %p)\n", package, appValue, sig);
+    *appValue = NULL;
     rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, sig->Name);
     if (rc == ERROR_SUCCESS)
     {
@@ -220,7 +228,8 @@ static UINT ACTION_AppSearchComponents(MSIPACKAGE *package, BOOL *appFound,
          debugstr_w(guid));
 
 end:
-        msiobj_release(&row->hdr);
+        if (row)
+            msiobj_release(&row->hdr);
         MSI_ViewClose(view);
         msiobj_release(&view->hdr);
     }
@@ -234,7 +243,58 @@ end:
     return rc;
 }
 
-static UINT ACTION_AppSearchReg(MSIPACKAGE *package, BOOL *appFound,
+static void ACTION_ConvertRegValue(DWORD regType, const BYTE *value, DWORD sz,
+ LPWSTR *appValue)
+{
+    static const WCHAR dwordFmt[] = { '#','%','d','\0' };
+    static const WCHAR expandSzFmt[] = { '#','%','%','%','s','\0' };
+    static const WCHAR binFmt[] = { '#','x','%','x','\0' };
+    DWORD i;
+
+    switch (regType)
+    {
+        case REG_SZ:
+            if (*(LPWSTR)value == '#')
+            {
+                /* escape leading pound with another */
+                *appValue = msi_alloc(sz + sizeof(WCHAR));
+                (*appValue)[0] = '#';
+                strcpyW(*appValue + 1, (LPCWSTR)value);
+            }
+            else
+            {
+                *appValue = msi_alloc(sz);
+                strcpyW(*appValue, (LPCWSTR)value);
+            }
+            break;
+        case REG_DWORD:
+            /* 7 chars for digits, 1 for NULL, 1 for #, and 1 for sign
+             * char if needed
+             */
+            *appValue = msi_alloc(10 * sizeof(WCHAR));
+            sprintfW(*appValue, dwordFmt, *(const DWORD *)value);
+            break;
+        case REG_EXPAND_SZ:
+            /* space for extra #% characters in front */
+            *appValue = msi_alloc(sz + 2 * sizeof(WCHAR));
+            sprintfW(*appValue, expandSzFmt, (LPCWSTR)value);
+            break;
+        case REG_BINARY:
+            /* 3 == length of "#x<nibble>" */
+            *appValue = msi_alloc((sz * 3 + 1) * sizeof(WCHAR));
+            for (i = 0; i < sz; i++)
+                sprintfW(*appValue + i * 3, binFmt, value[i]);
+            break;
+        default:
+            WARN("unimplemented for values of type %ld\n", regType);
+            *appValue = NULL;
+    }
+}
+
+static UINT ACTION_SearchDirectory(MSIPACKAGE *package, MSISIGNATURE *sig,
+ LPCWSTR path, int depth, LPWSTR *appValue);
+
+static UINT ACTION_AppSearchReg(MSIPACKAGE *package, LPWSTR *appValue,
  MSISIGNATURE *sig)
 {
     MSIQUERY *view;
@@ -245,20 +305,17 @@ static UINT ACTION_AppSearchReg(MSIPACKAGE *package, BOOL *appFound,
    'R','e','g','L','o','c','a','t','o','r',' ',
    'w','h','e','r','e',' ','S','i','g','n','a','t','u','r','e','_',' ','=',' ',
    '\'','%','s','\'',0};
-    static const WCHAR dwordFmt[] = { '#','%','d','\0' };
-    static const WCHAR expandSzFmt[] = { '#','%','%','%','s','\0' };
-    static const WCHAR binFmt[] = { '#','x','%','x','\0' };
 
-    TRACE("(package %p, appFound %p, sig %p)\n", package, appFound, sig);
-    *appFound = FALSE;
+    TRACE("(package %p, appValue %p, sig %p)\n", package, appValue, sig);
+    *appValue = NULL;
     rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, sig->Name);
     if (rc == ERROR_SUCCESS)
     {
         MSIRECORD *row = 0;
-        LPWSTR keyPath = NULL, valueName = NULL, propertyValue = NULL;
+        LPWSTR keyPath = NULL, valueName = NULL;
         int root, type;
         HKEY rootKey, key = NULL;
-        DWORD sz = 0, regType, i;
+        DWORD sz = 0, regType;
         LPBYTE value = NULL;
 
         rc = MSI_ViewExecute(view, 0);
@@ -282,13 +339,6 @@ static UINT ACTION_AppSearchReg(MSIPACKAGE *package, BOOL *appFound,
         /* FIXME: valueName probably does too */
         type = MSI_RecordGetInteger(row,5);
 
-        if ((type & 0x0f) != msidbLocatorTypeRawValue)
-        {
-            FIXME("AppSearch unimplemented for type %d (key path %s, value %s)\n",
-             type, debugstr_w(keyPath), debugstr_w(valueName));
-            goto end;
-        }
-
         switch (root)
         {
             case msidbRegistryRootClassesRoot:
@@ -308,10 +358,10 @@ static UINT ACTION_AppSearchReg(MSIPACKAGE *package, BOOL *appFound,
                 goto end;
         }
 
-        rc = RegCreateKeyW(rootKey, keyPath, &key);
+        rc = RegOpenKeyW(rootKey, keyPath, &key);
         if (rc)
         {
-            TRACE("RegCreateKeyW returned %d\n", rc);
+            TRACE("RegOpenKeyW returned %d\n", rc);
             rc = ERROR_SUCCESS;
             goto end;
         }
@@ -340,60 +390,29 @@ static UINT ACTION_AppSearchReg(MSIPACKAGE *package, BOOL *appFound,
             rc = ERROR_SUCCESS;
             goto end;
         }
-        
-        switch (regType)
+
+        switch (type & 0x0f)
         {
-            case REG_SZ:
-                if (*(LPWSTR)value == '#')
-                {
-                    /* escape leading pound with another */
-                    propertyValue = msi_alloc( sz + sizeof(WCHAR));
-                    propertyValue[0] = '#';
-                    strcpyW(propertyValue + 1, (LPWSTR)value);
-                }
-                else
-                {
-                    propertyValue = msi_alloc( sz);
-                    strcpyW(propertyValue, (LPWSTR)value);
-                }
-                break;
-            case REG_DWORD:
-                /* 7 chars for digits, 1 for NULL, 1 for #, and 1 for sign
-                 * char if needed
-                 */
-                propertyValue = msi_alloc( 10 * sizeof(WCHAR));
-                sprintfW(propertyValue, dwordFmt, *(DWORD *)value);
-                break;
-            case REG_EXPAND_SZ:
-                /* space for extra #% characters in front */
-                propertyValue = msi_alloc( sz + 2 * sizeof(WCHAR));
-                sprintfW(propertyValue, expandSzFmt, (LPWSTR)value);
-                break;
-            case REG_BINARY:
-                /* 3 == length of "#x<nibble>" */
-                propertyValue = msi_alloc( (sz * 3 + 1) * sizeof(WCHAR));
-                for (i = 0; i < sz; i++)
-                    sprintfW(propertyValue + i * 3, binFmt, value[i]);
-                break;
-            default:
-                WARN("unimplemented for values of type %ld\n", regType);
-                goto end;
+        case msidbLocatorTypeDirectory:
+            rc = ACTION_SearchDirectory(package, sig, (LPCWSTR)value, 0,
+             appValue);
+            break;
+        case msidbLocatorTypeRawValue:
+            ACTION_ConvertRegValue(regType, value, sz, appValue);
+            break;
+        default:
+            FIXME("AppSearch unimplemented for type %d (key path %s, value %s)\n",
+             type, debugstr_w(keyPath), debugstr_w(valueName));
         }
-
-        TRACE("found registry value, setting %s to %s\n",
-         debugstr_w(sig->Property), debugstr_w(propertyValue));
-        rc = MSI_SetPropertyW(package, sig->Property, propertyValue);
-        *appFound = TRUE;
-
 end:
-        msi_free( propertyValue);
         msi_free( value);
         RegCloseKey(key);
 
         msi_free( keyPath);
         msi_free( valueName);
 
-        msiobj_release(&row->hdr);
+        if (row)
+            msiobj_release(&row->hdr);
         MSI_ViewClose(view);
         msiobj_release(&view->hdr);
     }
@@ -407,7 +426,7 @@ end:
     return rc;
 }
 
-static UINT ACTION_AppSearchIni(MSIPACKAGE *package, BOOL *appFound,
+static UINT ACTION_AppSearchIni(MSIPACKAGE *package, LPWSTR *appValue,
  MSISIGNATURE *sig)
 {
     MSIQUERY *view;
@@ -419,13 +438,15 @@ static UINT ACTION_AppSearchIni(MSIPACKAGE *package, BOOL *appFound,
    'w','h','e','r','e',' ','S','i','g','n','a','t','u','r','e','_',' ','=',' ',
    '\'','%','s','\'',0};
 
-    TRACE("(package %p, appFound %p, sig %p)\n", package, appFound, sig);
-    *appFound = FALSE;
+    TRACE("(package %p, appValue %p, sig %p)\n", package, appValue, sig);
+    *appValue = NULL;
     rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, sig->Name);
     if (rc == ERROR_SUCCESS)
     {
         MSIRECORD *row = 0;
-        LPWSTR fileName;
+        LPWSTR fileName, section, key;
+        int field, type;
+        WCHAR buf[MAX_PATH];
 
         rc = MSI_ViewExecute(view, 0);
         if (rc != ERROR_SUCCESS)
@@ -441,14 +462,41 @@ static UINT ACTION_AppSearchIni(MSIPACKAGE *package, BOOL *appFound,
             goto end;
         }
 
-        /* get file name */
-        fileName = msi_dup_record_field(row,2);
-        FIXME("AppSearch unimplemented for IniLocator (ini file name %s)\n",
-         debugstr_w(fileName));
-        msi_free( fileName);
+        fileName = msi_dup_record_field(row, 2);
+        section = msi_dup_record_field(row, 3);
+        key = msi_dup_record_field(row, 4);
+        if ((field = MSI_RecordGetInteger(row, 5)) == MSI_NULL_INTEGER)
+            field = 0;
+        if ((type = MSI_RecordGetInteger(row, 6)) == MSI_NULL_INTEGER)
+            type = 0;
+
+        GetPrivateProfileStringW(section, key, NULL, buf,
+         sizeof(buf) / sizeof(WCHAR), fileName);
+        if (buf[0])
+        {
+            switch (type & 0x0f)
+            {
+            case msidbLocatorTypeDirectory:
+                FIXME("unimplemented for type Directory (dir: %s)\n",
+                 debugstr_w(buf));
+                break;
+            case msidbLocatorTypeFileName:
+                FIXME("unimplemented for type File (file: %s)\n",
+                 debugstr_w(buf));
+                break;
+            case msidbLocatorTypeRawValue:
+                *appValue = strdupW(buf);
+                break;
+            }
+        }
+
+        msi_free(fileName);
+        msi_free(section);
+        msi_free(key);
 
 end:
-        msiobj_release(&row->hdr);
+        if (row)
+            msiobj_release(&row->hdr);
         MSI_ViewClose(view);
         msiobj_release(&view->hdr);
     }
@@ -541,7 +589,7 @@ static UINT ACTION_FileVersionMatches(MSISIGNATURE *sig, LPCWSTR filePath,
     }
     else
     {
-        DWORD zero, size = GetFileVersionInfoSizeW((LPWSTR)filePath, &zero);
+        DWORD zero, size = GetFileVersionInfoSizeW(filePath, &zero);
 
         if (size)
         {
@@ -553,8 +601,8 @@ static UINT ACTION_FileVersionMatches(MSISIGNATURE *sig, LPCWSTR filePath,
                 UINT versionLen;
                 LPVOID subBlock = NULL;
 
-                if (GetFileVersionInfoW((LPWSTR)filePath, 0, size, buf))
-                    VerQueryValueW(buf, (LPWSTR)rootW, &subBlock, &versionLen);
+                if (GetFileVersionInfoW(filePath, 0, size, buf))
+                    VerQueryValueW(buf, rootW, &subBlock, &versionLen);
                 if (subBlock)
                 {
                     VS_FIXEDFILEINFO *info =
@@ -648,7 +696,7 @@ static UINT ACTION_FileMatchesSig(MSISIGNATURE *sig,
  * Returns ERROR_SUCCESS on success (which may include non-critical errors),
  * something else on failures which should halt the install.
  */
-static UINT ACTION_RecurseSearchDirectory(MSIPACKAGE *package, BOOL *appFound,
+static UINT ACTION_RecurseSearchDirectory(MSIPACKAGE *package, LPWSTR *appValue,
  MSISIGNATURE *sig, LPCWSTR dir, int depth)
 {
     static const WCHAR starDotStarW[] = { '*','.','*',0 };
@@ -662,7 +710,7 @@ static UINT ACTION_RecurseSearchDirectory(MSIPACKAGE *package, BOOL *appFound,
     if (depth < 0)
         return ERROR_INVALID_PARAMETER;
 
-    *appFound = FALSE;
+    *appValue = NULL;
     /* We need the buffer in both paths below, so go ahead and allocate it
      * here.  Add two because we might need to add a backslash if the dir name
      * isn't backslash-terminated.
@@ -689,14 +737,12 @@ static UINT ACTION_RecurseSearchDirectory(MSIPACKAGE *package, BOOL *appFound,
             if (!(rc = ACTION_FileMatchesSig(sig, &findData, buf, &matches))
              && matches)
             {
-                TRACE("found file, setting %s to %s\n",
-                 debugstr_w(sig->Property), debugstr_w(buf));
-                rc = MSI_SetPropertyW(package, sig->Property, buf);
-                *appFound = TRUE;
+                TRACE("found file, returning %s\n", debugstr_w(buf));
+                *appValue = buf;
             }
             FindClose(hFind);
         }
-        if (rc == ERROR_SUCCESS && !*appFound && depth > 0)
+        if (rc == ERROR_SUCCESS && !*appValue && depth > 0)
         {
             HANDLE hFind;
             WIN32_FIND_DATAW findData;
@@ -709,19 +755,20 @@ static UINT ACTION_RecurseSearchDirectory(MSIPACKAGE *package, BOOL *appFound,
             if (hFind != INVALID_HANDLE_VALUE)
             {
                 if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-                    rc = ACTION_RecurseSearchDirectory(package, appFound,
-                     sig, findData.cFileName, depth - 1);
-                while (rc == ERROR_SUCCESS && !*appFound &&
+                    rc = ACTION_RecurseSearchDirectory(package, appValue, sig,
+                     findData.cFileName, depth - 1);
+                while (rc == ERROR_SUCCESS && !*appValue &&
                  FindNextFileW(hFind, &findData) != 0)
                 {
                     if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-                        rc = ACTION_RecurseSearchDirectory(package, appFound,
+                        rc = ACTION_RecurseSearchDirectory(package, appValue,
                          sig, findData.cFileName, depth - 1);
                 }
                 FindClose(hFind);
             }
         }
-        msi_free(buf);
+        if (!*appValue)
+            msi_free(buf);
     }
     else
         rc = ERROR_OUTOFMEMORY;
@@ -729,16 +776,15 @@ static UINT ACTION_RecurseSearchDirectory(MSIPACKAGE *package, BOOL *appFound,
     return rc;
 }
 
-static UINT ACTION_CheckDirectory(MSIPACKAGE *package, MSISIGNATURE *sig,
- LPCWSTR dir)
+static UINT ACTION_CheckDirectory(MSIPACKAGE *package, LPCWSTR dir,
+ LPWSTR *appValue)
 {
     UINT rc = ERROR_SUCCESS;
 
     if (GetFileAttributesW(dir) & FILE_ATTRIBUTE_DIRECTORY)
     {
-        TRACE("directory exists, setting %s to %s\n",
-         debugstr_w(sig->Property), debugstr_w(dir));
-        rc = MSI_SetPropertyW(package, sig->Property, dir);
+        TRACE("directory exists, returning %s\n", debugstr_w(dir));
+        *appValue = strdupW(dir);
     }
     return rc;
 }
@@ -758,23 +804,23 @@ static BOOL ACTION_IsFullPath(LPCWSTR path)
 }
 
 static UINT ACTION_SearchDirectory(MSIPACKAGE *package, MSISIGNATURE *sig,
- LPCWSTR expanded, int depth)
+ LPCWSTR path, int depth, LPWSTR *appValue)
 {
     UINT rc;
-    BOOL found;
 
-    TRACE("%p, %p, %s, %d\n", package, sig, debugstr_w(expanded), depth);
-    if (ACTION_IsFullPath(expanded))
+    TRACE("%p, %p, %s, %d, %p\n", package, sig, debugstr_w(path), depth,
+     appValue);
+    if (ACTION_IsFullPath(path))
     {
         if (sig->File)
-            rc = ACTION_RecurseSearchDirectory(package, &found, sig,
-             expanded, depth);
+            rc = ACTION_RecurseSearchDirectory(package, appValue, sig,
+             path, depth);
         else
         {
             /* Recursively searching a directory makes no sense when the
              * directory to search is the thing you're trying to find.
              */
-            rc = ACTION_CheckDirectory(package, sig, expanded);
+            rc = ACTION_CheckDirectory(package, path, appValue);
         }
     }
     else
@@ -784,20 +830,21 @@ static UINT ACTION_SearchDirectory(MSIPACKAGE *package, MSISIGNATURE *sig,
         int i;
 
         rc = ERROR_SUCCESS;
-        found = FALSE;
-        for (i = 0; rc == ERROR_SUCCESS && !found && i < 26; i++)
+        *appValue = NULL;
+        for (i = 0; rc == ERROR_SUCCESS && !*appValue && i < 26; i++)
             if (drives & (1 << drives))
             {
                 pathWithDrive[0] = 'A' + i;
                 if (GetDriveTypeW(pathWithDrive) == DRIVE_FIXED)
                 {
-                    lstrcpynW(pathWithDrive + 3, expanded,
+                    lstrcpynW(pathWithDrive + 3, path,
                               sizeof(pathWithDrive) / sizeof(pathWithDrive[0]) - 3);
                     if (sig->File)
-                        rc = ACTION_RecurseSearchDirectory(package, &found, sig,
-                         pathWithDrive, depth);
+                        rc = ACTION_RecurseSearchDirectory(package, appValue,
+                         sig, pathWithDrive, depth);
                     else
-                        rc = ACTION_CheckDirectory(package, sig, pathWithDrive);
+                        rc = ACTION_CheckDirectory(package, pathWithDrive,
+                         appValue);
                 }
             }
     }
@@ -805,7 +852,11 @@ static UINT ACTION_SearchDirectory(MSIPACKAGE *package, MSISIGNATURE *sig,
     return rc;
 }
 
-static UINT ACTION_AppSearchDr(MSIPACKAGE *package, MSISIGNATURE *sig)
+static UINT ACTION_AppSearchSigName(MSIPACKAGE *package, LPCWSTR sigName,
+ MSISIGNATURE *sig, LPWSTR *appValue);
+
+static UINT ACTION_AppSearchDr(MSIPACKAGE *package, LPWSTR *appValue,
+ MSISIGNATURE *sig)
 {
     MSIQUERY *view;
     UINT rc;
@@ -821,8 +872,8 @@ static UINT ACTION_AppSearchDr(MSIPACKAGE *package, MSISIGNATURE *sig)
     if (rc == ERROR_SUCCESS)
     {
         MSIRECORD *row = 0;
-        WCHAR buffer[MAX_PATH], expanded[MAX_PATH];
-        DWORD sz;
+        WCHAR expanded[MAX_PATH];
+        LPWSTR parentName = NULL, path = NULL, parent = NULL;
         int depth;
 
         rc = MSI_ViewExecute(view, 0);
@@ -840,39 +891,43 @@ static UINT ACTION_AppSearchDr(MSIPACKAGE *package, MSISIGNATURE *sig)
         }
 
         /* check whether parent is set */
-        buffer[0] = 0;
-        sz=sizeof(buffer)/sizeof(buffer[0]);
-        rc = MSI_RecordGetStringW(row,2,buffer,&sz);
-        if (rc != ERROR_SUCCESS)
+        parentName = msi_dup_record_field(row,2);
+        if (parentName)
         {
-            ERR("Error is %x\n",rc);
-            goto end;
-        }
-        else if (buffer[0])
-        {
-            FIXME(": searching parent (%s) unimplemented\n",
-             debugstr_w(buffer));
-            goto end;
-        }
-        /* no parent, now look for path */
-        buffer[0] = 0;
-        sz=sizeof(buffer)/sizeof(buffer[0]);
-        rc = MSI_RecordGetStringW(row,3,buffer,&sz);
-        if (rc != ERROR_SUCCESS)
-        {
-            ERR("Error is %x\n",rc);
-            goto end;
+            MSISIGNATURE parentSig;
+
+            rc = ACTION_AppSearchSigName(package, parentName, &parentSig,
+             &parent);
+            ACTION_FreeSignature(&parentSig);
+            msi_free(parentName);
         }
+        /* now look for path */
+        path = msi_dup_record_field(row,3);
         if (MSI_RecordIsNull(row,4))
             depth = 0;
         else
             depth = MSI_RecordGetInteger(row,4);
-        ACTION_ExpandAnyPath(package, buffer, expanded,
+        ACTION_ExpandAnyPath(package, path, expanded,
          sizeof(expanded) / sizeof(expanded[0]));
-        rc = ACTION_SearchDirectory(package, sig, expanded, depth);
+        msi_free(path);
+        if (parent)
+        {
+            path = msi_alloc(strlenW(parent) + strlenW(expanded) + 1);
+            if (!path)
+                goto end;
+            strcpyW(path, parent);
+            strcatW(path, expanded);
+        }
+        else
+            path = expanded;
+        rc = ACTION_SearchDirectory(package, sig, path, depth, appValue);
 
 end:
-        msiobj_release(&row->hdr);
+        if (path != expanded)
+            msi_free(path);
+        msi_free(parent);
+        if (row)
+            msiobj_release(&row->hdr);
         MSI_ViewClose(view);
         msiobj_release(&view->hdr);
     }
@@ -882,11 +937,34 @@ end:
         rc = ERROR_SUCCESS;
     }
 
-
     TRACE("returning %d\n", rc);
     return rc;
 }
 
+static UINT ACTION_AppSearchSigName(MSIPACKAGE *package, LPCWSTR sigName,
+ MSISIGNATURE *sig, LPWSTR *appValue)
+{
+    UINT rc;
+
+    *appValue = NULL;
+    rc = ACTION_AppSearchGetSignature(package, sig, sigName);
+    if (rc == ERROR_SUCCESS)
+    {
+        rc = ACTION_AppSearchComponents(package, appValue, sig);
+        if (rc == ERROR_SUCCESS && !*appValue)
+        {
+            rc = ACTION_AppSearchReg(package, appValue, sig);
+            if (rc == ERROR_SUCCESS && !*appValue)
+            {
+                rc = ACTION_AppSearchIni(package, appValue, sig);
+                if (rc == ERROR_SUCCESS && !*appValue)
+                    rc = ACTION_AppSearchDr(package, appValue, sig);
+            }
+        }
+    }
+    return rc;
+}
+
 /* http://msdn.microsoft.com/library/en-us/msi/setup/appsearch_table.asp
  * is the best reference for the AppSearch table and how it's used.
  */
@@ -903,10 +981,7 @@ UINT ACTION_AppSearch(MSIPACKAGE *package)
     if (rc == ERROR_SUCCESS)
     {
         MSIRECORD *row = 0;
-        WCHAR propBuf[0x100], sigBuf[0x100];
-        DWORD sz;
-        MSISIGNATURE sig;
-        BOOL appFound = FALSE;
+        LPWSTR propName, sigName;
 
         rc = MSI_ViewExecute(view, 0);
         if (rc != ERROR_SUCCESS)
@@ -914,6 +989,9 @@ UINT ACTION_AppSearch(MSIPACKAGE *package)
 
         while (!rc)
         {
+            MSISIGNATURE sig;
+            LPWSTR value;
+
             rc = MSI_ViewFetch(view,&row);
             if (rc != ERROR_SUCCESS)
             {
@@ -922,46 +1000,21 @@ UINT ACTION_AppSearch(MSIPACKAGE *package)
             }
 
             /* get property and signature */
-            propBuf[0] = 0;
-            sz=sizeof(propBuf)/sizeof(propBuf[0]);
-            rc = MSI_RecordGetStringW(row,1,propBuf,&sz);
-            if (rc != ERROR_SUCCESS)
-            {
-                ERR("Error is %x\n",rc);
-                msiobj_release(&row->hdr);
-                break;
-            }
-            sigBuf[0] = 0;
-            sz=sizeof(sigBuf)/sizeof(sigBuf[0]);
-            rc = MSI_RecordGetStringW(row,2,sigBuf,&sz);
-            if (rc != ERROR_SUCCESS)
-            {
-                ERR("Error is %x\n",rc);
-                msiobj_release(&row->hdr);
-                break;
-            }
+            propName = msi_dup_record_field(row,1);
+            sigName = msi_dup_record_field(row,2);
+
             TRACE("Searching for Property %s, Signature_ %s\n",
-             debugstr_w(propBuf), debugstr_w(sigBuf));
-            /* This clears all the fields, so set Name and Property afterward */
-            rc = ACTION_AppSearchGetSignature(package, &sig, sigBuf);
-            sig.Name = sigBuf;
-            sig.Property = propBuf;
-            if (rc == ERROR_SUCCESS)
+             debugstr_w(propName), debugstr_w(sigName));
+
+            rc = ACTION_AppSearchSigName(package, sigName, &sig, &value);
+            if (value)
             {
-                rc = ACTION_AppSearchComponents(package, &appFound, &sig);
-                if (rc == ERROR_SUCCESS && !appFound)
-                {
-                    rc = ACTION_AppSearchReg(package, &appFound, &sig);
-                    if (rc == ERROR_SUCCESS && !appFound)
-                    {
-                        rc = ACTION_AppSearchIni(package, &appFound, &sig);
-                        if (rc == ERROR_SUCCESS && !appFound)
-                            rc = ACTION_AppSearchDr(package, &sig);
-                    }
-                }
+                MSI_SetPropertyW(package, propName, value);
+                msi_free(value);
             }
-            msi_free( sig.File);
-            msi_free( sig.Languages);
+            ACTION_FreeSignature(&sig);
+            msi_free(propName);
+            msi_free(sigName);
             msiobj_release(&row->hdr);
         }
 
index b7799f3..e2daaf8 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 /* actions handled in this module
@@ -716,7 +716,7 @@ static void mark_progid_for_install( MSIPACKAGE* package, MSIPROGID *progid )
     if (!progid)
         return;
 
-    if (progid->InstallMe == TRUE)
+    if (progid->InstallMe)
         return;
 
     progid->InstallMe = TRUE;
@@ -736,38 +736,6 @@ static void mark_mime_for_install( MSIMIME *mime )
     mime->InstallMe = TRUE;
 }
 
-LONG msi_reg_set_val_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
-{
-    DWORD len = value ? (lstrlenW(value) + 1) * sizeof (WCHAR) : 0;
-    return RegSetValueExW( hkey, name, 0, REG_SZ, (LPBYTE)value, len );
-}
-
-LONG msi_reg_set_val_multi_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
-{
-    LPCWSTR p = value;
-    while (*p) p += lstrlenW(p) + 1;
-    return RegSetValueExW( hkey, name, 0, REG_MULTI_SZ,
-                           (LPBYTE)value, (p + 1 - value) * sizeof(WCHAR) );
-}
-
-LONG msi_reg_set_val_dword( HKEY hkey, LPCWSTR name, DWORD val )
-{
-    return RegSetValueExW( hkey, name, 0, REG_DWORD, (LPBYTE)&val, sizeof (DWORD) );
-}
-
-LONG msi_reg_set_subkey_val( HKEY hkey, LPCWSTR path, LPCWSTR name, LPCWSTR val )
-{
-    HKEY hsubkey = 0;
-    LONG r;
-
-    r = RegCreateKeyW( hkey, path, &hsubkey );
-    if (r != ERROR_SUCCESS)
-        return r;
-    r = msi_reg_set_val_str( hsubkey, name, val );
-    RegCloseKey( hsubkey );
-    return r;
-}
-
 static UINT register_appid(MSIAPPID *appid, LPCWSTR app )
 {
     static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
@@ -832,7 +800,6 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
     static const WCHAR szInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
     static const WCHAR szFileType_fmt[] = {'F','i','l','e','T','y','p','e','\\','%','s','\\','%','i',0};
     HKEY hkey,hkey2,hkey3;
-    BOOL install_on_demand = FALSE;
     MSICLASS *cls;
 
     load_classes_and_such(package);
@@ -863,9 +830,9 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
          * yes. MSDN says that these are based on _Feature_ not on
          * Component.  So verify the feature is to be installed
          */
-        if ((!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL )) &&
-             !(install_on_demand &&
-               ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED )))
+        if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
+             /* && !(install_on_demand &&
+               ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))) */
         {
             TRACE("Skipping class %s reg due to disabled feature %s\n", 
                             debugstr_w(cls->clsid), 
@@ -1161,8 +1128,7 @@ static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid,
          size += strlenW(verb->Argument);
      size += 4;
 
-     command = msi_alloc(size * sizeof (WCHAR));
-     memset(command,0,size*sizeof(WCHAR));
+     command = msi_alloc_zero(size * sizeof (WCHAR));
 
      strcpyW(command,advertise);
      if (verb->Argument)
index 7abf2d3..6226e29 100644 (file)
@@ -17,7 +17,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include "config.h"
@@ -110,7 +110,7 @@ static BOOL num_from_prop( LPCWSTR p, INT *val )
     INT       value;
 }
 
-%token COND_SPACE COND_EOF COND_SPACE
+%token COND_SPACE COND_EOF
 %token COND_OR COND_AND COND_NOT COND_XOR COND_IMP COND_EQV
 %token COND_LT COND_GT COND_EQ COND_NE COND_GE COND_LE
 %token COND_ILT COND_IGT COND_IEQ COND_INE COND_IGE COND_ILE
@@ -186,6 +186,7 @@ boolean_factor:
   | value_s
         {
             $$ = ($1 && $1[0]) ? 1 : 0;
+            msi_free($1);
         }
   | value_i operator value_i
         {
@@ -198,6 +199,7 @@ boolean_factor:
                 $$ = compare_int( num, $2, $3 );
             else 
                 $$ = ($2 == COND_NE || $2 == COND_INE );
+            msi_free($1);
         }
   | value_i operator symbol_s
         {
@@ -206,6 +208,7 @@ boolean_factor:
                 $$ = compare_int( $1, $2, num );
             else 
                 $$ = ($2 == COND_NE || $2 == COND_INE );
+            msi_free($3);
         }
   | symbol_s operator symbol_s
         {
@@ -226,10 +229,12 @@ boolean_factor:
   | literal operator value_i
         {
             $$ = 0;
+            msi_free($1);
         }
   | value_i operator literal
         {
             $$ = 0;
+            msi_free($3);
         }
   | COND_LPAR expression COND_RPAR
         {
@@ -463,7 +468,7 @@ static INT compare_int( INT a, INT operator, INT b )
         return a >= b;
     case COND_LE:
     case COND_ILE:
-        return a >= b;
+        return a <= b;
     case COND_SS:
     case COND_ISS:
         return ( a & b ) ? 1 : 0;
@@ -492,21 +497,21 @@ static int COND_GetOperator( COND_input *cond )
         int id;
     } table[] = {
         { {'~','=',0},     COND_IEQ },
-        { {'~','>','=',0}, COND_ILE },
+        { {'~','<','=',0}, COND_ILE },
         { {'~','>','<',0}, COND_ISS },
         { {'~','>','>',0}, COND_IRHS },
-        { {'~','>',0},     COND_ILT },
         { {'~','<','>',0}, COND_INE },
-        { {'~','<','=',0}, COND_IGE },
+        { {'~','<',0},     COND_ILT },
+        { {'~','>','=',0}, COND_IGE },
         { {'~','<','<',0}, COND_ILHS },
-        { {'~','<',0},     COND_IGT },
+        { {'~','>',0},     COND_IGT },
         { {'>','=',0},     COND_GE  },
         { {'>','<',0},     COND_SS  },
-        { {'>','>',0},     COND_LHS },
+        { {'<','<',0},     COND_LHS },
         { {'>',0},         COND_GT  },
         { {'<','>',0},     COND_NE  },
         { {'<','=',0},     COND_LE  },
-        { {'<','<',0},     COND_RHS },
+        { {'>','>',0},     COND_RHS },
         { {'<',0},         COND_LT  },
         { {0},             0        }
     };
index fb93c62..a8fe65c 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
@@ -207,7 +207,7 @@ static UINT CREATE_delete( struct tagMSIVIEW *view )
 }
 
 
-MSIVIEWOPS create_ops =
+static const MSIVIEWOPS create_ops =
 {
     CREATE_fetch_int,
     NULL,
index 0238066..4c824bf 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 /*
@@ -38,7 +38,7 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/summa
 #include "msi.h"
 #include "msidefs.h"
 #include "msiquery.h"
-#include "fcntl.h"
+#include "msvcrt/fcntl.h"
 #include "objbase.h"
 #include "objidl.h"
 #include "msipriv.h"
@@ -67,6 +67,8 @@ static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source,
                                LPCWSTR target, const INT type, LPCWSTR action);
 static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source,
                                LPCWSTR target, const INT type, LPCWSTR action);
+static UINT HANDLE_CustomType17(MSIPACKAGE *package, LPCWSTR source,
+                                LPCWSTR target, const INT type, LPCWSTR action);
 static UINT HANDLE_CustomType18(MSIPACKAGE *package, LPCWSTR source,
                                 LPCWSTR target, const INT type, LPCWSTR action);
 static UINT HANDLE_CustomType19(MSIPACKAGE *package, LPCWSTR source,
@@ -207,6 +209,9 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute)
         case 19: /* Error that halts install */
             rc = HANDLE_CustomType19(package,source,target,type,action);
             break;
+        case 17:
+            rc = HANDLE_CustomType17(package,source,target,type,action);
+            break;
         case 50: /*EXE file specified by a property value */
             rc = HANDLE_CustomType50(package,source,target,type,action);
             break;
@@ -437,13 +442,13 @@ static DWORD WINAPI ACTION_CallDllFunction(thread_struct *stuff)
                 ERR("Handle for object %p not found\n", package );
         }
         else
-            ERR("Cannot load functon\n");
+            ERR("failed to resolve functon %s\n", debugstr_a(proc));
 
         msi_free(proc);
         FreeLibrary(hModule);
     }
     else
-        ERR("Unable to load library\n");
+        ERR("failed to load dll %s\n", debugstr_w(stuff->source));
     msiobj_release( &stuff->package->hdr );
     msi_free(stuff->source);
     msi_free(stuff->target);
@@ -468,15 +473,26 @@ static DWORD WINAPI DllThread(LPVOID info)
     return rc;
 }
 
+static HANDLE do_msidbCustomActionTypeDll(MSIPACKAGE *package, LPCWSTR dll, LPCWSTR target)
+{
+    thread_struct *info;
+
+    info = msi_alloc( sizeof(*info) );
+    msiobj_addref( &package->hdr );
+    info->package = package;
+    info->target = strdupW(target);
+    info->source = strdupW(dll);
+
+    return CreateThread(NULL, 0, DllThread, info, 0, NULL);
+}
+
 static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source, 
                                LPCWSTR target, const INT type, LPCWSTR action)
 {
     WCHAR tmp_file[MAX_PATH];
-    thread_struct *info;
-    DWORD ThreadId;
-    HANDLE ThreadHandle;
     UINT rc = ERROR_SUCCESS;
     BOOL finished = FALSE;
+    HANDLE ThreadHandle;
 
     store_binary_to_temp(package, source, tmp_file);
 
@@ -489,13 +505,7 @@ static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source,
         strcatW(tmp_file,dot);
     } 
 
-    info = msi_alloc( sizeof(*info) );
-    msiobj_addref( &package->hdr );
-    info->package = package;
-    info->target = strdupW(target);
-    info->source = strdupW(tmp_file);
-
-    ThreadHandle = CreateThread(NULL,0,DllThread,(LPVOID)info,0,&ThreadId);
+    ThreadHandle = do_msidbCustomActionTypeDll( package, tmp_file, target );
 
     rc = process_handle(package, type, ThreadHandle, NULL, action, &finished );
 
@@ -503,7 +513,7 @@ static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source,
         track_tempfile(package, tmp_file, tmp_file);
     else
         DeleteFileW(tmp_file);
+
     return rc;
 }
 
@@ -568,6 +578,26 @@ static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source,
     return prc;
 }
 
+static UINT HANDLE_CustomType17(MSIPACKAGE *package, LPCWSTR source,
+                                LPCWSTR target, const INT type, LPCWSTR action)
+{
+    HANDLE hThread;
+    MSIFILE *file;
+
+    TRACE("%s %s\n", debugstr_w(source), debugstr_w(target));
+
+    file = get_loaded_file( package, source );
+    if (!file)
+    {
+        ERR("invalid file key %s\n", debugstr_w( source ));
+        return ERROR_FUNCTION_FAILED;
+    }
+
+    hThread = do_msidbCustomActionTypeDll( package, file->TargetPath, target );
+
+    return process_handle(package, type, hThread, NULL, action, NULL );
+}
+
 static UINT HANDLE_CustomType18(MSIPACKAGE *package, LPCWSTR source,
                                 LPCWSTR target, const INT type, LPCWSTR action)
 {
index 4da5338..5ac7f48 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
@@ -208,7 +208,7 @@ UINT WINAPI MsiOpenDatabaseA(LPCSTR szDBPath, LPCSTR szPersist, MSIHANDLE *phDB)
             goto end;
     }
     else
-        szwPersist = (LPWSTR)(DWORD)szPersist;
+        szwPersist = (LPWSTR)(DWORD_PTR)szPersist;
 
     r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB );
 
@@ -344,3 +344,20 @@ end:
 
     return r;
 }
+
+MSIDBSTATE WINAPI MsiGetDatabaseState( MSIHANDLE handle )
+{
+    MSIDBSTATE ret = MSIDBSTATE_READ;
+    MSIDATABASE *db;
+
+    TRACE("%ld\n", handle);
+
+    db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
+    if (!db)
+        return MSIDBSTATE_ERROR;
+    if (db->mode != MSIDBOPEN_READONLY )
+        ret = MSIDBSTATE_WRITE;
+    msiobj_release( &db->hdr );
+
+    return ret;
+}
index 7f6675f..6a9d62a 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
@@ -182,8 +182,16 @@ static UINT DELETE_delete( struct tagMSIVIEW *view )
     return ERROR_SUCCESS;
 }
 
+static UINT DELETE_find_matching_rows( struct tagMSIVIEW *view, UINT col,
+    UINT val, UINT *row, MSIITERHANDLE *handle )
+{
+    TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
+
+    return ERROR_FUNCTION_FAILED;
+}
+
 
-MSIVIEWOPS delete_ops =
+static const MSIVIEWOPS delete_ops =
 {
     DELETE_fetch_int,
     DELETE_fetch_stream,
@@ -194,7 +202,8 @@ MSIVIEWOPS delete_ops =
     DELETE_get_dimensions,
     DELETE_get_column_info,
     DELETE_modify,
-    DELETE_delete
+    DELETE_delete,
+    DELETE_find_matching_rows
 };
 
 UINT DELETE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )
index 1384e22..9b1c32e 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #define COBJMACROS
@@ -45,6 +45,8 @@
 WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
 
+extern HINSTANCE msi_hInstance;
+
 struct msi_control_tag;
 typedef struct msi_control_tag msi_control;
 typedef UINT (*msi_handler)( msi_dialog *, msi_control *, WPARAM );
@@ -59,6 +61,9 @@ struct msi_control_tag
     HBITMAP hBitmap;
     HICON hIcon;
     LPWSTR tabnext;
+    HMODULE hDll;
+    float progress_current;
+    float progress_max;
     WCHAR name[1];
 };
 
@@ -66,6 +71,7 @@ typedef struct msi_font_tag
 {
     struct msi_font_tag *next;
     HFONT hfont;
+    COLORREF color;
     WCHAR name[1];
 } msi_font;
 
@@ -98,16 +104,18 @@ typedef struct
     msi_dialog* dialog;
     msi_control *parent;
     DWORD       attributes;
+    LPWSTR      propval;
 } radio_button_group_descr;
 
-const WCHAR szMsiDialogClass[] = {
+static const WCHAR szMsiDialogClass[] = {
     'M','s','i','D','i','a','l','o','g','C','l','o','s','e','C','l','a','s','s',0
 };
-const WCHAR szMsiHiddenWindow[] = {
+static const WCHAR szMsiHiddenWindow[] = {
     'M','s','i','H','i','d','d','e','n','W','i','n','d','o','w',0 };
 static const WCHAR szStatic[] = { 'S','t','a','t','i','c',0 };
 static const WCHAR szButton[] = { 'B','U','T','T','O','N', 0 };
 static const WCHAR szButtonData[] = { 'M','S','I','D','A','T','A',0 };
+static const WCHAR szProgress[] = { 'P','r','o','g','r','e','s','s',0 };
 static const WCHAR szText[] = { 'T','e','x','t',0 };
 static const WCHAR szPushButton[] = { 'P','u','s','h','B','u','t','t','o','n',0 };
 static const WCHAR szLine[] = { 'L','i','n','e',0 };
@@ -126,6 +134,8 @@ static const WCHAR szRadioButtonGroup[] = {
 static const WCHAR szIcon[] = { 'I','c','o','n',0 };
 static const WCHAR szSelectionTree[] = {
     'S','e','l','e','c','t','i','o','n','T','r','e','e',0 };
+static const WCHAR szGroupBox[] = { 'G','r','o','u','p','B','o','x',0 };
+static const WCHAR szListBox[] = { 'L','i','s','t','B','o','x',0 };
 
 static UINT msi_dialog_checkbox_handler( msi_dialog *, msi_control *, WPARAM );
 static void msi_dialog_checkbox_sync_state( msi_dialog *, msi_control * );
@@ -236,6 +246,8 @@ static UINT msi_dialog_add_font( MSIRECORD *rec, LPVOID param )
     font->next = dialog->font_list;
     dialog->font_list = font;
 
+    font->color = MSI_RecordGetInteger( rec, 4 );
+
     memset( &lf, 0, sizeof lf );
     face = MSI_RecordGetString( rec, 2 );
     lf.lfHeight = MSI_RecordGetInteger( rec, 3 );
@@ -310,7 +322,7 @@ static UINT msi_dialog_build_font_list( msi_dialog *dialog )
 }
 
 static msi_control *msi_dialog_create_window( msi_dialog *dialog,
-                MSIRECORD *rec, LPCWSTR szCls, LPCWSTR name, LPCWSTR text,
+                MSIRECORD *rec, DWORD exstyle, LPCWSTR szCls, LPCWSTR name, LPCWSTR text,
                 DWORD style, HWND parent )
 {
     DWORD x, y, width, height;
@@ -328,7 +340,10 @@ static msi_control *msi_dialog_create_window( msi_dialog *dialog,
     control->value = NULL;
     control->hBitmap = NULL;
     control->hIcon = NULL;
+    control->hDll = NULL;
     control->tabnext = strdupW( MSI_RecordGetString( rec, 11) );
+    control->progress_current = 0;
+    control->progress_max = 100;
 
     x = MSI_RecordGetInteger( rec, 4 );
     y = MSI_RecordGetInteger( rec, 5 );
@@ -346,7 +361,7 @@ static msi_control *msi_dialog_create_window( msi_dialog *dialog,
         font = msi_dialog_get_style( title_font, &title );
     }
 
-    control->hwnd = CreateWindowW( szCls, title, style,
+    control->hwnd = CreateWindowExW( exstyle, szCls, title, style,
                           x, y, width, height, parent, NULL, NULL, NULL );
 
     TRACE("Dialog %s control %s hwnd %p\n",
@@ -457,24 +472,56 @@ void msi_dialog_handle_event( msi_dialog* dialog, LPCWSTR control,
                               LPCWSTR attribute, MSIRECORD *rec )
 {
     msi_control* ctrl;
-    LPCWSTR text;
+    LPCWSTR font_text, text = NULL;
+    LPWSTR font;
 
     ctrl = msi_dialog_find_control( dialog, control );
     if (!ctrl)
         return;
-    if( lstrcmpW(attribute, szText) )
+    if( !lstrcmpW(attribute, szText) )
+    {
+        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',' ',
@@ -501,6 +548,7 @@ static msi_control *msi_dialog_add_control( msi_dialog *dialog,
 {
     DWORD attributes;
     LPCWSTR text, name;
+    DWORD exstyle = 0;
 
     name = MSI_RecordGetString( rec, 2 );
     attributes = MSI_RecordGetInteger( rec, 8 );
@@ -509,15 +557,18 @@ static msi_control *msi_dialog_add_control( msi_dialog *dialog,
         style |= WS_VISIBLE;
     if( ~attributes & msidbControlAttributesEnabled )
         style |= WS_DISABLED;
+    if( attributes & msidbControlAttributesSunken )
+        exstyle |= WS_EX_CLIENTEDGE;
 
     msi_dialog_map_events(dialog, name);
 
-    return msi_dialog_create_window( dialog, rec, szCls, name, text,
-                                     style, dialog->hwnd );
+    return msi_dialog_create_window( dialog, rec, exstyle, szCls, name,
+                                     text, style, dialog->hwnd );
 }
 
 struct msi_text_info
 {
+    msi_font *font;
     WNDPROC oldproc;
     DWORD attributes;
 };
@@ -547,6 +598,9 @@ MSIText_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 
     info = GetPropW(hWnd, szButtonData);
 
+    if ( info->font )
+        SetTextColor( (HDC)wParam, info->font->color );
+
     if( msg == WM_CTLCOLORSTATIC &&
        ( info->attributes & msidbControlAttributesTransparent ) )
     {
@@ -574,6 +628,8 @@ static UINT msi_dialog_text_control( msi_dialog *dialog, MSIRECORD *rec )
 {
     msi_control *control;
     struct msi_text_info *info;
+    LPCWSTR text, ptr;
+    LPWSTR font_name;
 
     TRACE("%p %p\n", dialog, rec);
 
@@ -585,6 +641,11 @@ static UINT msi_dialog_text_control( msi_dialog *dialog, MSIRECORD *rec )
     if( !info )
         return ERROR_SUCCESS;
 
+    text = MSI_RecordGetString( rec, 10 );
+    font_name = msi_dialog_get_style( text, &ptr );
+    info->font = ( font_name ) ? msi_dialog_find_font( dialog, font_name ) : NULL;
+    msi_free( font_name );
+
     info->attributes = MSI_RecordGetInteger( rec, 8 );
     if( info->attributes & msidbControlAttributesTransparent )
         SetWindowLongPtrW( control->hwnd, GWL_EXSTYLE, WS_EX_TRANSPARENT );
@@ -700,7 +761,6 @@ struct msi_scrolltext_info
     msi_dialog *dialog;
     msi_control *control;
     WNDPROC oldproc;
-    HMODULE hRichedit;
 };
 
 static LRESULT WINAPI
@@ -718,11 +778,11 @@ MSIScrollText_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
     switch( msg )
     {
     case WM_NCDESTROY:
-        FreeLibrary( info->hRichedit );
         msi_free( info );
         RemovePropW( hWnd, szButtonData );
         break;
-    case WM_VSCROLL:
+    case WM_PAINT:
+        /* native MSI sets a wait cursor here */
         msi_dialog_button_handler( info->dialog, info->control, BN_CLICKED );
         break;
     }
@@ -777,24 +837,27 @@ static UINT msi_dialog_scrolltext_control( msi_dialog *dialog, MSIRECORD *rec )
     };
     struct msi_scrolltext_info *info;
     msi_control *control;
+    HMODULE hRichedit;
     DWORD style;
 
     info = msi_alloc( sizeof *info );
     if (!info)
         return ERROR_FUNCTION_FAILED;
 
-    info->hRichedit = LoadLibraryA("riched20");
+    hRichedit = LoadLibraryA("riched20");
 
     style = WS_BORDER | ES_MULTILINE | WS_VSCROLL |
             ES_READONLY | ES_AUTOVSCROLL | WS_TABSTOP;
     control = msi_dialog_add_control( dialog, rec, szRichEdit20W, style );
     if (!control)
     {
-        FreeLibrary( info->hRichedit );
+        FreeLibrary( hRichedit );
         msi_free( info );
         return ERROR_FUNCTION_FAILED;
     }
 
+    control->hDll = hRichedit;
+
     info->dialog = dialog;
     info->control = control;
 
@@ -1314,12 +1377,15 @@ static UINT msi_dialog_create_radiobutton( MSIRECORD *rec, LPVOID param )
     if( ~attributes & 2 )
         style |= WS_DISABLED;
 
-    control = msi_dialog_create_window( dialog, rec, szButton, name, text,
+    control = msi_dialog_create_window( dialog, rec, 0, szButton, name, text,
                                         style, group->parent->hwnd );
     if (!control)
         return ERROR_FUNCTION_FAILED;
     control->handler = msi_dialog_radiogroup_handler;
 
+    if (!lstrcmpW(control->name, group->propval))
+        SendMessageW(control->hwnd, BM_SETCHECK, BST_CHECKED, 0);
+
     prop = MSI_RecordGetString( rec, 1 );
     if( prop )
         control->property = strdupW( prop );
@@ -1371,18 +1437,164 @@ static UINT msi_dialog_radiogroup_control( msi_dialog *dialog, MSIRECORD *rec )
     group.dialog = dialog;
     group.parent = control;
     group.attributes = MSI_RecordGetInteger( rec, 8 );
+    group.propval = msi_dup_property( dialog->package, control->property );
 
     r = MSI_IterateRecords( view, 0, msi_dialog_create_radiobutton, &group );
     msiobj_release( &view->hdr );
+    msi_free( group.propval );
 
     return r;
 }
 
 /******************** Selection Tree ***************************************/
 
+struct msi_selection_tree_info
+{
+    msi_dialog *dialog;
+    HWND hwnd;
+    WNDPROC oldproc;
+};
+
+static void
+msi_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;
@@ -1396,46 +1608,265 @@ msi_dialog_tv_add_child_features( MSIPACKAGE *package, HWND hwnd,
         if ( !feature->Title )
             continue;
 
+        if ( !feature->Display )
+            continue;
+
         memset( &tvis, 0, sizeof tvis );
         tvis.hParent = hParent;
-        tvis.hInsertAfter = TVI_SORT;
-        if (feature->Title)
-        {
-            tvis.u.item.mask = TVIF_TEXT;
-            tvis.u.item.pszText = feature->Title;
-        }
+        tvis.hInsertAfter = TVI_LAST;
+        tvis.u.item.mask = TVIF_TEXT | TVIF_PARAM;
+        tvis.u.item.pszText = feature->Title;
         tvis.u.item.lParam = (LPARAM) feature;
+
         hitem = (HTREEITEM) SendMessageW( hwnd, TVM_INSERTITEMW, 0, (LPARAM) &tvis );
         if (!hitem)
             continue;
 
-        msi_dialog_tv_add_child_features( package, hwnd,
-                                          feature->Feature, hitem );
+        msi_seltree_sync_item_state( hwnd, feature, hitem );
+        msi_seltree_add_child_features( package, hwnd,
+                                        feature->Feature, hitem );
+
+        /* the node is expanded if Display is odd */
+        if ( feature->Display % 2 != 0 )
+            SendMessageW( hwnd, TVM_EXPAND, TVE_EXPAND, (LPARAM) hitem );
+    }
+}
+
+static void msi_seltree_create_imagelist( HWND hwnd )
+{
+    const int bm_width = 32, bm_height = 16, bm_count = 3;
+    const int bm_resource = 0x1001;
+    HIMAGELIST himl;
+    int i;
+    HBITMAP hbmp;
+
+    himl = ImageList_Create( bm_width, bm_height, FALSE, 4, 0 );
+    if (!himl)
+    {
+        ERR("failed to create image list\n");
+        return;
+    }
+
+    for (i=0; i<bm_count; i++)
+    {
+        hbmp = LoadBitmapW( msi_hInstance, MAKEINTRESOURCEW(i+bm_resource) );
+        if (!hbmp)
+        {
+            ERR("failed to load bitmap %d\n", i);
+            break;
+        }
+
+        /*
+         * Add a dummy bitmap at offset zero because the treeview
+         * can't use it as a state mask (zero means no user state).
+         */
+        if (!i)
+            ImageList_Add( himl, hbmp, NULL );
+
+        ImageList_Add( himl, hbmp, NULL );
     }
+
+    SendMessageW( hwnd, TVM_SETIMAGELIST, TVSIL_STATE, (LPARAM)himl );
 }
 
 static UINT msi_dialog_selection_tree( msi_dialog *dialog, MSIRECORD *rec )
 {
     msi_control *control;
     LPCWSTR prop;
-    LPWSTR val;
     MSIPACKAGE *package = dialog->package;
+    DWORD style;
+    struct msi_selection_tree_info *info;
 
+    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 },
@@ -1451,6 +1882,8 @@ struct control_handler msi_dialog_handler[] =
     { szRadioButtonGroup, msi_dialog_radiogroup_control },
     { szIcon, msi_dialog_icon_control },
     { szSelectionTree, msi_dialog_selection_tree },
+    { szGroupBox, msi_dialog_group_box },
+    { szListBox, msi_dialog_list_box },
 };
 
 #define NUM_CONTROL_TYPES (sizeof msi_dialog_handler/sizeof msi_dialog_handler[0])
@@ -1719,7 +2152,6 @@ static LRESULT msi_dialog_oncreate( HWND hwnd, LPCREATESTRUCTW cs )
     SetWindowPos( hwnd, 0, 0, 0, size.cx, size.cy,
                   SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW );
 
-
     msi_dialog_build_font_list( dialog );
     msi_dialog_fill_controls( dialog );
     msi_dialog_evaluate_control_conditions( dialog );
@@ -1779,7 +2211,7 @@ static UINT msi_dialog_control_event( MSIRECORD *rec, LPVOID param )
 
     condition = MSI_RecordGetString( rec, 5 );
     r = MSI_EvaluateConditionW( dialog->package, condition );
-    if( r == MSICONDITION_TRUE )
+    if( r == MSICONDITION_TRUE || r == MSICONDITION_NONE )
     {
         event = MSI_RecordGetString( rec, 3 );
         arg = MSI_RecordGetString( rec, 4 );
@@ -2007,16 +2439,29 @@ static LRESULT WINAPI MSIDialog_WndProc( HWND hwnd, UINT msg,
     return DefWindowProcW(hwnd, msg, wParam, lParam);
 }
 
+static BOOL CALLBACK msi_radioground_child_enum( HWND hWnd, LPARAM lParam )
+{
+    EnableWindow( hWnd, lParam );
+    return TRUE;
+}
+
 static LRESULT WINAPI MSIRadioGroup_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
     WNDPROC oldproc = (WNDPROC) GetPropW(hWnd, szButtonData);
+    LRESULT r;
 
     TRACE("hWnd %p msg %04x wParam 0x%08x lParam 0x%08lx\n", hWnd, msg, wParam, lParam);
 
     if (msg == WM_COMMAND) /* Forward notifications to dialog */
         SendMessageW(GetParent(hWnd), msg, wParam, lParam);
 
-    return CallWindowProcW(oldproc, hWnd, msg, wParam, lParam);
+    r = CallWindowProcW(oldproc, hWnd, msg, wParam, lParam);
+
+    /* make sure the radio buttons show as disabled if the parent is disabled */
+    if (msg == WM_ENABLE)
+        EnumChildWindows( hWnd, msi_radioground_child_enum, wParam );
+
+    return r;
 }
 
 static LRESULT WINAPI MSIHiddenWindowProc( HWND hwnd, UINT msg,
@@ -2126,16 +2571,18 @@ void msi_dialog_check_messages( HANDLE handle )
 
 UINT msi_dialog_run_message_loop( msi_dialog *dialog )
 {
+    DWORD style;
     HWND hwnd;
 
-    if( !(dialog->attributes & msidbDialogAttributesVisible) )
-        return ERROR_SUCCESS;
-
     if( uiThreadId != GetCurrentThreadId() )
         return SendMessageW( hMsiHiddenWindow, WM_MSI_DIALOG_CREATE, 0, (LPARAM) dialog );
 
     /* create the dialog window, don't show it yet */
-    hwnd = CreateWindowW( szMsiDialogClass, dialog->name, WS_OVERLAPPEDWINDOW,
+    style = WS_OVERLAPPED;
+    if( dialog->attributes & msidbDialogAttributesVisible )
+        style |= WS_VISIBLE;
+
+    hwnd = CreateWindowW( szMsiDialogClass, dialog->name, style,
                      CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
                      NULL, NULL, NULL, dialog );
     if( !hwnd )
@@ -2198,6 +2645,8 @@ void msi_dialog_destroy( msi_dialog *dialog )
             DestroyIcon( t->hIcon );
         msi_free( t->tabnext );
         msi_free( t );
+        if (t->hDll)
+            FreeLibrary( t->hDll );
     }
 
     /* destroy the list of fonts */
index f5b6bd2..a00f274 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
@@ -246,8 +246,29 @@ static UINT DISTINCT_delete( struct tagMSIVIEW *view )
     return ERROR_SUCCESS;
 }
 
+static UINT DISTINCT_find_matching_rows( struct tagMSIVIEW *view, UINT col,
+    UINT val, UINT *row, MSIITERHANDLE *handle )
+{
+    MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
+    UINT r;
+
+    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,
@@ -258,7 +279,8 @@ MSIVIEWOPS distinct_ops =
     DISTINCT_get_dimensions,
     DISTINCT_get_column_info,
     DISTINCT_modify,
-    DISTINCT_delete
+    DISTINCT_delete,
+    DISTINCT_find_matching_rows,
 };
 
 UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )
index 393154a..4d1525a 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 
@@ -35,6 +35,7 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/contr
 #include "action.h"
 
 #include "wine/debug.h"
+#include "wine/unicode.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
@@ -368,7 +369,17 @@ UINT ACTION_DialogBox( MSIPACKAGE* package, LPCWSTR szDialogName )
     return r;
 }
 
-struct _events Events[] = {
+static UINT ControlEvent_SetInstallLevel(MSIPACKAGE* package, LPCWSTR argument,
+                                          msi_dialog* dialog)
+{
+    int iInstallLevel = atolW(argument);
+
+    TRACE("Setting install level: %i\n", iInstallLevel);
+
+    return MSI_SetInstallLevel( package, iInstallLevel );
+}
+
+static const struct _events Events[] = {
     { "EndDialog",ControlEvent_EndDialog },
     { "NewDialog",ControlEvent_NewDialog },
     { "SpawnDialog",ControlEvent_SpawnDialog },
@@ -379,6 +390,7 @@ struct _events Events[] = {
     { "AddSource",ControlEvent_AddSource },
     { "SetTargetPath",ControlEvent_SetTargetPath },
     { "Reset",ControlEvent_Reset },
+    { "SetInstallLevel",ControlEvent_SetInstallLevel },
     { NULL,NULL },
 };
 
index 694f6d6..ba36a0d 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 
@@ -180,7 +180,7 @@ static long cabinet_seek(INT_PTR hf, long dist, int seektype)
     return SetFilePointer(handle, dist, NULL, seektype);
 }
 
-static void msi_file_update_ui( MSIPACKAGE *package, MSIFILE *f )
+static void msi_file_update_ui( MSIPACKAGE *package, MSIFILE *f, const WCHAR *action )
 {
     MSIRECORD *uirow;
     LPWSTR uipath, p;
@@ -194,7 +194,7 @@ static void msi_file_update_ui( MSIPACKAGE *package, MSIFILE *f )
         p[1]=0;
     MSI_RecordSetStringW( uirow, 9, uipath);
     MSI_RecordSetInteger( uirow, 6, f->FileSize );
-    ui_actiondata( package, szInstallFiles, uirow);
+    ui_actiondata( package, action, uirow);
     msiobj_release( &uirow->hdr );
     msi_free( uipath );
     ui_progress( package, 2, f->FileSize, 0, 0);
@@ -210,6 +210,7 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
         HANDLE handle;
         LPWSTR file;
         MSIFILE *f;
+        DWORD attrs;
 
         file = strdupAtoW(pfdin->psz1);
         f = get_loaded_file(data->package, file);
@@ -227,12 +228,15 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
             return 0;
         }
 
-        msi_file_update_ui( data->package, f );
+        msi_file_update_ui( data->package, f, szInstallFiles );
 
         TRACE("extracting %s\n", debugstr_w(f->TargetPath) );
 
+        attrs = f->Attributes & (FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
+        if (!attrs) attrs = FILE_ATTRIBUTE_NORMAL;
+
         handle = CreateFileW( f->TargetPath, GENERIC_READ | GENERIC_WRITE, 0,
-                              NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
+                              NULL, CREATE_ALWAYS, attrs, NULL );
         if ( handle == INVALID_HANDLE_VALUE )
         {
             ERR("failed to create %s (error %ld)\n",
@@ -328,90 +332,21 @@ static VOID set_file_source(MSIPACKAGE* package, MSIFILE* file, MSICOMPONENT*
 {
     if (file->Attributes & msidbFileAttributesNoncompressed)
     {
-        LPWSTR p;
+        LPWSTR p, path;
         p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
-        file->SourcePath = build_directory_name(2, p, file->ShortName);
+        path = build_directory_name(2, p, file->ShortName);
+        if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW( path ))
+        {
+            msi_free(path);
+            path = build_directory_name(2, p, file->LongName);
+        }
+        file->SourcePath = path;
         msi_free(p);
     }
     else
         file->SourcePath = build_directory_name(2, path, file->File);
 }
 
-static BOOL check_volume(LPCWSTR path, LPCWSTR want_volume, LPWSTR volume, 
-        UINT *intype)
-{
-    WCHAR drive[4];
-    WCHAR name[MAX_PATH];
-    UINT type;
-
-    if (!(path[0] && path[1] == ':'))
-        return TRUE;
-
-    drive[0] = path[0];
-    drive[1] = path[1];
-    drive[2] = '\\';
-    drive[3] = 0;
-    TRACE("Checking volume %s .. (%s)\n",debugstr_w(drive), debugstr_w(want_volume));
-    type = GetDriveTypeW(drive);
-    TRACE("drive is of type %x\n",type);
-
-    if (type == DRIVE_UNKNOWN || type == DRIVE_NO_ROOT_DIR || 
-            type == DRIVE_FIXED || type == DRIVE_RAMDISK)
-        return TRUE;
-
-    GetVolumeInformationW(drive, name, MAX_PATH, NULL, NULL, NULL, NULL, 0);
-    TRACE("Drive contains %s\n", debugstr_w(name));
-    volume = strdupW(name);
-    if (*intype)
-        *intype=type;
-    return (strcmpiW(want_volume,name)==0);
-}
-
-static BOOL check_for_sourcefile(LPCWSTR source)
-{
-    DWORD attrib = GetFileAttributesW(source);
-    return (!(attrib == INVALID_FILE_ATTRIBUTES));
-}
-
-static UINT ready_volume(MSIPACKAGE* package, LPCWSTR path, LPWSTR last_volume, 
-                         MSIRECORD *row,UINT *type )
-{
-    LPWSTR volume = NULL; 
-    LPCWSTR want_volume = MSI_RecordGetString(row, 5);
-    BOOL ok = check_volume(path, want_volume, volume, type);
-
-    TRACE("Readying Volume for %s (%s, %s)\n", debugstr_w(path),
-          debugstr_w(want_volume), debugstr_w(last_volume));
-
-    if (check_for_sourcefile(path) && !ok)
-    {
-        FIXME("Found the Sourcefile but not on the correct volume.(%s,%s,%s)\n",
-                debugstr_w(path),debugstr_w(want_volume), debugstr_w(volume));
-        return ERROR_SUCCESS;
-    }
-
-    while (!ok)
-    {
-        INT rc;
-        LPCWSTR prompt;
-        LPWSTR msg;
-      
-        prompt = MSI_RecordGetString(row,3);
-        msg = generate_error_string(package, 1302, 1, prompt);
-        rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
-        msi_free(volume);
-        msi_free(msg);
-        if (rc == IDOK)
-            ok = check_for_sourcefile(path);
-        else
-            return ERROR_INSTALL_USEREXIT;
-    }
-
-    msi_free(last_volume);
-    last_volume = strdupW(volume);
-    return ERROR_SUCCESS;
-}
-
 struct media_info {
     UINT last_sequence; 
     LPWSTR last_volume;
@@ -457,7 +392,6 @@ static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi,
     LPCWSTR cab, volume;
     DWORD sz;
     INT seq;
-    UINT type;
     LPCWSTR prompt;
     MSICOMPONENT *comp = file->Component;
 
@@ -489,23 +423,15 @@ static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi,
     {
         mi->last_path = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
         set_file_source(package,file,comp,mi->last_path);
-        rc = ready_volume(package, file->SourcePath, mi->last_volume, row,&type);
 
         MsiSourceListAddMediaDiskW(package->ProductCode, NULL, 
             MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT, mi->count, volume,
             prompt);
 
-        if (type == DRIVE_REMOVABLE || type == DRIVE_CDROM || 
-                type == DRIVE_RAMDISK)
-            MsiSourceListSetInfoW(package->ProductCode, NULL, 
+        MsiSourceListSetInfoW(package->ProductCode, NULL, 
                 MSIINSTALLCONTEXT_USERMANAGED, 
                 MSICODE_PRODUCT|MSISOURCETYPE_MEDIA,
                 INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path);
-        else
-            MsiSourceListSetInfoW(package->ProductCode, NULL, 
-                MSIINSTALLCONTEXT_USERMANAGED, 
-                MSICODE_PRODUCT|MSISOURCETYPE_NETWORK,
-                INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path);
         msiobj_release(&row->hdr);
         return rc;
     }
@@ -550,18 +476,10 @@ static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi,
                 strcpyW(mi->last_path,mi->source);
                 strcatW(mi->source,cab);
 
-                rc = ready_volume(package, mi->source, mi->last_volume, row, &type);
-                if (type == DRIVE_REMOVABLE || type == DRIVE_CDROM || 
-                        type == DRIVE_RAMDISK)
-                    MsiSourceListSetInfoW(package->ProductCode, NULL,
+                MsiSourceListSetInfoW(package->ProductCode, NULL,
                             MSIINSTALLCONTEXT_USERMANAGED,
                             MSICODE_PRODUCT|MSISOURCETYPE_MEDIA,
                             INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path);
-                else
-                    MsiSourceListSetInfoW(package->ProductCode, NULL,
-                            MSIINSTALLCONTEXT_USERMANAGED,
-                            MSICODE_PRODUCT|MSISOURCETYPE_NETWORK,
-                            INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path);
 
                 /* extract the cab file into a folder in the temp folder */
                 sz = MAX_PATH;
@@ -578,19 +496,11 @@ static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi,
         mi->last_path = msi_alloc(MAX_PATH*sizeof(WCHAR));
         MSI_GetPropertyW(package,cszSourceDir,mi->source,&sz);
         strcpyW(mi->last_path,mi->source);
-        rc = ready_volume(package, mi->last_path, mi->last_volume, row, &type);
 
-        if (type == DRIVE_REMOVABLE || type == DRIVE_CDROM || 
-                type == DRIVE_RAMDISK)
-            MsiSourceListSetInfoW(package->ProductCode, NULL,
+        MsiSourceListSetInfoW(package->ProductCode, NULL,
                     MSIINSTALLCONTEXT_USERMANAGED,
                     MSICODE_PRODUCT|MSISOURCETYPE_MEDIA,
                     INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path);
-        else
-            MsiSourceListSetInfoW(package->ProductCode, NULL,
-                    MSIINSTALLCONTEXT_USERMANAGED,
-                    MSICODE_PRODUCT|MSISOURCETYPE_NETWORK,
-                    INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path);
     }
     set_file_source(package, file, comp, mi->last_path);
 
@@ -604,19 +514,14 @@ static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi,
 }
 
 static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key, 
-                                   LPWSTR* file_source)
+                            MSIFILE** file)
 {
-    MSIFILE *file;
-
-    LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
+    LIST_FOR_EACH_ENTRY( *file, &package->files, MSIFILE, entry )
     {
-        if (lstrcmpW( file_key, file->File )==0)
+        if (lstrcmpW( file_key, (*file)->File )==0)
         {
-            if (file->state >= msifs_overwrite)
-            {
-                *file_source = strdupW( file->TargetPath );
+            if ((*file)->state >= msifs_overwrite)
                 return ERROR_SUCCESS;
-            }
             else
                 return ERROR_FILE_NOT_FOUND;
         }
@@ -744,13 +649,13 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
 static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
 {
     MSIPACKAGE *package = (MSIPACKAGE*)param;
-    WCHAR *file_source = NULL;
     WCHAR dest_name[0x100];
     LPWSTR dest_path, dest;
     LPCWSTR file_key, component;
     DWORD sz;
     DWORD rc;
     MSICOMPONENT *comp;
+    MSIFILE *file;
 
     component = MSI_RecordGetString(row,2);
     comp = get_loaded_component(package,component);
@@ -775,17 +680,16 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
         return ERROR_FUNCTION_FAILED;
     }
 
-    rc = get_file_target(package,file_key,&file_source);
+    rc = get_file_target(package,file_key,&file);
 
     if (rc != ERROR_SUCCESS)
     {
         ERR("Original file unknown %s\n",debugstr_w(file_key));
-        msi_free(file_source);
         return ERROR_SUCCESS;
     }
 
     if (MSI_RecordIsNull(row,4))
-        strcpyW(dest_name,strrchrW(file_source,'\\')+1);
+        strcpyW(dest_name,strrchrW(file->TargetPath,'\\')+1);
     else
     {
         sz=0x100;
@@ -796,7 +700,7 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
     if (MSI_RecordIsNull(row,5))
     {
         LPWSTR p;
-        dest_path = strdupW(file_source);
+        dest_path = strdupW(file->TargetPath);
         p = strrchrW(dest_path,'\\');
         if (p)
             *p=0;
@@ -813,7 +717,6 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
             if (!dest_path)
             {
                 FIXME("Unable to get destination folder, try AppSearch properties\n");
-                msi_free(file_source);
                 return ERROR_SUCCESS;
             }
         }
@@ -821,23 +724,24 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
 
     dest = build_directory_name(2, dest_path, dest_name);
 
-    TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),
+    TRACE("Duplicating file %s to %s\n",debugstr_w(file->TargetPath),
                     debugstr_w(dest)); 
 
-    if (strcmpW(file_source,dest))
-        rc = !CopyFileW(file_source,dest,TRUE);
+    if (strcmpW(file->TargetPath,dest))
+        rc = !CopyFileW(file->TargetPath,dest,TRUE);
     else
         rc = ERROR_SUCCESS;
 
     if (rc != ERROR_SUCCESS)
         ERR("Failed to copy file %s -> %s, last error %ld\n",
-            debugstr_w(file_source), debugstr_w(dest_path), GetLastError());
+            debugstr_w(file->TargetPath), debugstr_w(dest_path), GetLastError());
 
     FIXME("We should track these duplicate files as well\n");   
 
     msi_free(dest_path);
     msi_free(dest);
-    msi_free(file_source);
+
+    msi_file_update_ui(package, file, szDuplicateFiles);
 
     return ERROR_SUCCESS;
 }
@@ -866,6 +770,9 @@ UINT ACTION_RemoveFiles( MSIPACKAGE *package )
 
     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
     {
+        MSIRECORD *uirow;
+        LPWSTR uipath, p;
+
         if ( !file->Component )
             continue;
         if ( file->Component->Installed == INSTALLSTATE_LOCAL )
@@ -881,6 +788,19 @@ UINT ACTION_RemoveFiles( MSIPACKAGE *package )
         if ( !DeleteFileW( file->TargetPath ) )
             ERR("failed to delete %s\n",  debugstr_w(file->TargetPath) );
         file->state = msifs_missing;
+
+        /* the UI chunk */
+        uirow = MSI_CreateRecord( 9 );
+        MSI_RecordSetStringW( uirow, 1, file->FileName );
+        uipath = strdupW( file->TargetPath );
+        p = strrchrW(uipath,'\\');
+        if (p)
+            p[1]=0;
+        MSI_RecordSetStringW( uirow, 9, uipath);
+        ui_actiondata( package, szRemoveFiles, uirow);
+        msiobj_release( &uirow->hdr );
+        msi_free( uipath );
+        /* FIXME: call ui_progress here? */
     }
 
     return ERROR_SUCCESS;
index 85f9028..b0d9d52 100644 (file)
@@ -16,7 +16,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 /*
index 52c2439..1cd82b3 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
@@ -188,6 +188,9 @@ UINT WINAPI MsiCloseHandle(MSIHANDLE handle)
 
     TRACE("%lx\n",handle);
 
+    if (!handle)
+        return ERROR_SUCCESS;
+
     EnterCriticalSection( &MSI_handle_cs );
 
     info = msihandle2msiinfo(handle, 0);
index 2b2ba06..51184d5 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 /*
@@ -43,47 +43,6 @@ const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0};
 const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0};
 const WCHAR cszbs[]={'\\',0};
 
-DWORD build_version_dword(LPCWSTR version_string)
-{
-    SHORT major,minor;
-    WORD build;
-    DWORD rc = 0x00000000;
-    LPCWSTR ptr1;
-
-    ptr1 = version_string;
-
-    if (!ptr1)
-        return rc;
-    else
-        major = atoiW(ptr1);
-
-
-    if(ptr1)
-        ptr1 = strchrW(ptr1,'.');
-    if (ptr1)
-    {
-        ptr1++;
-        minor = atoiW(ptr1);
-    }
-    else
-        minor = 0;
-
-    if (ptr1)
-        ptr1 = strchrW(ptr1,'.');
-
-    if (ptr1)
-    {
-        ptr1++;
-        build = atoiW(ptr1);
-    }
-    else
-        build = 0;
-
-    rc = MAKELONG(build,MAKEWORD(minor,major));
-    TRACE("%s -> 0x%lx\n",debugstr_w(version_string),rc);
-    return rc;
-}
-
 LPWSTR build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name )
 {
     LPWSTR SystemFolder, dest, FilePath;
@@ -133,6 +92,14 @@ LPWSTR msi_dup_property(MSIPACKAGE *package, LPCWSTR prop)
     return str;
 }
 
+int msi_get_property_int( MSIPACKAGE *package, LPCWSTR prop, int def )
+{
+    LPWSTR str = msi_dup_property( package, prop );
+    int val = str ? atoiW( str ) : def;
+    msi_free( str );
+    return val;
+}
+
 MSICOMPONENT* get_loaded_component( MSIPACKAGE* package, LPCWSTR Component )
 {
     MSICOMPONENT *comp;
@@ -228,6 +195,45 @@ static LPWSTR get_source_root( MSIPACKAGE *package )
     return path;
 }
 
+/*
+ * clean_spaces_from_path()
+ *
+ * removes spaces from the beginning and end of path segments
+ * removes multiple \\ characters
+ */
+static void clean_spaces_from_path( LPWSTR p )
+{
+    LPWSTR q = p;
+    int n, len = 0;
+
+    while (1)
+    {
+        /* copy until the end of the string or a space */
+        while (*p != ' ' && (*q = *p))
+        {
+            p++, len++;
+            /* reduce many backslashes to one */
+            if (*p != '\\' || *q != '\\')
+                q++;
+        }
+
+        /* quit at the end of the string */
+        if (!*p)
+            break;
+
+        /* count the number of spaces */
+        n = 0;
+        while (p[n] == ' ')
+            n++;
+
+        /* if it's leading or trailing space, skip it */
+        if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
+            p += n;
+        else  /* copy n spaces */
+            while (n && (*q++ = *p++)) n--;
+    }
+}
+
 LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, 
                       BOOL set_prop, MSIFOLDER **folder)
 {
@@ -255,6 +261,7 @@ LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
 
             /* correct misbuilt target dir */
             path = build_directory_name(2, check_path, NULL);
+            clean_spaces_from_path( path );
             if (strcmpiW(path,check_path)!=0)
                 MSI_SetPropertyW(package,cszTargetDir,path);
             msi_free(check_path);
@@ -307,6 +314,7 @@ LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
             TRACE("   TargetDefault = %s\n", debugstr_w(f->TargetDefault));
 
             path = build_directory_name( 3, p, f->TargetDefault, NULL );
+            clean_spaces_from_path( path );
             f->ResolvedTarget = strdupW( path );
             TRACE("target -> %s\n", debugstr_w(path));
             if (set_prop)
@@ -314,21 +322,37 @@ LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
         }
         else 
         {
-            if (f->SourceDefault && f->SourceDefault[0]!='.')
-                path = build_directory_name( 3, p, f->SourceDefault, NULL );
-            else
-                path = strdupW(p);
-            TRACE("source -> %s\n", debugstr_w(path));
+            /* source may be in a few different places ... check each of them */
+            path = NULL;
 
-            /* if the directory doesn't exist, use the root */
-            if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW( path ))
+            /* try the long path directory */
+            if (f->SourceLongPath)
             {
-                msi_free( path );
-                path = get_source_root( package );
-                TRACE("defaulting to %s\n", debugstr_w(path));
+                path = build_directory_name( 3, p, f->SourceLongPath, NULL );
+                if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW( path ))
+                {
+                    msi_free( path );
+                    path = NULL;
+                }
             }
-            else
-                f->ResolvedSource = strdupW( path );
+
+            /* try the short path directory */
+            if (!path && f->SourceShortPath)
+            {
+                path = build_directory_name( 3, p, f->SourceShortPath, NULL );
+                if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW( path ))
+                {
+                    msi_free( path );
+                    path = NULL;
+                }
+            }
+
+            /* try the root of the install */
+            if (!path)
+                path = get_source_root( package );
+
+            TRACE("source -> %s\n", debugstr_w(path));
+            f->ResolvedSource = strdupW( path );
         }
         msi_free(p);
     }
@@ -467,7 +491,8 @@ void ACTION_free_package_structures( MSIPACKAGE* package)
         list_remove( &folder->entry );
         msi_free( folder->Directory );
         msi_free( folder->TargetDefault );
-        msi_free( folder->SourceDefault );
+        msi_free( folder->SourceLongPath );
+        msi_free( folder->SourceShortPath );
         msi_free( folder->ResolvedTarget );
         msi_free( folder->ResolvedSource );
         msi_free( folder->Property );
@@ -496,6 +521,7 @@ void ACTION_free_package_structures( MSIPACKAGE* package)
         msi_free( file->File );
         msi_free( file->FileName );
         msi_free( file->ShortName );
+        msi_free( file->LongName );
         msi_free( file->Version );
         msi_free( file->Language );
         msi_free( file->SourcePath );
@@ -719,8 +745,6 @@ void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
     WCHAR message[1024];
     MSIRECORD * row = 0;
     DWORD size;
-    static const WCHAR szActionData[] = 
-        {'A','c','t','i','o','n','D','a','t','a',0};
 
     if (!package->LastAction || strcmpW(package->LastAction,action))
     {
@@ -753,8 +777,6 @@ void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
  
     MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
 
-    ControlEvent_FireSubscribedEvent(package,szActionData, row);
-
     msiobj_release(&row->hdr);
 }
 
@@ -803,49 +825,35 @@ void reduce_to_shortfilename(WCHAR* filename)
 LPWSTR create_component_advertise_string(MSIPACKAGE* package, 
                 MSICOMPONENT* component, LPCWSTR feature)
 {
-    GUID clsid;
-    WCHAR productid_85[21];
-    WCHAR component_85[21];
-    /*
-     * I have a fair bit of confusion as to when a < is used and when a > is
-     * used. I do not think i have it right...
-     *
-     * Ok it appears that the > is used if there is a guid for the compoenent
-     * and the < is used if not.
-     */
-    static WCHAR fmt1[] = {'%','s','%','s','<',0,0};
-    static WCHAR fmt2[] = {'%','s','%','s','>','%','s',0,0};
+    static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
+    WCHAR productid_85[21], component_85[21];
     LPWSTR output = NULL;
     DWORD sz = 0;
+    GUID clsid;
+
+    /* > 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;
 }
index 536daea..85c9f51 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
@@ -214,8 +214,16 @@ static UINT INSERT_delete( struct tagMSIVIEW *view )
     return ERROR_SUCCESS;
 }
 
+static UINT INSERT_find_matching_rows( struct tagMSIVIEW *view, UINT col,
+    UINT val, UINT *row, MSIITERHANDLE *handle )
+{
+    TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
+
+    return ERROR_FUNCTION_FAILED;
+}
+
 
-MSIVIEWOPS insert_ops =
+static const MSIVIEWOPS insert_ops =
 {
     INSERT_fetch_int,
     NULL,
@@ -226,7 +234,8 @@ MSIVIEWOPS insert_ops =
     INSERT_get_dimensions,
     INSERT_get_column_info,
     INSERT_modify,
-    INSERT_delete
+    INSERT_delete,
+    INSERT_find_matching_rows
 };
 
 UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
index 08b5f70..f5e2c42 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 /* Msi top level apis directly related to installs */
@@ -29,9 +29,8 @@
 #include "msi.h"
 #include "msidefs.h"
 #include "msipriv.h"
-#include "winuser.h"
-#include "wine/unicode.h"
 #include "action.h"
+#include "wine/unicode.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
@@ -331,13 +330,14 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
     LPWSTR path = NULL;
     LPWSTR path2 = NULL;
     MSIFOLDER *folder;
+    MSIFILE *file;
 
-    TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
+    TRACE("%p %s %s\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
 
     attrib = GetFileAttributesW(szFolderPath);
+    /* native MSI tests writeability by making temporary files at each drive */
     if ( attrib != INVALID_FILE_ATTRIBUTES &&
-          (!(attrib & FILE_ATTRIBUTE_DIRECTORY) ||
-           attrib & FILE_ATTRIBUTE_OFFLINE ||
+          (attrib & FILE_ATTRIBUTE_OFFLINE ||
            attrib & FILE_ATTRIBUTE_READONLY))
         return ERROR_FUNCTION_FAILED;
 
@@ -345,16 +345,6 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
     if (!path)
         return ERROR_DIRECTORY;
 
-    if (attrib == INVALID_FILE_ATTRIBUTES)
-    {
-        if (!CreateDirectoryW(szFolderPath,NULL))
-        {
-            msi_free( path );
-            return ERROR_FUNCTION_FAILED;
-        }
-        RemoveDirectoryW(szFolderPath);
-    }
-
     msi_free(folder->Property);
     folder->Property = build_directory_name(2, szFolderPath, NULL);
 
@@ -384,6 +374,21 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
             path2 = resolve_folder(package, f->Directory, FALSE, TRUE, NULL);
             msi_free(path2);
         }
+
+        LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
+        {
+            MSICOMPONENT *comp = file->Component;
+            LPWSTR p;
+
+            if (!comp)
+                continue;
+
+            p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
+            msi_free(file->TargetPath);
+
+            file->TargetPath = build_directory_name(2, p, file->FileName);
+            msi_free(p);
+        }
     }
     msi_free(path);
 
@@ -399,7 +404,7 @@ UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder,
     MSIPACKAGE *package;
     UINT ret;
 
-    TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
+    TRACE("%s %s\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
 
     if ( !szFolder || !szFolderPath )
         return ERROR_INVALID_PARAMETER;
@@ -446,7 +451,6 @@ UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder,
  *    Not in the state: FALSE
  *
  */
-
 BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
 {
     BOOL r = FALSE;
@@ -526,7 +530,7 @@ UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature,
     UINT rc = ERROR_SUCCESS;
     MSIFEATURE *feature, *child;
 
-    TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
+    TRACE("%s %i\n", debugstr_w(szFeature), iState);
 
     feature = get_loaded_feature(package,szFeature);
     if (!feature)
@@ -560,7 +564,7 @@ UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
     MSIPACKAGE* package;
     UINT rc = ERROR_SUCCESS;
 
-    TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
+    TRACE("%s %i\n",debugstr_w(szFeature), iState);
 
     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
     if (!package)
@@ -619,8 +623,7 @@ UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPWSTR szFeature,
     MSIPACKAGE* package;
     UINT ret;
 
-    TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled,
-piAction);
+    TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled, piAction);
 
     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
     if (!package)
@@ -747,7 +750,6 @@ LANGID WINAPI MsiGetLanguage(MSIHANDLE hInstall)
 {
     MSIPACKAGE* package;
     LANGID langid;
-    LPWSTR buffer;
     static const WCHAR szProductLanguage[] =
         {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
     
@@ -755,10 +757,51 @@ LANGID WINAPI MsiGetLanguage(MSIHANDLE hInstall)
     if (!package)
         return ERROR_INVALID_HANDLE;
 
-    buffer = msi_dup_property( package, szProductLanguage );
-    langid = atoiW(buffer);
-
-    msi_free(buffer);
-    msiobj_release (&package->hdr);
+    langid = msi_get_property_int( package, szProductLanguage, 0 );
+    msiobj_release( &package->hdr );
     return langid;
 }
+
+UINT MSI_SetInstallLevel( MSIPACKAGE *package, int iInstallLevel )
+{
+    static const WCHAR szInstallLevel[] = {
+        'I','N','S','T','A','L','L','L','E','V','E','L',0 };
+    static const WCHAR fmt[] = { '%','d',0 };
+    WCHAR level[6];
+    UINT r;
+
+    TRACE("%p %i\n", package, iInstallLevel);
+
+    if (iInstallLevel<1 || iInstallLevel>32767)
+        return ERROR_INVALID_PARAMETER;
+
+    sprintfW( level, fmt, iInstallLevel );
+    r = MSI_SetPropertyW( package, szInstallLevel, level );
+    if ( r == ERROR_SUCCESS )
+    {
+        r = MSI_SetFeatureStates( package );
+    }
+
+    return r;
+}
+
+/***********************************************************************
+ * MsiSetInstallLevel (MSI.@)
+ */
+UINT WINAPI MsiSetInstallLevel(MSIHANDLE hInstall, int iInstallLevel)
+{
+    MSIPACKAGE* package;
+    UINT r;
+
+    TRACE("%ld %i\n", hInstall, iInstallLevel);
+
+    package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
+    if ( !package )
+        return ERROR_INVALID_HANDLE;
+
+    r = MSI_SetInstallLevel( package, iInstallLevel );
+
+    msiobj_release( &package->hdr );
+
+    return r;
+}
diff --git a/reactos/dll/win32/msi/join.c b/reactos/dll/win32/msi/join.c
new file mode 100644 (file)
index 0000000..7ce408e
--- /dev/null
@@ -0,0 +1,472 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2006 Mike McCormack for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "wine/debug.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "objbase.h"
+#include "objidl.h"
+#include "msipriv.h"
+#include "query.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
+
+typedef struct tagMSIJOINVIEW
+{
+    MSIVIEW        view;
+    MSIDATABASE   *db;
+    MSIVIEW       *left, *right;
+    UINT           left_count, right_count;
+    UINT           left_key, right_key;
+    UINT          *pairs;
+    UINT           pair_count;
+} MSIJOINVIEW;
+
+static UINT JOIN_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
+{
+    MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
+    MSIVIEW *table;
+
+    TRACE("%p %d %d %p\n", jv, row, col, val );
+
+    if( !jv->left || !jv->right )
+         return ERROR_FUNCTION_FAILED;
+
+    if( (col==0) || (col>(jv->left_count + jv->right_count)) )
+         return ERROR_FUNCTION_FAILED;
+
+    if( row >= jv->pair_count )
+         return ERROR_FUNCTION_FAILED;
+
+    if( col <= jv->left_count )
+    {
+        table = jv->left;
+        row = jv->pairs[ row*2 ];
+    }
+    else
+    {
+        table = jv->right;
+        row = jv->pairs[ row*2 + 1 ];
+        col -= jv->left_count;
+    }
+
+    return table->ops->fetch_int( table, row, col, val );
+}
+
+static UINT JOIN_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm)
+{
+    MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
+    MSIVIEW *table;
+
+    TRACE("%p %d %d %p\n", jv, row, col, stm );
+
+    if( !jv->left || !jv->right )
+         return ERROR_FUNCTION_FAILED;
+
+    if( (col==0) || (col>(jv->left_count + jv->right_count)) )
+         return ERROR_FUNCTION_FAILED;
+
+    if( row <= jv->left_count )
+    {
+        table = jv->left;
+        row = jv->pairs[ row*2 ];
+    }
+    else
+    {
+        table = jv->right;
+        row = jv->pairs[ row*2 + 1 ];
+        col -= jv->left_count;
+    }
+
+    return table->ops->fetch_stream( table, row, col, stm );
+}
+
+static UINT JOIN_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val )
+{
+    MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
+
+    TRACE("%p %d %d %04x\n", jv, row, col, val );
+
+    return ERROR_FUNCTION_FAILED;
+}
+
+static UINT JOIN_insert_row( struct tagMSIVIEW *view, MSIRECORD *record )
+{
+    MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
+
+    TRACE("%p %p\n", jv, record );
+
+    return ERROR_FUNCTION_FAILED;
+}
+
+static int join_key_compare(const void *l, const void *r)
+{
+    const UINT *left = l, *right = r;
+    if (left[1] < right[1])
+        return -1;
+    if (left[1] == right[1])
+        return 0;
+    return 1;
+}
+
+static UINT join_load_key_column( MSIJOINVIEW *jv, MSIVIEW *table, UINT column,
+                                  UINT **pdata, UINT *pcount )
+{
+    UINT r, i, count = 0, *data = NULL;
+
+    r = table->ops->get_dimensions( table, &count, NULL );
+    if( r != ERROR_SUCCESS )
+        return r;
+
+    if (!count)
+        goto end;
+
+    data = msi_alloc( count * 2 * sizeof (UINT) );
+    if (!data)
+        return ERROR_SUCCESS;
+
+    for (i=0; i<count; i++)
+    {
+        data[i*2] = i;
+        r = table->ops->fetch_int( table, i, column, &data[i*2+1] );
+        if (r != ERROR_SUCCESS)
+            ERR("fetch data (%u,%u) failed\n", i, column);
+    }
+
+    qsort( data, count, 2 * sizeof (UINT), join_key_compare );
+
+end:
+    *pdata = data;
+    *pcount = count;
+
+    return ERROR_SUCCESS;
+}
+
+static UINT join_match( UINT *ldata, UINT lcount,
+                        UINT *rdata, UINT rcount,
+                        UINT **ppairs, UINT *ppair_count )
+{
+    UINT *pairs;
+    UINT n, i, j;
+
+    TRACE("left %u right %u\n", rcount, lcount);
+
+    /* there can be at most max(lcount, rcount) matches */
+    if (lcount > rcount)
+        n = lcount;
+    else
+        n = rcount;
+
+    pairs = msi_alloc( n * 2 * sizeof(UINT) );
+    if (!pairs)
+        return ERROR_OUTOFMEMORY;
+
+    for (n=0, i=0, j=0; i<lcount && j<rcount; )
+    {
+        /* values match... store the row numbers */
+        if (ldata[i*2+1] == rdata[j*2+1])
+        {
+            pairs[n*2] = ldata[i*2];
+            pairs[n*2+1] = rdata[j*2];
+            i++;  /* FIXME: assumes primary key on the right */
+            n++;
+            continue;
+        }
+
+        /* values differ... move along */
+        if (ldata[i*2+1] < rdata[j*2+1])
+            i++;
+        else
+            j++;
+    }
+
+    *ppairs = pairs;
+    *ppair_count = n;
+
+    return ERROR_SUCCESS;
+}
+
+static UINT JOIN_execute( struct tagMSIVIEW *view, MSIRECORD *record )
+{
+    MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
+    UINT r, *ldata = NULL, *rdata = NULL, lcount = 0, rcount = 0;
+
+    TRACE("%p %p\n", jv, record);
+
+    if( !jv->left || !jv->right )
+         return ERROR_FUNCTION_FAILED;
+
+    r = jv->left->ops->execute( jv->left, NULL );
+    if (r != ERROR_SUCCESS)
+        return r;
+
+    r = jv->right->ops->execute( jv->right, NULL );
+    if (r != ERROR_SUCCESS)
+        return r;
+
+    r = join_load_key_column( jv, jv->left, jv->left_key, &ldata, &lcount );
+    if (r != ERROR_SUCCESS)
+        return r;
+
+    r = join_load_key_column( jv, jv->right, jv->right_key, &rdata, &rcount );
+    if (r != ERROR_SUCCESS)
+        goto end;
+
+    r = join_match( ldata, lcount, rdata, rcount, &jv->pairs, &jv->pair_count );
+
+end:
+    msi_free( ldata );
+    msi_free( rdata );
+
+    return r;
+}
+
+static UINT JOIN_close( struct tagMSIVIEW *view )
+{
+    MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
+
+    TRACE("%p\n", jv );
+
+    if( !jv->left || !jv->right )
+        return ERROR_FUNCTION_FAILED;
+
+    jv->left->ops->close( jv->left );
+    jv->right->ops->close( jv->right );
+
+    return ERROR_SUCCESS;
+}
+
+static UINT JOIN_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
+{
+    MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
+
+    TRACE("%p %p %p\n", jv, rows, cols );
+
+    if( cols )
+        *cols = jv->left_count + jv->right_count;
+
+    if( rows )
+    {
+        if( !jv->left || !jv->right )
+            return ERROR_FUNCTION_FAILED;
+
+        *rows = jv->pair_count;
+    }
+
+    return ERROR_SUCCESS;
+}
+
+static UINT JOIN_get_column_info( struct tagMSIVIEW *view,
+                UINT n, LPWSTR *name, UINT *type )
+{
+    MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
+
+    TRACE("%p %d %p %p\n", jv, n, name, type );
+
+    if( !jv->left || !jv->right )
+        return ERROR_FUNCTION_FAILED;
+
+    if( (n==0) || (n>(jv->left_count + jv->right_count)) )
+        return ERROR_FUNCTION_FAILED;
+
+    if( n <= jv->left_count )
+        return jv->left->ops->get_column_info( jv->left, n, name, type );
+
+    n = n - jv->left_count;
+
+    return jv->right->ops->get_column_info( jv->right, n, name, type );
+}
+
+static UINT JOIN_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
+                MSIRECORD *rec )
+{
+    MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
+
+    TRACE("%p %d %p\n", jv, eModifyMode, rec );
+
+    return ERROR_FUNCTION_FAILED;
+}
+
+static UINT JOIN_delete( struct tagMSIVIEW *view )
+{
+    MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
+
+    TRACE("%p\n", jv );
+
+    if( jv->left )
+        jv->left->ops->delete( jv->left );
+    jv->left = NULL;
+
+    if( jv->right )
+        jv->right->ops->delete( jv->right );
+    jv->right = NULL;
+
+    msi_free( jv->pairs );
+    jv->pairs = NULL;
+
+    return ERROR_SUCCESS;
+}
+
+static UINT JOIN_find_matching_rows( struct tagMSIVIEW *view, UINT col,
+    UINT val, UINT *row, MSIITERHANDLE *handle )
+{
+    MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
+
+    FIXME("%p, %d, %u, %p\n", jv, col, val, *handle);
+
+    return ERROR_FUNCTION_FAILED;
+}
+
+static const MSIVIEWOPS join_ops =
+{
+    JOIN_fetch_int,
+    JOIN_fetch_stream,
+    JOIN_set_int,
+    JOIN_insert_row,
+    JOIN_execute,
+    JOIN_close,
+    JOIN_get_dimensions,
+    JOIN_get_column_info,
+    JOIN_modify,
+    JOIN_delete,
+    JOIN_find_matching_rows
+};
+
+/*
+ * join_check_condition
+ *
+ * This is probably overly strict about what kind of condition we need
+ *  for a join query.
+ */
+static UINT join_check_condition(MSIJOINVIEW *jv, struct expr *cond)
+{
+    UINT r, type = 0;
+
+    /* assume that we have  `KeyColumn` = `SubkeyColumn` */
+    if ( cond->type != EXPR_COMPLEX )
+        return ERROR_FUNCTION_FAILED;
+
+    if ( cond->u.expr.op != OP_EQ )
+        return ERROR_FUNCTION_FAILED;
+
+    if ( cond->u.expr.left->type != EXPR_COLUMN )
+        return ERROR_FUNCTION_FAILED;
+
+    if ( cond->u.expr.right->type != EXPR_COLUMN )
+        return ERROR_FUNCTION_FAILED;
+
+    /* make sure both columns exist */
+    r = VIEW_find_column( jv->left, cond->u.expr.left->u.column, &jv->left_key );
+    if (r != ERROR_SUCCESS)
+        return ERROR_FUNCTION_FAILED;
+
+    r = VIEW_find_column( jv->right, cond->u.expr.right->u.column, &jv->right_key );
+    if (r != ERROR_SUCCESS)
+        return ERROR_FUNCTION_FAILED;
+
+    /* make sure both columns are keys */
+    r = jv->left->ops->get_column_info( jv->left, jv->left_key, NULL, &type );
+    if (r != ERROR_SUCCESS)
+        return ERROR_FUNCTION_FAILED;
+
+    if (!(type & MSITYPE_KEY))
+        return ERROR_FUNCTION_FAILED;
+
+    r = jv->right->ops->get_column_info( jv->right, jv->right_key, NULL, &type );
+    if (r != ERROR_SUCCESS)
+        return ERROR_FUNCTION_FAILED;
+
+    if (!(type & MSITYPE_KEY))
+        return ERROR_FUNCTION_FAILED;
+
+    TRACE("left %s (%u) right %s (%u)\n",
+        debugstr_w(cond->u.expr.left->u.column), jv->left_key,
+        debugstr_w(cond->u.expr.right->u.column), jv->right_key);
+
+    return ERROR_SUCCESS;
+}
+
+UINT JOIN_CreateView( MSIDATABASE *db, MSIVIEW **view,
+                      LPCWSTR left, LPCWSTR right,
+                      struct expr *cond )
+{
+    MSIJOINVIEW *jv = NULL;
+    UINT r = ERROR_SUCCESS;
+
+    TRACE("%p (%s,%s)\n", jv, debugstr_w(left), debugstr_w(right) );
+
+    jv = msi_alloc_zero( sizeof *jv );
+    if( !jv )
+        return ERROR_FUNCTION_FAILED;
+
+    /* fill the structure */
+    jv->view.ops = &join_ops;
+    jv->db = db;
+
+    /* create the tables to join */
+    r = TABLE_CreateView( db, left, &jv->left );
+    if( r != ERROR_SUCCESS )
+    {
+        ERR("can't create left table\n");
+        goto end;
+    }
+
+    r = TABLE_CreateView( db, right, &jv->right );
+    if( r != ERROR_SUCCESS )
+    {
+        ERR("can't create right table\n");
+        goto end;
+    }
+
+    /* get the number of columns in each table */
+    r = jv->left->ops->get_dimensions( jv->left, NULL, &jv->left_count );
+    if( r != ERROR_SUCCESS )
+    {
+        ERR("can't get left table dimensions\n");
+        goto end;
+    }
+
+    r = jv->right->ops->get_dimensions( jv->right, NULL, &jv->right_count );
+    if( r != ERROR_SUCCESS )
+    {
+        ERR("can't get right table dimensions\n");
+        goto end;
+    }
+
+    r = join_check_condition( jv, cond );
+    if( r != ERROR_SUCCESS )
+    {
+        ERR("can't get join condition\n");
+        goto end;
+    }
+
+    *view = &jv->view;
+    return ERROR_SUCCESS;
+
+end:
+    jv->view.ops->delete( &jv->view );
+
+    return r;
+}
index 404bdf6..8c9139d 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
 
 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;
@@ -224,7 +198,7 @@ UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine)
     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)
@@ -276,7 +250,7 @@ UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel,
         ' ','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 &&
@@ -391,8 +365,6 @@ UINT WINAPI MsiConfigureProductA(LPCSTR szProduct, int iInstallLevel,
 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);
 }
 
@@ -457,152 +429,159 @@ UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer)
     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, &regval))
         {
-            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;
@@ -627,15 +606,20 @@ UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes)
 
     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;
 }
@@ -667,6 +651,9 @@ INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
 
     TRACE("%s\n", debugstr_w(szProduct));
 
+    if (!szProduct)
+        return INSTALLSTATE_INVALIDARG;
+
     rc = MSIREG_OpenUserProductsKey(szProduct,&hkey,FALSE);
     if (rc != ERROR_SUCCESS)
         goto end;
@@ -832,17 +819,27 @@ LANGID WINAPI MsiLoadStringA( MSIHANDLE handle, UINT id, LPSTR lpBuffer,
 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,
@@ -961,132 +958,99 @@ UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage )
     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;
 }
 
 /******************************************************************
@@ -1117,16 +1081,29 @@ end:
 /******************************************************************
  * 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));
 
@@ -1136,17 +1113,67 @@ INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR 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;
 }
 
 /******************************************************************
@@ -1267,134 +1294,11 @@ end:
     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);
@@ -1484,222 +1388,244 @@ end:
     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)
@@ -1751,8 +1677,26 @@ UINT WINAPI MsiCollectUserInfoA(LPCSTR 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;
 }
 
 /***********************************************************************
@@ -1760,30 +1704,90 @@ UINT WINAPI MsiConfigureFeatureA(LPCSTR szProduct, LPCSTR szFeature, INSTALLSTAT
  */
 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;
 }
 
 /***********************************************************************
@@ -1876,54 +1880,54 @@ UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
 {
     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 );
@@ -1933,23 +1937,15 @@ UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
     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;
 }
 
@@ -1967,33 +1963,23 @@ UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature,
     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.@]
@@ -2001,8 +1987,48 @@ UINT WINAPI MsiEnumPatchesW( LPCWSTR szProduct, DWORD iPatchIndex,
 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;
 }
 
 /***********************************************************************
@@ -2011,8 +2037,18 @@ UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
 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;
 }
 
 /***********************************************************************
index ffaa3ca..cc929af 100644 (file)
        <library>shlwapi</library>
        <library>winmm</library>
        <library>cabinet</library>
+       <library>comctl32</library>
        <library>ole32</library>
        <library>oleaut32</library>
        <library>version</library>
+       <library>wininet</library>
+       <library>urlmon</library>
        <file>action.c</file>
        <file>appsearch.c</file>
        <file>classes.c</file>
@@ -39,7 +42,9 @@
        <file>helpers.c</file>
        <file>insert.c</file>
        <file>install.c</file>
+       <file>join.c</file>
        <file>msi.c</file>
+       <file>msi_main.c</file>
        <file>msiquery.c</file>
        <file>order.c</file>
        <file>package.c</file>
index 7f57ef1..9199acc 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include "windef.h"
@@ -30,13 +30,102 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
 #include "msi_Bg.rc"
 #include "msi_De.rc"
 #include "msi_En.rc"
-#include "msi_Ja.rc" 
+#include "msi_Eo.rc"
 #include "msi_Es.rc"
 #include "msi_Fi.rc"
 #include "msi_Fr.rc"
+#include "msi_Hu.rc"
+#include "msi_It.rc"
 #include "msi_Ko.rc"
 #include "msi_Nl.rc"
 #include "msi_No.rc"
 #include "msi_Pt.rc"
 #include "msi_Ru.rc"
-#include "msi_Hu.rc"
+#include "msi_Tr.rc"
+
+/* BINRES instadvert.bmp */
+0x1001 BITMAP instadvert.bmp
+/* {
+ '42 4D 76 01 00 00 00 00 00 00 76 00 00 00 28 00'
+ '00 00 20 00 00 00 10 00 00 00 01 00 04 00 00 00'
+ '00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00'
+ '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80'
+ '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80'
+ '00 00 C0 C0 C0 00 80 80 80 00 00 00 FF 00 00 FF'
+ '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF'
+ '00 00 FF FF FF 00 77 77 77 77 77 77 77 77 77 77'
+ '77 77 77 77 77 77 77 77 77 77 77 77 77 77 77 77'
+ '77 77 77 77 77 77 77 77 70 00 00 07 77 77 77 77'
+ '77 77 77 77 77 77 77 70 03 33 B3 30 07 77 77 77'
+ '77 77 77 77 77 77 77 00 B3 33 33 33 00 77 77 77'
+ '77 77 77 77 77 77 77 03 33 B3 A3 B3 30 77 77 77'
+ '77 77 07 77 77 77 70 33 33 33 33 33 B3 07 77 77'
+ '77 70 00 77 77 77 70 33 B3 30 03 33 33 07 77 77'
+ '77 00 00 07 77 77 70 33 33 00 00 3B 33 07 77 77'
+ '70 00 00 00 77 77 70 33 B3 30 0B 33 3B 07 77 77'
+ '00 00 00 00 07 77 70 3B 3A 33 33 33 33 07 77 70'
+ '00 00 00 00 00 77 77 03 3B 3B 3A 3B 30 77 77 77'
+ '77 77 77 77 77 77 77 00 33 33 3B 33 00 77 77 77'
+ '77 77 77 77 77 77 77 70 03 B3 33 30 07 77 77 77'
+ '77 77 77 77 77 77 77 77 70 00 00 07 77 77 77 77'
+ '77 77 77 77 77 77 77 77 77 77 77 77 77 77 77 77'
+ '77 77 77 77 77 77'
+} */
+
+/* BINRES instabsent.bmp */
+0x1002 BITMAP instabsent.bmp
+/* {
+ '42 4D 76 01 00 00 00 00 00 00 76 00 00 00 28 00'
+ '00 00 20 00 00 00 10 00 00 00 01 00 04 00 00 00'
+ '00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00'
+ '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80'
+ '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80'
+ '00 00 C0 C0 C0 00 80 80 80 00 00 00 FF 00 00 FF'
+ '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF'
+ '00 00 FF FF FF 00 77 77 77 77 77 77 77 77 77 77'
+ '77 77 77 77 77 77 70 07 77 77 77 77 70 07 77 77'
+ '77 77 77 77 77 77 70 00 77 77 77 77 00 07 77 77'
+ '77 77 77 77 77 77 77 00 07 77 77 70 00 77 77 77'
+ '77 77 77 77 77 77 77 70 00 77 77 00 07 77 77 77'
+ '77 77 77 77 77 77 77 77 00 07 70 00 77 77 77 77'
+ '77 77 07 77 77 77 77 77 70 00 00 07 77 77 77 77'
+ '77 70 00 77 77 77 77 77 77 00 00 77 77 77 77 77'
+ '77 00 00 07 77 77 77 77 77 00 00 77 77 77 77 77'
+ '70 00 00 00 77 77 77 77 70 00 00 07 77 77 77 77'
+ '00 00 00 00 07 77 77 77 00 07 70 00 77 77 77 70'
+ '00 00 00 00 00 77 77 70 00 77 77 00 07 77 77 77'
+ '77 77 77 77 77 77 77 00 07 77 77 70 00 77 77 77'
+ '77 77 77 77 77 77 70 00 77 77 77 77 00 07 77 77'
+ '77 77 77 77 77 77 70 07 77 77 77 77 70 07 77 77'
+ '77 77 77 77 77 77 77 77 77 77 77 77 77 77 77 77'
+ '77 77 77 77 77 77'
+} */
+
+/* BINRES instlocal.bmp */
+0x1003 BITMAP instlocal.bmp
+/* {
+ '42 4D 76 01 00 00 00 00 00 00 76 00 00 00 28 00'
+ '00 00 20 00 00 00 10 00 00 00 01 00 04 00 00 00'
+ '00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00'
+ '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80'
+ '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80'
+ '00 00 C0 C0 C0 00 80 80 80 00 00 00 FF 00 00 FF'
+ '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF'
+ '00 00 FF FF FF 00 77 77 77 77 77 77 77 77 77 77'
+ '77 77 77 77 77 77 77 77 77 77 77 77 77 77 77 77'
+ '77 77 77 77 77 77 77 77 77 77 77 77 77 77 77 77'
+ '77 77 77 77 77 77 77 77 70 07 77 77 77 77 77 77'
+ '77 77 77 77 77 77 77 77 0F F0 77 77 77 77 77 77'
+ '77 77 77 77 77 77 77 70 FF FF 07 77 77 77 77 77'
+ '77 77 07 77 77 77 77 0F F0 0F F0 77 77 77 77 77'
+ '77 70 00 77 77 77 77 0F 07 70 FF 07 77 77 77 77'
+ '77 00 00 07 77 77 77 70 77 77 0F F0 77 77 77 77'
+ '70 00 00 00 77 77 77 77 77 77 70 FF 07 77 77 77'
+ '00 00 00 00 07 77 77 77 77 77 77 0F F0 77 77 70'
+ '00 00 00 00 00 77 77 77 77 77 77 70 FF 07 77 77'
+ '77 77 77 77 77 77 77 77 77 77 77 77 0F F0 77 77'
+ '77 77 77 77 77 77 77 77 77 77 77 77 70 F0 77 77'
+ '77 77 77 77 77 77 77 77 77 77 77 77 77 07 77 77'
+ '77 77 77 77 77 77 77 77 77 77 77 77 77 77 77 77'
+ '77 77 77 77 77 77'
+} */
index 802adef..d718fd2 100644 (file)
@@ -45,7 +45,7 @@
 49 stdcall MsiGetActiveDatabase(long)
 50 stdcall MsiGetComponentStateA(long str ptr ptr)
 51 stdcall MsiGetComponentStateW(long wstr ptr ptr)
-52 stub MsiGetDatabaseState
+52 stdcall MsiGetDatabaseState(long)
 53 stub MsiGetFeatureCostA
 54 stub MsiGetFeatureCostW
 55 stub MsiGetFeatureInfoA
 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
index 8a0ead5..d5818ef 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 LANGUAGE LANG_BULGARIAN, SUBLANG_DEFAULT
index 0b15276..c07a3eb 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 LANGUAGE LANG_GERMAN, SUBLANG_DEFAULT
index f3330c8..066d812 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
diff --git a/reactos/dll/win32/msi/msi_Eo.rc b/reactos/dll/win32/msi/msi_Eo.rc
new file mode 100644 (file)
index 0000000..5b050c1
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Esperanto resources for MSI
+ *
+ * Copyright 2006 Antonio Codazzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+LANGUAGE LANG_ESPERANTO, SUBLANG_DEFAULT
+
+STRINGTABLE DISCARDABLE
+{
+       5 "Mi ne trovis la vojon %s"
+       9 "enþovu la diskon %s"
+       10 "nekorektaj parametroj"
+       11 "enigu la nomon de dosierujo kiu enhavas %s"
+       12 "instalad-fonto por mankanta taýgeco"
+       13 "retdrajvo por mankanta taýgeco"
+       14 "taýgeco el:"
+       15 "elektu la dosierujo kiu enhavas %s"
+}
index 3d36ff7..43e7652 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL
index 5de0be8..18686d9 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 LANGUAGE LANG_FINNISH, SUBLANG_DEFAULT
index 6ed1034..fa50f68 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
index 7532831..4dacfe2 100644 (file)
@@ -1,34 +1,33 @@
-/*\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"
+}
diff --git a/reactos/dll/win32/msi/msi_It.rc b/reactos/dll/win32/msi/msi_It.rc
new file mode 100644 (file)
index 0000000..7a3056c
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Italian resources for MSI
+ *
+ * Copyright 2006 Antonio Codazzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+LANGUAGE LANG_ITALIAN, SUBLANG_DEFAULT
+
+STRINGTABLE DISCARDABLE
+{
+       5 "percorso %s non trovato"
+       9 "inserire disco %s"
+       10 "parametri incorretti"
+       11 "immettere il nome della cartella che contiene %s"
+       12 "sorgente di installazione per la funzionalità mancante"
+       13 "periferica di rete per la funzionalità mancante"
+       14 "funzionalità da:"
+       15 "selezionare la cartella che contiene %s"
+}
index fb4be6b..50b6225 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT
index aff08e7..f941c29 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 LANGUAGE LANG_DUTCH, SUBLANG_DEFAULT
index fbed9fb..5aaa271 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 LANGUAGE LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL
index aa87ad2..7b814ff 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 LANGUAGE LANG_PORTUGUESE, SUBLANG_DEFAULT
index b9f41d7..23e55ab 100644 (file)
@@ -1,8 +1,7 @@
 /*
  * Russian resources for MSI
  *
- * Copyright 2005 Mikhail Y. Zvyozdochkin
- *                Aleksey Bragin
+ * Copyright 2006 Vitaly Lipatov
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -16,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
@@ -26,9 +25,9 @@ STRINGTABLE DISCARDABLE
        5 "ïóòü %s Ã­Ã¥ Ã­Ã Ã©Ã¤Ã¥Ã­"
        9 "âñòàâüòå Ã¤Ã¨Ã±Ãª %s"
        10 "íåâåðíûå Ã¯Ã Ã°Ã Ã¬Ã¥Ã²Ã°Ã»"
-       11 "ââåäèòå, ÃªÃ ÃªÃ Ã¿ Ã¯Ã Ã¯ÃªÃ  Ã±Ã®Ã¤Ã¥Ã°Ã¦Ã¨Ã² %s"
-       12 "íåäîñòóïåí Ã¨Ã±Ã²Ã®Ã·Ã­Ã¨Ãª Ã³Ã±Ã²Ã Ã­Ã®Ã¢ÃªÃ¨ (ñúåìíûé Ã¨Ã«Ã¨ ÃªÃ®Ã¬Ã¯Ã ÃªÃ²-äèñê Ã­Ã¥ Ã¢Ã±Ã²Ã Ã¢Ã«Ã¥Ã­ Ã¢ Ã¤Ã¨Ã±ÃªÃ®Ã¢Ã®Ã¤)"
-       13 "íåäîñòóïåí Ã±Ã¥Ã²Ã¥Ã¢Ã®Ã© Ã¤Ã¨Ã±Ãª, Ã±Ã®Ã¤Ã¥Ã°Ã¦Ã Ã¹Ã¨Ã© Ã­Ã¥Ã®Ã¡ÃµÃ®Ã¤Ã¨Ã¬Ã»Ã© Ã´Ã Ã©Ã«"
-       14 "ôóíêöèîíàëüíîñòü Ã¨Ã§:"
-       15 "âûáåðèòå, ÃªÃ ÃªÃ Ã¿ Ã¯Ã Ã¯ÃªÃ  Ã±Ã®Ã¤Ã¥Ã°Ã¦Ã¨Ã² %s"
+       11 "óêàæèòå ÃªÃ Ã²Ã Ã«Ã®Ã£, Ã±Ã®Ã¤Ã¥Ã°Ã¦Ã Ã¹Ã¨Ã© %s"
+       12 "èñòî÷íèê Ã³Ã±Ã²Ã Ã­Ã®Ã¢ÃªÃ¨ Ã¤Ã Ã­Ã­Ã®Ã© Ã¢Ã®Ã§Ã¬Ã®Ã¦Ã­Ã®Ã±Ã²Ã¨ Ã­Ã¥ Ã³ÃªÃ Ã§Ã Ã­"
+       13 "ñåòåâîé Ã¤Ã¨Ã±Ãª Ã¤Ã«Ã¿ Ã¤Ã Ã­Ã­Ã®Ã© Ã¢Ã®Ã§Ã¬Ã®Ã¦Ã­Ã®Ã±Ã²Ã¨ Ã­Ã¥ Ã³ÃªÃ Ã§Ã Ã­"
+       14 "âîçìîæíîñòü Ã¨Ã§:"
+       15 "âûáåðèòå ÃªÃ Ã²Ã Ã«Ã®Ã£, Ã±Ã®Ã¤Ã¥Ã°Ã¦Ã Ã¹Ã¨Ã© %s"
 }
diff --git a/reactos/dll/win32/msi/msi_Tr.rc b/reactos/dll/win32/msi/msi_Tr.rc
new file mode 100644 (file)
index 0000000..dda287c
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Turkish resources for MSI
+ *
+ * Copyright 2006 Fatih Aþýcý
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+LANGUAGE LANG_TURKISH, SUBLANG_DEFAULT
+
+STRINGTABLE DISCARDABLE
+{
+       5 "%s yolu bulunamadý"
+       9 "%s nolu diski yerleþtirin"
+       10 "bozuk parametreler"
+       11 "%s Ã¶Ã°esini içeren dizini girin"
+       12 "eksik Ã¶zellik için kurulum kaynaðý"
+       13 "eksik Ã¶zellik için að sürücüsü"
+       14 "özellik buradan:"
+       15 "%s Ã¶Ã°esini içeren dizini seçin"
+}
diff --git a/reactos/dll/win32/msi/msi_main.c b/reactos/dll/win32/msi/msi_main.c
new file mode 100644 (file)
index 0000000..1cd36a0
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2006 Mike McCormack for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+
+#define COBJMACROS
+#define NONAMELESSUNION
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "shlwapi.h"
+#include "msipriv.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+static LONG dll_count;
+
+/* the UI level */
+INSTALLUILEVEL gUILevel = INSTALLUILEVEL_BASIC;
+HWND           gUIhwnd = 0;
+INSTALLUI_HANDLERA gUIHandlerA = NULL;
+INSTALLUI_HANDLERW gUIHandlerW = NULL;
+DWORD gUIFilter = 0;
+LPVOID gUIContext = NULL;
+WCHAR gszLogFile[MAX_PATH];
+HINSTANCE msi_hInstance;
+
+/*
+ * Dll lifetime tracking declaration
+ */
+static void LockModule(void)
+{
+    InterlockedIncrement(&dll_count);
+}
+
+static void UnlockModule(void)
+{
+    InterlockedDecrement(&dll_count);
+}
+
+/******************************************************************
+ *     DllMain
+ */
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+    switch (fdwReason)
+    {
+    case DLL_PROCESS_ATTACH:
+        msi_hInstance = hinstDLL;
+        DisableThreadLibraryCalls(hinstDLL);
+        msi_dialog_register_class();
+        break;
+    case DLL_PROCESS_DETACH:
+        msi_dialog_unregister_class();
+        break;
+    }
+    return TRUE;
+}
+
+typedef struct tagIClassFactoryImpl
+{
+    const IClassFactoryVtbl *lpVtbl;
+} IClassFactoryImpl;
+
+static HRESULT WINAPI MsiCF_QueryInterface(LPCLASSFACTORY iface,
+                REFIID riid,LPVOID *ppobj)
+{
+    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+    FIXME("%p %s %p\n",This,debugstr_guid(riid),ppobj);
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI MsiCF_AddRef(LPCLASSFACTORY iface)
+{
+    LockModule();
+    return 2;
+}
+
+static ULONG WINAPI MsiCF_Release(LPCLASSFACTORY iface)
+{
+    UnlockModule();
+    return 1;
+}
+
+static HRESULT WINAPI MsiCF_CreateInstance(LPCLASSFACTORY iface,
+    LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj)
+{
+    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+
+    FIXME("%p %p %s %p\n", This, pOuter, debugstr_guid(riid), ppobj);
+    return E_FAIL;
+}
+
+static HRESULT WINAPI MsiCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
+{
+    TRACE("%p %d\n", iface, dolock);
+
+    if (dolock)
+        LockModule();
+    else
+        UnlockModule();
+
+    return S_OK;
+}
+
+static const IClassFactoryVtbl MsiCF_Vtbl =
+{
+    MsiCF_QueryInterface,
+    MsiCF_AddRef,
+    MsiCF_Release,
+    MsiCF_CreateInstance,
+    MsiCF_LockServer
+};
+
+static IClassFactoryImpl Msi_CF = { &MsiCF_Vtbl };
+
+/******************************************************************
+ * DllGetClassObject          [MSI.@]
+ */
+HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
+{
+    TRACE("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
+
+    if( IsEqualCLSID (rclsid, &CLSID_IMsiServer) ||
+        IsEqualCLSID (rclsid, &CLSID_IMsiServerMessage) ||
+        IsEqualCLSID (rclsid, &CLSID_IMsiServerX1) ||
+        IsEqualCLSID (rclsid, &CLSID_IMsiServerX2) ||
+        IsEqualCLSID (rclsid, &CLSID_IMsiServerX3) )
+    {
+        *ppv = (LPVOID) &Msi_CF;
+        return S_OK;
+    }
+    return CLASS_E_CLASSNOTAVAILABLE;
+}
+
+/******************************************************************
+ * DllGetVersion              [MSI.@]
+ */
+HRESULT WINAPI DllGetVersion(DLLVERSIONINFO *pdvi)
+{
+    TRACE("%p\n",pdvi);
+
+    if (pdvi->cbSize != sizeof(DLLVERSIONINFO))
+        return E_INVALIDARG;
+
+    pdvi->dwMajorVersion = MSI_MAJORVERSION;
+    pdvi->dwMinorVersion = MSI_MINORVERSION;
+    pdvi->dwBuildNumber = MSI_BUILDNUMBER;
+    pdvi->dwPlatformID = 1;
+
+    return S_OK;
+}
+
+/******************************************************************
+ * DllCanUnloadNow            [MSI.@]
+ */
+HRESULT WINAPI DllCanUnloadNow(void)
+{
+    return dll_count == 0 ? S_OK : S_FALSE;
+}
index 575d121..3fa8466 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #ifndef __WINE_MSI_PRIVATE__
@@ -100,6 +100,8 @@ typedef struct tagMSIRECORD
     MSIFIELD fields[1]; /* nb. array size is count+1 */
 } MSIRECORD;
 
+typedef void *MSIITERHANDLE;
+
 typedef struct tagMSIVIEWOPS
 {
     /*
@@ -114,7 +116,7 @@ typedef struct tagMSIVIEWOPS
     UINT (*fetch_int)( struct tagMSIVIEW *, UINT row, UINT col, UINT *val );
 
     /*
-     * fetch_int - reads one integer from {row,col} in the table
+     * fetch_stream - gets a stream from {row,col} in the table
      *
      *  This function is similar to fetch_int, except fetches a
      *    stream instead of an integer.
@@ -170,12 +172,24 @@ typedef struct tagMSIVIEWOPS
      */
     UINT (*delete)( struct tagMSIVIEW * );
 
+    /*
+     * find_matching_rows - iterates through rows that match a value
+     *
+     * If the column type is a string then a string ID should be passed in. 
+     *  If the value to be looked up is an integer then no transformation of
+     *  the input value is required, except if the column is a string, in which
+     *  case a string ID should be passed in.
+     * The handle is an input/output parameter that keeps track of the current
+     *  position in the iteration. It must be initialised to zero before the
+     *  first call and continued to be passed in to subsequent calls.
+     */
+    UINT (*find_matching_rows)( struct tagMSIVIEW *, UINT col, UINT val, UINT *row, MSIITERHANDLE *handle );
 } MSIVIEWOPS;
 
 struct tagMSIVIEW
 {
     MSIOBJECTHDR hdr;
-    MSIVIEWOPS   *ops;
+    const MSIVIEWOPS *ops;
 };
 
 struct msi_dialog_tag;
@@ -325,6 +339,7 @@ extern UINT MSI_InstallPackage( MSIPACKAGE *, LPCWSTR, LPCWSTR );
 extern void ACTION_free_package_structures( MSIPACKAGE* );
 extern UINT ACTION_DialogBox( MSIPACKAGE*, LPCWSTR);
 extern UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode );
+extern UINT MSI_SetFeatureStates( MSIPACKAGE *package );
 
 /* record internals */
 extern UINT MSI_RecordSetIStream( MSIRECORD *, unsigned int, IStream *);
@@ -366,6 +381,9 @@ extern UINT MSI_ViewExecute( MSIQUERY*, MSIRECORD * );
 extern UINT MSI_ViewFetch( MSIQUERY*, MSIRECORD ** );
 extern UINT MSI_ViewClose( MSIQUERY* );
 
+/* install internals */
+extern UINT MSI_SetInstallLevel( MSIPACKAGE *package, int iInstallLevel );
+
 /* package internals */
 extern MSIPACKAGE *MSI_CreatePackage( MSIDATABASE * );
 extern UINT MSI_OpenPackageW( LPCWSTR szPackage, MSIPACKAGE ** );
@@ -401,9 +419,16 @@ extern UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL cr
 extern UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
 extern UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
 
+extern LPWSTR msi_reg_get_val_str( HKEY hkey, LPCWSTR name );
+extern BOOL msi_reg_get_val_dword( HKEY hkey, LPCWSTR name, DWORD *val);
+
+extern DWORD msi_version_str_to_dword(LPCWSTR p);
+extern LPWSTR msi_version_dword_to_str(DWORD version);
+
 extern LONG msi_reg_set_val_str( HKEY hkey, LPCWSTR name, LPCWSTR value );
 extern LONG msi_reg_set_val_multi_str( HKEY hkey, LPCWSTR name, LPCWSTR value );
 extern LONG msi_reg_set_val_dword( HKEY hkey, LPCWSTR name, DWORD val );
+extern LONG msi_reg_set_subkey_val( HKEY hkey, LPCWSTR path, LPCWSTR name, LPCWSTR val );
 
 /* msi dialog interface */
 typedef UINT (*msi_dialog_event_handler)( MSIPACKAGE*, LPCWSTR, LPCWSTR, msi_dialog* );
@@ -441,6 +466,7 @@ extern INSTALLUI_HANDLERW gUIHandlerW;
 extern DWORD gUIFilter;
 extern LPVOID gUIContext;
 extern WCHAR gszLogFile[MAX_PATH];
+extern HINSTANCE msi_hInstance;
 
 /* memory allocation macro functions */
 static inline void *msi_alloc( size_t len )
index 4824d87..06c6bf9 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
@@ -354,6 +354,10 @@ UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record)
 
     TRACE("%ld %p\n", hView, record);
 
+    if( !record )
+        return ERROR_INVALID_PARAMETER;
+    *record = 0;
+
     query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
     if( !query )
         return ERROR_INVALID_HANDLE;
@@ -853,16 +857,29 @@ UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb,
     return r;
 }
 
-UINT WINAPI MsiDatabaseIsTablePersistentA(
+MSICONDITION WINAPI MsiDatabaseIsTablePersistentA(
               MSIHANDLE hDatabase, LPSTR szTableName)
 {
-    FIXME("%lx %s\n", hDatabase, debugstr_a(szTableName));
-    return ERROR_CALL_NOT_IMPLEMENTED;
+    LPWSTR szwTableName = NULL;
+    MSICONDITION r;
+
+    TRACE("%lx %s\n", hDatabase, debugstr_a(szTableName));
+
+    if( szTableName )
+    {
+        szwTableName = strdupAtoW( szTableName );
+        if( !szwTableName )
+            return MSICONDITION_ERROR;
+    }
+    r = MsiDatabaseIsTablePersistentW( hDatabase, szwTableName );
+    msi_free( szwTableName );
+
+    return r;
 }
 
-UINT WINAPI MsiDatabaseIsTablePersistentW(
+MSICONDITION WINAPI MsiDatabaseIsTablePersistentW(
               MSIHANDLE hDatabase, LPWSTR szTableName)
 {
     FIXME("%lx %s\n", hDatabase, debugstr_w(szTableName));
-    return ERROR_CALL_NOT_IMPLEMENTED;
+    return MSICONDITION_FALSE;
 }
index 27da7c6..82b1269 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
@@ -249,8 +249,26 @@ static UINT ORDER_delete( struct tagMSIVIEW *view )
     return ERROR_SUCCESS;
 }
 
+static UINT ORDER_find_matching_rows( struct tagMSIVIEW *view, UINT col,
+    UINT val, UINT *row, MSIITERHANDLE *handle )
+{
+    MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
+    UINT r;
+
+    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,
@@ -261,7 +279,8 @@ MSIVIEWOPS order_ops =
     ORDER_get_dimensions,
     ORDER_get_column_info,
     ORDER_modify,
-    ORDER_delete
+    ORDER_delete,
+    ORDER_find_matching_rows
 };
 
 static UINT ORDER_AddColumn( MSIORDERVIEW *ov, LPCWSTR name )
index a77f853..53433d0 100644 (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
  */
 
 #define NONAMELESSUNION
+#define NONAMELESSSTRUCT
 
 #include <stdarg.h>
 #include <stdio.h>
@@ -34,6 +35,8 @@
 #include "objidl.h"
 #include "wincrypt.h"
 #include "winuser.h"
+#include "wininet.h"
+#include "urlmon.h"
 #include "shlobj.h"
 #include "wine/unicode.h"
 #include "objbase.h"
@@ -443,7 +446,7 @@ static LPCWSTR copy_package_to_temp( LPCWSTR szPackage, LPWSTR filename )
 
     if( !CopyFileW( szPackage, filename, FALSE ) )
     {
-        ERR("failed to copy package to temp path %s\n", debugstr_w(filename) );
+        ERR("failed to copy package %s\n", debugstr_w(szPackage) );
         return szPackage;
     }
 
@@ -451,6 +454,38 @@ static LPCWSTR copy_package_to_temp( LPCWSTR szPackage, LPWSTR filename )
     return filename;
 }
 
+static LPCWSTR msi_download_package( LPCWSTR szUrl, LPWSTR filename )
+{
+    LPINTERNET_CACHE_ENTRY_INFOW cache_entry;
+    DWORD size = 0;
+    HRESULT hr;
+
+    /* call will always fail, becase size is 0,
+     * but will return ERROR_FILE_NOT_FOUND first
+     * if the file doesn't exist
+     */
+    GetUrlCacheEntryInfoW( szUrl, NULL, &size );
+    if ( GetLastError() != ERROR_FILE_NOT_FOUND )
+    {
+        cache_entry = HeapAlloc( GetProcessHeap(), 0, size );
+        if ( !GetUrlCacheEntryInfoW( szUrl, cache_entry, &size ) )
+        {
+            HeapFree( GetProcessHeap(), 0, cache_entry );
+            return szUrl;
+        }
+
+        lstrcpyW( filename, cache_entry->lpszLocalFileName );
+        HeapFree( GetProcessHeap(), 0, cache_entry );
+        return filename;
+    }
+
+    hr = URLDownloadToCacheFileW( NULL, szUrl, filename, MAX_PATH, 0, NULL );
+    if ( FAILED(hr) )
+        return szUrl;
+
+    return filename;
+}
+
 UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
 {
     MSIDATABASE *db = NULL;
@@ -470,7 +505,12 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
     else
     {
         WCHAR temppath[MAX_PATH];
-        LPCWSTR file = copy_package_to_temp( szPackage, temppath );
+        LPCWSTR file;
+
+        if ( UrlIsW( szPackage, URLIS_URL ) )
+            file = msi_download_package( szPackage, temppath );
+        else
+            file = copy_package_to_temp( szPackage, temppath );
 
         r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &db );
 
@@ -513,6 +553,9 @@ UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phP
 
     TRACE("%s %08lx %p\n", debugstr_w(szPackage), dwOptions, phPackage );
 
+    if( szPackage == NULL )
+        return ERROR_INVALID_PARAMETER;
+
     if( dwOptions )
         FIXME("dwOptions %08lx not supported\n", dwOptions);
 
@@ -575,11 +618,16 @@ MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
 INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
                                MSIRECORD *record)
 {
+    static const WCHAR szActionData[] =
+        {'A','c','t','i','o','n','D','a','t','a',0};
+    static const WCHAR szSetProgress[] =
+        {'S','e','t','P','r','o','g','r','e','s','s',0};
+    static const WCHAR szActionText[] =
+        {'A','c','t','i','o','n','T','e','x','t',0};
     DWORD log_type = 0;
     LPWSTR message;
     DWORD sz;
     DWORD total_size = 0;
-    INT msg_field=1;
     INT i;
     INT rc;
     char *msg;
@@ -606,34 +654,63 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS)
         log_type |= 0x800;
 
-    message = msi_alloc(1*sizeof (WCHAR));
-    message[0]=0;
-    msg_field = MSI_RecordGetFieldCount(record);
-    for (i = 1; i <= msg_field; i++)
+    if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
+    {
+        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,
@@ -667,8 +744,38 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
         }
     }
     msi_free( msg );
-    
+
     msi_free( message);
+
+    switch (eMessageType & 0xff000000)
+    {
+    case INSTALLMESSAGE_ACTIONDATA:
+        /* FIXME: format record here instead of in ui_actiondata to get the
+         * correct action data for external scripts */
+        ControlEvent_FireSubscribedEvent(package, szActionData, record);
+        break;
+    case INSTALLMESSAGE_ACTIONSTART:
+    {
+        MSIRECORD *uirow;
+        LPWSTR deformated;
+        LPCWSTR action_text = MSI_RecordGetString(record, 2);
+
+        deformat_string(package, action_text, &deformated);
+        uirow = MSI_CreateRecord(1);
+        MSI_RecordSetStringW(uirow, 1, deformated);
+        TRACE("INSTALLMESSAGE_ACTIONSTART: %s\n", debugstr_w(deformated));
+        msi_free(deformated);
+
+        ControlEvent_FireSubscribedEvent(package, szActionText, uirow);
+
+        msiobj_release(&uirow->hdr);
+        break;
+    }
+    case INSTALLMESSAGE_PROGRESS:
+        ControlEvent_FireSubscribedEvent(package, szSetProgress, record);
+        break;
+    }
+
     return ERROR_SUCCESS;
 }
 
index 4c7c62b..7ee6c22 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
index e1fa104..c0de03b 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #ifndef __WINE_MSI_QUERY_H
@@ -53,6 +53,7 @@
 #define EXPR_STRCMP   7
 #define EXPR_WILDCARD 9
 #define EXPR_COL_NUMBER_STRING 10
+#define EXPR_COL_NUMBER32 11
 
 struct sql_str {
     LPCWSTR data;
@@ -116,6 +117,10 @@ UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **, LPWSTR table,
 
 UINT DELETE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table );
 
+UINT JOIN_CreateView( MSIDATABASE *db, MSIVIEW **view,
+                      LPCWSTR left, LPCWSTR right,
+                      struct expr *cond );
+
 int sqliteGetToken(const WCHAR *z, int *tokenType);
 
 #endif /* __WINE_MSI_QUERY_H */
index c1f6d1f..159fc0b 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
@@ -100,8 +100,10 @@ MSIHANDLE WINAPI MsiCreateRecord( unsigned int cParams )
 
     rec = MSI_CreateRecord( cParams );
     if( rec )
+    {
         ret = alloc_msihandle( &rec->hdr );
-    msiobj_release( &rec->hdr );
+        msiobj_release( &rec->hdr );
+    }
     return ret;
 }
 
@@ -319,7 +321,7 @@ UINT MSI_RecordGetStringA(MSIRECORD *rec, unsigned int iField,
         break;
     }
 
-    if( *pcchValue < len )
+    if( *pcchValue <= len )
         ret = ERROR_MORE_DATA;
     *pcchValue = len;
 
@@ -387,7 +389,7 @@ UINT MSI_RecordGetStringW(MSIRECORD *rec, unsigned int iField,
         break;
     }
 
-    if( *pcchValue < len )
+    if( *pcchValue <= len )
         ret = ERROR_MORE_DATA;
     *pcchValue = len;
 
index 528070e..e9c33f1 100644 (file)
@@ -16,7 +16,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
@@ -189,39 +189,33 @@ BOOL unsquash_guid(LPCWSTR in, LPWSTR out)
 
 BOOL squash_guid(LPCWSTR in, LPWSTR out)
 {
-    DWORD i,n=0;
+    DWORD i,n=1;
+    GUID guid;
 
-    if(in[n++] != '{')
+    if (FAILED(CLSIDFromString((LPOLESTR)in, &guid)))
         return FALSE;
+
     for(i=0; i<8; i++)
         out[7-i] = in[n++];
-    if(in[n++] != '-')
-        return FALSE;
+    n++;
     for(i=0; i<4; i++)
         out[11-i] = in[n++];
-    if(in[n++] != '-')
-        return FALSE;
+    n++;
     for(i=0; i<4; i++)
         out[15-i] = in[n++];
-    if(in[n++] != '-')
-        return FALSE;
+    n++;
     for(i=0; i<2; i++)
     {
         out[17+i*2] = in[n++];
         out[16+i*2] = in[n++];
     }
-    if(in[n++] != '-')
-        return FALSE;
+    n++;
     for( ; i<8; i++)
     {
         out[17+i*2] = in[n++];
         out[16+i*2] = in[n++];
     }
     out[32]=0;
-    if(in[n++] != '}')
-        return FALSE;
-    if(in[n])
-        return FALSE;
     return TRUE;
 }
 
@@ -305,6 +299,95 @@ BOOL encode_base85_guid( GUID *guid, LPWSTR str )
     return TRUE;
 }
 
+DWORD msi_version_str_to_dword(LPCWSTR p)
+{
+    DWORD major, minor = 0, build = 0, version = 0;
+
+    if (!p)
+        return version;
+
+    major = atoiW(p);
+
+    p = strchrW(p, '.');
+    if (p)
+    {
+        minor = atoiW(p+1);
+        p = strchrW(p+1, '.');
+        if (p)
+            build = atoiW(p+1);
+    }
+
+    return MAKELONG(build, MAKEWORD(minor, major));
+}
+
+LPWSTR msi_version_dword_to_str(DWORD version)
+{
+    const WCHAR fmt[] = { '%','u','.','%','u','.','%','u',0 };
+    LPWSTR str = msi_alloc(20);
+    sprintfW(str, fmt,
+             (version&0xff000000)>>24,
+             (version&0x00ff0000)>>16,
+              version&0x0000ffff);
+    return str;
+}
+
+LONG msi_reg_set_val_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
+{
+    DWORD len = value ? (lstrlenW(value) + 1) * sizeof (WCHAR) : 0;
+    return RegSetValueExW( hkey, name, 0, REG_SZ, (LPBYTE)value, len );
+}
+
+LONG msi_reg_set_val_multi_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
+{
+    LPCWSTR p = value;
+    while (*p) p += lstrlenW(p) + 1;
+    return RegSetValueExW( hkey, name, 0, REG_MULTI_SZ,
+                           (LPBYTE)value, (p + 1 - value) * sizeof(WCHAR) );
+}
+
+LONG msi_reg_set_val_dword( HKEY hkey, LPCWSTR name, DWORD val )
+{
+    return RegSetValueExW( hkey, name, 0, REG_DWORD, (LPBYTE)&val, sizeof (DWORD) );
+}
+
+LONG msi_reg_set_subkey_val( HKEY hkey, LPCWSTR path, LPCWSTR name, LPCWSTR val )
+{
+    HKEY hsubkey = 0;
+    LONG r;
+
+    r = RegCreateKeyW( hkey, path, &hsubkey );
+    if (r != ERROR_SUCCESS)
+        return r;
+    r = msi_reg_set_val_str( hsubkey, name, val );
+    RegCloseKey( hsubkey );
+    return r;
+}
+
+LPWSTR msi_reg_get_val_str( HKEY hkey, LPCWSTR name )
+{
+    DWORD len = 0;
+    LPWSTR val;
+    LONG r;
+
+    r = RegQueryValueExW(hkey, name, NULL, NULL, NULL, &len);
+    if (r != ERROR_SUCCESS)
+        return NULL;
+
+    len += sizeof (WCHAR);
+    val = msi_alloc( len );
+    if (!val)
+        return NULL;
+    val[0] = 0;
+    RegQueryValueExW(hkey, name, NULL, NULL, (LPBYTE) val, &len);
+    return val;
+}
+
+BOOL msi_reg_get_val_dword( HKEY hkey, LPCWSTR name, DWORD *val)
+{
+    DWORD type, len = sizeof (DWORD);
+    LONG r = RegQueryValueExW(hkey, name, NULL, &type, (LPBYTE) val, &len);
+    return r == ERROR_SUCCESS && type == REG_DWORD;
+}
 
 UINT MSIREG_OpenUninstallKey(LPCWSTR szProduct, HKEY* key, BOOL create)
 {
@@ -675,6 +758,9 @@ UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index,
 
     TRACE("%s %ld %p %p\n",debugstr_w(szProduct),index,szFeature,szParent);
 
+    if( !szProduct )
+        return ERROR_INVALID_PARAMETER;
+
     r = MSIREG_OpenFeaturesKey(szProduct,&hkeyProduct,FALSE);
     if( r != ERROR_SUCCESS )
         return ERROR_NO_MORE_ITEMS;
@@ -978,3 +1064,25 @@ UINT WINAPI MsiEnumRelatedProductsA(LPCSTR szUpgradeCode, DWORD dwReserved,
     msi_free( szwUpgradeCode);
     return r;
 }
+
+/***********************************************************************
+ * MsiEnumPatchesA            [MSI.@]
+ */
+UINT WINAPI MsiEnumPatchesA( LPCSTR szProduct, DWORD iPatchIndex, 
+        LPSTR lpPatchBuf, LPSTR lpTransformsBuf, DWORD* pcchTransformsBuf)
+{
+    FIXME("%s %ld %p %p %p\n", debugstr_a(szProduct),
+          iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
+    return ERROR_NO_MORE_ITEMS;
+}
+
+/***********************************************************************
+ * MsiEnumPatchesW            [MSI.@]
+ */
+UINT WINAPI MsiEnumPatchesW( LPCWSTR szProduct, DWORD iPatchIndex, 
+        LPWSTR lpPatchBuf, LPWSTR lpTransformsBuf, DWORD* pcchTransformsBuf)
+{
+    FIXME("%s %ld %p %p %p\n", debugstr_w(szProduct),
+          iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
+    return ERROR_NO_MORE_ITEMS;
+}
index f49b78a..242e795 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include "config.h"
@@ -160,7 +160,7 @@ static HRESULT register_interfaces(struct regsvr_interface const *list) {
        }
 
        if (list->base_iid) {
-           register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
+           res = register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
            if (res != ERROR_SUCCESS) goto error_close_iid_key;
        }
 
@@ -182,12 +182,12 @@ static HRESULT register_interfaces(struct regsvr_interface const *list) {
        }
 
        if (list->ps_clsid) {
-           register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
+           res = register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
            if (res != ERROR_SUCCESS) goto error_close_iid_key;
        }
 
        if (list->ps_clsid32) {
-           register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
+           res = register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
            if (res != ERROR_SUCCESS) goto error_close_iid_key;
        }
 
@@ -595,6 +595,39 @@ static struct regsvr_interface const interface_list[] = {
     { NULL }                   /* list terminator */
 };
 
+static HRESULT register_msiexec(void)
+{
+    static const WCHAR key[] = {
+        'S','o','f','t','w','a','r','e',
+        '\\','M','i','c','r','o','s','o','f','t',
+        '\\','W','i','n','d','o','w','s',
+        '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
+        '\\','I','n','s','t','a','l','l','e','r',0 };
+    static const WCHAR val[] = {
+        'I','n','s','t','a','l','l','e','r','L','o','c','a','t','i','o','n',0 };
+    WCHAR path[MAX_PATH];
+    HKEY hkey;
+    LONG res;
+    INT len;
+
+    len = GetSystemDirectoryW(path, MAX_PATH);
+    if (!len || len > MAX_PATH)
+        return E_FAIL;
+
+    res = RegCreateKeyExW(HKEY_LOCAL_MACHINE, key, 0,
+                         NULL, 0, KEY_READ | KEY_WRITE, NULL,
+                         &hkey, NULL);
+    if (res != ERROR_SUCCESS)
+        return E_FAIL;
+
+    res = RegSetValueExW(hkey, val, 0, REG_SZ,
+                        (BYTE*)path, (len + 1)*sizeof(WCHAR));
+
+    RegCloseKey(hkey);
+
+    return (res == ERROR_SUCCESS) ? S_OK : E_FAIL;
+}
+
 /***********************************************************************
  *             DllRegisterServer (MSI.@)
  */
@@ -607,6 +640,8 @@ HRESULT WINAPI DllRegisterServer(void)
     hr = register_coclasses(coclass_list);
     if (SUCCEEDED(hr))
        hr = register_interfaces(interface_list);
+    if (SUCCEEDED(hr))
+       hr = register_msiexec();
     return hr;
 }
 
index 9bc2b96..abb2dbd 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
@@ -196,8 +196,26 @@ static UINT SELECT_delete( struct tagMSIVIEW *view )
     return ERROR_SUCCESS;
 }
 
+static UINT SELECT_find_matching_rows( struct tagMSIVIEW *view, UINT col,
+    UINT val, UINT *row, MSIITERHANDLE *handle )
+{
+    MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
+
+    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,
@@ -208,7 +226,8 @@ MSIVIEWOPS select_ops =
     SELECT_get_dimensions,
     SELECT_get_column_info,
     SELECT_modify,
-    SELECT_delete
+    SELECT_delete,
+    SELECT_find_matching_rows
 };
 
 static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name )
@@ -245,20 +264,23 @@ static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name )
     return ERROR_SUCCESS;
 }
 
+int select_count_columns( column_info *col )
+{
+    int n;
+    for (n = 0; col; col = col->next)
+        n++;
+    return n;
+}
+
 UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
                         column_info *columns )
 {
     MSISELECTVIEW *sv = NULL;
-    UINT count = 0, r;
+    UINT count = 0, r = ERROR_SUCCESS;
 
     TRACE("%p\n", sv );
 
-    r = table->ops->get_dimensions( table, NULL, &count );
-    if( r != ERROR_SUCCESS )
-    {
-        ERR("can't get table dimensions\n");
-        return r;
-    }
+    count = select_count_columns( columns );
 
     sv = msi_alloc_zero( sizeof *sv + count*sizeof (UINT) );
     if( !sv )
index 4f67e18..ca66c1f 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
@@ -37,6 +37,7 @@
 #include "winuser.h"
 #include "wine/unicode.h"
 #include "action.h"
+#include "sddl.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
@@ -126,6 +127,7 @@ static UINT find_given_source(HKEY key, LPCWSTR szSource, media_info *ss)
     {
         val = NULL;
         val_size = 0;
+        size = sizeof(szIndex)/sizeof(szIndex[0]);
         rc = RegEnumValueW(key, index, szIndex, &size, NULL, NULL, NULL, &val_size);
         if (rc != ERROR_NO_MORE_ITEMS)
         {
@@ -396,6 +398,61 @@ UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
 
 }
 
+/******************************************************************
+ *  MsiSourceListAddSourceW (MSI.@)
+ */
+UINT WINAPI MsiSourceListAddSourceW( LPCWSTR szProduct, LPCWSTR szUserName,
+        DWORD dwReserved, LPCWSTR szSource)
+{
+    INT ret;
+    LPWSTR sidstr = NULL;
+    DWORD sidsize = 0;
+
+    TRACE("%s %s %s\n", debugstr_w(szProduct), debugstr_w(szUserName), debugstr_w(szSource));
+
+    if (LookupAccountNameW(NULL, szUserName, NULL, &sidsize, NULL, NULL, NULL))
+    {
+        PSID psid = msi_alloc(sidsize);
+
+        if (LookupAccountNameW(NULL, szUserName, psid, &sidsize, NULL, NULL, NULL))
+            ConvertSidToStringSidW(psid, &sidstr);
+
+        msi_free(psid);
+    }
+
+    ret = MsiSourceListAddSourceExW(szProduct, sidstr, 
+        MSIINSTALLCONTEXT_USERMANAGED, MSISOURCETYPE_NETWORK, szSource, 0);
+
+    if (sidstr)
+        LocalFree(sidstr);
+
+    return ret;
+}
+
+/******************************************************************
+ *  MsiSourceListAddSourceA (MSI.@)
+ */
+UINT WINAPI MsiSourceListAddSourceA( LPCSTR szProduct, LPCSTR szUserName,
+        DWORD dwReserved, LPCSTR szSource)
+{
+    INT ret;
+    LPWSTR szwproduct;
+    LPWSTR szwusername;
+    LPWSTR szwsource;
+
+    szwproduct = strdupAtoW( szProduct );
+    szwusername = strdupAtoW( szUserName );
+    szwsource = strdupAtoW( szSource );
+
+    ret = MsiSourceListAddSourceW(szwproduct, szwusername, 0, szwsource);
+
+    msi_free(szwproduct);
+    msi_free(szwusername);
+    msi_free(szwsource);
+
+    return ret;
+}
+
 /******************************************************************
  *  MsiSourceListAddSourceExW (MSI.@)
  */
@@ -442,6 +499,8 @@ UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid,
         rc = OpenNetworkSubkey(sourcekey, &typekey, TRUE);
     else if (dwOptions & MSISOURCETYPE_URL)
         rc = OpenURLSubkey(sourcekey, &typekey, TRUE);
+    else if (dwOptions & MSISOURCETYPE_MEDIA)
+        rc = OpenMediaSubkey(sourcekey, &typekey, TRUE);
     else
     {
         ERR("unknown media type: %08lx\n", dwOptions);
@@ -558,3 +617,21 @@ UINT WINAPI MsiSourceListAddMediaDiskW(LPCWSTR szProduct, LPCWSTR szUserSid,
 
     return ERROR_SUCCESS;
 }
+
+/******************************************************************
+ *  MsiSourceListAddSourceExA (MSI.@)
+ */
+UINT WINAPI MsiSourceListClearAllA( LPCSTR szProduct, LPCSTR szUserName, DWORD dwReserved )
+{
+    FIXME("(%s %s %ld) stub\n", debugstr_a(szProduct), debugstr_a(szUserName), dwReserved);
+    return ERROR_SUCCESS;
+}
+
+/******************************************************************
+ *  MsiSourceListAddSourceExW (MSI.@)
+ */
+UINT WINAPI MsiSourceListClearAllW( LPCWSTR szProduct, LPCWSTR szUserName, DWORD dwReserved )
+{
+    FIXME("(%s %s %ld) stub\n", debugstr_w(szProduct), debugstr_w(szUserName), dwReserved);
+    return ERROR_SUCCESS;
+}
index 6669441..76160ca 100644 (file)
@@ -17,7 +17,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 
@@ -126,12 +126,20 @@ static struct expr * EXPR_wildcard( void *info );
 %type <string> table id
 %type <column_list> selcollist column column_and_type column_def table_def
 %type <column_list> column_assignment update_assign_list constlist
-%type <query> query from fromtable selectfrom unorderedsel
+%type <query> query multifrom from fromtable selectfrom unorderedsel
 %type <query> oneupdate onedelete oneselect onequery onecreate oneinsert
 %type <expr> expr val column_val const_val
 %type <column_type> column_type data_type data_type_l data_count
 %type <integer> number
 
+/* Reference: http://mates.ms.mff.cuni.cz/oracle/doc/ora815nt/server.815/a67779/operator.htm */
+%left TK_OR
+%left TK_AND
+%left TK_NOT
+%left TK_EQ TK_NE TK_LT TK_GT TK_LE TK_GE TK_ISNULL TK_LIKE TK_BETWEEN TK_IN
+%left TK_PLUS TK_MINUS TK_CONCAT
+%right TK_NEGATION
+
 %%
 
 query:
@@ -361,7 +369,7 @@ unorderedsel:
     ;
 
 selectfrom:
-    selcollist from 
+    selcollist multifrom 
         {
             SQL_input* sql = (SQL_input*) info;
             UINT r;
@@ -393,6 +401,20 @@ selcollist:
         }
     ;
 
+multifrom:
+    from
+  | TK_FROM table TK_COMMA table TK_WHERE expr
+        {
+            SQL_input* sql = (SQL_input*) info;
+            UINT r;
+
+            /* only support inner joins on two tables */
+            r = JOIN_CreateView( sql->db, &$$, $2, $4, $6 );
+            if( r != ERROR_SUCCESS )
+                YYABORT;
+        }
+    ;
+
 from:
     fromtable
   | fromtable TK_WHERE expr
@@ -430,12 +452,6 @@ expr:
             if( !$$ )
                 YYABORT;
         }
-  | column_val TK_EQ column_val
-        {
-            $$ = EXPR_complex( info, $1, OP_EQ, $3 );
-            if( !$$ )
-                YYABORT;
-        }
   | expr TK_AND expr
         {
             $$ = EXPR_complex( info, $1, OP_AND, $3 );
@@ -545,7 +561,7 @@ const_val:
             if( !$$ )
                 YYABORT;
         }
-  | TK_MINUS number
+  | TK_MINUS number %prec TK_NEGATION
         {
             $$ = EXPR_ival( info, -$2 );
             if( !$$ )
index a5ec138..3155c12 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL(msidb);
 
+#define HASH_SIZE 67
+
 typedef struct _msistring
 {
-    UINT hash;
+    int hash_next;
     UINT refcount;
     LPWSTR str;
 } msistring;
@@ -49,6 +51,7 @@ struct string_table
     UINT maxcount;         /* the number of strings */
     UINT freeslot;
     UINT codepage;
+    int hash[HASH_SIZE];
     msistring *strings; /* an array of strings (in the tree) */
 };
 
@@ -65,12 +68,13 @@ static UINT msistring_makehash( const WCHAR *str )
         hash *= 53;
         hash = (hash<<5) | (hash>>27);
     }
-    return hash;
+    return hash % HASH_SIZE;
 }
 
 string_table *msi_init_stringtable( int entries, UINT codepage )
 {
     string_table *st;
+    int i;
 
     st = msi_alloc( sizeof (string_table) );
     if( !st )
@@ -78,7 +82,7 @@ string_table *msi_init_stringtable( int entries, UINT codepage )
     if( entries < 1 )
         entries = 1;
     st->strings = msi_alloc_zero( sizeof (msistring) * entries );
-    if( !st )
+    if( !st->strings )
     {
         msi_free( st );
         return NULL;    
@@ -87,6 +91,9 @@ string_table *msi_init_stringtable( int entries, UINT codepage )
     st->freeslot = 1;
     st->codepage = codepage;
 
+    for( i=0; i<HASH_SIZE; i++ )
+        st->hash[i] = -1;
+
     return st;
 }
 
@@ -133,15 +140,23 @@ static int st_find_free_entry( string_table *st )
     return st->freeslot;
 }
 
-static void st_mark_entry_used( string_table *st, UINT n )
+static void set_st_entry( string_table *st, UINT n, LPWSTR str )
 {
-    if( n >= st->maxcount )
-        return;
-    st->freeslot = n + 1;
+    UINT hash = msistring_makehash( str );
+
+    st->strings[n].refcount = 1;
+    st->strings[n].str = str;
+
+    st->strings[n].hash_next = st->hash[hash];
+    st->hash[hash] = n;
+
+    if( n < st->maxcount )
+        st->freeslot = n + 1;
 }
 
 int msi_addstring( string_table *st, UINT n, const CHAR *data, int len, UINT refcount )
 {
+    LPWSTR str;
     int sz;
 
     if( !data )
@@ -175,21 +190,21 @@ int msi_addstring( string_table *st, UINT n, const CHAR *data, int len, UINT ref
     if( len < 0 )
         len = strlen(data);
     sz = MultiByteToWideChar( st->codepage, 0, data, len, NULL, 0 );
-    st->strings[n].str = msi_alloc( (sz+1)*sizeof(WCHAR) );
-    if( !st->strings[n].str )
+    str = msi_alloc( (sz+1)*sizeof(WCHAR) );
+    if( !str )
         return -1;
-    MultiByteToWideChar( st->codepage, 0, data, len, st->strings[n].str, sz );
-    st->strings[n].str[sz] = 0;
-    st->strings[n].refcount = 1;
-    st->strings[n].hash = msistring_makehash( st->strings[n].str );
+    MultiByteToWideChar( st->codepage, 0, data, len, str, sz );
+    str[sz] = 0;
 
-    st_mark_entry_used( st, n );
+    set_st_entry( st, n, str );
 
     return n;
 }
 
 int msi_addstringW( string_table *st, UINT n, const WCHAR *data, int len, UINT refcount )
 {
+    LPWSTR str;
+
     /* TRACE("[%2d] = %s\n", string_no, debugstr_an(data,len) ); */
 
     if( !data )
@@ -224,16 +239,14 @@ int msi_addstringW( string_table *st, UINT n, const WCHAR *data, int len, UINT r
         len = strlenW(data);
     TRACE("%s, n = %d len = %d\n", debugstr_w(data), n, len );
 
-    st->strings[n].str = msi_alloc( (len+1)*sizeof(WCHAR) );
-    if( !st->strings[n].str )
+    str = msi_alloc( (len+1)*sizeof(WCHAR) );
+    if( !str )
         return -1;
     TRACE("%d\n",__LINE__);
-    memcpy( st->strings[n].str, data, len*sizeof(WCHAR) );
-    st->strings[n].str[len] = 0;
-    st->strings[n].refcount = 1;
-    st->strings[n].hash = msistring_makehash( st->strings[n].str );
+    memcpy( str, data, len*sizeof(WCHAR) );
+    str[len] = 0;
 
-    st_mark_entry_used( st, n );
+    set_st_entry( st, n, str );
 
     return n;
 }
@@ -349,23 +362,19 @@ UINT msi_id2stringA( string_table *st, UINT id, LPSTR buffer, UINT *sz )
  */
 UINT msi_string2idW( string_table *st, LPCWSTR str, UINT *id )
 {
-    UINT hash;
-    UINT i, r = ERROR_INVALID_PARAMETER;
+    UINT n, hash = msistring_makehash( str );
+    msistring *se = st->strings;
 
-    hash = msistring_makehash( str );
-    for( i=0; i<st->maxcount; i++ )
+    for (n = st->hash[hash]; n != -1; n = st->strings[n].hash_next )
     {
-        if ( (str == NULL && st->strings[i].str == NULL) || 
-            ( ( st->strings[i].hash == hash ) &&
-            !strcmpW( st->strings[i].str, str ) ))
+        if ((str == se[n].str) || !lstrcmpW(str, se[n].str))
         {
-            r = ERROR_SUCCESS;
-            *id = i;
-            break;
+            *id = n;
+            return ERROR_SUCCESS;
         }
     }
 
-    return r;
+    return ERROR_INVALID_PARAMETER;
 }
 
 UINT msi_string2idA( string_table *st, LPCSTR buffer, UINT *id )
index 8a5d973..6e07a3a 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
@@ -23,8 +23,6 @@
 #define COBJMACROS
 #define NONAMELESSUNION
 
-#define PRSPEC_PROPID (1)
-
 #include "windef.h"
 #include "winbase.h"
 #include "winreg.h"
index a3becc6..1a3ccb2 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL(msidb);
 
+#define MSITABLE_HASH_TABLE_SIZE 37
+
+typedef struct tagMSICOLUMNHASHENTRY
+{
+    struct tagMSICOLUMNHASHENTRY *next;
+    UINT value;
+    UINT row;
+} MSICOLUMNHASHENTRY;
+
 typedef struct tagMSICOLUMNINFO
 {
     LPCWSTR tablename;
@@ -46,6 +55,7 @@ typedef struct tagMSICOLUMNINFO
     LPCWSTR colname;
     UINT   type;
     UINT   offset;
+    MSICOLUMNHASHENTRY **hash_table;
 } MSICOLUMNINFO;
 
 struct tagMSITABLE
@@ -467,7 +477,7 @@ static MSITABLE *read_table_from_storage( IStorage *stg, LPCWSTR name,
         goto err;
 
     /* transpose all the data */
-    TRACE("Transposing data from %d columns\n", t->row_count );
+    TRACE("Transposing data from %d rows\n", t->row_count );
     for( i=0; i<t->row_count; i++ )
     {
         t->data[i] = msi_alloc( row_size );
@@ -673,8 +683,8 @@ HRESULT init_string_table( IStorage *stg )
 string_table *load_string_table( IStorage *stg )
 {
     string_table *st = NULL;
-    CHAR *data;
-    USHORT *pool;
+    CHAR *data = NULL;
+    USHORT *pool = NULL;
     UINT r, datasize = 0, poolsize = 0, codepage;
     DWORD i, count, offset, len, n;
     static const WCHAR szStringData[] = {
@@ -707,8 +717,8 @@ string_table *load_string_table( IStorage *stg )
          * and its the high word of the length is inserted in the null string's
          * reference count field.
          */
-        if( pool[i*2-2] == 0 )
-            len += pool[i*2-1] * 0x10000;
+        if( pool[i*2-2] == 0 && pool[i*2-1] )
+            len += pool[i*2+1] * 0x10000;
 
         if( (offset + len) > datasize )
         {
@@ -755,7 +765,7 @@ static UINT save_string_table( MSIDATABASE *db )
 
     /* construct the new table in memory first */
     datasize = msi_string_totalsize( db->strings, &count );
-    poolsize = count*2*sizeof(USHORT);
+    poolsize = (count + 1)*2*sizeof(USHORT);
 
     pool = msi_alloc( poolsize );
     if( ! pool )
@@ -884,6 +894,7 @@ static void msi_free_colinfo( MSICOLUMNINFO *colinfo, UINT count )
     {
         msi_free( (LPWSTR) colinfo[i].tablename );
         msi_free( (LPWSTR) colinfo[i].colname );
+        msi_free( colinfo[i].hash_table );
     }
 }
 
@@ -931,7 +942,7 @@ static UINT get_tablecolumns( MSIDATABASE *db,
         return r;
     }
 
-    TRACE("Table id is %d\n", table_id);
+    TRACE("Table id is %d, row count is %d\n", table_id, table->row_count);
 
     count = table->row_count;
     for( i=0; i<count; i++ )
@@ -945,6 +956,7 @@ static UINT get_tablecolumns( MSIDATABASE *db,
             colinfo[n].number = table->data[ i ][ 1 ] - (1<<15);
             colinfo[n].colname = MSI_makestring( db, id );
             colinfo[n].type = table->data[ i ] [ 3 ] ^ 0x8000;
+            colinfo[n].hash_table = NULL;
             /* this assumes that columns are in order in the table */
             if( n )
                 colinfo[n].offset = colinfo[n-1].offset
@@ -1296,6 +1308,8 @@ static UINT msi_table_modify_row( MSITABLEVIEW *tv, MSIRECORD *rec,
             val = MSI_RecordGetInteger( rec, i+1 );
             if ( 2 == bytes_per_column( &tv->columns[i] ) )
                 val ^= 0x8000;
+            else
+                val ^= 0x80000000;
         }
         r = TABLE_set_int( &tv->view, row, i+1, val );
         if( r )
@@ -1389,8 +1403,100 @@ static UINT TABLE_delete( struct tagMSIVIEW *view )
     return ERROR_SUCCESS;
 }
 
+static UINT TABLE_find_matching_rows( struct tagMSIVIEW *view, UINT col,
+    UINT val, UINT *row, MSIITERHANDLE *handle )
+{
+    MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
+    const MSICOLUMNHASHENTRY *entry;
+
+    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,
@@ -1401,7 +1507,8 @@ MSIVIEWOPS table_ops =
     TABLE_get_dimensions,
     TABLE_get_column_info,
     TABLE_modify,
-    TABLE_delete
+    TABLE_delete,
+    TABLE_find_matching_rows
 };
 
 UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view )
@@ -1499,13 +1606,12 @@ static MSIRECORD *msi_get_transform_record( MSITABLEVIEW *tv, string_table *st,
     USHORT mask = *rawdata++;
     MSICOLUMNINFO *columns = tv->columns;
     MSIRECORD *rec;
-    const int debug_transform = 0;
 
     rec = MSI_CreateRecord( tv->num_cols );
     if( !rec )
         return rec;
 
-    if( debug_transform ) MESSAGE("row -> ");
+    TRACE("row -> ");
     for( i=0; i<tv->num_cols; i++ )
     {
         UINT n = bytes_per_column( &columns[i] );
@@ -1525,20 +1631,20 @@ static MSIRECORD *msi_get_transform_record( MSITABLEVIEW *tv, string_table *st,
             {
                 LPCWSTR sval = msi_string_lookup_id( st, val );
                 MSI_RecordSetStringW( rec, i+1, sval );
-                if( debug_transform ) MESSAGE("[%s]", debugstr_w(sval));
+                TRACE("[%s]", debugstr_w(sval));
             }
             else
             {
                 val ^= 0x8000;
                 MSI_RecordSetInteger( rec, i+1, val );
-                if( debug_transform) MESSAGE("[0x%04x]", val );
+                TRACE("[0x%04x]", val );
             }
             break;
         case 4:
             val = rawdata[ofs] + (rawdata[ofs + 1]<<16);
             /* val ^= 0x80000000; */
             MSI_RecordSetInteger( rec, i+1, val );
-            if( debug_transform ) MESSAGE("[0x%08x]", val );
+            TRACE("[0x%08x]", val );
             break;
         default:
             ERR("oops - unknown column width %d\n", n);
@@ -1546,7 +1652,7 @@ static MSIRECORD *msi_get_transform_record( MSITABLEVIEW *tv, string_table *st,
         }
         ofs += n/2;
     }
-    if( debug_transform) MESSAGE("\n");
+    TRACE("\n");
     return rec;
 }
 
@@ -1554,20 +1660,18 @@ static void dump_record( MSIRECORD *rec )
 {
     UINT i, n;
 
-    MESSAGE("row -> ");
     n = MSI_RecordGetFieldCount( rec );
     for( i=1; i<=n; i++ )
     {
         LPCWSTR sval = MSI_RecordGetString( rec, i );
 
         if( MSI_RecordIsNull( rec, i ) )
-            MESSAGE("[]");
+            TRACE("row -> []\n");
         else if( (sval = MSI_RecordGetString( rec, i )) )
-            MESSAGE("[%s]", debugstr_w(sval));
+            TRACE("row -> [%s]\n", debugstr_w(sval));
         else
-            MESSAGE("[0x%08x]", MSI_RecordGetInteger( rec, i ) );
+            TRACE("row -> [0x%08x]\n", MSI_RecordGetInteger( rec, i ) );
     }
-    MESSAGE("\n");
 }
 
 static void dump_table( string_table *st, USHORT *rawdata, UINT rawsize )
@@ -1578,7 +1682,6 @@ static void dump_table( string_table *st, USHORT *rawdata, UINT rawsize )
     for( i=0; i<(rawsize/2); i++ )
     {
         sval = msi_string_lookup_id( st, rawdata[i] );
-        if( !sval ) sval = (WCHAR[]) {0};
         MESSAGE(" %04x %s\n", rawdata[i], debugstr_w(sval) );
     }
 }
@@ -1683,7 +1786,6 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
     MSITABLEVIEW *tv = NULL;
     UINT r, n, sz, i, mask;
     MSIRECORD *rec = NULL;
-    const int debug_transform = 0;
 
     TRACE("%p %p %p %s\n", db, stg, st, debugstr_w(name) );
 
@@ -1757,20 +1859,20 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
 
             if( rawdata[n] & 1)
             {
-                if( debug_transform ) MESSAGE("insert [%d]: ", row);
+                TRACE("insert [%d]: ", row);
                 TABLE_insert_row( &tv->view, rec );
             }
             else if( mask & 0xff )
             {
-                if( debug_transform ) MESSAGE("modify [%d]: ", row);
+                TRACE("modify [%d]: ", row);
                 msi_table_modify_row( tv, rec, row, mask );
             }
             else
             {
-                if( debug_transform ) MESSAGE("delete [%d]: ", row);
+                TRACE("delete [%d]: ", row);
                 msi_delete_row( tv, row );
             }
-            if( debug_transform ) dump_record( rec );
+            if( TRACE_ON(msidb) ) dump_record( rec );
             msiobj_release( &rec->hdr );
         }
 
index a36c519..9cbe55a 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have receuved a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
@@ -177,6 +177,13 @@ static UINT UPDATE_delete( struct tagMSIVIEW *view )
     return ERROR_SUCCESS;
 }
 
+static UINT UPDATE_find_matching_rows( struct tagMSIVIEW *view, UINT col, UINT val, UINT *row, MSIITERHANDLE *handle )
+{
+    TRACE("%p %d %d %p\n", view, col, val, *handle );
+
+    return ERROR_FUNCTION_FAILED;
+}
+
 
 static MSIVIEWOPS update_ops =
 {
@@ -189,7 +196,8 @@ static MSIVIEWOPS update_ops =
     UPDATE_get_dimensions,
     UPDATE_get_column_info,
     UPDATE_modify,
-    UPDATE_delete
+    UPDATE_delete,
+    UPDATE_find_matching_rows
 };
 
 UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
index 3851abb..63b1d99 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 /*
@@ -151,7 +151,7 @@ static UINT ITERATE_FindRelatedProducts(MSIRECORD *rec, LPVOID param)
                     (LPBYTE)&check, &sz);
             /* check min */
             ver = MSI_RecordGetString(rec,2);
-            comp_ver = build_version_dword(ver);
+            comp_ver = msi_version_str_to_dword(ver);
             r = check - comp_ver; 
             if (r < 0 || (r == 0 && !(attributes &
                                     msidbUpgradeAttributesVersionMinInclusive)))
@@ -163,7 +163,7 @@ static UINT ITERATE_FindRelatedProducts(MSIRECORD *rec, LPVOID param)
 
             /* check max */
             ver = MSI_RecordGetString(rec,3);
-            comp_ver = build_version_dword(ver);
+            comp_ver = msi_version_str_to_dword(ver);
             r = check - comp_ver;
             if (r > 0 || (r == 0 && !(attributes & 
                                     msidbUpgradeAttributesVersionMaxInclusive)))
index d5164a4..4fe3d91 100644 (file)
@@ -13,7 +13,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #define WINE_FILEDESCRIPTION_STR "Wine MSI dll"
index b11ebe7..d01510b 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
@@ -99,7 +99,7 @@ static UINT WHERE_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val
     return wv->table->ops->set_int( wv->table, row, col, val );
 }
 
-static UINT INT_evaluate( UINT lval, UINT op, UINT rval )
+static INT INT_evaluate( INT lval, UINT op, INT rval )
 {
     switch( op )
     {
@@ -156,7 +156,7 @@ static const WCHAR *STRING_evaluate( string_table *st,
 }
 
 static UINT STRCMP_Evaluate( string_table *st, MSIVIEW *table, UINT row, 
-                             struct expr *cond, UINT *val, MSIRECORD *record )
+                             struct expr *cond, INT *val, MSIRECORD *record )
 {
     int sr;
     const WCHAR *l_str, *r_str;
@@ -180,18 +180,25 @@ static UINT STRCMP_Evaluate( string_table *st, MSIVIEW *table, UINT row,
 }
 
 static UINT WHERE_evaluate( MSIDATABASE *db, MSIVIEW *table, UINT row, 
-                             struct expr *cond, UINT *val, MSIRECORD *record )
+                             struct expr *cond, INT *val, MSIRECORD *record )
 {
-    UINT r, lval, rval;
+    UINT r, tval;
+    INT lval, rval;
 
     if( !cond )
         return ERROR_SUCCESS;
 
     switch( cond->type )
     {
-    case EXPR_COL_NUMBER_STRING:
     case EXPR_COL_NUMBER:
-        return table->ops->fetch_int( table, row, cond->u.col_number, val );
+        r = table->ops->fetch_int( table, row, cond->u.col_number, &tval );
+        *val = tval - 0x8000;
+        return ERROR_SUCCESS;
+
+    case EXPR_COL_NUMBER32:
+        r = table->ops->fetch_int( table, row, cond->u.col_number, &tval );
+        *val = tval - 0x80000000;
+        return r;
 
     case EXPR_UVAL:
         *val = cond->u.uval;
@@ -226,7 +233,8 @@ static UINT WHERE_evaluate( MSIDATABASE *db, MSIVIEW *table, UINT row,
 static UINT WHERE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
 {
     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
-    UINT count = 0, r, val, i;
+    UINT count = 0, r, i;
+    INT val;
     MSIVIEW *table = wv->table;
 
     TRACE("%p %p\n", wv, record);
@@ -248,6 +256,51 @@ static UINT WHERE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
         return ERROR_FUNCTION_FAILED;
 
     wv->row_count = 0;
+    if (wv->cond->type == EXPR_STRCMP)
+    {
+        MSIITERHANDLE handle = NULL;
+        UINT row, value, col;
+        struct expr *col_cond = wv->cond->u.expr.left;
+        struct expr *val_cond = wv->cond->u.expr.right;
+
+        /* swap conditionals */
+        if (col_cond->type != EXPR_COL_NUMBER_STRING)
+        {
+            val_cond = wv->cond->u.expr.left;
+            col_cond = wv->cond->u.expr.right;
+        }
+
+        if ((col_cond->type == EXPR_COL_NUMBER_STRING) && (val_cond->type == EXPR_SVAL))
+        {
+            col = col_cond->u.col_number;
+            /* special case for "" - translate it into nil */
+            if (!val_cond->u.sval[0])
+                value = 0;
+            else
+            {
+                r = msi_string2idW(wv->db->strings, val_cond->u.sval, &value);
+                if (r != ERROR_SUCCESS)
+                {
+                    TRACE("no id for %s, assuming it doesn't exist in the table\n", debugstr_w(wv->cond->u.expr.right->u.sval));
+                    return ERROR_SUCCESS;
+                }
+            }
+
+            do
+            {
+                r = table->ops->find_matching_rows(table, col, value, &row, &handle);
+                if (r == ERROR_SUCCESS)
+                    wv->reorder[ wv->row_count ++ ] = row;
+            } while (r == ERROR_SUCCESS);
+
+            if (r == ERROR_NO_MORE_ITEMS)
+                return ERROR_SUCCESS;
+            else
+                return r;
+        }
+        /* else fallback to slow case */
+    }
+
     for( i=0; i<count; i++ )
     {
         val = 0;
@@ -341,8 +394,29 @@ static UINT WHERE_delete( struct tagMSIVIEW *view )
     return ERROR_SUCCESS;
 }
 
+static UINT WHERE_find_matching_rows( struct tagMSIVIEW *view, UINT col,
+    UINT val, UINT *row, MSIITERHANDLE *handle )
+{
+    MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
+    UINT r;
+
+    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,
@@ -353,7 +427,8 @@ MSIVIEWOPS where_ops =
     WHERE_get_dimensions,
     WHERE_get_column_info,
     WHERE_modify,
-    WHERE_delete
+    WHERE_delete,
+    WHERE_find_matching_rows
 };
 
 static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr *cond,
@@ -373,6 +448,8 @@ static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr
             {
                 if (type&MSITYPE_STRING)
                     cond->type = EXPR_COL_NUMBER_STRING;
+                else if ((type&0xff) == 4)
+                    cond->type = EXPR_COL_NUMBER32;
                 else
                     cond->type = EXPR_COL_NUMBER;
                 cond->u.col_number = val;
@@ -423,7 +500,7 @@ static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr
     case EXPR_IVAL:
         *valid = 1;
         cond->type = EXPR_UVAL;
-        cond->u.uval = cond->u.ival + (1<<15);
+        cond->u.uval = cond->u.ival;
         break;
     case EXPR_WILDCARD:
         *valid = 1;