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