[MSI]
authorChristoph von Wittich <christoph_vw@reactos.org>
Sat, 29 May 2010 08:55:43 +0000 (08:55 +0000)
committerChristoph von Wittich <christoph_vw@reactos.org>
Sat, 29 May 2010 08:55:43 +0000 (08:55 +0000)
sync to wine 1.2 RC2

svn path=/trunk/; revision=47397

50 files changed:
reactos/dll/win32/msi/action.c
reactos/dll/win32/msi/appsearch.c
reactos/dll/win32/msi/automation.c
reactos/dll/win32/msi/classes.c
reactos/dll/win32/msi/cond.tab.c
reactos/dll/win32/msi/cond.y
reactos/dll/win32/msi/custom.c
reactos/dll/win32/msi/database.c
reactos/dll/win32/msi/dialog.c
reactos/dll/win32/msi/events.c
reactos/dll/win32/msi/files.c
reactos/dll/win32/msi/font.c
reactos/dll/win32/msi/format.c
reactos/dll/win32/msi/helpers.c
reactos/dll/win32/msi/install.c
reactos/dll/win32/msi/media.c
reactos/dll/win32/msi/msi.c
reactos/dll/win32/msi/msi.spec
reactos/dll/win32/msi/msi_Bg.rc
reactos/dll/win32/msi/msi_Da.rc
reactos/dll/win32/msi/msi_De.rc
reactos/dll/win32/msi/msi_En.rc
reactos/dll/win32/msi/msi_Eo.rc
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
reactos/dll/win32/msi/msi_Ko.rc
reactos/dll/win32/msi/msi_Lt.rc
reactos/dll/win32/msi/msi_Nl.rc
reactos/dll/win32/msi/msi_No.rc
reactos/dll/win32/msi/msi_Pl.rc
reactos/dll/win32/msi/msi_Pt.rc
reactos/dll/win32/msi/msi_Ro.rc
reactos/dll/win32/msi/msi_Ru.rc
reactos/dll/win32/msi/msi_Si.rc
reactos/dll/win32/msi/msi_Sv.rc
reactos/dll/win32/msi/msi_Tr.rc
reactos/dll/win32/msi/msi_Uk.rc
reactos/dll/win32/msi/msi_Zh.rc
reactos/dll/win32/msi/msipriv.h
reactos/dll/win32/msi/package.c
reactos/dll/win32/msi/registry.c
reactos/dll/win32/msi/script.c
reactos/dll/win32/msi/storages.c
reactos/dll/win32/msi/streams.c
reactos/dll/win32/msi/string.c
reactos/dll/win32/msi/table.c
reactos/dll/win32/msi/upgrade.c

index 81dcba4..4c55972 100644 (file)
@@ -96,8 +96,6 @@ static const WCHAR szAllocateRegistrySpace[] =
     {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
 static const WCHAR szBindImage[] = 
     {'B','i','n','d','I','m','a','g','e',0};
-static const WCHAR szCCPSearch[] = 
-    {'C','C','P','S','e','a','r','c','h',0};
 static const WCHAR szDeleteServices[] = 
     {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
 static const WCHAR szDisableRollback[] = 
@@ -126,8 +124,6 @@ static const WCHAR szPublishComponents[] =
     {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
 static const WCHAR szRegisterComPlus[] =
     {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
-static const WCHAR szRegisterFonts[] =
-    {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
 static const WCHAR szRegisterUser[] =
     {'R','e','g','i','s','t','e','r','U','s','e','r',0};
 static const WCHAR szRemoveEnvironmentStrings[] =
@@ -160,18 +156,8 @@ static const WCHAR szUnpublishComponents[] =
     {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
 static const WCHAR szUnpublishFeatures[] =
     {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
-static const WCHAR szUnregisterClassInfo[] =
-    {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
 static const WCHAR szUnregisterComPlus[] =
     {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
-static const WCHAR szUnregisterExtensionInfo[] =
-    {'U','n','r','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};
-static const WCHAR szUnregisterFonts[] =
-    {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
-static const WCHAR szUnregisterMIMEInfo[] =
-    {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
-static const WCHAR szUnregisterProgIdInfo[] =
-    {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
 static const WCHAR szUnregisterTypeLibraries[] =
     {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
 static const WCHAR szValidateProductID[] =
@@ -291,9 +277,13 @@ UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
 
         if (lstrlenW(prop) > 0)
         {
+            UINT r = msi_set_property( package->db, prop, val );
+
             TRACE("Found commandline property (%s) = (%s)\n", 
                    debugstr_w(prop), debugstr_w(val));
-            MSI_SetPropertyW(package,prop,val);
+
+            if (r == ERROR_SUCCESS && !strcmpW( prop, cszSourceDir ))
+                msi_reset_folders( package, TRUE );
         }
         msi_free(val);
         msi_free(prop);
@@ -347,7 +337,7 @@ static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch
     LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
     UINT ret = ERROR_FUNCTION_FAILED;
 
-    prod_code = msi_dup_property( package, szProductCode );
+    prod_code = msi_dup_property( package->db, szProductCode );
     patch_product = msi_get_suminfo_product( patch );
 
     TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
@@ -379,7 +369,7 @@ static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch
             goto end;
         }
 
-        langid = msi_dup_property( package, szSystemLanguageID );
+        langid = msi_dup_property( package->db, szSystemLanguageID );
         if (!langid)
         {
             msiobj_release( &si->hdr );
@@ -443,7 +433,7 @@ UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
     LPWSTR guid_list, *guids, product_code;
     UINT i, ret = ERROR_FUNCTION_FAILED;
 
-    product_code = msi_dup_property( package, szProductCode );
+    product_code = msi_dup_property( package->db, szProductCode );
     if (!product_code)
     {
         /* FIXME: the property ProductCode should be written into the DB somewhere */
@@ -490,8 +480,8 @@ static UINT msi_set_media_source_prop(MSIPACKAGE *package)
     if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
     {
         prop = MSI_RecordGetString(rec, 1);
-        patch = msi_dup_property(package, szPatch);
-        MSI_SetPropertyW(package, prop, patch);
+        patch = msi_dup_property(package->db, szPatch);
+        msi_set_property(package->db, prop, patch);
         msi_free(patch);
     }
 
@@ -502,76 +492,130 @@ done:
     return r;
 }
 
-static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
+UINT msi_parse_patch_summary( MSISUMMARYINFO *si, MSIPATCHINFO **patch )
 {
-    MSISUMMARYINFO *si;
-    LPWSTR str, *substorage;
-    UINT i, r = ERROR_SUCCESS;
+    MSIPATCHINFO *pi;
+    UINT r = ERROR_SUCCESS;
 
-    si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
-    if (!si)
-        return ERROR_FUNCTION_FAILED;
+    pi = msi_alloc_zero( sizeof(MSIPATCHINFO) );
+    if (!pi)
+        return ERROR_OUTOFMEMORY;
 
-    if (msi_check_patch_applicable( package, si ) != ERROR_SUCCESS)
+    pi->patchcode = msi_suminfo_dup_string( si, PID_REVNUMBER );
+    if (!pi->patchcode)
     {
-        TRACE("Patch not applicable\n");
-        return ERROR_SUCCESS;
+        msi_free( pi );
+        return ERROR_OUTOFMEMORY;
     }
 
-    package->patch = msi_alloc(sizeof(MSIPATCHINFO));
-    if (!package->patch)
+    pi->transforms = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
+    if (!pi->transforms)
+    {
+        msi_free( pi->patchcode );
+        msi_free( pi );
         return ERROR_OUTOFMEMORY;
+    }
 
-    package->patch->patchcode = msi_suminfo_dup_string(si, PID_REVNUMBER);
-    if (!package->patch->patchcode)
-        return ERROR_OUTOFMEMORY;
+    *patch = pi;
+    return r;
+}
 
-    /* enumerate the substorage */
-    str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
-    package->patch->transforms = str;
+UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch )
+{
+    UINT i, r = ERROR_SUCCESS;
+    WCHAR **substorage;
 
-    substorage = msi_split_string( str, ';' );
-    for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
+    /* apply substorage transforms */
+    substorage = msi_split_string( patch->transforms, ';' );
+    for (i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++)
         r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
 
     msi_free( substorage );
-    msiobj_release( &si->hdr );
+    if (r != ERROR_SUCCESS)
+        return r;
 
-    msi_set_media_source_prop(package);
+    msi_set_media_source_prop( package );
 
-    return r;
+    /*
+     * There might be a CAB file in the patch package,
+     * so append it to the list of storages to search for streams.
+     */
+    append_storage_to_db( package->db, patch_db->storage );
+
+    list_add_tail( &package->patches, &patch->entry );
+    return ERROR_SUCCESS;
 }
 
 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
 {
+    static const WCHAR dotmsp[] = {'.','m','s','p',0};
     MSIDATABASE *patch_db = NULL;
-    UINT r;
+    WCHAR localfile[MAX_PATH];
+    MSISUMMARYINFO *si;
+    MSIPATCHINFO *patch = NULL;
+    UINT r = ERROR_SUCCESS;
 
     TRACE("%p %s\n", package, debugstr_w( file ) );
 
-    /* FIXME:
-     *  We probably want to make sure we only open a patch collection here.
-     *  Patch collections (.msp) and databases (.msi) have different GUIDs
-     *  but currently MSI_OpenDatabaseW will accept both.
-     */
-    r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
+    r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
     if ( r != ERROR_SUCCESS )
     {
         ERR("failed to open patch collection %s\n", debugstr_w( file ) );
         return r;
     }
 
-    msi_parse_patch_summary( package, patch_db );
+    si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
+    if (!si)
+    {
+        msiobj_release( &patch_db->hdr );
+        return ERROR_FUNCTION_FAILED;
+    }
 
-    /*
-     * There might be a CAB file in the patch package,
-     * so append it to the list of storage to search for streams.
-     */
-    append_storage_to_db( package->db, patch_db->storage );
+    r = msi_check_patch_applicable( package, si );
+    if (r != ERROR_SUCCESS)
+    {
+        TRACE("patch not applicable\n");
+        r = ERROR_SUCCESS;
+        goto done;
+    }
+
+    r = msi_parse_patch_summary( si, &patch );
+    if ( r != ERROR_SUCCESS )
+        goto done;
+
+    r = msi_get_local_package_name( localfile, dotmsp );
+    if ( r != ERROR_SUCCESS )
+        goto done;
+
+    TRACE("copying to local package %s\n", debugstr_w(localfile));
+
+    if (!CopyFileW( file, localfile, FALSE ))
+    {
+        ERR("Unable to copy package (%s -> %s) (error %u)\n",
+            debugstr_w(file), debugstr_w(localfile), GetLastError());
+        r = GetLastError();
+        goto done;
+    }
+    patch->localfile = strdupW( localfile );
 
+    r = msi_apply_patch_db( package, patch_db, patch );
+    if ( r != ERROR_SUCCESS )
+        WARN("patch failed to apply %u\n", r);
+
+done:
+    msiobj_release( &si->hdr );
     msiobj_release( &patch_db->hdr );
+    if (patch && r != ERROR_SUCCESS)
+    {
+        if (patch->localfile)
+            DeleteFileW( patch->localfile );
 
-    return ERROR_SUCCESS;
+        msi_free( patch->patchcode );
+        msi_free( patch->transforms );
+        msi_free( patch->localfile );
+        msi_free( patch );
+    }
+    return r;
 }
 
 /* get the PATCH property, and apply all the patches it specifies */
@@ -580,7 +624,7 @@ static UINT msi_apply_patches( MSIPACKAGE *package )
     LPWSTR patch_list, *patches;
     UINT i, r = ERROR_SUCCESS;
 
-    patch_list = msi_dup_property( package, szPatch );
+    patch_list = msi_dup_property( package->db, szPatch );
 
     TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
 
@@ -601,7 +645,7 @@ static UINT msi_apply_transforms( MSIPACKAGE *package )
     LPWSTR xform_list, *xforms;
     UINT i, r = ERROR_SUCCESS;
 
-    xform_list = msi_dup_property( package, szTransforms );
+    xform_list = msi_dup_property( package->db, szTransforms );
     xforms = msi_split_string( xform_list, ';' );
 
     for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
@@ -644,71 +688,76 @@ static BOOL ui_sequence_exists( MSIPACKAGE *package )
 
 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
 {
-    LPWSTR p, db;
     LPWSTR source, check;
-    DWORD len;
-
-    static const WCHAR szOriginalDatabase[] =
-        {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
 
-    db = msi_dup_property( package, szOriginalDatabase );
-    if (!db)
-        return ERROR_OUTOFMEMORY;
+    if (msi_get_property_int( package->db, szInstalled, 0 ))
+    {
+        HKEY hkey;
 
-    p = strrchrW( db, '\\' );
-    if (!p)
+        MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
+        source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
+        RegCloseKey( hkey );
+    }
+    else
     {
-        p = strrchrW( db, '/' );
+        LPWSTR p, db;
+        DWORD len;
+
+        db = msi_dup_property( package->db, szOriginalDatabase );
+        if (!db)
+            return ERROR_OUTOFMEMORY;
+
+        p = strrchrW( db, '\\' );
         if (!p)
         {
-            msi_free(db);
-            return ERROR_SUCCESS;
+            p = strrchrW( db, '/' );
+            if (!p)
+            {
+                msi_free(db);
+                return ERROR_SUCCESS;
+            }
         }
-    }
 
-    len = p - db + 2;
-    source = msi_alloc( len * sizeof(WCHAR) );
-    lstrcpynW( source, db, len );
+        len = p - db + 2;
+        source = msi_alloc( len * sizeof(WCHAR) );
+        lstrcpynW( source, db, len );
+        msi_free( db );
+    }
 
-    check = msi_dup_property( package, cszSourceDir );
+    check = msi_dup_property( package->db, cszSourceDir );
     if (!check || replace)
-        MSI_SetPropertyW( package, cszSourceDir, source );
-
+    {
+        UINT r = msi_set_property( package->db, cszSourceDir, source );
+        if (r == ERROR_SUCCESS)
+            msi_reset_folders( package, TRUE );
+    }
     msi_free( check );
 
-    check = msi_dup_property( package, cszSOURCEDIR );
+    check = msi_dup_property( package->db, cszSOURCEDIR );
     if (!check || replace)
-        MSI_SetPropertyW( package, cszSOURCEDIR, source );
+        msi_set_property( package->db, cszSOURCEDIR, source );
 
     msi_free( check );
     msi_free( source );
-    msi_free( db );
 
     return ERROR_SUCCESS;
 }
 
 static BOOL needs_ui_sequence(MSIPACKAGE *package)
 {
-    INT level = msi_get_property_int(package, szUILevel, 0);
+    INT level = msi_get_property_int(package->db, szUILevel, 0);
     return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
 }
 
-static UINT msi_set_context(MSIPACKAGE *package)
+UINT msi_set_context(MSIPACKAGE *package)
 {
-    WCHAR val[10];
-    DWORD sz = 10;
-    DWORD num;
-    UINT r;
+    int num;
 
     package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
 
-    r = MSI_GetPropertyW(package, szAllUsers, val, &sz);
-    if (r == ERROR_SUCCESS)
-    {
-        num = atolW(val);
-        if (num == 1 || num == 2)
-            package->Context = MSIINSTALLCONTEXT_MACHINE;
-    }
+    num = msi_get_property_int(package->db, szAllUsers, 0);
+    if (num == 1 || num == 2)
+        package->Context = MSIINSTALLCONTEXT_MACHINE;
 
     return ERROR_SUCCESS;
 }
@@ -1325,6 +1374,26 @@ done:
     return r;
 }
 
+static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
+{
+    MSIRECORD *row;
+    static const WCHAR query[] = {
+        'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
+        '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
+        '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
+
+    row = MSI_QueryGetRecord( package->db, query, file->Sequence );
+    if (!row)
+    {
+        WARN("query failed\n");
+        return ERROR_FUNCTION_FAILED;
+    }
+
+    file->disk_id = MSI_RecordGetInteger( row, 1 );
+    msiobj_release( &row->hdr );
+    return ERROR_SUCCESS;
+}
+
 static UINT load_file(MSIRECORD *row, LPVOID param)
 {
     MSIPACKAGE* package = param;
@@ -1386,6 +1455,7 @@ static UINT load_file(MSIRECORD *row, LPVOID param)
     }
 
     load_file_hash(package, file);
+    load_file_disk_id(package, file);
 
     TRACE("File Loaded (%s)\n",debugstr_w(file->File));  
 
@@ -1470,7 +1540,7 @@ static UINT load_folder( MSIRECORD *row, LPVOID param )
 
     folder->Parent = msi_dup_record_field( row, 2 );
 
-    folder->Property = msi_dup_property( package, folder->Directory );
+    folder->Property = msi_dup_property( package->db, folder->Directory );
 
     list_add_tail( &package->folders, &folder->entry );
 
@@ -1517,8 +1587,8 @@ static UINT ACTION_CostInitialize(MSIPACKAGE *package)
     static const WCHAR szCosting[] =
         {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
 
-    MSI_SetPropertyW(package, szCosting, szZero);
-    MSI_SetPropertyW(package, cszRootDrive, c_colon);
+    msi_set_property( package->db, szCosting, szZero );
+    msi_set_property( package->db, cszRootDrive, c_colon );
 
     load_all_folders( package );
     load_all_components( package );
@@ -1611,7 +1681,7 @@ static BOOL process_state_property(MSIPACKAGE* package, int level,
     LPWSTR override;
     MSIFEATURE *feature;
 
-    override = msi_dup_property( package, property );
+    override = msi_dup_property( package->db, property );
     if (!override)
         return FALSE;
 
@@ -1688,7 +1758,7 @@ static BOOL process_overrides( MSIPACKAGE *package, int level )
     ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
 
     if (ret)
-        MSI_SetPropertyW( package, szPreselected, szOne );
+        msi_set_property( package->db, szPreselected, szOne );
 
     return ret;
 }
@@ -1703,9 +1773,9 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
 
     TRACE("Checking Install Level\n");
 
-    level = msi_get_property_int(package, szlevel, 1);
+    level = msi_get_property_int(package->db, szlevel, 1);
 
-    if (!msi_get_property_int( package, szPreselected, 0 ))
+    if (!msi_get_property_int( package->db, szPreselected, 0 ))
     {
         LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
         {
@@ -1906,7 +1976,7 @@ static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
     return ERROR_SUCCESS;
 }
 
-static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
+static LPWSTR get_disk_file_version( LPCWSTR filename )
 {
     static const WCHAR name_fmt[] =
         {'%','u','.','%','u','.','%','u','.','%','u',0};
@@ -1944,7 +2014,36 @@ static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
     return strdupW( filever );
 }
 
-static UINT msi_check_file_install_states( MSIPACKAGE *package )
+static DWORD get_disk_file_size( LPCWSTR filename )
+{
+    HANDLE file;
+    DWORD size;
+
+    TRACE("%s\n", debugstr_w(filename));
+
+    file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
+    if (file == INVALID_HANDLE_VALUE)
+        return INVALID_FILE_SIZE;
+
+    size = GetFileSize( file, NULL );
+    CloseHandle( file );
+    return size;
+}
+
+static BOOL hash_matches( MSIFILE *file )
+{
+    UINT r;
+    MSIFILEHASHINFO hash;
+
+    hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
+    r = MsiGetFileHashW( file->TargetPath, 0, &hash );
+    if (r != ERROR_SUCCESS)
+        return FALSE;
+
+    return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
+}
+
+static UINT set_file_install_states( MSIPACKAGE *package )
 {
     LPWSTR file_version;
     MSIFILE *file;
@@ -1952,6 +2051,7 @@ static UINT msi_check_file_install_states( MSIPACKAGE *package )
     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
     {
         MSICOMPONENT* comp = file->Component;
+        DWORD file_size;
         LPWSTR p;
 
         if (!comp)
@@ -1975,38 +2075,43 @@ static UINT msi_check_file_install_states( MSIPACKAGE *package )
         TRACE("file %s resolves to %s\n",
                debugstr_w(file->File), debugstr_w(file->TargetPath));
 
-        /* don't check files of components that aren't installed */
-        if (comp->Installed == INSTALLSTATE_UNKNOWN ||
-            comp->Installed == INSTALLSTATE_ABSENT)
-        {
-            file->state = msifs_missing;  /* assume files are missing */
-            continue;
-        }
-
         if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
         {
             file->state = msifs_missing;
             comp->Cost += file->FileSize;
             continue;
         }
-
-        if (file->Version &&
-            (file_version = msi_get_disk_file_version( file->TargetPath )))
+        if (file->Version && (file_version = get_disk_file_version( file->TargetPath )))
         {
-            TRACE("new %s old %s\n", debugstr_w(file->Version),
-                  debugstr_w(file_version));
-            /* FIXME: seems like a bad way to compare version numbers */
-            if (lstrcmpiW(file_version, file->Version)<0)
+            TRACE("new %s old %s\n", debugstr_w(file->Version), debugstr_w(file_version));
+
+            if (strcmpiW(file_version, file->Version) < 0)
             {
                 file->state = msifs_overwrite;
                 comp->Cost += file->FileSize;
             }
             else
+            {
+                TRACE("Destination file version equal or greater, not overwriting\n");
                 file->state = msifs_present;
+            }
             msi_free( file_version );
+            continue;
         }
-        else
+        if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize)
+        {
+            file->state = msifs_overwrite;
+            comp->Cost += file->FileSize - file_size;
+            continue;
+        }
+        if (file->hash.dwFileHashInfoSize && hash_matches( file ))
+        {
+            TRACE("File hashes match, not overwriting\n");
             file->state = msifs_present;
+            continue;
+        }
+        file->state = msifs_overwrite;
+        comp->Cost += file->FileSize - file_size;
     }
 
     return ERROR_SUCCESS;
@@ -2051,12 +2156,12 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
     ACTION_GetComponentInstallStates(package);
     ACTION_GetFeatureInstallStates(package);
 
-    TRACE("File calculations\n");
-    msi_check_file_install_states( package );
+    TRACE("Calculating file install states\n");
+    set_file_install_states( package );
 
-    if (!process_overrides( package, msi_get_property_int( package, szlevel, 1 ) ))
+    if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
     {
-        TRACE("Evaluating Condition Table\n");
+        TRACE("Evaluating feature conditions\n");
 
         rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
         if (rc == ERROR_SUCCESS)
@@ -2064,29 +2169,29 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
             rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
             msiobj_release( &view->hdr );
         }
+    }
+    TRACE("Evaluating component conditions\n");
 
-        TRACE("Enabling or Disabling Components\n");
-        LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
+    LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
+    {
+        if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
         {
-            if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
-            {
-                TRACE("Disabling component %s\n", debugstr_w(comp->Component));
-                comp->Enabled = FALSE;
-            }
-            else
-                comp->Enabled = TRUE;
+            TRACE("Disabling component %s\n", debugstr_w(comp->Component));
+            comp->Enabled = FALSE;
         }
+        else
+            comp->Enabled = TRUE;
     }
 
-    MSI_SetPropertyW(package,szCosting,szOne);
+    msi_set_property( package->db, szCosting, szOne );
     /* set default run level if not set */
-    level = msi_dup_property( package, szlevel );
+    level = msi_dup_property( package->db, szlevel );
     if (!level)
-        MSI_SetPropertyW(package,szlevel, szOne);
+        msi_set_property( package->db, szlevel, szOne );
     msi_free(level);
 
     /* FIXME: check volume disk space */
-    MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
+    msi_set_property( package->db, szOutOfDiskSpace, szZero );
 
     return MSI_SetFeatureStates(package);
 }
@@ -2220,7 +2325,7 @@ static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key
     switch (root)
     {
     case -1:
-        if (msi_get_property_int( package, szAllUsers, 0 ))
+        if (msi_get_property_int( package->db, szAllUsers, 0 ))
         {
             *root_key = HKEY_LOCAL_MACHINE;
             ret = szHLM;
@@ -2364,12 +2469,8 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
     uirow = MSI_CreateRecord(3);
     MSI_RecordSetStringW(uirow,2,deformated);
     MSI_RecordSetStringW(uirow,1,uikey);
-
-    if (type == REG_SZ)
+    if (type == REG_SZ || type == REG_EXPAND_SZ)
         MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
-    else
-        MSI_RecordSetStringW(uirow,3,value);
-
     ui_actiondata(package,szWriteRegistryValues,uirow);
     msiobj_release( &uirow->hdr );
 
@@ -2995,6 +3096,7 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
             else
                 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
         }
+        comp->Action = comp->ActionRequest;
 
         /* UI stuff */
         uirow = MSI_CreateRecord(3);
@@ -3103,7 +3205,7 @@ static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
     {
         LPCWSTR guid;
         guid = MSI_RecordGetString(row,1);
-        CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
+        CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
         tl_struct.source = strdupW( file->TargetPath );
         tl_struct.path = NULL;
 
@@ -3204,7 +3306,7 @@ static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
     ui_actiondata( package, szUnregisterTypeLibraries, row );
 
     guid = MSI_RecordGetString( row, 1 );
-    CLSIDFromString( (LPWSTR)guid, &libid );
+    CLSIDFromString( (LPCWSTR)guid, &libid );
     version = MSI_RecordGetInteger( row, 4 );
     language = MSI_RecordGetInteger( row, 2 );
 
@@ -3610,17 +3712,17 @@ static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
         {'C','l','i','e','n','t','s',0};
     static const WCHAR szColon[] = {':',0};
 
-    buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
+    buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
     msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
     msi_free(buffer);
 
-    langid = msi_get_property_int(package, szProductLanguage, 0);
+    langid = msi_get_property_int(package->db, szProductLanguage, 0);
     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
 
     /* FIXME */
     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
 
-    buffer = msi_dup_property(package, szARPProductIcon);
+    buffer = msi_dup_property(package->db, szARPProductIcon);
     if (buffer)
     {
         LPWSTR path = build_icon_path(package,buffer);
@@ -3629,7 +3731,7 @@ static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
         msi_free(buffer);
     }
 
-    buffer = msi_dup_property(package, szProductVersion);
+    buffer = msi_dup_property(package->db, szProductVersion);
     if (buffer)
     {
         DWORD verdword = msi_version_str_to_dword(buffer);
@@ -3677,7 +3779,7 @@ static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
     static const WCHAR szUpgradeCode[] =
         {'U','p','g','r','a','d','e','C','o','d','e',0};
 
-    upgrade = msi_dup_property(package, szUpgradeCode);
+    upgrade = msi_dup_property(package->db, szUpgradeCode);
     if (!upgrade)
         return ERROR_SUCCESS;
 
@@ -3730,34 +3832,80 @@ static BOOL msi_check_unpublish(MSIPACKAGE *package)
     return TRUE;
 }
 
-static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
+static UINT msi_publish_patches( MSIPACKAGE *package, HKEY prodkey )
 {
+    static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
     WCHAR patch_squashed[GUID_SIZE];
-    HKEY patches;
+    HKEY patches_key = NULL, product_patches_key;
     LONG res;
-    UINT r = ERROR_FUNCTION_FAILED;
+    MSIPATCHINFO *patch;
+    UINT r;
+    WCHAR *p, *all_patches = NULL;
+    DWORD len = 0;
 
-    res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
-                          &patches, NULL);
+    res = RegCreateKeyExW( prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
     if (res != ERROR_SUCCESS)
         return ERROR_FUNCTION_FAILED;
 
-    squash_guid(package->patch->patchcode, patch_squashed);
+    r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
+    if (r != ERROR_SUCCESS)
+        goto done;
+
+    LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
+    {
+        squash_guid( patch->patchcode, patch_squashed );
+        len += strlenW( patch_squashed ) + 1;
+    }
+
+    p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
+    if (!all_patches)
+        goto done;
+
+    LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
+    {
+        HKEY patch_key;
 
-    res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
-                         (const BYTE *)patch_squashed,
-                         (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
+        squash_guid( patch->patchcode, p );
+        p += strlenW( p ) + 1;
+
+        res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
+                              (const BYTE *)patch->transforms,
+                              (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
+        if (res != ERROR_SUCCESS)
+            goto done;
+
+        r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
+        if (r != ERROR_SUCCESS)
+            goto done;
+
+        res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
+                              (const BYTE *)patch->localfile,
+                              (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
+        RegCloseKey( patch_key );
+        if (res != ERROR_SUCCESS)
+            goto done;
+
+        res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
+        RegCloseKey( patch_key );
+        if (res != ERROR_SUCCESS)
+            goto done;
+    }
+
+    all_patches[len] = 0;
+    res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
+                          (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
     if (res != ERROR_SUCCESS)
         goto done;
 
-    res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
-                         (const BYTE *)package->patch->transforms,
-                         (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
-    if (res == ERROR_SUCCESS)
-        r = ERROR_SUCCESS;
+    res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
+                          (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
+    if (res != ERROR_SUCCESS)
+        r = ERROR_FUNCTION_FAILED;
 
 done:
-    RegCloseKey(patches);
+    RegCloseKey( product_patches_key );
+    RegCloseKey( patches_key );
+    msi_free( all_patches );
     return r;
 }
 
@@ -3791,9 +3939,9 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package)
     if (rc != ERROR_SUCCESS)
         goto end;
 
-    if (package->patch)
+    if (!list_empty(&package->patches))
     {
-        rc = msi_publish_patch(package, hukey, hudkey);
+        rc = msi_publish_patches(package, hukey);
         if (rc != ERROR_SUCCESS)
             goto end;
     }
@@ -3836,10 +3984,10 @@ static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
     {
         folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
         if (!folder)
-            folder = msi_dup_property( package, dirprop );
+            folder = msi_dup_property( package->db, dirprop );
     }
     else
-        folder = msi_dup_property( package, szWindowsFolder );
+        folder = msi_dup_property( package->db, szWindowsFolder );
 
     if (!folder)
     {
@@ -4152,21 +4300,16 @@ static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
         CloseHandle(info.hProcess);
     }
 
-    msi_free(FullName);
-
-    /* the UI chunk */
     uirow = MSI_CreateRecord( 2 );
+    MSI_RecordSetStringW( uirow, 1, filename );
     uipath = strdupW( file->TargetPath );
-    p = strrchrW(uipath,'\\');
-    if (p)
-        p[0]=0;
-    MSI_RecordSetStringW( uirow, 1, &p[1] );
-    MSI_RecordSetStringW( uirow, 2, uipath);
-    ui_actiondata( package, szSelfRegModules, uirow);
+    if ((p = strrchrW( uipath,'\\' ))) *p = 0;
+    MSI_RecordSetStringW( uirow, 2, uipath );
+    ui_actiondata( package, szSelfRegModules, uirow );
     msiobj_release( &uirow->hdr );
-    msi_free( uipath );
-    /* FIXME: call ui_progress? */
 
+    msi_free( FullName );
+    msi_free( uipath );
     return ERROR_SUCCESS;
 }
 
@@ -4235,21 +4378,16 @@ static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
         CloseHandle( pi.hProcess );
     }
 
-    msi_free( cmdline );
-
     uirow = MSI_CreateRecord( 2 );
+    MSI_RecordSetStringW( uirow, 1, filename );
     uipath = strdupW( file->TargetPath );
-    if ((p = strrchrW( uipath, '\\' )))
-    {
-        *p = 0;
-        MSI_RecordSetStringW( uirow, 1, ++p );
-    }
+    if ((p = strrchrW( uipath,'\\' ))) *p = 0;
     MSI_RecordSetStringW( uirow, 2, uipath );
     ui_actiondata( package, szSelfUnregModules, uirow );
     msiobj_release( &uirow->hdr );
-    msi_free( uipath );
-    /* FIXME call ui_progress? */
 
+    msi_free( cmdline );
+    msi_free( uipath );
     return ERROR_SUCCESS;
 }
 
@@ -4351,7 +4489,7 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
         {
             size += sizeof(WCHAR);
             RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
-                           (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
+                           (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
         }
         else
         {
@@ -4384,6 +4522,7 @@ static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
 {
     UINT r;
     HKEY hkey;
+    MSIRECORD *uirow;
 
     TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
 
@@ -4403,6 +4542,11 @@ static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
         RegCloseKey(hkey);
     }
 
+    uirow = MSI_CreateRecord( 1 );
+    MSI_RecordSetStringW( uirow, 1, feature->Feature );
+    ui_actiondata( package, szUnpublishFeatures, uirow );
+    msiobj_release( &uirow->hdr );
+
     return ERROR_SUCCESS;
 }
 
@@ -4423,11 +4567,10 @@ static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
 
 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
 {
-    LPWSTR prop, val, key;
     SYSTEMTIME systime;
     DWORD size, langid;
-    WCHAR date[9];
-    LPWSTR buffer;
+    WCHAR date[9], *val, *buffer;
+    const WCHAR *prop, *key;
 
     static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
     static const WCHAR szWindowsInstaller[] =
@@ -4445,43 +4588,84 @@ static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
         {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
     static const WCHAR szProductVersion[] =
         {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
+    static const WCHAR szDisplayVersion[] =
+        {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
+    static const WCHAR szInstallSource[] =
+        {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
+    static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
+        {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
+    static const WCHAR szAuthorizedCDFPrefix[] =
+        {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
+    static const WCHAR szARPCONTACT[] =
+        {'A','R','P','C','O','N','T','A','C','T',0};
+    static const WCHAR szContact[] =
+        {'C','o','n','t','a','c','t',0};
+    static const WCHAR szARPCOMMENTS[] =
+        {'A','R','P','C','O','M','M','E','N','T','S',0};
+    static const WCHAR szComments[] =
+        {'C','o','m','m','e','n','t','s',0};
     static const WCHAR szProductName[] =
         {'P','r','o','d','u','c','t','N','a','m','e',0};
     static const WCHAR szDisplayName[] =
         {'D','i','s','p','l','a','y','N','a','m','e',0};
-    static const WCHAR szDisplayVersion[] =
-        {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
+    static const WCHAR szARPHELPLINK[] =
+        {'A','R','P','H','E','L','P','L','I','N','K',0};
+    static const WCHAR szHelpLink[] =
+        {'H','e','l','p','L','i','n','k',0};
+    static const WCHAR szARPHELPTELEPHONE[] =
+        {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
+    static const WCHAR szHelpTelephone[] =
+        {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
+    static const WCHAR szARPINSTALLLOCATION[] =
+        {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
+    static const WCHAR szInstallLocation[] =
+        {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
     static const WCHAR szManufacturer[] =
         {'M','a','n','u','f','a','c','t','u','r','e','r',0};
-
-    static const LPCSTR propval[] = {
-        "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
-        "ARPCONTACT",             "Contact",
-        "ARPCOMMENTS",            "Comments",
-        "ProductName",            "DisplayName",
-        "ProductVersion",         "DisplayVersion",
-        "ARPHELPLINK",            "HelpLink",
-        "ARPHELPTELEPHONE",       "HelpTelephone",
-        "ARPINSTALLLOCATION",     "InstallLocation",
-        "SourceDir",              "InstallSource",
-        "Manufacturer",           "Publisher",
-        "ARPREADME",              "Readme",
-        "ARPSIZE",                "Size",
-        "ARPURLINFOABOUT",        "URLInfoAbout",
-        "ARPURLUPDATEINFO",       "URLUpdateInfo",
-        NULL,
+    static const WCHAR szPublisher[] =
+        {'P','u','b','l','i','s','h','e','r',0};
+    static const WCHAR szARPREADME[] =
+        {'A','R','P','R','E','A','D','M','E',0};
+    static const WCHAR szReadme[] =
+        {'R','e','a','d','M','e',0};
+    static const WCHAR szARPSIZE[] =
+        {'A','R','P','S','I','Z','E',0};
+    static const WCHAR szSize[] =
+        {'S','i','z','e',0};
+    static const WCHAR szARPURLINFOABOUT[] =
+        {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
+    static const WCHAR szURLInfoAbout[] =
+        {'U','R','L','I','n','f','o','A','b','o','u','t',0};
+    static const WCHAR szARPURLUPDATEINFO[] =
+        {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
+    static const WCHAR szURLUpdateInfo[] =
+        {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
+
+    static const WCHAR *propval[] = {
+        szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
+        szARPCONTACT,             szContact,
+        szARPCOMMENTS,            szComments,
+        szProductName,            szDisplayName,
+        szARPHELPLINK,            szHelpLink,
+        szARPHELPTELEPHONE,       szHelpTelephone,
+        szARPINSTALLLOCATION,     szInstallLocation,
+        cszSourceDir,             szInstallSource,
+        szManufacturer,           szPublisher,
+        szARPREADME,              szReadme,
+        szARPSIZE,                szSize,
+        szARPURLINFOABOUT,        szURLInfoAbout,
+        szARPURLUPDATEINFO,       szURLUpdateInfo,
+        NULL
     };
-    const LPCSTR *p = propval;
+    const WCHAR **p = propval;
 
     while (*p)
     {
-        prop = strdupAtoW(*p++);
-        key = strdupAtoW(*p++);
-        val = msi_dup_property(package, prop);
+        prop = *p++;
+        key = *p++;
+        val = msi_dup_property(package->db, prop);
         msi_reg_set_val_str(hkey, key, val);
         msi_free(val);
-        msi_free(key);
-        msi_free(prop);
     }
 
     msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
@@ -4494,26 +4678,14 @@ static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
     /* FIXME: Write real Estimated Size when we have it */
     msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
 
-    buffer = msi_dup_property(package, szProductName);
-    msi_reg_set_val_str(hkey, szDisplayName, buffer);
-    msi_free(buffer);
-
-    buffer = msi_dup_property(package, cszSourceDir);
-    msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
-    msi_free(buffer);
-
-    buffer = msi_dup_property(package, szManufacturer);
-    msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
-    msi_free(buffer);
-
     GetLocalTime(&systime);
     sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
     msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
 
-    langid = msi_get_property_int(package, szProductLanguage, 0);
+    langid = msi_get_property_int(package->db, szProductLanguage, 0);
     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
 
-    buffer = msi_dup_property(package, szProductVersion);
+    buffer = msi_dup_property(package->db, szProductVersion);
     msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
     if (buffer)
     {
@@ -4565,7 +4737,7 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
     if (rc != ERROR_SUCCESS)
         goto done;
 
-    upgrade_code = msi_dup_property(package, szUpgradeCode);
+    upgrade_code = msi_dup_property(package->db, szUpgradeCode);
     if (upgrade_code)
     {
         MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
@@ -4597,11 +4769,12 @@ static UINT msi_unpublish_product(MSIPACKAGE *package)
     LPWSTR *features = NULL;
     BOOL full_uninstall = TRUE;
     MSIFEATURE *feature;
+    MSIPATCHINFO *patch;
 
     static const WCHAR szUpgradeCode[] =
         {'U','p','g','r','a','d','e','C','o','d','e',0};
 
-    remove = msi_dup_property(package, szRemove);
+    remove = msi_dup_property(package->db, szRemove);
     if (!remove)
         return ERROR_SUCCESS;
 
@@ -4642,13 +4815,18 @@ static UINT msi_unpublish_product(MSIPACKAGE *package)
         MSIREG_DeleteUserFeaturesKey(package->ProductCode);
     }
 
-    upgrade = msi_dup_property(package, szUpgradeCode);
+    upgrade = msi_dup_property(package->db, szUpgradeCode);
     if (upgrade)
     {
         MSIREG_DeleteUserUpgradeCodesKey(upgrade);
         msi_free(upgrade);
     }
 
+    LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
+    {
+        MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
+    }
+
 done:
     msi_free(remove);
     msi_free(features);
@@ -4809,7 +4987,7 @@ static UINT ACTION_RegisterUser(MSIPACKAGE *package)
         goto end;
     }
 
-    productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
+    productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
     if (!productid)
         goto end;
 
@@ -4820,7 +4998,7 @@ static UINT ACTION_RegisterUser(MSIPACKAGE *package)
 
     for( i = 0; szPropKeys[i][0]; i++ )
     {
-        buffer = msi_dup_property( package, szPropKeys[i] );
+        buffer = msi_dup_property( package->db, szPropKeys[i] );
         msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
         msi_free( buffer );
     }
@@ -5162,10 +5340,11 @@ static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
 {
     MSIPACKAGE *package = param;
     MSICOMPONENT *comp;
+    MSIRECORD *uirow;
     SC_HANDLE scm = NULL, service = NULL;
     LPCWSTR component, *vector = NULL;
-    LPWSTR name, args;
-    DWORD event, numargs;
+    LPWSTR name, args, display_name = NULL;
+    DWORD event, numargs, len;
     UINT r = ERROR_FUNCTION_FAILED;
 
     component = MSI_RecordGetString(rec, 6);
@@ -5198,6 +5377,14 @@ static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
         goto done;
     }
 
+    len = 0;
+    if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
+        GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+    {
+        if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
+            GetServiceDisplayNameW( scm, name, display_name, &len );
+    }
+
     service = OpenServiceW(scm, name, SERVICE_START);
     if (!service)
     {
@@ -5217,12 +5404,19 @@ static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
     r = ERROR_SUCCESS;
 
 done:
+    uirow = MSI_CreateRecord( 2 );
+    MSI_RecordSetStringW( uirow, 1, display_name );
+    MSI_RecordSetStringW( uirow, 2, name );
+    ui_actiondata( package, szStartServices, uirow );
+    msiobj_release( &uirow->hdr );
+
     CloseServiceHandle(service);
     CloseServiceHandle(scm);
 
     msi_free(name);
     msi_free(args);
     msi_free(vector);
+    msi_free(display_name);
     return r;
 }
 
@@ -5335,9 +5529,11 @@ static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
 {
     MSIPACKAGE *package = param;
     MSICOMPONENT *comp;
+    MSIRECORD *uirow;
     LPCWSTR component;
-    LPWSTR name;
-    DWORD event;
+    LPWSTR name = NULL, display_name = NULL;
+    DWORD event, len;
+    SC_HANDLE scm;
 
     event = MSI_RecordGetInteger( rec, 3 );
     if (!(event & msidbServiceControlEventStop))
@@ -5356,10 +5552,34 @@ static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
     }
     comp->Action = INSTALLSTATE_ABSENT;
 
+    scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
+    if (!scm)
+    {
+        ERR("Failed to open the service control manager\n");
+        goto done;
+    }
+
+    len = 0;
+    if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
+        GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+    {
+        if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
+            GetServiceDisplayNameW( scm, name, display_name, &len );
+    }
+    CloseServiceHandle( scm );
+
     deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
     stop_service( name );
-    msi_free( name );
 
+done:
+    uirow = MSI_CreateRecord( 2 );
+    MSI_RecordSetStringW( uirow, 1, display_name );
+    MSI_RecordSetStringW( uirow, 2, name );
+    ui_actiondata( package, szStopServices, uirow );
+    msiobj_release( &uirow->hdr );
+
+    msi_free( name );
+    msi_free( display_name );
     return ERROR_SUCCESS;
 }
 
@@ -6749,19 +6969,19 @@ static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
     LPWSTR key, template, id;
     UINT r = ERROR_SUCCESS;
 
-    id = msi_dup_property( package, szProductID );
+    id = msi_dup_property( package->db, szProductID );
     if (id)
     {
         msi_free( id );
         return ERROR_SUCCESS;
     }
-    template = msi_dup_property( package, szPIDTemplate );
-    key = msi_dup_property( package, szPIDKEY );
+    template = msi_dup_property( package->db, szPIDTemplate );
+    key = msi_dup_property( package->db, szPIDKEY );
 
     if (key && template)
     {
         FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
-        r = MSI_SetPropertyW( package, szProductID, key );
+        r = msi_set_property( package->db, szProductID, key );
     }
     msi_free( template );
     msi_free( key );
@@ -6780,7 +7000,7 @@ static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
     static const WCHAR szAvailableFreeReg[] =
         {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
     MSIRECORD *uirow;
-    int space = msi_get_property_int( package, szAvailableFreeReg, 0 );
+    int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
 
     TRACE("%p %d kilobytes\n", package, space);
 
@@ -6804,6 +7024,40 @@ static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
     return ERROR_SUCCESS;
 }
 
+static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
+{
+    UINT r, count;
+    MSIQUERY *view;
+
+    static const WCHAR driver_query[] = {
+        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+        'O','D','B','C','D','r','i','v','e','r',0 };
+
+    static const WCHAR translator_query[] = {
+        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+        'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
+
+    r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
+    if (r == ERROR_SUCCESS)
+    {
+        count = 0;
+        r = MSI_IterateRecords( view, &count, NULL, package );
+        msiobj_release( &view->hdr );
+        if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
+    }
+
+    r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
+    if (r == ERROR_SUCCESS)
+    {
+        count = 0;
+        r = MSI_IterateRecords( view, &count, NULL, package );
+        msiobj_release( &view->hdr );
+        if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
+    }
+
+    return ERROR_SUCCESS;
+}
+
 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
                                            LPCSTR action, LPCWSTR table )
 {
@@ -6890,36 +7144,6 @@ static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
     return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
 }
 
-static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
-{
-    static const WCHAR table[] = { 'D','i','r','e','c','t','o','r','y',0 };
-    return msi_unimplemented_action_stub( package, "SetODBCFolders", table );
-}
-
-static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
-{
-    static const WCHAR table[] = { 'A','p','p','I','d',0 };
-    return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
-}
-
-static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
-{
-    static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
-    return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
-}
-
-static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
-{
-    static const WCHAR table[] = { 'M','I','M','E',0 };
-    return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
-}
-
-static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
-{
-    static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
-    return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
-}
-
 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
 
 static const struct
@@ -7171,7 +7395,7 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
     static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
     static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
 
-    MSI_SetPropertyW(package, szAction, szInstall);
+    msi_set_property( package->db, szAction, szInstall );
 
     package->script->InWhatSequence = SEQUENCE_INSTALL;
 
@@ -7216,10 +7440,10 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
     msi_apply_transforms( package );
     msi_apply_patches( package );
 
-    if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 ))
+    if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
     {
         TRACE("setting reinstall property\n");
-        MSI_SetPropertyW( package, szReinstall, szAll );
+        msi_set_property( package->db, szReinstall, szAll );
     }
 
     /* properties may have been added by a transform */
index 12c7411..336bfca 100644 (file)
@@ -929,7 +929,8 @@ static UINT ACTION_AppSearchDr(MSIPACKAGE *package, LPWSTR *appValue, MSISIGNATU
         'D','r','L','o','c','a','t','o','r',' ',
         'w','h','e','r','e',' ',
         'S','i','g','n','a','t','u','r','e','_',' ','=',' ', '\'','%','s','\'',0};
-    LPWSTR parentName = NULL, parent = NULL;
+    LPWSTR parent = NULL;
+    LPCWSTR parentName;
     WCHAR path[MAX_PATH];
     WCHAR expanded[MAX_PATH];
     MSIRECORD *row;
@@ -949,14 +950,15 @@ static UINT ACTION_AppSearchDr(MSIPACKAGE *package, LPWSTR *appValue, MSISIGNATU
     }
 
     /* check whether parent is set */
-    parentName = msi_dup_record_field(row,2);
+    parentName = MSI_RecordGetString(row, 2);
     if (parentName)
     {
         MSISIGNATURE parentSig;
 
         rc = ACTION_AppSearchSigName(package, parentName, &parentSig, &parent);
         ACTION_FreeSignature(&parentSig);
-        msi_free(parentName);
+        if (!parent)
+            return ERROR_SUCCESS;
     }
 
     sz = MAX_PATH;
@@ -1041,7 +1043,10 @@ static UINT iterate_appsearch(MSIRECORD *row, LPVOID param)
     r = ACTION_AppSearchSigName(package, sigName, &sig, &value);
     if (value)
     {
-        MSI_SetPropertyW(package, propName, value);
+        r = msi_set_property( package->db, propName, value );
+        if (r == ERROR_SUCCESS && !strcmpW( propName, cszSourceDir ))
+            msi_reset_folders( package, TRUE );
+
         msi_free(value);
     }
     ACTION_FreeSignature(&sig);
@@ -1064,6 +1069,14 @@ UINT ACTION_AppSearch(MSIPACKAGE *package)
     MSIQUERY *view = NULL;
     UINT r;
 
+    if (check_unique_action(package, szAppSearch))
+    {
+        TRACE("Skipping AppSearch action: already done in UI sequence\n");
+        return ERROR_SUCCESS;
+    }
+    else
+        register_unique_action(package, szAppSearch);
+
     r = MSI_OpenQuery( package->db, &view, query );
     if (r != ERROR_SUCCESS)
         return ERROR_SUCCESS;
@@ -1092,7 +1105,7 @@ static UINT ITERATE_CCPSearch(MSIRECORD *row, LPVOID param)
     if (value)
     {
         TRACE("Found signature %s\n", debugstr_w(signature));
-        MSI_SetPropertyW(package, success, szOne);
+        msi_set_property(package->db, success, szOne);
         msi_free(value);
         r = ERROR_NO_MORE_ITEMS;
     }
@@ -1111,6 +1124,14 @@ UINT ACTION_CCPSearch(MSIPACKAGE *package)
     MSIQUERY *view = NULL;
     UINT r;
 
+    if (check_unique_action(package, szCCPSearch))
+    {
+        TRACE("Skipping AppSearch action: already done in UI sequence\n");
+        return ERROR_SUCCESS;
+    }
+    else
+        register_unique_action(package, szCCPSearch);
+
     r = MSI_OpenQuery(package->db, &view, query);
     if (r != ERROR_SUCCESS)
         return ERROR_SUCCESS;
index f935a64..d6ef5c9 100644 (file)
@@ -167,7 +167,7 @@ static HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter
     if( pUnkOuter )
         return CLASS_E_NOAGGREGATION;
 
-    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AutomationObject)+sizetPrivateData);
+    object = msi_alloc_zero( sizeof(AutomationObject) + sizetPrivateData );
 
     /* Set all the VTable references */
     object->lpVtbl = &AutomationObject_Vtbl;
@@ -184,7 +184,7 @@ static HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter
     object->iTypeInfo = NULL;
     hr = load_type_info((IDispatch *)object, &object->iTypeInfo, clsid, 0x0);
     if (FAILED(hr)) {
-        HeapFree(GetProcessHeap(), 0, object);
+        msi_free( object );
         return hr;
     }
 
@@ -203,7 +203,7 @@ static HRESULT create_list_enumerator(IUnknown *pUnkOuter, LPVOID *ppObj, Automa
     if( pUnkOuter )
         return CLASS_E_NOAGGREGATION;
 
-    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ListEnumerator));
+    object = msi_alloc_zero( sizeof(ListEnumerator) );
 
     /* Set all the VTable references */
     object->lpVtbl = &ListEnumerator_Vtbl;
@@ -288,7 +288,7 @@ static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
         if (This->funcFree) This->funcFree(This);
         ITypeInfo_Release(This->iTypeInfo);
         MsiCloseHandle(This->msiHandle);
-        HeapFree(GetProcessHeap(), 0, This);
+        msi_free(This);
     }
 
     return ref;
@@ -607,7 +607,7 @@ static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
     if (!ref)
     {
         if (This->pObj) IDispatch_Release((IDispatch *)This->pObj);
-        HeapFree(GetProcessHeap(), 0, This);
+        msi_free(This);
     }
 
     return ref;
@@ -1043,7 +1043,7 @@ static void WINAPI ListImpl_Free(AutomationObject *This)
 
     for (idx=0; idx<data->ulCount; idx++)
         VariantClear(&data->pVars[idx]);
-    HeapFree(GetProcessHeap(), 0, data->pVars);
+    msi_free(data->pVars);
 }
 
 static HRESULT WINAPI ViewImpl_Invoke(
index acd8429..22d11c1 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-/* actions handled in this module
+/* Actions handled in this module:
+ *
  * RegisterClassInfo
  * RegisterProgIdInfo
  * RegisterExtensionInfo
  * RegisterMIMEInfo
- * UnRegisterClassInfo (TODO)
- * UnRegisterProgIdInfo (TODO)
- * UnRegisterExtensionInfo (TODO)
- * UnRegisterMIMEInfo (TODO)
+ * UnregisterClassInfo
+ * UnregisterProgIdInfo
+ * UnregisterExtensionInfo
+ * UnregisterMIMEInfo
  */
 
 #include <stdarg.h>
@@ -343,7 +344,7 @@ static MSIEXTENSION *load_given_extension( MSIPACKAGE *package, LPCWSTR extensio
 
 static MSIMIME *load_mime( MSIPACKAGE* package, MSIRECORD *row )
 {
-    LPCWSTR buffer;
+    LPCWSTR extension;
     MSIMIME *mt;
 
     /* fill in the data */
@@ -355,8 +356,9 @@ static MSIMIME *load_mime( MSIPACKAGE* package, MSIRECORD *row )
     mt->ContentType = msi_dup_record_field( row, 1 ); 
     TRACE("loading mime %s\n", debugstr_w(mt->ContentType));
 
-    buffer = MSI_RecordGetString( row, 2 );
-    mt->Extension = load_given_extension( package, buffer );
+    extension = MSI_RecordGetString( row, 2 );
+    mt->Extension = load_given_extension( package, extension );
+    mt->suffix = strdupW( extension );
 
     mt->clsid = msi_dup_record_field( row, 3 );
     mt->Class = load_given_class( package, mt->clsid );
@@ -720,6 +722,25 @@ static void mark_progid_for_install( MSIPACKAGE* package, MSIPROGID *progid )
     }
 }
 
+static void mark_progid_for_uninstall( MSIPACKAGE *package, MSIPROGID *progid )
+{
+    MSIPROGID *child;
+
+    if (!progid)
+        return;
+
+    if (!progid->InstallMe)
+        return;
+
+    progid->InstallMe = FALSE;
+
+    LIST_FOR_EACH_ENTRY( child, &package->progids, MSIPROGID, entry )
+    {
+        if (child->Parent == progid)
+            mark_progid_for_uninstall( package, child );
+    }
+}
+
 static void mark_mime_for_install( MSIMIME *mime )
 {
     if (!mime)
@@ -727,9 +748,15 @@ static void mark_mime_for_install( MSIMIME *mime )
     mime->InstallMe = TRUE;
 }
 
+static void mark_mime_for_uninstall( MSIMIME *mime )
+{
+    if (!mime)
+        return;
+    mime->InstallMe = FALSE;
+}
+
 static UINT register_appid(const MSIAPPID *appid, LPCWSTR app )
 {
-    static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
     static const WCHAR szRemoteServerName[] =
          {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0};
     static const WCHAR szLocalService[] =
@@ -776,24 +803,13 @@ static UINT register_appid(const MSIAPPID *appid, LPCWSTR app )
 
 UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
 {
-    /* 
-     * Again I am assuming the words, "Whose key file represents" when referring
-     * to a Component as to meaning that Components KeyPath file
-     */
-    
-    UINT rc;
-    MSIRECORD *uirow;
-    static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
-    static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 };
-    static const WCHAR szVIProgID[] = { 'V','e','r','s','i','o','n','I','n','d','e','p','e','n','d','e','n','t','P','r','o','g','I','D',0 };
-    static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
     static const WCHAR szFileType_fmt[] = {'F','i','l','e','T','y','p','e','\\','%','s','\\','%','i',0};
+    MSIRECORD *uirow;
     HKEY hkey,hkey2,hkey3;
     MSICLASS *cls;
 
     load_classes_and_such(package);
-    rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
-    if (rc != ERROR_SUCCESS)
+    if (RegCreateKeyW(HKEY_CLASSES_ROOT, szCLSID, &hkey) != ERROR_SUCCESS)
         return ERROR_FUNCTION_FAILED;
 
     LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry )
@@ -812,16 +828,21 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
         if (!feature)
             continue;
 
-        /*
-         * MSDN says that these are based on Feature not on Component.
-         */
         if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
             feature->ActionRequest != INSTALLSTATE_ADVERTISED )
         {
-            TRACE("Feature %s not scheduled for installation, skipping regstration of class %s\n",
+            TRACE("Feature %s not scheduled for installation, skipping registration of class %s\n",
                   debugstr_w(feature->Feature), debugstr_w(cls->clsid));
             continue;
         }
+        feature->Action = feature->ActionRequest;
+
+        file = get_loaded_file( package, comp->KeyPath );
+        if (!file)
+        {
+            TRACE("COM server not provided, skipping class %s\n", debugstr_w(cls->clsid));
+            continue;
+        }
 
         TRACE("Registering class %s (%p)\n", debugstr_w(cls->clsid), cls);
 
@@ -834,12 +855,6 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
             msi_reg_set_val_str( hkey2, NULL, cls->Description );
 
         RegCreateKeyW( hkey2, cls->Context, &hkey3 );
-        file = get_loaded_file( package, comp->KeyPath );
-        if (!file)
-        {
-            TRACE("COM server not provided, skipping class %s\n", debugstr_w(cls->clsid));
-            continue;
-        }
 
         /*
          * FIXME: Implement install on demand (advertised components).
@@ -887,35 +902,18 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
         if (cls->AppID)
         {
             MSIAPPID *appid = cls->AppID;
-
             msi_reg_set_val_str( hkey2, szAppID, appid->AppID );
-
             register_appid( appid, cls->Description );
         }
 
         if (cls->IconPath)
-        {
-            static const WCHAR szDefaultIcon[] = 
-                {'D','e','f','a','u','l','t','I','c','o','n',0};
-
             msi_reg_set_subkey_val( hkey2, szDefaultIcon, NULL, cls->IconPath );
-        }
 
         if (cls->DefInprocHandler)
-        {
-            static const WCHAR szInproc[] =
-                {'I','n','p','r','o','c','H','a','n','d','l','e','r',0};
-
-            msi_reg_set_subkey_val( hkey2, szInproc, NULL, cls->DefInprocHandler );
-        }
+            msi_reg_set_subkey_val( hkey2, szInprocHandler, NULL, cls->DefInprocHandler );
 
         if (cls->DefInprocHandler32)
-        {
-            static const WCHAR szInproc32[] =
-                {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
-
-            msi_reg_set_subkey_val( hkey2, szInproc32, NULL, cls->DefInprocHandler32 );
-        }
+            msi_reg_set_subkey_val( hkey2, szInprocHandler32, NULL, cls->DefInprocHandler32 );
         
         RegCloseKey(hkey2);
 
@@ -947,14 +945,92 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
         }
         
         uirow = MSI_CreateRecord(1);
-
         MSI_RecordSetStringW( uirow, 1, cls->clsid );
         ui_actiondata(package,szRegisterClassInfo,uirow);
         msiobj_release(&uirow->hdr);
     }
 
     RegCloseKey(hkey);
-    return rc;
+    return ERROR_SUCCESS;
+}
+
+UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
+{
+    static const WCHAR szFileType[] = {'F','i','l','e','T','y','p','e','\\',0};
+    MSIRECORD *uirow;
+    MSICLASS *cls;
+    HKEY hkey, hkey2;
+
+    load_classes_and_such( package );
+    if (RegOpenKeyW( HKEY_CLASSES_ROOT, szCLSID, &hkey ) != ERROR_SUCCESS)
+        return ERROR_SUCCESS;
+
+    LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry )
+    {
+        MSIFEATURE *feature;
+        MSICOMPONENT *comp;
+        LPWSTR filetype;
+        LONG res;
+
+        comp = cls->Component;
+        if (!comp)
+            continue;
+
+        feature = cls->Feature;
+        if (!feature)
+            continue;
+
+        if (feature->ActionRequest != INSTALLSTATE_ABSENT)
+        {
+            TRACE("Feature %s not scheduled for removal, skipping unregistration of class %s\n",
+                  debugstr_w(feature->Feature), debugstr_w(cls->clsid));
+            continue;
+        }
+        feature->Action = feature->ActionRequest;
+
+        TRACE("Unregistering class %s (%p)\n", debugstr_w(cls->clsid), cls);
+
+        cls->Installed = FALSE;
+        mark_progid_for_uninstall( package, cls->ProgID );
+
+        res = RegDeleteTreeW( hkey, cls->clsid );
+        if (res != ERROR_SUCCESS)
+            WARN("Failed to delete class key %d\n", res);
+
+        if (cls->AppID)
+        {
+            res = RegOpenKeyW( HKEY_CLASSES_ROOT, szAppID, &hkey2 );
+            if (res == ERROR_SUCCESS)
+            {
+                res = RegDeleteKeyW( hkey2, cls->AppID->AppID );
+                if (res != ERROR_SUCCESS)
+                    WARN("Failed to delete appid key %d\n", res);
+                RegCloseKey( hkey2 );
+            }
+        }
+        if (cls->FileTypeMask)
+        {
+            filetype = msi_alloc( (strlenW( szFileType ) + strlenW( cls->clsid ) + 1) * sizeof(WCHAR) );
+            if (filetype)
+            {
+                strcpyW( filetype, szFileType );
+                strcatW( filetype, cls->clsid );
+                res = RegDeleteTreeW( HKEY_CLASSES_ROOT, filetype );
+                msi_free( filetype );
+
+                if (res != ERROR_SUCCESS)
+                    WARN("Failed to delete file type %d\n", res);
+            }
+        }
+
+        uirow = MSI_CreateRecord( 1 );
+        MSI_RecordSetStringW( uirow, 1, cls->clsid );
+        ui_actiondata( package, szUnregisterClassInfo, uirow );
+        msiobj_release( &uirow->hdr );
+    }
+
+    RegCloseKey( hkey );
+    return ERROR_SUCCESS;
 }
 
 static LPCWSTR get_clsid_of_progid( const MSIPROGID *progid )
@@ -972,11 +1048,7 @@ static LPCWSTR get_clsid_of_progid( const MSIPROGID *progid )
 
 static UINT register_progid( const MSIPROGID* progid )
 {
-    static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
-    static const WCHAR szDefaultIcon[] =
-        {'D','e','f','a','u','l','t','I','c','o','n',0};
-    static const WCHAR szCurVer[] =
-        {'C','u','r','V','e','r',0};
+    static const WCHAR szCurVer[] = {'C','u','r','V','e','r',0};
     HKEY hkey = 0;
     UINT rc;
 
@@ -1041,6 +1113,41 @@ UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
     return ERROR_SUCCESS;
 }
 
+UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
+{
+    MSIPROGID *progid;
+    MSIRECORD *uirow;
+    LONG res;
+
+    load_classes_and_such( package );
+
+    LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry )
+    {
+        /* check if this progid is to be removed */
+        if (progid->Class && !progid->Class->Installed)
+            progid->InstallMe = FALSE;
+
+        if (progid->InstallMe)
+        {
+            TRACE("progid %s not scheduled to be removed\n", debugstr_w(progid->ProgID));
+            continue;
+        }
+
+        TRACE("Unregistering progid %s\n", debugstr_w(progid->ProgID));
+
+        res = RegDeleteTreeW( HKEY_CLASSES_ROOT, progid->ProgID );
+        if (res != ERROR_SUCCESS)
+            WARN("Failed to delete progid key %d\n", res);
+
+        uirow = MSI_CreateRecord( 1 );
+        MSI_RecordSetStringW( uirow, 1, progid->ProgID );
+        ui_actiondata( package, szUnregisterProgIdInfo, uirow );
+        msiobj_release( &uirow->hdr );
+    }
+
+    return ERROR_SUCCESS;
+}
+
 static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid, 
                 MSICOMPONENT* component, const MSIEXTENSION* extension,
                 MSIVERB* verb, INT* Sequence )
@@ -1122,10 +1229,11 @@ UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
 {
     static const WCHAR szContentType[] = 
         {'C','o','n','t','e','n','t',' ','T','y','p','e',0 };
-    HKEY hkey;
+    HKEY hkey = NULL;
     MSIEXTENSION *ext;
     MSIRECORD *uirow;
     BOOL install_on_demand = TRUE;
+    LONG res;
 
     load_classes_and_such(package);
 
@@ -1157,6 +1265,7 @@ UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
                    debugstr_w(feature->Feature), debugstr_w(ext->Extension));
             continue;
         }
+        feature->Action = feature->ActionRequest;
 
         TRACE("Registering extension %s (%p)\n", debugstr_w(ext->Extension), ext);
 
@@ -1170,12 +1279,16 @@ UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
 
         mark_mime_for_install(ext->Mime);
 
-        extension = msi_alloc( (lstrlenW( ext->Extension ) + 2)*sizeof(WCHAR) );
-        extension[0] = '.';
-        lstrcpyW(extension+1,ext->Extension);
-
-        RegCreateKeyW(HKEY_CLASSES_ROOT,extension,&hkey);
-        msi_free( extension );
+        extension = msi_alloc( (strlenW( ext->Extension ) + 2) * sizeof(WCHAR) );
+        if (extension)
+        {
+            extension[0] = '.';
+            strcpyW( extension + 1, ext->Extension );
+            res = RegCreateKeyW( HKEY_CLASSES_ROOT, extension, &hkey );
+            msi_free( extension );
+            if (res != ERROR_SUCCESS)
+                WARN("Failed to create extension key %d\n", res);
+        }
 
         if (ext->Mime)
             msi_reg_set_val_str( hkey, szContentType, ext->Mime->ContentType );
@@ -1225,6 +1338,86 @@ UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
     return ERROR_SUCCESS;
 }
 
+UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
+{
+    MSIEXTENSION *ext;
+    MSIRECORD *uirow;
+    LONG res;
+
+    load_classes_and_such( package );
+
+    LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry )
+    {
+        LPWSTR extension;
+        MSIFEATURE *feature;
+
+        if (!ext->Component)
+            continue;
+
+        feature = ext->Feature;
+        if (!feature)
+            continue;
+
+        if (feature->ActionRequest != INSTALLSTATE_ABSENT)
+        {
+            TRACE("Feature %s not scheduled for removal, skipping unregistration of extension %s\n",
+                   debugstr_w(feature->Feature), debugstr_w(ext->Extension));
+            continue;
+        }
+
+        TRACE("Unregistering extension %s\n", debugstr_w(ext->Extension));
+
+        ext->Installed = FALSE;
+
+        if (ext->ProgID && !list_empty( &ext->verbs ))
+            mark_progid_for_uninstall( package, ext->ProgID );
+
+        mark_mime_for_uninstall( ext->Mime );
+
+        extension = msi_alloc( (strlenW( ext->Extension ) + 2) * sizeof(WCHAR) );
+        if (extension)
+        {
+            extension[0] = '.';
+            strcpyW( extension + 1, ext->Extension );
+            res = RegDeleteTreeW( HKEY_CLASSES_ROOT, extension );
+            msi_free( extension );
+            if (res != ERROR_SUCCESS)
+                WARN("Failed to delete extension key %d\n", res);
+        }
+
+        if (ext->ProgID || ext->ProgIDText)
+        {
+            static const WCHAR shellW[] = {'\\','s','h','e','l','l',0};
+            LPCWSTR progid;
+            LPWSTR progid_shell;
+
+            if (ext->ProgID)
+                progid = ext->ProgID->ProgID;
+            else
+                progid = ext->ProgIDText;
+
+            progid_shell = msi_alloc( (strlenW( progid ) + strlenW( shellW ) + 1) * sizeof(WCHAR) );
+            if (progid_shell)
+            {
+                strcpyW( progid_shell, progid );
+                strcatW( progid_shell, shellW );
+                res = RegDeleteTreeW( HKEY_CLASSES_ROOT, progid_shell );
+                msi_free( progid_shell );
+                if (res != ERROR_SUCCESS)
+                    WARN("Failed to delete shell key %d\n", res);
+                RegDeleteKeyW( HKEY_CLASSES_ROOT, progid );
+            }
+        }
+
+        uirow = MSI_CreateRecord( 1 );
+        MSI_RecordSetStringW( uirow, 1, ext->Extension );
+        ui_actiondata( package, szUnregisterExtensionInfo, uirow );
+        msiobj_release( &uirow->hdr );
+    }
+
+    return ERROR_SUCCESS;
+}
+
 UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package)
 {
     static const WCHAR szExten[] = 
@@ -1237,11 +1430,6 @@ UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package)
     LIST_FOR_EACH_ENTRY( mt, &package->mimes, MSIMIME, entry )
     {
         LPWSTR extension;
-        LPCWSTR exten;
-        LPCWSTR mime;
-        static const WCHAR fmt[] = 
-            {'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\',
-             'C','o','n','t','e','n','t',' ','T','y','p','e','\\', '%','s',0};
         LPWSTR key;
 
         /* 
@@ -1254,33 +1442,80 @@ UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package)
 
         if (!mt->InstallMe)
         {
-            TRACE("MIME %s not scheduled to be installed\n",
-                             debugstr_w(mt->ContentType));
+            TRACE("MIME %s not scheduled to be installed\n", debugstr_w(mt->ContentType));
             continue;
         }
-        
-        mime = mt->ContentType;
-        exten = mt->Extension->Extension;
 
-        extension = msi_alloc( (lstrlenW( exten ) + 2)*sizeof(WCHAR) );
-        extension[0] = '.';
-        lstrcpyW(extension+1,exten);
+        TRACE("Registering MIME type %s\n", debugstr_w(mt->ContentType));
+
+        extension = msi_alloc( (strlenW( mt->Extension->Extension ) + 2) * sizeof(WCHAR) );
+        key = msi_alloc( (strlenW( mt->ContentType ) + strlenW( szMIMEDatabase ) + 1) * sizeof(WCHAR) );
 
-        key = msi_alloc( (strlenW(mime)+strlenW(fmt)+1) * sizeof(WCHAR) );
-        sprintfW(key,fmt,mime);
-        msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, key, szExten, extension );
+        if (extension && key)
+        {
+            extension[0] = '.';
+            strcpyW( extension + 1, mt->Extension->Extension );
 
-        msi_free(extension);
-        msi_free(key);
+            strcpyW( key, szMIMEDatabase );
+            strcatW( key, mt->ContentType );
+            msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, key, szExten, extension );
 
-        if (mt->clsid)
-            FIXME("Handle non null for field 3\n");
+            if (mt->clsid)
+                msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, key, szCLSID, mt->clsid );
+        }
+        msi_free( extension );
+        msi_free( key );
 
-        uirow = MSI_CreateRecord(2);
-        MSI_RecordSetStringW(uirow,1,mt->ContentType);
-        MSI_RecordSetStringW(uirow,2,exten);
-        ui_actiondata(package,szRegisterMIMEInfo,uirow);
-        msiobj_release(&uirow->hdr);
+        uirow = MSI_CreateRecord( 2 );
+        MSI_RecordSetStringW( uirow, 1, mt->ContentType );
+        MSI_RecordSetStringW( uirow, 2, mt->suffix );
+        ui_actiondata( package, szRegisterMIMEInfo, uirow );
+        msiobj_release( &uirow->hdr );
+    }
+
+    return ERROR_SUCCESS;
+}
+
+UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
+{
+    MSIRECORD *uirow;
+    MSIMIME *mime;
+
+    load_classes_and_such( package );
+
+    LIST_FOR_EACH_ENTRY( mime, &package->mimes, MSIMIME, entry )
+    {
+        LONG res;
+        LPWSTR mime_key;
+
+        mime->InstallMe = (mime->InstallMe ||
+                          (mime->Class && mime->Class->Installed) ||
+                          (mime->Extension && mime->Extension->Installed));
+
+        if (mime->InstallMe)
+        {
+            TRACE("MIME %s not scheduled to be removed\n", debugstr_w(mime->ContentType));
+            continue;
+        }
+
+        TRACE("Unregistering MIME type %s\n", debugstr_w(mime->ContentType));
+
+        mime_key = msi_alloc( (strlenW( szMIMEDatabase ) + strlenW( mime->ContentType ) + 1) * sizeof(WCHAR) );
+        if (mime_key)
+        {
+            strcpyW( mime_key, szMIMEDatabase );
+            strcatW( mime_key, mime->ContentType );
+            res = RegDeleteKeyW( HKEY_CLASSES_ROOT, mime_key );
+            if (res != ERROR_SUCCESS)
+                WARN("Failed to delete MIME key %d\n", res);
+            msi_free( mime_key );
+        }
+
+        uirow = MSI_CreateRecord( 2 );
+        MSI_RecordSetStringW( uirow, 1, mime->ContentType );
+        MSI_RecordSetStringW( uirow, 2, mime->suffix );
+        ui_actiondata( package, szUnregisterMIMEInfo, uirow );
+        msiobj_release( &uirow->hdr );
     }
 
     return ERROR_SUCCESS;
index 5449d99..2b10d20 100644 (file)
@@ -1989,7 +1989,7 @@ yyreduce:
             COND_input* cond = (COND_input*) info;
             UINT len;
 
-            (yyval.string) = msi_dup_property( cond->package, (yyvsp[(1) - (1)].string) );
+            (yyval.string) = msi_dup_property( cond->package->db, (yyvsp[(1) - (1)].string) );
             if ((yyval.string))
             {
                 len = (lstrlenW((yyval.string)) + 1) * sizeof (WCHAR);
index f3db635..9a7a16d 100644 (file)
@@ -347,7 +347,7 @@ symbol_s:
             COND_input* cond = (COND_input*) info;
             UINT len;
 
-            $$ = msi_dup_property( cond->package, $1 );
+            $$ = msi_dup_property( cond->package->db, $1 );
             if ($$)
             {
                 len = (lstrlenW($$) + 1) * sizeof (WCHAR);
index 584c050..5a1787f 100644 (file)
@@ -163,17 +163,17 @@ static void set_deferred_action_props(MSIPACKAGE *package, LPWSTR deferred_data)
 
     end = strstrW(beg, sep);
     *end = '\0';
-    MSI_SetPropertyW(package, szCustomActionData, beg);
+    msi_set_property(package->db, szCustomActionData, beg);
     beg = end + 3;
 
     end = strstrW(beg, sep);
     *end = '\0';
-    MSI_SetPropertyW(package, szUserSID, beg);
+    msi_set_property(package->db, szUserSID, beg);
     beg = end + 3;
 
     end = strchrW(beg, ']');
     *end = '\0';
-    MSI_SetPropertyW(package, szProductCode, beg);
+    msi_set_property(package->db, szProductCode, beg);
 }
 
 UINT ACTION_CustomAction(MSIPACKAGE *package, LPCWSTR action, UINT script, BOOL execute)
@@ -231,9 +231,9 @@ UINT ACTION_CustomAction(MSIPACKAGE *package, LPCWSTR action, UINT script, BOOL
         }
         if (!execute)
         {
-            LPWSTR actiondata = msi_dup_property(package, action);
-            LPWSTR usersid = msi_dup_property(package, szUserSID);
-            LPWSTR prodcode = msi_dup_property(package, szProductCode);
+            LPWSTR actiondata = msi_dup_property(package->db, action);
+            LPWSTR usersid = msi_dup_property(package->db, szUserSID);
+            LPWSTR prodcode = msi_dup_property(package->db, szProductCode);
             LPWSTR deferred = msi_get_deferred_action(action, actiondata, usersid, prodcode);
 
             if (type & msidbCustomActionTypeCommit)
@@ -256,7 +256,7 @@ UINT ACTION_CustomAction(MSIPACKAGE *package, LPCWSTR action, UINT script, BOOL
         }
         else
         {
-            LPWSTR actiondata = msi_dup_property( package, action );
+            LPWSTR actiondata = msi_dup_property( package->db, action );
 
             switch (script)
             {
@@ -276,9 +276,9 @@ UINT ACTION_CustomAction(MSIPACKAGE *package, LPCWSTR action, UINT script, BOOL
             if (deferred_data)
                 set_deferred_action_props(package, deferred_data);
             else if (actiondata)
-                MSI_SetPropertyW(package, szCustomActionData, actiondata);
+                msi_set_property(package->db, szCustomActionData, actiondata);
             else
-                MSI_SetPropertyW(package, szCustomActionData, szEmpty);
+                msi_set_property(package->db, szCustomActionData, szEmpty);
 
             msi_free(actiondata);
         }
@@ -327,7 +327,9 @@ UINT ACTION_CustomAction(MSIPACKAGE *package, LPCWSTR action, UINT script, BOOL
                 break;
 
             deformat_string(package,target,&deformated);
-            rc = MSI_SetPropertyW(package,source,deformated);
+            rc = msi_set_property( package->db, source, deformated );
+            if (rc == ERROR_SUCCESS && !strcmpW( source, cszSourceDir ))
+                msi_reset_folders( package, TRUE );
             msi_free(deformated);
             break;
        case 37: /* JScript/VBScript text stored in target column. */
@@ -376,7 +378,7 @@ static UINT store_binary_to_temp(MSIPACKAGE *package, LPCWSTR source,
     DWORD sz = MAX_PATH;
     UINT r;
 
-    if (MSI_GetPropertyW(package, cszTempFolder, fmt, &sz) != ERROR_SUCCESS)
+    if (msi_get_property(package->db, cszTempFolder, fmt, &sz) != ERROR_SUCCESS)
         GetTempPathW(MAX_PATH, fmt);
 
     if (GetTempFileNameW(fmt, szMsi, 0, tmp_file) == 0)
@@ -864,7 +866,7 @@ static UINT HANDLE_CustomType23(MSIPACKAGE *package, LPCWSTR source,
     UINT r;
 
     size = MAX_PATH;
-    MSI_GetPropertyW(package, cszSourceDir, package_path, &size);
+    msi_get_property(package->db, cszSourceDir, package_path, &size);
     lstrcatW(package_path, szBackSlash);
     lstrcatW(package_path, source);
 
@@ -1078,7 +1080,7 @@ static UINT HANDLE_CustomType50(MSIPACKAGE *package, LPCWSTR source,
     memset(&si,0,sizeof(STARTUPINFOW));
     memset(&info,0,sizeof(PROCESS_INFORMATION));
 
-    prop = msi_dup_property( package, source );
+    prop = msi_dup_property( package->db, source );
     if (!prop)
         return ERROR_SUCCESS;
 
@@ -1380,7 +1382,7 @@ static UINT HANDLE_CustomType53_54(MSIPACKAGE *package, LPCWSTR source,
 
     TRACE("%s %s\n", debugstr_w(source), debugstr_w(target));
 
-    prop = msi_dup_property(package,source);
+    prop = msi_dup_property( package->db, source );
     if (!prop)
        return ERROR_SUCCESS;
 
@@ -1415,7 +1417,7 @@ void ACTION_FinishCustomActions(const MSIPACKAGE* package)
     EnterCriticalSection( &msi_custom_action_cs );
 
     handle_count = list_count( &msi_pending_custom_actions );
-    wait_handles = HeapAlloc( GetProcessHeap(), 0, handle_count * sizeof(HANDLE) );
+    wait_handles = msi_alloc( handle_count * sizeof(HANDLE) );
 
     handle_count = 0;
     LIST_FOR_EACH_ENTRY_SAFE( info, cursor, &msi_pending_custom_actions, msi_custom_action_info, entry )
@@ -1435,7 +1437,7 @@ void ACTION_FinishCustomActions(const MSIPACKAGE* package)
         CloseHandle( wait_handles[i] );
     }
 
-    HeapFree( GetProcessHeap(), 0, wait_handles );
+    msi_free( wait_handles );
 }
 
 typedef struct _msi_custom_remote_impl {
index cfa11e9..3e57792 100644 (file)
@@ -164,64 +164,6 @@ UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm )
     return SUCCEEDED(r) ? ERROR_SUCCESS : ERROR_FUNCTION_FAILED;
 }
 
-UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname,
-                              USHORT **pdata, UINT *psz )
-{
-    HRESULT r;
-    UINT ret = ERROR_FUNCTION_FAILED;
-    VOID *data;
-    ULONG sz, count;
-    IStream *stm = NULL;
-    STATSTG stat;
-    LPWSTR encname;
-
-    encname = encode_streamname( FALSE, stname );
-    r = db_get_raw_stream( db, encname, &stm );
-    msi_free( encname );
-
-    if( r != ERROR_SUCCESS)
-        return ret;
-
-    r = IStream_Stat(stm, &stat, STATFLAG_NONAME );
-    if( FAILED( r ) )
-    {
-        WARN("open stream failed r = %08x!\n", r);
-        goto end;
-    }
-
-    if( stat.cbSize.QuadPart >> 32 )
-    {
-        WARN("Too big!\n");
-        goto end;
-    }
-
-    sz = stat.cbSize.QuadPart;
-    data = msi_alloc( sz );
-    if( !data )
-    {
-        WARN("couldn't allocate memory r=%08x!\n", r);
-        ret = ERROR_NOT_ENOUGH_MEMORY;
-        goto end;
-    }
-
-    r = IStream_Read(stm, data, sz, &count );
-    if( FAILED( r ) || ( count != sz ) )
-    {
-        msi_free( data );
-        WARN("read stream failed r = %08x!\n", r);
-        goto end;
-    }
-
-    *pdata = data;
-    *psz = sz;
-    ret = ERROR_SUCCESS;
-
-end:
-    IStream_Release( stm );
-
-    return ret;
-}
-
 static void free_transforms( MSIDATABASE *db )
 {
     while( !list_empty( &db->transforms ) )
@@ -234,6 +176,37 @@ static void free_transforms( MSIDATABASE *db )
     }
 }
 
+void db_destroy_stream( MSIDATABASE *db, LPCWSTR stname )
+{
+    MSISTREAM *stream, *stream2;
+
+    LIST_FOR_EACH_ENTRY_SAFE( stream, stream2, &db->streams, MSISTREAM, entry )
+    {
+        HRESULT r;
+        STATSTG stat;
+
+        r = IStream_Stat( stream->stm, &stat, 0 );
+        if (FAILED(r))
+        {
+            WARN("failed to stat stream r = %08x\n", r);
+            continue;
+        }
+
+        if (!strcmpW( stname, stat.pwcsName ))
+        {
+            TRACE("destroying %s\n", debugstr_w(stname));
+
+            list_remove( &stream->entry );
+            IStream_Release( stream->stm );
+            msi_free( stream );
+            IStorage_DestroyElement( db->storage, stname );
+            CoTaskMemFree( stat.pwcsName );
+            break;
+        }
+        CoTaskMemFree( stat.pwcsName );
+    }
+}
+
 static void free_streams( MSIDATABASE *db )
 {
     while( !list_empty( &db->streams ) )
@@ -289,7 +262,7 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
     UINT ret = ERROR_FUNCTION_FAILED;
     LPCWSTR szMode, save_path;
     STATSTG stat;
-    BOOL created = FALSE;
+    BOOL created = FALSE, patch = FALSE;
     WCHAR path[MAX_PATH];
 
     static const WCHAR szTables[]  = { '_','T','a','b','l','e','s',0 };
@@ -304,6 +277,7 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
     {
         TRACE("Database is a patch\n");
         szPersist -= MSIDBOPEN_PATCHFILE;
+        patch = TRUE;
     }
 
     save_path = szDBPath;
@@ -331,7 +305,7 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
               STGM_CREATE|STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, &stg);
         if( r == ERROR_SUCCESS )
         {
-            IStorage_SetClass( stg, &CLSID_MsiDatabase );
+            IStorage_SetClass( stg, patch ? &CLSID_MsiPatch : &CLSID_MsiDatabase );
             /* create the _Tables stream */
             r = write_stream_data(stg, szTables, NULL, 0, TRUE);
             if (SUCCEEDED(r))
@@ -379,6 +353,14 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
         goto end;
     }
 
+    if ( patch && !IsEqualGUID( &stat.clsid, &CLSID_MsiPatch ) )
+    {
+        ERR("storage GUID is not the MSI patch GUID %s\n",
+             debugstr_guid(&stat.clsid) );
+        ret = ERROR_OPEN_FAILED;
+        goto end;
+    }
+
     db = alloc_msiobject( MSIHANDLETYPE_DATABASE, sizeof (MSIDATABASE),
                               MSI_CloseDatabase );
     if( !db )
index ac2e95a..2a00aa7 100644 (file)
@@ -171,6 +171,8 @@ static MSIFEATURE *msi_seltree_get_selected_feature( msi_control *control );
 static DWORD uiThreadId;
 static HWND hMsiHiddenWindow;
 
+static LPWSTR msi_get_window_text( HWND hwnd );
+
 static INT msi_dialog_scale_unit( msi_dialog *dialog, INT val )
 {
     return MulDiv( val, dialog->scale, 12 );
@@ -234,7 +236,7 @@ static LPWSTR msi_dialog_dup_property( msi_dialog *dialog, LPCWSTR property, BOO
         return NULL;
 
     if (indirect)
-        prop = msi_dup_property( dialog->package, property );
+        prop = msi_dup_property( dialog->package->db, property );
 
     if (!prop)
         prop = strdupW( property );
@@ -581,6 +583,13 @@ static void msi_dialog_update_controls( msi_dialog *dialog, LPCWSTR property )
     }
 }
 
+static void msi_dialog_set_property( MSIPACKAGE *package, LPCWSTR property, LPCWSTR value )
+{
+    UINT r = msi_set_property( package->db, property, value );
+    if (r == ERROR_SUCCESS && !strcmpW( property, cszSourceDir ))
+        msi_reset_folders( package, TRUE );
+}
+
 /* called from the Control Event subscription code */
 void msi_dialog_handle_event( msi_dialog* dialog, LPCWSTR control, 
                               LPCWSTR attribute, MSIRECORD *rec )
@@ -634,14 +643,14 @@ void msi_dialog_handle_event( msi_dialog* dialog, LPCWSTR control,
     else if ( !lstrcmpW(attribute, szProperty) )
     {
         MSIFEATURE *feature = msi_seltree_get_selected_feature( ctrl );
-        MSI_SetPropertyW( dialog->package, ctrl->property, feature->Directory );
+        msi_dialog_set_property( dialog->package, ctrl->property, feature->Directory );
     }
     else if ( !lstrcmpW(attribute, szSelectionPath) )
     {
         LPWSTR prop = msi_dialog_dup_property( dialog, ctrl->property, TRUE );
         LPWSTR path;
         if (!prop) return;
-        path = msi_dup_property( dialog->package, prop );
+        path = msi_dup_property( dialog->package->db, prop );
         SetWindowTextW( ctrl->hwnd, path );
         msi_free(prop);
         msi_free(path);
@@ -884,7 +893,7 @@ static LPWSTR msi_get_checkbox_value( msi_dialog *dialog, LPCWSTR prop )
     if (ret)
         return ret;
 
-    ret = msi_dup_property( dialog->package, prop );
+    ret = msi_dup_property( dialog->package->db, prop );
     if( ret && !ret[0] )
     {
         msi_free( ret );
@@ -1222,10 +1231,167 @@ static UINT msi_dialog_icon_control( msi_dialog *dialog, MSIRECORD *rec )
     return ERROR_SUCCESS;
 }
 
+/******************** Combo Box ***************************************/
+
+struct msi_combobox_info
+{
+    msi_dialog *dialog;
+    HWND hwnd;
+    WNDPROC oldproc;
+    DWORD num_items;
+    DWORD addpos_items;
+    LPWSTR *items;
+};
+
+static LRESULT WINAPI MSIComboBox_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    struct msi_combobox_info *info;
+    LRESULT r;
+    DWORD j;
+
+    TRACE("%p %04x %08lx %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] );
+        msi_free( info->items );
+        msi_free( info );
+        RemovePropW( hWnd, szButtonData );
+        break;
+    }
+
+    return r;
+}
+
+static UINT msi_combobox_add_item( MSIRECORD *rec, LPVOID param )
+{
+    struct msi_combobox_info *info = param;
+    LPCWSTR value, text;
+    int pos;
+
+    value = MSI_RecordGetString( rec, 3 );
+    text = MSI_RecordGetString( rec, 4 );
+
+    info->items[info->addpos_items] = strdupW( value );
+
+    pos = SendMessageW( info->hwnd, CB_ADDSTRING, 0, (LPARAM)text );
+    SendMessageW( info->hwnd, CB_SETITEMDATA, pos, (LPARAM)info->items[info->addpos_items] );
+    info->addpos_items++;
+
+    return ERROR_SUCCESS;
+}
+
+static UINT msi_combobox_add_items( struct msi_combobox_info *info, LPCWSTR property )
+{
+    UINT r;
+    MSIQUERY *view = NULL;
+    DWORD count;
+
+    static const WCHAR query[] = {
+        'S','E','L','E','C','T',' ','*',' ',
+        'F','R','O','M',' ','`','C','o','m','b','o','B','o','x','`',' ',
+        'W','H','E','R','E',' ',
+        '`','P','r','o','p','e','r','t','y','`',' ','=',' ','\'','%','s','\'',' ',
+        'O','R','D','E','R',' ','B','Y',' ','`','O','r','d','e','r','`',0
+    };
+
+    r = MSI_OpenQuery( info->dialog->package->db, &view, query, property );
+    if (r != ERROR_SUCCESS)
+        return r;
+
+    /* just get the number of records */
+    count = 0;
+    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_combobox_add_item, info );
+    msiobj_release( &view->hdr );
+
+    return r;
+}
+
+static UINT msi_dialog_combobox_handler( msi_dialog *dialog,
+                                         msi_control *control, WPARAM param )
+{
+    struct msi_combobox_info *info;
+    int index;
+    LPWSTR value;
+
+    if (HIWORD(param) != CBN_SELCHANGE && HIWORD(param) != CBN_EDITCHANGE)
+        return ERROR_SUCCESS;
+
+    info = GetPropW( control->hwnd, szButtonData );
+    index = SendMessageW( control->hwnd, CB_GETCURSEL, 0, 0 );
+    if (index == CB_ERR)
+        value = msi_get_window_text( control->hwnd );
+    else
+        value = (LPWSTR) SendMessageW( control->hwnd, CB_GETITEMDATA, index, 0 );
+
+    msi_dialog_set_property( info->dialog->package, control->property, value );
+    msi_dialog_evaluate_control_conditions( info->dialog );
+
+    if (index == CB_ERR)
+        msi_free( value );
+
+    return ERROR_SUCCESS;
+}
+
+static void msi_dialog_combobox_update( msi_dialog *dialog,
+                msi_control *control )
+{
+    struct msi_combobox_info *info;
+    LPWSTR value, tmp;
+    DWORD j;
+
+    info = GetPropW( control->hwnd, szButtonData );
+
+    value = msi_dup_property( dialog->package->db, control->property );
+    if (!value)
+    {
+        SendMessageW( control->hwnd, CB_SETCURSEL, -1, 0 );
+        return;
+    }
+
+    for (j = 0; j < info->num_items; j++)
+    {
+        tmp = (LPWSTR) SendMessageW( control->hwnd, CB_GETITEMDATA, j, 0 );
+        if (!lstrcmpW( value, tmp ))
+            break;
+    }
+
+    if (j < info->num_items)
+    {
+        SendMessageW( control->hwnd, CB_SETCURSEL, j, 0 );
+    }
+    else
+    {
+        SendMessageW( control->hwnd, CB_SETCURSEL, -1, 0 );
+        SetWindowTextW( control->hwnd, value );
+    }
+
+    msi_free(value);
+}
+
 static UINT msi_dialog_combo_control( msi_dialog *dialog, MSIRECORD *rec )
 {
-    static const WCHAR szCombo[] = { 'C','O','M','B','O','B','O','X',0 };
+    struct msi_combobox_info *info;
+    msi_control *control;
     DWORD attributes, style;
+    LPCWSTR prop;
+
+    info = msi_alloc( sizeof *info );
+    if (!info)
+        return ERROR_FUNCTION_FAILED;
 
     style = CBS_AUTOHSCROLL | WS_TABSTOP | WS_GROUP | WS_CHILD;
     attributes = MSI_RecordGetInteger( rec, 8 );
@@ -1236,7 +1402,33 @@ static UINT msi_dialog_combo_control( msi_dialog *dialog, MSIRECORD *rec )
     else
         style |= CBS_DROPDOWN;
 
-    msi_dialog_add_control( dialog, rec, szCombo, style );
+    control = msi_dialog_add_control( dialog, rec, WC_COMBOBOXW, style );
+    if (!control)
+    {
+        msi_free( info );
+        return ERROR_FUNCTION_FAILED;
+    }
+
+    control->handler = msi_dialog_combobox_handler;
+    control->update = msi_dialog_combobox_update;
+
+    prop = MSI_RecordGetString( rec, 9 );
+    control->property = msi_dialog_dup_property( dialog, prop, FALSE );
+
+    /* subclass */
+    info->dialog = dialog;
+    info->hwnd = control->hwnd;
+    info->items = NULL;
+    info->addpos_items = 0;
+    info->oldproc = (WNDPROC)SetWindowLongPtrW( control->hwnd, GWLP_WNDPROC,
+                                                (LONG_PTR)MSIComboBox_WndProc );
+    SetPropW( control->hwnd, szButtonData, info );
+
+    if (control->property)
+        msi_combobox_add_items( info, control->property );
+
+    msi_dialog_combobox_update( dialog, control );
+
     return ERROR_SUCCESS;
 }
 
@@ -1276,7 +1468,7 @@ static UINT msi_dialog_edit_control( msi_dialog *dialog, MSIRECORD *rec )
     if( prop )
         control->property = strdupW( prop );
 
-    val = msi_dup_property( dialog->package, control->property );
+    val = msi_dup_property( dialog->package->db, control->property );
     SetWindowTextW( control->hwnd, val );
     msi_free( val );
     return ERROR_SUCCESS;
@@ -1352,10 +1544,9 @@ static void msi_mask_control_change( struct msi_maskedit_info *info )
 
     if( i == info->num_groups )
     {
-        TRACE("Set property %s to %s\n",
-              debugstr_w(info->prop), debugstr_w(val) );
+        TRACE("Set property %s to %s\n", debugstr_w(info->prop), debugstr_w(val));
         CharUpperBuffW( val, info->num_chars );
-        MSI_SetPropertyW( info->dialog->package, info->prop, val );
+        msi_dialog_set_property( info->dialog->package, info->prop, val );
         msi_dialog_evaluate_control_conditions( info->dialog );
     }
     msi_free( val );
@@ -1587,7 +1778,7 @@ static UINT msi_dialog_maskedit_control( msi_dialog *dialog, MSIRECORD *rec )
 
     if( prop )
     {
-        val = msi_dup_property( dialog->package, prop );
+        val = msi_dup_property( dialog->package->db, prop );
         if( val )
         {
             msi_maskedit_set_text( info, val );
@@ -1705,7 +1896,7 @@ static BOOL msi_dialog_onkillfocus( msi_dialog *dialog, msi_control *control )
     else
     {
         valid = TRUE;
-        MSI_SetPropertyW( dialog->package, prop, buf );
+        msi_dialog_set_property( dialog->package, prop, buf );
     }
 
     msi_dialog_update_pathedit( dialog, control );
@@ -1855,7 +2046,7 @@ 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 );
+    group.propval = msi_dup_property( dialog->package->db, control->property );
 
     r = MSI_IterateRecords( view, 0, msi_dialog_create_radiobutton, &group );
     msiobj_release( &view->hdr );
@@ -2357,8 +2548,7 @@ static UINT msi_dialog_listbox_handler( msi_dialog *dialog,
     index = SendMessageW( control->hwnd, LB_GETCURSEL, 0, 0 );
     value = (LPCWSTR) SendMessageW( control->hwnd, LB_GETITEMDATA, index, 0 );
 
-    MSI_SetPropertyW( info->dialog->package,
-                      control->property, value );
+    msi_dialog_set_property( info->dialog->package, control->property, value );
     msi_dialog_evaluate_control_conditions( info->dialog );
 
     return ERROR_SUCCESS;
@@ -2521,7 +2711,7 @@ UINT msi_dialog_directorylist_up( msi_dialog *dialog )
     if (ptr != path) *(ptr - 1) = '\0';
     PathAddBackslashW( path );
 
-    MSI_SetPropertyW( dialog->package, prop, path );
+    msi_dialog_set_property( dialog->package, prop, path );
 
     msi_dialog_update_directory_list( dialog, NULL );
     msi_dialog_update_directory_combo( dialog, NULL );
@@ -2567,7 +2757,7 @@ static UINT msi_dialog_dirlist_handler( msi_dialog *dialog,
     lstrcatW( new_path, text );
     lstrcatW( new_path, szBackSlash );
 
-    MSI_SetPropertyW( dialog->package, prop, new_path );
+    msi_dialog_set_property( dialog->package, prop, new_path );
 
     msi_dialog_update_directory_list( dialog, NULL );
     msi_dialog_update_directory_combo( dialog, NULL );
@@ -2810,7 +3000,7 @@ static UINT msi_dialog_volsel_handler( msi_dialog *dialog,
     indirect = control->attributes & msidbControlAttributesIndirect;
     prop = msi_dialog_dup_property( dialog, control->property, indirect );
 
-    MSI_SetPropertyW( dialog->package, prop, text );
+    msi_dialog_set_property( dialog->package, prop, text );
 
     msi_free( prop );
     return ERROR_SUCCESS;
@@ -3078,8 +3268,8 @@ static void msi_dialog_adjust_dialog_pos( msi_dialog *dialog, MSIRECORD *rec, LP
     sz.cx = msi_dialog_scale_unit( dialog, sz.cx );
     sz.cy = msi_dialog_scale_unit( dialog, sz.cy );
 
-    xres = msi_get_property_int( dialog->package, szScreenX, 0 );
-    yres = msi_get_property_int( dialog->package, szScreenY, 0 );
+    xres = msi_get_property_int( dialog->package->db, szScreenX, 0 );
+    yres = msi_get_property_int( dialog->package->db, szScreenY, 0 );
 
     center.x = MulDiv( center.x, xres, 100 );
     center.y = MulDiv( center.y, yres, 100 );
@@ -3172,7 +3362,7 @@ static LRESULT msi_dialog_oncreate( HWND hwnd, LPCREATESTRUCTW cs )
 
     dialog->attributes = MSI_RecordGetInteger( rec, 6 );
 
-    dialog->default_font = msi_dup_property( dialog->package, df );
+    dialog->default_font = msi_dup_property( dialog->package->db, df );
     if (!dialog->default_font)
     {
         dialog->default_font = strdupW(dfv);
@@ -3213,7 +3403,7 @@ static UINT msi_dialog_send_event( msi_dialog *dialog, LPCWSTR event, LPCWSTR ar
     return ERROR_SUCCESS;
 }
 
-static UINT msi_dialog_set_property( msi_dialog *dialog, LPCWSTR event, LPCWSTR arg )
+static UINT msi_dialog_set_property_event( msi_dialog *dialog, LPCWSTR event, LPCWSTR arg )
 {
     static const WCHAR szNullArg[] = { '{','}',0 };
     LPWSTR p, prop, arg_fmt = NULL;
@@ -3228,7 +3418,7 @@ static UINT msi_dialog_set_property( msi_dialog *dialog, LPCWSTR event, LPCWSTR
         *p = 0;
         if( strcmpW( szNullArg, arg ) )
             deformat_string( dialog->package, arg, &arg_fmt );
-        MSI_SetPropertyW( dialog->package, prop, arg_fmt );
+        msi_dialog_set_property( dialog->package, prop, arg_fmt );
         msi_dialog_update_controls( dialog, prop );
         msi_free( arg_fmt );
     }
@@ -3251,7 +3441,7 @@ static UINT msi_dialog_control_event( MSIRECORD *rec, LPVOID param )
         event = MSI_RecordGetString( rec, 3 );
         arg = MSI_RecordGetString( rec, 4 );
         if( event[0] == '[' )
-            msi_dialog_set_property( dialog, event, arg );
+            msi_dialog_set_property_event( dialog, event, arg );
         else
             msi_dialog_send_event( dialog, event, arg );
     }
@@ -3366,7 +3556,7 @@ static UINT msi_dialog_get_checkbox_state( msi_dialog *dialog,
     WCHAR state[2] = { 0 };
     DWORD sz = 2;
 
-    MSI_GetPropertyW( dialog->package, control->property, state, &sz );
+    msi_get_property( dialog->package->db, control->property, state, &sz );
     return state[0] ? 1 : 0;
 }
 
@@ -3379,7 +3569,7 @@ static void msi_dialog_set_checkbox_state( msi_dialog *dialog,
     /* if uncheck then the property is set to NULL */
     if (!state)
     {
-        MSI_SetPropertyW( dialog->package, control->property, NULL );
+        msi_dialog_set_property( dialog->package, control->property, NULL );
         return;
     }
 
@@ -3389,7 +3579,7 @@ static void msi_dialog_set_checkbox_state( msi_dialog *dialog,
     else
         val = szState;
 
-    MSI_SetPropertyW( dialog->package, control->property, val );
+    msi_dialog_set_property( dialog->package, control->property, val );
 }
 
 static void msi_dialog_checkbox_sync_state( msi_dialog *dialog,
@@ -3433,8 +3623,7 @@ static UINT msi_dialog_edit_handler( msi_dialog *dialog,
           debugstr_w(control->property));
 
     buf = msi_get_window_text( control->hwnd );
-    MSI_SetPropertyW( dialog->package, control->property, buf );
-
+    msi_dialog_set_property( dialog->package, control->property, buf );
     msi_free( buf );
 
     return ERROR_SUCCESS;
@@ -3449,7 +3638,7 @@ static UINT msi_dialog_radiogroup_handler( msi_dialog *dialog,
     TRACE("clicked radio button %s, set %s\n", debugstr_w(control->name),
           debugstr_w(control->property));
 
-    MSI_SetPropertyW( dialog->package, control->property, control->name );
+    msi_dialog_set_property( dialog->package, control->property, control->name );
 
     return msi_dialog_button_handler( dialog, control, param );
 }
@@ -3835,7 +4024,7 @@ static UINT error_dialog_handler(MSIPACKAGE *package, LPCWSTR event,
     if ( !lstrcmpW( argument, error_abort ) || !lstrcmpW( argument, error_cancel ) ||
          !lstrcmpW( argument, error_no ) )
     {
-         MSI_SetPropertyW( package, result_prop, error_abort );
+         msi_set_property( package->db, result_prop, error_abort );
     }
 
     ControlEvent_CleanupSubscriptions(package);
@@ -3878,12 +4067,12 @@ UINT msi_spawn_error_dialog( MSIPACKAGE *package, LPWSTR error_dialog, LPWSTR er
         'M','S','I','E','r','r','o','r','D','i','a','l','o','g','R','e','s','u','l','t',0
     };
 
-    if ( (msi_get_property_int(package, szUILevel, 0) & INSTALLUILEVEL_MASK) == INSTALLUILEVEL_NONE )
+    if ( (msi_get_property_int( package->db, szUILevel, 0 ) & INSTALLUILEVEL_MASK) == INSTALLUILEVEL_NONE )
         return ERROR_SUCCESS;
 
     if ( !error_dialog )
     {
-        LPWSTR product_name = msi_dup_property( package, pn_prop );
+        LPWSTR product_name = msi_dup_property( package->db, pn_prop );
         WCHAR title[MAX_PATH];
 
         sprintfW( title, title_fmt, product_name );
@@ -3911,7 +4100,7 @@ UINT msi_spawn_error_dialog( MSIPACKAGE *package, LPWSTR error_dialog, LPWSTR er
     if ( r != ERROR_SUCCESS )
         goto done;
 
-    r = MSI_GetPropertyW( package, result_prop, result, &size );
+    r = msi_get_property( package->db, result_prop, result, &size );
     if ( r != ERROR_SUCCESS)
         r = ERROR_SUCCESS;
 
index e8f2297..4ed395b 100644 (file)
@@ -226,7 +226,7 @@ static UINT ControlEvent_AddSource(MSIPACKAGE* package, LPCWSTR argument,
 static UINT ControlEvent_SetTargetPath(MSIPACKAGE* package, LPCWSTR argument, 
                                    msi_dialog* dialog)
 {
-    LPWSTR path = msi_dup_property( package, argument );
+    LPWSTR path = msi_dup_property( package->db, argument );
     MSIRECORD *rec = MSI_CreateRecord( 1 );
     UINT r;
 
@@ -380,7 +380,13 @@ static UINT ControlEvent_DirectoryListUp(MSIPACKAGE *package, LPCWSTR argument,
 static UINT ControlEvent_ReinstallMode(MSIPACKAGE *package, LPCWSTR argument,
                                        msi_dialog *dialog)
 {
-    return MSI_SetPropertyW( package, szReinstallMode, argument );
+    return msi_set_property( package->db, szReinstallMode, argument );
+}
+
+static UINT ControlEvent_Reinstall( MSIPACKAGE *package, LPCWSTR argument,
+                                    msi_dialog *dialog )
+{
+    return msi_set_property( package->db, szReinstall, argument );
 }
 
 static UINT ControlEvent_ValidateProductID(MSIPACKAGE *package, LPCWSTR argument,
@@ -389,13 +395,13 @@ static UINT ControlEvent_ValidateProductID(MSIPACKAGE *package, LPCWSTR argument
     LPWSTR key, template;
     UINT ret = ERROR_SUCCESS;
 
-    template = msi_dup_property( package, szPIDTemplate );
-    key = msi_dup_property( package, szPIDKEY );
+    template = msi_dup_property( package->db, szPIDTemplate );
+    key = msi_dup_property( package->db, szPIDKEY );
 
     if (key && template)
     {
         FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
-        ret = MSI_SetPropertyW( package, szProductID, key );
+        ret = msi_set_property( package->db, szProductID, key );
     }
     msi_free( template );
     msi_free( key );
@@ -417,6 +423,7 @@ static const struct _events Events[] = {
     { "DirectoryListUp",ControlEvent_DirectoryListUp },
     { "SelectionBrowse",ControlEvent_SpawnDialog },
     { "ReinstallMode",ControlEvent_ReinstallMode },
+    { "Reinstall",ControlEvent_Reinstall },
     { "ValidateProductID",ControlEvent_ValidateProductID },
     { NULL,NULL },
 };
index 4050163..052a158 100644 (file)
@@ -98,6 +98,8 @@ static void schedule_install_files(MSIPACKAGE *package)
             ui_progress(package,2,file->FileSize,0,0);
             file->state = msifs_skipped;
         }
+        else
+            file->Component->Action = INSTALLSTATE_LOCAL;
     }
 }
 
@@ -119,8 +121,7 @@ static UINT copy_install_file(MSIPACKAGE *package, MSIFILE *file, LPWSTR source)
 {
     UINT gle;
 
-    TRACE("Copying %s to %s\n", debugstr_w(source),
-          debugstr_w(file->TargetPath));
+    TRACE("Copying %s to %s\n", debugstr_w(source), debugstr_w(file->TargetPath));
 
     gle = copy_file(file, source);
     if (gle == ERROR_SUCCESS)
@@ -147,7 +148,7 @@ static UINT copy_install_file(MSIPACKAGE *package, MSIFILE *file, LPWSTR source)
 
         GetTempFileNameW(szBackSlash, szMsi, 0, tmpfileW);
         len = strlenW(file->TargetPath) + strlenW(tmpfileW) + 1;
-        if (!(pathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
+        if (!(pathW = msi_alloc(len * sizeof(WCHAR))))
             return ERROR_OUTOFMEMORY;
 
         strcpyW(pathW, file->TargetPath);
@@ -167,32 +168,17 @@ static UINT copy_install_file(MSIPACKAGE *package, MSIFILE *file, LPWSTR source)
             gle = GetLastError();
             WARN("failed to schedule rename operation: %d)\n", gle);
         }
-        HeapFree(GetProcessHeap(), 0, pathW);
+        msi_free(pathW);
     }
 
     return gle;
 }
 
-static BOOL check_dest_hash_matches(MSIFILE *file)
-{
-    MSIFILEHASHINFO hash;
-    UINT r;
-
-    if (!file->hash.dwFileHashInfoSize)
-        return FALSE;
-
-    hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
-    r = MsiGetFileHashW(file->TargetPath, 0, &hash);
-    if (r != ERROR_SUCCESS)
-        return FALSE;
-
-    return !memcmp(&hash, &file->hash, sizeof(MSIFILEHASHINFO));
-}
-
 static BOOL installfiles_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
                             LPWSTR *path, DWORD *attrs, PVOID user)
 {
     static MSIFILE *f = NULL;
+    MSIMEDIAINFO *mi = user;
 
     if (action == MSICABEXTRACT_BEGINEXTRACT)
     {
@@ -203,11 +189,8 @@ static BOOL installfiles_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
             return FALSE;
         }
 
-        if (f->state != msifs_missing && f->state != msifs_overwrite)
-        {
-            TRACE("Skipping extraction of %s\n", debugstr_w(file));
+        if (f->disk_id != mi->disk_id || (f->state != msifs_missing && f->state != msifs_overwrite))
             return FALSE;
-        }
 
         msi_file_update_ui(package, f, szInstallFiles);
 
@@ -256,19 +239,6 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
         if (file->state != msifs_missing && !mi->is_continuous && file->state != msifs_overwrite)
             continue;
 
-        if (check_dest_hash_matches(file))
-        {
-            TRACE("File hashes match, not overwriting\n");
-            continue;
-        }
-
-        if (MsiGetFileVersionW(file->TargetPath, NULL, NULL, NULL, NULL) == ERROR_SUCCESS &&
-            msi_compare_file_version(file) >= 0)
-        {
-            TRACE("Destination file version greater, not overwriting\n");
-            continue;
-        }
-
         if (file->Sequence > mi->last_sequence || mi->is_continuous ||
             (file->IsCompressed && !mi->is_extracted))
         {
@@ -277,20 +247,20 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
             rc = ready_media(package, file, mi);
             if (rc != ERROR_SUCCESS)
             {
-                ERR("Failed to ready media\n");
+                ERR("Failed to ready media for %s\n", debugstr_w(file->File));
                 break;
             }
 
             data.mi = mi;
             data.package = package;
             data.cb = installfiles_cb;
-            data.user = NULL;
+            data.user = mi;
 
             if (file->IsCompressed &&
                 !msi_cabextract(package, mi, &data))
             {
                 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
-                rc = ERROR_FUNCTION_FAILED;
+                rc = ERROR_INSTALL_FAILURE;
                 break;
             }
         }
@@ -317,8 +287,7 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
         }
         else if (file->state != msifs_installed)
         {
-            ERR("compressed file wasn't extracted (%s)\n",
-                debugstr_w(file->TargetPath));
+            ERR("compressed file wasn't installed (%s)\n", debugstr_w(file->TargetPath));
             rc = ERROR_INSTALL_FAILURE;
             break;
         }
@@ -555,11 +524,11 @@ static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
     sourcename = MSI_RecordGetString(rec, 3);
     options = MSI_RecordGetInteger(rec, 7);
 
-    sourcedir = msi_dup_property(package, MSI_RecordGetString(rec, 5));
+    sourcedir = msi_dup_property(package->db, MSI_RecordGetString(rec, 5));
     if (!sourcedir)
         goto done;
 
-    destdir = msi_dup_property(package, MSI_RecordGetString(rec, 6));
+    destdir = msi_dup_property(package->db, MSI_RecordGetString(rec, 6));
     if (!destdir)
         goto done;
 
@@ -704,7 +673,7 @@ static WCHAR *get_duplicate_filename( MSIPACKAGE *package, MSIRECORD *row, const
         if (!dst_path)
         {
             /* try a property */
-            dst_path = msi_dup_property( package, dst_key );
+            dst_path = msi_dup_property( package->db, dst_key );
             if (!dst_path)
             {
                 FIXME("Unable to get destination folder, try AppSearch properties\n");
@@ -917,7 +886,7 @@ static UINT ITERATE_RemoveFiles(MSIRECORD *row, LPVOID param)
     UINT install_mode;
     LPWSTR dir = NULL, path = NULL;
     DWORD size;
-    UINT r;
+    UINT ret = ERROR_SUCCESS;
 
     component = MSI_RecordGetString(row, 2);
     filename = MSI_RecordGetString(row, 3);
@@ -938,7 +907,7 @@ static UINT ITERATE_RemoveFiles(MSIRECORD *row, LPVOID param)
         return ERROR_SUCCESS;
     }
 
-    dir = msi_dup_property(package, dirprop);
+    dir = msi_dup_property(package->db, dirprop);
     if (!dir)
         return ERROR_OUTOFMEMORY;
 
@@ -947,7 +916,7 @@ static UINT ITERATE_RemoveFiles(MSIRECORD *row, LPVOID param)
     path = msi_alloc(size * sizeof(WCHAR));
     if (!path)
     {
-        r = ERROR_OUTOFMEMORY;
+        ret = ERROR_OUTOFMEMORY;
         goto done;
     }
 
@@ -975,7 +944,7 @@ done:
 
     msi_free(path);
     msi_free(dir);
-    return ERROR_SUCCESS;
+    return ret;
 }
 
 UINT ACTION_RemoveFiles( MSIPACKAGE *package )
index 1b2c3c7..1d99a4c 100644 (file)
@@ -64,11 +64,6 @@ typedef struct _tagTT_NAME_RECORD {
 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
 
-static const WCHAR szRegisterFonts[] =
-    {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
-static const WCHAR szUnregisterFonts[] =
-    {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
-
 static const WCHAR regfont1[] =
     {'S','o','f','t','w','a','r','e','\\',
      'M','i','c','r','o','s','o','f','t','\\',
index f59024a..c4ff30f 100644 (file)
@@ -175,7 +175,7 @@ static LPWSTR deformat_property(FORMAT *format, FORMSTR *str)
     val = msi_alloc((str->len + 1) * sizeof(WCHAR));
     lstrcpynW(val, get_formstr_data(format, str), str->len + 1);
 
-    ret = msi_dup_property(format->package, val);
+    ret = msi_dup_property(format->package->db, val);
 
     msi_free(val);
     return ret;
@@ -805,12 +805,12 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr,
     format.deformatted = *data;
     format.len = *len;
 
-    stack = create_stack();
-    temp = create_stack();
-
     if (!verify_format(*data))
         return ERROR_SUCCESS;
 
+    stack = create_stack();
+    temp = create_stack();
+
     while ((type = format_lex(&format, &str)) != FORMAT_NULL)
     {
         if (type == FORMAT_LBRACK || type == FORMAT_LBRACE ||
index c45ba23..54d2199 100644 (file)
@@ -47,7 +47,7 @@ LPWSTR build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name )
     static const WCHAR szFolder[] =
         {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
 
-    SystemFolder = msi_dup_property( package, szFolder );
+    SystemFolder = msi_dup_property( package->db, szFolder );
 
     dest = build_directory_name(3, SystemFolder, szInstaller, package->ProductCode);
 
@@ -160,11 +160,11 @@ static LPWSTR get_source_root( MSIPACKAGE *package )
 {
     LPWSTR path, p;
 
-    path = msi_dup_property( package, cszSourceDir );
+    path = msi_dup_property( package->db, cszSourceDir );
     if (path)
         return path;
 
-    path = msi_dup_property( package, cszDatabase );
+    path = msi_dup_property( package->db, cszDatabase );
     if (path)
     {
         p = strrchrW(path,'\\');
@@ -265,19 +265,19 @@ LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
         if (!f->ResolvedTarget && !f->Property)
         {
             LPWSTR check_path;
-            check_path = msi_dup_property( package, cszTargetDir );
+            check_path = msi_dup_property( package->db, cszTargetDir );
             if (!check_path)
             {
-                check_path = msi_dup_property( package, cszRootDrive );
+                check_path = msi_dup_property( package->db, cszRootDrive );
                 if (set_prop)
-                    MSI_SetPropertyW(package,cszTargetDir,check_path);
+                    msi_set_property( package->db, cszTargetDir, check_path );
             }
 
             /* 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_set_property( package->db, cszTargetDir, path );
             msi_free(check_path);
 
             f->ResolvedTarget = path;
@@ -310,11 +310,11 @@ LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
 
         TRACE("   internally set to %s\n",debugstr_w(path));
         if (set_prop)
-            MSI_SetPropertyW( package, name, path );
+            msi_set_property( package->db, name, path );
         return path;
     }
 
-    if (!source && load_prop && (path = msi_dup_property( package, name )))
+    if (!source && load_prop && (path = msi_dup_property( package->db, name )))
     {
         f->ResolvedTarget = strdupW( path );
         TRACE("   property set to %s\n", debugstr_w(path));
@@ -338,7 +338,7 @@ LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
         f->ResolvedTarget = strdupW( path );
         TRACE("target -> %s\n", debugstr_w(path));
         if (set_prop)
-            MSI_SetPropertyW(package,name,path);
+            msi_set_property( package->db, name, path );
     }
     else
     {
index c23075d..fda49b9 100644 (file)
@@ -709,7 +709,7 @@ BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
         break;
 
     case MSIRUNMODE_MAINTENANCE:
-        r = msi_get_property_int( package, szInstalled, 0 ) != 0;
+        r = msi_get_property_int( package->db, szInstalled, 0 ) != 0;
         break;
 
     case MSIRUNMODE_REBOOTATEND:
@@ -721,6 +721,7 @@ BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
         r = TRUE;
     }
 
+    msiobj_release( &package->hdr );
     return r;
 }
 
@@ -774,6 +775,7 @@ UINT WINAPI MsiSetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode, BOOL fState)
         r = ERROR_ACCESS_DENIED;
     }
 
+    msiobj_release( &package->hdr );
     return r;
 }
 
@@ -1262,7 +1264,7 @@ LANGID WINAPI MsiGetLanguage(MSIHANDLE hInstall)
         return 0;
     }
 
-    langid = msi_get_property_int( package, szProductLanguage, 0 );
+    langid = msi_get_property_int( package->db, szProductLanguage, 0 );
     msiobj_release( &package->hdr );
     return langid;
 }
@@ -1284,7 +1286,7 @@ UINT MSI_SetInstallLevel( MSIPACKAGE *package, int iInstallLevel )
         return MSI_SetFeatureStates( package );
 
     sprintfW( level, fmt, iInstallLevel );
-    r = MSI_SetPropertyW( package, szInstallLevel, level );
+    r = msi_set_property( package->db, szInstallLevel, level );
     if ( r == ERROR_SUCCESS )
         r = MSI_SetFeatureStates( package );
 
index 0a6c431..49bc199 100644 (file)
@@ -20,6 +20,8 @@
 
 #include <stdarg.h>
 
+#define COBJMACROS
+
 #include "windef.h"
 #include "winerror.h"
 #include "wine/debug.h"
@@ -28,6 +30,7 @@
 #include "winuser.h"
 #include "winreg.h"
 #include "shlwapi.h"
+#include "objidl.h"
 #include "wine/unicode.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(msi);
@@ -76,13 +79,13 @@ static UINT msi_change_media(MSIPACKAGE *package, MSIMEDIAINFO *mi)
 
     static const WCHAR error_prop[] = {'E','r','r','o','r','D','i','a','l','o','g',0};
 
-    if ((msi_get_property_int(package, szUILevel, 0) & INSTALLUILEVEL_MASK) ==
+    if ((msi_get_property_int(package->db, szUILevel, 0) & INSTALLUILEVEL_MASK) ==
          INSTALLUILEVEL_NONE && !gUIHandlerA && !gUIHandlerW && !gUIHandlerRecord)
         return ERROR_SUCCESS;
 
     error = generate_error_string(package, 1302, 1, mi->disk_prompt);
-    error_dialog = msi_dup_property(package, error_prop);
-    source_dir = msi_dup_property(package, cszSourceDir);
+    error_dialog = msi_dup_property(package->db, error_prop);
+    source_dir = msi_dup_property(package->db, cszSourceDir);
 
     while (r == ERROR_SUCCESS && !source_matches_volume(mi, source_dir))
     {
@@ -114,49 +117,6 @@ static UINT msi_change_media(MSIPACKAGE *package, MSIMEDIAINFO *mi)
     return r;
 }
 
-static UINT writeout_cabinet_stream(MSIPACKAGE *package, LPCWSTR stream,
-                                    WCHAR* source)
-{
-    UINT rc;
-    USHORT* data;
-    UINT size;
-    DWORD write;
-    HANDLE hfile;
-    WCHAR tmp[MAX_PATH];
-
-    static const WCHAR cszTempFolder[]= {
-       'T','e','m','p','F','o','l','d','e','r',0};
-
-    rc = read_raw_stream_data(package->db, stream, &data, &size);
-    if (rc != ERROR_SUCCESS)
-        return rc;
-
-    write = MAX_PATH;
-    if (MSI_GetPropertyW(package, cszTempFolder, tmp, &write))
-        GetTempPathW(MAX_PATH, tmp);
-
-    GetTempFileNameW(tmp, stream, 0, source);
-
-    track_tempfile(package, source);
-    hfile = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
-                        FILE_ATTRIBUTE_NORMAL, NULL);
-
-    if (hfile == INVALID_HANDLE_VALUE)
-    {
-        ERR("Unable to create file %s\n", debugstr_w(source));
-        rc = ERROR_FUNCTION_FAILED;
-        goto end;
-    }
-
-    WriteFile(hfile, data, size, &write, NULL);
-    CloseHandle(hfile);
-    TRACE("wrote %i bytes to %s\n", write, debugstr_w(source));
-
-end:
-    msi_free(data);
-    return rc;
-}
-
 static void * CDECL cabinet_alloc(ULONG cb)
 {
     return msi_alloc(cb);
@@ -238,10 +198,72 @@ static LONG CDECL cabinet_seek(INT_PTR hf, LONG dist, int seektype)
     return SetFilePointer(handle, dist, NULL, seektype);
 }
 
+struct cab_stream
+{
+    MSIDATABASE *db;
+    WCHAR       *name;
+};
+
+static struct cab_stream cab_stream;
+
+static INT_PTR CDECL cabinet_open_stream( char *pszFile, int oflag, int pmode )
+{
+    UINT r;
+    IStream *stm;
+
+    if (oflag)
+        WARN("ignoring open flags 0x%08x\n", oflag);
+
+    r = db_get_raw_stream( cab_stream.db, cab_stream.name, &stm );
+    if (r != ERROR_SUCCESS)
+    {
+        WARN("Failed to get cabinet stream %u\n", r);
+        return 0;
+    }
+
+    return (INT_PTR)stm;
+}
+
+static UINT CDECL cabinet_read_stream( INT_PTR hf, void *pv, UINT cb )
+{
+    IStream *stm = (IStream *)hf;
+    DWORD read;
+    HRESULT hr;
+
+    hr = IStream_Read( stm, pv, cb, &read );
+    if (hr == S_OK || hr == S_FALSE)
+        return read;
+
+    return 0;
+}
+
+static int CDECL cabinet_close_stream( INT_PTR hf )
+{
+    IStream *stm = (IStream *)hf;
+    IStream_Release( stm );
+    return 0;
+}
+
+static LONG CDECL cabinet_seek_stream( INT_PTR hf, LONG dist, int seektype )
+{
+    IStream *stm = (IStream *)hf;
+    LARGE_INTEGER move;
+    ULARGE_INTEGER newpos;
+    HRESULT hr;
+
+    move.QuadPart = dist;
+    hr = IStream_Seek( stm, move, seektype, &newpos );
+    if (SUCCEEDED(hr))
+    {
+        if (newpos.QuadPart <= MAXLONG) return newpos.QuadPart;
+        ERR("Too big!\n");
+    }
+    return -1;
+}
+
 static UINT CDECL msi_media_get_disk_info(MSIPACKAGE *package, MSIMEDIAINFO *mi)
 {
     MSIRECORD *row;
-    LPWSTR ptr;
 
     static const WCHAR query[] = {
         'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
@@ -262,10 +284,7 @@ static UINT CDECL msi_media_get_disk_info(MSIPACKAGE *package, MSIMEDIAINFO *mi)
     if (!mi->first_volume)
         mi->first_volume = strdupW(mi->volume_label);
 
-    ptr = strrchrW(mi->source, '\\') + 1;
-    lstrcpyW(ptr, mi->cabinet);
     msiobj_release(&row->hdr);
-
     return ERROR_SUCCESS;
 }
 
@@ -277,12 +296,24 @@ static INT_PTR cabinet_partial_file(FDINOTIFICATIONTYPE fdint,
     return 0;
 }
 
+static WCHAR *get_cabinet_filename(MSIMEDIAINFO *mi)
+{
+    int len;
+    WCHAR *ret;
+
+    len = strlenW(mi->sourcedir) + strlenW(mi->cabinet) + 1;
+    if (!(ret = msi_alloc(len * sizeof(WCHAR)))) return NULL;
+    strcpyW(ret, mi->sourcedir);
+    strcatW(ret, mi->cabinet);
+    return ret;
+}
+
 static INT_PTR cabinet_next_cabinet(FDINOTIFICATIONTYPE fdint,
                                     PFDINOTIFICATION pfdin)
 {
     MSICABDATA *data = pfdin->pv;
     MSIMEDIAINFO *mi = data->mi;
-    LPWSTR cab = strdupAtoW(pfdin->psz1);
+    LPWSTR cabinet_file = NULL, cab = strdupAtoW(pfdin->psz1);
     INT_PTR res = -1;
     UINT rc;
 
@@ -309,10 +340,13 @@ static INT_PTR cabinet_next_cabinet(FDINOTIFICATIONTYPE fdint,
         goto done;
     }
 
-    TRACE("Searching for %s\n", debugstr_w(mi->source));
+    if (!(cabinet_file = get_cabinet_filename(mi)))
+        goto done;
+
+    TRACE("Searching for %s\n", debugstr_w(cabinet_file));
 
     res = 0;
-    if (GetFileAttributesW(mi->source) == INVALID_FILE_ATTRIBUTES)
+    if (GetFileAttributesW(cabinet_file) == INVALID_FILE_ATTRIBUTES)
     {
         if (msi_change_media(data->package, mi) != ERROR_SUCCESS)
             res = -1;
@@ -320,6 +354,7 @@ static INT_PTR cabinet_next_cabinet(FDINOTIFICATIONTYPE fdint,
 
 done:
     msi_free(cab);
+    msi_free(cabinet_file);
     return res;
 }
 
@@ -376,7 +411,7 @@ static INT_PTR cabinet_copy_file(FDINOTIFICATIONTYPE fdint,
 
             GetTempFileNameW(szBackSlash, szMsi, 0, tmpfileW);
             len = strlenW(path) + strlenW(tmpfileW) + 1;
-            if (!(tmppathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
+            if (!(tmppathW = msi_alloc(len * sizeof(WCHAR))))
                 return ERROR_OUTOFMEMORY;
 
             strcpyW(tmppathW, path);
@@ -394,7 +429,7 @@ static INT_PTR cabinet_copy_file(FDINOTIFICATIONTYPE fdint,
             else
                 WARN("failed to schedule rename operation %s (error %d)\n", debugstr_w(path), GetLastError());
 
-            HeapFree(GetProcessHeap(), 0, tmppathW);
+            msi_free(tmppathW);
         }
         else
             WARN("failed to create %s (error %d)\n", debugstr_w(path), err);
@@ -436,8 +471,6 @@ static INT_PTR cabinet_close_file_info(FDINOTIFICATIONTYPE fdint,
 
 static INT_PTR CDECL cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
 {
-    TRACE("(%d)\n", fdint);
-
     switch (fdint)
     {
     case fdintPARTIAL_FILE:
@@ -457,48 +490,94 @@ static INT_PTR CDECL cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION
     }
 }
 
-/***********************************************************************
- *            msi_cabextract
- *
- * Extract files from a cab file.
- */
-BOOL msi_cabextract(MSIPACKAGE* package, MSIMEDIAINFO *mi, LPVOID data)
+static INT_PTR CDECL cabinet_notify_stream( FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin )
+{
+    switch (fdint)
+    {
+    case fdintCOPY_FILE:
+        return cabinet_copy_file( fdint, pfdin );
+
+    case fdintCLOSE_FILE_INFO:
+        return cabinet_close_file_info( fdint, pfdin );
+
+    case fdintCABINET_INFO:
+        return 0;
+
+    default:
+        ERR("Unexpected notification %d\n", fdint);
+        return 0;
+    }
+}
+
+static BOOL extract_cabinet( MSIPACKAGE* package, MSIMEDIAINFO *mi, LPVOID data )
 {
     LPSTR cabinet, cab_path = NULL;
-    LPWSTR ptr;
     HFDI hfdi;
     ERF erf;
     BOOL ret = FALSE;
 
-    TRACE("Extracting %s\n", debugstr_w(mi->source));
+    TRACE("Extracting %s\n", debugstr_w(mi->cabinet));
 
-    hfdi = FDICreate(cabinet_alloc, cabinet_free, cabinet_open, cabinet_read,
-                     cabinet_write, cabinet_close, cabinet_seek, 0, &erf);
+    hfdi = FDICreate( cabinet_alloc, cabinet_free, cabinet_open, cabinet_read,
+                      cabinet_write, cabinet_close, cabinet_seek, 0, &erf );
     if (!hfdi)
     {
         ERR("FDICreate failed\n");
         return FALSE;
     }
 
-    ptr = strrchrW(mi->source, '\\') + 1;
-    cabinet = strdupWtoA(ptr);
+    cabinet = strdupWtoA( mi->cabinet );
     if (!cabinet)
         goto done;
 
-    cab_path = strdupWtoA(mi->source);
+    cab_path = strdupWtoA( mi->sourcedir );
     if (!cab_path)
         goto done;
 
-    cab_path[ptr - mi->source] = '\0';
+    ret = FDICopy( hfdi, cabinet, cab_path, 0, cabinet_notify, NULL, data );
+    if (!ret)
+        ERR("FDICopy failed\n");
+
+done:
+    FDIDestroy( hfdi );
+    msi_free(cabinet );
+    msi_free( cab_path );
+
+    if (ret)
+        mi->is_extracted = TRUE;
 
-    ret = FDICopy(hfdi, cabinet, cab_path, 0, cabinet_notify, NULL, data);
+    return ret;
+}
+
+static BOOL extract_cabinet_stream( MSIPACKAGE *package, MSIMEDIAINFO *mi, LPVOID data )
+{
+    static char filename[] = {'<','S','T','R','E','A','M','>',0};
+    HFDI hfdi;
+    ERF erf;
+    BOOL ret = FALSE;
+
+    TRACE("Extracting %s\n", debugstr_w(mi->cabinet));
+
+    hfdi = FDICreate( cabinet_alloc, cabinet_free, cabinet_open_stream, cabinet_read_stream,
+                      cabinet_write, cabinet_close_stream, cabinet_seek_stream, 0, &erf );
+    if (!hfdi)
+    {
+        ERR("FDICreate failed\n");
+        return FALSE;
+    }
+
+    cab_stream.db = package->db;
+    cab_stream.name = encode_streamname( FALSE, mi->cabinet + 1 );
+    if (!cab_stream.name)
+        goto done;
+
+    ret = FDICopy( hfdi, filename, NULL, 0, cabinet_notify_stream, NULL, data );
     if (!ret)
         ERR("FDICopy failed\n");
 
 done:
-    FDIDestroy(hfdi);
-    msi_free(cabinet);
-    msi_free(cab_path);
+    FDIDestroy( hfdi );
+    msi_free( cab_stream.name );
 
     if (ret)
         mi->is_extracted = TRUE;
@@ -506,6 +585,20 @@ done:
     return ret;
 }
 
+/***********************************************************************
+ *            msi_cabextract
+ *
+ * Extract files from a cabinet file or stream.
+ */
+BOOL msi_cabextract(MSIPACKAGE* package, MSIMEDIAINFO *mi, LPVOID data)
+{
+    if (mi->cabinet[0] == '#')
+    {
+        return extract_cabinet_stream( package, mi, data );
+    }
+    return extract_cabinet( package, mi, data );
+}
+
 void msi_free_media_info(MSIMEDIAINFO *mi)
 {
     msi_free(mi->disk_prompt);
@@ -532,7 +625,6 @@ static UINT msi_load_media_info(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO
     LPWSTR source_dir;
     LPWSTR source;
     DWORD options;
-    UINT r;
 
     static const WCHAR query[] = {
         'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
@@ -563,25 +655,10 @@ static UINT msi_load_media_info(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO
     if (!mi->first_volume)
         mi->first_volume = strdupW(mi->volume_label);
 
-    source_dir = msi_dup_property(package, cszSourceDir);
-    lstrcpyW(mi->source, source_dir);
+    source_dir = msi_dup_property(package->db, cszSourceDir);
+    lstrcpyW(mi->sourcedir, source_dir);
     mi->type = get_drive_type(source_dir);
 
-    if (file->IsCompressed && mi->cabinet)
-    {
-        if (mi->cabinet[0] == '#')
-        {
-            r = writeout_cabinet_stream(package, &mi->cabinet[1], mi->source);
-            if (r != ERROR_SUCCESS)
-            {
-                ERR("Failed to extract cabinet stream\n");
-                return ERROR_FUNCTION_FAILED;
-            }
-        }
-        else
-            lstrcatW(mi->source, mi->cabinet);
-    }
-
     options = MSICODE_PRODUCT;
     if (mi->type == DRIVE_CDROM || mi->type == DRIVE_REMOVABLE)
     {
@@ -595,7 +672,7 @@ static UINT msi_load_media_info(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO
     }
     else
     {
-        source = mi->source;
+        source = mi->sourcedir;
         options |= MSISOURCETYPE_NETWORK;
     }
 
@@ -610,7 +687,7 @@ static UINT msi_load_media_info(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO
     return ERROR_SUCCESS;
 }
 
-/* FIXME: search NETWORK and URL sources as well */
+/* FIXME: search URL sources as well */
 static UINT find_published_source(MSIPACKAGE *package, MSIMEDIAINFO *mi)
 {
     WCHAR source[MAX_PATH];
@@ -618,8 +695,16 @@ static UINT find_published_source(MSIPACKAGE *package, MSIMEDIAINFO *mi)
     WCHAR prompt[MAX_PATH];
     DWORD volumesz, promptsz;
     DWORD index, size, id;
+    WCHAR last_type[2];
     UINT r;
 
+    size = 2;
+    r = MsiSourceListGetInfoW(package->ProductCode, NULL,
+                              package->Context, MSICODE_PRODUCT,
+                              INSTALLPROPERTY_LASTUSEDTYPEW, last_type, &size);
+    if (r != ERROR_SUCCESS)
+        return r;
+
     size = MAX_PATH;
     r = MsiSourceListGetInfoW(package->ProductCode, NULL,
                               package->Context, MSICODE_PRODUCT,
@@ -627,6 +712,26 @@ static UINT find_published_source(MSIPACKAGE *package, MSIMEDIAINFO *mi)
     if (r != ERROR_SUCCESS)
         return r;
 
+    index = 0;
+    volumesz = MAX_PATH;
+    promptsz = MAX_PATH;
+
+    if (last_type[0] == 'n')
+    {
+        while (MsiSourceListEnumSourcesW(package->ProductCode, NULL,
+                                        package->Context,
+                                        MSISOURCETYPE_NETWORK, index++,
+                                        volume, &volumesz) == ERROR_SUCCESS)
+        {
+            if (!strncmpiW(source, volume, strlenW(source)))
+            {
+                lstrcpyW(mi->sourcedir, source);
+                TRACE("Found network source %s\n", debugstr_w(mi->sourcedir));
+                return ERROR_SUCCESS;
+            }
+        }
+    }
+
     index = 0;
     volumesz = MAX_PATH;
     promptsz = MAX_PATH;
@@ -644,7 +749,8 @@ static UINT find_published_source(MSIPACKAGE *package, MSIMEDIAINFO *mi)
         if (source_matches_volume(mi, source))
         {
             /* FIXME: what about SourceDir */
-            lstrcpyW(mi->source, source);
+            lstrcpyW(mi->sourcedir, source);
+            TRACE("Found disk source %s\n", debugstr_w(mi->sourcedir));
             return ERROR_SUCCESS;
         }
     }
@@ -655,6 +761,7 @@ static UINT find_published_source(MSIPACKAGE *package, MSIMEDIAINFO *mi)
 UINT ready_media(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO *mi)
 {
     UINT rc = ERROR_SUCCESS;
+    WCHAR *cabinet_file;
 
     /* media info for continuous cabinet is already loaded */
     if (mi->is_continuous)
@@ -663,7 +770,7 @@ UINT ready_media(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO *mi)
     rc = msi_load_media_info(package, file, mi);
     if (rc != ERROR_SUCCESS)
     {
-        ERR("Unable to load media info\n");
+        ERR("Unable to load media info %u\n", rc);
         return ERROR_FUNCTION_FAILED;
     }
 
@@ -671,15 +778,24 @@ UINT ready_media(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO *mi)
     if (!mi->cabinet || mi->cabinet[0] == '#')
         return ERROR_SUCCESS;
 
+    cabinet_file = get_cabinet_filename(mi);
+
     /* package should be downloaded */
     if (file->IsCompressed &&
-        GetFileAttributesW(mi->source) == INVALID_FILE_ATTRIBUTES &&
+        GetFileAttributesW(cabinet_file) == INVALID_FILE_ATTRIBUTES &&
         package->BaseURL && UrlIsW(package->BaseURL, URLIS_URL))
     {
-        WCHAR temppath[MAX_PATH];
+        WCHAR temppath[MAX_PATH], *p;
 
-        msi_download_file(mi->source, temppath);
-        lstrcpyW(mi->source, temppath);
+        msi_download_file(cabinet_file, temppath);
+        if ((p = strrchrW(temppath, '\\'))) *p = 0;
+
+        msi_free(mi->sourcedir);
+        strcpyW(mi->sourcedir, temppath);
+        msi_free(mi->cabinet);
+        strcpyW(mi->cabinet, p + 1);
+
+        msi_free(cabinet_file);
         return ERROR_SUCCESS;
     }
 
@@ -687,7 +803,7 @@ UINT ready_media(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO *mi)
     if (mi->volume_label && mi->disk_id > 1 &&
         lstrcmpW(mi->first_volume, mi->volume_label))
     {
-        LPWSTR source = msi_dup_property(package, cszSourceDir);
+        LPWSTR source = msi_dup_property(package->db, cszSourceDir);
         BOOL matches;
 
         matches = source_matches_volume(mi, source);
@@ -697,20 +813,25 @@ UINT ready_media(MSIPACKAGE *package, MSIFILE *file, MSIMEDIAINFO *mi)
         {
             rc = msi_change_media(package, mi);
             if (rc != ERROR_SUCCESS)
+            {
+                msi_free(cabinet_file);
                 return rc;
+            }
         }
     }
 
     if (file->IsCompressed &&
-        GetFileAttributesW(mi->source) == INVALID_FILE_ATTRIBUTES)
+        GetFileAttributesW(cabinet_file) == INVALID_FILE_ATTRIBUTES)
     {
         rc = find_published_source(package, mi);
         if (rc != ERROR_SUCCESS)
         {
-            ERR("Cabinet not found: %s\n", debugstr_w(mi->source));
+            ERR("Cabinet not found: %s\n", debugstr_w(cabinet_file));
+            msi_free(cabinet_file);
             return ERROR_INSTALL_FAILURE;
         }
     }
 
+    msi_free(cabinet_file);
     return ERROR_SUCCESS;
 }
index 0735640..9d8a88a 100644 (file)
@@ -305,9 +305,8 @@ static UINT MSI_ApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szProductCode, LPCWS
     UINT r = ERROR_SUCCESS, type;
     DWORD size = 0;
     LPCWSTR cmd_ptr = szCommandLine;
-    LPCWSTR product_code = szProductCode;
-    LPWSTR beg, end;
-    LPWSTR cmd = NULL, codes = NULL;
+    LPWSTR beg, end, cmd = NULL, codes = NULL;
+    BOOL succeeded = FALSE;
 
     static const WCHAR patcheq[] = {'P','A','T','C','H','=',0};
     static WCHAR empty[] = {0};
@@ -342,8 +341,6 @@ static UINT MSI_ApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szProductCode, LPCWS
         r = MsiSummaryInfoGetPropertyW(info, PID_TEMPLATE, &type, NULL, NULL, codes, &size);
         if (r != ERROR_SUCCESS)
             goto done;
-
-        product_code = codes;
     }
 
     if (!szCommandLine)
@@ -362,16 +359,25 @@ static UINT MSI_ApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szProductCode, LPCWS
     lstrcatW(cmd, patcheq);
     lstrcatW(cmd, szPatchPackage);
 
-    beg = codes;
-    while ((end = strchrW(beg, '}')))
+    if (szProductCode)
+        r = MsiConfigureProductExW(szProductCode, INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, cmd);
+    else
     {
-        *(end + 1) = '\0';
-
-        r = MsiConfigureProductExW(beg, INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, cmd);
-        if (r != ERROR_SUCCESS)
-            goto done;
+        beg = codes;
+        while ((end = strchrW(beg, '}')))
+        {
+            *(end + 1) = '\0';
+            r = MsiConfigureProductExW(beg, INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, cmd);
+            if (r == ERROR_SUCCESS)
+            {
+                TRACE("patch applied\n");
+                succeeded = TRUE;
+            }
+            beg = end + 2;
+        }
 
-        beg = end + 2;
+        if (succeeded)
+            r = ERROR_SUCCESS;
     }
 
 done:
@@ -480,10 +486,43 @@ UINT WINAPI MsiApplyMultiplePatchesW(LPCWSTR szPatchPackages,
 UINT WINAPI MsiDetermineApplicablePatchesA(LPCSTR szProductPackagePath,
         DWORD cPatchInfo, PMSIPATCHSEQUENCEINFOA pPatchInfo)
 {
-    FIXME("(%s, %d, %p): stub!\n", debugstr_a(szProductPackagePath),
-          cPatchInfo, pPatchInfo);
+    UINT i, r;
+    WCHAR *package_path = NULL;
+    MSIPATCHSEQUENCEINFOW *psi;
 
-    return ERROR_CALL_NOT_IMPLEMENTED;
+    TRACE("(%s, %d, %p)\n", debugstr_a(szProductPackagePath), cPatchInfo, pPatchInfo);
+
+    if (szProductPackagePath && !(package_path = strdupAtoW( szProductPackagePath )))
+        return ERROR_OUTOFMEMORY;
+
+    psi = msi_alloc( cPatchInfo * sizeof(*psi) );
+    if (!psi)
+    {
+        msi_free( package_path );
+        return ERROR_OUTOFMEMORY;
+    }
+
+    for (i = 0; i < cPatchInfo; i++)
+    {
+        psi[i].szPatchData = strdupAtoW( pPatchInfo[i].szPatchData );
+        psi[i].ePatchDataType = pPatchInfo[i].ePatchDataType;
+    }
+
+    r = MsiDetermineApplicablePatchesW( package_path, cPatchInfo, psi );
+    if (r == ERROR_SUCCESS)
+    {
+        for (i = 0; i < cPatchInfo; i++)
+        {
+            pPatchInfo[i].dwOrder = psi[i].dwOrder;
+            pPatchInfo[i].uStatus = psi[i].uStatus;
+        }
+    }
+
+    msi_free( package_path );
+    for (i = 0; i < cPatchInfo; i++)
+        msi_free( (WCHAR *)psi[i].szPatchData );
+    msi_free( psi );
+    return r;
 }
 
 static UINT MSI_ApplicablePatchW( MSIPACKAGE *package, LPCWSTR patch )
@@ -502,15 +541,14 @@ static UINT MSI_ApplicablePatchW( MSIPACKAGE *package, LPCWSTR patch )
     si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
     if (!si)
     {
-        r = ERROR_FUNCTION_FAILED;
-        goto done;
+        msiobj_release( &patch_db->hdr );
+        return ERROR_FUNCTION_FAILED;
     }
 
     r = msi_check_patch_applicable( package, si );
     if (r != ERROR_SUCCESS)
         TRACE("patch not applicable\n");
 
-done:
     msiobj_release( &patch_db->hdr );
     msiobj_release( &si->hdr );
     return r;
@@ -596,10 +634,6 @@ static UINT msi_open_package(LPCWSTR product, MSIINSTALLCONTEXT context,
     WCHAR sourcepath[MAX_PATH];
     WCHAR filename[MAX_PATH];
 
-    static const WCHAR szLocalPackage[] = {
-        'L','o','c','a','l','P','a','c','k','a','g','e',0};
-
-
     r = MSIREG_OpenInstallProps(product, context, NULL, &props, FALSE);
     if (r != ERROR_SUCCESS)
         return ERROR_BAD_CONFIGURATION;
@@ -1181,7 +1215,7 @@ done:
 
 static UINT msi_copy_outval(LPWSTR val, LPWSTR out, LPDWORD size)
 {
-    UINT r;
+    UINT r = ERROR_SUCCESS;
 
     if (!val)
         return ERROR_UNKNOWN_PROPERTY;
@@ -1201,7 +1235,7 @@ static UINT msi_copy_outval(LPWSTR val, LPWSTR out, LPDWORD size)
     if (size)
         *size = lstrlenW(val);
 
-    return ERROR_SUCCESS;
+    return r;
 }
 
 UINT WINAPI MsiGetProductInfoExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
@@ -2149,6 +2183,22 @@ UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uT
     return MessageBoxExW(hWnd,lpText,lpCaption,uType,wLanguageId); 
 }
 
+UINT WINAPI MsiMessageBoxExA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType,
+                DWORD unknown, WORD wLanguageId, DWORD f)
+{
+    FIXME("(%p, %s, %s, %u, 0x%08x, 0x%08x, 0x%08x): semi-stub\n", hWnd, debugstr_a(lpText),
+            debugstr_a(lpCaption), uType, unknown, wLanguageId, f);
+    return MessageBoxExA(hWnd, lpText, lpCaption, uType, wLanguageId);
+}
+
+UINT WINAPI MsiMessageBoxExW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
+                DWORD unknown, WORD wLanguageId, DWORD f)
+{
+    FIXME("(%p, %s, %s, %u, 0x%08x, 0x%08x, 0x%08x): semi-stub\n", hWnd, debugstr_w(lpText),
+            debugstr_w(lpCaption), uType, unknown, wLanguageId, f);
+    return MessageBoxExW(hWnd, lpText, lpCaption, uType, wLanguageId);
+}
+
 UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext,
                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf,
                 LPDWORD pcchPathBuf )
@@ -2337,6 +2387,7 @@ done:
         r = ERROR_SUCCESS;
     }
 
+    msiobj_release(&package->hdr);
     return r;
 }
 
@@ -3519,10 +3570,10 @@ UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
     if (r != ERROR_SUCCESS)
         return r;
 
-    MSI_SetPropertyW( package, szReinstallMode, reinstallmode );
-    MSI_SetPropertyW( package, szInstalled, szOne );
-    MSI_SetPropertyW( package, szLogVerbose, szOne );
-    MSI_SetPropertyW( package, szReinstall, szFeature );
+    msi_set_property( package->db, szReinstallMode, reinstallmode );
+    msi_set_property( package->db, szInstalled, szOne );
+    msi_set_property( package->db, szLogVerbose, szOne );
+    msi_set_property( package->db, szReinstall, szFeature );
 
     r = MSI_InstallPackage( package, sourcepath, NULL );
 
index 30daec9..94e3ed3 100644 (file)
 276 stub MsiSourceListClearMediaDiskW
 277 stdcall MsiDetermineApplicablePatchesA(str long ptr)
 278 stdcall MsiDetermineApplicablePatchesW(wstr long ptr)
-279 stub MsiMessageBoxExA
-280 stub MsiMessageBoxExW
+279 stdcall MsiMessageBoxExA(long str str long long long long)
+280 stdcall MsiMessageBoxExW(long wstr wstr long long long long)
 281 stdcall MsiSetExternalUIRecord(ptr long ptr ptr)
 
 @ stdcall -private DllCanUnloadNow()
index d3b8ca8..8aea169 100644 (file)
@@ -27,7 +27,33 @@ STRINGTABLE DISCARDABLE
        4 "The specified installation package could not be opened.  Please check the file path and try again."
        5 "ïúòÿò %s íå å íàìåðåí"
        9 "ïîñòàâåòå äèñê %s"
-       10 "íåêîðåêòíè ïàðàìåòðè"
+       10 "Windows Installer %s\n\n" \
+       "Usage:\n" \
+       "msiexec command {required parameter} [optional parammeter]\n\n" \
+       "Install a product:\n" \
+       "\t/i {package|productcode} [property]\n" \
+       "\t/package {package|productcode} [property]\n" \
+       "\t/a package [property]\n" \
+       "Repair an installation:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n" \
+       "Uninstall a product:\n" \
+       "\t/uninstall {package|productcode} [property]\n" \
+       "\t/x {package|productcode} [property]\n" \
+       "Advertise a product:\n" \
+       "\t/j[u|m] package [/t transform] [/g languageid]\n" \
+       "Apply a patch:\n" \
+       "\t/p patchpackage [property]\n" \
+       "\t/p patchpackage /a package [property]\n" \
+       "Log and UI Modifiers for above commands:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Register MSI Service:\n" \
+       "\t/y\n" \
+       "Unregister MSI Service:\n" \
+       "\t/z\n" \
+       "Display this help:\n" \
+       "\t/help\n" \
+       "\t/?\n"
        11 "âúâåäåòå ïàïêàòà, êîÿòî ñúäúðæà %s"
        12 "èçòî÷íèêà çà èíñòàëàöèÿ íà ôóíêöèîíàëíîñòòà ëèïñâà"
        13 "ìðåæîâîòî óñòðîéñòâà íóæíî çà ôóíêöèîíàëíîñòòà ëèïñâà "
index beee427..fa7e1c4 100644 (file)
@@ -27,7 +27,33 @@ STRINGTABLE DISCARDABLE
        4 "Kunne ikke åbne den specificerede installationspakke. Kontroller stien og prøv igen."
        5 "kunne ikke finden stien '%s'."
        9 "indsæt disk '%s'"
-       10 "forkerte parametere."
+       10 "Windows Installer %s\n\n" \
+       "Usage:\n" \
+       "msiexec command {required parameter} [optional parammeter]\n\n" \
+       "Install a product:\n" \
+       "\t/i {package|productcode} [property]\n" \
+       "\t/package {package|productcode} [property]\n" \
+       "\t/a package [property]\n" \
+       "Repair an installation:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n" \
+       "Uninstall a product:\n" \
+       "\t/uninstall {package|productcode} [property]\n" \
+       "\t/x {package|productcode} [property]\n" \
+       "Advertise a product:\n" \
+       "\t/j[u|m] package [/t transform] [/g languageid]\n" \
+       "Apply a patch:\n" \
+       "\t/p patchpackage [property]\n" \
+       "\t/p patchpackage /a package [property]\n" \
+       "Log and UI Modifiers for above commands:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Register MSI Service:\n" \
+       "\t/y\n" \
+       "Unregister MSI Service:\n" \
+       "\t/z\n" \
+       "Display this help:\n" \
+       "\t/help\n" \
+       "\t/?\n"
        11 "angiv kataloget som indeholder '%s'."
        12 "featurens installationskilde mangler."
         13 "featurens netværksdrev mangler."
index e0cccf0..e07b5ef 100644 (file)
@@ -2,6 +2,7 @@
  * German resources for MSI
  *
  * Copyright 2005 Henning Gerhardt
+ * Copyright 2010 Detlef Riekenberg
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -29,7 +30,33 @@ STRINGTABLE DISCARDABLE
        4 "Das angegebene Installationspaket konnte nicht geöffnet werden. Bitte überprüfen Sie den Pfadnamen und versuchen Sie es noch einmal."
        5 "Der Pfad %s wurde nicht gefunden."
        9 "Bitte Disk %s einlegen."
-       10 "Falsche Parameter"
+       10 "Windows Installer %s\n\n" \
+       "Benutzung:\n" \
+       "msiexec Befehl {Parameter} [Zusätzliche Parammeter]\n\n" \
+       "Produkt installieren:\n" \
+       "\t/i {Paket|Produktcode} [Eigenschaft]\n" \
+       "\t/package {Paket|Produktcode} [Eigenschaft]\n" \
+       "\t/a Paket [Eigenschaft]\n" \
+       "Installation reparieren:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {Paket|Produktcode}\n" \
+       "Produkt deinstallieren:\n" \
+       "\t/uninstall {Paket|Produktcode} [Eigenschaft]\n" \
+       "\t/x {Paket|Produktcode} [Eigenschaft]\n" \
+       "Produkt ankündigen:\n" \
+       "\t/j[u|m] Paket [/t Transformationspaket] [/g Sprachkennung]\n" \
+       "Patch integrieren:\n" \
+       "\t/p Patchpaket [Eigenschaft]\n" \
+       "\t/p Patchpaket /a Paket [Eigenschaft]\n" \
+       "Protokollierung und Benutzeroberfläche für die oberen Befehle anpassen:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] Protokolldatei\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "MSI Service registrieren:\n" \
+       "\t/y\n" \
+       "Registrierung des MSI Service aufheben:\n" \
+       "\t/z\n" \
+       "Hilfe anzeigen:\n" \
+       "\t/help\n" \
+       "\t/?\n"
        11 "Geben Sie das Verzeichnis ein, dass %s enthält."
        12 "Die Installationsquelle für das Feature fehlt."
        13 "Das Netzwerklaufwerk für das Feature fehlt."
index 74fc5c1..c506e00 100644 (file)
@@ -2,6 +2,7 @@
  * English resources for MSI
  *
  * Copyright 2005 Mike McCormack
+ * Copyright 2010 Detlef Riekenberg
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -27,7 +28,33 @@ STRINGTABLE DISCARDABLE
        4 "The specified installation package could not be opened.  Please check the file path and try again."
        5 "path %s not found"
        9 "insert disk %s"
-       10 "bad parameters"
+       10 "Windows Installer %s\n\n" \
+       "Usage:\n" \
+       "msiexec command {required parameter} [optional parameter]\n\n" \
+       "Install a product:\n" \
+       "\t/i {package|productcode} [property]\n" \
+       "\t/package {package|productcode} [property]\n" \
+       "\t/a package [property]\n" \
+       "Repair an installation:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n" \
+       "Uninstall a product:\n" \
+       "\t/uninstall {package|productcode} [property]\n" \
+       "\t/x {package|productcode} [property]\n" \
+       "Advertise a product:\n" \
+       "\t/j[u|m] package [/t transform] [/g languageid]\n" \
+       "Apply a patch:\n" \
+       "\t/p patchpackage [property]\n" \
+       "\t/p patchpackage /a package [property]\n" \
+       "Log and UI Modifiers for above commands:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Register MSI Service:\n" \
+       "\t/y\n" \
+       "Unregister MSI Service:\n" \
+       "\t/z\n" \
+       "Display this help:\n" \
+       "\t/help\n" \
+       "\t/?\n"
        11 "enter which folder contains %s"
        12 "install source for feature missing"
        13 "network drive for feature missing"
index 7579bdc..8b8c8d3 100644 (file)
@@ -27,7 +27,33 @@ STRINGTABLE DISCARDABLE
        4 "The specified installation package could not be opened.  Please check the file path and try again."
        5 "Mi ne trovis la vojon %s"
        9 "enþovu la diskon %s"
-       10 "nekorektaj parametroj"
+       10 "Windows Installer %s\n\n" \
+       "Usage:\n" \
+       "msiexec command {required parameter} [optional parammeter]\n\n" \
+       "Install a product:\n" \
+       "\t/i {package|productcode} [property]\n" \
+       "\t/package {package|productcode} [property]\n" \
+       "\t/a package [property]\n" \
+       "Repair an installation:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n" \
+       "Uninstall a product:\n" \
+       "\t/uninstall {package|productcode} [property]\n" \
+       "\t/x {package|productcode} [property]\n" \
+       "Advertise a product:\n" \
+       "\t/j[u|m] package [/t transform] [/g languageid]\n" \
+       "Apply a patch:\n" \
+       "\t/p patchpackage [property]\n" \
+       "\t/p patchpackage /a package [property]\n" \
+       "Log and UI Modifiers for above commands:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Register MSI Service:\n" \
+       "\t/y\n" \
+       "Unregister MSI Service:\n" \
+       "\t/z\n" \
+       "Display this help:\n" \
+       "\t/help\n" \
+       "\t/?\n"
        11 "enigu la nomon de dosierujo kiu enhavas %s"
        12 "instalad-fonto por mankanta taýgeco"
        13 "retdrajvo por mankanta taýgeco"
index 781be07..f5425db 100644 (file)
@@ -27,7 +27,33 @@ STRINGTABLE DISCARDABLE
        4 "No se ha podido abrir el paquete de instalación especificado. Por favor, compruebe la ruta del archivo y vuelva a intentarlo."
        5 "ruta %s no encontrada"
        9 "inserte el disco %s"
-       10 "parámetros incorrectos"
+       10 "Windows Installer %s\n\n" \
+       "Usage:\n" \
+       "msiexec command {required parameter} [optional parammeter]\n\n" \
+       "Install a product:\n" \
+       "\t/i {package|productcode} [property]\n" \
+       "\t/package {package|productcode} [property]\n" \
+       "\t/a package [property]\n" \
+       "Repair an installation:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n" \
+       "Uninstall a product:\n" \
+       "\t/uninstall {package|productcode} [property]\n" \
+       "\t/x {package|productcode} [property]\n" \
+       "Advertise a product:\n" \
+       "\t/j[u|m] package [/t transform] [/g languageid]\n" \
+       "Apply a patch:\n" \
+       "\t/p patchpackage [property]\n" \
+       "\t/p patchpackage /a package [property]\n" \
+       "Log and UI Modifiers for above commands:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Register MSI Service:\n" \
+       "\t/y\n" \
+       "Unregister MSI Service:\n" \
+       "\t/z\n" \
+       "Display this help:\n" \
+       "\t/help\n" \
+       "\t/?\n"
        11 "introduzca qué carpeta contiene %s"
        12 "instalar fuente para característica ausente"
        13 "unidad de red para característica ausente"
index 17721aa..f3d58bf 100644 (file)
@@ -27,7 +27,33 @@ STRINGTABLE DISCARDABLE
        4 "The specified installation package could not be opened.  Please check the file path and try again."
        5 "Polkua %s ei löydy."
        9 "Anna levy %s"
-       10 "Virheelliset parametrit."
+       10 "Windows Installer %s\n\n" \
+       "Usage:\n" \
+       "msiexec command {required parameter} [optional parammeter]\n\n" \
+       "Install a product:\n" \
+       "\t/i {package|productcode} [property]\n" \
+       "\t/package {package|productcode} [property]\n" \
+       "\t/a package [property]\n" \
+       "Repair an installation:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n" \
+       "Uninstall a product:\n" \
+       "\t/uninstall {package|productcode} [property]\n" \
+       "\t/x {package|productcode} [property]\n" \
+       "Advertise a product:\n" \
+       "\t/j[u|m] package [/t transform] [/g languageid]\n" \
+       "Apply a patch:\n" \
+       "\t/p patchpackage [property]\n" \
+       "\t/p patchpackage /a package [property]\n" \
+       "Log and UI Modifiers for above commands:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Register MSI Service:\n" \
+       "\t/y\n" \
+       "Unregister MSI Service:\n" \
+       "\t/z\n" \
+       "Display this help:\n" \
+       "\t/help\n" \
+       "\t/?\n"
        11 "Anna kansio, joka sisältää %s"
        12 "Ominaisuuden asennuslähde puuttuu."
        13 "Ominaisuuden verkkolevy puuttuu."
index f7f7338..6cd1fc5 100644 (file)
@@ -2,6 +2,7 @@
  * French resources for MSI
  *
  * Copyright 2005 Jonathan Ernst
+ * Copyright 2009-2010 Frédéric Delanoy
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -30,7 +31,33 @@ STRINGTABLE DISCARDABLE
        4 "Le paquet d'installation spécifié n'a pu être ouvert. Veuillez vérifier le chemin du fichier et réessayer."
        5 "Le chemin %s est introuvable"
        9 "insérez le disque %s"
-       10 "mauvais paramètres"
+       10 "Programme d'installation Windows %s\n\n" \
+       "Usage :\n" \
+       "msiexec commande {paramètre obligatoire} [paramètre optionnel]\n\n" \
+       "Installer un produit :\n" \
+       "\t/i {paquet|code_produit} [propriété]\n" \
+       "\t/package {paquet|code_produit} [propriété]\n" \
+       "\t/a paquet [propriété]\n" \
+       "Réparer une installation :\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {paquet|code_produit}\n" \
+       "Désinstaller un produit :\n" \
+       "\t/uninstall {paquet|code_produit} [propriété]\n" \
+       "\t/x {paquet|code_produit} [propriété]\n" \
+       "Publier un produit :\n" \
+       "\t/j[u|m] paquet [/t transformation] [/g id_langue]\n" \
+       "Appliquer un patch :\n" \
+       "\t/p paquet_patch [propriété]\n" \
+       "\t/p paquet_patch /a paquet [propriété]\n" \
+       "Modificateurs de journalisation et d'interface utilisateur pour les commandes ci-dessus :\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] fichier_journal\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Enregistrer le service MSI :\n" \
+       "\t/y\n" \
+       "Annuler l'enregistrement du service MSI :\n" \
+       "\t/z\n" \
+       "Afficher cette aide :\n" \
+       "\t/help\n" \
+       "\t/?\n"
        11 "saisissez le nom du dossier contenant %s"
        12 "source d'installation pour la fonctionnalité manquante"
        13 "lecteur réseau pour la fonctionnalité manquante"
index 21ba5cf..846de4c 100644 (file)
@@ -27,7 +27,33 @@ STRINGTABLE DISCARDABLE
        4 "The specified installation package could not be opened.  Please check the file path and try again."
        5 "%s útvonal nem található"
        9 "helyezze be a lemezt: %s"
-       10 "rossz paraméterek"
+       10 "Windows Installer %s\n\n" \
+       "Usage:\n" \
+       "msiexec command {required parameter} [optional parammeter]\n\n" \
+       "Install a product:\n" \
+       "\t/i {package|productcode} [property]\n" \
+       "\t/package {package|productcode} [property]\n" \
+       "\t/a package [property]\n" \
+       "Repair an installation:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n" \
+       "Uninstall a product:\n" \
+       "\t/uninstall {package|productcode} [property]\n" \
+       "\t/x {package|productcode} [property]\n" \
+       "Advertise a product:\n" \
+       "\t/j[u|m] package [/t transform] [/g languageid]\n" \
+       "Apply a patch:\n" \
+       "\t/p patchpackage [property]\n" \
+       "\t/p patchpackage /a package [property]\n" \
+       "Log and UI Modifiers for above commands:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Register MSI Service:\n" \
+       "\t/y\n" \
+       "Unregister MSI Service:\n" \
+       "\t/z\n" \
+       "Display this help:\n" \
+       "\t/help\n" \
+       "\t/?\n"
        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"
index a40a730..0586bb4 100644 (file)
@@ -30,7 +30,33 @@ STRINGTABLE DISCARDABLE
        4 "Impossibile aprire il pacchetto di installazione specificato.  Per favore controlla l'indirizzo del file e riprova."
        5 "percorso %s non trovato"
        9 "inserire disco %s"
-       10 "parametri incorretti"
+       10 "Windows Installer %s\n\n" \
+       "Usage:\n" \
+       "msiexec command {required parameter} [optional parammeter]\n\n" \
+       "Install a product:\n" \
+       "\t/i {package|productcode} [property]\n" \
+       "\t/package {package|productcode} [property]\n" \
+       "\t/a package [property]\n" \
+       "Repair an installation:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n" \
+       "Uninstall a product:\n" \
+       "\t/uninstall {package|productcode} [property]\n" \
+       "\t/x {package|productcode} [property]\n" \
+       "Advertise a product:\n" \
+       "\t/j[u|m] package [/t transform] [/g languageid]\n" \
+       "Apply a patch:\n" \
+       "\t/p patchpackage [property]\n" \
+       "\t/p patchpackage /a package [property]\n" \
+       "Log and UI Modifiers for above commands:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Register MSI Service:\n" \
+       "\t/y\n" \
+       "Unregister MSI Service:\n" \
+       "\t/z\n" \
+       "Display this help:\n" \
+       "\t/help\n" \
+       "\t/?\n"
        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"
index ca14253..17ab488 100644 (file)
@@ -27,7 +27,33 @@ STRINGTABLE DISCARDABLE
        4 " ÁöÁ¤ÇÑ ¼³Ä¡ ÆÐÅ°Áö¸¦ ¿­ ¼ö ¾ø½À´Ï´Ù. ÆÄÀÏ °æ·Î¸¦ È®ÀÎÇÏ°í ´Ù½Ã ½ÃµµÇϽʽÿÀ."
        5 "%s  °æ·Î¸¦ Ã£À»¼ö ¾ø½À´Ï´Ù"
        9 "µð½ºÅ© %s »ðÀÔ"
-       10 "À߸øµÈ ¸Å°³º¯¼ö"
+       10 "Windows Installer %s\n\n" \
+       "Usage:\n" \
+       "msiexec command {required parameter} [optional parammeter]\n\n" \
+       "Install a product:\n" \
+       "\t/i {package|productcode} [property]\n" \
+       "\t/package {package|productcode} [property]\n" \
+       "\t/a package [property]\n" \
+       "Repair an installation:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n" \
+       "Uninstall a product:\n" \
+       "\t/uninstall {package|productcode} [property]\n" \
+       "\t/x {package|productcode} [property]\n" \
+       "Advertise a product:\n" \
+       "\t/j[u|m] package [/t transform] [/g languageid]\n" \
+       "Apply a patch:\n" \
+       "\t/p patchpackage [property]\n" \
+       "\t/p patchpackage /a package [property]\n" \
+       "Log and UI Modifiers for above commands:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Register MSI Service:\n" \
+       "\t/y\n" \
+       "Unregister MSI Service:\n" \
+       "\t/z\n" \
+       "Display this help:\n" \
+       "\t/help\n" \
+       "\t/?\n"
        11 "%s¸¦ Æ÷ÇÔÇϴ Æú´õ¸¦ ÀÔ·ÂÇϼ¼¿©"
        12 "ºüÁø ºÎºÐ(feature)À» À§ÇÑ ¼³Ä¡ ¿øº»"
        13 "ºüÁø ºÎºÐ(feature)À» À§ÇÑ ³×Æ®¿öÅ© µå¶óÀ̺ê"
index 1cf1c52..c88592c 100644 (file)
@@ -30,7 +30,33 @@ STRINGTABLE DISCARDABLE
        4 "Nepavyko atverti nurodyto diegimo paketo. Patikrinkite failo kelią ir mėginkite dar kartą."
        5 "kelias %s nerastas"
        9 "įdėkite diską %s"
-       10 "blogi parametrai"
+       10 "Windows diegimo programa %s\n\n" \
+       "Naudojimas:\n" \
+       "msiexec komanda {būtinas parametras} [nebūtinas parametras]\n\n" \
+       "Įdiegti produktą:\n" \
+       "\t/i {paketas|produkto_kodas} [savybė]\n" \
+       "\t/package {paketas|produkto_kodas} [savybė]\n" \
+       "\t/a paketas [savybė]\n" \
+       "Taisyti įdiegimą:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {paketas|produkto_kodas}\n" \
+       "Pašalinti produktą:\n" \
+       "\t/uninstall {paketas|produkto_kodas} [savybė]\n" \
+       "\t/x {paketas|produkto_kodas} [savybė]\n" \
+       "Skelbti produktą:\n" \
+       "\t/j[u|m] paketas [/t pakeitimas] [/g kalbos_identifikatorius]\n" \
+       "Pritaikyti pataisą:\n" \
+       "\t/p pataisos_paketas [savybė]\n" \
+       "\t/p pataisos_paketas /a paketas [savybė]\n" \
+       "Žurnalo ir sąsajos modifikatoriai aukščiau išvardintoms komandoms:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] žurnalo_failas\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Registruoti MSI tarnybą:\n" \
+       "\t/y\n" \
+       "Išregistruoti MSI tarnybą:\n" \
+       "\t/z\n" \
+       "Parodyti šią pagalbą:\n" \
+       "\t/help\n" \
+       "\t/?\n"
        11 "įveskite aplanką, kuris turi %s"
        12 "trūksta diegimo šaltinio komponentui"
        13 "trūksta tinklo disko komponentui"
index da30430..306cfd7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Durch resources for MSI
+ * Dutch resources for MSI
  *
  * Copyright 2005 Hans Leidekker
  *
@@ -24,13 +24,39 @@ LANGUAGE LANG_DUTCH, SUBLANG_NEUTRAL
 
 STRINGTABLE DISCARDABLE
 {
-       4 "The specified installation package could not be opened.  Please check the file path and try again."
+       4 "Het opgegeven installatie pakket kon niet worden geopend.  Verifieer het bestandspad en probeer opnieuw."
        5 "Pad %s niet gevonden"
        9 "Plaats disk %s"
-       10 "Ongeldige parameters"
+       10 "Windows Installer %s\n\n" \
+       "Gebruik:\n" \
+       "msiexec commando {vereiste parameter} [optionele parameter]\n\n" \
+       "Installeer een product:\n" \
+       "\t/i {pakket|productcode} [eigenschap]\n" \
+       "\t/package {pakket|productcode} [eigenschap]\n" \
+       "\t/a pakket [eigenschap]\n" \
+       "Herstel een installatie:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {pakket|productcode}\n" \
+       "Verwijder een product:\n" \
+       "\t/uninstall {pakket|productcode} [eigenschap]\n" \
+       "\t/x {pakket|productcode} [eigenschap]\n" \
+       "Adverteer een product:\n" \
+       "\t/j[u|m] pakket [/t transform] [/g languageid]\n" \
+       "Pas een patch toe:\n" \
+       "\t/p patchpakket [eigenschap]\n" \
+       "\t/p patchpakket /a pakket [eigenschap]\n" \
+       "Log en UI Modifiers voor bovenstaande commando's:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logbestand\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Registreer MSI Service:\n" \
+       "\t/y\n" \
+       "Maak registratie MSI Service ongedaan:\n" \
+       "\t/z\n" \
+       "Laat dit helpvenster zien:\n" \
+       "\t/help\n" \
+       "\t/?\n"
        11 "Voer de map in die %s bevat"
-       12 "De installatiebron van het feature ontbreekt"
-       13 "De netwerkschijf met het feature ontbreekt"
+       12 "De installatiebron van de feature ontbreekt"
+       13 "De netwerkschijf met de feature ontbreekt"
        14 "Feature van:"
        15 "Kies de map die %s bevat"
 }
index e885f5a..93e26c6 100644 (file)
@@ -27,7 +27,33 @@ STRINGTABLE DISCARDABLE
        4 "Klarte ikke åpne den oppgitte installasjonspakken. Kontroller filbanen og prøv igjen."
        5 "Fant ikke stien '%s'."
        9 "Sett i disk '%s'"
-       10 "Gale parametere."
+       10 "Windows Installer %s\n\n" \
+       "Usage:\n" \
+       "msiexec command {required parameter} [optional parammeter]\n\n" \
+       "Install a product:\n" \
+       "\t/i {package|productcode} [property]\n" \
+       "\t/package {package|productcode} [property]\n" \
+       "\t/a package [property]\n" \
+       "Repair an installation:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n" \
+       "Uninstall a product:\n" \
+       "\t/uninstall {package|productcode} [property]\n" \
+       "\t/x {package|productcode} [property]\n" \
+       "Advertise a product:\n" \
+       "\t/j[u|m] package [/t transform] [/g languageid]\n" \
+       "Apply a patch:\n" \
+       "\t/p patchpackage [property]\n" \
+       "\t/p patchpackage /a package [property]\n" \
+       "Log and UI Modifiers for above commands:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Register MSI Service:\n" \
+       "\t/y\n" \
+       "Unregister MSI Service:\n" \
+       "\t/z\n" \
+       "Display this help:\n" \
+       "\t/help\n" \
+       "\t/?\n"
        11 "Oppgi katalogen som inneholder '%s'."
        12 "Egenskapens installasjonskilde mangler."
        13 "Egenskapens nettverksstasjon mangler."
index c31311e..ceb64dd 100644 (file)
@@ -28,7 +28,33 @@ STRINGTABLE DISCARDABLE
        4 "Nie uda³o siê otworzyæ wybranego pakietu instalacyjnego. Sprawd\9f czy \9ccie¿ka jest poprawna i spróbuj ponownie."
        5 "\9ccie¿ka '%s' nie zosta³a odnaleziona"
        9 "w³ó¿ dysk '%s'"
-       10 "z³e parametry"
+       10 "Windows Installer %s\n\n" \
+       "Usage:\n" \
+       "msiexec command {required parameter} [optional parammeter]\n\n" \
+       "Install a product:\n" \
+       "\t/i {package|productcode} [property]\n" \
+       "\t/package {package|productcode} [property]\n" \
+       "\t/a package [property]\n" \
+       "Repair an installation:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n" \
+       "Uninstall a product:\n" \
+       "\t/uninstall {package|productcode} [property]\n" \
+       "\t/x {package|productcode} [property]\n" \
+       "Advertise a product:\n" \
+       "\t/j[u|m] package [/t transform] [/g languageid]\n" \
+       "Apply a patch:\n" \
+       "\t/p patchpackage [property]\n" \
+       "\t/p patchpackage /a package [property]\n" \
+       "Log and UI Modifiers for above commands:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Register MSI Service:\n" \
+       "\t/y\n" \
+       "Unregister MSI Service:\n" \
+       "\t/z\n" \
+       "Display this help:\n" \
+       "\t/help\n" \
+       "\t/?\n"
        11 "wprowad\9f sice¿kê do folderu zawieraj¹cego '%s'"
        12 "\9fród³o danych zawieraj¹ce ¿¹danê funkcjê jest niedostêpne"
        13 "dysk siecowy zawieraj¹cy ¿¹dan¹ funckje jest niedostêpny"
index 64ab163..94cc633 100644 (file)
@@ -28,7 +28,33 @@ STRINGTABLE DISCARDABLE
        4 "The specified installation package could not be opened.  Please check the file path and try again."
        5 "caminho %s não encontrado"
        9 "insira disco %s"
-       10 "parâmetros inválidos"
+       10 "Windows Installer %s\n\n" \
+       "Usage:\n" \
+       "msiexec command {required parameter} [optional parammeter]\n\n" \
+       "Install a product:\n" \
+       "\t/i {package|productcode} [property]\n" \
+       "\t/package {package|productcode} [property]\n" \
+       "\t/a package [property]\n" \
+       "Repair an installation:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n" \
+       "Uninstall a product:\n" \
+       "\t/uninstall {package|productcode} [property]\n" \
+       "\t/x {package|productcode} [property]\n" \
+       "Advertise a product:\n" \
+       "\t/j[u|m] package [/t transform] [/g languageid]\n" \
+       "Apply a patch:\n" \
+       "\t/p patchpackage [property]\n" \
+       "\t/p patchpackage /a package [property]\n" \
+       "Log and UI Modifiers for above commands:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Register MSI Service:\n" \
+       "\t/y\n" \
+       "Unregister MSI Service:\n" \
+       "\t/z\n" \
+       "Display this help:\n" \
+       "\t/help\n" \
+       "\t/?\n"
        11 "entre qual pasta contém %s"
        12 "instalar fonte para característica faltando"
        13 "drive de rede para  característica faltando"
@@ -43,7 +69,33 @@ STRINGTABLE DISCARDABLE
        4 "The specified installation package could not be opened.  Please check the file path and try again."
        5 "localização %s não encontrada"
        9 "insira o disco %s"
-       10 "parâmetros inválidos"
+       10 "Windows Installer %s\n\n" \
+       "Usage:\n" \
+       "msiexec command {required parameter} [optional parammeter]\n\n" \
+       "Install a product:\n" \
+       "\t/i {package|productcode} [property]\n" \
+       "\t/package {package|productcode} [property]\n" \
+       "\t/a package [property]\n" \
+       "Repair an installation:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n" \
+       "Uninstall a product:\n" \
+       "\t/uninstall {package|productcode} [property]\n" \
+       "\t/x {package|productcode} [property]\n" \
+       "Advertise a product:\n" \
+       "\t/j[u|m] package [/t transform] [/g languageid]\n" \
+       "Apply a patch:\n" \
+       "\t/p patchpackage [property]\n" \
+       "\t/p patchpackage /a package [property]\n" \
+       "Log and UI Modifiers for above commands:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Register MSI Service:\n" \
+       "\t/y\n" \
+       "Unregister MSI Service:\n" \
+       "\t/z\n" \
+       "Display this help:\n" \
+       "\t/help\n" \
+       "\t/?\n"
        11 "indique que pasta contém %s"
        12 "instalar fonte para a opção em falta"
        13 "controlador de rede para a opção em falta"
index b877b42..ffd9c5e 100644 (file)
@@ -28,7 +28,33 @@ STRINGTABLE DISCARDABLE
         4 "Pachetul de instalare menționat nu a putut fi deschis. Verificați calea și încercați din nou."
         5 "calea %s nu a fost găsită"
         9 "inserați discul %s"
-        10 "parameteri greșiți"
+        10 "Windows Installer %s\n\n" \
+        "Usage:\n" \
+        "msiexec command {required parameter} [optional parammeter]\n\n" \
+        "Install a product:\n" \
+        "\t/i {package|productcode} [property]\n" \
+        "\t/package {package|productcode} [property]\n" \
+        "\t/a package [property]\n" \
+        "Repair an installation:\n" \
+        "\t/f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n" \
+        "Uninstall a product:\n" \
+        "\t/uninstall {package|productcode} [property]\n" \
+        "\t/x {package|productcode} [property]\n" \
+        "Advertise a product:\n" \
+        "\t/j[u|m] package [/t transform] [/g languageid]\n" \
+        "Apply a patch:\n" \
+        "\t/p patchpackage [property]\n" \
+        "\t/p patchpackage /a package [property]\n" \
+        "Log and UI Modifiers for above commands:\n" \
+        "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \
+        "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+        "Register MSI Service:\n" \
+        "\t/y\n" \
+        "Unregister MSI Service:\n" \
+        "\t/z\n" \
+        "Display this help:\n" \
+        "\t/help\n" \
+        "\t/?\n"
         11 "introduceți fișierul care conține %s"
         12 "lipsește sursa de instalare pentru această caracteristică"
         13 "lipsește unitatea de rețea pentru această caracteristică"
index 8e7aafd..7cd4a2b 100644 (file)
@@ -30,7 +30,33 @@ STRINGTABLE DISCARDABLE
        4 "Указанный пакет не может быть открыт. Проверьте файл и повторите попытку."
        5 "путь %s не найден"
        9 "вставьте диск %s"
-       10 "неверные параметры"
+       10 "Windows Installer %s\n\n" \
+       "Usage:\n" \
+       "msiexec command {required parameter} [optional parammeter]\n\n" \
+       "Install a product:\n" \
+       "\t/i {package|productcode} [property]\n" \
+       "\t/package {package|productcode} [property]\n" \
+       "\t/a package [property]\n" \
+       "Repair an installation:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n" \
+       "Uninstall a product:\n" \
+       "\t/uninstall {package|productcode} [property]\n" \
+       "\t/x {package|productcode} [property]\n" \
+       "Advertise a product:\n" \
+       "\t/j[u|m] package [/t transform] [/g languageid]\n" \
+       "Apply a patch:\n" \
+       "\t/p patchpackage [property]\n" \
+       "\t/p patchpackage /a package [property]\n" \
+       "Log and UI Modifiers for above commands:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Register MSI Service:\n" \
+       "\t/y\n" \
+       "Unregister MSI Service:\n" \
+       "\t/z\n" \
+       "Display this help:\n" \
+       "\t/help\n" \
+       "\t/?\n"
        11 "укажите каталог, содержащий %s"
        12 "источник установки данной возможности не указан"
        13 "сетевой диск для данной возможности не указан"
index 7582339..3477f1b 100644 (file)
@@ -29,7 +29,33 @@ STRINGTABLE DISCARDABLE
        4 "Navedenega namestitvenega paketa ni mogoče odpreti. Preverite ime datoteke in poskusite znova."
        5 "pot %s ne obstaja"
        9 "vnesite disk %s"
-       10 "neveljavni parametri"
+       10 "Windows Installer %s\n\n" \
+       "Usage:\n" \
+       "msiexec command {required parameter} [optional parammeter]\n\n" \
+       "Install a product:\n" \
+       "\t/i {package|productcode} [property]\n" \
+       "\t/package {package|productcode} [property]\n" \
+       "\t/a package [property]\n" \
+       "Repair an installation:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n" \
+       "Uninstall a product:\n" \
+       "\t/uninstall {package|productcode} [property]\n" \
+       "\t/x {package|productcode} [property]\n" \
+       "Advertise a product:\n" \
+       "\t/j[u|m] package [/t transform] [/g languageid]\n" \
+       "Apply a patch:\n" \
+       "\t/p patchpackage [property]\n" \
+       "\t/p patchpackage /a package [property]\n" \
+       "Log and UI Modifiers for above commands:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Register MSI Service:\n" \
+       "\t/y\n" \
+       "Unregister MSI Service:\n" \
+       "\t/z\n" \
+       "Display this help:\n" \
+       "\t/help\n" \
+       "\t/?\n"
        11 "vnesite ime mape, ki vsebuje %s"
        12 "manjkajoč namestitveni vir za namestitev funkcije"
        13 "manjkajoč omrežni pogon za namestitev funkcijo"
index 47bf09b..4c37cfc 100644 (file)
@@ -27,7 +27,33 @@ STRINGTABLE DISCARDABLE
        4 "Det angivna installationspaketet kunde inte öppnas.  Kontrollera filsökvägen och försök igen."
        5 "sökvägen %s hittades inte"
        9 "mata in %s"
-       10 "felaktiga parametrar"
+       10 "Windows Installer %s\n\n" \
+       "Usage:\n" \
+       "msiexec command {required parameter} [optional parammeter]\n\n" \
+       "Install a product:\n" \
+       "\t/i {package|productcode} [property]\n" \
+       "\t/package {package|productcode} [property]\n" \
+       "\t/a package [property]\n" \
+       "Repair an installation:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n" \
+       "Uninstall a product:\n" \
+       "\t/uninstall {package|productcode} [property]\n" \
+       "\t/x {package|productcode} [property]\n" \
+       "Advertise a product:\n" \
+       "\t/j[u|m] package [/t transform] [/g languageid]\n" \
+       "Apply a patch:\n" \
+       "\t/p patchpackage [property]\n" \
+       "\t/p patchpackage /a package [property]\n" \
+       "Log and UI Modifiers for above commands:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Register MSI Service:\n" \
+       "\t/y\n" \
+       "Unregister MSI Service:\n" \
+       "\t/z\n" \
+       "Display this help:\n" \
+       "\t/help\n" \
+       "\t/?\n"
        11 "ange vilken mapp som innehåller %s"
        12 "installationskälla för funktion saknar"
        13 "nätverksenhet för funktion saknar"
index a8e0f36..c6a12c1 100644 (file)
@@ -27,7 +27,33 @@ STRINGTABLE DISCARDABLE
        4 "The specified installation package could not be opened.  Please check the file path and try again."
        5 "%s yolu bulunamadý"
        9 "%s nolu diski yerleþtirin"
-       10 "bozuk parametreler"
+       10 "Windows Installer %s\n\n" \
+       "Usage:\n" \
+       "msiexec command {required parameter} [optional parammeter]\n\n" \
+       "Install a product:\n" \
+       "\t/i {package|productcode} [property]\n" \
+       "\t/package {package|productcode} [property]\n" \
+       "\t/a package [property]\n" \
+       "Repair an installation:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n" \
+       "Uninstall a product:\n" \
+       "\t/uninstall {package|productcode} [property]\n" \
+       "\t/x {package|productcode} [property]\n" \
+       "Advertise a product:\n" \
+       "\t/j[u|m] package [/t transform] [/g languageid]\n" \
+       "Apply a patch:\n" \
+       "\t/p patchpackage [property]\n" \
+       "\t/p patchpackage /a package [property]\n" \
+       "Log and UI Modifiers for above commands:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Register MSI Service:\n" \
+       "\t/y\n" \
+       "Unregister MSI Service:\n" \
+       "\t/z\n" \
+       "Display this help:\n" \
+       "\t/help\n" \
+       "\t/?\n"
        11 "%s öðesini içeren dizini girin"
        12 "eksik özellik için kurulum kaynaðý"
        13 "eksik özellik için að sürücüsü"
index 4b7173e..2407bbe 100644 (file)
@@ -32,7 +32,33 @@ STRINGTABLE DISCARDABLE
        4 "Не вдалося відкрити вказаний пакет інсталяції.  Перевірте шлях до файлу та спробуйте знов."
        5 "шлях %s не знайдено"
        9 "вставте диск %s"
-       10 "невірні параметри"
+       10 "Windows Installer %s\n\n" \
+       "Usage:\n" \
+       "msiexec command {required parameter} [optional parammeter]\n\n" \
+       "Install a product:\n" \
+       "\t/i {package|productcode} [property]\n" \
+       "\t/package {package|productcode} [property]\n" \
+       "\t/a package [property]\n" \
+       "Repair an installation:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n" \
+       "Uninstall a product:\n" \
+       "\t/uninstall {package|productcode} [property]\n" \
+       "\t/x {package|productcode} [property]\n" \
+       "Advertise a product:\n" \
+       "\t/j[u|m] package [/t transform] [/g languageid]\n" \
+       "Apply a patch:\n" \
+       "\t/p patchpackage [property]\n" \
+       "\t/p patchpackage /a package [property]\n" \
+       "Log and UI Modifiers for above commands:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Register MSI Service:\n" \
+       "\t/y\n" \
+       "Unregister MSI Service:\n" \
+       "\t/z\n" \
+       "Display this help:\n" \
+       "\t/help\n" \
+       "\t/?\n"
        11 "вкажіть папку, що містить %s"
        12 "джерело встановлення даної можливості не вказане"
        13 "мережевий диск для даної можливості не вказаний"
index a6d5cd1..91fd540 100644 (file)
@@ -30,7 +30,33 @@ STRINGTABLE DISCARDABLE
        4 "不能打开所指定的安装软件包. 请检查文件路径后再试."
        5 "路径 %s 没找到"
        9 "插入软盘 %s"
-       10 "错误参数"
+       10 "Windows Installer %s\n\n" \
+       "Usage:\n" \
+       "msiexec command {required parameter} [optional parammeter]\n\n" \
+       "Install a product:\n" \
+       "\t/i {package|productcode} [property]\n" \
+       "\t/package {package|productcode} [property]\n" \
+       "\t/a package [property]\n" \
+       "Repair an installation:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n" \
+       "Uninstall a product:\n" \
+       "\t/uninstall {package|productcode} [property]\n" \
+       "\t/x {package|productcode} [property]\n" \
+       "Advertise a product:\n" \
+       "\t/j[u|m] package [/t transform] [/g languageid]\n" \
+       "Apply a patch:\n" \
+       "\t/p patchpackage [property]\n" \
+       "\t/p patchpackage /a package [property]\n" \
+       "Log and UI Modifiers for above commands:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Register MSI Service:\n" \
+       "\t/y\n" \
+       "Unregister MSI Service:\n" \
+       "\t/z\n" \
+       "Display this help:\n" \
+       "\t/help\n" \
+       "\t/?\n"
        11 "输入包含 %s 的文件夹"
        12 "本功能的安装源不存在"
        13 "本功能的网络驱动器不存在"
@@ -45,7 +71,33 @@ STRINGTABLE DISCARDABLE
        4 "不能開啟所指定的安裝軟件包. 請檢查檔案路徑後再試."
        5 "路徑 %s 沒找到"
        9 "插入軟碟 %s"
-       10 "錯誤參數"
+       10 "Windows Installer %s\n\n" \
+       "Usage:\n" \
+       "msiexec command {required parameter} [optional parammeter]\n\n" \
+       "Install a product:\n" \
+       "\t/i {package|productcode} [property]\n" \
+       "\t/package {package|productcode} [property]\n" \
+       "\t/a package [property]\n" \
+       "Repair an installation:\n" \
+       "\t/f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n" \
+       "Uninstall a product:\n" \
+       "\t/uninstall {package|productcode} [property]\n" \
+       "\t/x {package|productcode} [property]\n" \
+       "Advertise a product:\n" \
+       "\t/j[u|m] package [/t transform] [/g languageid]\n" \
+       "Apply a patch:\n" \
+       "\t/p patchpackage [property]\n" \
+       "\t/p patchpackage /a package [property]\n" \
+       "Log and UI Modifiers for above commands:\n" \
+       "\t/l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n" \
+       "\t/q{|n|b|r|f|n+|b+|b-}\n" \
+       "Register MSI Service:\n" \
+       "\t/y\n" \
+       "Unregister MSI Service:\n" \
+       "\t/z\n" \
+       "Display this help:\n" \
+       "\t/help\n" \
+       "\t/?\n"
        11 "輸入包含 %s 的檔案夾"
        12 "本功能的安裝源不存在"
        13 "本功能的網路儲存槽不存在"
index 0516dd1..cf9e690 100644 (file)
@@ -143,13 +143,15 @@ typedef struct tagMSIMEDIAINFO
     LPWSTR volume_label;
     BOOL is_continuous;
     BOOL is_extracted;
-    WCHAR source[MAX_PATH];
+    WCHAR sourcedir[MAX_PATH];
 } MSIMEDIAINFO;
 
 typedef struct tagMSIPATCHINFO
 {
+    struct list entry;
     LPWSTR patchcode;
     LPWSTR transforms;
+    LPWSTR localfile;
 } MSIPATCHINFO;
 
 typedef struct _column_info
@@ -302,7 +304,7 @@ typedef struct tagMSIPACKAGE
 {
     MSIOBJECTHDR hdr;
     MSIDATABASE *db;
-    MSIPATCHINFO *patch;
+    struct list patches;
     struct list components;
     struct list features;
     struct list files;
@@ -466,6 +468,7 @@ typedef struct tagMSIFILE
     LPWSTR  TargetPath;
     BOOL IsCompressed;
     MSIFILEHASHINFO hash;
+    UINT disk_id;
 } MSIFILE;
 
 typedef struct tagMSITEMPFILE
@@ -553,6 +556,7 @@ struct tagMSIMIME
     struct list entry;
     LPWSTR ContentType;  /* Primary Key */
     MSIEXTENSION *Extension;
+    LPWSTR suffix;
     LPWSTR clsid;
     MSICLASS *Class;
     /* not in the table, set during installation */
@@ -660,8 +664,7 @@ enum StringPersistence
     StringNonPersistent = 1
 };
 
-extern BOOL msi_addstringW( string_table *st, UINT string_no, const WCHAR *data, int len, UINT refcount, enum StringPersistence persistence );
-
+extern BOOL msi_addstringW( string_table *st, const WCHAR *data, int len, USHORT refcount, enum StringPersistence persistence );
 extern UINT msi_string2idW( const string_table *st, LPCWSTR buffer, UINT *id );
 extern VOID msi_destroy_stringtable( string_table *st );
 extern const WCHAR *msi_string_lookup_id( const string_table *st, UINT id );
@@ -672,8 +675,6 @@ extern UINT msi_save_string_table( const string_table *st, IStorage *storage );
 extern BOOL TABLE_Exists( MSIDATABASE *db, LPCWSTR name );
 extern MSICONDITION MSI_DatabaseIsTablePersistent( MSIDATABASE *db, LPCWSTR table );
 
-extern UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname,
-                                  USHORT **pdata, UINT *psz );
 extern UINT read_stream_data( IStorage *stg, LPCWSTR stname, BOOL table,
                               BYTE **pdata, UINT *psz );
 extern UINT write_stream_data( IStorage *stg, LPCWSTR stname,
@@ -685,7 +686,10 @@ extern UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db,
                  LPCWSTR szTransformFile, int iErrorCond );
 extern void append_storage_to_db( MSIDATABASE *db, IStorage *stg );
 
+/* patch functions */
 extern UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si );
+extern UINT msi_parse_patch_summary( MSISUMMARYINFO *si, MSIPATCHINFO **patch );
+extern UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch );
 
 /* action internals */
 extern UINT MSI_InstallPackage( MSIPACKAGE *, LPCWSTR, LPCWSTR );
@@ -724,6 +728,7 @@ extern BOOL decode_streamname(LPCWSTR in, LPWSTR out);
 
 /* database internals */
 extern UINT db_get_raw_stream( MSIDATABASE *, LPCWSTR, IStream ** );
+void db_destroy_stream( MSIDATABASE *, LPCWSTR );
 extern UINT MSI_OpenDatabaseW( LPCWSTR, LPCWSTR, MSIDATABASE ** );
 extern UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY ** );
 extern UINT MSI_OpenQuery( MSIDATABASE *, MSIQUERY **, LPCWSTR, ... );
@@ -748,10 +753,7 @@ extern UINT MSI_SetInstallLevel( MSIPACKAGE *package, int iInstallLevel );
 extern MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *, LPCWSTR );
 extern UINT MSI_OpenPackageW( LPCWSTR szPackage, MSIPACKAGE **pPackage );
 extern UINT MSI_SetTargetPathW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
-extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
 extern INT MSI_ProcessMessage( MSIPACKAGE *, INSTALLMESSAGE, MSIRECORD * );
-extern UINT MSI_GetPropertyW( MSIPACKAGE *, LPCWSTR, LPWSTR, LPDWORD );
-extern UINT MSI_GetPropertyA(MSIPACKAGE *, LPCSTR, LPSTR, LPDWORD );
 extern MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *, LPCWSTR );
 extern UINT MSI_GetComponentStateW( MSIPACKAGE *, LPCWSTR, INSTALLSTATE *, INSTALLSTATE * );
 extern UINT MSI_GetFeatureStateW( MSIPACKAGE *, LPCWSTR, INSTALLSTATE *, INSTALLSTATE * );
@@ -760,6 +762,7 @@ extern UINT msi_download_file( LPCWSTR szUrl, LPWSTR filename );
 extern UINT msi_package_add_info(MSIPACKAGE *, DWORD, DWORD, LPCWSTR, LPWSTR);
 extern UINT msi_package_add_media_disk(MSIPACKAGE *, DWORD, DWORD, DWORD, LPWSTR, LPWSTR);
 extern UINT msi_clone_properties(MSIPACKAGE *);
+extern UINT msi_set_context(MSIPACKAGE *);
 extern UINT MSI_GetFeatureCost(MSIPACKAGE *, MSIFEATURE *, MSICOSTTREE, INSTALLSTATE, LPINT);
 
 /* for deformating */
@@ -787,12 +790,15 @@ extern UINT MSIREG_OpenUserDataProductKey(LPCWSTR szProduct, MSIINSTALLCONTEXT d
                                           LPCWSTR szUserSid, HKEY *key, BOOL create);
 extern UINT MSIREG_OpenUserDataPatchKey(LPCWSTR szPatch, MSIINSTALLCONTEXT dwContext,
                                         HKEY *key, BOOL create);
+extern UINT MSIREG_OpenUserDataProductPatchesKey(LPCWSTR product, MSIINSTALLCONTEXT context,
+                                                 HKEY *key, BOOL create);
 extern UINT MSIREG_OpenInstallProps(LPCWSTR szProduct, MSIINSTALLCONTEXT dwContext,
                                     LPCWSTR szUserSid, HKEY *key, BOOL create);
 extern UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
 extern UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
 extern UINT MSIREG_DeleteProductKey(LPCWSTR szProduct);
 extern UINT MSIREG_DeleteUserProductKey(LPCWSTR szProduct);
+extern UINT MSIREG_DeleteUserDataPatchKey(LPCWSTR patch, MSIINSTALLCONTEXT context);
 extern UINT MSIREG_DeleteUserDataProductKey(LPCWSTR szProduct);
 extern UINT MSIREG_DeleteUserFeaturesKey(LPCWSTR szProduct);
 extern UINT MSIREG_DeleteUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid);
@@ -963,16 +969,23 @@ extern UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package);
 extern UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package);
 extern UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package);
 extern UINT ACTION_RegisterFonts(MSIPACKAGE *package);
+extern UINT ACTION_UnregisterClassInfo(MSIPACKAGE *package);
+extern UINT ACTION_UnregisterExtensionInfo(MSIPACKAGE *package);
 extern UINT ACTION_UnregisterFonts(MSIPACKAGE *package);
+extern UINT ACTION_UnregisterMIMEInfo(MSIPACKAGE *package);
+extern UINT ACTION_UnregisterProgIdInfo(MSIPACKAGE *package);
 
 /* Helpers */
 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 msi_dup_property( MSIDATABASE *db, LPCWSTR prop );
+extern UINT msi_set_property( MSIDATABASE *, LPCWSTR, LPCWSTR );
+extern UINT msi_get_property( MSIDATABASE *, LPCWSTR, LPWSTR, LPDWORD );
+extern int msi_get_property_int( MSIDATABASE *package, LPCWSTR prop, int def );
 extern LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
                       BOOL set_prop, BOOL load_prop, MSIFOLDER **folder);
 extern LPWSTR resolve_file_source(MSIPACKAGE *package, MSIFILE *file);
+extern void msi_reset_folders( MSIPACKAGE *package, BOOL source );
 extern MSICOMPONENT *get_loaded_component( MSIPACKAGE* package, LPCWSTR Component );
 extern MSIFEATURE *get_loaded_feature( MSIPACKAGE* package, LPCWSTR Feature );
 extern MSIFILE *get_loaded_file( MSIPACKAGE* package, LPCWSTR file );
@@ -992,6 +1005,7 @@ extern WCHAR* generate_error_string(MSIPACKAGE *, UINT, DWORD, ... );
 extern UINT msi_create_component_directories( MSIPACKAGE *package );
 extern UINT msi_set_last_used_source(LPCWSTR product, LPCWSTR usersid,
                         MSIINSTALLCONTEXT context, DWORD options, LPCWSTR value);
+extern UINT msi_get_local_package_name(LPWSTR path, LPCWSTR suffix);
 
 /* media */
 
@@ -1084,6 +1098,23 @@ static const WCHAR szHU[] = {'H','K','E','Y','_','U','S','E','R','S','\\',0};
 static const WCHAR szWindowsFolder[] = {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
 static const WCHAR szAppSearch[] = {'A','p','p','S','e','a','r','c','h',0};
 static const WCHAR szMoveFiles[] = {'M','o','v','e','F','i','l','e','s',0};
+static const WCHAR szCCPSearch[] = {'C','C','P','S','e','a','r','c','h',0};
+static const WCHAR szUnregisterClassInfo[] = {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
+static const WCHAR szUnregisterExtensionInfo[] = {'U','n','r','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};
+static const WCHAR szUnregisterMIMEInfo[] = {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
+static const WCHAR szUnregisterProgIdInfo[] = {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
+static const WCHAR szRegisterFonts[] = {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
+static const WCHAR szUnregisterFonts[] = {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
+static const WCHAR szCLSID[] = {'C','L','S','I','D',0};
+static const WCHAR szProgID[] = {'P','r','o','g','I','D',0};
+static const WCHAR szVIProgID[] = {'V','e','r','s','i','o','n','I','n','d','e','p','e','n','d','e','n','t','P','r','o','g','I','D',0};
+static const WCHAR szAppID[] = {'A','p','p','I','D',0};
+static const WCHAR szDefaultIcon[] = {'D','e','f','a','u','l','t','I','c','o','n',0};
+static const WCHAR szInprocHandler[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r',0};
+static const WCHAR szInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
+static const WCHAR szMIMEDatabase[] = {'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\','C','o','n','t','e','n','t',' ','T','y','p','e','\\',0};
+static const WCHAR szLocalPackage[] = {'L','o','c','a','l','P','a','c','k','a','g','e',0};
+static const WCHAR szOriginalDatabase[] = {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
 
 /* memory allocation macro functions */
 static void *msi_alloc( size_t len ) __WINE_ALLOC_SIZE(1);
index b1741ae..fba722f 100644 (file)
@@ -214,6 +214,7 @@ static void free_package_structures( MSIPACKAGE *package )
         MSIMIME *mt = LIST_ENTRY( item, MSIMIME, entry );
 
         list_remove( &mt->entry );
+        msi_free( mt->suffix );
         msi_free( mt->clsid );
         msi_free( mt->ContentType );
         msi_free( mt );
@@ -263,11 +264,15 @@ static void free_package_structures( MSIPACKAGE *package )
         msi_free( package->script );
     }
 
-    if (package->patch)
+    LIST_FOR_EACH_SAFE( item, cursor, &package->patches )
     {
-        msi_free( package->patch->patchcode );
-        msi_free( package->patch->transforms );
-        msi_free( package->patch );
+        MSIPATCHINFO *patch = LIST_ENTRY( item, MSIPATCHINFO, entry );
+
+        list_remove( &patch->entry );
+        msi_free( patch->patchcode );
+        msi_free( patch->transforms );
+        msi_free( patch->localfile );
+        msi_free( patch );
     }
 
     msi_free( package->BaseURL );
@@ -388,7 +393,7 @@ static UINT set_installed_prop( MSIPACKAGE *package )
     if (r == ERROR_SUCCESS)
     {
         RegCloseKey( hkey );
-        MSI_SetPropertyW( package, szInstalled, szOne );
+        msi_set_property( package->db, szInstalled, szOne );
     }
 
     return r;
@@ -431,7 +436,7 @@ static UINT set_user_sid_prop( MSIPACKAGE *package )
     if (!ConvertSidToStringSidW( psid, &sid_str ))
         goto done;
 
-    r = MSI_SetPropertyW( package, szUserSID, sid_str );
+    r = msi_set_property( package->db, szUserSID, sid_str );
 
 done:
     LocalFree( sid_str );
@@ -563,7 +568,7 @@ static void set_msi_assembly_prop(MSIPACKAGE *package)
     if (!val_len || !verstr)
         goto done;
 
-    MSI_SetPropertyW(package, netasm, verstr);
+    msi_set_property(package->db, netasm, verstr);
 
 done:
     msi_free(fusion);
@@ -689,96 +694,96 @@ static VOID set_installer_properties(MSIPACKAGE *package)
 
     SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth);
     strcatW(pth, szBackSlash);
-    MSI_SetPropertyW(package, CFF, pth);
+    msi_set_property(package->db, CFF, pth);
 
     SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES,NULL,0,pth);
     strcatW(pth, szBackSlash);
-    MSI_SetPropertyW(package, PFF, pth);
+    msi_set_property(package->db, PFF, pth);
 
     SHGetFolderPathW(NULL,CSIDL_COMMON_APPDATA,NULL,0,pth);
     strcatW(pth, szBackSlash);
-    MSI_SetPropertyW(package, CADF, pth);
+    msi_set_property(package->db, CADF, pth);
 
     SHGetFolderPathW(NULL,CSIDL_FAVORITES,NULL,0,pth);
     strcatW(pth, szBackSlash);
-    MSI_SetPropertyW(package, FaF, pth);
+    msi_set_property(package->db, FaF, pth);
 
     SHGetFolderPathW(NULL,CSIDL_FONTS,NULL,0,pth);
     strcatW(pth, szBackSlash);
-    MSI_SetPropertyW(package, FoF, pth);
+    msi_set_property(package->db, FoF, pth);
 
     SHGetFolderPathW(NULL,CSIDL_SENDTO,NULL,0,pth);
     strcatW(pth, szBackSlash);
-    MSI_SetPropertyW(package, SendTF, pth);
+    msi_set_property(package->db, SendTF, pth);
 
     SHGetFolderPathW(NULL,CSIDL_STARTMENU,NULL,0,pth);
     strcatW(pth, szBackSlash);
-    MSI_SetPropertyW(package, SMF, pth);
+    msi_set_property(package->db, SMF, pth);
 
     SHGetFolderPathW(NULL,CSIDL_STARTUP,NULL,0,pth);
     strcatW(pth, szBackSlash);
-    MSI_SetPropertyW(package, StF, pth);
+    msi_set_property(package->db, StF, pth);
 
     SHGetFolderPathW(NULL,CSIDL_TEMPLATES,NULL,0,pth);
     strcatW(pth, szBackSlash);
-    MSI_SetPropertyW(package, TemplF, pth);
+    msi_set_property(package->db, TemplF, pth);
 
     SHGetFolderPathW(NULL,CSIDL_DESKTOP,NULL,0,pth);
     strcatW(pth, szBackSlash);
-    MSI_SetPropertyW(package, DF, pth);
+    msi_set_property(package->db, DF, pth);
 
     SHGetFolderPathW(NULL,CSIDL_PROGRAMS,NULL,0,pth);
     strcatW(pth, szBackSlash);
-    MSI_SetPropertyW(package, PMF, pth);
+    msi_set_property(package->db, PMF, pth);
 
     SHGetFolderPathW(NULL,CSIDL_ADMINTOOLS,NULL,0,pth);
     strcatW(pth, szBackSlash);
-    MSI_SetPropertyW(package, ATF, pth);
+    msi_set_property(package->db, ATF, pth);
 
     SHGetFolderPathW(NULL,CSIDL_APPDATA,NULL,0,pth);
     strcatW(pth, szBackSlash);
-    MSI_SetPropertyW(package, ADF, pth);
+    msi_set_property(package->db, ADF, pth);
 
     SHGetFolderPathW(NULL,CSIDL_SYSTEM,NULL,0,pth);
     strcatW(pth, szBackSlash);
-    MSI_SetPropertyW(package, SF, pth);
-    MSI_SetPropertyW(package, SF16, pth);
+    msi_set_property(package->db, SF, pth);
+    msi_set_property(package->db, SF16, pth);
 
     SHGetFolderPathW(NULL,CSIDL_LOCAL_APPDATA,NULL,0,pth);
     strcatW(pth, szBackSlash);
-    MSI_SetPropertyW(package, LADF, pth);
+    msi_set_property(package->db, LADF, pth);
 
     SHGetFolderPathW(NULL,CSIDL_MYPICTURES,NULL,0,pth);
     strcatW(pth, szBackSlash);
-    MSI_SetPropertyW(package, MPF, pth);
+    msi_set_property(package->db, MPF, pth);
 
     SHGetFolderPathW(NULL,CSIDL_PERSONAL,NULL,0,pth);
     strcatW(pth, szBackSlash);
-    MSI_SetPropertyW(package, PF, pth);
+    msi_set_property(package->db, PF, pth);
 
     SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
     strcatW(pth, szBackSlash);
-    MSI_SetPropertyW(package, WF, pth);
+    msi_set_property(package->db, WF, pth);
     
     /* Physical Memory is specified in MB. Using total amount. */
     msex.dwLength = sizeof(msex);
     GlobalMemoryStatusEx( &msex );
     sprintfW( bufstr, szIntFormat, (int)(msex.ullTotalPhys/1024/1024));
-    MSI_SetPropertyW(package, szPhysicalMemory, bufstr);
+    msi_set_property(package->db, szPhysicalMemory, bufstr);
 
     SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
     ptr = strchrW(pth,'\\');
     if (ptr)
        *(ptr+1) = 0;
-    MSI_SetPropertyW(package, WV, pth);
+    msi_set_property(package->db, WV, pth);
     
     GetTempPathW(MAX_PATH,pth);
-    MSI_SetPropertyW(package, TF, pth);
+    msi_set_property(package->db, TF, pth);
 
 
     /* in a wine environment the user is always admin and privileged */
-    MSI_SetPropertyW(package,szAdminUser,szOne);
-    MSI_SetPropertyW(package,szPriv,szOne);
+    msi_set_property(package->db, szAdminUser, szOne);
+    msi_set_property(package->db, szPriv, szOne);
 
     /* set the os things */
     OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
@@ -788,54 +793,54 @@ static VOID set_installer_properties(MSIPACKAGE *package)
     switch (OSVersion.dwPlatformId)
     {
         case VER_PLATFORM_WIN32_WINDOWS:    
-            MSI_SetPropertyW(package,v9x,verstr);
+            msi_set_property(package->db, v9x, verstr);
             break;
         case VER_PLATFORM_WIN32_NT:
-            MSI_SetPropertyW(package,vNT,verstr);
+            msi_set_property(package->db, vNT, verstr);
             sprintfW(verstr,szFormat,OSVersion.wProductType);
-            MSI_SetPropertyW(package,szMsiNTProductType,verstr);
+            msi_set_property(package->db, szMsiNTProductType, verstr);
             break;
     }
     sprintfW(verstr,szFormat,OSVersion.dwBuildNumber);
-    MSI_SetPropertyW(package,szWinBuild,verstr);
+    msi_set_property(package->db, szWinBuild, verstr);
     /* just fudge this */
-    MSI_SetPropertyW(package,szSPL,szSix);
+    msi_set_property(package->db, szSPL, szSix);
 
     sprintfW( bufstr, szFormat2, MSI_MAJORVERSION, MSI_MINORVERSION);
-    MSI_SetPropertyW( package, szVersionMsi, bufstr );
+    msi_set_property( package->db, szVersionMsi, bufstr );
     sprintfW( bufstr, szFormat, MSI_MAJORVERSION * 100);
-    MSI_SetPropertyW( package, szVersionDatabase, bufstr );
+    msi_set_property( package->db, szVersionDatabase, bufstr );
 
     GetSystemInfo( &sys_info );
     if (sys_info.u.s.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
     {
         sprintfW( bufstr, szIntFormat, sys_info.wProcessorLevel );
-        MSI_SetPropertyW( package, szIntel, bufstr );
+        msi_set_property( package->db, szIntel, bufstr );
     }
 
     /* Screen properties. */
     dc = GetDC(0);
     sprintfW( bufstr, szIntFormat, GetDeviceCaps( dc, HORZRES ) );
-    MSI_SetPropertyW( package, szScreenX, bufstr );
+    msi_set_property( package->db, szScreenX, bufstr );
     sprintfW( bufstr, szIntFormat, GetDeviceCaps( dc, VERTRES ));
-    MSI_SetPropertyW( package, szScreenY, bufstr );
+    msi_set_property( package->db, szScreenY, bufstr );
     sprintfW( bufstr, szIntFormat, GetDeviceCaps( dc, BITSPIXEL ));
-    MSI_SetPropertyW( package, szColorBits, bufstr );
+    msi_set_property( package->db, szColorBits, bufstr );
     ReleaseDC(0, dc);
 
     /* USERNAME and COMPANYNAME */
-    username = msi_dup_property( package, szUSERNAME );
-    companyname = msi_dup_property( package, szCOMPANYNAME );
+    username = msi_dup_property( package->db, szUSERNAME );
+    companyname = msi_dup_property( package->db, szCOMPANYNAME );
 
     if ((!username || !companyname) &&
         RegOpenKeyW( HKEY_CURRENT_USER, szUserInfo, &hkey ) == ERROR_SUCCESS)
     {
         if (!username &&
             (username = msi_reg_get_val_str( hkey, szDefName )))
-            MSI_SetPropertyW( package, szUSERNAME, username );
+            msi_set_property( package->db, szUSERNAME, username );
         if (!companyname &&
             (companyname = msi_reg_get_val_str( hkey, szDefCompany )))
-            MSI_SetPropertyW( package, szCOMPANYNAME, companyname );
+            msi_set_property( package->db, szCOMPANYNAME, companyname );
         CloseHandle( hkey );
     }
     if ((!username || !companyname) &&
@@ -843,10 +848,10 @@ static VOID set_installer_properties(MSIPACKAGE *package)
     {
         if (!username &&
             (username = msi_reg_get_val_str( hkey, szRegisteredUser )))
-            MSI_SetPropertyW( package, szUSERNAME, username );
+            msi_set_property( package->db, szUSERNAME, username );
         if (!companyname &&
             (companyname = msi_reg_get_val_str( hkey, szRegisteredOrg )))
-            MSI_SetPropertyW( package, szCOMPANYNAME, companyname );
+            msi_set_property( package->db, szCOMPANYNAME, companyname );
         CloseHandle( hkey );
     }
     msi_free( username );
@@ -859,7 +864,7 @@ static VOID set_installer_properties(MSIPACKAGE *package)
     GetSystemTime( &systemtime );
     if (GetDateFormatW( LOCALE_USER_DEFAULT, DATE_SHORTDATE, &systemtime,
                         NULL, bufstr, sizeof(bufstr)/sizeof(bufstr[0]) ))
-        MSI_SetPropertyW( package, szDate, bufstr );
+        msi_set_property( package->db, szDate, bufstr );
     else
         ERR("Couldn't set Date property: GetDateFormat failed with error %d\n", GetLastError());
 
@@ -867,7 +872,7 @@ static VOID set_installer_properties(MSIPACKAGE *package)
                         TIME_FORCE24HOURFORMAT | TIME_NOTIMEMARKER,
                         &systemtime, NULL, bufstr,
                         sizeof(bufstr)/sizeof(bufstr[0]) ))
-        MSI_SetPropertyW( package, szTime, bufstr );
+        msi_set_property( package->db, szTime, bufstr );
     else
         ERR("Couldn't set Time property: GetTimeFormat failed with error %d\n", GetLastError());
 
@@ -875,26 +880,24 @@ static VOID set_installer_properties(MSIPACKAGE *package)
 
     langid = GetUserDefaultLangID();
     sprintfW(bufstr, szIntFormat, langid);
-
-    MSI_SetPropertyW( package, szUserLangID, bufstr );
+    msi_set_property( package->db, szUserLangID, bufstr );
 
     langid = GetSystemDefaultLangID();
     sprintfW(bufstr, szIntFormat, langid);
-
-    MSI_SetPropertyW( package, szSystemLangID, bufstr );
+    msi_set_property( package->db, szSystemLangID, bufstr );
 
     sprintfW(bufstr, szIntFormat, MsiQueryProductStateW(package->ProductCode));
-    MSI_SetPropertyW( package, szProductState, bufstr );
+    msi_set_property( package->db, szProductState, bufstr );
 
     len = 0;
     if (!GetUserNameW( NULL, &len ) && GetLastError() == ERROR_MORE_DATA)
     {
         WCHAR *username;
-        if ((username = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
+        if ((username = msi_alloc( len * sizeof(WCHAR) )))
         {
             if (GetUserNameW( username, &len ))
-                MSI_SetPropertyW( package, szLogonUser, username );
-            HeapFree( GetProcessHeap(), 0, username );
+                msi_set_property( package->db, szLogonUser, username );
+            msi_free( username );
         }
     }
 }
@@ -952,7 +955,7 @@ static UINT msi_load_summary_properties( MSIPACKAGE *package )
         goto done;
     }
 
-    MSI_SetPropertyW( package, szPackageCode, package_code );
+    msi_set_property( package->db, szPackageCode, package_code );
     msi_free( package_code );
 
     /* load package attributes */
@@ -988,6 +991,7 @@ static MSIPACKAGE *msi_alloc_package( void )
         list_init( &package->RunningActions );
         list_init( &package->sourcelist_info );
         list_init( &package->sourcelist_media );
+        list_init( &package->patches );
     }
 
     return package;
@@ -1013,10 +1017,10 @@ static UINT msi_load_admin_properties(MSIPACKAGE *package)
 static void adjust_allusers_property( MSIPACKAGE *package )
 {
     /* FIXME: this should depend on the user's privileges */
-    if (msi_get_property_int( package, szAllUsers, 0 ) == 2)
+    if (msi_get_property_int( package->db, szAllUsers, 0 ) == 2)
     {
         TRACE("resetting ALLUSERS property from 2 to 1\n");
-        MSI_SetPropertyW( package, szAllUsers, szOne );
+        msi_set_property( package->db, szAllUsers, szOne );
     }
 }
 
@@ -1043,12 +1047,14 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPCWSTR base_url )
         create_temp_property_table( package );
         msi_clone_properties( package );
 
-        package->ProductCode = msi_dup_property( package, szProductCode );
+        package->ProductCode = msi_dup_property( package->db, szProductCode );
+        package->script = msi_alloc_zero( sizeof(MSISCRIPT) );
+
         set_installed_prop( package );
         set_installer_properties( package );
 
         sprintfW(uilevel,szpi,gUILevel);
-        MSI_SetPropertyW(package, szLevel, uilevel);
+        msi_set_property(package->db, szLevel, uilevel);
 
         r = msi_load_summary_properties( package );
         if (r != ERROR_SUCCESS)
@@ -1107,16 +1113,16 @@ UINT msi_download_file( LPCWSTR szUrl, LPWSTR filename )
     GetUrlCacheEntryInfoW( szUrl, NULL, &size );
     if ( GetLastError() != ERROR_FILE_NOT_FOUND )
     {
-        cache_entry = HeapAlloc( GetProcessHeap(), 0, size );
+        cache_entry = msi_alloc( size );
         if ( !GetUrlCacheEntryInfoW( szUrl, cache_entry, &size ) )
         {
             UINT error = GetLastError();
-            HeapFree( GetProcessHeap(), 0, cache_entry );
+            msi_free( cache_entry );
             return error;
         }
 
         lstrcpyW( filename, cache_entry->lpszLocalFileName );
-        HeapFree( GetProcessHeap(), 0, cache_entry );
+        msi_free( cache_entry );
         return ERROR_SUCCESS;
     }
 
@@ -1130,12 +1136,12 @@ UINT msi_download_file( LPCWSTR szUrl, LPWSTR filename )
     return ERROR_SUCCESS;
 }
 
-static UINT msi_get_local_package_name( LPWSTR path )
+UINT msi_get_local_package_name( LPWSTR path, LPCWSTR suffix )
 {
     static const WCHAR szInstaller[] = {
         '\\','I','n','s','t','a','l','l','e','r','\\',0};
-    static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
-    DWORD time, len, i;
+    static const WCHAR fmt[] = {'%','x',0};
+    DWORD time, len, i, offset;
     HANDLE handle;
 
     time = GetTickCount();
@@ -1146,7 +1152,8 @@ static UINT msi_get_local_package_name( LPWSTR path )
     len = strlenW(path);
     for (i = 0; i < 0x10000; i++)
     {
-        snprintfW( &path[len], MAX_PATH - len, fmt, (time + i)&0xffff );
+        offset = snprintfW( path + len, MAX_PATH - len, fmt, (time + i) & 0xffff );
+        memcpy( path + len + offset, suffix, (strlenW( suffix ) + 1) * sizeof(WCHAR) );
         handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
                               CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
         if (handle != INVALID_HANDLE_VALUE)
@@ -1162,11 +1169,64 @@ static UINT msi_get_local_package_name( LPWSTR path )
     return ERROR_SUCCESS;
 }
 
+static UINT apply_registered_patch( MSIPACKAGE *package, LPCWSTR patch_code )
+{
+    UINT r;
+    DWORD len;
+    WCHAR patch_file[MAX_PATH];
+    MSIDATABASE *patch_db;
+    MSIPATCHINFO *patch_info;
+    MSISUMMARYINFO *si;
+
+    len = sizeof(patch_file) / sizeof(WCHAR);
+    r = MsiGetPatchInfoExW( patch_code, package->ProductCode, NULL, package->Context,
+                            INSTALLPROPERTY_LOCALPACKAGEW, patch_file, &len );
+    if (r != ERROR_SUCCESS)
+    {
+        ERR("failed to get patch filename %u\n", r);
+        return r;
+    }
+
+    r = MSI_OpenDatabaseW( patch_file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
+    if (r != ERROR_SUCCESS)
+    {
+        ERR("failed to open patch database %s\n", debugstr_w( patch_file ));
+        return r;
+    }
+
+    si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
+    if (!si)
+    {
+        msiobj_release( &patch_db->hdr );
+        return ERROR_FUNCTION_FAILED;
+    }
+
+    r = msi_parse_patch_summary( si, &patch_info );
+    msiobj_release( &si->hdr );
+    if (r != ERROR_SUCCESS)
+    {
+        ERR("failed to parse patch summary %u\n", r);
+        msiobj_release( &patch_db->hdr );
+        return r;
+    }
+
+    r = msi_apply_patch_db( package, patch_db, patch_info );
+    msiobj_release( &patch_db->hdr );
+    if (r != ERROR_SUCCESS)
+    {
+        ERR("failed to apply patch %u\n", r);
+        msi_free( patch_info->patchcode );
+        msi_free( patch_info->transforms );
+        msi_free( patch_info->localfile );
+        msi_free( patch_info );
+    }
+    return r;
+}
+
 UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
 {
-    static const WCHAR OriginalDatabase[] =
-        {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
     static const WCHAR Database[] = {'D','A','T','A','B','A','S','E',0};
+    static const WCHAR dotmsi[] = {'.','m','s','i',0};
     MSIDATABASE *db = NULL;
     MSIPACKAGE *package;
     MSIHANDLE handle;
@@ -1174,6 +1234,7 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
     UINT r;
     WCHAR temppath[MAX_PATH], localfile[MAX_PATH], cachefile[MAX_PATH];
     LPCWSTR file = szPackage;
+    DWORD index = 0;
 
     TRACE("%s %p\n", debugstr_w(szPackage), pPackage);
 
@@ -1225,7 +1286,7 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
             file = temppath;
         }
 
-        r = msi_get_local_package_name( localfile );
+        r = msi_get_local_package_name( localfile, dotmsi );
         if (r != ERROR_SUCCESS)
             return r;
 
@@ -1273,23 +1334,44 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
     if( file != szPackage )
         track_tempfile( package, file );
 
-    MSI_SetPropertyW( package, Database, db->path );
+    msi_set_property( package->db, Database, db->path );
 
     if( UrlIsW( szPackage, URLIS_URL ) )
-        MSI_SetPropertyW( package, OriginalDatabase, szPackage );
+        msi_set_property( package->db, szOriginalDatabase, szPackage );
     else if( szPackage[0] == '#' )
-        MSI_SetPropertyW( package, OriginalDatabase, db->path );
+        msi_set_property( package->db, szOriginalDatabase, db->path );
     else
     {
         WCHAR fullpath[MAX_PATH];
 
         GetFullPathNameW( szPackage, MAX_PATH, fullpath, NULL );
-        MSI_SetPropertyW( package, OriginalDatabase, fullpath );
+        msi_set_property( package->db, szOriginalDatabase, fullpath );
     }
 
-    package->script = msi_alloc_zero( sizeof(MSISCRIPT) );
-    *pPackage = package;
+    msi_set_context( package );
+
+    while (1)
+    {
+        WCHAR patch_code[GUID_SIZE];
+        r = MsiEnumPatchesExW( package->ProductCode, NULL, package->Context,
+                               MSIPATCHSTATE_APPLIED, index, patch_code, NULL, NULL, NULL, NULL );
+        if (r != ERROR_SUCCESS)
+            break;
+
+        TRACE("found registered patch %s\n", debugstr_w(patch_code));
+
+        r = apply_registered_patch( package, patch_code );
+        if (r != ERROR_SUCCESS)
+        {
+            ERR("registered patch failed to apply %u\n", r);
+            MSI_FreePackage( (MSIOBJECTHDR *)package );
+            return r;
+        }
+
+        index++;
+    }
 
+    *pPackage = package;
     return ERROR_SUCCESS;
 }
 
@@ -1357,6 +1439,7 @@ MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
 {
     MSIPACKAGE *package;
     MSIHANDLE handle = 0;
+    IUnknown *remote_unk;
     IWineMsiRemotePackage *remote_package;
 
     TRACE("(%d)\n",hInstall);
@@ -1367,10 +1450,19 @@ MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
         handle = alloc_msihandle( &package->db->hdr );
         msiobj_release( &package->hdr );
     }
-    else if ((remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall )))
+    else if ((remote_unk = msi_get_remote(hInstall)))
     {
-        IWineMsiRemotePackage_GetActiveDatabase(remote_package, &handle);
-        IWineMsiRemotePackage_Release(remote_package);
+        if (IUnknown_QueryInterface(remote_unk, &IID_IWineMsiRemotePackage,
+                                        (LPVOID *)&remote_package) == S_OK)
+        {
+            IWineMsiRemotePackage_GetActiveDatabase(remote_package, &handle);
+            IWineMsiRemotePackage_Release(remote_package);
+        }
+        else
+        {
+            WARN("remote handle %d is not a package\n", hInstall);
+        }
+        IUnknown_Release(remote_unk);
     }
 
     return handle;
@@ -1621,7 +1713,7 @@ end:
     return r;
 }
 
-static void msi_reset_folders( MSIPACKAGE *package, BOOL source )
+void msi_reset_folders( MSIPACKAGE *package, BOOL source )
 {
     MSIFOLDER *folder;
 
@@ -1640,7 +1732,7 @@ static void msi_reset_folders( MSIPACKAGE *package, BOOL source )
     }
 }
 
-UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
+UINT msi_set_property( MSIDATABASE *db, LPCWSTR szName, LPCWSTR szValue )
 {
     MSIQUERY *view;
     MSIRECORD *row = NULL;
@@ -1664,7 +1756,7 @@ UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
         '`','_','P','r','o','p','e','r','t','y','`',' ','W','H','E','R','E',' ',
         '`','_','P','r','o','p','e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
 
-    TRACE("%p %s %s\n", package, debugstr_w(szName), debugstr_w(szValue));
+    TRACE("%p %s %s\n", db, debugstr_w(szName), debugstr_w(szValue));
 
     if (!szName)
         return ERROR_INVALID_PARAMETER;
@@ -1673,7 +1765,7 @@ UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
     if (!szName[0])
         return szValue ? ERROR_FUNCTION_FAILED : ERROR_SUCCESS;
 
-    rc = MSI_GetPropertyW(package, szName, 0, &sz);
+    rc = msi_get_property(db, szName, 0, &sz);
     if (!szValue || !*szValue)
     {
         sprintfW(Query, Delete, szName);
@@ -1694,7 +1786,7 @@ UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
         MSI_RecordSetStringW(row, 2, szValue);
     }
 
-    rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
+    rc = MSI_DatabaseOpenViewW(db, Query, &view);
     if (rc == ERROR_SUCCESS)
     {
         rc = MSI_ViewExecute(view, row);
@@ -1705,9 +1797,6 @@ UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
     if (row)
       msiobj_release(&row->hdr);
 
-    if (rc == ERROR_SUCCESS && (!lstrcmpW(szName, cszSourceDir)))
-        msi_reset_folders(package, TRUE);
-
     return rc;
 }
 
@@ -1754,12 +1843,15 @@ UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue
         return ERROR_SUCCESS;
     }
 
-    ret = MSI_SetPropertyW( package, szName, szValue);
+    ret = msi_set_property( package->db, szName, szValue );
+    if (ret == ERROR_SUCCESS && !strcmpW( szName, cszSourceDir ))
+        msi_reset_folders( package, TRUE );
+
     msiobj_release( &package->hdr );
     return ret;
 }
 
-static MSIRECORD *MSI_GetPropertyRow( MSIPACKAGE *package, LPCWSTR name )
+static MSIRECORD *msi_get_property_row( MSIDATABASE *db, LPCWSTR name )
 {
     MSIQUERY *view;
     MSIRECORD *rec, *row = NULL;
@@ -1780,7 +1872,7 @@ static MSIRECORD *MSI_GetPropertyRow( MSIPACKAGE *package, LPCWSTR name )
 
     MSI_RecordSetStringW(rec, 1, name);
 
-    r = MSI_DatabaseOpenViewW(package->db, query, &view);
+    r = MSI_DatabaseOpenViewW(db, query, &view);
     if (r == ERROR_SUCCESS)
     {
         MSI_ViewExecute(view, rec);
@@ -1794,13 +1886,13 @@ static MSIRECORD *MSI_GetPropertyRow( MSIPACKAGE *package, LPCWSTR name )
 }
 
 /* internal function, not compatible with MsiGetPropertyW */
-UINT MSI_GetPropertyW( MSIPACKAGE *package, LPCWSTR szName, 
+UINT msi_get_property( MSIDATABASE *db, LPCWSTR szName,
                        LPWSTR szValueBuf, LPDWORD pchValueBuf )
 {
     MSIRECORD *row;
     UINT rc = ERROR_FUNCTION_FAILED;
 
-    row = MSI_GetPropertyRow( package, szName );
+    row = msi_get_property_row( db, szName );
 
     if (*pchValueBuf > 0)
         szValueBuf[0] = 0;
@@ -1826,19 +1918,19 @@ UINT MSI_GetPropertyW( MSIPACKAGE *package, LPCWSTR szName,
     return rc;
 }
 
-LPWSTR msi_dup_property(MSIPACKAGE *package, LPCWSTR prop)
+LPWSTR msi_dup_property(MSIDATABASE *db, LPCWSTR prop)
 {
     DWORD sz = 0;
     LPWSTR str;
     UINT r;
 
-    r = MSI_GetPropertyW(package, prop, NULL, &sz);
+    r = msi_get_property(db, prop, NULL, &sz);
     if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
         return NULL;
 
     sz++;
     str = msi_alloc(sz * sizeof(WCHAR));
-    r = MSI_GetPropertyW(package, prop, str, &sz);
+    r = msi_get_property(db, prop, str, &sz);
     if (r != ERROR_SUCCESS)
     {
         msi_free(str);
@@ -1848,9 +1940,9 @@ LPWSTR msi_dup_property(MSIPACKAGE *package, LPCWSTR prop)
     return str;
 }
 
-int msi_get_property_int(MSIPACKAGE *package, LPCWSTR prop, int def)
+int msi_get_property_int( MSIDATABASE *db, LPCWSTR prop, int def )
 {
-    LPWSTR str = msi_dup_property(package, prop);
+    LPWSTR str = msi_dup_property( db, prop );
     int val = str ? atoiW(str) : def;
     msi_free(str);
     return val;
@@ -1929,7 +2021,7 @@ done:
         return r;
     }
 
-    row = MSI_GetPropertyRow( package, name );
+    row = msi_get_property_row( package->db, name );
     if (row)
         val = MSI_RecordGetString( row, 1 );
 
index 1cbdcc9..518303f 100644 (file)
@@ -183,6 +183,16 @@ static const WCHAR szUserDataPatch_fmt[] = {
 'U','s','e','r','D','a','t','a','\\',
 '%','s','\\','P','a','t','c','h','e','s','\\','%','s',0};
 
+static const WCHAR szUserDataProductPatches_fmt[] = {
+'S','o','f','t','w','a','r','e','\\',
+'M','i','c','r','o','s','o','f','t','\\',
+'W','i','n','d','o','w','s','\\',
+'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
+'I','n','s','t','a','l','l','e','r','\\',
+'U','s','e','r','D','a','t','a','\\',
+'%','s','\\','P','r','o','d','u','c','t','s','\\','%','s','\\',
+'P','a','t','c','h','e','s',0};
+
 static const WCHAR szInstallProperties_fmt[] = {
 'S','o','f','t','w','a','r','e','\\',
 'M','i','c','r','o','s','o','f','t','\\',
@@ -286,7 +296,7 @@ BOOL squash_guid(LPCWSTR in, LPWSTR out)
 
     out[0] = 0;
 
-    if (FAILED(CLSIDFromString((LPOLESTR)in, &guid)))
+    if (FAILED(CLSIDFromString((LPCOLESTR)in, &guid)))
         return FALSE;
 
     for(i=0; i<8; i++)
@@ -887,6 +897,69 @@ UINT MSIREG_OpenUserDataPatchKey(LPCWSTR szPatch, MSIINSTALLCONTEXT dwContext,
     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
 }
 
+UINT MSIREG_DeleteUserDataPatchKey(LPCWSTR patch, MSIINSTALLCONTEXT context)
+{
+    UINT r;
+    WCHAR squished_patch[GUID_SIZE];
+    WCHAR keypath[0x200];
+    LPWSTR usersid;
+
+    TRACE("%s\n", debugstr_w(patch));
+    if (!squash_guid(patch, squished_patch))
+        return ERROR_FUNCTION_FAILED;
+    TRACE("squished (%s)\n", debugstr_w(squished_patch));
+
+    if (context == MSIINSTALLCONTEXT_MACHINE)
+        sprintfW(keypath, szUserDataPatch_fmt, szLocalSid, squished_patch);
+    else
+    {
+        r = get_user_sid(&usersid);
+        if (r != ERROR_SUCCESS || !usersid)
+        {
+            ERR("Failed to retrieve user SID: %d\n", r);
+            return r;
+        }
+
+        sprintfW(keypath, szUserDataPatch_fmt, usersid, squished_patch);
+        LocalFree(usersid);
+    }
+
+    return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
+}
+
+UINT MSIREG_OpenUserDataProductPatchesKey(LPCWSTR product, MSIINSTALLCONTEXT context,
+                                          HKEY *key, BOOL create)
+{
+    UINT rc;
+    WCHAR squished_product[GUID_SIZE];
+    WCHAR keypath[0x200];
+    LPWSTR usersid;
+
+    TRACE("%s\n", debugstr_w(product));
+    if (!squash_guid(product, squished_product))
+        return ERROR_FUNCTION_FAILED;
+
+    if (context == MSIINSTALLCONTEXT_MACHINE)
+        sprintfW(keypath, szUserDataProductPatches_fmt, szLocalSid, squished_product);
+    else
+    {
+        rc = get_user_sid(&usersid);
+        if (rc != ERROR_SUCCESS || !usersid)
+        {
+            ERR("Failed to retrieve user SID: %d\n", rc);
+            return rc;
+        }
+
+        sprintfW(keypath, szUserDataProductPatches_fmt, usersid, squished_product);
+        LocalFree(usersid);
+    }
+
+    if (create)
+        return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
+
+    return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
+}
+
 UINT MSIREG_OpenInstallProps(LPCWSTR szProduct, MSIINSTALLCONTEXT dwContext,
                              LPCWSTR szUserSid, HKEY *key, BOOL create)
 {
@@ -1156,7 +1229,7 @@ UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct,
     len = ( &p[21] - szDescriptor );
 
     TRACE("length = %d\n", len);
-    *pUsed = len;
+    if (pUsed) *pUsed = len;
 
     return ERROR_SUCCESS;
 }
@@ -1236,17 +1309,13 @@ UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid)
     if (index && index - last_index != 1)
         return ERROR_INVALID_PARAMETER;
 
+    key = 0;
     r = RegCreateKeyW(HKEY_LOCAL_MACHINE, szInstaller_LocalClassesProd, &key);
-    if( r != ERROR_SUCCESS )
-        return ERROR_NO_MORE_ITEMS;
+    if( r != ERROR_SUCCESS ) goto failed;
 
     r = RegQueryInfoKeyW(key, NULL, NULL, NULL, &machine_count, NULL, NULL,
                          NULL, NULL, NULL, NULL, NULL);
-    if( r != ERROR_SUCCESS )
-    {
-        RegCloseKey(key);
-        return ERROR_NO_MORE_ITEMS;
-    }
+    if( r != ERROR_SUCCESS ) goto failed;
 
     if (machine_count && index <= machine_count)
     {
@@ -1261,26 +1330,23 @@ UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid)
     }
     RegCloseKey(key);
 
+    key = 0;
     r = get_user_sid(&usersid);
     if (r != ERROR_SUCCESS || !usersid)
     {
         ERR("Failed to retrieve user SID: %d\n", r);
+        last_index = 0;
         return r;
     }
     sprintfW(keypath, szInstaller_LocalManaged_fmt, usersid);
     LocalFree(usersid);
 
     r = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, &key);
-    if( r != ERROR_SUCCESS )
-        return ERROR_NO_MORE_ITEMS;
+    if( r != ERROR_SUCCESS ) goto failed;
 
     r = RegQueryInfoKeyW(key, NULL, NULL, NULL, &managed_count, NULL, NULL,
                          NULL, NULL, NULL, NULL, NULL);
-    if( r != ERROR_SUCCESS )
-    {
-        RegCloseKey(key);
-        return ERROR_NO_MORE_ITEMS;
-    }
+    if( r != ERROR_SUCCESS ) goto failed;
 
     if (managed_count && index <= machine_count + managed_count)
     {
@@ -1295,17 +1361,13 @@ UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid)
     }
     RegCloseKey(key);
 
+    key = 0;
     r = RegCreateKeyW(HKEY_CURRENT_USER, szUserProduct, &key);
-    if( r != ERROR_SUCCESS )
-        return ERROR_NO_MORE_ITEMS;
+    if( r != ERROR_SUCCESS ) goto failed;
 
     r = RegQueryInfoKeyW(key, NULL, NULL, NULL, &unmanaged_count, NULL, NULL,
                          NULL, NULL, NULL, NULL, NULL);
-    if( r != ERROR_SUCCESS )
-    {
-        RegCloseKey(key);
-        return ERROR_NO_MORE_ITEMS;
-    }
+    if( r != ERROR_SUCCESS ) goto failed;
 
     if (unmanaged_count && index <= machine_count + managed_count + unmanaged_count)
     {
@@ -1318,8 +1380,9 @@ UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid)
             return ERROR_SUCCESS;
         }
     }
+failed:
     RegCloseKey(key);
-
+    last_index = 0;
     return ERROR_NO_MORE_ITEMS;
 }
 
@@ -2051,7 +2114,7 @@ UINT WINAPI MsiEnumPatchesExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
     DWORD idx = 0;
     UINT r;
 
-    static int last_index = 0;
+    static DWORD last_index;
 
     TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p, %p)\n",
           debugstr_w(szProductCode), debugstr_w(szUserSid), dwContext, dwFilter,
@@ -2087,6 +2150,8 @@ UINT WINAPI MsiEnumPatchesExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
 
     if (r == ERROR_SUCCESS)
         last_index = dwIndex;
+    else
+        last_index = 0;
 
     return r;
 }
index 8dfa6d2..4f223da 100644 (file)
@@ -62,7 +62,7 @@ static HRESULT create_ActiveScriptSite(IUnknown *pUnkOuter, LPVOID *ppObj)
     if( pUnkOuter )
         return CLASS_E_NOAGGREGATION;
 
-    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MsiActiveScriptSite));
+    object = msi_alloc_zero( sizeof(MsiActiveScriptSite) );
 
     object->lpVtbl.lpVtbl = &ASS_Vtbl;
     object->ref = 1;
@@ -236,7 +236,7 @@ static ULONG WINAPI MsiActiveScriptSite_Release(IActiveScriptSite* iface)
     TRACE("(%p/%p)\n", iface, This);
 
     if (!ref)
-        HeapFree(GetProcessHeap(), 0, This);
+        msi_free(This);
 
     return ref;
 }
index 6a8134b..3e88874 100644 (file)
@@ -43,7 +43,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msidb);
 typedef struct tabSTORAGE
 {
     UINT str_index;
-    LPWSTR name;
     IStorage *storage;
 } STORAGE;
 
@@ -70,7 +69,7 @@ static BOOL storages_set_table_size(MSISTORAGESVIEW *sv, UINT size)
     return TRUE;
 }
 
-static STORAGE *create_storage(MSISTORAGESVIEW *sv, LPWSTR name, IStorage *stg)
+static STORAGE *create_storage(MSISTORAGESVIEW *sv, LPCWSTR name, IStorage *stg)
 {
     STORAGE *storage;
 
@@ -78,14 +77,7 @@ static STORAGE *create_storage(MSISTORAGESVIEW *sv, LPWSTR name, IStorage *stg)
     if (!storage)
         return NULL;
 
-    storage->name = strdupW(name);
-    if (!storage->name)
-    {
-        msi_free(storage);
-        return NULL;
-    }
-
-    storage->str_index = msi_addstringW(sv->db->strings, 0, storage->name, -1, 1, StringNonPersistent);
+    storage->str_index = msi_addstringW(sv->db->strings, name, -1, 1, StringNonPersistent);
     storage->storage = stg;
 
     if (storage->storage)
@@ -436,8 +428,6 @@ static UINT STORAGES_delete(struct tagMSIVIEW *view)
     {
         if (sv->storages[i]->storage)
             IStorage_Release(sv->storages[i]->storage);
-
-        msi_free(sv->storages[i]->name);
         msi_free(sv->storages[i]);
     }
 
index 66bda76..59e845d 100644 (file)
@@ -68,7 +68,7 @@ static BOOL streams_set_table_size(MSISTREAMSVIEW *sv, UINT size)
     return TRUE;
 }
 
-static STREAM *create_stream(MSISTREAMSVIEW *sv, LPWSTR name, BOOL encoded, IStream *stm)
+static STREAM *create_stream(MSISTREAMSVIEW *sv, LPCWSTR name, BOOL encoded, IStream *stm)
 {
     STREAM *stream;
     WCHAR decoded[MAX_STREAM_NAME_LEN];
@@ -84,7 +84,7 @@ static STREAM *create_stream(MSISTREAMSVIEW *sv, LPWSTR name, BOOL encoded, IStr
         name = decoded;
     }
 
-    stream->str_index = msi_addstringW(sv->db->strings, 0, name, -1, 1, StringNonPersistent);
+    stream->str_index = msi_addstringW(sv->db->strings, name, -1, 1, StringNonPersistent);
     stream->stream = stm;
     return stream;
 }
@@ -183,7 +183,7 @@ static UINT STREAMS_set_row(struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, U
     }
 
     encname = encode_streamname(FALSE, name);
-    IStorage_DestroyElement(sv->db->storage, encname);
+    db_destroy_stream(sv->db, encname);
 
     r = write_stream_data(sv->db->storage, name, data, count, FALSE);
     if (r != ERROR_SUCCESS)
index 3bdc436..21b1db2 100644 (file)
@@ -44,8 +44,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(msidb);
 
 typedef struct _msistring
 {
-    UINT persistent_refcount;
-    UINT nonpersistent_refcount;
+    USHORT persistent_refcount;
+    USHORT nonpersistent_refcount;
     LPWSTR str;
 } msistring;
 
@@ -188,7 +188,7 @@ static void insert_string_sorted( string_table *st, UINT string_id )
     st->sortcount++;
 }
 
-static void set_st_entry( string_table *st, UINT n, LPWSTR str, UINT refcount, enum StringPersistence persistence )
+static void set_st_entry( string_table *st, UINT n, LPWSTR str, USHORT refcount, enum StringPersistence persistence )
 {
     if (persistence == StringPersistent)
     {
@@ -237,7 +237,7 @@ static UINT msi_string2idA( const string_table *st, LPCSTR buffer, UINT *id )
     return r;
 }
 
-static int msi_addstring( string_table *st, UINT n, const CHAR *data, int len, UINT refcount, enum StringPersistence persistence )
+static int msi_addstring( string_table *st, UINT n, const CHAR *data, int len, USHORT refcount, enum StringPersistence persistence )
 {
     LPWSTR str;
     int sz;
@@ -288,42 +288,28 @@ static int msi_addstring( string_table *st, UINT n, const CHAR *data, int len, U
     return n;
 }
 
-int msi_addstringW( string_table *st, UINT n, const WCHAR *data, int len, UINT refcount, enum StringPersistence persistence )
+int msi_addstringW( string_table *st, const WCHAR *data, int len, USHORT refcount, enum StringPersistence persistence )
 {
+    UINT n;
     LPWSTR str;
 
-    /* TRACE("[%2d] = %s\n", string_no, debugstr_an(data,len) ); */
-
     if( !data )
         return 0;
     if( !data[0] )
         return 0;
-    if( n > 0 )
-    {
-        if( st->strings[n].persistent_refcount ||
-            st->strings[n].nonpersistent_refcount )
-            return -1;
-    }
-    else
+
+    if( msi_string2idW( st, data, &n ) == ERROR_SUCCESS )
     {
-        if( ERROR_SUCCESS == msi_string2idW( st, data, &n ) )
-        {
-            if (persistence == StringPersistent)
-                st->strings[n].persistent_refcount += refcount;
-            else
-                st->strings[n].nonpersistent_refcount += refcount;
-            return n;
-        }
-        n = st_find_free_entry( st );
-        if( n == -1 )
-            return -1;
+        if (persistence == StringPersistent)
+            st->strings[n].persistent_refcount += refcount;
+        else
+            st->strings[n].nonpersistent_refcount += refcount;
+        return n;
     }
 
-    if( n < 1 )
-    {
-        ERR("invalid index adding %s (%d)\n", debugstr_w( data ), n );
+    n = st_find_free_entry( st );
+    if( n == -1 )
         return -1;
-    }
 
     /* allocate a new string */
     if(len<0)
index 6737ac5..3b117ae 100644 (file)
@@ -1383,7 +1383,7 @@ static UINT TABLE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UI
                 if ( r != ERROR_SUCCESS )
                 {
                     LPCWSTR sval = MSI_RecordGetString( rec, i + 1 );
-                    val = msi_addstringW( tv->db->strings, 0, sval, -1, 1,
+                    val = msi_addstringW( tv->db->strings, sval, -1, 1,
                       persistent ? StringPersistent : StringNonPersistent );
 
                 }
index a440070..b131d66 100644 (file)
@@ -61,8 +61,9 @@ static void append_productcode(MSIPACKAGE* package, LPCWSTR action_property,
     LPWSTR prop;
     LPWSTR newprop;
     DWORD len;
+    UINT r;
 
-    prop = msi_dup_property(package, action_property );
+    prop = msi_dup_property(package->db, action_property );
     if (prop)
         len = strlenW(prop);
     else
@@ -87,9 +88,13 @@ static void append_productcode(MSIPACKAGE* package, LPCWSTR action_property,
         newprop[0] = 0;
     strcatW(newprop,productid);
 
-    MSI_SetPropertyW(package, action_property, newprop);
-    TRACE("Found Related Product... %s now %s\n",debugstr_w(action_property),
-                    debugstr_w(newprop));
+    r = msi_set_property( package->db, action_property, newprop );
+    if (r == ERROR_SUCCESS && !strcmpW( action_property, cszSourceDir ))
+        msi_reset_folders( package, TRUE );
+
+    TRACE("Found Related Product... %s now %s\n",
+          debugstr_w(action_property), debugstr_w(newprop));
+
     msi_free( prop );
     msi_free( newprop );
 }
@@ -146,26 +151,30 @@ static UINT ITERATE_FindRelatedProducts(MSIRECORD *rec, LPVOID param)
                     (LPBYTE)&check, &sz);
             /* check min */
             ver = MSI_RecordGetString(rec,2);
-            comp_ver = msi_version_str_to_dword(ver);
-            r = check - comp_ver; 
-            if (r < 0 || (r == 0 && !(attributes &
-                                    msidbUpgradeAttributesVersionMinInclusive)))
+            if (ver)
             {
-                RegCloseKey(hukey);
-                index ++;
-                continue;
+                comp_ver = msi_version_str_to_dword(ver);
+                r = check - comp_ver;
+                if (r < 0 || (r == 0 && !(attributes & msidbUpgradeAttributesVersionMinInclusive)))
+                {
+                    RegCloseKey(hukey);
+                    index ++;
+                    continue;
+                }
             }
 
             /* check max */
             ver = MSI_RecordGetString(rec,3);
-            comp_ver = msi_version_str_to_dword(ver);
-            r = check - comp_ver;
-            if (r > 0 || (r == 0 && !(attributes & 
-                                    msidbUpgradeAttributesVersionMaxInclusive)))
+            if (ver)
             {
-                RegCloseKey(hukey);
-                index ++;
-                continue;
+                comp_ver = msi_version_str_to_dword(ver);
+                r = check - comp_ver;
+                if (r > 0 || (r == 0 && !(attributes & msidbUpgradeAttributesVersionMaxInclusive)))
+                {
+                    RegCloseKey(hukey);
+                    index ++;
+                    continue;
+                }
             }
 
             /* check language*/
@@ -203,19 +212,19 @@ UINT ACTION_FindRelatedProducts(MSIPACKAGE *package)
     UINT rc = ERROR_SUCCESS;
     MSIQUERY *view;
 
-    if (msi_get_property_int(package, szInstalled, 0))
+    if (msi_get_property_int(package->db, szInstalled, 0))
     {
         TRACE("Skipping FindRelatedProducts action: product already installed\n");
         return ERROR_SUCCESS;
     }
 
-    if (check_unique_action(package,szFindRelatedProducts))
+    if (check_unique_action(package, szFindRelatedProducts))
     {
-        TRACE("Skipping FindRelatedProducts action: already done on client side\n");
+        TRACE("Skipping FindRelatedProducts action: already done in UI sequence\n");
         return ERROR_SUCCESS;
     }
     else
-        register_unique_action(package,szFindRelatedProducts);
+        register_unique_action(package, szFindRelatedProducts);
 
     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
     if (rc != ERROR_SUCCESS)