msi/tests: Move some tests around to avoid timeouts on the testbot.

Hans Leidekker hans at codeweavers.com
Mon Jun 10 11:58:30 CDT 2013


---
 dlls/msi/tests/install.c |  565 +--------------------------
 dlls/msi/tests/msi.c     |  968 +++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 968 insertions(+), 565 deletions(-)

diff --git a/dlls/msi/tests/install.c b/dlls/msi/tests/install.c
index e910fa0..e97ce6b 100644
--- a/dlls/msi/tests/install.c
+++ b/dlls/msi/tests/install.c
@@ -38,8 +38,6 @@ static UINT (WINAPI *pMsiQueryComponentStateA)
     (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, LPCSTR, INSTALLSTATE*);
 static UINT (WINAPI *pMsiSourceListEnumSourcesA)
     (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, DWORD, LPSTR, LPDWORD);
-static UINT (WINAPI *pMsiSourceListGetInfoA)
-    (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, LPCSTR, LPSTR, LPDWORD);
 static INSTALLSTATE (WINAPI *pMsiGetComponentPathExA)
     (LPCSTR, LPCSTR, LPCSTR, MSIINSTALLCONTEXT, LPSTR, LPDWORD);
 
@@ -496,11 +494,6 @@ static const CHAR rofc_media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\
                                      "Media\tDiskId\n"
                                      "1\t1\t\ttest1.cab\tDISK1\t\n";
 
-static const CHAR lus2_media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
-                                     "i2\ti4\tL64\tS255\tS32\tS72\n"
-                                     "Media\tDiskId\n"
-                                     "1\t1\t\t#test1.cab\tDISK1\t\n";
-
 static const CHAR sdp_install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
                                                "s72\tS255\tI2\n"
                                                "InstallExecuteSequence\tAction\n"
@@ -602,33 +595,6 @@ static const CHAR ci2_file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersio
                                    "File\tFile\n"
                                    "augustus\taugustus\taugustus\t500\t\t\t8192\t1";
 
-static const CHAR spf_custom_action_dat[] = "Action\tType\tSource\tTarget\tISComments\n"
-                                            "s72\ti2\tS64\tS0\tS255\n"
-                                            "CustomAction\tAction\n"
-                                            "SetFolderProp\t51\tMSITESTDIR\t[ProgramFilesFolder]\\msitest\\added\t\n";
-
-static const CHAR spf_install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
-                                               "s72\tS255\tI2\n"
-                                               "InstallExecuteSequence\tAction\n"
-                                               "CostFinalize\t\t1000\n"
-                                               "CostInitialize\t\t800\n"
-                                               "FileCost\t\t900\n"
-                                               "SetFolderProp\t\t950\n"
-                                               "InstallFiles\t\t4000\n"
-                                               "InstallServices\t\t5000\n"
-                                               "InstallFinalize\t\t6600\n"
-                                               "InstallInitialize\t\t1500\n"
-                                               "InstallValidate\t\t1400\n"
-                                               "LaunchConditions\t\t100";
-
-static const CHAR spf_install_ui_seq_dat[] = "Action\tCondition\tSequence\n"
-                                             "s72\tS255\tI2\n"
-                                             "InstallUISequence\tAction\n"
-                                             "CostInitialize\t\t800\n"
-                                             "FileCost\t\t900\n"
-                                             "CostFinalize\t\t1000\n"
-                                             "ExecuteAction\t\t1100\n";
-
 static const CHAR pp_install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
                                               "s72\tS255\tI2\n"
                                               "InstallExecuteSequence\tAction\n"
@@ -1042,140 +1008,6 @@ static const CHAR fo_install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
                                               "PublishProduct\t\t5200\n"
                                               "InstallFinalize\t\t6000\n";
 
-static const CHAR sd_file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
-                                  "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
-                                  "File\tFile\n"
-                                  "sourcedir.txt\tsourcedir\tsourcedir.txt\t1000\t\t\t8192\t1\n";
-
-static const CHAR sd_feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
-                                     "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
-                                     "Feature\tFeature\n"
-                                     "sourcedir\t\t\tsourcedir feature\t1\t2\tMSITESTDIR\t0\n";
-
-static const CHAR sd_feature_comp_dat[] = "Feature_\tComponent_\n"
-                                          "s38\ts72\n"
-                                          "FeatureComponents\tFeature_\tComponent_\n"
-                                          "sourcedir\tsourcedir\n";
-
-static const CHAR sd_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
-                                       "s72\tS38\ts72\ti2\tS255\tS72\n"
-                                       "Component\tComponent\n"
-                                       "sourcedir\t{DD422F92-3ED8-49B5-A0B7-F266F98357DF}\tMSITESTDIR\t0\t\tsourcedir.txt\n";
-
-static const CHAR sd_install_ui_seq_dat[] = "Action\tCondition\tSequence\n"
-                                            "s72\tS255\tI2\n"
-                                            "InstallUISequence\tAction\n"
-                                            "TestSourceDirProp1\tnot SourceDir and not SOURCEDIR and not Installed\t99\n"
-                                            "AppSearch\t\t100\n"
-                                            "TestSourceDirProp2\tnot SourceDir and not SOURCEDIR and not Installed\t101\n"
-                                            "LaunchConditions\tnot Installed \t110\n"
-                                            "TestSourceDirProp3\tnot SourceDir and not SOURCEDIR and not Installed\t111\n"
-                                            "FindRelatedProducts\t\t120\n"
-                                            "TestSourceDirProp4\tnot SourceDir and not SOURCEDIR and not Installed\t121\n"
-                                            "CCPSearch\t\t130\n"
-                                            "TestSourceDirProp5\tnot SourceDir and not SOURCEDIR and not Installed\t131\n"
-                                            "RMCCPSearch\t\t140\n"
-                                            "TestSourceDirProp6\tnot SourceDir and not SOURCEDIR and not Installed\t141\n"
-                                            "ValidateProductID\t\t150\n"
-                                            "TestSourceDirProp7\tnot SourceDir and not SOURCEDIR and not Installed\t151\n"
-                                            "CostInitialize\t\t800\n"
-                                            "TestSourceDirProp8\tnot SourceDir and not SOURCEDIR and not Installed\t801\n"
-                                            "FileCost\t\t900\n"
-                                            "TestSourceDirProp9\tnot SourceDir and not SOURCEDIR and not Installed\t901\n"
-                                            "IsolateComponents\t\t1000\n"
-                                            "TestSourceDirProp10\tnot SourceDir and not SOURCEDIR and not Installed\t1001\n"
-                                            "CostFinalize\t\t1100\n"
-                                            "TestSourceDirProp11\tnot SourceDir and not SOURCEDIR and not Installed\t1101\n"
-                                            "MigrateFeatureStates\t\t1200\n"
-                                            "TestSourceDirProp12\tnot SourceDir and not SOURCEDIR and not Installed\t1201\n"
-                                            "ExecuteAction\t\t1300\n"
-                                            "TestSourceDirProp13\tnot SourceDir and not SOURCEDIR and not Installed\t1301\n";
-
-static const CHAR sd_install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
-                                              "s72\tS255\tI2\n"
-                                              "InstallExecuteSequence\tAction\n"
-                                              "TestSourceDirProp14\tSourceDir and SOURCEDIR and not Installed\t99\n"
-                                              "LaunchConditions\t\t100\n"
-                                              "TestSourceDirProp15\tSourceDir and SOURCEDIR and not Installed\t101\n"
-                                              "ValidateProductID\t\t700\n"
-                                              "TestSourceDirProp16\tSourceDir and SOURCEDIR and not Installed\t701\n"
-                                              "CostInitialize\t\t800\n"
-                                              "TestSourceDirProp17\tSourceDir and SOURCEDIR and not Installed\t801\n"
-                                              "ResolveSource\tResolveSource and not Installed\t850\n"
-                                              "TestSourceDirProp18\tResolveSource and not SourceDir and not SOURCEDIR and not Installed\t851\n"
-                                              "TestSourceDirProp19\tnot ResolveSource and SourceDir and SOURCEDIR and not Installed\t852\n"
-                                              "FileCost\t\t900\n"
-                                              "TestSourceDirProp20\tSourceDir and SOURCEDIR and not Installed\t901\n"
-                                              "IsolateComponents\t\t1000\n"
-                                              "TestSourceDirProp21\tSourceDir and SOURCEDIR and not Installed\t1001\n"
-                                              "CostFinalize\t\t1100\n"
-                                              "TestSourceDirProp22\tSourceDir and SOURCEDIR and not Installed\t1101\n"
-                                              "MigrateFeatureStates\t\t1200\n"
-                                              "TestSourceDirProp23\tSourceDir and SOURCEDIR and not Installed\t1201\n"
-                                              "InstallValidate\t\t1400\n"
-                                              "TestSourceDirProp24\tSourceDir and SOURCEDIR and not Installed\t1401\n"
-                                              "InstallInitialize\t\t1500\n"
-                                              "TestSourceDirProp25\tSourceDir and SOURCEDIR and not Installed\t1501\n"
-                                              "ProcessComponents\t\t1600\n"
-                                              "TestSourceDirProp26\tnot SourceDir and not SOURCEDIR and not Installed\t1601\n"
-                                              "UnpublishFeatures\t\t1800\n"
-                                              "TestSourceDirProp27\tnot SourceDir and not SOURCEDIR and not Installed\t1801\n"
-                                              "RemoveFiles\t\t3500\n"
-                                              "TestSourceDirProp28\tnot SourceDir and not SOURCEDIR and not Installed\t3501\n"
-                                              "InstallFiles\t\t4000\n"
-                                              "TestSourceDirProp29\tnot SourceDir and not SOURCEDIR and not Installed\t4001\n"
-                                              "RegisterUser\t\t6000\n"
-                                              "TestSourceDirProp30\tnot SourceDir and not SOURCEDIR and not Installed\t6001\n"
-                                              "RegisterProduct\t\t6100\n"
-                                              "TestSourceDirProp31\tnot SourceDir and not SOURCEDIR and not Installed\t6101\n"
-                                              "PublishFeatures\t\t6300\n"
-                                              "TestSourceDirProp32\tnot SourceDir and not SOURCEDIR and not Installed\t6301\n"
-                                              "PublishProduct\t\t6400\n"
-                                              "TestSourceDirProp33\tnot SourceDir and not SOURCEDIR and not Installed\t6401\n"
-                                              "InstallExecute\t\t6500\n"
-                                              "TestSourceDirProp34\tnot SourceDir and not SOURCEDIR and not Installed\t6501\n"
-                                              "InstallFinalize\t\t6600\n"
-                                              "TestSourceDirProp35\tnot SourceDir and not SOURCEDIR and not Installed\t6601\n";
-
-static const CHAR sd_custom_action_dat[] = "Action\tType\tSource\tTarget\tISComments\n"
-                                           "s72\ti2\tS64\tS0\tS255\n"
-                                           "CustomAction\tAction\n"
-                                           "TestSourceDirProp1\t19\t\tTest 1 failed\t\n"
-                                           "TestSourceDirProp2\t19\t\tTest 2 failed\t\n"
-                                           "TestSourceDirProp3\t19\t\tTest 3 failed\t\n"
-                                           "TestSourceDirProp4\t19\t\tTest 4 failed\t\n"
-                                           "TestSourceDirProp5\t19\t\tTest 5 failed\t\n"
-                                           "TestSourceDirProp6\t19\t\tTest 6 failed\t\n"
-                                           "TestSourceDirProp7\t19\t\tTest 7 failed\t\n"
-                                           "TestSourceDirProp8\t19\t\tTest 8 failed\t\n"
-                                           "TestSourceDirProp9\t19\t\tTest 9 failed\t\n"
-                                           "TestSourceDirProp10\t19\t\tTest 10 failed\t\n"
-                                           "TestSourceDirProp11\t19\t\tTest 11 failed\t\n"
-                                           "TestSourceDirProp12\t19\t\tTest 12 failed\t\n"
-                                           "TestSourceDirProp13\t19\t\tTest 13 failed\t\n"
-                                           "TestSourceDirProp14\t19\t\tTest 14 failed\t\n"
-                                           "TestSourceDirProp15\t19\t\tTest 15 failed\t\n"
-                                           "TestSourceDirProp16\t19\t\tTest 16 failed\t\n"
-                                           "TestSourceDirProp17\t19\t\tTest 17 failed\t\n"
-                                           "TestSourceDirProp18\t19\t\tTest 18 failed\t\n"
-                                           "TestSourceDirProp19\t19\t\tTest 19 failed\t\n"
-                                           "TestSourceDirProp20\t19\t\tTest 20 failed\t\n"
-                                           "TestSourceDirProp21\t19\t\tTest 21 failed\t\n"
-                                           "TestSourceDirProp22\t19\t\tTest 22 failed\t\n"
-                                           "TestSourceDirProp23\t19\t\tTest 23 failed\t\n"
-                                           "TestSourceDirProp24\t19\t\tTest 24 failed\t\n"
-                                           "TestSourceDirProp25\t19\t\tTest 25 failed\t\n"
-                                           "TestSourceDirProp26\t19\t\tTest 26 failed\t\n"
-                                           "TestSourceDirProp27\t19\t\tTest 27 failed\t\n"
-                                           "TestSourceDirProp28\t19\t\tTest 28 failed\t\n"
-                                           "TestSourceDirProp29\t19\t\tTest 29 failed\t\n"
-                                           "TestSourceDirProp30\t19\t\tTest 30 failed\t\n"
-                                           "TestSourceDirProp31\t19\t\tTest 31 failed\t\n"
-                                           "TestSourceDirProp32\t19\t\tTest 32 failed\t\n"
-                                           "TestSourceDirProp33\t19\t\tTest 33 failed\t\n"
-                                           "TestSourceDirProp34\t19\t\tTest 34 failed\t\n"
-                                           "TestSourceDirProp35\t19\t\tTest 35 failed\t\n";
-
 static const CHAR cl_custom_action_dat[] = "Action\tType\tSource\tTarget\tISComments\n"
                                            "s72\ti2\tS64\tS0\tS255\n"
                                            "CustomAction\tAction\n"
@@ -1675,56 +1507,6 @@ static const msi_table ci2_tables[] =
     ADD_TABLE(property),
 };
 
-static const msi_table spf_tables[] =
-{
-    ADD_TABLE(ci_component),
-    ADD_TABLE(directory),
-    ADD_TABLE(rof_feature),
-    ADD_TABLE(rof_feature_comp),
-    ADD_TABLE(rof_file),
-    ADD_TABLE(spf_install_exec_seq),
-    ADD_TABLE(rof_media),
-    ADD_TABLE(property),
-    ADD_TABLE(spf_custom_action),
-    ADD_TABLE(spf_install_ui_seq),
-};
-
-static const msi_table lus0_tables[] =
-{
-    ADD_TABLE(ci_component),
-    ADD_TABLE(directory),
-    ADD_TABLE(rof_feature),
-    ADD_TABLE(rof_feature_comp),
-    ADD_TABLE(rof_file),
-    ADD_TABLE(pp_install_exec_seq),
-    ADD_TABLE(rof_media),
-    ADD_TABLE(property),
-};
-
-static const msi_table lus1_tables[] =
-{
-    ADD_TABLE(ci_component),
-    ADD_TABLE(directory),
-    ADD_TABLE(rof_feature),
-    ADD_TABLE(rof_feature_comp),
-    ADD_TABLE(rof_file),
-    ADD_TABLE(pp_install_exec_seq),
-    ADD_TABLE(rofc_media),
-    ADD_TABLE(property),
-};
-
-static const msi_table lus2_tables[] =
-{
-    ADD_TABLE(ci_component),
-    ADD_TABLE(directory),
-    ADD_TABLE(rof_feature),
-    ADD_TABLE(rof_feature_comp),
-    ADD_TABLE(rof_file),
-    ADD_TABLE(pp_install_exec_seq),
-    ADD_TABLE(lus2_media),
-    ADD_TABLE(property),
-};
-
 static const msi_table tp_tables[] =
 {
     ADD_TABLE(tp_component),
@@ -1962,20 +1744,6 @@ static const msi_table fiuc_tables[] =
     ADD_TABLE(property),
 };
 
-static const msi_table sd_tables[] =
-{
-    ADD_TABLE(directory),
-    ADD_TABLE(sd_component),
-    ADD_TABLE(sd_feature),
-    ADD_TABLE(sd_feature_comp),
-    ADD_TABLE(sd_file),
-    ADD_TABLE(sd_install_exec_seq),
-    ADD_TABLE(sd_install_ui_seq),
-    ADD_TABLE(sd_custom_action),
-    ADD_TABLE(media),
-    ADD_TABLE(property)
-};
-
 static const msi_table fo_tables[] =
 {
     ADD_TABLE(directory),
@@ -2187,7 +1955,6 @@ static void init_functionpointers(void)
 
     GET_PROC(hmsi, MsiQueryComponentStateA);
     GET_PROC(hmsi, MsiSourceListEnumSourcesA);
-    GET_PROC(hmsi, MsiSourceListGetInfoA);
     GET_PROC(hmsi, MsiGetComponentPathExA);
 
     GET_PROC(hadvapi32, ConvertSidToStringSidA);
@@ -3504,167 +3271,6 @@ error:
     DeleteFile(msifile);
 }
 
-static BOOL add_cabinet_storage(LPCSTR db, LPCSTR cabinet)
-{
-    WCHAR dbW[MAX_PATH], cabinetW[MAX_PATH];
-    IStorage *stg;
-    IStream *stm;
-    HRESULT hr;
-    HANDLE handle;
-
-    MultiByteToWideChar(CP_ACP, 0, db, -1, dbW, MAX_PATH);
-    hr = StgOpenStorage(dbW, NULL, STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
-    if (FAILED(hr))
-        return FALSE;
-
-    MultiByteToWideChar(CP_ACP, 0, cabinet, -1, cabinetW, MAX_PATH);
-    hr = IStorage_CreateStream(stg, cabinetW, STGM_WRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
-    if (FAILED(hr))
-    {
-        IStorage_Release(stg);
-        return FALSE;
-    }
-
-    handle = CreateFileW(cabinetW, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
-    if (handle != INVALID_HANDLE_VALUE)
-    {
-        DWORD count;
-        char buffer[1024];
-        if (ReadFile(handle, buffer, sizeof(buffer), &count, NULL))
-            IStream_Write(stm, buffer, count, &count);
-        CloseHandle(handle);
-    }
-
-    IStream_Release(stm);
-    IStorage_Release(stg);
-
-    return TRUE;
-}
-
-static void test_lastusedsource(void)
-{
-    static char prodcode[] = "{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}";
-
-    UINT r;
-    char value[MAX_PATH], path[MAX_PATH];
-    DWORD size;
-
-    if (!pMsiSourceListGetInfoA)
-    {
-        win_skip("MsiSourceListGetInfoA is not available\n");
-        return;
-    }
-
-    CreateDirectoryA("msitest", NULL);
-    create_file("maximus", 500);
-    create_cab_file("test1.cab", MEDIA_SIZE, "maximus\0");
-    DeleteFile("maximus");
-
-    create_database("msifile0.msi", lus0_tables, sizeof(lus0_tables) / sizeof(msi_table));
-    create_database("msifile1.msi", lus1_tables, sizeof(lus1_tables) / sizeof(msi_table));
-    create_database("msifile2.msi", lus2_tables, sizeof(lus2_tables) / sizeof(msi_table));
-
-    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
-
-    /* no cabinet file */
-
-    size = MAX_PATH;
-    lstrcpyA(value, "aaa");
-    r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
-                               MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, value, &size);
-    ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %u\n", r);
-    ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value);
-
-    r = MsiInstallProductA("msifile0.msi", "PUBLISH_PRODUCT=1");
-    if (r == ERROR_INSTALL_PACKAGE_REJECTED)
-    {
-        skip("Not enough rights to perform tests\n");
-        goto error;
-    }
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-
-    lstrcpyA(path, CURR_DIR);
-    lstrcatA(path, "\\");
-
-    size = MAX_PATH;
-    lstrcpyA(value, "aaa");
-    r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
-                               MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, value, &size);
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-    ok(!lstrcmpA(value, path), "Expected \"%s\", got \"%s\"\n", path, value);
-    ok(size == lstrlenA(path), "Expected %d, got %d\n", lstrlenA(path), size);
-
-    r = MsiInstallProductA("msifile0.msi", "REMOVE=ALL");
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-
-    /* separate cabinet file */
-
-    size = MAX_PATH;
-    lstrcpyA(value, "aaa");
-    r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
-                               MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, value, &size);
-    ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %u\n", r);
-    ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value);
-
-    r = MsiInstallProductA("msifile1.msi", "PUBLISH_PRODUCT=1");
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-
-    lstrcpyA(path, CURR_DIR);
-    lstrcatA(path, "\\");
-
-    size = MAX_PATH;
-    lstrcpyA(value, "aaa");
-    r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
-                               MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, value, &size);
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-    ok(!lstrcmpA(value, path), "Expected \"%s\", got \"%s\"\n", path, value);
-    ok(size == lstrlenA(path), "Expected %d, got %d\n", lstrlenA(path), size);
-
-    r = MsiInstallProductA("msifile1.msi", "REMOVE=ALL");
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-
-    size = MAX_PATH;
-    lstrcpyA(value, "aaa");
-    r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
-                               MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, value, &size);
-    ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %u\n", r);
-    ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value);
-
-    /* embedded cabinet stream */
-
-    add_cabinet_storage("msifile2.msi", "test1.cab");
-
-    r = MsiInstallProductA("msifile2.msi", "PUBLISH_PRODUCT=1");
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-
-    size = MAX_PATH;
-    lstrcpyA(value, "aaa");
-    r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
-                               MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, value, &size);
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-    ok(!lstrcmpA(value, path), "Expected \"%s\", got \"%s\"\n", path, value);
-    ok(size == lstrlenA(path), "Expected %d, got %d\n", lstrlenA(path), size);
-
-    r = MsiInstallProductA("msifile2.msi", "REMOVE=ALL");
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-
-    size = MAX_PATH;
-    lstrcpyA(value, "aaa");
-    r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
-                               MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, value, &size);
-    ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %u\n", r);
-    ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value);
-
-error:
-    /* Delete the files in the temp (current) folder */
-    delete_cab_files();
-    DeleteFile("msitest\\maximus");
-    RemoveDirectory("msitest");
-    DeleteFile("msifile0.msi");
-    DeleteFile("msifile1.msi");
-    DeleteFile("msifile2.msi");
-}
-
 static void test_setdirproperty(void)
 {
     UINT r;
@@ -3746,109 +3352,6 @@ error:
     RemoveDirectory("msitest");
 }
 
-static void test_concurrentinstall(void)
-{
-    UINT r;
-    CHAR path[MAX_PATH];
-
-    if (is_process_limited())
-    {
-        skip("process is limited\n");
-        return;
-    }
-
-    CreateDirectoryA("msitest", NULL);
-    CreateDirectoryA("msitest\\msitest", NULL);
-    create_file("msitest\\maximus", 500);
-    create_file("msitest\\msitest\\augustus", 500);
-
-    create_database(msifile, ci_tables, sizeof(ci_tables) / sizeof(msi_table));
-
-    lstrcpyA(path, CURR_DIR);
-    lstrcatA(path, "\\msitest\\concurrent.msi");
-    create_database(path, ci2_tables, sizeof(ci2_tables) / sizeof(msi_table));
-
-    MsiSetInternalUI(INSTALLUILEVEL_FULL, NULL);
-
-    r = MsiInstallProductA(msifile, NULL);
-    if (r == ERROR_INSTALL_PACKAGE_REJECTED)
-    {
-        skip("Not enough rights to perform tests\n");
-        DeleteFile(path);
-        goto error;
-    }
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-    if (!delete_pf("msitest\\augustus", TRUE))
-        trace("concurrent installs not supported\n");
-    ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n");
-    ok(delete_pf("msitest", FALSE), "Directory not created\n");
-
-    DeleteFile(path);
-
-    r = MsiInstallProductA(msifile, NULL);
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-    ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n");
-    ok(!delete_pf("msitest\\augustus", TRUE), "File installed\n");
-    ok(delete_pf("msitest", FALSE), "Directory not created\n");
-
-error:
-    DeleteFile(msifile);
-    DeleteFile("msitest\\msitest\\augustus");
-    DeleteFile("msitest\\maximus");
-    RemoveDirectory("msitest\\msitest");
-    RemoveDirectory("msitest");
-}
-
-static void test_setpropertyfolder(void)
-{
-    UINT r;
-    CHAR path[MAX_PATH];
-    DWORD attr;
-
-    if (is_process_limited())
-    {
-        skip("process is limited\n");
-        return;
-    }
-
-    lstrcpyA(path, PROG_FILES_DIR);
-    lstrcatA(path, "\\msitest\\added");
-
-    CreateDirectoryA("msitest", NULL);
-    create_file("msitest\\maximus", 500);
-
-    create_database(msifile, spf_tables, sizeof(spf_tables) / sizeof(msi_table));
-
-    MsiSetInternalUI(INSTALLUILEVEL_FULL, NULL);
-
-    r = MsiInstallProductA(msifile, NULL);
-    if (r == ERROR_INSTALL_PACKAGE_REJECTED)
-    {
-        skip("Not enough rights to perform tests\n");
-        goto error;
-    }
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-    attr = GetFileAttributesA(path);
-    if (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
-    {
-        ok(delete_pf("msitest\\added\\maximus", TRUE), "File not installed\n");
-        ok(delete_pf("msitest\\added", FALSE), "Directory not created\n");
-        ok(delete_pf("msitest", FALSE), "Directory not created\n");
-    }
-    else
-    {
-        trace("changing folder property not supported\n");
-        ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n");
-        ok(delete_pf("msitest", FALSE), "Directory not created\n");
-    }
-
-error:
-    /* Delete the files in the temp (current) folder */
-    DeleteFile(msifile);
-    DeleteFile("msitest\\maximus");
-    RemoveDirectory("msitest");
-}
-
 static BOOL file_exists(LPCSTR file)
 {
     return GetFileAttributes(file) != INVALID_FILE_ATTRIBUTES;
@@ -5844,68 +5347,6 @@ static void test_icon_table(void)
     DeleteFile(msifile);
 }
 
-static void test_sourcedir_props(void)
-{
-    UINT r;
-
-    if (is_process_limited())
-    {
-        skip("process is limited\n");
-        return;
-    }
-
-    create_test_files();
-    create_file("msitest\\sourcedir.txt", 1000);
-    create_database(msifile, sd_tables, sizeof(sd_tables) / sizeof(msi_table));
-
-    MsiSetInternalUI(INSTALLUILEVEL_FULL, NULL);
-
-    /* full UI, no ResolveSource action */
-    r = MsiInstallProductA(msifile, NULL);
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-
-    r = MsiInstallProductA(msifile, "REMOVE=ALL");
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-
-    ok(!delete_pf("msitest\\sourcedir.txt", TRUE), "file not removed\n");
-    ok(!delete_pf("msitest", FALSE), "directory not removed\n");
-
-    /* full UI, ResolveSource action */
-    r = MsiInstallProductA(msifile, "ResolveSource=1");
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-
-    r = MsiInstallProductA(msifile, "REMOVE=ALL");
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-
-    ok(!delete_pf("msitest\\sourcedir.txt", TRUE), "file not removed\n");
-    ok(!delete_pf("msitest", FALSE), "directory not removed\n");
-
-    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
-
-    /* no UI, no ResolveSource action */
-    r = MsiInstallProductA(msifile, NULL);
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-
-    r = MsiInstallProductA(msifile, "REMOVE=ALL");
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-
-    ok(!delete_pf("msitest\\sourcedir.txt", TRUE), "file not removed\n");
-    ok(!delete_pf("msitest", FALSE), "directory not removed\n");
-
-    /* no UI, ResolveSource action */
-    r = MsiInstallProductA(msifile, "ResolveSource=1");
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-
-    r = MsiInstallProductA(msifile, "REMOVE=ALL");
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-
-    ok(!delete_pf("msitest\\sourcedir.txt", TRUE), "file not removed\n");
-    ok(!delete_pf("msitest", FALSE), "directory not removed\n");
-
-    DeleteFileA("msitest\\sourcedir.txt");
-    DeleteFile(msifile);
-}
-
 static void test_package_validation(void)
 {
     UINT r;
@@ -6254,7 +5695,7 @@ static void test_command_line_parsing(void)
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
 
     DeleteFile(msifile);
-    RemoveDirectory("msitest");
+    delete_test_files();
 }
 
 static void test_upgrade_code(void)
@@ -6452,8 +5893,6 @@ START_TEST(install)
     test_readonlyfile_cab();
     test_setdirproperty();
     test_cabisextracted();
-    test_concurrentinstall();
-    test_setpropertyfolder();
     test_transformprop();
     test_currentworkingdir();
     test_admin();
@@ -6469,7 +5908,6 @@ START_TEST(install)
     test_propcase();
     test_int_widths();
     test_shortcut();
-    test_lastusedsource();
     test_preselected();
     test_installed_prop();
     test_file_in_use();
@@ -6477,7 +5915,6 @@ START_TEST(install)
     test_allusers_prop();
     test_feature_override();
     test_icon_table();
-    test_sourcedir_props();
     test_package_validation();
     test_command_line_parsing();
     test_upgrade_code();
diff --git a/dlls/msi/tests/msi.c b/dlls/msi/tests/msi.c
index 59ac8e8..6faa376 100644
--- a/dlls/msi/tests/msi.c
+++ b/dlls/msi/tests/msi.c
@@ -19,6 +19,7 @@
  */
 
 #define _WIN32_MSI 300
+#define COBJMACROS
 
 #include <stdio.h>
 #include <windows.h>
@@ -26,6 +27,7 @@
 #include <msiquery.h>
 #include <msidefs.h>
 #include <sddl.h>
+#include <fci.h>
 
 #include "wine/test.h"
 
@@ -67,6 +69,8 @@ static UINT (WINAPI *pMsiEnumComponentsExA)
     (LPCSTR, DWORD, DWORD, CHAR[39], MSIINSTALLCONTEXT *, LPSTR, LPDWORD);
 static UINT (WINAPI *pMsiSetExternalUIRecord)
     (INSTALLUI_HANDLER_RECORD, DWORD, LPVOID, PINSTALLUI_HANDLER_RECORD);
+static UINT (WINAPI *pMsiSourceListGetInfoA)
+    (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, LPCSTR, LPSTR, LPDWORD);
 
 static void init_functionpointers(void)
 {
@@ -91,6 +95,7 @@ static void init_functionpointers(void)
     GET_PROC(hmsi, MsiGetPatchInfoExA)
     GET_PROC(hmsi, MsiEnumProductsExA)
     GET_PROC(hmsi, MsiEnumComponentsExA)
+    GET_PROC(hmsi, MsiSourceListGetInfoA)
 
     GET_PROC(hadvapi32, ConvertSidToStringSidA)
     GET_PROC(hadvapi32, OpenProcessToken);
@@ -176,6 +181,275 @@ static BOOL is_process_limited(void)
     return (ret && type == TokenElevationTypeLimited);
 }
 
+/* cabinet definitions */
+
+/* make the max size large so there is only one cab file */
+#define MEDIA_SIZE          0x7FFFFFFF
+#define FOLDER_THRESHOLD    900000
+
+/* the FCI callbacks */
+
+static void * CDECL mem_alloc(ULONG cb)
+{
+    return HeapAlloc(GetProcessHeap(), 0, cb);
+}
+
+static void CDECL mem_free(void *memory)
+{
+    HeapFree(GetProcessHeap(), 0, memory);
+}
+
+static BOOL CDECL get_next_cabinet(PCCAB pccab, ULONG  cbPrevCab, void *pv)
+{
+    sprintf(pccab->szCab, pv, pccab->iCab);
+    return TRUE;
+}
+
+static LONG CDECL progress(UINT typeStatus, ULONG cb1, ULONG cb2, void *pv)
+{
+    return 0;
+}
+
+static int CDECL file_placed(PCCAB pccab, char *pszFile, LONG cbFile,
+                             BOOL fContinuation, void *pv)
+{
+    return 0;
+}
+
+static INT_PTR CDECL fci_open(char *pszFile, int oflag, int pmode, int *err, void *pv)
+{
+    HANDLE handle;
+    DWORD dwAccess = 0;
+    DWORD dwShareMode = 0;
+    DWORD dwCreateDisposition = OPEN_EXISTING;
+
+    dwAccess = GENERIC_READ | GENERIC_WRITE;
+    /* FILE_SHARE_DELETE is not supported by Windows Me/98/95 */
+    dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+
+    if (GetFileAttributesA(pszFile) != INVALID_FILE_ATTRIBUTES)
+        dwCreateDisposition = OPEN_EXISTING;
+    else
+        dwCreateDisposition = CREATE_NEW;
+
+    handle = CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
+                         dwCreateDisposition, 0, NULL);
+
+    ok(handle != INVALID_HANDLE_VALUE, "Failed to CreateFile %s\n", pszFile);
+
+    return (INT_PTR)handle;
+}
+
+static UINT CDECL fci_read(INT_PTR hf, void *memory, UINT cb, int *err, void *pv)
+{
+    HANDLE handle = (HANDLE)hf;
+    DWORD dwRead;
+    BOOL res;
+
+    res = ReadFile(handle, memory, cb, &dwRead, NULL);
+    ok(res, "Failed to ReadFile\n");
+
+    return dwRead;
+}
+
+static UINT CDECL fci_write(INT_PTR hf, void *memory, UINT cb, int *err, void *pv)
+{
+    HANDLE handle = (HANDLE)hf;
+    DWORD dwWritten;
+    BOOL res;
+
+    res = WriteFile(handle, memory, cb, &dwWritten, NULL);
+    ok(res, "Failed to WriteFile\n");
+
+    return dwWritten;
+}
+
+static int CDECL fci_close(INT_PTR hf, int *err, void *pv)
+{
+    HANDLE handle = (HANDLE)hf;
+    ok(CloseHandle(handle), "Failed to CloseHandle\n");
+
+    return 0;
+}
+
+static LONG CDECL fci_seek(INT_PTR hf, LONG dist, int seektype, int *err, void *pv)
+{
+    HANDLE handle = (HANDLE)hf;
+    DWORD ret;
+
+    ret = SetFilePointer(handle, dist, NULL, seektype);
+    ok(ret != INVALID_SET_FILE_POINTER, "Failed to SetFilePointer\n");
+
+    return ret;
+}
+
+static int CDECL fci_delete(char *pszFile, int *err, void *pv)
+{
+    BOOL ret = DeleteFileA(pszFile);
+    ok(ret, "Failed to DeleteFile %s\n", pszFile);
+
+    return 0;
+}
+
+static BOOL CDECL get_temp_file(char *pszTempName, int cbTempName, void *pv)
+{
+    LPSTR tempname;
+
+    tempname = HeapAlloc(GetProcessHeap(), 0, MAX_PATH);
+    GetTempFileNameA(".", "xx", 0, tempname);
+
+    if (tempname && (strlen(tempname) < (unsigned)cbTempName))
+    {
+        lstrcpyA(pszTempName, tempname);
+        HeapFree(GetProcessHeap(), 0, tempname);
+        return TRUE;
+    }
+
+    HeapFree(GetProcessHeap(), 0, tempname);
+
+    return FALSE;
+}
+
+static INT_PTR CDECL get_open_info(char *pszName, USHORT *pdate, USHORT *ptime,
+                                   USHORT *pattribs, int *err, void *pv)
+{
+    BY_HANDLE_FILE_INFORMATION finfo;
+    FILETIME filetime;
+    HANDLE handle;
+    DWORD attrs;
+    BOOL res;
+
+    handle = CreateFile(pszName, GENERIC_READ, FILE_SHARE_READ, NULL,
+                        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
+
+    ok(handle != INVALID_HANDLE_VALUE, "Failed to CreateFile %s\n", pszName);
+
+    res = GetFileInformationByHandle(handle, &finfo);
+    ok(res, "Expected GetFileInformationByHandle to succeed\n");
+
+    FileTimeToLocalFileTime(&finfo.ftLastWriteTime, &filetime);
+    FileTimeToDosDateTime(&filetime, pdate, ptime);
+
+    attrs = GetFileAttributes(pszName);
+    ok(attrs != INVALID_FILE_ATTRIBUTES, "Failed to GetFileAttributes\n");
+
+    return (INT_PTR)handle;
+}
+
+static BOOL add_file(HFCI hfci, const char *file, TCOMP compress)
+{
+    char path[MAX_PATH];
+    char filename[MAX_PATH];
+
+    lstrcpyA(path, CURR_DIR);
+    lstrcatA(path, "\\");
+    lstrcatA(path, file);
+
+    lstrcpyA(filename, file);
+
+    return FCIAddFile(hfci, path, filename, FALSE, get_next_cabinet,
+                      progress, get_open_info, compress);
+}
+
+static void set_cab_parameters(PCCAB pCabParams, const CHAR *name, DWORD max_size)
+{
+    ZeroMemory(pCabParams, sizeof(CCAB));
+
+    pCabParams->cb = max_size;
+    pCabParams->cbFolderThresh = FOLDER_THRESHOLD;
+    pCabParams->setID = 0xbeef;
+    pCabParams->iCab = 1;
+    lstrcpyA(pCabParams->szCabPath, CURR_DIR);
+    lstrcatA(pCabParams->szCabPath, "\\");
+    lstrcpyA(pCabParams->szCab, name);
+}
+
+static void create_cab_file(const CHAR *name, DWORD max_size, const CHAR *files)
+{
+    CCAB cabParams;
+    LPCSTR ptr;
+    HFCI hfci;
+    ERF erf;
+    BOOL res;
+
+    set_cab_parameters(&cabParams, name, max_size);
+
+    hfci = FCICreate(&erf, file_placed, mem_alloc, mem_free, fci_open,
+                      fci_read, fci_write, fci_close, fci_seek, fci_delete,
+                      get_temp_file, &cabParams, NULL);
+
+    ok(hfci != NULL, "Failed to create an FCI context\n");
+
+    ptr = files;
+    while (*ptr)
+    {
+        res = add_file(hfci, ptr, tcompTYPE_MSZIP);
+        ok(res, "Failed to add file: %s\n", ptr);
+        ptr += lstrlen(ptr) + 1;
+    }
+
+    res = FCIFlushCabinet(hfci, FALSE, get_next_cabinet, progress);
+    ok(res, "Failed to flush the cabinet\n");
+
+    res = FCIDestroy(hfci);
+    ok(res, "Failed to destroy the cabinet\n");
+}
+
+static BOOL add_cabinet_storage(LPCSTR db, LPCSTR cabinet)
+{
+    WCHAR dbW[MAX_PATH], cabinetW[MAX_PATH];
+    IStorage *stg;
+    IStream *stm;
+    HRESULT hr;
+    HANDLE handle;
+
+    MultiByteToWideChar(CP_ACP, 0, db, -1, dbW, MAX_PATH);
+    hr = StgOpenStorage(dbW, NULL, STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
+    if (FAILED(hr))
+        return FALSE;
+
+    MultiByteToWideChar(CP_ACP, 0, cabinet, -1, cabinetW, MAX_PATH);
+    hr = IStorage_CreateStream(stg, cabinetW, STGM_WRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
+    if (FAILED(hr))
+    {
+        IStorage_Release(stg);
+        return FALSE;
+    }
+
+    handle = CreateFileW(cabinetW, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+    if (handle != INVALID_HANDLE_VALUE)
+    {
+        DWORD count;
+        char buffer[1024];
+        if (ReadFile(handle, buffer, sizeof(buffer), &count, NULL))
+            IStream_Write(stm, buffer, count, &count);
+        CloseHandle(handle);
+    }
+
+    IStream_Release(stm);
+    IStorage_Release(stg);
+
+    return TRUE;
+}
+
+static void delete_cab_files(void)
+{
+    SHFILEOPSTRUCT shfl;
+    CHAR path[MAX_PATH+10];
+
+    lstrcpyA(path, CURR_DIR);
+    lstrcatA(path, "\\*.cab");
+    path[strlen(path) + 1] = '\0';
+
+    shfl.hwnd = NULL;
+    shfl.wFunc = FO_DELETE;
+    shfl.pFrom = path;
+    shfl.pTo = NULL;
+    shfl.fFlags = FOF_FILESONLY | FOF_NOCONFIRMATION | FOF_NORECURSION | FOF_SILENT;
+
+    SHFileOperation(&shfl);
+}
+
 /* msi database data */
 
 static const char directory_dat[] =
@@ -272,7 +546,7 @@ static const char mcp_feature_comp_dat[] =
     "heliox\thelium\n"
     "lithia\tlithium";
 
-static const CHAR mcp_file_dat[] =
+static const char mcp_file_dat[] =
     "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
     "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
     "File\tFile\n"
@@ -280,6 +554,286 @@ static const CHAR mcp_file_dat[] =
     "helium\thelium\thelium\t0\t\t\t8192\t1\n"
     "lithium\tlithium\tlithium\t0\t\t\t8192\t1";
 
+static const char lus_component_dat[] =
+    "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
+    "s72\tS38\ts72\ti2\tS255\tS72\n"
+    "Component\tComponent\n"
+    "maximus\t{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}\tMSITESTDIR\t0\tUILevel=5\tmaximus\n";
+
+static const char lus_feature_dat[] =
+    "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
+    "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
+    "Feature\tFeature\n"
+    "feature\t\tFeature\tFeature\t2\t1\tTARGETDIR\t0\n"
+    "montecristo\t\tFeature\tFeature\t2\t1\tTARGETDIR\t0";
+
+static const char lus_file_dat[] =
+    "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
+    "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
+    "File\tFile\n"
+    "maximus\tmaximus\tmaximus\t500\t\t\t8192\t1";
+
+static const char lus_feature_comp_dat[] =
+    "Feature_\tComponent_\n"
+    "s38\ts72\n"
+    "FeatureComponents\tFeature_\tComponent_\n"
+    "feature\tmaximus\n"
+    "montecristo\tmaximus";
+
+static const char lus_install_exec_seq_dat[] =
+    "Action\tCondition\tSequence\n"
+    "s72\tS255\tI2\n"
+    "InstallExecuteSequence\tAction\n"
+    "ValidateProductID\t\t700\n"
+    "CostInitialize\t\t800\n"
+    "FileCost\t\t900\n"
+    "CostFinalize\t\t1000\n"
+    "InstallValidate\t\t1400\n"
+    "InstallInitialize\t\t1500\n"
+    "ProcessComponents\tPROCESS_COMPONENTS=1 Or FULL=1\t1600\n"
+    "UnpublishFeatures\tUNPUBLISH_FEATURES=1 Or FULL=1\t1800\n"
+    "RemoveFiles\t\t3500\n"
+    "InstallFiles\t\t4000\n"
+    "RegisterUser\tREGISTER_USER=1 Or FULL=1\t6000\n"
+    "RegisterProduct\tREGISTER_PRODUCT=1 Or FULL=1\t6100\n"
+    "PublishFeatures\tPUBLISH_FEATURES=1 Or FULL=1\t6300\n"
+    "PublishProduct\tPUBLISH_PRODUCT=1 Or FULL=1\t6400\n"
+    "InstallFinalize\t\t6600";
+
+static const char lus0_media_dat[] =
+    "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
+    "i2\ti4\tL64\tS255\tS32\tS72\n"
+    "Media\tDiskId\n"
+    "1\t1\t\t\tDISK1\t\n";
+
+static const char lus1_media_dat[] =
+    "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
+    "i2\ti4\tL64\tS255\tS32\tS72\n"
+    "Media\tDiskId\n"
+    "1\t1\t\ttest1.cab\tDISK1\t\n";
+
+static const char lus2_media_dat[] =
+    "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
+    "i2\ti4\tL64\tS255\tS32\tS72\n"
+    "Media\tDiskId\n"
+    "1\t1\t\t#test1.cab\tDISK1\t\n";
+
+static const char spf_custom_action_dat[] =
+    "Action\tType\tSource\tTarget\tISComments\n"
+    "s72\ti2\tS64\tS0\tS255\n"
+    "CustomAction\tAction\n"
+    "SetFolderProp\t51\tMSITESTDIR\t[ProgramFilesFolder]\\msitest\\added\t\n";
+
+static const char spf_install_exec_seq_dat[] =
+    "Action\tCondition\tSequence\n"
+    "s72\tS255\tI2\n"
+    "InstallExecuteSequence\tAction\n"
+    "CostFinalize\t\t1000\n"
+    "CostInitialize\t\t800\n"
+    "FileCost\t\t900\n"
+    "SetFolderProp\t\t950\n"
+    "InstallFiles\t\t4000\n"
+    "InstallServices\t\t5000\n"
+    "InstallFinalize\t\t6600\n"
+    "InstallInitialize\t\t1500\n"
+    "InstallValidate\t\t1400\n"
+    "LaunchConditions\t\t100";
+
+static const char spf_install_ui_seq_dat[] =
+    "Action\tCondition\tSequence\n"
+    "s72\tS255\tI2\n"
+    "InstallUISequence\tAction\n"
+    "CostInitialize\t\t800\n"
+    "FileCost\t\t900\n"
+    "CostFinalize\t\t1000\n"
+    "ExecuteAction\t\t1100\n";
+
+static const char sd_file_dat[] =
+    "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
+    "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
+    "File\tFile\n"
+    "sourcedir.txt\tsourcedir\tsourcedir.txt\t1000\t\t\t8192\t1\n";
+
+static const char sd_feature_dat[] =
+    "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
+    "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
+    "Feature\tFeature\n"
+    "sourcedir\t\t\tsourcedir feature\t1\t2\tMSITESTDIR\t0\n";
+
+static const char sd_feature_comp_dat[] =
+    "Feature_\tComponent_\n"
+    "s38\ts72\n"
+    "FeatureComponents\tFeature_\tComponent_\n"
+    "sourcedir\tsourcedir\n";
+
+static const char sd_component_dat[] =
+    "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
+    "s72\tS38\ts72\ti2\tS255\tS72\n"
+    "Component\tComponent\n"
+    "sourcedir\t{DD422F92-3ED8-49B5-A0B7-F266F98357DF}\tMSITESTDIR\t0\t\tsourcedir.txt\n";
+
+static const char sd_install_ui_seq_dat[] =
+    "Action\tCondition\tSequence\n"
+    "s72\tS255\tI2\n"
+    "InstallUISequence\tAction\n"
+    "TestSourceDirProp1\tnot SourceDir and not SOURCEDIR and not Installed\t99\n"
+    "AppSearch\t\t100\n"
+    "TestSourceDirProp2\tnot SourceDir and not SOURCEDIR and not Installed\t101\n"
+    "LaunchConditions\tnot Installed \t110\n"
+    "TestSourceDirProp3\tnot SourceDir and not SOURCEDIR and not Installed\t111\n"
+    "FindRelatedProducts\t\t120\n"
+    "TestSourceDirProp4\tnot SourceDir and not SOURCEDIR and not Installed\t121\n"
+    "CCPSearch\t\t130\n"
+    "TestSourceDirProp5\tnot SourceDir and not SOURCEDIR and not Installed\t131\n"
+    "RMCCPSearch\t\t140\n"
+    "TestSourceDirProp6\tnot SourceDir and not SOURCEDIR and not Installed\t141\n"
+    "ValidateProductID\t\t150\n"
+    "TestSourceDirProp7\tnot SourceDir and not SOURCEDIR and not Installed\t151\n"
+    "CostInitialize\t\t800\n"
+    "TestSourceDirProp8\tnot SourceDir and not SOURCEDIR and not Installed\t801\n"
+    "FileCost\t\t900\n"
+    "TestSourceDirProp9\tnot SourceDir and not SOURCEDIR and not Installed\t901\n"
+    "IsolateComponents\t\t1000\n"
+    "TestSourceDirProp10\tnot SourceDir and not SOURCEDIR and not Installed\t1001\n"
+    "CostFinalize\t\t1100\n"
+    "TestSourceDirProp11\tnot SourceDir and not SOURCEDIR and not Installed\t1101\n"
+    "MigrateFeatureStates\t\t1200\n"
+    "TestSourceDirProp12\tnot SourceDir and not SOURCEDIR and not Installed\t1201\n"
+    "ExecuteAction\t\t1300\n"
+    "TestSourceDirProp13\tnot SourceDir and not SOURCEDIR and not Installed\t1301\n";
+
+static const char sd_install_exec_seq_dat[] =
+    "Action\tCondition\tSequence\n"
+    "s72\tS255\tI2\n"
+    "InstallExecuteSequence\tAction\n"
+    "TestSourceDirProp14\tSourceDir and SOURCEDIR and not Installed\t99\n"
+    "LaunchConditions\t\t100\n"
+    "TestSourceDirProp15\tSourceDir and SOURCEDIR and not Installed\t101\n"
+    "ValidateProductID\t\t700\n"
+    "TestSourceDirProp16\tSourceDir and SOURCEDIR and not Installed\t701\n"
+    "CostInitialize\t\t800\n"
+    "TestSourceDirProp17\tSourceDir and SOURCEDIR and not Installed\t801\n"
+    "ResolveSource\tResolveSource and not Installed\t850\n"
+    "TestSourceDirProp18\tResolveSource and not SourceDir and not SOURCEDIR and not Installed\t851\n"
+    "TestSourceDirProp19\tnot ResolveSource and SourceDir and SOURCEDIR and not Installed\t852\n"
+    "FileCost\t\t900\n"
+    "TestSourceDirProp20\tSourceDir and SOURCEDIR and not Installed\t901\n"
+    "IsolateComponents\t\t1000\n"
+    "TestSourceDirProp21\tSourceDir and SOURCEDIR and not Installed\t1001\n"
+    "CostFinalize\t\t1100\n"
+    "TestSourceDirProp22\tSourceDir and SOURCEDIR and not Installed\t1101\n"
+    "MigrateFeatureStates\t\t1200\n"
+    "TestSourceDirProp23\tSourceDir and SOURCEDIR and not Installed\t1201\n"
+    "InstallValidate\t\t1400\n"
+    "TestSourceDirProp24\tSourceDir and SOURCEDIR and not Installed\t1401\n"
+    "InstallInitialize\t\t1500\n"
+    "TestSourceDirProp25\tSourceDir and SOURCEDIR and not Installed\t1501\n"
+    "ProcessComponents\t\t1600\n"
+    "TestSourceDirProp26\tnot SourceDir and not SOURCEDIR and not Installed\t1601\n"
+    "UnpublishFeatures\t\t1800\n"
+    "TestSourceDirProp27\tnot SourceDir and not SOURCEDIR and not Installed\t1801\n"
+    "RemoveFiles\t\t3500\n"
+    "TestSourceDirProp28\tnot SourceDir and not SOURCEDIR and not Installed\t3501\n"
+    "InstallFiles\t\t4000\n"
+    "TestSourceDirProp29\tnot SourceDir and not SOURCEDIR and not Installed\t4001\n"
+    "RegisterUser\t\t6000\n"
+    "TestSourceDirProp30\tnot SourceDir and not SOURCEDIR and not Installed\t6001\n"
+    "RegisterProduct\t\t6100\n"
+    "TestSourceDirProp31\tnot SourceDir and not SOURCEDIR and not Installed\t6101\n"
+    "PublishFeatures\t\t6300\n"
+    "TestSourceDirProp32\tnot SourceDir and not SOURCEDIR and not Installed\t6301\n"
+    "PublishProduct\t\t6400\n"
+    "TestSourceDirProp33\tnot SourceDir and not SOURCEDIR and not Installed\t6401\n"
+    "InstallExecute\t\t6500\n"
+    "TestSourceDirProp34\tnot SourceDir and not SOURCEDIR and not Installed\t6501\n"
+    "InstallFinalize\t\t6600\n"
+    "TestSourceDirProp35\tnot SourceDir and not SOURCEDIR and not Installed\t6601\n";
+
+static const char sd_custom_action_dat[] =
+    "Action\tType\tSource\tTarget\tISComments\n"
+    "s72\ti2\tS64\tS0\tS255\n"
+    "CustomAction\tAction\n"
+    "TestSourceDirProp1\t19\t\tTest 1 failed\t\n"
+    "TestSourceDirProp2\t19\t\tTest 2 failed\t\n"
+    "TestSourceDirProp3\t19\t\tTest 3 failed\t\n"
+    "TestSourceDirProp4\t19\t\tTest 4 failed\t\n"
+    "TestSourceDirProp5\t19\t\tTest 5 failed\t\n"
+    "TestSourceDirProp6\t19\t\tTest 6 failed\t\n"
+    "TestSourceDirProp7\t19\t\tTest 7 failed\t\n"
+    "TestSourceDirProp8\t19\t\tTest 8 failed\t\n"
+    "TestSourceDirProp9\t19\t\tTest 9 failed\t\n"
+    "TestSourceDirProp10\t19\t\tTest 10 failed\t\n"
+    "TestSourceDirProp11\t19\t\tTest 11 failed\t\n"
+    "TestSourceDirProp12\t19\t\tTest 12 failed\t\n"
+    "TestSourceDirProp13\t19\t\tTest 13 failed\t\n"
+    "TestSourceDirProp14\t19\t\tTest 14 failed\t\n"
+    "TestSourceDirProp15\t19\t\tTest 15 failed\t\n"
+    "TestSourceDirProp16\t19\t\tTest 16 failed\t\n"
+    "TestSourceDirProp17\t19\t\tTest 17 failed\t\n"
+    "TestSourceDirProp18\t19\t\tTest 18 failed\t\n"
+    "TestSourceDirProp19\t19\t\tTest 19 failed\t\n"
+    "TestSourceDirProp20\t19\t\tTest 20 failed\t\n"
+    "TestSourceDirProp21\t19\t\tTest 21 failed\t\n"
+    "TestSourceDirProp22\t19\t\tTest 22 failed\t\n"
+    "TestSourceDirProp23\t19\t\tTest 23 failed\t\n"
+    "TestSourceDirProp24\t19\t\tTest 24 failed\t\n"
+    "TestSourceDirProp25\t19\t\tTest 25 failed\t\n"
+    "TestSourceDirProp26\t19\t\tTest 26 failed\t\n"
+    "TestSourceDirProp27\t19\t\tTest 27 failed\t\n"
+    "TestSourceDirProp28\t19\t\tTest 28 failed\t\n"
+    "TestSourceDirProp29\t19\t\tTest 29 failed\t\n"
+    "TestSourceDirProp30\t19\t\tTest 30 failed\t\n"
+    "TestSourceDirProp31\t19\t\tTest 31 failed\t\n"
+    "TestSourceDirProp32\t19\t\tTest 32 failed\t\n"
+    "TestSourceDirProp33\t19\t\tTest 33 failed\t\n"
+    "TestSourceDirProp34\t19\t\tTest 34 failed\t\n"
+    "TestSourceDirProp35\t19\t\tTest 35 failed\t\n";
+
+static const char ci_install_exec_seq_dat[] =
+    "Action\tCondition\tSequence\n"
+    "s72\tS255\tI2\n"
+    "InstallExecuteSequence\tAction\n"
+    "CostFinalize\t\t1000\n"
+    "CostInitialize\t\t800\n"
+    "FileCost\t\t900\n"
+    "InstallFiles\t\t4000\n"
+    "InstallServices\t\t5000\n"
+    "InstallFinalize\t\t6600\n"
+    "InstallInitialize\t\t1500\n"
+    "RunInstall\t\t1600\n"
+    "InstallValidate\t\t1400\n"
+    "LaunchConditions\t\t100";
+
+static const char ci_custom_action_dat[] =
+    "Action\tType\tSource\tTarget\tISComments\n"
+    "s72\ti2\tS64\tS0\tS255\n"
+    "CustomAction\tAction\n"
+    "RunInstall\t87\tmsitest\\concurrent.msi\tMYPROP=[UILevel]\t\n";
+
+static const char ci_component_dat[] =
+    "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
+    "s72\tS38\ts72\ti2\tS255\tS72\n"
+    "Component\tComponent\n"
+    "maximus\t{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}\tMSITESTDIR\t0\tUILevel=5\tmaximus\n";
+
+static const char ci2_component_dat[] =
+    "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
+    "s72\tS38\ts72\ti2\tS255\tS72\n"
+    "Component\tComponent\n"
+    "augustus\t\tMSITESTDIR\t0\tUILevel=3 AND MYPROP=5\taugustus\n";
+
+static const char ci2_feature_comp_dat[] =
+    "Feature_\tComponent_\n"
+    "s38\ts72\n"
+    "FeatureComponents\tFeature_\tComponent_\n"
+    "feature\taugustus";
+
+static const char ci2_file_dat[] =
+    "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
+    "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
+    "File\tFile\n"
+    "augustus\taugustus\taugustus\t500\t\t\t8192\t1";
+
 typedef struct _msi_table
 {
     const CHAR *filename;
@@ -313,6 +867,95 @@ static const msi_table mcp_tables[] =
     ADD_TABLE(property)
 };
 
+static const msi_table lus0_tables[] =
+{
+    ADD_TABLE(lus_component),
+    ADD_TABLE(directory),
+    ADD_TABLE(lus_feature),
+    ADD_TABLE(lus_feature_comp),
+    ADD_TABLE(lus_file),
+    ADD_TABLE(lus_install_exec_seq),
+    ADD_TABLE(lus0_media),
+    ADD_TABLE(property)
+};
+
+static const msi_table lus1_tables[] =
+{
+    ADD_TABLE(lus_component),
+    ADD_TABLE(directory),
+    ADD_TABLE(lus_feature),
+    ADD_TABLE(lus_feature_comp),
+    ADD_TABLE(lus_file),
+    ADD_TABLE(lus_install_exec_seq),
+    ADD_TABLE(lus1_media),
+    ADD_TABLE(property)
+};
+
+static const msi_table lus2_tables[] =
+{
+    ADD_TABLE(lus_component),
+    ADD_TABLE(directory),
+    ADD_TABLE(lus_feature),
+    ADD_TABLE(lus_feature_comp),
+    ADD_TABLE(lus_file),
+    ADD_TABLE(lus_install_exec_seq),
+    ADD_TABLE(lus2_media),
+    ADD_TABLE(property)
+};
+
+static const msi_table spf_tables[] =
+{
+    ADD_TABLE(lus_component),
+    ADD_TABLE(directory),
+    ADD_TABLE(lus_feature),
+    ADD_TABLE(lus_feature_comp),
+    ADD_TABLE(lus_file),
+    ADD_TABLE(lus0_media),
+    ADD_TABLE(property),
+    ADD_TABLE(spf_custom_action),
+    ADD_TABLE(spf_install_exec_seq),
+    ADD_TABLE(spf_install_ui_seq)
+};
+
+static const msi_table sd_tables[] =
+{
+    ADD_TABLE(directory),
+    ADD_TABLE(sd_component),
+    ADD_TABLE(sd_feature),
+    ADD_TABLE(sd_feature_comp),
+    ADD_TABLE(sd_file),
+    ADD_TABLE(sd_install_exec_seq),
+    ADD_TABLE(sd_install_ui_seq),
+    ADD_TABLE(sd_custom_action),
+    ADD_TABLE(media),
+    ADD_TABLE(property)
+};
+
+static const msi_table ci_tables[] =
+{
+    ADD_TABLE(ci_component),
+    ADD_TABLE(directory),
+    ADD_TABLE(lus_feature),
+    ADD_TABLE(lus_feature_comp),
+    ADD_TABLE(lus_file),
+    ADD_TABLE(ci_install_exec_seq),
+    ADD_TABLE(lus0_media),
+    ADD_TABLE(property),
+    ADD_TABLE(ci_custom_action),
+};
+
+static const msi_table ci2_tables[] =
+{
+    ADD_TABLE(ci2_component),
+    ADD_TABLE(directory),
+    ADD_TABLE(lus_feature),
+    ADD_TABLE(ci2_feature_comp),
+    ADD_TABLE(ci2_file),
+    ADD_TABLE(install_exec_seq),
+    ADD_TABLE(lus0_media),
+    ADD_TABLE(property),
+};
+
 static void write_file(const CHAR *filename, const char *data, int data_size)
 {
     DWORD size;
@@ -711,6 +1354,40 @@ static void create_file(LPCSTR name, LPCSTR data, DWORD size)
     CloseHandle(file);
 }
 
+static void create_test_files(void)
+{
+    CreateDirectoryA("msitest", NULL);
+    create_file("msitest\\one.txt", "msitest\\one.txt", 100);
+    CreateDirectoryA("msitest\\first", NULL);
+    create_file("msitest\\first\\two.txt", "msitest\\first\\two.txt", 100);
+    CreateDirectoryA("msitest\\second", NULL);
+    create_file("msitest\\second\\three.txt", "msitest\\second\\three.txt", 100);
+
+    create_file("four.txt", "four.txt", 100);
+    create_file("five.txt", "five.txt", 100);
+    create_cab_file("msitest.cab", MEDIA_SIZE, "four.txt\0five.txt\0");
+
+    create_file("msitest\\filename", "msitest\\filename", 100);
+    create_file("msitest\\service.exe", "msitest\\service.exe", 100);
+
+    DeleteFileA("four.txt");
+    DeleteFileA("five.txt");
+}
+
+static void delete_test_files(void)
+{
+    DeleteFileA("msitest.msi");
+    DeleteFileA("msitest.cab");
+    DeleteFileA("msitest\\second\\three.txt");
+    DeleteFileA("msitest\\first\\two.txt");
+    DeleteFileA("msitest\\one.txt");
+    DeleteFileA("msitest\\service.exe");
+    DeleteFileA("msitest\\filename");
+    RemoveDirectoryA("msitest\\second");
+    RemoveDirectoryA("msitest\\first");
+    RemoveDirectoryA("msitest");
+}
+
 #define HASHSIZE sizeof(MSIFILEHASHINFO)
 
 static const struct
@@ -13039,6 +13716,291 @@ static void test_MsiSetExternalUI(void)
     ok(!error, "MsiSetExternalUIRecord failed %u\n", error);
 }
 
+static void test_lastusedsource(void)
+{
+    static char prodcode[] = "{38847338-1BBC-4104-81AC-2FAAC7ECDDCD}";
+    char value[MAX_PATH], path[MAX_PATH];
+    DWORD size;
+    UINT r;
+
+    if (!pMsiSourceListGetInfoA)
+    {
+        win_skip("MsiSourceListGetInfoA is not available\n");
+        return;
+    }
+
+    CreateDirectoryA("msitest", NULL);
+    create_file("maximus", "maximus", 500);
+    create_cab_file("test1.cab", MEDIA_SIZE, "maximus\0");
+    DeleteFile("maximus");
+
+    create_database("msifile0.msi", lus0_tables, sizeof(lus0_tables) / sizeof(msi_table));
+    create_database("msifile1.msi", lus1_tables, sizeof(lus1_tables) / sizeof(msi_table));
+    create_database("msifile2.msi", lus2_tables, sizeof(lus2_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    /* no cabinet file */
+
+    size = MAX_PATH;
+    lstrcpyA(value, "aaa");
+    r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
+                               MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, value, &size);
+    ok(r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r);
+    ok(!lstrcmpA(value, "aaa"), "expected \"aaa\", got \"%s\"\n", value);
+
+    r = MsiInstallProductA("msifile0.msi", "PUBLISH_PRODUCT=1");
+    if (r == ERROR_INSTALL_PACKAGE_REJECTED)
+    {
+        skip("Not enough rights to perform tests\n");
+        goto error;
+    }
+    ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
+
+    lstrcpyA(path, CURR_DIR);
+    lstrcatA(path, "\\");
+
+    size = MAX_PATH;
+    lstrcpyA(value, "aaa");
+    r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
+                               MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, value, &size);
+    ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
+    ok(!lstrcmpA(value, path), "expected \"%s\", got \"%s\"\n", path, value);
+    ok(size == lstrlenA(path), "expected %d, got %d\n", lstrlenA(path), size);
+
+    r = MsiInstallProductA("msifile0.msi", "REMOVE=ALL");
+    ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
+
+    /* separate cabinet file */
+
+    size = MAX_PATH;
+    lstrcpyA(value, "aaa");
+    r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
+                               MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, value, &size);
+    ok(r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r);
+    ok(!lstrcmpA(value, "aaa"), "expected \"aaa\", got \"%s\"\n", value);
+
+    r = MsiInstallProductA("msifile1.msi", "PUBLISH_PRODUCT=1");
+    ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
+
+    lstrcpyA(path, CURR_DIR);
+    lstrcatA(path, "\\");
+
+    size = MAX_PATH;
+    lstrcpyA(value, "aaa");
+    r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
+                               MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, value, &size);
+    ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
+    ok(!lstrcmpA(value, path), "expected \"%s\", got \"%s\"\n", path, value);
+    ok(size == lstrlenA(path), "expected %d, got %d\n", lstrlenA(path), size);
+
+    r = MsiInstallProductA("msifile1.msi", "REMOVE=ALL");
+    ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
+
+    size = MAX_PATH;
+    lstrcpyA(value, "aaa");
+    r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
+                               MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, value, &size);
+    ok(r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r);
+    ok(!lstrcmpA(value, "aaa"), "expected \"aaa\", got \"%s\"\n", value);
+
+    /* embedded cabinet stream */
+
+    add_cabinet_storage("msifile2.msi", "test1.cab");
+
+    r = MsiInstallProductA("msifile2.msi", "PUBLISH_PRODUCT=1");
+    ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
+
+    size = MAX_PATH;
+    lstrcpyA(value, "aaa");
+    r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
+                               MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, value, &size);
+    ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
+    ok(!lstrcmpA(value, path), "expected \"%s\", got \"%s\"\n", path, value);
+    ok(size == lstrlenA(path), "expected %d, got %d\n", lstrlenA(path), size);
+
+    r = MsiInstallProductA("msifile2.msi", "REMOVE=ALL");
+    ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
+
+    size = MAX_PATH;
+    lstrcpyA(value, "aaa");
+    r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
+                               MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, value, &size);
+    ok(r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r);
+    ok(!lstrcmpA(value, "aaa"), "expected \"aaa\", got \"%s\"\n", value);
+
+error:
+    delete_cab_files();
+    DeleteFile("msitest\\maximus");
+    RemoveDirectory("msitest");
+    DeleteFile("msifile0.msi");
+    DeleteFile("msifile1.msi");
+    DeleteFile("msifile2.msi");
+}
+
+static void test_setpropertyfolder(void)
+{
+    UINT r;
+    CHAR path[MAX_PATH];
+    DWORD attr;
+
+    if (is_process_limited())
+    {
+        skip("process is limited\n");
+        return;
+    }
+
+    lstrcpyA(path, PROG_FILES_DIR);
+    lstrcatA(path, "\\msitest\\added");
+
+    CreateDirectoryA("msitest", NULL);
+    create_file("msitest\\maximus", "msitest\\maximus", 500);
+
+    create_database(msifile, spf_tables, sizeof(spf_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_FULL, NULL);
+
+    r = MsiInstallProductA(msifile, NULL);
+    if (r == ERROR_INSTALL_PACKAGE_REJECTED)
+    {
+        skip("Not enough rights to perform tests\n");
+        goto error;
+    }
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+    attr = GetFileAttributesA(path);
+    if (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
+    {
+        ok(delete_pf("msitest\\added\\maximus", TRUE), "File not installed\n");
+        ok(delete_pf("msitest\\added", FALSE), "Directory not created\n");
+        ok(delete_pf("msitest", FALSE), "Directory not created\n");
+    }
+    else
+    {
+        trace("changing folder property not supported\n");
+        ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n");
+        ok(delete_pf("msitest", FALSE), "Directory not created\n");
+    }
+
+error:
+    DeleteFile(msifile);
+    DeleteFile("msitest\\maximus");
+    RemoveDirectory("msitest");
+}
+
+static void test_sourcedir_props(void)
+{
+    UINT r;
+
+    if (is_process_limited())
+    {
+        skip("process is limited\n");
+        return;
+    }
+
+    create_test_files();
+    create_file("msitest\\sourcedir.txt", "msitest\\sourcedir.txt", 1000);
+    create_database(msifile, sd_tables, sizeof(sd_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_FULL, NULL);
+
+    /* full UI, no ResolveSource action */
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    r = MsiInstallProductA(msifile, "REMOVE=ALL");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ok(!delete_pf("msitest\\sourcedir.txt", TRUE), "file not removed\n");
+    ok(!delete_pf("msitest", FALSE), "directory not removed\n");
+
+    /* full UI, ResolveSource action */
+    r = MsiInstallProductA(msifile, "ResolveSource=1");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    r = MsiInstallProductA(msifile, "REMOVE=ALL");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ok(!delete_pf("msitest\\sourcedir.txt", TRUE), "file not removed\n");
+    ok(!delete_pf("msitest", FALSE), "directory not removed\n");
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    /* no UI, no ResolveSource action */
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    r = MsiInstallProductA(msifile, "REMOVE=ALL");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ok(!delete_pf("msitest\\sourcedir.txt", TRUE), "file not removed\n");
+    ok(!delete_pf("msitest", FALSE), "directory not removed\n");
+
+    /* no UI, ResolveSource action */
+    r = MsiInstallProductA(msifile, "ResolveSource=1");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    r = MsiInstallProductA(msifile, "REMOVE=ALL");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ok(!delete_pf("msitest\\sourcedir.txt", TRUE), "file not removed\n");
+    ok(!delete_pf("msitest", FALSE), "directory not removed\n");
+
+    DeleteFileA("msitest\\sourcedir.txt");
+    delete_test_files();
+    DeleteFile(msifile);
+}
+
+static void test_concurrentinstall(void)
+{
+    UINT r;
+    CHAR path[MAX_PATH];
+
+    if (is_process_limited())
+    {
+        skip("process is limited\n");
+        return;
+    }
+
+    CreateDirectoryA("msitest", NULL);
+    CreateDirectoryA("msitest\\msitest", NULL);
+    create_file("msitest\\maximus", "msitest\\maximus", 500);
+    create_file("msitest\\msitest\\augustus", "msitest\\msitest\\augustus", 500);
+
+    create_database(msifile, ci_tables, sizeof(ci_tables) / sizeof(msi_table));
+
+    lstrcpyA(path, CURR_DIR);
+    lstrcatA(path, "\\msitest\\concurrent.msi");
+    create_database(path, ci2_tables, sizeof(ci2_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_FULL, NULL);
+
+    r = MsiInstallProductA(msifile, NULL);
+    if (r == ERROR_INSTALL_PACKAGE_REJECTED)
+    {
+        skip("Not enough rights to perform tests\n");
+        DeleteFile(path);
+        goto error;
+    }
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+    if (!delete_pf("msitest\\augustus", TRUE))
+        trace("concurrent installs not supported\n");
+    ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n");
+    ok(delete_pf("msitest", FALSE), "Directory not created\n");
+
+    r = MsiConfigureProductA("{38847338-1BBC-4104-81AC-2FAAC7ECDDCD}", INSTALLLEVEL_DEFAULT,
+                             INSTALLSTATE_ABSENT);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    DeleteFile(path);
+
+error:
+    DeleteFile(msifile);
+    DeleteFile("msitest\\msitest\\augustus");
+    DeleteFile("msitest\\maximus");
+    RemoveDirectory("msitest\\msitest");
+    RemoveDirectory("msitest");
+}
+
 START_TEST(msi)
 {
     DWORD len;
@@ -13096,6 +14058,10 @@ START_TEST(msi)
     test_MsiSetFeatureAttributes();
     test_MsiGetFeatureInfo();
     test_MsiSetExternalUI();
+    test_lastusedsource();
+    test_setpropertyfolder();
+    test_sourcedir_props();
+    test_concurrentinstall();
 
     SetCurrentDirectoryA(prev_path);
 }
-- 
1.7.10.4






More information about the wine-patches mailing list