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