Fix command line parsing.
[wine] / dlls / msi / action.c
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2004 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 #include <stdio.h>
31
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winerror.h"
35 #include "winreg.h"
36 #include "wine/debug.h"
37 #include "msi.h"
38 #include "msiquery.h"
39 #include "objbase.h"
40 #include "objidl.h"
41 #include "msipriv.h"
42 #include "winnls.h"
43 #include "winuser.h"
44 #include "shlobj.h"
45 #include "wine/unicode.h"
46 #include "ver.h"
47
48 #define CUSTOM_ACTION_TYPE_MASK 0x3F
49
50 WINE_DEFAULT_DEBUG_CHANNEL(msi);
51
52 typedef struct tagMSIFEATURE
53 {
54     WCHAR Feature[96];
55     WCHAR Feature_Parent[96];
56     WCHAR Title[0x100];
57     WCHAR Description[0x100];
58     INT Display;
59     INT Level;
60     WCHAR Directory[96];
61     INT Attributes;
62     
63     INSTALLSTATE State;
64     BOOL Enabled;
65     INT ComponentCount;
66     INT Components[1024]; /* yes hardcoded limit.... I am bad */
67     INT Cost;
68 } MSIFEATURE;
69
70 typedef struct tagMSICOMPONENT
71 {
72     WCHAR Component[96];
73     WCHAR ComponentId[96];
74     WCHAR Directory[96];
75     INT Attributes;
76     WCHAR Condition[0x100];
77     WCHAR KeyPath[96];
78
79     INSTALLSTATE State;
80     BOOL FeatureState;
81     BOOL Enabled;
82     INT  Cost;
83 } MSICOMPONENT;
84
85 typedef struct tagMSIFOLDER
86 {
87     WCHAR Directory[96];
88     WCHAR TargetDefault[96];
89     WCHAR SourceDefault[96];
90
91     WCHAR ResolvedTarget[MAX_PATH];
92     WCHAR ResolvedSource[MAX_PATH];
93     WCHAR Property[MAX_PATH];   /* initially set property */
94     INT   ParentIndex;
95     INT   State;
96         /* 0 = uninitialized */
97         /* 1 = existing */
98         /* 2 = created remove if empty */
99         /* 3 = created persist if empty */
100     INT   Cost;
101     INT   Space;
102 }MSIFOLDER;
103
104 typedef struct tagMSIFILE
105 {
106     WCHAR File[72];
107     INT ComponentIndex;
108     WCHAR FileName[MAX_PATH];
109     INT FileSize;
110     WCHAR Version[72];
111     WCHAR Language[20];
112     INT Attributes;
113     INT Sequence;   
114
115     INT State;
116        /* 0 = uninitialize */
117        /* 1 = not present */
118        /* 2 = present but replace */
119        /* 3 = present do not replace */
120        /* 4 = Installed */
121     WCHAR   SourcePath[MAX_PATH];
122     WCHAR   TargetPath[MAX_PATH];
123     BOOL    Temporary; 
124 }MSIFILE;
125
126 /*
127  * Prototypes
128  */
129 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
130 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
131
132 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action);
133
134 static UINT ACTION_LaunchConditions(MSIPACKAGE *package);
135 static UINT ACTION_CostInitialize(MSIPACKAGE *package);
136 static UINT ACTION_CreateFolders(MSIPACKAGE *package);
137 static UINT ACTION_CostFinalize(MSIPACKAGE *package);
138 static UINT ACTION_FileCost(MSIPACKAGE *package);
139 static UINT ACTION_InstallFiles(MSIPACKAGE *package);
140 static UINT ACTION_DuplicateFiles(MSIPACKAGE *package);
141 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package);
142 static UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action);
143 static UINT ACTION_InstallInitialize(MSIPACKAGE *package);
144 static UINT ACTION_InstallValidate(MSIPACKAGE *package);
145 static UINT ACTION_ProcessComponents(MSIPACKAGE *package);
146 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package);
147 static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package);
148 static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package);
149 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package);
150 static UINT ACTION_PublishProduct(MSIPACKAGE *package);
151
152 static UINT HANDLE_CustomType1(MSIPACKAGE *package, const LPWSTR source, 
153                                 const LPWSTR target, const INT type);
154 static UINT HANDLE_CustomType2(MSIPACKAGE *package, const LPWSTR source, 
155                                 const LPWSTR target, const INT type);
156
157 static DWORD deformat_string(MSIPACKAGE *package, WCHAR* ptr,WCHAR** data);
158 static UINT resolve_folder(MSIPACKAGE *package, LPCWSTR name, LPWSTR path, 
159                            BOOL source, BOOL set_prop, MSIFOLDER **folder);
160
161 static UINT track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path);
162  
163 /*
164  * consts and values used
165  */
166 static const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0};
167 static const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0};
168 static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0};
169 static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
170 static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0};
171 static const WCHAR c_collen[] = {'C',':','\\',0};
172  
173 static const WCHAR cszlsb[]={'[',0};
174 static const WCHAR cszrsb[]={']',0};
175 static const WCHAR cszbs[]={'\\',0};
176
177 const static WCHAR szCreateFolders[] =
178     {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
179 const static WCHAR szCostFinalize[] =
180     {'C','o','s','t','F','i','n','a','l','i','z','e',0};
181 const static WCHAR szInstallFiles[] =
182     {'I','n','s','t','a','l','l','F','i','l','e','s',0};
183 const static WCHAR szDuplicateFiles[] =
184     {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
185 const static WCHAR szWriteRegistryValues[] =
186 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
187 const static WCHAR szCostInitialize[] =
188     {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
189 const static WCHAR szFileCost[] = {'F','i','l','e','C','o','s','t',0};
190 const static WCHAR szInstallInitialize[] = 
191     {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
192 const static WCHAR szInstallValidate[] = 
193     {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
194 const static WCHAR szLaunchConditions[] = 
195     {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
196 const static WCHAR szProcessComponents[] = 
197     {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
198 const static WCHAR szRegisterTypeLibraries[] = 
199 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r',
200 'i','e','s',0};
201 const static WCHAR szRegisterClassInfo[] = 
202 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
203 const static WCHAR szRegisterProgIdInfo[] = 
204 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
205 const static WCHAR szCreateShortcuts[] = 
206 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
207 const static WCHAR szPublishProduct[] = 
208 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
209
210 /******************************************************** 
211  * helper functions to get around current HACKS and such
212  ********************************************************/
213 inline static void reduce_to_longfilename(WCHAR* filename)
214 {
215     if (strchrW(filename,'|'))
216     {
217         WCHAR newname[MAX_PATH];
218         strcpyW(newname,strchrW(filename,'|')+1);
219         strcpyW(filename,newname);
220     }
221 }
222
223 inline static char *strdupWtoA( const WCHAR *str )
224 {
225     char *ret = NULL;
226     if (str)
227     {
228         DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL
229 );
230         if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
231             WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
232     }
233     return ret;
234 }
235
236 inline static WCHAR *strdupAtoW( const char *str )
237 {
238     WCHAR *ret = NULL;
239     if (str)
240     {
241         DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
242         if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
243             MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
244     }
245     return ret;
246 }
247
248 inline static WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index)
249 {
250     UINT rc;
251     DWORD sz;
252     LPWSTR ret;
253    
254     sz = 0; 
255     rc = MSI_RecordGetStringW(row,index,NULL,&sz);
256     if (sz <= 0)
257         return NULL;
258
259     sz ++;
260     ret = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR));
261     rc = MSI_RecordGetStringW(row,index,ret,&sz);
262     return ret;
263 }
264
265 inline static int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component )
266 {
267     INT rc = -1;
268     INT i;
269
270     for (i = 0; i < package->loaded_components; i++)
271     {
272         if (strcmpW(Component,package->components[i].Component)==0)
273         {
274             rc = i;
275             break;
276         }
277     }
278     return rc;
279 }
280
281 inline static int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature )
282 {
283     INT rc = -1;
284     INT i;
285
286     for (i = 0; i < package->loaded_features; i++)
287     {
288         if (strcmpW(Feature,package->features[i].Feature)==0)
289         {
290             rc = i;
291             break;
292         }
293     }
294     return rc;
295 }
296
297 inline static int get_loaded_file(MSIPACKAGE* package, LPCWSTR file)
298 {
299     INT rc = -1;
300     INT i;
301
302     for (i = 0; i < package->loaded_files; i++)
303     {
304         if (strcmpW(file,package->files[i].File)==0)
305         {
306             rc = i;
307             break;
308         }
309     }
310     return rc;
311 }
312
313 static UINT track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path)
314 {
315     int i;
316     int index;
317
318     if (!package)
319         return -2;
320
321     for (i=0; i < package->loaded_files; i++)
322         if (strcmpW(package->files[i].File,name)==0)
323             return -1;
324
325     index = package->loaded_files;
326     package->loaded_files++;
327     if (package->loaded_files== 1)
328         package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
329     else
330         package->files = HeapReAlloc(GetProcessHeap(),0,
331             package->files , package->loaded_files * sizeof(MSIFILE));
332
333     memset(&package->files[index],0,sizeof(MSIFILE));
334
335     strcpyW(package->files[index].File,name);
336     strcpyW(package->files[index].TargetPath,path);
337     package->files[index].Temporary = TRUE;
338
339     TRACE("Tracking tempfile (%s)\n",debugstr_w(package->files[index].File));  
340
341     return 0;
342 }
343
344 void ACTION_remove_tracked_tempfiles(MSIPACKAGE* package)
345 {
346     int i;
347
348     if (!package)
349         return;
350
351     for (i = 0; i < package->loaded_files; i++)
352     {
353         if (package->files[i].Temporary)
354             DeleteFileW(package->files[i].TargetPath);
355
356     }
357 }
358
359 static void ui_progress(MSIPACKAGE *package, int a, int b, int c, int d )
360 {
361     MSIRECORD * row;
362
363     row = MSI_CreateRecord(4);
364     MSI_RecordSetInteger(row,1,a);
365     MSI_RecordSetInteger(row,2,b);
366     MSI_RecordSetInteger(row,3,c);
367     MSI_RecordSetInteger(row,4,d);
368     MSI_ProcessMessage(package, INSTALLMESSAGE_PROGRESS, row);
369     msiobj_release(&row->hdr);
370 }
371
372 static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
373 {
374     static const WCHAR Query_t[] = 
375 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
376 'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
377 ' ','\'','%','s','\'',0};
378     WCHAR message[1024];
379     UINT rc;
380     MSIQUERY * view;
381     MSIRECORD * row = 0;
382     static WCHAR *ActionFormat=NULL;
383     static WCHAR LastAction[0x100] = {0};
384     WCHAR Query[1024];
385     LPWSTR ptr;
386
387     if (strcmpW(LastAction,action)!=0)
388     {
389         sprintfW(Query,Query_t,action);
390         rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
391         if (rc != ERROR_SUCCESS)
392             return;
393         rc = MSI_ViewExecute(view, 0);
394         if (rc != ERROR_SUCCESS)
395         {
396             MSI_ViewClose(view);
397             return;
398         }
399         rc = MSI_ViewFetch(view,&row);
400         if (rc != ERROR_SUCCESS)
401         {
402             MSI_ViewClose(view);
403             return;
404         }
405
406         if (MSI_RecordIsNull(row,3))
407         {
408             msiobj_release(&row->hdr);
409             MSI_ViewClose(view);
410             msiobj_release(&view->hdr);
411             return;
412         }
413
414         if (ActionFormat)
415             HeapFree(GetProcessHeap(),0,ActionFormat);
416
417         ActionFormat = load_dynamic_stringW(row,3);
418         strcpyW(LastAction,action);
419         msiobj_release(&row->hdr);
420         MSI_ViewClose(view);
421         msiobj_release(&view->hdr);
422     }
423
424     message[0]=0;
425     ptr = ActionFormat;
426     while (*ptr)
427     {
428         LPWSTR ptr2;
429         LPWSTR data=NULL;
430         WCHAR tmp[1023];
431         INT field;
432
433         ptr2 = strchrW(ptr,'[');
434         if (ptr2)
435         {
436             strncpyW(tmp,ptr,ptr2-ptr);
437             tmp[ptr2-ptr]=0;
438             strcatW(message,tmp);
439             ptr2++;
440             field = atoiW(ptr2);
441             data = load_dynamic_stringW(record,field);
442             if (data)
443             {
444                 strcatW(message,data);
445                 HeapFree(GetProcessHeap(),0,data);
446             }
447             ptr=strchrW(ptr2,']');
448             ptr++;
449         }
450         else
451         {
452             strcatW(message,ptr);
453             break;
454         }
455     }
456
457     row = MSI_CreateRecord(1);
458     MSI_RecordSetStringW(row,1,message);
459  
460     MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
461     msiobj_release(&row->hdr);
462 }
463
464
465 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
466 {
467     static const WCHAR template_s[]=
468 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ','%','s','.',0};
469     static const WCHAR format[] = 
470 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
471     static const WCHAR Query_t[] = 
472 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
473 'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
474 ' ','\'','%','s','\'',0};
475     WCHAR message[1024];
476     WCHAR timet[0x100];
477     UINT rc;
478     MSIQUERY * view;
479     MSIRECORD * row = 0;
480     WCHAR *ActionText=NULL;
481     WCHAR Query[1024];
482
483     GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
484
485     sprintfW(Query,Query_t,action);
486     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
487     if (rc != ERROR_SUCCESS)
488         return;
489     rc = MSI_ViewExecute(view, 0);
490     if (rc != ERROR_SUCCESS)
491     {
492         MSI_ViewClose(view);
493         msiobj_release(&view->hdr);
494         return;
495     }
496     rc = MSI_ViewFetch(view,&row);
497     if (rc != ERROR_SUCCESS)
498     {
499         MSI_ViewClose(view);
500         msiobj_release(&view->hdr);
501         return;
502     }
503
504     ActionText = load_dynamic_stringW(row,2);
505     msiobj_release(&row->hdr);
506     MSI_ViewClose(view);
507     msiobj_release(&view->hdr);
508
509     sprintfW(message,template_s,timet,action,ActionText);
510
511     row = MSI_CreateRecord(1);
512     MSI_RecordSetStringW(row,1,message);
513  
514     MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
515     msiobj_release(&row->hdr);
516     HeapFree(GetProcessHeap(),0,ActionText);
517 }
518
519 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start, 
520                           UINT rc)
521 {
522     MSIRECORD * row;
523     static const WCHAR template_s[]=
524 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ','%','s',
525 '.',0};
526     static const WCHAR template_e[]=
527 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ','%','s',
528 '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ','%','i','.',0};
529     static const WCHAR format[] = 
530 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
531     WCHAR message[1024];
532     WCHAR timet[0x100];
533
534     GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
535     if (start)
536         sprintfW(message,template_s,timet,action);
537     else
538         sprintfW(message,template_e,timet,action,rc);
539     
540     row = MSI_CreateRecord(1);
541     MSI_RecordSetStringW(row,1,message);
542  
543     MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
544     msiobj_release(&row->hdr);
545 }
546
547 /****************************************************
548  * TOP level entry points 
549  *****************************************************/
550
551 UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath,
552                               LPCWSTR szCommandLine)
553 {
554     DWORD sz;
555     WCHAR buffer[10];
556     UINT rc;
557     static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
558
559     if (szPackagePath)   
560     {
561         LPWSTR p;
562         WCHAR check[MAX_PATH];
563         WCHAR pth[MAX_PATH];
564         DWORD size;
565  
566         strcpyW(pth,szPackagePath);
567         p = strrchrW(pth,'\\');    
568         if (p)
569         {
570             p++;
571             *p=0;
572         }
573
574         size = MAX_PATH;
575         if (MSI_GetPropertyW(package,cszSourceDir,check,&size) 
576             != ERROR_SUCCESS )
577             MSI_SetPropertyW(package, cszSourceDir, pth);
578     }
579
580     if (szCommandLine)
581     {
582         LPWSTR ptr,ptr2;
583         ptr = (LPWSTR)szCommandLine;
584        
585         while (*ptr)
586         {
587             WCHAR prop[0x100];
588             WCHAR val[0x100];
589
590             TRACE("Looking at %s\n",debugstr_w(ptr));
591
592             ptr2 = strchrW(ptr,'=');
593             if (ptr2)
594             {
595                 BOOL quote=FALSE;
596                 DWORD len = 0;
597
598                 while (*ptr == ' ') ptr++;
599                 strncpyW(prop,ptr,ptr2-ptr);
600                 prop[ptr2-ptr]=0;
601                 ptr2++;
602             
603                 ptr = ptr2; 
604                 while (*ptr && (quote || (!quote && *ptr!=' ')))
605                 {
606                     if (*ptr == '"')
607                         quote = !quote;
608                     ptr++;
609                     len++;
610                 }
611                
612                 if (*ptr2=='"')
613                 {
614                     ptr2++;
615                     len -= 2;
616                 }
617                 strncpyW(val,ptr2,len);
618                 val[len]=0;
619
620                 if (strlenW(prop) > 0)
621                 {
622                     TRACE("Found commandline property (%s) = (%s)\n", debugstr_w(prop), debugstr_w(val));
623                     MSI_SetPropertyW(package,prop,val);
624                 }
625             }
626             ptr++;
627         }
628     }
629   
630     sz = 10; 
631     if (MSI_GetPropertyW(package,szUILevel,buffer,&sz) == ERROR_SUCCESS)
632     {
633         if (atoiW(buffer) >= INSTALLUILEVEL_REDUCED)
634         {
635             rc = ACTION_ProcessUISequence(package);
636             if (rc == ERROR_SUCCESS)
637                 rc = ACTION_ProcessExecSequence(package,TRUE);
638         }
639         else
640             rc = ACTION_ProcessExecSequence(package,FALSE);
641     }
642     else
643         rc = ACTION_ProcessExecSequence(package,FALSE);
644
645     return rc;
646 }
647
648
649 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
650 {
651     MSIQUERY * view;
652     UINT rc;
653     static const WCHAR ExecSeqQuery[] =  {
654        's','e','l','e','c','t',' ','*',' ',
655        'f','r','o','m',' ',
656            'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
657            'S','e','q','u','e','n','c','e',' ',
658        'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ',
659            '>',' ','%','i',' ','o','r','d','e','r',' ',
660        'b','y',' ','S','e','q','u','e','n','c','e',0 };
661     WCHAR Query[1024];
662     MSIRECORD * row = 0;
663     static const WCHAR IVQuery[] = {
664        's','e','l','e','c','t',' ','S','e','q','u','e','n','c','e',' ',
665        'f','r','o','m',' ','I','n','s','t','a','l','l',
666            'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e',' ',
667        'w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',' ',
668            '`','I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','`',
669        0};
670
671     if (UIran)
672     {
673         INT seq = 0;
674         
675         rc = MSI_DatabaseOpenViewW(package->db, IVQuery, &view);
676         if (rc != ERROR_SUCCESS)
677             return rc;
678         rc = MSI_ViewExecute(view, 0);
679         if (rc != ERROR_SUCCESS)
680         {
681             MSI_ViewClose(view);
682             msiobj_release(&view->hdr);
683             return rc;
684         }
685         rc = MSI_ViewFetch(view,&row);
686         if (rc != ERROR_SUCCESS)
687         {
688             MSI_ViewClose(view);
689             msiobj_release(&view->hdr);
690             return rc;
691         }
692         seq = MSI_RecordGetInteger(row,1);
693         msiobj_release(&row->hdr);
694         MSI_ViewClose(view);
695         msiobj_release(&view->hdr);
696         sprintfW(Query,ExecSeqQuery,seq);
697     }
698     else
699         sprintfW(Query,ExecSeqQuery,0);
700     
701     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
702     if (rc == ERROR_SUCCESS)
703     {
704         rc = MSI_ViewExecute(view, 0);
705
706         if (rc != ERROR_SUCCESS)
707         {
708             MSI_ViewClose(view);
709             msiobj_release(&view->hdr);
710             goto end;
711         }
712        
713         TRACE("Running the actions \n"); 
714
715         while (1)
716         {
717             WCHAR buffer[0x100];
718             DWORD sz = 0x100;
719
720             rc = MSI_ViewFetch(view,&row);
721             if (rc != ERROR_SUCCESS)
722             {
723                 rc = ERROR_SUCCESS;
724                 break;
725             }
726
727             /* check conditions */
728             if (!MSI_RecordIsNull(row,2))
729             {
730                 LPWSTR cond = NULL;
731                 cond = load_dynamic_stringW(row,2);
732
733                 if (cond)
734                 {
735                     /* this is a hack to skip errors in the condition code */
736                     if (MSI_EvaluateConditionW(package, cond) ==
737                             MSICONDITION_FALSE)
738                     {
739                         HeapFree(GetProcessHeap(),0,cond);
740                         msiobj_release(&row->hdr);
741                         continue; 
742                     }
743                     else
744                         HeapFree(GetProcessHeap(),0,cond);
745                 }
746             }
747
748             sz=0x100;
749             rc =  MSI_RecordGetStringW(row,1,buffer,&sz);
750             if (rc != ERROR_SUCCESS)
751             {
752                 ERR("Error is %x\n",rc);
753                 msiobj_release(&row->hdr);
754                 break;
755             }
756
757             rc = ACTION_PerformAction(package,buffer);
758
759             if (rc != ERROR_SUCCESS)
760             {
761                 ERR("Execution halted due to error (%i)\n",rc);
762                 msiobj_release(&row->hdr);
763                 break;
764             }
765
766             msiobj_release(&row->hdr);
767         }
768
769         MSI_ViewClose(view);
770         msiobj_release(&view->hdr);
771     }
772
773 end:
774     return rc;
775 }
776
777
778 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
779 {
780     MSIQUERY * view;
781     UINT rc;
782     static const WCHAR ExecSeqQuery [] = {
783       's','e','l','e','c','t',' ','*',' ',
784       'f','r','o','m',' ','I','n','s','t','a','l','l',
785             'U','I','S','e','q','u','e','n','c','e',' ',
786       'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ', '>',' ','0',' ',
787       'o','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e',0};
788     
789     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
790     
791     if (rc == ERROR_SUCCESS)
792     {
793         rc = MSI_ViewExecute(view, 0);
794
795         if (rc != ERROR_SUCCESS)
796         {
797             MSI_ViewClose(view);
798             msiobj_release(&view->hdr);
799             goto end;
800         }
801        
802         TRACE("Running the actions \n"); 
803
804         while (1)
805         {
806             WCHAR buffer[0x100];
807             DWORD sz = 0x100;
808             MSIRECORD * row = 0;
809
810             rc = MSI_ViewFetch(view,&row);
811             if (rc != ERROR_SUCCESS)
812             {
813                 rc = ERROR_SUCCESS;
814                 break;
815             }
816
817             /* check conditions */
818             if (!MSI_RecordIsNull(row,2))
819             {
820                 LPWSTR cond = NULL;
821                 cond = load_dynamic_stringW(row,2);
822
823                 if (cond)
824                 {
825                     /* this is a hack to skip errors in the condition code */
826                     if (MSI_EvaluateConditionW(package, cond) ==
827                             MSICONDITION_FALSE)
828                     {
829                         HeapFree(GetProcessHeap(),0,cond);
830                         msiobj_release(&row->hdr);
831                         continue; 
832                     }
833                     else
834                         HeapFree(GetProcessHeap(),0,cond);
835                 }
836             }
837
838             sz=0x100;
839             rc =  MSI_RecordGetStringW(row,1,buffer,&sz);
840             if (rc != ERROR_SUCCESS)
841             {
842                 ERR("Error is %x\n",rc);
843                 msiobj_release(&row->hdr);
844                 break;
845             }
846
847             rc = ACTION_PerformAction(package,buffer);
848
849             if (rc != ERROR_SUCCESS)
850             {
851                 ERR("Execution halted due to error (%i)\n",rc);
852                 msiobj_release(&row->hdr);
853                 break;
854             }
855
856             msiobj_release(&row->hdr);
857         }
858
859         MSI_ViewClose(view);
860         msiobj_release(&view->hdr);
861     }
862
863 end:
864     return rc;
865 }
866
867 /********************************************************
868  * ACTION helper functions and functions that perform the actions
869  *******************************************************/
870
871 /* 
872  * Alot of actions are really important even if they don't do anything
873  * explicit.. Lots of properties are set at the beginning of the installation
874  * CostFinalize does a bunch of work to translated the directories and such
875  * 
876  * But until I get write access to the database that is hard, so I am going to
877  * hack it to see if I can get something to run.
878  */
879 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action)
880 {
881     UINT rc = ERROR_SUCCESS; 
882
883     TRACE("Performing action (%s)\n",debugstr_w(action));
884     ui_actioninfo(package, action, TRUE, 0);
885     ui_actionstart(package, action);
886     ui_progress(package,2,1,0,0);
887
888     /* pre install, setup and configuration block */
889     if (strcmpW(action,szLaunchConditions)==0)
890         rc = ACTION_LaunchConditions(package);
891     else if (strcmpW(action,szCostInitialize)==0)
892         rc = ACTION_CostInitialize(package);
893     else if (strcmpW(action,szFileCost)==0)
894         rc = ACTION_FileCost(package);
895     else if (strcmpW(action,szCostFinalize)==0)
896         rc = ACTION_CostFinalize(package);
897     else if (strcmpW(action,szInstallValidate)==0)
898         rc = ACTION_InstallValidate(package);
899
900     /* install block */
901     else if (strcmpW(action,szProcessComponents)==0)
902         rc = ACTION_ProcessComponents(package);
903     else if (strcmpW(action,szInstallInitialize)==0)
904         rc = ACTION_InstallInitialize(package);
905     else if (strcmpW(action,szCreateFolders)==0)
906         rc = ACTION_CreateFolders(package);
907     else if (strcmpW(action,szInstallFiles)==0)
908         rc = ACTION_InstallFiles(package);
909     else if (strcmpW(action,szDuplicateFiles)==0)
910         rc = ACTION_DuplicateFiles(package);
911     else if (strcmpW(action,szWriteRegistryValues)==0)
912         rc = ACTION_WriteRegistryValues(package);
913      else if (strcmpW(action,szRegisterTypeLibraries)==0)
914         rc = ACTION_RegisterTypeLibraries(package);
915      else if (strcmpW(action,szRegisterClassInfo)==0)
916         rc = ACTION_RegisterClassInfo(package);
917      else if (strcmpW(action,szRegisterProgIdInfo)==0)
918         rc = ACTION_RegisterProgIdInfo(package);
919      else if (strcmpW(action,szCreateShortcuts)==0)
920         rc = ACTION_CreateShortcuts(package);
921     else if (strcmpW(action,szPublishProduct)==0)
922         rc = ACTION_PublishProduct(package);
923
924     /*
925      Called during iTunes but unimplemented and seem important
926
927      ResolveSource  (sets SourceDir)
928      RegisterProduct
929      InstallFinalize
930      */
931      else if ((rc = ACTION_CustomAction(package,action)) != ERROR_SUCCESS)
932      {
933         FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action));
934         rc = ERROR_SUCCESS;
935      }
936
937     ui_actioninfo(package, action, FALSE, rc);
938     return rc;
939 }
940
941
942 static UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action)
943 {
944     UINT rc = ERROR_SUCCESS;
945     MSIQUERY * view;
946     MSIRECORD * row = 0;
947     WCHAR ExecSeqQuery[1024] = 
948     {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','C','u','s','t','o'
949 ,'m','A','c','t','i','o','n',' ','w','h','e','r','e',' ','`','A','c','t','i'
950 ,'o','n','`',' ','=',' ','`',0};
951     static const WCHAR end[]={'`',0};
952     UINT type;
953     LPWSTR source;
954     LPWSTR target;
955     WCHAR *deformated=NULL;
956
957     strcatW(ExecSeqQuery,action);
958     strcatW(ExecSeqQuery,end);
959
960     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
961
962     if (rc != ERROR_SUCCESS)
963         return rc;
964
965     rc = MSI_ViewExecute(view, 0);
966     if (rc != ERROR_SUCCESS)
967     {
968         MSI_ViewClose(view);
969         msiobj_release(&view->hdr);
970         return rc;
971     }
972
973     rc = MSI_ViewFetch(view,&row);
974     if (rc != ERROR_SUCCESS)
975     {
976         MSI_ViewClose(view);
977         msiobj_release(&view->hdr);
978         return rc;
979     }
980
981     type = MSI_RecordGetInteger(row,2);
982
983     source = load_dynamic_stringW(row,3);
984     target = load_dynamic_stringW(row,4);
985
986     TRACE("Handling custom action %s (%x %s %s)\n",debugstr_w(action),type,
987           debugstr_w(source), debugstr_w(target));
988
989     /* we are ignoring ALOT of flags and important synchronization stuff */
990     switch (type & CUSTOM_ACTION_TYPE_MASK)
991     {
992         case 1: /* DLL file stored in a Binary table stream */
993             rc = HANDLE_CustomType1(package,source,target,type);
994             break;
995         case 2: /* EXE file stored in a Binary table strem */
996             rc = HANDLE_CustomType2(package,source,target,type);
997             break;
998         case 35: /* Directory set with formatted text. */
999         case 51: /* Property set with formatted text. */
1000             deformat_string(package,target,&deformated);
1001             rc = MSI_SetPropertyW(package,source,deformated);
1002             HeapFree(GetProcessHeap(),0,deformated);
1003             break;
1004         default:
1005             FIXME("UNHANDLED ACTION TYPE %i (%s %s)\n",
1006              type & CUSTOM_ACTION_TYPE_MASK, debugstr_w(source),
1007              debugstr_w(target));
1008     }
1009
1010     HeapFree(GetProcessHeap(),0,source);
1011     HeapFree(GetProcessHeap(),0,target);
1012     msiobj_release(&row->hdr);
1013     MSI_ViewClose(view);
1014     msiobj_release(&view->hdr);
1015     return rc;
1016 }
1017
1018 static UINT store_binary_to_temp(MSIPACKAGE *package, const LPWSTR source, 
1019                                 LPWSTR tmp_file)
1020 {
1021     DWORD sz=MAX_PATH;
1022
1023     if (MSI_GetPropertyW(package, cszTempFolder, tmp_file, &sz) 
1024         != ERROR_SUCCESS)
1025         GetTempPathW(MAX_PATH,tmp_file);
1026
1027     strcatW(tmp_file,source);
1028
1029     if (GetFileAttributesW(tmp_file) != INVALID_FILE_ATTRIBUTES)
1030     {
1031         TRACE("File already exists\n");
1032         return ERROR_SUCCESS;
1033     }
1034     else
1035     {
1036         /* write out the file */
1037         UINT rc;
1038         MSIQUERY * view;
1039         MSIRECORD * row = 0;
1040         WCHAR Query[1024] =
1041         {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','B','i'
1042 ,'n','a','r','y',' ','w','h','e','r','e',' ','N','a','m','e','=','`',0};
1043         static const WCHAR end[]={'`',0};
1044         HANDLE the_file;
1045         CHAR buffer[1024];
1046
1047         if (track_tempfile(package, source, tmp_file)!=0)
1048             FIXME("File Name in temp tracking collision\n");
1049
1050         the_file = CreateFileW(tmp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
1051                            FILE_ATTRIBUTE_NORMAL, NULL);
1052     
1053         if (the_file == INVALID_HANDLE_VALUE)
1054             return ERROR_FUNCTION_FAILED;
1055
1056         strcatW(Query,source);
1057         strcatW(Query,end);
1058
1059         rc = MSI_DatabaseOpenViewW( package->db, Query, &view);
1060         if (rc != ERROR_SUCCESS)
1061             return rc;
1062
1063         rc = MSI_ViewExecute(view, 0);
1064         if (rc != ERROR_SUCCESS)
1065         {
1066             MSI_ViewClose(view);
1067             msiobj_release(&view->hdr);
1068             return rc;
1069         }
1070
1071         rc = MSI_ViewFetch(view,&row);
1072         if (rc != ERROR_SUCCESS)
1073         {
1074             MSI_ViewClose(view);
1075             msiobj_release(&view->hdr);
1076             return rc;
1077         }
1078
1079         do 
1080         {
1081             DWORD write;
1082             sz = 1024;
1083             rc = MSI_RecordReadStream(row,2,buffer,&sz);
1084             if (rc != ERROR_SUCCESS)
1085             {
1086                 ERR("Failed to get stream\n");
1087                 CloseHandle(the_file);  
1088                 DeleteFileW(tmp_file);
1089                 break;
1090             }
1091             WriteFile(the_file,buffer,sz,&write,NULL);
1092         } while (sz == 1024);
1093
1094         CloseHandle(the_file);
1095
1096         msiobj_release(&row->hdr);
1097         MSI_ViewClose(view);
1098         msiobj_release(&view->hdr);
1099     }
1100
1101     return ERROR_SUCCESS;
1102 }
1103
1104
1105 typedef UINT CustomEntry(MSIHANDLE);
1106 typedef struct 
1107 {
1108         MSIPACKAGE *package;
1109         WCHAR target[MAX_PATH];
1110         WCHAR source[MAX_PATH];
1111 } thread_struct;
1112
1113 #if 0
1114 static DWORD WINAPI DllThread(LPVOID info)
1115 {
1116     HANDLE DLL;
1117     LPSTR proc;
1118     thread_struct *stuff;
1119     CustomEntry *fn;
1120      
1121     stuff = (thread_struct*)info;
1122
1123     TRACE("Asyncronous start (%s, %s) \n", debugstr_w(stuff->source),
1124           debugstr_w(stuff->target));
1125
1126     DLL = LoadLibraryW(stuff->source);
1127     if (DLL)
1128     {
1129         proc = strdupWtoA( stuff->target );
1130         fn = (CustomEntry*)GetProcAddress(DLL,proc);
1131         if (fn)
1132         {
1133             MSIHANDLE hPackage;
1134             MSIPACKAGE *package = stuff->package;
1135
1136             TRACE("Calling function\n");
1137             hPackage = msiobj_findhandle( &package->hdr );
1138             if( !hPackage )
1139                 ERR("Handle for object %p not found\n", package );
1140             fn(hPackage);
1141             msiobj_release( &package->hdr );
1142         }
1143         else
1144             ERR("Cannot load functon\n");
1145
1146         HeapFree(GetProcessHeap(),0,proc);
1147         FreeLibrary(DLL);
1148     }
1149     else
1150         ERR("Unable to load library\n");
1151     msiobj_release( &stuff->package->hdr );
1152     HeapFree( GetProcessHeap(), 0, info );
1153     return 0;
1154 }
1155 #endif
1156
1157 static UINT HANDLE_CustomType1(MSIPACKAGE *package, const LPWSTR source, 
1158                                 const LPWSTR target, const INT type)
1159 {
1160     WCHAR tmp_file[MAX_PATH];
1161     CustomEntry *fn;
1162     HANDLE DLL;
1163     LPSTR proc;
1164
1165     store_binary_to_temp(package, source, tmp_file);
1166
1167     TRACE("Calling function %s from %s\n",debugstr_w(target),
1168           debugstr_w(tmp_file));
1169
1170     if (!strchrW(tmp_file,'.'))
1171     {
1172         static const WCHAR dot[]={'.',0};
1173         strcatW(tmp_file,dot);
1174     } 
1175
1176     if (type & 0xc0)
1177     {
1178         /* DWORD ThreadId; */
1179         thread_struct *info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info) );
1180
1181         /* msiobj_addref( &package->hdr ); */
1182         info->package = package;
1183         strcpyW(info->target,target);
1184         strcpyW(info->source,tmp_file);
1185         TRACE("Start Asyncronous execution\n");
1186         FIXME("DATABASE NOT THREADSAFE... not starting\n");
1187         /* CreateThread(NULL,0,DllThread,(LPVOID)&info,0,&ThreadId); */
1188         /* FIXME: release the package if the CreateThread fails */
1189         HeapFree( GetProcessHeap(), 0, info );
1190         return ERROR_SUCCESS;
1191     }
1192  
1193     DLL = LoadLibraryW(tmp_file);
1194     if (DLL)
1195     {
1196         proc = strdupWtoA( target );
1197         fn = (CustomEntry*)GetProcAddress(DLL,proc);
1198         if (fn)
1199         {
1200             MSIHANDLE hPackage;
1201
1202             TRACE("Calling function\n");
1203             hPackage = msiobj_findhandle( &package->hdr );
1204             if( !hPackage )
1205                 ERR("Handle for object %p not found\n", package );
1206             fn(hPackage);
1207             msiobj_release( &package->hdr );
1208         }
1209         else
1210             ERR("Cannot load functon\n");
1211
1212         HeapFree(GetProcessHeap(),0,proc);
1213         FreeLibrary(DLL);
1214     }
1215     else
1216         ERR("Unable to load library\n");
1217
1218     return ERROR_SUCCESS;
1219 }
1220
1221 static UINT HANDLE_CustomType2(MSIPACKAGE *package, const LPWSTR source, 
1222                                 const LPWSTR target, const INT type)
1223 {
1224     WCHAR tmp_file[MAX_PATH*2];
1225     STARTUPINFOW si;
1226     PROCESS_INFORMATION info;
1227     BOOL rc;
1228     WCHAR *deformated;
1229     static const WCHAR spc[] = {' ',0};
1230
1231     memset(&si,0,sizeof(STARTUPINFOW));
1232     memset(&info,0,sizeof(PROCESS_INFORMATION));
1233
1234     store_binary_to_temp(package, source, tmp_file);
1235
1236     strcatW(tmp_file,spc);
1237     deformat_string(package,target,&deformated);
1238     strcatW(tmp_file,deformated);
1239
1240     HeapFree(GetProcessHeap(),0,deformated);
1241
1242     TRACE("executing exe %s \n",debugstr_w(tmp_file));
1243
1244     rc = CreateProcessW(NULL, tmp_file, NULL, NULL, FALSE, 0, NULL,
1245                   c_collen, &si, &info);
1246
1247     if ( !rc )
1248     {
1249         ERR("Unable to execute command\n");
1250         return ERROR_SUCCESS;
1251     }
1252
1253     if (!(type & 0xc0))
1254         WaitForSingleObject(info.hProcess,INFINITE);
1255
1256     return ERROR_SUCCESS;
1257 }
1258
1259 /***********************************************************************
1260  *            create_full_pathW
1261  *
1262  * Recursively create all directories in the path.
1263  *
1264  * shamelessly stolen from setupapi/queue.c
1265  */
1266 static BOOL create_full_pathW(const WCHAR *path)
1267 {
1268     BOOL ret = TRUE;
1269     int len;
1270     WCHAR *new_path;
1271
1272     new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) *
1273 sizeof(WCHAR));
1274     strcpyW(new_path, path);
1275
1276     while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
1277     new_path[len - 1] = 0;
1278
1279     while(!CreateDirectoryW(new_path, NULL))
1280     {
1281     WCHAR *slash;
1282     DWORD last_error = GetLastError();
1283     if(last_error == ERROR_ALREADY_EXISTS)
1284         break;
1285
1286     if(last_error != ERROR_PATH_NOT_FOUND)
1287     {
1288         ret = FALSE;
1289         break;
1290     }
1291
1292     if(!(slash = strrchrW(new_path, '\\')))
1293     {
1294         ret = FALSE;
1295         break;
1296     }
1297
1298     len = slash - new_path;
1299     new_path[len] = 0;
1300     if(!create_full_pathW(new_path))
1301     {
1302         ret = FALSE;
1303         break;
1304     }
1305     new_path[len] = '\\';
1306     }
1307
1308     HeapFree(GetProcessHeap(), 0, new_path);
1309     return ret;
1310 }
1311
1312 /*
1313  * Also we cannot enable/disable components either, so for now I am just going 
1314  * to do all the directories for all the components.
1315  */
1316 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1317 {
1318     static const WCHAR ExecSeqQuery[] = {
1319         's','e','l','e','c','t',' ','D','i','r','e','c','t','o','r','y','_',' ',
1320         'f','r','o','m',' ','C','r','e','a','t','e','F','o','l','d','e','r',0 };
1321     UINT rc;
1322     MSIQUERY *view;
1323     MSIFOLDER *folder;
1324
1325     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1326     if (rc != ERROR_SUCCESS)
1327         return rc;
1328
1329     rc = MSI_ViewExecute(view, 0);
1330     if (rc != ERROR_SUCCESS)
1331     {
1332         MSI_ViewClose(view);
1333         msiobj_release(&view->hdr);
1334         return rc;
1335     }
1336     
1337     while (1)
1338     {
1339         WCHAR dir[0x100];
1340         WCHAR full_path[MAX_PATH];
1341         DWORD sz;
1342         MSIRECORD *row = NULL, *uirow;
1343
1344         rc = MSI_ViewFetch(view,&row);
1345         if (rc != ERROR_SUCCESS)
1346         {
1347             rc = ERROR_SUCCESS;
1348             break;
1349         }
1350
1351         sz=0x100;
1352         rc = MSI_RecordGetStringW(row,1,dir,&sz);
1353
1354         if (rc!= ERROR_SUCCESS)
1355         {
1356             ERR("Unable to get folder id \n");
1357             msiobj_release(&row->hdr);
1358             continue;
1359         }
1360
1361         sz = MAX_PATH;
1362         rc = resolve_folder(package,dir,full_path,FALSE,FALSE,&folder);
1363
1364         if (rc != ERROR_SUCCESS)
1365         {
1366             ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1367             msiobj_release(&row->hdr);
1368             continue;
1369         }
1370
1371         TRACE("Folder is %s\n",debugstr_w(full_path));
1372
1373         /* UI stuff */
1374         uirow = MSI_CreateRecord(1);
1375         MSI_RecordSetStringW(uirow,1,full_path);
1376         ui_actiondata(package,szCreateFolders,uirow);
1377         msiobj_release( &uirow->hdr );
1378
1379         if (folder->State == 0)
1380             create_full_pathW(full_path);
1381
1382         folder->State = 3;
1383
1384         msiobj_release(&row->hdr);
1385     }
1386     MSI_ViewClose(view);
1387     msiobj_release(&view->hdr);
1388    
1389     return rc;
1390 }
1391
1392 static int load_component(MSIPACKAGE* package, MSIRECORD * row)
1393 {
1394     int index = package->loaded_components;
1395     DWORD sz;
1396
1397     /* fill in the data */
1398
1399     package->loaded_components++;
1400     if (package->loaded_components == 1)
1401         package->components = HeapAlloc(GetProcessHeap(),0,
1402                                         sizeof(MSICOMPONENT));
1403     else
1404         package->components = HeapReAlloc(GetProcessHeap(),0,
1405             package->components, package->loaded_components * 
1406             sizeof(MSICOMPONENT));
1407
1408     memset(&package->components[index],0,sizeof(MSICOMPONENT));
1409
1410     sz = 96;       
1411     MSI_RecordGetStringW(row,1,package->components[index].Component,&sz);
1412
1413     TRACE("Loading Component %s\n",
1414            debugstr_w(package->components[index].Component));
1415
1416     sz = 0x100;
1417     if (!MSI_RecordIsNull(row,2))
1418         MSI_RecordGetStringW(row,2,package->components[index].ComponentId,&sz);
1419             
1420     sz = 96;       
1421     MSI_RecordGetStringW(row,3,package->components[index].Directory,&sz);
1422
1423     package->components[index].Attributes = MSI_RecordGetInteger(row,4);
1424
1425     sz = 0x100;       
1426     MSI_RecordGetStringW(row,5,package->components[index].Condition,&sz);
1427
1428     sz = 96;       
1429     MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz);
1430
1431     package->components[index].State = INSTALLSTATE_UNKNOWN;
1432     package->components[index].Enabled = TRUE;
1433     package->components[index].FeatureState= FALSE;
1434
1435     return index;
1436 }
1437
1438 static void load_feature(MSIPACKAGE* package, MSIRECORD * row)
1439 {
1440     int index = package->loaded_features;
1441     DWORD sz;
1442     static const WCHAR Query1[] = {'S','E','L','E','C','T',' ','C','o','m','p',
1443 'o','n','e','n','t','_',' ','F','R','O','M',' ','F','e','a','t','u','r','e',
1444 'C','o','m','p','o','n','e','n','t','s',' ','W','H','E','R','E',' ','F','e',
1445 'a','t','u','r','e','_','=','\'','%','s','\'',0};
1446     static const WCHAR Query2[] = {'S','E','L','E','C','T',' ','*',' ','F','R',
1447 'O','M',' ','C','o','m','p','o','n','e','n','t',' ','W','H','E','R','E',' ','C',
1448 'o','m','p','o','n','e','n','t','=','\'','%','s','\'',0};
1449     WCHAR Query[1024];
1450     MSIQUERY * view;
1451     MSIQUERY * view2;
1452     MSIRECORD * row2;
1453     MSIRECORD * row3;
1454     UINT    rc;
1455
1456     /* fill in the data */
1457
1458     package->loaded_features ++;
1459     if (package->loaded_features == 1)
1460         package->features = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFEATURE));
1461     else
1462         package->features = HeapReAlloc(GetProcessHeap(),0,package->features,
1463                                 package->loaded_features * sizeof(MSIFEATURE));
1464
1465     memset(&package->features[index],0,sizeof(MSIFEATURE));
1466     
1467     sz = 96;       
1468     MSI_RecordGetStringW(row,1,package->features[index].Feature,&sz);
1469
1470     TRACE("Loading feature %s\n",debugstr_w(package->features[index].Feature));
1471
1472     sz = 96;
1473     if (!MSI_RecordIsNull(row,2))
1474         MSI_RecordGetStringW(row,2,package->features[index].Feature_Parent,&sz);
1475
1476     sz = 0x100;
1477      if (!MSI_RecordIsNull(row,3))
1478         MSI_RecordGetStringW(row,3,package->features[index].Title,&sz);
1479
1480      sz = 0x100;
1481      if (!MSI_RecordIsNull(row,4))
1482         MSI_RecordGetStringW(row,4,package->features[index].Description,&sz);
1483
1484     if (!MSI_RecordIsNull(row,5))
1485         package->features[index].Display = MSI_RecordGetInteger(row,5);
1486   
1487     package->features[index].Level= MSI_RecordGetInteger(row,6);
1488
1489      sz = 96;
1490      if (!MSI_RecordIsNull(row,7))
1491         MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz);
1492
1493     package->features[index].Attributes= MSI_RecordGetInteger(row,8);
1494     package->features[index].State = INSTALLSTATE_UNKNOWN;
1495
1496     /* load feature components */
1497
1498     sprintfW(Query,Query1,package->features[index].Feature);
1499     rc = MSI_DatabaseOpenViewW(package->db,Query,&view);
1500     if (rc != ERROR_SUCCESS)
1501         return;
1502     rc = MSI_ViewExecute(view,0);
1503     if (rc != ERROR_SUCCESS)
1504     {
1505         MSI_ViewClose(view);
1506         msiobj_release(&view->hdr);
1507         return;
1508     }
1509     while (1)
1510     {
1511         DWORD sz = 0x100;
1512         WCHAR buffer[0x100];
1513         DWORD rc;
1514         INT c_indx;
1515         INT cnt = package->features[index].ComponentCount;
1516
1517         rc = MSI_ViewFetch(view,&row2);
1518         if (rc != ERROR_SUCCESS)
1519             break;
1520
1521         sz = 0x100;
1522         MSI_RecordGetStringW(row2,1,buffer,&sz);
1523
1524         /* check to see if the component is already loaded */
1525         c_indx = get_loaded_component(package,buffer);
1526         if (c_indx != -1)
1527         {
1528             TRACE("Component %s already loaded at %i\n", debugstr_w(buffer),
1529                   c_indx);
1530             package->features[index].Components[cnt] = c_indx;
1531             package->features[index].ComponentCount ++;
1532         }
1533
1534         sprintfW(Query,Query2,buffer);
1535    
1536         rc = MSI_DatabaseOpenViewW(package->db,Query,&view2);
1537         if (rc != ERROR_SUCCESS)
1538         {
1539             msiobj_release( &row2->hdr );
1540             continue;
1541         }
1542         rc = MSI_ViewExecute(view2,0);
1543         if (rc != ERROR_SUCCESS)
1544         {
1545             msiobj_release( &row2->hdr );
1546             MSI_ViewClose(view2);
1547             msiobj_release( &view2->hdr );  
1548             continue;
1549         }
1550         while (1)
1551         {
1552             DWORD rc;
1553
1554             rc = MSI_ViewFetch(view2,&row3);
1555             if (rc != ERROR_SUCCESS)
1556                 break;
1557             c_indx = load_component(package,row3);
1558             msiobj_release( &row3->hdr );
1559
1560             package->features[index].Components[cnt] = c_indx;
1561             package->features[index].ComponentCount ++;
1562         }
1563         MSI_ViewClose(view2);
1564         msiobj_release( &view2->hdr );
1565         msiobj_release( &row2->hdr );
1566     }
1567     MSI_ViewClose(view);
1568     msiobj_release(&view->hdr);
1569 }
1570
1571 /*
1572  * I am not doing any of the costing functionality yet. 
1573  * Mostly looking at doing the Component and Feature loading
1574  *
1575  * The native MSI does ALOT of modification to tables here. Mostly adding alot
1576  * of temporary columns to the Feature and Component tables. 
1577  *
1578  *    note: native msi also tracks the short filename. but I am only going to
1579  *          track the long ones.  Also looking at this directory table
1580  *          it appears that the directory table does not get the parents
1581  *          resolved base on property only based on their entrys in the 
1582  *          directory table.
1583  */
1584 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1585 {
1586     MSIQUERY * view;
1587     MSIRECORD * row;
1588     DWORD sz;
1589     UINT rc;
1590     static const WCHAR Query_all[] = {
1591        'S','E','L','E','C','T',' ','*',' ',
1592        'F','R','O','M',' ','F','e','a','t','u','r','e',0};
1593     static const WCHAR szCosting[] = {
1594        'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1595     static const WCHAR szZero[] = { '0', 0 };
1596
1597     MSI_SetPropertyW(package, szCosting, szZero);
1598     MSI_SetPropertyW(package, cszRootDrive , c_collen);
1599
1600     sz = 0x100;
1601     rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
1602     if (rc != ERROR_SUCCESS)
1603         return rc;
1604     rc = MSI_ViewExecute(view,0);
1605     if (rc != ERROR_SUCCESS)
1606     {
1607         MSI_ViewClose(view);
1608         msiobj_release(&view->hdr);
1609         return rc;
1610     }
1611     while (1)
1612     {
1613         DWORD rc;
1614
1615         rc = MSI_ViewFetch(view,&row);
1616         if (rc != ERROR_SUCCESS)
1617             break;
1618        
1619         load_feature(package,row); 
1620         msiobj_release(&row->hdr);
1621     }
1622     MSI_ViewClose(view);
1623     msiobj_release(&view->hdr);
1624
1625     return ERROR_SUCCESS;
1626 }
1627
1628 static int load_file(MSIPACKAGE* package, MSIRECORD * row)
1629 {
1630     int index = package->loaded_files;
1631     int i;
1632     WCHAR buffer[0x100];
1633     DWORD sz;
1634
1635     /* fill in the data */
1636
1637     package->loaded_files++;
1638     if (package->loaded_files== 1)
1639         package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
1640     else
1641         package->files = HeapReAlloc(GetProcessHeap(),0,
1642             package->files , package->loaded_files * sizeof(MSIFILE));
1643
1644     memset(&package->files[index],0,sizeof(MSIFILE));
1645
1646     sz = 72;       
1647     MSI_RecordGetStringW(row,1,package->files[index].File,&sz);
1648
1649     sz = 0x100;       
1650     MSI_RecordGetStringW(row,2,buffer,&sz);
1651
1652     package->files[index].ComponentIndex = -1;
1653     for (i = 0; i < package->loaded_components; i++)
1654         if (strcmpW(package->components[i].Component,buffer)==0)
1655         {
1656             package->files[index].ComponentIndex = i;
1657             break;
1658         }
1659     if (package->files[index].ComponentIndex == -1)
1660         ERR("Unfound Component %s\n",debugstr_w(buffer));
1661
1662     sz = MAX_PATH;       
1663     MSI_RecordGetStringW(row,3,package->files[index].FileName,&sz);
1664
1665     reduce_to_longfilename(package->files[index].FileName);
1666     
1667     package->files[index].FileSize = MSI_RecordGetInteger(row,4);
1668
1669     sz = 72;       
1670     if (!MSI_RecordIsNull(row,5))
1671         MSI_RecordGetStringW(row,5,package->files[index].Version,&sz);
1672
1673     sz = 20;       
1674     if (!MSI_RecordIsNull(row,6))
1675         MSI_RecordGetStringW(row,6,package->files[index].Language,&sz);
1676
1677     if (!MSI_RecordIsNull(row,7))
1678         package->files[index].Attributes= MSI_RecordGetInteger(row,7);
1679
1680     package->files[index].Sequence= MSI_RecordGetInteger(row,8);
1681
1682     package->files[index].Temporary = FALSE;
1683     package->files[index].State = 0;
1684
1685     TRACE("File Loaded (%s)\n",debugstr_w(package->files[index].File));  
1686  
1687     return ERROR_SUCCESS;
1688 }
1689
1690 static UINT ACTION_FileCost(MSIPACKAGE *package)
1691 {
1692     MSIQUERY * view;
1693     MSIRECORD * row;
1694     UINT rc;
1695     static const WCHAR Query[] = {
1696         'S','E','L','E','C','T',' ','*',' ',
1697         'F','R','O','M',' ','F','i','l','e',' ',
1698         'O','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e', 0};
1699
1700     if (!package)
1701         return ERROR_INVALID_HANDLE;
1702
1703     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1704     if (rc != ERROR_SUCCESS)
1705         return rc;
1706    
1707     rc = MSI_ViewExecute(view, 0);
1708     if (rc != ERROR_SUCCESS)
1709     {
1710         MSI_ViewClose(view);
1711         msiobj_release(&view->hdr);
1712         return rc;
1713     }
1714
1715     while (1)
1716     {
1717         rc = MSI_ViewFetch(view,&row);
1718         if (rc != ERROR_SUCCESS)
1719         {
1720             rc = ERROR_SUCCESS;
1721             break;
1722         }
1723         load_file(package,row);
1724         msiobj_release(&row->hdr);
1725     }
1726     MSI_ViewClose(view);
1727     msiobj_release(&view->hdr);
1728
1729     return ERROR_SUCCESS;
1730 }
1731
1732 static INT load_folder(MSIPACKAGE *package, const WCHAR* dir)
1733
1734 {
1735     WCHAR Query[1024] = 
1736 {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','D','i','r','e','c',
1737 't','o','r','y',' ','w','h','e','r','e',' ','`','D','i','r','e','c','t',
1738 'o','r','y','`',' ','=',' ','`',0};
1739     static const WCHAR end[]={'`',0};
1740     UINT rc;
1741     MSIQUERY * view;
1742     WCHAR targetbuffer[0x100];
1743     WCHAR *srcdir = NULL;
1744     WCHAR *targetdir = NULL;
1745     WCHAR parent[0x100];
1746     DWORD sz=0x100;
1747     MSIRECORD * row = 0;
1748     INT i,index = -1;
1749
1750     TRACE("Looking for dir %s\n",debugstr_w(dir));
1751
1752     for (i = 0; i < package->loaded_folders; i++)
1753     {
1754         if (strcmpW(package->folders[i].Directory,dir)==0)
1755         {
1756             TRACE(" %s retuning on index %i\n",debugstr_w(dir),i);
1757             return i;
1758         }
1759     }
1760
1761     TRACE("Working to load %s\n",debugstr_w(dir));
1762
1763     index = package->loaded_folders; 
1764
1765     package->loaded_folders++;
1766     if (package->loaded_folders== 1)
1767         package->folders = HeapAlloc(GetProcessHeap(),0,
1768                                         sizeof(MSIFOLDER));
1769     else
1770         package->folders= HeapReAlloc(GetProcessHeap(),0,
1771             package->folders, package->loaded_folders* 
1772             sizeof(MSIFOLDER));
1773
1774     memset(&package->folders[index],0,sizeof(MSIFOLDER));
1775
1776     strcpyW(package->folders[index].Directory,dir);
1777
1778     strcatW(Query,dir);
1779     strcatW(Query,end);
1780
1781     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1782
1783     if (rc != ERROR_SUCCESS)
1784         return -1;
1785
1786     rc = MSI_ViewExecute(view, 0);
1787     if (rc != ERROR_SUCCESS)
1788     {
1789         MSI_ViewClose(view);
1790         msiobj_release(&view->hdr);
1791         return -1;
1792     }
1793
1794     rc = MSI_ViewFetch(view,&row);
1795     if (rc != ERROR_SUCCESS)
1796     {
1797         MSI_ViewClose(view);
1798         msiobj_release(&view->hdr);
1799         return -1;
1800     }
1801
1802     sz=0x100;
1803     MSI_RecordGetStringW(row,3,targetbuffer,&sz);
1804     targetdir=targetbuffer;
1805
1806     /* split src and target dir */
1807     if (strchrW(targetdir,':'))
1808     {
1809         srcdir=strchrW(targetdir,':');
1810         *srcdir=0;
1811         srcdir ++;
1812     }
1813     else
1814         srcdir=NULL;
1815
1816     /* for now only pick long filename versions */
1817     if (strchrW(targetdir,'|'))
1818     {
1819         targetdir = strchrW(targetdir,'|'); 
1820         *targetdir = 0;
1821         targetdir ++;
1822     }
1823     if (srcdir && strchrW(srcdir,'|'))
1824     {
1825         srcdir= strchrW(srcdir,'|'); 
1826         *srcdir= 0;
1827         srcdir ++;
1828     }
1829
1830     /* now check for root dirs */
1831     if (targetdir[0] == '.' && targetdir[1] == 0)
1832         targetdir = NULL;
1833         
1834     if (srcdir && srcdir[0] == '.' && srcdir[1] == 0)
1835         srcdir = NULL;
1836
1837      if (targetdir)
1838         strcpyW(package->folders[index].TargetDefault,targetdir);
1839
1840      if (srcdir)
1841         strcpyW(package->folders[index].SourceDefault,srcdir);
1842      else if (targetdir)
1843         strcpyW(package->folders[index].SourceDefault,targetdir);
1844
1845     if (MSI_RecordIsNull(row,2))
1846         parent[0]=0;
1847     else
1848     {
1849             sz=0x100;
1850             MSI_RecordGetStringW(row,2,parent,&sz);
1851     }
1852
1853     if (parent[0]) 
1854     {
1855         i = load_folder(package,parent);
1856         package->folders[index].ParentIndex = i;
1857         TRACE("Parent is index %i... %s %s\n",
1858                     package->folders[index].ParentIndex,
1859     debugstr_w(package->folders[package->folders[index].ParentIndex].Directory),
1860                     debugstr_w(parent));
1861     }
1862     else
1863         package->folders[index].ParentIndex = -2;
1864
1865     sz = MAX_PATH;
1866     rc = MSI_GetPropertyW(package, dir, package->folders[index].Property, &sz);
1867     if (rc != ERROR_SUCCESS)
1868         package->folders[index].Property[0]=0;
1869
1870     msiobj_release(&row->hdr);
1871     MSI_ViewClose(view);
1872     msiobj_release(&view->hdr);
1873     TRACE(" %s retuning on index %i\n",debugstr_w(dir),index);
1874     return index;
1875 }
1876
1877 static UINT resolve_folder(MSIPACKAGE *package, LPCWSTR name, LPWSTR path, 
1878                            BOOL source, BOOL set_prop, MSIFOLDER **folder)
1879 {
1880     INT i;
1881     UINT rc = ERROR_SUCCESS;
1882     DWORD sz;
1883
1884     TRACE("Working to resolve %s\n",debugstr_w(name));
1885
1886     if (!path)
1887         return rc;
1888
1889     /* special resolving for Target and Source root dir */
1890     if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0)
1891     {
1892         if (!source)
1893         {
1894             sz = MAX_PATH;
1895             rc = MSI_GetPropertyW(package,cszTargetDir,path,&sz);
1896             if (rc != ERROR_SUCCESS)
1897             {
1898                 sz = MAX_PATH;
1899                 rc = MSI_GetPropertyW(package,cszRootDrive,path,&sz);
1900                 if (set_prop)
1901                     MSI_SetPropertyW(package,cszTargetDir,path);
1902             }
1903             if (folder)
1904                 *folder = &(package->folders[0]);
1905             return rc;
1906         }
1907         else
1908         {
1909             sz = MAX_PATH;
1910             rc = MSI_GetPropertyW(package,cszSourceDir,path,&sz);
1911             if (rc != ERROR_SUCCESS)
1912             {
1913                 sz = MAX_PATH;
1914                 rc = MSI_GetPropertyW(package,cszDatabase,path,&sz);
1915                 if (rc == ERROR_SUCCESS)
1916                 {
1917                     LPWSTR ptr = strrchrW(path,'\\');
1918                     if (ptr)
1919                     {
1920                         ptr++;
1921                         *ptr = 0;
1922                     }
1923                 }
1924             }
1925             if (folder)
1926                 *folder = &(package->folders[0]);
1927             return rc;
1928         }
1929     }
1930
1931     for (i = 0; i < package->loaded_folders; i++)
1932     {
1933         if (strcmpW(package->folders[i].Directory,name)==0)
1934             break;
1935     }
1936
1937     if (i >= package->loaded_folders)
1938         return ERROR_FUNCTION_FAILED;
1939
1940     if (folder)
1941         *folder = &(package->folders[i]);
1942
1943     if (!source && package->folders[i].ResolvedTarget[0])
1944     {
1945         strcpyW(path,package->folders[i].ResolvedTarget);
1946         TRACE("   already resolved to %s\n",debugstr_w(path));
1947         return ERROR_SUCCESS;
1948     }
1949     else if (source && package->folders[i].ResolvedSource[0])
1950     {
1951         strcpyW(path,package->folders[i].ResolvedSource);
1952         return ERROR_SUCCESS;
1953     }
1954     else if (!source && package->folders[i].Property[0])
1955     {
1956         strcpyW(path,package->folders[i].Property);
1957         TRACE("   internally set to %s\n",debugstr_w(path));
1958         if (set_prop)
1959             MSI_SetPropertyW(package,name,path);
1960         return ERROR_SUCCESS;
1961     }
1962
1963     if (package->folders[i].ParentIndex >= 0)
1964     {
1965         TRACE(" ! Parent is %s\n", debugstr_w(package->folders[
1966                    package->folders[i].ParentIndex].Directory));
1967         resolve_folder(package, package->folders[
1968                        package->folders[i].ParentIndex].Directory, path,source,
1969                        set_prop, NULL);
1970
1971         if (!source)
1972         {
1973             if (package->folders[i].TargetDefault[0])
1974             {
1975                 strcatW(path,package->folders[i].TargetDefault);
1976                 strcatW(path,cszbs);
1977             }
1978             strcpyW(package->folders[i].ResolvedTarget,path);
1979             TRACE("   resolved into %s\n",debugstr_w(path));
1980             if (set_prop)
1981                 MSI_SetPropertyW(package,name,path);
1982         }
1983         else 
1984         {
1985             if (package->folders[i].SourceDefault[0])
1986             {
1987                 strcatW(path,package->folders[i].SourceDefault);
1988                 strcatW(path,cszbs);
1989             }
1990             strcpyW(package->folders[i].ResolvedSource,path);
1991         }
1992     }
1993     return rc;
1994 }
1995
1996 /* 
1997  * Alot is done in this function aside from just the costing.
1998  * The costing needs to be implemented at some point but for now I am going
1999  * to focus on the directory building
2000  *
2001  */
2002 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2003 {
2004     static const WCHAR ExecSeqQuery[] = {
2005         's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2006         'D','i','r','e','c','t','o','r','y',0};
2007     static const WCHAR ConditionQuery[] = {
2008         's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2009         'C','o','n','d','i','t','i','o','n',0};
2010     static const WCHAR szCosting[] = {
2011        'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2012     static const WCHAR szOne[] = { '1', 0 };
2013     UINT rc;
2014     MSIQUERY * view;
2015     INT i;
2016
2017     TRACE("Building Directory properties\n");
2018
2019     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2020     if (rc != ERROR_SUCCESS)
2021         return rc;
2022
2023     rc = MSI_ViewExecute(view, 0);
2024     if (rc != ERROR_SUCCESS)
2025     {
2026         MSI_ViewClose(view);
2027         msiobj_release(&view->hdr);
2028         return rc;
2029     }
2030     
2031     while (1)
2032     {
2033         WCHAR name[0x100];
2034         WCHAR path[MAX_PATH];
2035         MSIRECORD * row = 0;
2036         DWORD sz;
2037
2038         rc = MSI_ViewFetch(view,&row);
2039         if (rc != ERROR_SUCCESS)
2040         {
2041             rc = ERROR_SUCCESS;
2042             break;
2043         }
2044
2045         sz=0x100;
2046         MSI_RecordGetStringW(row,1,name,&sz);
2047
2048         /* This helper function now does ALL the work */
2049         TRACE("Dir %s ...\n",debugstr_w(name));
2050         load_folder(package,name);
2051         resolve_folder(package,name,path,FALSE,TRUE,NULL);
2052         TRACE("resolves to %s\n",debugstr_w(path));
2053
2054         msiobj_release(&row->hdr);
2055      }
2056     MSI_ViewClose(view);
2057     msiobj_release(&view->hdr);
2058
2059     TRACE("File calculations %i files\n",package->loaded_files);
2060
2061     for (i = 0; i < package->loaded_files; i++)
2062     {
2063         MSICOMPONENT* comp = NULL;
2064         MSIFILE* file= NULL;
2065
2066         file = &package->files[i];
2067         if (file->ComponentIndex >= 0)
2068             comp = &package->components[file->ComponentIndex];
2069
2070         if (comp)
2071         {
2072             /* calculate target */
2073             resolve_folder(package, comp->Directory, file->TargetPath, FALSE,
2074                        FALSE, NULL);
2075             strcatW(file->TargetPath,file->FileName);
2076
2077             TRACE("file %s resolves to %s\n",
2078                    debugstr_w(file->File),debugstr_w(file->TargetPath));       
2079  
2080             if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2081             {
2082                 file->State = 1;
2083                 comp->Cost += file->FileSize;
2084             }
2085             else
2086             {
2087                 if (file->Version[0])
2088                 {
2089                     DWORD handle;
2090                     DWORD versize;
2091                     UINT sz;
2092                     LPVOID version;
2093                     WCHAR filever[0x100];
2094                     static const WCHAR name[] =
2095                         {'\\','V','a','r','F','i','l','e','I','n','f','o',
2096                          '\\','F','i','l','e','V','e','r','s','i','o','n',0};
2097
2098                     FIXME("Version comparison.. Untried Untested and most "
2099                           "likely very very wrong\n");
2100                     versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
2101                     version = HeapAlloc(GetProcessHeap(),0,versize);
2102                     GetFileVersionInfoW(file->TargetPath, 0, versize, version);
2103                     sz = 0x100;
2104                     VerQueryValueW(version,name,(LPVOID)filever,&sz);
2105                     HeapFree(GetProcessHeap(),0,version);
2106                 
2107                     if (strcmpW(version,file->Version)<0)
2108                     {
2109                         file->State = 2;
2110                         FIXME("cost should be diff in size\n");
2111                         comp->Cost += file->FileSize;
2112                     }
2113                     else
2114                         file->State = 3;
2115                 }
2116                 else
2117                     file->State = 3;
2118             }
2119         } 
2120     }
2121
2122     TRACE("Evaluating Condition Table\n");
2123
2124     rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2125     if (rc != ERROR_SUCCESS)
2126         return rc;
2127
2128     rc = MSI_ViewExecute(view, 0);
2129     if (rc != ERROR_SUCCESS)
2130     {
2131         MSI_ViewClose(view);
2132         msiobj_release(&view->hdr);
2133         return rc;
2134     }
2135     
2136     while (1)
2137     {
2138         WCHAR Feature[0x100];
2139         MSIRECORD * row = 0;
2140         DWORD sz;
2141         int feature_index;
2142
2143         rc = MSI_ViewFetch(view,&row);
2144
2145         if (rc != ERROR_SUCCESS)
2146         {
2147             rc = ERROR_SUCCESS;
2148             break;
2149         }
2150
2151         sz = 0x100;
2152         MSI_RecordGetStringW(row,1,Feature,&sz);
2153
2154         feature_index = get_loaded_feature(package,Feature);
2155         if (feature_index < 0)
2156             ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature));
2157         else
2158         {
2159             LPWSTR Condition;
2160             Condition = load_dynamic_stringW(row,3);
2161
2162             if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2163             {
2164                 int level = MSI_RecordGetInteger(row,2);
2165                 TRACE("Reseting feature %s to level %i\n",debugstr_w(Feature),
2166                        level);
2167                 package->features[feature_index].Level = level;
2168             }
2169             HeapFree(GetProcessHeap(),0,Condition);
2170         }
2171
2172         msiobj_release(&row->hdr);
2173     }
2174     MSI_ViewClose(view);
2175     msiobj_release(&view->hdr);
2176
2177     TRACE("Enabling or Disabling Components\n");
2178     for (i = 0; i < package->loaded_components; i++)
2179     {
2180         if (package->components[i].Condition[0])
2181         {
2182             if (MSI_EvaluateConditionW(package,
2183                 package->components[i].Condition) == MSICONDITION_FALSE)
2184             {
2185                 TRACE("Disabling component %s\n",
2186                       debugstr_w(package->components[i].Component));
2187                 package->components[i].Enabled = FALSE;
2188             }
2189         }
2190     }
2191
2192     MSI_SetPropertyW(package,szCosting,szOne);
2193     return ERROR_SUCCESS;
2194 }
2195
2196 /*
2197  * This is a helper function for handling embedded cabinet media
2198  */
2199 static UINT writeout_cabinet_stream(MSIPACKAGE *package, WCHAR* stream_name,
2200                                     WCHAR* source)
2201 {
2202     UINT rc;
2203     USHORT* data;
2204     UINT    size;
2205     DWORD   write;
2206     HANDLE  the_file;
2207     WCHAR tmp[MAX_PATH];
2208
2209     rc = read_raw_stream_data(package->db,stream_name,&data,&size); 
2210     if (rc != ERROR_SUCCESS)
2211         return rc;
2212
2213     write = MAX_PATH;
2214     if (MSI_GetPropertyW(package, cszTempFolder, tmp, &write))
2215         GetTempPathW(MAX_PATH,tmp);
2216
2217     GetTempFileNameW(tmp,stream_name,0,source);
2218
2219     track_tempfile(package,strrchrW(source,'\\'), source);
2220     the_file = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2221                            FILE_ATTRIBUTE_NORMAL, NULL);
2222
2223     if (the_file == INVALID_HANDLE_VALUE)
2224     {
2225         rc = ERROR_FUNCTION_FAILED;
2226         goto end;
2227     }
2228
2229     WriteFile(the_file,data,size,&write,NULL);
2230     CloseHandle(the_file);
2231     TRACE("wrote %li bytes to %s\n",write,debugstr_w(source));
2232 end:
2233     HeapFree(GetProcessHeap(),0,data);
2234     return rc;
2235 }
2236
2237
2238 /***********************************************************************
2239  *            extract_cabinet_file
2240  *
2241  * Extract  files from a cab file.
2242  */
2243 static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
2244
2245 static BOOL extract_cabinet_file_advpack( const WCHAR *cabinet, 
2246                                           const WCHAR *root)
2247 {
2248     static HMODULE advpack;
2249
2250     char *cab_path, *cab_file;
2251
2252     if (!pExtractFiles)
2253     {
2254         if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
2255         {
2256             ERR( "could not load advpack.dll\n" );
2257             return FALSE;
2258         }
2259         if (!(pExtractFiles = (void *)GetProcAddress( advpack, "ExtractFiles"
2260 )))
2261         {
2262             ERR( "could not find ExtractFiles in advpack.dll\n" );
2263             return FALSE;
2264         }
2265     }
2266
2267     if (!(cab_file = strdupWtoA( cabinet ))) return FALSE;
2268     if (!(cab_path = strdupWtoA( root ))) return FALSE;
2269
2270     FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file) );
2271     pExtractFiles( cab_file, cab_path, 0, 0, 0, 0 );
2272     HeapFree( GetProcessHeap(), 0, cab_file );
2273     HeapFree( GetProcessHeap(), 0, cab_path );
2274     return TRUE;
2275 }
2276
2277 static BOOL extract_cabinet_file_cabinet( const WCHAR *cabinet, 
2278                                           const WCHAR *root)
2279                                   
2280 {
2281     /* from cabinet.h */
2282
2283     struct ExtractFileList {
2284         LPSTR  filename;
2285         struct ExtractFileList *next;
2286         BOOL   unknown;  /* always 1L */
2287     } ;
2288
2289     typedef struct {
2290         long  result1;          /* 0x000 */
2291         long  unknown1[3];      /* 0x004 */
2292         struct ExtractFileList* filelist;         /* 0x010 */
2293         long  filecount;        /* 0x014 */
2294         long  unknown2;         /* 0x018 */
2295         char  directory[0x104]; /* 0x01c */
2296         char  lastfile[0x20c];  /* 0x120 */
2297     } EXTRACTdest;
2298
2299     HRESULT WINAPI Extract(EXTRACTdest *dest, LPCSTR what);
2300
2301     char *cab_path, *src_path;
2302     EXTRACTdest exd;
2303     struct ExtractFileList fl;
2304
2305     if (!(cab_path = strdupWtoA( cabinet ))) return FALSE;
2306     if (!(src_path = strdupWtoA( root ))) return FALSE;
2307
2308     memset(&exd,0,sizeof(exd));
2309     strcpy(exd.directory,src_path);
2310     exd.unknown2 = 0x1;
2311     fl.filename = cab_path;
2312     fl.next = NULL;
2313     fl.unknown = 1;
2314     exd.filelist = &fl;
2315     FIXME( "more aweful hack: extracting cabinet %s\n", debugstr_a(cab_path) );
2316     Extract(&exd,cab_path);
2317
2318     HeapFree( GetProcessHeap(), 0, cab_path );
2319     HeapFree( GetProcessHeap(), 0, src_path );
2320     return TRUE;
2321 }
2322
2323 static BOOL extract_cabinet_file(const WCHAR* source, const WCHAR* path)
2324 {
2325     TRACE("Extracting %s to %s\n",debugstr_w(source), debugstr_w(path));
2326     if (!extract_cabinet_file_advpack(source,path))
2327         return extract_cabinet_file_cabinet(source,path);
2328     return TRUE;
2329 }
2330
2331 static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence, 
2332                                  WCHAR* path)
2333 {
2334     UINT rc;
2335     MSIQUERY * view;
2336     MSIRECORD * row = 0;
2337     WCHAR source[MAX_PATH];
2338     static const WCHAR ExecSeqQuery[] = {
2339         's','e','l','e','c','t',' ','*',' ',
2340         'f','r','o','m',' ','M','e','d','i','a',' ',
2341         'w','h','e','r','e',' ','L','a','s','t','S','e','q','u','e','n','c','e',' ','>','=',' ','%','i',' ',
2342         'o','r','d','e','r',' ','b','y',' ','L','a','s','t','S','e','q','u','e','n','c','e',0};
2343     WCHAR Query[1024];
2344     WCHAR cab[0x100];
2345     DWORD sz=0x100;
2346     INT seq;
2347     static INT last_sequence = 0; 
2348
2349     if (sequence <= last_sequence)
2350     {
2351         TRACE("Media already ready (%i, %i)\n",sequence,last_sequence);
2352         return ERROR_SUCCESS;
2353     }
2354
2355     sprintfW(Query,ExecSeqQuery,sequence);
2356
2357     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2358     if (rc != ERROR_SUCCESS)
2359         return rc;
2360
2361     rc = MSI_ViewExecute(view, 0);
2362     if (rc != ERROR_SUCCESS)
2363     {
2364         MSI_ViewClose(view);
2365         msiobj_release(&view->hdr);
2366         return rc;
2367     }
2368
2369     rc = MSI_ViewFetch(view,&row);
2370     if (rc != ERROR_SUCCESS)
2371     {
2372         MSI_ViewClose(view);
2373         msiobj_release(&view->hdr);
2374         return rc;
2375     }
2376     seq = MSI_RecordGetInteger(row,2);
2377     last_sequence = seq;
2378
2379     if (!MSI_RecordIsNull(row,4))
2380     {
2381         sz=0x100;
2382         MSI_RecordGetStringW(row,4,cab,&sz);
2383         TRACE("Source is CAB %s\n",debugstr_w(cab));
2384         /* the stream does not contain the # character */
2385         if (cab[0]=='#')
2386         {
2387             writeout_cabinet_stream(package,&cab[1],source);
2388             strcpyW(path,source);
2389             *(strrchrW(path,'\\')+1)=0;
2390         }
2391         else
2392         {
2393             sz = MAX_PATH;
2394             if (MSI_GetPropertyW(package, cszSourceDir, source, &sz))
2395             {
2396                 ERR("No Source dir defined \n");
2397                 rc = ERROR_FUNCTION_FAILED;
2398             }
2399             else
2400             {
2401                 strcpyW(path,source);
2402                 strcatW(source,cab);
2403                 /* extract the cab file into a folder in the temp folder */
2404                 sz = MAX_PATH;
2405                 if (MSI_GetPropertyW(package, cszTempFolder,path, &sz) 
2406                                     != ERROR_SUCCESS)
2407                     GetTempPathW(MAX_PATH,path);
2408             }
2409         }
2410         rc = !extract_cabinet_file(source,path);
2411     }
2412     msiobj_release(&row->hdr);
2413     MSI_ViewClose(view);
2414     msiobj_release(&view->hdr);
2415     return rc;
2416 }
2417
2418 inline static UINT create_component_directory ( MSIPACKAGE* package, INT component)
2419 {
2420     UINT rc;
2421     MSIFOLDER *folder;
2422     WCHAR install_path[MAX_PATH];
2423
2424     rc = resolve_folder(package, package->components[component].Directory,
2425                         install_path, FALSE, FALSE, &folder);
2426
2427     if (rc != ERROR_SUCCESS)
2428         return rc; 
2429
2430     /* create the path */
2431     if (folder->State == 0)
2432     {
2433         create_full_pathW(install_path);
2434         folder->State = 2;
2435     }
2436
2437     return rc;
2438 }
2439
2440 static UINT ACTION_InstallFiles(MSIPACKAGE *package)
2441 {
2442     UINT rc = ERROR_SUCCESS;
2443     INT index;
2444     MSIRECORD * uirow;
2445     WCHAR uipath[MAX_PATH];
2446
2447     if (!package)
2448         return ERROR_INVALID_HANDLE;
2449
2450     /* increment progress bar each time action data is sent */
2451     ui_progress(package,1,1,1,0);
2452
2453     for (index = 0; index < package->loaded_files; index++)
2454     {
2455         WCHAR path_to_source[MAX_PATH];
2456         MSIFILE *file;
2457         
2458         file = &package->files[index];
2459
2460         if (file->Temporary)
2461             continue;
2462
2463         if (!package->components[file->ComponentIndex].Enabled ||
2464             !package->components[file->ComponentIndex].FeatureState)
2465         {
2466             TRACE("File %s is not scheduled for install\n",
2467                    debugstr_w(file->File));
2468             continue;
2469         }
2470
2471         if ((file->State == 1) || (file->State == 2))
2472         {
2473             TRACE("Installing %s\n",debugstr_w(file->File));
2474             rc = ready_media_for_file(package,file->Sequence,path_to_source);
2475             /* 
2476              * WARNING!
2477              * our file table could change here because a new temp file
2478              * may have been created
2479              */
2480             file = &package->files[index];
2481             if (rc != ERROR_SUCCESS)
2482             {
2483                 ERR("Unable to ready media\n");
2484                 rc = ERROR_FUNCTION_FAILED;
2485                 break;
2486             }
2487
2488             create_component_directory( package, file->ComponentIndex);
2489
2490             strcpyW(file->SourcePath, path_to_source);
2491             strcatW(file->SourcePath, file->File);
2492
2493             TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
2494                   debugstr_w(file->TargetPath));
2495
2496             /* the UI chunk */
2497             uirow=MSI_CreateRecord(9);
2498             MSI_RecordSetStringW(uirow,1,file->File);
2499             strcpyW(uipath,file->TargetPath);
2500             *(strrchrW(uipath,'\\')+1)=0;
2501             MSI_RecordSetStringW(uirow,9,uipath);
2502             MSI_RecordSetInteger(uirow,6,file->FileSize);
2503             ui_actiondata(package,szInstallFiles,uirow);
2504             msiobj_release( &uirow->hdr );
2505
2506             rc = !MoveFileW(file->SourcePath,file->TargetPath);
2507             ui_progress(package,2,0,0,0);
2508
2509             if (rc)
2510             {
2511                 ERR("Unable to move file (error %li)\n",GetLastError());
2512                 rc = ERROR_SUCCESS;
2513             }
2514             else
2515                 file->State = 4;
2516         }
2517     }
2518
2519     return rc;
2520 }
2521
2522 inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key, 
2523                                    LPWSTR file_source)
2524 {
2525     INT index;
2526
2527     if (!package)
2528         return ERROR_INVALID_HANDLE;
2529
2530     for (index = 0; index < package->loaded_files; index ++)
2531     {
2532         if (strcmpW(file_key,package->files[index].File)==0)
2533         {
2534             if (package->files[index].State >= 3)
2535             {
2536                 strcpyW(file_source,package->files[index].TargetPath);
2537                 return ERROR_SUCCESS;
2538             }
2539             else
2540                 return ERROR_FILE_NOT_FOUND;
2541         }
2542     }
2543
2544     return ERROR_FUNCTION_FAILED;
2545 }
2546
2547 static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
2548 {
2549     UINT rc;
2550     MSIQUERY * view;
2551     MSIRECORD * row = 0;
2552     static const WCHAR ExecSeqQuery[] = {
2553         's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2554         'D','u','p','l','i','c','a','t','e','F','i','l','e',0};
2555
2556     if (!package)
2557         return ERROR_INVALID_HANDLE;
2558
2559     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2560     if (rc != ERROR_SUCCESS)
2561         return rc;
2562
2563     rc = MSI_ViewExecute(view, 0);
2564     if (rc != ERROR_SUCCESS)
2565     {
2566         MSI_ViewClose(view);
2567         msiobj_release(&view->hdr);
2568         return rc;
2569     }
2570
2571     while (1)
2572     {
2573         WCHAR file_key[0x100];
2574         WCHAR file_source[MAX_PATH];
2575         WCHAR dest_name[0x100];
2576         WCHAR dest_path[MAX_PATH];
2577         WCHAR component[0x100];
2578         INT component_index;
2579
2580         DWORD sz=0x100;
2581
2582         rc = MSI_ViewFetch(view,&row);
2583         if (rc != ERROR_SUCCESS)
2584         {
2585             rc = ERROR_SUCCESS;
2586             break;
2587         }
2588
2589         sz=0x100;
2590         rc = MSI_RecordGetStringW(row,2,component,&sz);
2591         if (rc != ERROR_SUCCESS)
2592         {
2593             ERR("Unable to get component\n");
2594             msiobj_release(&row->hdr);
2595             break;
2596         }
2597
2598         component_index = get_loaded_component(package,component);
2599         if (!package->components[component_index].Enabled ||
2600             !package->components[component_index].FeatureState)
2601         {
2602             TRACE("Skipping copy due to disabled component\n");
2603             msiobj_release(&row->hdr);
2604             continue;
2605         }
2606
2607         sz=0x100;
2608         rc = MSI_RecordGetStringW(row,3,file_key,&sz);
2609         if (rc != ERROR_SUCCESS)
2610         {
2611             ERR("Unable to get file key\n");
2612             msiobj_release(&row->hdr);
2613             break;
2614         }
2615
2616         rc = get_file_target(package,file_key,file_source);
2617
2618         if (rc != ERROR_SUCCESS)
2619         {
2620             ERR("Original file unknown %s\n",debugstr_w(file_key));
2621             msiobj_release(&row->hdr);
2622             break;
2623         }
2624
2625         if (MSI_RecordIsNull(row,4))
2626         {
2627             strcpyW(dest_name,strrchrW(file_source,'\\')+1);
2628         }
2629         else
2630         {
2631             sz=0x100;
2632             MSI_RecordGetStringW(row,4,dest_name,&sz);
2633             reduce_to_longfilename(dest_name);
2634          }
2635
2636         if (MSI_RecordIsNull(row,5))
2637         {
2638             strcpyW(dest_path,file_source);
2639             *strrchrW(dest_path,'\\')=0;
2640         }
2641         else
2642         {
2643             WCHAR destkey[0x100];
2644             sz=0x100;
2645             MSI_RecordGetStringW(row,5,destkey,&sz);
2646             sz = 0x100;
2647             rc = resolve_folder(package, destkey, dest_path,FALSE,FALSE,NULL);
2648             if (rc != ERROR_SUCCESS)
2649             {
2650                 ERR("Unable to get destination folder\n");
2651                 msiobj_release(&row->hdr);
2652                 break;
2653             }
2654         }
2655
2656         strcatW(dest_path,dest_name);
2657            
2658         TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),
2659               debugstr_w(dest_path)); 
2660         
2661         if (strcmpW(file_source,dest_path))
2662             rc = !CopyFileW(file_source,dest_path,TRUE);
2663         else
2664             rc = ERROR_SUCCESS;
2665         
2666         if (rc != ERROR_SUCCESS)
2667             ERR("Failed to copy file\n");
2668
2669         FIXME("We should track these duplicate files as well\n");   
2670  
2671         msiobj_release(&row->hdr);
2672     }
2673     MSI_ViewClose(view);
2674     msiobj_release(&view->hdr);
2675     return rc;
2676
2677 }
2678
2679
2680 /* OK this value is "interpretted" and then formatted based on the 
2681    first few characters */
2682 static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type, 
2683                          DWORD *size)
2684 {
2685     LPSTR data = NULL;
2686     if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2687     {
2688         if (value[1]=='x')
2689         {
2690             LPWSTR ptr;
2691             CHAR byte[5];
2692             LPWSTR deformated;
2693             int count;
2694
2695             deformat_string(package, &value[2], &deformated);
2696
2697             /* binary value type */
2698             ptr = deformated; 
2699             *type=REG_BINARY;
2700             *size = strlenW(ptr)/2;
2701             data = HeapAlloc(GetProcessHeap(),0,*size);
2702           
2703             byte[0] = '0'; 
2704             byte[1] = 'x'; 
2705             byte[4] = 0; 
2706             count = 0;
2707             while (*ptr)
2708             {
2709                 byte[2]= *ptr;
2710                 ptr++;
2711                 byte[3]= *ptr;
2712                 ptr++;
2713                 data[count] = (BYTE)strtol(byte,NULL,0);
2714                 count ++;
2715             }
2716             HeapFree(GetProcessHeap(),0,deformated);
2717
2718             TRACE("Data %li bytes(%i)\n",*size,count);
2719         }
2720         else
2721         {
2722             LPWSTR deformated;
2723             deformat_string(package, &value[1], &deformated);
2724
2725             *type=REG_DWORD; 
2726             *size = sizeof(DWORD);
2727             data = HeapAlloc(GetProcessHeap(),0,*size);
2728             *(LPDWORD)data = atoiW(deformated); 
2729             TRACE("DWORD %i\n",*data);
2730
2731             HeapFree(GetProcessHeap(),0,deformated);
2732         }
2733     }
2734     else
2735     {
2736         WCHAR *ptr;
2737         *type=REG_SZ;
2738
2739         if (value[0]=='#')
2740         {
2741             if (value[1]=='%')
2742             {
2743                 ptr = &value[2];
2744                 *type=REG_EXPAND_SZ;
2745             }
2746             else
2747                 ptr = &value[1];
2748          }
2749          else
2750             ptr=value;
2751
2752         *size = deformat_string(package, ptr,(LPWSTR*)&data);
2753     }
2754     return data;
2755 }
2756
2757 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2758 {
2759     UINT rc;
2760     MSIQUERY * view;
2761     MSIRECORD * row = 0;
2762     static const WCHAR ExecSeqQuery[] = {
2763         's','e','l','e','c','t',' ','*',' ',
2764         'f','r','o','m',' ','R','e','g','i','s','t','r','y',0 };
2765
2766     if (!package)
2767         return ERROR_INVALID_HANDLE;
2768
2769     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2770     if (rc != ERROR_SUCCESS)
2771         return rc;
2772
2773     rc = MSI_ViewExecute(view, 0);
2774     if (rc != ERROR_SUCCESS)
2775     {
2776         MSI_ViewClose(view);
2777         msiobj_release(&view->hdr);
2778         return rc;
2779     }
2780
2781     /* increment progress bar each time action data is sent */
2782     ui_progress(package,1,1,1,0);
2783
2784     while (1)
2785     {
2786         static const WCHAR szHCR[] = 
2787 {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T','\\',0};
2788         static const WCHAR szHCU[] =
2789 {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R','\\',0};
2790         static const WCHAR szHLM[] =
2791 {'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',
2792 '\\',0};
2793         static const WCHAR szHU[] =
2794 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2795
2796         WCHAR key[0x100];
2797         WCHAR name[0x100];
2798         LPWSTR value;
2799         LPSTR value_data = NULL;
2800         HKEY  root_key, hkey;
2801         DWORD type,size;
2802         WCHAR component[0x100];
2803         INT component_index;
2804         MSIRECORD * uirow;
2805         WCHAR uikey[0x110];
2806
2807         INT   root;
2808         DWORD sz=0x100;
2809
2810         rc = MSI_ViewFetch(view,&row);
2811         if (rc != ERROR_SUCCESS)
2812         {
2813             rc = ERROR_SUCCESS;
2814             break;
2815         }
2816
2817         sz= 0x100;
2818         MSI_RecordGetStringW(row,6,component,&sz);
2819         component_index = get_loaded_component(package,component);
2820
2821         if (!package->components[component_index].Enabled ||
2822             !package->components[component_index].FeatureState)
2823         {
2824             TRACE("Skipping write due to disabled component\n");
2825             msiobj_release(&row->hdr);
2826             continue;
2827         }
2828
2829         /* null values have special meanings during uninstalls and such */
2830         
2831         if(MSI_RecordIsNull(row,5))
2832         {
2833             msiobj_release(&row->hdr);
2834             continue;
2835         }
2836
2837         root = MSI_RecordGetInteger(row,2);
2838         sz = 0x100;
2839         MSI_RecordGetStringW(row,3,key,&sz);
2840       
2841         sz = 0x100; 
2842         if (MSI_RecordIsNull(row,4))
2843             name[0]=0;
2844         else
2845             MSI_RecordGetStringW(row,4,name,&sz);
2846    
2847         /* get the root key */
2848         switch (root)
2849         {
2850             case 0:  root_key = HKEY_CLASSES_ROOT; 
2851                      strcpyW(uikey,szHCR); break;
2852             case 1:  root_key = HKEY_CURRENT_USER;
2853                      strcpyW(uikey,szHCU); break;
2854             case 2:  root_key = HKEY_LOCAL_MACHINE;
2855                      strcpyW(uikey,szHLM); break;
2856             case 3:  root_key = HKEY_USERS; 
2857                      strcpyW(uikey,szHU); break;
2858             default:
2859                  ERR("Unknown root %i\n",root);
2860                  root_key=NULL;
2861                  break;
2862         }
2863         if (!root_key)
2864         {
2865             msiobj_release(&row->hdr);
2866             continue;
2867         }
2868
2869         strcatW(uikey,key);
2870         if (RegCreateKeyW( root_key, key, &hkey))
2871         {
2872             ERR("Could not create key %s\n",debugstr_w(key));
2873             msiobj_release(&row->hdr);
2874             continue;
2875         }
2876
2877         value = load_dynamic_stringW(row,5);
2878         value_data = parse_value(package, value, &type, &size); 
2879
2880         if (value_data)
2881         {
2882             TRACE("Setting value %s\n",debugstr_w(name));
2883             RegSetValueExW(hkey, name, 0, type, value_data, size);
2884
2885             uirow = MSI_CreateRecord(3);
2886             MSI_RecordSetStringW(uirow,2,name);
2887             MSI_RecordSetStringW(uirow,1,uikey);
2888
2889             if (type == REG_SZ)
2890                 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2891             else
2892                 MSI_RecordSetStringW(uirow,3,value);
2893
2894             ui_actiondata(package,szWriteRegistryValues,uirow);
2895             ui_progress(package,2,0,0,0);
2896             msiobj_release( &uirow->hdr );
2897
2898             HeapFree(GetProcessHeap(),0,value_data);
2899         }
2900         HeapFree(GetProcessHeap(),0,value);
2901
2902         msiobj_release(&row->hdr);
2903         RegCloseKey(hkey);
2904     }
2905     MSI_ViewClose(view);
2906     msiobj_release(&view->hdr);
2907     return rc;
2908 }
2909
2910 /*
2911  * This helper function should probably go alot of places
2912  *
2913  * Thinking about this, maybe this should become yet another Bison file
2914  */
2915 static DWORD deformat_string(MSIPACKAGE *package, WCHAR* ptr,WCHAR** data)
2916 {
2917     WCHAR* mark=NULL;
2918     DWORD size=0;
2919     DWORD chunk=0;
2920     WCHAR key[0x100];
2921     LPWSTR value;
2922     DWORD sz;
2923     UINT rc;
2924
2925     /* scan for special characters */
2926     if (!strchrW(ptr,'[') || (strchrW(ptr,'[') && !strchrW(ptr,']')))
2927     {
2928         /* not formatted */
2929         size = (strlenW(ptr)+1) * sizeof(WCHAR);
2930         *data = HeapAlloc(GetProcessHeap(),0,size);
2931         strcpyW(*data,ptr);
2932         return size;
2933     }
2934    
2935     /* formatted string located */ 
2936     mark = strchrW(ptr,'[');
2937     if (mark != ptr)
2938     {
2939         INT cnt = (mark - ptr);
2940         TRACE("%i  (%i) characters before marker\n",cnt,(mark-ptr));
2941         size = cnt * sizeof(WCHAR);
2942         size += sizeof(WCHAR);
2943         *data = HeapAlloc(GetProcessHeap(),0,size);
2944         strncpyW(*data,ptr,cnt);
2945         (*data)[cnt]=0;
2946     }
2947     else
2948     {
2949         size = sizeof(WCHAR);
2950         *data = HeapAlloc(GetProcessHeap(),0,size);
2951         (*data)[0]=0;
2952     }
2953     mark++;
2954     strcpyW(key,mark);
2955     *strchrW(key,']')=0;
2956     mark = strchrW(mark,']');
2957     mark++;
2958     TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
2959     sz = 0;
2960     rc = MSI_GetPropertyW(package, key, NULL, &sz);
2961     if ((rc == ERROR_SUCCESS) || (rc == ERROR_MORE_DATA))
2962     {
2963         LPWSTR newdata;
2964
2965         sz++;
2966         value = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR));
2967         MSI_GetPropertyW(package, key, value, &sz);
2968
2969         chunk = (strlenW(value)+1) * sizeof(WCHAR);
2970         size+=chunk;   
2971         newdata = HeapReAlloc(GetProcessHeap(),0,*data,size);
2972         *data = newdata;
2973         strcatW(*data,value);
2974     }
2975     TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
2976     if (*mark!=0)
2977     {
2978         LPWSTR newdata;
2979         chunk = (strlenW(mark)+1) * sizeof(WCHAR);
2980         size+=chunk;
2981         newdata = HeapReAlloc(GetProcessHeap(),0,*data,size);
2982         *data = newdata;
2983         strcatW(*data,mark);
2984     }
2985     (*data)[strlenW(*data)]=0;
2986     TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
2987
2988     /* recursively do this to clean up */
2989     mark = HeapAlloc(GetProcessHeap(),0,size);
2990     strcpyW(mark,*data);
2991     TRACE("String at this point %s\n",debugstr_w(mark));
2992     size = deformat_string(package,mark,data);
2993     HeapFree(GetProcessHeap(),0,mark);
2994     return size;
2995 }
2996
2997 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2998 {
2999     WCHAR level[10000];
3000     INT install_level;
3001     DWORD sz;
3002     INT i,j;
3003     DWORD rc;
3004     LPWSTR override = NULL;
3005     static const WCHAR addlocal[]={'A','D','D','L','O','C','A','L',0};
3006     static const WCHAR all[]={'A','L','L',0};
3007     static const WCHAR szlevel[] = {
3008         'I','N','S','T','A','L','L','L','E','V','E','L',0};
3009     static const WCHAR szAddLocal[] = {
3010         'A','D','D','L','O','C','A','L',0};
3011
3012     /* I do not know if this is where it should happen.. but */
3013
3014     TRACE("Checking Install Level\n");
3015
3016     sz = 10000;
3017     if (MSI_GetPropertyW(package,szlevel,level,&sz)==ERROR_SUCCESS)
3018         install_level = atoiW(level);
3019     else
3020         install_level = 1;
3021
3022     sz = 0;
3023     rc = MSI_GetPropertyW(package,szAddLocal,NULL,&sz);
3024     if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
3025     {
3026         sz++;
3027         override = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
3028         MSI_GetPropertyW(package, addlocal,override,&sz);
3029     }
3030    
3031     /*
3032      * Components FeatureState defaults to FALSE. The idea is we want to 
3033      * enable the component is ANY feature that uses it is enabled to install
3034      */
3035     for(i = 0; i < package->loaded_features; i++)
3036     {
3037         BOOL feature_state= ((package->features[i].Level > 0) &&
3038                              (package->features[i].Level <= install_level));
3039
3040         if (override && (strcmpiW(override,all)==0 || 
3041                          strstrW(override,package->features[i].Feature)))
3042         {
3043             TRACE("Override of install level found\n");
3044             feature_state = TRUE;
3045             package->features[i].Enabled = feature_state;
3046         }
3047
3048         TRACE("Feature %s has a state of %i\n",
3049                debugstr_w(package->features[i].Feature), feature_state);
3050         for( j = 0; j < package->features[i].ComponentCount; j++)
3051         {
3052             package->components[package->features[i].Components[j]].FeatureState
3053             |= feature_state;
3054         }
3055     } 
3056     if (override != NULL)
3057         HeapFree(GetProcessHeap(),0,override);
3058     /* 
3059      * So basically we ONLY want to install a component if its Enabled AND
3060      * FeatureState are both TRUE 
3061      */
3062     return ERROR_SUCCESS;
3063 }
3064
3065 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3066 {
3067     DWORD progress = 0;
3068     static const WCHAR q1[]={
3069         'S','E','L','E','C','T',' ','*',' ',
3070         'F','R','O','M',' ','R','e','g','i','s','t','r','y',0};
3071     UINT rc;
3072     MSIQUERY * view;
3073     MSIRECORD * row = 0;
3074
3075     TRACE(" InstallValidate \n");
3076
3077     rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
3078     if (rc != ERROR_SUCCESS)
3079         return rc;
3080     rc = MSI_ViewExecute(view, 0);
3081     if (rc != ERROR_SUCCESS)
3082     {
3083         MSI_ViewClose(view);
3084         msiobj_release(&view->hdr);
3085         return rc;
3086     }
3087     while (1)
3088     {
3089         rc = MSI_ViewFetch(view,&row);
3090         if (rc != ERROR_SUCCESS)
3091         {
3092             rc = ERROR_SUCCESS;
3093             break;
3094         }
3095         progress +=1;
3096
3097         msiobj_release(&row->hdr);
3098     }
3099     MSI_ViewClose(view);
3100     msiobj_release(&view->hdr);
3101
3102     ui_progress(package,0,progress+package->loaded_files,0,0);
3103
3104     return ERROR_SUCCESS;
3105 }
3106
3107 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3108 {
3109     UINT rc;
3110     MSIQUERY * view;
3111     MSIRECORD * row = 0;
3112     static const WCHAR ExecSeqQuery[] = {
3113         'S','E','L','E','C','T',' ','*',' ',
3114         'f','r','o','m',' ','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n',0};
3115     static const WCHAR title[]=
3116             {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3117
3118     TRACE("Checking launch conditions\n");
3119
3120     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3121     if (rc != ERROR_SUCCESS)
3122         return rc;
3123
3124     rc = MSI_ViewExecute(view, 0);
3125     if (rc != ERROR_SUCCESS)
3126     {
3127         MSI_ViewClose(view);
3128         msiobj_release(&view->hdr);
3129         return rc;
3130     }
3131
3132     rc = ERROR_SUCCESS;
3133     while (rc == ERROR_SUCCESS)
3134     {
3135         LPWSTR cond = NULL; 
3136         LPWSTR message = NULL;
3137
3138         rc = MSI_ViewFetch(view,&row);
3139         if (rc != ERROR_SUCCESS)
3140         {
3141             rc = ERROR_SUCCESS;
3142             break;
3143         }
3144
3145         cond = load_dynamic_stringW(row,1);
3146
3147         if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
3148         {
3149             message = load_dynamic_stringW(row,2);
3150             MessageBoxW(NULL,message,title,MB_OK);
3151             HeapFree(GetProcessHeap(),0,message);
3152             rc = ERROR_FUNCTION_FAILED;
3153         }
3154         HeapFree(GetProcessHeap(),0,cond);
3155         msiobj_release(&row->hdr);
3156     }
3157     MSI_ViewClose(view);
3158     msiobj_release(&view->hdr);
3159     return rc;
3160 }
3161
3162 static void resolve_keypath( MSIPACKAGE* package, INT
3163                             component_index, WCHAR *keypath)
3164 {
3165     MSICOMPONENT* cmp = &package->components[component_index];
3166
3167     if (cmp->KeyPath[0]==0)
3168     {
3169         resolve_folder(package,cmp->Directory,keypath,FALSE,FALSE,NULL);
3170         return;
3171     }
3172     if ((cmp->Attributes & 0x4) || (cmp->Attributes & 0x20))
3173     {
3174         FIXME("UNIMPLEMENTED keypath as Registry or ODBC Source\n");
3175         keypath[0]=0;
3176     }
3177     else
3178     {
3179         int j;
3180         j = get_loaded_file(package,cmp->KeyPath);
3181
3182         if (j>=0)
3183             strcpyW(keypath,package->files[j].TargetPath);
3184     }
3185 }
3186
3187 /*
3188  * Ok further analysis makes me think that this work is
3189  * actually done in the PublishComponents and PublishFeatures
3190  * step, and not here.  It appears like the keypath and all that is
3191  * resolved in this step, however actually written in the Publish steps.
3192  * But we will leave it here for now because it is unclear
3193  */
3194 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3195 {
3196     WCHAR productcode[0x100];
3197     WCHAR squished_pc[0x100];
3198     WCHAR squished_cc[0x100];
3199     DWORD sz;
3200     UINT rc;
3201     INT i;
3202     HKEY hkey=0,hkey2=0,hkey3=0;
3203     static const WCHAR szProductCode[]=
3204 {'P','r','o','d','u','c','t','C','o','d','e',0};
3205     static const WCHAR szInstaller[] = {
3206 'S','o','f','t','w','a','r','e','\\',
3207 'M','i','c','r','o','s','o','f','t','\\',
3208 'W','i','n','d','o','w','s','\\',
3209 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3210 'I','n','s','t','a','l','l','e','r',0 };
3211     static const WCHAR szFeatures[] = {
3212 'F','e','a','t','u','r','e','s',0 };
3213     static const WCHAR szComponents[] = {
3214 'C','o','m','p','o','n','e','n','t','s',0 };
3215
3216     if (!package)
3217         return ERROR_INVALID_HANDLE;
3218
3219     /* writes the Component and Features values to the registry */
3220     sz = 0x100;
3221     rc = MSI_GetPropertyW(package,szProductCode,productcode,&sz);
3222     if (rc != ERROR_SUCCESS)
3223         return ERROR_SUCCESS;
3224
3225     squash_guid(productcode,squished_pc);
3226     rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,szInstaller,&hkey);
3227     if (rc != ERROR_SUCCESS)
3228         goto end;
3229
3230     rc = RegCreateKeyW(hkey,szFeatures,&hkey2);
3231     if (rc != ERROR_SUCCESS)
3232         goto end;
3233
3234     rc = RegCreateKeyW(hkey2,squished_pc,&hkey3);
3235     if (rc != ERROR_SUCCESS)
3236         goto end;
3237
3238     /* here the guids are base 85 encoded */
3239     for (i = 0; i < package->loaded_features; i++)
3240     {
3241         LPWSTR data = NULL;
3242         GUID clsid;
3243         int j;
3244         INT size;
3245
3246         size = package->features[i].ComponentCount*21*sizeof(WCHAR);
3247         data = HeapAlloc(GetProcessHeap(), 0, size);
3248
3249         data[0] = 0;
3250         for (j = 0; j < package->features[i].ComponentCount; j++)
3251         {
3252             WCHAR buf[21];
3253             TRACE("From %s\n",debugstr_w(package->components
3254                             [package->features[i].Components[j]].ComponentId));
3255             CLSIDFromString(package->components
3256                             [package->features[i].Components[j]].ComponentId,
3257                             &clsid);
3258             encode_base85_guid(&clsid,buf);
3259             TRACE("to %s\n",debugstr_w(buf));
3260             strcatW(data,buf);
3261         }
3262
3263         size = strlenW(data)*sizeof(WCHAR);
3264         RegSetValueExW(hkey3,package->features[i].Feature,0,REG_SZ,
3265                        (LPSTR)data,size);
3266         HeapFree(GetProcessHeap(),0,data);
3267     }
3268
3269     RegCloseKey(hkey3);
3270     RegCloseKey(hkey2);
3271
3272     rc = RegCreateKeyW(hkey,szComponents,&hkey2);
3273     if (rc != ERROR_SUCCESS)
3274         goto end;
3275   
3276     for (i = 0; i < package->loaded_components; i++)
3277     {
3278         if (package->components[i].ComponentId[0]!=0)
3279         {
3280             WCHAR keypath[0x1000];
3281             MSIRECORD * uirow;
3282
3283             squash_guid(package->components[i].ComponentId,squished_cc);
3284             rc = RegCreateKeyW(hkey2,squished_cc,&hkey3);
3285             if (rc != ERROR_SUCCESS)
3286                 continue;
3287            
3288             resolve_keypath(package,i,keypath);
3289
3290             RegSetValueExW(hkey3,squished_pc,0,REG_SZ,(LPVOID)keypath,
3291                             (strlenW(keypath)+1)*sizeof(WCHAR));
3292             RegCloseKey(hkey3);
3293         
3294             /* UI stuff */
3295             uirow = MSI_CreateRecord(3);
3296             MSI_RecordSetStringW(uirow,1,productcode);
3297             MSI_RecordSetStringW(uirow,2,package->components[i].ComponentId);
3298             MSI_RecordSetStringW(uirow,3,keypath);
3299             ui_actiondata(package,szProcessComponents,uirow);
3300             msiobj_release( &uirow->hdr );
3301         }
3302     } 
3303 end:
3304     RegCloseKey(hkey2);
3305     RegCloseKey(hkey);
3306     return rc;
3307 }
3308
3309 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3310 {
3311     /* 
3312      * OK this is a bit confusing.. I am given a _Component key and I believe
3313      * that the file that is being registered as a type library is the "key file
3314      * of that component" which I interpret to mean "The file in the KeyPath of
3315      * that component".
3316      */
3317     UINT rc;
3318     MSIQUERY * view;
3319     MSIRECORD * row = 0;
3320     static const WCHAR Query[] = {
3321         'S','E','L','E','C','T',' ','*',' ',
3322         'f','r','o','m',' ','T','y','p','e','L','i','b',0};
3323     ITypeLib *ptLib;
3324     HRESULT res;
3325
3326     if (!package)
3327         return ERROR_INVALID_HANDLE;
3328
3329     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3330     if (rc != ERROR_SUCCESS)
3331         return rc;
3332
3333     rc = MSI_ViewExecute(view, 0);
3334     if (rc != ERROR_SUCCESS)
3335     {
3336         MSI_ViewClose(view);
3337         msiobj_release(&view->hdr);
3338         return rc;
3339     }
3340
3341     while (1)
3342     {   
3343         WCHAR component[0x100];
3344         DWORD sz;
3345         INT index;
3346
3347         rc = MSI_ViewFetch(view,&row);
3348         if (rc != ERROR_SUCCESS)
3349         {
3350             rc = ERROR_SUCCESS;
3351             break;
3352         }
3353
3354         sz = 0x100;
3355         MSI_RecordGetStringW(row,3,component,&sz);
3356
3357         index = get_loaded_component(package,component);
3358         if (index < 0)
3359         {
3360             msiobj_release(&row->hdr);
3361             continue;
3362         }
3363
3364         if (!package->components[index].Enabled ||
3365             !package->components[index].FeatureState)
3366         {
3367             TRACE("Skipping typelib reg due to disabled component\n");
3368             msiobj_release(&row->hdr);
3369             continue;
3370         }
3371
3372         index = get_loaded_file(package,package->components[index].KeyPath); 
3373    
3374         if (index < 0)
3375         {
3376             msiobj_release(&row->hdr);
3377             continue;
3378         }
3379
3380         res = LoadTypeLib(package->files[index].TargetPath,&ptLib);
3381         if (SUCCEEDED(res))
3382         {
3383             WCHAR help[MAX_PATH];
3384             WCHAR helpid[0x100];
3385
3386             sz = 0x100;
3387             MSI_RecordGetStringW(row,6,helpid,&sz);
3388
3389             resolve_folder(package,helpid,help,FALSE,FALSE,NULL);
3390
3391             res = RegisterTypeLib(ptLib,package->files[index].TargetPath,help);
3392             if (!SUCCEEDED(res))
3393                 ERR("Failed to register type library %s\n",
3394                      debugstr_w(package->files[index].TargetPath));
3395             else
3396             {
3397                 /* Yes the row has more fields than I need, but #1 is 
3398                    correct and the only one I need. Why make a new row? */
3399
3400                 ui_actiondata(package,szRegisterTypeLibraries,row);
3401                 
3402                 TRACE("Registered %s\n",
3403                        debugstr_w(package->files[index].TargetPath));
3404             }
3405
3406             if (ptLib)
3407                 ITypeLib_Release(ptLib);
3408         }
3409         else
3410             ERR("Failed to load type library %s\n",
3411                 debugstr_w(package->files[index].TargetPath));
3412         
3413         msiobj_release(&row->hdr);
3414     }
3415     MSI_ViewClose(view);
3416     msiobj_release(&view->hdr);
3417     return rc;
3418    
3419 }
3420
3421 static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app )
3422 {
3423     static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
3424     UINT rc;
3425     MSIQUERY * view;
3426     MSIRECORD * row = 0;
3427     static const WCHAR ExecSeqQuery[] = 
3428 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','p','p','I'
3429 ,'d',' ','w','h','e','r','e',' ','A','p','p','I','d','=','`','%','s','`',0};
3430     WCHAR Query[0x1000];
3431     HKEY hkey2,hkey3;
3432     LPWSTR buffer=0;
3433
3434     if (!package)
3435         return ERROR_INVALID_HANDLE;
3436
3437     sprintfW(Query,ExecSeqQuery,clsid);
3438
3439     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3440     if (rc != ERROR_SUCCESS)
3441         return rc;
3442
3443     rc = MSI_ViewExecute(view, 0);
3444     if (rc != ERROR_SUCCESS)
3445     {
3446         MSI_ViewClose(view);
3447         msiobj_release(&view->hdr);
3448         return rc;
3449     }
3450
3451     RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
3452     RegCreateKeyW(hkey2,clsid,&hkey3);
3453     RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app,
3454                    (strlenW(app)+1)*sizeof(WCHAR));
3455
3456     rc = MSI_ViewFetch(view,&row);
3457     if (rc != ERROR_SUCCESS)
3458     {
3459         MSI_ViewClose(view);
3460         msiobj_release(&view->hdr);
3461         return rc;
3462     }
3463
3464     if (!MSI_RecordIsNull(row,2)) 
3465     {
3466         LPWSTR deformated=0;
3467         UINT size; 
3468         static const WCHAR szRemoteServerName[] =
3469 {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0};
3470         buffer = load_dynamic_stringW(row,2);
3471         size = deformat_string(package,buffer,&deformated);
3472         RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,(LPVOID)deformated,
3473                        size);
3474         HeapFree(GetProcessHeap(),0,deformated);
3475         HeapFree(GetProcessHeap(),0,buffer);
3476     }
3477
3478     if (!MSI_RecordIsNull(row,3)) 
3479     {
3480         static const WCHAR szLocalService[] =
3481 {'L','o','c','a','l','S','e','r','v','i','c','e',0};
3482         UINT size;
3483         buffer = load_dynamic_stringW(row,3);
3484         size = (strlenW(buffer)+1) * sizeof(WCHAR);
3485         RegSetValueExW(hkey3,szLocalService,0,REG_SZ,(LPVOID)buffer,size);
3486         HeapFree(GetProcessHeap(),0,buffer);
3487     }
3488
3489     if (!MSI_RecordIsNull(row,4)) 
3490     {
3491         static const WCHAR szService[] =
3492 {'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0};
3493         UINT size;
3494         buffer = load_dynamic_stringW(row,4);
3495         size = (strlenW(buffer)+1) * sizeof(WCHAR);
3496         RegSetValueExW(hkey3,szService,0,REG_SZ,(LPVOID)buffer,size);
3497         HeapFree(GetProcessHeap(),0,buffer);
3498     }
3499
3500     if (!MSI_RecordIsNull(row,5)) 
3501     {
3502         static const WCHAR szDLL[] =
3503 {'D','l','l','S','u','r','r','o','g','a','t','e',0};
3504         UINT size;
3505         buffer = load_dynamic_stringW(row,5);
3506         size = (strlenW(buffer)+1) * sizeof(WCHAR);
3507         RegSetValueExW(hkey3,szDLL,0,REG_SZ,(LPVOID)buffer,size);
3508         HeapFree(GetProcessHeap(),0,buffer);
3509     }
3510
3511     if (!MSI_RecordIsNull(row,6)) 
3512     {
3513         static const WCHAR szActivate[] =
3514 {'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0};
3515         static const WCHAR szY[] = {'Y',0};
3516
3517         if (MSI_RecordGetInteger(row,6))
3518             RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4);
3519     }
3520
3521     if (!MSI_RecordIsNull(row,7)) 
3522     {
3523         static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
3524         static const WCHAR szUser[] = 
3525 {'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0};
3526
3527         if (MSI_RecordGetInteger(row,7))
3528             RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,34);
3529     }
3530
3531     msiobj_release(&row->hdr);
3532     MSI_ViewClose(view);
3533     msiobj_release(&view->hdr);
3534     RegCloseKey(hkey3);
3535     RegCloseKey(hkey2);
3536     return rc;
3537 }
3538
3539 static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
3540 {
3541     /* 
3542      * Again I am assuming the words, "Whose key file represents" when refering
3543      * to a Component as to meaning that Components KeyPath file
3544      *
3545      * Also there is a very strong connection between ClassInfo and ProgID
3546      * that I am mostly glossing over.  
3547      * What would be more propper is to load the ClassInfo and the ProgID info
3548      * into memory data structures and then be able to enable and disable them
3549      * based on component. 
3550      */
3551     
3552     UINT rc;
3553     MSIQUERY * view;
3554     MSIRECORD * row = 0;
3555     static const WCHAR ExecSeqQuery[] = {
3556         'S','E','L','E','C','T',' ','*',' ',
3557         'f','r','o','m',' ','C','l','a','s','s',0};
3558     static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
3559     static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 };
3560     static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
3561     HKEY hkey,hkey2,hkey3;
3562
3563     if (!package)
3564         return ERROR_INVALID_HANDLE;
3565
3566     rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
3567     if (rc != ERROR_SUCCESS)
3568         return ERROR_FUNCTION_FAILED;
3569
3570     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3571     if (rc != ERROR_SUCCESS)
3572         goto end;
3573
3574     rc = MSI_ViewExecute(view, 0);
3575     if (rc != ERROR_SUCCESS)
3576     {
3577         MSI_ViewClose(view);
3578         msiobj_release(&view->hdr);
3579         goto end;
3580     }
3581
3582     while (1)
3583     {
3584         WCHAR clsid[0x100];
3585         WCHAR buffer[0x100];
3586         WCHAR desc[0x100];
3587         DWORD sz;
3588         INT index;
3589      
3590         rc = MSI_ViewFetch(view,&row);
3591         if (rc != ERROR_SUCCESS)
3592         {
3593             rc = ERROR_SUCCESS;
3594             break;
3595         }
3596
3597         sz=0x100;
3598         MSI_RecordGetStringW(row,3,buffer,&sz);
3599
3600         index = get_loaded_component(package,buffer);
3601
3602         if (index < 0)
3603         {
3604             msiobj_release(&row->hdr);
3605             continue;
3606         }
3607
3608         if (!package->components[index].Enabled ||
3609             !package->components[index].FeatureState)
3610         {
3611             TRACE("Skipping class reg due to disabled component\n");
3612             msiobj_release(&row->hdr);
3613             continue;
3614         }
3615
3616         sz=0x100;
3617         MSI_RecordGetStringW(row,1,clsid,&sz);
3618         RegCreateKeyW(hkey,clsid,&hkey2);
3619
3620         if (!MSI_RecordIsNull(row,5))
3621         {
3622             sz=0x100;
3623             MSI_RecordGetStringW(row,5,desc,&sz);
3624
3625             RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)desc,
3626                            (strlenW(desc)+1)*sizeof(WCHAR));
3627         }
3628         else
3629             desc[0]=0;
3630
3631         sz=0x100;
3632         MSI_RecordGetStringW(row,2,buffer,&sz);
3633
3634         RegCreateKeyW(hkey2,buffer,&hkey3);
3635
3636         index = get_loaded_file(package,package->components[index].KeyPath);
3637         RegSetValueExW(hkey3,NULL,0,REG_SZ,
3638                        (LPVOID)package->files[index].TargetPath,
3639                        (strlenW(package->files[index].TargetPath)+1)
3640                         *sizeof(WCHAR));
3641
3642         RegCloseKey(hkey3);
3643
3644         if (!MSI_RecordIsNull(row,4))
3645         {
3646             sz=0x100;
3647             MSI_RecordGetStringW(row,4,buffer,&sz);
3648
3649             RegCreateKeyW(hkey2,szProgID,&hkey3);
3650     
3651             RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)buffer,
3652                        (strlenW(buffer)+1)*sizeof(WCHAR));
3653
3654             RegCloseKey(hkey3);
3655         }
3656
3657         if (!MSI_RecordIsNull(row,6))
3658         { 
3659             sz=0x100;
3660             MSI_RecordGetStringW(row,6,buffer,&sz);
3661
3662             RegSetValueExW(hkey2,szAppID,0,REG_SZ,(LPVOID)buffer,
3663                        (strlenW(buffer)+1)*sizeof(WCHAR));
3664
3665             register_appid(package,buffer,desc);
3666         }
3667
3668         RegCloseKey(hkey2);
3669
3670         FIXME("Process the rest of the fields >7\n");
3671
3672         ui_actiondata(package,szRegisterClassInfo,row);
3673
3674         msiobj_release(&row->hdr);
3675     }
3676     MSI_ViewClose(view);
3677     msiobj_release(&view->hdr);
3678
3679 end:
3680     RegCloseKey(hkey);
3681     return rc;
3682 }
3683
3684 static UINT register_progid_base(MSIRECORD * row, LPWSTR clsid)
3685 {
3686     static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
3687     HKEY hkey,hkey2;
3688     WCHAR buffer[0x100];
3689     DWORD sz;
3690
3691
3692     sz = 0x100;
3693     MSI_RecordGetStringW(row,1,buffer,&sz);
3694     RegCreateKeyW(HKEY_CLASSES_ROOT,buffer,&hkey);
3695
3696     if (!MSI_RecordIsNull(row,4))
3697     {
3698         sz = 0x100;
3699         MSI_RecordGetStringW(row,4,buffer,&sz);
3700         RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
3701                        sizeof(WCHAR));
3702     }
3703
3704     if (!MSI_RecordIsNull(row,3))
3705     {   
3706         sz = 0x100;
3707     
3708         MSI_RecordGetStringW(row,3,buffer,&sz);
3709         RegCreateKeyW(hkey,szCLSID,&hkey2);
3710         RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
3711                        sizeof(WCHAR));
3712
3713         if (clsid)
3714             strcpyW(clsid,buffer);
3715
3716         RegCloseKey(hkey2);
3717     }
3718     else
3719     {
3720         FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
3721         return ERROR_FUNCTION_FAILED;
3722     }
3723     if (!MSI_RecordIsNull(row,5))
3724         FIXME ("UNHANDLED icon in Progid\n");
3725     return ERROR_SUCCESS;
3726 }
3727
3728 static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid);
3729
3730 static UINT register_parent_progid(MSIPACKAGE *package, LPCWSTR parent, 
3731                                    LPWSTR clsid)
3732 {
3733     UINT rc;
3734     MSIQUERY * view;
3735     MSIRECORD * row = 0;
3736     static const WCHAR Query_t[] = 
3737 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','r','o','g'
3738 ,'I','d',' ','w','h','e','r','e',' ','P','r','o','g','I','d',' ','=',' ','`'
3739 ,'%','s','`',0};
3740     WCHAR Query[0x1000];
3741
3742     if (!package)
3743         return ERROR_INVALID_HANDLE;
3744
3745     sprintfW(Query,Query_t,parent);
3746
3747     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3748     if (rc != ERROR_SUCCESS)
3749         return rc;
3750
3751     rc = MSI_ViewExecute(view, 0);
3752     if (rc != ERROR_SUCCESS)
3753     {
3754         MSI_ViewClose(view);
3755         msiobj_release(&view->hdr);
3756         return rc;
3757     }
3758
3759     rc = MSI_ViewFetch(view,&row);
3760     if (rc != ERROR_SUCCESS)
3761     {
3762         MSI_ViewClose(view);
3763         msiobj_release(&view->hdr);
3764         return rc;
3765     }
3766
3767     register_progid(package,row,clsid);
3768
3769     msiobj_release(&row->hdr);
3770     MSI_ViewClose(view);
3771     msiobj_release(&view->hdr);
3772     return rc;
3773 }
3774
3775 static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid)
3776 {
3777     UINT rc = ERROR_SUCCESS; 
3778
3779     if (MSI_RecordIsNull(row,2))
3780         rc = register_progid_base(row,clsid);
3781     else
3782     {
3783         WCHAR buffer[0x1000];
3784         DWORD sz;
3785         HKEY hkey,hkey2;
3786         static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
3787
3788         sz = 0x100;
3789         MSI_RecordGetStringW(row,2,buffer,&sz);
3790         rc = register_parent_progid(package,buffer,clsid);
3791
3792         sz = 0x100;
3793         MSI_RecordGetStringW(row,1,buffer,&sz);
3794         RegCreateKeyW(HKEY_CLASSES_ROOT,buffer,&hkey);
3795         /* clasid is same as parent */
3796         RegCreateKeyW(hkey,szCLSID,&hkey2);
3797         RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) *
3798                        sizeof(WCHAR));
3799
3800         RegCloseKey(hkey2);
3801         if (!MSI_RecordIsNull(row,4))
3802         {
3803             sz = 0x100;
3804             MSI_RecordGetStringW(row,4,buffer,&sz);
3805             RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer,
3806                            (strlenW(buffer)+1) * sizeof(WCHAR));
3807         }
3808
3809         if (!MSI_RecordIsNull(row,5))
3810             FIXME ("UNHANDLED icon in Progid\n");
3811
3812         RegCloseKey(hkey);
3813     }
3814     return rc;
3815 }
3816
3817 static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
3818 {
3819     /* 
3820      * Sigh, here I am just brute force registering all progids
3821      * this needs to be linked to the Classes that have been registerd
3822      * but the easiest way to do that is to load all these stuff into
3823      * memory for easy checking.
3824      *
3825      * Gives me something to continue to work toward.
3826      */
3827     UINT rc;
3828     MSIQUERY * view;
3829     MSIRECORD * row = 0;
3830     static const WCHAR Query[] = {
3831         'S','E','L','E','C','T',' ','*',' ',
3832         'F','R','O','M',' ','P','r','o','g','I','d',0};
3833
3834     if (!package)
3835         return ERROR_INVALID_HANDLE;
3836
3837     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3838     if (rc != ERROR_SUCCESS)
3839         return rc;
3840
3841     rc = MSI_ViewExecute(view, 0);
3842     if (rc != ERROR_SUCCESS)
3843     {
3844         MSI_ViewClose(view);
3845         msiobj_release(&view->hdr);
3846         return rc;
3847     }
3848
3849     while (1)
3850     {
3851         WCHAR clsid[0x1000];
3852
3853         rc = MSI_ViewFetch(view,&row);
3854         if (rc != ERROR_SUCCESS)
3855         {
3856             rc = ERROR_SUCCESS;
3857             break;
3858         }
3859         
3860         register_progid(package,row,clsid);
3861         ui_actiondata(package,szRegisterProgIdInfo,row);
3862
3863         msiobj_release(&row->hdr);
3864     }
3865     MSI_ViewClose(view);
3866     msiobj_release(&view->hdr);
3867     return rc;
3868 }
3869
3870 static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, 
3871                             LPWSTR FilePath)
3872 {
3873     WCHAR ProductCode[0x100];
3874     WCHAR SystemFolder[MAX_PATH];
3875     DWORD sz;
3876
3877     static const WCHAR szInstaller[] = 
3878 {'I','n','s','t','a','l','l','e','r','\\',0};
3879     static const WCHAR szProductCode[] =
3880 {'P','r','o','d','u','c','t','C','o','d','e',0};
3881     static const WCHAR szFolder[] =
3882 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3883
3884     sz = 0x100;
3885     MSI_GetPropertyW(package,szProductCode,ProductCode,&sz);
3886     if (strlenW(ProductCode)==0)
3887         return ERROR_FUNCTION_FAILED;
3888
3889     sz = MAX_PATH;
3890     MSI_GetPropertyW(package,szFolder,SystemFolder,&sz);
3891     strcatW(SystemFolder,szInstaller); 
3892     strcatW(SystemFolder,ProductCode);
3893     create_full_pathW(SystemFolder);
3894
3895     strcpyW(FilePath,SystemFolder);
3896     strcatW(FilePath,cszbs);
3897     strcatW(FilePath,icon_name);
3898     return ERROR_SUCCESS;
3899 }
3900
3901 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3902 {
3903     UINT rc;
3904     MSIQUERY * view;
3905     MSIRECORD * row = 0;
3906     static const WCHAR Query[] = {
3907        'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ',
3908        'S','h','o','r','t','c','u','t',0};
3909     IShellLinkW *sl;
3910     IPersistFile *pf;
3911     HRESULT res;
3912
3913     if (!package)
3914         return ERROR_INVALID_HANDLE;
3915
3916     res = CoInitialize( NULL );
3917     if (FAILED (res))
3918     {
3919         ERR("CoInitialize failed\n");
3920         return ERROR_FUNCTION_FAILED;
3921     }
3922
3923     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3924     if (rc != ERROR_SUCCESS)
3925         return rc;
3926
3927     rc = MSI_ViewExecute(view, 0);
3928     if (rc != ERROR_SUCCESS)
3929     {
3930         MSI_ViewClose(view);
3931         msiobj_release(&view->hdr);
3932         return rc;
3933     }
3934
3935     while (1)
3936     {
3937         WCHAR target_file[MAX_PATH];
3938         WCHAR buffer[0x100];
3939         DWORD sz;
3940         DWORD index;
3941         static const WCHAR szlnk[]={'.','l','n','k',0};
3942
3943         rc = MSI_ViewFetch(view,&row);
3944         if (rc != ERROR_SUCCESS)
3945         {
3946             rc = ERROR_SUCCESS;
3947             break;
3948         }
3949         
3950         sz = 0x100;
3951         MSI_RecordGetStringW(row,4,buffer,&sz);
3952
3953         index = get_loaded_component(package,buffer);
3954
3955         if (index < 0)
3956         {
3957             msiobj_release(&row->hdr);
3958             continue;
3959         }
3960
3961         if (!package->components[index].Enabled ||
3962             !package->components[index].FeatureState)
3963         {
3964             TRACE("Skipping shortcut creation due to disabled component\n");
3965             msiobj_release(&row->hdr);
3966             continue;
3967         }
3968
3969         ui_actiondata(package,szCreateShortcuts,row);
3970
3971         res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3972                               &IID_IShellLinkW, (LPVOID *) &sl );
3973
3974         if (FAILED(res))
3975         {
3976             ERR("Is IID_IShellLink\n");
3977             msiobj_release(&row->hdr);
3978             continue;
3979         }
3980
3981         res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3982         if( FAILED( res ) )
3983         {
3984             ERR("Is IID_IPersistFile\n");
3985             msiobj_release(&row->hdr);
3986             continue;
3987         }
3988
3989         sz = 0x100;
3990         MSI_RecordGetStringW(row,2,buffer,&sz);
3991         resolve_folder(package, buffer,target_file,FALSE,FALSE,NULL);
3992
3993         sz = 0x100;
3994         MSI_RecordGetStringW(row,3,buffer,&sz);
3995         reduce_to_longfilename(buffer);
3996         strcatW(target_file,buffer);
3997         if (!strchrW(target_file,'.'))
3998             strcatW(target_file,szlnk);
3999
4000         sz = 0x100;
4001         MSI_RecordGetStringW(row,5,buffer,&sz);
4002         if (strchrW(buffer,'['))
4003         {
4004             LPWSTR deformated;
4005             deformat_string(package,buffer,&deformated);
4006             IShellLinkW_SetPath(sl,deformated);
4007             HeapFree(GetProcessHeap(),0,deformated);
4008         }
4009         else
4010         {
4011             FIXME("UNHANDLED shortcut format, advertised shortcut\n");
4012             IPersistFile_Release( pf );
4013             IShellLinkW_Release( sl );
4014             msiobj_release(&row->hdr);
4015             continue;
4016         }
4017
4018         if (!MSI_RecordIsNull(row,6))
4019         {
4020             LPWSTR deformated;
4021             sz = 0x100;
4022             MSI_RecordGetStringW(row,6,buffer,&sz);
4023             deformat_string(package,buffer,&deformated);
4024             IShellLinkW_SetArguments(sl,deformated);
4025             HeapFree(GetProcessHeap(),0,deformated);
4026         }
4027
4028         if (!MSI_RecordIsNull(row,7))
4029         {
4030             LPWSTR deformated;
4031             deformated = load_dynamic_stringW(row,7);
4032             IShellLinkW_SetDescription(sl,deformated);
4033             HeapFree(GetProcessHeap(),0,deformated);
4034         }
4035
4036         if (!MSI_RecordIsNull(row,8))
4037             IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
4038
4039         if (!MSI_RecordIsNull(row,9))
4040         {
4041             WCHAR Path[MAX_PATH];
4042             INT index; 
4043
4044             sz = 0x100;
4045             MSI_RecordGetStringW(row,9,buffer,&sz);
4046
4047             build_icon_path(package,buffer,Path);
4048             index = MSI_RecordGetInteger(row,10);
4049
4050             IShellLinkW_SetIconLocation(sl,Path,index);
4051         }
4052
4053         if (!MSI_RecordIsNull(row,11))
4054             IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
4055
4056         if (!MSI_RecordIsNull(row,12))
4057         {
4058             WCHAR Path[MAX_PATH];
4059
4060             sz = 0x100;
4061             MSI_RecordGetStringW(row,12,buffer,&sz);
4062             resolve_folder(package, buffer, Path, FALSE, FALSE, NULL);
4063             IShellLinkW_SetWorkingDirectory(sl,Path);
4064         }
4065
4066         TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
4067         IPersistFile_Save(pf,target_file,FALSE);
4068         
4069         IPersistFile_Release( pf );
4070         IShellLinkW_Release( sl );
4071
4072         msiobj_release(&row->hdr);
4073     }
4074     MSI_ViewClose(view);
4075     msiobj_release(&view->hdr);
4076
4077
4078     CoUninitialize();
4079
4080     return rc;
4081 }
4082
4083
4084 /*
4085  * 99% of the work done here is only done for 
4086  * advertised installs. However this is where the
4087  * Icon table is processed and written out
4088  * so that is waht I am going to do here.
4089  */
4090 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4091 {
4092     UINT rc;
4093     MSIQUERY * view;
4094     MSIRECORD * row = 0;
4095     static const WCHAR Query[]={
4096         'S','E','L','E','C','T',' ','*',' ',
4097         'f','r','o','m',' ','I','c','o','n',0};
4098     DWORD sz;
4099
4100     if (!package)
4101         return ERROR_INVALID_HANDLE;
4102
4103     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
4104     if (rc != ERROR_SUCCESS)
4105         return rc;
4106
4107     rc = MSI_ViewExecute(view, 0);
4108     if (rc != ERROR_SUCCESS)
4109     {
4110         MSI_ViewClose(view);
4111         msiobj_release(&view->hdr);
4112         return rc;
4113     }
4114
4115     while (1)
4116     {
4117         HANDLE the_file;
4118         WCHAR FilePath[MAX_PATH];
4119         WCHAR FileName[MAX_PATH];
4120         CHAR buffer[1024];
4121
4122         rc = MSI_ViewFetch(view,&row);
4123         if (rc != ERROR_SUCCESS)
4124         {
4125             rc = ERROR_SUCCESS;
4126             break;
4127         }
4128     
4129         sz = MAX_PATH;
4130         MSI_RecordGetStringW(row,1,FileName,&sz);
4131         if (sz == 0)
4132         {
4133             ERR("Unable to get FileName\n");
4134             msiobj_release(&row->hdr);
4135             continue;
4136         }
4137
4138         build_icon_path(package,FileName,FilePath);
4139
4140         TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
4141         
4142         the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
4143                            FILE_ATTRIBUTE_NORMAL, NULL);
4144
4145         if (the_file == INVALID_HANDLE_VALUE)
4146         {
4147             ERR("Unable to create file %s\n",debugstr_w(FilePath));
4148             msiobj_release(&row->hdr);
4149             continue;
4150         }
4151
4152         do 
4153         {
4154             DWORD write;
4155             sz = 1024;
4156             rc = MSI_RecordReadStream(row,2,buffer,&sz);
4157             if (rc != ERROR_SUCCESS)
4158             {
4159                 ERR("Failed to get stream\n");
4160                 CloseHandle(the_file);  
4161                 DeleteFileW(FilePath);
4162                 break;
4163             }
4164             WriteFile(the_file,buffer,sz,&write,NULL);
4165         } while (sz == 1024);
4166
4167         CloseHandle(the_file);
4168         msiobj_release(&row->hdr);
4169     }
4170     MSI_ViewClose(view);
4171     msiobj_release(&view->hdr);
4172     return rc;
4173
4174 }
4175
4176 /* Msi functions that seem appropriate here */
4177 UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
4178 {
4179     LPWSTR szwAction;
4180     UINT rc;
4181
4182     TRACE(" exteral attempt at action %s\n",szAction);
4183
4184     if (!szAction)
4185         return ERROR_FUNCTION_FAILED;
4186     if (hInstall == 0)
4187         return ERROR_FUNCTION_FAILED;
4188
4189     szwAction = strdupAtoW(szAction);
4190
4191     if (!szwAction)
4192         return ERROR_FUNCTION_FAILED; 
4193
4194
4195     rc = MsiDoActionW(hInstall, szwAction);
4196     HeapFree(GetProcessHeap(),0,szwAction);
4197     return rc;
4198 }
4199
4200 UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction )
4201 {
4202     MSIPACKAGE *package;
4203     UINT ret = ERROR_INVALID_HANDLE;
4204
4205     TRACE(" external attempt at action %s \n",debugstr_w(szAction));
4206
4207     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4208     if( package )
4209     {
4210         ret = ACTION_PerformAction(package,szAction);
4211         msiobj_release( &package->hdr );
4212     }
4213     return ret;
4214 }
4215
4216 UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder, 
4217                                LPSTR szPathBuf, DWORD* pcchPathBuf) 
4218 {
4219     LPWSTR szwFolder;
4220     LPWSTR szwPathBuf;
4221     UINT rc;
4222
4223     TRACE("getting folder %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
4224
4225     if (!szFolder)
4226         return ERROR_FUNCTION_FAILED;
4227     if (hInstall == 0)
4228         return ERROR_FUNCTION_FAILED;
4229
4230     szwFolder = strdupAtoW(szFolder);
4231
4232     if (!szwFolder)
4233         return ERROR_FUNCTION_FAILED; 
4234
4235     szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
4236
4237     rc = MsiGetTargetPathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
4238
4239     WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
4240                          *pcchPathBuf, NULL, NULL );
4241
4242     HeapFree(GetProcessHeap(),0,szwFolder);
4243     HeapFree(GetProcessHeap(),0,szwPathBuf);
4244
4245     return rc;
4246 }
4247
4248 UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
4249                                 szPathBuf, DWORD* pcchPathBuf) 
4250 {
4251     WCHAR path[MAX_PATH];
4252     UINT rc;
4253     MSIPACKAGE *package;
4254
4255     TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
4256
4257     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4258     if( !package )
4259         return ERROR_INVALID_HANDLE;
4260     rc = resolve_folder(package, szFolder, path, FALSE, FALSE, NULL);
4261     msiobj_release( &package->hdr );
4262
4263     if (rc == ERROR_SUCCESS && strlenW(path) > *pcchPathBuf)
4264     {
4265         *pcchPathBuf = strlenW(path)+1;
4266         return ERROR_MORE_DATA;
4267     }
4268     else if (rc == ERROR_SUCCESS)
4269     {
4270         *pcchPathBuf = strlenW(path)+1;
4271         strcpyW(szPathBuf,path);
4272         TRACE("Returning Path %s\n",debugstr_w(path));
4273     }
4274     
4275     return rc;
4276 }
4277
4278
4279 UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder, 
4280                                LPSTR szPathBuf, DWORD* pcchPathBuf) 
4281 {
4282     LPWSTR szwFolder;
4283     LPWSTR szwPathBuf;
4284     UINT rc;
4285
4286     TRACE("getting source %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
4287
4288     if (!szFolder)
4289         return ERROR_FUNCTION_FAILED;
4290     if (hInstall == 0)
4291         return ERROR_FUNCTION_FAILED;
4292
4293     szwFolder = strdupAtoW(szFolder);
4294     if (!szwFolder)
4295         return ERROR_FUNCTION_FAILED; 
4296
4297     szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
4298
4299     rc = MsiGetSourcePathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
4300
4301     WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
4302                          *pcchPathBuf, NULL, NULL );
4303
4304     HeapFree(GetProcessHeap(),0,szwFolder);
4305     HeapFree(GetProcessHeap(),0,szwPathBuf);
4306
4307     return rc;
4308 }
4309
4310 UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
4311                                 szPathBuf, DWORD* pcchPathBuf) 
4312 {
4313     WCHAR path[MAX_PATH];
4314     UINT rc;
4315     MSIPACKAGE *package;
4316
4317     TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
4318
4319     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4320     if( !package )
4321         return ERROR_INVALID_HANDLE;
4322     rc = resolve_folder(package, szFolder, path, TRUE, FALSE, NULL);
4323     msiobj_release( &package->hdr );
4324
4325     if (rc == ERROR_SUCCESS && strlenW(path) > *pcchPathBuf)
4326     {
4327         *pcchPathBuf = strlenW(path)+1;
4328         return ERROR_MORE_DATA;
4329     }
4330     else if (rc == ERROR_SUCCESS)
4331     {
4332         *pcchPathBuf = strlenW(path)+1;
4333         strcpyW(szPathBuf,path);
4334         TRACE("Returning Path %s\n",debugstr_w(path));
4335     }
4336     
4337     return rc;
4338 }
4339
4340
4341 UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder, 
4342                              LPCSTR szFolderPath)
4343 {
4344     LPWSTR szwFolder;
4345     LPWSTR szwFolderPath;
4346     UINT rc;
4347
4348     if (!szFolder)
4349         return ERROR_FUNCTION_FAILED;
4350     if (hInstall == 0)
4351         return ERROR_FUNCTION_FAILED;
4352
4353     szwFolder = strdupAtoW(szFolder);
4354     if (!szwFolder)
4355         return ERROR_FUNCTION_FAILED; 
4356
4357     szwFolderPath = strdupAtoW(szFolderPath);
4358     if (!szwFolderPath)
4359     {
4360         HeapFree(GetProcessHeap(),0,szwFolder);
4361         return ERROR_FUNCTION_FAILED; 
4362     }
4363
4364     rc = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath);
4365
4366     HeapFree(GetProcessHeap(),0,szwFolder);
4367     HeapFree(GetProcessHeap(),0,szwFolderPath);
4368
4369     return rc;
4370 }
4371
4372 UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder, 
4373                              LPCWSTR szFolderPath)
4374 {
4375     INT i;
4376     WCHAR path[MAX_PATH];
4377     MSIFOLDER *folder;
4378
4379     TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
4380
4381     if (package==NULL)
4382         return ERROR_INVALID_HANDLE;
4383
4384     if (szFolderPath[0]==0)
4385         return ERROR_FUNCTION_FAILED;
4386
4387     if (GetFileAttributesW(szFolderPath) == INVALID_FILE_ATTRIBUTES)
4388         return ERROR_FUNCTION_FAILED;
4389
4390     resolve_folder(package,szFolder,path,FALSE,FALSE,&folder);
4391
4392     if (!folder)
4393         return ERROR_INVALID_PARAMETER;
4394
4395     strcpyW(folder->Property,szFolderPath);
4396
4397     for (i = 0; i < package->loaded_folders; i++)
4398         package->folders[i].ResolvedTarget[0]=0;
4399
4400     for (i = 0; i < package->loaded_folders; i++)
4401         resolve_folder(package, package->folders[i].Directory, path, FALSE,
4402                        TRUE, NULL);
4403
4404     return ERROR_SUCCESS;
4405 }
4406
4407 UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder, 
4408                              LPCWSTR szFolderPath)
4409 {
4410     MSIPACKAGE *package;
4411     UINT ret;
4412
4413     TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
4414
4415     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4416     ret = MSI_SetTargetPathW( package, szFolder, szFolderPath );
4417     msiobj_release( &package->hdr );
4418     return ret;
4419 }
4420
4421 BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, DWORD iRunMode)
4422 {
4423     FIXME("STUB (%li)\n",iRunMode);
4424     return FALSE;
4425 }
4426
4427 /*
4428  * according to the docs when this is called it immediently recalculates all the
4429  * components states as well
4430  */
4431 UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
4432                                 INSTALLSTATE iState)
4433 {
4434     LPWSTR szwFeature = NULL;
4435     UINT rc;
4436
4437     szwFeature = strdupAtoW(szFeature);
4438
4439     if (!szwFeature)
4440         return ERROR_FUNCTION_FAILED;
4441    
4442     rc = MsiSetFeatureStateW(hInstall,szwFeature, iState); 
4443
4444     HeapFree(GetProcessHeap(),0,szwFeature);
4445
4446     return rc;
4447 }
4448
4449 UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
4450                                 INSTALLSTATE iState)
4451 {
4452     MSIPACKAGE* package;
4453     INT index;
4454
4455     TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
4456
4457     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4458     if (!package)
4459         return ERROR_INVALID_HANDLE;
4460
4461     index = get_loaded_feature(package,szFeature);
4462     if (index < 0)
4463         return ERROR_UNKNOWN_FEATURE;
4464
4465     package->features[index].State = iState;
4466
4467     return ERROR_SUCCESS;
4468 }
4469
4470 UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPSTR szFeature,
4471                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
4472 {
4473     LPWSTR szwFeature = NULL;
4474     UINT rc;
4475     
4476     szwFeature = strdupAtoW(szFeature);
4477
4478     rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction);
4479
4480     HeapFree( GetProcessHeap(), 0 , szwFeature);
4481
4482     return rc;
4483 }
4484
4485 UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature,
4486                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
4487 {
4488     INT index;
4489
4490     index = get_loaded_feature(package,szFeature);
4491     if (index < 0)
4492         return ERROR_UNKNOWN_FEATURE;
4493
4494     if (piInstalled)
4495         *piInstalled = package->features[index].State;
4496
4497     if (piAction)
4498     {
4499         if (package->features[index].Enabled)
4500             *piAction = INSTALLSTATE_LOCAL;
4501         else
4502             *piAction = INSTALLSTATE_UNKNOWN;
4503     }
4504
4505     return ERROR_SUCCESS;
4506 }
4507
4508 UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPWSTR szFeature,
4509                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
4510 {
4511     MSIPACKAGE* package;
4512     UINT ret;
4513
4514     TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled,
4515 piAction);
4516
4517     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4518     if (!package)
4519         return ERROR_INVALID_HANDLE;
4520     ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction);
4521     msiobj_release( &package->hdr );
4522     return ret;
4523 }
4524
4525 UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPSTR szComponent,
4526                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
4527 {
4528     LPWSTR szwComponent= NULL;
4529     UINT rc;
4530     
4531     szwComponent= strdupAtoW(szComponent);
4532
4533     rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);
4534
4535     HeapFree( GetProcessHeap(), 0 , szwComponent);
4536
4537     return rc;
4538 }
4539
4540 UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPWSTR szComponent,
4541                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
4542 {
4543     INT index;
4544
4545     TRACE("%p %s %p %p\n", package, debugstr_w(szComponent), piInstalled,
4546 piAction);
4547
4548     index = get_loaded_component(package,szComponent);
4549     if (index < 0)
4550         return ERROR_UNKNOWN_COMPONENT;
4551
4552     if (piInstalled)
4553         *piInstalled = package->components[index].State;
4554
4555     if (piAction)
4556     {
4557         if (package->components[index].Enabled &&
4558             package->components[index].FeatureState)
4559             *piAction = INSTALLSTATE_LOCAL;
4560         else
4561             *piAction = INSTALLSTATE_UNKNOWN;
4562     }
4563
4564     return ERROR_SUCCESS;
4565 }
4566
4567 UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPWSTR szComponent,
4568                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
4569 {
4570     MSIPACKAGE* package;
4571     UINT ret;
4572
4573     TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szComponent),
4574            piInstalled, piAction);
4575
4576     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4577     if (!package)
4578         return ERROR_INVALID_HANDLE;
4579     ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);
4580     msiobj_release( &package->hdr );
4581     return ret;
4582 }
4583
4584 #if 0
4585 static UINT ACTION_Template(MSIPACKAGE *package)
4586 {
4587     UINT rc;
4588     MSIQUERY * view;
4589     MSIRECORD * row = 0;
4590     static const WCHAR ExecSeqQuery[] = {0};
4591
4592     rc = MsiDatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4593     if (rc != ERROR_SUCCESS)
4594         return rc;
4595
4596     rc = MsiViewExecute(view, 0);
4597     if (rc != ERROR_SUCCESS)
4598     {
4599         MsiViewClose(view);
4600         msiobj_release(&view->hdr);
4601         return rc;
4602     }
4603
4604     while (1)
4605     {
4606         rc = MsiViewFetch(view,&row);
4607         if (rc != ERROR_SUCCESS)
4608         {
4609             rc = ERROR_SUCCESS;
4610             break;
4611         }
4612
4613         msiobj_release(&row->hdr);
4614     }
4615     MsiViewClose(view);
4616     msiobj_release(&view->hdr);
4617     return rc;
4618 }
4619 #endif