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