~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/msi/action.c

Version: ~ [ wine-1.5.4 ] ~ [ wine-1.5.3 ] ~ [ wine-1.5.2 ] ~ [ wine-1.5.1 ] ~ [ wine-1.5.0 ] ~ [ wine-1.4 ] ~ [ wine-1.4-rc6 ] ~ [ wine-1.4-rc5 ] ~ [ wine-1.4-rc4 ] ~ [ wine-1.4-rc3 ] ~ [ wine-1.4-rc2 ] ~ [ wine-1.4-rc1 ] ~ [ wine-1.3.37 ] ~ [ wine-1.3.36 ] ~ [ wine-1.3.35 ] ~ [ wine-1.3.34 ] ~ [ wine-1.3.33 ] ~ [ wine-1.3.32 ] ~ [ wine-1.3.31 ] ~ [ wine-1.3.30 ] ~ [ wine-1.3.29 ] ~ [ wine-1.3.28 ] ~ [ wine-1.3.27 ] ~ [ wine-1.3.26 ] ~ [ wine-1.3.25 ] ~ [ wine-1.3.24 ] ~ [ wine-1.3.23 ] ~ [ wine-1.3.22 ] ~ [ wine-1.3.21 ] ~ [ wine-1.3.20 ] ~ [ wine-1.3.19 ] ~ [ wine-1.3.18 ] ~ [ wine-1.2.3 ] ~ [ wine-1.3.17 ] ~ [ wine-1.3.16 ] ~ [ wine-1.3.15 ] ~ [ wine-1.3.14 ] ~ [ wine-1.3.13 ] ~ [ wine-1.3.12 ] ~ [ wine-1.3.11 ] ~ [ wine-1.3.10 ] ~ [ wine-1.3.9 ] ~ [ wine-1.2.2 ] ~ [ wine-1.3.8 ] ~ [ wine-1.3.7 ] ~ [ wine-1.3.6 ] ~ [ wine-1.3.5 ] ~ [ wine-1.2.1 ] ~ [ wine-1.3.4 ] ~ [ wine-1.3.3 ] ~ [ wine-1.3.2 ] ~ [ wine-1.3.1 ] ~ [ wine-1.3.0 ] ~ [ wine-1.2 ] ~ [ wine-1.2-rc7 ] ~ [ wine-1.2-rc6 ] ~ [ wine-1.2-rc5 ] ~ [ wine-1.2-rc4 ] ~ [ wine-1.2-rc3 ] ~ [ wine-1.2-rc2 ] ~ [ wine-1.2-rc1 ] ~ [ wine-1.1.44 ] ~ [ wine-1.1.43 ] ~ [ wine-1.1.42 ] ~ [ wine-1.1.41 ] ~ [ wine-1.1.40 ] ~ [ wine-1.1.39 ] ~ [ wine-1.1.38 ] ~ [ wine-1.1.37 ] ~ [ wine-1.1.36 ] ~ [ wine-1.1.35 ] ~ [ wine-1.1.34 ] ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

  1 /*
  2  * Implementation of the Microsoft Installer (msi.dll)
  3  *
  4  * Copyright 2004,2005 Aric Stewart for CodeWeavers
  5  *
  6  * This library is free software; you can redistribute it and/or
  7  * modify it under the terms of the GNU Lesser General Public
  8  * License as published by the Free Software Foundation; either
  9  * version 2.1 of the License, or (at your option) any later version.
 10  *
 11  * This library is distributed in the hope that it will be useful,
 12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 14  * Lesser General Public License for more details.
 15  *
 16  * You should have received a copy of the GNU Lesser General Public
 17  * License along with this library; if not, write to the Free Software
 18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 19  */
 20 
 21 #include <stdarg.h>
 22 
 23 #define COBJMACROS
 24 
 25 #include "windef.h"
 26 #include "winbase.h"
 27 #include "winerror.h"
 28 #include "winreg.h"
 29 #include "winsvc.h"
 30 #include "odbcinst.h"
 31 #include "wine/debug.h"
 32 #include "msidefs.h"
 33 #include "msipriv.h"
 34 #include "winuser.h"
 35 #include "shlobj.h"
 36 #include "objbase.h"
 37 #include "mscoree.h"
 38 #include "shlwapi.h"
 39 #include "imagehlp.h"
 40 #include "wine/unicode.h"
 41 #include "winver.h"
 42 
 43 #define REG_PROGRESS_VALUE 13200
 44 #define COMPONENT_PROGRESS_VALUE 24000
 45 
 46 WINE_DEFAULT_DEBUG_CHANNEL(msi);
 47 
 48 static const WCHAR szCreateFolders[] =
 49     {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
 50 static const WCHAR szCostFinalize[] =
 51     {'C','o','s','t','F','i','n','a','l','i','z','e',0};
 52 static const WCHAR szWriteRegistryValues[] =
 53     {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
 54 static const WCHAR szFileCost[] = 
 55     {'F','i','l','e','C','o','s','t',0};
 56 static const WCHAR szInstallInitialize[] = 
 57     {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
 58 static const WCHAR szInstallValidate[] = 
 59     {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
 60 static const WCHAR szLaunchConditions[] = 
 61     {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
 62 static const WCHAR szProcessComponents[] = 
 63     {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
 64 static const WCHAR szRegisterTypeLibraries[] = 
 65     {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
 66 static const WCHAR szCreateShortcuts[] = 
 67     {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
 68 static const WCHAR szPublishProduct[] = 
 69     {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
 70 static const WCHAR szWriteIniValues[] = 
 71     {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
 72 static const WCHAR szSelfRegModules[] = 
 73     {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
 74 static const WCHAR szPublishFeatures[] = 
 75     {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
 76 static const WCHAR szRegisterProduct[] = 
 77     {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
 78 static const WCHAR szInstallExecute[] = 
 79     {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
 80 static const WCHAR szInstallExecuteAgain[] = 
 81     {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
 82 static const WCHAR szInstallFinalize[] = 
 83     {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
 84 static const WCHAR szForceReboot[] = 
 85     {'F','o','r','c','e','R','e','b','o','o','t',0};
 86 static const WCHAR szResolveSource[] =
 87     {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
 88 static const WCHAR szAllocateRegistrySpace[] = 
 89     {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
 90 static const WCHAR szBindImage[] = 
 91     {'B','i','n','d','I','m','a','g','e',0};
 92 static const WCHAR szDeleteServices[] = 
 93     {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
 94 static const WCHAR szDisableRollback[] = 
 95     {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
 96 static const WCHAR szExecuteAction[] = 
 97     {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
 98 static const WCHAR szInstallAdminPackage[] = 
 99     {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
100 static const WCHAR szInstallSFPCatalogFile[] = 
101     {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
102 static const WCHAR szIsolateComponents[] = 
103     {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
104 static const WCHAR szMigrateFeatureStates[] =
105     {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
106 static const WCHAR szMsiUnpublishAssemblies[] = 
107     {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
108 static const WCHAR szInstallODBC[] = 
109     {'I','n','s','t','a','l','l','O','D','B','C',0};
110 static const WCHAR szInstallServices[] = 
111     {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
112 static const WCHAR szPublishComponents[] = 
113     {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
114 static const WCHAR szRegisterComPlus[] =
115     {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
116 static const WCHAR szRegisterUser[] =
117     {'R','e','g','i','s','t','e','r','U','s','e','r',0};
118 static const WCHAR szRemoveEnvironmentStrings[] =
119     {'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};
120 static const WCHAR szRemoveExistingProducts[] =
121     {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
122 static const WCHAR szRemoveFolders[] =
123     {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
124 static const WCHAR szRemoveIniValues[] =
125     {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
126 static const WCHAR szRemoveODBC[] =
127     {'R','e','m','o','v','e','O','D','B','C',0};
128 static const WCHAR szRemoveRegistryValues[] =
129     {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
130 static const WCHAR szRemoveShortcuts[] =
131     {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
132 static const WCHAR szRMCCPSearch[] =
133     {'R','M','C','C','P','S','e','a','r','c','h',0};
134 static const WCHAR szScheduleReboot[] =
135     {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
136 static const WCHAR szSelfUnregModules[] =
137     {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
138 static const WCHAR szSetODBCFolders[] =
139     {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
140 static const WCHAR szStartServices[] =
141     {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
142 static const WCHAR szStopServices[] =
143     {'S','t','o','p','S','e','r','v','i','c','e','s',0};
144 static const WCHAR szUnpublishComponents[] =
145     {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
146 static const WCHAR szUnpublishFeatures[] =
147     {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
148 static const WCHAR szUnregisterComPlus[] =
149     {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
150 static const WCHAR szUnregisterTypeLibraries[] =
151     {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
152 static const WCHAR szValidateProductID[] =
153     {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
154 static const WCHAR szWriteEnvironmentStrings[] =
155     {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
156 
157 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
158 {
159     static const WCHAR Query_t[] = 
160         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
161          '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
162          'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=', 
163          ' ','\'','%','s','\'',0};
164     MSIRECORD * row;
165 
166     row = MSI_QueryGetRecord( package->db, Query_t, action );
167     if (!row)
168         return;
169     MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
170     msiobj_release(&row->hdr);
171 }
172 
173 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start, 
174                           UINT rc)
175 {
176     MSIRECORD * row;
177     static const WCHAR template_s[]=
178         {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
179          '%','s', '.',0};
180     static const WCHAR template_e[]=
181         {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
182          '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
183          '%','i','.',0};
184     static const WCHAR format[] = 
185         {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
186     WCHAR message[1024];
187     WCHAR timet[0x100];
188 
189     GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
190     if (start)
191         sprintfW(message,template_s,timet,action);
192     else
193         sprintfW(message,template_e,timet,action,rc);
194     
195     row = MSI_CreateRecord(1);
196     MSI_RecordSetStringW(row,1,message);
197  
198     MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
199     msiobj_release(&row->hdr);
200 }
201 
202 enum parse_state
203 {
204     state_whitespace,
205     state_token,
206     state_quote
207 };
208 
209 static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
210 {
211     enum parse_state state = state_quote;
212     const WCHAR *p;
213     WCHAR *out = value;
214     int ignore, in_quotes = 0, count = 0, len = 0;
215 
216     for (p = str; *p; p++)
217     {
218         ignore = 0;
219         switch (state)
220         {
221         case state_whitespace:
222             switch (*p)
223             {
224             case ' ':
225                 in_quotes = 1;
226                 ignore = 1;
227                 len++;
228                 break;
229             case '"':
230                 state = state_quote;
231                 if (in_quotes && p[1] != '\"') count--;
232                 else count++;
233                 break;
234             default:
235                 state = state_token;
236                 in_quotes = 1;
237                 len++;
238                 break;
239             }
240             break;
241 
242         case state_token:
243             switch (*p)
244             {
245             case '"':
246                 state = state_quote;
247                 if (in_quotes) count--;
248                 else count++;
249                 break;
250             case ' ':
251                 state = state_whitespace;
252                 if (!count) goto done;
253                 in_quotes = 1;
254                 len++;
255                 break;
256             default:
257                 if (!count) in_quotes = 0;
258                 else in_quotes = 1;
259                 len++;
260                 break;
261             }
262             break;
263 
264         case state_quote:
265             switch (*p)
266             {
267             case '"':
268                 if (in_quotes && p[1] != '\"') count--;
269                 else count++;
270                 break;
271             case ' ':
272                 state = state_whitespace;
273                 if (!count || (count > 1 && !len)) goto done;
274                 in_quotes = 1;
275                 len++;
276                 break;
277             default:
278                 state = state_token;
279                 if (!count) in_quotes = 0;
280                 else in_quotes = 1;
281                 len++;
282                 break;
283             }
284             break;
285 
286         default: break;
287         }
288         if (!ignore) *out++ = *p;
289     }
290 
291 done:
292     if (!len) *value = 0;
293     else *out = 0;
294 
295     *quotes = count;
296     return p - str;
297 }
298 
299 static void remove_quotes( WCHAR *str )
300 {
301     WCHAR *p = str;
302     int len = strlenW( str );
303 
304     while ((p = strchrW( p, '"' )))
305     {
306         memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
307         p++;
308     }
309 }
310 
311 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
312                              BOOL preserve_case )
313 {
314     LPCWSTR ptr, ptr2;
315     int num_quotes;
316     DWORD len;
317     WCHAR *prop, *val;
318     UINT r;
319 
320     if (!szCommandLine)
321         return ERROR_SUCCESS;
322 
323     ptr = szCommandLine;
324     while (*ptr)
325     {
326         while (*ptr == ' ') ptr++;
327         if (!*ptr) break;
328 
329         ptr2 = strchrW( ptr, '=' );
330         if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
331  
332         len = ptr2 - ptr;
333         if (!len) return ERROR_INVALID_COMMAND_LINE;
334 
335         prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
336         memcpy( prop, ptr, len * sizeof(WCHAR) );
337         prop[len] = 0;
338         if (!preserve_case) struprW( prop );
339 
340         ptr2++;
341         while (*ptr2 == ' ') ptr2++;
342 
343         num_quotes = 0;
344         val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) );
345         len = parse_prop( ptr2, val, &num_quotes );
346         if (num_quotes % 2)
347         {
348             WARN("unbalanced quotes\n");
349             msi_free( val );
350             msi_free( prop );
351             return ERROR_INVALID_COMMAND_LINE;
352         }
353         remove_quotes( val );
354         TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
355 
356         r = msi_set_property( package->db, prop, val );
357         if (r == ERROR_SUCCESS && !strcmpW( prop, szSourceDir ))
358             msi_reset_folders( package, TRUE );
359 
360         msi_free( val );
361         msi_free( prop );
362 
363         ptr = ptr2 + len;
364     }
365 
366     return ERROR_SUCCESS;
367 }
368 
369 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
370 {
371     LPCWSTR pc;
372     LPWSTR p, *ret = NULL;
373     UINT count = 0;
374 
375     if (!str)
376         return ret;
377 
378     /* count the number of substrings */
379     for ( pc = str, count = 0; pc; count++ )
380     {
381         pc = strchrW( pc, sep );
382         if (pc)
383             pc++;
384     }
385 
386     /* allocate space for an array of substring pointers and the substrings */
387     ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
388                      (lstrlenW(str)+1) * sizeof(WCHAR) );
389     if (!ret)
390         return ret;
391 
392     /* copy the string and set the pointers */
393     p = (LPWSTR) &ret[count+1];
394     lstrcpyW( p, str );
395     for( count = 0; (ret[count] = p); count++ )
396     {
397         p = strchrW( p, sep );
398         if (p)
399             *p++ = 0;
400     }
401 
402     return ret;
403 }
404 
405 static BOOL ui_sequence_exists( MSIPACKAGE *package )
406 {
407     static const WCHAR query [] = {
408         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
409         '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
410         'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','',' ',
411         'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
412     MSIQUERY *view;
413     UINT rc;
414 
415     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
416     if (rc == ERROR_SUCCESS)
417     {
418         msiobj_release(&view->hdr);
419         return TRUE;
420     }
421     return FALSE;
422 }
423 
424 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
425 {
426     LPWSTR source, check;
427 
428     if (msi_get_property_int( package->db, szInstalled, 0 ))
429     {
430         HKEY hkey;
431 
432         MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
433         source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
434         RegCloseKey( hkey );
435     }
436     else
437     {
438         LPWSTR p, db;
439         DWORD len;
440 
441         db = msi_dup_property( package->db, szOriginalDatabase );
442         if (!db)
443             return ERROR_OUTOFMEMORY;
444 
445         p = strrchrW( db, '\\' );
446         if (!p)
447         {
448             p = strrchrW( db, '/' );
449             if (!p)
450             {
451                 msi_free(db);
452                 return ERROR_SUCCESS;
453             }
454         }
455 
456         len = p - db + 2;
457         source = msi_alloc( len * sizeof(WCHAR) );
458         lstrcpynW( source, db, len );
459         msi_free( db );
460     }
461 
462     check = msi_dup_property( package->db, szSourceDir );
463     if (!check || replace)
464     {
465         UINT r = msi_set_property( package->db, szSourceDir, source );
466         if (r == ERROR_SUCCESS)
467             msi_reset_folders( package, TRUE );
468     }
469     msi_free( check );
470 
471     check = msi_dup_property( package->db, szSOURCEDIR );
472     if (!check || replace)
473         msi_set_property( package->db, szSOURCEDIR, source );
474 
475     msi_free( check );
476     msi_free( source );
477 
478     return ERROR_SUCCESS;
479 }
480 
481 static BOOL needs_ui_sequence(MSIPACKAGE *package)
482 {
483     return (package->ui_level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
484 }
485 
486 UINT msi_set_context(MSIPACKAGE *package)
487 {
488     UINT r = msi_locate_product( package->ProductCode, &package->Context );
489     if (r != ERROR_SUCCESS)
490     {
491         int num = msi_get_property_int( package->db, szAllUsers, 0 );
492         if (num == 1 || num == 2)
493             package->Context = MSIINSTALLCONTEXT_MACHINE;
494         else
495             package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
496     }
497     return ERROR_SUCCESS;
498 }
499 
500 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
501 {
502     UINT rc;
503     LPCWSTR cond, action;
504     MSIPACKAGE *package = param;
505 
506     action = MSI_RecordGetString(row,1);
507     if (!action)
508     {
509         ERR("Error is retrieving action name\n");
510         return ERROR_FUNCTION_FAILED;
511     }
512 
513     /* check conditions */
514     cond = MSI_RecordGetString(row,2);
515 
516     /* this is a hack to skip errors in the condition code */
517     if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
518     {
519         TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
520         return ERROR_SUCCESS;
521     }
522 
523     if (needs_ui_sequence(package))
524         rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
525     else
526         rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
527 
528     msi_dialog_check_messages( NULL );
529 
530     if (package->CurrentInstallState != ERROR_SUCCESS)
531         rc = package->CurrentInstallState;
532 
533     if (rc == ERROR_FUNCTION_NOT_CALLED)
534         rc = ERROR_SUCCESS;
535 
536     if (rc != ERROR_SUCCESS)
537         ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
538 
539     if (package->need_reboot_now)
540     {
541         TRACE("action %s asked for immediate reboot, suspending installation\n",
542               debugstr_w(action));
543         rc = ACTION_ForceReboot( package );
544     }
545     return rc;
546 }
547 
548 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR table )
549 {
550     static const WCHAR query[] = {
551         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',
552          ' ','W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ',
553          '>',' ','',' ','O','R','D','E','R',' ','B','Y',' ',
554          '`','S','e','q','u','e','n','c','e','`',0};
555     MSIQUERY *view;
556     UINT r;
557 
558     TRACE("%p %s\n", package, debugstr_w(table));
559 
560     r = MSI_OpenQuery( package->db, &view, query, table );
561     if (r == ERROR_SUCCESS)
562     {
563         r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
564         msiobj_release(&view->hdr);
565     }
566     return r;
567 }
568 
569 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
570 {
571     static const WCHAR query[] = {
572         'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
573         '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
574         'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
575         '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
576         'O','R','D','E','R',' ', 'B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
577     static const WCHAR query_validate[] = {
578         'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
579         ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
580         'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
581         'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
582         ' ','\'', 'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','\'',0};
583     MSIQUERY *view;
584     INT seq = 0;
585     UINT rc;
586 
587     if (package->script->ExecuteSequenceRun)
588     {
589         TRACE("Execute Sequence already Run\n");
590         return ERROR_SUCCESS;
591     }
592 
593     package->script->ExecuteSequenceRun = TRUE;
594 
595     /* get the sequence number */
596     if (UIran)
597     {
598         MSIRECORD *row = MSI_QueryGetRecord(package->db, query_validate);
599         if (!row) return ERROR_FUNCTION_FAILED;
600         seq = MSI_RecordGetInteger(row,1);
601         msiobj_release(&row->hdr);
602     }
603     rc = MSI_OpenQuery(package->db, &view, query, seq);
604     if (rc == ERROR_SUCCESS)
605     {
606         TRACE("Running the actions\n");
607 
608         msi_set_property(package->db, szSourceDir, NULL);
609         rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
610         msiobj_release(&view->hdr);
611     }
612     return rc;
613 }
614 
615 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
616 {
617     static const WCHAR query[] = {
618         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
619         '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
620         'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','',' ',
621         'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
622     MSIQUERY *view;
623     UINT rc;
624 
625     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
626     if (rc == ERROR_SUCCESS)
627     {
628         TRACE("Running the actions\n"); 
629         rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
630         msiobj_release(&view->hdr);
631     }
632     return rc;
633 }
634 
635 /********************************************************
636  * ACTION helper functions and functions that perform the actions
637  *******************************************************/
638 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
639                                        UINT* rc, UINT script, BOOL force )
640 {
641     BOOL ret=FALSE;
642     UINT arc;
643 
644     arc = ACTION_CustomAction(package, action, script, force);
645 
646     if (arc != ERROR_CALL_NOT_IMPLEMENTED)
647     {
648         *rc = arc;
649         ret = TRUE;
650     }
651     return ret;
652 }
653 
654 MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component )
655 {
656     MSICOMPONENT *comp;
657 
658     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
659     {
660         if (!strcmpW( Component, comp->Component )) return comp;
661     }
662     return NULL;
663 }
664 
665 MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature )
666 {
667     MSIFEATURE *feature;
668 
669     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
670     {
671         if (!strcmpW( Feature, feature->Feature )) return feature;
672     }
673     return NULL;
674 }
675 
676 MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key )
677 {
678     MSIFILE *file;
679 
680     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
681     {
682         if (!strcmpW( key, file->File )) return file;
683     }
684     return NULL;
685 }
686 
687 MSIFILEPATCH *msi_get_loaded_filepatch( MSIPACKAGE *package, const WCHAR *key )
688 {
689     MSIFILEPATCH *patch;
690 
691     /* FIXME: There might be more than one patch */
692     LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
693     {
694         if (!strcmpW( key, patch->File->File )) return patch;
695     }
696     return NULL;
697 }
698 
699 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
700 {
701     MSIFOLDER *folder;
702 
703     LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
704     {
705         if (!strcmpW( dir, folder->Directory )) return folder;
706     }
707     return NULL;
708 }
709 
710 /*
711  * Recursively create all directories in the path.
712  * shamelessly stolen from setupapi/queue.c
713  */
714 BOOL msi_create_full_path( const WCHAR *path )
715 {
716     BOOL ret = TRUE;
717     WCHAR *new_path;
718     int len;
719 
720     new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) );
721     strcpyW( new_path, path );
722 
723     while ((len = strlenW( new_path )) && new_path[len - 1] == '\\')
724     new_path[len - 1] = 0;
725 
726     while (!CreateDirectoryW( new_path, NULL ))
727     {
728         WCHAR *slash;
729         DWORD last_error = GetLastError();
730         if (last_error == ERROR_ALREADY_EXISTS) break;
731         if (last_error != ERROR_PATH_NOT_FOUND)
732         {
733             ret = FALSE;
734             break;
735         }
736         if (!(slash = strrchrW( new_path, '\\' )))
737         {
738             ret = FALSE;
739             break;
740         }
741         len = slash - new_path;
742         new_path[len] = 0;
743         if (!msi_create_full_path( new_path ))
744         {
745             ret = FALSE;
746             break;
747         }
748         new_path[len] = '\\';
749     }
750     msi_free( new_path );
751     return ret;
752 }
753 
754 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
755 {
756     MSIRECORD *row;
757 
758     row = MSI_CreateRecord( 4 );
759     MSI_RecordSetInteger( row, 1, a );
760     MSI_RecordSetInteger( row, 2, b );
761     MSI_RecordSetInteger( row, 3, c );
762     MSI_RecordSetInteger( row, 4, d );
763     MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row );
764     msiobj_release( &row->hdr );
765 
766     msi_dialog_check_messages( NULL );
767 }
768 
769 void msi_ui_actiondata( MSIPACKAGE *package, const WCHAR *action, MSIRECORD *record )
770 {
771     static const WCHAR query[] =
772         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
773          '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
774          'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
775     WCHAR message[1024];
776     MSIRECORD *row = 0;
777     DWORD size;
778 
779     if (!package->LastAction || strcmpW( package->LastAction, action ))
780     {
781         if (!(row = MSI_QueryGetRecord( package->db, query, action ))) return;
782 
783         if (MSI_RecordIsNull( row, 3 ))
784         {
785             msiobj_release( &row->hdr );
786             return;
787         }
788         /* update the cached action format */
789         msi_free( package->ActionFormat );
790         package->ActionFormat = msi_dup_record_field( row, 3 );
791         msi_free( package->LastAction );
792         package->LastAction = strdupW( action );
793         msiobj_release( &row->hdr );
794     }
795     size = 1024;
796     MSI_RecordSetStringW( record, 0, package->ActionFormat );
797     MSI_FormatRecordW( package, record, message, &size );
798     row = MSI_CreateRecord( 1 );
799     MSI_RecordSetStringW( row, 1, message );
800     MSI_ProcessMessage( package, INSTALLMESSAGE_ACTIONDATA, row );
801     msiobj_release( &row->hdr );
802 }
803 
804 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp )
805 {
806     if (!comp->Enabled)
807     {
808         TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
809         return INSTALLSTATE_UNKNOWN;
810     }
811     if (package->need_rollback) return comp->Installed;
812     return comp->ActionRequest;
813 }
814 
815 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature )
816 {
817     if (package->need_rollback) return feature->Installed;
818     return feature->ActionRequest;
819 }
820 
821 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
822 {
823     MSIPACKAGE *package = param;
824     LPCWSTR dir, component, full_path;
825     MSIRECORD *uirow;
826     MSIFOLDER *folder;
827     MSICOMPONENT *comp;
828 
829     component = MSI_RecordGetString(row, 2);
830     if (!component)
831         return ERROR_SUCCESS;
832 
833     comp = msi_get_loaded_component(package, component);
834     if (!comp)
835         return ERROR_SUCCESS;
836 
837     comp->Action = msi_get_component_action( package, comp );
838     if (comp->Action != INSTALLSTATE_LOCAL)
839     {
840         TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
841         return ERROR_SUCCESS;
842     }
843 
844     dir = MSI_RecordGetString(row,1);
845     if (!dir)
846     {
847         ERR("Unable to get folder id\n");
848         return ERROR_SUCCESS;
849     }
850 
851     uirow = MSI_CreateRecord(1);
852     MSI_RecordSetStringW(uirow, 1, dir);
853     msi_ui_actiondata(package, szCreateFolders, uirow);
854     msiobj_release(&uirow->hdr);
855 
856     full_path = msi_get_target_folder( package, dir );
857     if (!full_path)
858     {
859         ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
860         return ERROR_SUCCESS;
861     }
862     TRACE("folder is %s\n", debugstr_w(full_path));
863 
864     folder = msi_get_loaded_folder( package, dir );
865     if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( full_path );
866     folder->State = FOLDER_STATE_CREATED;
867     return ERROR_SUCCESS;
868 }
869 
870 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
871 {
872     static const WCHAR query[] = {
873         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
874         '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
875     MSIQUERY *view;
876     UINT rc;
877 
878     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
879     if (rc != ERROR_SUCCESS)
880         return ERROR_SUCCESS;
881 
882     rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
883     msiobj_release(&view->hdr);
884     return rc;
885 }
886 
887 static void remove_persistent_folder( MSIFOLDER *folder )
888 {
889     FolderList *fl;
890 
891     LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
892     {
893         remove_persistent_folder( fl->folder );
894     }
895     if (folder->persistent && folder->State != FOLDER_STATE_REMOVED)
896     {
897         if (RemoveDirectoryW( folder->ResolvedTarget )) folder->State = FOLDER_STATE_REMOVED;
898     }
899 }
900 
901 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
902 {
903     MSIPACKAGE *package = param;
904     LPCWSTR dir, component, full_path;
905     MSIRECORD *uirow;
906     MSIFOLDER *folder;
907     MSICOMPONENT *comp;
908 
909     component = MSI_RecordGetString(row, 2);
910     if (!component)
911         return ERROR_SUCCESS;
912 
913     comp = msi_get_loaded_component(package, component);
914     if (!comp)
915         return ERROR_SUCCESS;
916 
917     comp->Action = msi_get_component_action( package, comp );
918     if (comp->Action != INSTALLSTATE_ABSENT)
919     {
920         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
921         return ERROR_SUCCESS;
922     }
923 
924     dir = MSI_RecordGetString( row, 1 );
925     if (!dir)
926     {
927         ERR("Unable to get folder id\n");
928         return ERROR_SUCCESS;
929     }
930 
931     full_path = msi_get_target_folder( package, dir );
932     if (!full_path)
933     {
934         ERR("Unable to resolve folder %s\n", debugstr_w(dir));
935         return ERROR_SUCCESS;
936     }
937     TRACE("folder is %s\n", debugstr_w(full_path));
938 
939     uirow = MSI_CreateRecord( 1 );
940     MSI_RecordSetStringW( uirow, 1, dir );
941     msi_ui_actiondata( package, szRemoveFolders, uirow );
942     msiobj_release( &uirow->hdr );
943 
944     folder = msi_get_loaded_folder( package, dir );
945     remove_persistent_folder( folder );
946     return ERROR_SUCCESS;
947 }
948 
949 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
950 {
951     static const WCHAR query[] = {
952         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
953         '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
954     MSIQUERY *view;
955     UINT rc;
956 
957     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
958     if (rc != ERROR_SUCCESS)
959         return ERROR_SUCCESS;
960 
961     rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
962     msiobj_release( &view->hdr );
963     return rc;
964 }
965 
966 static UINT load_component( MSIRECORD *row, LPVOID param )
967 {
968     MSIPACKAGE *package = param;
969     MSICOMPONENT *comp;
970 
971     comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
972     if (!comp)
973         return ERROR_FUNCTION_FAILED;
974 
975     list_add_tail( &package->components, &comp->entry );
976 
977     /* fill in the data */
978     comp->Component = msi_dup_record_field( row, 1 );
979 
980     TRACE("Loading Component %s\n", debugstr_w(comp->Component));
981 
982     comp->ComponentId = msi_dup_record_field( row, 2 );
983     comp->Directory = msi_dup_record_field( row, 3 );
984     comp->Attributes = MSI_RecordGetInteger(row,4);
985     comp->Condition = msi_dup_record_field( row, 5 );
986     comp->KeyPath = msi_dup_record_field( row, 6 );
987 
988     comp->Installed = INSTALLSTATE_UNKNOWN;
989     comp->Action = INSTALLSTATE_UNKNOWN;
990     comp->ActionRequest = INSTALLSTATE_UNKNOWN;
991 
992     comp->assembly = msi_load_assembly( package, comp );
993     return ERROR_SUCCESS;
994 }
995 
996 UINT msi_load_all_components( MSIPACKAGE *package )
997 {
998     static const WCHAR query[] = {
999         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1000         '`','C','o','m','p','o','n','e','n','t','`',0};
1001     MSIQUERY *view;
1002     UINT r;
1003 
1004     if (!list_empty(&package->components))
1005         return ERROR_SUCCESS;
1006 
1007     r = MSI_DatabaseOpenViewW( package->db, query, &view );
1008     if (r != ERROR_SUCCESS)
1009         return r;
1010 
1011     if (!msi_init_assembly_caches( package ))
1012     {
1013         ERR("can't initialize assembly caches\n");
1014         msiobj_release( &view->hdr );
1015         return ERROR_FUNCTION_FAILED;
1016     }
1017 
1018     r = MSI_IterateRecords(view, NULL, load_component, package);
1019     msiobj_release(&view->hdr);
1020     msi_destroy_assembly_caches( package );
1021     return r;
1022 }
1023 
1024 typedef struct {
1025     MSIPACKAGE *package;
1026     MSIFEATURE *feature;
1027 } _ilfs;
1028 
1029 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1030 {
1031     ComponentList *cl;
1032 
1033     cl = msi_alloc( sizeof (*cl) );
1034     if ( !cl )
1035         return ERROR_NOT_ENOUGH_MEMORY;
1036     cl->component = comp;
1037     list_add_tail( &feature->Components, &cl->entry );
1038 
1039     return ERROR_SUCCESS;
1040 }
1041 
1042 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1043 {
1044     FeatureList *fl;
1045 
1046     fl = msi_alloc( sizeof(*fl) );
1047     if ( !fl )
1048         return ERROR_NOT_ENOUGH_MEMORY;
1049     fl->feature = child;
1050     list_add_tail( &parent->Children, &fl->entry );
1051 
1052     return ERROR_SUCCESS;
1053 }
1054 
1055 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1056 {
1057     _ilfs* ilfs = param;
1058     LPCWSTR component;
1059     MSICOMPONENT *comp;
1060 
1061     component = MSI_RecordGetString(row,1);
1062 
1063     /* check to see if the component is already loaded */
1064     comp = msi_get_loaded_component( ilfs->package, component );
1065     if (!comp)
1066     {
1067         WARN("ignoring unknown component %s\n", debugstr_w(component));
1068         return ERROR_SUCCESS;
1069     }
1070     add_feature_component( ilfs->feature, comp );
1071     comp->Enabled = TRUE;
1072 
1073     return ERROR_SUCCESS;
1074 }
1075 
1076 static UINT load_feature(MSIRECORD * row, LPVOID param)
1077 {
1078     static const WCHAR query[] = {
1079         'S','E','L','E','C','T',' ','`','C','o','m','p','o','n','e','n','t','_','`',
1080          ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1081          'C','o','m','p','o','n','e','n','t','s','`',' ','W','H','E','R','E',' ',
1082          '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1083     MSIPACKAGE *package = param;
1084     MSIFEATURE *feature;
1085     MSIQUERY *view;
1086     _ilfs ilfs;
1087     UINT rc;
1088 
1089     /* fill in the data */
1090 
1091     feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1092     if (!feature)
1093         return ERROR_NOT_ENOUGH_MEMORY;
1094 
1095     list_init( &feature->Children );
1096     list_init( &feature->Components );
1097     
1098     feature->Feature = msi_dup_record_field( row, 1 );
1099 
1100     TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1101 
1102     feature->Feature_Parent = msi_dup_record_field( row, 2 );
1103     feature->Title = msi_dup_record_field( row, 3 );
1104     feature->Description = msi_dup_record_field( row, 4 );
1105 
1106     if (!MSI_RecordIsNull(row,5))
1107         feature->Display = MSI_RecordGetInteger(row,5);
1108   
1109     feature->Level= MSI_RecordGetInteger(row,6);
1110     feature->Directory = msi_dup_record_field( row, 7 );
1111     feature->Attributes = MSI_RecordGetInteger(row,8);
1112 
1113     feature->Installed = INSTALLSTATE_UNKNOWN;
1114     feature->Action = INSTALLSTATE_UNKNOWN;
1115     feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1116 
1117     list_add_tail( &package->features, &feature->entry );
1118 
1119     /* load feature components */
1120 
1121     rc = MSI_OpenQuery( package->db, &view, query, feature->Feature );
1122     if (rc != ERROR_SUCCESS)
1123         return ERROR_SUCCESS;
1124 
1125     ilfs.package = package;
1126     ilfs.feature = feature;
1127 
1128     rc = MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1129     msiobj_release(&view->hdr);
1130     return rc;
1131 }
1132 
1133 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1134 {
1135     MSIPACKAGE *package = param;
1136     MSIFEATURE *parent, *child;
1137 
1138     child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) );
1139     if (!child)
1140         return ERROR_FUNCTION_FAILED;
1141 
1142     if (!child->Feature_Parent)
1143         return ERROR_SUCCESS;
1144 
1145     parent = msi_get_loaded_feature( package, child->Feature_Parent );
1146     if (!parent)
1147         return ERROR_FUNCTION_FAILED;
1148 
1149     add_feature_child( parent, child );
1150     return ERROR_SUCCESS;
1151 }
1152 
1153 UINT msi_load_all_features( MSIPACKAGE *package )
1154 {
1155     static const WCHAR query[] = {
1156         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1157         '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',' ','B','Y',' ',
1158         '`','D','i','s','p','l','a','y','`',0};
1159     MSIQUERY *view;
1160     UINT r;
1161 
1162     if (!list_empty(&package->features))
1163         return ERROR_SUCCESS;
1164  
1165     r = MSI_DatabaseOpenViewW( package->db, query, &view );
1166     if (r != ERROR_SUCCESS)
1167         return r;
1168 
1169     r = MSI_IterateRecords( view, NULL, load_feature, package );
1170     if (r != ERROR_SUCCESS)
1171     {
1172         msiobj_release( &view->hdr );
1173         return r;
1174     }
1175     r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1176     msiobj_release( &view->hdr );
1177     return r;
1178 }
1179 
1180 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1181 {
1182     if (!p)
1183         return p;
1184     p = strchrW(p, ch);
1185     if (!p)
1186         return p;
1187     *p = 0;
1188     return p+1;
1189 }
1190 
1191 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1192 {
1193     static const WCHAR query[] = {
1194         'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1195         '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1196         'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1197     MSIQUERY *view = NULL;
1198     MSIRECORD *row = NULL;
1199     UINT r;
1200 
1201     TRACE("%s\n", debugstr_w(file->File));
1202 
1203     r = MSI_OpenQuery(package->db, &view, query, file->File);
1204     if (r != ERROR_SUCCESS)
1205         goto done;
1206 
1207     r = MSI_ViewExecute(view, NULL);
1208     if (r != ERROR_SUCCESS)
1209         goto done;
1210 
1211     r = MSI_ViewFetch(view, &row);
1212     if (r != ERROR_SUCCESS)
1213         goto done;
1214 
1215     file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1216     file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1217     file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1218     file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1219     file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1220 
1221 done:
1222     if (view) msiobj_release(&view->hdr);
1223     if (row) msiobj_release(&row->hdr);
1224     return r;
1225 }
1226 
1227 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1228 {
1229     MSIRECORD *row;
1230     static const WCHAR query[] = {
1231         'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1232         '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1233         '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1234 
1235     row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1236     if (!row)
1237     {
1238         WARN("query failed\n");
1239         return ERROR_FUNCTION_FAILED;
1240     }
1241 
1242     file->disk_id = MSI_RecordGetInteger( row, 1 );
1243     msiobj_release( &row->hdr );
1244     return ERROR_SUCCESS;
1245 }
1246 
1247 static UINT load_file(MSIRECORD *row, LPVOID param)
1248 {
1249     MSIPACKAGE* package = param;
1250     LPCWSTR component;
1251     MSIFILE *file;
1252 
1253     /* fill in the data */
1254 
1255     file = msi_alloc_zero( sizeof (MSIFILE) );
1256     if (!file)
1257         return ERROR_NOT_ENOUGH_MEMORY;
1258  
1259     file->File = msi_dup_record_field( row, 1 );
1260 
1261     component = MSI_RecordGetString( row, 2 );
1262     file->Component = msi_get_loaded_component( package, component );
1263 
1264     if (!file->Component)
1265     {
1266         WARN("Component not found: %s\n", debugstr_w(component));
1267         msi_free(file->File);
1268         msi_free(file);
1269         return ERROR_SUCCESS;
1270     }
1271 
1272     file->FileName = msi_dup_record_field( row, 3 );
1273     msi_reduce_to_long_filename( file->FileName );
1274 
1275     file->ShortName = msi_dup_record_field( row, 3 );
1276     file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1277     
1278     file->FileSize = MSI_RecordGetInteger( row, 4 );
1279     file->Version = msi_dup_record_field( row, 5 );
1280     file->Language = msi_dup_record_field( row, 6 );
1281     file->Attributes = MSI_RecordGetInteger( row, 7 );
1282     file->Sequence = MSI_RecordGetInteger( row, 8 );
1283 
1284     file->state = msifs_invalid;
1285 
1286     /* if the compressed bits are not set in the file attributes,
1287      * then read the information from the package word count property
1288      */
1289     if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1290     {
1291         file->IsCompressed = FALSE;
1292     }
1293     else if (file->Attributes &
1294              (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1295     {
1296         file->IsCompressed = TRUE;
1297     }
1298     else if (file->Attributes & msidbFileAttributesNoncompressed)
1299     {
1300         file->IsCompressed = FALSE;
1301     }
1302     else
1303     {
1304         file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1305     }
1306 
1307     load_file_hash(package, file);
1308     load_file_disk_id(package, file);
1309 
1310     TRACE("File Loaded (%s)\n",debugstr_w(file->File));  
1311 
1312     list_add_tail( &package->files, &file->entry );
1313  
1314     return ERROR_SUCCESS;
1315 }
1316 
1317 static UINT load_all_files(MSIPACKAGE *package)
1318 {
1319     static const WCHAR query[] = {
1320         'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1321         '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1322         '`','S','e','q','u','e','n','c','e','`', 0};
1323     MSIQUERY *view;
1324     UINT rc;
1325 
1326     if (!list_empty(&package->files))
1327         return ERROR_SUCCESS;
1328 
1329     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1330     if (rc != ERROR_SUCCESS)
1331         return ERROR_SUCCESS;
1332 
1333     rc = MSI_IterateRecords(view, NULL, load_file, package);
1334     msiobj_release(&view->hdr);
1335     return rc;
1336 }
1337 
1338 static UINT load_media( MSIRECORD *row, LPVOID param )
1339 {
1340     MSIPACKAGE *package = param;
1341     UINT disk_id = MSI_RecordGetInteger( row, 1 );
1342     const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
1343 
1344     /* FIXME: load external cabinets and directory sources too */
1345     if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
1346     msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
1347     return ERROR_SUCCESS;
1348 }
1349 
1350 static UINT load_all_media( MSIPACKAGE *package )
1351 {
1352     static const WCHAR query[] = {
1353         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`',
1354         'M','e','d','i','a','`',' ','O','R','D','E','R',' ','B','Y',' ',
1355         '`','D','i','s','k','I','d','`',0};
1356     MSIQUERY *view;
1357     UINT r;
1358 
1359     r = MSI_DatabaseOpenViewW( package->db, query, &view );
1360     if (r != ERROR_SUCCESS)
1361         return ERROR_SUCCESS;
1362 
1363     r = MSI_IterateRecords( view, NULL, load_media, package );
1364     msiobj_release( &view->hdr );
1365     return r;
1366 }
1367 
1368 static UINT load_patch(MSIRECORD *row, LPVOID param)
1369 {
1370     MSIPACKAGE *package = param;
1371     MSIFILEPATCH *patch;
1372     LPWSTR file_key;
1373 
1374     patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
1375     if (!patch)
1376         return ERROR_NOT_ENOUGH_MEMORY;
1377 
1378     file_key = msi_dup_record_field( row, 1 );
1379     patch->File = msi_get_loaded_file( package, file_key );
1380     msi_free(file_key);
1381 
1382     if( !patch->File )
1383     {
1384         ERR("Failed to find target for patch in File table\n");
1385         msi_free(patch);
1386         return ERROR_FUNCTION_FAILED;
1387     }
1388 
1389     patch->Sequence = MSI_RecordGetInteger( row, 2 );
1390 
1391     /* FIXME: The database should be properly transformed */
1392     patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
1393 
1394     patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1395     patch->Attributes = MSI_RecordGetInteger( row, 4 );
1396     patch->IsApplied = FALSE;
1397 
1398     /* FIXME:
1399      * Header field - for patch validation.
1400      * _StreamRef   - External key into MsiPatchHeaders (instead of the header field)
1401      */
1402 
1403     TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
1404 
1405     list_add_tail( &package->filepatches, &patch->entry );
1406 
1407     return ERROR_SUCCESS;
1408 }
1409 
1410 static UINT load_all_patches(MSIPACKAGE *package)
1411 {
1412     static const WCHAR query[] = {
1413         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1414         '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
1415         '`','S','e','q','u','e','n','c','e','`',0};
1416     MSIQUERY *view;
1417     UINT rc;
1418 
1419     if (!list_empty(&package->filepatches))
1420         return ERROR_SUCCESS;
1421 
1422     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1423     if (rc != ERROR_SUCCESS)
1424         return ERROR_SUCCESS;
1425 
1426     rc = MSI_IterateRecords(view, NULL, load_patch, package);
1427     msiobj_release(&view->hdr);
1428     return rc;
1429 }
1430 
1431 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
1432 {
1433     static const WCHAR query[] = {
1434         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1435         '`','C','r','e','a','t','e','F','o','l','d','e','r','`',' ','W','H','E','R','E',' ',
1436         '`','D','i','r','e','c','t','o','r','y','_','`',' ','=','\'','%','s','\'',0};
1437     MSIQUERY *view;
1438 
1439     folder->persistent = FALSE;
1440     if (!MSI_OpenQuery( package->db, &view, query, folder->Directory ))
1441     {
1442         if (!MSI_ViewExecute( view, NULL ))
1443         {
1444             MSIRECORD *rec;
1445             if (!MSI_ViewFetch( view, &rec ))
1446             {
1447                 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory));
1448                 folder->persistent = TRUE;
1449                 msiobj_release( &rec->hdr );
1450             }
1451         }
1452         msiobj_release( &view->hdr );
1453     }
1454     return ERROR_SUCCESS;
1455 }
1456 
1457 static UINT load_folder( MSIRECORD *row, LPVOID param )
1458 {
1459     MSIPACKAGE *package = param;
1460     static WCHAR szEmpty[] = { 0 };
1461     LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1462     MSIFOLDER *folder;
1463 
1464     if (!(folder = msi_alloc_zero( sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY;
1465     list_init( &folder->children );
1466     folder->Directory = msi_dup_record_field( row, 1 );
1467     folder->Parent = msi_dup_record_field( row, 2 );
1468     p = msi_dup_record_field(row, 3);
1469 
1470     TRACE("%s\n", debugstr_w(folder->Directory));
1471 
1472     /* split src and target dir */
1473     tgt_short = p;
1474     src_short = folder_split_path( p, ':' );
1475 
1476     /* split the long and short paths */
1477     tgt_long = folder_split_path( tgt_short, '|' );
1478     src_long = folder_split_path( src_short, '|' );
1479 
1480     /* check for no-op dirs */
1481     if (tgt_short && !strcmpW( szDot, tgt_short ))
1482         tgt_short = szEmpty;
1483     if (src_short && !strcmpW( szDot, src_short ))
1484         src_short = szEmpty;
1485 
1486     if (!tgt_long)
1487         tgt_long = tgt_short;
1488 
1489     if (!src_short) {
1490         src_short = tgt_short;
1491         src_long = tgt_long;
1492     }
1493 
1494     if (!src_long)
1495         src_long = src_short;
1496 
1497     /* FIXME: use the target short path too */
1498     folder->TargetDefault = strdupW(tgt_long);
1499     folder->SourceShortPath = strdupW(src_short);
1500     folder->SourceLongPath = strdupW(src_long);
1501     msi_free(p);
1502 
1503     TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1504     TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1505     TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1506 
1507     load_folder_persistence( package, folder );
1508 
1509     list_add_tail( &package->folders, &folder->entry );
1510     return ERROR_SUCCESS;
1511 }
1512 
1513 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
1514 {
1515     FolderList *fl;
1516 
1517     if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
1518     fl->folder = child;
1519     list_add_tail( &parent->children, &fl->entry );
1520     return ERROR_SUCCESS;
1521 }
1522 
1523 static UINT find_folder_children( MSIRECORD *row, LPVOID param )
1524 {
1525     MSIPACKAGE *package = param;
1526     MSIFOLDER *parent, *child;
1527 
1528     if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
1529         return ERROR_FUNCTION_FAILED;
1530 
1531     if (!child->Parent) return ERROR_SUCCESS;
1532 
1533     if (!(parent = msi_get_loaded_folder( package, child->Parent )))
1534         return ERROR_FUNCTION_FAILED;
1535 
1536     return add_folder_child( parent, child );
1537 }
1538 
1539 static UINT load_all_folders( MSIPACKAGE *package )
1540 {
1541     static const WCHAR query[] = {
1542         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1543         '`','D','i','r','e','c','t','o','r','y','`',0};
1544     MSIQUERY *view;
1545     UINT r;
1546 
1547     if (!list_empty(&package->folders))
1548         return ERROR_SUCCESS;
1549 
1550     r = MSI_DatabaseOpenViewW( package->db, query, &view );
1551     if (r != ERROR_SUCCESS)
1552         return r;
1553 
1554     r = MSI_IterateRecords( view, NULL, load_folder, package );
1555     if (r != ERROR_SUCCESS)
1556     {
1557         msiobj_release( &view->hdr );
1558         return r;
1559     }
1560     r = MSI_IterateRecords( view, NULL, find_folder_children, package );
1561     msiobj_release( &view->hdr );
1562     return r;
1563 }
1564 
1565 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1566 {
1567     msi_set_property( package->db, szCostingComplete, szZero );
1568     msi_set_property( package->db, szRootDrive, szCRoot );
1569 
1570     load_all_folders( package );
1571     msi_load_all_components( package );
1572     msi_load_all_features( package );
1573     load_all_files( package );
1574     load_all_patches( package );
1575     load_all_media( package );
1576 
1577     return ERROR_SUCCESS;
1578 }
1579 
1580 static UINT execute_script_action( MSIPACKAGE *package, UINT script, UINT index )
1581 {
1582     const WCHAR *action = package->script->Actions[script][index];
1583     ui_actionstart( package, action );
1584     TRACE("executing %s\n", debugstr_w(action));
1585     return ACTION_PerformAction( package, action, script );
1586 }
1587 
1588 static UINT execute_script( MSIPACKAGE *package, UINT script )
1589 {
1590     UINT i, rc = ERROR_SUCCESS;
1591 
1592     TRACE("executing script %u\n", script);
1593 
1594     if (!package->script)
1595     {
1596         ERR("no script!\n");
1597         return ERROR_FUNCTION_FAILED;
1598     }
1599     if (script == SCRIPT_ROLLBACK)
1600     {
1601         for (i = package->script->ActionCount[script]; i > 0; i--)
1602         {
1603             rc = execute_script_action( package, script, i - 1 );
1604             if (rc != ERROR_SUCCESS) break;
1605         }
1606     }
1607     else
1608     {
1609         for (i = 0; i < package->script->ActionCount[script]; i++)
1610         {
1611             rc = execute_script_action( package, script, i );
1612             if (rc != ERROR_SUCCESS) break;
1613         }
1614     }
1615     msi_free_action_script(package, script);
1616     return rc;
1617 }
1618 
1619 static UINT ACTION_FileCost(MSIPACKAGE *package)
1620 {
1621     return ERROR_SUCCESS;
1622 }
1623 
1624 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1625 {
1626     MSICOMPONENT *comp;
1627     UINT r;
1628 
1629     LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1630     {
1631         if (!comp->ComponentId) continue;
1632 
1633         r = MsiQueryComponentStateW( package->ProductCode, NULL,
1634                                      MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1635                                      &comp->Installed );
1636         if (r == ERROR_SUCCESS) continue;
1637 
1638         r = MsiQueryComponentStateW( package->ProductCode, NULL,
1639                                      MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1640                                      &comp->Installed );
1641         if (r == ERROR_SUCCESS) continue;
1642 
1643         r = MsiQueryComponentStateW( package->ProductCode, NULL,
1644                                      MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1645                                      &comp->Installed );
1646         if (r == ERROR_SUCCESS) continue;
1647 
1648         comp->Installed = INSTALLSTATE_ABSENT;
1649     }
1650 }
1651 
1652 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1653 {
1654     MSIFEATURE *feature;
1655 
1656     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1657     {
1658         INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1659 
1660         if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1661             feature->Installed = INSTALLSTATE_ABSENT;
1662         else
1663             feature->Installed = state;
1664     }
1665 }
1666 
1667 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1668 {
1669     return (feature->Level > 0 && feature->Level <= level);
1670 }
1671 
1672 static BOOL process_state_property(MSIPACKAGE* package, int level,
1673                                    LPCWSTR property, INSTALLSTATE state)
1674 {
1675     LPWSTR override;
1676     MSIFEATURE *feature;
1677 
1678     override = msi_dup_property( package->db, property );
1679     if (!override)
1680         return FALSE;
1681 
1682     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1683     {
1684         if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1685             continue;
1686 
1687         if (!strcmpW(property, szReinstall)) state = feature->Installed;
1688 
1689         if (!strcmpiW( override, szAll ))
1690         {
1691             if (feature->Installed != state)
1692             {
1693                 feature->Action = state;
1694                 feature->ActionRequest = state;
1695             }
1696         }
1697         else
1698         {
1699             LPWSTR ptr = override;
1700             LPWSTR ptr2 = strchrW(override,',');
1701 
1702             while (ptr)
1703             {
1704                 int len = ptr2 - ptr;
1705 
1706                 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1707                     || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1708                 {
1709                     if (feature->Installed != state)
1710                     {
1711                         feature->Action = state;
1712                         feature->ActionRequest = state;
1713                     }
1714                     break;
1715                 }
1716                 if (ptr2)
1717                 {
1718                     ptr=ptr2+1;
1719                     ptr2 = strchrW(ptr,',');
1720                 }
1721                 else
1722                     break;
1723             }
1724         }
1725     }
1726     msi_free(override);
1727     return TRUE;
1728 }
1729 
1730 static BOOL process_overrides( MSIPACKAGE *package, int level )
1731 {
1732     static const WCHAR szAddLocal[] =
1733         {'A','D','D','L','O','C','A','L',0};
1734     static const WCHAR szAddSource[] =
1735         {'A','D','D','S','O','U','R','C','E',0};
1736     static const WCHAR szAdvertise[] =
1737         {'A','D','V','E','R','T','I','S','E',0};
1738     BOOL ret = FALSE;
1739 
1740     /* all these activation/deactivation things happen in order and things
1741      * later on the list override things earlier on the list.
1742      *
1743      *  0  INSTALLLEVEL processing
1744      *  1  ADDLOCAL
1745      *  2  REMOVE
1746      *  3  ADDSOURCE
1747      *  4  ADDDEFAULT
1748      *  5  REINSTALL
1749      *  6  ADVERTISE
1750      *  7  COMPADDLOCAL
1751      *  8  COMPADDSOURCE
1752      *  9  FILEADDLOCAL
1753      * 10  FILEADDSOURCE
1754      * 11  FILEADDDEFAULT
1755      */
1756     ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1757     ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1758     ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1759     ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1760     ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1761 
1762     if (ret)
1763         msi_set_property( package->db, szPreselected, szOne );
1764 
1765     return ret;
1766 }
1767 
1768 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1769 {
1770     int level;
1771     MSICOMPONENT* component;
1772     MSIFEATURE *feature;
1773 
1774     TRACE("Checking Install Level\n");
1775 
1776     level = msi_get_property_int(package->db, szInstallLevel, 1);
1777 
1778     if (!msi_get_property_int( package->db, szPreselected, 0 ))
1779     {
1780         LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1781         {
1782             if (!is_feature_selected( feature, level )) continue;
1783 
1784             if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1785             {
1786                 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1787                 {
1788                     feature->Action = INSTALLSTATE_SOURCE;
1789                     feature->ActionRequest = INSTALLSTATE_SOURCE;
1790                 }
1791                 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1792                 {
1793                     feature->Action = INSTALLSTATE_ADVERTISED;
1794                     feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1795                 }
1796                 else
1797                 {
1798                     feature->Action = INSTALLSTATE_LOCAL;
1799                     feature->ActionRequest = INSTALLSTATE_LOCAL;
1800                 }
1801             }
1802         }
1803         /* disable child features of unselected parent or follow parent */
1804         LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1805         {
1806             FeatureList *fl;
1807 
1808             LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1809             {
1810                 if (!is_feature_selected( feature, level ))
1811                 {
1812                     fl->feature->Action = INSTALLSTATE_UNKNOWN;
1813                     fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1814                 }
1815                 else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1816                 {
1817                     TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1818                           debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1819                           debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1820                     fl->feature->Action = feature->Action;
1821                     fl->feature->ActionRequest = feature->ActionRequest;
1822                 }
1823             }
1824         }
1825     }
1826     else /* preselected */
1827     {
1828         LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1829         {
1830             if (!is_feature_selected( feature, level )) continue;
1831 
1832             if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1833             {
1834                 if (feature->Installed == INSTALLSTATE_ABSENT)
1835                 {
1836                     feature->Action = INSTALLSTATE_UNKNOWN;
1837                     feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1838                 }
1839                 else
1840                 {
1841                     feature->Action = feature->Installed;
1842                     feature->ActionRequest = feature->Installed;
1843                 }
1844             }
1845         }
1846         LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1847         {
1848             FeatureList *fl;
1849 
1850             LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1851             {
1852                 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent &&
1853                     (!(feature->Attributes & msidbFeatureAttributesFavorAdvertise)))
1854                 {
1855                     TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1856                           debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1857                           debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1858                     fl->feature->Action = feature->Action;
1859                     fl->feature->ActionRequest = feature->ActionRequest;
1860                 }
1861             }
1862         }
1863     }
1864 
1865     /* now we want to set component state based based on feature state */
1866     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1867     {
1868         ComponentList *cl;
1869 
1870         TRACE("examining feature %s (level %d installed %d request %d action %d)\n",
1871               debugstr_w(feature->Feature), feature->Level, feature->Installed,
1872               feature->ActionRequest, feature->Action);
1873 
1874         if (!is_feature_selected( feature, level )) continue;
1875 
1876         /* features with components that have compressed files are made local */
1877         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1878         {
1879             if (cl->component->ForceLocalState &&
1880                 feature->ActionRequest == INSTALLSTATE_SOURCE)
1881             {
1882                 feature->Action = INSTALLSTATE_LOCAL;
1883                 feature->ActionRequest = INSTALLSTATE_LOCAL;
1884                 break;
1885             }
1886         }
1887 
1888         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1889         {
1890             component = cl->component;
1891 
1892             switch (feature->ActionRequest)
1893             {
1894             case INSTALLSTATE_ABSENT:
1895                 component->anyAbsent = 1;
1896                 break;
1897             case INSTALLSTATE_ADVERTISED:
1898                 component->hasAdvertiseFeature = 1;
1899                 break;
1900             case INSTALLSTATE_SOURCE:
1901                 component->hasSourceFeature = 1;
1902                 break;
1903             case INSTALLSTATE_LOCAL:
1904                 component->hasLocalFeature = 1;
1905                 break;
1906             case INSTALLSTATE_DEFAULT:
1907                 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1908                     component->hasAdvertiseFeature = 1;
1909                 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1910                     component->hasSourceFeature = 1;
1911                 else
1912                     component->hasLocalFeature = 1;
1913                 break;
1914             default:
1915                 break;
1916             }
1917         }
1918     }
1919 
1920     LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1921     {
1922         /* check if it's local or source */
1923         if (!(component->Attributes & msidbComponentAttributesOptional) &&
1924              (component->hasLocalFeature || component->hasSourceFeature))
1925         {
1926             if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1927                  !component->ForceLocalState)
1928             {
1929                 component->Action = INSTALLSTATE_SOURCE;
1930                 component->ActionRequest = INSTALLSTATE_SOURCE;
1931             }
1932             else
1933             {
1934                 component->Action = INSTALLSTATE_LOCAL;
1935                 component->ActionRequest = INSTALLSTATE_LOCAL;
1936             }
1937             continue;
1938         }
1939 
1940         /* if any feature is local, the component must be local too */
1941         if (component->hasLocalFeature)
1942         {
1943             component->Action = INSTALLSTATE_LOCAL;
1944             component->ActionRequest = INSTALLSTATE_LOCAL;
1945             continue;
1946         }
1947         if (component->hasSourceFeature)
1948         {
1949             component->Action = INSTALLSTATE_SOURCE;
1950             component->ActionRequest = INSTALLSTATE_SOURCE;
1951             continue;
1952         }
1953         if (component->hasAdvertiseFeature)
1954         {
1955             component->Action = INSTALLSTATE_ADVERTISED;
1956             component->ActionRequest = INSTALLSTATE_ADVERTISED;
1957             continue;
1958         }
1959         TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1960         if (component->anyAbsent &&
1961             (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
1962         {
1963             component->Action = INSTALLSTATE_ABSENT;
1964             component->ActionRequest = INSTALLSTATE_ABSENT;
1965         }
1966     }
1967 
1968     LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1969     {
1970         if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1971         {
1972             TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1973             component->Action = INSTALLSTATE_LOCAL;
1974             component->ActionRequest = INSTALLSTATE_LOCAL;
1975         }
1976 
1977         if (component->ActionRequest == INSTALLSTATE_SOURCE &&
1978             component->Installed == INSTALLSTATE_SOURCE &&
1979             component->hasSourceFeature)
1980         {
1981             component->Action = INSTALLSTATE_UNKNOWN;
1982             component->ActionRequest = INSTALLSTATE_UNKNOWN;
1983         }
1984 
1985         TRACE("component %s (installed %d request %d action %d)\n",
1986               debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
1987     }
1988 
1989     return ERROR_SUCCESS;
1990 }
1991 
1992 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1993 {
1994     MSIPACKAGE *package = param;
1995     LPCWSTR name;
1996     MSIFEATURE *feature;
1997 
1998     name = MSI_RecordGetString( row, 1 );
1999 
2000     feature = msi_get_loaded_feature( package, name );
2001     if (!feature)
2002         ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2003     else
2004     {
2005         LPCWSTR Condition;
2006         Condition = MSI_RecordGetString(row,3);
2007 
2008         if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2009         {
2010             int level = MSI_RecordGetInteger(row,2);
2011             TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2012             feature->Level = level;
2013         }
2014     }
2015     return ERROR_SUCCESS;
2016 }
2017 
2018 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2019 {
2020     static const WCHAR name[] = {'\\',0};
2021     VS_FIXEDFILEINFO *ptr, *ret;
2022     LPVOID version;
2023     DWORD versize, handle;
2024     UINT sz;
2025 
2026     versize = GetFileVersionInfoSizeW( filename, &handle );
2027     if (!versize)
2028         return NULL;
2029 
2030     version = msi_alloc( versize );
2031     if (!version)
2032         return NULL;
2033 
2034     GetFileVersionInfoW( filename, 0, versize, version );
2035 
2036     if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2037     {
2038         msi_free( version );
2039         return NULL;
2040     }
2041 
2042     ret = msi_alloc( sz );
2043     memcpy( ret, ptr, sz );
2044 
2045     msi_free( version );
2046     return ret;
2047 }
2048 
2049 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2050 {
2051     DWORD ms, ls;
2052 
2053     msi_parse_version_string( version, &ms, &ls );
2054 
2055     if (fi->dwFileVersionMS > ms) return 1;
2056     else if (fi->dwFileVersionMS < ms) return -1;
2057     else if (fi->dwFileVersionLS > ls) return 1;
2058     else if (fi->dwFileVersionLS < ls) return -1;
2059     return 0;
2060 }
2061 
2062 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2063 {
2064     DWORD ms1, ms2;
2065 
2066     msi_parse_version_string( ver1, &ms1, NULL );
2067     msi_parse_version_string( ver2, &ms2, NULL );
2068 
2069     if (ms1 > ms2) return 1;
2070     else if (ms1 < ms2) return -1;
2071     return 0;
2072 }
2073 
2074 DWORD msi_get_disk_file_size( LPCWSTR filename )
2075 {
2076     HANDLE file;
2077     DWORD size;
2078 
2079     file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2080     if (file == INVALID_HANDLE_VALUE)
2081         return INVALID_FILE_SIZE;
2082 
2083     size = GetFileSize( file, NULL );
2084     TRACE("size is %u\n", size);
2085     CloseHandle( file );
2086     return size;
2087 }
2088 
2089 BOOL msi_file_hash_matches( MSIFILE *file )
2090 {
2091     UINT r;
2092     MSIFILEHASHINFO hash;
2093 
2094     hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2095     r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2096     if (r != ERROR_SUCCESS)
2097         return FALSE;
2098 
2099     return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2100 }
2101 
2102 static WCHAR *get_temp_dir( void )
2103 {
2104     static UINT id;
2105     WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2106 
2107     GetTempPathW( MAX_PATH, tmp );
2108     for (;;)
2109     {
2110         if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2111         if (CreateDirectoryW( dir, NULL )) break;
2112     }
2113     return strdupW( dir );
2114 }
2115 
2116 /*
2117  *  msi_build_directory_name()
2118  *
2119  *  This function is to save messing round with directory names
2120  *  It handles adding backslashes between path segments,
2121  *  and can add \ at the end of the directory name if told to.
2122  *
2123  *  It takes a variable number of arguments.
2124  *  It always allocates a new string for the result, so make sure
2125  *  to free the return value when finished with it.
2126  *
2127  *  The first arg is the number of path segments that follow.
2128  *  The arguments following count are a list of path segments.
2129  *  A path segment may be NULL.
2130  *
2131  *  Path segments will be added with a \ separating them.
2132  *  A \ will not be added after the last segment, however if the
2133  *  last segment is NULL, then the last character will be a \
2134  */
2135 WCHAR *msi_build_directory_name( DWORD count, ... )
2136 {
2137     DWORD sz = 1, i;
2138     WCHAR *dir;
2139     va_list va;
2140 
2141     va_start( va, count );
2142     for (i = 0; i < count; i++)
2143     {
2144         const WCHAR *str = va_arg( va, const WCHAR * );
2145         if (str) sz += strlenW( str ) + 1;
2146     }
2147     va_end( va );
2148 
2149     dir = msi_alloc( sz * sizeof(WCHAR) );
2150     dir[0] = 0;
2151 
2152     va_start( va, count );
2153     for (i = 0; i < count; i++)
2154     {
2155         const WCHAR *str = va_arg( va, const WCHAR * );
2156         if (!str) continue;
2157         strcatW( dir, str );
2158         if ( i + 1 != count && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash );
2159     }
2160     va_end( va );
2161     return dir;
2162 }
2163 
2164 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2165 {
2166     MSIASSEMBLY *assembly = file->Component->assembly;
2167 
2168     TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2169 
2170     msi_free( file->TargetPath );
2171     if (assembly && !assembly->application)
2172     {
2173         if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2174         file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
2175         msi_track_tempfile( package, file->TargetPath );
2176     }
2177     else
2178     {
2179         const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2180         file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2181     }
2182 
2183     TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2184 }
2185 
2186 static UINT calculate_file_cost( MSIPACKAGE *package )
2187 {
2188     VS_FIXEDFILEINFO *file_version;
2189     WCHAR *font_version;
2190     MSIFILE *file;
2191 
2192     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2193     {
2194         MSICOMPONENT *comp = file->Component;
2195         DWORD file_size;
2196 
2197         if (!comp->Enabled) continue;
2198 
2199         if (file->IsCompressed)
2200             comp->ForceLocalState = TRUE;
2201 
2202         set_target_path( package, file );
2203 
2204         if ((comp->assembly && !comp->assembly->installed) ||
2205             GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2206         {
2207             comp->Cost += file->FileSize;
2208             continue;
2209         }
2210         file_size = msi_get_disk_file_size( file->TargetPath );
2211 
2212         if (file->Version)
2213         {
2214             if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2215             {
2216                 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2217                 {
2218                     comp->Cost += file->FileSize - file_size;
2219                 }
2220                 msi_free( file_version );
2221                 continue;
2222             }
2223             else if ((font_version = msi_font_version_from_file( file->TargetPath )))
2224             {
2225                 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2226                 {
2227                     comp->Cost += file->FileSize - file_size;
2228                 }
2229                 msi_free( font_version );
2230                 continue;
2231             }
2232         }
2233         if (file_size != file->FileSize)
2234         {
2235             comp->Cost += file->FileSize - file_size;
2236         }
2237     }
2238     return ERROR_SUCCESS;
2239 }
2240 
2241 WCHAR *msi_normalize_path( const WCHAR *in )
2242 {
2243     const WCHAR *p = in;
2244     WCHAR *q, *ret;
2245     int n, len = strlenW( in ) + 2;
2246 
2247     if (!(q = ret = msi_alloc( len * sizeof(WCHAR) ))) return NULL;
2248 
2249     len = 0;
2250     while (1)
2251     {
2252         /* copy until the end of the string or a space */
2253         while (*p != ' ' && (*q = *p))
2254         {
2255             p++, len++;
2256             /* reduce many backslashes to one */
2257             if (*p != '\\' || *q != '\\')
2258                 q++;
2259         }
2260 
2261         /* quit at the end of the string */
2262         if (!*p)
2263             break;
2264 
2265         /* count the number of spaces */
2266         n = 0;
2267         while (p[n] == ' ')
2268             n++;
2269 
2270         /* if it's leading or trailing space, skip it */
2271         if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
2272             p += n;
2273         else  /* copy n spaces */
2274             while (n && (*q++ = *p++)) n--;
2275     }
2276     while (q - ret > 0 && q[-1] == ' ') q--;
2277     if (q - ret > 0 && q[-1] != '\\')
2278     {
2279         q[0] = '\\';
2280         q[1] = 0;
2281     }
2282     return ret;
2283 }
2284 
2285 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2286 {
2287     FolderList *fl;
2288     MSIFOLDER *folder, *parent, *child;
2289     WCHAR *path, *normalized_path;
2290 
2291     TRACE("resolving %s\n", debugstr_w(name));
2292 
2293     if (!(folder = msi_get_loaded_folder( package, name ))) return;
2294 
2295     if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
2296     {
2297         if (!load_prop || !(path = msi_dup_property( package->db, szTargetDir )))
2298         {
2299             path = msi_dup_property( package->db, szRootDrive );
2300         }
2301     }
2302     else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2303     {
2304         if (folder->Parent && strcmpW( folder->Directory, folder->Parent ))
2305         {
2306             parent = msi_get_loaded_folder( package, folder->Parent );
2307             path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2308         }
2309         else
2310             path = msi_build_directory_name( 2, folder->TargetDefault, NULL );
2311     }
2312     normalized_path = msi_normalize_path( path );
2313     msi_free( path );
2314     if (folder->ResolvedTarget && !strcmpiW( normalized_path, folder->ResolvedTarget ))
2315     {
2316         TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2317         msi_free( normalized_path );
2318         return;
2319     }
2320     msi_set_property( package->db, folder->Directory, normalized_path );
2321     msi_free( folder->ResolvedTarget );
2322     folder->ResolvedTarget = normalized_path;
2323 
2324     LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2325     {
2326         child = fl->folder;
2327         msi_resolve_target_folder( package, child->Directory, load_prop );
2328     }
2329     TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2330 }
2331 
2332 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2333 {
2334     static const WCHAR query[] = {
2335         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2336         '`','C','o','n','d','i','t','i','o','n','`',0};
2337     static const WCHAR szOutOfDiskSpace[] = {
2338         'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2339     MSICOMPONENT *comp;
2340     MSIQUERY *view;
2341     LPWSTR level;
2342     UINT rc;
2343 
2344     TRACE("Building directory properties\n");
2345     msi_resolve_target_folder( package, szTargetDir, TRUE );
2346 
2347     TRACE("Evaluating component conditions\n");
2348     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2349     {
2350         if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2351         {
2352             TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2353             comp->Enabled = FALSE;
2354         }
2355         else
2356             comp->Enabled = TRUE;
2357     }
2358 
2359     /* read components states from the registry */
2360     ACTION_GetComponentInstallStates(package);
2361     ACTION_GetFeatureInstallStates(package);
2362 
2363     if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
2364     {
2365         TRACE("Evaluating feature conditions\n");
2366 
2367         rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2368         if (rc == ERROR_SUCCESS)
2369         {
2370             rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2371             msiobj_release( &view->hdr );
2372             if (rc != ERROR_SUCCESS)
2373                 return rc;
2374         }
2375     }
2376 
2377     TRACE("Calculating file cost\n");
2378     calculate_file_cost( package );
2379 
2380     msi_set_property( package->db, szCostingComplete, szOne );
2381     /* set default run level if not set */
2382     level = msi_dup_property( package->db, szInstallLevel );
2383     if (!level)
2384         msi_set_property( package->db, szInstallLevel, szOne );
2385     msi_free(level);
2386 
2387     /* FIXME: check volume disk space */
2388     msi_set_property( package->db, szOutOfDiskSpace, szZero );
2389 
2390     return MSI_SetFeatureStates(package);
2391 }
2392 
2393 /* OK this value is "interpreted" and then formatted based on the 
2394    first few characters */
2395 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type, 
2396                          DWORD *size)
2397 {
2398     LPSTR data = NULL;
2399 
2400     if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2401     {
2402         if (value[1]=='x')
2403         {
2404             LPWSTR ptr;
2405             CHAR byte[5];
2406             LPWSTR deformated = NULL;
2407             int count;
2408 
2409             deformat_string(package, &value[2], &deformated);
2410 
2411             /* binary value type */
2412             ptr = deformated;
2413             *type = REG_BINARY;
2414             if (strlenW(ptr)%2)
2415                 *size = (strlenW(ptr)/2)+1;
2416             else
2417                 *size = strlenW(ptr)/2;
2418 
2419             data = msi_alloc(*size);
2420 
2421             byte[0] = ''; 
2422             byte[1] = 'x'; 
2423             byte[4] = 0; 
2424             count = 0;
2425             /* if uneven pad with a zero in front */
2426             if (strlenW(ptr)%2)
2427             {
2428                 byte[2]= '';
2429                 byte[3]= *ptr;
2430                 ptr++;
2431                 data[count] = (BYTE)strtol(byte,NULL,0);
2432                 count ++;
2433                 TRACE("Uneven byte count\n");
2434             }
2435             while (*ptr)
2436             {
2437                 byte[2]= *ptr;
2438                 ptr++;
2439                 byte[3]= *ptr;
2440                 ptr++;
2441                 data[count] = (BYTE)strtol(byte,NULL,0);
2442                 count ++;
2443             }
2444             msi_free(deformated);
2445 
2446             TRACE("Data %i bytes(%i)\n",*size,count);
2447         }
2448         else
2449         {
2450             LPWSTR deformated;
2451             LPWSTR p;
2452             DWORD d = 0;
2453             deformat_string(package, &value[1], &deformated);
2454 
2455             *type=REG_DWORD; 
2456             *size = sizeof(DWORD);
2457             data = msi_alloc(*size);
2458             p = deformated;
2459             if (*p == '-')
2460                 p++;
2461             while (*p)
2462             {
2463                 if ( (*p < '') || (*p > '9') )
2464                     break;
2465                 d *= 10;
2466                 d += (*p - '');
2467                 p++;
2468             }
2469             if (deformated[0] == '-')
2470                 d = -d;
2471             *(LPDWORD)data = d;
2472             TRACE("DWORD %i\n",*(LPDWORD)data);
2473 
2474             msi_free(deformated);
2475         }
2476     }
2477     else
2478     {
2479         static const WCHAR szMulti[] = {'[','~',']',0};
2480         LPCWSTR ptr;
2481         *type=REG_SZ;
2482 
2483         if (value[0]=='#')
2484         {
2485             if (value[1]=='%')
2486             {
2487                 ptr = &value[2];
2488                 *type=REG_EXPAND_SZ;
2489             }
2490             else
2491                 ptr = &value[1];
2492          }
2493          else
2494             ptr=value;
2495 
2496         if (strstrW(value, szMulti))
2497             *type = REG_MULTI_SZ;
2498 
2499         /* remove initial delimiter */
2500         if (!strncmpW(value, szMulti, 3))
2501             ptr = value + 3;
2502 
2503         *size = deformat_string(package, ptr,(LPWSTR*)&data);
2504 
2505         /* add double NULL terminator */
2506         if (*type == REG_MULTI_SZ)
2507         {
2508             *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2509             data = msi_realloc_zero(data, *size);
2510         }
2511     }
2512     return data;
2513 }
2514 
2515 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2516 {
2517     const WCHAR *ret;
2518 
2519     switch (root)
2520     {
2521     case -1:
2522         if (msi_get_property_int( package->db, szAllUsers, 0 ))
2523         {
2524             *root_key = HKEY_LOCAL_MACHINE;
2525             ret = szHLM;
2526         }
2527         else
2528         {
2529             *root_key = HKEY_CURRENT_USER;
2530             ret = szHCU;
2531         }
2532         break;
2533     case 0:
2534         *root_key = HKEY_CLASSES_ROOT;
2535         ret = szHCR;
2536         break;
2537     case 1:
2538         *root_key = HKEY_CURRENT_USER;
2539         ret = szHCU;
2540         break;
2541     case 2:
2542         *root_key = HKEY_LOCAL_MACHINE;
2543         ret = szHLM;
2544         break;
2545     case 3:
2546         *root_key = HKEY_USERS;
2547         ret = szHU;
2548         break;
2549     default:
2550         ERR("Unknown root %i\n", root);
2551         return NULL;
2552     }
2553 
2554     return ret;
2555 }
2556 
2557 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2558 {
2559     static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2560     static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2561 
2562     if (is_64bit && package->platform == PLATFORM_INTEL &&
2563         root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2564     {
2565         UINT size;
2566         WCHAR *path_32node;
2567 
2568         size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2569         if (!(path_32node = msi_alloc( size ))) return NULL;
2570 
2571         memcpy( path_32node, path, len * sizeof(WCHAR) );
2572         strcpyW( path_32node + len, szWow6432Node );
2573         strcatW( path_32node, szBackSlash );
2574         strcatW( path_32node, path + len );
2575         return path_32node;
2576     }
2577 
2578     return strdupW( path );
2579 }
2580 
2581 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2582 {
2583     MSIPACKAGE *package = param;
2584     LPSTR value_data = NULL;
2585     HKEY  root_key, hkey;
2586     DWORD type,size;
2587     LPWSTR deformated, uikey, keypath;
2588     LPCWSTR szRoot, component, name, key, value;
2589     MSICOMPONENT *comp;
2590     MSIRECORD * uirow;
2591     INT   root;
2592     BOOL check_first = FALSE;
2593     UINT rc;
2594 
2595     msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2596 
2597     component = MSI_RecordGetString(row, 6);
2598     comp = msi_get_loaded_component(package,component);
2599     if (!comp)
2600         return ERROR_SUCCESS;
2601 
2602     comp->Action = msi_get_component_action( package, comp );
2603     if (comp->Action != INSTALLSTATE_LOCAL)
2604     {
2605         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2606         return ERROR_SUCCESS;
2607     }
2608 
2609     name = MSI_RecordGetString(row, 4);
2610     if( MSI_RecordIsNull(row,5) && name )
2611     {
2612         /* null values can have special meanings */
2613         if (name[0]=='-' && name[1] == 0)
2614                 return ERROR_SUCCESS;
2615         else if ((name[0]=='+' && name[1] == 0) || 
2616                  (name[0] == '*' && name[1] == 0))
2617                 name = NULL;
2618         check_first = TRUE;
2619     }
2620 
2621     root = MSI_RecordGetInteger(row,2);
2622     key = MSI_RecordGetString(row, 3);
2623 
2624     szRoot = get_root_key( package, root, &root_key );
2625     if (!szRoot)
2626         return ERROR_SUCCESS;
2627 
2628     deformat_string(package, key , &deformated);
2629     size = strlenW(deformated) + strlenW(szRoot) + 1;
2630     uikey = msi_alloc(size*sizeof(WCHAR));
2631     strcpyW(uikey,szRoot);
2632     strcatW(uikey,deformated);
2633 
2634     keypath = get_keypath( package, root_key, deformated );
2635     msi_free( deformated );
2636     if (RegCreateKeyW( root_key, keypath, &hkey ))
2637     {
2638         ERR("Could not create key %s\n", debugstr_w(keypath));
2639         msi_free(uikey);
2640         msi_free(keypath);
2641         return ERROR_SUCCESS;
2642     }
2643 
2644     value = MSI_RecordGetString(row,5);
2645     if (value)
2646         value_data = parse_value(package, value, &type, &size); 
2647     else
2648     {
2649         value_data = (LPSTR)strdupW(szEmpty);
2650         size = sizeof(szEmpty);
2651         type = REG_SZ;
2652     }
2653 
2654     deformat_string(package, name, &deformated);
2655 
2656     if (!check_first)
2657     {
2658         TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2659                         debugstr_w(uikey));
2660         RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2661     }
2662     else
2663     {
2664         DWORD sz = 0;
2665         rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2666         if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2667         {
2668             TRACE("value %s of %s checked already exists\n",
2669                             debugstr_w(deformated), debugstr_w(uikey));
2670         }
2671         else
2672         {
2673             TRACE("Checked and setting value %s of %s\n",
2674                             debugstr_w(deformated), debugstr_w(uikey));
2675             if (deformated || size)
2676                 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2677         }
2678     }
2679     RegCloseKey(hkey);
2680 
2681     uirow = MSI_CreateRecord(3);
2682     MSI_RecordSetStringW(uirow,2,deformated);
2683     MSI_RecordSetStringW(uirow,1,uikey);
2684     if (type == REG_SZ || type == REG_EXPAND_SZ)
2685         MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2686     msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2687     msiobj_release( &uirow->hdr );
2688 
2689     msi_free(value_data);
2690     msi_free(deformated);
2691     msi_free(uikey);
2692     msi_free(keypath);
2693 
2694     return ERROR_SUCCESS;
2695 }
2696 
2697 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2698 {
2699     static const WCHAR query[] = {
2700         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2701         '`','R','e','g','i','s','t','r','y','`',0};
2702     MSIQUERY *view;
2703     UINT rc;
2704 
2705     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2706     if (rc != ERROR_SUCCESS)
2707         return ERROR_SUCCESS;
2708 
2709     rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2710     msiobj_release(&view->hdr);
2711     return rc;
2712 }
2713 
2714 static void delete_reg_value( HKEY root, const WCHAR *keypath, const WCHAR *value )
2715 {
2716     LONG res;
2717     HKEY hkey;
2718     DWORD num_subkeys, num_values;
2719 
2720     if (!(res = RegOpenKeyW( root, keypath, &hkey )))
2721     {
2722         if ((res = RegDeleteValueW( hkey, value )))
2723         {
2724             TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
2725         }
2726         res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2727                                 NULL, NULL, NULL, NULL );
2728         RegCloseKey( hkey );
2729         if (!res && !num_subkeys && !num_values)
2730         {
2731             TRACE("removing empty key %s\n", debugstr_w(keypath));
2732             RegDeleteKeyW( root, keypath );
2733         }
2734         return;
2735     }
2736     TRACE("failed to open key %s (%d)\n", debugstr_w(keypath), res);
2737 }
2738 
2739 static void delete_reg_key( HKEY root, const WCHAR *keypath )
2740 {
2741     LONG res = RegDeleteTreeW( root, keypath );
2742     if (res) TRACE("failed to delete key %s (%d)\n", debugstr_w(keypath), res);
2743 }
2744 
2745 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2746 {
2747     MSIPACKAGE *package = param;
2748     LPCWSTR component, name, key_str, root_key_str;
2749     LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2750     MSICOMPONENT *comp;
2751     MSIRECORD *uirow;
2752     BOOL delete_key = FALSE;
2753     HKEY hkey_root;
2754     UINT size;
2755     INT root;
2756 
2757     msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2758 
2759     component = MSI_RecordGetString( row, 6 );
2760     comp = msi_get_loaded_component( package, component );
2761     if (!comp)
2762         return ERROR_SUCCESS;
2763 
2764     comp->Action = msi_get_component_action( package, comp );
2765     if (comp->Action != INSTALLSTATE_ABSENT)
2766     {
2767         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2768         return ERROR_SUCCESS;
2769     }
2770 
2771     name = MSI_RecordGetString( row, 4 );
2772     if (MSI_RecordIsNull( row, 5 ) && name )
2773     {
2774         if (name[0] == '+' && !name[1])
2775             return ERROR_SUCCESS;
2776         else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2777         {
2778             delete_key = TRUE;
2779             name = NULL;
2780         }
2781     }
2782 
2783     root = MSI_RecordGetInteger( row, 2 );
2784     key_str = MSI_RecordGetString( row, 3 );
2785 
2786     root_key_str = get_root_key( package, root, &hkey_root );
2787     if (!root_key_str)
2788         return ERROR_SUCCESS;
2789 
2790     deformat_string( package, key_str, &deformated_key );
2791     size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2792     ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2793     strcpyW( ui_key_str, root_key_str );
2794     strcatW( ui_key_str, deformated_key );
2795 
2796     deformat_string( package, name, &deformated_name );
2797 
2798     keypath = get_keypath( package, hkey_root, deformated_key );
2799     msi_free( deformated_key );
2800     if (delete_key) delete_reg_key( hkey_root, keypath );
2801     else delete_reg_value( hkey_root, keypath, deformated_name );
2802     msi_free( keypath );
2803 
2804     uirow = MSI_CreateRecord( 2 );
2805     MSI_RecordSetStringW( uirow, 1, ui_key_str );
2806     MSI_RecordSetStringW( uirow, 2, deformated_name );
2807     msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2808     msiobj_release( &uirow->hdr );
2809 
2810     msi_free( ui_key_str );
2811     msi_free( deformated_name );
2812     return ERROR_SUCCESS;
2813 }
2814 
2815 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2816 {
2817     MSIPACKAGE *package = param;
2818     LPCWSTR component, name, key_str, root_key_str;
2819     LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2820     MSICOMPONENT *comp;
2821     MSIRECORD *uirow;
2822     BOOL delete_key = FALSE;
2823     HKEY hkey_root;
2824     UINT size;
2825     INT root;
2826 
2827     component = MSI_RecordGetString( row, 5 );
2828     comp = msi_get_loaded_component( package, component );
2829     if (!comp)
2830         return ERROR_SUCCESS;
2831 
2832     comp->Action = msi_get_component_action( package, comp );
2833     if (comp->Action != INSTALLSTATE_LOCAL)
2834     {
2835         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2836         return ERROR_SUCCESS;
2837     }
2838 
2839     if ((name = MSI_RecordGetString( row, 4 )))
2840     {
2841         if (name[0] == '-' && !name[1])
2842         {
2843             delete_key = TRUE;
2844             name = NULL;
2845         }
2846     }
2847 
2848     root = MSI_RecordGetInteger( row, 2 );
2849     key_str = MSI_RecordGetString( row, 3 );
2850 
2851     root_key_str = get_root_key( package, root, &hkey_root );
2852     if (!root_key_str)
2853         return ERROR_SUCCESS;
2854 
2855     deformat_string( package, key_str, &deformated_key );
2856     size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2857     ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2858     strcpyW( ui_key_str, root_key_str );
2859     strcatW( ui_key_str, deformated_key );
2860 
2861     deformat_string( package, name, &deformated_name );
2862 
2863     keypath = get_keypath( package, hkey_root, deformated_key );
2864     msi_free( deformated_key );
2865     if (delete_key) delete_reg_key( hkey_root, keypath );
2866     else delete_reg_value( hkey_root, keypath, deformated_name );
2867     msi_free( keypath );
2868 
2869     uirow = MSI_CreateRecord( 2 );
2870     MSI_RecordSetStringW( uirow, 1, ui_key_str );
2871     MSI_RecordSetStringW( uirow, 2, deformated_name );
2872     msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2873     msiobj_release( &uirow->hdr );
2874 
2875     msi_free( ui_key_str );
2876     msi_free( deformated_name );
2877     return ERROR_SUCCESS;
2878 }
2879 
2880 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2881 {
2882     static const WCHAR registry_query[] = {
2883         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2884         '`','R','e','g','i','s','t','r','y','`',0};
2885     static const WCHAR remove_registry_query[] = {
2886         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2887         '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0};
2888     MSIQUERY *view;
2889     UINT rc;
2890 
2891     rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2892     if (rc == ERROR_SUCCESS)
2893     {
2894         rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2895         msiobj_release( &view->hdr );
2896         if (rc != ERROR_SUCCESS)
2897             return rc;
2898     }
2899     rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2900     if (rc == ERROR_SUCCESS)
2901     {
2902         rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2903         msiobj_release( &view->hdr );
2904         if (rc != ERROR_SUCCESS)
2905             return rc;
2906     }
2907     return ERROR_SUCCESS;
2908 }
2909 
2910 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2911 {
2912     package->script->CurrentlyScripting = TRUE;
2913 
2914     return ERROR_SUCCESS;
2915 }
2916 
2917 
2918 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2919 {
2920     static const WCHAR query[]= {
2921         'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2922         '`','R','e','g','i','s','t','r','y','`',0};
2923     MSICOMPONENT *comp;
2924     DWORD total = 0, count = 0;
2925     MSIQUERY *view;
2926     MSIFEATURE *feature;
2927     MSIFILE *file;
2928     UINT rc;
2929 
2930     TRACE("InstallValidate\n");
2931 
2932     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2933     if (rc == ERROR_SUCCESS)
2934     {
2935         rc = MSI_IterateRecords( view, &count, NULL, package );
2936         msiobj_release( &view->hdr );
2937         if (rc != ERROR_SUCCESS)
2938             return rc;
2939         total += count * REG_PROGRESS_VALUE;
2940     }
2941     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2942         total += COMPONENT_PROGRESS_VALUE;
2943 
2944     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2945         total += file->FileSize;
2946 
2947     msi_ui_progress( package, 0, total, 0, 0 );
2948 
2949     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2950     {
2951         TRACE("Feature: %s Installed %d Request %d Action %d\n",
2952               debugstr_w(feature->Feature), feature->Installed,
2953               feature->ActionRequest, feature->Action);
2954     }
2955     return ERROR_SUCCESS;
2956 }
2957 
2958 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2959 {
2960     MSIPACKAGE* package = param;
2961     LPCWSTR cond = NULL; 
2962     LPCWSTR message = NULL;
2963     UINT r;
2964 
2965     static const WCHAR title[]=
2966         {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2967 
2968     cond = MSI_RecordGetString(row,1);
2969 
2970     r = MSI_EvaluateConditionW(package,cond);
2971     if (r == MSICONDITION_FALSE)
2972     {
2973         if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2974         {
2975             LPWSTR deformated;
2976             message = MSI_RecordGetString(row,2);
2977             deformat_string(package,message,&deformated);
2978             MessageBoxW(NULL,deformated,title,MB_OK);
2979             msi_free(deformated);
2980         }
2981 
2982         return ERROR_INSTALL_FAILURE;
2983     }
2984 
2985     return ERROR_SUCCESS;
2986 }
2987 
2988 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2989 {
2990     static const WCHAR query[] = {
2991         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2992         '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2993     MSIQUERY *view;
2994     UINT rc;
2995 
2996     TRACE("Checking launch conditions\n");
2997 
2998     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2999     if (rc != ERROR_SUCCESS)
3000         return ERROR_SUCCESS;
3001 
3002     rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3003     msiobj_release(&view->hdr);
3004     return rc;
3005 }
3006 
3007 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3008 {
3009 
3010     if (!cmp->KeyPath)
3011         return strdupW( msi_get_target_folder( package, cmp->Directory ) );
3012 
3013     if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3014     {
3015         static const WCHAR query[] = {
3016             'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3017             '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ',
3018             '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0};
3019         static const WCHAR fmt[] = {'%','','2','i',':','\\','%','s','\\',0};
3020         static const WCHAR fmt2[]= {'%','','2','i',':','\\','%','s','\\','%','s',0};
3021         MSIRECORD *row;
3022         UINT root, len;
3023         LPWSTR deformated, buffer, deformated_name;
3024         LPCWSTR key, name;
3025 
3026         row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
3027         if (!row)
3028             return NULL;
3029 
3030         root = MSI_RecordGetInteger(row,2);
3031         key = MSI_RecordGetString(row, 3);
3032         name = MSI_RecordGetString(row, 4);
3033         deformat_string(package, key , &deformated);
3034         deformat_string(package, name, &deformated_name);
3035 
3036         len = strlenW(deformated) + 6;
3037         if (deformated_name)
3038             len+=strlenW(deformated_name);
3039 
3040         buffer = msi_alloc( len *sizeof(WCHAR));
3041 
3042         if (deformated_name)
3043             sprintfW(buffer,fmt2,root,deformated,deformated_name);
3044         else
3045             sprintfW(buffer,fmt,root,deformated);
3046 
3047         msi_free(deformated);
3048         msi_free(deformated_name);
3049         msiobj_release(&row->hdr);
3050 
3051         return buffer;
3052     }
3053     else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3054     {
3055         FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3056         return NULL;
3057     }
3058     else
3059     {
3060         MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3061 
3062         if (file)
3063             return strdupW( file->TargetPath );
3064     }
3065     return NULL;
3066 }
3067 
3068 static HKEY openSharedDLLsKey(void)
3069 {
3070     HKEY hkey=0;
3071     static const WCHAR path[] =
3072         {'S','o','f','t','w','a','r','e','\\',
3073          'M','i','c','r','o','s','o','f','t','\\',
3074          'W','i','n','d','o','w','s','\\',
3075          'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3076          'S','h','a','r','e','d','D','L','L','s',0};
3077 
3078     RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3079     return hkey;
3080 }
3081 
3082 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3083 {
3084     HKEY hkey;
3085     DWORD count=0;
3086     DWORD type;
3087     DWORD sz = sizeof(count);
3088     DWORD rc;
3089     
3090     hkey = openSharedDLLsKey();
3091     rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3092     if (rc != ERROR_SUCCESS)
3093         count = 0;
3094     RegCloseKey(hkey);
3095     return count;
3096 }
3097 
3098 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3099 {
3100     HKEY hkey;
3101 
3102     hkey = openSharedDLLsKey();
3103     if (count > 0)
3104         msi_reg_set_val_dword( hkey, path, count );
3105     else
3106         RegDeleteValueW(hkey,path);
3107     RegCloseKey(hkey);
3108     return count;
3109 }
3110 
3111 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3112 {
3113     MSIFEATURE *feature;
3114     INT count = 0;
3115     BOOL write = FALSE;
3116 
3117     /* only refcount DLLs */
3118     if (comp->KeyPath == NULL || 
3119         comp->assembly ||
3120         comp->Attributes & msidbComponentAttributesRegistryKeyPath || 
3121         comp->Attributes & msidbComponentAttributesODBCDataSource)
3122         write = FALSE;
3123     else
3124     {
3125         count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3126         write = (count > 0);
3127 
3128         if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3129             write = TRUE;
3130     }
3131 
3132     /* increment counts */
3133     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3134     {
3135         ComponentList *cl;
3136 
3137         if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3138             continue;
3139 
3140         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3141         {
3142             if ( cl->component == comp )
3143                 count++;
3144         }
3145     }
3146 
3147     /* decrement counts */
3148     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3149     {
3150         ComponentList *cl;
3151 
3152         if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3153             continue;
3154 
3155         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3156         {
3157             if ( cl->component == comp )
3158                 count--;
3159         }
3160     }
3161 
3162     /* ref count all the files in the component */
3163     if (write)
3164     {
3165         MSIFILE *file;
3166 
3167         LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3168         {
3169             if (file->Component == comp)
3170                 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3171         }
3172     }
3173     
3174     /* add a count for permanent */
3175     if (comp->Attributes & msidbComponentAttributesPermanent)
3176         count ++;
3177     
3178     comp->RefCount = count;
3179 
3180     if (write)
3181         ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3182 }
3183 
3184 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3185 {
3186     if (comp->assembly)
3187     {
3188         const WCHAR prefixW[] = {'<','\\',0};
3189         DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3190         WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3191 
3192         if (keypath)
3193         {
3194             strcpyW( keypath, prefixW );
3195             strcatW( keypath, comp->assembly->display_name );
3196         }
3197         return keypath;
3198     }
3199     return resolve_keypath( package, comp );
3200 }
3201 
3202 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3203 {
3204     WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3205     UINT rc;
3206     MSICOMPONENT *comp;
3207     HKEY hkey;
3208 
3209     TRACE("\n");
3210 
3211     squash_guid(package->ProductCode,squished_pc);
3212     msi_set_sourcedir_props(package, FALSE);
3213 
3214     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3215     {
3216         MSIRECORD *uirow;
3217         INSTALLSTATE action;
3218 
3219         msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3220         if (!comp->ComponentId)
3221             continue;
3222 
3223         squash_guid( comp->ComponentId, squished_cc );
3224         msi_free( comp->FullKeypath );
3225         comp->FullKeypath = build_full_keypath( package, comp );
3226 
3227         ACTION_RefCountComponent( package, comp );
3228 
3229         if (package->need_rollback) action = comp->Installed;
3230         else action = comp->ActionRequest;
3231 
3232         TRACE("Component %s (%s), Keypath=%s, RefCount=%u Action=%u\n",
3233                             debugstr_w(comp->Component), debugstr_w(squished_cc),
3234                             debugstr_w(comp->FullKeypath), comp->RefCount, action);
3235 
3236         if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3237         {
3238             if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3239                 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3240             else
3241                 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3242 
3243             if (rc != ERROR_SUCCESS)
3244                 continue;
3245 
3246             if (comp->Attributes & msidbComponentAttributesPermanent)
3247             {
3248                 static const WCHAR szPermKey[] =
3249                     { '','','','','','','','','','','','',
3250                       '','','','','','','','','','','','',
3251                       '','','','','','','','',0 };
3252 
3253                 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3254             }
3255             if (action == INSTALLSTATE_LOCAL)
3256                 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3257             else
3258             {
3259                 MSIFILE *file;
3260                 MSIRECORD *row;
3261                 LPWSTR ptr, ptr2;
3262                 WCHAR source[MAX_PATH];
3263                 WCHAR base[MAX_PATH];
3264                 LPWSTR sourcepath;
3265 
3266                 static const WCHAR fmt[] = {'%','','2','d','\\',0};
3267                 static const WCHAR query[] = {
3268                     'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3269                     '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3270                     '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3271                     '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3272                     '`','D','i','s','k','I','d','`',0};
3273 
3274                 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3275                     continue;
3276 
3277                 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3278                 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3279                 ptr2 = strrchrW(source, '\\') + 1;
3280                 msiobj_release(&row->hdr);
3281 
3282                 lstrcpyW(base, package->PackagePath);
3283                 ptr = strrchrW(base, '\\');
3284                 *(ptr + 1) = '\0';
3285 
3286                 sourcepath = msi_resolve_file_source(package, file);
3287                 ptr = sourcepath + lstrlenW(base);
3288                 lstrcpyW(ptr2, ptr);
3289                 msi_free(sourcepath);
3290 
3291                 msi_reg_set_val_str(hkey, squished_pc, source);
3292             }
3293             RegCloseKey(hkey);
3294         }
3295         else if (action == INSTALLSTATE_ABSENT)
3296         {
3297             if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3298                 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3299             else
3300                 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3301         }
3302 
3303         /* UI stuff */
3304         uirow = MSI_CreateRecord(3);
3305         MSI_RecordSetStringW(uirow,1,package->ProductCode);
3306         MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3307         MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3308         msi_ui_actiondata( package, szProcessComponents, uirow );
3309         msiobj_release( &uirow->hdr );
3310     }
3311     return ERROR_SUCCESS;
3312 }
3313 
3314 typedef struct {
3315     CLSID       clsid;
3316     LPWSTR      source;
3317 
3318     LPWSTR      path;
3319     ITypeLib    *ptLib;
3320 } typelib_struct;
3321 
3322 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType, 
3323                                        LPWSTR lpszName, LONG_PTR lParam)
3324 {
3325     TLIBATTR *attr;
3326     typelib_struct *tl_struct = (typelib_struct*) lParam;
3327     static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3328     int sz; 
3329     HRESULT res;
3330 
3331     if (!IS_INTRESOURCE(lpszName))
3332     {
3333         ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3334         return TRUE;
3335     }
3336 
3337     sz = strlenW(tl_struct->source)+4;
3338     sz *= sizeof(WCHAR);
3339 
3340     if ((INT_PTR)lpszName == 1)
3341         tl_struct->path = strdupW(tl_struct->source);
3342     else
3343     {
3344         tl_struct->path = msi_alloc(sz);
3345         sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3346     }
3347 
3348     TRACE("trying %s\n", debugstr_w(tl_struct->path));
3349     res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3350     if (FAILED(res))
3351     {
3352         msi_free(tl_struct->path);
3353         tl_struct->path = NULL;
3354 
3355         return TRUE;
3356     }
3357 
3358     ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3359     if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3360     {
3361         ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3362         return FALSE;
3363     }
3364 
3365     msi_free(tl_struct->path);
3366     tl_struct->path = NULL;
3367 
3368     ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3369     ITypeLib_Release(tl_struct->ptLib);
3370 
3371     return TRUE;
3372 }
3373 
3374 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3375 {
3376     MSIPACKAGE* package = param;
3377     LPCWSTR component;
3378     MSICOMPONENT *comp;
3379     MSIFILE *file;
3380     typelib_struct tl_struct;
3381     ITypeLib *tlib;
3382     HMODULE module;
3383     HRESULT hr;
3384 
3385     component = MSI_RecordGetString(row,3);
3386     comp = msi_get_loaded_component(package,component);
3387     if (!comp)
3388         return ERROR_SUCCESS;
3389 
3390     comp->Action = msi_get_component_action( package, comp );
3391     if (comp->Action != INSTALLSTATE_LOCAL)
3392     {
3393         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3394         return ERROR_SUCCESS;
3395     }
3396 
3397     if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3398     {
3399         TRACE("component has no key path\n");
3400         return ERROR_SUCCESS;
3401     }
3402     msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3403 
3404     module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3405     if (module)
3406     {
3407         LPCWSTR guid;
3408         guid = MSI_RecordGetString(row,1);
3409         CLSIDFromString( guid, &tl_struct.clsid);
3410         tl_struct.source = strdupW( file->TargetPath );
3411         tl_struct.path = NULL;
3412 
3413         EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3414                         (LONG_PTR)&tl_struct);
3415 
3416         if (tl_struct.path)
3417         {
3418             LPCWSTR helpid, help_path = NULL;
3419             HRESULT res;
3420 
3421             helpid = MSI_RecordGetString(row,6);
3422 
3423             if (helpid) help_path = msi_get_target_folder( package, helpid );
3424             res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3425 
3426             if (FAILED(res))
3427                 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3428             else
3429                 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3430 
3431             ITypeLib_Release(tl_struct.ptLib);
3432             msi_free(tl_struct.path);
3433         }
3434         else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3435 
3436         FreeLibrary(module);
3437         msi_free(tl_struct.source);
3438     }
3439     else
3440     {
3441         hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3442         if (FAILED(hr))
3443         {
3444             ERR("Failed to load type library: %08x\n", hr);
3445             return ERROR_INSTALL_FAILURE;
3446         }
3447 
3448         ITypeLib_Release(tlib);
3449     }
3450 
3451     return ERROR_SUCCESS;
3452 }
3453 
3454 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3455 {
3456     static const WCHAR query[] = {
3457         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3458         '`','T','y','p','e','L','i','b','`',0};
3459     MSIQUERY *view;
3460     UINT rc;
3461 
3462     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3463     if (rc != ERROR_SUCCESS)
3464         return ERROR_SUCCESS;
3465 
3466     rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3467     msiobj_release(&view->hdr);
3468     return rc;
3469 }
3470 
3471 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3472 {
3473     MSIPACKAGE *package = param;
3474     LPCWSTR component, guid;
3475     MSICOMPONENT *comp;
3476     GUID libid;
3477     UINT version;
3478     LCID language;
3479     SYSKIND syskind;
3480     HRESULT hr;
3481 
3482     component = MSI_RecordGetString( row, 3 );
3483     comp = msi_get_loaded_component( package, component );
3484     if (!comp)
3485         return ERROR_SUCCESS;
3486 
3487     comp->Action = msi_get_component_action( package, comp );
3488     if (comp->Action != INSTALLSTATE_ABSENT)
3489     {
3490         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3491         return ERROR_SUCCESS;
3492     }
3493     msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3494 
3495     guid = MSI_RecordGetString( row, 1 );
3496     CLSIDFromString( guid, &libid );
3497     version = MSI_RecordGetInteger( row, 4 );
3498     language = MSI_RecordGetInteger( row, 2 );
3499 
3500 #ifdef _WIN64
3501     syskind = SYS_WIN64;
3502 #else
3503     syskind = SYS_WIN32;
3504 #endif
3505 
3506     hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3507     if (FAILED(hr))
3508     {
3509         WARN("Failed to unregister typelib: %08x\n", hr);
3510     }
3511 
3512     return ERROR_SUCCESS;
3513 }
3514 
3515 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3516 {
3517     static const WCHAR query[] = {
3518         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3519         '`','T','y','p','e','L','i','b','`',0};
3520     MSIQUERY *view;
3521     UINT rc;
3522 
3523     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3524     if (rc != ERROR_SUCCESS)
3525         return ERROR_SUCCESS;
3526 
3527     rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3528     msiobj_release( &view->hdr );
3529     return rc;
3530 }
3531 
3532 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3533 {
3534     static const WCHAR szlnk[] = {'.','l','n','k',0};
3535     LPCWSTR directory, extension, link_folder;
3536     LPWSTR link_file, filename;
3537 
3538     directory = MSI_RecordGetString( row, 2 );
3539     link_folder = msi_get_target_folder( package, directory );
3540     if (!link_folder)
3541     {
3542         ERR("unable to resolve folder %s\n", debugstr_w(directory));
3543         return NULL;
3544     }
3545     /* may be needed because of a bug somewhere else */
3546     msi_create_full_path( link_folder );
3547 
3548     filename = msi_dup_record_field( row, 3 );
3549     msi_reduce_to_long_filename( filename );
3550 
3551     extension = strchrW( filename, '.' );
3552     if (!extension || strcmpiW( extension, szlnk ))
3553     {
3554         int len = strlenW( filename );
3555         filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3556         memcpy( filename + len, szlnk, sizeof(szlnk) );
3557     }
3558     link_file = msi_build_directory_name( 2, link_folder, filename );
3559     msi_free( filename );
3560 
3561     return link_file;
3562 }
3563 
3564 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3565 {
3566     static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3567     static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3568     WCHAR *folder, *dest, *path;
3569 
3570     if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3571         folder = msi_dup_property( package->db, szWindowsFolder );
3572     else
3573     {
3574         WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3575         folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3576         msi_free( appdata );
3577     }
3578     dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3579     msi_create_full_path( dest );
3580     path = msi_build_directory_name( 2, dest, icon_name );
3581     msi_free( folder );
3582     msi_free( dest );
3583     return path;
3584 }
3585 
3586 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3587 {
3588     MSIPACKAGE *package = param;
3589     LPWSTR link_file, deformated, path;
3590     LPCWSTR component, target;
3591     MSICOMPONENT *comp;
3592     IShellLinkW *sl = NULL;
3593     IPersistFile *pf = NULL;
3594     HRESULT res;
3595 
3596     component = MSI_RecordGetString(row, 4);
3597     comp = msi_get_loaded_component(package, component);
3598     if (!comp)
3599         return ERROR_SUCCESS;
3600 
3601     comp->Action = msi_get_component_action( package, comp );
3602     if (comp->Action != INSTALLSTATE_LOCAL)
3603     {
3604         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3605         return ERROR_SUCCESS;
3606     }
3607     msi_ui_actiondata( package, szCreateShortcuts, row );
3608 
3609     res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3610                     &IID_IShellLinkW, (LPVOID *) &sl );
3611 
3612     if (FAILED( res ))
3613     {
3614         ERR("CLSID_ShellLink not available\n");
3615         goto err;
3616     }
3617 
3618     res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3619     if (FAILED( res ))
3620     {
3621         ERR("QueryInterface(IID_IPersistFile) failed\n");
3622         goto err;
3623     }
3624 
3625     target = MSI_RecordGetString(row, 5);
3626     if (strchrW(target, '['))
3627     {
3628         deformat_string( package, target, &path );
3629         TRACE("target path is %s\n", debugstr_w(path));
3630         IShellLinkW_SetPath( sl, path );
3631         msi_free( path );
3632     }
3633     else
3634     {
3635         FIXME("poorly handled shortcut format, advertised shortcut\n");
3636         IShellLinkW_SetPath(sl,comp->FullKeypath);
3637     }
3638 
3639     if (!MSI_RecordIsNull(row,6))
3640     {
3641         LPCWSTR arguments = MSI_RecordGetString(row, 6);
3642         deformat_string(package, arguments, &deformated);
3643         IShellLinkW_SetArguments(sl,deformated);
3644         msi_free(deformated);
3645     }
3646 
3647     if (!MSI_RecordIsNull(row,7))
3648     {
3649         LPCWSTR description = MSI_RecordGetString(row, 7);
3650         IShellLinkW_SetDescription(sl, description);
3651     }
3652 
3653     if (!MSI_RecordIsNull(row,8))
3654         IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3655 
3656     if (!MSI_RecordIsNull(row,9))
3657     {
3658         INT index; 
3659         LPCWSTR icon = MSI_RecordGetString(row, 9);
3660 
3661         path = msi_build_icon_path(package, icon);
3662         index = MSI_RecordGetInteger(row,10);
3663 
3664         /* no value means 0 */
3665         if (index == MSI_NULL_INTEGER)
3666             index = 0;
3667 
3668         IShellLinkW_SetIconLocation(sl, path, index);
3669         msi_free(path);
3670     }
3671 
3672     if (!MSI_RecordIsNull(row,11))
3673         IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3674 
3675     if (!MSI_RecordIsNull(row,12))
3676     {
3677         LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3678         full_path = msi_get_target_folder( package, wkdir );
3679         if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3680     }
3681     link_file = get_link_file(package, row);
3682 
3683     TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3684     IPersistFile_Save(pf, link_file, FALSE);
3685     msi_free(link_file);
3686 
3687 err:
3688     if (pf)
3689         IPersistFile_Release( pf );
3690     if (sl)
3691         IShellLinkW_Release( sl );
3692 
3693     return ERROR_SUCCESS;
3694 }
3695 
3696 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3697 {
3698     static const WCHAR query[] = {
3699         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3700         '`','S','h','o','r','t','c','u','t','`',0};
3701     MSIQUERY *view;
3702     HRESULT res;
3703     UINT rc;
3704 
3705     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3706     if (rc != ERROR_SUCCESS)
3707         return ERROR_SUCCESS;
3708 
3709     res = CoInitialize( NULL );
3710 
3711     rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3712     msiobj_release(&view->hdr);
3713 
3714     if (SUCCEEDED(res)) CoUninitialize();
3715     return rc;
3716 }
3717 
3718 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3719 {
3720     MSIPACKAGE *package = param;
3721     LPWSTR link_file;
3722     LPCWSTR component;
3723     MSICOMPONENT *comp;
3724 
3725     component = MSI_RecordGetString( row, 4 );
3726     comp = msi_get_loaded_component( package, component );
3727     if (!comp)
3728         return ERROR_SUCCESS;
3729 
3730     comp->Action = msi_get_component_action( package, comp );
3731     if (comp->Action != INSTALLSTATE_ABSENT)
3732     {
3733         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3734         return ERROR_SUCCESS;
3735     }
3736     msi_ui_actiondata( package, szRemoveShortcuts, row );
3737 
3738     link_file = get_link_file( package, row );
3739 
3740     TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3741     if (!DeleteFileW( link_file ))
3742     {
3743         WARN("Failed to remove shortcut file %u\n", GetLastError());
3744     }
3745     msi_free( link_file );
3746 
3747     return ERROR_SUCCESS;
3748 }
3749 
3750 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3751 {
3752     static const WCHAR query[] = {
3753         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3754         '`','S','h','o','r','t','c','u','t','`',0};
3755     MSIQUERY *view;
3756     UINT rc;
3757 
3758     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3759     if (rc != ERROR_SUCCESS)
3760         return ERROR_SUCCESS;
3761 
3762     rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3763     msiobj_release( &view->hdr );
3764     return rc;
3765 }
3766 
3767 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3768 {
3769     MSIPACKAGE* package = param;
3770     HANDLE the_file;
3771     LPWSTR FilePath;
3772     LPCWSTR FileName;
3773     CHAR buffer[1024];
3774     DWORD sz;
3775     UINT rc;
3776 
3777     FileName = MSI_RecordGetString(row,1);
3778     if (!FileName)
3779     {
3780         ERR("Unable to get FileName\n");
3781         return ERROR_SUCCESS;
3782     }
3783 
3784     FilePath = msi_build_icon_path(package, FileName);
3785 
3786     TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3787 
3788     the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3789                         FILE_ATTRIBUTE_NORMAL, NULL);
3790 
3791     if (the_file == INVALID_HANDLE_VALUE)
3792     {
3793         ERR("Unable to create file %s\n",debugstr_w(FilePath));
3794         msi_free(FilePath);
3795         return ERROR_SUCCESS;
3796     }
3797 
3798     do 
3799     {
3800         DWORD write;
3801         sz = 1024;
3802         rc = MSI_RecordReadStream(row,2,buffer,&sz);
3803         if (rc != ERROR_SUCCESS)
3804         {
3805             ERR("Failed to get stream\n");
3806             CloseHandle(the_file);  
3807             DeleteFileW(FilePath);
3808             break;
3809         }
3810         WriteFile(the_file,buffer,sz,&write,NULL);
3811     } while (sz == 1024);
3812 
3813     msi_free(FilePath);
3814     CloseHandle(the_file);
3815 
3816     return ERROR_SUCCESS;
3817 }
3818 
3819 static UINT msi_publish_icons(MSIPACKAGE *package)
3820 {
3821     static const WCHAR query[]= {
3822         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3823         '`','I','c','o','n','`',0};
3824     MSIQUERY *view;
3825     UINT r;
3826 
3827     r = MSI_DatabaseOpenViewW(package->db, query, &view);
3828     if (r == ERROR_SUCCESS)
3829     {
3830         r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3831         msiobj_release(&view->hdr);
3832         if (r != ERROR_SUCCESS)
3833             return r;
3834     }
3835     return ERROR_SUCCESS;
3836 }
3837 
3838 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3839 {
3840     UINT r;
3841     HKEY source;
3842     LPWSTR buffer;
3843     MSIMEDIADISK *disk;
3844     MSISOURCELISTINFO *info;
3845 
3846     r = RegCreateKeyW(hkey, szSourceList, &source);
3847     if (r != ERROR_SUCCESS)
3848         return r;
3849 
3850     RegCloseKey(source);
3851 
3852     buffer = strrchrW(package->PackagePath, '\\') + 1;
3853     r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3854                               package->Context, MSICODE_PRODUCT,
3855                               INSTALLPROPERTY_PACKAGENAMEW, buffer);
3856     if (r != ERROR_SUCCESS)
3857         return r;
3858 
3859     r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3860                               package->Context, MSICODE_PRODUCT,
3861                               INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3862     if (r != ERROR_SUCCESS)
3863         return r;
3864 
3865     r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3866                               package->Context, MSICODE_PRODUCT,
3867                               INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3868     if (r != ERROR_SUCCESS)
3869         return r;
3870 
3871     LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3872     {
3873         if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3874             msi_set_last_used_source(package->ProductCode, NULL, info->context,
3875                                      info->options, info->value);
3876         else
3877             MsiSourceListSetInfoW(package->ProductCode, NULL,
3878                                   info->context, info->options,
3879                                   info->property, info->value);
3880     }
3881 
3882     LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3883     {
3884         MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3885                                    disk->context, disk->options,
3886                                    disk->disk_id, disk->volume_label, disk->disk_prompt);
3887     }
3888 
3889     return ERROR_SUCCESS;
3890 }
3891 
3892 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3893 {
3894     MSIHANDLE hdb, suminfo;
3895     WCHAR guids[MAX_PATH];
3896     WCHAR packcode[SQUISH_GUID_SIZE];
3897     LPWSTR buffer;
3898     LPWSTR ptr;
3899     DWORD langid;
3900     DWORD size;
3901     UINT r;
3902 
3903     static const WCHAR szARPProductIcon[] =
3904         {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3905     static const WCHAR szAssignment[] =
3906         {'A','s','s','i','g','n','m','e','n','t',0};
3907     static const WCHAR szAdvertiseFlags[] =
3908         {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3909     static const WCHAR szClients[] =
3910         {'C','l','i','e','n','t','s',0};
3911     static const WCHAR szColon[] = {':',0};
3912 
3913     buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3914     msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3915     msi_free(buffer);
3916 
3917     langid = msi_get_property_int(package->db, szProductLanguage, 0);
3918     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3919 
3920     /* FIXME */
3921     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3922 
3923     buffer = msi_dup_property(package->db, szARPProductIcon);
3924     if (buffer)
3925     {
3926         LPWSTR path = msi_build_icon_path(package, buffer);
3927         msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3928         msi_free(path);
3929         msi_free(buffer);
3930     }
3931 
3932     buffer = msi_dup_property(package->db, szProductVersion);
3933     if (buffer)
3934     {
3935         DWORD verdword = msi_version_str_to_dword(buffer);
3936         msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3937         msi_free(buffer);
3938     }
3939 
3940     msi_reg_set_val_dword(hkey, szAssignment, 0);
3941     msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3942     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3943     msi_reg_set_val_str(hkey, szClients, szColon);
3944 
3945     hdb = alloc_msihandle(&package->db->hdr);
3946     if (!hdb)
3947         return ERROR_NOT_ENOUGH_MEMORY;
3948 
3949     r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3950     MsiCloseHandle(hdb);
3951     if (r != ERROR_SUCCESS)
3952         goto done;
3953 
3954     size = MAX_PATH;
3955     r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3956                                    NULL, guids, &size);
3957     if (r != ERROR_SUCCESS)
3958         goto done;
3959 
3960     ptr = strchrW(guids, ';');
3961     if (ptr) *ptr = 0;
3962     squash_guid(guids, packcode);
3963     msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3964 
3965 done:
3966     MsiCloseHandle(suminfo);
3967     return ERROR_SUCCESS;
3968 }
3969 
3970 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3971 {
3972     UINT r;
3973     HKEY hkey;
3974     LPWSTR upgrade;
3975     WCHAR squashed_pc[SQUISH_GUID_SIZE];
3976 
3977     upgrade = msi_dup_property(package->db, szUpgradeCode);
3978     if (!upgrade)
3979         return ERROR_SUCCESS;
3980 
3981     if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3982         r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3983     else
3984         r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3985 
3986     if (r != ERROR_SUCCESS)
3987     {
3988         WARN("failed to open upgrade code key\n");
3989         msi_free(upgrade);
3990         return ERROR_SUCCESS;
3991     }
3992     squash_guid(package->ProductCode, squashed_pc);
3993     msi_reg_set_val_str(hkey, squashed_pc, NULL);
3994     RegCloseKey(hkey);
3995     msi_free(upgrade);
3996     return ERROR_SUCCESS;
3997 }
3998 
3999 static BOOL msi_check_publish(MSIPACKAGE *package)
4000 {
4001     MSIFEATURE *feature;
4002 
4003     LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4004     {
4005         feature->Action = msi_get_feature_action( package, feature );
4006         if (feature->Action == INSTALLSTATE_LOCAL)
4007             return TRUE;
4008     }
4009 
4010     return FALSE;
4011 }
4012 
4013 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4014 {
4015     MSIFEATURE *feature;
4016 
4017     LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4018     {
4019         feature->Action = msi_get_feature_action( package, feature );
4020         if (feature->Action != INSTALLSTATE_ABSENT)
4021             return FALSE;
4022     }
4023 
4024     return TRUE;
4025 }
4026 
4027 static UINT msi_publish_patches( MSIPACKAGE *package )
4028 {
4029     static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4030     WCHAR patch_squashed[GUID_SIZE];
4031     HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4032     LONG res;
4033     MSIPATCHINFO *patch;
4034     UINT r;
4035     WCHAR *p, *all_patches = NULL;
4036     DWORD len = 0;
4037 
4038     r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4039     if (r != ERROR_SUCCESS)
4040         return ERROR_FUNCTION_FAILED;
4041 
4042     res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4043     if (res != ERROR_SUCCESS)
4044     {
4045         r = ERROR_FUNCTION_FAILED;
4046         goto done;
4047     }
4048 
4049     r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4050     if (r != ERROR_SUCCESS)
4051         goto done;
4052 
4053     LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4054     {
4055         squash_guid( patch->patchcode, patch_squashed );
4056         len += strlenW( patch_squashed ) + 1;
4057     }
4058 
4059     p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4060     if (!all_patches)
4061         goto done;
4062 
4063     LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4064     {
4065         HKEY patch_key;
4066 
4067         squash_guid( patch->patchcode, p );
4068         p += strlenW( p ) + 1;
4069 
4070         res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4071                               (const BYTE *)patch->transforms,
4072                               (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4073         if (res != ERROR_SUCCESS)
4074             goto done;
4075 
4076         r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4077         if (r != ERROR_SUCCESS)
4078             goto done;
4079 
4080         res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4081                               (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4082         RegCloseKey( patch_key );
4083         if (res != ERROR_SUCCESS)
4084             goto done;
4085 
4086         if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4087         {
4088             res = GetLastError();
4089             ERR("Unable to copy patch package %d\n", res);
4090             goto done;
4091         }
4092         res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4093         if (res != ERROR_SUCCESS)
4094             goto done;
4095 
4096         res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4097         RegCloseKey( patch_key );
4098         if (res != ERROR_SUCCESS)
4099             goto done;
4100     }
4101 
4102     all_patches[len] = 0;
4103     res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4104                           (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4105     if (res != ERROR_SUCCESS)
4106         goto done;
4107 
4108     res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4109                           (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4110     if (res != ERROR_SUCCESS)
4111         r = ERROR_FUNCTION_FAILED;
4112 
4113 done:
4114     RegCloseKey( product_patches_key );
4115     RegCloseKey( patches_key );
4116     RegCloseKey( product_key );
4117     msi_free( all_patches );
4118     return r;
4119 }
4120 
4121 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4122 {
4123     UINT rc;
4124     HKEY hukey = NULL, hudkey = NULL;
4125     MSIRECORD *uirow;
4126 
4127     if (!list_empty(&package->patches))
4128     {
4129         rc = msi_publish_patches(package);
4130         if (rc != ERROR_SUCCESS)
4131             goto end;
4132     }
4133 
4134     /* FIXME: also need to publish if the product is in advertise mode */
4135     if (!msi_check_publish(package))
4136         return ERROR_SUCCESS;
4137 
4138     rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4139                                &hukey, TRUE);
4140     if (rc != ERROR_SUCCESS)
4141         goto end;
4142 
4143     rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4144                                        NULL, &hudkey, TRUE);
4145     if (rc != ERROR_SUCCESS)
4146         goto end;
4147 
4148     rc = msi_publish_upgrade_code(package);
4149     if (rc != ERROR_SUCCESS)
4150         goto end;
4151 
4152     rc = msi_publish_product_properties(package, hukey);
4153     if (rc != ERROR_SUCCESS)
4154         goto end;
4155 
4156     rc = msi_publish_sourcelist(package, hukey);
4157     if (rc != ERROR_SUCCESS)
4158         goto end;
4159 
4160     rc = msi_publish_icons(package);
4161 
4162 end:
4163     uirow = MSI_CreateRecord( 1 );
4164     MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4165     msi_ui_actiondata( package, szPublishProduct, uirow );
4166     msiobj_release( &uirow->hdr );
4167 
4168     RegCloseKey(hukey);
4169     RegCloseKey(hudkey);
4170     return rc;
4171 }
4172 
4173 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4174 {
4175     WCHAR *filename, *ptr, *folder, *ret;
4176     const WCHAR *dirprop;
4177 
4178     filename = msi_dup_record_field( row, 2 );
4179     if (filename && (ptr = strchrW( filename, '|' )))
4180         ptr++;
4181     else
4182         ptr = filename;
4183 
4184     dirprop = MSI_RecordGetString( row, 3 );
4185     if (dirprop)
4186     {
4187         folder = strdupW( msi_get_target_folder( package, dirprop ) );
4188         if (!folder) folder = msi_dup_property( package->db, dirprop );
4189     }
4190     else
4191         folder = msi_dup_property( package->db, szWindowsFolder );
4192 
4193     if (!folder)
4194     {
4195         ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4196         msi_free( filename );
4197         return NULL;
4198     }
4199 
4200     ret = msi_build_directory_name( 2, folder, ptr );
4201 
4202     msi_free( filename );
4203     msi_free( folder );
4204     return ret;
4205 }
4206 
4207 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4208 {
4209     MSIPACKAGE *package = param;
4210     LPCWSTR component, section, key, value, identifier;
4211     LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4212     MSIRECORD * uirow;
4213     INT action;
4214     MSICOMPONENT *comp;
4215 
4216     component = MSI_RecordGetString(row, 8);
4217     comp = msi_get_loaded_component(package,component);
4218     if (!comp)
4219         return ERROR_SUCCESS;
4220 
4221     comp->Action = msi_get_component_action( package, comp );
4222     if (comp->Action != INSTALLSTATE_LOCAL)
4223     {
4224         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4225         return ERROR_SUCCESS;
4226     }
4227 
4228     identifier = MSI_RecordGetString(row,1); 
4229     section = MSI_RecordGetString(row,4);
4230     key = MSI_RecordGetString(row,5);
4231     value = MSI_RecordGetString(row,6);
4232     action = MSI_RecordGetInteger(row,7);
4233 
4234     deformat_string(package,section,&deformated_section);
4235     deformat_string(package,key,&deformated_key);
4236     deformat_string(package,value,&deformated_value);
4237 
4238     fullname = get_ini_file_name(package, row);
4239 
4240     if (action == 0)
4241     {
4242         TRACE("Adding value %s to section %s in %s\n",
4243                 debugstr_w(deformated_key), debugstr_w(deformated_section),
4244                 debugstr_w(fullname));
4245         WritePrivateProfileStringW(deformated_section, deformated_key,
4246                                    deformated_value, fullname);
4247     }
4248     else if (action == 1)
4249     {
4250         WCHAR returned[10];
4251         GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4252                                  returned, 10, fullname);
4253         if (returned[0] == 0)
4254         {
4255             TRACE("Adding value %s to section %s in %s\n",
4256                     debugstr_w(deformated_key), debugstr_w(deformated_section),
4257                     debugstr_w(fullname));
4258 
4259             WritePrivateProfileStringW(deformated_section, deformated_key,
4260                                        deformated_value, fullname);
4261         }
4262     }
4263     else if (action == 3)
4264         FIXME("Append to existing section not yet implemented\n");
4265 
4266     uirow = MSI_CreateRecord(4);
4267     MSI_RecordSetStringW(uirow,1,identifier);
4268     MSI_RecordSetStringW(uirow,2,deformated_section);
4269     MSI_RecordSetStringW(uirow,3,deformated_key);
4270     MSI_RecordSetStringW(uirow,4,deformated_value);
4271     msi_ui_actiondata( package, szWriteIniValues, uirow );
4272     msiobj_release( &uirow->hdr );
4273 
4274     msi_free(fullname);
4275     msi_free(deformated_key);
4276     msi_free(deformated_value);
4277     msi_free(deformated_section);
4278     return ERROR_SUCCESS;
4279 }
4280 
4281 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4282 {
4283     static const WCHAR query[] = {
4284         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4285         '`','I','n','i','F','i','l','e','`',0};
4286     MSIQUERY *view;
4287     UINT rc;
4288 
4289     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4290     if (rc != ERROR_SUCCESS)
4291         return ERROR_SUCCESS;
4292 
4293     rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4294     msiobj_release(&view->hdr);
4295     return rc;
4296 }
4297 
4298 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4299 {
4300     MSIPACKAGE *package = param;
4301     LPCWSTR component, section, key, value, identifier;
4302     LPWSTR deformated_section, deformated_key, deformated_value, filename;
4303     MSICOMPONENT *comp;
4304     MSIRECORD *uirow;
4305     INT action;
4306 
4307     component = MSI_RecordGetString( row, 8 );
4308     comp = msi_get_loaded_component( package, component );
4309     if (!comp)
4310         return ERROR_SUCCESS;
4311 
4312     comp->Action = msi_get_component_action( package, comp );
4313     if (comp->Action != INSTALLSTATE_ABSENT)
4314     {
4315         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4316         return ERROR_SUCCESS;
4317     }
4318 
4319     identifier = MSI_RecordGetString( row, 1 );
4320     section = MSI_RecordGetString( row, 4 );
4321     key = MSI_RecordGetString( row, 5 );
4322     value = MSI_RecordGetString( row, 6 );
4323     action = MSI_RecordGetInteger( row, 7 );
4324 
4325     deformat_string( package, section, &deformated_section );
4326     deformat_string( package, key, &deformated_key );
4327     deformat_string( package, value, &deformated_value );
4328 
4329     if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4330     {
4331         filename = get_ini_file_name( package, row );
4332 
4333         TRACE("Removing key %s from section %s in %s\n",
4334                debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4335 
4336         if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4337         {
4338             WARN("Unable to remove key %u\n", GetLastError());
4339         }
4340         msi_free( filename );
4341     }
4342     else
4343         FIXME("Unsupported action %d\n", action);
4344 
4345 
4346     uirow = MSI_CreateRecord( 4 );
4347     MSI_RecordSetStringW( uirow, 1, identifier );
4348     MSI_RecordSetStringW( uirow, 2, deformated_section );
4349     MSI_RecordSetStringW( uirow, 3, deformated_key );
4350     MSI_RecordSetStringW( uirow, 4, deformated_value );
4351     msi_ui_actiondata( package, szRemoveIniValues, uirow );
4352     msiobj_release( &uirow->hdr );
4353 
4354     msi_free( deformated_key );
4355     msi_free( deformated_value );
4356     msi_free( deformated_section );
4357     return ERROR_SUCCESS;
4358 }
4359 
4360 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4361 {
4362     MSIPACKAGE *package = param;
4363     LPCWSTR component, section, key, value, identifier;
4364     LPWSTR deformated_section, deformated_key, deformated_value, filename;
4365     MSICOMPONENT *comp;
4366     MSIRECORD *uirow;
4367     INT action;
4368 
4369     component = MSI_RecordGetString( row, 8 );
4370     comp = msi_get_loaded_component( package, component );
4371     if (!comp)
4372         return ERROR_SUCCESS;
4373 
4374     comp->Action = msi_get_component_action( package, comp );
4375     if (comp->Action != INSTALLSTATE_LOCAL)
4376     {
4377         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4378         return ERROR_SUCCESS;
4379     }
4380 
4381     identifier = MSI_RecordGetString( row, 1 );
4382     section = MSI_RecordGetString( row, 4 );
4383     key = MSI_RecordGetString( row, 5 );
4384     value = MSI_RecordGetString( row, 6 );
4385     action = MSI_RecordGetInteger( row, 7 );
4386 
4387     deformat_string( package, section, &deformated_section );
4388     deformat_string( package, key, &deformated_key );
4389     deformat_string( package, value, &deformated_value );
4390 
4391     if (action == msidbIniFileActionRemoveLine)
4392     {
4393         filename = get_ini_file_name( package, row );
4394 
4395         TRACE("Removing key %s from section %s in %s\n",
4396                debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4397 
4398         if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4399         {
4400             WARN("Unable to remove key %u\n", GetLastError());
4401         }
4402         msi_free( filename );
4403     }
4404     else
4405         FIXME("Unsupported action %d\n", action);
4406 
4407     uirow = MSI_CreateRecord( 4 );
4408     MSI_RecordSetStringW( uirow, 1, identifier );
4409     MSI_RecordSetStringW( uirow, 2, deformated_section );
4410     MSI_RecordSetStringW( uirow, 3, deformated_key );
4411     MSI_RecordSetStringW( uirow, 4, deformated_value );
4412     msi_ui_actiondata( package, szRemoveIniValues, uirow );
4413     msiobj_release( &uirow->hdr );
4414 
4415     msi_free( deformated_key );
4416     msi_free( deformated_value );
4417     msi_free( deformated_section );
4418     return ERROR_SUCCESS;
4419 }
4420 
4421 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4422 {
4423     static const WCHAR query[] = {
4424         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4425         '`','I','n','i','F','i','l','e','`',0};
4426     static const WCHAR remove_query[] = {
4427         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4428         '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4429     MSIQUERY *view;
4430     UINT rc;
4431 
4432     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4433     if (rc == ERROR_SUCCESS)
4434     {
4435         rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4436         msiobj_release( &view->hdr );
4437         if (rc != ERROR_SUCCESS)
4438             return rc;
4439     }
4440     rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4441     if (rc == ERROR_SUCCESS)
4442     {
4443         rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4444         msiobj_release( &view->hdr );
4445         if (rc != ERROR_SUCCESS)
4446             return rc;
4447     }
4448     return ERROR_SUCCESS;
4449 }
4450 
4451 static void register_dll( const WCHAR *dll, BOOL unregister )
4452 {
4453     HMODULE hmod;
4454 
4455     hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4456     if (hmod)
4457     {
4458         HRESULT (WINAPI *func_ptr)( void );
4459         const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4460 
4461         func_ptr = (void *)GetProcAddress( hmod, func );
4462         if (func_ptr)
4463         {
4464             HRESULT hr = func_ptr();
4465             if (FAILED( hr ))
4466                 WARN("failed to register dll 0x%08x\n", hr);
4467         }
4468         else
4469             WARN("entry point %s not found\n", func);
4470         FreeLibrary( hmod );
4471         return;
4472     }
4473     WARN("failed to load library %u\n", GetLastError());
4474 }
4475 
4476 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4477 {
4478     MSIPACKAGE *package = param;
4479     LPCWSTR filename;
4480     MSIFILE *file;
4481     MSIRECORD *uirow;
4482 
4483     filename = MSI_RecordGetString( row, 1 );
4484     file = msi_get_loaded_file( package, filename );
4485     if (!file)
4486     {
4487         WARN("unable to find file %s\n", debugstr_w(filename));
4488         return ERROR_SUCCESS;
4489     }
4490     file->Component->Action = msi_get_component_action( package, file->Component );
4491     if (file->Component->Action != INSTALLSTATE_LOCAL)
4492     {
4493         TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4494         return ERROR_SUCCESS;
4495     }
4496 
4497     TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4498     register_dll( file->TargetPath, FALSE );
4499 
4500     uirow = MSI_CreateRecord( 2 );
4501     MSI_RecordSetStringW( uirow, 1, file->File );
4502     MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4503     msi_ui_actiondata( package, szSelfRegModules, uirow );
4504     msiobj_release( &uirow->hdr );
4505 
4506     return ERROR_SUCCESS;
4507 }
4508 
4509 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4510 {
4511     static const WCHAR query[] = {
4512         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4513         '`','S','e','l','f','R','e','g','`',0};
4514     MSIQUERY *view;
4515     UINT rc;
4516 
4517     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4518     if (rc != ERROR_SUCCESS)
4519         return ERROR_SUCCESS;
4520 
4521     rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4522     msiobj_release(&view->hdr);
4523     return rc;
4524 }
4525 
4526 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4527 {
4528     MSIPACKAGE *package = param;
4529     LPCWSTR filename;
4530     MSIFILE *file;
4531     MSIRECORD *uirow;
4532 
4533     filename = MSI_RecordGetString( row, 1 );
4534     file = msi_get_loaded_file( package, filename );
4535     if (!file)
4536     {
4537         WARN("unable to find file %s\n", debugstr_w(filename));
4538         return ERROR_SUCCESS;
4539     }
4540     file->Component->Action = msi_get_component_action( package, file->Component );
4541     if (file->Component->Action != INSTALLSTATE_ABSENT)
4542     {
4543         TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4544         return ERROR_SUCCESS;
4545     }
4546 
4547     TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4548     register_dll( file->TargetPath, TRUE );
4549 
4550     uirow = MSI_CreateRecord( 2 );
4551     MSI_RecordSetStringW( uirow, 1, file->File );
4552     MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4553     msi_ui_actiondata( package, szSelfUnregModules, uirow );
4554     msiobj_release( &uirow->hdr );
4555 
4556     return ERROR_SUCCESS;
4557 }
4558 
4559 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4560 {
4561     static const WCHAR query[] = {
4562         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4563         '`','S','e','l','f','R','e','g','`',0};
4564     MSIQUERY *view;
4565     UINT rc;
4566 
4567     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4568     if (rc != ERROR_SUCCESS)
4569         return ERROR_SUCCESS;
4570 
4571     rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4572     msiobj_release( &view->hdr );
4573     return rc;
4574 }
4575 
4576 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4577 {
4578     MSIFEATURE *feature;
4579     UINT rc;
4580     HKEY hkey = NULL, userdata = NULL;
4581 
4582     if (!msi_check_publish(package))
4583         return ERROR_SUCCESS;
4584 
4585     rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4586                                 &hkey, TRUE);
4587     if (rc != ERROR_SUCCESS)
4588         goto end;
4589 
4590     rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4591                                         &userdata, TRUE);
4592     if (rc != ERROR_SUCCESS)
4593         goto end;
4594 
4595     /* here the guids are base 85 encoded */
4596     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4597     {
4598         ComponentList *cl;
4599         LPWSTR data = NULL;
4600         GUID clsid;
4601         INT size;
4602         BOOL absent = FALSE;
4603         MSIRECORD *uirow;
4604 
4605         if (feature->Action != INSTALLSTATE_LOCAL &&
4606             feature->Action != INSTALLSTATE_SOURCE &&
4607             feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4608 
4609         size = 1;
4610         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4611         {
4612             size += 21;
4613         }
4614         if (feature->Feature_Parent)
4615             size += strlenW( feature->Feature_Parent )+2;
4616 
4617         data = msi_alloc(size * sizeof(WCHAR));
4618 
4619         data[0] = 0;
4620         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4621         {
4622             MSICOMPONENT* component = cl->component;
4623             WCHAR buf[21];
4624 
4625             buf[0] = 0;
4626             if (component->ComponentId)
4627             {
4628                 TRACE("From %s\n",debugstr_w(component->ComponentId));
4629                 CLSIDFromString(component->ComponentId, &clsid);
4630                 encode_base85_guid(&clsid,buf);
4631                 TRACE("to %s\n",debugstr_w(buf));
4632                 strcatW(data,buf);
4633             }
4634         }
4635 
4636         if (feature->Feature_Parent)
4637         {
4638             static const WCHAR sep[] = {'\2',0};
4639             strcatW(data,sep);
4640             strcatW(data,feature->Feature_Parent);
4641         }
4642 
4643         msi_reg_set_val_str( userdata, feature->Feature, data );
4644         msi_free(data);
4645 
4646         size = 0;
4647         if (feature->Feature_Parent)
4648             size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4649         if (!absent)
4650         {
4651             size += sizeof(WCHAR);
4652             RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4653                            (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4654         }
4655         else
4656         {
4657             size += 2*sizeof(WCHAR);
4658             data = msi_alloc(size);
4659             data[0] = 0x6;
4660             data[1] = 0;
4661             if (feature->Feature_Parent)
4662                 strcpyW( &data[1], feature->Feature_Parent );
4663             RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4664                        (LPBYTE)data,size);
4665             msi_free(data);
4666         }
4667 
4668         /* the UI chunk */
4669         uirow = MSI_CreateRecord( 1 );
4670         MSI_RecordSetStringW( uirow, 1, feature->Feature );
4671         msi_ui_actiondata( package, szPublishFeatures, uirow );
4672         msiobj_release( &uirow->hdr );
4673         /* FIXME: call msi_ui_progress? */
4674     }
4675 
4676 end:
4677     RegCloseKey(hkey);
4678     RegCloseKey(userdata);
4679     return rc;
4680 }
4681 
4682 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4683 {
4684     UINT r;
4685     HKEY hkey;
4686     MSIRECORD *uirow;
4687 
4688     TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4689 
4690     r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4691                                &hkey, FALSE);
4692     if (r == ERROR_SUCCESS)
4693     {
4694         RegDeleteValueW(hkey, feature->Feature);
4695         RegCloseKey(hkey);
4696     }
4697 
4698     r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4699                                        &hkey, FALSE);
4700     if (r == ERROR_SUCCESS)
4701     {
4702         RegDeleteValueW(hkey, feature->Feature);
4703         RegCloseKey(hkey);
4704     }
4705 
4706     uirow = MSI_CreateRecord( 1 );
4707     MSI_RecordSetStringW( uirow, 1, feature->Feature );
4708     msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4709     msiobj_release( &uirow->hdr );
4710 
4711     return ERROR_SUCCESS;
4712 }
4713 
4714 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4715 {
4716     MSIFEATURE *feature;
4717 
4718     if (!msi_check_unpublish(package))
4719         return ERROR_SUCCESS;
4720 
4721     LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4722     {
4723         msi_unpublish_feature(package, feature);
4724     }
4725 
4726     return ERROR_SUCCESS;
4727 }
4728 
4729 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4730 {
4731     SYSTEMTIME systime;
4732     DWORD size, langid;
4733     WCHAR date[9], *val, *buffer;
4734     const WCHAR *prop, *key;
4735 
4736     static const WCHAR date_fmt[] = {'%','i','%','','2','i','%','','2','i',0};
4737     static const WCHAR modpath_fmt[] =
4738         {'M','s','i','E','x','e','c','.','e','x','e',' ',
4739          '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4740     static const WCHAR szModifyPath[] =
4741         {'M','o','d','i','f','y','P','a','t','h',0};
4742     static const WCHAR szUninstallString[] =
4743         {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4744     static const WCHAR szEstimatedSize[] =
4745         {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4746     static const WCHAR szDisplayVersion[] =
4747         {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4748     static const WCHAR szInstallSource[] =
4749         {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4750     static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4751         {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4752     static const WCHAR szAuthorizedCDFPrefix[] =
4753         {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4754     static const WCHAR szARPCONTACT[] =
4755         {'A','R','P','C','O','N','T','A','C','T',0};
4756     static const WCHAR szContact[] =
4757         {'C','o','n','t','a','c','t',0};
4758     static const WCHAR szARPCOMMENTS[] =
4759         {'A','R','P','C','O','M','M','E','N','T','S',0};
4760     static const WCHAR szComments[] =
4761         {'C','o','m','m','e','n','t','s',0};
4762     static const WCHAR szProductName[] =
4763         {'P','r','o','d','u','c','t','N','a','m','e',0};
4764     static const WCHAR szDisplayName[] =
4765         {'D','i','s','p','l','a','y','N','a','m','e',0};
4766     static const WCHAR szARPHELPLINK[] =
4767         {'A','R','P','H','E','L','P','L','I','N','K',0};
4768     static const WCHAR szHelpLink[] =
4769         {'H','e','l','p','L','i','n','k',0};
4770     static const WCHAR szARPHELPTELEPHONE[] =
4771         {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4772     static const WCHAR szHelpTelephone[] =
4773         {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4774     static const WCHAR szARPINSTALLLOCATION[] =
4775         {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4776     static const WCHAR szInstallLocation[] =
4777         {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4778     static const WCHAR szManufacturer[] =
4779         {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4780     static const WCHAR szPublisher[] =
4781         {'P','u','b','l','i','s','h','e','r',0};
4782     static const WCHAR szARPREADME[] =
4783         {'A','R','P','R','E','A','D','M','E',0};
4784     static const WCHAR szReadme[] =
4785         {'R','e','a','d','M','e',0};
4786     static const WCHAR szARPSIZE[] =
4787         {'A','R','P','S','I','Z','E',0};
4788     static const WCHAR szSize[] =
4789         {'S','i','z','e',0};
4790     static const WCHAR szARPURLINFOABOUT[] =
4791         {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4792     static const WCHAR szURLInfoAbout[] =
4793         {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4794     static const WCHAR szARPURLUPDATEINFO[] =
4795         {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4796     static const WCHAR szURLUpdateInfo[] =
4797         {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4798     static const WCHAR szARPSYSTEMCOMPONENT[] =
4799         {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4800     static const WCHAR szSystemComponent[] =
4801         {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4802 
4803     static const WCHAR *propval[] = {
4804         szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4805         szARPCONTACT,             szContact,
4806         szARPCOMMENTS,            szComments,
4807         szProductName,            szDisplayName,
4808         szARPHELPLINK,            szHelpLink,
4809         szARPHELPTELEPHONE,       szHelpTelephone,
4810         szARPINSTALLLOCATION,     szInstallLocation,
4811         szSourceDir,              szInstallSource,
4812         szManufacturer,           szPublisher,
4813         szARPREADME,              szReadme,
4814         szARPSIZE,                szSize,
4815         szARPURLINFOABOUT,        szURLInfoAbout,
4816         szARPURLUPDATEINFO,       szURLUpdateInfo,
4817         NULL
4818     };
4819     const WCHAR **p = propval;
4820 
4821     while (*p)
4822     {
4823         prop = *p++;
4824         key = *p++;
4825         val = msi_dup_property(package->db, prop);
4826         msi_reg_set_val_str(hkey, key, val);
4827         msi_free(val);
4828     }
4829 
4830     msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4831     if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4832     {
4833         msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4834     }
4835     size = deformat_string(package, modpath_fmt, &buffer);
4836     RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4837     RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4838     msi_free(buffer);
4839 
4840     /* FIXME: Write real Estimated Size when we have it */
4841     msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4842 
4843     GetLocalTime(&systime);
4844     sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4845     msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4846 
4847     langid = msi_get_property_int(package->db, szProductLanguage, 0);
4848     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4849 
4850     buffer = msi_dup_property(package->db, szProductVersion);
4851     msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4852     if (buffer)
4853     {
4854         DWORD verdword = msi_version_str_to_dword(buffer);
4855 
4856         msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4857         msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4858         msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4859         msi_free(buffer);
4860     }
4861 
4862     return ERROR_SUCCESS;
4863 }
4864 
4865 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4866 {
4867     WCHAR squashed_pc[SQUISH_GUID_SIZE];
4868     MSIRECORD *uirow;
4869     LPWSTR upgrade_code;
4870     HKEY hkey, props, upgrade_key;
4871     UINT rc;
4872 
4873     /* FIXME: also need to publish if the product is in advertise mode */
4874     if (!msi_check_publish(package))
4875         return ERROR_SUCCESS;
4876 
4877     rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4878     if (rc != ERROR_SUCCESS)
4879         return rc;
4880 
4881     rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4882     if (rc != ERROR_SUCCESS)
4883         goto done;
4884 
4885     rc = msi_publish_install_properties(package, hkey);
4886     if (rc != ERROR_SUCCESS)
4887         goto done;
4888 
4889     rc = msi_publish_install_properties(package, props);
4890     if (rc != ERROR_SUCCESS)
4891         goto done;
4892 
4893     upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4894     if (upgrade_code)
4895     {
4896         rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4897         if (rc == ERROR_SUCCESS)
4898         {
4899             squash_guid( package->ProductCode, squashed_pc );
4900             msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4901             RegCloseKey( upgrade_key );
4902         }
4903         msi_free( upgrade_code );
4904     }
4905     msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4906     package->delete_on_close = FALSE;
4907 
4908 done:
4909     uirow = MSI_CreateRecord( 1 );
4910     MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4911     msi_ui_actiondata( package, szRegisterProduct, uirow );
4912     msiobj_release( &uirow->hdr );
4913 
4914     RegCloseKey(hkey);
4915     return ERROR_SUCCESS;
4916 }
4917 
4918 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4919 {
4920     return execute_script(package, SCRIPT_INSTALL);
4921 }
4922 
4923 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
4924 {
4925     MSIPACKAGE *package = param;
4926     const WCHAR *icon = MSI_RecordGetString( row, 1 );
4927     WCHAR *p, *icon_path;
4928 
4929     if (!icon) return ERROR_SUCCESS;
4930     if ((icon_path = msi_build_icon_path( package, icon )))
4931     {
4932         TRACE("removing icon file %s\n", debugstr_w(icon_path));
4933         DeleteFileW( icon_path );
4934         if ((p = strrchrW( icon_path, '\\' )))
4935         {
4936             *p = 0;
4937             RemoveDirectoryW( icon_path );
4938         }
4939         msi_free( icon_path );
4940     }
4941     return ERROR_SUCCESS;
4942 }
4943 
4944 static UINT msi_unpublish_icons( MSIPACKAGE *package )
4945 {
4946     static const WCHAR query[]= {
4947         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
4948     MSIQUERY *view;
4949     UINT r;
4950 
4951     r = MSI_DatabaseOpenViewW( package->db, query, &view );
4952     if (r == ERROR_SUCCESS)
4953     {
4954         r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
4955         msiobj_release( &view->hdr );
4956         if (r != ERROR_SUCCESS)
4957             return r;
4958     }
4959     return ERROR_SUCCESS;
4960 }
4961 
4962 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
4963 {
4964     static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
4965     WCHAR *upgrade, **features;
4966     BOOL full_uninstall = TRUE;
4967     MSIFEATURE *feature;
4968     MSIPATCHINFO *patch;
4969     UINT i;
4970 
4971     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4972     {
4973         if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
4974     }
4975     features = msi_split_string( remove, ',' );
4976     for (i = 0; features && features[i]; i++)
4977     {
4978         if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
4979     }
4980     msi_free(features);
4981 
4982     if (!full_uninstall)
4983         return ERROR_SUCCESS;
4984 
4985     MSIREG_DeleteProductKey(package->ProductCode);
4986     MSIREG_DeleteUserDataProductKey(package->ProductCode);
4987     MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
4988 
4989     MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4990     MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4991     MSIREG_DeleteUserProductKey(package->ProductCode);
4992     MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4993 
4994     upgrade = msi_dup_property(package->db, szUpgradeCode);
4995     if (upgrade)
4996     {
4997         MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4998         MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
4999         msi_free(upgrade);
5000     }
5001 
5002     LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5003     {
5004         MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5005         if (!strcmpW( package->ProductCode, patch->products ))
5006         {
5007             TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
5008             patch->delete_on_close = TRUE;
5009         }
5010         /* FIXME: remove local patch package if this is the last product */
5011     }
5012     TRACE("removing local package %s\n", debugstr_w(package->localfile));
5013     package->delete_on_close = TRUE;
5014 
5015     msi_unpublish_icons( package );
5016     return ERROR_SUCCESS;
5017 }
5018 
5019 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5020 {
5021     UINT rc;
5022     WCHAR *remove;
5023 
5024     /* turn off scheduling */
5025     package->script->CurrentlyScripting= FALSE;
5026 
5027     /* first do the same as an InstallExecute */
5028     rc = ACTION_InstallExecute(package);
5029     if (rc != ERROR_SUCCESS)
5030         return rc;
5031 
5032     /* then handle commit actions */
5033     rc = execute_script(package, SCRIPT_COMMIT);
5034     if (rc != ERROR_SUCCESS)
5035         return rc;
5036 
5037     remove = msi_dup_property(package->db, szRemove);
5038     rc = msi_unpublish_product(package, remove);
5039     msi_free(remove);
5040     return rc;
5041 }
5042 
5043 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5044 {
5045     static const WCHAR RunOnce[] = {
5046     'S','o','f','t','w','a','r','e','\\',
5047     'M','i','c','r','o','s','o','f','t','\\',
5048     'W','i','n','d','o','w','s','\\',
5049     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5050     'R','u','n','O','n','c','e',0};
5051     static const WCHAR InstallRunOnce[] = {
5052     'S','o','f','t','w','a','r','e','\\',
5053     'M','i','c','r','o','s','o','f','t','\\',
5054     'W','i','n','d','o','w','s','\\',
5055     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5056     'I','n','s','t','a','l','l','e','r','\\',
5057     'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5058 
5059     static const WCHAR msiexec_fmt[] = {
5060     '%','s',
5061     '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5062     '\"','%','s','\"',0};
5063     static const WCHAR install_fmt[] = {
5064     '/','I',' ','\"','%','s','\"',' ',
5065     'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5066     'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5067     WCHAR buffer[256], sysdir[MAX_PATH];
5068     HKEY hkey;
5069     WCHAR squished_pc[100];
5070 
5071     squash_guid(package->ProductCode,squished_pc);
5072 
5073     GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5074     RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5075     snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5076      squished_pc);
5077 
5078     msi_reg_set_val_str( hkey, squished_pc, buffer );
5079     RegCloseKey(hkey);
5080 
5081     TRACE("Reboot command %s\n",debugstr_w(buffer));
5082 
5083     RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5084     sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5085 
5086     msi_reg_set_val_str( hkey, squished_pc, buffer );
5087     RegCloseKey(hkey);
5088 
5089     return ERROR_INSTALL_SUSPEND;
5090 }
5091 
5092 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5093 {
5094     static const WCHAR query[] =
5095         {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5096          'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5097          '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5098     MSIRECORD *rec, *row;
5099     DWORD i, size = 0;
5100     va_list va;
5101     const WCHAR *str;
5102     WCHAR *data;
5103 
5104     if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5105 
5106     rec = MSI_CreateRecord( count + 2 );
5107     str = MSI_RecordGetString( row, 1 );
5108     MSI_RecordSetStringW( rec, 0, str );
5109     msiobj_release( &row->hdr );
5110     MSI_RecordSetInteger( rec, 1, error );
5111 
5112     va_start( va, count );
5113     for (i = 0; i < count; i++)
5114     {
5115         str = va_arg( va, const WCHAR *);
5116         MSI_RecordSetStringW( rec, i + 2, str );
5117     }
5118     va_end( va );
5119 
5120     MSI_FormatRecordW( package, rec, NULL, &size );
5121     size++;
5122     data = msi_alloc( size * sizeof(WCHAR) );
5123     if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5124     else data[0] = 0;
5125     msiobj_release( &rec->hdr );
5126     return data;
5127 }
5128 
5129 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5130 {
5131     DWORD attrib;
5132     UINT rc;
5133 
5134     /*
5135      * We are currently doing what should be done here in the top level Install
5136      * however for Administrative and uninstalls this step will be needed
5137      */
5138     if (!package->PackagePath)
5139         return ERROR_SUCCESS;
5140 
5141     msi_set_sourcedir_props(package, TRUE);
5142 
5143     attrib = GetFileAttributesW(package->db->path);
5144     if (attrib == INVALID_FILE_ATTRIBUTES)
5145     {
5146         LPWSTR prompt, msg;
5147         DWORD size = 0;
5148 
5149         rc = MsiSourceListGetInfoW(package->ProductCode, NULL, 
5150                 package->Context, MSICODE_PRODUCT,
5151                 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5152         if (rc == ERROR_MORE_DATA)
5153         {
5154             prompt = msi_alloc(size * sizeof(WCHAR));
5155             MsiSourceListGetInfoW(package->ProductCode, NULL, 
5156                     package->Context, MSICODE_PRODUCT,
5157                     INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5158         }
5159         else
5160             prompt = strdupW(package->db->path);
5161 
5162         msg = msi_build_error_string(package, 1302, 1, prompt);
5163         msi_free(prompt);
5164         while(attrib == INVALID_FILE_ATTRIBUTES)
5165         {
5166             rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
5167             if (rc == IDCANCEL)
5168             {
5169                 msi_free(msg);
5170                 return ERROR_INSTALL_USEREXIT;
5171             }
5172             attrib = GetFileAttributesW(package->db->path);
5173         }
5174         msi_free(msg);
5175         rc = ERROR_SUCCESS;
5176     }
5177     else
5178         return ERROR_SUCCESS;
5179 
5180     return rc;
5181 }
5182 
5183 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5184 {
5185     HKEY hkey = 0;
5186     LPWSTR buffer, productid = NULL;
5187     UINT i, rc = ERROR_SUCCESS;
5188     MSIRECORD *uirow;
5189 
5190     static const WCHAR szPropKeys[][80] = 
5191     {
5192         {'P','r','o','d','u','c','t','I','D',0},
5193         {'U','S','E','R','N','A','M','E',0},
5194         {'C','O','M','P','A','N','Y','N','A','M','E',0},
5195         {0},
5196     };
5197 
5198     static const WCHAR szRegKeys[][80] = 
5199     {
5200         {'P','r','o','d','u','c','t','I','D',0},
5201         {'R','e','g','O','w','n','e','r',0},
5202         {'R','e','g','C','o','m','p','a','n','y',0},
5203         {0},
5204     };
5205 
5206     if (msi_check_unpublish(package))
5207     {
5208         MSIREG_DeleteUserDataProductKey(package->ProductCode);
5209         goto end;
5210     }
5211 
5212     productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5213     if (!productid)
5214         goto end;
5215 
5216     rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5217                                  NULL, &hkey, TRUE);
5218     if (rc != ERROR_SUCCESS)
5219         goto end;
5220 
5221     for( i = 0; szPropKeys[i][0]; i++ )
5222     {
5223         buffer = msi_dup_property( package->db, szPropKeys[i] );
5224         msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5225         msi_free( buffer );
5226     }
5227 
5228 end:
5229     uirow = MSI_CreateRecord( 1 );
5230     MSI_RecordSetStringW( uirow, 1, productid );
5231     msi_ui_actiondata( package, szRegisterUser, uirow );
5232     msiobj_release( &uirow->hdr );
5233 
5234     msi_free(productid);
5235     RegCloseKey(hkey);
5236     return rc;
5237 }
5238 
5239 
5240 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5241 {
5242     UINT rc;
5243 
5244     package->script->InWhatSequence |= SEQUENCE_EXEC;
5245     rc = ACTION_ProcessExecSequence(package,FALSE);
5246     return rc;
5247 }
5248 
5249 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5250 {
5251     static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5252     WCHAR productid_85[21], component_85[21], *ret;
5253     GUID clsid;
5254     DWORD sz;
5255 
5256     /* > is used if there is a component GUID and < if not.  */
5257 
5258     productid_85[0] = 0;
5259     component_85[0] = 0;
5260     CLSIDFromString( package->ProductCode, &clsid );
5261 
5262     encode_base85_guid( &clsid, productid_85 );
5263     if (component)
5264     {
5265         CLSIDFromString( component->ComponentId, &clsid );
5266         encode_base85_guid( &clsid, component_85 );
5267     }
5268 
5269     TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5270           debugstr_w(component_85));
5271 
5272     sz = 20 + strlenW( feature ) + 20 + 3;
5273     ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5274     if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5275     return ret;
5276 }
5277 
5278 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5279 {
5280     MSIPACKAGE *package = param;
5281     LPCWSTR compgroupid, component, feature, qualifier, text;
5282     LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5283     HKEY hkey = NULL;
5284     UINT rc;
5285     MSICOMPONENT *comp;
5286     MSIFEATURE *feat;
5287     DWORD sz;
5288     MSIRECORD *uirow;
5289     int len;
5290 
5291     feature = MSI_RecordGetString(rec, 5);
5292     feat = msi_get_loaded_feature(package, feature);
5293     if (!feat)
5294         return ERROR_SUCCESS;
5295 
5296     feat->Action = msi_get_feature_action( package, feat );
5297     if (feat->Action != INSTALLSTATE_LOCAL &&
5298         feat->Action != INSTALLSTATE_SOURCE &&
5299         feat->Action != INSTALLSTATE_ADVERTISED)
5300     {
5301         TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5302         return ERROR_SUCCESS;
5303     }
5304 
5305     component = MSI_RecordGetString(rec, 3);
5306     comp = msi_get_loaded_component(package, component);
5307     if (!comp)
5308         return ERROR_SUCCESS;
5309 
5310     compgroupid = MSI_RecordGetString(rec,1);
5311     qualifier = MSI_RecordGetString(rec,2);
5312 
5313     rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5314     if (rc != ERROR_SUCCESS)
5315         goto end;
5316 
5317     advertise = msi_create_component_advertise_string( package, comp, feature );
5318     text = MSI_RecordGetString( rec, 4 );
5319     if (text)
5320     {
5321         p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5322         strcpyW( p, advertise );
5323         strcatW( p, text );
5324         msi_free( advertise );
5325         advertise = p;
5326     }
5327     existing = msi_reg_get_val_str( hkey, qualifier );
5328 
5329     sz = strlenW( advertise ) + 1;
5330     if (existing)
5331     {
5332         for (p = existing; *p; p += len)
5333         {
5334             len = strlenW( p ) + 1;
5335             if (strcmpW( advertise, p )) sz += len;
5336         }
5337     }
5338     if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5339     {
5340         rc = ERROR_OUTOFMEMORY;
5341         goto end;
5342     }
5343     q = output;
5344     if (existing)
5345     {
5346         for (p = existing; *p; p += len)
5347         {
5348             len = strlenW( p ) + 1;
5349             if (strcmpW( advertise, p ))
5350             {
5351                 memcpy( q, p, len * sizeof(WCHAR) );
5352                 q += len;
5353             }
5354         }
5355     }
5356     strcpyW( q, advertise );
5357     q[strlenW( q ) + 1] = 0;
5358 
5359     msi_reg_set_val_multi_str( hkey, qualifier, output );
5360     
5361 end:
5362     RegCloseKey(hkey);
5363     msi_free( output );
5364     msi_free( advertise );
5365     msi_free( existing );
5366 
5367     /* the UI chunk */
5368     uirow = MSI_CreateRecord( 2 );
5369     MSI_RecordSetStringW( uirow, 1, compgroupid );
5370     MSI_RecordSetStringW( uirow, 2, qualifier);
5371     msi_ui_actiondata( package, szPublishComponents, uirow );
5372     msiobj_release( &uirow->hdr );
5373     /* FIXME: call ui_progress? */
5374 
5375     return rc;
5376 }
5377 
5378 /*
5379  * At present I am ignorning the advertised components part of this and only
5380  * focusing on the qualified component sets
5381  */
5382 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5383 {
5384     static const WCHAR query[] = {
5385         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5386         '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5387     MSIQUERY *view;
5388     UINT rc;
5389     
5390     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5391     if (rc != ERROR_SUCCESS)
5392         return ERROR_SUCCESS;
5393 
5394     rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5395     msiobj_release(&view->hdr);
5396     return rc;
5397 }
5398 
5399 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5400 {
5401     static const WCHAR szInstallerComponents[] = {
5402         'S','o','f','t','w','a','r','e','\\',
5403         'M','i','c','r','o','s','o','f','t','\\',
5404         'I','n','s','t','a','l','l','e','r','\\',
5405         'C','o','m','p','o','n','e','n','t','s','\\',0};
5406 
5407     MSIPACKAGE *package = param;
5408     LPCWSTR compgroupid, component, feature, qualifier;
5409     MSICOMPONENT *comp;
5410     MSIFEATURE *feat;
5411     MSIRECORD *uirow;
5412     WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5413     LONG res;
5414 
5415     feature = MSI_RecordGetString( rec, 5 );
5416     feat = msi_get_loaded_feature( package, feature );
5417     if (!feat)
5418         return ERROR_SUCCESS;
5419 
5420     feat->Action = msi_get_feature_action( package, feat );
5421     if (feat->Action != INSTALLSTATE_ABSENT)
5422     {
5423         TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5424         return ERROR_SUCCESS;
5425     }
5426 
5427     component = MSI_RecordGetString( rec, 3 );
5428     comp = msi_get_loaded_component( package, component );
5429     if (!comp)
5430         return ERROR_SUCCESS;
5431 
5432     compgroupid = MSI_RecordGetString( rec, 1 );
5433     qualifier = MSI_RecordGetString( rec, 2 );
5434 
5435     squash_guid( compgroupid, squashed );
5436     strcpyW( keypath, szInstallerComponents );
5437     strcatW( keypath, squashed );
5438 
5439     res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5440     if (res != ERROR_SUCCESS)
5441     {
5442         WARN("Unable to delete component key %d\n", res);
5443     }
5444 
5445     uirow = MSI_CreateRecord( 2 );
5446     MSI_RecordSetStringW( uirow, 1, compgroupid );
5447     MSI_RecordSetStringW( uirow, 2, qualifier );
5448     msi_ui_actiondata( package, szUnpublishComponents, uirow );
5449     msiobj_release( &uirow->hdr );
5450 
5451     return ERROR_SUCCESS;
5452 }
5453 
5454 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5455 {
5456     static const WCHAR query[] = {
5457         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5458         '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5459     MSIQUERY *view;
5460     UINT rc;
5461 
5462     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5463     if (rc != ERROR_SUCCESS)
5464         return ERROR_SUCCESS;
5465 
5466     rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5467     msiobj_release( &view->hdr );
5468     return rc;
5469 }
5470 
5471 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5472 {
5473     static const WCHAR query[] =
5474         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5475          '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5476          '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5477     MSIPACKAGE *package = param;
5478     MSICOMPONENT *component;
5479     MSIRECORD *row;
5480     MSIFILE *file;
5481     SC_HANDLE hscm = NULL, service = NULL;
5482     LPCWSTR comp, key;
5483     LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5484     LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5485     DWORD serv_type, start_type, err_control;
5486     SERVICE_DESCRIPTIONW sd = {NULL};
5487 
5488     comp = MSI_RecordGetString( rec, 12 );
5489     component = msi_get_loaded_component( package, comp );
5490     if (!component)
5491     {
5492         WARN("service component not found\n");
5493         goto done;
5494     }
5495     component->Action = msi_get_component_action( package, component );
5496     if (component->Action != INSTALLSTATE_LOCAL)
5497     {
5498         TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5499         goto done;
5500     }
5501     hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5502     if (!hscm)
5503     {
5504         ERR("Failed to open the SC Manager!\n");
5505         goto done;
5506     }
5507 
5508     start_type = MSI_RecordGetInteger(rec, 5);
5509     if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5510         goto done;
5511 
5512     deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5513     deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5514     serv_type = MSI_RecordGetInteger(rec, 4);
5515     err_control = MSI_RecordGetInteger(rec, 6);
5516     deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5517     deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5518     deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5519     deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5520     deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5521     deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5522 
5523     /* fetch the service path */
5524     row = MSI_QueryGetRecord(package->db, query, comp);
5525     if (!row)
5526     {
5527         ERR("Query failed\n");
5528         goto done;
5529     }
5530     key = MSI_RecordGetString(row, 6);
5531     file = msi_get_loaded_file(package, key);
5532     msiobj_release(&row->hdr);
5533     if (!file)
5534     {
5535         ERR("Failed to load the service file\n");
5536         goto done;
5537     }
5538 
5539     if (!args || !args[0]) image_path = file->TargetPath;
5540     else
5541     {
5542         int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5543         if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5544             return ERROR_OUTOFMEMORY;
5545 
5546         strcpyW(image_path, file->TargetPath);
5547         strcatW(image_path, szSpace);
5548         strcatW(image_path, args);
5549     }
5550     service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5551                              start_type, err_control, image_path, load_order,
5552                              NULL, depends, serv_name, pass);
5553 
5554     if (!service)
5555     {
5556         if (GetLastError() != ERROR_SERVICE_EXISTS)
5557             ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5558     }
5559     else if (sd.lpDescription)
5560     {
5561         if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5562             WARN("failed to set service description %u\n", GetLastError());
5563     }
5564 
5565     if (image_path != file->TargetPath) msi_free(image_path);
5566 done:
5567     CloseServiceHandle(service);
5568     CloseServiceHandle(hscm);
5569     msi_free(name);
5570     msi_free(disp);
5571     msi_free(sd.lpDescription);
5572     msi_free(load_order);
5573     msi_free(serv_name);
5574     msi_free(pass);
5575     msi_free(depends);
5576     msi_free(args);
5577 
5578     return ERROR_SUCCESS;
5579 }
5580 
5581 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5582 {
5583     static const WCHAR query[] = {
5584         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5585         'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5586     MSIQUERY *view;
5587     UINT rc;
5588     
5589     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5590     if (rc != ERROR_SUCCESS)
5591         return ERROR_SUCCESS;
5592 
5593     rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5594     msiobj_release(&view->hdr);
5595     return rc;
5596 }
5597 
5598 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5599 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5600 {
5601     LPCWSTR *vector, *temp_vector;
5602     LPWSTR p, q;
5603     DWORD sep_len;
5604 
5605     static const WCHAR separator[] = {'[','~',']',0};
5606 
5607     *numargs = 0;
5608     sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5609 
5610     if (!args)
5611         return NULL;
5612 
5613     vector = msi_alloc(sizeof(LPWSTR));
5614     if (!vector)
5615         return NULL;
5616 
5617     p = args;
5618     do
5619     {
5620         (*numargs)++;
5621         vector[*numargs - 1] = p;
5622 
5623         if ((q = strstrW(p, separator)))
5624         {
5625             *q = '\0';
5626 
5627             temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5628             if (!temp_vector)
5629             {
5630                 msi_free(vector);
5631                 return NULL;
5632             }
5633             vector = temp_vector;
5634 
5635             p = q + sep_len;
5636         }
5637     } while (q);
5638 
5639     return vector;
5640 }
5641 
5642 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5643 {
5644     MSIPACKAGE *package = param;
5645     MSICOMPONENT *comp;
5646     MSIRECORD *uirow;
5647     SC_HANDLE scm = NULL, service = NULL;
5648     LPCWSTR component, *vector = NULL;
5649     LPWSTR name, args, display_name = NULL;
5650     DWORD event, numargs, len, wait, dummy;
5651     UINT r = ERROR_FUNCTION_FAILED;
5652     SERVICE_STATUS_PROCESS status;
5653     ULONGLONG start_time;
5654 
5655     component = MSI_RecordGetString(rec, 6);
5656     comp = msi_get_loaded_component(package, component);
5657     if (!comp)
5658         return ERROR_SUCCESS;
5659 
5660     comp->Action = msi_get_component_action( package, comp );
5661     if (comp->Action != INSTALLSTATE_LOCAL)
5662     {
5663         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5664         return ERROR_SUCCESS;
5665     }
5666 
5667     deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5668     deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5669     event = MSI_RecordGetInteger(rec, 3);
5670     wait = MSI_RecordGetInteger(rec, 5);
5671 
5672     if (!(event & msidbServiceControlEventStart))
5673     {
5674         r = ERROR_SUCCESS;
5675         goto done;
5676     }
5677 
5678     scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5679     if (!scm)
5680     {
5681         ERR("Failed to open the service control manager\n");
5682         goto done;
5683     }
5684 
5685     len = 0;
5686     if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5687         GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5688     {
5689         if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5690             GetServiceDisplayNameW( scm, name, display_name, &len );
5691     }
5692 
5693     service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS);
5694     if (!service)
5695     {
5696         ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5697         goto done;
5698     }
5699 
5700     vector = msi_service_args_to_vector(args, &numargs);
5701 
5702     if (!StartServiceW(service, numargs, vector) &&
5703         GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5704     {
5705         ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5706         goto done;
5707     }
5708 
5709     r = ERROR_SUCCESS;
5710     if (wait)
5711     {
5712         /* wait for at most 30 seconds for the service to be up and running */
5713         if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5714             (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5715         {
5716             TRACE("failed to query service status (%u)\n", GetLastError());
5717             goto done;
5718         }
5719         start_time = GetTickCount64();
5720         while (status.dwCurrentState == SERVICE_START_PENDING)
5721         {
5722             if (GetTickCount64() - start_time > 30000) break;
5723             Sleep(1000);
5724             if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5725                 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5726             {
5727                 TRACE("failed to query service status (%u)\n", GetLastError());
5728                 goto done;
5729             }
5730         }
5731         if (status.dwCurrentState != SERVICE_RUNNING)
5732         {
5733             WARN("service failed to start %u\n", status.dwCurrentState);
5734             r = ERROR_FUNCTION_FAILED;
5735         }
5736     }
5737 
5738 done:
5739     uirow = MSI_CreateRecord( 2 );
5740     MSI_RecordSetStringW( uirow, 1, display_name );
5741     MSI_RecordSetStringW( uirow, 2, name );
5742     msi_ui_actiondata( package, szStartServices, uirow );
5743     msiobj_release( &uirow->hdr );
5744 
5745     CloseServiceHandle(service);
5746     CloseServiceHandle(scm);
5747 
5748     msi_free(name);
5749     msi_free(args);
5750     msi_free(vector);
5751     msi_free(display_name);
5752     return r;
5753 }
5754 
5755 static UINT ACTION_StartServices( MSIPACKAGE *package )
5756 {
5757     static const WCHAR query[] = {
5758         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5759         'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5760     MSIQUERY *view;
5761     UINT rc;
5762 
5763     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5764     if (rc != ERROR_SUCCESS)
5765         return ERROR_SUCCESS;
5766 
5767     rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5768     msiobj_release(&view->hdr);
5769     return rc;
5770 }
5771 
5772 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5773 {
5774     DWORD i, needed, count;
5775     ENUM_SERVICE_STATUSW *dependencies;
5776     SERVICE_STATUS ss;
5777     SC_HANDLE depserv;
5778 
5779     if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5780                                0, &needed, &count))
5781         return TRUE;
5782 
5783     if (GetLastError() != ERROR_MORE_DATA)
5784         return FALSE;
5785 
5786     dependencies = msi_alloc(needed);
5787     if (!dependencies)
5788         return FALSE;
5789 
5790     if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5791                                 needed, &needed, &count))
5792         goto error;
5793 
5794     for (i = 0; i < count; i++)
5795     {
5796         depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5797                                SERVICE_STOP | SERVICE_QUERY_STATUS);
5798         if (!depserv)
5799             goto error;
5800 
5801         if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5802             goto error;
5803     }
5804 
5805     return TRUE;
5806 
5807 error:
5808     msi_free(dependencies);
5809     return FALSE;
5810 }
5811 
5812 static UINT stop_service( LPCWSTR name )
5813 {
5814     SC_HANDLE scm = NULL, service = NULL;
5815     SERVICE_STATUS status;
5816     SERVICE_STATUS_PROCESS ssp;
5817     DWORD needed;
5818 
5819     scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5820     if (!scm)
5821     {
5822         WARN("Failed to open the SCM: %d\n", GetLastError());
5823         goto done;
5824     }
5825 
5826     service = OpenServiceW(scm, name,
5827                            SERVICE_STOP |
5828                            SERVICE_QUERY_STATUS |
5829                            SERVICE_ENUMERATE_DEPENDENTS);
5830     if (!service)
5831     {
5832         WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5833         goto done;
5834     }
5835 
5836     if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5837                               sizeof(SERVICE_STATUS_PROCESS), &needed))
5838     {
5839         WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5840         goto done;
5841     }
5842 
5843     if (ssp.dwCurrentState == SERVICE_STOPPED)
5844         goto done;
5845 
5846     stop_service_dependents(scm, service);
5847 
5848     if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5849         WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5850 
5851 done:
5852     CloseServiceHandle(service);
5853     CloseServiceHandle(scm);
5854 
5855     return ERROR_SUCCESS;
5856 }
5857 
5858 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5859 {
5860     MSIPACKAGE *package = param;
5861     MSICOMPONENT *comp;
5862     MSIRECORD *uirow;
5863     LPCWSTR component;
5864     LPWSTR name = NULL, display_name = NULL;
5865     DWORD event, len;
5866     SC_HANDLE scm;
5867 
5868     event = MSI_RecordGetInteger( rec, 3 );
5869     if (!(event & msidbServiceControlEventStop))
5870         return ERROR_SUCCESS;
5871 
5872     component = MSI_RecordGetString( rec, 6 );
5873     comp = msi_get_loaded_component( package, component );
5874     if (!comp)
5875         return ERROR_SUCCESS;
5876 
5877     comp->Action = msi_get_component_action( package, comp );
5878     if (comp->Action != INSTALLSTATE_ABSENT)
5879     {
5880         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5881         return ERROR_SUCCESS;
5882     }
5883 
5884     scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5885     if (!scm)
5886     {
5887         ERR("Failed to open the service control manager\n");
5888         goto done;
5889     }
5890 
5891     len = 0;
5892     if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5893         GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5894     {
5895         if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5896             GetServiceDisplayNameW( scm, name, display_name, &len );
5897     }
5898     CloseServiceHandle( scm );
5899 
5900     deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5901     stop_service( name );
5902 
5903 done:
5904     uirow = MSI_CreateRecord( 2 );
5905     MSI_RecordSetStringW( uirow, 1, display_name );
5906     MSI_RecordSetStringW( uirow, 2, name );
5907     msi_ui_actiondata( package, szStopServices, uirow );
5908     msiobj_release( &uirow->hdr );
5909 
5910     msi_free( name );
5911     msi_free( display_name );
5912     return ERROR_SUCCESS;
5913 }
5914 
5915 static UINT ACTION_StopServices( MSIPACKAGE *package )
5916 {
5917     static const WCHAR query[] = {
5918         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5919         'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5920     MSIQUERY *view;
5921     UINT rc;
5922 
5923     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5924     if (rc != ERROR_SUCCESS)
5925         return ERROR_SUCCESS;
5926 
5927     rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5928     msiobj_release(&view->hdr);
5929     return rc;
5930 }
5931 
5932 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5933 {
5934     MSIPACKAGE *package = param;
5935     MSICOMPONENT *comp;
5936     MSIRECORD *uirow;
5937     LPWSTR name = NULL, display_name = NULL;
5938     DWORD event, len;
5939     SC_HANDLE scm = NULL, service = NULL;
5940 
5941     comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) );
5942     if (!comp)
5943         return ERROR_SUCCESS;
5944 
5945     event = MSI_RecordGetInteger( rec, 3 );
5946     deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5947 
5948     comp->Action = msi_get_component_action( package, comp );
5949     if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) &&
5950         !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete)))
5951     {
5952         TRACE("service %s not scheduled for removal\n", debugstr_w(name));
5953         msi_free( name );
5954         return ERROR_SUCCESS;
5955     }
5956     stop_service( name );
5957 
5958     scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5959     if (!scm)
5960     {
5961         WARN("Failed to open the SCM: %d\n", GetLastError());
5962         goto done;
5963     }
5964 
5965     len = 0;
5966     if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5967         GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5968     {
5969         if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5970             GetServiceDisplayNameW( scm, name, display_name, &len );
5971     }
5972 
5973     service = OpenServiceW( scm, name, DELETE );
5974     if (!service)
5975     {
5976         WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5977         goto done;
5978     }
5979 
5980     if (!DeleteService( service ))
5981         WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5982 
5983 done:
5984     uirow = MSI_CreateRecord( 2 );
5985     MSI_RecordSetStringW( uirow, 1, display_name );
5986     MSI_RecordSetStringW( uirow, 2, name );
5987     msi_ui_actiondata( package, szDeleteServices, uirow );
5988     msiobj_release( &uirow->hdr );
5989 
5990     CloseServiceHandle( service );
5991     CloseServiceHandle( scm );
5992     msi_free( name );
5993     msi_free( display_name );
5994 
5995     return ERROR_SUCCESS;
5996 }
5997 
5998 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5999 {
6000     static const WCHAR query[] = {
6001         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6002         'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6003     MSIQUERY *view;
6004     UINT rc;
6005 
6006     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6007     if (rc != ERROR_SUCCESS)
6008         return ERROR_SUCCESS;
6009 
6010     rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6011     msiobj_release( &view->hdr );
6012     return rc;
6013 }
6014 
6015 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6016 {
6017     MSIPACKAGE *package = param;
6018     LPWSTR driver, driver_path, ptr;
6019     WCHAR outpath[MAX_PATH];
6020     MSIFILE *driver_file = NULL, *setup_file = NULL;
6021     MSICOMPONENT *comp;
6022     MSIRECORD *uirow;
6023     LPCWSTR desc, file_key, component;
6024     DWORD len, usage;
6025     UINT r = ERROR_SUCCESS;
6026 
6027     static const WCHAR driver_fmt[] = {
6028         'D','r','i','v','e','r','=','%','s',0};
6029     static const WCHAR setup_fmt[] = {
6030         'S','e','t','u','p','=','%','s',0};
6031     static const WCHAR usage_fmt[] = {
6032         'F','i','l','e','U','s','a','g','e','=','1',0};
6033 
6034     component = MSI_RecordGetString( rec, 2 );
6035     comp = msi_get_loaded_component( package, component );
6036     if (!comp)
6037         return ERROR_SUCCESS;
6038 
6039     comp->Action = msi_get_component_action( package, comp );
6040     if (comp->Action != INSTALLSTATE_LOCAL)
6041     {
6042         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6043         return ERROR_SUCCESS;
6044     }
6045     desc = MSI_RecordGetString(rec, 3);
6046 
6047     file_key = MSI_RecordGetString( rec, 4 );
6048     if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6049 
6050     file_key = MSI_RecordGetString( rec, 5 );
6051     if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6052 
6053     if (!driver_file)
6054     {
6055         ERR("ODBC Driver entry not found!\n");
6056         return ERROR_FUNCTION_FAILED;
6057     }
6058 
6059     len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6060     if (setup_file)
6061         len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6062     len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6063 
6064     driver = msi_alloc(len * sizeof(WCHAR));
6065     if (!driver)
6066         return ERROR_OUTOFMEMORY;
6067 
6068     ptr = driver;
6069     lstrcpyW(ptr, desc);
6070     ptr += lstrlenW(ptr) + 1;
6071 
6072     len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6073     ptr += len + 1;
6074 
6075     if (setup_file)
6076     {
6077         len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6078         ptr += len + 1;
6079     }
6080 
6081     lstrcpyW(ptr, usage_fmt);
6082     ptr += lstrlenW(ptr) + 1;
6083     *ptr = '\0';
6084 
6085     if (!driver_file->TargetPath)
6086     {
6087         const WCHAR *dir = msi_get_target_folder( package, driver_file->Component->Directory );
6088         driver_file->TargetPath = msi_build_directory_name( 2, dir, driver_file->FileName );
6089     }
6090     driver_path = strdupW(driver_file->TargetPath);
6091     ptr = strrchrW(driver_path, '\\');
6092     if (ptr) *ptr = '\0';
6093 
6094     if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6095                              NULL, ODBC_INSTALL_COMPLETE, &usage))
6096     {
6097         ERR("Failed to install SQL driver!\n");
6098         r = ERROR_FUNCTION_FAILED;
6099     }
6100 
6101     uirow = MSI_CreateRecord( 5 );
6102     MSI_RecordSetStringW( uirow, 1, desc );
6103     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6104     MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6105     msi_ui_actiondata( package, szInstallODBC, uirow );
6106     msiobj_release( &uirow->hdr );
6107 
6108     msi_free(driver);
6109     msi_free(driver_path);
6110 
6111     return r;
6112 }
6113 
6114 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6115 {
6116     MSIPACKAGE *package = param;
6117     LPWSTR translator, translator_path, ptr;
6118     WCHAR outpath[MAX_PATH];
6119     MSIFILE *translator_file = NULL, *setup_file = NULL;
6120     MSICOMPONENT *comp;
6121     MSIRECORD *uirow;
6122     LPCWSTR desc, file_key, component;
6123     DWORD len, usage;
6124     UINT r = ERROR_SUCCESS;
6125 
6126     static const WCHAR translator_fmt[] = {
6127         'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6128     static const WCHAR setup_fmt[] = {
6129         'S','e','t','u','p','=','%','s',0};
6130 
6131     component = MSI_RecordGetString( rec, 2 );
6132     comp = msi_get_loaded_component( package, component );
6133     if (!comp)
6134         return ERROR_SUCCESS;
6135 
6136     comp->Action = msi_get_component_action( package, comp );
6137     if (comp->Action != INSTALLSTATE_LOCAL)
6138     {
6139         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6140         return ERROR_SUCCESS;
6141     }
6142     desc = MSI_RecordGetString(rec, 3);
6143 
6144     file_key = MSI_RecordGetString( rec, 4 );
6145     if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6146 
6147     file_key = MSI_RecordGetString( rec, 5 );
6148     if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6149 
6150     if (!translator_file)
6151     {
6152         ERR("ODBC Translator entry not found!\n");
6153         return ERROR_FUNCTION_FAILED;
6154     }
6155 
6156     len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6157     if (setup_file)
6158         len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6159 
6160     translator = msi_alloc(len * sizeof(WCHAR));
6161     if (!translator)
6162         return ERROR_OUTOFMEMORY;
6163 
6164     ptr = translator;
6165     lstrcpyW(ptr, desc);
6166     ptr += lstrlenW(ptr) + 1;
6167 
6168     len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6169     ptr += len + 1;
6170 
6171     if (setup_file)
6172     {
6173         len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6174         ptr += len + 1;
6175     }
6176     *ptr = '\0';
6177 
6178     translator_path = strdupW(translator_file->TargetPath);
6179     ptr = strrchrW(translator_path, '\\');
6180     if (ptr) *ptr = '\0';
6181 
6182     if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6183                                  NULL, ODBC_INSTALL_COMPLETE, &usage))
6184     {
6185         ERR("Failed to install SQL translator!\n");
6186         r = ERROR_FUNCTION_FAILED;
6187     }
6188 
6189     uirow = MSI_CreateRecord( 5 );
6190     MSI_RecordSetStringW( uirow, 1, desc );
6191     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6192     MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6193     msi_ui_actiondata( package, szInstallODBC, uirow );
6194     msiobj_release( &uirow->hdr );
6195 
6196     msi_free(translator);
6197     msi_free(translator_path);
6198 
6199     return r;
6200 }
6201 
6202 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6203 {
6204     MSIPACKAGE *package = param;
6205     MSICOMPONENT *comp;
6206     LPWSTR attrs;
6207     LPCWSTR desc, driver, component;
6208     WORD request = ODBC_ADD_SYS_DSN;
6209     INT registration;
6210     DWORD len;
6211     UINT r = ERROR_SUCCESS;
6212     MSIRECORD *uirow;
6213 
6214     static const WCHAR attrs_fmt[] = {
6215         'D','S','N','=','%','s',0 };
6216 
6217     component = MSI_RecordGetString( rec, 2 );
6218     comp = msi_get_loaded_component( package, component );
6219     if (!comp)
6220         return ERROR_SUCCESS;
6221 
6222     comp->Action = msi_get_component_action( package, comp );
6223     if (comp->Action != INSTALLSTATE_LOCAL)
6224     {
6225         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6226         return ERROR_SUCCESS;
6227     }
6228 
6229     desc = MSI_RecordGetString(rec, 3);
6230     driver = MSI_RecordGetString(rec, 4);
6231     registration = MSI_RecordGetInteger(rec, 5);
6232 
6233     if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6234     else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6235 
6236     len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6237     attrs = msi_alloc(len * sizeof(WCHAR));
6238     if (!attrs)
6239         return ERROR_OUTOFMEMORY;
6240 
6241     len = sprintfW(attrs, attrs_fmt, desc);
6242     attrs[len + 1] = 0;
6243 
6244     if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6245     {
6246         ERR("Failed to install SQL data source!\n");
6247         r = ERROR_FUNCTION_FAILED;
6248     }
6249 
6250     uirow = MSI_CreateRecord( 5 );
6251     MSI_RecordSetStringW( uirow, 1, desc );
6252     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6253     MSI_RecordSetInteger( uirow, 3, request );
6254     msi_ui_actiondata( package, szInstallODBC, uirow );
6255     msiobj_release( &uirow->hdr );
6256 
6257     msi_free(attrs);
6258 
6259     return r;
6260 }
6261 
6262 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6263 {
6264     static const WCHAR driver_query[] = {
6265         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6266         'O','D','B','C','D','r','i','v','e','r',0};
6267     static const WCHAR translator_query[] = {
6268         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6269         'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6270     static const WCHAR source_query[] = {
6271         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6272         'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6273     MSIQUERY *view;
6274     UINT rc;
6275 
6276     rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6277     if (rc == ERROR_SUCCESS)
6278     {
6279         rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6280         msiobj_release(&view->hdr);
6281         if (rc != ERROR_SUCCESS)
6282             return rc;
6283     }
6284     rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6285     if (rc == ERROR_SUCCESS)
6286     {
6287         rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6288         msiobj_release(&view->hdr);
6289         if (rc != ERROR_SUCCESS)
6290             return rc;
6291     }
6292     rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6293     if (rc == ERROR_SUCCESS)
6294     {
6295         rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6296         msiobj_release(&view->hdr);
6297         if (rc != ERROR_SUCCESS)
6298             return rc;
6299     }
6300     return ERROR_SUCCESS;
6301 }
6302 
6303 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6304 {
6305     MSIPACKAGE *package = param;
6306     MSICOMPONENT *comp;
6307     MSIRECORD *uirow;
6308     DWORD usage;
6309     LPCWSTR desc, component;
6310 
6311     component = MSI_RecordGetString( rec, 2 );
6312     comp = msi_get_loaded_component( package, component );
6313     if (!comp)
6314         return ERROR_SUCCESS;
6315 
6316     comp->Action = msi_get_component_action( package, comp );
6317     if (comp->Action != INSTALLSTATE_ABSENT)
6318     {
6319         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6320         return ERROR_SUCCESS;
6321     }
6322 
6323     desc = MSI_RecordGetString( rec, 3 );
6324     if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6325     {
6326         WARN("Failed to remove ODBC driver\n");
6327     }
6328     else if (!usage)
6329     {
6330         FIXME("Usage count reached 0\n");
6331     }
6332 
6333     uirow = MSI_CreateRecord( 2 );
6334     MSI_RecordSetStringW( uirow, 1, desc );
6335     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6336     msi_ui_actiondata( package, szRemoveODBC, uirow );
6337     msiobj_release( &uirow->hdr );
6338 
6339     return ERROR_SUCCESS;
6340 }
6341 
6342 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6343 {
6344     MSIPACKAGE *package = param;
6345     MSICOMPONENT *comp;
6346     MSIRECORD *uirow;
6347     DWORD usage;
6348     LPCWSTR desc, component;
6349 
6350     component = MSI_RecordGetString( rec, 2 );
6351     comp = msi_get_loaded_component( package, component );
6352     if (!comp)
6353         return ERROR_SUCCESS;
6354 
6355     comp->Action = msi_get_component_action( package, comp );
6356     if (comp->Action != INSTALLSTATE_ABSENT)
6357     {
6358         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6359         return ERROR_SUCCESS;
6360     }
6361 
6362     desc = MSI_RecordGetString( rec, 3 );
6363     if (!SQLRemoveTranslatorW( desc, &usage ))
6364     {
6365         WARN("Failed to remove ODBC translator\n");
6366     }
6367     else if (!usage)
6368     {
6369         FIXME("Usage count reached 0\n");
6370     }
6371 
6372     uirow = MSI_CreateRecord( 2 );
6373     MSI_RecordSetStringW( uirow, 1, desc );
6374     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6375     msi_ui_actiondata( package, szRemoveODBC, uirow );
6376     msiobj_release( &uirow->hdr );
6377 
6378     return ERROR_SUCCESS;
6379 }
6380 
6381 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6382 {
6383     MSIPACKAGE *package = param;
6384     MSICOMPONENT *comp;
6385     MSIRECORD *uirow;
6386     LPWSTR attrs;
6387     LPCWSTR desc, driver, component;
6388     WORD request = ODBC_REMOVE_SYS_DSN;
6389     INT registration;
6390     DWORD len;
6391 
6392     static const WCHAR attrs_fmt[] = {
6393         'D','S','N','=','%','s',0 };
6394 
6395     component = MSI_RecordGetString( rec, 2 );
6396     comp = msi_get_loaded_component( package, component );
6397     if (!comp)
6398         return ERROR_SUCCESS;
6399 
6400     comp->Action = msi_get_component_action( package, comp );
6401     if (comp->Action != INSTALLSTATE_ABSENT)
6402     {
6403         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6404         return ERROR_SUCCESS;
6405     }
6406 
6407     desc = MSI_RecordGetString( rec, 3 );
6408     driver = MSI_RecordGetString( rec, 4 );
6409     registration = MSI_RecordGetInteger( rec, 5 );
6410 
6411     if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6412     else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6413 
6414     len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6415     attrs = msi_alloc( len * sizeof(WCHAR) );
6416     if (!attrs)
6417         return ERROR_OUTOFMEMORY;
6418 
6419     FIXME("Use ODBCSourceAttribute table\n");
6420 
6421     len = sprintfW( attrs, attrs_fmt, desc );
6422     attrs[len + 1] = 0;
6423 
6424     if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6425     {
6426         WARN("Failed to remove ODBC data source\n");
6427     }
6428     msi_free( attrs );
6429 
6430     uirow = MSI_CreateRecord( 3 );
6431     MSI_RecordSetStringW( uirow, 1, desc );
6432     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6433     MSI_RecordSetInteger( uirow, 3, request );
6434     msi_ui_actiondata( package, szRemoveODBC, uirow );
6435     msiobj_release( &uirow->hdr );
6436 
6437     return ERROR_SUCCESS;
6438 }
6439 
6440 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6441 {
6442     static const WCHAR driver_query[] = {
6443         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6444         'O','D','B','C','D','r','i','v','e','r',0};
6445     static const WCHAR translator_query[] = {
6446         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6447         'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6448     static const WCHAR source_query[] = {
6449         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6450         'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6451     MSIQUERY *view;
6452     UINT rc;
6453 
6454     rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6455     if (rc == ERROR_SUCCESS)
6456     {
6457         rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6458         msiobj_release( &view->hdr );
6459         if (rc != ERROR_SUCCESS)
6460             return rc;
6461     }
6462     rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6463     if (rc == ERROR_SUCCESS)
6464     {
6465         rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6466         msiobj_release( &view->hdr );
6467         if (rc != ERROR_SUCCESS)
6468             return rc;
6469     }
6470     rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6471     if (rc == ERROR_SUCCESS)
6472     {
6473         rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6474         msiobj_release( &view->hdr );
6475         if (rc != ERROR_SUCCESS)
6476             return rc;
6477     }
6478     return ERROR_SUCCESS;
6479 }
6480 
6481 #define ENV_ACT_SETALWAYS   0x1
6482 #define ENV_ACT_SETABSENT   0x2
6483 #define ENV_ACT_REMOVE      0x4
6484 #define ENV_ACT_REMOVEMATCH 0x8
6485 
6486 #define ENV_MOD_MACHINE     0x20000000
6487 #define ENV_MOD_APPEND      0x40000000
6488 #define ENV_MOD_PREFIX      0x80000000
6489 #define ENV_MOD_MASK        0xC0000000
6490 
6491 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6492 
6493 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6494 {
6495     LPCWSTR cptr = *name;
6496 
6497     static const WCHAR prefix[] = {'[','~',']',0};
6498     static const int prefix_len = 3;
6499 
6500     *flags = 0;
6501     while (*cptr)
6502     {
6503         if (*cptr == '=')
6504             *flags |= ENV_ACT_SETALWAYS;
6505         else if (*cptr == '+')
6506             *flags |= ENV_ACT_SETABSENT;
6507         else if (*cptr == '-')
6508             *flags |= ENV_ACT_REMOVE;
6509         else if (*cptr == '!')
6510             *flags |= ENV_ACT_REMOVEMATCH;
6511         else if (*cptr == '*')
6512             *flags |= ENV_MOD_MACHINE;
6513         else
6514             break;
6515 
6516         cptr++;
6517         (*name)++;
6518     }
6519 
6520     if (!*cptr)
6521     {
6522         ERR("Missing environment variable\n");
6523         return ERROR_FUNCTION_FAILED;
6524     }
6525 
6526     if (*value)
6527     {
6528         LPCWSTR ptr = *value;
6529         if (!strncmpW(ptr, prefix, prefix_len))
6530         {
6531             if (ptr[prefix_len] == szSemiColon[0])
6532             {
6533                 *flags |= ENV_MOD_APPEND;
6534                 *value += lstrlenW(prefix);
6535             }
6536             else
6537             {
6538                 *value = NULL;
6539             }
6540         }
6541         else if (lstrlenW(*value) >= prefix_len)
6542         {
6543             ptr += lstrlenW(ptr) - prefix_len;
6544             if (!strcmpW( ptr, prefix ))
6545             {
6546                 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6547                 {
6548                     *flags |= ENV_MOD_PREFIX;
6549                     /* the "[~]" will be removed by deformat_string */;
6550                 }
6551                 else
6552                 {
6553                     *value = NULL;
6554                 }
6555             }
6556         }
6557     }
6558 
6559     if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6560         check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6561         check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6562         check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6563     {
6564         ERR("Invalid flags: %08x\n", *flags);
6565         return ERROR_FUNCTION_FAILED;
6566     }
6567 
6568     if (!*flags)
6569         *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6570 
6571     return ERROR_SUCCESS;
6572 }
6573 
6574 static UINT open_env_key( DWORD flags, HKEY *key )
6575 {
6576     static const WCHAR user_env[] =
6577         {'E','n','v','i','r','o','n','m','e','n','t',0};
6578     static const WCHAR machine_env[] =
6579         {'S','y','s','t','e','m','\\',
6580          'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6581          'C','o','n','t','r','o','l','\\',
6582          'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6583          'E','n','v','i','r','o','n','m','e','n','t',0};
6584     const WCHAR *env;
6585     HKEY root;
6586     LONG res;
6587 
6588     if (flags & ENV_MOD_MACHINE)
6589     {
6590         env = machine_env;
6591         root = HKEY_LOCAL_MACHINE;
6592     }
6593     else
6594     {
6595         env = user_env;
6596         root = HKEY_CURRENT_USER;
6597     }
6598 
6599     res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6600     if (res != ERROR_SUCCESS)
6601     {
6602         WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6603         return ERROR_FUNCTION_FAILED;
6604     }
6605 
6606     return ERROR_SUCCESS;
6607 }
6608 
6609 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6610 {
6611     MSIPACKAGE *package = param;
6612     LPCWSTR name, value, component;
6613     LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6614     DWORD flags, type, size;
6615     UINT res;
6616     HKEY env = NULL;
6617     MSICOMPONENT *comp;
6618     MSIRECORD *uirow;
6619     int action = 0;
6620 
6621     component = MSI_RecordGetString(rec, 4);
6622     comp = msi_get_loaded_component(package, component);
6623     if (!comp)
6624         return ERROR_SUCCESS;
6625 
6626     comp->Action = msi_get_component_action( package, comp );
6627     if (comp->Action != INSTALLSTATE_LOCAL)
6628     {
6629         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6630         return ERROR_SUCCESS;
6631     }
6632     name = MSI_RecordGetString(rec, 2);
6633     value = MSI_RecordGetString(rec, 3);
6634 
6635     TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6636 
6637     res = env_parse_flags(&name, &value, &flags);
6638     if (res != ERROR_SUCCESS || !value)
6639        goto done;
6640 
6641     if (value && !deformat_string(package, value, &deformatted))
6642     {
6643         res = ERROR_OUTOFMEMORY;
6644         goto done;
6645     }
6646 
6647     value = deformatted;
6648 
6649     res = open_env_key( flags, &env );
6650     if (res != ERROR_SUCCESS)
6651         goto done;
6652 
6653     if (flags & ENV_MOD_MACHINE)
6654         action |= 0x20000000;
6655 
6656     size = 0;
6657     type = REG_SZ;
6658     res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6659     if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6660         (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6661         goto done;
6662 
6663     if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6664     {
6665         action = 0x2;
6666 
6667         /* Nothing to do. */
6668         if (!value)
6669         {
6670             res = ERROR_SUCCESS;
6671             goto done;
6672         }
6673 
6674         /* If we are appending but the string was empty, strip ; */
6675         if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6676 
6677         size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6678         newval = strdupW(value);
6679         if (!newval)
6680         {
6681             res = ERROR_OUTOFMEMORY;
6682             goto done;
6683         }
6684     }
6685     else
6686     {
6687         action = 0x1;
6688 
6689         /* Contrary to MSDN, +-variable to [~];path works */
6690         if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6691         {
6692             res = ERROR_SUCCESS;
6693             goto done;
6694         }
6695 
6696         data = msi_alloc(size);
6697         if (!data)
6698         {
6699             RegCloseKey(env);
6700             return ERROR_OUTOFMEMORY;
6701         }
6702 
6703         res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6704         if (res != ERROR_SUCCESS)
6705             goto done;
6706 
6707         if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6708         {
6709             action = 0x4;
6710             res = RegDeleteValueW(env, name);
6711             if (res != ERROR_SUCCESS)
6712                 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6713             goto done;
6714         }
6715 
6716         size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6717         if (flags & ENV_MOD_MASK)
6718         {
6719             DWORD mod_size;
6720             int multiplier = 0;
6721             if (flags & ENV_MOD_APPEND) multiplier++;
6722             if (flags & ENV_MOD_PREFIX) multiplier++;
6723             mod_size = lstrlenW(value) * multiplier;
6724             size += mod_size * sizeof(WCHAR);
6725         }
6726 
6727         newval = msi_alloc(size);
6728         ptr = newval;
6729         if (!newval)
6730         {
6731             res = ERROR_OUTOFMEMORY;
6732             goto done;
6733         }
6734 
6735         if (flags & ENV_MOD_PREFIX)
6736         {
6737             lstrcpyW(newval, value);
6738             ptr = newval + lstrlenW(value);
6739             action |= 0x80000000;
6740         }
6741 
6742         lstrcpyW(ptr, data);
6743 
6744         if (flags & ENV_MOD_APPEND)
6745         {
6746             lstrcatW(newval, value);
6747             action |= 0x40000000;
6748         }
6749     }
6750     TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6751     res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6752     if (res)
6753     {
6754         WARN("Failed to set %s to %s (%d)\n",  debugstr_w(name), debugstr_w(newval), res);
6755     }
6756 
6757 done:
6758     uirow = MSI_CreateRecord( 3 );
6759     MSI_RecordSetStringW( uirow, 1, name );
6760     MSI_RecordSetStringW( uirow, 2, newval );
6761     MSI_RecordSetInteger( uirow, 3, action );
6762     msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6763     msiobj_release( &uirow->hdr );
6764 
6765     if (env) RegCloseKey(env);
6766     msi_free(deformatted);
6767     msi_free(data);
6768     msi_free(newval);
6769     return res;
6770 }
6771 
6772 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6773 {
6774     static const WCHAR query[] = {
6775         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6776         '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6777     MSIQUERY *view;
6778     UINT rc;
6779 
6780     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6781     if (rc != ERROR_SUCCESS)
6782         return ERROR_SUCCESS;
6783 
6784     rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6785     msiobj_release(&view->hdr);
6786     return rc;
6787 }
6788 
6789 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6790 {
6791     MSIPACKAGE *package = param;
6792     LPCWSTR name, value, component;
6793     LPWSTR deformatted = NULL;
6794     DWORD flags;
6795     HKEY env;
6796     MSICOMPONENT *comp;
6797     MSIRECORD *uirow;
6798     int action = 0;
6799     LONG res;
6800     UINT r;
6801 
6802     component = MSI_RecordGetString( rec, 4 );
6803     comp = msi_get_loaded_component( package, component );
6804     if (!comp)
6805         return ERROR_SUCCESS;
6806 
6807     comp->Action = msi_get_component_action( package, comp );
6808     if (comp->Action != INSTALLSTATE_ABSENT)
6809     {
6810         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6811         return ERROR_SUCCESS;
6812     }
6813     name = MSI_RecordGetString( rec, 2 );
6814     value = MSI_RecordGetString( rec, 3 );
6815 
6816     TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6817 
6818     r = env_parse_flags( &name, &value, &flags );
6819     if (r != ERROR_SUCCESS)
6820        return r;
6821 
6822     if (!(flags & ENV_ACT_REMOVE))
6823     {
6824         TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6825         return ERROR_SUCCESS;
6826     }
6827 
6828     if (value && !deformat_string( package, value, &deformatted ))
6829         return ERROR_OUTOFMEMORY;
6830 
6831     value = deformatted;
6832 
6833     r = open_env_key( flags, &env );
6834     if (r != ERROR_SUCCESS)
6835     {
6836         r = ERROR_SUCCESS;
6837         goto done;
6838     }
6839 
6840     if (flags & ENV_MOD_MACHINE)
6841         action |= 0x20000000;
6842 
6843     TRACE("Removing %s\n", debugstr_w(name));
6844 
6845     res = RegDeleteValueW( env, name );
6846     if (res != ERROR_SUCCESS)
6847     {
6848         WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6849         r = ERROR_SUCCESS;
6850     }
6851 
6852 done:
6853     uirow = MSI_CreateRecord( 3 );
6854     MSI_RecordSetStringW( uirow, 1, name );
6855     MSI_RecordSetStringW( uirow, 2, value );
6856     MSI_RecordSetInteger( uirow, 3, action );
6857     msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6858     msiobj_release( &uirow->hdr );
6859 
6860     if (env) RegCloseKey( env );
6861     msi_free( deformatted );
6862     return r;
6863 }
6864 
6865 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6866 {
6867     static const WCHAR query[] = {
6868         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6869         '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6870     MSIQUERY *view;
6871     UINT rc;
6872 
6873     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6874     if (rc != ERROR_SUCCESS)
6875         return ERROR_SUCCESS;
6876 
6877     rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6878     msiobj_release( &view->hdr );
6879     return rc;
6880 }
6881 
6882 UINT msi_validate_product_id( MSIPACKAGE *package )
6883 {
6884     LPWSTR key, template, id;
6885     UINT r = ERROR_SUCCESS;
6886 
6887     id = msi_dup_property( package->db, szProductID );
6888     if (id)
6889     {
6890         msi_free( id );
6891         return ERROR_SUCCESS;
6892     }
6893     template = msi_dup_property( package->db, szPIDTemplate );
6894     key = msi_dup_property( package->db, szPIDKEY );
6895     if (key && template)
6896     {
6897         FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6898         r = msi_set_property( package->db, szProductID, key );
6899     }
6900     msi_free( template );
6901     msi_free( key );
6902     return r;
6903 }
6904 
6905 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6906 {
6907     return msi_validate_product_id( package );
6908 }
6909 
6910 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6911 {
6912     TRACE("\n");
6913     package->need_reboot_at_end = 1;
6914     return ERROR_SUCCESS;
6915 }
6916 
6917 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6918 {
6919     static const WCHAR szAvailableFreeReg[] =
6920         {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6921     MSIRECORD *uirow;
6922     int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6923 
6924     TRACE("%p %d kilobytes\n", package, space);
6925 
6926     uirow = MSI_CreateRecord( 1 );
6927     MSI_RecordSetInteger( uirow, 1, space );
6928     msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6929     msiobj_release( &uirow->hdr );
6930 
6931     return ERROR_SUCCESS;
6932 }
6933 
6934 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6935 {
6936     TRACE("%p\n", package);
6937 
6938     msi_set_property( package->db, szRollbackDisabled, szOne );
6939     return ERROR_SUCCESS;
6940 }
6941 
6942 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6943 {
6944     FIXME("%p\n", package);
6945     return ERROR_SUCCESS;
6946 }
6947 
6948 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6949 {
6950     static const WCHAR driver_query[] = {
6951         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6952         'O','D','B','C','D','r','i','v','e','r',0};
6953     static const WCHAR translator_query[] = {
6954         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6955         'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6956     MSIQUERY *view;
6957     UINT r, count;
6958 
6959     r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6960     if (r == ERROR_SUCCESS)
6961     {
6962         count = 0;
6963         r = MSI_IterateRecords( view, &count, NULL, package );
6964         msiobj_release( &view->hdr );
6965         if (r != ERROR_SUCCESS)
6966             return r;
6967         if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6968     }
6969     r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6970     if (r == ERROR_SUCCESS)
6971     {
6972         count = 0;
6973         r = MSI_IterateRecords( view, &count, NULL, package );
6974         msiobj_release( &view->hdr );
6975         if (r != ERROR_SUCCESS)
6976             return r;
6977         if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6978     }
6979     return ERROR_SUCCESS;
6980 }
6981 
6982 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6983 {
6984     MSIPACKAGE *package = param;
6985     const WCHAR *property = MSI_RecordGetString( rec, 1 );
6986     WCHAR *value;
6987 
6988     if ((value = msi_dup_property( package->db, property )))
6989     {
6990         FIXME("remove %s\n", debugstr_w(value));
6991         msi_free( value );
6992     }
6993     return ERROR_SUCCESS;
6994 }
6995 
6996 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6997 {
6998     static const WCHAR query[] = {
6999         'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',' ',
7000         'F','R','O','M',' ','U','p','g','r','a','d','e',0};
7001     MSIQUERY *view;
7002     UINT r;
7003 
7004     r = MSI_DatabaseOpenViewW( package->db, query, &view );
7005     if (r == ERROR_SUCCESS)
7006     {
7007         r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7008         msiobj_release( &view->hdr );
7009         if (r != ERROR_SUCCESS)
7010             return r;
7011     }
7012     return ERROR_SUCCESS;
7013 }
7014 
7015 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7016 {
7017     MSIPACKAGE *package = param;
7018     int attributes = MSI_RecordGetInteger( rec, 5 );
7019 
7020     if (attributes & msidbUpgradeAttributesMigrateFeatures)
7021     {
7022         const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7023         const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7024         const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7025         const WCHAR *language = MSI_RecordGetString( rec, 4 );
7026         HKEY hkey;
7027         UINT r;
7028 
7029         if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7030         {
7031             r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7032             if (r != ERROR_SUCCESS)
7033                 return ERROR_SUCCESS;
7034         }
7035         else
7036         {
7037             r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7038             if (r != ERROR_SUCCESS)
7039                 return ERROR_SUCCESS;
7040         }
7041         RegCloseKey( hkey );
7042 
7043         FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7044               debugstr_w(upgrade_code), debugstr_w(version_min),
7045               debugstr_w(version_max), debugstr_w(language));
7046     }
7047     return ERROR_SUCCESS;
7048 }
7049 
7050 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7051 {
7052     static const WCHAR query[] = {
7053         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7054         'U','p','g','r','a','d','e',0};
7055     MSIQUERY *view;
7056     UINT r;
7057 
7058     if (msi_get_property_int( package->db, szInstalled, 0 ))
7059     {
7060         TRACE("product is installed, skipping action\n");
7061         return ERROR_SUCCESS;
7062     }
7063     if (msi_get_property_int( package->db, szPreselected, 0 ))
7064     {
7065         TRACE("Preselected property is set, not migrating feature states\n");
7066         return ERROR_SUCCESS;
7067     }
7068     r = MSI_DatabaseOpenViewW( package->db, query, &view );
7069     if (r == ERROR_SUCCESS)
7070     {
7071         r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7072         msiobj_release( &view->hdr );
7073         if (r != ERROR_SUCCESS)
7074             return r;
7075     }
7076     return ERROR_SUCCESS;
7077 }
7078 
7079 static void bind_image( const char *filename, const char *path )
7080 {
7081     if (!BindImageEx( 0, filename, path, NULL, NULL ))
7082     {
7083         WARN("failed to bind image %u\n", GetLastError());
7084     }
7085 }
7086 
7087 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7088 {
7089     UINT i;
7090     MSIFILE *file;
7091     MSIPACKAGE *package = param;
7092     const WCHAR *key = MSI_RecordGetString( rec, 1 );
7093     const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7094     char *filenameA, *pathA;
7095     WCHAR *pathW, **path_list;
7096 
7097     if (!(file = msi_get_loaded_file( package, key )))
7098     {
7099         WARN("file %s not found\n", debugstr_w(key));
7100         return ERROR_SUCCESS;
7101     }
7102     if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7103     path_list = msi_split_string( paths, ';' );
7104     if (!path_list) bind_image( filenameA, NULL );
7105     else
7106     {
7107         for (i = 0; path_list[i] && path_list[i][0]; i++)
7108         {
7109             deformat_string( package, path_list[i], &pathW );
7110             if ((pathA = strdupWtoA( pathW )))
7111             {
7112                 bind_image( filenameA, pathA );
7113                 msi_free( pathA );
7114             }
7115             msi_free( pathW );
7116         }
7117     }
7118     msi_free( path_list );
7119     msi_free( filenameA );
7120     return ERROR_SUCCESS;
7121 }
7122 
7123 static UINT ACTION_BindImage( MSIPACKAGE *package )
7124 {
7125     static const WCHAR query[] = {
7126         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7127         'B','i','n','d','I','m','a','g','e',0};
7128     MSIQUERY *view;
7129     UINT r;
7130 
7131     r = MSI_DatabaseOpenViewW( package->db, query, &view );
7132     if (r == ERROR_SUCCESS)
7133     {
7134         r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7135         msiobj_release( &view->hdr );
7136         if (r != ERROR_SUCCESS)
7137             return r;
7138     }
7139     return ERROR_SUCCESS;
7140 }
7141 
7142 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7143 {
7144     static const WCHAR query[] = {
7145         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7146     MSIQUERY *view;
7147     DWORD count = 0;
7148     UINT r;
7149     
7150     r = MSI_OpenQuery( package->db, &view, query, table );
7151     if (r == ERROR_SUCCESS)
7152     {
7153         r = MSI_IterateRecords(view, &count, NULL, package);
7154         msiobj_release(&view->hdr);
7155         if (r != ERROR_SUCCESS)
7156             return r;
7157     }
7158     if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7159     return ERROR_SUCCESS;
7160 }
7161 
7162 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7163 {
7164     static const WCHAR table[] = {
7165         'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7166     return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7167 }
7168 
7169 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7170 {
7171     static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7172     return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7173 }
7174 
7175 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7176 {
7177     static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7178     return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7179 }
7180 
7181 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7182 {
7183     static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7184     return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7185 }
7186 
7187 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7188 {
7189     static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7190     return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7191 }
7192 
7193 static const struct
7194 {
7195     const WCHAR *action;
7196     UINT (*handler)(MSIPACKAGE *);
7197     const WCHAR *action_rollback;
7198 }
7199 StandardActions[] =
7200 {
7201     { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7202     { szAppSearch, ACTION_AppSearch, NULL },
7203     { szBindImage, ACTION_BindImage, NULL },
7204     { szCCPSearch, ACTION_CCPSearch, NULL },
7205     { szCostFinalize, ACTION_CostFinalize, NULL },
7206     { szCostInitialize, ACTION_CostInitialize, NULL },
7207     { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7208     { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7209     { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7210     { szDisableRollback, ACTION_DisableRollback, NULL },
7211     { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7212     { szExecuteAction, ACTION_ExecuteAction, NULL },
7213     { szFileCost, ACTION_FileCost, NULL },
7214     { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7215     { szForceReboot, ACTION_ForceReboot, NULL },
7216     { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7217     { szInstallExecute, ACTION_InstallExecute, NULL },
7218     { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7219     { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7220     { szInstallFinalize, ACTION_InstallFinalize, NULL },
7221     { szInstallInitialize, ACTION_InstallInitialize, NULL },
7222     { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7223     { szInstallServices, ACTION_InstallServices, szDeleteServices },
7224     { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7225     { szInstallValidate, ACTION_InstallValidate, NULL },
7226     { szIsolateComponents, ACTION_IsolateComponents, NULL },
7227     { szLaunchConditions, ACTION_LaunchConditions, NULL },
7228     { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7229     { szMoveFiles, ACTION_MoveFiles, NULL },
7230     { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7231     { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7232     { szPatchFiles, ACTION_PatchFiles, NULL },
7233     { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7234     { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7235     { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7236     { szPublishProduct, ACTION_PublishProduct, NULL },
7237     { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7238     { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7239     { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7240     { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7241     { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7242     { szRegisterProduct, ACTION_RegisterProduct, NULL },
7243     { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7244     { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7245     { szRegisterUser, ACTION_RegisterUser, NULL },
7246     { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7247     { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7248     { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7249     { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7250     { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7251     { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7252     { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7253     { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7254     { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7255     { szResolveSource, ACTION_ResolveSource, NULL },
7256     { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7257     { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7258     { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7259     { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules },
7260     { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7261     { szStartServices, ACTION_StartServices, szStopServices },
7262     { szStopServices, ACTION_StopServices, szStartServices },
7263     { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7264     { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7265     { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7266     { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7267     { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7268     { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7269     { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7270     { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7271     { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7272     { szValidateProductID, ACTION_ValidateProductID, NULL },
7273     { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7274     { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7275     { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7276     { NULL, NULL, NULL }
7277 };
7278 
7279 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7280 {
7281     BOOL ret = FALSE;
7282     UINT i;
7283 
7284     i = 0;
7285     while (StandardActions[i].action != NULL)
7286     {
7287         if (!strcmpW( StandardActions[i].action, action ))
7288         {
7289             ui_actionstart( package, action );
7290             if (StandardActions[i].handler)
7291             {
7292                 ui_actioninfo( package, action, TRUE, 0 );
7293                 *rc = StandardActions[i].handler( package );
7294                 ui_actioninfo( package, action, FALSE, *rc );
7295 
7296                 if (StandardActions[i].action_rollback && !package->need_rollback)
7297                 {
7298                     TRACE("scheduling rollback action\n");
7299                     msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback );
7300                 }
7301             }
7302             else
7303             {
7304                 FIXME("unhandled standard action %s\n", debugstr_w(action));
7305                 *rc = ERROR_SUCCESS;
7306             }
7307             ret = TRUE;
7308             break;
7309         }
7310         i++;
7311     }
7312     return ret;
7313 }
7314 
7315 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7316 {
7317     UINT rc = ERROR_SUCCESS;
7318     BOOL handled;
7319 
7320     TRACE("Performing action (%s)\n", debugstr_w(action));
7321 
7322     handled = ACTION_HandleStandardAction(package, action, &rc);
7323 
7324     if (!handled)
7325         handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7326 
7327     if (!handled)
7328     {
7329         WARN("unhandled msi action %s\n", debugstr_w(action));
7330         rc = ERROR_FUNCTION_NOT_CALLED;
7331     }
7332 
7333     return rc;
7334 }
7335 
7336 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7337 {
7338     UINT rc = ERROR_SUCCESS;
7339     BOOL handled = FALSE;
7340 
7341     TRACE("Performing action (%s)\n", debugstr_w(action));
7342 
7343     handled = ACTION_HandleStandardAction(package, action, &rc);
7344 
7345     if (!handled)
7346         handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7347 
7348     if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7349         handled = TRUE;
7350 
7351     if (!handled)
7352     {
7353         WARN("unhandled msi action %s\n", debugstr_w(action));
7354         rc = ERROR_FUNCTION_NOT_CALLED;
7355     }
7356 
7357     return rc;
7358 }
7359 
7360 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7361 {
7362     UINT rc = ERROR_SUCCESS;
7363     MSIRECORD *row;
7364 
7365     static const WCHAR query[] =
7366         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7367          '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7368          'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7369          '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7370     static const WCHAR ui_query[] =
7371         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7372      '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7373      '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7374          ' ', '=',' ','%','i',0};
7375 
7376     if (needs_ui_sequence(package))
7377         row = MSI_QueryGetRecord(package->db, ui_query, seq);
7378     else
7379         row = MSI_QueryGetRecord(package->db, query, seq);
7380 
7381     if (row)
7382     {
7383         LPCWSTR action, cond;
7384 
7385         TRACE("Running the actions\n");
7386 
7387         /* check conditions */
7388         cond = MSI_RecordGetString(row, 2);
7389 
7390         /* this is a hack to skip errors in the condition code */
7391         if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7392         {
7393             msiobj_release(&row->hdr);
7394             return ERROR_SUCCESS;
7395         }
7396 
7397         action = MSI_RecordGetString(row, 1);
7398         if (!action)
7399         {
7400             ERR("failed to fetch action\n");
7401             msiobj_release(&row->hdr);
7402             return ERROR_FUNCTION_FAILED;
7403         }
7404 
7405         if (needs_ui_sequence(package))
7406             rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
7407         else
7408             rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
7409 
7410         msiobj_release(&row->hdr);
7411     }
7412 
7413     return rc;
7414 }
7415 
7416 /****************************************************
7417  * TOP level entry points
7418  *****************************************************/
7419 
7420 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7421                          LPCWSTR szCommandLine )
7422 {
7423     static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7424     static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7425     static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7426     WCHAR *reinstall = NULL;
7427     BOOL ui_exists;
7428     UINT rc;
7429 
7430     msi_set_property( package->db, szAction, szInstall );
7431 
7432     package->script->InWhatSequence = SEQUENCE_INSTALL;
7433 
7434     if (szPackagePath)
7435     {
7436         LPWSTR p, dir;
7437         LPCWSTR file;
7438 
7439         dir = strdupW(szPackagePath);
7440         p = strrchrW(dir, '\\');
7441         if (p)
7442         {
7443             *(++p) = 0;
7444             file = szPackagePath + (p - dir);
7445         }
7446         else
7447         {
7448             msi_free(dir);
7449             dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7450             GetCurrentDirectoryW(MAX_PATH, dir);
7451             lstrcatW(dir, szBackSlash);
7452             file = szPackagePath;
7453         }
7454 
7455         msi_free( package->PackagePath );
7456         package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7457         if (!package->PackagePath)
7458         {
7459             msi_free(dir);
7460             return ERROR_OUTOFMEMORY;
7461         }
7462 
7463         lstrcpyW(package->PackagePath, dir);
7464         lstrcatW(package->PackagePath, file);
7465         msi_free(dir);
7466 
7467         msi_set_sourcedir_props(package, FALSE);
7468     }
7469 
7470     rc = msi_parse_command_line( package, szCommandLine, FALSE );
7471     if (rc != ERROR_SUCCESS)
7472         return rc;
7473 
7474     msi_apply_transforms( package );
7475     msi_apply_patches( package );
7476 
7477     if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7478     {
7479         TRACE("setting reinstall property\n");
7480         msi_set_property( package->db, szReinstall, szAll );
7481     }
7482 
7483     /* properties may have been added by a transform */
7484     msi_clone_properties( package );
7485 
7486     msi_parse_command_line( package, szCommandLine, FALSE );
7487     msi_adjust_privilege_properties( package );
7488     msi_set_context( package );
7489 
7490     if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7491     {
7492         TRACE("disabling rollback\n");
7493         msi_set_property( package->db, szRollbackDisabled, szOne );
7494     }
7495 
7496     if (needs_ui_sequence( package))
7497     {
7498         package->script->InWhatSequence |= SEQUENCE_UI;
7499         rc = ACTION_ProcessUISequence(package);
7500         ui_exists = ui_sequence_exists(package);
7501         if (rc == ERROR_SUCCESS || !ui_exists)
7502         {
7503             package->script->InWhatSequence |= SEQUENCE_EXEC;
7504             rc = ACTION_ProcessExecSequence(package, ui_exists);
7505         }
7506     }
7507     else
7508         rc = ACTION_ProcessExecSequence(package, FALSE);
7509 
7510     package->script->CurrentlyScripting = FALSE;
7511 
7512     /* process the ending type action */
7513     if (rc == ERROR_SUCCESS)
7514         ACTION_PerformActionSequence(package, -1);
7515     else if (rc == ERROR_INSTALL_USEREXIT)
7516         ACTION_PerformActionSequence(package, -2);
7517     else if (rc == ERROR_INSTALL_SUSPEND)
7518         ACTION_PerformActionSequence(package, -4);
7519     else  /* failed */
7520     {
7521         ACTION_PerformActionSequence(package, -3);
7522         if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7523         {
7524             package->need_rollback = TRUE;
7525         }
7526     }
7527 
7528     /* finish up running custom actions */
7529     ACTION_FinishCustomActions(package);
7530 
7531     if (package->need_rollback && !(reinstall = msi_dup_property( package->db, szReinstall )))
7532     {
7533         WARN("installation failed, running rollback script\n");
7534         execute_script( package, SCRIPT_ROLLBACK );
7535     }
7536     msi_free( reinstall );
7537 
7538     if (rc == ERROR_SUCCESS && package->need_reboot_at_end)
7539         return ERROR_SUCCESS_REBOOT_REQUIRED;
7540 
7541     return rc;
7542 }
7543 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.