msi: Fix typo's (Coverity).
[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 /*
22  * Pages I need
23  *
24 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
25
26 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
27  */
28
29 #include <stdarg.h>
30
31 #define COBJMACROS
32
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winerror.h"
36 #include "winreg.h"
37 #include "winsvc.h"
38 #include "wine/debug.h"
39 #include "msidefs.h"
40 #include "msipriv.h"
41 #include "winuser.h"
42 #include "shlobj.h"
43 #include "wine/unicode.h"
44 #include "winver.h"
45
46 #define REG_PROGRESS_VALUE 13200
47 #define COMPONENT_PROGRESS_VALUE 24000
48
49 WINE_DEFAULT_DEBUG_CHANNEL(msi);
50
51 /*
52  * Prototypes
53  */
54 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
55 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
56 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
57
58 /*
59  * consts and values used
60  */
61 static const WCHAR c_colon[] = {'C',':','\\',0};
62
63 static const WCHAR szCreateFolders[] =
64     {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
65 static const WCHAR szCostFinalize[] =
66     {'C','o','s','t','F','i','n','a','l','i','z','e',0};
67 const WCHAR szInstallFiles[] =
68     {'I','n','s','t','a','l','l','F','i','l','e','s',0};
69 const WCHAR szDuplicateFiles[] =
70     {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
71 static const WCHAR szWriteRegistryValues[] =
72     {'W','r','i','t','e','R','e','g','i','s','t','r','y',
73             'V','a','l','u','e','s',0};
74 static const WCHAR szCostInitialize[] =
75     {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
76 static const WCHAR szFileCost[] = 
77     {'F','i','l','e','C','o','s','t',0};
78 static const WCHAR szInstallInitialize[] = 
79     {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
80 static const WCHAR szInstallValidate[] = 
81     {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
82 static const WCHAR szLaunchConditions[] = 
83     {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
84 static const WCHAR szProcessComponents[] = 
85     {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
86 static const WCHAR szRegisterTypeLibraries[] = 
87     {'R','e','g','i','s','t','e','r','T','y','p','e',
88             'L','i','b','r','a','r','i','e','s',0};
89 const WCHAR szRegisterClassInfo[] = 
90     {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
91 const WCHAR szRegisterProgIdInfo[] = 
92     {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
93 static const WCHAR szCreateShortcuts[] = 
94     {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
95 static const WCHAR szPublishProduct[] = 
96     {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
97 static const WCHAR szWriteIniValues[] = 
98     {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
99 static const WCHAR szSelfRegModules[] = 
100     {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
101 static const WCHAR szPublishFeatures[] = 
102     {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
103 static const WCHAR szRegisterProduct[] = 
104     {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
105 static const WCHAR szInstallExecute[] = 
106     {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
107 static const WCHAR szInstallExecuteAgain[] = 
108     {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
109             'A','g','a','i','n',0};
110 static const WCHAR szInstallFinalize[] = 
111     {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
112 static const WCHAR szForceReboot[] = 
113     {'F','o','r','c','e','R','e','b','o','o','t',0};
114 static const WCHAR szResolveSource[] =
115     {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
116 static const WCHAR szAppSearch[] = 
117     {'A','p','p','S','e','a','r','c','h',0};
118 static const WCHAR szAllocateRegistrySpace[] = 
119     {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
120             'S','p','a','c','e',0};
121 static const WCHAR szBindImage[] = 
122     {'B','i','n','d','I','m','a','g','e',0};
123 static const WCHAR szCCPSearch[] = 
124     {'C','C','P','S','e','a','r','c','h',0};
125 static const WCHAR szDeleteServices[] = 
126     {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
127 static const WCHAR szDisableRollback[] = 
128     {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
129 static const WCHAR szExecuteAction[] = 
130     {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
131 const WCHAR szFindRelatedProducts[] = 
132     {'F','i','n','d','R','e','l','a','t','e','d',
133             'P','r','o','d','u','c','t','s',0};
134 static const WCHAR szInstallAdminPackage[] = 
135     {'I','n','s','t','a','l','l','A','d','m','i','n',
136             'P','a','c','k','a','g','e',0};
137 static const WCHAR szInstallSFPCatalogFile[] = 
138     {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
139             'F','i','l','e',0};
140 static const WCHAR szIsolateComponents[] = 
141     {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
142 const WCHAR szMigrateFeatureStates[] = 
143     {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
144             'S','t','a','t','e','s',0};
145 const WCHAR szMoveFiles[] = 
146     {'M','o','v','e','F','i','l','e','s',0};
147 static const WCHAR szMsiPublishAssemblies[] = 
148     {'M','s','i','P','u','b','l','i','s','h',
149             'A','s','s','e','m','b','l','i','e','s',0};
150 static const WCHAR szMsiUnpublishAssemblies[] = 
151     {'M','s','i','U','n','p','u','b','l','i','s','h',
152             'A','s','s','e','m','b','l','i','e','s',0};
153 static const WCHAR szInstallODBC[] = 
154     {'I','n','s','t','a','l','l','O','D','B','C',0};
155 static const WCHAR szInstallServices[] = 
156     {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
157 const WCHAR szPatchFiles[] = 
158     {'P','a','t','c','h','F','i','l','e','s',0};
159 static const WCHAR szPublishComponents[] = 
160     {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
161 static const WCHAR szRegisterComPlus[] =
162     {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
163 const WCHAR szRegisterExtensionInfo[] =
164     {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
165             'I','n','f','o',0};
166 static const WCHAR szRegisterFonts[] =
167     {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
168 const WCHAR szRegisterMIMEInfo[] =
169     {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
170 static const WCHAR szRegisterUser[] =
171     {'R','e','g','i','s','t','e','r','U','s','e','r',0};
172 const WCHAR szRemoveDuplicateFiles[] =
173     {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
174             'F','i','l','e','s',0};
175 static const WCHAR szRemoveEnvironmentStrings[] =
176     {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
177             'S','t','r','i','n','g','s',0};
178 const WCHAR szRemoveExistingProducts[] =
179     {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
180             'P','r','o','d','u','c','t','s',0};
181 const WCHAR szRemoveFiles[] =
182     {'R','e','m','o','v','e','F','i','l','e','s',0};
183 static const WCHAR szRemoveFolders[] =
184     {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
185 static const WCHAR szRemoveIniValues[] =
186     {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
187 static const WCHAR szRemoveODBC[] =
188     {'R','e','m','o','v','e','O','D','B','C',0};
189 static const WCHAR szRemoveRegistryValues[] =
190     {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
191             'V','a','l','u','e','s',0};
192 static const WCHAR szRemoveShortcuts[] =
193     {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
194 static const WCHAR szRMCCPSearch[] =
195     {'R','M','C','C','P','S','e','a','r','c','h',0};
196 static const WCHAR szScheduleReboot[] =
197     {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
198 static const WCHAR szSelfUnregModules[] =
199     {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
200 static const WCHAR szSetODBCFolders[] =
201     {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
202 static const WCHAR szStartServices[] =
203     {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
204 static const WCHAR szStopServices[] =
205     {'S','t','o','p','S','e','r','v','i','c','e','s',0};
206 static const WCHAR szUnpublishComponents[] =
207     {'U','n','p','u','b','l','i','s','h',
208             'C','o','m','p','o','n','e','n','t','s',0};
209 static const WCHAR szUnpublishFeatures[] =
210     {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
211 const WCHAR szUnregisterClassInfo[] =
212     {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
213             'I','n','f','o',0};
214 static const WCHAR szUnregisterComPlus[] =
215     {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
216 const WCHAR szUnregisterExtensionInfo[] =
217     {'U','n','r','e','g','i','s','t','e','r',
218             'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
219 static const WCHAR szUnregisterFonts[] =
220     {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
221 const WCHAR szUnregisterMIMEInfo[] =
222     {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
223 const WCHAR szUnregisterProgIdInfo[] =
224     {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
225             'I','n','f','o',0};
226 static const WCHAR szUnregisterTypeLibraries[] =
227     {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
228             'L','i','b','r','a','r','i','e','s',0};
229 static const WCHAR szValidateProductID[] =
230     {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
231 static const WCHAR szWriteEnvironmentStrings[] =
232     {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
233             'S','t','r','i','n','g','s',0};
234
235 /* action handlers */
236 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
237
238 struct _actions {
239     LPCWSTR action;
240     STANDARDACTIONHANDLER handler;
241 };
242
243 static struct _actions StandardActions[];
244
245
246 /********************************************************
247  * helper functions
248  ********************************************************/
249
250 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
251 {
252     static const WCHAR Query_t[] = 
253         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
254          '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
255          'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=', 
256          ' ','\'','%','s','\'',0};
257     MSIRECORD * row;
258
259     row = MSI_QueryGetRecord( package->db, Query_t, action );
260     if (!row)
261         return;
262     MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
263     msiobj_release(&row->hdr);
264 }
265
266 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start, 
267                           UINT rc)
268 {
269     MSIRECORD * row;
270     static const WCHAR template_s[]=
271         {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
272          '%','s', '.',0};
273     static const WCHAR template_e[]=
274         {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
275          '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
276          '%','i','.',0};
277     static const WCHAR format[] = 
278         {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
279     WCHAR message[1024];
280     WCHAR timet[0x100];
281
282     GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
283     if (start)
284         sprintfW(message,template_s,timet,action);
285     else
286         sprintfW(message,template_e,timet,action,rc);
287     
288     row = MSI_CreateRecord(1);
289     MSI_RecordSetStringW(row,1,message);
290  
291     MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
292     msiobj_release(&row->hdr);
293 }
294
295 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
296 {
297     LPCWSTR ptr,ptr2;
298     BOOL quote;
299     DWORD len;
300     LPWSTR prop = NULL, val = NULL;
301
302     if (!szCommandLine)
303         return ERROR_SUCCESS;
304
305     ptr = szCommandLine;
306        
307     while (*ptr)
308     {
309         if (*ptr==' ')
310         {
311             ptr++;
312             continue;
313         }
314
315         TRACE("Looking at %s\n",debugstr_w(ptr));
316
317         ptr2 = strchrW(ptr,'=');
318         if (!ptr2)
319         {
320             ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
321             break;
322         }
323  
324         quote = FALSE;
325
326         len = ptr2-ptr;
327         prop = msi_alloc((len+1)*sizeof(WCHAR));
328         memcpy(prop,ptr,len*sizeof(WCHAR));
329         prop[len]=0;
330         ptr2++;
331        
332         len = 0; 
333         ptr = ptr2; 
334         while (*ptr && (quote || (!quote && *ptr!=' ')))
335         {
336             if (*ptr == '"')
337                 quote = !quote;
338             ptr++;
339             len++;
340         }
341        
342         if (*ptr2=='"')
343         {
344             ptr2++;
345             len -= 2;
346         }
347         val = msi_alloc((len+1)*sizeof(WCHAR));
348         memcpy(val,ptr2,len*sizeof(WCHAR));
349         val[len] = 0;
350
351         if (lstrlenW(prop) > 0)
352         {
353             TRACE("Found commandline property (%s) = (%s)\n", 
354                    debugstr_w(prop), debugstr_w(val));
355             MSI_SetPropertyW(package,prop,val);
356         }
357         msi_free(val);
358         msi_free(prop);
359     }
360
361     return ERROR_SUCCESS;
362 }
363
364
365 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
366 {
367     LPCWSTR pc;
368     LPWSTR p, *ret = NULL;
369     UINT count = 0;
370
371     if (!str)
372         return ret;
373
374     /* count the number of substrings */
375     for ( pc = str, count = 0; pc; count++ )
376     {
377         pc = strchrW( pc, sep );
378         if (pc)
379             pc++;
380     }
381
382     /* allocate space for an array of substring pointers and the substrings */
383     ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
384                      (lstrlenW(str)+1) * sizeof(WCHAR) );
385     if (!ret)
386         return ret;
387
388     /* copy the string and set the pointers */
389     p = (LPWSTR) &ret[count+1];
390     lstrcpyW( p, str );
391     for( count = 0; (ret[count] = p); count++ )
392     {
393         p = strchrW( p, sep );
394         if (p)
395             *p++ = 0;
396     }
397
398     return ret;
399 }
400
401 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
402 {
403     WCHAR szProductCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
404     LPWSTR prod_code, patch_product;
405     UINT ret;
406
407     prod_code = msi_dup_property( package, szProductCode );
408     patch_product = msi_get_suminfo_product( patch );
409
410     TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
411
412     if ( strstrW( patch_product, prod_code ) )
413         ret = ERROR_SUCCESS;
414     else
415         ret = ERROR_FUNCTION_FAILED;
416
417     msi_free( patch_product );
418     msi_free( prod_code );
419
420     return ret;
421 }
422
423 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
424                                  MSIDATABASE *patch_db, LPCWSTR name )
425 {
426     UINT ret = ERROR_FUNCTION_FAILED;
427     IStorage *stg = NULL;
428     HRESULT r;
429
430     TRACE("%p %s\n", package, debugstr_w(name) );
431
432     if (*name++ != ':')
433     {
434         ERR("expected a colon in %s\n", debugstr_w(name));
435         return ERROR_FUNCTION_FAILED;
436     }
437
438     r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
439     if (SUCCEEDED(r))
440     {
441         ret = msi_check_transform_applicable( package, stg );
442         if (ret == ERROR_SUCCESS)
443             msi_table_apply_transform( package->db, stg );
444         else
445             TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
446         IStorage_Release( stg );
447     }
448     else
449         ERR("failed to open substorage %s\n", debugstr_w(name));
450
451     return ERROR_SUCCESS;
452 }
453
454 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
455 {
456     static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
457     LPWSTR guid_list, *guids, product_id;
458     UINT i, ret = ERROR_FUNCTION_FAILED;
459
460     product_id = msi_dup_property( package, szProdID );
461     if (!product_id)
462     {
463         /* FIXME: the property ProductID should be written into the DB somewhere */
464         ERR("no product ID to check\n");
465         return ERROR_SUCCESS;
466     }
467
468     guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
469     guids = msi_split_string( guid_list, ';' );
470     for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
471     {
472         if (!lstrcmpW( guids[i], product_id ))
473             ret = ERROR_SUCCESS;
474     }
475     msi_free( guids );
476     msi_free( guid_list );
477     msi_free( product_id );
478
479     return ret;
480 }
481
482 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
483 {
484     MSISUMMARYINFO *si;
485     LPWSTR str, *substorage;
486     UINT i, r = ERROR_SUCCESS;
487
488     si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
489     if (!si)
490         return ERROR_FUNCTION_FAILED;
491
492     msi_check_patch_applicable( package, si );
493
494     /* enumerate the substorage */
495     str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
496     substorage = msi_split_string( str, ';' );
497     for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
498         r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
499     msi_free( substorage );
500     msi_free( str );
501
502     /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
503
504     msiobj_release( &si->hdr );
505
506     return r;
507 }
508
509 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
510 {
511     MSIDATABASE *patch_db = NULL;
512     UINT r;
513
514     TRACE("%p %s\n", package, debugstr_w( file ) );
515
516     /* FIXME:
517      *  We probably want to make sure we only open a patch collection here.
518      *  Patch collections (.msp) and databases (.msi) have different GUIDs
519      *  but currently MSI_OpenDatabaseW will accept both.
520      */
521     r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
522     if ( r != ERROR_SUCCESS )
523     {
524         ERR("failed to open patch collection %s\n", debugstr_w( file ) );
525         return r;
526     }
527
528     msi_parse_patch_summary( package, patch_db );
529
530     /*
531      * There might be a CAB file in the patch package,
532      * so append it to the list of storage to search for streams.
533      */
534     append_storage_to_db( package->db, patch_db->storage );
535
536     msiobj_release( &patch_db->hdr );
537
538     return ERROR_SUCCESS;
539 }
540
541 /* get the PATCH property, and apply all the patches it specifies */
542 static UINT msi_apply_patches( MSIPACKAGE *package )
543 {
544     static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
545     LPWSTR patch_list, *patches;
546     UINT i, r = ERROR_SUCCESS;
547
548     patch_list = msi_dup_property( package, szPatch );
549
550     TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
551
552     patches = msi_split_string( patch_list, ';' );
553     for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
554         r = msi_apply_patch_package( package, patches[i] );
555
556     msi_free( patches );
557     msi_free( patch_list );
558
559     return r;
560 }
561
562 static UINT msi_apply_transforms( MSIPACKAGE *package )
563 {
564     static const WCHAR szTransforms[] = {
565         'T','R','A','N','S','F','O','R','M','S',0 };
566     LPWSTR xform_list, *xforms;
567     UINT i, r = ERROR_SUCCESS;
568
569     xform_list = msi_dup_property( package, szTransforms );
570     xforms = msi_split_string( xform_list, ';' );
571
572     for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
573     {
574         if (xforms[i][0] == ':')
575             r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
576         else
577             r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
578     }
579
580     msi_free( xforms );
581     msi_free( xform_list );
582
583     return r;
584 }
585
586 /****************************************************
587  * TOP level entry points 
588  *****************************************************/
589
590 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
591                          LPCWSTR szCommandLine )
592 {
593     UINT rc;
594     BOOL ui = FALSE;
595     static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
596     static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
597     static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
598
599     MSI_SetPropertyW(package, szAction, szInstall);
600
601     package->script = msi_alloc_zero(sizeof(MSISCRIPT));
602
603     package->script->InWhatSequence = SEQUENCE_INSTALL;
604
605     if (szPackagePath)   
606     {
607         LPWSTR p, check, path;
608  
609         path = strdupW(szPackagePath);
610         p = strrchrW(path,'\\');    
611         if (p)
612         {
613             p++;
614             *p=0;
615         }
616         else
617         {
618             msi_free(path);
619             path = msi_alloc(MAX_PATH*sizeof(WCHAR));
620             GetCurrentDirectoryW(MAX_PATH,path);
621             strcatW(path,cszbs);
622         }
623
624         check = msi_dup_property( package, cszSourceDir );
625         if (!check)
626             MSI_SetPropertyW(package, cszSourceDir, path);
627         msi_free(check);
628
629         check = msi_dup_property( package, cszSOURCEDIR );
630         if (!check)
631             MSI_SetPropertyW(package, cszSOURCEDIR, path);
632
633         msi_free( package->PackagePath );
634         package->PackagePath = path;
635
636         msi_free(check);
637     }
638
639     msi_parse_command_line( package, szCommandLine );
640
641     msi_apply_transforms( package );
642     msi_apply_patches( package );
643
644     if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
645     {
646         package->script->InWhatSequence |= SEQUENCE_UI;
647         rc = ACTION_ProcessUISequence(package);
648         ui = TRUE;
649         if (rc == ERROR_SUCCESS)
650         {
651             package->script->InWhatSequence |= SEQUENCE_EXEC;
652             rc = ACTION_ProcessExecSequence(package,TRUE);
653         }
654     }
655     else
656         rc = ACTION_ProcessExecSequence(package,FALSE);
657     
658     if (rc == -1)
659     {
660         /* install was halted but should be considered a success */
661         rc = ERROR_SUCCESS;
662     }
663
664     package->script->CurrentlyScripting= FALSE;
665
666     /* process the ending type action */
667     if (rc == ERROR_SUCCESS)
668         ACTION_PerformActionSequence(package,-1,ui);
669     else if (rc == ERROR_INSTALL_USEREXIT) 
670         ACTION_PerformActionSequence(package,-2,ui);
671     else if (rc == ERROR_INSTALL_SUSPEND) 
672         ACTION_PerformActionSequence(package,-4,ui);
673     else  /* failed */
674         ACTION_PerformActionSequence(package,-3,ui);
675
676     /* finish up running custom actions */
677     ACTION_FinishCustomActions(package);
678     
679     return rc;
680 }
681
682 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
683 {
684     UINT rc = ERROR_SUCCESS;
685     MSIRECORD * row = 0;
686     static const WCHAR ExecSeqQuery[] =
687         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
688          '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
689          'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
690          '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
691
692     static const WCHAR UISeqQuery[] =
693         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
694      '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
695      '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
696          ' ', '=',' ','%','i',0};
697
698     if (UI)
699         row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
700     else
701         row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
702
703     if (row)
704     {
705         LPCWSTR action, cond;
706
707         TRACE("Running the actions\n"); 
708
709         /* check conditions */
710         cond = MSI_RecordGetString(row,2);
711
712         /* this is a hack to skip errors in the condition code */
713         if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
714             goto end;
715
716         action = MSI_RecordGetString(row,1);
717         if (!action)
718         {
719             ERR("failed to fetch action\n");
720             rc = ERROR_FUNCTION_FAILED;
721             goto end;
722         }
723
724         if (UI)
725             rc = ACTION_PerformUIAction(package,action);
726         else
727             rc = ACTION_PerformAction(package,action,FALSE);
728 end:
729         msiobj_release(&row->hdr);
730     }
731     else
732         rc = ERROR_SUCCESS;
733
734     return rc;
735 }
736
737 typedef struct {
738     MSIPACKAGE* package;
739     BOOL UI;
740 } iterate_action_param;
741
742 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
743 {
744     iterate_action_param *iap= (iterate_action_param*)param;
745     UINT rc;
746     LPCWSTR cond, action;
747
748     action = MSI_RecordGetString(row,1);
749     if (!action)
750     {
751         ERR("Error is retrieving action name\n");
752         return ERROR_FUNCTION_FAILED;
753     }
754
755     /* check conditions */
756     cond = MSI_RecordGetString(row,2);
757
758     /* this is a hack to skip errors in the condition code */
759     if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
760     {
761         TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
762         return ERROR_SUCCESS;
763     }
764
765     if (iap->UI)
766         rc = ACTION_PerformUIAction(iap->package,action);
767     else
768         rc = ACTION_PerformAction(iap->package,action,FALSE);
769
770     msi_dialog_check_messages( NULL );
771
772     if (iap->package->CurrentInstallState != ERROR_SUCCESS )
773         rc = iap->package->CurrentInstallState;
774
775     if (rc == ERROR_FUNCTION_NOT_CALLED)
776         rc = ERROR_SUCCESS;
777
778     if (rc != ERROR_SUCCESS)
779         ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
780
781     return rc;
782 }
783
784 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
785 {
786     MSIQUERY * view;
787     UINT r;
788     static const WCHAR query[] =
789         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
790          '`','%','s','`',
791          ' ','W','H','E','R','E',' ', 
792          '`','S','e','q','u','e','n','c','e','`',' ',
793          '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
794          '`','S','e','q','u','e','n','c','e','`',0};
795     iterate_action_param iap;
796
797     /*
798      * FIXME: probably should be checking UILevel in the
799      *       ACTION_PerformUIAction/ACTION_PerformAction
800      *       rather than saving the UI level here. Those
801      *       two functions can be merged too.
802      */
803     iap.package = package;
804     iap.UI = TRUE;
805
806     TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
807
808     r = MSI_OpenQuery( package->db, &view, query, szTable );
809     if (r == ERROR_SUCCESS)
810     {
811         r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
812         msiobj_release(&view->hdr);
813     }
814
815     return r;
816 }
817
818 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
819 {
820     MSIQUERY * view;
821     UINT rc;
822     static const WCHAR ExecSeqQuery[] =
823         {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
824          '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
825          'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
826          '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
827          'O','R','D','E','R',' ', 'B','Y',' ',
828          '`','S','e','q','u','e','n','c','e','`',0 };
829     MSIRECORD * row = 0;
830     static const WCHAR IVQuery[] =
831         {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
832          ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
833          'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
834          'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
835          ' ','\'', 'I','n','s','t','a','l','l',
836          'V','a','l','i','d','a','t','e','\'', 0};
837     INT seq = 0;
838     iterate_action_param iap;
839
840     iap.package = package;
841     iap.UI = FALSE;
842
843     if (package->script->ExecuteSequenceRun)
844     {
845         TRACE("Execute Sequence already Run\n");
846         return ERROR_SUCCESS;
847     }
848
849     package->script->ExecuteSequenceRun = TRUE;
850
851     /* get the sequence number */
852     if (UIran)
853     {
854         row = MSI_QueryGetRecord(package->db, IVQuery);
855         if( !row )
856             return ERROR_FUNCTION_FAILED;
857         seq = MSI_RecordGetInteger(row,1);
858         msiobj_release(&row->hdr);
859     }
860
861     rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
862     if (rc == ERROR_SUCCESS)
863     {
864         TRACE("Running the actions\n");
865
866         rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
867         msiobj_release(&view->hdr);
868     }
869
870     return rc;
871 }
872
873 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
874 {
875     MSIQUERY * view;
876     UINT rc;
877     static const WCHAR ExecSeqQuery [] =
878         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
879          '`','I','n','s','t','a','l','l',
880          'U','I','S','e','q','u','e','n','c','e','`',
881          ' ','W','H','E','R','E',' ', 
882          '`','S','e','q','u','e','n','c','e','`',' ',
883          '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
884          '`','S','e','q','u','e','n','c','e','`',0};
885     iterate_action_param iap;
886
887     iap.package = package;
888     iap.UI = TRUE;
889
890     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
891     
892     if (rc == ERROR_SUCCESS)
893     {
894         TRACE("Running the actions\n"); 
895
896         rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
897         msiobj_release(&view->hdr);
898     }
899
900     return rc;
901 }
902
903 /********************************************************
904  * ACTION helper functions and functions that perform the actions
905  *******************************************************/
906 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, 
907                                         UINT* rc, BOOL force )
908 {
909     BOOL ret = FALSE; 
910     BOOL run = force;
911     int i;
912
913     if (!run && !package->script->CurrentlyScripting)
914         run = TRUE;
915    
916     if (!run)
917     {
918         if (strcmpW(action,szInstallFinalize) == 0 ||
919             strcmpW(action,szInstallExecute) == 0 ||
920             strcmpW(action,szInstallExecuteAgain) == 0) 
921                 run = TRUE;
922     }
923     
924     i = 0;
925     while (StandardActions[i].action != NULL)
926     {
927         if (strcmpW(StandardActions[i].action, action)==0)
928         {
929             if (!run)
930             {
931                 ui_actioninfo(package, action, TRUE, 0);
932                 *rc = schedule_action(package,INSTALL_SCRIPT,action);
933                 ui_actioninfo(package, action, FALSE, *rc);
934             }
935             else
936             {
937                 ui_actionstart(package, action);
938                 if (StandardActions[i].handler)
939                 {
940                     *rc = StandardActions[i].handler(package);
941                 }
942                 else
943                 {
944                     FIXME("unhandled standard action %s\n",debugstr_w(action));
945                     *rc = ERROR_SUCCESS;
946                 }
947             }
948             ret = TRUE;
949             break;
950         }
951         i++;
952     }
953     return ret;
954 }
955
956 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
957                                        UINT* rc, BOOL force )
958 {
959     BOOL ret=FALSE;
960     UINT arc;
961
962     arc = ACTION_CustomAction(package,action, force);
963
964     if (arc != ERROR_CALL_NOT_IMPLEMENTED)
965     {
966         *rc = arc;
967         ret = TRUE;
968     }
969     return ret;
970 }
971
972 /* 
973  * A lot of actions are really important even if they don't do anything
974  * explicit... Lots of properties are set at the beginning of the installation
975  * CostFinalize does a bunch of work to translate the directories and such
976  * 
977  * But until I get write access to the database that is hard, so I am going to
978  * hack it to see if I can get something to run.
979  */
980 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
981 {
982     UINT rc = ERROR_SUCCESS; 
983     BOOL handled;
984
985     TRACE("Performing action (%s)\n",debugstr_w(action));
986
987     handled = ACTION_HandleStandardAction(package, action, &rc, force);
988
989     if (!handled)
990         handled = ACTION_HandleCustomAction(package, action, &rc, force);
991
992     if (!handled)
993     {
994         FIXME("unhandled msi action %s\n",debugstr_w(action));
995         rc = ERROR_FUNCTION_NOT_CALLED;
996     }
997
998     return rc;
999 }
1000
1001 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
1002 {
1003     UINT rc = ERROR_SUCCESS;
1004     BOOL handled = FALSE;
1005
1006     TRACE("Performing action (%s)\n",debugstr_w(action));
1007
1008     handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1009
1010     if (!handled)
1011         handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
1012
1013     if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1014         handled = TRUE;
1015
1016     if (!handled)
1017     {
1018         FIXME("unhandled msi action %s\n",debugstr_w(action));
1019         rc = ERROR_FUNCTION_NOT_CALLED;
1020     }
1021
1022     return rc;
1023 }
1024
1025
1026 /*
1027  * Actual Action Handlers
1028  */
1029
1030 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1031 {
1032     MSIPACKAGE *package = (MSIPACKAGE*)param;
1033     LPCWSTR dir;
1034     LPWSTR full_path;
1035     MSIRECORD *uirow;
1036     MSIFOLDER *folder;
1037
1038     dir = MSI_RecordGetString(row,1);
1039     if (!dir)
1040     {
1041         ERR("Unable to get folder id\n");
1042         return ERROR_SUCCESS;
1043     }
1044
1045     full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1046     if (!full_path)
1047     {
1048         ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1049         return ERROR_SUCCESS;
1050     }
1051
1052     TRACE("Folder is %s\n",debugstr_w(full_path));
1053
1054     /* UI stuff */
1055     uirow = MSI_CreateRecord(1);
1056     MSI_RecordSetStringW(uirow,1,full_path);
1057     ui_actiondata(package,szCreateFolders,uirow);
1058     msiobj_release( &uirow->hdr );
1059
1060     if (folder->State == 0)
1061         create_full_pathW(full_path);
1062
1063     folder->State = 3;
1064
1065     msi_free(full_path);
1066     return ERROR_SUCCESS;
1067 }
1068
1069 /* FIXME: probably should merge this with the above function */
1070 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1071 {
1072     UINT rc = ERROR_SUCCESS;
1073     MSIFOLDER *folder;
1074     LPWSTR install_path;
1075
1076     install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1077     if (!install_path)
1078         return ERROR_FUNCTION_FAILED; 
1079
1080     /* create the path */
1081     if (folder->State == 0)
1082     {
1083         create_full_pathW(install_path);
1084         folder->State = 2;
1085     }
1086     msi_free(install_path);
1087
1088     return rc;
1089 }
1090
1091 UINT msi_create_component_directories( MSIPACKAGE *package )
1092 {
1093     MSICOMPONENT *comp;
1094
1095     /* create all the folders required by the components are going to install */
1096     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1097     {
1098         if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1099             continue;
1100         msi_create_directory( package, comp->Directory );
1101     }
1102
1103     return ERROR_SUCCESS;
1104 }
1105
1106 /*
1107  * Also we cannot enable/disable components either, so for now I am just going 
1108  * to do all the directories for all the components.
1109  */
1110 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1111 {
1112     static const WCHAR ExecSeqQuery[] =
1113         {'S','E','L','E','C','T',' ',
1114          '`','D','i','r','e','c','t','o','r','y','_','`',
1115          ' ','F','R','O','M',' ',
1116          '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1117     UINT rc;
1118     MSIQUERY *view;
1119
1120     /* create all the empty folders specified in the CreateFolder table */
1121     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1122     if (rc != ERROR_SUCCESS)
1123         return ERROR_SUCCESS;
1124
1125     rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1126     msiobj_release(&view->hdr);
1127
1128     msi_create_component_directories( package );
1129
1130     return rc;
1131 }
1132
1133 static UINT load_component( MSIRECORD *row, LPVOID param )
1134 {
1135     MSIPACKAGE *package = param;
1136     MSICOMPONENT *comp;
1137
1138     comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1139     if (!comp)
1140         return ERROR_FUNCTION_FAILED;
1141
1142     list_add_tail( &package->components, &comp->entry );
1143
1144     /* fill in the data */
1145     comp->Component = msi_dup_record_field( row, 1 );
1146
1147     TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1148
1149     comp->ComponentId = msi_dup_record_field( row, 2 );
1150     comp->Directory = msi_dup_record_field( row, 3 );
1151     comp->Attributes = MSI_RecordGetInteger(row,4);
1152     comp->Condition = msi_dup_record_field( row, 5 );
1153     comp->KeyPath = msi_dup_record_field( row, 6 );
1154
1155     comp->Installed = INSTALLSTATE_UNKNOWN;
1156     msi_component_set_state( comp, INSTALLSTATE_UNKNOWN );
1157
1158     return ERROR_SUCCESS;
1159 }
1160
1161 static UINT load_all_components( MSIPACKAGE *package )
1162 {
1163     static const WCHAR query[] = {
1164         'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ', 
1165          '`','C','o','m','p','o','n','e','n','t','`',0 };
1166     MSIQUERY *view;
1167     UINT r;
1168
1169     if (!list_empty(&package->components))
1170         return ERROR_SUCCESS;
1171
1172     r = MSI_DatabaseOpenViewW( package->db, query, &view );
1173     if (r != ERROR_SUCCESS)
1174         return r;
1175
1176     r = MSI_IterateRecords(view, NULL, load_component, package);
1177     msiobj_release(&view->hdr);
1178     return r;
1179 }
1180
1181 typedef struct {
1182     MSIPACKAGE *package;
1183     MSIFEATURE *feature;
1184 } _ilfs;
1185
1186 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1187 {
1188     ComponentList *cl;
1189
1190     cl = msi_alloc( sizeof (*cl) );
1191     if ( !cl )
1192         return ERROR_NOT_ENOUGH_MEMORY;
1193     cl->component = comp;
1194     list_add_tail( &feature->Components, &cl->entry );
1195
1196     return ERROR_SUCCESS;
1197 }
1198
1199 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1200 {
1201     FeatureList *fl;
1202
1203     fl = msi_alloc( sizeof(*fl) );
1204     if ( !fl )
1205         return ERROR_NOT_ENOUGH_MEMORY;
1206     fl->feature = child;
1207     list_add_tail( &parent->Children, &fl->entry );
1208
1209     return ERROR_SUCCESS;
1210 }
1211
1212 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1213 {
1214     _ilfs* ilfs= (_ilfs*)param;
1215     LPCWSTR component;
1216     MSICOMPONENT *comp;
1217
1218     component = MSI_RecordGetString(row,1);
1219
1220     /* check to see if the component is already loaded */
1221     comp = get_loaded_component( ilfs->package, component );
1222     if (!comp)
1223     {
1224         ERR("unknown component %s\n", debugstr_w(component));
1225         return ERROR_FUNCTION_FAILED;
1226     }
1227
1228     add_feature_component( ilfs->feature, comp );
1229     comp->Enabled = TRUE;
1230
1231     return ERROR_SUCCESS;
1232 }
1233
1234 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1235 {
1236     MSIFEATURE *feature;
1237
1238     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1239     {
1240         if ( !lstrcmpW( feature->Feature, name ) )
1241             return feature;
1242     }
1243
1244     return NULL;
1245 }
1246
1247 static UINT load_feature(MSIRECORD * row, LPVOID param)
1248 {
1249     MSIPACKAGE* package = (MSIPACKAGE*)param;
1250     MSIFEATURE* feature;
1251     static const WCHAR Query1[] = 
1252         {'S','E','L','E','C','T',' ',
1253          '`','C','o','m','p','o','n','e','n','t','_','`',
1254          ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1255          'C','o','m','p','o','n','e','n','t','s','`',' ',
1256          'W','H','E','R','E',' ',
1257          '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1258     MSIQUERY * view;
1259     UINT    rc;
1260     _ilfs ilfs;
1261
1262     /* fill in the data */
1263
1264     feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1265     if (!feature)
1266         return ERROR_NOT_ENOUGH_MEMORY;
1267
1268     list_init( &feature->Children );
1269     list_init( &feature->Components );
1270     
1271     feature->Feature = msi_dup_record_field( row, 1 );
1272
1273     TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1274
1275     feature->Feature_Parent = msi_dup_record_field( row, 2 );
1276     feature->Title = msi_dup_record_field( row, 3 );
1277     feature->Description = msi_dup_record_field( row, 4 );
1278
1279     if (!MSI_RecordIsNull(row,5))
1280         feature->Display = MSI_RecordGetInteger(row,5);
1281   
1282     feature->Level= MSI_RecordGetInteger(row,6);
1283     feature->Directory = msi_dup_record_field( row, 7 );
1284     feature->Attributes = MSI_RecordGetInteger(row,8);
1285
1286     feature->Installed = INSTALLSTATE_UNKNOWN;
1287     msi_feature_set_state( feature, INSTALLSTATE_UNKNOWN );
1288
1289     list_add_tail( &package->features, &feature->entry );
1290
1291     /* load feature components */
1292
1293     rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1294     if (rc != ERROR_SUCCESS)
1295         return ERROR_SUCCESS;
1296
1297     ilfs.package = package;
1298     ilfs.feature = feature;
1299
1300     MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1301     msiobj_release(&view->hdr);
1302
1303     return ERROR_SUCCESS;
1304 }
1305
1306 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1307 {
1308     MSIPACKAGE* package = (MSIPACKAGE*)param;
1309     MSIFEATURE *parent, *child;
1310
1311     child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1312     if (!child)
1313         return ERROR_FUNCTION_FAILED;
1314
1315     if (!child->Feature_Parent)
1316         return ERROR_SUCCESS;
1317
1318     parent = find_feature_by_name( package, child->Feature_Parent );
1319     if (!parent)
1320         return ERROR_FUNCTION_FAILED;
1321
1322     add_feature_child( parent, child );
1323     return ERROR_SUCCESS;
1324 }
1325
1326 static UINT load_all_features( MSIPACKAGE *package )
1327 {
1328     static const WCHAR query[] = {
1329         'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1330         '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1331         ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1332     MSIQUERY *view;
1333     UINT r;
1334
1335     if (!list_empty(&package->features))
1336         return ERROR_SUCCESS;
1337  
1338     r = MSI_DatabaseOpenViewW( package->db, query, &view );
1339     if (r != ERROR_SUCCESS)
1340         return r;
1341
1342     r = MSI_IterateRecords( view, NULL, load_feature, package );
1343     if (r != ERROR_SUCCESS)
1344         return r;
1345
1346     r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1347     msiobj_release( &view->hdr );
1348
1349     return r;
1350 }
1351
1352 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1353 {
1354     if (!p)
1355         return p;
1356     p = strchrW(p, ch);
1357     if (!p)
1358         return p;
1359     *p = 0;
1360     return p+1;
1361 }
1362
1363 static UINT load_file(MSIRECORD *row, LPVOID param)
1364 {
1365     MSIPACKAGE* package = (MSIPACKAGE*)param;
1366     LPCWSTR component;
1367     MSIFILE *file;
1368
1369     /* fill in the data */
1370
1371     file = msi_alloc_zero( sizeof (MSIFILE) );
1372     if (!file)
1373         return ERROR_NOT_ENOUGH_MEMORY;
1374  
1375     file->File = msi_dup_record_field( row, 1 );
1376
1377     component = MSI_RecordGetString( row, 2 );
1378     file->Component = get_loaded_component( package, component );
1379
1380     if (!file->Component)
1381         ERR("Unfound Component %s\n",debugstr_w(component));
1382
1383     file->FileName = msi_dup_record_field( row, 3 );
1384     reduce_to_longfilename( file->FileName );
1385
1386     file->ShortName = msi_dup_record_field( row, 3 );
1387     file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1388     
1389     file->FileSize = MSI_RecordGetInteger( row, 4 );
1390     file->Version = msi_dup_record_field( row, 5 );
1391     file->Language = msi_dup_record_field( row, 6 );
1392     file->Attributes = MSI_RecordGetInteger( row, 7 );
1393     file->Sequence = MSI_RecordGetInteger( row, 8 );
1394
1395     file->state = msifs_invalid;
1396
1397     /* if the compressed bits are not set in the file attributes,
1398      * then read the information from the package word count property
1399      */
1400     if (file->Attributes & msidbFileAttributesCompressed)
1401     {
1402         file->IsCompressed = TRUE;
1403     }
1404     else if (file->Attributes & msidbFileAttributesNoncompressed)
1405     {
1406         file->IsCompressed = FALSE;
1407     }
1408     else
1409     {
1410         file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1411     }
1412
1413     TRACE("File Loaded (%s)\n",debugstr_w(file->File));  
1414
1415     list_add_tail( &package->files, &file->entry );
1416  
1417     return ERROR_SUCCESS;
1418 }
1419
1420 static UINT load_all_files(MSIPACKAGE *package)
1421 {
1422     MSIQUERY * view;
1423     UINT rc;
1424     static const WCHAR Query[] =
1425         {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1426          '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1427          '`','S','e','q','u','e','n','c','e','`', 0};
1428
1429     if (!list_empty(&package->files))
1430         return ERROR_SUCCESS;
1431
1432     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1433     if (rc != ERROR_SUCCESS)
1434         return ERROR_SUCCESS;
1435
1436     rc = MSI_IterateRecords(view, NULL, load_file, package);
1437     msiobj_release(&view->hdr);
1438
1439     return ERROR_SUCCESS;
1440 }
1441
1442
1443 /*
1444  * I am not doing any of the costing functionality yet.
1445  * Mostly looking at doing the Component and Feature loading
1446  *
1447  * The native MSI does A LOT of modification to tables here. Mostly adding
1448  * a lot of temporary columns to the Feature and Component tables.
1449  *
1450  *    note: Native msi also tracks the short filename. But I am only going to
1451  *          track the long ones.  Also looking at this directory table
1452  *          it appears that the directory table does not get the parents
1453  *          resolved base on property only based on their entries in the
1454  *          directory table.
1455  */
1456 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1457 {
1458     static const WCHAR szCosting[] =
1459         {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1460     static const WCHAR szZero[] = { '0', 0 };
1461
1462     if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1463         return ERROR_SUCCESS;
1464
1465     MSI_SetPropertyW(package, szCosting, szZero);
1466     MSI_SetPropertyW(package, cszRootDrive, c_colon);
1467
1468     load_all_components( package );
1469     load_all_features( package );
1470     load_all_files( package );
1471
1472     return ERROR_SUCCESS;
1473 }
1474
1475 static UINT execute_script(MSIPACKAGE *package, UINT script )
1476 {
1477     int i;
1478     UINT rc = ERROR_SUCCESS;
1479
1480     TRACE("Executing Script %i\n",script);
1481
1482     if (!package->script)
1483     {
1484         ERR("no script!\n");
1485         return ERROR_FUNCTION_FAILED;
1486     }
1487
1488     for (i = 0; i < package->script->ActionCount[script]; i++)
1489     {
1490         LPWSTR action;
1491         action = package->script->Actions[script][i];
1492         ui_actionstart(package, action);
1493         TRACE("Executing Action (%s)\n",debugstr_w(action));
1494         rc = ACTION_PerformAction(package, action, TRUE);
1495         if (rc != ERROR_SUCCESS)
1496             break;
1497     }
1498     msi_free_action_script(package, script);
1499     return rc;
1500 }
1501
1502 static UINT ACTION_FileCost(MSIPACKAGE *package)
1503 {
1504     return ERROR_SUCCESS;
1505 }
1506
1507 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1508 {
1509     static const WCHAR Query[] =
1510         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1511          '`','D','i','r','e','c', 't','o','r','y','`',' ',
1512          'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1513          ' ','=',' ','\'','%','s','\'',
1514          0};
1515     static const WCHAR szDot[] = { '.',0 };
1516     static WCHAR szEmpty[] = { 0 };
1517     LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1518     LPCWSTR parent;
1519     MSIRECORD *row;
1520     MSIFOLDER *folder;
1521
1522     TRACE("Looking for dir %s\n",debugstr_w(dir));
1523
1524     folder = get_loaded_folder( package, dir );
1525     if (folder)
1526         return folder;
1527
1528     TRACE("Working to load %s\n",debugstr_w(dir));
1529
1530     folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1531     if (!folder)
1532         return NULL;
1533
1534     folder->Directory = strdupW(dir);
1535
1536     row = MSI_QueryGetRecord(package->db, Query, dir);
1537     if (!row)
1538         return NULL;
1539
1540     p = msi_dup_record_field(row, 3);
1541
1542     /* split src and target dir */
1543     tgt_short = p;
1544     src_short = folder_split_path( p, ':' );
1545
1546     /* split the long and short paths */
1547     tgt_long = folder_split_path( tgt_short, '|' );
1548     src_long = folder_split_path( src_short, '|' );
1549
1550     /* check for no-op dirs */
1551     if (!lstrcmpW(szDot, tgt_short))
1552         tgt_short = szEmpty;
1553     if (!lstrcmpW(szDot, src_short))
1554         src_short = szEmpty;
1555
1556     if (!tgt_long)
1557         tgt_long = tgt_short;
1558         
1559     if (!src_short) {
1560         src_short = tgt_short;
1561         src_long = tgt_long;
1562     }
1563     
1564     if (!src_long)
1565         src_long = src_short;
1566
1567     /* FIXME: use the target short path too */
1568     folder->TargetDefault = strdupW(tgt_long);
1569     folder->SourceShortPath = strdupW(src_short);
1570     folder->SourceLongPath = strdupW(src_long);
1571     msi_free(p);
1572
1573     TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1574     TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1575     TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1576
1577     parent = MSI_RecordGetString(row, 2);
1578     if (parent) 
1579     {
1580         folder->Parent = load_folder( package, parent );
1581         if ( folder->Parent )
1582             TRACE("loaded parent %p %s\n", folder->Parent,
1583                   debugstr_w(folder->Parent->Directory));
1584         else
1585             ERR("failed to load parent folder %s\n", debugstr_w(parent));
1586     }
1587
1588     folder->Property = msi_dup_property( package, dir );
1589
1590     msiobj_release(&row->hdr);
1591
1592     list_add_tail( &package->folders, &folder->entry );
1593
1594     TRACE("%s returning %p\n",debugstr_w(dir),folder);
1595
1596     return folder;
1597 }
1598
1599 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1600 {
1601     MSICOMPONENT *comp;
1602
1603     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1604     {
1605         INSTALLSTATE res;
1606
1607         if (!comp->ComponentId)
1608             continue;
1609
1610         res = MsiGetComponentPathW( package->ProductCode,
1611                                     comp->ComponentId, NULL, NULL);
1612         if (res < 0)
1613             res = INSTALLSTATE_ABSENT;
1614         comp->Installed = res;
1615     }
1616 }
1617
1618 /* scan for and update current install states */
1619 static void ACTION_UpdateFeatureInstallStates(MSIPACKAGE *package)
1620 {
1621     MSICOMPONENT *comp;
1622     MSIFEATURE *feature;
1623
1624     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1625     {
1626         ComponentList *cl;
1627         INSTALLSTATE res = INSTALLSTATE_ABSENT;
1628
1629         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1630         {
1631             comp= cl->component;
1632
1633             if (!comp->ComponentId)
1634             {
1635                 res = INSTALLSTATE_ABSENT;
1636                 break;
1637             }
1638
1639             if (res == INSTALLSTATE_ABSENT)
1640                 res = comp->Installed;
1641             else
1642             {
1643                 if (res == comp->Installed)
1644                     continue;
1645
1646                 if (res != INSTALLSTATE_DEFAULT && res != INSTALLSTATE_LOCAL &&
1647                     res != INSTALLSTATE_SOURCE)
1648                 {
1649                     res = INSTALLSTATE_INCOMPLETE;
1650                 }
1651             }
1652         }
1653         feature->Installed = res;
1654     }
1655 }
1656
1657 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property, 
1658                                     INSTALLSTATE state)
1659 {
1660     static const WCHAR all[]={'A','L','L',0};
1661     LPWSTR override;
1662     MSIFEATURE *feature;
1663
1664     override = msi_dup_property( package, property );
1665     if (!override)
1666         return FALSE;
1667
1668     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1669     {
1670         if (strcmpiW(override,all)==0)
1671             msi_feature_set_state( feature, state );
1672         else
1673         {
1674             LPWSTR ptr = override;
1675             LPWSTR ptr2 = strchrW(override,',');
1676
1677             while (ptr)
1678             {
1679                 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1680                     || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1681                 {
1682                     msi_feature_set_state( feature, state );
1683                     break;
1684                 }
1685                 if (ptr2)
1686                 {
1687                     ptr=ptr2+1;
1688                     ptr2 = strchrW(ptr,',');
1689                 }
1690                 else
1691                     break;
1692             }
1693         }
1694     }
1695     msi_free(override);
1696
1697     return TRUE;
1698 }
1699
1700 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1701 {
1702     int install_level;
1703     static const WCHAR szlevel[] =
1704         {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1705     static const WCHAR szAddLocal[] =
1706         {'A','D','D','L','O','C','A','L',0};
1707     static const WCHAR szRemove[] =
1708         {'R','E','M','O','V','E',0};
1709     static const WCHAR szReinstall[] =
1710         {'R','E','I','N','S','T','A','L','L',0};
1711     BOOL override = FALSE;
1712     MSICOMPONENT* component;
1713     MSIFEATURE *feature;
1714
1715
1716     /* I do not know if this is where it should happen.. but */
1717
1718     TRACE("Checking Install Level\n");
1719
1720     install_level = msi_get_property_int( package, szlevel, 1 );
1721
1722     /* ok here is the _real_ rub
1723      * all these activation/deactivation things happen in order and things
1724      * later on the list override things earlier on the list.
1725      * 1) INSTALLLEVEL processing
1726      * 2) ADDLOCAL
1727      * 3) REMOVE
1728      * 4) ADDSOURCE
1729      * 5) ADDDEFAULT
1730      * 6) REINSTALL
1731      * 7) COMPADDLOCAL
1732      * 8) COMPADDSOURCE
1733      * 9) FILEADDLOCAL
1734      * 10) FILEADDSOURCE
1735      * 11) FILEADDDEFAULT
1736      * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1737      * ignored for all the features. seems strange, especially since it is not
1738      * documented anywhere, but it is how it works.
1739      *
1740      * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1741      * REMOVE are the big ones, since we don't handle administrative installs
1742      * yet anyway.
1743      */
1744     override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1745     override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1746     override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1747
1748     if (!override)
1749     {
1750         LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1751         {
1752             BOOL feature_state = ((feature->Level > 0) &&
1753                              (feature->Level <= install_level));
1754
1755             if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1756             {
1757                 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1758                     msi_feature_set_state( feature, INSTALLSTATE_SOURCE );
1759                 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1760                     msi_feature_set_state( feature, INSTALLSTATE_ADVERTISED );
1761                 else
1762                     msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1763             }
1764         }
1765
1766         /* disable child features of unselected parent features */
1767         LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1768         {
1769             FeatureList *fl;
1770
1771             if (feature->Level > 0 && feature->Level <= install_level)
1772                 continue;
1773
1774             LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1775                 msi_feature_set_state( fl->feature, INSTALLSTATE_UNKNOWN );
1776         }
1777     }
1778     else
1779     {
1780         /* set the Preselected Property */
1781         static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1782         static const WCHAR szOne[] = { '1', 0 };
1783
1784         MSI_SetPropertyW(package,szPreselected,szOne);
1785     }
1786
1787     /*
1788      * now we want to enable or disable components base on feature
1789      */
1790
1791     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1792     {
1793         ComponentList *cl;
1794
1795         TRACE("Examining Feature %s (Installed %i, Action %i)\n",
1796             debugstr_w(feature->Feature), feature->Installed, feature->Action);
1797
1798         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1799         {
1800             component = cl->component;
1801
1802             if (!component->Enabled)
1803                 continue;
1804
1805             if (component->Attributes & msidbComponentAttributesOptional)
1806                 msi_component_set_state( component, INSTALLSTATE_DEFAULT );
1807             else
1808             {
1809                 if (component->Attributes & msidbComponentAttributesSourceOnly)
1810                     msi_component_set_state( component, INSTALLSTATE_SOURCE );
1811                 else
1812                     msi_component_set_state( component, INSTALLSTATE_LOCAL );
1813             }
1814
1815             if (component->ForceLocalState)
1816                 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1817
1818             if (feature->Attributes == msidbFeatureAttributesFavorLocal)
1819             {
1820                 if (!(component->Attributes & msidbComponentAttributesSourceOnly))
1821                     msi_component_set_state( component, INSTALLSTATE_LOCAL );
1822             }
1823             else if (feature->Attributes == msidbFeatureAttributesFavorSource)
1824             {
1825                 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1826                     (component->Action == INSTALLSTATE_ABSENT) ||
1827                     (component->Action == INSTALLSTATE_ADVERTISED) ||
1828                     (component->Action == INSTALLSTATE_DEFAULT))
1829                     msi_component_set_state( component, INSTALLSTATE_SOURCE );
1830             }
1831             else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1832             {
1833                 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1834                     (component->Action == INSTALLSTATE_ABSENT))
1835                     msi_component_set_state( component, INSTALLSTATE_ADVERTISED );
1836             }
1837             else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1838             {
1839                 if (component->Action == INSTALLSTATE_UNKNOWN)
1840                     msi_component_set_state( component, INSTALLSTATE_ABSENT );
1841             }
1842             else if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1843                 msi_component_set_state( component, INSTALLSTATE_UNKNOWN );
1844
1845             if (component->ForceLocalState && feature->Action == INSTALLSTATE_SOURCE)
1846                 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1847         }
1848     }
1849
1850     LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1851     {
1852         if (component->Action == INSTALLSTATE_DEFAULT)
1853         {
1854             TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1855             msi_component_set_state( component, INSTALLSTATE_LOCAL );
1856         }
1857
1858         TRACE("Result: Component %s (Installed %i, Action %i)\n",
1859             debugstr_w(component->Component), component->Installed, component->Action);
1860     }
1861
1862
1863     return ERROR_SUCCESS;
1864 }
1865
1866 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1867 {
1868     MSIPACKAGE *package = (MSIPACKAGE*)param;
1869     LPCWSTR name;
1870     LPWSTR path;
1871
1872     name = MSI_RecordGetString(row,1);
1873
1874     /* This helper function now does ALL the work */
1875     TRACE("Dir %s ...\n",debugstr_w(name));
1876     load_folder(package,name);
1877     path = resolve_folder(package,name,FALSE,TRUE,NULL);
1878     TRACE("resolves to %s\n",debugstr_w(path));
1879     msi_free(path);
1880
1881     return ERROR_SUCCESS;
1882 }
1883
1884 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1885 {
1886     MSIPACKAGE *package = (MSIPACKAGE*)param;
1887     LPCWSTR name;
1888     MSIFEATURE *feature;
1889
1890     name = MSI_RecordGetString( row, 1 );
1891
1892     feature = get_loaded_feature( package, name );
1893     if (!feature)
1894         ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1895     else
1896     {
1897         LPCWSTR Condition;
1898         Condition = MSI_RecordGetString(row,3);
1899
1900         if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1901         {
1902             int level = MSI_RecordGetInteger(row,2);
1903             TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1904             feature->Level = level;
1905         }
1906     }
1907     return ERROR_SUCCESS;
1908 }
1909
1910 LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1911 {
1912     static const WCHAR name_fmt[] =
1913         {'%','u','.','%','u','.','%','u','.','%','u',0};
1914     static WCHAR name[] = {'\\',0};
1915     VS_FIXEDFILEINFO *lpVer;
1916     WCHAR filever[0x100];
1917     LPVOID version;
1918     DWORD versize;
1919     DWORD handle;
1920     UINT sz;
1921
1922     TRACE("%s\n", debugstr_w(filename));
1923
1924     versize = GetFileVersionInfoSizeW( filename, &handle );
1925     if (!versize)
1926         return NULL;
1927
1928     version = msi_alloc( versize );
1929     GetFileVersionInfoW( filename, 0, versize, version );
1930
1931     VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz );
1932     msi_free( version );
1933
1934     sprintfW( filever, name_fmt,
1935         HIWORD(lpVer->dwFileVersionMS),
1936         LOWORD(lpVer->dwFileVersionMS),
1937         HIWORD(lpVer->dwFileVersionLS),
1938         LOWORD(lpVer->dwFileVersionLS));
1939
1940     return strdupW( filever );
1941 }
1942
1943 static UINT msi_check_file_install_states( MSIPACKAGE *package )
1944 {
1945     LPWSTR file_version;
1946     MSIFILE *file;
1947
1948     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1949     {
1950         MSICOMPONENT* comp = file->Component;
1951         LPWSTR p;
1952
1953         if (!comp)
1954             continue;
1955
1956         if (file->IsCompressed)
1957             comp->ForceLocalState = TRUE;
1958
1959         /* calculate target */
1960         p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1961
1962         msi_free(file->TargetPath);
1963
1964         TRACE("file %s is named %s\n",
1965                debugstr_w(file->File), debugstr_w(file->FileName));
1966
1967         file->TargetPath = build_directory_name(2, p, file->FileName);
1968
1969         msi_free(p);
1970
1971         TRACE("file %s resolves to %s\n",
1972                debugstr_w(file->File), debugstr_w(file->TargetPath));
1973
1974         /* don't check files of components that aren't installed */
1975         if (comp->Installed == INSTALLSTATE_UNKNOWN ||
1976             comp->Installed == INSTALLSTATE_ABSENT)
1977         {
1978             file->state = msifs_missing;  /* assume files are missing */
1979             continue;
1980         }
1981
1982         if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1983         {
1984             file->state = msifs_missing;
1985             comp->Cost += file->FileSize;
1986             comp->Installed = INSTALLSTATE_INCOMPLETE;
1987             continue;
1988         }
1989
1990         if (file->Version &&
1991             (file_version = msi_get_disk_file_version( file->TargetPath )))
1992         {
1993             TRACE("new %s old %s\n", debugstr_w(file->Version),
1994                   debugstr_w(file_version));
1995             /* FIXME: seems like a bad way to compare version numbers */
1996             if (lstrcmpiW(file_version, file->Version)<0)
1997             {
1998                 file->state = msifs_overwrite;
1999                 comp->Cost += file->FileSize;
2000                 comp->Installed = INSTALLSTATE_INCOMPLETE;
2001             }
2002             else
2003                 file->state = msifs_present;
2004             msi_free( file_version );
2005         }
2006         else
2007             file->state = msifs_present;
2008     }
2009
2010     return ERROR_SUCCESS;
2011 }
2012
2013 /*
2014  * A lot is done in this function aside from just the costing.
2015  * The costing needs to be implemented at some point but for now I am going
2016  * to focus on the directory building
2017  *
2018  */
2019 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2020 {
2021     static const WCHAR ExecSeqQuery[] =
2022         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2023          '`','D','i','r','e','c','t','o','r','y','`',0};
2024     static const WCHAR ConditionQuery[] =
2025         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2026          '`','C','o','n','d','i','t','i','o','n','`',0};
2027     static const WCHAR szCosting[] =
2028         {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2029     static const WCHAR szlevel[] =
2030         {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2031     static const WCHAR szOne[] = { '1', 0 };
2032     MSICOMPONENT *comp;
2033     UINT rc;
2034     MSIQUERY * view;
2035     LPWSTR level;
2036
2037     if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
2038         return ERROR_SUCCESS;
2039
2040     TRACE("Building Directory properties\n");
2041
2042     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2043     if (rc == ERROR_SUCCESS)
2044     {
2045         rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2046                         package);
2047         msiobj_release(&view->hdr);
2048     }
2049
2050     /* read components states from the registry */
2051     ACTION_GetComponentInstallStates(package);
2052
2053     TRACE("File calculations\n");
2054     msi_check_file_install_states( package );
2055
2056     TRACE("Evaluating Condition Table\n");
2057
2058     rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2059     if (rc == ERROR_SUCCESS)
2060     {
2061         rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2062                     package);
2063         msiobj_release(&view->hdr);
2064     }
2065
2066     TRACE("Enabling or Disabling Components\n");
2067     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2068     {
2069         if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2070         {
2071             TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2072             comp->Enabled = FALSE;
2073         }
2074     }
2075
2076     MSI_SetPropertyW(package,szCosting,szOne);
2077     /* set default run level if not set */
2078     level = msi_dup_property( package, szlevel );
2079     if (!level)
2080         MSI_SetPropertyW(package,szlevel, szOne);
2081     msi_free(level);
2082
2083     ACTION_UpdateFeatureInstallStates(package);
2084
2085     return MSI_SetFeatureStates(package);
2086 }
2087
2088 /* OK this value is "interpreted" and then formatted based on the 
2089    first few characters */
2090 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type, 
2091                          DWORD *size)
2092 {
2093     LPSTR data = NULL;
2094     if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2095     {
2096         if (value[1]=='x')
2097         {
2098             LPWSTR ptr;
2099             CHAR byte[5];
2100             LPWSTR deformated = NULL;
2101             int count;
2102
2103             deformat_string(package, &value[2], &deformated);
2104
2105             /* binary value type */
2106             ptr = deformated;
2107             *type = REG_BINARY;
2108             if (strlenW(ptr)%2)
2109                 *size = (strlenW(ptr)/2)+1;
2110             else
2111                 *size = strlenW(ptr)/2;
2112
2113             data = msi_alloc(*size);
2114
2115             byte[0] = '0'; 
2116             byte[1] = 'x'; 
2117             byte[4] = 0; 
2118             count = 0;
2119             /* if uneven pad with a zero in front */
2120             if (strlenW(ptr)%2)
2121             {
2122                 byte[2]= '0';
2123                 byte[3]= *ptr;
2124                 ptr++;
2125                 data[count] = (BYTE)strtol(byte,NULL,0);
2126                 count ++;
2127                 TRACE("Uneven byte count\n");
2128             }
2129             while (*ptr)
2130             {
2131                 byte[2]= *ptr;
2132                 ptr++;
2133                 byte[3]= *ptr;
2134                 ptr++;
2135                 data[count] = (BYTE)strtol(byte,NULL,0);
2136                 count ++;
2137             }
2138             msi_free(deformated);
2139
2140             TRACE("Data %i bytes(%i)\n",*size,count);
2141         }
2142         else
2143         {
2144             LPWSTR deformated;
2145             LPWSTR p;
2146             DWORD d = 0;
2147             deformat_string(package, &value[1], &deformated);
2148
2149             *type=REG_DWORD; 
2150             *size = sizeof(DWORD);
2151             data = msi_alloc(*size);
2152             p = deformated;
2153             if (*p == '-')
2154                 p++;
2155             while (*p)
2156             {
2157                 if ( (*p < '0') || (*p > '9') )
2158                     break;
2159                 d *= 10;
2160                 d += (*p - '0');
2161                 p++;
2162             }
2163             if (deformated[0] == '-')
2164                 d = -d;
2165             *(LPDWORD)data = d;
2166             TRACE("DWORD %i\n",*(LPDWORD)data);
2167
2168             msi_free(deformated);
2169         }
2170     }
2171     else
2172     {
2173         static const WCHAR szMulti[] = {'[','~',']',0};
2174         LPCWSTR ptr;
2175         *type=REG_SZ;
2176
2177         if (value[0]=='#')
2178         {
2179             if (value[1]=='%')
2180             {
2181                 ptr = &value[2];
2182                 *type=REG_EXPAND_SZ;
2183             }
2184             else
2185                 ptr = &value[1];
2186          }
2187          else
2188             ptr=value;
2189
2190         if (strstrW(value,szMulti))
2191             *type = REG_MULTI_SZ;
2192
2193         *size = deformat_string(package, ptr,(LPWSTR*)&data);
2194     }
2195     return data;
2196 }
2197
2198 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2199 {
2200     MSIPACKAGE *package = (MSIPACKAGE*)param;
2201     static const WCHAR szHCR[] = 
2202         {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2203          'R','O','O','T','\\',0};
2204     static const WCHAR szHCU[] =
2205         {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2206          'U','S','E','R','\\',0};
2207     static const WCHAR szHLM[] =
2208         {'H','K','E','Y','_','L','O','C','A','L','_',
2209          'M','A','C','H','I','N','E','\\',0};
2210     static const WCHAR szHU[] =
2211         {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2212
2213     LPSTR value_data = NULL;
2214     HKEY  root_key, hkey;
2215     DWORD type,size;
2216     LPWSTR  deformated;
2217     LPCWSTR szRoot, component, name, key, value;
2218     MSICOMPONENT *comp;
2219     MSIRECORD * uirow;
2220     LPWSTR uikey;
2221     INT   root;
2222     BOOL check_first = FALSE;
2223     UINT rc;
2224
2225     ui_progress(package,2,0,0,0);
2226
2227     value = NULL;
2228     key = NULL;
2229     uikey = NULL;
2230     name = NULL;
2231
2232     component = MSI_RecordGetString(row, 6);
2233     comp = get_loaded_component(package,component);
2234     if (!comp)
2235         return ERROR_SUCCESS;
2236
2237     if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2238     {
2239         TRACE("Skipping write due to disabled component %s\n",
2240                         debugstr_w(component));
2241
2242         comp->Action = comp->Installed;
2243
2244         return ERROR_SUCCESS;
2245     }
2246
2247     comp->Action = INSTALLSTATE_LOCAL;
2248
2249     name = MSI_RecordGetString(row, 4);
2250     if( MSI_RecordIsNull(row,5) && name )
2251     {
2252         /* null values can have special meanings */
2253         if (name[0]=='-' && name[1] == 0)
2254                 return ERROR_SUCCESS;
2255         else if ((name[0]=='+' && name[1] == 0) || 
2256                  (name[0] == '*' && name[1] == 0))
2257                 name = NULL;
2258         check_first = TRUE;
2259     }
2260
2261     root = MSI_RecordGetInteger(row,2);
2262     key = MSI_RecordGetString(row, 3);
2263
2264     /* get the root key */
2265     switch (root)
2266     {
2267         case -1: 
2268             {
2269                 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2270                 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2271                 if (all_users && all_users[0] == '1')
2272                 {
2273                     root_key = HKEY_LOCAL_MACHINE;
2274                     szRoot = szHLM;
2275                 }
2276                 else
2277                 {
2278                     root_key = HKEY_CURRENT_USER;
2279                     szRoot = szHCU;
2280                 }
2281                 msi_free(all_users);
2282             }
2283                  break;
2284         case 0:  root_key = HKEY_CLASSES_ROOT; 
2285                  szRoot = szHCR;
2286                  break;
2287         case 1:  root_key = HKEY_CURRENT_USER;
2288                  szRoot = szHCU;
2289                  break;
2290         case 2:  root_key = HKEY_LOCAL_MACHINE;
2291                  szRoot = szHLM;
2292                  break;
2293         case 3:  root_key = HKEY_USERS; 
2294                  szRoot = szHU;
2295                  break;
2296         default:
2297                  ERR("Unknown root %i\n",root);
2298                  root_key=NULL;
2299                  szRoot = NULL;
2300                  break;
2301     }
2302     if (!root_key)
2303         return ERROR_SUCCESS;
2304
2305     deformat_string(package, key , &deformated);
2306     size = strlenW(deformated) + strlenW(szRoot) + 1;
2307     uikey = msi_alloc(size*sizeof(WCHAR));
2308     strcpyW(uikey,szRoot);
2309     strcatW(uikey,deformated);
2310
2311     if (RegCreateKeyW( root_key, deformated, &hkey))
2312     {
2313         ERR("Could not create key %s\n",debugstr_w(deformated));
2314         msi_free(deformated);
2315         msi_free(uikey);
2316         return ERROR_SUCCESS;
2317     }
2318     msi_free(deformated);
2319
2320     value = MSI_RecordGetString(row,5);
2321     if (value)
2322         value_data = parse_value(package, value, &type, &size); 
2323     else
2324     {
2325         static const WCHAR szEmpty[] = {0};
2326         value_data = (LPSTR)strdupW(szEmpty);
2327         size = 0;
2328         type = REG_SZ;
2329     }
2330
2331     deformat_string(package, name, &deformated);
2332
2333     /* get the double nulls to terminate SZ_MULTI */
2334     if (type == REG_MULTI_SZ)
2335         size +=sizeof(WCHAR);
2336
2337     if (!check_first)
2338     {
2339         TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2340                         debugstr_w(uikey));
2341         RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2342     }
2343     else
2344     {
2345         DWORD sz = 0;
2346         rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2347         if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2348         {
2349             TRACE("value %s of %s checked already exists\n",
2350                             debugstr_w(deformated), debugstr_w(uikey));
2351         }
2352         else
2353         {
2354             TRACE("Checked and setting value %s of %s\n",
2355                             debugstr_w(deformated), debugstr_w(uikey));
2356             if (deformated || size)
2357                 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2358         }
2359     }
2360     RegCloseKey(hkey);
2361
2362     uirow = MSI_CreateRecord(3);
2363     MSI_RecordSetStringW(uirow,2,deformated);
2364     MSI_RecordSetStringW(uirow,1,uikey);
2365
2366     if (type == REG_SZ)
2367         MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2368     else
2369         MSI_RecordSetStringW(uirow,3,value);
2370
2371     ui_actiondata(package,szWriteRegistryValues,uirow);
2372     msiobj_release( &uirow->hdr );
2373
2374     msi_free(value_data);
2375     msi_free(deformated);
2376     msi_free(uikey);
2377
2378     return ERROR_SUCCESS;
2379 }
2380
2381 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2382 {
2383     UINT rc;
2384     MSIQUERY * view;
2385     static const WCHAR ExecSeqQuery[] =
2386         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2387          '`','R','e','g','i','s','t','r','y','`',0 };
2388
2389     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2390     if (rc != ERROR_SUCCESS)
2391         return ERROR_SUCCESS;
2392
2393     /* increment progress bar each time action data is sent */
2394     ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2395
2396     rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2397
2398     msiobj_release(&view->hdr);
2399     return rc;
2400 }
2401
2402 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2403 {
2404     package->script->CurrentlyScripting = TRUE;
2405
2406     return ERROR_SUCCESS;
2407 }
2408
2409
2410 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2411 {
2412     MSICOMPONENT *comp;
2413     DWORD progress = 0;
2414     DWORD total = 0;
2415     static const WCHAR q1[]=
2416         {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2417          '`','R','e','g','i','s','t','r','y','`',0};
2418     UINT rc;
2419     MSIQUERY * view;
2420     MSIFEATURE *feature;
2421     MSIFILE *file;
2422
2423     TRACE("InstallValidate\n");
2424
2425     rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2426     if (rc == ERROR_SUCCESS)
2427     {
2428         MSI_IterateRecords( view, &progress, NULL, package );
2429         msiobj_release( &view->hdr );
2430         total += progress * REG_PROGRESS_VALUE;
2431     }
2432
2433     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2434         total += COMPONENT_PROGRESS_VALUE;
2435
2436     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2437         total += file->FileSize;
2438
2439     ui_progress(package,0,total,0,0);
2440
2441     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2442     {
2443         TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2444             debugstr_w(feature->Feature), feature->Installed, feature->Action,
2445             feature->ActionRequest);
2446     }
2447     
2448     return ERROR_SUCCESS;
2449 }
2450
2451 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2452 {
2453     MSIPACKAGE* package = (MSIPACKAGE*)param;
2454     LPCWSTR cond = NULL; 
2455     LPCWSTR message = NULL;
2456     static const WCHAR title[]=
2457         {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2458
2459     cond = MSI_RecordGetString(row,1);
2460
2461     if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2462     {
2463         LPWSTR deformated;
2464         message = MSI_RecordGetString(row,2);
2465         deformat_string(package,message,&deformated); 
2466         MessageBoxW(NULL,deformated,title,MB_OK);
2467         msi_free(deformated);
2468         return ERROR_FUNCTION_FAILED;
2469     }
2470
2471     return ERROR_SUCCESS;
2472 }
2473
2474 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2475 {
2476     UINT rc;
2477     MSIQUERY * view = NULL;
2478     static const WCHAR ExecSeqQuery[] =
2479         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2480          '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2481
2482     TRACE("Checking launch conditions\n");
2483
2484     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2485     if (rc != ERROR_SUCCESS)
2486         return ERROR_SUCCESS;
2487
2488     rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2489     msiobj_release(&view->hdr);
2490
2491     return rc;
2492 }
2493
2494 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2495 {
2496
2497     if (!cmp->KeyPath)
2498         return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2499
2500     if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2501     {
2502         MSIRECORD * row = 0;
2503         UINT root,len;
2504         LPWSTR deformated,buffer,deformated_name;
2505         LPCWSTR key,name;
2506         static const WCHAR ExecSeqQuery[] =
2507             {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2508              '`','R','e','g','i','s','t','r','y','`',' ',
2509              'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2510              ' ','=',' ' ,'\'','%','s','\'',0 };
2511         static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2512         static const WCHAR fmt2[]=
2513             {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2514
2515         row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2516         if (!row)
2517             return NULL;
2518
2519         root = MSI_RecordGetInteger(row,2);
2520         key = MSI_RecordGetString(row, 3);
2521         name = MSI_RecordGetString(row, 4);
2522         deformat_string(package, key , &deformated);
2523         deformat_string(package, name, &deformated_name);
2524
2525         len = strlenW(deformated) + 6;
2526         if (deformated_name)
2527             len+=strlenW(deformated_name);
2528
2529         buffer = msi_alloc( len *sizeof(WCHAR));
2530
2531         if (deformated_name)
2532             sprintfW(buffer,fmt2,root,deformated,deformated_name);
2533         else
2534             sprintfW(buffer,fmt,root,deformated);
2535
2536         msi_free(deformated);
2537         msi_free(deformated_name);
2538         msiobj_release(&row->hdr);
2539
2540         return buffer;
2541     }
2542     else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2543     {
2544         FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2545         return NULL;
2546     }
2547     else
2548     {
2549         MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2550
2551         if (file)
2552             return strdupW( file->TargetPath );
2553     }
2554     return NULL;
2555 }
2556
2557 static HKEY openSharedDLLsKey(void)
2558 {
2559     HKEY hkey=0;
2560     static const WCHAR path[] =
2561         {'S','o','f','t','w','a','r','e','\\',
2562          'M','i','c','r','o','s','o','f','t','\\',
2563          'W','i','n','d','o','w','s','\\',
2564          'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2565          'S','h','a','r','e','d','D','L','L','s',0};
2566
2567     RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2568     return hkey;
2569 }
2570
2571 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2572 {
2573     HKEY hkey;
2574     DWORD count=0;
2575     DWORD type;
2576     DWORD sz = sizeof(count);
2577     DWORD rc;
2578     
2579     hkey = openSharedDLLsKey();
2580     rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2581     if (rc != ERROR_SUCCESS)
2582         count = 0;
2583     RegCloseKey(hkey);
2584     return count;
2585 }
2586
2587 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2588 {
2589     HKEY hkey;
2590
2591     hkey = openSharedDLLsKey();
2592     if (count > 0)
2593         msi_reg_set_val_dword( hkey, path, count );
2594     else
2595         RegDeleteValueW(hkey,path);
2596     RegCloseKey(hkey);
2597     return count;
2598 }
2599
2600 /*
2601  * Return TRUE if the count should be written out and FALSE if not
2602  */
2603 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2604 {
2605     MSIFEATURE *feature;
2606     INT count = 0;
2607     BOOL write = FALSE;
2608
2609     /* only refcount DLLs */
2610     if (comp->KeyPath == NULL || 
2611         comp->Attributes & msidbComponentAttributesRegistryKeyPath || 
2612         comp->Attributes & msidbComponentAttributesODBCDataSource)
2613         write = FALSE;
2614     else
2615     {
2616         count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2617         write = (count > 0);
2618
2619         if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2620             write = TRUE;
2621     }
2622
2623     /* increment counts */
2624     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2625     {
2626         ComponentList *cl;
2627
2628         if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2629             continue;
2630
2631         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2632         {
2633             if ( cl->component == comp )
2634                 count++;
2635         }
2636     }
2637
2638     /* decrement counts */
2639     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2640     {
2641         ComponentList *cl;
2642
2643         if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2644             continue;
2645
2646         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2647         {
2648             if ( cl->component == comp )
2649                 count--;
2650         }
2651     }
2652
2653     /* ref count all the files in the component */
2654     if (write)
2655     {
2656         MSIFILE *file;
2657
2658         LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2659         {
2660             if (file->Component == comp)
2661                 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2662         }
2663     }
2664     
2665     /* add a count for permenent */
2666     if (comp->Attributes & msidbComponentAttributesPermanent)
2667         count ++;
2668     
2669     comp->RefCount = count;
2670
2671     if (write)
2672         ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2673 }
2674
2675 /*
2676  * Ok further analysis makes me think that this work is
2677  * actually done in the PublishComponents and PublishFeatures
2678  * step, and not here.  It appears like the keypath and all that is
2679  * resolved in this step, however actually written in the Publish steps.
2680  * But we will leave it here for now because it is unclear
2681  */
2682 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2683 {
2684     WCHAR squished_pc[GUID_SIZE];
2685     WCHAR squished_cc[GUID_SIZE];
2686     UINT rc;
2687     MSICOMPONENT *comp;
2688     HKEY hkey=0,hkey2=0;
2689
2690     /* writes the Component and Features values to the registry */
2691
2692     rc = MSIREG_OpenComponents(&hkey);
2693     if (rc != ERROR_SUCCESS)
2694         return rc;
2695
2696     squash_guid(package->ProductCode,squished_pc);
2697     ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2698
2699     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2700     {
2701         MSIRECORD * uirow;
2702
2703         ui_progress(package,2,0,0,0);
2704         if (!comp->ComponentId)
2705             continue;
2706
2707         squash_guid(comp->ComponentId,squished_cc);
2708            
2709         msi_free(comp->FullKeypath);
2710         comp->FullKeypath = resolve_keypath( package, comp );
2711
2712         /* do the refcounting */
2713         ACTION_RefCountComponent( package, comp );
2714
2715         TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2716                             debugstr_w(comp->Component),
2717                             debugstr_w(squished_cc),
2718                             debugstr_w(comp->FullKeypath),
2719                             comp->RefCount);
2720         /*
2721          * Write the keypath out if the component is to be registered
2722          * and delete the key if the component is to be deregistered
2723          */
2724         if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2725         {
2726             rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2727             if (rc != ERROR_SUCCESS)
2728                 continue;
2729
2730             if (!comp->FullKeypath)
2731                 continue;
2732
2733             msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2734
2735             if (comp->Attributes & msidbComponentAttributesPermanent)
2736             {
2737                 static const WCHAR szPermKey[] =
2738                     { '0','0','0','0','0','0','0','0','0','0','0','0',
2739                       '0','0','0','0','0','0','0','0','0','0','0','0',
2740                       '0','0','0','0','0','0','0','0',0 };
2741
2742                 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2743             }
2744
2745             RegCloseKey(hkey2);
2746
2747             /* UI stuff */
2748             uirow = MSI_CreateRecord(3);
2749             MSI_RecordSetStringW(uirow,1,package->ProductCode);
2750             MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2751             MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2752             ui_actiondata(package,szProcessComponents,uirow);
2753             msiobj_release( &uirow->hdr );
2754         }
2755         else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2756         {
2757             DWORD res;
2758
2759             rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2760             if (rc != ERROR_SUCCESS)
2761                 continue;
2762
2763             RegDeleteValueW(hkey2,squished_pc);
2764
2765             /* if the key is empty delete it */
2766             res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2767             RegCloseKey(hkey2);
2768             if (res == ERROR_NO_MORE_ITEMS)
2769                 RegDeleteKeyW(hkey,squished_cc);
2770
2771             /* UI stuff */
2772             uirow = MSI_CreateRecord(2);
2773             MSI_RecordSetStringW(uirow,1,package->ProductCode);
2774             MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2775             ui_actiondata(package,szProcessComponents,uirow);
2776             msiobj_release( &uirow->hdr );
2777         }
2778     } 
2779     RegCloseKey(hkey);
2780     return rc;
2781 }
2782
2783 typedef struct {
2784     CLSID       clsid;
2785     LPWSTR      source;
2786
2787     LPWSTR      path;
2788     ITypeLib    *ptLib;
2789 } typelib_struct;
2790
2791 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType, 
2792                                        LPWSTR lpszName, LONG_PTR lParam)
2793 {
2794     TLIBATTR *attr;
2795     typelib_struct *tl_struct = (typelib_struct*) lParam;
2796     static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2797     int sz; 
2798     HRESULT res;
2799
2800     if (!IS_INTRESOURCE(lpszName))
2801     {
2802         ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2803         return TRUE;
2804     }
2805
2806     sz = strlenW(tl_struct->source)+4;
2807     sz *= sizeof(WCHAR);
2808
2809     if ((INT_PTR)lpszName == 1)
2810         tl_struct->path = strdupW(tl_struct->source);
2811     else
2812     {
2813         tl_struct->path = msi_alloc(sz);
2814         sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2815     }
2816
2817     TRACE("trying %s\n", debugstr_w(tl_struct->path));
2818     res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2819     if (!SUCCEEDED(res))
2820     {
2821         msi_free(tl_struct->path);
2822         tl_struct->path = NULL;
2823
2824         return TRUE;
2825     }
2826
2827     ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2828     if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2829     {
2830         ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2831         return FALSE;
2832     }
2833
2834     msi_free(tl_struct->path);
2835     tl_struct->path = NULL;
2836
2837     ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2838     ITypeLib_Release(tl_struct->ptLib);
2839
2840     return TRUE;
2841 }
2842
2843 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2844 {
2845     MSIPACKAGE* package = (MSIPACKAGE*)param;
2846     LPCWSTR component;
2847     MSICOMPONENT *comp;
2848     MSIFILE *file;
2849     typelib_struct tl_struct;
2850     HMODULE module;
2851     static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2852
2853     component = MSI_RecordGetString(row,3);
2854     comp = get_loaded_component(package,component);
2855     if (!comp)
2856         return ERROR_SUCCESS;
2857
2858     if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2859     {
2860         TRACE("Skipping typelib reg due to disabled component\n");
2861
2862         comp->Action = comp->Installed;
2863
2864         return ERROR_SUCCESS;
2865     }
2866
2867     comp->Action = INSTALLSTATE_LOCAL;
2868
2869     file = get_loaded_file( package, comp->KeyPath ); 
2870     if (!file)
2871         return ERROR_SUCCESS;
2872
2873     module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2874     if (module)
2875     {
2876         LPCWSTR guid;
2877         guid = MSI_RecordGetString(row,1);
2878         CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2879         tl_struct.source = strdupW( file->TargetPath );
2880         tl_struct.path = NULL;
2881
2882         EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2883                         (LONG_PTR)&tl_struct);
2884
2885         if (tl_struct.path)
2886         {
2887             LPWSTR help = NULL;
2888             LPCWSTR helpid;
2889             HRESULT res;
2890
2891             helpid = MSI_RecordGetString(row,6);
2892
2893             if (helpid)
2894                 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2895             res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2896             msi_free(help);
2897
2898             if (!SUCCEEDED(res))
2899                 ERR("Failed to register type library %s\n",
2900                         debugstr_w(tl_struct.path));
2901             else
2902             {
2903                 ui_actiondata(package,szRegisterTypeLibraries,row);
2904
2905                 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2906             }
2907
2908             ITypeLib_Release(tl_struct.ptLib);
2909             msi_free(tl_struct.path);
2910         }
2911         else
2912             ERR("Failed to load type library %s\n",
2913                     debugstr_w(tl_struct.source));
2914
2915         FreeLibrary(module);
2916         msi_free(tl_struct.source);
2917     }
2918     else
2919         ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2920
2921     return ERROR_SUCCESS;
2922 }
2923
2924 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2925 {
2926     /* 
2927      * OK this is a bit confusing.. I am given a _Component key and I believe
2928      * that the file that is being registered as a type library is the "key file
2929      * of that component" which I interpret to mean "The file in the KeyPath of
2930      * that component".
2931      */
2932     UINT rc;
2933     MSIQUERY * view;
2934     static const WCHAR Query[] =
2935         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2936          '`','T','y','p','e','L','i','b','`',0};
2937
2938     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2939     if (rc != ERROR_SUCCESS)
2940         return ERROR_SUCCESS;
2941
2942     rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2943     msiobj_release(&view->hdr);
2944     return rc;
2945 }
2946
2947 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2948 {
2949     MSIPACKAGE *package = (MSIPACKAGE*)param;
2950     LPWSTR target_file, target_folder, filename;
2951     LPCWSTR buffer, extension;
2952     MSICOMPONENT *comp;
2953     static const WCHAR szlnk[]={'.','l','n','k',0};
2954     IShellLinkW *sl = NULL;
2955     IPersistFile *pf = NULL;
2956     HRESULT res;
2957
2958     buffer = MSI_RecordGetString(row,4);
2959     comp = get_loaded_component(package,buffer);
2960     if (!comp)
2961         return ERROR_SUCCESS;
2962
2963     if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2964     {
2965         TRACE("Skipping shortcut creation due to disabled component\n");
2966
2967         comp->Action = comp->Installed;
2968
2969         return ERROR_SUCCESS;
2970     }
2971
2972     comp->Action = INSTALLSTATE_LOCAL;
2973
2974     ui_actiondata(package,szCreateShortcuts,row);
2975
2976     res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2977                     &IID_IShellLinkW, (LPVOID *) &sl );
2978
2979     if (FAILED( res ))
2980     {
2981         ERR("CLSID_ShellLink not available\n");
2982         goto err;
2983     }
2984
2985     res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2986     if (FAILED( res ))
2987     {
2988         ERR("QueryInterface(IID_IPersistFile) failed\n");
2989         goto err;
2990     }
2991
2992     buffer = MSI_RecordGetString(row,2);
2993     target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2994
2995     /* may be needed because of a bug somehwere else */
2996     create_full_pathW(target_folder);
2997
2998     filename = msi_dup_record_field( row, 3 );
2999     reduce_to_longfilename(filename);
3000
3001     extension = strchrW(filename,'.');
3002     if (!extension || strcmpiW(extension,szlnk))
3003     {
3004         int len = strlenW(filename);
3005         filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3006         memcpy(filename + len, szlnk, sizeof(szlnk));
3007     }
3008     target_file = build_directory_name(2, target_folder, filename);
3009     msi_free(target_folder);
3010     msi_free(filename);
3011
3012     buffer = MSI_RecordGetString(row,5);
3013     if (strchrW(buffer,'['))
3014     {
3015         LPWSTR deformated;
3016         deformat_string(package,buffer,&deformated);
3017         IShellLinkW_SetPath(sl,deformated);
3018         msi_free(deformated);
3019     }
3020     else
3021     {
3022         FIXME("poorly handled shortcut format, advertised shortcut\n");
3023         IShellLinkW_SetPath(sl,comp->FullKeypath);
3024     }
3025
3026     if (!MSI_RecordIsNull(row,6))
3027     {
3028         LPWSTR deformated;
3029         buffer = MSI_RecordGetString(row,6);
3030         deformat_string(package,buffer,&deformated);
3031         IShellLinkW_SetArguments(sl,deformated);
3032         msi_free(deformated);
3033     }
3034
3035     if (!MSI_RecordIsNull(row,7))
3036     {
3037         buffer = MSI_RecordGetString(row,7);
3038         IShellLinkW_SetDescription(sl,buffer);
3039     }
3040
3041     if (!MSI_RecordIsNull(row,8))
3042         IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3043
3044     if (!MSI_RecordIsNull(row,9))
3045     {
3046         LPWSTR Path;
3047         INT index; 
3048
3049         buffer = MSI_RecordGetString(row,9);
3050
3051         Path = build_icon_path(package,buffer);
3052         index = MSI_RecordGetInteger(row,10);
3053
3054         /* no value means 0 */
3055         if (index == MSI_NULL_INTEGER)
3056             index = 0;
3057
3058         IShellLinkW_SetIconLocation(sl,Path,index);
3059         msi_free(Path);
3060     }
3061
3062     if (!MSI_RecordIsNull(row,11))
3063         IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3064
3065     if (!MSI_RecordIsNull(row,12))
3066     {
3067         LPWSTR Path;
3068         buffer = MSI_RecordGetString(row,12);
3069         Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
3070         if (Path)
3071             IShellLinkW_SetWorkingDirectory(sl,Path);
3072         msi_free(Path);
3073     }
3074
3075     TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3076     IPersistFile_Save(pf,target_file,FALSE);
3077
3078     msi_free(target_file);    
3079
3080 err:
3081     if (pf)
3082         IPersistFile_Release( pf );
3083     if (sl)
3084         IShellLinkW_Release( sl );
3085
3086     return ERROR_SUCCESS;
3087 }
3088
3089 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3090 {
3091     UINT rc;
3092     HRESULT res;
3093     MSIQUERY * view;
3094     static const WCHAR Query[] =
3095         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3096          '`','S','h','o','r','t','c','u','t','`',0};
3097
3098     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3099     if (rc != ERROR_SUCCESS)
3100         return ERROR_SUCCESS;
3101
3102     res = CoInitialize( NULL );
3103     if (FAILED (res))
3104     {
3105         ERR("CoInitialize failed\n");
3106         return ERROR_FUNCTION_FAILED;
3107     }
3108
3109     rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3110     msiobj_release(&view->hdr);
3111
3112     CoUninitialize();
3113
3114     return rc;
3115 }
3116
3117 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3118 {
3119     MSIPACKAGE* package = (MSIPACKAGE*)param;
3120     HANDLE the_file;
3121     LPWSTR FilePath;
3122     LPCWSTR FileName;
3123     CHAR buffer[1024];
3124     DWORD sz;
3125     UINT rc;
3126     MSIRECORD *uirow;
3127
3128     FileName = MSI_RecordGetString(row,1);
3129     if (!FileName)
3130     {
3131         ERR("Unable to get FileName\n");
3132         return ERROR_SUCCESS;
3133     }
3134
3135     FilePath = build_icon_path(package,FileName);
3136
3137     TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3138
3139     the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3140                         FILE_ATTRIBUTE_NORMAL, NULL);
3141
3142     if (the_file == INVALID_HANDLE_VALUE)
3143     {
3144         ERR("Unable to create file %s\n",debugstr_w(FilePath));
3145         msi_free(FilePath);
3146         return ERROR_SUCCESS;
3147     }
3148
3149     do 
3150     {
3151         DWORD write;
3152         sz = 1024;
3153         rc = MSI_RecordReadStream(row,2,buffer,&sz);
3154         if (rc != ERROR_SUCCESS)
3155         {
3156             ERR("Failed to get stream\n");
3157             CloseHandle(the_file);  
3158             DeleteFileW(FilePath);
3159             break;
3160         }
3161         WriteFile(the_file,buffer,sz,&write,NULL);
3162     } while (sz == 1024);
3163
3164     msi_free(FilePath);
3165
3166     CloseHandle(the_file);
3167
3168     uirow = MSI_CreateRecord(1);
3169     MSI_RecordSetStringW(uirow,1,FileName);
3170     ui_actiondata(package,szPublishProduct,uirow);
3171     msiobj_release( &uirow->hdr );
3172
3173     return ERROR_SUCCESS;
3174 }
3175
3176 /*
3177  * 99% of the work done here is only done for 
3178  * advertised installs. However this is where the
3179  * Icon table is processed and written out
3180  * so that is what I am going to do here.
3181  */
3182 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3183 {
3184     UINT rc;
3185     MSIQUERY * view;
3186     static const WCHAR Query[]=
3187         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3188          '`','I','c','o','n','`',0};
3189     /* for registry stuff */
3190     HKEY hkey=0;
3191     HKEY hukey=0;
3192     static const WCHAR szProductLanguage[] =
3193         {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3194     static const WCHAR szARPProductIcon[] =
3195         {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3196     static const WCHAR szProductVersion[] =
3197         {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3198     DWORD langid;
3199     LPWSTR buffer;
3200     DWORD size;
3201     MSIHANDLE hDb, hSumInfo;
3202
3203     /* write out icon files */
3204
3205     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3206     if (rc == ERROR_SUCCESS)
3207     {
3208         MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3209         msiobj_release(&view->hdr);
3210     }
3211
3212     /* ok there is a lot more done here but i need to figure out what */
3213
3214     rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3215     if (rc != ERROR_SUCCESS)
3216         goto end;
3217
3218     rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3219     if (rc != ERROR_SUCCESS)
3220         goto end;
3221
3222
3223     buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3224     msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3225     msi_free(buffer);
3226
3227     langid = msi_get_property_int( package, szProductLanguage, 0 );
3228     msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3229
3230     buffer = msi_dup_property( package, szARPProductIcon );
3231     if (buffer)
3232     {
3233         LPWSTR path = build_icon_path(package,buffer);
3234         msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3235         msi_free( path );
3236     }
3237     msi_free(buffer);
3238
3239     buffer = msi_dup_property( package, szProductVersion );
3240     if (buffer)
3241     {
3242         DWORD verdword = msi_version_str_to_dword(buffer);
3243         msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3244     }
3245     msi_free(buffer);
3246     
3247     /* FIXME: Need to write more keys to the user registry */
3248   
3249     hDb= alloc_msihandle( &package->db->hdr );
3250     if (!hDb) {
3251         rc = ERROR_NOT_ENOUGH_MEMORY;
3252         goto end;
3253     }
3254     rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo); 
3255     MsiCloseHandle(hDb);
3256     if (rc == ERROR_SUCCESS)
3257     {
3258         WCHAR guidbuffer[0x200];
3259         size = 0x200;
3260         rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3261                                         guidbuffer, &size);
3262         if (rc == ERROR_SUCCESS)
3263         {
3264             WCHAR squashed[GUID_SIZE];
3265             /* for now we only care about the first guid */
3266             LPWSTR ptr = strchrW(guidbuffer,';');
3267             if (ptr) *ptr = 0;
3268             squash_guid(guidbuffer,squashed);
3269             msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3270         }
3271         else
3272         {
3273             ERR("Unable to query Revision_Number...\n");
3274             rc = ERROR_SUCCESS;
3275         }
3276         MsiCloseHandle(hSumInfo);
3277     }
3278     else
3279     {
3280         ERR("Unable to open Summary Information\n");
3281         rc = ERROR_SUCCESS;
3282     }
3283
3284 end:
3285
3286     RegCloseKey(hkey);
3287     RegCloseKey(hukey);
3288
3289     return rc;
3290 }
3291
3292 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3293 {
3294     MSIPACKAGE *package = (MSIPACKAGE*)param;
3295     LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3296     LPWSTR deformated_section, deformated_key, deformated_value;
3297     LPWSTR folder, fullname = NULL;
3298     MSIRECORD * uirow;
3299     INT action;
3300     MSICOMPONENT *comp;
3301     static const WCHAR szWindowsFolder[] =
3302           {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3303
3304     component = MSI_RecordGetString(row, 8);
3305     comp = get_loaded_component(package,component);
3306
3307     if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3308     {
3309         TRACE("Skipping ini file due to disabled component %s\n",
3310                         debugstr_w(component));
3311
3312         comp->Action = comp->Installed;
3313
3314         return ERROR_SUCCESS;
3315     }
3316
3317     comp->Action = INSTALLSTATE_LOCAL;
3318
3319     identifier = MSI_RecordGetString(row,1); 
3320     filename = MSI_RecordGetString(row,2);
3321     dirproperty = MSI_RecordGetString(row,3);
3322     section = MSI_RecordGetString(row,4);
3323     key = MSI_RecordGetString(row,5);
3324     value = MSI_RecordGetString(row,6);
3325     action = MSI_RecordGetInteger(row,7);
3326
3327     deformat_string(package,section,&deformated_section);
3328     deformat_string(package,key,&deformated_key);
3329     deformat_string(package,value,&deformated_value);
3330
3331     if (dirproperty)
3332     {
3333         folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3334         if (!folder)
3335             folder = msi_dup_property( package, dirproperty );
3336     }
3337     else
3338         folder = msi_dup_property( package, szWindowsFolder );
3339
3340     if (!folder)
3341     {
3342         ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3343         goto cleanup;
3344     }
3345
3346     fullname = build_directory_name(2, folder, filename);
3347
3348     if (action == 0)
3349     {
3350         TRACE("Adding value %s to section %s in %s\n",
3351                 debugstr_w(deformated_key), debugstr_w(deformated_section),
3352                 debugstr_w(fullname));
3353         WritePrivateProfileStringW(deformated_section, deformated_key,
3354                                    deformated_value, fullname);
3355     }
3356     else if (action == 1)
3357     {
3358         WCHAR returned[10];
3359         GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3360                                  returned, 10, fullname);
3361         if (returned[0] == 0)
3362         {
3363             TRACE("Adding value %s to section %s in %s\n",
3364                     debugstr_w(deformated_key), debugstr_w(deformated_section),
3365                     debugstr_w(fullname));
3366
3367             WritePrivateProfileStringW(deformated_section, deformated_key,
3368                                        deformated_value, fullname);
3369         }
3370     }
3371     else if (action == 3)
3372         FIXME("Append to existing section not yet implemented\n");
3373
3374     uirow = MSI_CreateRecord(4);
3375     MSI_RecordSetStringW(uirow,1,identifier);
3376     MSI_RecordSetStringW(uirow,2,deformated_section);
3377     MSI_RecordSetStringW(uirow,3,deformated_key);
3378     MSI_RecordSetStringW(uirow,4,deformated_value);
3379     ui_actiondata(package,szWriteIniValues,uirow);
3380     msiobj_release( &uirow->hdr );
3381 cleanup:
3382     msi_free(fullname);
3383     msi_free(folder);
3384     msi_free(deformated_key);
3385     msi_free(deformated_value);
3386     msi_free(deformated_section);
3387     return ERROR_SUCCESS;
3388 }
3389
3390 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3391 {
3392     UINT rc;
3393     MSIQUERY * view;
3394     static const WCHAR ExecSeqQuery[] = 
3395         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3396          '`','I','n','i','F','i','l','e','`',0};
3397
3398     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3399     if (rc != ERROR_SUCCESS)
3400     {
3401         TRACE("no IniFile table\n");
3402         return ERROR_SUCCESS;
3403     }
3404
3405     rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3406     msiobj_release(&view->hdr);
3407     return rc;
3408 }
3409
3410 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3411 {
3412     MSIPACKAGE *package = (MSIPACKAGE*)param;
3413     LPCWSTR filename;
3414     LPWSTR FullName;
3415     MSIFILE *file;
3416     DWORD len;
3417     static const WCHAR ExeStr[] =
3418         {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3419     static const WCHAR close[] =  {'\"',0};
3420     STARTUPINFOW si;
3421     PROCESS_INFORMATION info;
3422     BOOL brc;
3423     MSIRECORD *uirow;
3424     LPWSTR uipath, p;
3425
3426     memset(&si,0,sizeof(STARTUPINFOW));
3427
3428     filename = MSI_RecordGetString(row,1);
3429     file = get_loaded_file( package, filename );
3430
3431     if (!file)
3432     {
3433         ERR("Unable to find file id %s\n",debugstr_w(filename));
3434         return ERROR_SUCCESS;
3435     }
3436
3437     len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3438
3439     FullName = msi_alloc(len*sizeof(WCHAR));
3440     strcpyW(FullName,ExeStr);
3441     strcatW( FullName, file->TargetPath );
3442     strcatW(FullName,close);
3443
3444     TRACE("Registering %s\n",debugstr_w(FullName));
3445     brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3446                     &si, &info);
3447
3448     if (brc)
3449         msi_dialog_check_messages(info.hProcess);
3450
3451     msi_free(FullName);
3452
3453     /* the UI chunk */
3454     uirow = MSI_CreateRecord( 2 );
3455     uipath = strdupW( file->TargetPath );
3456     p = strrchrW(uipath,'\\');
3457     if (p)
3458         p[1]=0;
3459     MSI_RecordSetStringW( uirow, 1, &p[2] );
3460     MSI_RecordSetStringW( uirow, 2, uipath);
3461     ui_actiondata( package, szSelfRegModules, uirow);
3462     msiobj_release( &uirow->hdr );
3463     msi_free( uipath );
3464     /* FIXME: call ui_progress? */
3465
3466     return ERROR_SUCCESS;
3467 }
3468
3469 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3470 {
3471     UINT rc;
3472     MSIQUERY * view;
3473     static const WCHAR ExecSeqQuery[] = 
3474         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3475          '`','S','e','l','f','R','e','g','`',0};
3476
3477     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3478     if (rc != ERROR_SUCCESS)
3479     {
3480         TRACE("no SelfReg table\n");
3481         return ERROR_SUCCESS;
3482     }
3483
3484     MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3485     msiobj_release(&view->hdr);
3486
3487     return ERROR_SUCCESS;
3488 }
3489
3490 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3491 {
3492     MSIFEATURE *feature;
3493     UINT rc;
3494     HKEY hkey=0;
3495     HKEY hukey=0;
3496     
3497     rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3498     if (rc != ERROR_SUCCESS)
3499         goto end;
3500
3501     rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3502     if (rc != ERROR_SUCCESS)
3503         goto end;
3504
3505     /* here the guids are base 85 encoded */
3506     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3507     {
3508         ComponentList *cl;
3509         LPWSTR data = NULL;
3510         GUID clsid;
3511         INT size;
3512         BOOL absent = FALSE;
3513         MSIRECORD *uirow;
3514
3515         if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3516             !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3517             !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3518             absent = TRUE;
3519
3520         size = 1;
3521         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3522         {
3523             size += 21;
3524         }
3525         if (feature->Feature_Parent)
3526             size += strlenW( feature->Feature_Parent )+2;
3527
3528         data = msi_alloc(size * sizeof(WCHAR));
3529
3530         data[0] = 0;
3531         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3532         {
3533             MSICOMPONENT* component = cl->component;
3534             WCHAR buf[21];
3535
3536             buf[0] = 0;
3537             if (component->ComponentId)
3538             {
3539                 TRACE("From %s\n",debugstr_w(component->ComponentId));
3540                 CLSIDFromString(component->ComponentId, &clsid);
3541                 encode_base85_guid(&clsid,buf);
3542                 TRACE("to %s\n",debugstr_w(buf));
3543                 strcatW(data,buf);
3544             }
3545         }
3546         if (feature->Feature_Parent)
3547         {
3548             static const WCHAR sep[] = {'\2',0};
3549             strcatW(data,sep);
3550             strcatW(data,feature->Feature_Parent);
3551         }
3552
3553         msi_reg_set_val_str( hkey, feature->Feature, data );
3554         msi_free(data);
3555
3556         size = 0;
3557         if (feature->Feature_Parent)
3558             size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3559         if (!absent)
3560         {
3561             RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3562                        (LPBYTE)feature->Feature_Parent,size);
3563         }
3564         else
3565         {
3566             size += 2*sizeof(WCHAR);
3567             data = msi_alloc(size);
3568             data[0] = 0x6;
3569             data[1] = 0;
3570             if (feature->Feature_Parent)
3571                 strcpyW( &data[1], feature->Feature_Parent );
3572             RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3573                        (LPBYTE)data,size);
3574             msi_free(data);
3575         }
3576
3577         /* the UI chunk */
3578         uirow = MSI_CreateRecord( 1 );
3579         MSI_RecordSetStringW( uirow, 1, feature->Feature );
3580         ui_actiondata( package, szPublishFeatures, uirow);
3581         msiobj_release( &uirow->hdr );
3582         /* FIXME: call ui_progress? */
3583     }
3584
3585 end:
3586     RegCloseKey(hkey);
3587     RegCloseKey(hukey);
3588     return rc;
3589 }
3590
3591 static UINT msi_get_local_package_name( LPWSTR path )
3592 {
3593     static const WCHAR szInstaller[] = {
3594         '\\','I','n','s','t','a','l','l','e','r','\\',0};
3595     static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3596     DWORD time, len, i;
3597     HANDLE handle;
3598
3599     time = GetTickCount();
3600     GetWindowsDirectoryW( path, MAX_PATH );
3601     lstrcatW( path, szInstaller );
3602     CreateDirectoryW( path, NULL );
3603
3604     len = lstrlenW(path);
3605     for (i=0; i<0x10000; i++)
3606     {
3607         snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3608         handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3609                               CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3610         if (handle != INVALID_HANDLE_VALUE)
3611         {
3612             CloseHandle(handle);
3613             break;
3614         }
3615         if (GetLastError() != ERROR_FILE_EXISTS &&
3616             GetLastError() != ERROR_SHARING_VIOLATION)
3617             return ERROR_FUNCTION_FAILED;
3618     }
3619
3620     return ERROR_SUCCESS;
3621 }
3622
3623 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3624 {
3625     static const WCHAR szOriginalDatabase[] =
3626         {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3627     WCHAR packagefile[MAX_PATH];
3628     LPWSTR msiFilePath;
3629     UINT r;
3630
3631     r = msi_get_local_package_name( packagefile );
3632     if (r != ERROR_SUCCESS)
3633         return r;
3634
3635     TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3636
3637     msiFilePath = msi_dup_property( package, szOriginalDatabase );
3638     r = CopyFileW( msiFilePath, packagefile, FALSE);
3639     msi_free( msiFilePath );
3640
3641     if (!r)
3642     {
3643         ERR("Unable to copy package (%s -> %s) (error %d)\n",
3644             debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3645         return ERROR_FUNCTION_FAILED;
3646     }
3647
3648     /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3649     msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3650     return ERROR_SUCCESS;
3651 }
3652
3653 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3654 {
3655     LPWSTR prop, val, key;
3656     static const LPCSTR propval[] = {
3657         "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3658         "ARPCONTACT",             "Contact",
3659         "ARPCOMMENTS",            "Comments",
3660         "ProductName",            "DisplayName",
3661         "ProductVersion",         "DisplayVersion",
3662         "ARPHELPLINK",            "HelpLink",
3663         "ARPHELPTELEPHONE",       "HelpTelephone",
3664         "ARPINSTALLLOCATION",     "InstallLocation",
3665         "SourceDir",              "InstallSource",
3666         "Manufacturer",           "Publisher",
3667         "ARPREADME",              "Readme",
3668         "ARPSIZE",                "Size",
3669         "ARPURLINFOABOUT",        "URLInfoAbout",
3670         "ARPURLUPDATEINFO",       "URLUpdateInfo",
3671         NULL,
3672     };
3673     const LPCSTR *p = propval;
3674
3675     while( *p )
3676     {
3677         prop = strdupAtoW( *p++ );
3678         key = strdupAtoW( *p++ );
3679         val = msi_dup_property( package, prop );
3680         msi_reg_set_val_str( hkey, key, val );
3681         msi_free(val);
3682         msi_free(key);
3683         msi_free(prop);
3684     }
3685     return ERROR_SUCCESS;
3686 }
3687
3688 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3689 {
3690     HKEY hkey=0;
3691     LPWSTR buffer = NULL;
3692     UINT rc;
3693     DWORD size, langid;
3694     static const WCHAR szWindowsInstaller[] = 
3695         {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3696     static const WCHAR szUpgradeCode[] = 
3697         {'U','p','g','r','a','d','e','C','o','d','e',0};
3698     static const WCHAR modpath_fmt[] = 
3699         {'M','s','i','E','x','e','c','.','e','x','e',' ',
3700          '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3701     static const WCHAR szModifyPath[] = 
3702         {'M','o','d','i','f','y','P','a','t','h',0};
3703     static const WCHAR szUninstallString[] = 
3704         {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3705     static const WCHAR szEstimatedSize[] = 
3706         {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3707     static const WCHAR szProductLanguage[] =
3708         {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3709     static const WCHAR szProductVersion[] =
3710         {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3711
3712     SYSTEMTIME systime;
3713     static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3714     LPWSTR upgrade_code;
3715     WCHAR szDate[9]; 
3716
3717     rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3718     if (rc != ERROR_SUCCESS)
3719         return rc;
3720
3721     /* dump all the info i can grab */
3722     /* FIXME: Flesh out more information */
3723
3724     msi_write_uninstall_property_vals( package, hkey );
3725
3726     msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3727     
3728     msi_make_package_local( package, hkey );
3729
3730     /* do ModifyPath and UninstallString */
3731     size = deformat_string(package,modpath_fmt,&buffer);
3732     RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3733     RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3734     msi_free(buffer);
3735
3736     /* FIXME: Write real Estimated Size when we have it */
3737     msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3738    
3739     GetLocalTime(&systime);
3740     sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3741     msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3742    
3743     langid = msi_get_property_int( package, szProductLanguage, 0 );
3744     msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3745
3746     buffer = msi_dup_property( package, szProductVersion );
3747     if (buffer)
3748     {
3749         DWORD verdword = msi_version_str_to_dword(buffer);
3750
3751         msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3752         msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3753         msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3754     }
3755     msi_free(buffer);
3756     
3757     /* Handle Upgrade Codes */
3758     upgrade_code = msi_dup_property( package, szUpgradeCode );
3759     if (upgrade_code)
3760     {
3761         HKEY hkey2;
3762         WCHAR squashed[33];
3763         MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3764         squash_guid(package->ProductCode,squashed);
3765         msi_reg_set_val_str( hkey2, squashed, NULL );
3766         RegCloseKey(hkey2);
3767         MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3768         squash_guid(package->ProductCode,squashed);
3769         msi_reg_set_val_str( hkey2, squashed, NULL );
3770         RegCloseKey(hkey2);
3771
3772         msi_free(upgrade_code);
3773     }
3774     
3775     RegCloseKey(hkey);
3776
3777     /* FIXME: call ui_actiondata */
3778
3779     return ERROR_SUCCESS;
3780 }
3781
3782 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3783 {
3784     return execute_script(package,INSTALL_SCRIPT);
3785 }
3786
3787 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3788 {
3789     UINT rc;
3790
3791     /* turn off scheduleing */
3792     package->script->CurrentlyScripting= FALSE;
3793
3794     /* first do the same as an InstallExecute */
3795     rc = ACTION_InstallExecute(package);
3796     if (rc != ERROR_SUCCESS)
3797         return rc;
3798
3799     /* then handle Commit Actions */
3800     rc = execute_script(package,COMMIT_SCRIPT);
3801
3802     return rc;
3803 }
3804
3805 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3806 {
3807     static const WCHAR RunOnce[] = {
3808     'S','o','f','t','w','a','r','e','\\',
3809     'M','i','c','r','o','s','o','f','t','\\',
3810     'W','i','n','d','o','w','s','\\',
3811     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3812     'R','u','n','O','n','c','e',0};
3813     static const WCHAR InstallRunOnce[] = {
3814     'S','o','f','t','w','a','r','e','\\',
3815     'M','i','c','r','o','s','o','f','t','\\',
3816     'W','i','n','d','o','w','s','\\',
3817     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3818     'I','n','s','t','a','l','l','e','r','\\',
3819     'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3820
3821     static const WCHAR msiexec_fmt[] = {
3822     '%','s',
3823     '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3824     '\"','%','s','\"',0};
3825     static const WCHAR install_fmt[] = {
3826     '/','I',' ','\"','%','s','\"',' ',
3827     'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3828     'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3829     WCHAR buffer[256], sysdir[MAX_PATH];
3830     HKEY hkey;
3831     WCHAR squished_pc[100];
3832
3833     squash_guid(package->ProductCode,squished_pc);
3834
3835     GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3836     RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3837     snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3838      squished_pc);
3839
3840     msi_reg_set_val_str( hkey, squished_pc, buffer );
3841     RegCloseKey(hkey);
3842
3843     TRACE("Reboot command %s\n",debugstr_w(buffer));
3844
3845     RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3846     sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3847
3848     msi_reg_set_val_str( hkey, squished_pc, buffer );
3849     RegCloseKey(hkey);
3850
3851     return ERROR_INSTALL_SUSPEND;
3852 }
3853
3854 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
3855 {
3856     DWORD attrib, len;
3857     LPWSTR ptr, source;
3858     UINT rc;
3859     
3860     /*
3861      * we are currently doing what should be done here in the top level Install
3862      * however for Adminastrative and uninstalls this step will be needed
3863      */
3864     if (!package->PackagePath)
3865         return ERROR_SUCCESS;
3866
3867     ptr = strrchrW(package->PackagePath, '\\');
3868     if (!ptr)
3869         return ERROR_SUCCESS;
3870
3871     len = ptr - package->PackagePath + 2;
3872     source = msi_alloc(len * sizeof(WCHAR));
3873     lstrcpynW(source,  package->PackagePath, len);
3874
3875     MSI_SetPropertyW(package, cszSourceDir, source);
3876     MSI_SetPropertyW(package, cszSOURCEDIR, source);
3877
3878     msi_free(source);
3879
3880     attrib = GetFileAttributesW(package->PackagePath);
3881     if (attrib == INVALID_FILE_ATTRIBUTES)
3882     {
3883         LPWSTR prompt;
3884         LPWSTR msg;
3885         DWORD size = 0;
3886
3887         rc = MsiSourceListGetInfoW(package->ProductCode, NULL, 
3888                 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3889                 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3890         if (rc == ERROR_MORE_DATA)
3891         {
3892             prompt = msi_alloc(size * sizeof(WCHAR));
3893             MsiSourceListGetInfoW(package->ProductCode, NULL, 
3894                     MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3895                     INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3896         }
3897         else
3898             prompt = strdupW(package->PackagePath);
3899
3900         msg = generate_error_string(package,1302,1,prompt);
3901         while(attrib == INVALID_FILE_ATTRIBUTES)
3902         {
3903             rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3904             if (rc == IDCANCEL)
3905             {
3906                 rc = ERROR_INSTALL_USEREXIT;
3907                 break;
3908             }
3909             attrib = GetFileAttributesW(package->PackagePath);
3910         }
3911         msi_free(prompt);
3912         rc = ERROR_SUCCESS;
3913     }
3914     else
3915         return ERROR_SUCCESS;
3916
3917     return rc;
3918 }
3919
3920 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3921 {
3922     HKEY hkey=0;
3923     LPWSTR buffer;
3924     LPWSTR productid;
3925     UINT rc,i;
3926
3927     static const WCHAR szPropKeys[][80] = 
3928     {
3929         {'P','r','o','d','u','c','t','I','D',0},
3930         {'U','S','E','R','N','A','M','E',0},
3931         {'C','O','M','P','A','N','Y','N','A','M','E',0},
3932         {0},
3933     };
3934
3935     static const WCHAR szRegKeys[][80] = 
3936     {
3937         {'P','r','o','d','u','c','t','I','D',0},
3938         {'R','e','g','O','w','n','e','r',0},
3939         {'R','e','g','C','o','m','p','a','n','y',0},
3940         {0},
3941     };
3942
3943     productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3944     if (!productid)
3945         return ERROR_SUCCESS;
3946
3947     rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3948     if (rc != ERROR_SUCCESS)
3949         goto end;
3950
3951     for( i = 0; szPropKeys[i][0]; i++ )
3952     {
3953         buffer = msi_dup_property( package, szPropKeys[i] );
3954         msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3955         msi_free( buffer );
3956     }
3957
3958 end:
3959     msi_free(productid);
3960     RegCloseKey(hkey);
3961
3962     /* FIXME: call ui_actiondata */
3963
3964     return ERROR_SUCCESS;
3965 }
3966
3967
3968 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3969 {
3970     UINT rc;
3971
3972     package->script->InWhatSequence |= SEQUENCE_EXEC;
3973     rc = ACTION_ProcessExecSequence(package,FALSE);
3974     return rc;
3975 }
3976
3977
3978 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
3979 {
3980     MSIPACKAGE *package = (MSIPACKAGE*)param;
3981     LPCWSTR compgroupid=NULL;
3982     LPCWSTR feature=NULL;
3983     LPCWSTR text = NULL;
3984     LPCWSTR qualifier = NULL;
3985     LPCWSTR component = NULL;
3986     LPWSTR advertise = NULL;
3987     LPWSTR output = NULL;
3988     HKEY hkey;
3989     UINT rc = ERROR_SUCCESS;
3990     MSICOMPONENT *comp;
3991     DWORD sz = 0;
3992     MSIRECORD *uirow;
3993
3994     component = MSI_RecordGetString(rec,3);
3995     comp = get_loaded_component(package,component);
3996
3997     if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) && 
3998        !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
3999        !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4000     {
4001         TRACE("Skipping: Component %s not scheduled for install\n",
4002                         debugstr_w(component));
4003
4004         return ERROR_SUCCESS;
4005     }
4006
4007     compgroupid = MSI_RecordGetString(rec,1);
4008     qualifier = MSI_RecordGetString(rec,2);
4009
4010     rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4011     if (rc != ERROR_SUCCESS)
4012         goto end;
4013     
4014     text = MSI_RecordGetString(rec,4);
4015     feature = MSI_RecordGetString(rec,5);
4016   
4017     advertise = create_component_advertise_string(package, comp, feature);
4018
4019     sz = strlenW(advertise);
4020
4021     if (text)
4022         sz += lstrlenW(text);
4023
4024     sz+=3;
4025     sz *= sizeof(WCHAR);
4026            
4027     output = msi_alloc_zero(sz);
4028     strcpyW(output,advertise);
4029     msi_free(advertise);
4030
4031     if (text)
4032         strcatW(output,text);
4033
4034     msi_reg_set_val_multi_str( hkey, qualifier, output );
4035     
4036 end:
4037     RegCloseKey(hkey);
4038     msi_free(output);
4039
4040     /* the UI chunk */
4041     uirow = MSI_CreateRecord( 2 );
4042     MSI_RecordSetStringW( uirow, 1, compgroupid );
4043     MSI_RecordSetStringW( uirow, 2, qualifier);
4044     ui_actiondata( package, szPublishComponents, uirow);
4045     msiobj_release( &uirow->hdr );
4046     /* FIXME: call ui_progress? */
4047
4048     return rc;
4049 }
4050
4051 /*
4052  * At present I am ignorning the advertised components part of this and only
4053  * focusing on the qualified component sets
4054  */
4055 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4056 {
4057     UINT rc;
4058     MSIQUERY * view;
4059     static const WCHAR ExecSeqQuery[] =
4060         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4061          '`','P','u','b','l','i','s','h',
4062          'C','o','m','p','o','n','e','n','t','`',0};
4063     
4064     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4065     if (rc != ERROR_SUCCESS)
4066         return ERROR_SUCCESS;
4067
4068     rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4069     msiobj_release(&view->hdr);
4070
4071     return rc;
4072 }
4073
4074 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4075 {
4076     MSIPACKAGE *package = (MSIPACKAGE*)param;
4077     MSIRECORD *row;
4078     MSIFILE *file;
4079     SC_HANDLE hscm, service = NULL;
4080     LPCWSTR name, disp, comp, depends, pass;
4081     LPCWSTR load_order, serv_name, key;
4082     DWORD serv_type, start_type;
4083     DWORD err_control;
4084
4085     static const WCHAR query[] =
4086         {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4087          '`','C','o','m','p','o','n','e','n','t','`',' ',
4088          'W','H','E','R','E',' ',
4089          '`','C','o','m','p','o','n','e','n','t','`',' ',
4090          '=','\'','%','s','\'',0};
4091
4092     hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4093     if (!hscm)
4094     {
4095         ERR("Failed to open the SC Manager!\n");
4096         goto done;
4097     }
4098
4099     start_type = MSI_RecordGetInteger(rec, 5);
4100     if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4101         goto done;
4102
4103     depends = MSI_RecordGetString(rec, 8);
4104     if (depends && *depends)
4105         FIXME("Dependency list unhandled!\n");
4106
4107     name = MSI_RecordGetString(rec, 2);
4108     disp = MSI_RecordGetString(rec, 3);
4109     serv_type = MSI_RecordGetInteger(rec, 4);
4110     err_control = MSI_RecordGetInteger(rec, 6);
4111     load_order = MSI_RecordGetString(rec, 7);
4112     serv_name = MSI_RecordGetString(rec, 9);
4113     pass = MSI_RecordGetString(rec, 10);
4114     comp = MSI_RecordGetString(rec, 12);
4115
4116     /* fetch the service path */
4117     row = MSI_QueryGetRecord(package->db, query, comp);
4118     if (!row)
4119     {
4120         ERR("Control query failed!\n");
4121         goto done;
4122     }
4123
4124     key = MSI_RecordGetString(row, 6);
4125     msiobj_release(&row->hdr);
4126
4127     file = get_loaded_file(package, key);
4128     if (!file)
4129     {
4130         ERR("Failed to load the service file\n");
4131         goto done;
4132     }
4133
4134     service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4135                              start_type, err_control, file->TargetPath,
4136                              load_order, NULL, NULL, serv_name, pass);
4137     if (!service)
4138     {
4139         if (GetLastError() != ERROR_SERVICE_EXISTS)
4140             ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4141     }
4142
4143 done:
4144     CloseServiceHandle(service);
4145     CloseServiceHandle(hscm);
4146
4147     return ERROR_SUCCESS;
4148 }
4149
4150 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4151 {
4152     UINT rc;
4153     MSIQUERY * view;
4154     static const WCHAR ExecSeqQuery[] =
4155         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4156          'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4157     
4158     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4159     if (rc != ERROR_SUCCESS)
4160         return ERROR_SUCCESS;
4161
4162     rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4163     msiobj_release(&view->hdr);
4164
4165     return rc;
4166 }
4167
4168 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4169                                            LPCSTR action, LPCWSTR table )
4170 {
4171     static const WCHAR query[] = {
4172         'S','E','L','E','C','T',' ','*',' ',
4173         'F','R','O','M',' ','`','%','s','`',0 };
4174     MSIQUERY *view = NULL;
4175     DWORD count = 0;
4176     UINT r;
4177     
4178     r = MSI_OpenQuery( package->db, &view, query, table );
4179     if (r == ERROR_SUCCESS)
4180     {
4181         r = MSI_IterateRecords(view, &count, NULL, package);
4182         msiobj_release(&view->hdr);
4183     }
4184
4185     if (count)
4186         FIXME("%s -> %u ignored %s table values\n",
4187               action, count, debugstr_w(table));
4188
4189     return ERROR_SUCCESS;
4190 }
4191
4192 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4193 {
4194     TRACE("%p\n", package);
4195     return ERROR_SUCCESS;
4196 }
4197
4198 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4199 {
4200     static const WCHAR table[] =
4201          {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4202     return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4203 }
4204
4205 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4206 {
4207     static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4208     return msi_unimplemented_action_stub( package, "MoveFiles", table );
4209 }
4210
4211 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4212 {
4213     static const WCHAR table[] = { 'P','a','t','c','h',0 };
4214     return msi_unimplemented_action_stub( package, "PatchFiles", table );
4215 }
4216
4217 static UINT ACTION_BindImage( MSIPACKAGE *package )
4218 {
4219     static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4220     return msi_unimplemented_action_stub( package, "BindImage", table );
4221 }
4222
4223 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4224 {
4225     static const WCHAR table[] = {
4226         'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4227     return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4228 }
4229
4230 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4231 {
4232     static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4233     return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4234 }
4235
4236 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4237 {
4238     static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4239     return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4240 }
4241
4242 static UINT ACTION_StartServices( MSIPACKAGE *package )
4243 {
4244     static const WCHAR table[] = {
4245         'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4246     return msi_unimplemented_action_stub( package, "StartServices", table );
4247 }
4248
4249 static UINT ACTION_StopServices( MSIPACKAGE *package )
4250 {
4251     static const WCHAR table[] = {
4252         'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4253     return msi_unimplemented_action_stub( package, "StopServices", table );
4254 }
4255
4256 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4257 {
4258     static const WCHAR table[] = {
4259         'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4260     return msi_unimplemented_action_stub( package, "DeleteServices", table );
4261 }
4262
4263 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4264 {
4265     static const WCHAR table[] = {
4266         'E','n','v','i','r','o','n','m','e','n','t',0 };
4267     return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4268 }
4269
4270 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4271 {
4272     static const WCHAR table[] = {
4273         'E','n','v','i','r','o','n','m','e','n','t',0 };
4274     return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4275 }
4276
4277 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4278 {
4279     static const WCHAR table[] = {
4280         'M','s','i','A','s','s','e','m','b','l','y',0 };
4281     return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4282 }
4283
4284 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4285 {
4286     static const WCHAR table[] = {
4287         'M','s','i','A','s','s','e','m','b','l','y',0 };
4288     return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4289 }
4290
4291 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4292 {
4293     static const WCHAR table[] = { 'F','o','n','t',0 };
4294     return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4295 }
4296
4297 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4298 {
4299     static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4300     return msi_unimplemented_action_stub( package, "CCPSearch", table );
4301 }
4302
4303 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4304 {
4305     static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4306     return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4307 }
4308
4309 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4310 {
4311     static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4312     return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4313 }
4314
4315 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4316 {
4317     static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4318     return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4319 }
4320
4321 static struct _actions StandardActions[] = {
4322     { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4323     { szAppSearch, ACTION_AppSearch },
4324     { szBindImage, ACTION_BindImage },
4325     { szCCPSearch, ACTION_CCPSearch},
4326     { szCostFinalize, ACTION_CostFinalize },
4327     { szCostInitialize, ACTION_CostInitialize },
4328     { szCreateFolders, ACTION_CreateFolders },
4329     { szCreateShortcuts, ACTION_CreateShortcuts },
4330     { szDeleteServices, ACTION_DeleteServices },
4331     { szDisableRollback, NULL},
4332     { szDuplicateFiles, ACTION_DuplicateFiles },
4333     { szExecuteAction, ACTION_ExecuteAction },
4334     { szFileCost, ACTION_FileCost },
4335     { szFindRelatedProducts, ACTION_FindRelatedProducts },
4336     { szForceReboot, ACTION_ForceReboot },
4337     { szInstallAdminPackage, NULL},
4338     { szInstallExecute, ACTION_InstallExecute },
4339     { szInstallExecuteAgain, ACTION_InstallExecute },
4340     { szInstallFiles, ACTION_InstallFiles},
4341     { szInstallFinalize, ACTION_InstallFinalize },
4342     { szInstallInitialize, ACTION_InstallInitialize },
4343     { szInstallSFPCatalogFile, NULL},
4344     { szInstallValidate, ACTION_InstallValidate },
4345     { szIsolateComponents, ACTION_IsolateComponents },
4346     { szLaunchConditions, ACTION_LaunchConditions },
4347     { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4348     { szMoveFiles, ACTION_MoveFiles },
4349     { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4350     { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4351     { szInstallODBC, NULL},
4352     { szInstallServices, ACTION_InstallServices },
4353     { szPatchFiles, ACTION_PatchFiles },
4354     { szProcessComponents, ACTION_ProcessComponents },
4355     { szPublishComponents, ACTION_PublishComponents },
4356     { szPublishFeatures, ACTION_PublishFeatures },
4357     { szPublishProduct, ACTION_PublishProduct },
4358     { szRegisterClassInfo, ACTION_RegisterClassInfo },
4359     { szRegisterComPlus, ACTION_RegisterComPlus},
4360     { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4361     { szRegisterFonts, ACTION_RegisterFonts },
4362     { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4363     { szRegisterProduct, ACTION_RegisterProduct },
4364     { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4365     { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4366     { szRegisterUser, ACTION_RegisterUser},
4367     { szRemoveDuplicateFiles, NULL},
4368     { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4369     { szRemoveExistingProducts, NULL},
4370     { szRemoveFiles, ACTION_RemoveFiles},
4371     { szRemoveFolders, NULL},
4372     { szRemoveIniValues, ACTION_RemoveIniValues },
4373     { szRemoveODBC, NULL},
4374     { szRemoveRegistryValues, NULL},
4375     { szRemoveShortcuts, NULL},
4376     { szResolveSource, ACTION_ResolveSource},
4377     { szRMCCPSearch, ACTION_RMCCPSearch},
4378     { szScheduleReboot, NULL},
4379     { szSelfRegModules, ACTION_SelfRegModules },
4380     { szSelfUnregModules, ACTION_SelfUnregModules },
4381     { szSetODBCFolders, NULL},
4382     { szStartServices, ACTION_StartServices },
4383     { szStopServices, ACTION_StopServices },
4384     { szUnpublishComponents, NULL},
4385     { szUnpublishFeatures, NULL},
4386     { szUnregisterClassInfo, NULL},
4387     { szUnregisterComPlus, ACTION_UnregisterComPlus},
4388     { szUnregisterExtensionInfo, NULL},
4389     { szUnregisterFonts, ACTION_UnregisterFonts },
4390     { szUnregisterMIMEInfo, NULL},
4391     { szUnregisterProgIdInfo, NULL},
4392     { szUnregisterTypeLibraries, NULL},
4393     { szValidateProductID, NULL},
4394     { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4395     { szWriteIniValues, ACTION_WriteIniValues },
4396     { szWriteRegistryValues, ACTION_WriteRegistryValues},
4397     { NULL, NULL},
4398 };