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