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