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