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