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