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