[MSI_WINETEST]
[reactos.git] / rostests / winetests / msi / install.c
index 8fa729a..70013e5 100644 (file)
 #include <msi.h>
 #include <fci.h>
 #include <objidl.h>
+#include <srrestoreptapi.h>
 
 #include "wine/test.h"
 
 static UINT (WINAPI *pMsiQueryComponentStateA)
     (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, LPCSTR, INSTALLSTATE*);
+static UINT (WINAPI *pMsiSetExternalUIRecord)
+    (INSTALLUI_HANDLER_RECORD, DWORD, LPVOID, PINSTALLUI_HANDLER_RECORD);
 static UINT (WINAPI *pMsiSourceListEnumSourcesA)
     (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, DWORD, LPSTR, LPDWORD);
 static UINT (WINAPI *pMsiSourceListGetInfoA)
     (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, LPCSTR, LPSTR, LPDWORD);
 
+static BOOL (WINAPI *pConvertSidToStringSidA)(PSID, LPSTR*);
+
+static HMODULE hsrclient = 0;
+static BOOL (WINAPI *pSRRemoveRestorePoint)(DWORD);
+static BOOL (WINAPI *pSRSetRestorePointA)(RESTOREPOINTINFOA*, STATEMGRSTATUS*);
+
+static BOOL on_win9x = FALSE;
+
 static const char *msifile = "msitest.msi";
 static const char *msifile2 = "winetest2.msi";
 static const char *mstfile = "winetest.mst";
@@ -53,7 +64,7 @@ static const CHAR component_dat[] = "Component\tComponentId\tDirectory_\tAttribu
                                     "Component\tComponent\n"
                                     "Five\t{8CC92E9D-14B2-4CA4-B2AA-B11D02078087}\tNEWDIR\t2\t\tfive.txt\n"
                                     "Four\t{FD37B4EA-7209-45C0-8917-535F35A2F080}\tCABOUTDIR\t2\t\tfour.txt\n"
-                                    "One\t{783B242E-E185-4A56-AF86-C09815EC053C}\tMSITESTDIR\t2\t\tone.txt\n"
+                                    "One\t{783B242E-E185-4A56-AF86-C09815EC053C}\tMSITESTDIR\t2\tNOT REINSTALL\tone.txt\n"
                                     "Three\t{010B6ADD-B27D-4EDD-9B3D-34C4F7D61684}\tCHANGEDDIR\t2\t\tthree.txt\n"
                                     "Two\t{BF03D1A6-20DA-4A65-82F3-6CAC995915CE}\tFIRSTDIR\t2\t\ttwo.txt\n"
                                     "dangler\t{6091DF25-EF96-45F1-B8E9-A9B1420C7A3C}\tTARGETDIR\t4\t\tregdata\n"
@@ -115,6 +126,8 @@ static const CHAR install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
                                            "MoveFiles\t\t1700\n"
                                            "InstallFiles\t\t4000\n"
                                            "DuplicateFiles\t\t4500\n"
+                                           "WriteEnvironmentStrings\t\t4550\n"
+                                           "CreateShortcuts\t\t4600\n"
                                            "InstallServices\t\t5000\n"
                                            "InstallFinalize\t\t6600\n"
                                            "InstallInitialize\t\t1500\n"
@@ -150,6 +163,173 @@ static const CHAR property_dat[] = "Property\tValue\n"
                                    "SERVNAME\tTestService\n"
                                    "SERVDISP\tTestServiceDisp\n";
 
+static const CHAR aup_property_dat[] = "Property\tValue\n"
+                                       "s72\tl0\n"
+                                       "Property\tProperty\n"
+                                       "DefaultUIFont\tDlgFont8\n"
+                                       "HASUIRUN\t0\n"
+                                       "ALLUSERS\t1\n"
+                                       "INSTALLLEVEL\t3\n"
+                                       "InstallMode\tTypical\n"
+                                       "Manufacturer\tWine\n"
+                                       "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n"
+                                       "ProductCode\t{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}\n"
+                                       "ProductID\tnone\n"
+                                       "ProductLanguage\t1033\n"
+                                       "ProductName\tMSITEST\n"
+                                       "ProductVersion\t1.1.1\n"
+                                       "PROMPTROLLBACKCOST\tP\n"
+                                       "Setup\tSetup\n"
+                                       "UpgradeCode\t{4C0EAA15-0264-4E5A-8758-609EF142B92D}\n"
+                                       "AdminProperties\tPOSTADMIN\n"
+                                       "ROOTDRIVE\tC:\\\n"
+                                       "SERVNAME\tTestService\n"
+                                       "SERVDISP\tTestServiceDisp\n";
+
+static const CHAR aup2_property_dat[] = "Property\tValue\n"
+                                        "s72\tl0\n"
+                                        "Property\tProperty\n"
+                                        "DefaultUIFont\tDlgFont8\n"
+                                        "HASUIRUN\t0\n"
+                                        "ALLUSERS\t2\n"
+                                        "INSTALLLEVEL\t3\n"
+                                        "InstallMode\tTypical\n"
+                                        "Manufacturer\tWine\n"
+                                        "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n"
+                                        "ProductCode\t{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}\n"
+                                        "ProductID\tnone\n"
+                                        "ProductLanguage\t1033\n"
+                                        "ProductName\tMSITEST\n"
+                                        "ProductVersion\t1.1.1\n"
+                                        "PROMPTROLLBACKCOST\tP\n"
+                                        "Setup\tSetup\n"
+                                        "UpgradeCode\t{4C0EAA15-0264-4E5A-8758-609EF142B92D}\n"
+                                        "AdminProperties\tPOSTADMIN\n"
+                                        "ROOTDRIVE\tC:\\\n"
+                                        "SERVNAME\tTestService\n"
+                                        "SERVDISP\tTestServiceDisp\n";
+
+static const CHAR shortcut_dat[] = "Shortcut\tDirectory_\tName\tComponent_\tTarget\tArguments\tDescription\tHotkey\tIcon_\tIconIndex\tShowCmd\tWkDir\n"
+                                   "s72\ts72\tl128\ts72\ts72\tS255\tL255\tI2\tS72\tI2\tI2\tS72\n"
+                                   "Shortcut\tShortcut\n"
+                                   "Shortcut\tMSITESTDIR\tShortcut\tcomponent\tShortcut\t\tShortcut\t\t\t\t\t\n";
+
+static const CHAR environment_dat[] = "Environment\tName\tValue\tComponent_\n"
+                                      "s72\tl255\tL255\ts72\n"
+                                      "Environment\tEnvironment\n"
+                                      "Var1\t=-MSITESTVAR1\t1\tOne\n"
+                                      "Var2\tMSITESTVAR2\t1\tOne\n"
+                                      "Var3\t=-MSITESTVAR3\t1\tOne\n"
+                                      "Var4\tMSITESTVAR4\t1\tOne\n"
+                                      "Var5\t-MSITESTVAR5\t\tOne\n"
+                                      "Var6\tMSITESTVAR6\t\tOne\n"
+                                      "Var7\t!-MSITESTVAR7\t\tOne\n"
+                                      "Var8\t!-*MSITESTVAR8\t\tOne\n"
+                                      "Var9\t=-MSITESTVAR9\t\tOne\n"
+                                      "Var10\t=MSITESTVAR10\t\tOne\n"
+                                      "Var11\t+-MSITESTVAR11\t[~];1\tOne\n"
+                                      "Var12\t+-MSITESTVAR11\t[~];2\tOne\n"
+                                      "Var13\t+-MSITESTVAR12\t[~];1\tOne\n"
+                                      "Var14\t=MSITESTVAR13\t[~];1\tOne\n"
+                                      "Var15\t=MSITESTVAR13\t[~];2\tOne\n"
+                                      "Var16\t=MSITESTVAR14\t;1;\tOne\n"
+                                      "Var17\t=MSITESTVAR15\t;;1;;\tOne\n"
+                                      "Var18\t=MSITESTVAR16\t 1 \tOne\n"
+                                      "Var19\t+-MSITESTVAR17\t1\tOne\n"
+                                      "Var20\t+-MSITESTVAR17\t;;2;;[~]\tOne\n"
+                                      "Var21\t+-MSITESTVAR18\t1\tOne\n"
+                                      "Var22\t+-MSITESTVAR18\t[~];;2;;\tOne\n"
+                                      "Var23\t+-MSITESTVAR19\t1\tOne\n"
+                                      "Var24\t+-MSITESTVAR19\t[~]2\tOne\n"
+                                      "Var25\t+-MSITESTVAR20\t1\tOne\n"
+                                      "Var26\t+-MSITESTVAR20\t2[~]\tOne\n";
+
+/* Expected results, starting from MSITESTVAR11 onwards */
+static const CHAR *environment_dat_results[] = {"1;2",    /*MSITESTVAR11*/
+                                                "1",      /*MSITESTVAR12*/
+                                                "1;2",    /*MSITESTVAR13*/
+                                                ";1;",    /*MSITESTVAR14*/
+                                                ";;1;;",  /*MSITESTVAR15*/
+                                                " 1 ",    /*MSITESTVAR16*/
+                                                ";;2;;1", /*MSITESTVAR17*/
+                                                "1;;2;;", /*MSITESTVAR18*/
+                                                "1",      /*MSITESTVAR19*/
+                                                "1",      /*MSITESTVAR20*/
+                                                NULL};
+
+static const CHAR condition_dat[] = "Feature_\tLevel\tCondition\n"
+                                    "s38\ti2\tS255\n"
+                                    "Condition\tFeature_\tLevel\n"
+                                    "One\t4\t1\n";
+
+static const CHAR up_property_dat[] = "Property\tValue\n"
+                                      "s72\tl0\n"
+                                      "Property\tProperty\n"
+                                      "DefaultUIFont\tDlgFont8\n"
+                                      "HASUIRUN\t0\n"
+                                      "INSTALLLEVEL\t3\n"
+                                      "InstallMode\tTypical\n"
+                                      "Manufacturer\tWine\n"
+                                      "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n"
+                                      "ProductCode\t{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}\n"
+                                      "ProductID\tnone\n"
+                                      "ProductLanguage\t1033\n"
+                                      "ProductName\tMSITEST\n"
+                                      "ProductVersion\t1.1.1\n"
+                                      "PROMPTROLLBACKCOST\tP\n"
+                                      "Setup\tSetup\n"
+                                      "UpgradeCode\t{4C0EAA15-0264-4E5A-8758-609EF142B92D}\n"
+                                      "AdminProperties\tPOSTADMIN\n"
+                                      "ROOTDRIVE\tC:\\\n"
+                                      "SERVNAME\tTestService\n"
+                                      "SERVDISP\tTestServiceDisp\n"
+                                      "RemovePreviousVersions\t1\n";
+
+static const CHAR up2_property_dat[] = "Property\tValue\n"
+                                       "s72\tl0\n"
+                                       "Property\tProperty\n"
+                                       "DefaultUIFont\tDlgFont8\n"
+                                       "HASUIRUN\t0\n"
+                                       "INSTALLLEVEL\t3\n"
+                                       "InstallMode\tTypical\n"
+                                       "Manufacturer\tWine\n"
+                                       "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n"
+                                       "ProductCode\t{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}\n"
+                                       "ProductID\tnone\n"
+                                       "ProductLanguage\t1033\n"
+                                       "ProductName\tMSITEST\n"
+                                       "ProductVersion\t1.1.2\n"
+                                       "PROMPTROLLBACKCOST\tP\n"
+                                       "Setup\tSetup\n"
+                                       "UpgradeCode\t{4C0EAA15-0264-4E5A-8758-609EF142B92D}\n"
+                                       "AdminProperties\tPOSTADMIN\n"
+                                       "ROOTDRIVE\tC:\\\n"
+                                       "SERVNAME\tTestService\n"
+                                       "SERVDISP\tTestServiceDisp\n";
+
+static const CHAR up3_property_dat[] = "Property\tValue\n"
+                                       "s72\tl0\n"
+                                       "Property\tProperty\n"
+                                       "DefaultUIFont\tDlgFont8\n"
+                                       "HASUIRUN\t0\n"
+                                       "INSTALLLEVEL\t3\n"
+                                       "InstallMode\tTypical\n"
+                                       "Manufacturer\tWine\n"
+                                       "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n"
+                                       "ProductCode\t{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}\n"
+                                       "ProductID\tnone\n"
+                                       "ProductLanguage\t1033\n"
+                                       "ProductName\tMSITEST\n"
+                                       "ProductVersion\t1.1.2\n"
+                                       "PROMPTROLLBACKCOST\tP\n"
+                                       "Setup\tSetup\n"
+                                       "UpgradeCode\t{4C0EAA15-0264-4E5A-8758-609EF142B92D}\n"
+                                       "AdminProperties\tPOSTADMIN\n"
+                                       "ROOTDRIVE\tC:\\\n"
+                                       "SERVNAME\tTestService\n"
+                                       "SERVDISP\tTestServiceDisp\n"
+                                       "RemovePreviousVersions\t1\n";
+
 static const CHAR registry_dat[] = "Registry\tRoot\tKey\tName\tValue\tComponent_\n"
                                    "s72\ti2\tl255\tL255\tL0\ts72\n"
                                    "Registry\tRegistry\n"
@@ -169,6 +349,30 @@ static const CHAR service_control_dat[] = "ServiceControl\tName\tEvent\tArgument
                                           "ServiceControl\tServiceControl\n"
                                           "ServiceControl\tTestService\t8\t\t0\tservice_comp";
 
+static const CHAR sss_service_control_dat[] = "ServiceControl\tName\tEvent\tArguments\tWait\tComponent_\n"
+                                              "s72\tl255\ti2\tL255\tI2\ts72\n"
+                                              "ServiceControl\tServiceControl\n"
+                                              "ServiceControl\tSpooler\t1\t\t0\tservice_comp";
+
+static const CHAR sss_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"
+                                               "ResolveSource\t\t950\n"
+                                               "MoveFiles\t\t1700\n"
+                                               "InstallFiles\t\t4000\n"
+                                               "DuplicateFiles\t\t4500\n"
+                                               "WriteEnvironmentStrings\t\t4550\n"
+                                               "CreateShortcuts\t\t4600\n"
+                                               "StartServices\t\t5000\n"
+                                               "DeleteServices\t\t5500\n"
+                                               "InstallFinalize\t\t6600\n"
+                                               "InstallInitialize\t\t1500\n"
+                                               "InstallValidate\t\t1400\n"
+                                               "LaunchConditions\t\t100\n";
+
 /* tables for test_continuouscabs */
 static const CHAR cc_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
                                        "s72\tS38\ts72\ti2\tS255\tS72\n"
@@ -304,6 +508,21 @@ static const CHAR rof_media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\t
                                     "Media\tDiskId\n"
                                     "1\t1\t\t\tDISK1\t\n";
 
+static const CHAR rofc_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\t16384\t1";
+
+static const CHAR rofc_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 sdp_install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
                                                "s72\tS255\tI2\n"
                                                "InstallExecuteSequence\tAction\n"
@@ -439,6 +658,30 @@ static const CHAR pp_install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
                                               "PublishProduct\tPUBLISH_PRODUCT=1 Or FULL=1\t6400\n"
                                               "InstallFinalize\t\t6600";
 
+static const CHAR ppc_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"
+                                        "augustus\t{5AD3C142-CEF8-490D-B569-784D80670685}\tMSITESTDIR\t1\t\taugustus\n";
+
+static const CHAR ppc_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\n"
+                                   "augustus\taugustus\taugustus\t500\t\t\t8192\t2";
+
+static const CHAR ppc_media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
+                                    "i2\ti4\tL64\tS255\tS32\tS72\n"
+                                    "Media\tDiskId\n"
+                                    "1\t2\t\t\tDISK1\t\n";
+
+static const CHAR ppc_feature_comp_dat[] = "Feature_\tComponent_\n"
+                                           "s38\ts72\n"
+                                           "FeatureComponents\tFeature_\tComponent_\n"
+                                           "feature\tmaximus\n"
+                                           "feature\taugustus\n"
+                                           "montecristo\tmaximus";
+
 static const CHAR tp_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
                                        "s72\tS38\ts72\ti2\tS255\tS72\n"
                                        "Component\tComponent\n"
@@ -475,7 +718,7 @@ static const CHAR adm_admin_exec_seq_dat[] = "Action\tCondition\tSequence\n"
 static const CHAR amp_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
                                         "s72\tS38\ts72\ti2\tS255\tS72\n"
                                         "Component\tComponent\n"
-                                        "augustus\t\tMSITESTDIR\t0\tMYPROP=2718\taugustus\n";
+                                        "augustus\t\tMSITESTDIR\t0\tMYPROP=2718 and MyProp=42\taugustus\n";
 
 static const CHAR rem_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
                                         "s72\tS38\ts72\ti2\tS255\tS72\n"
@@ -527,7 +770,8 @@ static const CHAR rem_remove_files_dat[] = "FileKey\tComponent_\tFileName\tDirPr
                                            "attoparsec\tlithium\tattoparsec\tMSITESTDIR\t2\n"
                                            "storeys\thydrogen\tstoreys\tMSITESTDIR\t3\n"
                                            "block\thelium\tblock\tMSITESTDIR\t3\n"
-                                           "siriometer\tlithium\tsiriometer\tMSITESTDIR\t3\n";
+                                           "siriometer\tlithium\tsiriometer\tMSITESTDIR\t3\n"
+                                           "nanoacre\thydrogen\t\tCABOUTDIR\t3\n";
 
 static const CHAR mov_move_file_dat[] = "FileKey\tComponent_\tSourceName\tDestName\tSourceFolder\tDestFolder\tOptions\n"
                                         "s72\ts72\tS255\tS255\tS72\ts72\ti2\n"
@@ -545,6 +789,7 @@ static const CHAR mov_move_file_dat[] = "FileKey\tComponent_\tSourceName\tDestNa
                                         "kazakhstan\taugustus\t\tkiribati\tFILEPATHGOOD\tMSITESTDIR\t1\n"
                                         "laos\taugustus\tlatvia\tlebanon\tSourceDir\tMSITESTDIR\t1\n"
                                         "namibia\taugustus\tnauru\tkiribati\tSourceDir\tMSITESTDIR\t1\n"
+                                        "pakistan\taugustus\tperu\tsfn|poland\tSourceDir\tMSITESTDIR\t1\n"
                                         "wildcard\taugustus\tapp*\twildcard\tSourceDir\tMSITESTDIR\t1\n"
                                         "single\taugustus\tf?o\tsingle\tSourceDir\tMSITESTDIR\t1\n"
                                         "wildcardnodest\taugustus\tbudd*\t\tSourceDir\tMSITESTDIR\t1\n"
@@ -593,7 +838,8 @@ static const CHAR df_duplicate_file_dat[] = "FileKey\tComponent_\tFile_\tDestNam
                                             "s72\ts72\ts72\tS255\tS72\n"
                                             "DuplicateFile\tFileKey\n"
                                             "maximus\tmaximus\tmaximus\taugustus\t\n"
-                                            "caesar\tmaximus\tmaximus\t\tNONEXISTENT\n";
+                                            "caesar\tmaximus\tmaximus\t\tNONEXISTENT\n"
+                                            "augustus\tnosuchcomponent\tmaximus\t\tMSITESTDIR\n";
 
 static const CHAR wrv_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
                                         "s72\tS38\ts72\ti2\tS255\tS72\n"
@@ -617,7 +863,9 @@ static const CHAR ca51_install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
                                                 "GoodSetProperty\t\t725\n"
                                                 "BadSetProperty\t\t750\n"
                                                 "CostInitialize\t\t800\n"
+                                                "ResolveSource\t\t810\n"
                                                 "FileCost\t\t900\n"
+                                                "SetSourceDir\tSRCDIR\t910\n"
                                                 "CostFinalize\t\t1000\n"
                                                 "InstallValidate\t\t1400\n"
                                                 "InstallInitialize\t\t1500\n"
@@ -628,7 +876,8 @@ static const CHAR ca51_custom_action_dat[] = "Action\tType\tSource\tTarget\n"
                                              "s72\ti2\tS64\tS0\n"
                                              "CustomAction\tAction\n"
                                              "GoodSetProperty\t51\tMYPROP\t42\n"
-                                             "BadSetProperty\t51\t\tMYPROP\n";
+                                             "BadSetProperty\t51\t\tMYPROP\n"
+                                             "SetSourceDir\t51\tSourceDir\t[SRCDIR]\n";
 
 static const CHAR is_feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
                                      "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
@@ -691,6 +940,518 @@ static const CHAR is_media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tV
                                    "Media\tDiskId\n"
                                    "1\t12\t\t\tDISK1\t\n";
 
+static const CHAR sp_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
+                                        "s72\tS38\ts72\ti2\tS255\tS72\n"
+                                        "Component\tComponent\n"
+                                        "augustus\t\tTWODIR\t0\t\taugustus\n";
+
+static const CHAR sp_directory_dat[] = "Directory\tDirectory_Parent\tDefaultDir\n"
+                                       "s72\tS72\tl255\n"
+                                       "Directory\tDirectory\n"
+                                       "TARGETDIR\t\tSourceDir\n"
+                                       "ProgramFilesFolder\tTARGETDIR\t.\n"
+                                       "MSITESTDIR\tProgramFilesFolder\tmsitest:.\n"
+                                       "ONEDIR\tMSITESTDIR\t.:shortone|longone\n"
+                                       "TWODIR\tONEDIR\t.:shorttwo|longtwo";
+
+static const CHAR mcp_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
+                                        "s72\tS38\ts72\ti2\tS255\tS72\n"
+                                        "Component\tComponent\n"
+                                        "hydrogen\t{C844BD1E-1907-4C00-8BC9-150BD70DF0A1}\tMSITESTDIR\t2\t\thydrogen\n"
+                                        "helium\t{5AD3C142-CEF8-490D-B569-784D80670685}\tMSITESTDIR\t2\t\thelium\n"
+                                        "lithium\t{4AF28FFC-71C7-4307-BDE4-B77C5338F56F}\tMSITESTDIR\t2\tPROPVAR=42\tlithium\n";
+
+static const CHAR mcp_feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
+                                      "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
+                                      "Feature\tFeature\n"
+                                      "hydroxyl\t\thydroxyl\thydroxyl\t2\t1\tTARGETDIR\t0\n"
+                                      "heliox\t\theliox\theliox\t2\t5\tTARGETDIR\t0\n"
+                                      "lithia\t\tlithia\tlithia\t2\t10\tTARGETDIR\t0";
+
+static const CHAR mcp_feature_comp_dat[] = "Feature_\tComponent_\n"
+                                           "s38\ts72\n"
+                                           "FeatureComponents\tFeature_\tComponent_\n"
+                                           "hydroxyl\thydrogen\n"
+                                           "heliox\thelium\n"
+                                           "lithia\tlithium";
+
+static const CHAR mcomp_file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
+                                     "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
+                                     "File\tFile\n"
+                                     "hydrogen\thydrogen\thydrogen\t0\t\t\t8192\t1\n"
+                                     "helium\thelium\thelium\t0\t\t\t8192\t1\n"
+                                     "lithium\tlithium\tlithium\t0\t\t\t8192\t1\n"
+                                     "beryllium\tmissingcomp\tberyllium\t0\t\t\t8192\t1";
+
+static const CHAR ai_file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
+                                  "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
+                                  "File\tFile\n"
+                                  "five.txt\tFive\tfive.txt\t1000\t\t\t16384\t5\n"
+                                  "four.txt\tFour\tfour.txt\t1000\t\t\t16384\t4\n"
+                                  "one.txt\tOne\tone.txt\t1000\t\t\t16384\t1\n"
+                                  "three.txt\tThree\tthree.txt\t1000\t\t\t16384\t3\n"
+                                  "two.txt\tTwo\ttwo.txt\t1000\t\t\t16384\t2\n"
+                                  "file\tcomponent\tfilename\t100\t\t\t8192\t1\n"
+                                  "service_file\tservice_comp\tservice.exe\t100\t\t\t8192\t1";
+
+static const CHAR ip_install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
+                                              "s72\tS255\tI2\n"
+                                              "InstallExecuteSequence\tAction\n"
+                                              "CostFinalize\t\t1000\n"
+                                              "ValidateProductID\t\t700\n"
+                                              "CostInitialize\t\t800\n"
+                                              "FileCost\t\t900\n"
+                                              "RemoveFiles\t\t3500\n"
+                                              "InstallFiles\t\t4000\n"
+                                              "RegisterUser\t\t6000\n"
+                                              "RegisterProduct\t\t6100\n"
+                                              "PublishFeatures\t\t6300\n"
+                                              "PublishProduct\t\t6400\n"
+                                              "InstallFinalize\t\t6600\n"
+                                              "InstallInitialize\t\t1500\n"
+                                              "ProcessComponents\t\t1600\n"
+                                              "UnpublishFeatures\t\t1800\n"
+                                              "InstallValidate\t\t1400\n"
+                                              "LaunchConditions\t\t100\n"
+                                              "TestInstalledProp\tInstalled AND NOT REMOVE\t950\n";
+
+static const CHAR ip_custom_action_dat[] = "Action\tType\tSource\tTarget\tISComments\n"
+                                           "s72\ti2\tS64\tS0\tS255\n"
+                                           "CustomAction\tAction\n"
+                                           "TestInstalledProp\t19\t\tTest failed\t\n";
+
+static const CHAR aup_install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
+                                               "s72\tS255\tI2\n"
+                                               "InstallExecuteSequence\tAction\n"
+                                               "CostFinalize\t\t1000\n"
+                                               "ValidateProductID\t\t700\n"
+                                               "CostInitialize\t\t800\n"
+                                               "FileCost\t\t900\n"
+                                               "RemoveFiles\t\t3500\n"
+                                               "InstallFiles\t\t4000\n"
+                                               "RegisterUser\t\t6000\n"
+                                               "RegisterProduct\t\t6100\n"
+                                               "PublishFeatures\t\t6300\n"
+                                               "PublishProduct\t\t6400\n"
+                                               "InstallFinalize\t\t6600\n"
+                                               "InstallInitialize\t\t1500\n"
+                                               "ProcessComponents\t\t1600\n"
+                                               "UnpublishFeatures\t\t1800\n"
+                                               "InstallValidate\t\t1400\n"
+                                               "LaunchConditions\t\t100\n"
+                                               "TestAllUsersProp\tALLUSERS AND NOT REMOVE\t50\n";
+
+static const CHAR aup2_install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
+                                                "s72\tS255\tI2\n"
+                                                "InstallExecuteSequence\tAction\n"
+                                                "CostFinalize\t\t1000\n"
+                                                "ValidateProductID\t\t700\n"
+                                                "CostInitialize\t\t800\n"
+                                                "FileCost\t\t900\n"
+                                                "RemoveFiles\t\t3500\n"
+                                                "InstallFiles\t\t4000\n"
+                                                "RegisterUser\t\t6000\n"
+                                                "RegisterProduct\t\t6100\n"
+                                                "PublishFeatures\t\t6300\n"
+                                                "PublishProduct\t\t6400\n"
+                                                "InstallFinalize\t\t6600\n"
+                                                "InstallInitialize\t\t1500\n"
+                                                "ProcessComponents\t\t1600\n"
+                                                "UnpublishFeatures\t\t1800\n"
+                                                "InstallValidate\t\t1400\n"
+                                                "LaunchConditions\t\t100\n"
+                                                "TestAllUsersProp\tALLUSERS=2 AND NOT REMOVE\t50\n";
+
+static const CHAR aup3_install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
+                                                "s72\tS255\tI2\n"
+                                                "InstallExecuteSequence\tAction\n"
+                                                "CostFinalize\t\t1000\n"
+                                                "ValidateProductID\t\t700\n"
+                                                "CostInitialize\t\t800\n"
+                                                "FileCost\t\t900\n"
+                                                "RemoveFiles\t\t3500\n"
+                                                "InstallFiles\t\t4000\n"
+                                                "RegisterUser\t\t6000\n"
+                                                "RegisterProduct\t\t6100\n"
+                                                "PublishFeatures\t\t6300\n"
+                                                "PublishProduct\t\t6400\n"
+                                                "InstallFinalize\t\t6600\n"
+                                                "InstallInitialize\t\t1500\n"
+                                                "ProcessComponents\t\t1600\n"
+                                                "UnpublishFeatures\t\t1800\n"
+                                                "InstallValidate\t\t1400\n"
+                                                "LaunchConditions\t\t100\n"
+                                                "TestAllUsersProp\tALLUSERS=1 AND NOT REMOVE\t50\n";
+
+static const CHAR aup_custom_action_dat[] = "Action\tType\tSource\tTarget\tISComments\n"
+                                            "s72\ti2\tS64\tS0\tS255\n"
+                                            "CustomAction\tAction\n"
+                                            "TestAllUsersProp\t19\t\tTest failed\t\n";
+
+static const CHAR cf_create_folders_dat[] = "Directory_\tComponent_\n"
+                                            "s72\ts72\n"
+                                            "CreateFolder\tDirectory_\tComponent_\n"
+                                            "FIRSTDIR\tOne\n";
+
+static const CHAR cf_install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
+                                              "s72\tS255\tI2\n"
+                                              "InstallExecuteSequence\tAction\n"
+                                              "CostFinalize\t\t1000\n"
+                                              "ValidateProductID\t\t700\n"
+                                              "CostInitialize\t\t800\n"
+                                              "FileCost\t\t900\n"
+                                              "RemoveFiles\t\t3500\n"
+                                              "CreateFolders\t\t3700\n"
+                                              "InstallExecute\t\t3800\n"
+                                              "TestCreateFolders\t\t3900\n"
+                                              "InstallFiles\t\t4000\n"
+                                              "RegisterUser\t\t6000\n"
+                                              "RegisterProduct\t\t6100\n"
+                                              "PublishFeatures\t\t6300\n"
+                                              "PublishProduct\t\t6400\n"
+                                              "InstallFinalize\t\t6600\n"
+                                              "InstallInitialize\t\t1500\n"
+                                              "ProcessComponents\t\t1600\n"
+                                              "UnpublishFeatures\t\t1800\n"
+                                              "InstallValidate\t\t1400\n"
+                                              "LaunchConditions\t\t100\n";
+
+static const CHAR cf_custom_action_dat[] = "Action\tType\tSource\tTarget\tISComments\n"
+                                           "s72\ti2\tS64\tS0\tS255\n"
+                                           "CustomAction\tAction\n"
+                                           "TestCreateFolders\t19\t\tHalts installation\t\n";
+
+static const CHAR rf_install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
+                                              "s72\tS255\tI2\n"
+                                              "InstallExecuteSequence\tAction\n"
+                                              "CostFinalize\t\t1000\n"
+                                              "ValidateProductID\t\t700\n"
+                                              "CostInitialize\t\t800\n"
+                                              "FileCost\t\t900\n"
+                                              "RemoveFiles\t\t3500\n"
+                                              "CreateFolders\t\t3600\n"
+                                              "RemoveFolders\t\t3700\n"
+                                              "InstallExecute\t\t3800\n"
+                                              "TestCreateFolders\t\t3900\n"
+                                              "InstallFiles\t\t4000\n"
+                                              "RegisterUser\t\t6000\n"
+                                              "RegisterProduct\t\t6100\n"
+                                              "PublishFeatures\t\t6300\n"
+                                              "PublishProduct\t\t6400\n"
+                                              "InstallFinalize\t\t6600\n"
+                                              "InstallInitialize\t\t1500\n"
+                                              "ProcessComponents\t\t1600\n"
+                                              "UnpublishFeatures\t\t1800\n"
+                                              "InstallValidate\t\t1400\n"
+                                              "LaunchConditions\t\t100\n";
+
+
+static const CHAR sr_selfreg_dat[] = "File_\tCost\n"
+                                     "s72\tI2\n"
+                                     "SelfReg\tFile_\n"
+                                     "one.txt\t1\n";
+
+static const CHAR sr_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"
+                                              "ResolveSource\t\t950\n"
+                                              "MoveFiles\t\t1700\n"
+                                              "SelfUnregModules\t\t3900\n"
+                                              "InstallFiles\t\t4000\n"
+                                              "DuplicateFiles\t\t4500\n"
+                                              "WriteEnvironmentStrings\t\t4550\n"
+                                              "CreateShortcuts\t\t4600\n"
+                                              "InstallFinalize\t\t6600\n"
+                                              "InstallInitialize\t\t1500\n"
+                                              "InstallValidate\t\t1400\n"
+                                              "LaunchConditions\t\t100\n";
+
+static const CHAR font_media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
+                                     "i2\ti4\tL64\tS255\tS32\tS72\n"
+                                     "Media\tDiskId\n"
+                                     "1\t3\t\t\tDISK1\t\n";
+
+static const CHAR font_file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
+                                    "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
+                                    "File\tFile\n"
+                                    "font.ttf\tfonts\tfont.ttf\t1000\t\t\t8192\t1\n";
+
+static const CHAR font_feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
+                                       "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
+                                       "Feature\tFeature\n"
+                                       "fonts\t\t\tfont feature\t1\t2\tMSITESTDIR\t0\n";
+
+static const CHAR font_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
+                                         "s72\tS38\ts72\ti2\tS255\tS72\n"
+                                         "Component\tComponent\n"
+                                         "fonts\t{F5920ED0-1183-4B8F-9330-86CE56557C05}\tMSITESTDIR\t0\t\tfont.ttf\n";
+
+static const CHAR font_feature_comp_dat[] = "Feature_\tComponent_\n"
+                                            "s38\ts72\n"
+                                            "FeatureComponents\tFeature_\tComponent_\n"
+                                            "fonts\tfonts\n";
+
+static const CHAR font_dat[] = "File_\tFontTitle\n"
+                               "s72\tS128\n"
+                               "Font\tFile_\n"
+                               "font.ttf\tmsi test font\n";
+
+static const CHAR font_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\t\t1600\n"
+                                                "UnpublishFeatures\t\t1800\n"
+                                                "RemoveFiles\t\t3500\n"
+                                                "InstallFiles\t\t4000\n"
+                                                "RegisterFonts\t\t4100\n"
+                                                "UnregisterFonts\t\t4200\n"
+                                                "RegisterUser\t\t6000\n"
+                                                "RegisterProduct\t\t6100\n"
+                                                "PublishFeatures\t\t6300\n"
+                                                "PublishProduct\t\t6400\n"
+                                                "InstallFinalize\t\t6600";
+
+static const CHAR vp_property_dat[] = "Property\tValue\n"
+                                      "s72\tl0\n"
+                                      "Property\tProperty\n"
+                                      "HASUIRUN\t0\n"
+                                      "INSTALLLEVEL\t3\n"
+                                      "InstallMode\tTypical\n"
+                                      "Manufacturer\tWine\n"
+                                      "PIDTemplate\t###-#######\n"
+                                      "ProductCode\t{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}\n"
+                                      "ProductLanguage\t1033\n"
+                                      "ProductName\tMSITEST\n"
+                                      "ProductVersion\t1.1.1\n"
+                                      "UpgradeCode\t{4C0EAA15-0264-4E5A-8758-609EF142B92D}\n";
+
+static const CHAR vp_custom_action_dat[] = "Action\tType\tSource\tTarget\tISComments\n"
+                                           "s72\ti2\tS64\tS0\tS255\n"
+                                           "CustomAction\tAction\n"
+                                           "SetProductID1\t51\tProductID\t1\t\n"
+                                           "SetProductID2\t51\tProductID\t2\t\n"
+                                           "TestProductID1\t19\t\t\tHalts installation\n"
+                                           "TestProductID2\t19\t\t\tHalts installation\n";
+
+static const CHAR vp_install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
+                                              "s72\tS255\tI2\n"
+                                              "InstallExecuteSequence\tAction\n"
+                                              "LaunchConditions\t\t100\n"
+                                              "CostInitialize\t\t800\n"
+                                              "FileCost\t\t900\n"
+                                              "CostFinalize\t\t1000\n"
+                                              "InstallValidate\t\t1400\n"
+                                              "InstallInitialize\t\t1500\n"
+                                              "SetProductID1\tSET_PRODUCT_ID=1\t3000\n"
+                                              "SetProductID2\tSET_PRODUCT_ID=2\t3100\n"
+                                              "ValidateProductID\t\t3200\n"
+                                              "InstallExecute\t\t3300\n"
+                                              "TestProductID1\tProductID=1\t3400\n"
+                                              "TestProductID2\tProductID=\"123-1234567\"\t3500\n"
+                                              "InstallFiles\t\t4000\n"
+                                              "InstallFinalize\t\t6000\n";
+
+static const CHAR odbc_file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
+                                    "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
+                                    "File\tFile\n"
+                                    "ODBCdriver.dll\todbc\tODBCdriver.dll\t1000\t\t\t8192\t1\n"
+                                    "ODBCdriver2.dll\todbc\tODBCdriver2.dll\t1000\t\t\t8192\t2\n"
+                                    "ODBCtranslator.dll\todbc\tODBCtranslator.dll\t1000\t\t\t8192\t3\n"
+                                    "ODBCtranslator2.dll\todbc\tODBCtranslator2.dll\t1000\t\t\t8192\t4\n"
+                                    "ODBCsetup.dll\todbc\tODBCsetup.dll\t1000\t\t\t8192\t5\n";
+
+static const CHAR odbc_feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
+                                       "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
+                                       "Feature\tFeature\n"
+                                       "odbc\t\t\todbc feature\t1\t2\tMSITESTDIR\t0\n";
+
+static const CHAR odbc_feature_comp_dat[] = "Feature_\tComponent_\n"
+                                            "s38\ts72\n"
+                                            "FeatureComponents\tFeature_\tComponent_\n"
+                                            "odbc\todbc\n";
+
+static const CHAR odbc_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
+                                         "s72\tS38\ts72\ti2\tS255\tS72\n"
+                                         "Component\tComponent\n"
+                                         "odbc\t{B6F3E4AE-35D1-4B72-9044-989F03E20A43}\tMSITESTDIR\t0\t\tODBCdriver.dll\n";
+
+static const CHAR odbc_driver_dat[] = "Driver\tComponent_\tDescription\tFile_\tFile_Setup\n"
+                                      "s72\ts72\ts255\ts72\tS72\n"
+                                      "ODBCDriver\tDriver\n"
+                                      "ODBC test driver\todbc\tODBC test driver\tODBCdriver.dll\t\n"
+                                      "ODBC test driver2\todbc\tODBC test driver2\tODBCdriver2.dll\tODBCsetup.dll\n";
+
+static const CHAR odbc_translator_dat[] = "Translator\tComponent_\tDescription\tFile_\tFile_Setup\n"
+                                          "s72\ts72\ts255\ts72\tS72\n"
+                                          "ODBCTranslator\tTranslator\n"
+                                          "ODBC test translator\todbc\tODBC test translator\tODBCtranslator.dll\t\n"
+                                          "ODBC test translator2\todbc\tODBC test translator2\tODBCtranslator2.dll\tODBCsetup.dll\n";
+
+static const CHAR odbc_datasource_dat[] = "DataSource\tComponent_\tDescription\tDriverDescription\tRegistration\n"
+                                          "s72\ts72\ts255\ts255\ti2\n"
+                                          "ODBCDataSource\tDataSource\n"
+                                          "ODBC data source\todbc\tODBC data source\tODBC driver\t0\n";
+
+static const CHAR odbc_install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
+                                                "s72\tS255\tI2\n"
+                                                "InstallExecuteSequence\tAction\n"
+                                                "LaunchConditions\t\t100\n"
+                                                "CostInitialize\t\t800\n"
+                                                "FileCost\t\t900\n"
+                                                "CostFinalize\t\t1000\n"
+                                                "InstallValidate\t\t1400\n"
+                                                "InstallInitialize\t\t1500\n"
+                                                "InstallODBC\t\t3000\n"
+                                                "RemoveODBC\t\t3100\n"
+                                                "InstallFiles\t\t4000\n"
+                                                "InstallFinalize\t\t6000\n";
+
+static const CHAR odbc_media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
+                                     "i2\ti4\tL64\tS255\tS32\tS72\n"
+                                     "Media\tDiskId\n"
+                                     "1\t5\t\t\tDISK1\t\n";
+
+static const CHAR tl_file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
+                                  "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
+                                  "File\tFile\n"
+                                  "typelib.dll\ttypelib\ttypelib.dll\t1000\t\t\t8192\t1\n";
+
+static const CHAR tl_feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
+                                     "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
+                                     "Feature\tFeature\n"
+                                     "typelib\t\t\ttypelib feature\t1\t2\tMSITESTDIR\t0\n";
+
+static const CHAR tl_feature_comp_dat[] = "Feature_\tComponent_\n"
+                                          "s38\ts72\n"
+                                          "FeatureComponents\tFeature_\tComponent_\n"
+                                          "typelib\ttypelib\n";
+
+static const CHAR tl_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
+                                       "s72\tS38\ts72\ti2\tS255\tS72\n"
+                                       "Component\tComponent\n"
+                                       "typelib\t{BB4C26FD-89D8-4E49-AF1C-DB4DCB5BF1B0}\tMSITESTDIR\t0\t\ttypelib.dll\n";
+
+static const CHAR tl_typelib_dat[] = "LibID\tLanguage\tComponent_\tVersion\tDescription\tDirectory_\tFeature_\tCost\n"
+                                     "s38\ti2\ts72\tI4\tL128\tS72\ts38\tI4\n"
+                                     "TypeLib\tLibID\tLanguage\tComponent_\n"
+                                     "{EAC5166A-9734-4D91-878F-1DD02304C66C}\t0\ttypelib\t1793\t\tMSITESTDIR\ttypelib\t\n";
+
+static const CHAR tl_install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
+                                              "s72\tS255\tI2\n"
+                                              "InstallExecuteSequence\tAction\n"
+                                              "LaunchConditions\t\t100\n"
+                                              "CostInitialize\t\t800\n"
+                                              "FileCost\t\t900\n"
+                                              "CostFinalize\t\t1000\n"
+                                              "InstallValidate\t\t1400\n"
+                                              "InstallInitialize\t\t1500\n"
+                                              "ProcessComponents\t\t1600\n"
+                                              "RemoveFiles\t\t1700\n"
+                                              "InstallFiles\t\t2000\n"
+                                              "RegisterTypeLibraries\tREGISTER_TYPELIB=1\t3000\n"
+                                              "UnregisterTypeLibraries\t\t3100\n"
+                                              "RegisterProduct\t\t5100\n"
+                                              "PublishFeatures\t\t5200\n"
+                                              "PublishProduct\t\t5300\n"
+                                              "InstallFinalize\t\t6000\n";
+
+static const CHAR crs_file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
+                                   "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
+                                   "File\tFile\n"
+                                   "target.txt\tshortcut\ttarget.txt\t1000\t\t\t8192\t1\n";
+
+static const CHAR crs_feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
+                                      "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
+                                      "Feature\tFeature\n"
+                                      "shortcut\t\t\tshortcut feature\t1\t2\tMSITESTDIR\t0\n";
+
+static const CHAR crs_feature_comp_dat[] = "Feature_\tComponent_\n"
+                                           "s38\ts72\n"
+                                           "FeatureComponents\tFeature_\tComponent_\n"
+                                           "shortcut\tshortcut\n";
+
+static const CHAR crs_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
+                                        "s72\tS38\ts72\ti2\tS255\tS72\n"
+                                        "Component\tComponent\n"
+                                        "shortcut\t{5D20E3C6-7206-498F-AC28-87AF2F9AD4CC}\tMSITESTDIR\t0\t\ttarget.txt\n";
+
+static const CHAR crs_shortcut_dat[] = "Shortcut\tDirectory_\tName\tComponent_\tTarget\tArguments\tDescription\tHotkey\tIcon_\tIconIndex\tShowCmd\tWkDir\n"
+                                       "s72\ts72\tl128\ts72\ts72\tL255\tL255\tI2\tS72\tI2\tI2\tS72\n"
+                                       "Shortcut\tShortcut\n"
+                                       "shortcut\tMSITESTDIR\tshortcut\tshortcut\t[MSITESTDIR]target.txt\t\t\t\t\t\t\t\n";
+
+static const CHAR crs_install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
+                                               "s72\tS255\tI2\n"
+                                               "InstallExecuteSequence\tAction\n"
+                                               "LaunchConditions\t\t100\n"
+                                               "CostInitialize\t\t800\n"
+                                               "FileCost\t\t900\n"
+                                               "CostFinalize\t\t1000\n"
+                                               "InstallValidate\t\t1400\n"
+                                               "InstallInitialize\t\t1500\n"
+                                               "ProcessComponents\t\t1600\n"
+                                               "RemoveFiles\t\t1700\n"
+                                               "InstallFiles\t\t2000\n"
+                                               "RemoveShortcuts\t\t3000\n"
+                                               "CreateShortcuts\t\t3100\n"
+                                               "RegisterProduct\t\t5000\n"
+                                               "PublishFeatures\t\t5100\n"
+                                               "PublishProduct\t\t5200\n"
+                                               "InstallFinalize\t\t6000\n";
+
+static const CHAR pub_file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
+                                   "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
+                                   "File\tFile\n"
+                                   "english.txt\tpublish\tenglish.txt\t1000\t\t\t8192\t1\n";
+
+static const CHAR pub_feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
+                                      "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
+                                      "Feature\tFeature\n"
+                                      "publish\t\t\tpublish feature\t1\t2\tMSITESTDIR\t0\n";
+
+static const CHAR pub_feature_comp_dat[] = "Feature_\tComponent_\n"
+                                           "s38\ts72\n"
+                                           "FeatureComponents\tFeature_\tComponent_\n"
+                                           "publish\tpublish\n";
+
+static const CHAR pub_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
+                                        "s72\tS38\ts72\ti2\tS255\tS72\n"
+                                        "Component\tComponent\n"
+                                        "publish\t{B4EA0ACF-6238-426E-9C6D-7869F0F9C768}\tMSITESTDIR\t0\t\tenglish.txt\n";
+
+static const CHAR pub_publish_component_dat[] = "ComponentId\tQualifier\tComponent_\tAppData\tFeature_\n"
+                                                "s38\ts255\ts72\tL255\ts38\n"
+                                                "PublishComponent\tComponentId\tQualifier\tComponent_\n"
+                                                "{92AFCBC0-9CA6-4270-8454-47C5EE2B8FAA}\tenglish.txt\tpublish\t\tpublish\n";
+
+static const CHAR pub_install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
+                                               "s72\tS255\tI2\n"
+                                               "InstallExecuteSequence\tAction\n"
+                                               "LaunchConditions\t\t100\n"
+                                               "CostInitialize\t\t800\n"
+                                               "FileCost\t\t900\n"
+                                               "CostFinalize\t\t1000\n"
+                                               "InstallValidate\t\t1400\n"
+                                               "InstallInitialize\t\t1500\n"
+                                               "ProcessComponents\t\t1600\n"
+                                               "RemoveFiles\t\t1700\n"
+                                               "InstallFiles\t\t2000\n"
+                                               "PublishComponents\t\t3000\n"
+                                               "UnpublishComponents\t\t3100\n"
+                                               "RegisterProduct\t\t5000\n"
+                                               "PublishFeatures\t\t5100\n"
+                                               "PublishProduct\t\t5200\n"
+                                               "InstallFinalize\t\t6000\n";
+
 typedef struct _msi_table
 {
     const CHAR *filename;
@@ -715,9 +1476,153 @@ static const msi_table tables[] =
     ADD_TABLE(service_control)
 };
 
-static const msi_table cc_tables[] =
+static const msi_table sc_tables[] =
 {
-    ADD_TABLE(cc_component),
+    ADD_TABLE(component),
+    ADD_TABLE(directory),
+    ADD_TABLE(feature),
+    ADD_TABLE(feature_comp),
+    ADD_TABLE(file),
+    ADD_TABLE(install_exec_seq),
+    ADD_TABLE(media),
+    ADD_TABLE(property),
+    ADD_TABLE(shortcut)
+};
+
+static const msi_table ps_tables[] =
+{
+    ADD_TABLE(component),
+    ADD_TABLE(directory),
+    ADD_TABLE(feature),
+    ADD_TABLE(feature_comp),
+    ADD_TABLE(file),
+    ADD_TABLE(install_exec_seq),
+    ADD_TABLE(media),
+    ADD_TABLE(property),
+    ADD_TABLE(condition)
+};
+
+static const msi_table env_tables[] =
+{
+    ADD_TABLE(component),
+    ADD_TABLE(directory),
+    ADD_TABLE(feature),
+    ADD_TABLE(feature_comp),
+    ADD_TABLE(file),
+    ADD_TABLE(install_exec_seq),
+    ADD_TABLE(media),
+    ADD_TABLE(property),
+    ADD_TABLE(environment)
+};
+
+static const msi_table up_tables[] =
+{
+    ADD_TABLE(component),
+    ADD_TABLE(directory),
+    ADD_TABLE(feature),
+    ADD_TABLE(feature_comp),
+    ADD_TABLE(file),
+    ADD_TABLE(install_exec_seq),
+    ADD_TABLE(media),
+    ADD_TABLE(up_property),
+    ADD_TABLE(registry),
+    ADD_TABLE(service_install),
+    ADD_TABLE(service_control)
+};
+
+static const msi_table up2_tables[] =
+{
+    ADD_TABLE(component),
+    ADD_TABLE(directory),
+    ADD_TABLE(feature),
+    ADD_TABLE(feature_comp),
+    ADD_TABLE(file),
+    ADD_TABLE(install_exec_seq),
+    ADD_TABLE(media),
+    ADD_TABLE(up2_property),
+    ADD_TABLE(registry),
+    ADD_TABLE(service_install),
+    ADD_TABLE(service_control)
+};
+
+static const msi_table up3_tables[] =
+{
+    ADD_TABLE(component),
+    ADD_TABLE(directory),
+    ADD_TABLE(feature),
+    ADD_TABLE(feature_comp),
+    ADD_TABLE(file),
+    ADD_TABLE(install_exec_seq),
+    ADD_TABLE(media),
+    ADD_TABLE(up3_property),
+    ADD_TABLE(registry),
+    ADD_TABLE(service_install),
+    ADD_TABLE(service_control)
+};
+
+static const msi_table up4_tables[] =
+{
+    ADD_TABLE(component),
+    ADD_TABLE(directory),
+    ADD_TABLE(feature),
+    ADD_TABLE(feature_comp),
+    ADD_TABLE(file),
+    ADD_TABLE(pp_install_exec_seq),
+    ADD_TABLE(media),
+    ADD_TABLE(property),
+    ADD_TABLE(registry),
+    ADD_TABLE(service_install),
+    ADD_TABLE(service_control)
+};
+
+static const msi_table up5_tables[] =
+{
+    ADD_TABLE(component),
+    ADD_TABLE(directory),
+    ADD_TABLE(feature),
+    ADD_TABLE(feature_comp),
+    ADD_TABLE(file),
+    ADD_TABLE(pp_install_exec_seq),
+    ADD_TABLE(media),
+    ADD_TABLE(up_property),
+    ADD_TABLE(registry),
+    ADD_TABLE(service_install),
+    ADD_TABLE(service_control)
+};
+
+static const msi_table up6_tables[] =
+{
+    ADD_TABLE(component),
+    ADD_TABLE(directory),
+    ADD_TABLE(feature),
+    ADD_TABLE(feature_comp),
+    ADD_TABLE(file),
+    ADD_TABLE(pp_install_exec_seq),
+    ADD_TABLE(media),
+    ADD_TABLE(up2_property),
+    ADD_TABLE(registry),
+    ADD_TABLE(service_install),
+    ADD_TABLE(service_control)
+};
+
+static const msi_table up7_tables[] =
+{
+    ADD_TABLE(component),
+    ADD_TABLE(directory),
+    ADD_TABLE(feature),
+    ADD_TABLE(feature_comp),
+    ADD_TABLE(file),
+    ADD_TABLE(pp_install_exec_seq),
+    ADD_TABLE(media),
+    ADD_TABLE(up3_property),
+    ADD_TABLE(registry),
+    ADD_TABLE(service_install),
+    ADD_TABLE(service_control)
+};
+
+static const msi_table cc_tables[] =
+{
+    ADD_TABLE(cc_component),
     ADD_TABLE(directory),
     ADD_TABLE(cc_feature),
     ADD_TABLE(cc_feature_comp),
@@ -813,6 +1718,18 @@ static const msi_table rof_tables[] =
     ADD_TABLE(property),
 };
 
+static const msi_table rofc_tables[] =
+{
+    ADD_TABLE(rof_component),
+    ADD_TABLE(directory),
+    ADD_TABLE(rof_feature),
+    ADD_TABLE(rof_feature_comp),
+    ADD_TABLE(rofc_file),
+    ADD_TABLE(install_exec_seq),
+    ADD_TABLE(rofc_media),
+    ADD_TABLE(property),
+};
+
 static const msi_table sdp_tables[] =
 {
     ADD_TABLE(rof_component),
@@ -889,6 +1806,54 @@ static const msi_table pp_tables[] =
     ADD_TABLE(property),
 };
 
+static const msi_table ppc_tables[] =
+{
+    ADD_TABLE(ppc_component),
+    ADD_TABLE(directory),
+    ADD_TABLE(rof_feature),
+    ADD_TABLE(ppc_feature_comp),
+    ADD_TABLE(ppc_file),
+    ADD_TABLE(pp_install_exec_seq),
+    ADD_TABLE(ppc_media),
+    ADD_TABLE(property),
+};
+
+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),
@@ -1041,54 +2006,350 @@ static const msi_table is_tables[] =
     ADD_TABLE(property),
 };
 
-/* cabinet definitions */
-
-/* make the max size large so there is only one cab file */
-#define MEDIA_SIZE          0x7FFFFFFF
-#define FOLDER_THRESHOLD    900000
+static const msi_table sp_tables[] =
+{
+    ADD_TABLE(sp_component),
+    ADD_TABLE(sp_directory),
+    ADD_TABLE(rof_feature),
+    ADD_TABLE(ci2_feature_comp),
+    ADD_TABLE(ci2_file),
+    ADD_TABLE(install_exec_seq),
+    ADD_TABLE(rof_media),
+    ADD_TABLE(property),
+};
 
-/* the FCI callbacks */
+static const msi_table mcp_tables[] =
+{
+    ADD_TABLE(mcp_component),
+    ADD_TABLE(directory),
+    ADD_TABLE(mcp_feature),
+    ADD_TABLE(mcp_feature_comp),
+    ADD_TABLE(rem_file),
+    ADD_TABLE(rem_install_exec_seq),
+    ADD_TABLE(rof_media),
+    ADD_TABLE(property),
+};
 
-static void *mem_alloc(ULONG cb)
+static const msi_table mcomp_tables[] =
 {
-    return HeapAlloc(GetProcessHeap(), 0, cb);
-}
+    ADD_TABLE(mcp_component),
+    ADD_TABLE(directory),
+    ADD_TABLE(mcp_feature),
+    ADD_TABLE(mcp_feature_comp),
+    ADD_TABLE(mcomp_file),
+    ADD_TABLE(rem_install_exec_seq),
+    ADD_TABLE(rof_media),
+    ADD_TABLE(property),
+};
 
-static void mem_free(void *memory)
+static const msi_table ai_tables[] =
 {
-    HeapFree(GetProcessHeap(), 0, memory);
-}
+    ADD_TABLE(component),
+    ADD_TABLE(directory),
+    ADD_TABLE(feature),
+    ADD_TABLE(feature_comp),
+    ADD_TABLE(ai_file),
+    ADD_TABLE(install_exec_seq),
+    ADD_TABLE(media),
+    ADD_TABLE(property)
+};
 
-static BOOL get_next_cabinet(PCCAB pccab, ULONG  cbPrevCab, void *pv)
+static const msi_table pc_tables[] =
 {
-    sprintf(pccab->szCab, pv, pccab->iCab);
-    return TRUE;
-}
+    ADD_TABLE(ca51_component),
+    ADD_TABLE(directory),
+    ADD_TABLE(rof_feature),
+    ADD_TABLE(ci2_feature_comp),
+    ADD_TABLE(ci2_file),
+    ADD_TABLE(install_exec_seq),
+    ADD_TABLE(rof_media),
+    ADD_TABLE(property)
+};
 
-static long progress(UINT typeStatus, ULONG cb1, ULONG cb2, void *pv)
+static const msi_table ip_tables[] =
 {
-    return 0;
-}
+    ADD_TABLE(component),
+    ADD_TABLE(directory),
+    ADD_TABLE(feature),
+    ADD_TABLE(feature_comp),
+    ADD_TABLE(file),
+    ADD_TABLE(ip_install_exec_seq),
+    ADD_TABLE(ip_custom_action),
+    ADD_TABLE(media),
+    ADD_TABLE(property)
+};
 
-static int file_placed(PCCAB pccab, char *pszFile, long cbFile,
-                       BOOL fContinuation, void *pv)
+static const msi_table aup_tables[] =
 {
-    return 0;
-}
+    ADD_TABLE(component),
+    ADD_TABLE(directory),
+    ADD_TABLE(feature),
+    ADD_TABLE(feature_comp),
+    ADD_TABLE(file),
+    ADD_TABLE(aup_install_exec_seq),
+    ADD_TABLE(aup_custom_action),
+    ADD_TABLE(media),
+    ADD_TABLE(property)
+};
 
-static INT_PTR fci_open(char *pszFile, int oflag, int pmode, int *err, void *pv)
+static const msi_table aup2_tables[] =
 {
-    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;
+    ADD_TABLE(component),
+    ADD_TABLE(directory),
+    ADD_TABLE(feature),
+    ADD_TABLE(feature_comp),
+    ADD_TABLE(file),
+    ADD_TABLE(aup2_install_exec_seq),
+    ADD_TABLE(aup_custom_action),
+    ADD_TABLE(media),
+    ADD_TABLE(aup_property)
+};
 
-    if (GetFileAttributesA(pszFile) != INVALID_FILE_ATTRIBUTES)
-        dwCreateDisposition = OPEN_EXISTING;
+static const msi_table aup3_tables[] =
+{
+    ADD_TABLE(component),
+    ADD_TABLE(directory),
+    ADD_TABLE(feature),
+    ADD_TABLE(feature_comp),
+    ADD_TABLE(file),
+    ADD_TABLE(aup2_install_exec_seq),
+    ADD_TABLE(aup_custom_action),
+    ADD_TABLE(media),
+    ADD_TABLE(aup2_property)
+};
+
+static const msi_table aup4_tables[] =
+{
+    ADD_TABLE(component),
+    ADD_TABLE(directory),
+    ADD_TABLE(feature),
+    ADD_TABLE(feature_comp),
+    ADD_TABLE(file),
+    ADD_TABLE(aup3_install_exec_seq),
+    ADD_TABLE(aup_custom_action),
+    ADD_TABLE(media),
+    ADD_TABLE(aup2_property)
+};
+
+static const msi_table fiu_tables[] =
+{
+    ADD_TABLE(rof_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 fiuc_tables[] =
+{
+    ADD_TABLE(rof_component),
+    ADD_TABLE(directory),
+    ADD_TABLE(rof_feature),
+    ADD_TABLE(rof_feature_comp),
+    ADD_TABLE(rofc_file),
+    ADD_TABLE(pp_install_exec_seq),
+    ADD_TABLE(rofc_media),
+    ADD_TABLE(property),
+};
+
+static const msi_table cf_tables[] =
+{
+    ADD_TABLE(component),
+    ADD_TABLE(directory),
+    ADD_TABLE(feature),
+    ADD_TABLE(feature_comp),
+    ADD_TABLE(file),
+    ADD_TABLE(cf_create_folders),
+    ADD_TABLE(cf_install_exec_seq),
+    ADD_TABLE(cf_custom_action),
+    ADD_TABLE(media),
+    ADD_TABLE(property)
+};
+
+static const msi_table rf_tables[] =
+{
+    ADD_TABLE(component),
+    ADD_TABLE(directory),
+    ADD_TABLE(feature),
+    ADD_TABLE(feature_comp),
+    ADD_TABLE(file),
+    ADD_TABLE(cf_create_folders),
+    ADD_TABLE(rf_install_exec_seq),
+    ADD_TABLE(cf_custom_action),
+    ADD_TABLE(media),
+    ADD_TABLE(property)
+};
+
+static const msi_table sss_tables[] =
+{
+    ADD_TABLE(component),
+    ADD_TABLE(directory),
+    ADD_TABLE(feature),
+    ADD_TABLE(feature_comp),
+    ADD_TABLE(file),
+    ADD_TABLE(sss_install_exec_seq),
+    ADD_TABLE(sss_service_control),
+    ADD_TABLE(media),
+    ADD_TABLE(property)
+};
+
+static const msi_table sds_tables[] =
+{
+    ADD_TABLE(component),
+    ADD_TABLE(directory),
+    ADD_TABLE(feature),
+    ADD_TABLE(feature_comp),
+    ADD_TABLE(file),
+    ADD_TABLE(sss_install_exec_seq),
+    ADD_TABLE(service_control),
+    ADD_TABLE(media),
+    ADD_TABLE(property)
+};
+
+static const msi_table sr_tables[] =
+{
+    ADD_TABLE(component),
+    ADD_TABLE(directory),
+    ADD_TABLE(feature),
+    ADD_TABLE(feature_comp),
+    ADD_TABLE(file),
+    ADD_TABLE(sr_selfreg),
+    ADD_TABLE(sr_install_exec_seq),
+    ADD_TABLE(media),
+    ADD_TABLE(property)
+};
+
+static const msi_table font_tables[] =
+{
+    ADD_TABLE(font_component),
+    ADD_TABLE(directory),
+    ADD_TABLE(font_feature),
+    ADD_TABLE(font_feature_comp),
+    ADD_TABLE(font_file),
+    ADD_TABLE(font),
+    ADD_TABLE(font_install_exec_seq),
+    ADD_TABLE(font_media),
+    ADD_TABLE(property)
+};
+
+static const msi_table vp_tables[] =
+{
+    ADD_TABLE(component),
+    ADD_TABLE(directory),
+    ADD_TABLE(feature),
+    ADD_TABLE(feature_comp),
+    ADD_TABLE(file),
+    ADD_TABLE(vp_custom_action),
+    ADD_TABLE(vp_install_exec_seq),
+    ADD_TABLE(media),
+    ADD_TABLE(vp_property)
+};
+
+static const msi_table odbc_tables[] =
+{
+    ADD_TABLE(odbc_component),
+    ADD_TABLE(directory),
+    ADD_TABLE(odbc_feature),
+    ADD_TABLE(odbc_feature_comp),
+    ADD_TABLE(odbc_file),
+    ADD_TABLE(odbc_driver),
+    ADD_TABLE(odbc_translator),
+    ADD_TABLE(odbc_datasource),
+    ADD_TABLE(odbc_install_exec_seq),
+    ADD_TABLE(odbc_media),
+    ADD_TABLE(property)
+};
+
+static const msi_table tl_tables[] =
+{
+    ADD_TABLE(tl_component),
+    ADD_TABLE(directory),
+    ADD_TABLE(tl_feature),
+    ADD_TABLE(tl_feature_comp),
+    ADD_TABLE(tl_file),
+    ADD_TABLE(tl_typelib),
+    ADD_TABLE(tl_install_exec_seq),
+    ADD_TABLE(media),
+    ADD_TABLE(property)
+};
+
+static const msi_table crs_tables[] =
+{
+    ADD_TABLE(crs_component),
+    ADD_TABLE(directory),
+    ADD_TABLE(crs_feature),
+    ADD_TABLE(crs_feature_comp),
+    ADD_TABLE(crs_file),
+    ADD_TABLE(crs_shortcut),
+    ADD_TABLE(crs_install_exec_seq),
+    ADD_TABLE(media),
+    ADD_TABLE(property)
+};
+
+static const msi_table pub_tables[] =
+{
+    ADD_TABLE(directory),
+    ADD_TABLE(pub_component),
+    ADD_TABLE(pub_feature),
+    ADD_TABLE(pub_feature_comp),
+    ADD_TABLE(pub_file),
+    ADD_TABLE(pub_publish_component),
+    ADD_TABLE(pub_install_exec_seq),
+    ADD_TABLE(media),
+    ADD_TABLE(property)
+};
+
+/* 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;
 
@@ -1100,7 +2361,7 @@ static INT_PTR fci_open(char *pszFile, int oflag, int pmode, int *err, void *pv)
     return (INT_PTR)handle;
 }
 
-static UINT fci_read(INT_PTR hf, void *memory, UINT cb, int *err, void *pv)
+static UINT CDECL fci_read(INT_PTR hf, void *memory, UINT cb, int *err, void *pv)
 {
     HANDLE handle = (HANDLE)hf;
     DWORD dwRead;
@@ -1112,7 +2373,7 @@ static UINT fci_read(INT_PTR hf, void *memory, UINT cb, int *err, void *pv)
     return dwRead;
 }
 
-static UINT fci_write(INT_PTR hf, void *memory, UINT cb, int *err, void *pv)
+static UINT CDECL fci_write(INT_PTR hf, void *memory, UINT cb, int *err, void *pv)
 {
     HANDLE handle = (HANDLE)hf;
     DWORD dwWritten;
@@ -1124,7 +2385,7 @@ static UINT fci_write(INT_PTR hf, void *memory, UINT cb, int *err, void *pv)
     return dwWritten;
 }
 
-static int fci_close(INT_PTR hf, int *err, void *pv)
+static int CDECL fci_close(INT_PTR hf, int *err, void *pv)
 {
     HANDLE handle = (HANDLE)hf;
     ok(CloseHandle(handle), "Failed to CloseHandle\n");
@@ -1132,7 +2393,7 @@ static int fci_close(INT_PTR hf, int *err, void *pv)
     return 0;
 }
 
-static long fci_seek(INT_PTR hf, long dist, int seektype, int *err, void *pv)
+static LONG CDECL fci_seek(INT_PTR hf, LONG dist, int seektype, int *err, void *pv)
 {
     HANDLE handle = (HANDLE)hf;
     DWORD ret;
@@ -1143,7 +2404,7 @@ static long fci_seek(INT_PTR hf, long dist, int seektype, int *err, void *pv)
     return ret;
 }
 
-static int fci_delete(char *pszFile, int *err, void *pv)
+static int CDECL fci_delete(char *pszFile, int *err, void *pv)
 {
     BOOL ret = DeleteFileA(pszFile);
     ok(ret, "Failed to DeleteFile %s\n", pszFile);
@@ -1154,38 +2415,62 @@ static int fci_delete(char *pszFile, int *err, void *pv)
 static void init_functionpointers(void)
 {
     HMODULE hmsi = GetModuleHandleA("msi.dll");
+    HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll");
 
-#define GET_PROC(func) \
-    p ## func = (void*)GetProcAddress(hmsi, #func); \
+#define GET_PROC(mod, func) \
+    p ## func = (void*)GetProcAddress(mod, #func); \
     if(!p ## func) \
       trace("GetProcAddress(%s) failed\n", #func);
 
-    GET_PROC(MsiQueryComponentStateA);
-    GET_PROC(MsiSourceListEnumSourcesA);
-    GET_PROC(MsiSourceListGetInfoA);
+    GET_PROC(hmsi, MsiQueryComponentStateA);
+    GET_PROC(hmsi, MsiSetExternalUIRecord);
+    GET_PROC(hmsi, MsiSourceListEnumSourcesA);
+    GET_PROC(hmsi, MsiSourceListGetInfoA);
+
+    GET_PROC(hadvapi32, ConvertSidToStringSidA);
+
+    hsrclient = LoadLibraryA("srclient.dll");
+    GET_PROC(hsrclient, SRRemoveRestorePoint);
+    GET_PROC(hsrclient, SRSetRestorePointA);
 
 #undef GET_PROC
 }
 
-static void get_user_sid(LPSTR *usersid)
+static BOOL check_win9x(void)
+{
+    SC_HANDLE scm;
+
+    scm = OpenSCManager(NULL, NULL, GENERIC_ALL);
+    if (!scm && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED))
+        return TRUE;
+
+    CloseServiceHandle(scm);
+
+    return FALSE;
+}
+
+static LPSTR get_user_sid(LPSTR *usersid)
 {
     HANDLE token;
     BYTE buf[1024];
     DWORD size;
     PTOKEN_USER user;
-    HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll");
-    static BOOL (WINAPI *pConvertSidToStringSidA)(PSID, LPSTR*);
 
-    *usersid = NULL;
-    pConvertSidToStringSidA = (void *)GetProcAddress(hadvapi32, "ConvertSidToStringSidA");
     if (!pConvertSidToStringSidA)
-        return;
+    {
+        win_skip("ConvertSidToStringSidA is not available\n");
+        return NULL;
+    }
 
+    *usersid = NULL;
     OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token);
     size = sizeof(buf);
-    GetTokenInformation(token, TokenUser, (void *)buf, size, &size);
+    GetTokenInformation(token, TokenUser, buf, size, &size);
     user = (PTOKEN_USER)buf;
     pConvertSidToStringSidA(user->User.Sid, usersid);
+    ok(*usersid != NULL, "pConvertSidToStringSidA failed lre=%d\n", GetLastError());
+    CloseHandle(token);
+    return *usersid;
 }
 
 static BOOL check_record(MSIHANDLE rec, UINT field, LPCSTR val)
@@ -1199,7 +2484,7 @@ static BOOL check_record(MSIHANDLE rec, UINT field, LPCSTR val)
     return (r == ERROR_SUCCESS ) && !strcmp(val, buffer);
 }
 
-static BOOL get_temp_file(char *pszTempName, int cbTempName, void *pv)
+static BOOL CDECL get_temp_file(char *pszTempName, int cbTempName, void *pv)
 {
     LPSTR tempname;
 
@@ -1218,8 +2503,8 @@ static BOOL get_temp_file(char *pszTempName, int cbTempName, void *pv)
     return FALSE;
 }
 
-static INT_PTR get_open_info(char *pszName, USHORT *pdate, USHORT *ptime,
-                             USHORT *pattribs, int *err, void *pv)
+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;
@@ -1334,7 +2619,9 @@ static void create_file_data(LPCSTR name, LPCSTR data, DWORD size)
     DWORD written;
 
     file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
-    ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
+    if (file == INVALID_HANDLE_VALUE)
+        return;
+
     WriteFile(file, data, strlen(data), &written, NULL);
 
     if (size)
@@ -1421,7 +2708,7 @@ static void write_file(const CHAR *filename, const char *data, int data_size)
     CloseHandle(hf);
 }
 
-static void write_msi_summary_info(MSIHANDLE db)
+static void write_msi_summary_info(MSIHANDLE db, INT wordcount)
 {
     MSIHANDLE summary;
     UINT r;
@@ -1439,7 +2726,7 @@ static void write_msi_summary_info(MSIHANDLE db)
     r = MsiSummaryInfoSetPropertyA(summary, PID_PAGECOUNT, VT_I4, 100, NULL, NULL);
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
 
-    r = MsiSummaryInfoSetPropertyA(summary, PID_WORDCOUNT, VT_I4, 0, NULL, NULL);
+    r = MsiSummaryInfoSetPropertyA(summary, PID_WORDCOUNT, VT_I4, wordcount, NULL, NULL);
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
 
     r = MsiSummaryInfoSetPropertyA(summary, PID_TITLE, VT_LPSTR, 0, NULL, "MSITEST");
@@ -1452,7 +2739,11 @@ static void write_msi_summary_info(MSIHANDLE db)
     MsiCloseHandle(summary);
 }
 
-static void create_database(const CHAR *name, const msi_table *tables, int num_tables)
+#define create_database(name, tables, num_tables) \
+    create_database_wordcount(name, tables, num_tables, 0);
+
+static void create_database_wordcount(const CHAR *name, const msi_table *tables,
+                                      int num_tables, INT wordcount)
 {
     MSIHANDLE db;
     UINT r;
@@ -1474,7 +2765,7 @@ static void create_database(const CHAR *name, const msi_table *tables, int num_t
         DeleteFileA(table->filename);
     }
 
-    write_msi_summary_info(db);
+    write_msi_summary_info(db, wordcount);
 
     r = MsiDatabaseCommit(db);
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
@@ -1500,6 +2791,27 @@ static void check_service_is_installed(void)
     CloseServiceHandle(scm);
 }
 
+static BOOL notify_system_change(DWORD event_type, STATEMGRSTATUS *status)
+{
+    RESTOREPOINTINFOA spec;
+
+    spec.dwEventType = event_type;
+    spec.dwRestorePtType = APPLICATION_INSTALL;
+    spec.llSequenceNumber = status->llSequenceNumber;
+    lstrcpyA(spec.szDescription, "msitest restore point");
+
+    return pSRSetRestorePointA(&spec, status);
+}
+
+static void remove_restore_point(DWORD seq_number)
+{
+    DWORD res;
+
+    res = pSRRemoveRestorePoint(seq_number);
+    if (res != ERROR_SUCCESS)
+        trace("Failed to remove the restore point : %08x\n", res);
+}
+
 static void test_MsiInstallProduct(void)
 {
     UINT r;
@@ -1507,19 +2819,32 @@ static void test_MsiInstallProduct(void)
     LONG res;
     HKEY hkey;
     DWORD num, size, type;
-    SC_HANDLE scm;
 
-    scm = OpenSCManager(NULL, NULL, GENERIC_ALL);
-    if (!scm && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED))
+    if (on_win9x)
     {
-        skip("Services are not implemented, we are most likely on win9x\n");
+        win_skip("Services are not implemented on Win9x and WinMe\n");
         return;
     }
-    CloseServiceHandle(scm);
+
+    /* szPackagePath is NULL */
+    r = MsiInstallProductA(NULL, "INSTALL=ALL");
+    ok(r == ERROR_INVALID_PARAMETER,
+       "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
+
+    /* both szPackagePath and szCommandLine are NULL */
+    r = MsiInstallProductA(NULL, NULL);
+    ok(r == ERROR_INVALID_PARAMETER,
+       "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
+
+    /* szPackagePath is empty */
+    r = MsiInstallProductA("", "INSTALL=ALL");
+    ok(r == ERROR_PATH_NOT_FOUND,
+       "Expected ERROR_PATH_NOT_FOUND, got %d\n", r);
 
     create_test_files();
     create_database(msifile, tables, sizeof(tables) / sizeof(msi_table));
 
+    /* install, don't publish */
     r = MsiInstallProductA(msifile, NULL);
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
 
@@ -1560,48 +2885,251 @@ static void test_MsiInstallProduct(void)
     type = REG_SZ;
     res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
-    ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
+    ok(!lstrcmpA(path, "OrderTestValue"), "Expected OrderTestValue, got %s\n", path);
 
     check_service_is_installed();
 
     RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest");
 
-    delete_test_files();
-}
-
-static void test_MsiSetComponentState(void)
-{
-    INSTALLSTATE installed, action;
-    MSIHANDLE package;
-    char path[MAX_PATH];
-    UINT r;
+    /* not published, reinstall */
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
 
-    create_database(msifile, tables, sizeof(tables) / sizeof(msi_table));
+    ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
+    ok(delete_pf("msitest", FALSE), "File not installed\n");
 
-    CoInitialize(NULL);
+    res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+    RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest");
 
-    lstrcpy(path, CURR_DIR);
-    lstrcat(path, "\\");
-    lstrcat(path, msifile);
+    create_database(msifile, up_tables, sizeof(up_tables) / sizeof(msi_table));
 
-    r = MsiOpenPackage(path, &package);
+    /* not published, RemovePreviousVersions set */
+    r = MsiInstallProductA(msifile, NULL);
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
 
-    r = MsiDoAction(package, "CostInitialize");
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+    ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
+    ok(delete_pf("msitest", FALSE), "File not installed\n");
 
-    r = MsiDoAction(package, "FileCost");
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+    res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+    RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest");
 
-    r = MsiDoAction(package, "CostFinalize");
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+    create_database(msifile, up2_tables, sizeof(up2_tables) / sizeof(msi_table));
 
-    r = MsiGetComponentState(package, "dangler", &installed, &action);
+    /* not published, version number bumped */
+    r = MsiInstallProductA(msifile, NULL);
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-    ok(installed == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", installed);
-    ok(action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action);
 
-    r = MsiSetComponentState(package, "dangler", INSTALLSTATE_SOURCE);
+    ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
+    ok(delete_pf("msitest", FALSE), "File not installed\n");
+
+    res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+    RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest");
+
+    create_database(msifile, up3_tables, sizeof(up3_tables) / sizeof(msi_table));
+
+    /* not published, RemovePreviousVersions set and version number bumped */
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
+    ok(delete_pf("msitest", FALSE), "File not installed\n");
+
+    res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+    RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest");
+
+    create_database(msifile, up4_tables, sizeof(up4_tables) / sizeof(msi_table));
+
+    /* install, publish product */
+    r = MsiInstallProductA(msifile, "PUBLISH_PRODUCT=1");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
+    ok(delete_pf("msitest", FALSE), "File not installed\n");
+
+    res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
+    ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
+
+    create_database(msifile, up4_tables, sizeof(up4_tables) / sizeof(msi_table));
+
+    /* published, reinstall */
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
+    ok(delete_pf("msitest", FALSE), "File not installed\n");
+
+    res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
+    ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
+
+    create_database(msifile, up5_tables, sizeof(up5_tables) / sizeof(msi_table));
+
+    /* published product, RemovePreviousVersions set */
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
+    ok(delete_pf("msitest", FALSE), "File not installed\n");
+
+    res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
+    ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
+
+    create_database(msifile, up6_tables, sizeof(up6_tables) / sizeof(msi_table));
+
+    /* published product, version number bumped */
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
+    ok(delete_pf("msitest", FALSE), "File not installed\n");
+
+    res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
+    ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
+
+    create_database(msifile, up7_tables, sizeof(up7_tables) / sizeof(msi_table));
+
+    /* published product, RemovePreviousVersions set and version number bumped */
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
+    ok(delete_pf("msitest", FALSE), "File not installed\n");
+
+    res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
+    ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
+
+    r = MsiInstallProductA(msifile, "REMOVE=ALL");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    delete_test_files();
+}
+
+static void test_MsiSetComponentState(void)
+{
+    INSTALLSTATE installed, action;
+    MSIHANDLE package;
+    char path[MAX_PATH];
+    UINT r;
+
+    create_database(msifile, tables, sizeof(tables) / sizeof(msi_table));
+
+    CoInitialize(NULL);
+
+    lstrcpy(path, CURR_DIR);
+    lstrcat(path, "\\");
+    lstrcat(path, msifile);
+
+    r = MsiOpenPackage(path, &package);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    r = MsiDoAction(package, "CostInitialize");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    r = MsiDoAction(package, "FileCost");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    r = MsiDoAction(package, "CostFinalize");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    r = MsiGetComponentState(package, "dangler", &installed, &action);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+    ok(installed == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", installed);
+    ok(action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action);
+
+    r = MsiSetComponentState(package, "dangler", INSTALLSTATE_SOURCE);
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
 
     MsiCloseHandle(package);
@@ -1658,6 +3186,8 @@ static void test_packagecoltypes(void)
     MsiCloseHandle(rec);
     MsiCloseHandle(view);
     MsiCloseHandle(hdb);
+    CoUninitialize();
+
     DeleteFile(msifile);
 }
 
@@ -1958,7 +3488,7 @@ static void test_readonlyfile(void)
     file = CreateFile(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
                       NULL, CREATE_NEW, FILE_ATTRIBUTE_READONLY, NULL);
 
-    WriteFile(file, "readonlyfile", 20, &size, NULL);
+    WriteFile(file, "readonlyfile", strlen("readonlyfile"), &size, NULL);
     CloseHandle(file);
 
     r = MsiInstallProductA(msifile, NULL);
@@ -1973,70 +3503,283 @@ static void test_readonlyfile(void)
     DeleteFile(msifile);
 }
 
-static void test_setdirproperty(void)
+static void test_readonlyfile_cab(void)
 {
     UINT r;
+    DWORD size;
+    HANDLE file;
+    CHAR path[MAX_PATH];
+    CHAR buf[16];
 
     CreateDirectoryA("msitest", NULL);
-    create_file("msitest\\maximus", 500);
-    create_database(msifile, sdp_tables, sizeof(sdp_tables) / sizeof(msi_table));
+    create_file("maximus", 500);
+    create_cab_file("test1.cab", MEDIA_SIZE, "maximus\0");
+    DeleteFile("maximus");
+
+    create_database(msifile, rofc_tables, sizeof(rofc_tables) / sizeof(msi_table));
 
     MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
 
+    lstrcpy(path, PROG_FILES_DIR);
+    lstrcat(path, "\\msitest");
+    CreateDirectory(path, NULL);
+
+    lstrcat(path, "\\maximus");
+    file = CreateFile(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+                      NULL, CREATE_NEW, FILE_ATTRIBUTE_READONLY, NULL);
+
+    WriteFile(file, "readonlyfile", strlen("readonlyfile"), &size, NULL);
+    CloseHandle(file);
+
     r = MsiInstallProductA(msifile, NULL);
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-    ok(delete_cf("msitest\\maximus", TRUE), "File not installed\n");
-    ok(delete_cf("msitest", FALSE), "File not installed\n");
+
+    memset( buf, 0, sizeof(buf) );
+    if ((file = CreateFile(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+                           NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE)
+    {
+        ReadFile(file, buf, sizeof(buf) - 1, &size, NULL);
+        CloseHandle(file);
+    }
+    ok(!memcmp( buf, "maximus", sizeof("maximus")-1 ), "Expected file to be overwritten, got '%s'\n", buf);
+    ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n");
+    ok(delete_pf("msitest", FALSE), "File not installed\n");
 
     /* Delete the files in the temp (current) folder */
-    DeleteFile(msifile);
+    delete_cab_files();
     DeleteFile("msitest\\maximus");
     RemoveDirectory("msitest");
+    DeleteFile(msifile);
 }
 
-static void test_cabisextracted(void)
+static BOOL add_cabinet_storage(LPCSTR db, LPCSTR cabinet)
 {
-    UINT r;
-
-    CreateDirectoryA("msitest", NULL);
-    create_file("msitest\\gaius", 500);
-    create_file("maximus", 500);
-    create_file("augustus", 500);
-    create_file("caesar", 500);
+    WCHAR dbW[MAX_PATH], cabinetW[MAX_PATH];
+    IStorage *stg;
+    IStream *stm;
+    HRESULT hr;
+    HANDLE handle;
 
-    create_cab_file("test1.cab", MEDIA_SIZE, "maximus\0");
-    create_cab_file("test2.cab", MEDIA_SIZE, "augustus\0");
-    create_cab_file("test3.cab", MEDIA_SIZE, "caesar\0");
+    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;
 
-    create_database(msifile, cie_tables, sizeof(cie_tables) / sizeof(msi_table));
+    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;
+    }
 
-    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+    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);
+    }
 
-    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 not installed\n");
-    ok(delete_pf("msitest\\caesar", TRUE), "File not installed\n");
-    ok(delete_pf("msitest\\gaius", TRUE), "File not installed\n");
-    ok(delete_pf("msitest", FALSE), "File not installed\n");
+    IStream_Release(stm);
+    IStorage_Release(stg);
 
-    /* Delete the files in the temp (current) folder */
-    delete_cab_files();
-    DeleteFile(msifile);
-    DeleteFile("maximus");
-    DeleteFile("augustus");
-    DeleteFile("caesar");
-    DeleteFile("msitest\\gaius");
-    RemoveDirectory("msitest");
+    return TRUE;
 }
 
-static void test_concurrentinstall(void)
+static void test_lastusedsource(void)
 {
+    static char prodcode[] = "{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}";
+
     UINT r;
-    CHAR path[MAX_PATH];
+    char value[MAX_PATH], path[MAX_PATH];
+    DWORD size;
 
-    CreateDirectoryA("msitest", NULL);
-    CreateDirectoryA("msitest\\msitest", NULL);
+    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");
+    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);
+    todo_wine
+    {
+    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);
+    todo_wine
+    {
+    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);
+    todo_wine
+    {
+    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);
+
+    /* 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;
+
+    CreateDirectoryA("msitest", NULL);
+    create_file("msitest\\maximus", 500);
+    create_database(msifile, sdp_tables, sizeof(sdp_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+    ok(delete_cf("msitest\\maximus", TRUE), "File not installed\n");
+    ok(delete_cf("msitest", FALSE), "File not installed\n");
+
+    /* Delete the files in the temp (current) folder */
+    DeleteFile(msifile);
+    DeleteFile("msitest\\maximus");
+    RemoveDirectory("msitest");
+}
+
+static void test_cabisextracted(void)
+{
+    UINT r;
+
+    CreateDirectoryA("msitest", NULL);
+    create_file("msitest\\gaius", 500);
+    create_file("maximus", 500);
+    create_file("augustus", 500);
+    create_file("caesar", 500);
+
+    create_cab_file("test1.cab", MEDIA_SIZE, "maximus\0");
+    create_cab_file("test2.cab", MEDIA_SIZE, "augustus\0");
+    create_cab_file("test3.cab", MEDIA_SIZE, "caesar\0");
+
+    create_database(msifile, cie_tables, sizeof(cie_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    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 not installed\n");
+    ok(delete_pf("msitest\\caesar", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\gaius", TRUE), "File not installed\n");
+    ok(delete_pf("msitest", FALSE), "File not installed\n");
+
+    /* Delete the files in the temp (current) folder */
+    delete_cab_files();
+    DeleteFile(msifile);
+    DeleteFile("maximus");
+    DeleteFile("augustus");
+    DeleteFile("caesar");
+    DeleteFile("msitest\\gaius");
+    RemoveDirectory("msitest");
+}
+
+static void test_concurrentinstall(void)
+{
+    UINT r;
+    CHAR path[MAX_PATH];
+
+    CreateDirectoryA("msitest", NULL);
+    CreateDirectoryA("msitest\\msitest", NULL);
     create_file("msitest\\maximus", 500);
     create_file("msitest\\msitest\\augustus", 500);
 
@@ -2074,6 +3817,7 @@ static void test_setpropertyfolder(void)
 {
     UINT r;
     CHAR path[MAX_PATH];
+    DWORD attr;
 
     lstrcpyA(path, PROG_FILES_DIR);
     lstrcatA(path, "\\msitest\\added");
@@ -2087,7 +3831,8 @@ static void test_setpropertyfolder(void)
 
     r = MsiInstallProductA(msifile, NULL);
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-    if (GetFileAttributesA(path) == FILE_ATTRIBUTE_DIRECTORY)
+    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), "File not installed\n");
@@ -2189,6 +3934,41 @@ static void check_reg_dword(HKEY prodkey, LPCSTR name, DWORD expected, DWORD lin
     ok_(__FILE__, line)(val == expected, "Expected %d, got %d\n", expected, val);
 }
 
+static void check_reg_dword2(HKEY prodkey, LPCSTR name, DWORD expected1, DWORD expected2, DWORD line)
+{
+    DWORD val, size, type;
+    LONG res;
+
+    size = sizeof(DWORD);
+    res = RegQueryValueExA(prodkey, name, NULL, &type, (LPBYTE)&val, &size);
+
+    if (res != ERROR_SUCCESS || type != REG_DWORD)
+    {
+        ok_(__FILE__, line)(FALSE, "Key doesn't exist or wrong type\n");
+        return;
+    }
+
+    ok_(__FILE__, line)(val == expected1 || val == expected2, "Expected %d or %d, got %d\n", expected1, expected2, val);
+}
+
+static void check_reg_dword3(HKEY prodkey, LPCSTR name, DWORD expected1, DWORD expected2, DWORD expected3, DWORD line)
+{
+    DWORD val, size, type;
+    LONG res;
+
+    size = sizeof(DWORD);
+    res = RegQueryValueExA(prodkey, name, NULL, &type, (LPBYTE)&val, &size);
+
+    if (res != ERROR_SUCCESS || type != REG_DWORD)
+    {
+        ok_(__FILE__, line)(FALSE, "Key doesn't exist or wrong type\n");
+        return;
+    }
+
+    ok_(__FILE__, line)(val == expected1 || val == expected2 || val == expected3,
+                        "Expected %d, %d or %d, got %d\n", expected1, expected2, expected3, val);
+}
+
 #define CHECK_REG_STR(prodkey, name, expected) \
     check_reg_str(prodkey, name, expected, TRUE, __LINE__);
 
@@ -2210,6 +3990,20 @@ static void check_reg_dword(HKEY prodkey, LPCSTR name, DWORD expected, DWORD lin
     check_reg_dword(prodkey, name, expected, __LINE__); \
     RegDeleteValueA(prodkey, name);
 
+#define CHECK_REG_DWORD2(prodkey, name, expected1, expected2) \
+    check_reg_dword2(prodkey, name, expected1, expected2, __LINE__);
+
+#define CHECK_DEL_REG_DWORD2(prodkey, name, expected1, expected2) \
+    check_reg_dword2(prodkey, name, expected1, expected2, __LINE__); \
+    RegDeleteValueA(prodkey, name);
+
+#define CHECK_REG_DWORD3(prodkey, name, expected1, expected2, expected3) \
+    check_reg_dword3(prodkey, name, expected1, expected2, expected3, __LINE__);
+
+#define CHECK_DEL_REG_DWORD3(prodkey, name, expected1, expected2, expected3) \
+    check_reg_dword3(prodkey, name, expected1, expected2, expected3, __LINE__); \
+    RegDeleteValueA(prodkey, name);
+
 static void get_date_str(LPSTR date)
 {
     SYSTEMTIME systime;
@@ -2239,12 +4033,8 @@ static void test_publish_registerproduct(void)
     static const CHAR userugkey[] = "Software\\Microsoft\\Installer\\UpgradeCodes"
                                     "\\51AAE0C44620A5E4788506E91F249BD2";
 
-    get_user_sid(&usersid);
-    if (!usersid)
-    {
-        skip("ConvertSidToStringSidA is not available\n");
+    if (!get_user_sid(&usersid))
         return;
-    }
 
     get_date_str(date);
     GetTempPath(MAX_PATH, temp);
@@ -2292,7 +4082,7 @@ static void test_publish_registerproduct(void)
     CHECK_DEL_REG_DWORD(hkey, "WindowsInstaller", 1);
     todo_wine
     {
-        CHECK_DEL_REG_DWORD(hkey, "EstimatedSize", 12);
+        CHECK_DEL_REG_DWORD3(hkey, "EstimatedSize", 12, -12, 4);
     }
 
     RegDeleteKeyA(hkey, "");
@@ -2330,7 +4120,7 @@ static void test_publish_registerproduct(void)
     CHECK_DEL_REG_DWORD(props, "WindowsInstaller", 1);
     todo_wine
     {
-        CHECK_DEL_REG_DWORD(props, "EstimatedSize", 12);
+        CHECK_DEL_REG_DWORD3(props, "EstimatedSize", 12, -12, 4);
     }
 
     RegDeleteKeyA(props, "");
@@ -2391,7 +4181,7 @@ static void test_publish_registerproduct(void)
     CHECK_DEL_REG_DWORD(hkey, "WindowsInstaller", 1);
     todo_wine
     {
-        CHECK_DEL_REG_DWORD(hkey, "EstimatedSize", 12);
+        CHECK_DEL_REG_DWORD3(hkey, "EstimatedSize", 12, -12, 4);
     }
 
     RegDeleteKeyA(hkey, "");
@@ -2429,7 +4219,7 @@ static void test_publish_registerproduct(void)
     CHECK_DEL_REG_DWORD(props, "WindowsInstaller", 1);
     todo_wine
     {
-        CHECK_DEL_REG_DWORD(props, "EstimatedSize", 12);
+        CHECK_DEL_REG_DWORD3(props, "EstimatedSize", 12, -12, 4);
     }
 
     RegDeleteKeyA(props, "");
@@ -2484,12 +4274,8 @@ static void test_publish_publishproduct(void)
     static const CHAR machprod[] = "Installer\\Products\\84A88FD7F6998CE40A22FB59F6B9C2BB";
     static const CHAR machup[] = "Installer\\UpgradeCodes\\51AAE0C44620A5E4788506E91F249BD2";
 
-    get_user_sid(&usersid);
-    if (!usersid)
-    {
-        skip("ConvertSidToStringSidA is not available\n");
+    if (!get_user_sid(&usersid))
         return;
-    }
 
     GetTempPath(MAX_PATH, temp);
 
@@ -2680,12 +4466,8 @@ static void test_publish_publishfeatures(void)
     static const CHAR classfeat[] = "Software\\Classes\\Installer\\Features"
                                     "\\84A88FD7F6998CE40A22FB59F6B9C2BB";
 
-    get_user_sid(&usersid);
-    if (!usersid)
-    {
-        skip("ConvertSidToStringSidA is not available\n");
+    if (!get_user_sid(&usersid))
         return;
-    }
 
     CreateDirectoryA("msitest", NULL);
     create_file("msitest\\maximus", 500);
@@ -2842,12 +4624,8 @@ static void test_publish_registeruser(void)
         "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\"
         "UserData\\%s\\Products\\84A88FD7F6998CE40A22FB59F6B9C2BB\\InstallProperties";
 
-    get_user_sid(&usersid);
-    if (!usersid)
-    {
-        skip("ConvertSidToStringSidA is not available\n");
+    if (!get_user_sid(&usersid))
         return;
-    }
 
     get_owner_company(&owner, &company);
 
@@ -2906,6 +4684,7 @@ static void test_publish_registeruser(void)
     DeleteFile(msifile);
     DeleteFile("msitest\\maximus");
     RemoveDirectory("msitest");
+    LocalFree(usersid);
 }
 
 static void test_publish_processcomponents(void)
@@ -2917,24 +4696,21 @@ static void test_publish_processcomponents(void)
     LPSTR usersid;
     CHAR val[MAX_PATH];
     CHAR keypath[MAX_PATH];
+    CHAR program_files_maximus[MAX_PATH];
 
     static const CHAR keyfmt[] =
         "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\"
-        "UserData\\%s\\Components\\CBABC2FDCCB35E749A8944D8C1C098B5";
+        "UserData\\%s\\Components\\%s";
     static const CHAR compkey[] =
         "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Components";
 
-    get_user_sid(&usersid);
-    if (!usersid)
-    {
-        skip("ConvertSidToStringSidA is not available\n");
+    if (!get_user_sid(&usersid))
         return;
-    }
 
     CreateDirectoryA("msitest", NULL);
     create_file("msitest\\maximus", 500);
 
-    create_database(msifile, pp_tables, sizeof(pp_tables) / sizeof(msi_table));
+    create_database(msifile, ppc_tables, sizeof(ppc_tables) / sizeof(msi_table));
 
     MsiSetInternalUI(INSTALLUILEVEL_FULL, NULL);
 
@@ -2944,7 +4720,30 @@ static void test_publish_processcomponents(void)
     ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n");
     ok(delete_pf("msitest", FALSE), "File not installed\n");
 
-    sprintf(keypath, keyfmt, usersid);
+    sprintf(keypath, keyfmt, usersid, "CBABC2FDCCB35E749A8944D8C1C098B5");
+
+    res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &comp);
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+
+    size = MAX_PATH;
+    res = RegQueryValueExA(comp, "84A88FD7F6998CE40A22FB59F6B9C2BB",
+                           NULL, NULL, (LPBYTE)val, &size);
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+
+    lstrcpyA(program_files_maximus,PROG_FILES_DIR);
+    lstrcatA(program_files_maximus,"\\msitest\\maximus");
+
+    ok(!lstrcmpiA(val, program_files_maximus),
+       "Expected \"%s\", got \"%s\"\n", program_files_maximus, val);
+
+    res = RegOpenKeyA(HKEY_LOCAL_MACHINE, compkey, &hkey);
+    ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
+
+    RegDeleteValueA(comp, "84A88FD7F6998CE40A22FB59F6B9C2BB");
+    RegDeleteKeyA(comp, "");
+    RegCloseKey(comp);
+
+    sprintf(keypath, keyfmt, usersid, "241C3DA58FECD0945B9687D408766058");
 
     res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &comp);
     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
@@ -2953,8 +4752,8 @@ static void test_publish_processcomponents(void)
     res = RegQueryValueExA(comp, "84A88FD7F6998CE40A22FB59F6B9C2BB",
                            NULL, NULL, (LPBYTE)val, &size);
     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
-    ok(!lstrcmpA(val, "C:\\Program Files\\msitest\\maximus"),
-       "Expected \"%s\", got \"%s\"\n", "C:\\Program Files\\msitest\\maximus", val);
+    ok(!lstrcmpA(val, "01\\msitest\\augustus"),
+       "Expected \"01\\msitest\\augustus\", got \"%s\"\n", val);
 
     res = RegOpenKeyA(HKEY_LOCAL_MACHINE, compkey, &hkey);
     ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
@@ -2969,7 +4768,7 @@ static void test_publish_processcomponents(void)
     ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n");
     ok(delete_pf("msitest", FALSE), "File not installed\n");
 
-    sprintf(keypath, keyfmt, "S-1-5-18");
+    sprintf(keypath, keyfmt, "S-1-5-18", "CBABC2FDCCB35E749A8944D8C1C098B5");
 
     res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &comp);
     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
@@ -2978,8 +4777,27 @@ static void test_publish_processcomponents(void)
     res = RegQueryValueExA(comp, "84A88FD7F6998CE40A22FB59F6B9C2BB",
                            NULL, NULL, (LPBYTE)val, &size);
     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
-    ok(!lstrcmpA(val, "C:\\Program Files\\msitest\\maximus"),
-       "Expected \"%s\", got \"%s\"\n", "C:\\Program Files\\msitest\\maximus", val);
+    ok(!lstrcmpiA(val, program_files_maximus),
+       "Expected \"%s\", got \"%s\"\n", program_files_maximus, val);
+
+    res = RegOpenKeyA(HKEY_LOCAL_MACHINE, compkey, &hkey);
+    ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
+
+    RegDeleteValueA(comp, "84A88FD7F6998CE40A22FB59F6B9C2BB");
+    RegDeleteKeyA(comp, "");
+    RegCloseKey(comp);
+
+    sprintf(keypath, keyfmt, "S-1-5-18", "241C3DA58FECD0945B9687D408766058");
+
+    res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &comp);
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+
+    size = MAX_PATH;
+    res = RegQueryValueExA(comp, "84A88FD7F6998CE40A22FB59F6B9C2BB",
+                           NULL, NULL, (LPBYTE)val, &size);
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+    ok(!lstrcmpA(val, "01\\msitest\\augustus"),
+       "Expected \"01\\msitest\\augustus\", got \"%s\"\n", val);
 
     res = RegOpenKeyA(HKEY_LOCAL_MACHINE, compkey, &hkey);
     ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
@@ -2991,6 +4809,7 @@ static void test_publish_processcomponents(void)
     DeleteFile(msifile);
     DeleteFile("msitest\\maximus");
     RemoveDirectory("msitest");
+    LocalFree(usersid);
 }
 
 static void test_publish(void)
@@ -3007,7 +4826,7 @@ static void test_publish(void)
 
     if (!pMsiQueryComponentStateA)
     {
-        skip("MsiQueryComponentStateA is not available\n");
+        win_skip("MsiQueryComponentStateA is not available\n");
         return;
     }
 
@@ -3111,7 +4930,7 @@ static void test_publish(void)
     CHECK_REG_DWORD(prodkey, "WindowsInstaller", 1);
     todo_wine
     {
-        CHECK_REG_DWORD(prodkey, "EstimatedSize", 12);
+        CHECK_REG_DWORD2(prodkey, "EstimatedSize", 12, -12);
     }
 
     RegCloseKey(prodkey);
@@ -3185,7 +5004,7 @@ static void test_publish(void)
     CHECK_REG_DWORD(prodkey, "WindowsInstaller", 1);
     todo_wine
     {
-        CHECK_REG_DWORD(prodkey, "EstimatedSize", 12);
+        CHECK_REG_DWORD2(prodkey, "EstimatedSize", 12, -12);
     }
 
     RegCloseKey(prodkey);
@@ -3193,9 +5012,9 @@ static void test_publish(void)
     /* no UnpublishFeatures */
     r = MsiInstallProductA(msifile, "REMOVE=ALL");
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+    ok(!pf_exists("msitest\\maximus"), "File deleted\n");
     todo_wine
     {
-        ok(!pf_exists("msitest\\maximus"), "File deleted\n");
         ok(!pf_exists("msitest"), "File deleted\n");
     }
 
@@ -3263,7 +5082,7 @@ static void test_publish(void)
     CHECK_REG_DWORD(prodkey, "WindowsInstaller", 1);
     todo_wine
     {
-        CHECK_REG_DWORD(prodkey, "EstimatedSize", 12);
+        CHECK_REG_DWORD2(prodkey, "EstimatedSize", 12, -12);
     }
 
     RegCloseKey(prodkey);
@@ -3271,7 +5090,7 @@ static void test_publish(void)
     /* UnpublishFeatures, only feature removed.  Only works when entire product is removed */
     r = MsiInstallProductA(msifile, "UNPUBLISH_FEATURES=1 REMOVE=feature");
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
-    ok(pf_exists("msitest\\maximus"), "File deleted\n");
+    todo_wine ok(pf_exists("msitest\\maximus"), "File deleted\n");
     ok(pf_exists("msitest"), "File deleted\n");
 
     state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}");
@@ -3315,7 +5134,7 @@ static void test_publish(void)
     CHECK_REG_DWORD(prodkey, "WindowsInstaller", 1);
     todo_wine
     {
-        CHECK_REG_DWORD(prodkey, "EstimatedSize", 12);
+        CHECK_REG_DWORD2(prodkey, "EstimatedSize", 12, -12);
     }
 
     RegCloseKey(prodkey);
@@ -3367,7 +5186,7 @@ static void test_publish(void)
     CHECK_REG_DWORD(prodkey, "WindowsInstaller", 1);
     todo_wine
     {
-        CHECK_REG_DWORD(prodkey, "EstimatedSize", 12);
+        CHECK_REG_DWORD2(prodkey, "EstimatedSize", 12, -20);
     }
 
     RegCloseKey(prodkey);
@@ -3375,9 +5194,9 @@ static void test_publish(void)
     /* UnpublishFeatures, both features removed */
     r = MsiInstallProductA(msifile, "UNPUBLISH_FEATURES=1 REMOVE=feature,montecristo");
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+    ok(!pf_exists("msitest\\maximus"), "File not deleted\n");
     todo_wine
     {
-        ok(!pf_exists("msitest\\maximus"), "File not deleted\n");
         ok(!pf_exists("msitest"), "File not deleted\n");
     }
 
@@ -3445,7 +5264,7 @@ static void test_publish(void)
     CHECK_REG_DWORD(prodkey, "WindowsInstaller", 1);
     todo_wine
     {
-        CHECK_REG_DWORD(prodkey, "EstimatedSize", 12);
+        CHECK_REG_DWORD2(prodkey, "EstimatedSize", 12, -12);
     }
 
     RegCloseKey(prodkey);
@@ -3453,9 +5272,9 @@ static void test_publish(void)
     /* complete uninstall */
     r = MsiInstallProductA(msifile, "FULL=1 REMOVE=ALL");
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+    ok(!pf_exists("msitest\\maximus"), "File not deleted\n");
     todo_wine
     {
-        ok(!pf_exists("msitest\\maximus"), "File not deleted\n");
         ok(!pf_exists("msitest"), "File not deleted\n");
     }
 
@@ -3495,7 +5314,7 @@ static void test_publishsourcelist(void)
 
     if (!pMsiSourceListEnumSourcesA || !pMsiSourceListGetInfoA)
     {
-        skip("MsiSourceListEnumSourcesA and/or MsiSourceListGetInfoA are not available\n");
+        win_skip("MsiSourceListEnumSourcesA and/or MsiSourceListGetInfoA are not available\n");
         return;
     }
 
@@ -3512,17 +5331,21 @@ static void test_publishsourcelist(void)
     ok(pf_exists("msitest"), "File not installed\n");
 
     /* nothing published */
-    size = 0xdeadbeef;
+    size = MAX_PATH;
+    lstrcpyA(value, "aaa");
     r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
-                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size);
+                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, value, &size);
     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
-    ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size);
+    ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size);
+    ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value);
 
-    size = 0xdeadbeef;
+    size = MAX_PATH;
+    lstrcpyA(value, "aaa");
     r = pMsiSourceListEnumSourcesA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
-                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, NULL, &size);
+                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
-    ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size);
+    ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size);
+    ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value);
 
     r = MsiInstallProductA(msifile, "REGISTER_PRODUCT=1");
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
@@ -3530,17 +5353,21 @@ static void test_publishsourcelist(void)
     ok(pf_exists("msitest"), "File not installed\n");
 
     /* after RegisterProduct */
-    size = 0xdeadbeef;
+    size = MAX_PATH;
+    lstrcpyA(value, "aaa");
     r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
-                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size);
+                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, value, &size);
     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
-    ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size);
+    ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size);
+    ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value);
 
-    size = 0xdeadbeef;
+    size = MAX_PATH;
+    lstrcpyA(value, "aaa");
     r = pMsiSourceListEnumSourcesA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
-                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, NULL, &size);
+                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
-    ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size);
+    ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size);
+    ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value);
 
     r = MsiInstallProductA(msifile, "PROCESS_COMPONENTS=1");
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
@@ -3548,17 +5375,21 @@ static void test_publishsourcelist(void)
     ok(pf_exists("msitest"), "File not installed\n");
 
     /* after ProcessComponents */
-    size = 0xdeadbeef;
+    size = MAX_PATH;
+    lstrcpyA(value, "aaa");
     r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
-                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size);
+                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, value, &size);
     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
-    ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size);
+    ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size);
+    ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value);
 
-    size = 0xdeadbeef;
+    size = MAX_PATH;
+    lstrcpyA(value, "aaa");
     r = pMsiSourceListEnumSourcesA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
-                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, NULL, &size);
+                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
-    ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size);
+    ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size);
+    ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value);
 
     r = MsiInstallProductA(msifile, "PUBLISH_FEATURES=1");
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
@@ -3566,17 +5397,21 @@ static void test_publishsourcelist(void)
     ok(pf_exists("msitest"), "File not installed\n");
 
     /* after PublishFeatures */
-    size = 0xdeadbeef;
+    size = MAX_PATH;
+    lstrcpyA(value, "aaa");
     r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
-                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size);
+                               MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, value, &size);
     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
-    ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size);
+    ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size);
+    ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value);
 
-    size = 0xdeadbeef;
+    size = MAX_PATH;
+    lstrcpyA(value, "aaa");
     r = pMsiSourceListEnumSourcesA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
-                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, NULL, &size);
+                                   MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size);
     ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
-    ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size);
+    ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size);
+    ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value);
 
     r = MsiInstallProductA(msifile, "PUBLISH_PRODUCT=1");
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
@@ -3654,9 +5489,9 @@ static void test_publishsourcelist(void)
     /* complete uninstall */
     r = MsiInstallProductA(msifile, "FULL=1 REMOVE=ALL");
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+    ok(!pf_exists("msitest\\maximus"), "File not deleted\n");
     todo_wine
     {
-        ok(!pf_exists("msitest\\maximus"), "File not deleted\n");
         ok(!pf_exists("msitest"), "File not deleted\n");
     }
 
@@ -3691,37 +5526,22 @@ static void set_transform_summary_info(void)
 
     /* build summary info */
     r = MsiGetSummaryInformation(0, mstfile, 3, &suminfo);
-    todo_wine
-    {
-        ok(r == ERROR_SUCCESS , "Failed to open summaryinfo\n");
-    }
+    ok(r == ERROR_SUCCESS , "Failed to open summaryinfo\n");
 
     r = MsiSummaryInfoSetProperty(suminfo, PID_TITLE, VT_LPSTR, 0, NULL, "MSITEST");
-    todo_wine
-    {
-        ok(r == ERROR_SUCCESS, "Failed to set summary info\n");
-    }
+    ok(r == ERROR_SUCCESS, "Failed to set summary info\n");
 
     r = MsiSummaryInfoSetProperty(suminfo, PID_REVNUMBER, VT_LPSTR, 0, NULL,
                         "{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}1.1.1;"
                         "{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}1.1.1;"
                         "{4C0EAA15-0264-4E5A-8758-609EF142B92D}");
-    todo_wine
-    {
-        ok(r == ERROR_SUCCESS , "Failed to set summary info\n");
-    }
+    ok(r == ERROR_SUCCESS , "Failed to set summary info\n");
 
     r = MsiSummaryInfoSetProperty(suminfo, PID_PAGECOUNT, VT_I4, 100, NULL, NULL);
-    todo_wine
-    {
-        ok(r == ERROR_SUCCESS, "Failed to set summary info\n");
-    }
+    ok(r == ERROR_SUCCESS, "Failed to set summary info\n");
 
     r = MsiSummaryInfoPersist(suminfo);
-    todo_wine
-    {
-        ok(r == ERROR_SUCCESS , "Failed to make summary info persist\n");
-    }
+    ok(r == ERROR_SUCCESS , "Failed to make summary info persist\n");
 
     r = MsiCloseHandle(suminfo);
     ok(r == ERROR_SUCCESS , "Failed to close suminfo\n");
@@ -3879,8 +5699,8 @@ static void test_transformprop(void)
 static void test_currentworkingdir(void)
 {
     UINT r;
-    CHAR path[MAX_PATH];
-    LPSTR ptr, ptr2;
+    CHAR drive[MAX_PATH], path[MAX_PATH];
+    LPSTR ptr;
 
     CreateDirectoryA("msitest", NULL);
     create_file("msitest\\augustus", 500);
@@ -3907,18 +5727,17 @@ static void test_currentworkingdir(void)
     ok(delete_pf("msitest\\augustus", TRUE), "File not installed\n");
     ok(delete_pf("msitest", FALSE), "File not installed\n");
 
-    lstrcpyA(path, CURR_DIR);
+    lstrcpyA(drive, CURR_DIR);
+    drive[2] = '\\';
+    drive[3] = '\0';
+    SetCurrentDirectoryA(drive);
+
+    lstrcpy(path, CURR_DIR);
     if (path[lstrlenA(path) - 1] != '\\')
         lstrcatA(path, "\\");
-    lstrcatA(path, "msitest.msi");
-
-    ptr2 = strrchr(path, '\\');
-    *ptr2 = '\0';
-    ptr = strrchr(path, '\\');
-    *ptr2 = '\\';
-    *(ptr++) = '\0';
-
-    SetCurrentDirectoryA(path);
+    lstrcatA(path, msifile);
+    ptr = strchr(path, ':');
+    ptr +=2;
 
     r = MsiInstallProductA(ptr, NULL);
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
@@ -4004,7 +5823,8 @@ static void set_admin_property_stream(LPCSTR file)
 
     /* AdminProperties */
     static const WCHAR stmname[] = {0x41ca,0x4330,0x3e71,0x44b5,0x4233,0x45f5,0x422c,0x4836,0};
-    static const WCHAR data[] = {'M','Y','P','R','O','P','=','2','7','1','8',0};
+    static const WCHAR data[] = {'M','Y','P','R','O','P','=','2','7','1','8',' ',
+        'M','y','P','r','o','p','=','4','2',0};
 
     MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, MAX_PATH);
 
@@ -4084,13 +5904,10 @@ static void test_removefiles(void)
 
     r = MsiInstallProductA(msifile, "REMOVE=ALL");
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+    ok(!pf_exists("msitest\\hydrogen"), "File not deleted\n");
     ok(!pf_exists("msitest\\helium"), "File not deleted\n");
     ok(delete_pf("msitest\\lithium", TRUE), "File deleted\n");
-    todo_wine
-    {
-        ok(!pf_exists("msitest\\hydrogen"), "File not deleted\n");
-        ok(delete_pf("msitest", FALSE), "File deleted\n");
-    }
+    ok(delete_pf("msitest", FALSE), "File deleted\n");
 
     create_pf("msitest", FALSE);
     create_pf("msitest\\hydrogen", TRUE);
@@ -4106,13 +5923,10 @@ static void test_removefiles(void)
 
     r = MsiInstallProductA(msifile, "REMOVE=ALL");
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+    ok(!pf_exists("msitest\\hydrogen"), "File not deleted\n");
     ok(delete_pf("msitest\\helium", TRUE), "File deleted\n");
     ok(delete_pf("msitest\\lithium", TRUE), "File deleted\n");
-    todo_wine
-    {
-        ok(!pf_exists("msitest\\hydrogen"), "File not deleted\n");
-        ok(delete_pf("msitest", FALSE), "File deleted\n");
-    }
+    ok(delete_pf("msitest", FALSE), "File deleted\n");
 
     create_pf("msitest", FALSE);
     create_pf("msitest\\furlong", TRUE);
@@ -4124,25 +5938,25 @@ static void test_removefiles(void)
     create_pf("msitest\\storeys", TRUE);
     create_pf("msitest\\block", TRUE);
     create_pf("msitest\\siriometer", TRUE);
+    create_pf("msitest\\cabout", FALSE);
+    create_pf("msitest\\cabout\\blocker", TRUE);
 
     r = MsiInstallProductA(msifile, NULL);
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
     ok(pf_exists("msitest\\hydrogen"), "File not installed\n");
     ok(!pf_exists("msitest\\helium"), "File installed\n");
     ok(pf_exists("msitest\\lithium"), "File not installed\n");
+    ok(!pf_exists("msitest\\furlong"), "File not deleted\n");
+    ok(!pf_exists("msitest\\firkin"), "File not deleted\n");
+    ok(!pf_exists("msitest\\fortnight"), "File not deleted\n");
     ok(pf_exists("msitest\\becquerel"), "File not installed\n");
     ok(pf_exists("msitest\\dioptre"), "File not installed\n");
     ok(pf_exists("msitest\\attoparsec"), "File not installed\n");
+    ok(!pf_exists("msitest\\storeys"), "File not deleted\n");
+    ok(!pf_exists("msitest\\block"), "File not deleted\n");
+    ok(!pf_exists("msitest\\siriometer"), "File not deleted\n");
+    ok(pf_exists("msitest\\cabout"), "Directory removed\n");
     ok(pf_exists("msitest"), "File not installed\n");
-    todo_wine
-    {
-        ok(!pf_exists("msitest\\firkin"), "File not deleted\n");
-        ok(!pf_exists("msitest\\fortnight"), "File not deleted\n");
-        ok(!pf_exists("msitest\\furlong"), "File not deleted\n");
-        ok(!pf_exists("msitest\\storeys"), "File not deleted\n");
-        ok(!pf_exists("msitest\\block"), "File not deleted\n");
-        ok(!pf_exists("msitest\\siriometer"), "File not deleted\n");
-    }
 
     create_pf("msitest\\furlong", TRUE);
     create_pf("msitest\\firkin", TRUE);
@@ -4153,22 +5967,35 @@ static void test_removefiles(void)
 
     r = MsiInstallProductA(msifile, "REMOVE=ALL");
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+    ok(!delete_pf("msitest\\hydrogen", TRUE), "File not deleted\n");
     ok(!delete_pf("msitest\\helium", TRUE), "File not deleted\n");
     ok(delete_pf("msitest\\lithium", TRUE), "File deleted\n");
     ok(delete_pf("msitest\\furlong", TRUE), "File deleted\n");
     ok(delete_pf("msitest\\firkin", TRUE), "File deleted\n");
     ok(delete_pf("msitest\\fortnight", TRUE), "File deleted\n");
+    ok(!delete_pf("msitest\\becquerel", TRUE), "File not deleted\n");
+    ok(!delete_pf("msitest\\dioptre", TRUE), "File not deleted\n");
     ok(delete_pf("msitest\\attoparsec", TRUE), "File deleted\n");
+    ok(!delete_pf("msitest\\storeys", TRUE), "File not deleted\n");
+    ok(!delete_pf("msitest\\block", TRUE), "File not deleted\n");
     ok(delete_pf("msitest\\siriometer", TRUE), "File deleted\n");
-    todo_wine
-    {
-        ok(!delete_pf("msitest\\hydrogen", TRUE), "File not deleted\n");
-        ok(!delete_pf("msitest\\becquerel", TRUE), "File not deleted\n");
-        ok(!delete_pf("msitest\\dioptre", TRUE), "File not deleted\n");
-        ok(!delete_pf("msitest\\storeys", TRUE), "File not deleted\n");
-        ok(!delete_pf("msitest\\block", TRUE), "File not deleted\n");
-    }
-    ok(delete_pf("msitest", FALSE), "File deleted\n");
+    ok(pf_exists("msitest\\cabout"), "Directory deleted\n");
+    ok(pf_exists("msitest"), "Directory deleted\n");
+
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+    ok(delete_pf("msitest\\hydrogen", TRUE), "File not installed\n");
+    ok(!delete_pf("msitest\\helium", TRUE), "File installed\n");
+    ok(delete_pf("msitest\\lithium", TRUE), "File not installed\n");
+    ok(pf_exists("msitest\\cabout"), "Directory deleted\n");
+    ok(pf_exists("msitest"), "Directory deleted\n");
+
+    delete_pf("msitest\\cabout\\blocker", TRUE);
+
+    r = MsiInstallProductA(msifile, "REMOVE=ALL");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+    ok(!delete_pf("msitest\\cabout", FALSE), "Directory not deleted\n");
+    ok(delete_pf("msitest", FALSE), "Directory deleted\n");
 
     DeleteFile(msifile);
     DeleteFile("msitest\\hydrogen");
@@ -4195,6 +6022,7 @@ static void test_movefiles(void)
     create_file("kenya", 100);
     CreateDirectoryA("latvia", NULL);
     create_file("nauru", 100);
+    create_file("peru", 100);
     create_file("apple", 100);
     create_file("application", 100);
     create_file("ape", 100);
@@ -4235,6 +6063,7 @@ static void test_movefiles(void)
     ok(delete_pf("msitest\\kiribati", TRUE), "File not moved\n");
     ok(!delete_pf("msitest\\lebanon", TRUE), "File moved\n");
     ok(!delete_pf("msitest\\lebanon", FALSE), "Directory moved\n");
+    ok(delete_pf("msitest\\poland", TRUE), "File not moved\n");
     /* either apple or application will be moved depending on directory order */
     if (!delete_pf("msitest\\apple", TRUE))
         ok(delete_pf("msitest\\application", TRUE), "File not moved\n");
@@ -4267,6 +6096,7 @@ static void test_movefiles(void)
     ok(!DeleteFileA("kenya"), "File not moved\n");
     ok(RemoveDirectoryA("latvia"), "Directory moved\n");
     ok(!DeleteFileA("nauru"), "File not moved\n");
+    ok(!DeleteFileA("peru"), "File not moved\n");
     ok(!DeleteFileA("apple"), "File not moved\n");
     ok(!DeleteFileA("application"), "File not moved\n");
     ok(DeleteFileA("ape"), "File moved\n");
@@ -4303,10 +6133,15 @@ static void test_missingcab(void)
     create_pf_data("msitest\\caesar", "abcdefgh", TRUE);
 
     r = MsiInstallProductA(msifile, NULL);
-    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-    ok(delete_pf("msitest\\augustus", TRUE), "File not installed\n");
+    ok(r == ERROR_SUCCESS ||
+       broken(r == ERROR_INSTALL_FAILURE), /* win9x */
+       "Expected ERROR_SUCCESS, got %u\n", r);
+    if (r == ERROR_SUCCESS)
+    {
+      ok(delete_pf("msitest\\augustus", TRUE), "File not installed\n");
+      ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n");
+    }
     ok(delete_pf("msitest\\caesar", TRUE), "File not installed\n");
-    ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n");
     ok(!delete_pf("msitest\\gaius", TRUE), "File installed\n");
     ok(delete_pf("msitest", FALSE), "File not installed\n");
 
@@ -4411,22 +6246,22 @@ static void test_sourcefolder(void)
     MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
 
     r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_INSTALL_FAILURE,
+       "Expected ERROR_INSTALL_FAILURE, got %u\n", r);
     ok(!delete_pf("msitest\\augustus", TRUE), "File installed\n");
     todo_wine
     {
-        ok(r == ERROR_INSTALL_FAILURE,
-           "Expected ERROR_INSTALL_FAILURE, got %u\n", r);
         ok(!delete_pf("msitest", FALSE), "File installed\n");
     }
 
     RemoveDirectoryA("msitest");
 
     r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_INSTALL_FAILURE,
+       "Expected ERROR_INSTALL_FAILURE, got %u\n", r);
+    ok(!delete_pf("msitest\\augustus", TRUE), "File installed\n");
     todo_wine
     {
-        ok(r == ERROR_INSTALL_FAILURE,
-           "Expected ERROR_INSTALL_FAILURE, got %u\n", r);
-        ok(!delete_pf("msitest\\augustus", TRUE), "File installed\n");
         ok(!delete_pf("msitest", FALSE), "File installed\n");
     }
 
@@ -4557,57 +6392,2028 @@ static void test_installstate(void)
     RemoveDirectory("msitest");
 }
 
-START_TEST(install)
+struct sourcepathmap
 {
-    DWORD len;
-    char temp_path[MAX_PATH], prev_path[MAX_PATH];
+    BOOL sost; /* shortone\shorttwo */
+    BOOL solt; /* shortone\longtwo */
+    BOOL lost; /* longone\shorttwo */
+    BOOL lolt; /* longone\longtwo */
+    BOOL soste; /* shortone\shorttwo source exists */
+    BOOL solte; /* shortone\longtwo source exists */
+    BOOL loste; /* longone\shorttwo source exists */
+    BOOL lolte; /* longone\longtwo source exists */
+    UINT err;
+    DWORD size;
+} spmap[256] =
+{
+    {TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200},
+    {FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0},
+    {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0},
+};
 
-    init_functionpointers();
+static DWORD get_pf_file_size(LPCSTR file)
+{
+    CHAR path[MAX_PATH];
+    HANDLE hfile;
+    DWORD size;
 
-    GetCurrentDirectoryA(MAX_PATH, prev_path);
-    GetTempPath(MAX_PATH, temp_path);
-    SetCurrentDirectoryA(temp_path);
+    lstrcpyA(path, PROG_FILES_DIR);
+    lstrcatA(path, "\\");
+    lstrcatA(path, file);
 
-    lstrcpyA(CURR_DIR, temp_path);
-    len = lstrlenA(CURR_DIR);
+    hfile = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+    if (hfile == INVALID_HANDLE_VALUE)
+        return 0;
 
-    if(len && (CURR_DIR[len - 1] == '\\'))
-        CURR_DIR[len - 1] = 0;
+    size = GetFileSize(hfile, NULL);
+    CloseHandle(hfile);
+    return size;
+}
 
-    get_program_files_dir(PROG_FILES_DIR, COMMON_FILES_DIR);
+static void test_sourcepath(void)
+{
+    UINT r, i;
 
-    test_MsiInstallProduct();
-    test_MsiSetComponentState();
-    test_packagecoltypes();
-    test_continuouscabs();
-    test_caborder();
-    test_mixedmedia();
-    test_samesequence();
-    test_uiLevelFlags();
-    test_readonlyfile();
-    test_setdirproperty();
-    test_cabisextracted();
-    test_concurrentinstall();
-    test_setpropertyfolder();
-    test_publish_registerproduct();
-    test_publish_publishproduct();
-    test_publish_publishfeatures();
-    test_publish_registeruser();
-    test_publish_processcomponents();
-    test_publish();
-    test_publishsourcelist();
-    test_transformprop();
-    test_currentworkingdir();
-    test_admin();
-    test_adminprops();
-    test_removefiles();
-    test_movefiles();
-    test_missingcab();
-    test_duplicatefiles();
-    test_writeregistryvalues();
-    test_sourcefolder();
-    test_customaction51();
-    test_installstate();
+    if (!winetest_interactive)
+    {
+        skip("Run in interactive mode to run source path tests.\n");
+        return;
+    }
+
+    create_database(msifile, sp_tables, sizeof(sp_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    for (i = 0; i < sizeof(spmap) / sizeof(spmap[0]); i++)
+    {
+        if (spmap[i].sost)
+        {
+            CreateDirectoryA("shortone", NULL);
+            CreateDirectoryA("shortone\\shorttwo", NULL);
+        }
+
+        if (spmap[i].solt)
+        {
+            CreateDirectoryA("shortone", NULL);
+            CreateDirectoryA("shortone\\longtwo", NULL);
+        }
+
+        if (spmap[i].lost)
+        {
+            CreateDirectoryA("longone", NULL);
+            CreateDirectoryA("longone\\shorttwo", NULL);
+        }
+
+        if (spmap[i].lolt)
+        {
+            CreateDirectoryA("longone", NULL);
+            CreateDirectoryA("longone\\longtwo", NULL);
+        }
+
+        if (spmap[i].soste)
+            create_file("shortone\\shorttwo\\augustus", 50);
+        if (spmap[i].solte)
+            create_file("shortone\\longtwo\\augustus", 100);
+        if (spmap[i].loste)
+            create_file("longone\\shorttwo\\augustus", 150);
+        if (spmap[i].lolte)
+            create_file("longone\\longtwo\\augustus", 200);
+
+        r = MsiInstallProductA(msifile, NULL);
+        ok(r == spmap[i].err, "%d: Expected %d, got %d\n", i, spmap[i].err, r);
+        ok(get_pf_file_size("msitest\\augustus") == spmap[i].size,
+           "%d: Expected %d, got %d\n", i, spmap[i].size,
+           get_pf_file_size("msitest\\augustus"));
+
+        if (r == ERROR_SUCCESS)
+        {
+            ok(delete_pf("msitest\\augustus", TRUE), "%d: File not installed\n", i);
+            ok(delete_pf("msitest", FALSE), "%d: File not installed\n", i);
+        }
+        else
+        {
+            ok(!delete_pf("msitest\\augustus", TRUE), "%d: File installed\n", i);
+            todo_wine ok(!delete_pf("msitest", FALSE), "%d: File installed\n", i);
+        }
+
+        DeleteFileA("shortone\\shorttwo\\augustus");
+        DeleteFileA("shortone\\longtwo\\augustus");
+        DeleteFileA("longone\\shorttwo\\augustus");
+        DeleteFileA("longone\\longtwo\\augustus");
+        RemoveDirectoryA("shortone\\shorttwo");
+        RemoveDirectoryA("shortone\\longtwo");
+        RemoveDirectoryA("longone\\shorttwo");
+        RemoveDirectoryA("longone\\longtwo");
+        RemoveDirectoryA("shortone");
+        RemoveDirectoryA("longone");
+    }
+
+    DeleteFileA(msifile);
+}
+
+static void test_MsiConfigureProductEx(void)
+{
+    UINT r;
+    LONG res;
+    DWORD type, size;
+    HKEY props, source;
+    CHAR keypath[MAX_PATH * 2];
+    CHAR localpack[MAX_PATH];
+
+    if (on_win9x)
+    {
+        win_skip("Different registry keys on Win9x and WinMe\n");
+        return;
+    }
+
+    CreateDirectoryA("msitest", NULL);
+    create_file("msitest\\hydrogen", 500);
+    create_file("msitest\\helium", 500);
+    create_file("msitest\\lithium", 500);
+
+    create_database(msifile, mcp_tables, sizeof(mcp_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    /* NULL szProduct */
+    r = MsiConfigureProductExA(NULL, INSTALLLEVEL_DEFAULT,
+                               INSTALLSTATE_DEFAULT, "PROPVAR=42");
+    ok(r == ERROR_INVALID_PARAMETER,
+       "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
+
+    /* empty szProduct */
+    r = MsiConfigureProductExA("", INSTALLLEVEL_DEFAULT,
+                               INSTALLSTATE_DEFAULT, "PROPVAR=42");
+    ok(r == ERROR_INVALID_PARAMETER,
+       "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
+
+    /* garbage szProduct */
+    r = MsiConfigureProductExA("garbage", INSTALLLEVEL_DEFAULT,
+                               INSTALLSTATE_DEFAULT, "PROPVAR=42");
+    ok(r == ERROR_INVALID_PARAMETER,
+       "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
+
+    /* guid without brackets */
+    r = MsiConfigureProductExA("6700E8CF-95AB-4D9C-BC2C-15840DEA7A5D",
+                               INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT,
+                               "PROPVAR=42");
+    ok(r == ERROR_INVALID_PARAMETER,
+       "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
+
+    /* guid with brackets */
+    r = MsiConfigureProductExA("{6700E8CF-95AB-4D9C-BC2C-15840DEA7A5D}",
+                               INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT,
+                               "PROPVAR=42");
+    ok(r == ERROR_UNKNOWN_PRODUCT,
+       "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
+
+    /* same length as guid, but random */
+    r = MsiConfigureProductExA("A938G02JF-2NF3N93-VN3-2NNF-3KGKALDNF93",
+                               INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT,
+                               "PROPVAR=42");
+    ok(r == ERROR_UNKNOWN_PRODUCT,
+       "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
+
+    /* product not installed yet */
+    r = MsiConfigureProductExA("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}",
+                               INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT,
+                               "PROPVAR=42");
+    ok(r == ERROR_UNKNOWN_PRODUCT,
+       "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r);
+
+    /* install the product, per-user unmanaged */
+    r = MsiInstallProductA(msifile, "INSTALLLEVEL=10 PROPVAR=42");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+    ok(pf_exists("msitest\\hydrogen"), "File not installed\n");
+    ok(pf_exists("msitest\\helium"), "File not installed\n");
+    ok(pf_exists("msitest\\lithium"), "File not installed\n");
+    ok(pf_exists("msitest"), "File not installed\n");
+
+    /* product is installed per-user managed, remove it */
+    r = MsiConfigureProductExA("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}",
+                               INSTALLLEVEL_DEFAULT, INSTALLSTATE_ABSENT,
+                               "PROPVAR=42");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+    ok(!delete_pf("msitest\\hydrogen", TRUE), "File not removed\n");
+    ok(!delete_pf("msitest\\helium", TRUE), "File not removed\n");
+    ok(!delete_pf("msitest\\lithium", TRUE), "File not removed\n");
+    todo_wine
+    {
+        ok(!delete_pf("msitest", FALSE), "File not removed\n");
+    }
+
+    /* product has been removed */
+    r = MsiConfigureProductExA("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}",
+                               INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT,
+                               "PROPVAR=42");
+    ok(r == ERROR_UNKNOWN_PRODUCT,
+       "Expected ERROR_UNKNOWN_PRODUCT, got %u\n", r);
+
+    /* install the product, machine */
+    r = MsiInstallProductA(msifile, "ALLUSERS=1 INSTALLLEVEL=10 PROPVAR=42");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+    ok(pf_exists("msitest\\hydrogen"), "File not installed\n");
+    ok(pf_exists("msitest\\helium"), "File not installed\n");
+    ok(pf_exists("msitest\\lithium"), "File not installed\n");
+    ok(pf_exists("msitest"), "File not installed\n");
+
+    /* product is installed machine, remove it */
+    r = MsiConfigureProductExA("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}",
+                               INSTALLLEVEL_DEFAULT, INSTALLSTATE_ABSENT,
+                               "PROPVAR=42");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+    ok(!delete_pf("msitest\\hydrogen", TRUE), "File not removed\n");
+    ok(!delete_pf("msitest\\helium", TRUE), "File not removed\n");
+    ok(!delete_pf("msitest\\lithium", TRUE), "File not removed\n");
+    todo_wine
+    {
+        ok(!delete_pf("msitest", FALSE), "File not removed\n");
+    }
+
+    /* product has been removed */
+    r = MsiConfigureProductExA("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}",
+                               INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT,
+                               "PROPVAR=42");
+    ok(r == ERROR_UNKNOWN_PRODUCT,
+       "Expected ERROR_UNKNOWN_PRODUCT, got %u\n", r);
+
+    /* install the product, machine */
+    r = MsiInstallProductA(msifile, "ALLUSERS=1 INSTALLLEVEL=10 PROPVAR=42");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+    ok(pf_exists("msitest\\hydrogen"), "File not installed\n");
+    ok(pf_exists("msitest\\helium"), "File not installed\n");
+    ok(pf_exists("msitest\\lithium"), "File not installed\n");
+    ok(pf_exists("msitest"), "File not installed\n");
+
+    DeleteFileA(msifile);
+
+    /* local msifile is removed */
+    r = MsiConfigureProductExA("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}",
+                               INSTALLLEVEL_DEFAULT, INSTALLSTATE_ABSENT,
+                               "PROPVAR=42");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+    ok(!delete_pf("msitest\\hydrogen", TRUE), "File not removed\n");
+    ok(!delete_pf("msitest\\helium", TRUE), "File not removed\n");
+    ok(!delete_pf("msitest\\lithium", TRUE), "File not removed\n");
+    todo_wine
+    {
+        ok(!delete_pf("msitest", FALSE), "File not removed\n");
+    }
+
+    create_database(msifile, mcp_tables, sizeof(mcp_tables) / sizeof(msi_table));
+
+    /* install the product, machine */
+    r = MsiInstallProductA(msifile, "ALLUSERS=1 INSTALLLEVEL=10 PROPVAR=42");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+    ok(pf_exists("msitest\\hydrogen"), "File not installed\n");
+    ok(pf_exists("msitest\\helium"), "File not installed\n");
+    ok(pf_exists("msitest\\lithium"), "File not installed\n");
+    ok(pf_exists("msitest"), "File not installed\n");
+
+    DeleteFileA(msifile);
+
+    lstrcpyA(keypath, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\");
+    lstrcatA(keypath, "Installer\\UserData\\S-1-5-18\\Products\\");
+    lstrcatA(keypath, "84A88FD7F6998CE40A22FB59F6B9C2BB\\InstallProperties");
+
+    res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &props);
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+
+    res = RegSetValueExA(props, "LocalPackage", 0, REG_SZ,
+                         (const BYTE *)"C:\\idontexist.msi", 18);
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+
+    /* LocalPackage is used to find the cached msi package */
+    r = MsiConfigureProductExA("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}",
+                               INSTALLLEVEL_DEFAULT, INSTALLSTATE_ABSENT,
+                               "PROPVAR=42");
+    ok(r == ERROR_INSTALL_SOURCE_ABSENT,
+       "Expected ERROR_INSTALL_SOURCE_ABSENT, got %d\n", r);
+    ok(pf_exists("msitest\\hydrogen"), "File not installed\n");
+    ok(pf_exists("msitest\\helium"), "File not installed\n");
+    ok(pf_exists("msitest\\lithium"), "File not installed\n");
+    ok(pf_exists("msitest"), "File not installed\n");
+
+    RegCloseKey(props);
+    create_database(msifile, mcp_tables, sizeof(mcp_tables) / sizeof(msi_table));
+
+    /* LastUsedSource (local msi package) can be used as a last resort */
+    r = MsiConfigureProductExA("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}",
+                               INSTALLLEVEL_DEFAULT, INSTALLSTATE_ABSENT,
+                               "PROPVAR=42");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+    ok(!delete_pf("msitest\\hydrogen", TRUE), "File not removed\n");
+    ok(!delete_pf("msitest\\helium", TRUE), "File not removed\n");
+    ok(!delete_pf("msitest\\lithium", TRUE), "File not removed\n");
+    todo_wine
+    {
+        ok(!delete_pf("msitest", FALSE), "File not removed\n");
+    }
+
+    /* install the product, machine */
+    r = MsiInstallProductA(msifile, "ALLUSERS=1 INSTALLLEVEL=10 PROPVAR=42");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+    ok(pf_exists("msitest\\hydrogen"), "File not installed\n");
+    ok(pf_exists("msitest\\helium"), "File not installed\n");
+    ok(pf_exists("msitest\\lithium"), "File not installed\n");
+    ok(pf_exists("msitest"), "File not installed\n");
+
+    lstrcpyA(keypath, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\");
+    lstrcatA(keypath, "Installer\\UserData\\S-1-5-18\\Products\\");
+    lstrcatA(keypath, "84A88FD7F6998CE40A22FB59F6B9C2BB\\InstallProperties");
+
+    res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &props);
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+
+    res = RegSetValueExA(props, "LocalPackage", 0, REG_SZ,
+                         (const BYTE *)"C:\\idontexist.msi", 18);
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+
+    lstrcpyA(keypath, "SOFTWARE\\Classes\\Installer\\Products\\");
+    lstrcatA(keypath, "84A88FD7F6998CE40A22FB59F6B9C2BB\\SourceList");
+
+    res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &source);
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+
+    type = REG_SZ;
+    size = MAX_PATH;
+    res = RegQueryValueExA(source, "PackageName", NULL, &type,
+                           (LPBYTE)localpack, &size);
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+
+    res = RegSetValueExA(source, "PackageName", 0, REG_SZ,
+                         (const BYTE *)"idontexist.msi", 15);
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+
+    /* SourceList is altered */
+    r = MsiConfigureProductExA("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}",
+                               INSTALLLEVEL_DEFAULT, INSTALLSTATE_ABSENT,
+                               "PROPVAR=42");
+    ok(r == ERROR_INSTALL_SOURCE_ABSENT,
+       "Expected ERROR_INSTALL_SOURCE_ABSENT, got %d\n", r);
+    ok(pf_exists("msitest\\hydrogen"), "File not installed\n");
+    ok(pf_exists("msitest\\helium"), "File not installed\n");
+    ok(pf_exists("msitest\\lithium"), "File not installed\n");
+    ok(pf_exists("msitest"), "File not installed\n");
+
+    /* restore the SourceList */
+    res = RegSetValueExA(source, "PackageName", 0, REG_SZ,
+                         (const BYTE *)localpack, lstrlenA(localpack) + 1);
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+
+    /* finally remove the product */
+    r = MsiConfigureProductExA("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}",
+                               INSTALLLEVEL_DEFAULT, INSTALLSTATE_ABSENT,
+                               "PROPVAR=42");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+    ok(!delete_pf("msitest\\hydrogen", TRUE), "File not removed\n");
+    ok(!delete_pf("msitest\\helium", TRUE), "File not removed\n");
+    ok(!delete_pf("msitest\\lithium", TRUE), "File not removed\n");
+    todo_wine
+    {
+        ok(!delete_pf("msitest", FALSE), "File not removed\n");
+    }
+
+    DeleteFileA(msifile);
+    RegCloseKey(source);
+    RegCloseKey(props);
+    DeleteFileA("msitest\\hydrogen");
+    DeleteFileA("msitest\\helium");
+    DeleteFileA("msitest\\lithium");
+    RemoveDirectoryA("msitest");
+}
+
+static void test_missingcomponent(void)
+{
+    UINT r;
+
+    CreateDirectoryA("msitest", NULL);
+    create_file("msitest\\hydrogen", 500);
+    create_file("msitest\\helium", 500);
+    create_file("msitest\\lithium", 500);
+    create_file("beryllium", 500);
+
+    create_database(msifile, mcomp_tables, sizeof(mcomp_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    r = MsiInstallProductA(msifile, "INSTALLLEVEL=10 PROPVAR=42");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+    ok(pf_exists("msitest\\hydrogen"), "File not installed\n");
+    ok(pf_exists("msitest\\helium"), "File not installed\n");
+    ok(pf_exists("msitest\\lithium"), "File not installed\n");
+    ok(!pf_exists("msitest\\beryllium"), "File installed\n");
+    ok(pf_exists("msitest"), "File not installed\n");
+
+    r = MsiInstallProductA(msifile, "REMOVE=ALL INSTALLLEVEL=10 PROPVAR=42");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+    ok(!delete_pf("msitest\\hydrogen", TRUE), "File not removed\n");
+    ok(!delete_pf("msitest\\helium", TRUE), "File not removed\n");
+    ok(!delete_pf("msitest\\lithium", TRUE), "File not removed\n");
+    ok(!pf_exists("msitest\\beryllium"), "File installed\n");
+    todo_wine
+    {
+        ok(!delete_pf("msitest", FALSE), "File not removed\n");
+    }
+
+    DeleteFileA(msifile);
+    DeleteFileA("msitest\\hydrogen");
+    DeleteFileA("msitest\\helium");
+    DeleteFileA("msitest\\lithium");
+    DeleteFileA("beryllium");
+    RemoveDirectoryA("msitest");
+}
+
+static void test_sourcedirprop(void)
+{
+    UINT r;
+    CHAR props[MAX_PATH];
+
+    CreateDirectoryA("msitest", NULL);
+    create_file("msitest\\augustus", 500);
+
+    create_database(msifile, ca51_tables, sizeof(ca51_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+    ok(delete_pf("msitest\\augustus", TRUE), "File installed\n");
+    ok(delete_pf("msitest", FALSE), "File installed\n");
+
+    DeleteFile("msitest\\augustus");
+    RemoveDirectory("msitest");
+
+    CreateDirectoryA("altsource", NULL);
+    CreateDirectoryA("altsource\\msitest", NULL);
+    create_file("altsource\\msitest\\augustus", 500);
+
+    sprintf(props, "SRCDIR=%s\\altsource\\", CURR_DIR);
+
+    r = MsiInstallProductA(msifile, props);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+    ok(delete_pf("msitest\\augustus", TRUE), "File installed\n");
+    ok(delete_pf("msitest", FALSE), "File installed\n");
+
+    DeleteFile(msifile);
+    DeleteFile("altsource\\msitest\\augustus");
+    RemoveDirectory("altsource\\msitest");
+    RemoveDirectory("altsource");
+}
+
+static void test_adminimage(void)
+{
+    UINT r;
+
+    CreateDirectoryA("msitest", NULL);
+    CreateDirectoryA("msitest\\first", NULL);
+    CreateDirectoryA("msitest\\second", NULL);
+    CreateDirectoryA("msitest\\cabout", NULL);
+    CreateDirectoryA("msitest\\cabout\\new", NULL);
+    create_file("msitest\\one.txt", 100);
+    create_file("msitest\\first\\two.txt", 100);
+    create_file("msitest\\second\\three.txt", 100);
+    create_file("msitest\\cabout\\four.txt", 100);
+    create_file("msitest\\cabout\\new\\five.txt", 100);
+    create_file("msitest\\filename", 100);
+    create_file("msitest\\service.exe", 100);
+
+    create_database_wordcount(msifile, ai_tables,
+                              sizeof(ai_tables) / sizeof(msi_table),
+                              msidbSumInfoSourceTypeAdminImage);
+
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
+    ok(delete_pf("msitest", FALSE), "File not installed\n");
+
+    DeleteFileA("msitest.msi");
+    DeleteFileA("msitest\\cabout\\new\\five.txt");
+    DeleteFileA("msitest\\cabout\\four.txt");
+    DeleteFileA("msitest\\second\\three.txt");
+    DeleteFileA("msitest\\first\\two.txt");
+    DeleteFileA("msitest\\one.txt");
+    DeleteFileA("msitest\\service.exe");
+    DeleteFileA("msitest\\filename");
+    RemoveDirectoryA("msitest\\cabout\\new");
+    RemoveDirectoryA("msitest\\cabout");
+    RemoveDirectoryA("msitest\\second");
+    RemoveDirectoryA("msitest\\first");
+    RemoveDirectoryA("msitest");
+}
+
+static void test_propcase(void)
+{
+    UINT r;
+
+    CreateDirectoryA("msitest", NULL);
+    create_file("msitest\\augustus", 500);
+
+    create_database(msifile, pc_tables, sizeof(pc_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    r = MsiInstallProductA(msifile, "MyProp=42");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+    ok(delete_pf("msitest\\augustus", TRUE), "File not installed\n");
+    ok(delete_pf("msitest", FALSE), "File not installed\n");
+
+    DeleteFile(msifile);
+    DeleteFile("msitest\\augustus");
+    RemoveDirectory("msitest");
+}
+
+static void test_int_widths( void )
+{
+    static const char int0[] = "int0\ni0\nint0\tint0\n1";
+    static const char int1[] = "int1\ni1\nint1\tint1\n1";
+    static const char int2[] = "int2\ni2\nint2\tint2\n1";
+    static const char int3[] = "int3\ni3\nint3\tint3\n1";
+    static const char int4[] = "int4\ni4\nint4\tint4\n1";
+    static const char int5[] = "int5\ni5\nint5\tint5\n1";
+    static const char int8[] = "int8\ni8\nint8\tint8\n1";
+
+    static const struct
+    {
+        const char  *data;
+        unsigned int size;
+        UINT         ret;
+    }
+    tests[] =
+    {
+        { int0, sizeof(int0) - 1, ERROR_SUCCESS },
+        { int1, sizeof(int1) - 1, ERROR_SUCCESS },
+        { int2, sizeof(int2) - 1, ERROR_SUCCESS },
+        { int3, sizeof(int3) - 1, ERROR_FUNCTION_FAILED },
+        { int4, sizeof(int4) - 1, ERROR_SUCCESS },
+        { int5, sizeof(int5) - 1, ERROR_FUNCTION_FAILED },
+        { int8, sizeof(int8) - 1, ERROR_FUNCTION_FAILED }
+    };
+
+    char tmpdir[MAX_PATH], msitable[MAX_PATH], msidb[MAX_PATH];
+    MSIHANDLE db;
+    UINT r, i;
+
+    GetTempPathA(MAX_PATH, tmpdir);
+    CreateDirectoryA(tmpdir, NULL);
+
+    strcpy(msitable, tmpdir);
+    strcat(msitable, "\\msitable.idt");
+
+    strcpy(msidb, tmpdir);
+    strcat(msidb, "\\msitest.msi");
+
+    r = MsiOpenDatabaseA(msidb, MSIDBOPEN_CREATE, &db);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
+    {
+        write_file(msitable, tests[i].data, tests[i].size);
+
+        r = MsiDatabaseImportA(db, tmpdir, "msitable.idt");
+        ok(r == tests[i].ret, " %u expected %u, got %u\n", i, tests[i].ret, r);
+
+        r = MsiDatabaseCommit(db);
+        ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+        DeleteFileA(msitable);
+    }
+
+    MsiCloseHandle(db);
+    DeleteFileA(msidb);
+    RemoveDirectoryA(tmpdir);
+}
+
+static void test_shortcut(void)
+{
+    UINT r;
+    HRESULT hr;
+
+    create_test_files();
+    create_database(msifile, sc_tables, sizeof(sc_tables) / sizeof(msi_table));
+
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
+    ok(SUCCEEDED(hr), "CoInitialize failed 0x%08x\n", hr);
+
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    CoUninitialize();
+
+    hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+    ok(SUCCEEDED(hr), "CoInitialize failed 0x%08x\n", hr);
+
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    CoUninitialize();
+
+    delete_pf("msitest\\cabout\\new\\five.txt", TRUE);
+    delete_pf("msitest\\cabout\\new", FALSE);
+    delete_pf("msitest\\cabout\\four.txt", TRUE);
+    delete_pf("msitest\\cabout", FALSE);
+    delete_pf("msitest\\changed\\three.txt", TRUE);
+    delete_pf("msitest\\changed", FALSE);
+    delete_pf("msitest\\first\\two.txt", TRUE);
+    delete_pf("msitest\\first", FALSE);
+    delete_pf("msitest\\filename", TRUE);
+    delete_pf("msitest\\one.txt", TRUE);
+    delete_pf("msitest\\service.exe", TRUE);
+    delete_pf("msitest\\Shortcut.lnk", TRUE);
+    delete_pf("msitest", FALSE);
+    delete_test_files();
+}
+
+static void test_envvar(void)
+{
+    UINT r;
+    HKEY env;
+    LONG res;
+    DWORD type, size;
+    char buffer[16];
+    UINT i;
+
+    if (on_win9x)
+    {
+        win_skip("Environment variables are handled differently on Win9x and WinMe\n");
+        return;
+    }
+
+    create_test_files();
+    create_database(msifile, env_tables, sizeof(env_tables) / sizeof(msi_table));
+
+    res = RegCreateKeyExA(HKEY_CURRENT_USER, "Environment", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &env, NULL);
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+
+    res = RegSetValueExA(env, "MSITESTVAR1", 0, REG_SZ, (const BYTE *)"0", 2);
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+
+    res = RegSetValueExA(env, "MSITESTVAR2", 0, REG_SZ, (const BYTE *)"0", 2);
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    type = REG_NONE;
+    size = sizeof(buffer);
+    buffer[0] = 0;
+    res = RegQueryValueExA(env, "MSITESTVAR1", NULL, &type, (LPBYTE)buffer, &size);
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+    ok(type == REG_SZ, "Expected REG_SZ, got %u\n", type);
+    ok(!lstrcmp(buffer, "1"), "Expected \"1\", got %s\n", buffer);
+
+    res = RegDeleteValueA(env, "MSITESTVAR1");
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+
+    type = REG_NONE;
+    size = sizeof(buffer);
+    buffer[0] = 0;
+    res = RegQueryValueExA(env, "MSITESTVAR2", NULL, &type, (LPBYTE)buffer, &size);
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+    ok(type == REG_SZ, "Expected REG_SZ, got %u\n", type);
+    ok(!lstrcmp(buffer, "1"), "Expected \"1\", got %s\n", buffer);
+
+    res = RegDeleteValueA(env, "MSITESTVAR2");
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+
+    res = RegDeleteValueA(env, "MSITESTVAR3");
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+
+    res = RegDeleteValueA(env, "MSITESTVAR4");
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+
+    res = RegDeleteValueA(env, "MSITESTVAR5");
+    ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
+
+    res = RegDeleteValueA(env, "MSITESTVAR6");
+    ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
+
+    res = RegDeleteValueA(env, "MSITESTVAR7");
+    ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
+
+    res = RegDeleteValueA(env, "MSITESTVAR8");
+    ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
+
+    res = RegDeleteValueA(env, "MSITESTVAR9");
+    ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
+
+    res = RegDeleteValueA(env, "MSITESTVAR10");
+    ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
+
+    i = 11;
+    while (environment_dat_results[(i-11)]) {
+        char name[20];
+        sprintf(name, "MSITESTVAR%d", i);
+
+        type = REG_NONE;
+        size = sizeof(buffer);
+        buffer[0] = 0;
+        res = RegQueryValueExA(env, name, NULL, &type, (LPBYTE)buffer, &size);
+        ok(res == ERROR_SUCCESS, "%d: Expected ERROR_SUCCESS, got %d\n", i, res);
+        ok(type == REG_SZ, "%d: Expected REG_SZ, got %u\n", i, type);
+        ok(!lstrcmp(buffer, environment_dat_results[(i-11)]), "%d: Expected %s, got %s\n",
+           i, environment_dat_results[(i-11)], buffer);
+
+        res = RegDeleteValueA(env, name);
+        ok(res == ERROR_SUCCESS, "%d: Expected ERROR_SUCCESS, got %d\n", i, res);
+        i++;
+    }
+
+
+    RegCloseKey(env);
+    delete_pf("msitest\\cabout\\new\\five.txt", TRUE);
+    delete_pf("msitest\\cabout\\new", FALSE);
+    delete_pf("msitest\\cabout\\four.txt", TRUE);
+    delete_pf("msitest\\cabout", FALSE);
+    delete_pf("msitest\\changed\\three.txt", TRUE);
+    delete_pf("msitest\\changed", FALSE);
+    delete_pf("msitest\\first\\two.txt", TRUE);
+    delete_pf("msitest\\first", FALSE);
+    delete_pf("msitest\\filename", TRUE);
+    delete_pf("msitest\\one.txt", TRUE);
+    delete_pf("msitest\\service.exe", TRUE);
+    delete_pf("msitest", FALSE);
+    delete_test_files();
+}
+
+static void test_preselected(void)
+{
+    UINT r;
+
+    create_test_files();
+    create_database(msifile, ps_tables, sizeof(ps_tables) / sizeof(msi_table));
+
+    r = MsiInstallProductA(msifile, "ADDLOCAL=One");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ok(!delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\cabout\\new", FALSE), "File installed\n");
+    ok(!delete_pf("msitest\\cabout\\four.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\cabout", FALSE), "File installed\n");
+    ok(!delete_pf("msitest\\changed\\three.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\changed", FALSE), "File installed\n");
+    ok(!delete_pf("msitest\\first\\two.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\first", FALSE), "File installed\n");
+    ok(!delete_pf("msitest\\filename", TRUE), "File installed\n");
+    ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
+    ok(!delete_pf("msitest\\service.exe", TRUE), "File installed\n");
+    ok(delete_pf("msitest", FALSE), "File not installed\n");
+
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
+    ok(!delete_pf("msitest\\one.txt", TRUE), "File installed\n");
+    ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
+    ok(delete_pf("msitest", FALSE), "File not installed\n");
+    delete_test_files();
+}
+
+static void test_installed_prop(void)
+{
+    static char prodcode[] = "{7df88a48-996f-4ec8-a022-bf956f9b2cbb}";
+    UINT r;
+
+    create_test_files();
+    create_database(msifile, ip_tables, sizeof(ip_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    r = MsiInstallProductA(msifile, "FULL=1");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    r = MsiInstallProductA(msifile, "FULL=1");
+    ok(r == ERROR_INSTALL_FAILURE, "Expected ERROR_INSTALL_FAILURE, got %u\n", r);
+
+    r = MsiConfigureProductExA(prodcode, INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, "FULL=1");
+    ok(r == ERROR_INSTALL_FAILURE, "Expected ERROR_INSTALL_FAILURE, got %u\n", r);
+
+    ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\one.txt", TRUE), "File installed\n");
+    ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
+    ok(delete_pf("msitest", FALSE), "File not installed\n");
+
+    r = MsiInstallProductA(msifile, "REMOVE=ALL");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    delete_test_files();
+}
+
+static void test_allusers_prop(void)
+{
+    UINT r;
+
+    create_test_files();
+    create_database(msifile, aup_tables, sizeof(aup_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    /* ALLUSERS property unset */
+    r = MsiInstallProductA(msifile, "FULL=1");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\one.txt", TRUE), "File installed\n");
+    ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
+    ok(delete_pf("msitest", FALSE), "File not installed\n");
+
+    r = MsiInstallProductA(msifile, "REMOVE=ALL");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    delete_test_files();
+
+    create_test_files();
+    create_database(msifile, aup2_tables, sizeof(aup2_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    /* ALLUSERS property set to 1 */
+    r = MsiInstallProductA(msifile, "FULL=1");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\one.txt", TRUE), "File installed\n");
+    ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
+    ok(delete_pf("msitest", FALSE), "File not installed\n");
+
+    r = MsiInstallProductA(msifile, "REMOVE=ALL");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    delete_test_files();
+
+    create_test_files();
+    create_database(msifile, aup3_tables, sizeof(aup3_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    /* ALLUSERS property set to 2 */
+    r = MsiInstallProductA(msifile, "FULL=1");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
+    ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\one.txt", TRUE), "File installed\n");
+    ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
+    ok(delete_pf("msitest", FALSE), "File not installed\n");
+
+    r = MsiInstallProductA(msifile, "REMOVE=ALL");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    delete_test_files();
+
+    create_test_files();
+    create_database(msifile, aup4_tables, sizeof(aup4_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    /* ALLUSERS property set to 2, conditioned on ALLUSERS = 1 */
+    r = MsiInstallProductA(msifile, "FULL=1");
+    if (r == ERROR_SUCCESS)
+    {
+        /* Win9x/WinMe */
+        win_skip("Win9x and WinMe act differently with respect to ALLUSERS\n");
+
+        ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
+        ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
+        ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
+        ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
+        ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
+        ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
+        ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
+        ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
+        ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
+        ok(delete_pf("msitest\\one.txt", TRUE), "File installed\n");
+        ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
+        ok(delete_pf("msitest", FALSE), "File not installed\n");
+
+        r = MsiInstallProductA(msifile, "REMOVE=ALL");
+        ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+        delete_test_files();
+    }
+    else
+        ok(r == ERROR_INSTALL_FAILURE, "Expected ERROR_INSTALL_FAILURE, got %u\n", r);
+}
+
+static char session_manager[] = "System\\CurrentControlSet\\Control\\Session Manager";
+static char rename_ops[]      = "PendingFileRenameOperations";
+
+static void process_pending_renames(HKEY hkey)
+{
+    char *buf, *src, *dst, *buf2, *buf2ptr;
+    DWORD size, buf2len = 0;
+    LONG ret;
+    BOOL found = FALSE;
+
+    ret = RegQueryValueExA(hkey, rename_ops, NULL, NULL, NULL, &size);
+    buf = HeapAlloc(GetProcessHeap(), 0, size);
+    buf2ptr = buf2 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
+    buf[0] = 0;
+
+    ret = RegQueryValueExA(hkey, rename_ops, NULL, NULL, (LPBYTE)buf, &size);
+    ok(!ret, "RegQueryValueExA failed %d (%u)\n", ret, GetLastError());
+
+    for (src = buf; *src; src = dst + strlen(dst) + 1)
+    {
+        DWORD flags = MOVEFILE_COPY_ALLOWED;
+
+        dst = src + strlen(src) + 1;
+
+        if (!strstr(src, "msitest"))
+        {
+            lstrcpyA(buf2ptr, src);
+            buf2len += strlen(src) + 1;
+            buf2ptr += strlen(src) + 1;
+            if (*dst)
+            {
+                lstrcpyA(buf2ptr, dst);
+                buf2ptr += strlen(dst) + 1;
+                buf2len += strlen(dst) + 1;
+            }
+            buf2ptr++;
+            buf2len++;
+            continue;
+        }
+
+        found = TRUE;
+
+        if (*dst == '!')
+        {
+            flags |= MOVEFILE_REPLACE_EXISTING;
+            dst++;
+        }
+        if (src[0] == '\\' && src[1] == '?' && src[2] == '?' && src[3] == '\\') src += 4;
+        if (*dst)
+        {
+            if (dst[0] == '\\' && dst[1] == '?' && dst[2] == '?' && dst[3] == '\\') dst += 4;
+            ok(MoveFileExA(src, dst, flags), "Failed to move file %s -> %s (%u)\n", src, dst, GetLastError());
+        }
+        else
+            ok(DeleteFileA(src), "Failed to delete file %s (%u)\n", src, GetLastError());
+    }
+
+    ok(found, "Expected a 'msitest' entry\n");
+
+    if (*buf2)
+    {
+        buf2len++;
+        RegSetValueExA(hkey, rename_ops, 0, REG_MULTI_SZ, (LPBYTE)buf2, buf2len);
+    }
+    else
+        RegDeleteValueA(hkey, rename_ops);
+
+    HeapFree(GetProcessHeap(), 0, buf);
+    HeapFree(GetProcessHeap(), 0, buf2);
+}
+
+static BOOL file_matches_data(LPCSTR file, LPCSTR data)
+{
+    DWORD len, data_len = strlen(data);
+    HANDLE handle;
+    char buf[128];
+
+    handle = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+    ok(handle != INVALID_HANDLE_VALUE, "failed to open %s (%u)\n", file, GetLastError());
+
+    if (ReadFile(handle, buf, sizeof(buf), &len, NULL) && len >= data_len)
+    {
+        CloseHandle(handle);
+        return !memcmp(buf, data, data_len);
+    }
+    CloseHandle(handle);
+    return FALSE;
+}
+
+static void test_file_in_use(void)
+{
+    UINT r;
+    HANDLE file;
+    HKEY hkey;
+    char path[MAX_PATH];
+
+    if (on_win9x)
+    {
+        win_skip("Pending file renaming is implemented differently on Win9x and WinMe\n");
+        return;
+    }
+
+    RegOpenKeyExA(HKEY_LOCAL_MACHINE, session_manager, 0, KEY_ALL_ACCESS, &hkey);
+
+    CreateDirectoryA("msitest", NULL);
+    create_file("msitest\\maximus", 500);
+    create_database(msifile, fiu_tables, sizeof(fiu_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    lstrcpy(path, PROG_FILES_DIR);
+    lstrcat(path, "\\msitest");
+    CreateDirectoryA(path, NULL);
+
+    lstrcat(path, "\\maximus");
+    file = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
+
+    r = MsiInstallProductA(msifile, "REBOOT=ReallySuppress FULL=1");
+    ok(r == ERROR_SUCCESS_REBOOT_REQUIRED, "Expected ERROR_SUCCESS_REBOOT_REQUIRED got %u\n", r);
+    ok(!file_matches_data(path, "msitest\\maximus"), "Expected file not to match\n");
+    CloseHandle(file);
+    ok(!file_matches_data(path, "msitest\\maximus"), "Expected file not to match\n");
+
+    process_pending_renames(hkey);
+    RegCloseKey(hkey);
+
+    ok(file_matches_data(path, "msitest\\maximus"), "Expected file to match\n");
+    ok(delete_pf("msitest\\maximus", TRUE), "File not present\n");
+    ok(delete_pf("msitest", FALSE), "Directory not present or not empty\n");
+
+    r = MsiInstallProductA(msifile, "REMOVE=ALL");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    delete_test_files();
+}
+
+static void test_file_in_use_cab(void)
+{
+    UINT r;
+    HANDLE file;
+    HKEY hkey;
+    char path[MAX_PATH];
+
+    if (on_win9x)
+    {
+        win_skip("Pending file renaming is implemented differently on Win9x and WinMe\n");
+        return;
+    }
+
+    RegOpenKeyExA(HKEY_LOCAL_MACHINE, session_manager, 0, KEY_ALL_ACCESS, &hkey);
+
+    CreateDirectoryA("msitest", NULL);
+    create_file("maximus", 500);
+    create_cab_file("test1.cab", MEDIA_SIZE, "maximus\0");
+    DeleteFile("maximus");
+
+    create_database(msifile, fiuc_tables, sizeof(fiuc_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    lstrcpy(path, PROG_FILES_DIR);
+    lstrcat(path, "\\msitest");
+    CreateDirectoryA(path, NULL);
+
+    lstrcat(path, "\\maximus");
+    file = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
+
+    r = MsiInstallProductA(msifile, "REBOOT=ReallySuppress FULL=1");
+    ok(r == ERROR_SUCCESS_REBOOT_REQUIRED, "Expected ERROR_SUCCESS_REBOOT_REQUIRED got %u\n", r);
+    ok(!file_matches_data(path, "maximus"), "Expected file not to match\n");
+    CloseHandle(file);
+    ok(!file_matches_data(path, "maximus"), "Expected file not to match\n");
+
+    process_pending_renames(hkey);
+    RegCloseKey(hkey);
+
+    ok(file_matches_data(path, "maximus"), "Expected file to match\n");
+    ok(delete_pf("msitest\\maximus", TRUE), "File not present\n");
+    ok(delete_pf("msitest", FALSE), "Directory not present or not empty\n");
+
+    r = MsiInstallProductA(msifile, "REMOVE=ALL");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    delete_cab_files();
+    delete_test_files();
+}
+
+static INT CALLBACK handler_a(LPVOID context, UINT type, LPCSTR msg)
+{
+    return IDOK;
+}
+
+static INT CALLBACK handler_w(LPVOID context, UINT type, LPCWSTR msg)
+{
+    return IDOK;
+}
+
+static INT CALLBACK handler_record(LPVOID context, UINT type, MSIHANDLE record)
+{
+    return IDOK;
+}
+
+static void test_MsiSetExternalUI(void)
+{
+    INSTALLUI_HANDLERA ret_a;
+    INSTALLUI_HANDLERW ret_w;
+    INSTALLUI_HANDLER_RECORD prev;
+    UINT error;
+
+    ret_a = MsiSetExternalUIA(handler_a, INSTALLLOGMODE_ERROR, NULL);
+    ok(ret_a == NULL, "expected NULL, got %p\n", ret_a);
+
+    ret_a = MsiSetExternalUIA(NULL, 0, NULL);
+    ok(ret_a == handler_a, "expected %p, got %p\n", handler_a, ret_a);
+
+    /* Not present before Installer 3.1 */
+    if (!pMsiSetExternalUIRecord) {
+        win_skip("MsiSetExternalUIRecord is not available\n");
+        return;
+    }
+
+    error = pMsiSetExternalUIRecord(handler_record, INSTALLLOGMODE_ERROR, NULL, &prev);
+    ok(!error, "MsiSetExternalUIRecord failed %u\n", error);
+    ok(prev == NULL, "expected NULL, got %p\n", prev);
+
+    prev = (INSTALLUI_HANDLER_RECORD)0xdeadbeef;
+    error = pMsiSetExternalUIRecord(NULL, INSTALLLOGMODE_ERROR, NULL, &prev);
+    ok(!error, "MsiSetExternalUIRecord failed %u\n", error);
+    ok(prev == handler_record, "expected %p, got %p\n", handler_record, prev);
+
+    ret_w = MsiSetExternalUIW(handler_w, INSTALLLOGMODE_ERROR, NULL);
+    ok(ret_w == NULL, "expected NULL, got %p\n", ret_w);
+
+    ret_w = MsiSetExternalUIW(NULL, 0, NULL);
+    ok(ret_w == handler_w, "expected %p, got %p\n", handler_w, ret_w);
+
+    ret_a = MsiSetExternalUIA(handler_a, INSTALLLOGMODE_ERROR, NULL);
+    ok(ret_a == NULL, "expected NULL, got %p\n", ret_a);
+
+    ret_w = MsiSetExternalUIW(handler_w, INSTALLLOGMODE_ERROR, NULL);
+    ok(ret_w == NULL, "expected NULL, got %p\n", ret_w);
+
+    prev = (INSTALLUI_HANDLER_RECORD)0xdeadbeef;
+    error = pMsiSetExternalUIRecord(handler_record, INSTALLLOGMODE_ERROR, NULL, &prev);
+    ok(!error, "MsiSetExternalUIRecord failed %u\n", error);
+    ok(prev == NULL, "expected NULL, got %p\n", prev);
+
+    ret_a = MsiSetExternalUIA(NULL, 0, NULL);
+    ok(ret_a == NULL, "expected NULL, got %p\n", ret_a);
+
+    ret_w = MsiSetExternalUIW(NULL, 0, NULL);
+    ok(ret_w == NULL, "expected NULL, got %p\n", ret_w);
+
+    prev = (INSTALLUI_HANDLER_RECORD)0xdeadbeef;
+    error = pMsiSetExternalUIRecord(NULL, 0, NULL, &prev);
+    ok(!error, "MsiSetExternalUIRecord failed %u\n", error);
+    ok(prev == handler_record, "expected %p, got %p\n", handler_record, prev);
+
+    error = pMsiSetExternalUIRecord(handler_record, INSTALLLOGMODE_ERROR, NULL, NULL);
+    ok(!error, "MsiSetExternalUIRecord failed %u\n", error);
+
+    error = pMsiSetExternalUIRecord(NULL, 0, NULL, NULL);
+    ok(!error, "MsiSetExternalUIRecord failed %u\n", error);
+}
+
+static void test_feature_override(void)
+{
+    UINT r;
+
+    create_test_files();
+    create_database(msifile, tables, sizeof(tables) / sizeof(msi_table));
+
+    r = MsiInstallProductA(msifile, "ADDLOCAL=One");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ok(!delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\cabout\\new", FALSE), "File installed\n");
+    ok(!delete_pf("msitest\\cabout\\four.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\cabout", FALSE), "File installed\n");
+    ok(!delete_pf("msitest\\changed\\three.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\changed", FALSE), "File installed\n");
+    ok(!delete_pf("msitest\\first\\two.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\first", FALSE), "File installed\n");
+    ok(!delete_pf("msitest\\filename", TRUE), "File installed\n");
+    ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
+    ok(!delete_pf("msitest\\service.exe", TRUE), "File installed\n");
+    ok(delete_pf("msitest", FALSE), "File not installed\n");
+
+    delete_test_files();
+}
+
+static void test_create_folder(void)
+{
+    UINT r;
+
+    create_test_files();
+    create_database(msifile, cf_tables, sizeof(cf_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_INSTALL_FAILURE, "Expected ERROR_INSTALL_FAILURE, got %u\n", r);
+
+    ok(!delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\cabout\\new", FALSE), "Directory created\n");
+    ok(!delete_pf("msitest\\cabout\\four.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\cabout", FALSE), "Directory created\n");
+    ok(!delete_pf("msitest\\changed\\three.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\changed", FALSE), "Directory created\n");
+    ok(!delete_pf("msitest\\first\\two.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\first", FALSE), "Directory created\n");
+    ok(!delete_pf("msitest\\filename", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\one.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\service.exe", TRUE), "File installed\n");
+    ok(!delete_pf("msitest", FALSE), "Directory created\n");
+
+    r = MsiInstallProductA(msifile, "LOCAL=Two");
+    ok(r == ERROR_INSTALL_FAILURE, "Expected ERROR_INSTALL_FAILURE, got %u\n", r);
+
+    ok(!delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\cabout\\new", FALSE), "Directory created\n");
+    ok(!delete_pf("msitest\\cabout\\four.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\cabout", FALSE), "Directory created\n");
+    ok(!delete_pf("msitest\\changed\\three.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\changed", FALSE), "Directory created\n");
+    ok(!delete_pf("msitest\\first\\two.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\first", FALSE), "Directory created\n");
+    ok(!delete_pf("msitest\\filename", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\one.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\service.exe", TRUE), "File installed\n");
+    ok(!delete_pf("msitest", FALSE), "Directory created\n");
+
+    delete_test_files();
+}
+
+static void test_remove_folder(void)
+{
+    UINT r;
+
+    create_test_files();
+    create_database(msifile, rf_tables, sizeof(rf_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_INSTALL_FAILURE, "Expected ERROR_INSTALL_FAILURE, got %u\n", r);
+
+    ok(!delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\cabout\\new", FALSE), "Directory created\n");
+    ok(!delete_pf("msitest\\cabout\\four.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\cabout", FALSE), "Directory created\n");
+    ok(!delete_pf("msitest\\changed\\three.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\changed", FALSE), "Directory created\n");
+    ok(!delete_pf("msitest\\first\\two.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\first", FALSE), "Directory created\n");
+    ok(!delete_pf("msitest\\filename", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\one.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\service.exe", TRUE), "File installed\n");
+    ok(!delete_pf("msitest", FALSE), "Directory created\n");
+
+    r = MsiInstallProductA(msifile, "LOCAL=Two");
+    ok(r == ERROR_INSTALL_FAILURE, "Expected ERROR_INSTALL_FAILURE, got %u\n", r);
+
+    ok(!delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\cabout\\new", FALSE), "Directory created\n");
+    ok(!delete_pf("msitest\\cabout\\four.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\cabout", FALSE), "Directory created\n");
+    ok(!delete_pf("msitest\\changed\\three.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\changed", FALSE), "Directory created\n");
+    ok(!delete_pf("msitest\\first\\two.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\first", FALSE), "Directory created\n");
+    ok(!delete_pf("msitest\\filename", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\one.txt", TRUE), "File installed\n");
+    ok(!delete_pf("msitest\\service.exe", TRUE), "File installed\n");
+    ok(!delete_pf("msitest", FALSE), "Directory created\n");
+
+    delete_test_files();
+}
+
+static void test_start_services(void)
+{
+    UINT r;
+    SC_HANDLE scm, service;
+    BOOL ret;
+    DWORD error = ERROR_SUCCESS;
+
+    if (on_win9x)
+    {
+        win_skip("Services are not implemented on Win9x and WinMe\n");
+        return;
+    }
+    scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+    ok(scm != NULL, "Failed to open the SC Manager\n");
+    if (!scm) return;
+
+    service = OpenService(scm, "Spooler", SC_MANAGER_ALL_ACCESS);
+    if (!service && GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST)
+    {
+        win_skip("The 'Spooler' service does not exist\n");
+        CloseServiceHandle(scm);
+        return;
+    }
+    ok(service != NULL, "Failed to open Spooler, error %d\n", GetLastError());
+    if (!service) {
+        CloseServiceHandle(scm);
+        return;
+    }
+
+    ret = StartService(service, 0, NULL);
+    if (!ret && (error = GetLastError()) != ERROR_SERVICE_ALREADY_RUNNING)
+    {
+        skip("Terminal service not available, skipping test\n");
+        CloseServiceHandle(service);
+        CloseServiceHandle(scm);
+        return;
+    }
+
+    CloseServiceHandle(service);
+    CloseServiceHandle(scm);
+
+    create_test_files();
+    create_database(msifile, sss_tables, sizeof(sss_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\new", FALSE), "Directory not created\n");
+    ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout", FALSE), "Directory not created\n");
+    ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\changed", FALSE), "Directory not created\n");
+    ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\first", FALSE), "Directory not created\n");
+    ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
+    ok(delete_pf("msitest", FALSE), "Directory not created\n");
+
+    delete_test_files();
+
+    if (error == ERROR_SUCCESS)
+    {
+        SERVICE_STATUS status;
+
+        scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+        service = OpenService(scm, "Spooler", SC_MANAGER_ALL_ACCESS);
+
+        ret = ControlService(service, SERVICE_CONTROL_STOP, &status);
+        ok(ret, "ControlService failed %u\n", GetLastError());
+
+        CloseServiceHandle(service);
+        CloseServiceHandle(scm);
+    }
+}
+
+static void test_delete_services(void)
+{
+    UINT r;
+
+    create_test_files();
+    create_database(msifile, sds_tables, sizeof(sds_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\new", FALSE), "Directory not created\n");
+    ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout", FALSE), "Directory not created\n");
+    ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\changed", FALSE), "Directory not created\n");
+    ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\first", FALSE), "Directory not created\n");
+    ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
+    ok(delete_pf("msitest", FALSE), "Directory not created\n");
+
+    delete_test_files();
+}
+
+static void test_self_registration(void)
+{
+    UINT r;
+
+    create_test_files();
+    create_database(msifile, sr_tables, sizeof(sr_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\new", FALSE), "Directory not created\n");
+    ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout", FALSE), "Directory not created\n");
+    ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\changed", FALSE), "Directory not created\n");
+    ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\first", FALSE), "Directory not created\n");
+    ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
+    ok(delete_pf("msitest", FALSE), "Directory not created\n");
+
+    delete_test_files();
+}
+
+static void test_register_font(void)
+{
+    static const char regfont1[] = "Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";
+    static const char regfont2[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Fonts";
+    LONG ret;
+    HKEY key;
+    UINT r;
+
+    create_test_files();
+    create_file("msitest\\font.ttf", 1000);
+    create_database(msifile, font_tables, sizeof(font_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, regfont1, &key);
+    if (ret)
+        RegOpenKeyA(HKEY_LOCAL_MACHINE, regfont2, &key);
+
+    ret = RegQueryValueExA(key, "msi test font", NULL, NULL, NULL, NULL);
+    ok(ret != ERROR_FILE_NOT_FOUND, "unexpected result %d\n", ret);
+
+    r = MsiInstallProductA(msifile, "REMOVE=ALL");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    todo_wine ok(!delete_pf("msitest", FALSE), "directory not removed\n");
+
+    ret = RegQueryValueExA(key, "msi test font", NULL, NULL, NULL, NULL);
+    ok(ret == ERROR_FILE_NOT_FOUND, "unexpected result %d\n", ret);
+
+    RegDeleteValueA(key, "msi test font");
+    RegCloseKey(key);
+    delete_test_files();
+}
+
+static void test_validate_product_id(void)
+{
+    UINT r;
+
+    create_test_files();
+    create_database(msifile, vp_tables, sizeof(vp_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    r = MsiInstallProductA(msifile, "SET_PRODUCT_ID=1");
+    ok(r == ERROR_INSTALL_FAILURE, "Expected ERROR_INSTALL_FAILURE, got %u\n", r);
+
+    r = MsiInstallProductA(msifile, "SET_PRODUCT_ID=2");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    r = MsiInstallProductA(msifile, "PIDKEY=123-1234567");
+    ok(r == ERROR_INSTALL_FAILURE, "Expected ERROR_INSTALL_FAILURE, got %u\n", r);
+
+    ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout\\new", FALSE), "Directory not created\n");
+    ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\cabout", FALSE), "Directory not created\n");
+    ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\changed", FALSE), "Directory not created\n");
+    ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\first", FALSE), "Directory not created\n");
+    ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
+    ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
+    ok(delete_pf("msitest", FALSE), "Directory not created\n");
+
+    delete_test_files();
+}
+
+static void test_install_remove_odbc(void)
+{
+    UINT r;
+
+    create_test_files();
+    create_file("msitest\\ODBCdriver.dll", 1000);
+    create_file("msitest\\ODBCdriver2.dll", 1000);
+    create_file("msitest\\ODBCtranslator.dll", 1000);
+    create_file("msitest\\ODBCtranslator2.dll", 1000);
+    create_file("msitest\\ODBCsetup.dll", 1000);
+    create_database(msifile, odbc_tables, sizeof(odbc_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ok(delete_pf("msitest\\ODBCdriver.dll", TRUE), "file not created\n");
+    ok(delete_pf("msitest\\ODBCdriver2.dll", TRUE), "file not created\n");
+    ok(delete_pf("msitest\\ODBCtranslator.dll", TRUE), "file not created\n");
+    ok(delete_pf("msitest\\ODBCtranslator2.dll", TRUE), "file not created\n");
+    ok(delete_pf("msitest\\ODBCsetup.dll", TRUE), "file not created\n");
+    ok(delete_pf("msitest", FALSE), "directory not created\n");
+
+    delete_test_files();
+}
+
+static void test_register_typelib(void)
+{
+    UINT r;
+
+    create_test_files();
+    create_file("msitest\\typelib.dll", 1000);
+    create_database(msifile, tl_tables, sizeof(tl_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    r = MsiInstallProductA(msifile, "REGISTER_TYPELIB=1");
+    ok(r == ERROR_INSTALL_FAILURE, "Expected ERROR_INSTALL_FAILURE, got %u\n", r);
+
+    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\\typelib.dll", TRUE), "file not removed\n");
+    todo_wine ok(!delete_pf("msitest", FALSE), "directory not removed\n");
+
+    delete_test_files();
+}
+
+static void test_create_remove_shortcut(void)
+{
+    UINT r;
+
+    create_test_files();
+    create_file("msitest\\target.txt", 1000);
+    create_database(msifile, crs_tables, sizeof(crs_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ok(pf_exists("msitest\\target.txt"), "file not created\n");
+    ok(pf_exists("msitest\\shortcut.lnk"), "file not created\n");
+
+    r = MsiInstallProductA(msifile, "REMOVE=ALL");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    ok(!delete_pf("msitest\\shortcut.lnk", TRUE), "file not removed\n");
+    ok(!delete_pf("msitest\\target.txt", TRUE), "file not removed\n");
+    todo_wine ok(!delete_pf("msitest", FALSE), "directory not removed\n");
+
+    delete_test_files();
+}
+
+static void test_publish_components(void)
+{
+    static char keypath[] =
+        "Software\\Microsoft\\Installer\\Components\\0CBCFA296AC907244845745CEEB2F8AA";
+
+    UINT r;
+    LONG res;
+    HKEY key;
+
+    create_test_files();
+    create_file("msitest\\english.txt", 1000);
+    create_database(msifile, pub_tables, sizeof(pub_tables) / sizeof(msi_table));
+
+    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+    r = MsiInstallProductA(msifile, NULL);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    res = RegOpenKeyA(HKEY_CURRENT_USER, keypath, &key);
+    ok(res == ERROR_SUCCESS, "components key not created %d\n", res);
+
+    res = RegQueryValueExA(key, "english.txt", NULL, NULL, NULL, NULL);
+    ok(res == ERROR_SUCCESS, "value not found %d\n", res);
+    RegCloseKey(key);
+
+    r = MsiInstallProductA(msifile, "REMOVE=ALL");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+    res = RegOpenKeyA(HKEY_CURRENT_USER, keypath, &key);
+    ok(res == ERROR_FILE_NOT_FOUND, "unexpected result %d\n", res);
+
+    ok(!delete_pf("msitest\\english.txt", TRUE), "file not removed\n");
+    todo_wine ok(!delete_pf("msitest", FALSE), "directory not removed\n");
+    delete_test_files();
+}
+
+START_TEST(install)
+{
+    DWORD len;
+    char temp_path[MAX_PATH], prev_path[MAX_PATH], log_file[MAX_PATH];
+    STATEMGRSTATUS status;
+    BOOL ret = FALSE;
+
+    init_functionpointers();
+
+    on_win9x = check_win9x();
+
+    GetCurrentDirectoryA(MAX_PATH, prev_path);
+    GetTempPath(MAX_PATH, temp_path);
+    SetCurrentDirectoryA(temp_path);
+
+    lstrcpyA(CURR_DIR, temp_path);
+    len = lstrlenA(CURR_DIR);
+
+    if(len && (CURR_DIR[len - 1] == '\\'))
+        CURR_DIR[len - 1] = 0;
+
+    get_program_files_dir(PROG_FILES_DIR, COMMON_FILES_DIR);
+
+    /* Create a restore point ourselves so we circumvent the multitude of restore points
+     * that would have been created by all the installation and removal tests.
+     */
+    if (pSRSetRestorePointA)
+    {
+        memset(&status, 0, sizeof(status));
+        ret = notify_system_change(BEGIN_NESTED_SYSTEM_CHANGE, &status);
+    }
+
+    /* Create only one log file and don't append. We have to pass something
+     * for the log mode for this to work. The logfile needs to have an absolute
+     * path otherwise we still end up with some extra logfiles as some tests
+     * change the current directory.
+     */
+    lstrcpyA(log_file, temp_path);
+    lstrcatA(log_file, "\\msitest.log");
+    MsiEnableLogA(INSTALLLOGMODE_FATALEXIT, log_file, 0);
+
+    test_MsiInstallProduct();
+    test_MsiSetComponentState();
+    test_packagecoltypes();
+    test_continuouscabs();
+    test_caborder();
+    test_mixedmedia();
+    test_samesequence();
+    test_uiLevelFlags();
+    test_readonlyfile();
+    test_readonlyfile_cab();
+    test_setdirproperty();
+    test_cabisextracted();
+    test_concurrentinstall();
+    test_setpropertyfolder();
+    test_publish_registerproduct();
+    test_publish_publishproduct();
+    test_publish_publishfeatures();
+    test_publish_registeruser();
+    test_publish_processcomponents();
+    test_publish();
+    test_publishsourcelist();
+    test_transformprop();
+    test_currentworkingdir();
+    test_admin();
+    test_adminprops();
+    test_removefiles();
+    test_movefiles();
+    test_missingcab();
+    test_duplicatefiles();
+    test_writeregistryvalues();
+    test_sourcefolder();
+    test_customaction51();
+    test_installstate();
+    test_sourcepath();
+    test_MsiConfigureProductEx();
+    test_missingcomponent();
+    test_sourcedirprop();
+    test_adminimage();
+    test_propcase();
+    test_int_widths();
+    test_shortcut();
+    test_envvar();
+    test_lastusedsource();
+    test_preselected();
+    test_installed_prop();
+    test_file_in_use();
+    test_file_in_use_cab();
+    test_MsiSetExternalUI();
+    test_allusers_prop();
+    test_feature_override();
+    test_create_folder();
+    test_remove_folder();
+    test_start_services();
+    test_delete_services();
+    test_self_registration();
+    test_register_font();
+    test_validate_product_id();
+    test_install_remove_odbc();
+    test_register_typelib();
+    test_create_remove_shortcut();
+    test_publish_components();
+
+    DeleteFileA(log_file);
+
+    if (pSRSetRestorePointA && ret)
+    {
+        ret = notify_system_change(END_NESTED_SYSTEM_CHANGE, &status);
+        if (ret)
+            remove_restore_point(status.llSequenceNumber);
+    }
+    FreeLibrary(hsrclient);
 
     SetCurrentDirectoryA(prev_path);
 }