Sync to Wine-20050725:
Robert Shearman <rob@codeweavers.com>
- In MsiLocateComponent pcchBuf can be NULL so don't try to dereference
  it.
Alexandre Julliard <julliard@winehq.org>
- Use the official names for the Unicode string constants.
Aric Stewart <aric@codeweavers.com>
- Implement MsiGetLanguage.
- Relocate the msi file to prevent cd locking, corrected to properly not
  try to relocated #nnnn handles as files.
- Use the SourceList functions to get the source path in
  ConfigureProductExW.
- Handle installs off multiple volumes and properly pull the prompt
  string from the error table.
- If MsiGetProperty(A/W) is called with a NULL for the value buffer but
  a value in the size for the value buffer, then Msi fills in the size
  of the value into the pointer for size.  This is tested and confirmed
  with native MSI.
- Bail out if the reg key is empty. This prevents us from writing
  garbage to the property table.
- Properly resize the buffer based on ERROR_MORE_DATA.
  Also remember to free the allocated buffer.
- Further testing shows that when CustomActionData needs to be blank it
  is an empty string not ' '.
- Correct an error where I was not properly advancing a pointer.
- Add source.c to start handling the various MsiSourceList apis used in
  v3 of MSI, and now internally.
- Update files.c to use the MsiSourceList apis to make sure our
  SourceList keys in the registry are included and correct.
- Use the strings defined in msi.h.
- Use SOURCEDIR instead of PackagePath. Because the PackagePath may be
  local, while SOURCEDIR is more proper and will be a full directory.
- InstallShield does a number of actions using DoAction before the
  Install starts so the PackageCode needs to be loaded on OpenPackage
  instead of the beginning of the install process.
- When working toward install on demand support we need to reset all the
  constant values so that multiple install process do not get confused
  by leftover values from the previous install.
- Fill and use the ProductCode part of the MSIPACKAGE structure.
- Add the string constants located in msi.h and make use of them in
  files.c and source.c.
- Keep track of what sequence we are in and register unique
  actions. This allows us to make sure actions and custom actions
  flagged to run only once, actually run only once.
- Also clean up some of the numeric constants in custom.c using the
  defined values from msidefs.h.
Mike McCormack <mike@codeweavers.com>
- gcc 4.0 -Wpointer-sign fixes.
- Display icons in buttons that have them.
- Use LoadImage to load bitmaps and icons.
- Set the initial focus on the control specified by Control_First in the
  Dialog table.
- Move to the next mask edit field when the current one becomes full.
- Make the tab order in msi dialogs right.
- Don't crash when cancelling out of a modeless dialog.
- Stop the install when cancelling from a modeless dialog.
Modified: trunk/reactos/lib/msi/Makefile.in
Modified: trunk/reactos/lib/msi/action.c
Modified: trunk/reactos/lib/msi/action.h
Modified: trunk/reactos/lib/msi/appsearch.c
Modified: trunk/reactos/lib/msi/custom.c
Modified: trunk/reactos/lib/msi/dialog.c
Modified: trunk/reactos/lib/msi/events.c
Modified: trunk/reactos/lib/msi/files.c
Modified: trunk/reactos/lib/msi/helpers.c
Modified: trunk/reactos/lib/msi/install.c
Modified: trunk/reactos/lib/msi/msi.c
Modified: trunk/reactos/lib/msi/msi.spec
Modified: trunk/reactos/lib/msi/msi.xml
Modified: trunk/reactos/lib/msi/msipriv.h
Modified: trunk/reactos/lib/msi/package.c
Modified: trunk/reactos/lib/msi/registry.c
Added: trunk/reactos/lib/msi/source.c
Modified: trunk/reactos/lib/msi/string.c
Modified: trunk/reactos/lib/msi/suminfo.c
Modified: trunk/reactos/lib/msi/upgrade.c
Modified: trunk/reactos/w32api/include/msi.h

Modified: trunk/reactos/lib/msi/Makefile.in
--- trunk/reactos/lib/msi/Makefile.in	2005-08-12 16:59:41 UTC (rev 17330)
+++ trunk/reactos/lib/msi/Makefile.in	2005-08-12 17:07:28 UTC (rev 17331)
@@ -33,6 +33,7 @@
 	registry.c \
 	regsvr.c \
 	select.c \
+	source.c \
 	string.c \
 	suminfo.c \
 	table.c \

Modified: trunk/reactos/lib/msi/action.c
--- trunk/reactos/lib/msi/action.c	2005-08-12 16:59:41 UTC (rev 17330)
+++ trunk/reactos/lib/msi/action.c	2005-08-12 17:07:28 UTC (rev 17331)
@@ -432,7 +432,7 @@
  *****************************************************/
 
 UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath,
-                              LPCWSTR szCommandLine)
+                              LPCWSTR szCommandLine, LPCWSTR msiFilePath)
 {
     DWORD sz;
     WCHAR buffer[10];
@@ -447,6 +447,10 @@
     package->script = HeapAlloc(GetProcessHeap(),0,sizeof(MSISCRIPT));
     memset(package->script,0,sizeof(MSISCRIPT));
 
+    package->script->InWhatSequence = SEQUENCE_INSTALL;
+
+    package->msiFilePath= strdupW(msiFilePath);
+
     if (szPackagePath)   
     {
         LPWSTR p, check, path;
@@ -538,10 +542,14 @@
     {
         if (atoiW(buffer) >= INSTALLUILEVEL_REDUCED)
         {
+            package->script->InWhatSequence |= SEQUENCE_UI;
             rc = ACTION_ProcessUISequence(package);
             ui = TRUE;
             if (rc == ERROR_SUCCESS)
+            {
+                package->script->InWhatSequence |= SEQUENCE_EXEC;
                 rc = ACTION_ProcessExecSequence(package,TRUE);
+            }
         }
         else
             rc = ACTION_ProcessExecSequence(package,FALSE);
@@ -666,6 +674,11 @@
     else
         rc = ACTION_PerformAction(iap->package,action,FALSE);
 
+    msi_dialog_check_messages( NULL );
+
+    if (iap->package->CurrentInstallState != ERROR_SUCCESS )
+        rc = iap->package->CurrentInstallState;
+
     if (rc == ERROR_FUNCTION_NOT_CALLED)
         rc = ERROR_SUCCESS;
 
@@ -814,18 +827,6 @@
     return ret;
 }
 
-static BOOL ACTION_HandleDialogBox( MSIPACKAGE *package, LPCWSTR dialog, UINT* rc )
-{
-    BOOL ret = FALSE;
-
-    if (ACTION_DialogBox(package,dialog) == ERROR_SUCCESS)
-    {
-        *rc = package->CurrentInstallState;
-        ret = TRUE;
-    }
-    return ret;
-}
-
 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
                                        UINT* rc, BOOL force )
 {
@@ -868,7 +869,6 @@
         rc = ERROR_FUNCTION_NOT_CALLED;
     }
 
-    package->CurrentInstallState = rc;
     return rc;
 }
 
@@ -884,18 +884,15 @@
     if (!handled)
         handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
 
-    if (!handled)
-        handled = ACTION_HandleDialogBox(package, action, &rc);
+    if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
+        handled = TRUE;
 
-    msi_dialog_check_messages( NULL );
-
     if (!handled)
     {
         FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action));
         rc = ERROR_FUNCTION_NOT_CALLED;
     }
 
-    package->CurrentInstallState = rc;
     return rc;
 }
 
@@ -1371,9 +1368,6 @@
     if (targetdir[0] == '.' && targetdir[1] == 0)
         targetdir = NULL;
         
-    if (srcdir && srcdir[0] == '.' && srcdir[1] == 0)
-        srcdir = NULL;
-
     if (targetdir)
     {
         TRACE("   TargetDefault = %s\n",debugstr_w(targetdir));
@@ -1414,14 +1408,11 @@
 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
 {
     int i;
-    LPWSTR productcode;
 
-    productcode = load_dynamic_property(package,szProductCode,NULL);
-
     for (i = 0; i < package->loaded_components; i++)
     {
         INSTALLSTATE res;
-        res = MsiGetComponentPathW(productcode, 
+        res = MsiGetComponentPathW(package->ProductCode, 
                         package->components[i].ComponentId , NULL, NULL);
         if (res < 0)
             res = INSTALLSTATE_ABSENT;
@@ -2127,7 +2118,7 @@
     {
         TRACE("Setting value %s of %s\n",debugstr_w(deformated),
                         debugstr_w(uikey));
-        RegSetValueExW(hkey, deformated, 0, type, value_data, size);
+        RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
     }
     else
     {
@@ -2143,7 +2134,7 @@
             TRACE("Checked and setting value %s of %s\n",
                             debugstr_w(deformated), debugstr_w(uikey));
             if (deformated || size)
-                RegSetValueExW(hkey, deformated, 0, type, value_data, size);
+                RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
         }
     }
     RegCloseKey(hkey);
@@ -2500,7 +2491,6 @@
  */
 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
 {
-    LPWSTR productcode;
     WCHAR squished_pc[GUID_SIZE];
     WCHAR squished_cc[GUID_SIZE];
     UINT rc;
@@ -2511,15 +2501,12 @@
         return ERROR_INVALID_HANDLE;
 
     /* writes the Component and Features values to the registry */
-    productcode = load_dynamic_property(package,szProductCode,&rc);
-    if (!productcode)
-        return rc;
 
     rc = MSIREG_OpenComponents(&hkey);
     if (rc != ERROR_SUCCESS)
         goto end;
       
-    squash_guid(productcode,squished_pc);
+    squash_guid(package->ProductCode,squished_pc);
     ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
     for (i = 0; i < package->loaded_components; i++)
     {
@@ -2555,7 +2542,7 @@
 
                 if (keypath)
                 {
-                    RegSetValueExW(hkey2,squished_pc,0,REG_SZ,(LPVOID)keypath,
+                    RegSetValueExW(hkey2,squished_pc,0,REG_SZ,(LPBYTE)keypath,
                                 (strlenW(keypath)+1)*sizeof(WCHAR));
 
                     if (package->components[i].Attributes & 
@@ -2567,7 +2554,7 @@
                               '0','0','0','0','0','0','0','0',0};
 
                         RegSetValueExW(hkey2,szPermKey,0,REG_SZ,
-                                        (LPVOID)keypath,
+                                        (LPBYTE)keypath,
                                         (strlenW(keypath)+1)*sizeof(WCHAR));
                     }
                     
@@ -2575,7 +2562,7 @@
         
                     /* UI stuff */
                     uirow = MSI_CreateRecord(3);
-                    MSI_RecordSetStringW(uirow,1,productcode);
+                    MSI_RecordSetStringW(uirow,1,package->ProductCode);
                     MSI_RecordSetStringW(uirow,2,package->components[i].
                                                             ComponentId);
                     MSI_RecordSetStringW(uirow,3,keypath);
@@ -2602,7 +2589,7 @@
         
                 /* UI stuff */
                 uirow = MSI_CreateRecord(2);
-                MSI_RecordSetStringW(uirow,1,productcode);
+                MSI_RecordSetStringW(uirow,1,package->ProductCode);
                 MSI_RecordSetStringW(uirow,2,package->components[i].
                                 ComponentId);
                 ui_actiondata(package,szProcessComponents,uirow);
@@ -2611,7 +2598,6 @@
         }
     } 
 end:
-    HeapFree(GetProcessHeap(), 0, productcode);
     RegCloseKey(hkey);
     return rc;
 }
@@ -3019,25 +3005,14 @@
         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
          '`','I','c','o','n','`',0};
     /* for registry stuff */
-    LPWSTR productcode;
     HKEY hkey=0;
     HKEY hukey=0;
-    static const WCHAR szProductName[] =
-        {'P','r','o','d','u','c','t','N','a','m','e',0};
-    static const WCHAR szPackageCode[] =
-        {'P','a','c','k','a','g','e','C','o','d','e',0};
-    static const WCHAR szLanguage[] =
-        {'L','a','n','g','u','a','g','e',0};
     static const WCHAR szProductLanguage[] =
         {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
-    static const WCHAR szProductIcon[] =
-        {'P','r','o','d','u','c','t','I','c','o','n',0};
     static const WCHAR szARPProductIcon[] =
         {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
     static const WCHAR szProductVersion[] =
         {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
-    static const WCHAR szVersion[] =
-        {'V','e','r','s','i','o','n',0};
     DWORD langid;
     LPWSTR buffer;
     DWORD size;
@@ -3057,28 +3032,26 @@
 
     /* ok there is a lot more done here but i need to figure out what */
 
-    productcode = load_dynamic_property(package,szProductCode,&rc);
-    if (!productcode)
-        return rc;
-
-    rc = MSIREG_OpenProductsKey(productcode,&hkey,TRUE);
+    rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
     if (rc != ERROR_SUCCESS)
         goto end;
 
-    rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE);
+    rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
     if (rc != ERROR_SUCCESS)
         goto end;
 
 
-    buffer = load_dynamic_property(package,szProductName,NULL);
+    buffer = load_dynamic_property(package,INSTALLPROPERTY_PRODUCTNAMEW,NULL);
     size = strlenW(buffer)*sizeof(WCHAR);
-    RegSetValueExW(hukey,szProductName,0,REG_SZ, (BYTE *)buffer,size);
+    RegSetValueExW(hukey,INSTALLPROPERTY_PRODUCTNAMEW,0,REG_SZ, 
+            (LPBYTE)buffer,size);
     HeapFree(GetProcessHeap(),0,buffer);
 
     buffer = load_dynamic_property(package,szProductLanguage,NULL);
     size = sizeof(DWORD);
     langid = atoiW(buffer);
-    RegSetValueExW(hukey,szLanguage,0,REG_DWORD, (BYTE *)&langid,size);
+    RegSetValueExW(hukey,INSTALLPROPERTY_LANGUAGEW,0,REG_DWORD, 
+            (LPBYTE)&langid,size);
     HeapFree(GetProcessHeap(),0,buffer);
 
     buffer = load_dynamic_property(package,szARPProductIcon,NULL);
@@ -3087,7 +3060,8 @@
         LPWSTR path;
         build_icon_path(package,buffer,&path);
         size = strlenW(path) * sizeof(WCHAR);
-        RegSetValueExW(hukey,szProductIcon,0,REG_SZ, (BYTE *)path,size);
+        RegSetValueExW(hukey,INSTALLPROPERTY_PRODUCTICONW,0,REG_SZ,
+                (LPBYTE)path,size);
     }
     HeapFree(GetProcessHeap(),0,buffer);
 
@@ -3096,7 +3070,8 @@
     {
         DWORD verdword = build_version_dword(buffer);
         size = sizeof(DWORD);
-        RegSetValueExW(hukey,szVersion,0,REG_DWORD, (BYTE *)&verdword,size);
+        RegSetValueExW(hukey,INSTALLPROPERTY_VERSIONW,0,REG_DWORD, (LPBYTE
+                    )&verdword,size);
     }
     HeapFree(GetProcessHeap(),0,buffer);
     
@@ -3119,8 +3094,8 @@
             if (ptr) *ptr = 0;
             squash_guid(guidbuffer,squashed);
             size = strlenW(squashed)*sizeof(WCHAR);
-            RegSetValueExW(hukey,szPackageCode,0,REG_SZ, (LPSTR)squashed,
-                           size);
+            RegSetValueExW(hukey,INSTALLPROPERTY_PACKAGECODEW,0,REG_SZ,
+                    (LPBYTE)squashed, size);
         }
         else
         {
@@ -3137,7 +3112,6 @@
 
 end:
 
-    HeapFree(GetProcessHeap(),0,productcode);    
     RegCloseKey(hkey);
     RegCloseKey(hukey);
 
@@ -3331,7 +3305,6 @@
 
 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
 {
-    LPWSTR productcode;
     UINT rc;
     DWORD i;
     HKEY hkey=0;
@@ -3340,15 +3313,11 @@
     if (!package)
         return ERROR_INVALID_HANDLE;
 
-    productcode = load_dynamic_property(package,szProductCode,&rc);
-    if (!productcode)
-        return rc;
-
-    rc = MSIREG_OpenFeaturesKey(productcode,&hkey,TRUE);
+    rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
     if (rc != ERROR_SUCCESS)
         goto end;
 
-    rc = MSIREG_OpenUserFeaturesKey(productcode,&hukey,TRUE);
+    rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
     if (rc != ERROR_SUCCESS)
         goto end;
 
@@ -3400,14 +3369,14 @@
 
         size = (strlenW(data)+1)*sizeof(WCHAR);
         RegSetValueExW(hkey,package->features[i].Feature,0,REG_SZ,
-                       (LPSTR)data,size);
+                       (LPBYTE)data,size);
         HeapFree(GetProcessHeap(),0,data);
 
         if (!absent)
         {
             size = strlenW(package->features[i].Feature_Parent)*sizeof(WCHAR);
             RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ,
-                       (LPSTR)package->features[i].Feature_Parent,size);
+                       (LPBYTE)package->features[i].Feature_Parent,size);
         }
         else
         {
@@ -3417,7 +3386,7 @@
             data[0] = 0x6;
             strcpyW(&data[1],package->features[i].Feature_Parent);
             RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ,
-                       (LPSTR)data,size);
+                       (LPBYTE)data,size);
             HeapFree(GetProcessHeap(),0,data);
         }
     }
@@ -3425,7 +3394,6 @@
 end:
     RegCloseKey(hkey);
     RegCloseKey(hukey);
-    HeapFree(GetProcessHeap(), 0, productcode);
     return rc;
 }
 
@@ -3433,7 +3401,6 @@
 {
     HKEY hkey=0;
     LPWSTR buffer = NULL;
-    LPWSTR productcode;
     UINT rc,i;
     DWORD size;
     static WCHAR szNONE[] = {0};
@@ -3484,8 +3451,6 @@
     '%','s','\\',
     'I','n','s','t','a','l','l','e','r','\\',
     '%','x','.','m','s','i',0};
-    static const WCHAR szLocalPackage[]=
-         {'L','o','c','a','l','P','a','c','k','a','g','e',0};
     static const WCHAR szUpgradeCode[] = 
         {'U','p','g','r','a','d','e','C','o','d','e',0};
     static const WCHAR modpath_fmt[] = 
@@ -3496,20 +3461,10 @@
         {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
     static const WCHAR szEstimatedSize[] = 
         {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
-    static const WCHAR szInstallDate[] = 
-        {'I','n','s','t','a','l','l','D','a','t','e',0};
-    static const WCHAR szLanguage[] =
-        {'L','a','n','g','u','a','g','e',0};
     static const WCHAR szProductLanguage[] =
         {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
     static const WCHAR szProductVersion[] =
         {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
-    static const WCHAR szVersion[] =
-        {'V','e','r','s','i','o','n',0};
-    static const WCHAR szVersionMajor[] =
-        {'V','e','r','s','i','o','n','M','a','j','o','r',0};
-    static const WCHAR szVersionMinor[] =
-        {'V','e','r','s','i','o','n','M','i','n','o','r',0};
 
     SYSTEMTIME systime;
     static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
@@ -3520,11 +3475,7 @@
     if (!package)
         return ERROR_INVALID_HANDLE;
 
-    productcode = load_dynamic_property(package,szProductCode,&rc);
-    if (!productcode)
-        return rc;
-
-    rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE);
+    rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
     if (rc != ERROR_SUCCESS)
         goto end;
 
@@ -3538,14 +3489,14 @@
         if (rc != ERROR_SUCCESS)
             buffer = szNONE;
         size = strlenW(buffer)*sizeof(WCHAR);
-        RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size);
+        RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPBYTE)buffer,size);
         HeapFree(GetProcessHeap(),0,buffer);
         i++;
     }
 
     rc = 0x1;
     size = sizeof(rc);
-    RegSetValueExW(hkey,szWindowsInstaler,0,REG_DWORD,(LPSTR)&rc,size);
+    RegSetValueExW(hkey,szWindowsInstaler,0,REG_DWORD,(LPBYTE)&rc,size);
     
     /* copy the package locally */
     num = GetTickCount() & 0xffff;
@@ -3574,34 +3525,37 @@
     snprintfW(path,sizeof(path)/sizeof(path[0]),installerPathFmt,windir);
     create_full_pathW(path);
     TRACE("Copying to local package %s\n",debugstr_w(packagefile));
-    if (!CopyFileW(package->PackagePath,packagefile,FALSE))
+    if (!CopyFileW(package->msiFilePath,packagefile,FALSE))
         ERR("Unable to copy package (%s -> %s) (error %ld)\n",
-            debugstr_w(package->PackagePath), debugstr_w(packagefile),
+            debugstr_w(package->msiFilePath), debugstr_w(packagefile),
             GetLastError());
     size = strlenW(packagefile)*sizeof(WCHAR);
-    RegSetValueExW(hkey,szLocalPackage,0,REG_SZ,(LPSTR)packagefile,size);
+    RegSetValueExW(hkey,INSTALLPROPERTY_LOCALPACKAGEW,0,REG_SZ,
+            (LPBYTE)packagefile,size);
 
     /* do ModifyPath and UninstallString */
     size = deformat_string(package,modpath_fmt,&buffer);
-    RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPSTR)buffer,size);
-    RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPSTR)buffer,size);
+    RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
+    RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
     HeapFree(GetProcessHeap(),0,buffer);
 
     FIXME("Write real Estimated Size when we have it\n");
     size = 0;
-    RegSetValueExW(hkey,szEstimatedSize,0,REG_DWORD,(LPSTR)&size,sizeof(DWORD));
+    RegSetValueExW(hkey,szEstimatedSize,0,REG_DWORD,(LPBYTE)&size,sizeof(DWORD));
    
     GetLocalTime(&systime);
     size = 9*sizeof(WCHAR);
     buffer= HeapAlloc(GetProcessHeap(),0,size);
     sprintfW(buffer,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
     size = strlenW(buffer)*sizeof(WCHAR);
-    RegSetValueExW(hkey,szInstallDate,0,REG_SZ,(LPSTR)buffer,size);
+    RegSetValueExW(hkey,INSTALLPROPERTY_INSTALLDATEW,0,REG_SZ,
+            (LPBYTE)buffer,size);
     HeapFree(GetProcessHeap(),0,buffer);
    
     buffer = load_dynamic_property(package,szProductLanguage,NULL);
     size = atoiW(buffer);
-    RegSetValueExW(hkey,szLanguage,0,REG_DWORD, (LPSTR)&size,sizeof(DWORD));
+    RegSetValueExW(hkey,INSTALLPROPERTY_LANGUAGEW,0,REG_DWORD,
+            (LPBYTE)&size,sizeof(DWORD));
     HeapFree(GetProcessHeap(),1,buffer);
 
     buffer = load_dynamic_property(package,szProductVersion,NULL);
@@ -3611,9 +3565,12 @@
         DWORD vermajor = verdword>>24;
         DWORD verminor = (verdword>>16)&0x00FF;
         size = sizeof(DWORD);
-        RegSetValueExW(hkey,szVersion,0,REG_DWORD,(LPSTR)&verdword,size);
-        RegSetValueExW(hkey,szVersionMajor,0,REG_DWORD,(LPSTR)&vermajor,size);
-        RegSetValueExW(hkey,szVersionMinor,0,REG_DWORD,(LPSTR)&verminor,size);
+        RegSetValueExW(hkey,INSTALLPROPERTY_VERSIONW,0,REG_DWORD,
+                (LPBYTE)&verdword,size);
+        RegSetValueExW(hkey,INSTALLPROPERTY_VERSIONMAJORW,0,REG_DWORD,
+                (LPBYTE)&vermajor,size);
+        RegSetValueExW(hkey,INSTALLPROPERTY_VERSIONMINORW,0,REG_DWORD,
+                (LPBYTE)&verminor,size);
     }
     HeapFree(GetProcessHeap(),0,buffer);
     
@@ -3624,11 +3581,11 @@
         HKEY hkey2;
         WCHAR squashed[33];
         MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
-        squash_guid(productcode,squashed);
+        squash_guid(package->ProductCode,squashed);
         RegSetValueExW(hkey2, squashed, 0,REG_SZ,NULL,0);
         RegCloseKey(hkey2);
         MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
-        squash_guid(productcode,squashed);
+        squash_guid(package->ProductCode,squashed);
         RegSetValueExW(hkey2, squashed, 0,REG_SZ,NULL,0);
         RegCloseKey(hkey2);
 
@@ -3636,7 +3593,6 @@
     }
     
 end:
-    HeapFree(GetProcessHeap(),0,productcode);
     RegCloseKey(hkey);
 
     return ERROR_SUCCESS;
@@ -3700,68 +3656,33 @@
     'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
     'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
     WCHAR buffer[256], sysdir[MAX_PATH];
-    HKEY hkey,hukey;
-    LPWSTR productcode;
+    HKEY hkey;
     WCHAR  squished_pc[100];
-    INT rc;
     DWORD size;
-    static const WCHAR szLUS[] = {
-         'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0};
-    static const WCHAR szSourceList[] = {
-         'S','o','u','r','c','e','L','i','s','t',0};
-    static const WCHAR szPackageName[] = { 
-        'P','a','c','k','a','g','e','N','a','m','e',0};
 
     if (!package)
         return ERROR_INVALID_HANDLE;
 
-    productcode = load_dynamic_property(package,szProductCode,&rc);
-    if (!productcode)
-        return rc;
+    squash_guid(package->ProductCode,squished_pc);
 
-    squash_guid(productcode,squished_pc);
-
     GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
     RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
     snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
      squished_pc);
 
     size = strlenW(buffer)*sizeof(WCHAR);
-    RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size);
+    RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPBYTE)buffer,size);
     RegCloseKey(hkey);
 
     TRACE("Reboot command %s\n",debugstr_w(buffer));
 
     RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
-    sprintfW(buffer,install_fmt,productcode,squished_pc);
+    sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
 
     size = strlenW(buffer)*sizeof(WCHAR);
-    RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size);
+    RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPBYTE)buffer,size);
     RegCloseKey(hkey);
 
-    rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE);
-    if (rc == ERROR_SUCCESS)
-    {
-        HKEY hukey2;
-        LPWSTR buf;
-        RegCreateKeyW(hukey, szSourceList, &hukey2);
-        buf = load_dynamic_property(package,cszSourceDir,NULL);
-        size = strlenW(buf)*sizeof(WCHAR);
-        RegSetValueExW(hukey2,szLUS,0,REG_SZ,(LPSTR)buf,size);
-        HeapFree(GetProcessHeap(),0,buf); 
-
-        buf = strrchrW(package->PackagePath,'\\');
-        if (buf)
-        {
-            buf++;
-            size = strlenW(buf)*sizeof(WCHAR);
-            RegSetValueExW(hukey2,szPackageName,0,REG_SZ,(LPSTR)buf,size);
-        }
-
-        RegCloseKey(hukey2);
-    }
-    HeapFree(GetProcessHeap(),0,productcode);
-
     return ERROR_INSTALL_SUSPEND;
 }
 
@@ -3776,11 +3697,8 @@
 
 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
 {
-    static const WCHAR szProductID[]=
-         {'P','r','o','d','u','c','t','I','D',0};
     HKEY hkey=0;
     LPWSTR buffer;
-    LPWSTR productcode;
     LPWSTR productid;
     UINT rc,i;
     DWORD size;
@@ -3804,15 +3722,12 @@
     if (!package)
         return ERROR_INVALID_HANDLE;
 
-    productid = load_dynamic_property(package,szProductID,&rc);
+    productid = load_dynamic_property(package,INSTALLPROPERTY_PRODUCTIDW,
+            &rc);
     if (!productid)
         return ERROR_SUCCESS;
 
-    productcode = load_dynamic_property(package,szProductCode,&rc);
-    if (!productcode)
-        return rc;
-
-    rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE);
+    rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
     if (rc != ERROR_SUCCESS)
         goto end;
 
@@ -3823,7 +3738,7 @@
         if (rc == ERROR_SUCCESS)
         {
             size = strlenW(buffer)*sizeof(WCHAR);
-            RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size);
+            RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPBYTE)buffer,size);
         }
         else
             RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,NULL,0);
@@ -3831,7 +3746,6 @@
     }
 
 end:
-    HeapFree(GetProcessHeap(),0,productcode);
     HeapFree(GetProcessHeap(),0,productid);
     RegCloseKey(hkey);
 
@@ -3848,6 +3762,7 @@
     level = load_dynamic_property(package,szUILevel,NULL);
 
     MSI_SetPropertyW(package,szUILevel,szTwo);
+    package->script->InWhatSequence |= SEQUENCE_EXEC;
     rc = ACTION_ProcessExecSequence(package,FALSE);
     MSI_SetPropertyW(package,szUILevel,level);
     HeapFree(GetProcessHeap(),0,level);

Modified: trunk/reactos/lib/msi/action.h
--- trunk/reactos/lib/msi/action.h	2005-08-12 16:59:41 UTC (rev 17330)
+++ trunk/reactos/lib/msi/action.h	2005-08-12 17:07:28 UTC (rev 17331)
@@ -187,13 +187,19 @@
         TOTAL_SCRIPTS = 3
 };
 
+#define SEQUENCE_UI       0x1
+#define SEQUENCE_EXEC     0x2
+#define SEQUENCE_INSTALL  0x10
+
 typedef struct tagMSISCRIPT
 {
     LPWSTR  *Actions[TOTAL_SCRIPTS];
     UINT    ActionCount[TOTAL_SCRIPTS];
     BOOL    ExecuteSequenceRun;
-    BOOL    FindRelatedProductsRun;
     BOOL    CurrentlyScripting;
+    UINT    InWhatSequence;
+    LPWSTR  *UniqueActions;
+    UINT    UniqueActionsCount;
 }MSISCRIPT;
 
 
@@ -234,6 +240,9 @@
 void reduce_to_shortfilename(WCHAR*);
 LPWSTR create_component_advertise_string(MSIPACKAGE*, MSICOMPONENT*, LPCWSTR);
 void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature);
+UINT register_unique_action(MSIPACKAGE *, LPCWSTR);
+BOOL check_unique_action(MSIPACKAGE *, LPCWSTR);
+WCHAR* generate_error_string(MSIPACKAGE *, UINT, DWORD, ... );
 
 
 /* control event stuff */

Modified: trunk/reactos/lib/msi/appsearch.c
--- trunk/reactos/lib/msi/appsearch.c	2005-08-12 16:59:41 UTC (rev 17330)
+++ trunk/reactos/lib/msi/appsearch.c	2005-08-12 17:07:28 UTC (rev 17331)
@@ -334,6 +334,13 @@
             goto end;
         }
 
+        /* bail out if the registry key is empty */
+        if (sz == 0)
+        {
+            rc = ERROR_SUCCESS;
+            goto end;
+        }
+        
         switch (regType)
         {
             case REG_SZ:

Modified: trunk/reactos/lib/msi/custom.c
--- trunk/reactos/lib/msi/custom.c	2005-08-12 16:59:41 UTC (rev 17330)
+++ trunk/reactos/lib/msi/custom.c	2005-08-12 17:07:28 UTC (rev 17331)
@@ -36,6 +36,7 @@
 #include "wine/debug.h"
 #include "fdi.h"
 #include "msi.h"
+#include "msidefs.h"
 #include "msiquery.h"
 #include "fcntl.h"
 #include "objbase.h"
@@ -74,6 +75,45 @@
 static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source,
                                 LPCWSTR target, const INT type, LPCWSTR action);
 
+
+static BOOL check_execution_scheduling_options(MSIPACKAGE *package, LPCWSTR action, UINT options)
+{
+    if (!package->script)
+        return TRUE;
+
+    if ((options & msidbCustomActionTypeClientRepeat) == 
+            msidbCustomActionTypeClientRepeat)
+    {
+        if (!(package->script->InWhatSequence & SEQUENCE_UI &&
+            package->script->InWhatSequence & SEQUENCE_EXEC))
+        {
+            TRACE("Skipping action due to dbCustomActionTypeClientRepeat option.\n");
+            return FALSE;
+        }
+    }
+    else if (options & msidbCustomActionTypeFirstSequence)
+    {
+        if (package->script->InWhatSequence & SEQUENCE_UI &&
+            package->script->InWhatSequence & SEQUENCE_EXEC )
+        {
+            TRACE("Skipping action due to msidbCustomActionTypeFirstSequence option.\n");
+            return FALSE;
+        }
+    }
+    else if (options & msidbCustomActionTypeOncePerProcess)
+    {
+        if (check_unique_action(package,action))
+        {
+            TRACE("Skipping action due to msidbCustomActionTypeOncePerProcess option.\n");
+            return FALSE;
+        }
+        else
+            register_unique_action(package,action);
+    }
+
+    return TRUE;
+}
+
 UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute)
 {
     UINT rc = ERROR_SUCCESS;
@@ -101,9 +141,15 @@
           debugstr_w(source), debugstr_w(target));
 
     /* handle some of the deferred actions */
-    if (type & 0x400)
+    if (type & msidbCustomActionTypeTSAware)
+        FIXME("msidbCustomActionTypeTSAware not handled\n");
+
+    if (type & msidbCustomActionTypeInScript)
     {
-        if (type & 0x100)
+        if (type & msidbCustomActionTypeNoImpersonate)
+            FIXME("msidbCustomActionTypeNoImpersonate not handled\n");
+
+        if (type & msidbCustomActionTypeRollback)
         {
             FIXME("Rollback only action... rollbacks not supported yet\n");
             schedule_action(package, ROLLBACK_SCRIPT, action);
@@ -114,7 +160,7 @@
         }
         if (!execute)
         {
-            if (type & 0x200)
+            if (type & msidbCustomActionTypeCommit)
             {
                 TRACE("Deferring Commit Action!\n");
                 schedule_action(package, COMMIT_SCRIPT, action);
@@ -136,11 +182,16 @@
 
             static const WCHAR szActionData[] = {
             'C','u','s','t','o','m','A','c','t','i','o','n','D','a','t','a',0};
+            static const WCHAR szBlank[] = {0};
             LPWSTR actiondata = load_dynamic_property(package,action,NULL);
             if (actiondata)
                 MSI_SetPropertyW(package,szActionData,actiondata);
+            else
+                MSI_SetPropertyW(package,szActionData,szBlank);
         }
     }
+    else if (!check_execution_scheduling_options(package,action,type))
+        return ERROR_SUCCESS;
 
     switch (type & CUSTOM_ACTION_TYPE_MASK)
     {
@@ -304,7 +355,7 @@
 {
     UINT rc = ERROR_SUCCESS;
 
-    if (!(type & 0x80))
+    if (!(type & msidbCustomActionTypeAsync))
     {
         /* synchronous */
         TRACE("Synchronous Execution of action %s\n",debugstr_w(Name));
@@ -313,7 +364,7 @@
         else
             msi_dialog_check_messages(ThreadHandle);
 
-        if (!(type & 0x40))
+        if (!(type & msidbCustomActionTypeContinue))
         {
             if (ProcessHandle)
                 rc = process_action_return_value(2,ProcessHandle);
@@ -331,7 +382,7 @@
     {
         TRACE("Asynchronous Execution of action %s\n",debugstr_w(Name));
         /* asynchronous */
-        if (type & 0x40)
+        if (type & msidbCustomActionTypeContinue)
         {
             if (ProcessHandle)
             {

Modified: trunk/reactos/lib/msi/dialog.c
--- trunk/reactos/lib/msi/dialog.c	2005-08-12 16:59:41 UTC (rev 17330)
+++ trunk/reactos/lib/msi/dialog.c	2005-08-12 17:07:28 UTC (rev 17331)
@@ -53,8 +53,9 @@
     msi_handler handler;
     LPWSTR property;
     LPWSTR value;
-    IPicture *pic;
+    HBITMAP hBitmap;
     HICON hIcon;
+    LPWSTR tabnext;
     WCHAR name[1];
 };
 
@@ -76,6 +77,7 @@
     LPWSTR default_font;
     msi_font *font_list;
     msi_control *control_list;
+    HWND hWndFocus;
     WCHAR name[1];
 };
 
@@ -143,6 +145,8 @@
 {
     msi_control *control;
 
+    if( !name )
+        return NULL;
     for( control = dialog->control_list; control; control = control->next )
         if( !strcmpW( control->name, name ) ) /* FIXME: case sensitive? */
             break;
@@ -297,8 +301,9 @@
     control->handler = NULL;
     control->property = NULL;
     control->value = NULL;
-    control->pic = NULL;
+    control->hBitmap = NULL;
     control->hIcon = NULL;
+    control->tabnext = strdupW( MSI_RecordGetString( rec, 11) );
 
     x = MSI_RecordGetInteger( rec, 4 );
     y = MSI_RecordGetInteger( rec, 5 );
@@ -331,6 +336,97 @@
     return control;
 }
 
+static MSIRECORD *msi_get_binary_record( MSIDATABASE *db, LPCWSTR name )
+{
+    const static WCHAR query[] = {
+        's','e','l','e','c','t',' ','*',' ',
+        'f','r','o','m',' ','B','i','n','a','r','y',' ',
+        'w','h','e','r','e',' ',
+            '`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0
+    };
+
+    return MSI_QueryGetRecord( db, query, name );
+}
+
+static LPWSTR msi_create_tmp_path(void)
+{
+    WCHAR tmp[MAX_PATH];
+    LPWSTR path = NULL;
+    static const WCHAR prefix[] = { 'm','s','i',0 };
+    DWORD len, r;
+
+    r = GetTempPathW( MAX_PATH, tmp );
+    if( !r )
+        return path;
+    len = lstrlenW( tmp ) + 20;
+    path = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
+    if( path )
+    {
+        r = GetTempFileNameW( tmp, prefix, 0, path );
+        if (!r)
+        {
+            HeapFree( GetProcessHeap(), 0, path );
+            path = NULL;
+        }
+    }
+    return path;
+}
+
+
+static HANDLE msi_load_image( MSIDATABASE *db, LPCWSTR name, UINT type,
+                              UINT cx, UINT cy, UINT flags )
+{
+    MSIRECORD *rec = NULL;
+    HANDLE himage = NULL;
+    LPWSTR tmp;
+    UINT r;
+
+    TRACE("%p %s %u %u %08x\n", db, debugstr_w(name), cx, cy, flags);
+
+    tmp = msi_create_tmp_path();
+    if( !tmp )
+        return himage;
+
+    rec = msi_get_binary_record( db, name );
+    if( rec )
+    {
+        r = MSI_RecordStreamToFile( rec, 2, tmp );
+        if( r == ERROR_SUCCESS )
+        {
+            himage = LoadImageW( 0, tmp, type, cx, cy, flags );
+            DeleteFileW( tmp );
+        }
+        msiobj_release( &rec->hdr );
+    }
+
+    HeapFree( GetProcessHeap(), 0, tmp );
+    return himage;
+}
+
+static HICON msi_load_icon( MSIDATABASE *db, LPCWSTR text, UINT attributes )
+{
+    DWORD cx = 0, cy = 0, flags;
+
+    flags = LR_LOADFROMFILE | LR_DEFAULTSIZE;
+    if( attributes & msidbControlAttributesFixedSize )
+    {
+        flags &= ~LR_DEFAULTSIZE;
+        if( attributes & msidbControlAttributesIconSize16 )
+        {
+            cx += 16;
+            cy += 16;
+        }
+        if( attributes & msidbControlAttributesIconSize32 )
+        {
+            cx += 32;
+            cy += 32;
+        }
+        /* msidbControlAttributesIconSize48 handled by above logic */
+    }
+    return msi_load_image( db, text, IMAGE_ICON, cx, cy, flags );
+}
+
+
 /* called from the Control Event subscription code */
 void msi_dialog_handle_event( msi_dialog* dialog, LPCWSTR control, 
                               LPCWSTR attribute, MSIRECORD *rec )
@@ -475,12 +571,28 @@
 static UINT msi_dialog_button_control( msi_dialog *dialog, MSIRECORD *rec )
 {
     msi_control *control;
+    UINT attributes, style;
+    LPCWSTR text;
 
     TRACE("%p %p\n", dialog, rec);
 
-    control = msi_dialog_add_control( dialog, rec, szButton, WS_TABSTOP );
[truncated at 1000 lines; 1702 more skipped]