Implement A->W call for GetNamedSecurityInfo.
[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 int 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     DWORD 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     DWORD 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     DWORD 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 int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path)
314 {
315     DWORD i;
316     DWORD 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     DWORD 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 __stdcall 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("Asynchronous 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 Asynchronous 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 ERROR_SUCCESS;
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 UINT load_file(MSIPACKAGE* package, MSIRECORD * row)
1629 {
1630     DWORD index = package->loaded_files;
1631     DWORD 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 ERROR_SUCCESS;
1706    
1707     rc = MSI_ViewExecute(view, 0);
1708     if (rc != ERROR_SUCCESS)
1709     {
1710         MSI_ViewClose(view);
1711         msiobj_release(&view->hdr);
1712         return ERROR_SUCCESS;
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 index = -1;
1749     DWORD i;
1750
1751     TRACE("Looking for dir %s\n",debugstr_w(dir));
1752
1753     for (i = 0; i < package->loaded_folders; i++)
1754     {
1755         if (strcmpW(package->folders[i].Directory,dir)==0)
1756         {
1757             TRACE(" %s retuning on index %lu\n",debugstr_w(dir),i);
1758             return i;
1759         }
1760     }
1761
1762     TRACE("Working to load %s\n",debugstr_w(dir));
1763
1764     index = package->loaded_folders; 
1765
1766     package->loaded_folders++;
1767     if (package->loaded_folders== 1)
1768         package->folders = HeapAlloc(GetProcessHeap(),0,
1769                                         sizeof(MSIFOLDER));
1770     else
1771         package->folders= HeapReAlloc(GetProcessHeap(),0,
1772             package->folders, package->loaded_folders* 
1773             sizeof(MSIFOLDER));
1774
1775     memset(&package->folders[index],0,sizeof(MSIFOLDER));
1776
1777     strcpyW(package->folders[index].Directory,dir);
1778
1779     strcatW(Query,dir);
1780     strcatW(Query,end);
1781
1782     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1783
1784     if (rc != ERROR_SUCCESS)
1785         return -1;
1786
1787     rc = MSI_ViewExecute(view, 0);
1788     if (rc != ERROR_SUCCESS)
1789     {
1790         MSI_ViewClose(view);
1791         msiobj_release(&view->hdr);
1792         return -1;
1793     }
1794
1795     rc = MSI_ViewFetch(view,&row);
1796     if (rc != ERROR_SUCCESS)
1797     {
1798         MSI_ViewClose(view);
1799         msiobj_release(&view->hdr);
1800         return -1;
1801     }
1802
1803     sz=0x100;
1804     MSI_RecordGetStringW(row,3,targetbuffer,&sz);
1805     targetdir=targetbuffer;
1806
1807     /* split src and target dir */
1808     if (strchrW(targetdir,':'))
1809     {
1810         srcdir=strchrW(targetdir,':');
1811         *srcdir=0;
1812         srcdir ++;
1813     }
1814     else
1815         srcdir=NULL;
1816
1817     /* for now only pick long filename versions */
1818     if (strchrW(targetdir,'|'))
1819     {
1820         targetdir = strchrW(targetdir,'|'); 
1821         *targetdir = 0;
1822         targetdir ++;
1823     }
1824     if (srcdir && strchrW(srcdir,'|'))
1825     {
1826         srcdir= strchrW(srcdir,'|'); 
1827         *srcdir= 0;
1828         srcdir ++;
1829     }
1830
1831     /* now check for root dirs */
1832     if (targetdir[0] == '.' && targetdir[1] == 0)
1833         targetdir = NULL;
1834         
1835     if (srcdir && srcdir[0] == '.' && srcdir[1] == 0)
1836         srcdir = NULL;
1837
1838      if (targetdir)
1839         strcpyW(package->folders[index].TargetDefault,targetdir);
1840
1841      if (srcdir)
1842         strcpyW(package->folders[index].SourceDefault,srcdir);
1843      else if (targetdir)
1844         strcpyW(package->folders[index].SourceDefault,targetdir);
1845
1846     if (MSI_RecordIsNull(row,2))
1847         parent[0]=0;
1848     else
1849     {
1850             sz=0x100;
1851             MSI_RecordGetStringW(row,2,parent,&sz);
1852     }
1853
1854     if (parent[0]) 
1855     {
1856         i = load_folder(package,parent);
1857         package->folders[index].ParentIndex = i;
1858         TRACE("Parent is index %i... %s %s\n",
1859                     package->folders[index].ParentIndex,
1860     debugstr_w(package->folders[package->folders[index].ParentIndex].Directory),
1861                     debugstr_w(parent));
1862     }
1863     else
1864         package->folders[index].ParentIndex = -2;
1865
1866     sz = MAX_PATH;
1867     rc = MSI_GetPropertyW(package, dir, package->folders[index].Property, &sz);
1868     if (rc != ERROR_SUCCESS)
1869         package->folders[index].Property[0]=0;
1870
1871     msiobj_release(&row->hdr);
1872     MSI_ViewClose(view);
1873     msiobj_release(&view->hdr);
1874     TRACE(" %s retuning on index %i\n",debugstr_w(dir),index);
1875     return index;
1876 }
1877
1878 static UINT resolve_folder(MSIPACKAGE *package, LPCWSTR name, LPWSTR path, 
1879                            BOOL source, BOOL set_prop, MSIFOLDER **folder)
1880 {
1881     DWORD i;
1882     UINT rc = ERROR_SUCCESS;
1883     DWORD sz;
1884
1885     TRACE("Working to resolve %s\n",debugstr_w(name));
1886
1887     if (!path)
1888         return rc;
1889
1890     /* special resolving for Target and Source root dir */
1891     if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0)
1892     {
1893         if (!source)
1894         {
1895             sz = MAX_PATH;
1896             rc = MSI_GetPropertyW(package,cszTargetDir,path,&sz);
1897             if (rc != ERROR_SUCCESS)
1898             {
1899                 sz = MAX_PATH;
1900                 rc = MSI_GetPropertyW(package,cszRootDrive,path,&sz);
1901                 if (set_prop)
1902                     MSI_SetPropertyW(package,cszTargetDir,path);
1903             }
1904             if (folder)
1905                 *folder = &(package->folders[0]);
1906             return rc;
1907         }
1908         else
1909         {
1910             sz = MAX_PATH;
1911             rc = MSI_GetPropertyW(package,cszSourceDir,path,&sz);
1912             if (rc != ERROR_SUCCESS)
1913             {
1914                 sz = MAX_PATH;
1915                 rc = MSI_GetPropertyW(package,cszDatabase,path,&sz);
1916                 if (rc == ERROR_SUCCESS)
1917                 {
1918                     LPWSTR ptr = strrchrW(path,'\\');
1919                     if (ptr)
1920                     {
1921                         ptr++;
1922                         *ptr = 0;
1923                     }
1924                 }
1925             }
1926             if (folder)
1927                 *folder = &(package->folders[0]);
1928             return rc;
1929         }
1930     }
1931
1932     for (i = 0; i < package->loaded_folders; i++)
1933     {
1934         if (strcmpW(package->folders[i].Directory,name)==0)
1935             break;
1936     }
1937
1938     if (i >= package->loaded_folders)
1939         return ERROR_FUNCTION_FAILED;
1940
1941     if (folder)
1942         *folder = &(package->folders[i]);
1943
1944     if (!source && package->folders[i].ResolvedTarget[0])
1945     {
1946         strcpyW(path,package->folders[i].ResolvedTarget);
1947         TRACE("   already resolved to %s\n",debugstr_w(path));
1948         return ERROR_SUCCESS;
1949     }
1950     else if (source && package->folders[i].ResolvedSource[0])
1951     {
1952         strcpyW(path,package->folders[i].ResolvedSource);
1953         return ERROR_SUCCESS;
1954     }
1955     else if (!source && package->folders[i].Property[0])
1956     {
1957         strcpyW(path,package->folders[i].Property);
1958         TRACE("   internally set to %s\n",debugstr_w(path));
1959         if (set_prop)
1960             MSI_SetPropertyW(package,name,path);
1961         return ERROR_SUCCESS;
1962     }
1963
1964     if (package->folders[i].ParentIndex >= 0)
1965     {
1966         TRACE(" ! Parent is %s\n", debugstr_w(package->folders[
1967                    package->folders[i].ParentIndex].Directory));
1968         resolve_folder(package, package->folders[
1969                        package->folders[i].ParentIndex].Directory, path,source,
1970                        set_prop, NULL);
1971
1972         if (!source)
1973         {
1974             if (package->folders[i].TargetDefault[0])
1975             {
1976                 strcatW(path,package->folders[i].TargetDefault);
1977                 strcatW(path,cszbs);
1978             }
1979             strcpyW(package->folders[i].ResolvedTarget,path);
1980             TRACE("   resolved into %s\n",debugstr_w(path));
1981             if (set_prop)
1982                 MSI_SetPropertyW(package,name,path);
1983         }
1984         else 
1985         {
1986             if (package->folders[i].SourceDefault[0])
1987             {
1988                 strcatW(path,package->folders[i].SourceDefault);
1989                 strcatW(path,cszbs);
1990             }
1991             strcpyW(package->folders[i].ResolvedSource,path);
1992         }
1993     }
1994     return rc;
1995 }
1996
1997 /* 
1998  * Alot is done in this function aside from just the costing.
1999  * The costing needs to be implemented at some point but for now I am going
2000  * to focus on the directory building
2001  *
2002  */
2003 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2004 {
2005     static const WCHAR ExecSeqQuery[] = {
2006         's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2007         'D','i','r','e','c','t','o','r','y',0};
2008     static const WCHAR ConditionQuery[] = {
2009         's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2010         'C','o','n','d','i','t','i','o','n',0};
2011     static const WCHAR szCosting[] = {
2012        'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2013     static const WCHAR szOne[] = { '1', 0 };
2014     UINT rc;
2015     MSIQUERY * view;
2016     DWORD i;
2017
2018     TRACE("Building Directory properties\n");
2019
2020     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2021     if (rc == ERROR_SUCCESS)
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
2060     TRACE("File calculations %i files\n",package->loaded_files);
2061
2062     for (i = 0; i < package->loaded_files; i++)
2063     {
2064         MSICOMPONENT* comp = NULL;
2065         MSIFILE* file= NULL;
2066
2067         file = &package->files[i];
2068         if (file->ComponentIndex >= 0)
2069             comp = &package->components[file->ComponentIndex];
2070
2071         if (comp)
2072         {
2073             /* calculate target */
2074             resolve_folder(package, comp->Directory, file->TargetPath, FALSE,
2075                        FALSE, NULL);
2076             strcatW(file->TargetPath,file->FileName);
2077
2078             TRACE("file %s resolves to %s\n",
2079                    debugstr_w(file->File),debugstr_w(file->TargetPath));       
2080  
2081             if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2082             {
2083                 file->State = 1;
2084                 comp->Cost += file->FileSize;
2085             }
2086             else
2087             {
2088                 if (file->Version[0])
2089                 {
2090                     DWORD handle;
2091                     DWORD versize;
2092                     UINT sz;
2093                     LPVOID version;
2094                     WCHAR filever[0x100];
2095                     static const WCHAR name[] =
2096                         {'\\','V','a','r','F','i','l','e','I','n','f','o',
2097                          '\\','F','i','l','e','V','e','r','s','i','o','n',0};
2098
2099                     FIXME("Version comparison.. Untried Untested and most "
2100                           "likely very very wrong\n");
2101                     versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
2102                     version = HeapAlloc(GetProcessHeap(),0,versize);
2103                     GetFileVersionInfoW(file->TargetPath, 0, versize, version);
2104                     sz = 0x100;
2105                     VerQueryValueW(version,name,(LPVOID)filever,&sz);
2106                     HeapFree(GetProcessHeap(),0,version);
2107                 
2108                     if (strcmpW(version,file->Version)<0)
2109                     {
2110                         file->State = 2;
2111                         FIXME("cost should be diff in size\n");
2112                         comp->Cost += file->FileSize;
2113                     }
2114                     else
2115                         file->State = 3;
2116                 }
2117                 else
2118                     file->State = 3;
2119             }
2120         } 
2121     }
2122
2123     TRACE("Evaluating Condition Table\n");
2124
2125     rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2126     if (rc == ERROR_SUCCESS)
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) == 
2163                     MSICONDITION_TRUE)
2164             {
2165                 int level = MSI_RecordGetInteger(row,2);
2166                     TRACE("Reseting feature %s to level %i\n",
2167                            debugstr_w(Feature), level);
2168                 package->features[feature_index].Level = level;
2169             }
2170             HeapFree(GetProcessHeap(),0,Condition);
2171         }
2172
2173         msiobj_release(&row->hdr);
2174     }
2175     MSI_ViewClose(view);
2176     msiobj_release(&view->hdr);
2177     }
2178
2179     TRACE("Enabling or Disabling Components\n");
2180     for (i = 0; i < package->loaded_components; i++)
2181     {
2182         if (package->components[i].Condition[0])
2183         {
2184             if (MSI_EvaluateConditionW(package,
2185                 package->components[i].Condition) == MSICONDITION_FALSE)
2186             {
2187                 TRACE("Disabling component %s\n",
2188                       debugstr_w(package->components[i].Component));
2189                 package->components[i].Enabled = FALSE;
2190             }
2191         }
2192     }
2193
2194     MSI_SetPropertyW(package,szCosting,szOne);
2195     return ERROR_SUCCESS;
2196 }
2197
2198 /*
2199  * This is a helper function for handling embedded cabinet media
2200  */
2201 static UINT writeout_cabinet_stream(MSIPACKAGE *package, WCHAR* stream_name,
2202                                     WCHAR* source)
2203 {
2204     UINT rc;
2205     USHORT* data;
2206     UINT    size;
2207     DWORD   write;
2208     HANDLE  the_file;
2209     WCHAR tmp[MAX_PATH];
2210
2211     rc = read_raw_stream_data(package->db,stream_name,&data,&size); 
2212     if (rc != ERROR_SUCCESS)
2213         return rc;
2214
2215     write = MAX_PATH;
2216     if (MSI_GetPropertyW(package, cszTempFolder, tmp, &write))
2217         GetTempPathW(MAX_PATH,tmp);
2218
2219     GetTempFileNameW(tmp,stream_name,0,source);
2220
2221     track_tempfile(package,strrchrW(source,'\\'), source);
2222     the_file = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2223                            FILE_ATTRIBUTE_NORMAL, NULL);
2224
2225     if (the_file == INVALID_HANDLE_VALUE)
2226     {
2227         rc = ERROR_FUNCTION_FAILED;
2228         goto end;
2229     }
2230
2231     WriteFile(the_file,data,size,&write,NULL);
2232     CloseHandle(the_file);
2233     TRACE("wrote %li bytes to %s\n",write,debugstr_w(source));
2234 end:
2235     HeapFree(GetProcessHeap(),0,data);
2236     return rc;
2237 }
2238
2239
2240 /***********************************************************************
2241  *            extract_cabinet_file
2242  *
2243  * Extract  files from a cab file.
2244  */
2245 static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
2246
2247 static BOOL extract_cabinet_file_advpack( const WCHAR *cabinet, 
2248                                           const WCHAR *root)
2249 {
2250     static HMODULE advpack;
2251
2252     char *cab_path, *cab_file;
2253
2254     if (!pExtractFiles)
2255     {
2256         if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
2257         {
2258             ERR( "could not load advpack.dll\n" );
2259             return FALSE;
2260         }
2261         if (!(pExtractFiles = (void *)GetProcAddress( advpack, "ExtractFiles"
2262 )))
2263         {
2264             ERR( "could not find ExtractFiles in advpack.dll\n" );
2265             return FALSE;
2266         }
2267     }
2268
2269     if (!(cab_file = strdupWtoA( cabinet ))) return FALSE;
2270     if (!(cab_path = strdupWtoA( root ))) return FALSE;
2271
2272     FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file) );
2273     pExtractFiles( cab_file, cab_path, 0, 0, 0, 0 );
2274     HeapFree( GetProcessHeap(), 0, cab_file );
2275     HeapFree( GetProcessHeap(), 0, cab_path );
2276     return TRUE;
2277 }
2278
2279 static BOOL extract_cabinet_file_cabinet( const WCHAR *cabinet, 
2280                                           const WCHAR *root)
2281                                   
2282 {
2283     /* from cabinet.h */
2284
2285     struct ExtractFileList {
2286         LPSTR  filename;
2287         struct ExtractFileList *next;
2288         BOOL   unknown;  /* always 1L */
2289     } ;
2290
2291     typedef struct {
2292         long  result1;          /* 0x000 */
2293         long  unknown1[3];      /* 0x004 */
2294         struct ExtractFileList* filelist;         /* 0x010 */
2295         long  filecount;        /* 0x014 */
2296         long  unknown2;         /* 0x018 */
2297         char  directory[0x104]; /* 0x01c */
2298         char  lastfile[0x20c];  /* 0x120 */
2299     } EXTRACTdest;
2300
2301     HRESULT WINAPI Extract(EXTRACTdest *dest, LPCSTR what);
2302
2303     char *cab_path, *src_path;
2304     EXTRACTdest exd;
2305     struct ExtractFileList fl;
2306
2307     if (!(cab_path = strdupWtoA( cabinet ))) return FALSE;
2308     if (!(src_path = strdupWtoA( root ))) return FALSE;
2309
2310     memset(&exd,0,sizeof(exd));
2311     strcpy(exd.directory,src_path);
2312     exd.unknown2 = 0x1;
2313     fl.filename = cab_path;
2314     fl.next = NULL;
2315     fl.unknown = 1;
2316     exd.filelist = &fl;
2317     FIXME( "more aweful hack: extracting cabinet %s\n", debugstr_a(cab_path) );
2318     Extract(&exd,cab_path);
2319
2320     HeapFree( GetProcessHeap(), 0, cab_path );
2321     HeapFree( GetProcessHeap(), 0, src_path );
2322     return TRUE;
2323 }
2324
2325 static BOOL extract_cabinet_file(const WCHAR* source, const WCHAR* path)
2326 {
2327     TRACE("Extracting %s to %s\n",debugstr_w(source), debugstr_w(path));
2328     if (!extract_cabinet_file_advpack(source,path))
2329         return extract_cabinet_file_cabinet(source,path);
2330     return TRUE;
2331 }
2332
2333 static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence, 
2334                                  WCHAR* path)
2335 {
2336     UINT rc;
2337     MSIQUERY * view;
2338     MSIRECORD * row = 0;
2339     WCHAR source[MAX_PATH];
2340     static const WCHAR ExecSeqQuery[] = {
2341         's','e','l','e','c','t',' ','*',' ',
2342         'f','r','o','m',' ','M','e','d','i','a',' ',
2343         'w','h','e','r','e',' ','L','a','s','t','S','e','q','u','e','n','c','e',' ','>','=',' ','%','i',' ',
2344         'o','r','d','e','r',' ','b','y',' ','L','a','s','t','S','e','q','u','e','n','c','e',0};
2345     WCHAR Query[1024];
2346     WCHAR cab[0x100];
2347     DWORD sz=0x100;
2348     INT seq;
2349     static UINT last_sequence = 0; 
2350
2351     if (sequence <= last_sequence)
2352     {
2353         TRACE("Media already ready (%u, %u)\n",sequence,last_sequence);
2354         return ERROR_SUCCESS;
2355     }
2356
2357     sprintfW(Query,ExecSeqQuery,sequence);
2358
2359     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2360     if (rc != ERROR_SUCCESS)
2361         return rc;
2362
2363     rc = MSI_ViewExecute(view, 0);
2364     if (rc != ERROR_SUCCESS)
2365     {
2366         MSI_ViewClose(view);
2367         msiobj_release(&view->hdr);
2368         return rc;
2369     }
2370
2371     rc = MSI_ViewFetch(view,&row);
2372     if (rc != ERROR_SUCCESS)
2373     {
2374         MSI_ViewClose(view);
2375         msiobj_release(&view->hdr);
2376         return rc;
2377     }
2378     seq = MSI_RecordGetInteger(row,2);
2379     last_sequence = seq;
2380
2381     if (!MSI_RecordIsNull(row,4))
2382     {
2383         sz=0x100;
2384         MSI_RecordGetStringW(row,4,cab,&sz);
2385         TRACE("Source is CAB %s\n",debugstr_w(cab));
2386         /* the stream does not contain the # character */
2387         if (cab[0]=='#')
2388         {
2389             writeout_cabinet_stream(package,&cab[1],source);
2390             strcpyW(path,source);
2391             *(strrchrW(path,'\\')+1)=0;
2392         }
2393         else
2394         {
2395             sz = MAX_PATH;
2396             if (MSI_GetPropertyW(package, cszSourceDir, source, &sz))
2397             {
2398                 ERR("No Source dir defined \n");
2399                 rc = ERROR_FUNCTION_FAILED;
2400             }
2401             else
2402             {
2403                 strcpyW(path,source);
2404                 strcatW(source,cab);
2405                 /* extract the cab file into a folder in the temp folder */
2406                 sz = MAX_PATH;
2407                 if (MSI_GetPropertyW(package, cszTempFolder,path, &sz) 
2408                                     != ERROR_SUCCESS)
2409                     GetTempPathW(MAX_PATH,path);
2410             }
2411         }
2412         rc = !extract_cabinet_file(source,path);
2413     }
2414     msiobj_release(&row->hdr);
2415     MSI_ViewClose(view);
2416     msiobj_release(&view->hdr);
2417     return rc;
2418 }
2419
2420 inline static UINT create_component_directory ( MSIPACKAGE* package, INT component)
2421 {
2422     UINT rc;
2423     MSIFOLDER *folder;
2424     WCHAR install_path[MAX_PATH];
2425
2426     rc = resolve_folder(package, package->components[component].Directory,
2427                         install_path, FALSE, FALSE, &folder);
2428
2429     if (rc != ERROR_SUCCESS)
2430         return rc; 
2431
2432     /* create the path */
2433     if (folder->State == 0)
2434     {
2435         create_full_pathW(install_path);
2436         folder->State = 2;
2437     }
2438
2439     return rc;
2440 }
2441
2442 static UINT ACTION_InstallFiles(MSIPACKAGE *package)
2443 {
2444     UINT rc = ERROR_SUCCESS;
2445     DWORD index;
2446     MSIRECORD * uirow;
2447     WCHAR uipath[MAX_PATH];
2448
2449     if (!package)
2450         return ERROR_INVALID_HANDLE;
2451
2452     /* increment progress bar each time action data is sent */
2453     ui_progress(package,1,1,1,0);
2454
2455     for (index = 0; index < package->loaded_files; index++)
2456     {
2457         WCHAR path_to_source[MAX_PATH];
2458         MSIFILE *file;
2459         
2460         file = &package->files[index];
2461
2462         if (file->Temporary)
2463             continue;
2464
2465         if (!package->components[file->ComponentIndex].Enabled ||
2466             !package->components[file->ComponentIndex].FeatureState)
2467         {
2468             TRACE("File %s is not scheduled for install\n",
2469                    debugstr_w(file->File));
2470             continue;
2471         }
2472
2473         if ((file->State == 1) || (file->State == 2))
2474         {
2475             TRACE("Installing %s\n",debugstr_w(file->File));
2476             rc = ready_media_for_file(package,file->Sequence,path_to_source);
2477             /* 
2478              * WARNING!
2479              * our file table could change here because a new temp file
2480              * may have been created
2481              */
2482             file = &package->files[index];
2483             if (rc != ERROR_SUCCESS)
2484             {
2485                 ERR("Unable to ready media\n");
2486                 rc = ERROR_FUNCTION_FAILED;
2487                 break;
2488             }
2489
2490             create_component_directory( package, file->ComponentIndex);
2491
2492             strcpyW(file->SourcePath, path_to_source);
2493             strcatW(file->SourcePath, file->File);
2494
2495             TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
2496                   debugstr_w(file->TargetPath));
2497
2498             /* the UI chunk */
2499             uirow=MSI_CreateRecord(9);
2500             MSI_RecordSetStringW(uirow,1,file->File);
2501             strcpyW(uipath,file->TargetPath);
2502             *(strrchrW(uipath,'\\')+1)=0;
2503             MSI_RecordSetStringW(uirow,9,uipath);
2504             MSI_RecordSetInteger(uirow,6,file->FileSize);
2505             ui_actiondata(package,szInstallFiles,uirow);
2506             msiobj_release( &uirow->hdr );
2507
2508             rc = !MoveFileW(file->SourcePath,file->TargetPath);
2509             ui_progress(package,2,0,0,0);
2510
2511             if (rc)
2512             {
2513                 ERR("Unable to move file (error %li)\n",GetLastError());
2514                 rc = ERROR_SUCCESS;
2515             }
2516             else
2517                 file->State = 4;
2518         }
2519     }
2520
2521     return rc;
2522 }
2523
2524 inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key, 
2525                                    LPWSTR file_source)
2526 {
2527     DWORD index;
2528
2529     if (!package)
2530         return ERROR_INVALID_HANDLE;
2531
2532     for (index = 0; index < package->loaded_files; index ++)
2533     {
2534         if (strcmpW(file_key,package->files[index].File)==0)
2535         {
2536             if (package->files[index].State >= 3)
2537             {
2538                 strcpyW(file_source,package->files[index].TargetPath);
2539                 return ERROR_SUCCESS;
2540             }
2541             else
2542                 return ERROR_FILE_NOT_FOUND;
2543         }
2544     }
2545
2546     return ERROR_FUNCTION_FAILED;
2547 }
2548
2549 static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
2550 {
2551     UINT rc;
2552     MSIQUERY * view;
2553     MSIRECORD * row = 0;
2554     static const WCHAR ExecSeqQuery[] = {
2555         's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2556         'D','u','p','l','i','c','a','t','e','F','i','l','e',0};
2557
2558     if (!package)
2559         return ERROR_INVALID_HANDLE;
2560
2561     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2562     if (rc != ERROR_SUCCESS)
2563         return ERROR_SUCCESS;
2564
2565     rc = MSI_ViewExecute(view, 0);
2566     if (rc != ERROR_SUCCESS)
2567     {
2568         MSI_ViewClose(view);
2569         msiobj_release(&view->hdr);
2570         return rc;
2571     }
2572
2573     while (1)
2574     {
2575         WCHAR file_key[0x100];
2576         WCHAR file_source[MAX_PATH];
2577         WCHAR dest_name[0x100];
2578         WCHAR dest_path[MAX_PATH];
2579         WCHAR component[0x100];
2580         INT component_index;
2581
2582         DWORD sz=0x100;
2583
2584         rc = MSI_ViewFetch(view,&row);
2585         if (rc != ERROR_SUCCESS)
2586         {
2587             rc = ERROR_SUCCESS;
2588             break;
2589         }
2590
2591         sz=0x100;
2592         rc = MSI_RecordGetStringW(row,2,component,&sz);
2593         if (rc != ERROR_SUCCESS)
2594         {
2595             ERR("Unable to get component\n");
2596             msiobj_release(&row->hdr);
2597             break;
2598         }
2599
2600         component_index = get_loaded_component(package,component);
2601         if (!package->components[component_index].Enabled ||
2602             !package->components[component_index].FeatureState)
2603         {
2604             TRACE("Skipping copy due to disabled component\n");
2605             msiobj_release(&row->hdr);
2606             continue;
2607         }
2608
2609         sz=0x100;
2610         rc = MSI_RecordGetStringW(row,3,file_key,&sz);
2611         if (rc != ERROR_SUCCESS)
2612         {
2613             ERR("Unable to get file key\n");
2614             msiobj_release(&row->hdr);
2615             break;
2616         }
2617
2618         rc = get_file_target(package,file_key,file_source);
2619
2620         if (rc != ERROR_SUCCESS)
2621         {
2622             ERR("Original file unknown %s\n",debugstr_w(file_key));
2623             msiobj_release(&row->hdr);
2624             break;
2625         }
2626
2627         if (MSI_RecordIsNull(row,4))
2628         {
2629             strcpyW(dest_name,strrchrW(file_source,'\\')+1);
2630         }
2631         else
2632         {
2633             sz=0x100;
2634             MSI_RecordGetStringW(row,4,dest_name,&sz);
2635             reduce_to_longfilename(dest_name);
2636          }
2637
2638         if (MSI_RecordIsNull(row,5))
2639         {
2640             strcpyW(dest_path,file_source);
2641             *strrchrW(dest_path,'\\')=0;
2642         }
2643         else
2644         {
2645             WCHAR destkey[0x100];
2646             sz=0x100;
2647             MSI_RecordGetStringW(row,5,destkey,&sz);
2648             sz = 0x100;
2649             rc = resolve_folder(package, destkey, dest_path,FALSE,FALSE,NULL);
2650             if (rc != ERROR_SUCCESS)
2651             {
2652                 ERR("Unable to get destination folder\n");
2653                 msiobj_release(&row->hdr);
2654                 break;
2655             }
2656         }
2657
2658         strcatW(dest_path,dest_name);
2659            
2660         TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),
2661               debugstr_w(dest_path)); 
2662         
2663         if (strcmpW(file_source,dest_path))
2664             rc = !CopyFileW(file_source,dest_path,TRUE);
2665         else
2666             rc = ERROR_SUCCESS;
2667         
2668         if (rc != ERROR_SUCCESS)
2669             ERR("Failed to copy file\n");
2670
2671         FIXME("We should track these duplicate files as well\n");   
2672  
2673         msiobj_release(&row->hdr);
2674     }
2675     MSI_ViewClose(view);
2676     msiobj_release(&view->hdr);
2677     return rc;
2678
2679 }
2680
2681
2682 /* OK this value is "interpretted" and then formatted based on the 
2683    first few characters */
2684 static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type, 
2685                          DWORD *size)
2686 {
2687     LPSTR data = NULL;
2688     if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2689     {
2690         if (value[1]=='x')
2691         {
2692             LPWSTR ptr;
2693             CHAR byte[5];
2694             LPWSTR deformated;
2695             int count;
2696
2697             deformat_string(package, &value[2], &deformated);
2698
2699             /* binary value type */
2700             ptr = deformated; 
2701             *type=REG_BINARY;
2702             *size = strlenW(ptr)/2;
2703             data = HeapAlloc(GetProcessHeap(),0,*size);
2704           
2705             byte[0] = '0'; 
2706             byte[1] = 'x'; 
2707             byte[4] = 0; 
2708             count = 0;
2709             while (*ptr)
2710             {
2711                 byte[2]= *ptr;
2712                 ptr++;
2713                 byte[3]= *ptr;
2714                 ptr++;
2715                 data[count] = (BYTE)strtol(byte,NULL,0);
2716                 count ++;
2717             }
2718             HeapFree(GetProcessHeap(),0,deformated);
2719
2720             TRACE("Data %li bytes(%i)\n",*size,count);
2721         }
2722         else
2723         {
2724             LPWSTR deformated;
2725             deformat_string(package, &value[1], &deformated);
2726
2727             *type=REG_DWORD; 
2728             *size = sizeof(DWORD);
2729             data = HeapAlloc(GetProcessHeap(),0,*size);
2730             *(LPDWORD)data = atoiW(deformated); 
2731             TRACE("DWORD %i\n",*data);
2732
2733             HeapFree(GetProcessHeap(),0,deformated);
2734         }
2735     }
2736     else
2737     {
2738         WCHAR *ptr;
2739         *type=REG_SZ;
2740
2741         if (value[0]=='#')
2742         {
2743             if (value[1]=='%')
2744             {
2745                 ptr = &value[2];
2746                 *type=REG_EXPAND_SZ;
2747             }
2748             else
2749                 ptr = &value[1];
2750          }
2751          else
2752             ptr=value;
2753
2754         *size = deformat_string(package, ptr,(LPWSTR*)&data);
2755     }
2756     return data;
2757 }
2758
2759 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2760 {
2761     UINT rc;
2762     MSIQUERY * view;
2763     MSIRECORD * row = 0;
2764     static const WCHAR ExecSeqQuery[] = {
2765         's','e','l','e','c','t',' ','*',' ',
2766         'f','r','o','m',' ','R','e','g','i','s','t','r','y',0 };
2767
2768     if (!package)
2769         return ERROR_INVALID_HANDLE;
2770
2771     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2772     if (rc != ERROR_SUCCESS)
2773         return ERROR_SUCCESS;
2774
2775     rc = MSI_ViewExecute(view, 0);
2776     if (rc != ERROR_SUCCESS)
2777     {
2778         MSI_ViewClose(view);
2779         msiobj_release(&view->hdr);
2780         return rc;
2781     }
2782
2783     /* increment progress bar each time action data is sent */
2784     ui_progress(package,1,1,1,0);
2785
2786     while (1)
2787     {
2788         static const WCHAR szHCR[] = 
2789 {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T','\\',0};
2790         static const WCHAR szHCU[] =
2791 {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R','\\',0};
2792         static const WCHAR szHLM[] =
2793 {'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',
2794 '\\',0};
2795         static const WCHAR szHU[] =
2796 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2797
2798         WCHAR key[0x100];
2799         WCHAR name[0x100];
2800         LPWSTR value;
2801         LPSTR value_data = NULL;
2802         HKEY  root_key, hkey;
2803         DWORD type,size;
2804         WCHAR component[0x100];
2805         INT component_index;
2806         MSIRECORD * uirow;
2807         WCHAR uikey[0x110];
2808
2809         INT   root;
2810         DWORD sz=0x100;
2811
2812         rc = MSI_ViewFetch(view,&row);
2813         if (rc != ERROR_SUCCESS)
2814         {
2815             rc = ERROR_SUCCESS;
2816             break;
2817         }
2818
2819         sz= 0x100;
2820         MSI_RecordGetStringW(row,6,component,&sz);
2821         component_index = get_loaded_component(package,component);
2822
2823         if (!package->components[component_index].Enabled ||
2824             !package->components[component_index].FeatureState)
2825         {
2826             TRACE("Skipping write due to disabled component\n");
2827             msiobj_release(&row->hdr);
2828             continue;
2829         }
2830
2831         /* null values have special meanings during uninstalls and such */
2832         
2833         if(MSI_RecordIsNull(row,5))
2834         {
2835             msiobj_release(&row->hdr);
2836             continue;
2837         }
2838
2839         root = MSI_RecordGetInteger(row,2);
2840         sz = 0x100;
2841         MSI_RecordGetStringW(row,3,key,&sz);
2842       
2843         sz = 0x100; 
2844         if (MSI_RecordIsNull(row,4))
2845             name[0]=0;
2846         else
2847             MSI_RecordGetStringW(row,4,name,&sz);
2848    
2849         /* get the root key */
2850         switch (root)
2851         {
2852             case 0:  root_key = HKEY_CLASSES_ROOT; 
2853                      strcpyW(uikey,szHCR); break;
2854             case 1:  root_key = HKEY_CURRENT_USER;
2855                      strcpyW(uikey,szHCU); break;
2856             case 2:  root_key = HKEY_LOCAL_MACHINE;
2857                      strcpyW(uikey,szHLM); break;
2858             case 3:  root_key = HKEY_USERS; 
2859                      strcpyW(uikey,szHU); break;
2860             default:
2861                  ERR("Unknown root %i\n",root);
2862                  root_key=NULL;
2863                  break;
2864         }
2865         if (!root_key)
2866         {
2867             msiobj_release(&row->hdr);
2868             continue;
2869         }
2870
2871         strcatW(uikey,key);
2872         if (RegCreateKeyW( root_key, key, &hkey))
2873         {
2874             ERR("Could not create key %s\n",debugstr_w(key));
2875             msiobj_release(&row->hdr);
2876             continue;
2877         }
2878
2879         value = load_dynamic_stringW(row,5);
2880         value_data = parse_value(package, value, &type, &size); 
2881
2882         if (value_data)
2883         {
2884             TRACE("Setting value %s\n",debugstr_w(name));
2885             RegSetValueExW(hkey, name, 0, type, value_data, size);
2886
2887             uirow = MSI_CreateRecord(3);
2888             MSI_RecordSetStringW(uirow,2,name);
2889             MSI_RecordSetStringW(uirow,1,uikey);
2890
2891             if (type == REG_SZ)
2892                 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2893             else
2894                 MSI_RecordSetStringW(uirow,3,value);
2895
2896             ui_actiondata(package,szWriteRegistryValues,uirow);
2897             ui_progress(package,2,0,0,0);
2898             msiobj_release( &uirow->hdr );
2899
2900             HeapFree(GetProcessHeap(),0,value_data);
2901         }
2902         HeapFree(GetProcessHeap(),0,value);
2903
2904         msiobj_release(&row->hdr);
2905         RegCloseKey(hkey);
2906     }
2907     MSI_ViewClose(view);
2908     msiobj_release(&view->hdr);
2909     return rc;
2910 }
2911
2912 /*
2913  * This helper function should probably go alot of places
2914  *
2915  * Thinking about this, maybe this should become yet another Bison file
2916  */
2917 static DWORD deformat_string(MSIPACKAGE *package, WCHAR* ptr,WCHAR** data)
2918 {
2919     WCHAR* mark=NULL;
2920     DWORD size=0;
2921     DWORD chunk=0;
2922     WCHAR key[0x100];
2923     LPWSTR value;
2924     DWORD sz;
2925     UINT rc;
2926
2927     /* scan for special characters */
2928     if (!strchrW(ptr,'[') || (strchrW(ptr,'[') && !strchrW(ptr,']')))
2929     {
2930         /* not formatted */
2931         size = (strlenW(ptr)+1) * sizeof(WCHAR);
2932         *data = HeapAlloc(GetProcessHeap(),0,size);
2933         strcpyW(*data,ptr);
2934         return size;
2935     }
2936    
2937     /* formatted string located */ 
2938     mark = strchrW(ptr,'[');
2939     if (mark != ptr)
2940     {
2941         INT cnt = (mark - ptr);
2942         TRACE("%i  (%i) characters before marker\n",cnt,(mark-ptr));
2943         size = cnt * sizeof(WCHAR);
2944         size += sizeof(WCHAR);
2945         *data = HeapAlloc(GetProcessHeap(),0,size);
2946         strncpyW(*data,ptr,cnt);
2947         (*data)[cnt]=0;
2948     }
2949     else
2950     {
2951         size = sizeof(WCHAR);
2952         *data = HeapAlloc(GetProcessHeap(),0,size);
2953         (*data)[0]=0;
2954     }
2955     mark++;
2956     strcpyW(key,mark);
2957     *strchrW(key,']')=0;
2958     mark = strchrW(mark,']');
2959     mark++;
2960     TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
2961     sz = 0;
2962     rc = MSI_GetPropertyW(package, key, NULL, &sz);
2963     if ((rc == ERROR_SUCCESS) || (rc == ERROR_MORE_DATA))
2964     {
2965         LPWSTR newdata;
2966
2967         sz++;
2968         value = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR));
2969         MSI_GetPropertyW(package, key, value, &sz);
2970
2971         chunk = (strlenW(value)+1) * sizeof(WCHAR);
2972         size+=chunk;   
2973         newdata = HeapReAlloc(GetProcessHeap(),0,*data,size);
2974         *data = newdata;
2975         strcatW(*data,value);
2976     }
2977     TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
2978     if (*mark!=0)
2979     {
2980         LPWSTR newdata;
2981         chunk = (strlenW(mark)+1) * sizeof(WCHAR);
2982         size+=chunk;
2983         newdata = HeapReAlloc(GetProcessHeap(),0,*data,size);
2984         *data = newdata;
2985         strcatW(*data,mark);
2986     }
2987     (*data)[strlenW(*data)]=0;
2988     TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
2989
2990     /* recursively do this to clean up */
2991     mark = HeapAlloc(GetProcessHeap(),0,size);
2992     strcpyW(mark,*data);
2993     TRACE("String at this point %s\n",debugstr_w(mark));
2994     size = deformat_string(package,mark,data);
2995     HeapFree(GetProcessHeap(),0,mark);
2996     return size;
2997 }
2998
2999 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3000 {
3001     WCHAR level[10000];
3002     INT install_level;
3003     DWORD sz;
3004     DWORD i;
3005     INT j;
3006     DWORD rc;
3007     LPWSTR override = NULL;
3008     static const WCHAR addlocal[]={'A','D','D','L','O','C','A','L',0};
3009     static const WCHAR all[]={'A','L','L',0};
3010     static const WCHAR szlevel[] = {
3011         'I','N','S','T','A','L','L','L','E','V','E','L',0};
3012     static const WCHAR szAddLocal[] = {
3013         'A','D','D','L','O','C','A','L',0};
3014
3015     /* I do not know if this is where it should happen.. but */
3016
3017     TRACE("Checking Install Level\n");
3018
3019     sz = 10000;
3020     if (MSI_GetPropertyW(package,szlevel,level,&sz)==ERROR_SUCCESS)
3021         install_level = atoiW(level);
3022     else
3023         install_level = 1;
3024
3025     sz = 0;
3026     rc = MSI_GetPropertyW(package,szAddLocal,NULL,&sz);
3027     if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
3028     {
3029         sz++;
3030         override = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
3031         MSI_GetPropertyW(package, addlocal,override,&sz);
3032     }
3033    
3034     /*
3035      * Components FeatureState defaults to FALSE. The idea is we want to 
3036      * enable the component is ANY feature that uses it is enabled to install
3037      */
3038     for(i = 0; i < package->loaded_features; i++)
3039     {
3040         BOOL feature_state= ((package->features[i].Level > 0) &&
3041                              (package->features[i].Level <= install_level));
3042
3043         if (override && (strcmpiW(override,all)==0 || 
3044                          strstrW(override,package->features[i].Feature)))
3045         {
3046             TRACE("Override of install level found\n");
3047             feature_state = TRUE;
3048             package->features[i].Enabled = feature_state;
3049         }
3050
3051         TRACE("Feature %s has a state of %i\n",
3052                debugstr_w(package->features[i].Feature), feature_state);
3053         for( j = 0; j < package->features[i].ComponentCount; j++)
3054         {
3055             package->components[package->features[i].Components[j]].FeatureState
3056             |= feature_state;
3057         }
3058     } 
3059     if (override != NULL)
3060         HeapFree(GetProcessHeap(),0,override);
3061     /* 
3062      * So basically we ONLY want to install a component if its Enabled AND
3063      * FeatureState are both TRUE 
3064      */
3065     return ERROR_SUCCESS;
3066 }
3067
3068 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3069 {
3070     DWORD progress = 0;
3071     static const WCHAR q1[]={
3072         'S','E','L','E','C','T',' ','*',' ',
3073         'F','R','O','M',' ','R','e','g','i','s','t','r','y',0};
3074     UINT rc;
3075     MSIQUERY * view;
3076     MSIRECORD * row = 0;
3077
3078     TRACE(" InstallValidate \n");
3079
3080     rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
3081     if (rc != ERROR_SUCCESS)
3082         return ERROR_SUCCESS;
3083
3084     rc = MSI_ViewExecute(view, 0);
3085     if (rc != ERROR_SUCCESS)
3086     {
3087         MSI_ViewClose(view);
3088         msiobj_release(&view->hdr);
3089         return rc;
3090     }
3091     while (1)
3092     {
3093         rc = MSI_ViewFetch(view,&row);
3094         if (rc != ERROR_SUCCESS)
3095         {
3096             rc = ERROR_SUCCESS;
3097             break;
3098         }
3099         progress +=1;
3100
3101         msiobj_release(&row->hdr);
3102     }
3103     MSI_ViewClose(view);
3104     msiobj_release(&view->hdr);
3105
3106     ui_progress(package,0,progress+package->loaded_files,0,0);
3107
3108     return ERROR_SUCCESS;
3109 }
3110
3111 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3112 {
3113     UINT rc;
3114     MSIQUERY * view = NULL;
3115     MSIRECORD * row = 0;
3116     static const WCHAR ExecSeqQuery[] = {
3117         'S','E','L','E','C','T',' ','*',' ',
3118         'f','r','o','m',' ','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n',0};
3119     static const WCHAR title[]=
3120             {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3121
3122     TRACE("Checking launch conditions\n");
3123
3124     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3125     if (rc != ERROR_SUCCESS)
3126         return ERROR_SUCCESS;
3127
3128     rc = MSI_ViewExecute(view, 0);
3129     if (rc != ERROR_SUCCESS)
3130     {
3131         MSI_ViewClose(view);
3132         msiobj_release(&view->hdr);
3133         return rc;
3134     }
3135
3136     rc = ERROR_SUCCESS;
3137     while (rc == ERROR_SUCCESS)
3138     {
3139         LPWSTR cond = NULL; 
3140         LPWSTR message = NULL;
3141
3142         rc = MSI_ViewFetch(view,&row);
3143         if (rc != ERROR_SUCCESS)
3144         {
3145             rc = ERROR_SUCCESS;
3146             break;
3147         }
3148
3149         cond = load_dynamic_stringW(row,1);
3150
3151         if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
3152         {
3153             message = load_dynamic_stringW(row,2);
3154             MessageBoxW(NULL,message,title,MB_OK);
3155             HeapFree(GetProcessHeap(),0,message);
3156             rc = ERROR_FUNCTION_FAILED;
3157         }
3158         HeapFree(GetProcessHeap(),0,cond);
3159         msiobj_release(&row->hdr);
3160     }
3161     MSI_ViewClose(view);
3162     msiobj_release(&view->hdr);
3163     return rc;
3164 }
3165
3166 static void resolve_keypath( MSIPACKAGE* package, INT
3167                             component_index, WCHAR *keypath)
3168 {
3169     MSICOMPONENT* cmp = &package->components[component_index];
3170
3171     if (cmp->KeyPath[0]==0)
3172     {
3173         resolve_folder(package,cmp->Directory,keypath,FALSE,FALSE,NULL);
3174         return;
3175     }
3176     if ((cmp->Attributes & 0x4) || (cmp->Attributes & 0x20))
3177     {
3178         FIXME("UNIMPLEMENTED keypath as Registry or ODBC Source\n");
3179         keypath[0]=0;
3180     }
3181     else
3182     {
3183         int j;
3184         j = get_loaded_file(package,cmp->KeyPath);
3185
3186         if (j>=0)
3187             strcpyW(keypath,package->files[j].TargetPath);
3188     }
3189 }
3190
3191 /*
3192  * Ok further analysis makes me think that this work is
3193  * actually done in the PublishComponents and PublishFeatures
3194  * step, and not here.  It appears like the keypath and all that is
3195  * resolved in this step, however actually written in the Publish steps.
3196  * But we will leave it here for now because it is unclear
3197  */
3198 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3199 {
3200     WCHAR productcode[0x100];
3201     WCHAR squished_pc[0x100];
3202     WCHAR squished_cc[0x100];
3203     DWORD sz;
3204     UINT rc;
3205     DWORD i;
3206     HKEY hkey=0,hkey2=0,hkey3=0;
3207     static const WCHAR szProductCode[]=
3208 {'P','r','o','d','u','c','t','C','o','d','e',0};
3209     static const WCHAR szInstaller[] = {
3210 'S','o','f','t','w','a','r','e','\\',
3211 'M','i','c','r','o','s','o','f','t','\\',
3212 'W','i','n','d','o','w','s','\\',
3213 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3214 'I','n','s','t','a','l','l','e','r',0 };
3215     static const WCHAR szFeatures[] = {
3216 'F','e','a','t','u','r','e','s',0 };
3217     static const WCHAR szComponents[] = {
3218 'C','o','m','p','o','n','e','n','t','s',0 };
3219
3220     if (!package)
3221         return ERROR_INVALID_HANDLE;
3222
3223     /* writes the Component and Features values to the registry */
3224     sz = 0x100;
3225     rc = MSI_GetPropertyW(package,szProductCode,productcode,&sz);
3226     if (rc != ERROR_SUCCESS)
3227         return ERROR_SUCCESS;
3228
3229     squash_guid(productcode,squished_pc);
3230     rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,szInstaller,&hkey);
3231     if (rc != ERROR_SUCCESS)
3232         goto end;
3233
3234     rc = RegCreateKeyW(hkey,szFeatures,&hkey2);
3235     if (rc != ERROR_SUCCESS)
3236         goto end;
3237
3238     rc = RegCreateKeyW(hkey2,squished_pc,&hkey3);
3239     if (rc != ERROR_SUCCESS)
3240         goto end;
3241
3242     /* here the guids are base 85 encoded */
3243     for (i = 0; i < package->loaded_features; i++)
3244     {
3245         LPWSTR data = NULL;
3246         GUID clsid;
3247         int j;
3248         INT size;
3249
3250         size = package->features[i].ComponentCount*21*sizeof(WCHAR);
3251         data = HeapAlloc(GetProcessHeap(), 0, size);
3252
3253         data[0] = 0;
3254         for (j = 0; j < package->features[i].ComponentCount; j++)
3255         {
3256             WCHAR buf[21];
3257             TRACE("From %s\n",debugstr_w(package->components
3258                             [package->features[i].Components[j]].ComponentId));
3259             CLSIDFromString(package->components
3260                             [package->features[i].Components[j]].ComponentId,
3261                             &clsid);
3262             encode_base85_guid(&clsid,buf);
3263             TRACE("to %s\n",debugstr_w(buf));
3264             strcatW(data,buf);
3265         }
3266
3267         size = strlenW(data)*sizeof(WCHAR);
3268         RegSetValueExW(hkey3,package->features[i].Feature,0,REG_SZ,
3269                        (LPSTR)data,size);
3270         HeapFree(GetProcessHeap(),0,data);
3271     }
3272
3273     RegCloseKey(hkey3);
3274     RegCloseKey(hkey2);
3275
3276     rc = RegCreateKeyW(hkey,szComponents,&hkey2);
3277     if (rc != ERROR_SUCCESS)
3278         goto end;
3279   
3280     for (i = 0; i < package->loaded_components; i++)
3281     {
3282         if (package->components[i].ComponentId[0]!=0)
3283         {
3284             WCHAR keypath[0x1000];
3285             MSIRECORD * uirow;
3286
3287             squash_guid(package->components[i].ComponentId,squished_cc);
3288             rc = RegCreateKeyW(hkey2,squished_cc,&hkey3);
3289             if (rc != ERROR_SUCCESS)
3290                 continue;
3291            
3292             resolve_keypath(package,i,keypath);
3293
3294             RegSetValueExW(hkey3,squished_pc,0,REG_SZ,(LPVOID)keypath,
3295                             (strlenW(keypath)+1)*sizeof(WCHAR));
3296             RegCloseKey(hkey3);
3297         
3298             /* UI stuff */
3299             uirow = MSI_CreateRecord(3);
3300             MSI_RecordSetStringW(uirow,1,productcode);
3301             MSI_RecordSetStringW(uirow,2,package->components[i].ComponentId);
3302             MSI_RecordSetStringW(uirow,3,keypath);
3303             ui_actiondata(package,szProcessComponents,uirow);
3304             msiobj_release( &uirow->hdr );
3305         }
3306     } 
3307 end:
3308     RegCloseKey(hkey2);
3309     RegCloseKey(hkey);
3310     return rc;
3311 }
3312
3313 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3314 {
3315     /* 
3316      * OK this is a bit confusing.. I am given a _Component key and I believe
3317      * that the file that is being registered as a type library is the "key file
3318      * of that component" which I interpret to mean "The file in the KeyPath of
3319      * that component".
3320      */
3321     UINT rc;
3322     MSIQUERY * view;
3323     MSIRECORD * row = 0;
3324     static const WCHAR Query[] = {
3325         'S','E','L','E','C','T',' ','*',' ',
3326         'f','r','o','m',' ','T','y','p','e','L','i','b',0};
3327     ITypeLib *ptLib;
3328     HRESULT res;
3329
3330     if (!package)
3331         return ERROR_INVALID_HANDLE;
3332
3333     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3334     if (rc != ERROR_SUCCESS)
3335         return ERROR_SUCCESS;
3336
3337     rc = MSI_ViewExecute(view, 0);
3338     if (rc != ERROR_SUCCESS)
3339     {
3340         MSI_ViewClose(view);
3341         msiobj_release(&view->hdr);
3342         return rc;
3343     }
3344
3345     while (1)
3346     {   
3347         WCHAR component[0x100];
3348         DWORD sz;
3349         INT index;
3350
3351         rc = MSI_ViewFetch(view,&row);
3352         if (rc != ERROR_SUCCESS)
3353         {
3354             rc = ERROR_SUCCESS;
3355             break;
3356         }
3357
3358         sz = 0x100;
3359         MSI_RecordGetStringW(row,3,component,&sz);
3360
3361         index = get_loaded_component(package,component);
3362         if (index < 0)
3363         {
3364             msiobj_release(&row->hdr);
3365             continue;
3366         }
3367
3368         if (!package->components[index].Enabled ||
3369             !package->components[index].FeatureState)
3370         {
3371             TRACE("Skipping typelib reg due to disabled component\n");
3372             msiobj_release(&row->hdr);
3373             continue;
3374         }
3375
3376         index = get_loaded_file(package,package->components[index].KeyPath); 
3377    
3378         if (index < 0)
3379         {
3380             msiobj_release(&row->hdr);
3381             continue;
3382         }
3383
3384         res = LoadTypeLib(package->files[index].TargetPath,&ptLib);
3385         if (SUCCEEDED(res))
3386         {
3387             WCHAR help[MAX_PATH];
3388             WCHAR helpid[0x100];
3389
3390             sz = 0x100;
3391             MSI_RecordGetStringW(row,6,helpid,&sz);
3392
3393             resolve_folder(package,helpid,help,FALSE,FALSE,NULL);
3394
3395             res = RegisterTypeLib(ptLib,package->files[index].TargetPath,help);
3396             if (!SUCCEEDED(res))
3397                 ERR("Failed to register type library %s\n",
3398                      debugstr_w(package->files[index].TargetPath));
3399             else
3400             {
3401                 /* Yes the row has more fields than I need, but #1 is 
3402                    correct and the only one I need. Why make a new row? */
3403
3404                 ui_actiondata(package,szRegisterTypeLibraries,row);
3405                 
3406                 TRACE("Registered %s\n",
3407                        debugstr_w(package->files[index].TargetPath));
3408             }
3409
3410             if (ptLib)
3411                 ITypeLib_Release(ptLib);
3412         }
3413         else
3414             ERR("Failed to load type library %s\n",
3415                 debugstr_w(package->files[index].TargetPath));
3416         
3417         msiobj_release(&row->hdr);
3418     }
3419     MSI_ViewClose(view);
3420     msiobj_release(&view->hdr);
3421     return rc;
3422    
3423 }
3424
3425 static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app )
3426 {
3427     static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
3428     UINT rc;
3429     MSIQUERY * view;
3430     MSIRECORD * row = 0;
3431     static const WCHAR ExecSeqQuery[] = 
3432 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','p','p','I'
3433 ,'d',' ','w','h','e','r','e',' ','A','p','p','I','d','=','`','%','s','`',0};
3434     WCHAR Query[0x1000];
3435     HKEY hkey2,hkey3;
3436     LPWSTR buffer=0;
3437
3438     if (!package)
3439         return ERROR_INVALID_HANDLE;
3440
3441     sprintfW(Query,ExecSeqQuery,clsid);
3442
3443     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3444     if (rc != ERROR_SUCCESS)
3445         return rc;
3446
3447     rc = MSI_ViewExecute(view, 0);
3448     if (rc != ERROR_SUCCESS)
3449     {
3450         MSI_ViewClose(view);
3451         msiobj_release(&view->hdr);
3452         return rc;
3453     }
3454
3455     RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
3456     RegCreateKeyW(hkey2,clsid,&hkey3);
3457     RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app,
3458                    (strlenW(app)+1)*sizeof(WCHAR));
3459
3460     rc = MSI_ViewFetch(view,&row);
3461     if (rc != ERROR_SUCCESS)
3462     {
3463         MSI_ViewClose(view);
3464         msiobj_release(&view->hdr);
3465         return rc;
3466     }
3467
3468     if (!MSI_RecordIsNull(row,2)) 
3469     {
3470         LPWSTR deformated=0;
3471         UINT size; 
3472         static const WCHAR szRemoteServerName[] =
3473 {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0};
3474         buffer = load_dynamic_stringW(row,2);
3475         size = deformat_string(package,buffer,&deformated);
3476         RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,(LPVOID)deformated,
3477                        size);
3478         HeapFree(GetProcessHeap(),0,deformated);
3479         HeapFree(GetProcessHeap(),0,buffer);
3480     }
3481
3482     if (!MSI_RecordIsNull(row,3)) 
3483     {
3484         static const WCHAR szLocalService[] =
3485 {'L','o','c','a','l','S','e','r','v','i','c','e',0};
3486         UINT size;
3487         buffer = load_dynamic_stringW(row,3);
3488         size = (strlenW(buffer)+1) * sizeof(WCHAR);
3489         RegSetValueExW(hkey3,szLocalService,0,REG_SZ,(LPVOID)buffer,size);
3490         HeapFree(GetProcessHeap(),0,buffer);
3491     }
3492
3493     if (!MSI_RecordIsNull(row,4)) 
3494     {
3495         static const WCHAR szService[] =
3496 {'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0};
3497         UINT size;
3498         buffer = load_dynamic_stringW(row,4);
3499         size = (strlenW(buffer)+1) * sizeof(WCHAR);
3500         RegSetValueExW(hkey3,szService,0,REG_SZ,(LPVOID)buffer,size);
3501         HeapFree(GetProcessHeap(),0,buffer);
3502     }
3503
3504     if (!MSI_RecordIsNull(row,5)) 
3505     {
3506         static const WCHAR szDLL[] =
3507 {'D','l','l','S','u','r','r','o','g','a','t','e',0};
3508         UINT size;
3509         buffer = load_dynamic_stringW(row,5);
3510         size = (strlenW(buffer)+1) * sizeof(WCHAR);
3511         RegSetValueExW(hkey3,szDLL,0,REG_SZ,(LPVOID)buffer,size);
3512         HeapFree(GetProcessHeap(),0,buffer);
3513     }
3514
3515     if (!MSI_RecordIsNull(row,6)) 
3516     {
3517         static const WCHAR szActivate[] =
3518 {'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0};
3519         static const WCHAR szY[] = {'Y',0};
3520
3521         if (MSI_RecordGetInteger(row,6))
3522             RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4);
3523     }
3524
3525     if (!MSI_RecordIsNull(row,7)) 
3526     {
3527         static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
3528         static const WCHAR szUser[] = 
3529 {'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0};
3530
3531         if (MSI_RecordGetInteger(row,7))
3532             RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,34);
3533     }
3534
3535     msiobj_release(&row->hdr);
3536     MSI_ViewClose(view);
3537     msiobj_release(&view->hdr);
3538     RegCloseKey(hkey3);
3539     RegCloseKey(hkey2);
3540     return rc;
3541 }
3542
3543 static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
3544 {
3545     /* 
3546      * Again I am assuming the words, "Whose key file represents" when referring
3547      * to a Component as to meaning that Components KeyPath file
3548      *
3549      * Also there is a very strong connection between ClassInfo and ProgID
3550      * that I am mostly glossing over.  
3551      * What would be more propper is to load the ClassInfo and the ProgID info
3552      * into memory data structures and then be able to enable and disable them
3553      * based on component. 
3554      */
3555     
3556     UINT rc;
3557     MSIQUERY * view;
3558     MSIRECORD * row = 0;
3559     static const WCHAR ExecSeqQuery[] = {
3560         'S','E','L','E','C','T',' ','*',' ',
3561         'f','r','o','m',' ','C','l','a','s','s',0};
3562     static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
3563     static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 };
3564     static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
3565     HKEY hkey,hkey2,hkey3;
3566
3567     if (!package)
3568         return ERROR_INVALID_HANDLE;
3569
3570     rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
3571     if (rc != ERROR_SUCCESS)
3572         return ERROR_FUNCTION_FAILED;
3573
3574     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3575     if (rc != ERROR_SUCCESS)
3576     {
3577         rc = ERROR_SUCCESS;
3578         goto end;
3579     }
3580
3581     rc = MSI_ViewExecute(view, 0);
3582     if (rc != ERROR_SUCCESS)
3583     {
3584         MSI_ViewClose(view);
3585         msiobj_release(&view->hdr);
3586         goto end;
3587     }
3588
3589     while (1)
3590     {
3591         WCHAR clsid[0x100];
3592         WCHAR buffer[0x100];
3593         WCHAR desc[0x100];
3594         DWORD sz;
3595         INT index;
3596      
3597         rc = MSI_ViewFetch(view,&row);
3598         if (rc != ERROR_SUCCESS)
3599         {
3600             rc = ERROR_SUCCESS;
3601             break;
3602         }
3603
3604         sz=0x100;
3605         MSI_RecordGetStringW(row,3,buffer,&sz);
3606
3607         index = get_loaded_component(package,buffer);
3608
3609         if (index < 0)
3610         {
3611             msiobj_release(&row->hdr);
3612             continue;
3613         }
3614
3615         if (!package->components[index].Enabled ||
3616             !package->components[index].FeatureState)
3617         {
3618             TRACE("Skipping class reg due to disabled component\n");
3619             msiobj_release(&row->hdr);
3620             continue;
3621         }
3622
3623         sz=0x100;
3624         MSI_RecordGetStringW(row,1,clsid,&sz);
3625         RegCreateKeyW(hkey,clsid,&hkey2);
3626
3627         if (!MSI_RecordIsNull(row,5))
3628         {
3629             sz=0x100;
3630             MSI_RecordGetStringW(row,5,desc,&sz);
3631
3632             RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)desc,
3633                            (strlenW(desc)+1)*sizeof(WCHAR));
3634         }
3635         else
3636             desc[0]=0;
3637
3638         sz=0x100;
3639         MSI_RecordGetStringW(row,2,buffer,&sz);
3640
3641         RegCreateKeyW(hkey2,buffer,&hkey3);
3642
3643         index = get_loaded_file(package,package->components[index].KeyPath);
3644         RegSetValueExW(hkey3,NULL,0,REG_SZ,
3645                        (LPVOID)package->files[index].TargetPath,
3646                        (strlenW(package->files[index].TargetPath)+1)
3647                         *sizeof(WCHAR));
3648
3649         RegCloseKey(hkey3);
3650
3651         if (!MSI_RecordIsNull(row,4))
3652         {
3653             sz=0x100;
3654             MSI_RecordGetStringW(row,4,buffer,&sz);
3655
3656             RegCreateKeyW(hkey2,szProgID,&hkey3);
3657     
3658             RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)buffer,
3659                        (strlenW(buffer)+1)*sizeof(WCHAR));
3660
3661             RegCloseKey(hkey3);
3662         }
3663
3664         if (!MSI_RecordIsNull(row,6))
3665         { 
3666             sz=0x100;
3667             MSI_RecordGetStringW(row,6,buffer,&sz);
3668
3669             RegSetValueExW(hkey2,szAppID,0,REG_SZ,(LPVOID)buffer,
3670                        (strlenW(buffer)+1)*sizeof(WCHAR));
3671
3672             register_appid(package,buffer,desc);
3673         }
3674
3675         RegCloseKey(hkey2);
3676
3677         FIXME("Process the rest of the fields >7\n");
3678
3679         ui_actiondata(package,szRegisterClassInfo,row);
3680
3681         msiobj_release(&row->hdr);
3682     }
3683     MSI_ViewClose(view);
3684     msiobj_release(&view->hdr);
3685
3686 end:
3687     RegCloseKey(hkey);
3688     return rc;
3689 }
3690
3691 static UINT register_progid_base(MSIRECORD * row, LPWSTR clsid)
3692 {
3693     static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
3694     HKEY hkey,hkey2;
3695     WCHAR buffer[0x100];
3696     DWORD sz;
3697
3698
3699     sz = 0x100;
3700     MSI_RecordGetStringW(row,1,buffer,&sz);
3701     RegCreateKeyW(HKEY_CLASSES_ROOT,buffer,&hkey);
3702
3703     if (!MSI_RecordIsNull(row,4))
3704     {
3705         sz = 0x100;
3706         MSI_RecordGetStringW(row,4,buffer,&sz);
3707         RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
3708                        sizeof(WCHAR));
3709     }
3710
3711     if (!MSI_RecordIsNull(row,3))
3712     {   
3713         sz = 0x100;
3714     
3715         MSI_RecordGetStringW(row,3,buffer,&sz);
3716         RegCreateKeyW(hkey,szCLSID,&hkey2);
3717         RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
3718                        sizeof(WCHAR));
3719
3720         if (clsid)
3721             strcpyW(clsid,buffer);
3722
3723         RegCloseKey(hkey2);
3724     }
3725     else
3726     {
3727         FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
3728         return ERROR_FUNCTION_FAILED;
3729     }
3730     if (!MSI_RecordIsNull(row,5))
3731         FIXME ("UNHANDLED icon in Progid\n");
3732     return ERROR_SUCCESS;
3733 }
3734
3735 static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid);
3736
3737 static UINT register_parent_progid(MSIPACKAGE *package, LPCWSTR parent, 
3738                                    LPWSTR clsid)
3739 {
3740     UINT rc;
3741     MSIQUERY * view;
3742     MSIRECORD * row = 0;
3743     static const WCHAR Query_t[] = 
3744 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','r','o','g'
3745 ,'I','d',' ','w','h','e','r','e',' ','P','r','o','g','I','d',' ','=',' ','`'
3746 ,'%','s','`',0};
3747     WCHAR Query[0x1000];
3748
3749     if (!package)
3750         return ERROR_INVALID_HANDLE;
3751
3752     sprintfW(Query,Query_t,parent);
3753
3754     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3755     if (rc != ERROR_SUCCESS)
3756         return rc;
3757
3758     rc = MSI_ViewExecute(view, 0);
3759     if (rc != ERROR_SUCCESS)
3760     {
3761         MSI_ViewClose(view);
3762         msiobj_release(&view->hdr);
3763         return rc;
3764     }
3765
3766     rc = MSI_ViewFetch(view,&row);
3767     if (rc != ERROR_SUCCESS)
3768     {
3769         MSI_ViewClose(view);
3770         msiobj_release(&view->hdr);
3771         return rc;
3772     }
3773
3774     register_progid(package,row,clsid);
3775
3776     msiobj_release(&row->hdr);
3777     MSI_ViewClose(view);
3778     msiobj_release(&view->hdr);
3779     return rc;
3780 }
3781
3782 static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid)
3783 {
3784     UINT rc = ERROR_SUCCESS; 
3785
3786     if (MSI_RecordIsNull(row,2))
3787         rc = register_progid_base(row,clsid);
3788     else
3789     {
3790         WCHAR buffer[0x1000];
3791         DWORD sz;
3792         HKEY hkey,hkey2;
3793         static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
3794
3795         sz = 0x100;
3796         MSI_RecordGetStringW(row,2,buffer,&sz);
3797         rc = register_parent_progid(package,buffer,clsid);
3798
3799         sz = 0x100;
3800         MSI_RecordGetStringW(row,1,buffer,&sz);
3801         RegCreateKeyW(HKEY_CLASSES_ROOT,buffer,&hkey);
3802         /* clasid is same as parent */
3803         RegCreateKeyW(hkey,szCLSID,&hkey2);
3804         RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) *
3805                        sizeof(WCHAR));
3806
3807         RegCloseKey(hkey2);
3808         if (!MSI_RecordIsNull(row,4))
3809         {
3810             sz = 0x100;
3811             MSI_RecordGetStringW(row,4,buffer,&sz);
3812             RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer,
3813                            (strlenW(buffer)+1) * sizeof(WCHAR));
3814         }
3815
3816         if (!MSI_RecordIsNull(row,5))
3817             FIXME ("UNHANDLED icon in Progid\n");
3818
3819         RegCloseKey(hkey);
3820     }
3821     return rc;
3822 }
3823
3824 static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
3825 {
3826     /* 
3827      * Sigh, here I am just brute force registering all progids
3828      * this needs to be linked to the Classes that have been registered
3829      * but the easiest way to do that is to load all these stuff into
3830      * memory for easy checking.
3831      *
3832      * Gives me something to continue to work toward.
3833      */
3834     UINT rc;
3835     MSIQUERY * view;
3836     MSIRECORD * row = 0;
3837     static const WCHAR Query[] = {
3838         'S','E','L','E','C','T',' ','*',' ',
3839         'F','R','O','M',' ','P','r','o','g','I','d',0};
3840
3841     if (!package)
3842         return ERROR_INVALID_HANDLE;
3843
3844     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3845     if (rc != ERROR_SUCCESS)
3846         return ERROR_SUCCESS;
3847
3848     rc = MSI_ViewExecute(view, 0);
3849     if (rc != ERROR_SUCCESS)
3850     {
3851         MSI_ViewClose(view);
3852         msiobj_release(&view->hdr);
3853         return rc;
3854     }
3855
3856     while (1)
3857     {
3858         WCHAR clsid[0x1000];
3859
3860         rc = MSI_ViewFetch(view,&row);
3861         if (rc != ERROR_SUCCESS)
3862         {
3863             rc = ERROR_SUCCESS;
3864             break;
3865         }
3866         
3867         register_progid(package,row,clsid);
3868         ui_actiondata(package,szRegisterProgIdInfo,row);
3869
3870         msiobj_release(&row->hdr);
3871     }
3872     MSI_ViewClose(view);
3873     msiobj_release(&view->hdr);
3874     return rc;
3875 }
3876
3877 static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, 
3878                             LPWSTR FilePath)
3879 {
3880     WCHAR ProductCode[0x100];
3881     WCHAR SystemFolder[MAX_PATH];
3882     DWORD sz;
3883
3884     static const WCHAR szInstaller[] = 
3885 {'I','n','s','t','a','l','l','e','r','\\',0};
3886     static const WCHAR szProductCode[] =
3887 {'P','r','o','d','u','c','t','C','o','d','e',0};
3888     static const WCHAR szFolder[] =
3889 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3890
3891     sz = 0x100;
3892     MSI_GetPropertyW(package,szProductCode,ProductCode,&sz);
3893     if (strlenW(ProductCode)==0)
3894         return ERROR_FUNCTION_FAILED;
3895
3896     sz = MAX_PATH;
3897     MSI_GetPropertyW(package,szFolder,SystemFolder,&sz);
3898     strcatW(SystemFolder,szInstaller); 
3899     strcatW(SystemFolder,ProductCode);
3900     create_full_pathW(SystemFolder);
3901
3902     strcpyW(FilePath,SystemFolder);
3903     strcatW(FilePath,cszbs);
3904     strcatW(FilePath,icon_name);
3905     return ERROR_SUCCESS;
3906 }
3907
3908 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3909 {
3910     UINT rc;
3911     MSIQUERY * view;
3912     MSIRECORD * row = 0;
3913     static const WCHAR Query[] = {
3914        'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ',
3915        'S','h','o','r','t','c','u','t',0};
3916     IShellLinkW *sl;
3917     IPersistFile *pf;
3918     HRESULT res;
3919
3920     if (!package)
3921         return ERROR_INVALID_HANDLE;
3922
3923     res = CoInitialize( NULL );
3924     if (FAILED (res))
3925     {
3926         ERR("CoInitialize failed\n");
3927         return ERROR_FUNCTION_FAILED;
3928     }
3929
3930     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3931     if (rc != ERROR_SUCCESS)
3932         return ERROR_SUCCESS;
3933
3934     rc = MSI_ViewExecute(view, 0);
3935     if (rc != ERROR_SUCCESS)
3936     {
3937         MSI_ViewClose(view);
3938         msiobj_release(&view->hdr);
3939         return rc;
3940     }
3941
3942     while (1)
3943     {
3944         WCHAR target_file[MAX_PATH];
3945         WCHAR buffer[0x100];
3946         DWORD sz;
3947         DWORD index;
3948         static const WCHAR szlnk[]={'.','l','n','k',0};
3949
3950         rc = MSI_ViewFetch(view,&row);
3951         if (rc != ERROR_SUCCESS)
3952         {
3953             rc = ERROR_SUCCESS;
3954             break;
3955         }
3956         
3957         sz = 0x100;
3958         MSI_RecordGetStringW(row,4,buffer,&sz);
3959
3960         index = get_loaded_component(package,buffer);
3961
3962         if (index < 0)
3963         {
3964             msiobj_release(&row->hdr);
3965             continue;
3966         }
3967
3968         if (!package->components[index].Enabled ||
3969             !package->components[index].FeatureState)
3970         {
3971             TRACE("Skipping shortcut creation due to disabled component\n");
3972             msiobj_release(&row->hdr);
3973             continue;
3974         }
3975
3976         ui_actiondata(package,szCreateShortcuts,row);
3977
3978         res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3979                               &IID_IShellLinkW, (LPVOID *) &sl );
3980
3981         if (FAILED(res))
3982         {
3983             ERR("Is IID_IShellLink\n");
3984             msiobj_release(&row->hdr);
3985             continue;
3986         }
3987
3988         res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3989         if( FAILED( res ) )
3990         {
3991             ERR("Is IID_IPersistFile\n");
3992             msiobj_release(&row->hdr);
3993             continue;
3994         }
3995
3996         sz = 0x100;
3997         MSI_RecordGetStringW(row,2,buffer,&sz);
3998         resolve_folder(package, buffer,target_file,FALSE,FALSE,NULL);
3999
4000         sz = 0x100;
4001         MSI_RecordGetStringW(row,3,buffer,&sz);
4002         reduce_to_longfilename(buffer);
4003         strcatW(target_file,buffer);
4004         if (!strchrW(target_file,'.'))
4005             strcatW(target_file,szlnk);
4006
4007         sz = 0x100;
4008         MSI_RecordGetStringW(row,5,buffer,&sz);
4009         if (strchrW(buffer,'['))
4010         {
4011             LPWSTR deformated;
4012             deformat_string(package,buffer,&deformated);
4013             IShellLinkW_SetPath(sl,deformated);
4014             HeapFree(GetProcessHeap(),0,deformated);
4015         }
4016         else
4017         {
4018             FIXME("UNHANDLED shortcut format, advertised shortcut\n");
4019             IPersistFile_Release( pf );
4020             IShellLinkW_Release( sl );
4021             msiobj_release(&row->hdr);
4022             continue;
4023         }
4024
4025         if (!MSI_RecordIsNull(row,6))
4026         {
4027             LPWSTR deformated;
4028             sz = 0x100;
4029             MSI_RecordGetStringW(row,6,buffer,&sz);
4030             deformat_string(package,buffer,&deformated);
4031             IShellLinkW_SetArguments(sl,deformated);
4032             HeapFree(GetProcessHeap(),0,deformated);
4033         }
4034
4035         if (!MSI_RecordIsNull(row,7))
4036         {
4037             LPWSTR deformated;
4038             deformated = load_dynamic_stringW(row,7);
4039             IShellLinkW_SetDescription(sl,deformated);
4040             HeapFree(GetProcessHeap(),0,deformated);
4041         }
4042
4043         if (!MSI_RecordIsNull(row,8))
4044             IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
4045
4046         if (!MSI_RecordIsNull(row,9))
4047         {
4048             WCHAR Path[MAX_PATH];
4049             INT index; 
4050
4051             sz = 0x100;
4052             MSI_RecordGetStringW(row,9,buffer,&sz);
4053
4054             build_icon_path(package,buffer,Path);
4055             index = MSI_RecordGetInteger(row,10);
4056
4057             IShellLinkW_SetIconLocation(sl,Path,index);
4058         }
4059
4060         if (!MSI_RecordIsNull(row,11))
4061             IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
4062
4063         if (!MSI_RecordIsNull(row,12))
4064         {
4065             WCHAR Path[MAX_PATH];
4066
4067             sz = 0x100;
4068             MSI_RecordGetStringW(row,12,buffer,&sz);
4069             resolve_folder(package, buffer, Path, FALSE, FALSE, NULL);
4070             IShellLinkW_SetWorkingDirectory(sl,Path);
4071         }
4072
4073         TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
4074         IPersistFile_Save(pf,target_file,FALSE);
4075         
4076         IPersistFile_Release( pf );
4077         IShellLinkW_Release( sl );
4078
4079         msiobj_release(&row->hdr);
4080     }
4081     MSI_ViewClose(view);
4082     msiobj_release(&view->hdr);
4083
4084
4085     CoUninitialize();
4086
4087     return rc;
4088 }
4089
4090
4091 /*
4092  * 99% of the work done here is only done for 
4093  * advertised installs. However this is where the
4094  * Icon table is processed and written out
4095  * so that is what I am going to do here.
4096  */
4097 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4098 {
4099     UINT rc;
4100     MSIQUERY * view;
4101     MSIRECORD * row = 0;
4102     static const WCHAR Query[]={
4103         'S','E','L','E','C','T',' ','*',' ',
4104         'f','r','o','m',' ','I','c','o','n',0};
4105     DWORD sz;
4106
4107     if (!package)
4108         return ERROR_INVALID_HANDLE;
4109
4110     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
4111     if (rc != ERROR_SUCCESS)
4112         return ERROR_SUCCESS;
4113
4114     rc = MSI_ViewExecute(view, 0);
4115     if (rc != ERROR_SUCCESS)
4116     {
4117         MSI_ViewClose(view);
4118         msiobj_release(&view->hdr);
4119         return rc;
4120     }
4121
4122     while (1)
4123     {
4124         HANDLE the_file;
4125         WCHAR FilePath[MAX_PATH];
4126         WCHAR FileName[MAX_PATH];
4127         CHAR buffer[1024];
4128
4129         rc = MSI_ViewFetch(view,&row);
4130         if (rc != ERROR_SUCCESS)
4131         {
4132             rc = ERROR_SUCCESS;
4133             break;
4134         }
4135     
4136         sz = MAX_PATH;
4137         MSI_RecordGetStringW(row,1,FileName,&sz);
4138         if (sz == 0)
4139         {
4140             ERR("Unable to get FileName\n");
4141             msiobj_release(&row->hdr);
4142             continue;
4143         }
4144
4145         build_icon_path(package,FileName,FilePath);
4146
4147         TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
4148         
4149         the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
4150                            FILE_ATTRIBUTE_NORMAL, NULL);
4151
4152         if (the_file == INVALID_HANDLE_VALUE)
4153         {
4154             ERR("Unable to create file %s\n",debugstr_w(FilePath));
4155             msiobj_release(&row->hdr);
4156             continue;
4157         }
4158
4159         do 
4160         {
4161             DWORD write;
4162             sz = 1024;
4163             rc = MSI_RecordReadStream(row,2,buffer,&sz);
4164             if (rc != ERROR_SUCCESS)
4165             {
4166                 ERR("Failed to get stream\n");
4167                 CloseHandle(the_file);  
4168                 DeleteFileW(FilePath);
4169                 break;
4170             }
4171             WriteFile(the_file,buffer,sz,&write,NULL);
4172         } while (sz == 1024);
4173
4174         CloseHandle(the_file);
4175         msiobj_release(&row->hdr);
4176     }
4177     MSI_ViewClose(view);
4178     msiobj_release(&view->hdr);
4179     return rc;
4180
4181 }
4182
4183 /* Msi functions that seem appropriate here */
4184 UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
4185 {
4186     LPWSTR szwAction;
4187     UINT rc;
4188
4189     TRACE(" exteral attempt at action %s\n",szAction);
4190
4191     if (!szAction)
4192         return ERROR_FUNCTION_FAILED;
4193     if (hInstall == 0)
4194         return ERROR_FUNCTION_FAILED;
4195
4196     szwAction = strdupAtoW(szAction);
4197
4198     if (!szwAction)
4199         return ERROR_FUNCTION_FAILED; 
4200
4201
4202     rc = MsiDoActionW(hInstall, szwAction);
4203     HeapFree(GetProcessHeap(),0,szwAction);
4204     return rc;
4205 }
4206
4207 UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction )
4208 {
4209     MSIPACKAGE *package;
4210     UINT ret = ERROR_INVALID_HANDLE;
4211
4212     TRACE(" external attempt at action %s \n",debugstr_w(szAction));
4213
4214     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4215     if( package )
4216     {
4217         ret = ACTION_PerformAction(package,szAction);
4218         msiobj_release( &package->hdr );
4219     }
4220     return ret;
4221 }
4222
4223 UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder, 
4224                                LPSTR szPathBuf, DWORD* pcchPathBuf) 
4225 {
4226     LPWSTR szwFolder;
4227     LPWSTR szwPathBuf;
4228     UINT rc;
4229
4230     TRACE("getting folder %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
4231
4232     if (!szFolder)
4233         return ERROR_FUNCTION_FAILED;
4234     if (hInstall == 0)
4235         return ERROR_FUNCTION_FAILED;
4236
4237     szwFolder = strdupAtoW(szFolder);
4238
4239     if (!szwFolder)
4240         return ERROR_FUNCTION_FAILED; 
4241
4242     szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
4243
4244     rc = MsiGetTargetPathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
4245
4246     WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
4247                          *pcchPathBuf, NULL, NULL );
4248
4249     HeapFree(GetProcessHeap(),0,szwFolder);
4250     HeapFree(GetProcessHeap(),0,szwPathBuf);
4251
4252     return rc;
4253 }
4254
4255 UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
4256                                 szPathBuf, DWORD* pcchPathBuf) 
4257 {
4258     WCHAR path[MAX_PATH];
4259     UINT rc;
4260     MSIPACKAGE *package;
4261
4262     TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
4263
4264     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4265     if( !package )
4266         return ERROR_INVALID_HANDLE;
4267     rc = resolve_folder(package, szFolder, path, FALSE, FALSE, NULL);
4268     msiobj_release( &package->hdr );
4269
4270     if (rc == ERROR_SUCCESS && strlenW(path) > *pcchPathBuf)
4271     {
4272         *pcchPathBuf = strlenW(path)+1;
4273         return ERROR_MORE_DATA;
4274     }
4275     else if (rc == ERROR_SUCCESS)
4276     {
4277         *pcchPathBuf = strlenW(path)+1;
4278         strcpyW(szPathBuf,path);
4279         TRACE("Returning Path %s\n",debugstr_w(path));
4280     }
4281     
4282     return rc;
4283 }
4284
4285
4286 UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder, 
4287                                LPSTR szPathBuf, DWORD* pcchPathBuf) 
4288 {
4289     LPWSTR szwFolder;
4290     LPWSTR szwPathBuf;
4291     UINT rc;
4292
4293     TRACE("getting source %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
4294
4295     if (!szFolder)
4296         return ERROR_FUNCTION_FAILED;
4297     if (hInstall == 0)
4298         return ERROR_FUNCTION_FAILED;
4299
4300     szwFolder = strdupAtoW(szFolder);
4301     if (!szwFolder)
4302         return ERROR_FUNCTION_FAILED; 
4303
4304     szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
4305
4306     rc = MsiGetSourcePathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
4307
4308     WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
4309                          *pcchPathBuf, NULL, NULL );
4310
4311     HeapFree(GetProcessHeap(),0,szwFolder);
4312     HeapFree(GetProcessHeap(),0,szwPathBuf);
4313
4314     return rc;
4315 }
4316
4317 UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
4318                                 szPathBuf, DWORD* pcchPathBuf) 
4319 {
4320     WCHAR path[MAX_PATH];
4321     UINT rc;
4322     MSIPACKAGE *package;
4323
4324     TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
4325
4326     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4327     if( !package )
4328         return ERROR_INVALID_HANDLE;
4329     rc = resolve_folder(package, szFolder, path, TRUE, FALSE, NULL);
4330     msiobj_release( &package->hdr );
4331
4332     if (rc == ERROR_SUCCESS && strlenW(path) > *pcchPathBuf)
4333     {
4334         *pcchPathBuf = strlenW(path)+1;
4335         return ERROR_MORE_DATA;
4336     }
4337     else if (rc == ERROR_SUCCESS)
4338     {
4339         *pcchPathBuf = strlenW(path)+1;
4340         strcpyW(szPathBuf,path);
4341         TRACE("Returning Path %s\n",debugstr_w(path));
4342     }
4343     
4344     return rc;
4345 }
4346
4347
4348 UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder, 
4349                              LPCSTR szFolderPath)
4350 {
4351     LPWSTR szwFolder;
4352     LPWSTR szwFolderPath;
4353     UINT rc;
4354
4355     if (!szFolder)
4356         return ERROR_FUNCTION_FAILED;
4357     if (hInstall == 0)
4358         return ERROR_FUNCTION_FAILED;
4359
4360     szwFolder = strdupAtoW(szFolder);
4361     if (!szwFolder)
4362         return ERROR_FUNCTION_FAILED; 
4363
4364     szwFolderPath = strdupAtoW(szFolderPath);
4365     if (!szwFolderPath)
4366     {
4367         HeapFree(GetProcessHeap(),0,szwFolder);
4368         return ERROR_FUNCTION_FAILED; 
4369     }
4370
4371     rc = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath);
4372
4373     HeapFree(GetProcessHeap(),0,szwFolder);
4374     HeapFree(GetProcessHeap(),0,szwFolderPath);
4375
4376     return rc;
4377 }
4378
4379 UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder, 
4380                              LPCWSTR szFolderPath)
4381 {
4382     DWORD i;
4383     WCHAR path[MAX_PATH];
4384     MSIFOLDER *folder;
4385
4386     TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
4387
4388     if (package==NULL)
4389         return ERROR_INVALID_HANDLE;
4390
4391     if (szFolderPath[0]==0)
4392         return ERROR_FUNCTION_FAILED;
4393
4394     if (GetFileAttributesW(szFolderPath) == INVALID_FILE_ATTRIBUTES)
4395         return ERROR_FUNCTION_FAILED;
4396
4397     resolve_folder(package,szFolder,path,FALSE,FALSE,&folder);
4398
4399     if (!folder)
4400         return ERROR_INVALID_PARAMETER;
4401
4402     strcpyW(folder->Property,szFolderPath);
4403
4404     for (i = 0; i < package->loaded_folders; i++)
4405         package->folders[i].ResolvedTarget[0]=0;
4406
4407     for (i = 0; i < package->loaded_folders; i++)
4408         resolve_folder(package, package->folders[i].Directory, path, FALSE,
4409                        TRUE, NULL);
4410
4411     return ERROR_SUCCESS;
4412 }
4413
4414 UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder, 
4415                              LPCWSTR szFolderPath)
4416 {
4417     MSIPACKAGE *package;
4418     UINT ret;
4419
4420     TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
4421
4422     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4423     ret = MSI_SetTargetPathW( package, szFolder, szFolderPath );
4424     msiobj_release( &package->hdr );
4425     return ret;
4426 }
4427
4428 BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, DWORD iRunMode)
4429 {
4430     FIXME("STUB (%li)\n",iRunMode);
4431     return FALSE;
4432 }
4433
4434 /*
4435  * according to the docs when this is called it immediently recalculates all the
4436  * components states as well
4437  */
4438 UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
4439                                 INSTALLSTATE iState)
4440 {
4441     LPWSTR szwFeature = NULL;
4442     UINT rc;
4443
4444     szwFeature = strdupAtoW(szFeature);
4445
4446     if (!szwFeature)
4447         return ERROR_FUNCTION_FAILED;
4448    
4449     rc = MsiSetFeatureStateW(hInstall,szwFeature, iState); 
4450
4451     HeapFree(GetProcessHeap(),0,szwFeature);
4452
4453     return rc;
4454 }
4455
4456 UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
4457                                 INSTALLSTATE iState)
4458 {
4459     MSIPACKAGE* package;
4460     INT index;
4461
4462     TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
4463
4464     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4465     if (!package)
4466         return ERROR_INVALID_HANDLE;
4467
4468     index = get_loaded_feature(package,szFeature);
4469     if (index < 0)
4470         return ERROR_UNKNOWN_FEATURE;
4471
4472     package->features[index].State = iState;
4473
4474     return ERROR_SUCCESS;
4475 }
4476
4477 UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPSTR szFeature,
4478                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
4479 {
4480     LPWSTR szwFeature = NULL;
4481     UINT rc;
4482     
4483     szwFeature = strdupAtoW(szFeature);
4484
4485     rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction);
4486
4487     HeapFree( GetProcessHeap(), 0 , szwFeature);
4488
4489     return rc;
4490 }
4491
4492 UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature,
4493                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
4494 {
4495     INT index;
4496
4497     index = get_loaded_feature(package,szFeature);
4498     if (index < 0)
4499         return ERROR_UNKNOWN_FEATURE;
4500
4501     if (piInstalled)
4502         *piInstalled = package->features[index].State;
4503
4504     if (piAction)
4505     {
4506         if (package->features[index].Enabled)
4507             *piAction = INSTALLSTATE_LOCAL;
4508         else
4509             *piAction = INSTALLSTATE_UNKNOWN;
4510     }
4511
4512     return ERROR_SUCCESS;
4513 }
4514
4515 UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPWSTR szFeature,
4516                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
4517 {
4518     MSIPACKAGE* package;
4519     UINT ret;
4520
4521     TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled,
4522 piAction);
4523
4524     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4525     if (!package)
4526         return ERROR_INVALID_HANDLE;
4527     ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction);
4528     msiobj_release( &package->hdr );
4529     return ret;
4530 }
4531
4532 UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPSTR szComponent,
4533                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
4534 {
4535     LPWSTR szwComponent= NULL;
4536     UINT rc;
4537     
4538     szwComponent= strdupAtoW(szComponent);
4539
4540     rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);
4541
4542     HeapFree( GetProcessHeap(), 0 , szwComponent);
4543
4544     return rc;
4545 }
4546
4547 UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPWSTR szComponent,
4548                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
4549 {
4550     INT index;
4551
4552     TRACE("%p %s %p %p\n", package, debugstr_w(szComponent), piInstalled,
4553 piAction);
4554
4555     index = get_loaded_component(package,szComponent);
4556     if (index < 0)
4557         return ERROR_UNKNOWN_COMPONENT;
4558
4559     if (piInstalled)
4560         *piInstalled = package->components[index].State;
4561
4562     if (piAction)
4563     {
4564         if (package->components[index].Enabled &&
4565             package->components[index].FeatureState)
4566             *piAction = INSTALLSTATE_LOCAL;
4567         else
4568             *piAction = INSTALLSTATE_UNKNOWN;
4569     }
4570
4571     return ERROR_SUCCESS;
4572 }
4573
4574 UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPWSTR szComponent,
4575                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
4576 {
4577     MSIPACKAGE* package;
4578     UINT ret;
4579
4580     TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szComponent),
4581            piInstalled, piAction);
4582
4583     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4584     if (!package)
4585         return ERROR_INVALID_HANDLE;
4586     ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);
4587     msiobj_release( &package->hdr );
4588     return ret;
4589 }
4590
4591 #if 0
4592 static UINT ACTION_Template(MSIPACKAGE *package)
4593 {
4594     UINT rc;
4595     MSIQUERY * view;
4596     MSIRECORD * row = 0;
4597     static const WCHAR ExecSeqQuery[] = {0};
4598
4599     rc = MsiDatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4600     if (rc != ERROR_SUCCESS)
4601         return rc;
4602
4603     rc = MsiViewExecute(view, 0);
4604     if (rc != ERROR_SUCCESS)
4605     {
4606         MsiViewClose(view);
4607         msiobj_release(&view->hdr);
4608         return rc;
4609     }
4610
4611     while (1)
4612     {
4613         rc = MsiViewFetch(view,&row);
4614         if (rc != ERROR_SUCCESS)
4615         {
4616             rc = ERROR_SUCCESS;
4617             break;
4618         }
4619
4620         msiobj_release(&row->hdr);
4621     }
4622     MsiViewClose(view);
4623     msiobj_release(&view->hdr);
4624     return rc;
4625 }
4626 #endif