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