ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

action.c
Go to the documentation of this file.
00001 /*
00002  * Implementation of the Microsoft Installer (msi.dll)
00003  *
00004  * Copyright 2004,2005 Aric Stewart for CodeWeavers
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00019  */
00020 
00021 #include <stdarg.h>
00022 
00023 #define COBJMACROS
00024 
00025 #include "windef.h"
00026 #include "winbase.h"
00027 #include "winerror.h"
00028 #include "winreg.h"
00029 #include "winsvc.h"
00030 #include "odbcinst.h"
00031 #include "wine/debug.h"
00032 #include "msidefs.h"
00033 #include "msipriv.h"
00034 #include "winuser.h"
00035 #include "shlobj.h"
00036 #include "objbase.h"
00037 #include "mscoree.h"
00038 #include "shlwapi.h"
00039 #include "imagehlp.h"
00040 #include "wine/unicode.h"
00041 #include "winver.h"
00042 
00043 #define REG_PROGRESS_VALUE 13200
00044 #define COMPONENT_PROGRESS_VALUE 24000
00045 
00046 WINE_DEFAULT_DEBUG_CHANNEL(msi);
00047 
00048 static const WCHAR szCreateFolders[] =
00049     {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
00050 static const WCHAR szCostFinalize[] =
00051     {'C','o','s','t','F','i','n','a','l','i','z','e',0};
00052 static const WCHAR szWriteRegistryValues[] =
00053     {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
00054 static const WCHAR szFileCost[] = 
00055     {'F','i','l','e','C','o','s','t',0};
00056 static const WCHAR szInstallInitialize[] = 
00057     {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
00058 static const WCHAR szInstallValidate[] = 
00059     {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
00060 static const WCHAR szLaunchConditions[] = 
00061     {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
00062 static const WCHAR szProcessComponents[] = 
00063     {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
00064 static const WCHAR szRegisterTypeLibraries[] = 
00065     {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
00066 static const WCHAR szCreateShortcuts[] = 
00067     {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
00068 static const WCHAR szPublishProduct[] = 
00069     {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
00070 static const WCHAR szWriteIniValues[] = 
00071     {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
00072 static const WCHAR szSelfRegModules[] = 
00073     {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
00074 static const WCHAR szPublishFeatures[] = 
00075     {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
00076 static const WCHAR szRegisterProduct[] = 
00077     {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
00078 static const WCHAR szInstallExecute[] = 
00079     {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
00080 static const WCHAR szInstallExecuteAgain[] = 
00081     {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
00082 static const WCHAR szInstallFinalize[] = 
00083     {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
00084 static const WCHAR szForceReboot[] = 
00085     {'F','o','r','c','e','R','e','b','o','o','t',0};
00086 static const WCHAR szResolveSource[] =
00087     {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
00088 static const WCHAR szAllocateRegistrySpace[] = 
00089     {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
00090 static const WCHAR szBindImage[] = 
00091     {'B','i','n','d','I','m','a','g','e',0};
00092 static const WCHAR szDeleteServices[] = 
00093     {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
00094 static const WCHAR szDisableRollback[] = 
00095     {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
00096 static const WCHAR szExecuteAction[] = 
00097     {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
00098 static const WCHAR szInstallAdminPackage[] = 
00099     {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
00100 static const WCHAR szInstallSFPCatalogFile[] = 
00101     {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
00102 static const WCHAR szIsolateComponents[] = 
00103     {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
00104 static const WCHAR szMigrateFeatureStates[] =
00105     {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
00106 static const WCHAR szMsiUnpublishAssemblies[] = 
00107     {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
00108 static const WCHAR szInstallODBC[] = 
00109     {'I','n','s','t','a','l','l','O','D','B','C',0};
00110 static const WCHAR szInstallServices[] = 
00111     {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
00112 static const WCHAR szPublishComponents[] = 
00113     {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
00114 static const WCHAR szRegisterComPlus[] =
00115     {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
00116 static const WCHAR szRegisterUser[] =
00117     {'R','e','g','i','s','t','e','r','U','s','e','r',0};
00118 static const WCHAR szRemoveEnvironmentStrings[] =
00119     {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
00120 static const WCHAR szRemoveExistingProducts[] =
00121     {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
00122 static const WCHAR szRemoveFolders[] =
00123     {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
00124 static const WCHAR szRemoveIniValues[] =
00125     {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
00126 static const WCHAR szRemoveODBC[] =
00127     {'R','e','m','o','v','e','O','D','B','C',0};
00128 static const WCHAR szRemoveRegistryValues[] =
00129     {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
00130 static const WCHAR szRemoveShortcuts[] =
00131     {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
00132 static const WCHAR szRMCCPSearch[] =
00133     {'R','M','C','C','P','S','e','a','r','c','h',0};
00134 static const WCHAR szScheduleReboot[] =
00135     {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
00136 static const WCHAR szSelfUnregModules[] =
00137     {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
00138 static const WCHAR szSetODBCFolders[] =
00139     {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
00140 static const WCHAR szStartServices[] =
00141     {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
00142 static const WCHAR szStopServices[] =
00143     {'S','t','o','p','S','e','r','v','i','c','e','s',0};
00144 static const WCHAR szUnpublishComponents[] =
00145     {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
00146 static const WCHAR szUnpublishFeatures[] =
00147     {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
00148 static const WCHAR szUnregisterComPlus[] =
00149     {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
00150 static const WCHAR szUnregisterTypeLibraries[] =
00151     {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
00152 static const WCHAR szValidateProductID[] =
00153     {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
00154 static const WCHAR szWriteEnvironmentStrings[] =
00155     {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
00156 
00157 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
00158 {
00159     static const WCHAR Query_t[] = 
00160         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
00161          '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
00162          'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=', 
00163          ' ','\'','%','s','\'',0};
00164     MSIRECORD * row;
00165 
00166     row = MSI_QueryGetRecord( package->db, Query_t, action );
00167     if (!row)
00168         return;
00169     MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
00170     msiobj_release(&row->hdr);
00171 }
00172 
00173 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start, 
00174                           UINT rc)
00175 {
00176     MSIRECORD * row;
00177     static const WCHAR template_s[]=
00178         {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
00179          '%','s', '.',0};
00180     static const WCHAR template_e[]=
00181         {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
00182          '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
00183          '%','i','.',0};
00184     static const WCHAR format[] = 
00185         {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
00186     WCHAR message[1024];
00187     WCHAR timet[0x100];
00188 
00189     GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
00190     if (start)
00191         sprintfW(message,template_s,timet,action);
00192     else
00193         sprintfW(message,template_e,timet,action,rc);
00194     
00195     row = MSI_CreateRecord(1);
00196     MSI_RecordSetStringW(row,1,message);
00197  
00198     MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
00199     msiobj_release(&row->hdr);
00200 }
00201 
00202 enum parse_state
00203 {
00204     state_whitespace,
00205     state_token,
00206     state_quote
00207 };
00208 
00209 static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
00210 {
00211     enum parse_state state = state_quote;
00212     const WCHAR *p;
00213     WCHAR *out = value;
00214     int ignore, in_quotes = 0, count = 0, len = 0;
00215 
00216     for (p = str; *p; p++)
00217     {
00218         ignore = 0;
00219         switch (state)
00220         {
00221         case state_whitespace:
00222             switch (*p)
00223             {
00224             case ' ':
00225                 in_quotes = 1;
00226                 ignore = 1;
00227                 len++;
00228                 break;
00229             case '"':
00230                 state = state_quote;
00231                 if (in_quotes && p[1] != '\"') count--;
00232                 else count++;
00233                 break;
00234             default:
00235                 state = state_token;
00236                 in_quotes = 1;
00237                 len++;
00238                 break;
00239             }
00240             break;
00241 
00242         case state_token:
00243             switch (*p)
00244             {
00245             case '"':
00246                 state = state_quote;
00247                 if (in_quotes) count--;
00248                 else count++;
00249                 break;
00250             case ' ':
00251                 state = state_whitespace;
00252                 if (!count) goto done;
00253                 in_quotes = 1;
00254                 len++;
00255                 break;
00256             default:
00257                 if (!count) in_quotes = 0;
00258                 else in_quotes = 1;
00259                 len++;
00260                 break;
00261             }
00262             break;
00263 
00264         case state_quote:
00265             switch (*p)
00266             {
00267             case '"':
00268                 if (in_quotes && p[1] != '\"') count--;
00269                 else count++;
00270                 break;
00271             case ' ':
00272                 state = state_whitespace;
00273                 if (!count || (count > 1 && !len)) goto done;
00274                 in_quotes = 1;
00275                 len++;
00276                 break;
00277             default:
00278                 state = state_token;
00279                 if (!count) in_quotes = 0;
00280                 else in_quotes = 1;
00281                 len++;
00282                 break;
00283             }
00284             break;
00285 
00286         default: break;
00287         }
00288         if (!ignore) *out++ = *p;
00289     }
00290 
00291 done:
00292     if (!len) *value = 0;
00293     else *out = 0;
00294 
00295     *quotes = count;
00296     return p - str;
00297 }
00298 
00299 static void remove_quotes( WCHAR *str )
00300 {
00301     WCHAR *p = str;
00302     int len = strlenW( str );
00303 
00304     while ((p = strchrW( p, '"' )))
00305     {
00306         memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
00307         p++;
00308     }
00309 }
00310 
00311 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
00312                              BOOL preserve_case )
00313 {
00314     LPCWSTR ptr, ptr2;
00315     int num_quotes;
00316     DWORD len;
00317     WCHAR *prop, *val;
00318     UINT r;
00319 
00320     if (!szCommandLine)
00321         return ERROR_SUCCESS;
00322 
00323     ptr = szCommandLine;
00324     while (*ptr)
00325     {
00326         while (*ptr == ' ') ptr++;
00327         if (!*ptr) break;
00328 
00329         ptr2 = strchrW( ptr, '=' );
00330         if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
00331  
00332         len = ptr2 - ptr;
00333         if (!len) return ERROR_INVALID_COMMAND_LINE;
00334 
00335         prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
00336         memcpy( prop, ptr, len * sizeof(WCHAR) );
00337         prop[len] = 0;
00338         if (!preserve_case) struprW( prop );
00339 
00340         ptr2++;
00341         while (*ptr2 == ' ') ptr2++;
00342 
00343         num_quotes = 0;
00344         val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) );
00345         len = parse_prop( ptr2, val, &num_quotes );
00346         if (num_quotes % 2)
00347         {
00348             WARN("unbalanced quotes\n");
00349             msi_free( val );
00350             msi_free( prop );
00351             return ERROR_INVALID_COMMAND_LINE;
00352         }
00353         remove_quotes( val );
00354         TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
00355 
00356         r = msi_set_property( package->db, prop, val );
00357         if (r == ERROR_SUCCESS && !strcmpW( prop, szSourceDir ))
00358             msi_reset_folders( package, TRUE );
00359 
00360         msi_free( val );
00361         msi_free( prop );
00362 
00363         ptr = ptr2 + len;
00364     }
00365 
00366     return ERROR_SUCCESS;
00367 }
00368 
00369 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
00370 {
00371     LPCWSTR pc;
00372     LPWSTR p, *ret = NULL;
00373     UINT count = 0;
00374 
00375     if (!str)
00376         return ret;
00377 
00378     /* count the number of substrings */
00379     for ( pc = str, count = 0; pc; count++ )
00380     {
00381         pc = strchrW( pc, sep );
00382         if (pc)
00383             pc++;
00384     }
00385 
00386     /* allocate space for an array of substring pointers and the substrings */
00387     ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
00388                      (lstrlenW(str)+1) * sizeof(WCHAR) );
00389     if (!ret)
00390         return ret;
00391 
00392     /* copy the string and set the pointers */
00393     p = (LPWSTR) &ret[count+1];
00394     lstrcpyW( p, str );
00395     for( count = 0; (ret[count] = p); count++ )
00396     {
00397         p = strchrW( p, sep );
00398         if (p)
00399             *p++ = 0;
00400     }
00401 
00402     return ret;
00403 }
00404 
00405 static BOOL ui_sequence_exists( MSIPACKAGE *package )
00406 {
00407     static const WCHAR query [] = {
00408         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
00409         '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
00410         'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
00411         'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
00412     MSIQUERY *view;
00413     UINT rc;
00414 
00415     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
00416     if (rc == ERROR_SUCCESS)
00417     {
00418         msiobj_release(&view->hdr);
00419         return TRUE;
00420     }
00421     return FALSE;
00422 }
00423 
00424 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
00425 {
00426     LPWSTR source, check;
00427 
00428     if (msi_get_property_int( package->db, szInstalled, 0 ))
00429     {
00430         HKEY hkey;
00431 
00432         MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
00433         source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
00434         RegCloseKey( hkey );
00435     }
00436     else
00437     {
00438         LPWSTR p, db;
00439         DWORD len;
00440 
00441         db = msi_dup_property( package->db, szOriginalDatabase );
00442         if (!db)
00443             return ERROR_OUTOFMEMORY;
00444 
00445         p = strrchrW( db, '\\' );
00446         if (!p)
00447         {
00448             p = strrchrW( db, '/' );
00449             if (!p)
00450             {
00451                 msi_free(db);
00452                 return ERROR_SUCCESS;
00453             }
00454         }
00455 
00456         len = p - db + 2;
00457         source = msi_alloc( len * sizeof(WCHAR) );
00458         lstrcpynW( source, db, len );
00459         msi_free( db );
00460     }
00461 
00462     check = msi_dup_property( package->db, szSourceDir );
00463     if (!check || replace)
00464     {
00465         UINT r = msi_set_property( package->db, szSourceDir, source );
00466         if (r == ERROR_SUCCESS)
00467             msi_reset_folders( package, TRUE );
00468     }
00469     msi_free( check );
00470 
00471     check = msi_dup_property( package->db, szSOURCEDIR );
00472     if (!check || replace)
00473         msi_set_property( package->db, szSOURCEDIR, source );
00474 
00475     msi_free( check );
00476     msi_free( source );
00477 
00478     return ERROR_SUCCESS;
00479 }
00480 
00481 static BOOL needs_ui_sequence(MSIPACKAGE *package)
00482 {
00483     return (package->ui_level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
00484 }
00485 
00486 UINT msi_set_context(MSIPACKAGE *package)
00487 {
00488     UINT r = msi_locate_product( package->ProductCode, &package->Context );
00489     if (r != ERROR_SUCCESS)
00490     {
00491         int num = msi_get_property_int( package->db, szAllUsers, 0 );
00492         if (num == 1 || num == 2)
00493             package->Context = MSIINSTALLCONTEXT_MACHINE;
00494         else
00495             package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
00496     }
00497     return ERROR_SUCCESS;
00498 }
00499 
00500 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
00501 {
00502     UINT rc;
00503     LPCWSTR cond, action;
00504     MSIPACKAGE *package = param;
00505 
00506     action = MSI_RecordGetString(row,1);
00507     if (!action)
00508     {
00509         ERR("Error is retrieving action name\n");
00510         return ERROR_FUNCTION_FAILED;
00511     }
00512 
00513     /* check conditions */
00514     cond = MSI_RecordGetString(row,2);
00515 
00516     /* this is a hack to skip errors in the condition code */
00517     if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
00518     {
00519         TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
00520         return ERROR_SUCCESS;
00521     }
00522 
00523     if (needs_ui_sequence(package))
00524         rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
00525     else
00526         rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
00527 
00528     msi_dialog_check_messages( NULL );
00529 
00530     if (package->CurrentInstallState != ERROR_SUCCESS)
00531         rc = package->CurrentInstallState;
00532 
00533     if (rc == ERROR_FUNCTION_NOT_CALLED)
00534         rc = ERROR_SUCCESS;
00535 
00536     if (rc != ERROR_SUCCESS)
00537         ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
00538 
00539     if (package->need_reboot_now)
00540     {
00541         TRACE("action %s asked for immediate reboot, suspending installation\n",
00542               debugstr_w(action));
00543         rc = ACTION_ForceReboot( package );
00544     }
00545     return rc;
00546 }
00547 
00548 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR table )
00549 {
00550     static const WCHAR query[] = {
00551         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',
00552          ' ','W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ',
00553          '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
00554          '`','S','e','q','u','e','n','c','e','`',0};
00555     MSIQUERY *view;
00556     UINT r;
00557 
00558     TRACE("%p %s\n", package, debugstr_w(table));
00559 
00560     r = MSI_OpenQuery( package->db, &view, query, table );
00561     if (r == ERROR_SUCCESS)
00562     {
00563         r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
00564         msiobj_release(&view->hdr);
00565     }
00566     return r;
00567 }
00568 
00569 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
00570 {
00571     static const WCHAR query[] = {
00572         'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
00573         '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
00574         'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
00575         '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
00576         'O','R','D','E','R',' ', 'B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
00577     static const WCHAR query_validate[] = {
00578         'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
00579         ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
00580         'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
00581         'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
00582         ' ','\'', 'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','\'',0};
00583     MSIQUERY *view;
00584     INT seq = 0;
00585     UINT rc;
00586 
00587     if (package->script->ExecuteSequenceRun)
00588     {
00589         TRACE("Execute Sequence already Run\n");
00590         return ERROR_SUCCESS;
00591     }
00592 
00593     package->script->ExecuteSequenceRun = TRUE;
00594 
00595     /* get the sequence number */
00596     if (UIran)
00597     {
00598         MSIRECORD *row = MSI_QueryGetRecord(package->db, query_validate);
00599         if (!row) return ERROR_FUNCTION_FAILED;
00600         seq = MSI_RecordGetInteger(row,1);
00601         msiobj_release(&row->hdr);
00602     }
00603     rc = MSI_OpenQuery(package->db, &view, query, seq);
00604     if (rc == ERROR_SUCCESS)
00605     {
00606         TRACE("Running the actions\n");
00607 
00608         msi_set_property(package->db, szSourceDir, NULL);
00609         rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
00610         msiobj_release(&view->hdr);
00611     }
00612     return rc;
00613 }
00614 
00615 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
00616 {
00617     static const WCHAR query[] = {
00618         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
00619         '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
00620         'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
00621         'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
00622     MSIQUERY *view;
00623     UINT rc;
00624 
00625     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
00626     if (rc == ERROR_SUCCESS)
00627     {
00628         TRACE("Running the actions\n"); 
00629         rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
00630         msiobj_release(&view->hdr);
00631     }
00632     return rc;
00633 }
00634 
00635 /********************************************************
00636  * ACTION helper functions and functions that perform the actions
00637  *******************************************************/
00638 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
00639                                        UINT* rc, UINT script, BOOL force )
00640 {
00641     BOOL ret=FALSE;
00642     UINT arc;
00643 
00644     arc = ACTION_CustomAction(package, action, script, force);
00645 
00646     if (arc != ERROR_CALL_NOT_IMPLEMENTED)
00647     {
00648         *rc = arc;
00649         ret = TRUE;
00650     }
00651     return ret;
00652 }
00653 
00654 MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component )
00655 {
00656     MSICOMPONENT *comp;
00657 
00658     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
00659     {
00660         if (!strcmpW( Component, comp->Component )) return comp;
00661     }
00662     return NULL;
00663 }
00664 
00665 MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature )
00666 {
00667     MSIFEATURE *feature;
00668 
00669     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
00670     {
00671         if (!strcmpW( Feature, feature->Feature )) return feature;
00672     }
00673     return NULL;
00674 }
00675 
00676 MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key )
00677 {
00678     MSIFILE *file;
00679 
00680     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
00681     {
00682         if (!strcmpW( key, file->File )) return file;
00683     }
00684     return NULL;
00685 }
00686 
00687 MSIFILEPATCH *msi_get_loaded_filepatch( MSIPACKAGE *package, const WCHAR *key )
00688 {
00689     MSIFILEPATCH *patch;
00690 
00691     /* FIXME: There might be more than one patch */
00692     LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
00693     {
00694         if (!strcmpW( key, patch->File->File )) return patch;
00695     }
00696     return NULL;
00697 }
00698 
00699 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
00700 {
00701     MSIFOLDER *folder;
00702 
00703     LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
00704     {
00705         if (!strcmpW( dir, folder->Directory )) return folder;
00706     }
00707     return NULL;
00708 }
00709 
00710 /*
00711  * Recursively create all directories in the path.
00712  * shamelessly stolen from setupapi/queue.c
00713  */
00714 BOOL msi_create_full_path( const WCHAR *path )
00715 {
00716     BOOL ret = TRUE;
00717     WCHAR *new_path;
00718     int len;
00719 
00720     new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) );
00721     strcpyW( new_path, path );
00722 
00723     while ((len = strlenW( new_path )) && new_path[len - 1] == '\\')
00724     new_path[len - 1] = 0;
00725 
00726     while (!CreateDirectoryW( new_path, NULL ))
00727     {
00728         WCHAR *slash;
00729         DWORD last_error = GetLastError();
00730         if (last_error == ERROR_ALREADY_EXISTS) break;
00731         if (last_error != ERROR_PATH_NOT_FOUND)
00732         {
00733             ret = FALSE;
00734             break;
00735         }
00736         if (!(slash = strrchrW( new_path, '\\' )))
00737         {
00738             ret = FALSE;
00739             break;
00740         }
00741         len = slash - new_path;
00742         new_path[len] = 0;
00743         if (!msi_create_full_path( new_path ))
00744         {
00745             ret = FALSE;
00746             break;
00747         }
00748         new_path[len] = '\\';
00749     }
00750     msi_free( new_path );
00751     return ret;
00752 }
00753 
00754 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
00755 {
00756     MSIRECORD *row;
00757 
00758     row = MSI_CreateRecord( 4 );
00759     MSI_RecordSetInteger( row, 1, a );
00760     MSI_RecordSetInteger( row, 2, b );
00761     MSI_RecordSetInteger( row, 3, c );
00762     MSI_RecordSetInteger( row, 4, d );
00763     MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row );
00764     msiobj_release( &row->hdr );
00765 
00766     msi_dialog_check_messages( NULL );
00767 }
00768 
00769 void msi_ui_actiondata( MSIPACKAGE *package, const WCHAR *action, MSIRECORD *record )
00770 {
00771     static const WCHAR query[] =
00772         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
00773          '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
00774          'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
00775     WCHAR message[1024];
00776     MSIRECORD *row = 0;
00777     DWORD size;
00778 
00779     if (!package->LastAction || strcmpW( package->LastAction, action ))
00780     {
00781         if (!(row = MSI_QueryGetRecord( package->db, query, action ))) return;
00782 
00783         if (MSI_RecordIsNull( row, 3 ))
00784         {
00785             msiobj_release( &row->hdr );
00786             return;
00787         }
00788         /* update the cached action format */
00789         msi_free( package->ActionFormat );
00790         package->ActionFormat = msi_dup_record_field( row, 3 );
00791         msi_free( package->LastAction );
00792         package->LastAction = strdupW( action );
00793         msiobj_release( &row->hdr );
00794     }
00795     size = 1024;
00796     MSI_RecordSetStringW( record, 0, package->ActionFormat );
00797     MSI_FormatRecordW( package, record, message, &size );
00798     row = MSI_CreateRecord( 1 );
00799     MSI_RecordSetStringW( row, 1, message );
00800     MSI_ProcessMessage( package, INSTALLMESSAGE_ACTIONDATA, row );
00801     msiobj_release( &row->hdr );
00802 }
00803 
00804 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp )
00805 {
00806     if (!comp->Enabled)
00807     {
00808         TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
00809         return INSTALLSTATE_UNKNOWN;
00810     }
00811     if (package->need_rollback) return comp->Installed;
00812     return comp->ActionRequest;
00813 }
00814 
00815 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature )
00816 {
00817     if (package->need_rollback) return feature->Installed;
00818     return feature->ActionRequest;
00819 }
00820 
00821 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
00822 {
00823     MSIPACKAGE *package = param;
00824     LPCWSTR dir, component, full_path;
00825     MSIRECORD *uirow;
00826     MSIFOLDER *folder;
00827     MSICOMPONENT *comp;
00828 
00829     component = MSI_RecordGetString(row, 2);
00830     if (!component)
00831         return ERROR_SUCCESS;
00832 
00833     comp = msi_get_loaded_component(package, component);
00834     if (!comp)
00835         return ERROR_SUCCESS;
00836 
00837     comp->Action = msi_get_component_action( package, comp );
00838     if (comp->Action != INSTALLSTATE_LOCAL)
00839     {
00840         TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
00841         return ERROR_SUCCESS;
00842     }
00843 
00844     dir = MSI_RecordGetString(row,1);
00845     if (!dir)
00846     {
00847         ERR("Unable to get folder id\n");
00848         return ERROR_SUCCESS;
00849     }
00850 
00851     uirow = MSI_CreateRecord(1);
00852     MSI_RecordSetStringW(uirow, 1, dir);
00853     msi_ui_actiondata(package, szCreateFolders, uirow);
00854     msiobj_release(&uirow->hdr);
00855 
00856     full_path = msi_get_target_folder( package, dir );
00857     if (!full_path)
00858     {
00859         ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
00860         return ERROR_SUCCESS;
00861     }
00862     TRACE("folder is %s\n", debugstr_w(full_path));
00863 
00864     folder = msi_get_loaded_folder( package, dir );
00865     if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( full_path );
00866     folder->State = FOLDER_STATE_CREATED;
00867     return ERROR_SUCCESS;
00868 }
00869 
00870 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
00871 {
00872     static const WCHAR query[] = {
00873         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
00874         '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
00875     MSIQUERY *view;
00876     UINT rc;
00877 
00878     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
00879     if (rc != ERROR_SUCCESS)
00880         return ERROR_SUCCESS;
00881 
00882     rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
00883     msiobj_release(&view->hdr);
00884     return rc;
00885 }
00886 
00887 static void remove_persistent_folder( MSIFOLDER *folder )
00888 {
00889     FolderList *fl;
00890 
00891     LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
00892     {
00893         remove_persistent_folder( fl->folder );
00894     }
00895     if (folder->persistent && folder->State != FOLDER_STATE_REMOVED)
00896     {
00897         if (RemoveDirectoryW( folder->ResolvedTarget )) folder->State = FOLDER_STATE_REMOVED;
00898     }
00899 }
00900 
00901 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
00902 {
00903     MSIPACKAGE *package = param;
00904     LPCWSTR dir, component, full_path;
00905     MSIRECORD *uirow;
00906     MSIFOLDER *folder;
00907     MSICOMPONENT *comp;
00908 
00909     component = MSI_RecordGetString(row, 2);
00910     if (!component)
00911         return ERROR_SUCCESS;
00912 
00913     comp = msi_get_loaded_component(package, component);
00914     if (!comp)
00915         return ERROR_SUCCESS;
00916 
00917     comp->Action = msi_get_component_action( package, comp );
00918     if (comp->Action != INSTALLSTATE_ABSENT)
00919     {
00920         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
00921         return ERROR_SUCCESS;
00922     }
00923 
00924     dir = MSI_RecordGetString( row, 1 );
00925     if (!dir)
00926     {
00927         ERR("Unable to get folder id\n");
00928         return ERROR_SUCCESS;
00929     }
00930 
00931     full_path = msi_get_target_folder( package, dir );
00932     if (!full_path)
00933     {
00934         ERR("Unable to resolve folder %s\n", debugstr_w(dir));
00935         return ERROR_SUCCESS;
00936     }
00937     TRACE("folder is %s\n", debugstr_w(full_path));
00938 
00939     uirow = MSI_CreateRecord( 1 );
00940     MSI_RecordSetStringW( uirow, 1, dir );
00941     msi_ui_actiondata( package, szRemoveFolders, uirow );
00942     msiobj_release( &uirow->hdr );
00943 
00944     folder = msi_get_loaded_folder( package, dir );
00945     remove_persistent_folder( folder );
00946     return ERROR_SUCCESS;
00947 }
00948 
00949 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
00950 {
00951     static const WCHAR query[] = {
00952         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
00953         '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
00954     MSIQUERY *view;
00955     UINT rc;
00956 
00957     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
00958     if (rc != ERROR_SUCCESS)
00959         return ERROR_SUCCESS;
00960 
00961     rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
00962     msiobj_release( &view->hdr );
00963     return rc;
00964 }
00965 
00966 static UINT load_component( MSIRECORD *row, LPVOID param )
00967 {
00968     MSIPACKAGE *package = param;
00969     MSICOMPONENT *comp;
00970 
00971     comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
00972     if (!comp)
00973         return ERROR_FUNCTION_FAILED;
00974 
00975     list_add_tail( &package->components, &comp->entry );
00976 
00977     /* fill in the data */
00978     comp->Component = msi_dup_record_field( row, 1 );
00979 
00980     TRACE("Loading Component %s\n", debugstr_w(comp->Component));
00981 
00982     comp->ComponentId = msi_dup_record_field( row, 2 );
00983     comp->Directory = msi_dup_record_field( row, 3 );
00984     comp->Attributes = MSI_RecordGetInteger(row,4);
00985     comp->Condition = msi_dup_record_field( row, 5 );
00986     comp->KeyPath = msi_dup_record_field( row, 6 );
00987 
00988     comp->Installed = INSTALLSTATE_UNKNOWN;
00989     comp->Action = INSTALLSTATE_UNKNOWN;
00990     comp->ActionRequest = INSTALLSTATE_UNKNOWN;
00991 
00992     comp->assembly = msi_load_assembly( package, comp );
00993     return ERROR_SUCCESS;
00994 }
00995 
00996 UINT msi_load_all_components( MSIPACKAGE *package )
00997 {
00998     static const WCHAR query[] = {
00999         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
01000         '`','C','o','m','p','o','n','e','n','t','`',0};
01001     MSIQUERY *view;
01002     UINT r;
01003 
01004     if (!list_empty(&package->components))
01005         return ERROR_SUCCESS;
01006 
01007     r = MSI_DatabaseOpenViewW( package->db, query, &view );
01008     if (r != ERROR_SUCCESS)
01009         return r;
01010 
01011     if (!msi_init_assembly_caches( package ))
01012     {
01013         ERR("can't initialize assembly caches\n");
01014         msiobj_release( &view->hdr );
01015         return ERROR_FUNCTION_FAILED;
01016     }
01017 
01018     r = MSI_IterateRecords(view, NULL, load_component, package);
01019     msiobj_release(&view->hdr);
01020     msi_destroy_assembly_caches( package );
01021     return r;
01022 }
01023 
01024 typedef struct {
01025     MSIPACKAGE *package;
01026     MSIFEATURE *feature;
01027 } _ilfs;
01028 
01029 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
01030 {
01031     ComponentList *cl;
01032 
01033     cl = msi_alloc( sizeof (*cl) );
01034     if ( !cl )
01035         return ERROR_NOT_ENOUGH_MEMORY;
01036     cl->component = comp;
01037     list_add_tail( &feature->Components, &cl->entry );
01038 
01039     return ERROR_SUCCESS;
01040 }
01041 
01042 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
01043 {
01044     FeatureList *fl;
01045 
01046     fl = msi_alloc( sizeof(*fl) );
01047     if ( !fl )
01048         return ERROR_NOT_ENOUGH_MEMORY;
01049     fl->feature = child;
01050     list_add_tail( &parent->Children, &fl->entry );
01051 
01052     return ERROR_SUCCESS;
01053 }
01054 
01055 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
01056 {
01057     _ilfs* ilfs = param;
01058     LPCWSTR component;
01059     MSICOMPONENT *comp;
01060 
01061     component = MSI_RecordGetString(row,1);
01062 
01063     /* check to see if the component is already loaded */
01064     comp = msi_get_loaded_component( ilfs->package, component );
01065     if (!comp)
01066     {
01067         WARN("ignoring unknown component %s\n", debugstr_w(component));
01068         return ERROR_SUCCESS;
01069     }
01070     add_feature_component( ilfs->feature, comp );
01071     comp->Enabled = TRUE;
01072 
01073     return ERROR_SUCCESS;
01074 }
01075 
01076 static UINT load_feature(MSIRECORD * row, LPVOID param)
01077 {
01078     static const WCHAR query[] = {
01079         'S','E','L','E','C','T',' ','`','C','o','m','p','o','n','e','n','t','_','`',
01080          ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
01081          'C','o','m','p','o','n','e','n','t','s','`',' ','W','H','E','R','E',' ',
01082          '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
01083     MSIPACKAGE *package = param;
01084     MSIFEATURE *feature;
01085     MSIQUERY *view;
01086     _ilfs ilfs;
01087     UINT rc;
01088 
01089     /* fill in the data */
01090 
01091     feature = msi_alloc_zero( sizeof (MSIFEATURE) );
01092     if (!feature)
01093         return ERROR_NOT_ENOUGH_MEMORY;
01094 
01095     list_init( &feature->Children );
01096     list_init( &feature->Components );
01097     
01098     feature->Feature = msi_dup_record_field( row, 1 );
01099 
01100     TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
01101 
01102     feature->Feature_Parent = msi_dup_record_field( row, 2 );
01103     feature->Title = msi_dup_record_field( row, 3 );
01104     feature->Description = msi_dup_record_field( row, 4 );
01105 
01106     if (!MSI_RecordIsNull(row,5))
01107         feature->Display = MSI_RecordGetInteger(row,5);
01108   
01109     feature->Level= MSI_RecordGetInteger(row,6);
01110     feature->Directory = msi_dup_record_field( row, 7 );
01111     feature->Attributes = MSI_RecordGetInteger(row,8);
01112 
01113     feature->Installed = INSTALLSTATE_UNKNOWN;
01114     feature->Action = INSTALLSTATE_UNKNOWN;
01115     feature->ActionRequest = INSTALLSTATE_UNKNOWN;
01116 
01117     list_add_tail( &package->features, &feature->entry );
01118 
01119     /* load feature components */
01120 
01121     rc = MSI_OpenQuery( package->db, &view, query, feature->Feature );
01122     if (rc != ERROR_SUCCESS)
01123         return ERROR_SUCCESS;
01124 
01125     ilfs.package = package;
01126     ilfs.feature = feature;
01127 
01128     rc = MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
01129     msiobj_release(&view->hdr);
01130     return rc;
01131 }
01132 
01133 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
01134 {
01135     MSIPACKAGE *package = param;
01136     MSIFEATURE *parent, *child;
01137 
01138     child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) );
01139     if (!child)
01140         return ERROR_FUNCTION_FAILED;
01141 
01142     if (!child->Feature_Parent)
01143         return ERROR_SUCCESS;
01144 
01145     parent = msi_get_loaded_feature( package, child->Feature_Parent );
01146     if (!parent)
01147         return ERROR_FUNCTION_FAILED;
01148 
01149     add_feature_child( parent, child );
01150     return ERROR_SUCCESS;
01151 }
01152 
01153 UINT msi_load_all_features( MSIPACKAGE *package )
01154 {
01155     static const WCHAR query[] = {
01156         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
01157         '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',' ','B','Y',' ',
01158         '`','D','i','s','p','l','a','y','`',0};
01159     MSIQUERY *view;
01160     UINT r;
01161 
01162     if (!list_empty(&package->features))
01163         return ERROR_SUCCESS;
01164  
01165     r = MSI_DatabaseOpenViewW( package->db, query, &view );
01166     if (r != ERROR_SUCCESS)
01167         return r;
01168 
01169     r = MSI_IterateRecords( view, NULL, load_feature, package );
01170     if (r != ERROR_SUCCESS)
01171     {
01172         msiobj_release( &view->hdr );
01173         return r;
01174     }
01175     r = MSI_IterateRecords( view, NULL, find_feature_children, package );
01176     msiobj_release( &view->hdr );
01177     return r;
01178 }
01179 
01180 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
01181 {
01182     if (!p)
01183         return p;
01184     p = strchrW(p, ch);
01185     if (!p)
01186         return p;
01187     *p = 0;
01188     return p+1;
01189 }
01190 
01191 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
01192 {
01193     static const WCHAR query[] = {
01194         'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
01195         '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
01196         'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
01197     MSIQUERY *view = NULL;
01198     MSIRECORD *row = NULL;
01199     UINT r;
01200 
01201     TRACE("%s\n", debugstr_w(file->File));
01202 
01203     r = MSI_OpenQuery(package->db, &view, query, file->File);
01204     if (r != ERROR_SUCCESS)
01205         goto done;
01206 
01207     r = MSI_ViewExecute(view, NULL);
01208     if (r != ERROR_SUCCESS)
01209         goto done;
01210 
01211     r = MSI_ViewFetch(view, &row);
01212     if (r != ERROR_SUCCESS)
01213         goto done;
01214 
01215     file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
01216     file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
01217     file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
01218     file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
01219     file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
01220 
01221 done:
01222     if (view) msiobj_release(&view->hdr);
01223     if (row) msiobj_release(&row->hdr);
01224     return r;
01225 }
01226 
01227 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
01228 {
01229     MSIRECORD *row;
01230     static const WCHAR query[] = {
01231         'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
01232         '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
01233         '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
01234 
01235     row = MSI_QueryGetRecord( package->db, query, file->Sequence );
01236     if (!row)
01237     {
01238         WARN("query failed\n");
01239         return ERROR_FUNCTION_FAILED;
01240     }
01241 
01242     file->disk_id = MSI_RecordGetInteger( row, 1 );
01243     msiobj_release( &row->hdr );
01244     return ERROR_SUCCESS;
01245 }
01246 
01247 static UINT load_file(MSIRECORD *row, LPVOID param)
01248 {
01249     MSIPACKAGE* package = param;
01250     LPCWSTR component;
01251     MSIFILE *file;
01252 
01253     /* fill in the data */
01254 
01255     file = msi_alloc_zero( sizeof (MSIFILE) );
01256     if (!file)
01257         return ERROR_NOT_ENOUGH_MEMORY;
01258  
01259     file->File = msi_dup_record_field( row, 1 );
01260 
01261     component = MSI_RecordGetString( row, 2 );
01262     file->Component = msi_get_loaded_component( package, component );
01263 
01264     if (!file->Component)
01265     {
01266         WARN("Component not found: %s\n", debugstr_w(component));
01267         msi_free(file->File);
01268         msi_free(file);
01269         return ERROR_SUCCESS;
01270     }
01271 
01272     file->FileName = msi_dup_record_field( row, 3 );
01273     msi_reduce_to_long_filename( file->FileName );
01274 
01275     file->ShortName = msi_dup_record_field( row, 3 );
01276     file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
01277     
01278     file->FileSize = MSI_RecordGetInteger( row, 4 );
01279     file->Version = msi_dup_record_field( row, 5 );
01280     file->Language = msi_dup_record_field( row, 6 );
01281     file->Attributes = MSI_RecordGetInteger( row, 7 );
01282     file->Sequence = MSI_RecordGetInteger( row, 8 );
01283 
01284     file->state = msifs_invalid;
01285 
01286     /* if the compressed bits are not set in the file attributes,
01287      * then read the information from the package word count property
01288      */
01289     if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
01290     {
01291         file->IsCompressed = FALSE;
01292     }
01293     else if (file->Attributes &
01294              (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
01295     {
01296         file->IsCompressed = TRUE;
01297     }
01298     else if (file->Attributes & msidbFileAttributesNoncompressed)
01299     {
01300         file->IsCompressed = FALSE;
01301     }
01302     else
01303     {
01304         file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
01305     }
01306 
01307     load_file_hash(package, file);
01308     load_file_disk_id(package, file);
01309 
01310     TRACE("File Loaded (%s)\n",debugstr_w(file->File));  
01311 
01312     list_add_tail( &package->files, &file->entry );
01313  
01314     return ERROR_SUCCESS;
01315 }
01316 
01317 static UINT load_all_files(MSIPACKAGE *package)
01318 {
01319     static const WCHAR query[] = {
01320         'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
01321         '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
01322         '`','S','e','q','u','e','n','c','e','`', 0};
01323     MSIQUERY *view;
01324     UINT rc;
01325 
01326     if (!list_empty(&package->files))
01327         return ERROR_SUCCESS;
01328 
01329     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
01330     if (rc != ERROR_SUCCESS)
01331         return ERROR_SUCCESS;
01332 
01333     rc = MSI_IterateRecords(view, NULL, load_file, package);
01334     msiobj_release(&view->hdr);
01335     return rc;
01336 }
01337 
01338 static UINT load_media( MSIRECORD *row, LPVOID param )
01339 {
01340     MSIPACKAGE *package = param;
01341     UINT disk_id = MSI_RecordGetInteger( row, 1 );
01342     const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
01343 
01344     /* FIXME: load external cabinets and directory sources too */
01345     if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
01346     msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
01347     return ERROR_SUCCESS;
01348 }
01349 
01350 static UINT load_all_media( MSIPACKAGE *package )
01351 {
01352     static const WCHAR query[] = {
01353         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`',
01354         'M','e','d','i','a','`',' ','O','R','D','E','R',' ','B','Y',' ',
01355         '`','D','i','s','k','I','d','`',0};
01356     MSIQUERY *view;
01357     UINT r;
01358 
01359     r = MSI_DatabaseOpenViewW( package->db, query, &view );
01360     if (r != ERROR_SUCCESS)
01361         return ERROR_SUCCESS;
01362 
01363     r = MSI_IterateRecords( view, NULL, load_media, package );
01364     msiobj_release( &view->hdr );
01365     return r;
01366 }
01367 
01368 static UINT load_patch(MSIRECORD *row, LPVOID param)
01369 {
01370     MSIPACKAGE *package = param;
01371     MSIFILEPATCH *patch;
01372     LPWSTR file_key;
01373 
01374     patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
01375     if (!patch)
01376         return ERROR_NOT_ENOUGH_MEMORY;
01377 
01378     file_key = msi_dup_record_field( row, 1 );
01379     patch->File = msi_get_loaded_file( package, file_key );
01380     msi_free(file_key);
01381 
01382     if( !patch->File )
01383     {
01384         ERR("Failed to find target for patch in File table\n");
01385         msi_free(patch);
01386         return ERROR_FUNCTION_FAILED;
01387     }
01388 
01389     patch->Sequence = MSI_RecordGetInteger( row, 2 );
01390 
01391     /* FIXME: The database should be properly transformed */
01392     patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
01393 
01394     patch->PatchSize = MSI_RecordGetInteger( row, 3 );
01395     patch->Attributes = MSI_RecordGetInteger( row, 4 );
01396     patch->IsApplied = FALSE;
01397 
01398     /* FIXME:
01399      * Header field - for patch validation.
01400      * _StreamRef   - External key into MsiPatchHeaders (instead of the header field)
01401      */
01402 
01403     TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
01404 
01405     list_add_tail( &package->filepatches, &patch->entry );
01406 
01407     return ERROR_SUCCESS;
01408 }
01409 
01410 static UINT load_all_patches(MSIPACKAGE *package)
01411 {
01412     static const WCHAR query[] = {
01413         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
01414         '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
01415         '`','S','e','q','u','e','n','c','e','`',0};
01416     MSIQUERY *view;
01417     UINT rc;
01418 
01419     if (!list_empty(&package->filepatches))
01420         return ERROR_SUCCESS;
01421 
01422     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
01423     if (rc != ERROR_SUCCESS)
01424         return ERROR_SUCCESS;
01425 
01426     rc = MSI_IterateRecords(view, NULL, load_patch, package);
01427     msiobj_release(&view->hdr);
01428     return rc;
01429 }
01430 
01431 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
01432 {
01433     static const WCHAR query[] = {
01434         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
01435         '`','C','r','e','a','t','e','F','o','l','d','e','r','`',' ','W','H','E','R','E',' ',
01436         '`','D','i','r','e','c','t','o','r','y','_','`',' ','=','\'','%','s','\'',0};
01437     MSIQUERY *view;
01438 
01439     folder->persistent = FALSE;
01440     if (!MSI_OpenQuery( package->db, &view, query, folder->Directory ))
01441     {
01442         if (!MSI_ViewExecute( view, NULL ))
01443         {
01444             MSIRECORD *rec;
01445             if (!MSI_ViewFetch( view, &rec ))
01446             {
01447                 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory));
01448                 folder->persistent = TRUE;
01449                 msiobj_release( &rec->hdr );
01450             }
01451         }
01452         msiobj_release( &view->hdr );
01453     }
01454     return ERROR_SUCCESS;
01455 }
01456 
01457 static UINT load_folder( MSIRECORD *row, LPVOID param )
01458 {
01459     MSIPACKAGE *package = param;
01460     static WCHAR szEmpty[] = { 0 };
01461     LPWSTR p, tgt_short, tgt_long, src_short, src_long;
01462     MSIFOLDER *folder;
01463 
01464     if (!(folder = msi_alloc_zero( sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY;
01465     list_init( &folder->children );
01466     folder->Directory = msi_dup_record_field( row, 1 );
01467     folder->Parent = msi_dup_record_field( row, 2 );
01468     p = msi_dup_record_field(row, 3);
01469 
01470     TRACE("%s\n", debugstr_w(folder->Directory));
01471 
01472     /* split src and target dir */
01473     tgt_short = p;
01474     src_short = folder_split_path( p, ':' );
01475 
01476     /* split the long and short paths */
01477     tgt_long = folder_split_path( tgt_short, '|' );
01478     src_long = folder_split_path( src_short, '|' );
01479 
01480     /* check for no-op dirs */
01481     if (tgt_short && !strcmpW( szDot, tgt_short ))
01482         tgt_short = szEmpty;
01483     if (src_short && !strcmpW( szDot, src_short ))
01484         src_short = szEmpty;
01485 
01486     if (!tgt_long)
01487         tgt_long = tgt_short;
01488 
01489     if (!src_short) {
01490         src_short = tgt_short;
01491         src_long = tgt_long;
01492     }
01493 
01494     if (!src_long)
01495         src_long = src_short;
01496 
01497     /* FIXME: use the target short path too */
01498     folder->TargetDefault = strdupW(tgt_long);
01499     folder->SourceShortPath = strdupW(src_short);
01500     folder->SourceLongPath = strdupW(src_long);
01501     msi_free(p);
01502 
01503     TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
01504     TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
01505     TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
01506 
01507     load_folder_persistence( package, folder );
01508 
01509     list_add_tail( &package->folders, &folder->entry );
01510     return ERROR_SUCCESS;
01511 }
01512 
01513 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
01514 {
01515     FolderList *fl;
01516 
01517     if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
01518     fl->folder = child;
01519     list_add_tail( &parent->children, &fl->entry );
01520     return ERROR_SUCCESS;
01521 }
01522 
01523 static UINT find_folder_children( MSIRECORD *row, LPVOID param )
01524 {
01525     MSIPACKAGE *package = param;
01526     MSIFOLDER *parent, *child;
01527 
01528     if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
01529         return ERROR_FUNCTION_FAILED;
01530 
01531     if (!child->Parent) return ERROR_SUCCESS;
01532 
01533     if (!(parent = msi_get_loaded_folder( package, child->Parent )))
01534         return ERROR_FUNCTION_FAILED;
01535 
01536     return add_folder_child( parent, child );
01537 }
01538 
01539 static UINT load_all_folders( MSIPACKAGE *package )
01540 {
01541     static const WCHAR query[] = {
01542         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
01543         '`','D','i','r','e','c','t','o','r','y','`',0};
01544     MSIQUERY *view;
01545     UINT r;
01546 
01547     if (!list_empty(&package->folders))
01548         return ERROR_SUCCESS;
01549 
01550     r = MSI_DatabaseOpenViewW( package->db, query, &view );
01551     if (r != ERROR_SUCCESS)
01552         return r;
01553 
01554     r = MSI_IterateRecords( view, NULL, load_folder, package );
01555     if (r != ERROR_SUCCESS)
01556     {
01557         msiobj_release( &view->hdr );
01558         return r;
01559     }
01560     r = MSI_IterateRecords( view, NULL, find_folder_children, package );
01561     msiobj_release( &view->hdr );
01562     return r;
01563 }
01564 
01565 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
01566 {
01567     msi_set_property( package->db, szCostingComplete, szZero );
01568     msi_set_property( package->db, szRootDrive, szCRoot );
01569 
01570     load_all_folders( package );
01571     msi_load_all_components( package );
01572     msi_load_all_features( package );
01573     load_all_files( package );
01574     load_all_patches( package );
01575     load_all_media( package );
01576 
01577     return ERROR_SUCCESS;
01578 }
01579 
01580 static UINT execute_script_action( MSIPACKAGE *package, UINT script, UINT index )
01581 {
01582     const WCHAR *action = package->script->Actions[script][index];
01583     ui_actionstart( package, action );
01584     TRACE("executing %s\n", debugstr_w(action));
01585     return ACTION_PerformAction( package, action, script );
01586 }
01587 
01588 static UINT execute_script( MSIPACKAGE *package, UINT script )
01589 {
01590     UINT i, rc = ERROR_SUCCESS;
01591 
01592     TRACE("executing script %u\n", script);
01593 
01594     if (!package->script)
01595     {
01596         ERR("no script!\n");
01597         return ERROR_FUNCTION_FAILED;
01598     }
01599     if (script == SCRIPT_ROLLBACK)
01600     {
01601         for (i = package->script->ActionCount[script]; i > 0; i--)
01602         {
01603             rc = execute_script_action( package, script, i - 1 );
01604             if (rc != ERROR_SUCCESS) break;
01605         }
01606     }
01607     else
01608     {
01609         for (i = 0; i < package->script->ActionCount[script]; i++)
01610         {
01611             rc = execute_script_action( package, script, i );
01612             if (rc != ERROR_SUCCESS) break;
01613         }
01614     }
01615     msi_free_action_script(package, script);
01616     return rc;
01617 }
01618 
01619 static UINT ACTION_FileCost(MSIPACKAGE *package)
01620 {
01621     return ERROR_SUCCESS;
01622 }
01623 
01624 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
01625 {
01626     MSICOMPONENT *comp;
01627     UINT r;
01628 
01629     LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
01630     {
01631         if (!comp->ComponentId) continue;
01632 
01633         r = MsiQueryComponentStateW( package->ProductCode, NULL,
01634                                      MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
01635                                      &comp->Installed );
01636         if (r == ERROR_SUCCESS) continue;
01637 
01638         r = MsiQueryComponentStateW( package->ProductCode, NULL,
01639                                      MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
01640                                      &comp->Installed );
01641         if (r == ERROR_SUCCESS) continue;
01642 
01643         r = MsiQueryComponentStateW( package->ProductCode, NULL,
01644                                      MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
01645                                      &comp->Installed );
01646         if (r == ERROR_SUCCESS) continue;
01647 
01648         comp->Installed = INSTALLSTATE_ABSENT;
01649     }
01650 }
01651 
01652 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
01653 {
01654     MSIFEATURE *feature;
01655 
01656     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
01657     {
01658         INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
01659 
01660         if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
01661             feature->Installed = INSTALLSTATE_ABSENT;
01662         else
01663             feature->Installed = state;
01664     }
01665 }
01666 
01667 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
01668 {
01669     return (feature->Level > 0 && feature->Level <= level);
01670 }
01671 
01672 static BOOL process_state_property(MSIPACKAGE* package, int level,
01673                                    LPCWSTR property, INSTALLSTATE state)
01674 {
01675     LPWSTR override;
01676     MSIFEATURE *feature;
01677 
01678     override = msi_dup_property( package->db, property );
01679     if (!override)
01680         return FALSE;
01681 
01682     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
01683     {
01684         if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
01685             continue;
01686 
01687         if (!strcmpW(property, szReinstall)) state = feature->Installed;
01688 
01689         if (!strcmpiW( override, szAll ))
01690         {
01691             if (feature->Installed != state)
01692             {
01693                 feature->Action = state;
01694                 feature->ActionRequest = state;
01695             }
01696         }
01697         else
01698         {
01699             LPWSTR ptr = override;
01700             LPWSTR ptr2 = strchrW(override,',');
01701 
01702             while (ptr)
01703             {
01704                 int len = ptr2 - ptr;
01705 
01706                 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
01707                     || (!ptr2 && !strcmpW(ptr, feature->Feature)))
01708                 {
01709                     if (feature->Installed != state)
01710                     {
01711                         feature->Action = state;
01712                         feature->ActionRequest = state;
01713                     }
01714                     break;
01715                 }
01716                 if (ptr2)
01717                 {
01718                     ptr=ptr2+1;
01719                     ptr2 = strchrW(ptr,',');
01720                 }
01721                 else
01722                     break;
01723             }
01724         }
01725     }
01726     msi_free(override);
01727     return TRUE;
01728 }
01729 
01730 static BOOL process_overrides( MSIPACKAGE *package, int level )
01731 {
01732     static const WCHAR szAddLocal[] =
01733         {'A','D','D','L','O','C','A','L',0};
01734     static const WCHAR szAddSource[] =
01735         {'A','D','D','S','O','U','R','C','E',0};
01736     static const WCHAR szAdvertise[] =
01737         {'A','D','V','E','R','T','I','S','E',0};
01738     BOOL ret = FALSE;
01739 
01740     /* all these activation/deactivation things happen in order and things
01741      * later on the list override things earlier on the list.
01742      *
01743      *  0  INSTALLLEVEL processing
01744      *  1  ADDLOCAL
01745      *  2  REMOVE
01746      *  3  ADDSOURCE
01747      *  4  ADDDEFAULT
01748      *  5  REINSTALL
01749      *  6  ADVERTISE
01750      *  7  COMPADDLOCAL
01751      *  8  COMPADDSOURCE
01752      *  9  FILEADDLOCAL
01753      * 10  FILEADDSOURCE
01754      * 11  FILEADDDEFAULT
01755      */
01756     ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
01757     ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
01758     ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
01759     ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
01760     ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
01761 
01762     if (ret)
01763         msi_set_property( package->db, szPreselected, szOne );
01764 
01765     return ret;
01766 }
01767 
01768 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
01769 {
01770     int level;
01771     MSICOMPONENT* component;
01772     MSIFEATURE *feature;
01773 
01774     TRACE("Checking Install Level\n");
01775 
01776     level = msi_get_property_int(package->db, szInstallLevel, 1);
01777 
01778     if (!msi_get_property_int( package->db, szPreselected, 0 ))
01779     {
01780         LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
01781         {
01782             if (!is_feature_selected( feature, level )) continue;
01783 
01784             if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
01785             {
01786                 if (feature->Attributes & msidbFeatureAttributesFavorSource)
01787                 {
01788                     feature->Action = INSTALLSTATE_SOURCE;
01789                     feature->ActionRequest = INSTALLSTATE_SOURCE;
01790                 }
01791                 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
01792                 {
01793                     feature->Action = INSTALLSTATE_ADVERTISED;
01794                     feature->ActionRequest = INSTALLSTATE_ADVERTISED;
01795                 }
01796                 else
01797                 {
01798                     feature->Action = INSTALLSTATE_LOCAL;
01799                     feature->ActionRequest = INSTALLSTATE_LOCAL;
01800                 }
01801             }
01802         }
01803         /* disable child features of unselected parent or follow parent */
01804         LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
01805         {
01806             FeatureList *fl;
01807 
01808             LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
01809             {
01810                 if (!is_feature_selected( feature, level ))
01811                 {
01812                     fl->feature->Action = INSTALLSTATE_UNKNOWN;
01813                     fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
01814                 }
01815                 else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
01816                 {
01817                     TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
01818                           debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
01819                           debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
01820                     fl->feature->Action = feature->Action;
01821                     fl->feature->ActionRequest = feature->ActionRequest;
01822                 }
01823             }
01824         }
01825     }
01826     else /* preselected */
01827     {
01828         LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
01829         {
01830             if (!is_feature_selected( feature, level )) continue;
01831 
01832             if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
01833             {
01834                 if (feature->Installed == INSTALLSTATE_ABSENT)
01835                 {
01836                     feature->Action = INSTALLSTATE_UNKNOWN;
01837                     feature->ActionRequest = INSTALLSTATE_UNKNOWN;
01838                 }
01839                 else
01840                 {
01841                     feature->Action = feature->Installed;
01842                     feature->ActionRequest = feature->Installed;
01843                 }
01844             }
01845         }
01846         LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
01847         {
01848             FeatureList *fl;
01849 
01850             LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
01851             {
01852                 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent &&
01853                     (!(feature->Attributes & msidbFeatureAttributesFavorAdvertise)))
01854                 {
01855                     TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
01856                           debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
01857                           debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
01858                     fl->feature->Action = feature->Action;
01859                     fl->feature->ActionRequest = feature->ActionRequest;
01860                 }
01861             }
01862         }
01863     }
01864 
01865     /* now we want to set component state based based on feature state */
01866     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
01867     {
01868         ComponentList *cl;
01869 
01870         TRACE("examining feature %s (level %d installed %d request %d action %d)\n",
01871               debugstr_w(feature->Feature), feature->Level, feature->Installed,
01872               feature->ActionRequest, feature->Action);
01873 
01874         if (!is_feature_selected( feature, level )) continue;
01875 
01876         /* features with components that have compressed files are made local */
01877         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
01878         {
01879             if (cl->component->ForceLocalState &&
01880                 feature->ActionRequest == INSTALLSTATE_SOURCE)
01881             {
01882                 feature->Action = INSTALLSTATE_LOCAL;
01883                 feature->ActionRequest = INSTALLSTATE_LOCAL;
01884                 break;
01885             }
01886         }
01887 
01888         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
01889         {
01890             component = cl->component;
01891 
01892             switch (feature->ActionRequest)
01893             {
01894             case INSTALLSTATE_ABSENT:
01895                 component->anyAbsent = 1;
01896                 break;
01897             case INSTALLSTATE_ADVERTISED:
01898                 component->hasAdvertiseFeature = 1;
01899                 break;
01900             case INSTALLSTATE_SOURCE:
01901                 component->hasSourceFeature = 1;
01902                 break;
01903             case INSTALLSTATE_LOCAL:
01904                 component->hasLocalFeature = 1;
01905                 break;
01906             case INSTALLSTATE_DEFAULT:
01907                 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
01908                     component->hasAdvertiseFeature = 1;
01909                 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
01910                     component->hasSourceFeature = 1;
01911                 else
01912                     component->hasLocalFeature = 1;
01913                 break;
01914             default:
01915                 break;
01916             }
01917         }
01918     }
01919 
01920     LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
01921     {
01922         /* check if it's local or source */
01923         if (!(component->Attributes & msidbComponentAttributesOptional) &&
01924              (component->hasLocalFeature || component->hasSourceFeature))
01925         {
01926             if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
01927                  !component->ForceLocalState)
01928             {
01929                 component->Action = INSTALLSTATE_SOURCE;
01930                 component->ActionRequest = INSTALLSTATE_SOURCE;
01931             }
01932             else
01933             {
01934                 component->Action = INSTALLSTATE_LOCAL;
01935                 component->ActionRequest = INSTALLSTATE_LOCAL;
01936             }
01937             continue;
01938         }
01939 
01940         /* if any feature is local, the component must be local too */
01941         if (component->hasLocalFeature)
01942         {
01943             component->Action = INSTALLSTATE_LOCAL;
01944             component->ActionRequest = INSTALLSTATE_LOCAL;
01945             continue;
01946         }
01947         if (component->hasSourceFeature)
01948         {
01949             component->Action = INSTALLSTATE_SOURCE;
01950             component->ActionRequest = INSTALLSTATE_SOURCE;
01951             continue;
01952         }
01953         if (component->hasAdvertiseFeature)
01954         {
01955             component->Action = INSTALLSTATE_ADVERTISED;
01956             component->ActionRequest = INSTALLSTATE_ADVERTISED;
01957             continue;
01958         }
01959         TRACE("nobody wants component %s\n", debugstr_w(component->Component));
01960         if (component->anyAbsent &&
01961             (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
01962         {
01963             component->Action = INSTALLSTATE_ABSENT;
01964             component->ActionRequest = INSTALLSTATE_ABSENT;
01965         }
01966     }
01967 
01968     LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
01969     {
01970         if (component->ActionRequest == INSTALLSTATE_DEFAULT)
01971         {
01972             TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
01973             component->Action = INSTALLSTATE_LOCAL;
01974             component->ActionRequest = INSTALLSTATE_LOCAL;
01975         }
01976 
01977         if (component->ActionRequest == INSTALLSTATE_SOURCE &&
01978             component->Installed == INSTALLSTATE_SOURCE &&
01979             component->hasSourceFeature)
01980         {
01981             component->Action = INSTALLSTATE_UNKNOWN;
01982             component->ActionRequest = INSTALLSTATE_UNKNOWN;
01983         }
01984 
01985         TRACE("component %s (installed %d request %d action %d)\n",
01986               debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
01987     }
01988 
01989     return ERROR_SUCCESS;
01990 }
01991 
01992 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
01993 {
01994     MSIPACKAGE *package = param;
01995     LPCWSTR name;
01996     MSIFEATURE *feature;
01997 
01998     name = MSI_RecordGetString( row, 1 );
01999 
02000     feature = msi_get_loaded_feature( package, name );
02001     if (!feature)
02002         ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
02003     else
02004     {
02005         LPCWSTR Condition;
02006         Condition = MSI_RecordGetString(row,3);
02007 
02008         if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
02009         {
02010             int level = MSI_RecordGetInteger(row,2);
02011             TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
02012             feature->Level = level;
02013         }
02014     }
02015     return ERROR_SUCCESS;
02016 }
02017 
02018 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
02019 {
02020     static const WCHAR name[] = {'\\',0};
02021     VS_FIXEDFILEINFO *ptr, *ret;
02022     LPVOID version;
02023     DWORD versize, handle;
02024     UINT sz;
02025 
02026     versize = GetFileVersionInfoSizeW( filename, &handle );
02027     if (!versize)
02028         return NULL;
02029 
02030     version = msi_alloc( versize );
02031     if (!version)
02032         return NULL;
02033 
02034     GetFileVersionInfoW( filename, 0, versize, version );
02035 
02036     if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
02037     {
02038         msi_free( version );
02039         return NULL;
02040     }
02041 
02042     ret = msi_alloc( sz );
02043     memcpy( ret, ptr, sz );
02044 
02045     msi_free( version );
02046     return ret;
02047 }
02048 
02049 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
02050 {
02051     DWORD ms, ls;
02052 
02053     msi_parse_version_string( version, &ms, &ls );
02054 
02055     if (fi->dwFileVersionMS > ms) return 1;
02056     else if (fi->dwFileVersionMS < ms) return -1;
02057     else if (fi->dwFileVersionLS > ls) return 1;
02058     else if (fi->dwFileVersionLS < ls) return -1;
02059     return 0;
02060 }
02061 
02062 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
02063 {
02064     DWORD ms1, ms2;
02065 
02066     msi_parse_version_string( ver1, &ms1, NULL );
02067     msi_parse_version_string( ver2, &ms2, NULL );
02068 
02069     if (ms1 > ms2) return 1;
02070     else if (ms1 < ms2) return -1;
02071     return 0;
02072 }
02073 
02074 DWORD msi_get_disk_file_size( LPCWSTR filename )
02075 {
02076     HANDLE file;
02077     DWORD size;
02078 
02079     file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
02080     if (file == INVALID_HANDLE_VALUE)
02081         return INVALID_FILE_SIZE;
02082 
02083     size = GetFileSize( file, NULL );
02084     TRACE("size is %u\n", size);
02085     CloseHandle( file );
02086     return size;
02087 }
02088 
02089 BOOL msi_file_hash_matches( MSIFILE *file )
02090 {
02091     UINT r;
02092     MSIFILEHASHINFO hash;
02093 
02094     hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
02095     r = MsiGetFileHashW( file->TargetPath, 0, &hash );
02096     if (r != ERROR_SUCCESS)
02097         return FALSE;
02098 
02099     return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
02100 }
02101 
02102 static WCHAR *get_temp_dir( void )
02103 {
02104     static UINT id;
02105     WCHAR tmp[MAX_PATH], dir[MAX_PATH];
02106 
02107     GetTempPathW( MAX_PATH, tmp );
02108     for (;;)
02109     {
02110         if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
02111         if (CreateDirectoryW( dir, NULL )) break;
02112     }
02113     return strdupW( dir );
02114 }
02115 
02116 /*
02117  *  msi_build_directory_name()
02118  *
02119  *  This function is to save messing round with directory names
02120  *  It handles adding backslashes between path segments,
02121  *  and can add \ at the end of the directory name if told to.
02122  *
02123  *  It takes a variable number of arguments.
02124  *  It always allocates a new string for the result, so make sure
02125  *  to free the return value when finished with it.
02126  *
02127  *  The first arg is the number of path segments that follow.
02128  *  The arguments following count are a list of path segments.
02129  *  A path segment may be NULL.
02130  *
02131  *  Path segments will be added with a \ separating them.
02132  *  A \ will not be added after the last segment, however if the
02133  *  last segment is NULL, then the last character will be a \
02134  */
02135 WCHAR *msi_build_directory_name( DWORD count, ... )
02136 {
02137     DWORD sz = 1, i;
02138     WCHAR *dir;
02139     va_list va;
02140 
02141     va_start( va, count );
02142     for (i = 0; i < count; i++)
02143     {
02144         const WCHAR *str = va_arg( va, const WCHAR * );
02145         if (str) sz += strlenW( str ) + 1;
02146     }
02147     va_end( va );
02148 
02149     dir = msi_alloc( sz * sizeof(WCHAR) );
02150     dir[0] = 0;
02151 
02152     va_start( va, count );
02153     for (i = 0; i < count; i++)
02154     {
02155         const WCHAR *str = va_arg( va, const WCHAR * );
02156         if (!str) continue;
02157         strcatW( dir, str );
02158         if ( i + 1 != count && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash );
02159     }
02160     va_end( va );
02161     return dir;
02162 }
02163 
02164 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
02165 {
02166     MSIASSEMBLY *assembly = file->Component->assembly;
02167 
02168     TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
02169 
02170     msi_free( file->TargetPath );
02171     if (assembly && !assembly->application)
02172     {
02173         if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
02174         file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
02175         msi_track_tempfile( package, file->TargetPath );
02176     }
02177     else
02178     {
02179         const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
02180         file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
02181     }
02182 
02183     TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
02184 }
02185 
02186 static UINT calculate_file_cost( MSIPACKAGE *package )
02187 {
02188     VS_FIXEDFILEINFO *file_version;
02189     WCHAR *font_version;
02190     MSIFILE *file;
02191 
02192     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
02193     {
02194         MSICOMPONENT *comp = file->Component;
02195         DWORD file_size;
02196 
02197         if (!comp->Enabled) continue;
02198 
02199         if (file->IsCompressed)
02200             comp->ForceLocalState = TRUE;
02201 
02202         set_target_path( package, file );
02203 
02204         if ((comp->assembly && !comp->assembly->installed) ||
02205             GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
02206         {
02207             comp->Cost += file->FileSize;
02208             continue;
02209         }
02210         file_size = msi_get_disk_file_size( file->TargetPath );
02211 
02212         if (file->Version)
02213         {
02214             if ((file_version = msi_get_disk_file_version( file->TargetPath )))
02215             {
02216                 if (msi_compare_file_versions( file_version, file->Version ) < 0)
02217                 {
02218                     comp->Cost += file->FileSize - file_size;
02219                 }
02220                 msi_free( file_version );
02221                 continue;
02222             }
02223             else if ((font_version = msi_font_version_from_file( file->TargetPath )))
02224             {
02225                 if (msi_compare_font_versions( font_version, file->Version ) < 0)
02226                 {
02227                     comp->Cost += file->FileSize - file_size;
02228                 }
02229                 msi_free( font_version );
02230                 continue;
02231             }
02232         }
02233         if (file_size != file->FileSize)
02234         {
02235             comp->Cost += file->FileSize - file_size;
02236         }
02237     }
02238     return ERROR_SUCCESS;
02239 }
02240 
02241 WCHAR *msi_normalize_path( const WCHAR *in )
02242 {
02243     const WCHAR *p = in;
02244     WCHAR *q, *ret;
02245     int n, len = strlenW( in ) + 2;
02246 
02247     if (!(q = ret = msi_alloc( len * sizeof(WCHAR) ))) return NULL;
02248 
02249     len = 0;
02250     while (1)
02251     {
02252         /* copy until the end of the string or a space */
02253         while (*p != ' ' && (*q = *p))
02254         {
02255             p++, len++;
02256             /* reduce many backslashes to one */
02257             if (*p != '\\' || *q != '\\')
02258                 q++;
02259         }
02260 
02261         /* quit at the end of the string */
02262         if (!*p)
02263             break;
02264 
02265         /* count the number of spaces */
02266         n = 0;
02267         while (p[n] == ' ')
02268             n++;
02269 
02270         /* if it's leading or trailing space, skip it */
02271         if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
02272             p += n;
02273         else  /* copy n spaces */
02274             while (n && (*q++ = *p++)) n--;
02275     }
02276     while (q - ret > 0 && q[-1] == ' ') q--;
02277     if (q - ret > 0 && q[-1] != '\\')
02278     {
02279         q[0] = '\\';
02280         q[1] = 0;
02281     }
02282     return ret;
02283 }
02284 
02285 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
02286 {
02287     FolderList *fl;
02288     MSIFOLDER *folder, *parent, *child;
02289     WCHAR *path, *normalized_path;
02290 
02291     TRACE("resolving %s\n", debugstr_w(name));
02292 
02293     if (!(folder = msi_get_loaded_folder( package, name ))) return;
02294 
02295     if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
02296     {
02297         if (!load_prop || !(path = msi_dup_property( package->db, szTargetDir )))
02298         {
02299             path = msi_dup_property( package->db, szRootDrive );
02300         }
02301     }
02302     else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
02303     {
02304         if (folder->Parent && strcmpW( folder->Directory, folder->Parent ))
02305         {
02306             parent = msi_get_loaded_folder( package, folder->Parent );
02307             path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
02308         }
02309         else
02310             path = msi_build_directory_name( 2, folder->TargetDefault, NULL );
02311     }
02312     normalized_path = msi_normalize_path( path );
02313     msi_free( path );
02314     if (folder->ResolvedTarget && !strcmpiW( normalized_path, folder->ResolvedTarget ))
02315     {
02316         TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
02317         msi_free( normalized_path );
02318         return;
02319     }
02320     msi_set_property( package->db, folder->Directory, normalized_path );
02321     msi_free( folder->ResolvedTarget );
02322     folder->ResolvedTarget = normalized_path;
02323 
02324     LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
02325     {
02326         child = fl->folder;
02327         msi_resolve_target_folder( package, child->Directory, load_prop );
02328     }
02329     TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
02330 }
02331 
02332 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
02333 {
02334     static const WCHAR query[] = {
02335         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
02336         '`','C','o','n','d','i','t','i','o','n','`',0};
02337     static const WCHAR szOutOfDiskSpace[] = {
02338         'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
02339     MSICOMPONENT *comp;
02340     MSIQUERY *view;
02341     LPWSTR level;
02342     UINT rc;
02343 
02344     TRACE("Building directory properties\n");
02345     msi_resolve_target_folder( package, szTargetDir, TRUE );
02346 
02347     TRACE("Evaluating component conditions\n");
02348     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
02349     {
02350         if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
02351         {
02352             TRACE("Disabling component %s\n", debugstr_w(comp->Component));
02353             comp->Enabled = FALSE;
02354         }
02355         else
02356             comp->Enabled = TRUE;
02357     }
02358 
02359     /* read components states from the registry */
02360     ACTION_GetComponentInstallStates(package);
02361     ACTION_GetFeatureInstallStates(package);
02362 
02363     if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
02364     {
02365         TRACE("Evaluating feature conditions\n");
02366 
02367         rc = MSI_DatabaseOpenViewW( package->db, query, &view );
02368         if (rc == ERROR_SUCCESS)
02369         {
02370             rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
02371             msiobj_release( &view->hdr );
02372             if (rc != ERROR_SUCCESS)
02373                 return rc;
02374         }
02375     }
02376 
02377     TRACE("Calculating file cost\n");
02378     calculate_file_cost( package );
02379 
02380     msi_set_property( package->db, szCostingComplete, szOne );
02381     /* set default run level if not set */
02382     level = msi_dup_property( package->db, szInstallLevel );
02383     if (!level)
02384         msi_set_property( package->db, szInstallLevel, szOne );
02385     msi_free(level);
02386 
02387     /* FIXME: check volume disk space */
02388     msi_set_property( package->db, szOutOfDiskSpace, szZero );
02389 
02390     return MSI_SetFeatureStates(package);
02391 }
02392 
02393 /* OK this value is "interpreted" and then formatted based on the 
02394    first few characters */
02395 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type, 
02396                          DWORD *size)
02397 {
02398     LPSTR data = NULL;
02399 
02400     if (value[0]=='#' && value[1]!='#' && value[1]!='%')
02401     {
02402         if (value[1]=='x')
02403         {
02404             LPWSTR ptr;
02405             CHAR byte[5];
02406             LPWSTR deformated = NULL;
02407             int count;
02408 
02409             deformat_string(package, &value[2], &deformated);
02410 
02411             /* binary value type */
02412             ptr = deformated;
02413             *type = REG_BINARY;
02414             if (strlenW(ptr)%2)
02415                 *size = (strlenW(ptr)/2)+1;
02416             else
02417                 *size = strlenW(ptr)/2;
02418 
02419             data = msi_alloc(*size);
02420 
02421             byte[0] = '0'; 
02422             byte[1] = 'x'; 
02423             byte[4] = 0; 
02424             count = 0;
02425             /* if uneven pad with a zero in front */
02426             if (strlenW(ptr)%2)
02427             {
02428                 byte[2]= '0';
02429                 byte[3]= *ptr;
02430                 ptr++;
02431                 data[count] = (BYTE)strtol(byte,NULL,0);
02432                 count ++;
02433                 TRACE("Uneven byte count\n");
02434             }
02435             while (*ptr)
02436             {
02437                 byte[2]= *ptr;
02438                 ptr++;
02439                 byte[3]= *ptr;
02440                 ptr++;
02441                 data[count] = (BYTE)strtol(byte,NULL,0);
02442                 count ++;
02443             }
02444             msi_free(deformated);
02445 
02446             TRACE("Data %i bytes(%i)\n",*size,count);
02447         }
02448         else
02449         {
02450             LPWSTR deformated;
02451             LPWSTR p;
02452             DWORD d = 0;
02453             deformat_string(package, &value[1], &deformated);
02454 
02455             *type=REG_DWORD; 
02456             *size = sizeof(DWORD);
02457             data = msi_alloc(*size);
02458             p = deformated;
02459             if (*p == '-')
02460                 p++;
02461             while (*p)
02462             {
02463                 if ( (*p < '0') || (*p > '9') )
02464                     break;
02465                 d *= 10;
02466                 d += (*p - '0');
02467                 p++;
02468             }
02469             if (deformated[0] == '-')
02470                 d = -d;
02471             *(LPDWORD)data = d;
02472             TRACE("DWORD %i\n",*(LPDWORD)data);
02473 
02474             msi_free(deformated);
02475         }
02476     }
02477     else
02478     {
02479         static const WCHAR szMulti[] = {'[','~',']',0};
02480         LPCWSTR ptr;
02481         *type=REG_SZ;
02482 
02483         if (value[0]=='#')
02484         {
02485             if (value[1]=='%')
02486             {
02487                 ptr = &value[2];
02488                 *type=REG_EXPAND_SZ;
02489             }
02490             else
02491                 ptr = &value[1];
02492          }
02493          else
02494             ptr=value;
02495 
02496         if (strstrW(value, szMulti))
02497             *type = REG_MULTI_SZ;
02498 
02499         /* remove initial delimiter */
02500         if (!strncmpW(value, szMulti, 3))
02501             ptr = value + 3;
02502 
02503         *size = deformat_string(package, ptr,(LPWSTR*)&data);
02504 
02505         /* add double NULL terminator */
02506         if (*type == REG_MULTI_SZ)
02507         {
02508             *size += 2 * sizeof(WCHAR); /* two NULL terminators */
02509             data = msi_realloc_zero(data, *size);
02510         }
02511     }
02512     return data;
02513 }
02514 
02515 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
02516 {
02517     const WCHAR *ret;
02518 
02519     switch (root)
02520     {
02521     case -1:
02522         if (msi_get_property_int( package->db, szAllUsers, 0 ))
02523         {
02524             *root_key = HKEY_LOCAL_MACHINE;
02525             ret = szHLM;
02526         }
02527         else
02528         {
02529             *root_key = HKEY_CURRENT_USER;
02530             ret = szHCU;
02531         }
02532         break;
02533     case 0:
02534         *root_key = HKEY_CLASSES_ROOT;
02535         ret = szHCR;
02536         break;
02537     case 1:
02538         *root_key = HKEY_CURRENT_USER;
02539         ret = szHCU;
02540         break;
02541     case 2:
02542         *root_key = HKEY_LOCAL_MACHINE;
02543         ret = szHLM;
02544         break;
02545     case 3:
02546         *root_key = HKEY_USERS;
02547         ret = szHU;
02548         break;
02549     default:
02550         ERR("Unknown root %i\n", root);
02551         return NULL;
02552     }
02553 
02554     return ret;
02555 }
02556 
02557 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
02558 {
02559     static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
02560     static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
02561 
02562     if (is_64bit && package->platform == PLATFORM_INTEL &&
02563         root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
02564     {
02565         UINT size;
02566         WCHAR *path_32node;
02567 
02568         size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
02569         if (!(path_32node = msi_alloc( size ))) return NULL;
02570 
02571         memcpy( path_32node, path, len * sizeof(WCHAR) );
02572         strcpyW( path_32node + len, szWow6432Node );
02573         strcatW( path_32node, szBackSlash );
02574         strcatW( path_32node, path + len );
02575         return path_32node;
02576     }
02577 
02578     return strdupW( path );
02579 }
02580 
02581 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
02582 {
02583     MSIPACKAGE *package = param;
02584     LPSTR value_data = NULL;
02585     HKEY  root_key, hkey;
02586     DWORD type,size;
02587     LPWSTR deformated, uikey, keypath;
02588     LPCWSTR szRoot, component, name, key, value;
02589     MSICOMPONENT *comp;
02590     MSIRECORD * uirow;
02591     INT   root;
02592     BOOL check_first = FALSE;
02593     UINT rc;
02594 
02595     msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
02596 
02597     component = MSI_RecordGetString(row, 6);
02598     comp = msi_get_loaded_component(package,component);
02599     if (!comp)
02600         return ERROR_SUCCESS;
02601 
02602     comp->Action = msi_get_component_action( package, comp );
02603     if (comp->Action != INSTALLSTATE_LOCAL)
02604     {
02605         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
02606         return ERROR_SUCCESS;
02607     }
02608 
02609     name = MSI_RecordGetString(row, 4);
02610     if( MSI_RecordIsNull(row,5) && name )
02611     {
02612         /* null values can have special meanings */
02613         if (name[0]=='-' && name[1] == 0)
02614                 return ERROR_SUCCESS;
02615         else if ((name[0]=='+' && name[1] == 0) || 
02616                  (name[0] == '*' && name[1] == 0))
02617                 name = NULL;
02618         check_first = TRUE;
02619     }
02620 
02621     root = MSI_RecordGetInteger(row,2);
02622     key = MSI_RecordGetString(row, 3);
02623 
02624     szRoot = get_root_key( package, root, &root_key );
02625     if (!szRoot)
02626         return ERROR_SUCCESS;
02627 
02628     deformat_string(package, key , &deformated);
02629     size = strlenW(deformated) + strlenW(szRoot) + 1;
02630     uikey = msi_alloc(size*sizeof(WCHAR));
02631     strcpyW(uikey,szRoot);
02632     strcatW(uikey,deformated);
02633 
02634     keypath = get_keypath( package, root_key, deformated );
02635     msi_free( deformated );
02636     if (RegCreateKeyW( root_key, keypath, &hkey ))
02637     {
02638         ERR("Could not create key %s\n", debugstr_w(keypath));
02639         msi_free(uikey);
02640         msi_free(keypath);
02641         return ERROR_SUCCESS;
02642     }
02643 
02644     value = MSI_RecordGetString(row,5);
02645     if (value)
02646         value_data = parse_value(package, value, &type, &size); 
02647     else
02648     {
02649         value_data = (LPSTR)strdupW(szEmpty);
02650         size = sizeof(szEmpty);
02651         type = REG_SZ;
02652     }
02653 
02654     deformat_string(package, name, &deformated);
02655 
02656     if (!check_first)
02657     {
02658         TRACE("Setting value %s of %s\n",debugstr_w(deformated),
02659                         debugstr_w(uikey));
02660         RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
02661     }
02662     else
02663     {
02664         DWORD sz = 0;
02665         rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
02666         if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
02667         {
02668             TRACE("value %s of %s checked already exists\n",
02669                             debugstr_w(deformated), debugstr_w(uikey));
02670         }
02671         else
02672         {
02673             TRACE("Checked and setting value %s of %s\n",
02674                             debugstr_w(deformated), debugstr_w(uikey));
02675             if (deformated || size)
02676                 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
02677         }
02678     }
02679     RegCloseKey(hkey);
02680 
02681     uirow = MSI_CreateRecord(3);
02682     MSI_RecordSetStringW(uirow,2,deformated);
02683     MSI_RecordSetStringW(uirow,1,uikey);
02684     if (type == REG_SZ || type == REG_EXPAND_SZ)
02685         MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
02686     msi_ui_actiondata( package, szWriteRegistryValues, uirow );
02687     msiobj_release( &uirow->hdr );
02688 
02689     msi_free(value_data);
02690     msi_free(deformated);
02691     msi_free(uikey);
02692     msi_free(keypath);
02693 
02694     return ERROR_SUCCESS;
02695 }
02696 
02697 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
02698 {
02699     static const WCHAR query[] = {
02700         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
02701         '`','R','e','g','i','s','t','r','y','`',0};
02702     MSIQUERY *view;
02703     UINT rc;
02704 
02705     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
02706     if (rc != ERROR_SUCCESS)
02707         return ERROR_SUCCESS;
02708 
02709     rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
02710     msiobj_release(&view->hdr);
02711     return rc;
02712 }
02713 
02714 static void delete_reg_value( HKEY root, const WCHAR *keypath, const WCHAR *value )
02715 {
02716     LONG res;
02717     HKEY hkey;
02718     DWORD num_subkeys, num_values;
02719 
02720     if (!(res = RegOpenKeyW( root, keypath, &hkey )))
02721     {
02722         if ((res = RegDeleteValueW( hkey, value )))
02723         {
02724             TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
02725         }
02726         res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
02727                                 NULL, NULL, NULL, NULL );
02728         RegCloseKey( hkey );
02729         if (!res && !num_subkeys && !num_values)
02730         {
02731             TRACE("removing empty key %s\n", debugstr_w(keypath));
02732             RegDeleteKeyW( root, keypath );
02733         }
02734         return;
02735     }
02736     TRACE("failed to open key %s (%d)\n", debugstr_w(keypath), res);
02737 }
02738 
02739 static void delete_reg_key( HKEY root, const WCHAR *keypath )
02740 {
02741     LONG res = RegDeleteTreeW( root, keypath );
02742     if (res) TRACE("failed to delete key %s (%d)\n", debugstr_w(keypath), res);
02743 }
02744 
02745 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
02746 {
02747     MSIPACKAGE *package = param;
02748     LPCWSTR component, name, key_str, root_key_str;
02749     LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
02750     MSICOMPONENT *comp;
02751     MSIRECORD *uirow;
02752     BOOL delete_key = FALSE;
02753     HKEY hkey_root;
02754     UINT size;
02755     INT root;
02756 
02757     msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
02758 
02759     component = MSI_RecordGetString( row, 6 );
02760     comp = msi_get_loaded_component( package, component );
02761     if (!comp)
02762         return ERROR_SUCCESS;
02763 
02764     comp->Action = msi_get_component_action( package, comp );
02765     if (comp->Action != INSTALLSTATE_ABSENT)
02766     {
02767         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
02768         return ERROR_SUCCESS;
02769     }
02770 
02771     name = MSI_RecordGetString( row, 4 );
02772     if (MSI_RecordIsNull( row, 5 ) && name )
02773     {
02774         if (name[0] == '+' && !name[1])
02775             return ERROR_SUCCESS;
02776         else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
02777         {
02778             delete_key = TRUE;
02779             name = NULL;
02780         }
02781     }
02782 
02783     root = MSI_RecordGetInteger( row, 2 );
02784     key_str = MSI_RecordGetString( row, 3 );
02785 
02786     root_key_str = get_root_key( package, root, &hkey_root );
02787     if (!root_key_str)
02788         return ERROR_SUCCESS;
02789 
02790     deformat_string( package, key_str, &deformated_key );
02791     size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
02792     ui_key_str = msi_alloc( size * sizeof(WCHAR) );
02793     strcpyW( ui_key_str, root_key_str );
02794     strcatW( ui_key_str, deformated_key );
02795 
02796     deformat_string( package, name, &deformated_name );
02797 
02798     keypath = get_keypath( package, hkey_root, deformated_key );
02799     msi_free( deformated_key );
02800     if (delete_key) delete_reg_key( hkey_root, keypath );
02801     else delete_reg_value( hkey_root, keypath, deformated_name );
02802     msi_free( keypath );
02803 
02804     uirow = MSI_CreateRecord( 2 );
02805     MSI_RecordSetStringW( uirow, 1, ui_key_str );
02806     MSI_RecordSetStringW( uirow, 2, deformated_name );
02807     msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
02808     msiobj_release( &uirow->hdr );
02809 
02810     msi_free( ui_key_str );
02811     msi_free( deformated_name );
02812     return ERROR_SUCCESS;
02813 }
02814 
02815 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
02816 {
02817     MSIPACKAGE *package = param;
02818     LPCWSTR component, name, key_str, root_key_str;
02819     LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
02820     MSICOMPONENT *comp;
02821     MSIRECORD *uirow;
02822     BOOL delete_key = FALSE;
02823     HKEY hkey_root;
02824     UINT size;
02825     INT root;
02826 
02827     component = MSI_RecordGetString( row, 5 );
02828     comp = msi_get_loaded_component( package, component );
02829     if (!comp)
02830         return ERROR_SUCCESS;
02831 
02832     comp->Action = msi_get_component_action( package, comp );
02833     if (comp->Action != INSTALLSTATE_LOCAL)
02834     {
02835         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
02836         return ERROR_SUCCESS;
02837     }
02838 
02839     if ((name = MSI_RecordGetString( row, 4 )))
02840     {
02841         if (name[0] == '-' && !name[1])
02842         {
02843             delete_key = TRUE;
02844             name = NULL;
02845         }
02846     }
02847 
02848     root = MSI_RecordGetInteger( row, 2 );
02849     key_str = MSI_RecordGetString( row, 3 );
02850 
02851     root_key_str = get_root_key( package, root, &hkey_root );
02852     if (!root_key_str)
02853         return ERROR_SUCCESS;
02854 
02855     deformat_string( package, key_str, &deformated_key );
02856     size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
02857     ui_key_str = msi_alloc( size * sizeof(WCHAR) );
02858     strcpyW( ui_key_str, root_key_str );
02859     strcatW( ui_key_str, deformated_key );
02860 
02861     deformat_string( package, name, &deformated_name );
02862 
02863     keypath = get_keypath( package, hkey_root, deformated_key );
02864     msi_free( deformated_key );
02865     if (delete_key) delete_reg_key( hkey_root, keypath );
02866     else delete_reg_value( hkey_root, keypath, deformated_name );
02867     msi_free( keypath );
02868 
02869     uirow = MSI_CreateRecord( 2 );
02870     MSI_RecordSetStringW( uirow, 1, ui_key_str );
02871     MSI_RecordSetStringW( uirow, 2, deformated_name );
02872     msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
02873     msiobj_release( &uirow->hdr );
02874 
02875     msi_free( ui_key_str );
02876     msi_free( deformated_name );
02877     return ERROR_SUCCESS;
02878 }
02879 
02880 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
02881 {
02882     static const WCHAR registry_query[] = {
02883         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
02884         '`','R','e','g','i','s','t','r','y','`',0};
02885     static const WCHAR remove_registry_query[] = {
02886         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
02887         '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0};
02888     MSIQUERY *view;
02889     UINT rc;
02890 
02891     rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
02892     if (rc == ERROR_SUCCESS)
02893     {
02894         rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
02895         msiobj_release( &view->hdr );
02896         if (rc != ERROR_SUCCESS)
02897             return rc;
02898     }
02899     rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
02900     if (rc == ERROR_SUCCESS)
02901     {
02902         rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
02903         msiobj_release( &view->hdr );
02904         if (rc != ERROR_SUCCESS)
02905             return rc;
02906     }
02907     return ERROR_SUCCESS;
02908 }
02909 
02910 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
02911 {
02912     package->script->CurrentlyScripting = TRUE;
02913 
02914     return ERROR_SUCCESS;
02915 }
02916 
02917 
02918 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
02919 {
02920     static const WCHAR query[]= {
02921         'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
02922         '`','R','e','g','i','s','t','r','y','`',0};
02923     MSICOMPONENT *comp;
02924     DWORD total = 0, count = 0;
02925     MSIQUERY *view;
02926     MSIFEATURE *feature;
02927     MSIFILE *file;
02928     UINT rc;
02929 
02930     TRACE("InstallValidate\n");
02931 
02932     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
02933     if (rc == ERROR_SUCCESS)
02934     {
02935         rc = MSI_IterateRecords( view, &count, NULL, package );
02936         msiobj_release( &view->hdr );
02937         if (rc != ERROR_SUCCESS)
02938             return rc;
02939         total += count * REG_PROGRESS_VALUE;
02940     }
02941     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
02942         total += COMPONENT_PROGRESS_VALUE;
02943 
02944     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
02945         total += file->FileSize;
02946 
02947     msi_ui_progress( package, 0, total, 0, 0 );
02948 
02949     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
02950     {
02951         TRACE("Feature: %s Installed %d Request %d Action %d\n",
02952               debugstr_w(feature->Feature), feature->Installed,
02953               feature->ActionRequest, feature->Action);
02954     }
02955     return ERROR_SUCCESS;
02956 }
02957 
02958 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
02959 {
02960     MSIPACKAGE* package = param;
02961     LPCWSTR cond = NULL; 
02962     LPCWSTR message = NULL;
02963     UINT r;
02964 
02965     static const WCHAR title[]=
02966         {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
02967 
02968     cond = MSI_RecordGetString(row,1);
02969 
02970     r = MSI_EvaluateConditionW(package,cond);
02971     if (r == MSICONDITION_FALSE)
02972     {
02973         if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
02974         {
02975             LPWSTR deformated;
02976             message = MSI_RecordGetString(row,2);
02977             deformat_string(package,message,&deformated);
02978             MessageBoxW(NULL,deformated,title,MB_OK);
02979             msi_free(deformated);
02980         }
02981 
02982         return ERROR_INSTALL_FAILURE;
02983     }
02984 
02985     return ERROR_SUCCESS;
02986 }
02987 
02988 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
02989 {
02990     static const WCHAR query[] = {
02991         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
02992         '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
02993     MSIQUERY *view;
02994     UINT rc;
02995 
02996     TRACE("Checking launch conditions\n");
02997 
02998     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
02999     if (rc != ERROR_SUCCESS)
03000         return ERROR_SUCCESS;
03001 
03002     rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
03003     msiobj_release(&view->hdr);
03004     return rc;
03005 }
03006 
03007 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
03008 {
03009 
03010     if (!cmp->KeyPath)
03011         return strdupW( msi_get_target_folder( package, cmp->Directory ) );
03012 
03013     if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
03014     {
03015         static const WCHAR query[] = {
03016             'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
03017             '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ',
03018             '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0};
03019         static const WCHAR fmt[] = {'%','0','2','i',':','\\','%','s','\\',0};
03020         static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0};
03021         MSIRECORD *row;
03022         UINT root, len;
03023         LPWSTR deformated, buffer, deformated_name;
03024         LPCWSTR key, name;
03025 
03026         row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
03027         if (!row)
03028             return NULL;
03029 
03030         root = MSI_RecordGetInteger(row,2);
03031         key = MSI_RecordGetString(row, 3);
03032         name = MSI_RecordGetString(row, 4);
03033         deformat_string(package, key , &deformated);
03034         deformat_string(package, name, &deformated_name);
03035 
03036         len = strlenW(deformated) + 6;
03037         if (deformated_name)
03038             len+=strlenW(deformated_name);
03039 
03040         buffer = msi_alloc( len *sizeof(WCHAR));
03041 
03042         if (deformated_name)
03043             sprintfW(buffer,fmt2,root,deformated,deformated_name);
03044         else
03045             sprintfW(buffer,fmt,root,deformated);
03046 
03047         msi_free(deformated);
03048         msi_free(deformated_name);
03049         msiobj_release(&row->hdr);
03050 
03051         return buffer;
03052     }
03053     else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
03054     {
03055         FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
03056         return NULL;
03057     }
03058     else
03059     {
03060         MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
03061 
03062         if (file)
03063             return strdupW( file->TargetPath );
03064     }
03065     return NULL;
03066 }
03067 
03068 static HKEY openSharedDLLsKey(void)
03069 {
03070     HKEY hkey=0;
03071     static const WCHAR path[] =
03072         {'S','o','f','t','w','a','r','e','\\',
03073          'M','i','c','r','o','s','o','f','t','\\',
03074          'W','i','n','d','o','w','s','\\',
03075          'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
03076          'S','h','a','r','e','d','D','L','L','s',0};
03077 
03078     RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
03079     return hkey;
03080 }
03081 
03082 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
03083 {
03084     HKEY hkey;
03085     DWORD count=0;
03086     DWORD type;
03087     DWORD sz = sizeof(count);
03088     DWORD rc;
03089     
03090     hkey = openSharedDLLsKey();
03091     rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
03092     if (rc != ERROR_SUCCESS)
03093         count = 0;
03094     RegCloseKey(hkey);
03095     return count;
03096 }
03097 
03098 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
03099 {
03100     HKEY hkey;
03101 
03102     hkey = openSharedDLLsKey();
03103     if (count > 0)
03104         msi_reg_set_val_dword( hkey, path, count );
03105     else
03106         RegDeleteValueW(hkey,path);
03107     RegCloseKey(hkey);
03108     return count;
03109 }
03110 
03111 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
03112 {
03113     MSIFEATURE *feature;
03114     INT count = 0;
03115     BOOL write = FALSE;
03116 
03117     /* only refcount DLLs */
03118     if (comp->KeyPath == NULL || 
03119         comp->assembly ||
03120         comp->Attributes & msidbComponentAttributesRegistryKeyPath || 
03121         comp->Attributes & msidbComponentAttributesODBCDataSource)
03122         write = FALSE;
03123     else
03124     {
03125         count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
03126         write = (count > 0);
03127 
03128         if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
03129             write = TRUE;
03130     }
03131 
03132     /* increment counts */
03133     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
03134     {
03135         ComponentList *cl;
03136 
03137         if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
03138             continue;
03139 
03140         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
03141         {
03142             if ( cl->component == comp )
03143                 count++;
03144         }
03145     }
03146 
03147     /* decrement counts */
03148     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
03149     {
03150         ComponentList *cl;
03151 
03152         if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
03153             continue;
03154 
03155         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
03156         {
03157             if ( cl->component == comp )
03158                 count--;
03159         }
03160     }
03161 
03162     /* ref count all the files in the component */
03163     if (write)
03164     {
03165         MSIFILE *file;
03166 
03167         LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
03168         {
03169             if (file->Component == comp)
03170                 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
03171         }
03172     }
03173     
03174     /* add a count for permanent */
03175     if (comp->Attributes & msidbComponentAttributesPermanent)
03176         count ++;
03177     
03178     comp->RefCount = count;
03179 
03180     if (write)
03181         ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
03182 }
03183 
03184 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
03185 {
03186     if (comp->assembly)
03187     {
03188         const WCHAR prefixW[] = {'<','\\',0};
03189         DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
03190         WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
03191 
03192         if (keypath)
03193         {
03194             strcpyW( keypath, prefixW );
03195             strcatW( keypath, comp->assembly->display_name );
03196         }
03197         return keypath;
03198     }
03199     return resolve_keypath( package, comp );
03200 }
03201 
03202 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
03203 {
03204     WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
03205     UINT rc;
03206     MSICOMPONENT *comp;
03207     HKEY hkey;
03208 
03209     TRACE("\n");
03210 
03211     squash_guid(package->ProductCode,squished_pc);
03212     msi_set_sourcedir_props(package, FALSE);
03213 
03214     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
03215     {
03216         MSIRECORD *uirow;
03217         INSTALLSTATE action;
03218 
03219         msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
03220         if (!comp->ComponentId)
03221             continue;
03222 
03223         squash_guid( comp->ComponentId, squished_cc );
03224         msi_free( comp->FullKeypath );
03225         comp->FullKeypath = build_full_keypath( package, comp );
03226 
03227         ACTION_RefCountComponent( package, comp );
03228 
03229         if (package->need_rollback) action = comp->Installed;
03230         else action = comp->ActionRequest;
03231 
03232         TRACE("Component %s (%s), Keypath=%s, RefCount=%u Action=%u\n",
03233                             debugstr_w(comp->Component), debugstr_w(squished_cc),
03234                             debugstr_w(comp->FullKeypath), comp->RefCount, action);
03235 
03236         if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
03237         {
03238             if (package->Context == MSIINSTALLCONTEXT_MACHINE)
03239                 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
03240             else
03241                 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
03242 
03243             if (rc != ERROR_SUCCESS)
03244                 continue;
03245 
03246             if (comp->Attributes & msidbComponentAttributesPermanent)
03247             {
03248                 static const WCHAR szPermKey[] =
03249                     { '0','0','0','0','0','0','0','0','0','0','0','0',
03250                       '0','0','0','0','0','0','0','0','0','0','0','0',
03251                       '0','0','0','0','0','0','0','0',0 };
03252 
03253                 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
03254             }
03255             if (action == INSTALLSTATE_LOCAL)
03256                 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
03257             else
03258             {
03259                 MSIFILE *file;
03260                 MSIRECORD *row;
03261                 LPWSTR ptr, ptr2;
03262                 WCHAR source[MAX_PATH];
03263                 WCHAR base[MAX_PATH];
03264                 LPWSTR sourcepath;
03265 
03266                 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
03267                 static const WCHAR query[] = {
03268                     'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
03269                     '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
03270                     '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
03271                     '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
03272                     '`','D','i','s','k','I','d','`',0};
03273 
03274                 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
03275                     continue;
03276 
03277                 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
03278                 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
03279                 ptr2 = strrchrW(source, '\\') + 1;
03280                 msiobj_release(&row->hdr);
03281 
03282                 lstrcpyW(base, package->PackagePath);
03283                 ptr = strrchrW(base, '\\');
03284                 *(ptr + 1) = '\0';
03285 
03286                 sourcepath = msi_resolve_file_source(package, file);
03287                 ptr = sourcepath + lstrlenW(base);
03288                 lstrcpyW(ptr2, ptr);
03289                 msi_free(sourcepath);
03290 
03291                 msi_reg_set_val_str(hkey, squished_pc, source);
03292             }
03293             RegCloseKey(hkey);
03294         }
03295         else if (action == INSTALLSTATE_ABSENT)
03296         {
03297             if (package->Context == MSIINSTALLCONTEXT_MACHINE)
03298                 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
03299             else
03300                 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
03301         }
03302 
03303         /* UI stuff */
03304         uirow = MSI_CreateRecord(3);
03305         MSI_RecordSetStringW(uirow,1,package->ProductCode);
03306         MSI_RecordSetStringW(uirow,2,comp->ComponentId);
03307         MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
03308         msi_ui_actiondata( package, szProcessComponents, uirow );
03309         msiobj_release( &uirow->hdr );
03310     }
03311     return ERROR_SUCCESS;
03312 }
03313 
03314 typedef struct {
03315     CLSID       clsid;
03316     LPWSTR      source;
03317 
03318     LPWSTR      path;
03319     ITypeLib    *ptLib;
03320 } typelib_struct;
03321 
03322 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType, 
03323                                        LPWSTR lpszName, LONG_PTR lParam)
03324 {
03325     TLIBATTR *attr;
03326     typelib_struct *tl_struct = (typelib_struct*) lParam;
03327     static const WCHAR fmt[] = {'%','s','\\','%','i',0};
03328     int sz; 
03329     HRESULT res;
03330 
03331     if (!IS_INTRESOURCE(lpszName))
03332     {
03333         ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
03334         return TRUE;
03335     }
03336 
03337     sz = strlenW(tl_struct->source)+4;
03338     sz *= sizeof(WCHAR);
03339 
03340     if ((INT_PTR)lpszName == 1)
03341         tl_struct->path = strdupW(tl_struct->source);
03342     else
03343     {
03344         tl_struct->path = msi_alloc(sz);
03345         sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
03346     }
03347 
03348     TRACE("trying %s\n", debugstr_w(tl_struct->path));
03349     res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
03350     if (FAILED(res))
03351     {
03352         msi_free(tl_struct->path);
03353         tl_struct->path = NULL;
03354 
03355         return TRUE;
03356     }
03357 
03358     ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
03359     if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
03360     {
03361         ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
03362         return FALSE;
03363     }
03364 
03365     msi_free(tl_struct->path);
03366     tl_struct->path = NULL;
03367 
03368     ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
03369     ITypeLib_Release(tl_struct->ptLib);
03370 
03371     return TRUE;
03372 }
03373 
03374 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
03375 {
03376     MSIPACKAGE* package = param;
03377     LPCWSTR component;
03378     MSICOMPONENT *comp;
03379     MSIFILE *file;
03380     typelib_struct tl_struct;
03381     ITypeLib *tlib;
03382     HMODULE module;
03383     HRESULT hr;
03384 
03385     component = MSI_RecordGetString(row,3);
03386     comp = msi_get_loaded_component(package,component);
03387     if (!comp)
03388         return ERROR_SUCCESS;
03389 
03390     comp->Action = msi_get_component_action( package, comp );
03391     if (comp->Action != INSTALLSTATE_LOCAL)
03392     {
03393         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
03394         return ERROR_SUCCESS;
03395     }
03396 
03397     if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
03398     {
03399         TRACE("component has no key path\n");
03400         return ERROR_SUCCESS;
03401     }
03402     msi_ui_actiondata( package, szRegisterTypeLibraries, row );
03403 
03404     module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
03405     if (module)
03406     {
03407         LPCWSTR guid;
03408         guid = MSI_RecordGetString(row,1);
03409         CLSIDFromString( guid, &tl_struct.clsid);
03410         tl_struct.source = strdupW( file->TargetPath );
03411         tl_struct.path = NULL;
03412 
03413         EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
03414                         (LONG_PTR)&tl_struct);
03415 
03416         if (tl_struct.path)
03417         {
03418             LPCWSTR helpid, help_path = NULL;
03419             HRESULT res;
03420 
03421             helpid = MSI_RecordGetString(row,6);
03422 
03423             if (helpid) help_path = msi_get_target_folder( package, helpid );
03424             res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
03425 
03426             if (FAILED(res))
03427                 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
03428             else
03429                 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
03430 
03431             ITypeLib_Release(tl_struct.ptLib);
03432             msi_free(tl_struct.path);
03433         }
03434         else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
03435 
03436         FreeLibrary(module);
03437         msi_free(tl_struct.source);
03438     }
03439     else
03440     {
03441         hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
03442         if (FAILED(hr))
03443         {
03444             ERR("Failed to load type library: %08x\n", hr);
03445             return ERROR_INSTALL_FAILURE;
03446         }
03447 
03448         ITypeLib_Release(tlib);
03449     }
03450 
03451     return ERROR_SUCCESS;
03452 }
03453 
03454 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
03455 {
03456     static const WCHAR query[] = {
03457         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
03458         '`','T','y','p','e','L','i','b','`',0};
03459     MSIQUERY *view;
03460     UINT rc;
03461 
03462     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
03463     if (rc != ERROR_SUCCESS)
03464         return ERROR_SUCCESS;
03465 
03466     rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
03467     msiobj_release(&view->hdr);
03468     return rc;
03469 }
03470 
03471 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
03472 {
03473     MSIPACKAGE *package = param;
03474     LPCWSTR component, guid;
03475     MSICOMPONENT *comp;
03476     GUID libid;
03477     UINT version;
03478     LCID language;
03479     SYSKIND syskind;
03480     HRESULT hr;
03481 
03482     component = MSI_RecordGetString( row, 3 );
03483     comp = msi_get_loaded_component( package, component );
03484     if (!comp)
03485         return ERROR_SUCCESS;
03486 
03487     comp->Action = msi_get_component_action( package, comp );
03488     if (comp->Action != INSTALLSTATE_ABSENT)
03489     {
03490         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
03491         return ERROR_SUCCESS;
03492     }
03493     msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
03494 
03495     guid = MSI_RecordGetString( row, 1 );
03496     CLSIDFromString( guid, &libid );
03497     version = MSI_RecordGetInteger( row, 4 );
03498     language = MSI_RecordGetInteger( row, 2 );
03499 
03500 #ifdef _WIN64
03501     syskind = SYS_WIN64;
03502 #else
03503     syskind = SYS_WIN32;
03504 #endif
03505 
03506     hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
03507     if (FAILED(hr))
03508     {
03509         WARN("Failed to unregister typelib: %08x\n", hr);
03510     }
03511 
03512     return ERROR_SUCCESS;
03513 }
03514 
03515 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
03516 {
03517     static const WCHAR query[] = {
03518         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
03519         '`','T','y','p','e','L','i','b','`',0};
03520     MSIQUERY *view;
03521     UINT rc;
03522 
03523     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
03524     if (rc != ERROR_SUCCESS)
03525         return ERROR_SUCCESS;
03526 
03527     rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
03528     msiobj_release( &view->hdr );
03529     return rc;
03530 }
03531 
03532 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
03533 {
03534     static const WCHAR szlnk[] = {'.','l','n','k',0};
03535     LPCWSTR directory, extension, link_folder;
03536     LPWSTR link_file, filename;
03537 
03538     directory = MSI_RecordGetString( row, 2 );
03539     link_folder = msi_get_target_folder( package, directory );
03540     if (!link_folder)
03541     {
03542         ERR("unable to resolve folder %s\n", debugstr_w(directory));
03543         return NULL;
03544     }
03545     /* may be needed because of a bug somewhere else */
03546     msi_create_full_path( link_folder );
03547 
03548     filename = msi_dup_record_field( row, 3 );
03549     msi_reduce_to_long_filename( filename );
03550 
03551     extension = strchrW( filename, '.' );
03552     if (!extension || strcmpiW( extension, szlnk ))
03553     {
03554         int len = strlenW( filename );
03555         filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
03556         memcpy( filename + len, szlnk, sizeof(szlnk) );
03557     }
03558     link_file = msi_build_directory_name( 2, link_folder, filename );
03559     msi_free( filename );
03560 
03561     return link_file;
03562 }
03563 
03564 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
03565 {
03566     static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
03567     static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
03568     WCHAR *folder, *dest, *path;
03569 
03570     if (package->Context == MSIINSTALLCONTEXT_MACHINE)
03571         folder = msi_dup_property( package->db, szWindowsFolder );
03572     else
03573     {
03574         WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
03575         folder = msi_build_directory_name( 2, appdata, szMicrosoft );
03576         msi_free( appdata );
03577     }
03578     dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
03579     msi_create_full_path( dest );
03580     path = msi_build_directory_name( 2, dest, icon_name );
03581     msi_free( folder );
03582     msi_free( dest );
03583     return path;
03584 }
03585 
03586 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
03587 {
03588     MSIPACKAGE *package = param;
03589     LPWSTR link_file, deformated, path;
03590     LPCWSTR component, target;
03591     MSICOMPONENT *comp;
03592     IShellLinkW *sl = NULL;
03593     IPersistFile *pf = NULL;
03594     HRESULT res;
03595 
03596     component = MSI_RecordGetString(row, 4);
03597     comp = msi_get_loaded_component(package, component);
03598     if (!comp)
03599         return ERROR_SUCCESS;
03600 
03601     comp->Action = msi_get_component_action( package, comp );
03602     if (comp->Action != INSTALLSTATE_LOCAL)
03603     {
03604         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
03605         return ERROR_SUCCESS;
03606     }
03607     msi_ui_actiondata( package, szCreateShortcuts, row );
03608 
03609     res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
03610                     &IID_IShellLinkW, (LPVOID *) &sl );
03611 
03612     if (FAILED( res ))
03613     {
03614         ERR("CLSID_ShellLink not available\n");
03615         goto err;
03616     }
03617 
03618     res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
03619     if (FAILED( res ))
03620     {
03621         ERR("QueryInterface(IID_IPersistFile) failed\n");
03622         goto err;
03623     }
03624 
03625     target = MSI_RecordGetString(row, 5);
03626     if (strchrW(target, '['))
03627     {
03628         deformat_string( package, target, &path );
03629         TRACE("target path is %s\n", debugstr_w(path));
03630         IShellLinkW_SetPath( sl, path );
03631         msi_free( path );
03632     }
03633     else
03634     {
03635         FIXME("poorly handled shortcut format, advertised shortcut\n");
03636         IShellLinkW_SetPath(sl,comp->FullKeypath);
03637     }
03638 
03639     if (!MSI_RecordIsNull(row,6))
03640     {
03641         LPCWSTR arguments = MSI_RecordGetString(row, 6);
03642         deformat_string(package, arguments, &deformated);
03643         IShellLinkW_SetArguments(sl,deformated);
03644         msi_free(deformated);
03645     }
03646 
03647     if (!MSI_RecordIsNull(row,7))
03648     {
03649         LPCWSTR description = MSI_RecordGetString(row, 7);
03650         IShellLinkW_SetDescription(sl, description);
03651     }
03652 
03653     if (!MSI_RecordIsNull(row,8))
03654         IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
03655 
03656     if (!MSI_RecordIsNull(row,9))
03657     {
03658         INT index; 
03659         LPCWSTR icon = MSI_RecordGetString(row, 9);
03660 
03661         path = msi_build_icon_path(package, icon);
03662         index = MSI_RecordGetInteger(row,10);
03663 
03664         /* no value means 0 */
03665         if (index == MSI_NULL_INTEGER)
03666             index = 0;
03667 
03668         IShellLinkW_SetIconLocation(sl, path, index);
03669         msi_free(path);
03670     }
03671 
03672     if (!MSI_RecordIsNull(row,11))
03673         IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
03674 
03675     if (!MSI_RecordIsNull(row,12))
03676     {
03677         LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
03678         full_path = msi_get_target_folder( package, wkdir );
03679         if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
03680     }
03681     link_file = get_link_file(package, row);
03682 
03683     TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
03684     IPersistFile_Save(pf, link_file, FALSE);
03685     msi_free(link_file);
03686 
03687 err:
03688     if (pf)
03689         IPersistFile_Release( pf );
03690     if (sl)
03691         IShellLinkW_Release( sl );
03692 
03693     return ERROR_SUCCESS;
03694 }
03695 
03696 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
03697 {
03698     static const WCHAR query[] = {
03699         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
03700         '`','S','h','o','r','t','c','u','t','`',0};
03701     MSIQUERY *view;
03702     HRESULT res;
03703     UINT rc;
03704 
03705     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
03706     if (rc != ERROR_SUCCESS)
03707         return ERROR_SUCCESS;
03708 
03709     res = CoInitialize( NULL );
03710 
03711     rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
03712     msiobj_release(&view->hdr);
03713 
03714     if (SUCCEEDED(res)) CoUninitialize();
03715     return rc;
03716 }
03717 
03718 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
03719 {
03720     MSIPACKAGE *package = param;
03721     LPWSTR link_file;
03722     LPCWSTR component;
03723     MSICOMPONENT *comp;
03724 
03725     component = MSI_RecordGetString( row, 4 );
03726     comp = msi_get_loaded_component( package, component );
03727     if (!comp)
03728         return ERROR_SUCCESS;
03729 
03730     comp->Action = msi_get_component_action( package, comp );
03731     if (comp->Action != INSTALLSTATE_ABSENT)
03732     {
03733         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
03734         return ERROR_SUCCESS;
03735     }
03736     msi_ui_actiondata( package, szRemoveShortcuts, row );
03737 
03738     link_file = get_link_file( package, row );
03739 
03740     TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
03741     if (!DeleteFileW( link_file ))
03742     {
03743         WARN("Failed to remove shortcut file %u\n", GetLastError());
03744     }
03745     msi_free( link_file );
03746 
03747     return ERROR_SUCCESS;
03748 }
03749 
03750 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
03751 {
03752     static const WCHAR query[] = {
03753         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
03754         '`','S','h','o','r','t','c','u','t','`',0};
03755     MSIQUERY *view;
03756     UINT rc;
03757 
03758     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
03759     if (rc != ERROR_SUCCESS)
03760         return ERROR_SUCCESS;
03761 
03762     rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
03763     msiobj_release( &view->hdr );
03764     return rc;
03765 }
03766 
03767 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
03768 {
03769     MSIPACKAGE* package = param;
03770     HANDLE the_file;
03771     LPWSTR FilePath;
03772     LPCWSTR FileName;
03773     CHAR buffer[1024];
03774     DWORD sz;
03775     UINT rc;
03776 
03777     FileName = MSI_RecordGetString(row,1);
03778     if (!FileName)
03779     {
03780         ERR("Unable to get FileName\n");
03781         return ERROR_SUCCESS;
03782     }
03783 
03784     FilePath = msi_build_icon_path(package, FileName);
03785 
03786     TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
03787 
03788     the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
03789                         FILE_ATTRIBUTE_NORMAL, NULL);
03790 
03791     if (the_file == INVALID_HANDLE_VALUE)
03792     {
03793         ERR("Unable to create file %s\n",debugstr_w(FilePath));
03794         msi_free(FilePath);
03795         return ERROR_SUCCESS;
03796     }
03797 
03798     do 
03799     {
03800         DWORD write;
03801         sz = 1024;
03802         rc = MSI_RecordReadStream(row,2,buffer,&sz);
03803         if (rc != ERROR_SUCCESS)
03804         {
03805             ERR("Failed to get stream\n");
03806             CloseHandle(the_file);  
03807             DeleteFileW(FilePath);
03808             break;
03809         }
03810         WriteFile(the_file,buffer,sz,&write,NULL);
03811     } while (sz == 1024);
03812 
03813     msi_free(FilePath);
03814     CloseHandle(the_file);
03815 
03816     return ERROR_SUCCESS;
03817 }
03818 
03819 static UINT msi_publish_icons(MSIPACKAGE *package)
03820 {
03821     static const WCHAR query[]= {
03822         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
03823         '`','I','c','o','n','`',0};
03824     MSIQUERY *view;
03825     UINT r;
03826 
03827     r = MSI_DatabaseOpenViewW(package->db, query, &view);
03828     if (r == ERROR_SUCCESS)
03829     {
03830         r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
03831         msiobj_release(&view->hdr);
03832         if (r != ERROR_SUCCESS)
03833             return r;
03834     }
03835     return ERROR_SUCCESS;
03836 }
03837 
03838 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
03839 {
03840     UINT r;
03841     HKEY source;
03842     LPWSTR buffer;
03843     MSIMEDIADISK *disk;
03844     MSISOURCELISTINFO *info;
03845 
03846     r = RegCreateKeyW(hkey, szSourceList, &source);
03847     if (r != ERROR_SUCCESS)
03848         return r;
03849 
03850     RegCloseKey(source);
03851 
03852     buffer = strrchrW(package->PackagePath, '\\') + 1;
03853     r = MsiSourceListSetInfoW(package->ProductCode, NULL,
03854                               package->Context, MSICODE_PRODUCT,
03855                               INSTALLPROPERTY_PACKAGENAMEW, buffer);
03856     if (r != ERROR_SUCCESS)
03857         return r;
03858 
03859     r = MsiSourceListSetInfoW(package->ProductCode, NULL,
03860                               package->Context, MSICODE_PRODUCT,
03861                               INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
03862     if (r != ERROR_SUCCESS)
03863         return r;
03864 
03865     r = MsiSourceListSetInfoW(package->ProductCode, NULL,
03866                               package->Context, MSICODE_PRODUCT,
03867                               INSTALLPROPERTY_DISKPROMPTW, szEmpty);
03868     if (r != ERROR_SUCCESS)
03869         return r;
03870 
03871     LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
03872     {
03873         if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
03874             msi_set_last_used_source(package->ProductCode, NULL, info->context,
03875                                      info->options, info->value);
03876         else
03877             MsiSourceListSetInfoW(package->ProductCode, NULL,
03878                                   info->context, info->options,
03879                                   info->property, info->value);
03880     }
03881 
03882     LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
03883     {
03884         MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
03885                                    disk->context, disk->options,
03886                                    disk->disk_id, disk->volume_label, disk->disk_prompt);
03887     }
03888 
03889     return ERROR_SUCCESS;
03890 }
03891 
03892 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
03893 {
03894     MSIHANDLE hdb, suminfo;
03895     WCHAR guids[MAX_PATH];
03896     WCHAR packcode[SQUISH_GUID_SIZE];
03897     LPWSTR buffer;
03898     LPWSTR ptr;
03899     DWORD langid;
03900     DWORD size;
03901     UINT r;
03902 
03903     static const WCHAR szARPProductIcon[] =
03904         {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
03905     static const WCHAR szAssignment[] =
03906         {'A','s','s','i','g','n','m','e','n','t',0};
03907     static const WCHAR szAdvertiseFlags[] =
03908         {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
03909     static const WCHAR szClients[] =
03910         {'C','l','i','e','n','t','s',0};
03911     static const WCHAR szColon[] = {':',0};
03912 
03913     buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
03914     msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
03915     msi_free(buffer);
03916 
03917     langid = msi_get_property_int(package->db, szProductLanguage, 0);
03918     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
03919 
03920     /* FIXME */
03921     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
03922 
03923     buffer = msi_dup_property(package->db, szARPProductIcon);
03924     if (buffer)
03925     {
03926         LPWSTR path = msi_build_icon_path(package, buffer);
03927         msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
03928         msi_free(path);
03929         msi_free(buffer);
03930     }
03931 
03932     buffer = msi_dup_property(package->db, szProductVersion);
03933     if (buffer)
03934     {
03935         DWORD verdword = msi_version_str_to_dword(buffer);
03936         msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
03937         msi_free(buffer);
03938     }
03939 
03940     msi_reg_set_val_dword(hkey, szAssignment, 0);
03941     msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
03942     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
03943     msi_reg_set_val_str(hkey, szClients, szColon);
03944 
03945     hdb = alloc_msihandle(&package->db->hdr);
03946     if (!hdb)
03947         return ERROR_NOT_ENOUGH_MEMORY;
03948 
03949     r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
03950     MsiCloseHandle(hdb);
03951     if (r != ERROR_SUCCESS)
03952         goto done;
03953 
03954     size = MAX_PATH;
03955     r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
03956                                    NULL, guids, &size);
03957     if (r != ERROR_SUCCESS)
03958         goto done;
03959 
03960     ptr = strchrW(guids, ';');
03961     if (ptr) *ptr = 0;
03962     squash_guid(guids, packcode);
03963     msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
03964 
03965 done:
03966     MsiCloseHandle(suminfo);
03967     return ERROR_SUCCESS;
03968 }
03969 
03970 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
03971 {
03972     UINT r;
03973     HKEY hkey;
03974     LPWSTR upgrade;
03975     WCHAR squashed_pc[SQUISH_GUID_SIZE];
03976 
03977     upgrade = msi_dup_property(package->db, szUpgradeCode);
03978     if (!upgrade)
03979         return ERROR_SUCCESS;
03980 
03981     if (package->Context == MSIINSTALLCONTEXT_MACHINE)
03982         r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
03983     else
03984         r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
03985 
03986     if (r != ERROR_SUCCESS)
03987     {
03988         WARN("failed to open upgrade code key\n");
03989         msi_free(upgrade);
03990         return ERROR_SUCCESS;
03991     }
03992     squash_guid(package->ProductCode, squashed_pc);
03993     msi_reg_set_val_str(hkey, squashed_pc, NULL);
03994     RegCloseKey(hkey);
03995     msi_free(upgrade);
03996     return ERROR_SUCCESS;
03997 }
03998 
03999 static BOOL msi_check_publish(MSIPACKAGE *package)
04000 {
04001     MSIFEATURE *feature;
04002 
04003     LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
04004     {
04005         feature->Action = msi_get_feature_action( package, feature );
04006         if (feature->Action == INSTALLSTATE_LOCAL)
04007             return TRUE;
04008     }
04009 
04010     return FALSE;
04011 }
04012 
04013 static BOOL msi_check_unpublish(MSIPACKAGE *package)
04014 {
04015     MSIFEATURE *feature;
04016 
04017     LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
04018     {
04019         feature->Action = msi_get_feature_action( package, feature );
04020         if (feature->Action != INSTALLSTATE_ABSENT)
04021             return FALSE;
04022     }
04023 
04024     return TRUE;
04025 }
04026 
04027 static UINT msi_publish_patches( MSIPACKAGE *package )
04028 {
04029     static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
04030     WCHAR patch_squashed[GUID_SIZE];
04031     HKEY patches_key = NULL, product_patches_key = NULL, product_key;
04032     LONG res;
04033     MSIPATCHINFO *patch;
04034     UINT r;
04035     WCHAR *p, *all_patches = NULL;
04036     DWORD len = 0;
04037 
04038     r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
04039     if (r != ERROR_SUCCESS)
04040         return ERROR_FUNCTION_FAILED;
04041 
04042     res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
04043     if (res != ERROR_SUCCESS)
04044     {
04045         r = ERROR_FUNCTION_FAILED;
04046         goto done;
04047     }
04048 
04049     r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
04050     if (r != ERROR_SUCCESS)
04051         goto done;
04052 
04053     LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
04054     {
04055         squash_guid( patch->patchcode, patch_squashed );
04056         len += strlenW( patch_squashed ) + 1;
04057     }
04058 
04059     p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
04060     if (!all_patches)
04061         goto done;
04062 
04063     LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
04064     {
04065         HKEY patch_key;
04066 
04067         squash_guid( patch->patchcode, p );
04068         p += strlenW( p ) + 1;
04069 
04070         res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
04071                               (const BYTE *)patch->transforms,
04072                               (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
04073         if (res != ERROR_SUCCESS)
04074             goto done;
04075 
04076         r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
04077         if (r != ERROR_SUCCESS)
04078             goto done;
04079 
04080         res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
04081                               (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
04082         RegCloseKey( patch_key );
04083         if (res != ERROR_SUCCESS)
04084             goto done;
04085 
04086         if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
04087         {
04088             res = GetLastError();
04089             ERR("Unable to copy patch package %d\n", res);
04090             goto done;
04091         }
04092         res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
04093         if (res != ERROR_SUCCESS)
04094             goto done;
04095 
04096         res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
04097         RegCloseKey( patch_key );
04098         if (res != ERROR_SUCCESS)
04099             goto done;
04100     }
04101 
04102     all_patches[len] = 0;
04103     res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
04104                           (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
04105     if (res != ERROR_SUCCESS)
04106         goto done;
04107 
04108     res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
04109                           (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
04110     if (res != ERROR_SUCCESS)
04111         r = ERROR_FUNCTION_FAILED;
04112 
04113 done:
04114     RegCloseKey( product_patches_key );
04115     RegCloseKey( patches_key );
04116     RegCloseKey( product_key );
04117     msi_free( all_patches );
04118     return r;
04119 }
04120 
04121 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
04122 {
04123     UINT rc;
04124     HKEY hukey = NULL, hudkey = NULL;
04125     MSIRECORD *uirow;
04126 
04127     if (!list_empty(&package->patches))
04128     {
04129         rc = msi_publish_patches(package);
04130         if (rc != ERROR_SUCCESS)
04131             goto end;
04132     }
04133 
04134     /* FIXME: also need to publish if the product is in advertise mode */
04135     if (!msi_check_publish(package))
04136         return ERROR_SUCCESS;
04137 
04138     rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
04139                                &hukey, TRUE);
04140     if (rc != ERROR_SUCCESS)
04141         goto end;
04142 
04143     rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
04144                                        NULL, &hudkey, TRUE);
04145     if (rc != ERROR_SUCCESS)
04146         goto end;
04147 
04148     rc = msi_publish_upgrade_code(package);
04149     if (rc != ERROR_SUCCESS)
04150         goto end;
04151 
04152     rc = msi_publish_product_properties(package, hukey);
04153     if (rc != ERROR_SUCCESS)
04154         goto end;
04155 
04156     rc = msi_publish_sourcelist(package, hukey);
04157     if (rc != ERROR_SUCCESS)
04158         goto end;
04159 
04160     rc = msi_publish_icons(package);
04161 
04162 end:
04163     uirow = MSI_CreateRecord( 1 );
04164     MSI_RecordSetStringW( uirow, 1, package->ProductCode );
04165     msi_ui_actiondata( package, szPublishProduct, uirow );
04166     msiobj_release( &uirow->hdr );
04167 
04168     RegCloseKey(hukey);
04169     RegCloseKey(hudkey);
04170     return rc;
04171 }
04172 
04173 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
04174 {
04175     WCHAR *filename, *ptr, *folder, *ret;
04176     const WCHAR *dirprop;
04177 
04178     filename = msi_dup_record_field( row, 2 );
04179     if (filename && (ptr = strchrW( filename, '|' )))
04180         ptr++;
04181     else
04182         ptr = filename;
04183 
04184     dirprop = MSI_RecordGetString( row, 3 );
04185     if (dirprop)
04186     {
04187         folder = strdupW( msi_get_target_folder( package, dirprop ) );
04188         if (!folder) folder = msi_dup_property( package->db, dirprop );
04189     }
04190     else
04191         folder = msi_dup_property( package->db, szWindowsFolder );
04192 
04193     if (!folder)
04194     {
04195         ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
04196         msi_free( filename );
04197         return NULL;
04198     }
04199 
04200     ret = msi_build_directory_name( 2, folder, ptr );
04201 
04202     msi_free( filename );
04203     msi_free( folder );
04204     return ret;
04205 }
04206 
04207 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
04208 {
04209     MSIPACKAGE *package = param;
04210     LPCWSTR component, section, key, value, identifier;
04211     LPWSTR deformated_section, deformated_key, deformated_value, fullname;
04212     MSIRECORD * uirow;
04213     INT action;
04214     MSICOMPONENT *comp;
04215 
04216     component = MSI_RecordGetString(row, 8);
04217     comp = msi_get_loaded_component(package,component);
04218     if (!comp)
04219         return ERROR_SUCCESS;
04220 
04221     comp->Action = msi_get_component_action( package, comp );
04222     if (comp->Action != INSTALLSTATE_LOCAL)
04223     {
04224         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
04225         return ERROR_SUCCESS;
04226     }
04227 
04228     identifier = MSI_RecordGetString(row,1); 
04229     section = MSI_RecordGetString(row,4);
04230     key = MSI_RecordGetString(row,5);
04231     value = MSI_RecordGetString(row,6);
04232     action = MSI_RecordGetInteger(row,7);
04233 
04234     deformat_string(package,section,&deformated_section);
04235     deformat_string(package,key,&deformated_key);
04236     deformat_string(package,value,&deformated_value);
04237 
04238     fullname = get_ini_file_name(package, row);
04239 
04240     if (action == 0)
04241     {
04242         TRACE("Adding value %s to section %s in %s\n",
04243                 debugstr_w(deformated_key), debugstr_w(deformated_section),
04244                 debugstr_w(fullname));
04245         WritePrivateProfileStringW(deformated_section, deformated_key,
04246                                    deformated_value, fullname);
04247     }
04248     else if (action == 1)
04249     {
04250         WCHAR returned[10];
04251         GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
04252                                  returned, 10, fullname);
04253         if (returned[0] == 0)
04254         {
04255             TRACE("Adding value %s to section %s in %s\n",
04256                     debugstr_w(deformated_key), debugstr_w(deformated_section),
04257                     debugstr_w(fullname));
04258 
04259             WritePrivateProfileStringW(deformated_section, deformated_key,
04260                                        deformated_value, fullname);
04261         }
04262     }
04263     else if (action == 3)
04264         FIXME("Append to existing section not yet implemented\n");
04265 
04266     uirow = MSI_CreateRecord(4);
04267     MSI_RecordSetStringW(uirow,1,identifier);
04268     MSI_RecordSetStringW(uirow,2,deformated_section);
04269     MSI_RecordSetStringW(uirow,3,deformated_key);
04270     MSI_RecordSetStringW(uirow,4,deformated_value);
04271     msi_ui_actiondata( package, szWriteIniValues, uirow );
04272     msiobj_release( &uirow->hdr );
04273 
04274     msi_free(fullname);
04275     msi_free(deformated_key);
04276     msi_free(deformated_value);
04277     msi_free(deformated_section);
04278     return ERROR_SUCCESS;
04279 }
04280 
04281 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
04282 {
04283     static const WCHAR query[] = {
04284         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
04285         '`','I','n','i','F','i','l','e','`',0};
04286     MSIQUERY *view;
04287     UINT rc;
04288 
04289     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
04290     if (rc != ERROR_SUCCESS)
04291         return ERROR_SUCCESS;
04292 
04293     rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
04294     msiobj_release(&view->hdr);
04295     return rc;
04296 }
04297 
04298 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
04299 {
04300     MSIPACKAGE *package = param;
04301     LPCWSTR component, section, key, value, identifier;
04302     LPWSTR deformated_section, deformated_key, deformated_value, filename;
04303     MSICOMPONENT *comp;
04304     MSIRECORD *uirow;
04305     INT action;
04306 
04307     component = MSI_RecordGetString( row, 8 );
04308     comp = msi_get_loaded_component( package, component );
04309     if (!comp)
04310         return ERROR_SUCCESS;
04311 
04312     comp->Action = msi_get_component_action( package, comp );
04313     if (comp->Action != INSTALLSTATE_ABSENT)
04314     {
04315         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
04316         return ERROR_SUCCESS;
04317     }
04318 
04319     identifier = MSI_RecordGetString( row, 1 );
04320     section = MSI_RecordGetString( row, 4 );
04321     key = MSI_RecordGetString( row, 5 );
04322     value = MSI_RecordGetString( row, 6 );
04323     action = MSI_RecordGetInteger( row, 7 );
04324 
04325     deformat_string( package, section, &deformated_section );
04326     deformat_string( package, key, &deformated_key );
04327     deformat_string( package, value, &deformated_value );
04328 
04329     if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
04330     {
04331         filename = get_ini_file_name( package, row );
04332 
04333         TRACE("Removing key %s from section %s in %s\n",
04334                debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
04335 
04336         if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
04337         {
04338             WARN("Unable to remove key %u\n", GetLastError());
04339         }
04340         msi_free( filename );
04341     }
04342     else
04343         FIXME("Unsupported action %d\n", action);
04344 
04345 
04346     uirow = MSI_CreateRecord( 4 );
04347     MSI_RecordSetStringW( uirow, 1, identifier );
04348     MSI_RecordSetStringW( uirow, 2, deformated_section );
04349     MSI_RecordSetStringW( uirow, 3, deformated_key );
04350     MSI_RecordSetStringW( uirow, 4, deformated_value );
04351     msi_ui_actiondata( package, szRemoveIniValues, uirow );
04352     msiobj_release( &uirow->hdr );
04353 
04354     msi_free( deformated_key );
04355     msi_free( deformated_value );
04356     msi_free( deformated_section );
04357     return ERROR_SUCCESS;
04358 }
04359 
04360 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
04361 {
04362     MSIPACKAGE *package = param;
04363     LPCWSTR component, section, key, value, identifier;
04364     LPWSTR deformated_section, deformated_key, deformated_value, filename;
04365     MSICOMPONENT *comp;
04366     MSIRECORD *uirow;
04367     INT action;
04368 
04369     component = MSI_RecordGetString( row, 8 );
04370     comp = msi_get_loaded_component( package, component );
04371     if (!comp)
04372         return ERROR_SUCCESS;
04373 
04374     comp->Action = msi_get_component_action( package, comp );
04375     if (comp->Action != INSTALLSTATE_LOCAL)
04376     {
04377         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
04378         return ERROR_SUCCESS;
04379     }
04380 
04381     identifier = MSI_RecordGetString( row, 1 );
04382     section = MSI_RecordGetString( row, 4 );
04383     key = MSI_RecordGetString( row, 5 );
04384     value = MSI_RecordGetString( row, 6 );
04385     action = MSI_RecordGetInteger( row, 7 );
04386 
04387     deformat_string( package, section, &deformated_section );
04388     deformat_string( package, key, &deformated_key );
04389     deformat_string( package, value, &deformated_value );
04390 
04391     if (action == msidbIniFileActionRemoveLine)
04392     {
04393         filename = get_ini_file_name( package, row );
04394 
04395         TRACE("Removing key %s from section %s in %s\n",
04396                debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
04397 
04398         if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
04399         {
04400             WARN("Unable to remove key %u\n", GetLastError());
04401         }
04402         msi_free( filename );
04403     }
04404     else
04405         FIXME("Unsupported action %d\n", action);
04406 
04407     uirow = MSI_CreateRecord( 4 );
04408     MSI_RecordSetStringW( uirow, 1, identifier );
04409     MSI_RecordSetStringW( uirow, 2, deformated_section );
04410     MSI_RecordSetStringW( uirow, 3, deformated_key );
04411     MSI_RecordSetStringW( uirow, 4, deformated_value );
04412     msi_ui_actiondata( package, szRemoveIniValues, uirow );
04413     msiobj_release( &uirow->hdr );
04414 
04415     msi_free( deformated_key );
04416     msi_free( deformated_value );
04417     msi_free( deformated_section );
04418     return ERROR_SUCCESS;
04419 }
04420 
04421 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
04422 {
04423     static const WCHAR query[] = {
04424         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
04425         '`','I','n','i','F','i','l','e','`',0};
04426     static const WCHAR remove_query[] = {
04427         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
04428         '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
04429     MSIQUERY *view;
04430     UINT rc;
04431 
04432     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
04433     if (rc == ERROR_SUCCESS)
04434     {
04435         rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
04436         msiobj_release( &view->hdr );
04437         if (rc != ERROR_SUCCESS)
04438             return rc;
04439     }
04440     rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
04441     if (rc == ERROR_SUCCESS)
04442     {
04443         rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
04444         msiobj_release( &view->hdr );
04445         if (rc != ERROR_SUCCESS)
04446             return rc;
04447     }
04448     return ERROR_SUCCESS;
04449 }
04450 
04451 static void register_dll( const WCHAR *dll, BOOL unregister )
04452 {
04453     HMODULE hmod;
04454 
04455     hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
04456     if (hmod)
04457     {
04458         HRESULT (WINAPI *func_ptr)( void );
04459         const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
04460 
04461         func_ptr = (void *)GetProcAddress( hmod, func );
04462         if (func_ptr)
04463         {
04464             HRESULT hr = func_ptr();
04465             if (FAILED( hr ))
04466                 WARN("failed to register dll 0x%08x\n", hr);
04467         }
04468         else
04469             WARN("entry point %s not found\n", func);
04470         FreeLibrary( hmod );
04471         return;
04472     }
04473     WARN("failed to load library %u\n", GetLastError());
04474 }
04475 
04476 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
04477 {
04478     MSIPACKAGE *package = param;
04479     LPCWSTR filename;
04480     MSIFILE *file;
04481     MSIRECORD *uirow;
04482 
04483     filename = MSI_RecordGetString( row, 1 );
04484     file = msi_get_loaded_file( package, filename );
04485     if (!file)
04486     {
04487         WARN("unable to find file %s\n", debugstr_w(filename));
04488         return ERROR_SUCCESS;
04489     }
04490     file->Component->Action = msi_get_component_action( package, file->Component );
04491     if (file->Component->Action != INSTALLSTATE_LOCAL)
04492     {
04493         TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
04494         return ERROR_SUCCESS;
04495     }
04496 
04497     TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
04498     register_dll( file->TargetPath, FALSE );
04499 
04500     uirow = MSI_CreateRecord( 2 );
04501     MSI_RecordSetStringW( uirow, 1, file->File );
04502     MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
04503     msi_ui_actiondata( package, szSelfRegModules, uirow );
04504     msiobj_release( &uirow->hdr );
04505 
04506     return ERROR_SUCCESS;
04507 }
04508 
04509 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
04510 {
04511     static const WCHAR query[] = {
04512         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
04513         '`','S','e','l','f','R','e','g','`',0};
04514     MSIQUERY *view;
04515     UINT rc;
04516 
04517     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
04518     if (rc != ERROR_SUCCESS)
04519         return ERROR_SUCCESS;
04520 
04521     rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
04522     msiobj_release(&view->hdr);
04523     return rc;
04524 }
04525 
04526 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
04527 {
04528     MSIPACKAGE *package = param;
04529     LPCWSTR filename;
04530     MSIFILE *file;
04531     MSIRECORD *uirow;
04532 
04533     filename = MSI_RecordGetString( row, 1 );
04534     file = msi_get_loaded_file( package, filename );
04535     if (!file)
04536     {
04537         WARN("unable to find file %s\n", debugstr_w(filename));
04538         return ERROR_SUCCESS;
04539     }
04540     file->Component->Action = msi_get_component_action( package, file->Component );
04541     if (file->Component->Action != INSTALLSTATE_ABSENT)
04542     {
04543         TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
04544         return ERROR_SUCCESS;
04545     }
04546 
04547     TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
04548     register_dll( file->TargetPath, TRUE );
04549 
04550     uirow = MSI_CreateRecord( 2 );
04551     MSI_RecordSetStringW( uirow, 1, file->File );
04552     MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
04553     msi_ui_actiondata( package, szSelfUnregModules, uirow );
04554     msiobj_release( &uirow->hdr );
04555 
04556     return ERROR_SUCCESS;
04557 }
04558 
04559 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
04560 {
04561     static const WCHAR query[] = {
04562         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
04563         '`','S','e','l','f','R','e','g','`',0};
04564     MSIQUERY *view;
04565     UINT rc;
04566 
04567     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
04568     if (rc != ERROR_SUCCESS)
04569         return ERROR_SUCCESS;
04570 
04571     rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
04572     msiobj_release( &view->hdr );
04573     return rc;
04574 }
04575 
04576 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
04577 {
04578     MSIFEATURE *feature;
04579     UINT rc;
04580     HKEY hkey = NULL, userdata = NULL;
04581 
04582     if (!msi_check_publish(package))
04583         return ERROR_SUCCESS;
04584 
04585     rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
04586                                 &hkey, TRUE);
04587     if (rc != ERROR_SUCCESS)
04588         goto end;
04589 
04590     rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
04591                                         &userdata, TRUE);
04592     if (rc != ERROR_SUCCESS)
04593         goto end;
04594 
04595     /* here the guids are base 85 encoded */
04596     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
04597     {
04598         ComponentList *cl;
04599         LPWSTR data = NULL;
04600         GUID clsid;
04601         INT size;
04602         BOOL absent = FALSE;
04603         MSIRECORD *uirow;
04604 
04605         if (feature->Action != INSTALLSTATE_LOCAL &&
04606             feature->Action != INSTALLSTATE_SOURCE &&
04607             feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
04608 
04609         size = 1;
04610         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
04611         {
04612             size += 21;
04613         }
04614         if (feature->Feature_Parent)
04615             size += strlenW( feature->Feature_Parent )+2;
04616 
04617         data = msi_alloc(size * sizeof(WCHAR));
04618 
04619         data[0] = 0;
04620         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
04621         {
04622             MSICOMPONENT* component = cl->component;
04623             WCHAR buf[21];
04624 
04625             buf[0] = 0;
04626             if (component->ComponentId)
04627             {
04628                 TRACE("From %s\n",debugstr_w(component->ComponentId));
04629                 CLSIDFromString(component->ComponentId, &clsid);
04630                 encode_base85_guid(&clsid,buf);
04631                 TRACE("to %s\n",debugstr_w(buf));
04632                 strcatW(data,buf);
04633             }
04634         }
04635 
04636         if (feature->Feature_Parent)
04637         {
04638             static const WCHAR sep[] = {'\2',0};
04639             strcatW(data,sep);
04640             strcatW(data,feature->Feature_Parent);
04641         }
04642 
04643         msi_reg_set_val_str( userdata, feature->Feature, data );
04644         msi_free(data);
04645 
04646         size = 0;
04647         if (feature->Feature_Parent)
04648             size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
04649         if (!absent)
04650         {
04651             size += sizeof(WCHAR);
04652             RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
04653                            (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
04654         }
04655         else
04656         {
04657             size += 2*sizeof(WCHAR);
04658             data = msi_alloc(size);
04659             data[0] = 0x6;
04660             data[1] = 0;
04661             if (feature->Feature_Parent)
04662                 strcpyW( &data[1], feature->Feature_Parent );
04663             RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
04664                        (LPBYTE)data,size);
04665             msi_free(data);
04666         }
04667 
04668         /* the UI chunk */
04669         uirow = MSI_CreateRecord( 1 );
04670         MSI_RecordSetStringW( uirow, 1, feature->Feature );
04671         msi_ui_actiondata( package, szPublishFeatures, uirow );
04672         msiobj_release( &uirow->hdr );
04673         /* FIXME: call msi_ui_progress? */
04674     }
04675 
04676 end:
04677     RegCloseKey(hkey);
04678     RegCloseKey(userdata);
04679     return rc;
04680 }
04681 
04682 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
04683 {
04684     UINT r;
04685     HKEY hkey;
04686     MSIRECORD *uirow;
04687 
04688     TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
04689 
04690     r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
04691                                &hkey, FALSE);
04692     if (r == ERROR_SUCCESS)
04693     {
04694         RegDeleteValueW(hkey, feature->Feature);
04695         RegCloseKey(hkey);
04696     }
04697 
04698     r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
04699                                        &hkey, FALSE);
04700     if (r == ERROR_SUCCESS)
04701     {
04702         RegDeleteValueW(hkey, feature->Feature);
04703         RegCloseKey(hkey);
04704     }
04705 
04706     uirow = MSI_CreateRecord( 1 );
04707     MSI_RecordSetStringW( uirow, 1, feature->Feature );
04708     msi_ui_actiondata( package, szUnpublishFeatures, uirow );
04709     msiobj_release( &uirow->hdr );
04710 
04711     return ERROR_SUCCESS;
04712 }
04713 
04714 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
04715 {
04716     MSIFEATURE *feature;
04717 
04718     if (!msi_check_unpublish(package))
04719         return ERROR_SUCCESS;
04720 
04721     LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
04722     {
04723         msi_unpublish_feature(package, feature);
04724     }
04725 
04726     return ERROR_SUCCESS;
04727 }
04728 
04729 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
04730 {
04731     SYSTEMTIME systime;
04732     DWORD size, langid;
04733     WCHAR date[9], *val, *buffer;
04734     const WCHAR *prop, *key;
04735 
04736     static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
04737     static const WCHAR modpath_fmt[] =
04738         {'M','s','i','E','x','e','c','.','e','x','e',' ',
04739          '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
04740     static const WCHAR szModifyPath[] =
04741         {'M','o','d','i','f','y','P','a','t','h',0};
04742     static const WCHAR szUninstallString[] =
04743         {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
04744     static const WCHAR szEstimatedSize[] =
04745         {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
04746     static const WCHAR szDisplayVersion[] =
04747         {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
04748     static const WCHAR szInstallSource[] =
04749         {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
04750     static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
04751         {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
04752     static const WCHAR szAuthorizedCDFPrefix[] =
04753         {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
04754     static const WCHAR szARPCONTACT[] =
04755         {'A','R','P','C','O','N','T','A','C','T',0};
04756     static const WCHAR szContact[] =
04757         {'C','o','n','t','a','c','t',0};
04758     static const WCHAR szARPCOMMENTS[] =
04759         {'A','R','P','C','O','M','M','E','N','T','S',0};
04760     static const WCHAR szComments[] =
04761         {'C','o','m','m','e','n','t','s',0};
04762     static const WCHAR szProductName[] =
04763         {'P','r','o','d','u','c','t','N','a','m','e',0};
04764     static const WCHAR szDisplayName[] =
04765         {'D','i','s','p','l','a','y','N','a','m','e',0};
04766     static const WCHAR szARPHELPLINK[] =
04767         {'A','R','P','H','E','L','P','L','I','N','K',0};
04768     static const WCHAR szHelpLink[] =
04769         {'H','e','l','p','L','i','n','k',0};
04770     static const WCHAR szARPHELPTELEPHONE[] =
04771         {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
04772     static const WCHAR szHelpTelephone[] =
04773         {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
04774     static const WCHAR szARPINSTALLLOCATION[] =
04775         {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
04776     static const WCHAR szInstallLocation[] =
04777         {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
04778     static const WCHAR szManufacturer[] =
04779         {'M','a','n','u','f','a','c','t','u','r','e','r',0};
04780     static const WCHAR szPublisher[] =
04781         {'P','u','b','l','i','s','h','e','r',0};
04782     static const WCHAR szARPREADME[] =
04783         {'A','R','P','R','E','A','D','M','E',0};
04784     static const WCHAR szReadme[] =
04785         {'R','e','a','d','M','e',0};
04786     static const WCHAR szARPSIZE[] =
04787         {'A','R','P','S','I','Z','E',0};
04788     static const WCHAR szSize[] =
04789         {'S','i','z','e',0};
04790     static const WCHAR szARPURLINFOABOUT[] =
04791         {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
04792     static const WCHAR szURLInfoAbout[] =
04793         {'U','R','L','I','n','f','o','A','b','o','u','t',0};
04794     static const WCHAR szARPURLUPDATEINFO[] =
04795         {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
04796     static const WCHAR szURLUpdateInfo[] =
04797         {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
04798     static const WCHAR szARPSYSTEMCOMPONENT[] =
04799         {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
04800     static const WCHAR szSystemComponent[] =
04801         {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
04802 
04803     static const WCHAR *propval[] = {
04804         szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
04805         szARPCONTACT,             szContact,
04806         szARPCOMMENTS,            szComments,
04807         szProductName,            szDisplayName,
04808         szARPHELPLINK,            szHelpLink,
04809         szARPHELPTELEPHONE,       szHelpTelephone,
04810         szARPINSTALLLOCATION,     szInstallLocation,
04811         szSourceDir,              szInstallSource,
04812         szManufacturer,           szPublisher,
04813         szARPREADME,              szReadme,
04814         szARPSIZE,                szSize,
04815         szARPURLINFOABOUT,        szURLInfoAbout,
04816         szARPURLUPDATEINFO,       szURLUpdateInfo,
04817         NULL
04818     };
04819     const WCHAR **p = propval;
04820 
04821     while (*p)
04822     {
04823         prop = *p++;
04824         key = *p++;
04825         val = msi_dup_property(package->db, prop);
04826         msi_reg_set_val_str(hkey, key, val);
04827         msi_free(val);
04828     }
04829 
04830     msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
04831     if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
04832     {
04833         msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
04834     }
04835     size = deformat_string(package, modpath_fmt, &buffer);
04836     RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
04837     RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
04838     msi_free(buffer);
04839 
04840     /* FIXME: Write real Estimated Size when we have it */
04841     msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
04842 
04843     GetLocalTime(&systime);
04844     sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
04845     msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
04846 
04847     langid = msi_get_property_int(package->db, szProductLanguage, 0);
04848     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
04849 
04850     buffer = msi_dup_property(package->db, szProductVersion);
04851     msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
04852     if (buffer)
04853     {
04854         DWORD verdword = msi_version_str_to_dword(buffer);
04855 
04856         msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
04857         msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
04858         msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
04859         msi_free(buffer);
04860     }
04861 
04862     return ERROR_SUCCESS;
04863 }
04864 
04865 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
04866 {
04867     WCHAR squashed_pc[SQUISH_GUID_SIZE];
04868     MSIRECORD *uirow;
04869     LPWSTR upgrade_code;
04870     HKEY hkey, props, upgrade_key;
04871     UINT rc;
04872 
04873     /* FIXME: also need to publish if the product is in advertise mode */
04874     if (!msi_check_publish(package))
04875         return ERROR_SUCCESS;
04876 
04877     rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
04878     if (rc != ERROR_SUCCESS)
04879         return rc;
04880 
04881     rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
04882     if (rc != ERROR_SUCCESS)
04883         goto done;
04884 
04885     rc = msi_publish_install_properties(package, hkey);
04886     if (rc != ERROR_SUCCESS)
04887         goto done;
04888 
04889     rc = msi_publish_install_properties(package, props);
04890     if (rc != ERROR_SUCCESS)
04891         goto done;
04892 
04893     upgrade_code = msi_dup_property(package->db, szUpgradeCode);
04894     if (upgrade_code)
04895     {
04896         rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
04897         if (rc == ERROR_SUCCESS)
04898         {
04899             squash_guid( package->ProductCode, squashed_pc );
04900             msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
04901             RegCloseKey( upgrade_key );
04902         }
04903         msi_free( upgrade_code );
04904     }
04905     msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
04906     package->delete_on_close = FALSE;
04907 
04908 done:
04909     uirow = MSI_CreateRecord( 1 );
04910     MSI_RecordSetStringW( uirow, 1, package->ProductCode );
04911     msi_ui_actiondata( package, szRegisterProduct, uirow );
04912     msiobj_release( &uirow->hdr );
04913 
04914     RegCloseKey(hkey);
04915     return ERROR_SUCCESS;
04916 }
04917 
04918 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
04919 {
04920     return execute_script(package, SCRIPT_INSTALL);
04921 }
04922 
04923 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
04924 {
04925     MSIPACKAGE *package = param;
04926     const WCHAR *icon = MSI_RecordGetString( row, 1 );
04927     WCHAR *p, *icon_path;
04928 
04929     if (!icon) return ERROR_SUCCESS;
04930     if ((icon_path = msi_build_icon_path( package, icon )))
04931     {
04932         TRACE("removing icon file %s\n", debugstr_w(icon_path));
04933         DeleteFileW( icon_path );
04934         if ((p = strrchrW( icon_path, '\\' )))
04935         {
04936             *p = 0;
04937             RemoveDirectoryW( icon_path );
04938         }
04939         msi_free( icon_path );
04940     }
04941     return ERROR_SUCCESS;
04942 }
04943 
04944 static UINT msi_unpublish_icons( MSIPACKAGE *package )
04945 {
04946     static const WCHAR query[]= {
04947         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
04948     MSIQUERY *view;
04949     UINT r;
04950 
04951     r = MSI_DatabaseOpenViewW( package->db, query, &view );
04952     if (r == ERROR_SUCCESS)
04953     {
04954         r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
04955         msiobj_release( &view->hdr );
04956         if (r != ERROR_SUCCESS)
04957             return r;
04958     }
04959     return ERROR_SUCCESS;
04960 }
04961 
04962 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
04963 {
04964     static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
04965     WCHAR *upgrade, **features;
04966     BOOL full_uninstall = TRUE;
04967     MSIFEATURE *feature;
04968     MSIPATCHINFO *patch;
04969     UINT i;
04970 
04971     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
04972     {
04973         if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
04974     }
04975     features = msi_split_string( remove, ',' );
04976     for (i = 0; features && features[i]; i++)
04977     {
04978         if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
04979     }
04980     msi_free(features);
04981 
04982     if (!full_uninstall)
04983         return ERROR_SUCCESS;
04984 
04985     MSIREG_DeleteProductKey(package->ProductCode);
04986     MSIREG_DeleteUserDataProductKey(package->ProductCode);
04987     MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
04988 
04989     MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
04990     MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
04991     MSIREG_DeleteUserProductKey(package->ProductCode);
04992     MSIREG_DeleteUserFeaturesKey(package->ProductCode);
04993 
04994     upgrade = msi_dup_property(package->db, szUpgradeCode);
04995     if (upgrade)
04996     {
04997         MSIREG_DeleteUserUpgradeCodesKey(upgrade);
04998         MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
04999         msi_free(upgrade);
05000     }
05001 
05002     LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
05003     {
05004         MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
05005         if (!strcmpW( package->ProductCode, patch->products ))
05006         {
05007             TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
05008             patch->delete_on_close = TRUE;
05009         }
05010         /* FIXME: remove local patch package if this is the last product */
05011     }
05012     TRACE("removing local package %s\n", debugstr_w(package->localfile));
05013     package->delete_on_close = TRUE;
05014 
05015     msi_unpublish_icons( package );
05016     return ERROR_SUCCESS;
05017 }
05018 
05019 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
05020 {
05021     UINT rc;
05022     WCHAR *remove;
05023 
05024     /* turn off scheduling */
05025     package->script->CurrentlyScripting= FALSE;
05026 
05027     /* first do the same as an InstallExecute */
05028     rc = ACTION_InstallExecute(package);
05029     if (rc != ERROR_SUCCESS)
05030         return rc;
05031 
05032     /* then handle commit actions */
05033     rc = execute_script(package, SCRIPT_COMMIT);
05034     if (rc != ERROR_SUCCESS)
05035         return rc;
05036 
05037     remove = msi_dup_property(package->db, szRemove);
05038     rc = msi_unpublish_product(package, remove);
05039     msi_free(remove);
05040     return rc;
05041 }
05042 
05043 UINT ACTION_ForceReboot(MSIPACKAGE *package)
05044 {
05045     static const WCHAR RunOnce[] = {
05046     'S','o','f','t','w','a','r','e','\\',
05047     'M','i','c','r','o','s','o','f','t','\\',
05048     'W','i','n','d','o','w','s','\\',
05049     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
05050     'R','u','n','O','n','c','e',0};
05051     static const WCHAR InstallRunOnce[] = {
05052     'S','o','f','t','w','a','r','e','\\',
05053     'M','i','c','r','o','s','o','f','t','\\',
05054     'W','i','n','d','o','w','s','\\',
05055     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
05056     'I','n','s','t','a','l','l','e','r','\\',
05057     'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
05058 
05059     static const WCHAR msiexec_fmt[] = {
05060     '%','s',
05061     '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
05062     '\"','%','s','\"',0};
05063     static const WCHAR install_fmt[] = {
05064     '/','I',' ','\"','%','s','\"',' ',
05065     'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
05066     'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
05067     WCHAR buffer[256], sysdir[MAX_PATH];
05068     HKEY hkey;
05069     WCHAR squished_pc[100];
05070 
05071     squash_guid(package->ProductCode,squished_pc);
05072 
05073     GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
05074     RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
05075     snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
05076      squished_pc);
05077 
05078     msi_reg_set_val_str( hkey, squished_pc, buffer );
05079     RegCloseKey(hkey);
05080 
05081     TRACE("Reboot command %s\n",debugstr_w(buffer));
05082 
05083     RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
05084     sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
05085 
05086     msi_reg_set_val_str( hkey, squished_pc, buffer );
05087     RegCloseKey(hkey);
05088 
05089     return ERROR_INSTALL_SUSPEND;
05090 }
05091 
05092 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
05093 {
05094     static const WCHAR query[] =
05095         {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
05096          'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
05097          '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
05098     MSIRECORD *rec, *row;
05099     DWORD i, size = 0;
05100     va_list va;
05101     const WCHAR *str;
05102     WCHAR *data;
05103 
05104     if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
05105 
05106     rec = MSI_CreateRecord( count + 2 );
05107     str = MSI_RecordGetString( row, 1 );
05108     MSI_RecordSetStringW( rec, 0, str );
05109     msiobj_release( &row->hdr );
05110     MSI_RecordSetInteger( rec, 1, error );
05111 
05112     va_start( va, count );
05113     for (i = 0; i < count; i++)
05114     {
05115         str = va_arg( va, const WCHAR *);
05116         MSI_RecordSetStringW( rec, i + 2, str );
05117     }
05118     va_end( va );
05119 
05120     MSI_FormatRecordW( package, rec, NULL, &size );
05121     size++;
05122     data = msi_alloc( size * sizeof(WCHAR) );
05123     if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
05124     else data[0] = 0;
05125     msiobj_release( &rec->hdr );
05126     return data;
05127 }
05128 
05129 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
05130 {
05131     DWORD attrib;
05132     UINT rc;
05133 
05134     /*
05135      * We are currently doing what should be done here in the top level Install
05136      * however for Administrative and uninstalls this step will be needed
05137      */
05138     if (!package->PackagePath)
05139         return ERROR_SUCCESS;
05140 
05141     msi_set_sourcedir_props(package, TRUE);
05142 
05143     attrib = GetFileAttributesW(package->db->path);
05144     if (attrib == INVALID_FILE_ATTRIBUTES)
05145     {
05146         LPWSTR prompt, msg;
05147         DWORD size = 0;
05148 
05149         rc = MsiSourceListGetInfoW(package->ProductCode, NULL, 
05150                 package->Context, MSICODE_PRODUCT,
05151                 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
05152         if (rc == ERROR_MORE_DATA)
05153         {
05154             prompt = msi_alloc(size * sizeof(WCHAR));
05155             MsiSourceListGetInfoW(package->ProductCode, NULL, 
05156                     package->Context, MSICODE_PRODUCT,
05157                     INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
05158         }
05159         else
05160             prompt = strdupW(package->db->path);
05161 
05162         msg = msi_build_error_string(package, 1302, 1, prompt);
05163         msi_free(prompt);
05164         while(attrib == INVALID_FILE_ATTRIBUTES)
05165         {
05166             rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
05167             if (rc == IDCANCEL)
05168             {
05169                 msi_free(msg);
05170                 return ERROR_INSTALL_USEREXIT;
05171             }
05172             attrib = GetFileAttributesW(package->db->path);
05173         }
05174         msi_free(msg);
05175         rc = ERROR_SUCCESS;
05176     }
05177     else
05178         return ERROR_SUCCESS;
05179 
05180     return rc;
05181 }
05182 
05183 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
05184 {
05185     HKEY hkey = 0;
05186     LPWSTR buffer, productid = NULL;
05187     UINT i, rc = ERROR_SUCCESS;
05188     MSIRECORD *uirow;
05189 
05190     static const WCHAR szPropKeys[][80] = 
05191     {
05192         {'P','r','o','d','u','c','t','I','D',0},
05193         {'U','S','E','R','N','A','M','E',0},
05194         {'C','O','M','P','A','N','Y','N','A','M','E',0},
05195         {0},
05196     };
05197 
05198     static const WCHAR szRegKeys[][80] = 
05199     {
05200         {'P','r','o','d','u','c','t','I','D',0},
05201         {'R','e','g','O','w','n','e','r',0},
05202         {'R','e','g','C','o','m','p','a','n','y',0},
05203         {0},
05204     };
05205 
05206     if (msi_check_unpublish(package))
05207     {
05208         MSIREG_DeleteUserDataProductKey(package->ProductCode);
05209         goto end;
05210     }
05211 
05212     productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
05213     if (!productid)
05214         goto end;
05215 
05216     rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
05217                                  NULL, &hkey, TRUE);
05218     if (rc != ERROR_SUCCESS)
05219         goto end;
05220 
05221     for( i = 0; szPropKeys[i][0]; i++ )
05222     {
05223         buffer = msi_dup_property( package->db, szPropKeys[i] );
05224         msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
05225         msi_free( buffer );
05226     }
05227 
05228 end:
05229     uirow = MSI_CreateRecord( 1 );
05230     MSI_RecordSetStringW( uirow, 1, productid );
05231     msi_ui_actiondata( package, szRegisterUser, uirow );
05232     msiobj_release( &uirow->hdr );
05233 
05234     msi_free(productid);
05235     RegCloseKey(hkey);
05236     return rc;
05237 }
05238 
05239 
05240 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
05241 {
05242     UINT rc;
05243 
05244     package->script->InWhatSequence |= SEQUENCE_EXEC;
05245     rc = ACTION_ProcessExecSequence(package,FALSE);
05246     return rc;
05247 }
05248 
05249 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
05250 {
05251     static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
05252     WCHAR productid_85[21], component_85[21], *ret;
05253     GUID clsid;
05254     DWORD sz;
05255 
05256     /* > is used if there is a component GUID and < if not.  */
05257 
05258     productid_85[0] = 0;
05259     component_85[0] = 0;
05260     CLSIDFromString( package->ProductCode, &clsid );
05261 
05262     encode_base85_guid( &clsid, productid_85 );
05263     if (component)
05264     {
05265         CLSIDFromString( component->ComponentId, &clsid );
05266         encode_base85_guid( &clsid, component_85 );
05267     }
05268 
05269     TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
05270           debugstr_w(component_85));
05271 
05272     sz = 20 + strlenW( feature ) + 20 + 3;
05273     ret = msi_alloc_zero( sz * sizeof(WCHAR) );
05274     if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
05275     return ret;
05276 }
05277 
05278 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
05279 {
05280     MSIPACKAGE *package = param;
05281     LPCWSTR compgroupid, component, feature, qualifier, text;
05282     LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
05283     HKEY hkey = NULL;
05284     UINT rc;
05285     MSICOMPONENT *comp;
05286     MSIFEATURE *feat;
05287     DWORD sz;
05288     MSIRECORD *uirow;
05289     int len;
05290 
05291     feature = MSI_RecordGetString(rec, 5);
05292     feat = msi_get_loaded_feature(package, feature);
05293     if (!feat)
05294         return ERROR_SUCCESS;
05295 
05296     feat->Action = msi_get_feature_action( package, feat );
05297     if (feat->Action != INSTALLSTATE_LOCAL &&
05298         feat->Action != INSTALLSTATE_SOURCE &&
05299         feat->Action != INSTALLSTATE_ADVERTISED)
05300     {
05301         TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
05302         return ERROR_SUCCESS;
05303     }
05304 
05305     component = MSI_RecordGetString(rec, 3);
05306     comp = msi_get_loaded_component(package, component);
05307     if (!comp)
05308         return ERROR_SUCCESS;
05309 
05310     compgroupid = MSI_RecordGetString(rec,1);
05311     qualifier = MSI_RecordGetString(rec,2);
05312 
05313     rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
05314     if (rc != ERROR_SUCCESS)
05315         goto end;
05316 
05317     advertise = msi_create_component_advertise_string( package, comp, feature );
05318     text = MSI_RecordGetString( rec, 4 );
05319     if (text)
05320     {
05321         p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
05322         strcpyW( p, advertise );
05323         strcatW( p, text );
05324         msi_free( advertise );
05325         advertise = p;
05326     }
05327     existing = msi_reg_get_val_str( hkey, qualifier );
05328 
05329     sz = strlenW( advertise ) + 1;
05330     if (existing)
05331     {
05332         for (p = existing; *p; p += len)
05333         {
05334             len = strlenW( p ) + 1;
05335             if (strcmpW( advertise, p )) sz += len;
05336         }
05337     }
05338     if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
05339     {
05340         rc = ERROR_OUTOFMEMORY;
05341         goto end;
05342     }
05343     q = output;
05344     if (existing)
05345     {
05346         for (p = existing; *p; p += len)
05347         {
05348             len = strlenW( p ) + 1;
05349             if (strcmpW( advertise, p ))
05350             {
05351                 memcpy( q, p, len * sizeof(WCHAR) );
05352                 q += len;
05353             }
05354         }
05355     }
05356     strcpyW( q, advertise );
05357     q[strlenW( q ) + 1] = 0;
05358 
05359     msi_reg_set_val_multi_str( hkey, qualifier, output );
05360     
05361 end:
05362     RegCloseKey(hkey);
05363     msi_free( output );
05364     msi_free( advertise );
05365     msi_free( existing );
05366 
05367     /* the UI chunk */
05368     uirow = MSI_CreateRecord( 2 );
05369     MSI_RecordSetStringW( uirow, 1, compgroupid );
05370     MSI_RecordSetStringW( uirow, 2, qualifier);
05371     msi_ui_actiondata( package, szPublishComponents, uirow );
05372     msiobj_release( &uirow->hdr );
05373     /* FIXME: call ui_progress? */
05374 
05375     return rc;
05376 }
05377 
05378 /*
05379  * At present I am ignorning the advertised components part of this and only
05380  * focusing on the qualified component sets
05381  */
05382 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
05383 {
05384     static const WCHAR query[] = {
05385         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
05386         '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
05387     MSIQUERY *view;
05388     UINT rc;
05389     
05390     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
05391     if (rc != ERROR_SUCCESS)
05392         return ERROR_SUCCESS;
05393 
05394     rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
05395     msiobj_release(&view->hdr);
05396     return rc;
05397 }
05398 
05399 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
05400 {
05401     static const WCHAR szInstallerComponents[] = {
05402         'S','o','f','t','w','a','r','e','\\',
05403         'M','i','c','r','o','s','o','f','t','\\',
05404         'I','n','s','t','a','l','l','e','r','\\',
05405         'C','o','m','p','o','n','e','n','t','s','\\',0};
05406 
05407     MSIPACKAGE *package = param;
05408     LPCWSTR compgroupid, component, feature, qualifier;
05409     MSICOMPONENT *comp;
05410     MSIFEATURE *feat;
05411     MSIRECORD *uirow;
05412     WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
05413     LONG res;
05414 
05415     feature = MSI_RecordGetString( rec, 5 );
05416     feat = msi_get_loaded_feature( package, feature );
05417     if (!feat)
05418         return ERROR_SUCCESS;
05419 
05420     feat->Action = msi_get_feature_action( package, feat );
05421     if (feat->Action != INSTALLSTATE_ABSENT)
05422     {
05423         TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
05424         return ERROR_SUCCESS;
05425     }
05426 
05427     component = MSI_RecordGetString( rec, 3 );
05428     comp = msi_get_loaded_component( package, component );
05429     if (!comp)
05430         return ERROR_SUCCESS;
05431 
05432     compgroupid = MSI_RecordGetString( rec, 1 );
05433     qualifier = MSI_RecordGetString( rec, 2 );
05434 
05435     squash_guid( compgroupid, squashed );
05436     strcpyW( keypath, szInstallerComponents );
05437     strcatW( keypath, squashed );
05438 
05439     res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
05440     if (res != ERROR_SUCCESS)
05441     {
05442         WARN("Unable to delete component key %d\n", res);
05443     }
05444 
05445     uirow = MSI_CreateRecord( 2 );
05446     MSI_RecordSetStringW( uirow, 1, compgroupid );
05447     MSI_RecordSetStringW( uirow, 2, qualifier );
05448     msi_ui_actiondata( package, szUnpublishComponents, uirow );
05449     msiobj_release( &uirow->hdr );
05450 
05451     return ERROR_SUCCESS;
05452 }
05453 
05454 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
05455 {
05456     static const WCHAR query[] = {
05457         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
05458         '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
05459     MSIQUERY *view;
05460     UINT rc;
05461 
05462     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
05463     if (rc != ERROR_SUCCESS)
05464         return ERROR_SUCCESS;
05465 
05466     rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
05467     msiobj_release( &view->hdr );
05468     return rc;
05469 }
05470 
05471 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
05472 {
05473     static const WCHAR query[] =
05474         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
05475          '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
05476          '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
05477     MSIPACKAGE *package = param;
05478     MSICOMPONENT *component;
05479     MSIRECORD *row;
05480     MSIFILE *file;
05481     SC_HANDLE hscm = NULL, service = NULL;
05482     LPCWSTR comp, key;
05483     LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
05484     LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
05485     DWORD serv_type, start_type, err_control;
05486     SERVICE_DESCRIPTIONW sd = {NULL};
05487 
05488     comp = MSI_RecordGetString( rec, 12 );
05489     component = msi_get_loaded_component( package, comp );
05490     if (!component)
05491     {
05492         WARN("service component not found\n");
05493         goto done;
05494     }
05495     component->Action = msi_get_component_action( package, component );
05496     if (component->Action != INSTALLSTATE_LOCAL)
05497     {
05498         TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
05499         goto done;
05500     }
05501     hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
05502     if (!hscm)
05503     {
05504         ERR("Failed to open the SC Manager!\n");
05505         goto done;
05506     }
05507 
05508     start_type = MSI_RecordGetInteger(rec, 5);
05509     if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
05510         goto done;
05511 
05512     deformat_string(package, MSI_RecordGetString(rec, 2), &name);
05513     deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
05514     serv_type = MSI_RecordGetInteger(rec, 4);
05515     err_control = MSI_RecordGetInteger(rec, 6);
05516     deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
05517     deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
05518     deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
05519     deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
05520     deformat_string(package, MSI_RecordGetString(rec, 11), &args);
05521     deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
05522 
05523     /* fetch the service path */
05524     row = MSI_QueryGetRecord(package->db, query, comp);
05525     if (!row)
05526     {
05527         ERR("Query failed\n");
05528         goto done;
05529     }
05530     key = MSI_RecordGetString(row, 6);
05531     file = msi_get_loaded_file(package, key);
05532     msiobj_release(&row->hdr);
05533     if (!file)
05534     {
05535         ERR("Failed to load the service file\n");
05536         goto done;
05537     }
05538 
05539     if (!args || !args[0]) image_path = file->TargetPath;
05540     else
05541     {
05542         int len = strlenW(file->TargetPath) + strlenW(args) + 2;
05543         if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
05544             return ERROR_OUTOFMEMORY;
05545 
05546         strcpyW(image_path, file->TargetPath);
05547         strcatW(image_path, szSpace);
05548         strcatW(image_path, args);
05549     }
05550     service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
05551                              start_type, err_control, image_path, load_order,
05552                              NULL, depends, serv_name, pass);
05553 
05554     if (!service)
05555     {
05556         if (GetLastError() != ERROR_SERVICE_EXISTS)
05557             ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
05558     }
05559     else if (sd.lpDescription)
05560     {
05561         if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
05562             WARN("failed to set service description %u\n", GetLastError());
05563     }
05564 
05565     if (image_path != file->TargetPath) msi_free(image_path);
05566 done:
05567     CloseServiceHandle(service);
05568     CloseServiceHandle(hscm);
05569     msi_free(name);
05570     msi_free(disp);
05571     msi_free(sd.lpDescription);
05572     msi_free(load_order);
05573     msi_free(serv_name);
05574     msi_free(pass);
05575     msi_free(depends);
05576     msi_free(args);
05577 
05578     return ERROR_SUCCESS;
05579 }
05580 
05581 static UINT ACTION_InstallServices( MSIPACKAGE *package )
05582 {
05583     static const WCHAR query[] = {
05584         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
05585         'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
05586     MSIQUERY *view;
05587     UINT rc;
05588     
05589     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
05590     if (rc != ERROR_SUCCESS)
05591         return ERROR_SUCCESS;
05592 
05593     rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
05594     msiobj_release(&view->hdr);
05595     return rc;
05596 }
05597 
05598 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
05599 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
05600 {
05601     LPCWSTR *vector, *temp_vector;
05602     LPWSTR p, q;
05603     DWORD sep_len;
05604 
05605     static const WCHAR separator[] = {'[','~',']',0};
05606 
05607     *numargs = 0;
05608     sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
05609 
05610     if (!args)
05611         return NULL;
05612 
05613     vector = msi_alloc(sizeof(LPWSTR));
05614     if (!vector)
05615         return NULL;
05616 
05617     p = args;
05618     do
05619     {
05620         (*numargs)++;
05621         vector[*numargs - 1] = p;
05622 
05623         if ((q = strstrW(p, separator)))
05624         {
05625             *q = '\0';
05626 
05627             temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
05628             if (!temp_vector)
05629             {
05630                 msi_free(vector);
05631                 return NULL;
05632             }
05633             vector = temp_vector;
05634 
05635             p = q + sep_len;
05636         }
05637     } while (q);
05638 
05639     return vector;
05640 }
05641 
05642 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
05643 {
05644     MSIPACKAGE *package = param;
05645     MSICOMPONENT *comp;
05646     MSIRECORD *uirow;
05647     SC_HANDLE scm = NULL, service = NULL;
05648     LPCWSTR component, *vector = NULL;
05649     LPWSTR name, args, display_name = NULL;
05650     DWORD event, numargs, len, wait, dummy;
05651     UINT r = ERROR_FUNCTION_FAILED;
05652     SERVICE_STATUS_PROCESS status;
05653     ULONGLONG start_time;
05654 
05655     component = MSI_RecordGetString(rec, 6);
05656     comp = msi_get_loaded_component(package, component);
05657     if (!comp)
05658         return ERROR_SUCCESS;
05659 
05660     comp->Action = msi_get_component_action( package, comp );
05661     if (comp->Action != INSTALLSTATE_LOCAL)
05662     {
05663         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
05664         return ERROR_SUCCESS;
05665     }
05666 
05667     deformat_string(package, MSI_RecordGetString(rec, 2), &name);
05668     deformat_string(package, MSI_RecordGetString(rec, 4), &args);
05669     event = MSI_RecordGetInteger(rec, 3);
05670     wait = MSI_RecordGetInteger(rec, 5);
05671 
05672     if (!(event & msidbServiceControlEventStart))
05673     {
05674         r = ERROR_SUCCESS;
05675         goto done;
05676     }
05677 
05678     scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
05679     if (!scm)
05680     {
05681         ERR("Failed to open the service control manager\n");
05682         goto done;
05683     }
05684 
05685     len = 0;
05686     if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
05687         GetLastError() == ERROR_INSUFFICIENT_BUFFER)
05688     {
05689         if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
05690             GetServiceDisplayNameW( scm, name, display_name, &len );
05691     }
05692 
05693     service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS);
05694     if (!service)
05695     {
05696         ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
05697         goto done;
05698     }
05699 
05700     vector = msi_service_args_to_vector(args, &numargs);
05701 
05702     if (!StartServiceW(service, numargs, vector) &&
05703         GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
05704     {
05705         ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
05706         goto done;
05707     }
05708 
05709     r = ERROR_SUCCESS;
05710     if (wait)
05711     {
05712         /* wait for at most 30 seconds for the service to be up and running */
05713         if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
05714             (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
05715         {
05716             TRACE("failed to query service status (%u)\n", GetLastError());
05717             goto done;
05718         }
05719         start_time = GetTickCount64();
05720         while (status.dwCurrentState == SERVICE_START_PENDING)
05721         {
05722             if (GetTickCount64() - start_time > 30000) break;
05723             Sleep(1000);
05724             if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
05725                 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
05726             {
05727                 TRACE("failed to query service status (%u)\n", GetLastError());
05728                 goto done;
05729             }
05730         }
05731         if (status.dwCurrentState != SERVICE_RUNNING)
05732         {
05733             WARN("service failed to start %u\n", status.dwCurrentState);
05734             r = ERROR_FUNCTION_FAILED;
05735         }
05736     }
05737 
05738 done:
05739     uirow = MSI_CreateRecord( 2 );
05740     MSI_RecordSetStringW( uirow, 1, display_name );
05741     MSI_RecordSetStringW( uirow, 2, name );
05742     msi_ui_actiondata( package, szStartServices, uirow );
05743     msiobj_release( &uirow->hdr );
05744 
05745     CloseServiceHandle(service);
05746     CloseServiceHandle(scm);
05747 
05748     msi_free(name);
05749     msi_free(args);
05750     msi_free(vector);
05751     msi_free(display_name);
05752     return r;
05753 }
05754 
05755 static UINT ACTION_StartServices( MSIPACKAGE *package )
05756 {
05757     static const WCHAR query[] = {
05758         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
05759         'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
05760     MSIQUERY *view;
05761     UINT rc;
05762 
05763     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
05764     if (rc != ERROR_SUCCESS)
05765         return ERROR_SUCCESS;
05766 
05767     rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
05768     msiobj_release(&view->hdr);
05769     return rc;
05770 }
05771 
05772 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
05773 {
05774     DWORD i, needed, count;
05775     ENUM_SERVICE_STATUSW *dependencies;
05776     SERVICE_STATUS ss;
05777     SC_HANDLE depserv;
05778 
05779     if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
05780                                0, &needed, &count))
05781         return TRUE;
05782 
05783     if (GetLastError() != ERROR_MORE_DATA)
05784         return FALSE;
05785 
05786     dependencies = msi_alloc(needed);
05787     if (!dependencies)
05788         return FALSE;
05789 
05790     if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
05791                                 needed, &needed, &count))
05792         goto error;
05793 
05794     for (i = 0; i < count; i++)
05795     {
05796         depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
05797                                SERVICE_STOP | SERVICE_QUERY_STATUS);
05798         if (!depserv)
05799             goto error;
05800 
05801         if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
05802             goto error;
05803     }
05804 
05805     return TRUE;
05806 
05807 error:
05808     msi_free(dependencies);
05809     return FALSE;
05810 }
05811 
05812 static UINT stop_service( LPCWSTR name )
05813 {
05814     SC_HANDLE scm = NULL, service = NULL;
05815     SERVICE_STATUS status;
05816     SERVICE_STATUS_PROCESS ssp;
05817     DWORD needed;
05818 
05819     scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
05820     if (!scm)
05821     {
05822         WARN("Failed to open the SCM: %d\n", GetLastError());
05823         goto done;
05824     }
05825 
05826     service = OpenServiceW(scm, name,
05827                            SERVICE_STOP |
05828                            SERVICE_QUERY_STATUS |
05829                            SERVICE_ENUMERATE_DEPENDENTS);
05830     if (!service)
05831     {
05832         WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
05833         goto done;
05834     }
05835 
05836     if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
05837                               sizeof(SERVICE_STATUS_PROCESS), &needed))
05838     {
05839         WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
05840         goto done;
05841     }
05842 
05843     if (ssp.dwCurrentState == SERVICE_STOPPED)
05844         goto done;
05845 
05846     stop_service_dependents(scm, service);
05847 
05848     if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
05849         WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
05850 
05851 done:
05852     CloseServiceHandle(service);
05853     CloseServiceHandle(scm);
05854 
05855     return ERROR_SUCCESS;
05856 }
05857 
05858 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
05859 {
05860     MSIPACKAGE *package = param;
05861     MSICOMPONENT *comp;
05862     MSIRECORD *uirow;
05863     LPCWSTR component;
05864     LPWSTR name = NULL, display_name = NULL;
05865     DWORD event, len;
05866     SC_HANDLE scm;
05867 
05868     event = MSI_RecordGetInteger( rec, 3 );
05869     if (!(event & msidbServiceControlEventStop))
05870         return ERROR_SUCCESS;
05871 
05872     component = MSI_RecordGetString( rec, 6 );
05873     comp = msi_get_loaded_component( package, component );
05874     if (!comp)
05875         return ERROR_SUCCESS;
05876 
05877     comp->Action = msi_get_component_action( package, comp );
05878     if (comp->Action != INSTALLSTATE_ABSENT)
05879     {
05880         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
05881         return ERROR_SUCCESS;
05882     }
05883 
05884     scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
05885     if (!scm)
05886     {
05887         ERR("Failed to open the service control manager\n");
05888         goto done;
05889     }
05890 
05891     len = 0;
05892     if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
05893         GetLastError() == ERROR_INSUFFICIENT_BUFFER)
05894     {
05895         if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
05896             GetServiceDisplayNameW( scm, name, display_name, &len );
05897     }
05898     CloseServiceHandle( scm );
05899 
05900     deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
05901     stop_service( name );
05902 
05903 done:
05904     uirow = MSI_CreateRecord( 2 );
05905     MSI_RecordSetStringW( uirow, 1, display_name );
05906     MSI_RecordSetStringW( uirow, 2, name );
05907     msi_ui_actiondata( package, szStopServices, uirow );
05908     msiobj_release( &uirow->hdr );
05909 
05910     msi_free( name );
05911     msi_free( display_name );
05912     return ERROR_SUCCESS;
05913 }
05914 
05915 static UINT ACTION_StopServices( MSIPACKAGE *package )
05916 {
05917     static const WCHAR query[] = {
05918         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
05919         'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
05920     MSIQUERY *view;
05921     UINT rc;
05922 
05923     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
05924     if (rc != ERROR_SUCCESS)
05925         return ERROR_SUCCESS;
05926 
05927     rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
05928     msiobj_release(&view->hdr);
05929     return rc;
05930 }
05931 
05932 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
05933 {
05934     MSIPACKAGE *package = param;
05935     MSICOMPONENT *comp;
05936     MSIRECORD *uirow;
05937     LPWSTR name = NULL, display_name = NULL;
05938     DWORD event, len;
05939     SC_HANDLE scm = NULL, service = NULL;
05940 
05941     comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) );
05942     if (!comp)
05943         return ERROR_SUCCESS;
05944 
05945     event = MSI_RecordGetInteger( rec, 3 );
05946     deformat_string( package, MSI_RecordGetString(rec, 2), &name );
05947 
05948     comp->Action = msi_get_component_action( package, comp );
05949     if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) &&
05950         !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete)))
05951     {
05952         TRACE("service %s not scheduled for removal\n", debugstr_w(name));
05953         msi_free( name );
05954         return ERROR_SUCCESS;
05955     }
05956     stop_service( name );
05957 
05958     scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
05959     if (!scm)
05960     {
05961         WARN("Failed to open the SCM: %d\n", GetLastError());
05962         goto done;
05963     }
05964 
05965     len = 0;
05966     if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
05967         GetLastError() == ERROR_INSUFFICIENT_BUFFER)
05968     {
05969         if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
05970             GetServiceDisplayNameW( scm, name, display_name, &len );
05971     }
05972 
05973     service = OpenServiceW( scm, name, DELETE );
05974     if (!service)
05975     {
05976         WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
05977         goto done;
05978     }
05979 
05980     if (!DeleteService( service ))
05981         WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
05982 
05983 done:
05984     uirow = MSI_CreateRecord( 2 );
05985     MSI_RecordSetStringW( uirow, 1, display_name );
05986     MSI_RecordSetStringW( uirow, 2, name );
05987     msi_ui_actiondata( package, szDeleteServices, uirow );
05988     msiobj_release( &uirow->hdr );
05989 
05990     CloseServiceHandle( service );
05991     CloseServiceHandle( scm );
05992     msi_free( name );
05993     msi_free( display_name );
05994 
05995     return ERROR_SUCCESS;
05996 }
05997 
05998 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
05999 {
06000     static const WCHAR query[] = {
06001         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
06002         'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
06003     MSIQUERY *view;
06004     UINT rc;
06005 
06006     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
06007     if (rc != ERROR_SUCCESS)
06008         return ERROR_SUCCESS;
06009 
06010     rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
06011     msiobj_release( &view->hdr );
06012     return rc;
06013 }
06014 
06015 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
06016 {
06017     MSIPACKAGE *package = param;
06018     LPWSTR driver, driver_path, ptr;
06019     WCHAR outpath[MAX_PATH];
06020     MSIFILE *driver_file = NULL, *setup_file = NULL;
06021     MSICOMPONENT *comp;
06022     MSIRECORD *uirow;
06023     LPCWSTR desc, file_key, component;
06024     DWORD len, usage;
06025     UINT r = ERROR_SUCCESS;
06026 
06027     static const WCHAR driver_fmt[] = {
06028         'D','r','i','v','e','r','=','%','s',0};
06029     static const WCHAR setup_fmt[] = {
06030         'S','e','t','u','p','=','%','s',0};
06031     static const WCHAR usage_fmt[] = {
06032         'F','i','l','e','U','s','a','g','e','=','1',0};
06033 
06034     component = MSI_RecordGetString( rec, 2 );
06035     comp = msi_get_loaded_component( package, component );
06036     if (!comp)
06037         return ERROR_SUCCESS;
06038 
06039     comp->Action = msi_get_component_action( package, comp );
06040     if (comp->Action != INSTALLSTATE_LOCAL)
06041     {
06042         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
06043         return ERROR_SUCCESS;
06044     }
06045     desc = MSI_RecordGetString(rec, 3);
06046 
06047     file_key = MSI_RecordGetString( rec, 4 );
06048     if (file_key) driver_file = msi_get_loaded_file( package, file_key );
06049 
06050     file_key = MSI_RecordGetString( rec, 5 );
06051     if (file_key) setup_file = msi_get_loaded_file( package, file_key );
06052 
06053     if (!driver_file)
06054     {
06055         ERR("ODBC Driver entry not found!\n");
06056         return ERROR_FUNCTION_FAILED;
06057     }
06058 
06059     len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
06060     if (setup_file)
06061         len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
06062     len += lstrlenW(usage_fmt) + 2; /* \0\0 */
06063 
06064     driver = msi_alloc(len * sizeof(WCHAR));
06065     if (!driver)
06066         return ERROR_OUTOFMEMORY;
06067 
06068     ptr = driver;
06069     lstrcpyW(ptr, desc);
06070     ptr += lstrlenW(ptr) + 1;
06071 
06072     len = sprintfW(ptr, driver_fmt, driver_file->FileName);
06073     ptr += len + 1;
06074 
06075     if (setup_file)
06076     {
06077         len = sprintfW(ptr, setup_fmt, setup_file->FileName);
06078         ptr += len + 1;
06079     }
06080 
06081     lstrcpyW(ptr, usage_fmt);
06082     ptr += lstrlenW(ptr) + 1;
06083     *ptr = '\0';
06084 
06085     if (!driver_file->TargetPath)
06086     {
06087         const WCHAR *dir = msi_get_target_folder( package, driver_file->Component->Directory );
06088         driver_file->TargetPath = msi_build_directory_name( 2, dir, driver_file->FileName );
06089     }
06090     driver_path = strdupW(driver_file->TargetPath);
06091     ptr = strrchrW(driver_path, '\\');
06092     if (ptr) *ptr = '\0';
06093 
06094     if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
06095                              NULL, ODBC_INSTALL_COMPLETE, &usage))
06096     {
06097         ERR("Failed to install SQL driver!\n");
06098         r = ERROR_FUNCTION_FAILED;
06099     }
06100 
06101     uirow = MSI_CreateRecord( 5 );
06102     MSI_RecordSetStringW( uirow, 1, desc );
06103     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
06104     MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
06105     msi_ui_actiondata( package, szInstallODBC, uirow );
06106     msiobj_release( &uirow->hdr );
06107 
06108     msi_free(driver);
06109     msi_free(driver_path);
06110 
06111     return r;
06112 }
06113 
06114 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
06115 {
06116     MSIPACKAGE *package = param;
06117     LPWSTR translator, translator_path, ptr;
06118     WCHAR outpath[MAX_PATH];
06119     MSIFILE *translator_file = NULL, *setup_file = NULL;
06120     MSICOMPONENT *comp;
06121     MSIRECORD *uirow;
06122     LPCWSTR desc, file_key, component;
06123     DWORD len, usage;
06124     UINT r = ERROR_SUCCESS;
06125 
06126     static const WCHAR translator_fmt[] = {
06127         'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
06128     static const WCHAR setup_fmt[] = {
06129         'S','e','t','u','p','=','%','s',0};
06130 
06131     component = MSI_RecordGetString( rec, 2 );
06132     comp = msi_get_loaded_component( package, component );
06133     if (!comp)
06134         return ERROR_SUCCESS;
06135 
06136     comp->Action = msi_get_component_action( package, comp );
06137     if (comp->Action != INSTALLSTATE_LOCAL)
06138     {
06139         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
06140         return ERROR_SUCCESS;
06141     }
06142     desc = MSI_RecordGetString(rec, 3);
06143 
06144     file_key = MSI_RecordGetString( rec, 4 );
06145     if (file_key) translator_file = msi_get_loaded_file( package, file_key );
06146 
06147     file_key = MSI_RecordGetString( rec, 5 );
06148     if (file_key) setup_file = msi_get_loaded_file( package, file_key );
06149 
06150     if (!translator_file)
06151     {
06152         ERR("ODBC Translator entry not found!\n");
06153         return ERROR_FUNCTION_FAILED;
06154     }
06155 
06156     len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
06157     if (setup_file)
06158         len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
06159 
06160     translator = msi_alloc(len * sizeof(WCHAR));
06161     if (!translator)
06162         return ERROR_OUTOFMEMORY;
06163 
06164     ptr = translator;
06165     lstrcpyW(ptr, desc);
06166     ptr += lstrlenW(ptr) + 1;
06167 
06168     len = sprintfW(ptr, translator_fmt, translator_file->FileName);
06169     ptr += len + 1;
06170 
06171     if (setup_file)
06172     {
06173         len = sprintfW(ptr, setup_fmt, setup_file->FileName);
06174         ptr += len + 1;
06175     }
06176     *ptr = '\0';
06177 
06178     translator_path = strdupW(translator_file->TargetPath);
06179     ptr = strrchrW(translator_path, '\\');
06180     if (ptr) *ptr = '\0';
06181 
06182     if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
06183                                  NULL, ODBC_INSTALL_COMPLETE, &usage))
06184     {
06185         ERR("Failed to install SQL translator!\n");
06186         r = ERROR_FUNCTION_FAILED;
06187     }
06188 
06189     uirow = MSI_CreateRecord( 5 );
06190     MSI_RecordSetStringW( uirow, 1, desc );
06191     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
06192     MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
06193     msi_ui_actiondata( package, szInstallODBC, uirow );
06194     msiobj_release( &uirow->hdr );
06195 
06196     msi_free(translator);
06197     msi_free(translator_path);
06198 
06199     return r;
06200 }
06201 
06202 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
06203 {
06204     MSIPACKAGE *package = param;
06205     MSICOMPONENT *comp;
06206     LPWSTR attrs;
06207     LPCWSTR desc, driver, component;
06208     WORD request = ODBC_ADD_SYS_DSN;
06209     INT registration;
06210     DWORD len;
06211     UINT r = ERROR_SUCCESS;
06212     MSIRECORD *uirow;
06213 
06214     static const WCHAR attrs_fmt[] = {
06215         'D','S','N','=','%','s',0 };
06216 
06217     component = MSI_RecordGetString( rec, 2 );
06218     comp = msi_get_loaded_component( package, component );
06219     if (!comp)
06220         return ERROR_SUCCESS;
06221 
06222     comp->Action = msi_get_component_action( package, comp );
06223     if (comp->Action != INSTALLSTATE_LOCAL)
06224     {
06225         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
06226         return ERROR_SUCCESS;
06227     }
06228 
06229     desc = MSI_RecordGetString(rec, 3);
06230     driver = MSI_RecordGetString(rec, 4);
06231     registration = MSI_RecordGetInteger(rec, 5);
06232 
06233     if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
06234     else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
06235 
06236     len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
06237     attrs = msi_alloc(len * sizeof(WCHAR));
06238     if (!attrs)
06239         return ERROR_OUTOFMEMORY;
06240 
06241     len = sprintfW(attrs, attrs_fmt, desc);
06242     attrs[len + 1] = 0;
06243 
06244     if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
06245     {
06246         ERR("Failed to install SQL data source!\n");
06247         r = ERROR_FUNCTION_FAILED;
06248     }
06249 
06250     uirow = MSI_CreateRecord( 5 );
06251     MSI_RecordSetStringW( uirow, 1, desc );
06252     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
06253     MSI_RecordSetInteger( uirow, 3, request );
06254     msi_ui_actiondata( package, szInstallODBC, uirow );
06255     msiobj_release( &uirow->hdr );
06256 
06257     msi_free(attrs);
06258 
06259     return r;
06260 }
06261 
06262 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
06263 {
06264     static const WCHAR driver_query[] = {
06265         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
06266         'O','D','B','C','D','r','i','v','e','r',0};
06267     static const WCHAR translator_query[] = {
06268         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
06269         'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
06270     static const WCHAR source_query[] = {
06271         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
06272         'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
06273     MSIQUERY *view;
06274     UINT rc;
06275 
06276     rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
06277     if (rc == ERROR_SUCCESS)
06278     {
06279         rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
06280         msiobj_release(&view->hdr);
06281         if (rc != ERROR_SUCCESS)
06282             return rc;
06283     }
06284     rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
06285     if (rc == ERROR_SUCCESS)
06286     {
06287         rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
06288         msiobj_release(&view->hdr);
06289         if (rc != ERROR_SUCCESS)
06290             return rc;
06291     }
06292     rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
06293     if (rc == ERROR_SUCCESS)
06294     {
06295         rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
06296         msiobj_release(&view->hdr);
06297         if (rc != ERROR_SUCCESS)
06298             return rc;
06299     }
06300     return ERROR_SUCCESS;
06301 }
06302 
06303 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
06304 {
06305     MSIPACKAGE *package = param;
06306     MSICOMPONENT *comp;
06307     MSIRECORD *uirow;
06308     DWORD usage;
06309     LPCWSTR desc, component;
06310 
06311     component = MSI_RecordGetString( rec, 2 );
06312     comp = msi_get_loaded_component( package, component );
06313     if (!comp)
06314         return ERROR_SUCCESS;
06315 
06316     comp->Action = msi_get_component_action( package, comp );
06317     if (comp->Action != INSTALLSTATE_ABSENT)
06318     {
06319         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
06320         return ERROR_SUCCESS;
06321     }
06322 
06323     desc = MSI_RecordGetString( rec, 3 );
06324     if (!SQLRemoveDriverW( desc, FALSE, &usage ))
06325     {
06326         WARN("Failed to remove ODBC driver\n");
06327     }
06328     else if (!usage)
06329     {
06330         FIXME("Usage count reached 0\n");
06331     }
06332 
06333     uirow = MSI_CreateRecord( 2 );
06334     MSI_RecordSetStringW( uirow, 1, desc );
06335     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
06336     msi_ui_actiondata( package, szRemoveODBC, uirow );
06337     msiobj_release( &uirow->hdr );
06338 
06339     return ERROR_SUCCESS;
06340 }
06341 
06342 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
06343 {
06344     MSIPACKAGE *package = param;
06345     MSICOMPONENT *comp;
06346     MSIRECORD *uirow;
06347     DWORD usage;
06348     LPCWSTR desc, component;
06349 
06350     component = MSI_RecordGetString( rec, 2 );
06351     comp = msi_get_loaded_component( package, component );
06352     if (!comp)
06353         return ERROR_SUCCESS;
06354 
06355     comp->Action = msi_get_component_action( package, comp );
06356     if (comp->Action != INSTALLSTATE_ABSENT)
06357     {
06358         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
06359         return ERROR_SUCCESS;
06360     }
06361 
06362     desc = MSI_RecordGetString( rec, 3 );
06363     if (!SQLRemoveTranslatorW( desc, &usage ))
06364     {
06365         WARN("Failed to remove ODBC translator\n");
06366     }
06367     else if (!usage)
06368     {
06369         FIXME("Usage count reached 0\n");
06370     }
06371 
06372     uirow = MSI_CreateRecord( 2 );
06373     MSI_RecordSetStringW( uirow, 1, desc );
06374     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
06375     msi_ui_actiondata( package, szRemoveODBC, uirow );
06376     msiobj_release( &uirow->hdr );
06377 
06378     return ERROR_SUCCESS;
06379 }
06380 
06381 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
06382 {
06383     MSIPACKAGE *package = param;
06384     MSICOMPONENT *comp;
06385     MSIRECORD *uirow;
06386     LPWSTR attrs;
06387     LPCWSTR desc, driver, component;
06388     WORD request = ODBC_REMOVE_SYS_DSN;
06389     INT registration;
06390     DWORD len;
06391 
06392     static const WCHAR attrs_fmt[] = {
06393         'D','S','N','=','%','s',0 };
06394 
06395     component = MSI_RecordGetString( rec, 2 );
06396     comp = msi_get_loaded_component( package, component );
06397     if (!comp)
06398         return ERROR_SUCCESS;
06399 
06400     comp->Action = msi_get_component_action( package, comp );
06401     if (comp->Action != INSTALLSTATE_ABSENT)
06402     {
06403         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
06404         return ERROR_SUCCESS;
06405     }
06406 
06407     desc = MSI_RecordGetString( rec, 3 );
06408     driver = MSI_RecordGetString( rec, 4 );
06409     registration = MSI_RecordGetInteger( rec, 5 );
06410 
06411     if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
06412     else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
06413 
06414     len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
06415     attrs = msi_alloc( len * sizeof(WCHAR) );
06416     if (!attrs)
06417         return ERROR_OUTOFMEMORY;
06418 
06419     FIXME("Use ODBCSourceAttribute table\n");
06420 
06421     len = sprintfW( attrs, attrs_fmt, desc );
06422     attrs[len + 1] = 0;
06423 
06424     if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
06425     {
06426         WARN("Failed to remove ODBC data source\n");
06427     }
06428     msi_free( attrs );
06429 
06430     uirow = MSI_CreateRecord( 3 );
06431     MSI_RecordSetStringW( uirow, 1, desc );
06432     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
06433     MSI_RecordSetInteger( uirow, 3, request );
06434     msi_ui_actiondata( package, szRemoveODBC, uirow );
06435     msiobj_release( &uirow->hdr );
06436 
06437     return ERROR_SUCCESS;
06438 }
06439 
06440 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
06441 {
06442     static const WCHAR driver_query[] = {
06443         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
06444         'O','D','B','C','D','r','i','v','e','r',0};
06445     static const WCHAR translator_query[] = {
06446         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
06447         'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
06448     static const WCHAR source_query[] = {
06449         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
06450         'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
06451     MSIQUERY *view;
06452     UINT rc;
06453 
06454     rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
06455     if (rc == ERROR_SUCCESS)
06456     {
06457         rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
06458         msiobj_release( &view->hdr );
06459         if (rc != ERROR_SUCCESS)
06460             return rc;
06461     }
06462     rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
06463     if (rc == ERROR_SUCCESS)
06464     {
06465         rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
06466         msiobj_release( &view->hdr );
06467         if (rc != ERROR_SUCCESS)
06468             return rc;
06469     }
06470     rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
06471     if (rc == ERROR_SUCCESS)
06472     {
06473         rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
06474         msiobj_release( &view->hdr );
06475         if (rc != ERROR_SUCCESS)
06476             return rc;
06477     }
06478     return ERROR_SUCCESS;
06479 }
06480 
06481 #define ENV_ACT_SETALWAYS   0x1
06482 #define ENV_ACT_SETABSENT   0x2
06483 #define ENV_ACT_REMOVE      0x4
06484 #define ENV_ACT_REMOVEMATCH 0x8
06485 
06486 #define ENV_MOD_MACHINE     0x20000000
06487 #define ENV_MOD_APPEND      0x40000000
06488 #define ENV_MOD_PREFIX      0x80000000
06489 #define ENV_MOD_MASK        0xC0000000
06490 
06491 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
06492 
06493 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
06494 {
06495     LPCWSTR cptr = *name;
06496 
06497     static const WCHAR prefix[] = {'[','~',']',0};
06498     static const int prefix_len = 3;
06499 
06500     *flags = 0;
06501     while (*cptr)
06502     {
06503         if (*cptr == '=')
06504             *flags |= ENV_ACT_SETALWAYS;
06505         else if (*cptr == '+')
06506             *flags |= ENV_ACT_SETABSENT;
06507         else if (*cptr == '-')
06508             *flags |= ENV_ACT_REMOVE;
06509         else if (*cptr == '!')
06510             *flags |= ENV_ACT_REMOVEMATCH;
06511         else if (*cptr == '*')
06512             *flags |= ENV_MOD_MACHINE;
06513         else
06514             break;
06515 
06516         cptr++;
06517         (*name)++;
06518     }
06519 
06520     if (!*cptr)
06521     {
06522         ERR("Missing environment variable\n");
06523         return ERROR_FUNCTION_FAILED;
06524     }
06525 
06526     if (*value)
06527     {
06528         LPCWSTR ptr = *value;
06529         if (!strncmpW(ptr, prefix, prefix_len))
06530         {
06531             if (ptr[prefix_len] == szSemiColon[0])
06532             {
06533                 *flags |= ENV_MOD_APPEND;
06534                 *value += lstrlenW(prefix);
06535             }
06536             else
06537             {
06538                 *value = NULL;
06539             }
06540         }
06541         else if (lstrlenW(*value) >= prefix_len)
06542         {
06543             ptr += lstrlenW(ptr) - prefix_len;
06544             if (!strcmpW( ptr, prefix ))
06545             {
06546                 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
06547                 {
06548                     *flags |= ENV_MOD_PREFIX;
06549                     /* the "[~]" will be removed by deformat_string */;
06550                 }
06551                 else
06552                 {
06553                     *value = NULL;
06554                 }
06555             }
06556         }
06557     }
06558 
06559     if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
06560         check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
06561         check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
06562         check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
06563     {
06564         ERR("Invalid flags: %08x\n", *flags);
06565         return ERROR_FUNCTION_FAILED;
06566     }
06567 
06568     if (!*flags)
06569         *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
06570 
06571     return ERROR_SUCCESS;
06572 }
06573 
06574 static UINT open_env_key( DWORD flags, HKEY *key )
06575 {
06576     static const WCHAR user_env[] =
06577         {'E','n','v','i','r','o','n','m','e','n','t',0};
06578     static const WCHAR machine_env[] =
06579         {'S','y','s','t','e','m','\\',
06580          'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
06581          'C','o','n','t','r','o','l','\\',
06582          'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
06583          'E','n','v','i','r','o','n','m','e','n','t',0};
06584     const WCHAR *env;
06585     HKEY root;
06586     LONG res;
06587 
06588     if (flags & ENV_MOD_MACHINE)
06589     {
06590         env = machine_env;
06591         root = HKEY_LOCAL_MACHINE;
06592     }
06593     else
06594     {
06595         env = user_env;
06596         root = HKEY_CURRENT_USER;
06597     }
06598 
06599     res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
06600     if (res != ERROR_SUCCESS)
06601     {
06602         WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
06603         return ERROR_FUNCTION_FAILED;
06604     }
06605 
06606     return ERROR_SUCCESS;
06607 }
06608 
06609 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
06610 {
06611     MSIPACKAGE *package = param;
06612     LPCWSTR name, value, component;
06613     LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
06614     DWORD flags, type, size;
06615     UINT res;
06616     HKEY env = NULL;
06617     MSICOMPONENT *comp;
06618     MSIRECORD *uirow;
06619     int action = 0;
06620 
06621     component = MSI_RecordGetString(rec, 4);
06622     comp = msi_get_loaded_component(package, component);
06623     if (!comp)
06624         return ERROR_SUCCESS;
06625 
06626     comp->Action = msi_get_component_action( package, comp );
06627     if (comp->Action != INSTALLSTATE_LOCAL)
06628     {
06629         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
06630         return ERROR_SUCCESS;
06631     }
06632     name = MSI_RecordGetString(rec, 2);
06633     value = MSI_RecordGetString(rec, 3);
06634 
06635     TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
06636 
06637     res = env_parse_flags(&name, &value, &flags);
06638     if (res != ERROR_SUCCESS || !value)
06639        goto done;
06640 
06641     if (value && !deformat_string(package, value, &deformatted))
06642     {
06643         res = ERROR_OUTOFMEMORY;
06644         goto done;
06645     }
06646 
06647     value = deformatted;
06648 
06649     res = open_env_key( flags, &env );
06650     if (res != ERROR_SUCCESS)
06651         goto done;
06652 
06653     if (flags & ENV_MOD_MACHINE)
06654         action |= 0x20000000;
06655 
06656     size = 0;
06657     type = REG_SZ;
06658     res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
06659     if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
06660         (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
06661         goto done;
06662 
06663     if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
06664     {
06665         action = 0x2;
06666 
06667         /* Nothing to do. */
06668         if (!value)
06669         {
06670             res = ERROR_SUCCESS;
06671             goto done;
06672         }
06673 
06674         /* If we are appending but the string was empty, strip ; */
06675         if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
06676 
06677         size = (lstrlenW(value) + 1) * sizeof(WCHAR);
06678         newval = strdupW(value);
06679         if (!newval)
06680         {
06681             res = ERROR_OUTOFMEMORY;
06682             goto done;
06683         }
06684     }
06685     else
06686     {
06687         action = 0x1;
06688 
06689         /* Contrary to MSDN, +-variable to [~];path works */
06690         if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
06691         {
06692             res = ERROR_SUCCESS;
06693             goto done;
06694         }
06695 
06696         data = msi_alloc(size);
06697         if (!data)
06698         {
06699             RegCloseKey(env);
06700             return ERROR_OUTOFMEMORY;
06701         }
06702 
06703         res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
06704         if (res != ERROR_SUCCESS)
06705             goto done;
06706 
06707         if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
06708         {
06709             action = 0x4;
06710             res = RegDeleteValueW(env, name);
06711             if (res != ERROR_SUCCESS)
06712                 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
06713             goto done;
06714         }
06715 
06716         size = (lstrlenW(data) + 1) * sizeof(WCHAR);
06717         if (flags & ENV_MOD_MASK)
06718         {
06719             DWORD mod_size;
06720             int multiplier = 0;
06721             if (flags & ENV_MOD_APPEND) multiplier++;
06722             if (flags & ENV_MOD_PREFIX) multiplier++;
06723             mod_size = lstrlenW(value) * multiplier;
06724             size += mod_size * sizeof(WCHAR);
06725         }
06726 
06727         newval = msi_alloc(size);
06728         ptr = newval;
06729         if (!newval)
06730         {
06731             res = ERROR_OUTOFMEMORY;
06732             goto done;
06733         }
06734 
06735         if (flags & ENV_MOD_PREFIX)
06736         {
06737             lstrcpyW(newval, value);
06738             ptr = newval + lstrlenW(value);
06739             action |= 0x80000000;
06740         }
06741 
06742         lstrcpyW(ptr, data);
06743 
06744         if (flags & ENV_MOD_APPEND)
06745         {
06746             lstrcatW(newval, value);
06747             action |= 0x40000000;
06748         }
06749     }
06750     TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
06751     res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
06752     if (res)
06753     {
06754         WARN("Failed to set %s to %s (%d)\n",  debugstr_w(name), debugstr_w(newval), res);
06755     }
06756 
06757 done:
06758     uirow = MSI_CreateRecord( 3 );
06759     MSI_RecordSetStringW( uirow, 1, name );
06760     MSI_RecordSetStringW( uirow, 2, newval );
06761     MSI_RecordSetInteger( uirow, 3, action );
06762     msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
06763     msiobj_release( &uirow->hdr );
06764 
06765     if (env) RegCloseKey(env);
06766     msi_free(deformatted);
06767     msi_free(data);
06768     msi_free(newval);
06769     return res;
06770 }
06771 
06772 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
06773 {
06774     static const WCHAR query[] = {
06775         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
06776         '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
06777     MSIQUERY *view;
06778     UINT rc;
06779 
06780     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
06781     if (rc != ERROR_SUCCESS)
06782         return ERROR_SUCCESS;
06783 
06784     rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
06785     msiobj_release(&view->hdr);
06786     return rc;
06787 }
06788 
06789 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
06790 {
06791     MSIPACKAGE *package = param;
06792     LPCWSTR name, value, component;
06793     LPWSTR deformatted = NULL;
06794     DWORD flags;
06795     HKEY env;
06796     MSICOMPONENT *comp;
06797     MSIRECORD *uirow;
06798     int action = 0;
06799     LONG res;
06800     UINT r;
06801 
06802     component = MSI_RecordGetString( rec, 4 );
06803     comp = msi_get_loaded_component( package, component );
06804     if (!comp)
06805         return ERROR_SUCCESS;
06806 
06807     comp->Action = msi_get_component_action( package, comp );
06808     if (comp->Action != INSTALLSTATE_ABSENT)
06809     {
06810         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
06811         return ERROR_SUCCESS;
06812     }
06813     name = MSI_RecordGetString( rec, 2 );
06814     value = MSI_RecordGetString( rec, 3 );
06815 
06816     TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
06817 
06818     r = env_parse_flags( &name, &value, &flags );
06819     if (r != ERROR_SUCCESS)
06820        return r;
06821 
06822     if (!(flags & ENV_ACT_REMOVE))
06823     {
06824         TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
06825         return ERROR_SUCCESS;
06826     }
06827 
06828     if (value && !deformat_string( package, value, &deformatted ))
06829         return ERROR_OUTOFMEMORY;
06830 
06831     value = deformatted;
06832 
06833     r = open_env_key( flags, &env );
06834     if (r != ERROR_SUCCESS)
06835     {
06836         r = ERROR_SUCCESS;
06837         goto done;
06838     }
06839 
06840     if (flags & ENV_MOD_MACHINE)
06841         action |= 0x20000000;
06842 
06843     TRACE("Removing %s\n", debugstr_w(name));
06844 
06845     res = RegDeleteValueW( env, name );
06846     if (res != ERROR_SUCCESS)
06847     {
06848         WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
06849         r = ERROR_SUCCESS;
06850     }
06851 
06852 done:
06853     uirow = MSI_CreateRecord( 3 );
06854     MSI_RecordSetStringW( uirow, 1, name );
06855     MSI_RecordSetStringW( uirow, 2, value );
06856     MSI_RecordSetInteger( uirow, 3, action );
06857     msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
06858     msiobj_release( &uirow->hdr );
06859 
06860     if (env) RegCloseKey( env );
06861     msi_free( deformatted );
06862     return r;
06863 }
06864 
06865 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
06866 {
06867     static const WCHAR query[] = {
06868         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
06869         '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
06870     MSIQUERY *view;
06871     UINT rc;
06872 
06873     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
06874     if (rc != ERROR_SUCCESS)
06875         return ERROR_SUCCESS;
06876 
06877     rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
06878     msiobj_release( &view->hdr );
06879     return rc;
06880 }
06881 
06882 UINT msi_validate_product_id( MSIPACKAGE *package )
06883 {
06884     LPWSTR key, template, id;
06885     UINT r = ERROR_SUCCESS;
06886 
06887     id = msi_dup_property( package->db, szProductID );
06888     if (id)
06889     {
06890         msi_free( id );
06891         return ERROR_SUCCESS;
06892     }
06893     template = msi_dup_property( package->db, szPIDTemplate );
06894     key = msi_dup_property( package->db, szPIDKEY );
06895     if (key && template)
06896     {
06897         FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
06898         r = msi_set_property( package->db, szProductID, key );
06899     }
06900     msi_free( template );
06901     msi_free( key );
06902     return r;
06903 }
06904 
06905 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
06906 {
06907     return msi_validate_product_id( package );
06908 }
06909 
06910 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
06911 {
06912     TRACE("\n");
06913     package->need_reboot_at_end = 1;
06914     return ERROR_SUCCESS;
06915 }
06916 
06917 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
06918 {
06919     static const WCHAR szAvailableFreeReg[] =
06920         {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
06921     MSIRECORD *uirow;
06922     int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
06923 
06924     TRACE("%p %d kilobytes\n", package, space);
06925 
06926     uirow = MSI_CreateRecord( 1 );
06927     MSI_RecordSetInteger( uirow, 1, space );
06928     msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
06929     msiobj_release( &uirow->hdr );
06930 
06931     return ERROR_SUCCESS;
06932 }
06933 
06934 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
06935 {
06936     TRACE("%p\n", package);
06937 
06938     msi_set_property( package->db, szRollbackDisabled, szOne );
06939     return ERROR_SUCCESS;
06940 }
06941 
06942 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
06943 {
06944     FIXME("%p\n", package);
06945     return ERROR_SUCCESS;
06946 }
06947 
06948 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
06949 {
06950     static const WCHAR driver_query[] = {
06951         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
06952         'O','D','B','C','D','r','i','v','e','r',0};
06953     static const WCHAR translator_query[] = {
06954         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
06955         'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
06956     MSIQUERY *view;
06957     UINT r, count;
06958 
06959     r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
06960     if (r == ERROR_SUCCESS)
06961     {
06962         count = 0;
06963         r = MSI_IterateRecords( view, &count, NULL, package );
06964         msiobj_release( &view->hdr );
06965         if (r != ERROR_SUCCESS)
06966             return r;
06967         if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
06968     }
06969     r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
06970     if (r == ERROR_SUCCESS)
06971     {
06972         count = 0;
06973         r = MSI_IterateRecords( view, &count, NULL, package );
06974         msiobj_release( &view->hdr );
06975         if (r != ERROR_SUCCESS)
06976             return r;
06977         if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
06978     }
06979     return ERROR_SUCCESS;
06980 }
06981 
06982 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
06983 {
06984     MSIPACKAGE *package = param;
06985     const WCHAR *property = MSI_RecordGetString( rec, 1 );
06986     WCHAR *value;
06987 
06988     if ((value = msi_dup_property( package->db, property )))
06989     {
06990         FIXME("remove %s\n", debugstr_w(value));
06991         msi_free( value );
06992     }
06993     return ERROR_SUCCESS;
06994 }
06995 
06996 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
06997 {
06998     static const WCHAR query[] = {
06999         'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',' ',
07000         'F','R','O','M',' ','U','p','g','r','a','d','e',0};
07001     MSIQUERY *view;
07002     UINT r;
07003 
07004     r = MSI_DatabaseOpenViewW( package->db, query, &view );
07005     if (r == ERROR_SUCCESS)
07006     {
07007         r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
07008         msiobj_release( &view->hdr );
07009         if (r != ERROR_SUCCESS)
07010             return r;
07011     }
07012     return ERROR_SUCCESS;
07013 }
07014 
07015 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
07016 {
07017     MSIPACKAGE *package = param;
07018     int attributes = MSI_RecordGetInteger( rec, 5 );
07019 
07020     if (attributes & msidbUpgradeAttributesMigrateFeatures)
07021     {
07022         const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
07023         const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
07024         const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
07025         const WCHAR *language = MSI_RecordGetString( rec, 4 );
07026         HKEY hkey;
07027         UINT r;
07028 
07029         if (package->Context == MSIINSTALLCONTEXT_MACHINE)
07030         {
07031             r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
07032             if (r != ERROR_SUCCESS)
07033                 return ERROR_SUCCESS;
07034         }
07035         else
07036         {
07037             r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
07038             if (r != ERROR_SUCCESS)
07039                 return ERROR_SUCCESS;
07040         }
07041         RegCloseKey( hkey );
07042 
07043         FIXME("migrate feature states from %s version min %s version max %s language %s\n",
07044               debugstr_w(upgrade_code), debugstr_w(version_min),
07045               debugstr_w(version_max), debugstr_w(language));
07046     }
07047     return ERROR_SUCCESS;
07048 }
07049 
07050 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
07051 {
07052     static const WCHAR query[] = {
07053         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
07054         'U','p','g','r','a','d','e',0};
07055     MSIQUERY *view;
07056     UINT r;
07057 
07058     if (msi_get_property_int( package->db, szInstalled, 0 ))
07059     {
07060         TRACE("product is installed, skipping action\n");
07061         return ERROR_SUCCESS;
07062     }
07063     if (msi_get_property_int( package->db, szPreselected, 0 ))
07064     {
07065         TRACE("Preselected property is set, not migrating feature states\n");
07066         return ERROR_SUCCESS;
07067     }
07068     r = MSI_DatabaseOpenViewW( package->db, query, &view );
07069     if (r == ERROR_SUCCESS)
07070     {
07071         r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
07072         msiobj_release( &view->hdr );
07073         if (r != ERROR_SUCCESS)
07074             return r;
07075     }
07076     return ERROR_SUCCESS;
07077 }
07078 
07079 static void bind_image( const char *filename, const char *path )
07080 {
07081     if (!BindImageEx( 0, filename, path, NULL, NULL ))
07082     {
07083         WARN("failed to bind image %u\n", GetLastError());
07084     }
07085 }
07086 
07087 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
07088 {
07089     UINT i;
07090     MSIFILE *file;
07091     MSIPACKAGE *package = param;
07092     const WCHAR *key = MSI_RecordGetString( rec, 1 );
07093     const WCHAR *paths = MSI_RecordGetString( rec, 2 );
07094     char *filenameA, *pathA;
07095     WCHAR *pathW, **path_list;
07096 
07097     if (!(file = msi_get_loaded_file( package, key )))
07098     {
07099         WARN("file %s not found\n", debugstr_w(key));
07100         return ERROR_SUCCESS;
07101     }
07102     if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
07103     path_list = msi_split_string( paths, ';' );
07104     if (!path_list) bind_image( filenameA, NULL );
07105     else
07106     {
07107         for (i = 0; path_list[i] && path_list[i][0]; i++)
07108         {
07109             deformat_string( package, path_list[i], &pathW );
07110             if ((pathA = strdupWtoA( pathW )))
07111             {
07112                 bind_image( filenameA, pathA );
07113                 msi_free( pathA );
07114             }
07115             msi_free( pathW );
07116         }
07117     }
07118     msi_free( path_list );
07119     msi_free( filenameA );
07120     return ERROR_SUCCESS;
07121 }
07122 
07123 static UINT ACTION_BindImage( MSIPACKAGE *package )
07124 {
07125     static const WCHAR query[] = {
07126         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
07127         'B','i','n','d','I','m','a','g','e',0};
07128     MSIQUERY *view;
07129     UINT r;
07130 
07131     r = MSI_DatabaseOpenViewW( package->db, query, &view );
07132     if (r == ERROR_SUCCESS)
07133     {
07134         r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
07135         msiobj_release( &view->hdr );
07136         if (r != ERROR_SUCCESS)
07137             return r;
07138     }
07139     return ERROR_SUCCESS;
07140 }
07141 
07142 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
07143 {
07144     static const WCHAR query[] = {
07145         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
07146     MSIQUERY *view;
07147     DWORD count = 0;
07148     UINT r;
07149     
07150     r = MSI_OpenQuery( package->db, &view, query, table );
07151     if (r == ERROR_SUCCESS)
07152     {
07153         r = MSI_IterateRecords(view, &count, NULL, package);
07154         msiobj_release(&view->hdr);
07155         if (r != ERROR_SUCCESS)
07156             return r;
07157     }
07158     if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
07159     return ERROR_SUCCESS;
07160 }
07161 
07162 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
07163 {
07164     static const WCHAR table[] = {
07165         'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
07166     return msi_unimplemented_action_stub( package, "IsolateComponents", table );
07167 }
07168 
07169 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
07170 {
07171     static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
07172     return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
07173 }
07174 
07175 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
07176 {
07177     static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
07178     return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
07179 }
07180 
07181 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
07182 {
07183     static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
07184     return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
07185 }
07186 
07187 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
07188 {
07189     static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
07190     return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
07191 }
07192 
07193 static const struct
07194 {
07195     const WCHAR *action;
07196     UINT (*handler)(MSIPACKAGE *);
07197     const WCHAR *action_rollback;
07198 }
07199 StandardActions[] =
07200 {
07201     { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
07202     { szAppSearch, ACTION_AppSearch, NULL },
07203     { szBindImage, ACTION_BindImage, NULL },
07204     { szCCPSearch, ACTION_CCPSearch, NULL },
07205     { szCostFinalize, ACTION_CostFinalize, NULL },
07206     { szCostInitialize, ACTION_CostInitialize, NULL },
07207     { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
07208     { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
07209     { szDeleteServices, ACTION_DeleteServices, szInstallServices },
07210     { szDisableRollback, ACTION_DisableRollback, NULL },
07211     { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
07212     { szExecuteAction, ACTION_ExecuteAction, NULL },
07213     { szFileCost, ACTION_FileCost, NULL },
07214     { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
07215     { szForceReboot, ACTION_ForceReboot, NULL },
07216     { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
07217     { szInstallExecute, ACTION_InstallExecute, NULL },
07218     { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
07219     { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
07220     { szInstallFinalize, ACTION_InstallFinalize, NULL },
07221     { szInstallInitialize, ACTION_InstallInitialize, NULL },
07222     { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
07223     { szInstallServices, ACTION_InstallServices, szDeleteServices },
07224     { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
07225     { szInstallValidate, ACTION_InstallValidate, NULL },
07226     { szIsolateComponents, ACTION_IsolateComponents, NULL },
07227     { szLaunchConditions, ACTION_LaunchConditions, NULL },
07228     { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
07229     { szMoveFiles, ACTION_MoveFiles, NULL },
07230     { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
07231     { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
07232     { szPatchFiles, ACTION_PatchFiles, NULL },
07233     { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
07234     { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
07235     { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
07236     { szPublishProduct, ACTION_PublishProduct, NULL },
07237     { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
07238     { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
07239     { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
07240     { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
07241     { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
07242     { szRegisterProduct, ACTION_RegisterProduct, NULL },
07243     { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
07244     { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
07245     { szRegisterUser, ACTION_RegisterUser, NULL },
07246     { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
07247     { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
07248     { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
07249     { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
07250     { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
07251     { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
07252     { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
07253     { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
07254     { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
07255     { szResolveSource, ACTION_ResolveSource, NULL },
07256     { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
07257     { szScheduleReboot, ACTION_ScheduleReboot, NULL },
07258     { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
07259     { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules },
07260     { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
07261     { szStartServices, ACTION_StartServices, szStopServices },
07262     { szStopServices, ACTION_StopServices, szStartServices },
07263     { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
07264     { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
07265     { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
07266     { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
07267     { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
07268     { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
07269     { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
07270     { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
07271     { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
07272     { szValidateProductID, ACTION_ValidateProductID, NULL },
07273     { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
07274     { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
07275     { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
07276     { NULL, NULL, NULL }
07277 };
07278 
07279 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
07280 {
07281     BOOL ret = FALSE;
07282     UINT i;
07283 
07284     i = 0;
07285     while (StandardActions[i].action != NULL)
07286     {
07287         if (!strcmpW( StandardActions[i].action, action ))
07288         {
07289             ui_actionstart( package, action );
07290             if (StandardActions[i].handler)
07291             {
07292                 ui_actioninfo( package, action, TRUE, 0 );
07293                 *rc = StandardActions[i].handler( package );
07294                 ui_actioninfo( package, action, FALSE, *rc );
07295 
07296                 if (StandardActions[i].action_rollback && !package->need_rollback)
07297                 {
07298                     TRACE("scheduling rollback action\n");
07299                     msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback );
07300                 }
07301             }
07302             else
07303             {
07304                 FIXME("unhandled standard action %s\n", debugstr_w(action));
07305                 *rc = ERROR_SUCCESS;
07306             }
07307             ret = TRUE;
07308             break;
07309         }
07310         i++;
07311     }
07312     return ret;
07313 }
07314 
07315 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
07316 {
07317     UINT rc = ERROR_SUCCESS;
07318     BOOL handled;
07319 
07320     TRACE("Performing action (%s)\n", debugstr_w(action));
07321 
07322     handled = ACTION_HandleStandardAction(package, action, &rc);
07323 
07324     if (!handled)
07325         handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
07326 
07327     if (!handled)
07328     {
07329         WARN("unhandled msi action %s\n", debugstr_w(action));
07330         rc = ERROR_FUNCTION_NOT_CALLED;
07331     }
07332 
07333     return rc;
07334 }
07335 
07336 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
07337 {
07338     UINT rc = ERROR_SUCCESS;
07339     BOOL handled = FALSE;
07340 
07341     TRACE("Performing action (%s)\n", debugstr_w(action));
07342 
07343     handled = ACTION_HandleStandardAction(package, action, &rc);
07344 
07345     if (!handled)
07346         handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
07347 
07348     if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
07349         handled = TRUE;
07350 
07351     if (!handled)
07352     {
07353         WARN("unhandled msi action %s\n", debugstr_w(action));
07354         rc = ERROR_FUNCTION_NOT_CALLED;
07355     }
07356 
07357     return rc;
07358 }
07359 
07360 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
07361 {
07362     UINT rc = ERROR_SUCCESS;
07363     MSIRECORD *row;
07364 
07365     static const WCHAR query[] =
07366         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
07367          '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
07368          'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
07369          '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
07370     static const WCHAR ui_query[] =
07371         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
07372      '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
07373      '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
07374      ' ', '=',' ','%','i',0};
07375 
07376     if (needs_ui_sequence(package))
07377         row = MSI_QueryGetRecord(package->db, ui_query, seq);
07378     else
07379         row = MSI_QueryGetRecord(package->db, query, seq);
07380 
07381     if (row)
07382     {
07383         LPCWSTR action, cond;
07384 
07385         TRACE("Running the actions\n");
07386 
07387         /* check conditions */
07388         cond = MSI_RecordGetString(row, 2);
07389 
07390         /* this is a hack to skip errors in the condition code */
07391         if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
07392         {
07393             msiobj_release(&row->hdr);
07394             return ERROR_SUCCESS;
07395         }
07396 
07397         action = MSI_RecordGetString(row, 1);
07398         if (!action)
07399         {
07400             ERR("failed to fetch action\n");
07401             msiobj_release(&row->hdr);
07402             return ERROR_FUNCTION_FAILED;
07403         }
07404 
07405         if (needs_ui_sequence(package))
07406             rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
07407         else
07408             rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
07409 
07410         msiobj_release(&row->hdr);
07411     }
07412 
07413     return rc;
07414 }
07415 
07416 /****************************************************
07417  * TOP level entry points
07418  *****************************************************/
07419 
07420 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
07421                          LPCWSTR szCommandLine )
07422 {
07423     static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
07424     static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
07425     static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
07426     WCHAR *reinstall = NULL;
07427     BOOL ui_exists;
07428     UINT rc;
07429 
07430     msi_set_property( package->db, szAction, szInstall );
07431 
07432     package->script->InWhatSequence = SEQUENCE_INSTALL;
07433 
07434     if (szPackagePath)
07435     {
07436         LPWSTR p, dir;
07437         LPCWSTR file;
07438 
07439         dir = strdupW(szPackagePath);
07440         p = strrchrW(dir, '\\');
07441         if (p)
07442         {
07443             *(++p) = 0;
07444             file = szPackagePath + (p - dir);
07445         }
07446         else
07447         {
07448             msi_free(dir);
07449             dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
07450             GetCurrentDirectoryW(MAX_PATH, dir);
07451             lstrcatW(dir, szBackSlash);
07452             file = szPackagePath;
07453         }
07454 
07455         msi_free( package->PackagePath );
07456         package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
07457         if (!package->PackagePath)
07458         {
07459             msi_free(dir);
07460             return ERROR_OUTOFMEMORY;
07461         }
07462 
07463         lstrcpyW(package->PackagePath, dir);
07464         lstrcatW(package->PackagePath, file);
07465         msi_free(dir);
07466 
07467         msi_set_sourcedir_props(package, FALSE);
07468     }
07469 
07470     rc = msi_parse_command_line( package, szCommandLine, FALSE );
07471     if (rc != ERROR_SUCCESS)
07472         return rc;
07473 
07474     msi_apply_transforms( package );
07475     msi_apply_patches( package );
07476 
07477     if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
07478     {
07479         TRACE("setting reinstall property\n");
07480         msi_set_property( package->db, szReinstall, szAll );
07481     }
07482 
07483     /* properties may have been added by a transform */
07484     msi_clone_properties( package );
07485 
07486     msi_parse_command_line( package, szCommandLine, FALSE );
07487     msi_adjust_privilege_properties( package );
07488     msi_set_context( package );
07489 
07490     if (msi_get_property_int( package->db, szDisableRollback, 0 ))
07491     {
07492         TRACE("disabling rollback\n");
07493         msi_set_property( package->db, szRollbackDisabled, szOne );
07494     }
07495 
07496     if (needs_ui_sequence( package))
07497     {
07498         package->script->InWhatSequence |= SEQUENCE_UI;
07499         rc = ACTION_ProcessUISequence(package);
07500         ui_exists = ui_sequence_exists(package);
07501         if (rc == ERROR_SUCCESS || !ui_exists)
07502         {
07503             package->script->InWhatSequence |= SEQUENCE_EXEC;
07504             rc = ACTION_ProcessExecSequence(package, ui_exists);
07505         }
07506     }
07507     else
07508         rc = ACTION_ProcessExecSequence(package, FALSE);
07509 
07510     package->script->CurrentlyScripting = FALSE;
07511 
07512     /* process the ending type action */
07513     if (rc == ERROR_SUCCESS)
07514         ACTION_PerformActionSequence(package, -1);
07515     else if (rc == ERROR_INSTALL_USEREXIT)
07516         ACTION_PerformActionSequence(package, -2);
07517     else if (rc == ERROR_INSTALL_SUSPEND)
07518         ACTION_PerformActionSequence(package, -4);
07519     else  /* failed */
07520     {
07521         ACTION_PerformActionSequence(package, -3);
07522         if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
07523         {
07524             package->need_rollback = TRUE;
07525         }
07526     }
07527 
07528     /* finish up running custom actions */
07529     ACTION_FinishCustomActions(package);
07530 
07531     if (package->need_rollback && !(reinstall = msi_dup_property( package->db, szReinstall )))
07532     {
07533         WARN("installation failed, running rollback script\n");
07534         execute_script( package, SCRIPT_ROLLBACK );
07535     }
07536     msi_free( reinstall );
07537 
07538     if (rc == ERROR_SUCCESS && package->need_reboot_at_end)
07539         return ERROR_SUCCESS_REBOOT_REQUIRED;
07540 
07541     return rc;
07542 }

Generated on Sun May 27 2012 04:25:11 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.