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