- Properly deformat keys written to the registry.
[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 \ seperating 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 DllThread(LPVOID info)
1417 {
1418     HANDLE DLL;
1419     LPSTR proc;
1420     thread_struct *stuff;
1421     CustomEntry *fn;
1422      
1423     stuff = (thread_struct*)info;
1424
1425     TRACE("Asynchronous start (%s, %s) \n", debugstr_w(stuff->source),
1426           debugstr_w(stuff->target));
1427
1428     DLL = LoadLibraryW(stuff->source);
1429     if (DLL)
1430     {
1431         proc = strdupWtoA( stuff->target );
1432         fn = (CustomEntry*)GetProcAddress(DLL,proc);
1433         if (fn)
1434         {
1435             MSIHANDLE hPackage;
1436             MSIPACKAGE *package = stuff->package;
1437
1438             TRACE("Calling function\n");
1439             hPackage = msiobj_findhandle( &package->hdr );
1440             if( !hPackage )
1441                 ERR("Handle for object %p not found\n", package );
1442             fn(hPackage);
1443             msiobj_release( &package->hdr );
1444         }
1445         else
1446             ERR("Cannot load functon\n");
1447
1448         HeapFree(GetProcessHeap(),0,proc);
1449         FreeLibrary(DLL);
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 UINT HANDLE_CustomType1(MSIPACKAGE *package, const LPWSTR source, 
1461                                 const LPWSTR target, const INT type)
1462 {
1463     WCHAR tmp_file[MAX_PATH];
1464     CustomEntry *fn;
1465     HANDLE DLL;
1466     LPSTR proc;
1467
1468     store_binary_to_temp(package, source, tmp_file);
1469
1470     TRACE("Calling function %s from %s\n",debugstr_w(target),
1471           debugstr_w(tmp_file));
1472
1473     if (!strchrW(tmp_file,'.'))
1474     {
1475         static const WCHAR dot[]={'.',0};
1476         strcatW(tmp_file,dot);
1477     } 
1478
1479     if (type & 0xc0)
1480     {
1481         DWORD ThreadId;
1482         HANDLE ThreadHandle;
1483         thread_struct *info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info) );
1484
1485         msiobj_addref( &package->hdr );
1486         info->package = package;
1487         info->target = dupstrW(target);
1488         info->source = dupstrW(tmp_file);
1489         TRACE("Start Asynchronous execution of dll\n");
1490         ThreadHandle = CreateThread(NULL,0,DllThread,(LPVOID)info,0,&ThreadId);
1491         CloseHandle(ThreadHandle);
1492         /* FIXME: release the package if the CreateThread fails */
1493         return ERROR_SUCCESS;
1494     }
1495  
1496     DLL = LoadLibraryW(tmp_file);
1497     if (DLL)
1498     {
1499         proc = strdupWtoA( target );
1500         fn = (CustomEntry*)GetProcAddress(DLL,proc);
1501         if (fn)
1502         {
1503             MSIHANDLE hPackage;
1504
1505             TRACE("Calling function\n");
1506             hPackage = msiobj_findhandle( &package->hdr );
1507             if( !hPackage )
1508                 ERR("Handle for object %p not found\n", package );
1509             fn(hPackage);
1510             msiobj_release( &package->hdr );
1511         }
1512         else
1513             ERR("Cannot load functon\n");
1514
1515         HeapFree(GetProcessHeap(),0,proc);
1516         FreeLibrary(DLL);
1517     }
1518     else
1519         ERR("Unable to load library\n");
1520
1521     return ERROR_SUCCESS;
1522 }
1523
1524 static UINT HANDLE_CustomType2(MSIPACKAGE *package, const LPWSTR source, 
1525                                 const LPWSTR target, const INT type)
1526 {
1527     WCHAR tmp_file[MAX_PATH];
1528     STARTUPINFOW si;
1529     PROCESS_INFORMATION info;
1530     BOOL rc;
1531     INT len;
1532     WCHAR *deformated;
1533     WCHAR *cmd;
1534     static const WCHAR spc[] = {' ',0};
1535
1536     memset(&si,0,sizeof(STARTUPINFOW));
1537
1538     store_binary_to_temp(package, source, tmp_file);
1539
1540     deformat_string(package,target,&deformated);
1541
1542     len = strlenW(tmp_file) + strlenW(deformated) + 2;
1543    
1544     cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*len);
1545
1546     strcpyW(cmd,tmp_file);
1547     strcatW(cmd,spc);
1548     strcatW(cmd,deformated);
1549
1550     HeapFree(GetProcessHeap(),0,deformated);
1551
1552     TRACE("executing exe %s \n",debugstr_w(cmd));
1553
1554     rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
1555                   c_collen, &si, &info);
1556
1557     HeapFree(GetProcessHeap(),0,cmd);
1558
1559     if ( !rc )
1560     {
1561         ERR("Unable to execute command\n");
1562         return ERROR_SUCCESS;
1563     }
1564
1565     if (!(type & 0xc0))
1566         WaitForSingleObject(info.hProcess,INFINITE);
1567
1568     CloseHandle( info.hProcess );
1569     CloseHandle( info.hThread );
1570     return ERROR_SUCCESS;
1571 }
1572
1573 static UINT HANDLE_CustomType18(MSIPACKAGE *package, const LPWSTR source,
1574                                 const LPWSTR target, const INT type)
1575 {
1576     STARTUPINFOW si;
1577     PROCESS_INFORMATION info;
1578     BOOL rc;
1579     WCHAR *deformated;
1580     WCHAR *cmd;
1581     INT len;
1582     static const WCHAR spc[] = {' ',0};
1583     int index;
1584
1585     memset(&si,0,sizeof(STARTUPINFOW));
1586
1587     index = get_loaded_file(package,source);
1588
1589     len = strlenW(package->files[index].TargetPath);
1590
1591     deformat_string(package,target,&deformated);
1592     len += strlenW(deformated);
1593     len += 2;
1594
1595     cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,len * sizeof(WCHAR));
1596
1597     strcpyW(cmd, package->files[index].TargetPath);
1598     strcatW(cmd, spc);
1599     strcatW(cmd, deformated);
1600
1601     HeapFree(GetProcessHeap(),0,deformated);
1602
1603     TRACE("executing exe %s \n",debugstr_w(cmd));
1604
1605     rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
1606                   c_collen, &si, &info);
1607
1608     HeapFree(GetProcessHeap(),0,cmd);
1609     
1610     if ( !rc )
1611     {
1612         ERR("Unable to execute command\n");
1613         return ERROR_SUCCESS;
1614     }
1615
1616     if (!(type & 0xc0))
1617         WaitForSingleObject(info.hProcess,INFINITE);
1618
1619     CloseHandle( info.hProcess );
1620     CloseHandle( info.hThread );
1621     return ERROR_SUCCESS;
1622 }
1623
1624 static UINT HANDLE_CustomType50(MSIPACKAGE *package, const LPWSTR source,
1625                                 const LPWSTR target, const INT type)
1626 {
1627     STARTUPINFOW si;
1628     PROCESS_INFORMATION info;
1629     WCHAR *prop;
1630     BOOL rc;
1631     WCHAR *deformated;
1632     WCHAR *cmd;
1633     INT len;
1634     UINT prc;
1635     static const WCHAR spc[] = {' ',0};
1636
1637     memset(&si,0,sizeof(STARTUPINFOW));
1638     memset(&info,0,sizeof(PROCESS_INFORMATION));
1639
1640     prop = load_dynamic_property(package,source,&prc);
1641     if (!prop)
1642         return prc;
1643
1644     deformat_string(package,target,&deformated);
1645     len = strlenW(prop) + strlenW(deformated) + 2;
1646     cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*len);
1647
1648     strcpyW(cmd,prop);
1649     strcatW(cmd,spc);
1650     strcatW(cmd,deformated);
1651
1652     HeapFree(GetProcessHeap(),0,deformated);
1653
1654     TRACE("executing exe %s \n",debugstr_w(cmd));
1655
1656     rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
1657                   c_collen, &si, &info);
1658
1659     HeapFree(GetProcessHeap(),0,cmd);
1660     
1661     if ( !rc )
1662     {
1663         ERR("Unable to execute command\n");
1664         return ERROR_SUCCESS;
1665     }
1666
1667     if (!(type & 0xc0))
1668         WaitForSingleObject(info.hProcess,INFINITE);
1669
1670     CloseHandle( info.hProcess );
1671     CloseHandle( info.hThread );
1672     return ERROR_SUCCESS;
1673 }
1674
1675 static UINT HANDLE_CustomType34(MSIPACKAGE *package, const LPWSTR source,
1676                                 const LPWSTR target, const INT type)
1677 {
1678     LPWSTR filename, deformated;
1679     STARTUPINFOW si;
1680     PROCESS_INFORMATION info;
1681     BOOL rc;
1682
1683     memset(&si,0,sizeof(STARTUPINFOW));
1684
1685     filename = resolve_folder(package, source, FALSE, FALSE, NULL);
1686
1687     if (!filename)
1688         return ERROR_FUNCTION_FAILED;
1689
1690     SetCurrentDirectoryW(filename);
1691     HeapFree(GetProcessHeap(),0,filename);
1692
1693     deformat_string(package,target,&deformated);
1694
1695     TRACE("executing exe %s \n",debugstr_w(deformated));
1696
1697     rc = CreateProcessW(NULL, deformated, NULL, NULL, FALSE, 0, NULL,
1698                   c_collen, &si, &info);
1699     HeapFree(GetProcessHeap(),0,deformated);
1700
1701     if ( !rc )
1702     {
1703         ERR("Unable to execute command\n");
1704         return ERROR_SUCCESS;
1705     }
1706
1707     if (!(type & 0xc0))
1708         WaitForSingleObject(info.hProcess,INFINITE);
1709
1710     CloseHandle( info.hProcess );
1711     CloseHandle( info.hThread );
1712     return ERROR_SUCCESS;
1713 }
1714
1715 /***********************************************************************
1716  *            create_full_pathW
1717  *
1718  * Recursively create all directories in the path.
1719  *
1720  * shamelessly stolen from setupapi/queue.c
1721  */
1722 static BOOL create_full_pathW(const WCHAR *path)
1723 {
1724     BOOL ret = TRUE;
1725     int len;
1726     WCHAR *new_path;
1727
1728     new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) *
1729                                               sizeof(WCHAR));
1730
1731     strcpyW(new_path, path);
1732
1733     while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
1734     new_path[len - 1] = 0;
1735
1736     while(!CreateDirectoryW(new_path, NULL))
1737     {
1738         WCHAR *slash;
1739         DWORD last_error = GetLastError();
1740         if(last_error == ERROR_ALREADY_EXISTS)
1741             break;
1742
1743         if(last_error != ERROR_PATH_NOT_FOUND)
1744         {
1745             ret = FALSE;
1746             break;
1747         }
1748
1749         if(!(slash = strrchrW(new_path, '\\')))
1750         {
1751             ret = FALSE;
1752             break;
1753         }
1754
1755         len = slash - new_path;
1756         new_path[len] = 0;
1757         if(!create_full_pathW(new_path))
1758         {
1759             ret = FALSE;
1760             break;
1761         }
1762         new_path[len] = '\\';
1763     }
1764
1765     HeapFree(GetProcessHeap(), 0, new_path);
1766     return ret;
1767 }
1768
1769 /*
1770  * Also we cannot enable/disable components either, so for now I am just going 
1771  * to do all the directories for all the components.
1772  */
1773 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1774 {
1775     static const WCHAR ExecSeqQuery[] = {
1776         's','e','l','e','c','t',' ','D','i','r','e','c','t','o','r','y','_',' ',
1777         'f','r','o','m',' ','C','r','e','a','t','e','F','o','l','d','e','r',0 };
1778     UINT rc;
1779     MSIQUERY *view;
1780     MSIFOLDER *folder;
1781
1782     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1783     if (rc != ERROR_SUCCESS)
1784         return ERROR_SUCCESS;
1785
1786     rc = MSI_ViewExecute(view, 0);
1787     if (rc != ERROR_SUCCESS)
1788     {
1789         MSI_ViewClose(view);
1790         msiobj_release(&view->hdr);
1791         return rc;
1792     }
1793     
1794     while (1)
1795     {
1796         WCHAR dir[0x100];
1797         LPWSTR full_path;
1798         DWORD sz;
1799         MSIRECORD *row = NULL, *uirow;
1800
1801         rc = MSI_ViewFetch(view,&row);
1802         if (rc != ERROR_SUCCESS)
1803         {
1804             rc = ERROR_SUCCESS;
1805             break;
1806         }
1807
1808         sz=0x100;
1809         rc = MSI_RecordGetStringW(row,1,dir,&sz);
1810
1811         if (rc!= ERROR_SUCCESS)
1812         {
1813             ERR("Unable to get folder id \n");
1814             msiobj_release(&row->hdr);
1815             continue;
1816         }
1817
1818         sz = MAX_PATH;
1819         full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1820         if (!full_path)
1821         {
1822             ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1823             msiobj_release(&row->hdr);
1824             continue;
1825         }
1826
1827         TRACE("Folder is %s\n",debugstr_w(full_path));
1828
1829         /* UI stuff */
1830         uirow = MSI_CreateRecord(1);
1831         MSI_RecordSetStringW(uirow,1,full_path);
1832         ui_actiondata(package,szCreateFolders,uirow);
1833         msiobj_release( &uirow->hdr );
1834
1835         if (folder->State == 0)
1836             create_full_pathW(full_path);
1837
1838         folder->State = 3;
1839
1840         msiobj_release(&row->hdr);
1841         HeapFree(GetProcessHeap(),0,full_path);
1842     }
1843     MSI_ViewClose(view);
1844     msiobj_release(&view->hdr);
1845    
1846     return rc;
1847 }
1848
1849 static int load_component(MSIPACKAGE* package, MSIRECORD * row)
1850 {
1851     int index = package->loaded_components;
1852     DWORD sz;
1853
1854     /* fill in the data */
1855
1856     package->loaded_components++;
1857     if (package->loaded_components == 1)
1858         package->components = HeapAlloc(GetProcessHeap(),0,
1859                                         sizeof(MSICOMPONENT));
1860     else
1861         package->components = HeapReAlloc(GetProcessHeap(),0,
1862             package->components, package->loaded_components * 
1863             sizeof(MSICOMPONENT));
1864
1865     memset(&package->components[index],0,sizeof(MSICOMPONENT));
1866
1867     sz = 96;       
1868     MSI_RecordGetStringW(row,1,package->components[index].Component,&sz);
1869
1870     TRACE("Loading Component %s\n",
1871            debugstr_w(package->components[index].Component));
1872
1873     sz = 0x100;
1874     if (!MSI_RecordIsNull(row,2))
1875         MSI_RecordGetStringW(row,2,package->components[index].ComponentId,&sz);
1876             
1877     sz = 96;       
1878     MSI_RecordGetStringW(row,3,package->components[index].Directory,&sz);
1879
1880     package->components[index].Attributes = MSI_RecordGetInteger(row,4);
1881
1882     sz = 0x100;       
1883     MSI_RecordGetStringW(row,5,package->components[index].Condition,&sz);
1884
1885     sz = 96;       
1886     MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz);
1887
1888     package->components[index].Installed = INSTALLSTATE_ABSENT;
1889     package->components[index].Action = INSTALLSTATE_UNKNOWN;
1890     package->components[index].ActionRequest = INSTALLSTATE_UNKNOWN;
1891
1892     package->components[index].Enabled = TRUE;
1893
1894     return index;
1895 }
1896
1897 static void load_feature(MSIPACKAGE* package, MSIRECORD * row)
1898 {
1899     int index = package->loaded_features;
1900     DWORD sz;
1901     static const WCHAR Query1[] = {'S','E','L','E','C','T',' ','C','o','m','p',
1902         'o','n','e','n','t','_',' ','F','R','O','M',' ','F','e','a','t','u','r','e',
1903         'C','o','m','p','o','n','e','n','t','s',' ','W','H','E','R','E',' ','F','e',
1904         'a','t','u','r','e','_','=','\'','%','s','\'',0};
1905     static const WCHAR Query2[] = {'S','E','L','E','C','T',' ','*',' ','F','R',
1906         'O','M',' ','C','o','m','p','o','n','e','n','t',' ','W','H','E','R','E',' ','C',
1907         'o','m','p','o','n','e','n','t','=','\'','%','s','\'',0};
1908     MSIQUERY * view;
1909     MSIQUERY * view2;
1910     MSIRECORD * row2;
1911     MSIRECORD * row3;
1912     UINT    rc;
1913
1914     /* fill in the data */
1915
1916     package->loaded_features ++;
1917     if (package->loaded_features == 1)
1918         package->features = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFEATURE));
1919     else
1920         package->features = HeapReAlloc(GetProcessHeap(),0,package->features,
1921                                 package->loaded_features * sizeof(MSIFEATURE));
1922
1923     memset(&package->features[index],0,sizeof(MSIFEATURE));
1924     
1925     sz = 96;       
1926     MSI_RecordGetStringW(row,1,package->features[index].Feature,&sz);
1927
1928     TRACE("Loading feature %s\n",debugstr_w(package->features[index].Feature));
1929
1930     sz = 96;
1931     if (!MSI_RecordIsNull(row,2))
1932         MSI_RecordGetStringW(row,2,package->features[index].Feature_Parent,&sz);
1933
1934     sz = 0x100;
1935      if (!MSI_RecordIsNull(row,3))
1936         MSI_RecordGetStringW(row,3,package->features[index].Title,&sz);
1937
1938      sz = 0x100;
1939      if (!MSI_RecordIsNull(row,4))
1940         MSI_RecordGetStringW(row,4,package->features[index].Description,&sz);
1941
1942     if (!MSI_RecordIsNull(row,5))
1943         package->features[index].Display = MSI_RecordGetInteger(row,5);
1944   
1945     package->features[index].Level= MSI_RecordGetInteger(row,6);
1946
1947      sz = 96;
1948      if (!MSI_RecordIsNull(row,7))
1949         MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz);
1950
1951     package->features[index].Attributes= MSI_RecordGetInteger(row,8);
1952
1953     package->features[index].Installed = INSTALLSTATE_ABSENT;
1954     package->features[index].Action = INSTALLSTATE_UNKNOWN;
1955     package->features[index].ActionRequest = INSTALLSTATE_UNKNOWN;
1956
1957     /* load feature components */
1958
1959     rc = ACTION_OpenQuery(package->db, &view, Query1, package->features[index].Feature);
1960     if (rc != ERROR_SUCCESS)
1961         return;
1962     rc = MSI_ViewExecute(view,0);
1963     if (rc != ERROR_SUCCESS)
1964     {
1965         MSI_ViewClose(view);
1966         msiobj_release(&view->hdr);
1967         return;
1968     }
1969     while (1)
1970     {
1971         DWORD sz = 0x100;
1972         WCHAR buffer[0x100];
1973         DWORD rc;
1974         INT c_indx;
1975         INT cnt = package->features[index].ComponentCount;
1976
1977         rc = MSI_ViewFetch(view,&row2);
1978         if (rc != ERROR_SUCCESS)
1979             break;
1980
1981         sz = 0x100;
1982         MSI_RecordGetStringW(row2,1,buffer,&sz);
1983
1984         /* check to see if the component is already loaded */
1985         c_indx = get_loaded_component(package,buffer);
1986         if (c_indx != -1)
1987         {
1988             TRACE("Component %s already loaded at %i\n", debugstr_w(buffer),
1989                   c_indx);
1990             package->features[index].Components[cnt] = c_indx;
1991             package->features[index].ComponentCount ++;
1992             continue;
1993         }
1994
1995         rc = ACTION_OpenQuery(package->db, &view2, Query2, buffer);
1996         if (rc != ERROR_SUCCESS)
1997         {
1998             msiobj_release( &row2->hdr );
1999             continue;
2000         }
2001         rc = MSI_ViewExecute(view2,0);
2002         if (rc != ERROR_SUCCESS)
2003         {
2004             msiobj_release( &row2->hdr );
2005             MSI_ViewClose(view2);
2006             msiobj_release( &view2->hdr );  
2007             continue;
2008         }
2009         while (1)
2010         {
2011             DWORD rc;
2012
2013             rc = MSI_ViewFetch(view2,&row3);
2014             if (rc != ERROR_SUCCESS)
2015                 break;
2016             c_indx = load_component(package,row3);
2017             msiobj_release( &row3->hdr );
2018
2019             package->features[index].Components[cnt] = c_indx;
2020             package->features[index].ComponentCount ++;
2021             TRACE("Loaded new component to index %i\n",c_indx);
2022         }
2023         MSI_ViewClose(view2);
2024         msiobj_release( &view2->hdr );
2025         msiobj_release( &row2->hdr );
2026     }
2027     MSI_ViewClose(view);
2028     msiobj_release(&view->hdr);
2029 }
2030
2031 /*
2032  * I am not doing any of the costing functionality yet. 
2033  * Mostly looking at doing the Component and Feature loading
2034  *
2035  * The native MSI does ALOT of modification to tables here. Mostly adding alot
2036  * of temporary columns to the Feature and Component tables. 
2037  *
2038  *    note: native msi also tracks the short filename. but I am only going to
2039  *          track the long ones.  Also looking at this directory table
2040  *          it appears that the directory table does not get the parents
2041  *          resolved base on property only based on their entrys in the 
2042  *          directory table.
2043  */
2044 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
2045 {
2046     MSIQUERY * view;
2047     MSIRECORD * row;
2048     UINT rc;
2049     static const WCHAR Query_all[] = {
2050        'S','E','L','E','C','T',' ','*',' ',
2051        'F','R','O','M',' ','F','e','a','t','u','r','e',0};
2052     static const WCHAR szCosting[] = {
2053        'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2054     static const WCHAR szZero[] = { '0', 0 };
2055
2056     MSI_SetPropertyW(package, szCosting, szZero);
2057     MSI_SetPropertyW(package, cszRootDrive , c_collen);
2058
2059     rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
2060     if (rc != ERROR_SUCCESS)
2061         return rc;
2062     rc = MSI_ViewExecute(view,0);
2063     if (rc != ERROR_SUCCESS)
2064     {
2065         MSI_ViewClose(view);
2066         msiobj_release(&view->hdr);
2067         return rc;
2068     }
2069     while (1)
2070     {
2071         DWORD rc;
2072
2073         rc = MSI_ViewFetch(view,&row);
2074         if (rc != ERROR_SUCCESS)
2075             break;
2076        
2077         load_feature(package,row); 
2078         msiobj_release(&row->hdr);
2079     }
2080     MSI_ViewClose(view);
2081     msiobj_release(&view->hdr);
2082
2083     return ERROR_SUCCESS;
2084 }
2085
2086 static UINT load_file(MSIPACKAGE* package, MSIRECORD * row)
2087 {
2088     DWORD index = package->loaded_files;
2089     DWORD i;
2090     LPWSTR buffer;
2091
2092     /* fill in the data */
2093
2094     package->loaded_files++;
2095     if (package->loaded_files== 1)
2096         package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
2097     else
2098         package->files = HeapReAlloc(GetProcessHeap(),0,
2099             package->files , package->loaded_files * sizeof(MSIFILE));
2100
2101     memset(&package->files[index],0,sizeof(MSIFILE));
2102  
2103     package->files[index].File = load_dynamic_stringW(row, 1);
2104     buffer = load_dynamic_stringW(row, 2);
2105
2106     package->files[index].ComponentIndex = -1;
2107     for (i = 0; i < package->loaded_components; i++)
2108         if (strcmpW(package->components[i].Component,buffer)==0)
2109         {
2110             package->files[index].ComponentIndex = i;
2111             break;
2112         }
2113     if (package->files[index].ComponentIndex == -1)
2114         ERR("Unfound Component %s\n",debugstr_w(buffer));
2115     HeapFree(GetProcessHeap(), 0, buffer);
2116
2117     package->files[index].FileName = load_dynamic_stringW(row,3);
2118
2119     reduce_to_longfilename(package->files[index].FileName);
2120     
2121     package->files[index].FileSize = MSI_RecordGetInteger(row,4);
2122     package->files[index].Version = load_dynamic_stringW(row, 5);
2123     package->files[index].Language = load_dynamic_stringW(row, 6);
2124     package->files[index].Attributes= MSI_RecordGetInteger(row,7);
2125     package->files[index].Sequence= MSI_RecordGetInteger(row,8);
2126
2127     package->files[index].Temporary = FALSE;
2128     package->files[index].State = 0;
2129
2130     TRACE("File Loaded (%s)\n",debugstr_w(package->files[index].File));  
2131  
2132     return ERROR_SUCCESS;
2133 }
2134
2135 static UINT ACTION_FileCost(MSIPACKAGE *package)
2136 {
2137     MSIQUERY * view;
2138     MSIRECORD * row;
2139     UINT rc;
2140     static const WCHAR Query[] = {
2141         'S','E','L','E','C','T',' ','*',' ',
2142         'F','R','O','M',' ','F','i','l','e',' ',
2143         'O','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e', 0};
2144
2145     if (!package)
2146         return ERROR_INVALID_HANDLE;
2147
2148     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2149     if (rc != ERROR_SUCCESS)
2150         return ERROR_SUCCESS;
2151    
2152     rc = MSI_ViewExecute(view, 0);
2153     if (rc != ERROR_SUCCESS)
2154     {
2155         MSI_ViewClose(view);
2156         msiobj_release(&view->hdr);
2157         return ERROR_SUCCESS;
2158     }
2159
2160     while (1)
2161     {
2162         rc = MSI_ViewFetch(view,&row);
2163         if (rc != ERROR_SUCCESS)
2164         {
2165             rc = ERROR_SUCCESS;
2166             break;
2167         }
2168         load_file(package,row);
2169         msiobj_release(&row->hdr);
2170     }
2171     MSI_ViewClose(view);
2172     msiobj_release(&view->hdr);
2173
2174     return ERROR_SUCCESS;
2175 }
2176
2177 static INT load_folder(MSIPACKAGE *package, const WCHAR* dir)
2178
2179 {
2180     static const WCHAR Query[] =
2181         {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','D','i','r','e','c',
2182          't','o','r','y',' ','w','h','e','r','e',' ','`','D','i','r','e','c','t',
2183          'o','r','y','`',' ','=',' ','`','%','s','`',0};
2184     UINT rc;
2185     MSIQUERY * view;
2186     LPWSTR targetdir, parent, srcdir;
2187     MSIRECORD * row = 0;
2188     INT index = -1;
2189     DWORD i;
2190
2191     TRACE("Looking for dir %s\n",debugstr_w(dir));
2192
2193     for (i = 0; i < package->loaded_folders; i++)
2194     {
2195         if (strcmpW(package->folders[i].Directory,dir)==0)
2196         {
2197             TRACE(" %s retuning on index %lu\n",debugstr_w(dir),i);
2198             return i;
2199         }
2200     }
2201
2202     TRACE("Working to load %s\n",debugstr_w(dir));
2203
2204     index = package->loaded_folders++;
2205     if (package->loaded_folders==1)
2206         package->folders = HeapAlloc(GetProcessHeap(),0,
2207                                         sizeof(MSIFOLDER));
2208     else
2209         package->folders= HeapReAlloc(GetProcessHeap(),0,
2210             package->folders, package->loaded_folders* 
2211             sizeof(MSIFOLDER));
2212
2213     memset(&package->folders[index],0,sizeof(MSIFOLDER));
2214
2215     package->folders[index].Directory = dupstrW(dir);
2216
2217     rc = ACTION_OpenQuery(package->db, &view, Query, dir);
2218     if (rc != ERROR_SUCCESS)
2219         return -1;
2220
2221     rc = MSI_ViewExecute(view, 0);
2222     if (rc != ERROR_SUCCESS)
2223     {
2224         MSI_ViewClose(view);
2225         msiobj_release(&view->hdr);
2226         return -1;
2227     }
2228
2229     rc = MSI_ViewFetch(view,&row);
2230     if (rc != ERROR_SUCCESS)
2231     {
2232         MSI_ViewClose(view);
2233         msiobj_release(&view->hdr);
2234         return -1;
2235     }
2236
2237     targetdir = load_dynamic_stringW(row,3);
2238
2239     /* split src and target dir */
2240     if (strchrW(targetdir,':'))
2241     {
2242         srcdir=strchrW(targetdir,':');
2243         *srcdir=0;
2244         srcdir ++;
2245     }
2246     else
2247         srcdir=NULL;
2248
2249     /* for now only pick long filename versions */
2250     if (strchrW(targetdir,'|'))
2251     {
2252         targetdir = strchrW(targetdir,'|'); 
2253         *targetdir = 0;
2254         targetdir ++;
2255     }
2256     if (srcdir && strchrW(srcdir,'|'))
2257     {
2258         srcdir= strchrW(srcdir,'|'); 
2259         *srcdir= 0;
2260         srcdir ++;
2261     }
2262
2263     /* now check for root dirs */
2264     if (targetdir[0] == '.' && targetdir[1] == 0)
2265         targetdir = NULL;
2266         
2267     if (srcdir && srcdir[0] == '.' && srcdir[1] == 0)
2268         srcdir = NULL;
2269
2270     if (targetdir)
2271     {
2272         TRACE("   TargetDefault = %s\n",debugstr_w(targetdir));
2273         if (package->folders[index].TargetDefault)
2274             HeapFree(GetProcessHeap(),0, package->folders[index].TargetDefault);
2275         package->folders[index].TargetDefault = dupstrW(targetdir);
2276     }
2277
2278     if (srcdir)
2279        package->folders[index].SourceDefault = dupstrW(srcdir);
2280     else if (targetdir)
2281         package->folders[index].SourceDefault = dupstrW(targetdir);
2282     HeapFree(GetProcessHeap(), 0, targetdir);
2283
2284     parent = load_dynamic_stringW(row,2);
2285     if (parent) 
2286     {
2287         i = load_folder(package,parent);
2288         package->folders[index].ParentIndex = i;
2289         TRACE("Parent is index %i... %s %s\n",
2290                     package->folders[index].ParentIndex,
2291         debugstr_w(package->folders[package->folders[index].ParentIndex].Directory),
2292                     debugstr_w(parent));
2293     }
2294     else
2295         package->folders[index].ParentIndex = -2;
2296     HeapFree(GetProcessHeap(), 0, parent);
2297
2298     package->folders[index].Property = load_dynamic_property(package, dir,NULL);
2299
2300     msiobj_release(&row->hdr);
2301     MSI_ViewClose(view);
2302     msiobj_release(&view->hdr);
2303     TRACE(" %s retuning on index %i\n",debugstr_w(dir),index);
2304     return index;
2305 }
2306
2307
2308 static LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name,
2309                            BOOL source, BOOL set_prop, MSIFOLDER **folder)
2310 {
2311     DWORD i;
2312     LPWSTR p, path = NULL;
2313
2314     TRACE("Working to resolve %s\n",debugstr_w(name));
2315
2316     /* special resolving for Target and Source root dir */
2317     if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0)
2318     {
2319         if (!source)
2320         {
2321             path = load_dynamic_property(package,cszTargetDir,NULL);
2322             if (!path)
2323             {
2324                 path = load_dynamic_property(package,cszRootDrive,NULL);
2325                 if (set_prop)
2326                     MSI_SetPropertyW(package,cszTargetDir,path);
2327             }
2328             if (folder)
2329             {
2330                 for (i = 0; i < package->loaded_folders; i++)
2331                 {
2332                     if (strcmpW(package->folders[i].Directory,name)==0)
2333                         break;
2334                 }
2335                 *folder = &(package->folders[i]);
2336             }
2337             return path;
2338         }
2339         else
2340         {
2341             path = load_dynamic_property(package,cszSourceDir,NULL);
2342             if (!path)
2343             {
2344                 path = load_dynamic_property(package,cszDatabase,NULL);
2345                 if (path)
2346                 {
2347                     p = strrchrW(path,'\\');
2348                     if (p)
2349                         *(p+1) = 0;
2350                 }
2351             }
2352             if (folder)
2353             {
2354                 for (i = 0; i < package->loaded_folders; i++)
2355                 {
2356                     if (strcmpW(package->folders[i].Directory,name)==0)
2357                         break;
2358                 }
2359                 *folder = &(package->folders[i]);
2360             }
2361             return path;
2362         }
2363     }
2364
2365     for (i = 0; i < package->loaded_folders; i++)
2366     {
2367         if (strcmpW(package->folders[i].Directory,name)==0)
2368             break;
2369     }
2370
2371     if (i >= package->loaded_folders)
2372         return NULL;
2373
2374     if (folder)
2375         *folder = &(package->folders[i]);
2376
2377     if (!source && package->folders[i].ResolvedTarget)
2378     {
2379         path = dupstrW(package->folders[i].ResolvedTarget);
2380         TRACE("   already resolved to %s\n",debugstr_w(path));
2381         return path;
2382     }
2383     else if (source && package->folders[i].ResolvedSource)
2384     {
2385         path = dupstrW(package->folders[i].ResolvedSource);
2386         return path;
2387     }
2388     else if (!source && package->folders[i].Property)
2389     {
2390         path = dupstrW(package->folders[i].Property);
2391         TRACE("   internally set to %s\n",debugstr_w(path));
2392         if (set_prop)
2393             MSI_SetPropertyW(package,name,path);
2394         return path;
2395     }
2396
2397     if (package->folders[i].ParentIndex >= 0)
2398     {
2399         LPWSTR parent = package->folders[package->folders[i].ParentIndex].Directory;
2400
2401         TRACE(" ! Parent is %s\n", debugstr_w(parent));
2402
2403         p = resolve_folder(package, parent, source, set_prop, NULL);
2404         if (!source)
2405         {
2406             TRACE("   TargetDefault = %s\n",debugstr_w(package->folders[i].TargetDefault));
2407             path = build_directory_name(3, p, package->folders[i].TargetDefault, NULL);
2408             package->folders[i].ResolvedTarget = dupstrW(path);
2409             TRACE("   resolved into %s\n",debugstr_w(path));
2410             if (set_prop)
2411                 MSI_SetPropertyW(package,name,path);
2412         }
2413         else 
2414         {
2415             path = build_directory_name(3, p, package->folders[i].SourceDefault, NULL);
2416             package->folders[i].ResolvedSource = dupstrW(path);
2417         }
2418         HeapFree(GetProcessHeap(),0,p);
2419     }
2420     return path;
2421 }
2422
2423 static UINT SetFeatureStates(MSIPACKAGE *package)
2424 {
2425     LPWSTR level;
2426     INT install_level;
2427     DWORD i;
2428     INT j;
2429     LPWSTR override = NULL;
2430     static const WCHAR all[]={'A','L','L',0};
2431     static const WCHAR szlevel[] = {
2432         'I','N','S','T','A','L','L','L','E','V','E','L',0};
2433     static const WCHAR szAddLocal[] = {
2434         'A','D','D','L','O','C','A','L',0};
2435
2436     /* I do not know if this is where it should happen.. but */
2437
2438     TRACE("Checking Install Level\n");
2439
2440     level = load_dynamic_property(package,szlevel,NULL);
2441     if (level)
2442     {
2443         install_level = atoiW(level);
2444         HeapFree(GetProcessHeap(), 0, level);
2445     }
2446     else
2447         install_level = 1;
2448
2449     /* ok hereis the rub
2450      * ADDLOCAL and its friend OVERRIDE INSTALLLEVLE
2451      * I have confirmed this if ADDLOCALis stated then the INSTALLLEVEL is
2452      * itnored for all the features. seems strange, epsecially since it is not
2453      * documented anywhere, but it is how it works. 
2454      */
2455     
2456     override = load_dynamic_property(package,szAddLocal,NULL);
2457   
2458     if (override)
2459     {
2460         for(i = 0; i < package->loaded_features; i++)
2461         {
2462             if (strcmpiW(override,all)==0)
2463             {
2464                 package->features[i].ActionRequest= INSTALLSTATE_LOCAL;
2465                 package->features[i].Action = INSTALLSTATE_LOCAL;
2466             }
2467             else
2468             {
2469                 LPWSTR ptr = override;
2470                 LPWSTR ptr2 = strchrW(override,',');
2471
2472                 while (ptr)
2473                 {
2474                     if ((ptr2 && 
2475                         strncmpW(ptr,package->features[i].Feature, ptr2-ptr)==0)
2476                         || (!ptr2 &&
2477                         strcmpW(ptr,package->features[i].Feature)==0))
2478                     {
2479                         package->features[i].ActionRequest= INSTALLSTATE_LOCAL;
2480                         package->features[i].Action = INSTALLSTATE_LOCAL;
2481                         break;
2482                     }
2483                     if (ptr2)
2484                     {
2485                         ptr=ptr2+1;
2486                         ptr2 = strchrW(ptr,',');
2487                     }
2488                     else
2489                         break;
2490                 }
2491             }
2492         }
2493         HeapFree(GetProcessHeap(),0,override);
2494     } 
2495     else
2496     {
2497         for(i = 0; i < package->loaded_features; i++)
2498         {
2499             BOOL feature_state= ((package->features[i].Level > 0) &&
2500                              (package->features[i].Level <= install_level));
2501
2502             if (feature_state)
2503             {
2504                 package->features[i].ActionRequest= INSTALLSTATE_LOCAL;
2505                 package->features[i].Action = INSTALLSTATE_LOCAL;
2506             }
2507         }
2508     }
2509
2510     /*
2511      * now we want to enable or disable components base on feature 
2512     */
2513
2514     for(i = 0; i < package->loaded_features; i++)
2515     {
2516         MSIFEATURE* feature = &package->features[i];
2517         TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
2518             debugstr_w(feature->Feature), feature->Installed, feature->Action,
2519             feature->ActionRequest);
2520
2521         for( j = 0; j < feature->ComponentCount; j++)
2522         {
2523             MSICOMPONENT* component = &package->components[
2524                                                     feature->Components[j]];
2525
2526             if (!component->Enabled)
2527             {
2528                 component->Action = INSTALLSTATE_ABSENT;
2529                 component->ActionRequest = INSTALLSTATE_ABSENT;
2530             }
2531             else
2532             {
2533                 if (feature->Action == INSTALLSTATE_LOCAL)
2534                     component->Action = INSTALLSTATE_LOCAL;
2535                 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
2536                     component->ActionRequest = INSTALLSTATE_LOCAL;
2537             }
2538         }
2539     } 
2540
2541     for(i = 0; i < package->loaded_components; i++)
2542     {
2543         MSICOMPONENT* component= &package->components[i];
2544
2545         TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
2546             debugstr_w(component->Component), component->Installed, 
2547             component->Action, component->ActionRequest);
2548     }
2549
2550
2551     return ERROR_SUCCESS;
2552 }
2553
2554 /* 
2555  * Alot is done in this function aside from just the costing.
2556  * The costing needs to be implemented at some point but for now I am going
2557  * to focus on the directory building
2558  *
2559  */
2560 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2561 {
2562     static const WCHAR ExecSeqQuery[] = {
2563         's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2564         'D','i','r','e','c','t','o','r','y',0};
2565     static const WCHAR ConditionQuery[] = {
2566         's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2567         'C','o','n','d','i','t','i','o','n',0};
2568     static const WCHAR szCosting[] = {
2569        'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2570     static const WCHAR szlevel[] = {
2571         'I','N','S','T','A','L','L','L','E','V','E','L',0};
2572     static const WCHAR szOne[] = { '1', 0 };
2573     UINT rc;
2574     MSIQUERY * view;
2575     DWORD i;
2576     LPWSTR level;
2577
2578     TRACE("Building Directory properties\n");
2579
2580     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2581     if (rc == ERROR_SUCCESS)
2582     {
2583         rc = MSI_ViewExecute(view, 0);
2584         if (rc != ERROR_SUCCESS)
2585         {
2586             MSI_ViewClose(view);
2587             msiobj_release(&view->hdr);
2588             return rc;
2589         }
2590
2591         while (1)
2592         {
2593             WCHAR name[0x100];
2594             LPWSTR path;
2595             MSIRECORD * row = 0;
2596             DWORD sz;
2597
2598             rc = MSI_ViewFetch(view,&row);
2599             if (rc != ERROR_SUCCESS)
2600             {
2601                 rc = ERROR_SUCCESS;
2602                 break;
2603             }
2604
2605             sz=0x100;
2606             MSI_RecordGetStringW(row,1,name,&sz);
2607
2608             /* This helper function now does ALL the work */
2609             TRACE("Dir %s ...\n",debugstr_w(name));
2610             load_folder(package,name);
2611             path = resolve_folder(package,name,FALSE,TRUE,NULL);
2612             TRACE("resolves to %s\n",debugstr_w(path));
2613             HeapFree( GetProcessHeap(), 0, path);
2614
2615             msiobj_release(&row->hdr);
2616         }
2617         MSI_ViewClose(view);
2618         msiobj_release(&view->hdr);
2619     }
2620
2621     TRACE("File calculations %i files\n",package->loaded_files);
2622
2623     for (i = 0; i < package->loaded_files; i++)
2624     {
2625         MSICOMPONENT* comp = NULL;
2626         MSIFILE* file= NULL;
2627
2628         file = &package->files[i];
2629         if (file->ComponentIndex >= 0)
2630             comp = &package->components[file->ComponentIndex];
2631
2632         if (file->Temporary == TRUE)
2633             continue;
2634
2635         if (comp)
2636         {
2637             LPWSTR p;
2638
2639             /* calculate target */
2640             p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
2641
2642             if (file->TargetPath)
2643                 HeapFree(GetProcessHeap(),0,file->TargetPath);
2644
2645             TRACE("file %s is named %s\n",
2646                    debugstr_w(file->File),debugstr_w(file->FileName));       
2647
2648             file->TargetPath = build_directory_name(2, p, file->FileName);
2649
2650             HeapFree(GetProcessHeap(),0,p);
2651
2652             TRACE("file %s resolves to %s\n",
2653                    debugstr_w(file->File),debugstr_w(file->TargetPath));       
2654
2655             if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2656             {
2657                 file->State = 1;
2658                 comp->Cost += file->FileSize;
2659             }
2660             else
2661             {
2662                 if (file->Version)
2663                 {
2664                     DWORD handle;
2665                     DWORD versize;
2666                     UINT sz;
2667                     LPVOID version;
2668                     static const WCHAR name[] = 
2669                     {'\\',0};
2670                     static const WCHAR name_fmt[] = 
2671                     {'%','u','.','%','u','.','%','u','.','%','u',0};
2672                     WCHAR filever[0x100];
2673                     VS_FIXEDFILEINFO *lpVer;
2674
2675                     FIXME("Version comparison.. \n");
2676                     versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
2677                     version = HeapAlloc(GetProcessHeap(),0,versize);
2678                     GetFileVersionInfoW(file->TargetPath, 0, versize, version);
2679
2680                     VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
2681
2682                     sprintfW(filever,name_fmt,
2683                         HIWORD(lpVer->dwFileVersionMS),
2684                         LOWORD(lpVer->dwFileVersionMS),
2685                         HIWORD(lpVer->dwFileVersionLS),
2686                         LOWORD(lpVer->dwFileVersionLS));
2687
2688                     TRACE("new %s old %s\n", debugstr_w(file->Version),
2689                           debugstr_w(filever));
2690                     if (strcmpiW(filever,file->Version)<0)
2691                     {
2692                         file->State = 2;
2693                         FIXME("cost should be diff in size\n");
2694                         comp->Cost += file->FileSize;
2695                     }
2696                     else
2697                         file->State = 3;
2698                     HeapFree(GetProcessHeap(),0,version);
2699                 }
2700                 else
2701                     file->State = 3;
2702             }
2703         } 
2704     }
2705
2706     TRACE("Evaluating Condition Table\n");
2707
2708     rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2709     if (rc == ERROR_SUCCESS)
2710     {
2711         rc = MSI_ViewExecute(view, 0);
2712         if (rc != ERROR_SUCCESS)
2713         {
2714             MSI_ViewClose(view);
2715             msiobj_release(&view->hdr);
2716             return rc;
2717         }
2718     
2719         while (1)
2720         {
2721             WCHAR Feature[0x100];
2722             MSIRECORD * row = 0;
2723             DWORD sz;
2724             int feature_index;
2725
2726             rc = MSI_ViewFetch(view,&row);
2727
2728             if (rc != ERROR_SUCCESS)
2729             {
2730                 rc = ERROR_SUCCESS;
2731                 break;
2732             }
2733
2734             sz = 0x100;
2735             MSI_RecordGetStringW(row,1,Feature,&sz);
2736
2737             feature_index = get_loaded_feature(package,Feature);
2738             if (feature_index < 0)
2739                 ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature));
2740             else
2741             {
2742                 LPWSTR Condition;
2743                 Condition = load_dynamic_stringW(row,3);
2744
2745                 if (MSI_EvaluateConditionW(package,Condition) == 
2746                     MSICONDITION_TRUE)
2747                 {
2748                     int level = MSI_RecordGetInteger(row,2);
2749                     TRACE("Reseting feature %s to level %i\n",
2750                            debugstr_w(Feature), level);
2751                     package->features[feature_index].Level = level;
2752                 }
2753                 HeapFree(GetProcessHeap(),0,Condition);
2754             }
2755
2756             msiobj_release(&row->hdr);
2757         }
2758         MSI_ViewClose(view);
2759         msiobj_release(&view->hdr);
2760     }
2761
2762     TRACE("Enabling or Disabling Components\n");
2763     for (i = 0; i < package->loaded_components; i++)
2764     {
2765         if (package->components[i].Condition[0])
2766         {
2767             if (MSI_EvaluateConditionW(package,
2768                 package->components[i].Condition) == MSICONDITION_FALSE)
2769             {
2770                 TRACE("Disabling component %s\n",
2771                       debugstr_w(package->components[i].Component));
2772                 package->components[i].Enabled = FALSE;
2773             }
2774         }
2775     }
2776
2777     MSI_SetPropertyW(package,szCosting,szOne);
2778     /* set default run level if not set */
2779     level = load_dynamic_property(package,szlevel,NULL);
2780     if (!level)
2781         MSI_SetPropertyW(package,szlevel, szOne);
2782     else
2783         HeapFree(GetProcessHeap(),0,level);
2784
2785     return SetFeatureStates(package);
2786
2787 }
2788
2789 /*
2790  * This is a helper function for handling embedded cabinet media
2791  */
2792 static UINT writeout_cabinet_stream(MSIPACKAGE *package, WCHAR* stream_name,
2793                                     WCHAR* source)
2794 {
2795     UINT rc;
2796     USHORT* data;
2797     UINT    size;
2798     DWORD   write;
2799     HANDLE  the_file;
2800     WCHAR tmp[MAX_PATH];
2801
2802     rc = read_raw_stream_data(package->db,stream_name,&data,&size); 
2803     if (rc != ERROR_SUCCESS)
2804         return rc;
2805
2806     write = MAX_PATH;
2807     if (MSI_GetPropertyW(package, cszTempFolder, tmp, &write))
2808         GetTempPathW(MAX_PATH,tmp);
2809
2810     GetTempFileNameW(tmp,stream_name,0,source);
2811
2812     track_tempfile(package,strrchrW(source,'\\'), source);
2813     the_file = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2814                            FILE_ATTRIBUTE_NORMAL, NULL);
2815
2816     if (the_file == INVALID_HANDLE_VALUE)
2817     {
2818         rc = ERROR_FUNCTION_FAILED;
2819         goto end;
2820     }
2821
2822     WriteFile(the_file,data,size,&write,NULL);
2823     CloseHandle(the_file);
2824     TRACE("wrote %li bytes to %s\n",write,debugstr_w(source));
2825 end:
2826     HeapFree(GetProcessHeap(),0,data);
2827     return rc;
2828 }
2829
2830
2831 /* Support functions for FDI functions */
2832 typedef struct
2833 {
2834     MSIPACKAGE* package;
2835     LPCSTR cab_path;
2836     LPCSTR file_name;
2837 } CabData;
2838
2839 static void * cabinet_alloc(ULONG cb)
2840 {
2841     return HeapAlloc(GetProcessHeap(), 0, cb);
2842 }
2843
2844 static void cabinet_free(void *pv)
2845 {
2846     HeapFree(GetProcessHeap(), 0, pv);
2847 }
2848
2849 static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode)
2850 {
2851     DWORD dwAccess = 0;
2852     DWORD dwShareMode = 0;
2853     DWORD dwCreateDisposition = OPEN_EXISTING;
2854     switch (oflag & _O_ACCMODE)
2855     {
2856     case _O_RDONLY:
2857         dwAccess = GENERIC_READ;
2858         dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;
2859         break;
2860     case _O_WRONLY:
2861         dwAccess = GENERIC_WRITE;
2862         dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2863         break;
2864     case _O_RDWR:
2865         dwAccess = GENERIC_READ | GENERIC_WRITE;
2866         dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2867         break;
2868     }
2869     if ((oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))
2870         dwCreateDisposition = CREATE_NEW;
2871     else if (oflag & _O_CREAT)
2872         dwCreateDisposition = CREATE_ALWAYS;
2873     return (INT_PTR)CreateFileA(pszFile, dwAccess, dwShareMode, NULL, dwCreateDisposition, 0, NULL);
2874 }
2875
2876 static UINT cabinet_read(INT_PTR hf, void *pv, UINT cb)
2877 {
2878     DWORD dwRead;
2879     if (ReadFile((HANDLE)hf, pv, cb, &dwRead, NULL))
2880         return dwRead;
2881     return 0;
2882 }
2883
2884 static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb)
2885 {
2886     DWORD dwWritten;
2887     if (WriteFile((HANDLE)hf, pv, cb, &dwWritten, NULL))
2888         return dwWritten;
2889     return 0;
2890 }
2891
2892 static int cabinet_close(INT_PTR hf)
2893 {
2894     return CloseHandle((HANDLE)hf) ? 0 : -1;
2895 }
2896
2897 static long cabinet_seek(INT_PTR hf, long dist, int seektype)
2898 {
2899     /* flags are compatible and so are passed straight through */
2900     return SetFilePointer((HANDLE)hf, dist, NULL, seektype);
2901 }
2902
2903 static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
2904 {
2905     /* FIXME: try to do more processing in this function */
2906     switch (fdint)
2907     {
2908     case fdintCOPY_FILE:
2909     {
2910         CabData *data = (CabData*) pfdin->pv;
2911         ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1);
2912         char *file;
2913
2914         LPWSTR trackname;
2915         LPWSTR trackpath;
2916         LPWSTR tracknametmp;
2917         static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0};
2918        
2919         if (data->file_name && strcmp(data->file_name,pfdin->psz1))
2920                 return 0;
2921         
2922         file = cabinet_alloc((len+1)*sizeof(char));
2923         strcpy(file, data->cab_path);
2924         strcat(file, pfdin->psz1);
2925
2926         TRACE("file: %s\n", debugstr_a(file));
2927
2928         /* track this file so it can be deleted if not installed */
2929         trackpath=strdupAtoW(file);
2930         tracknametmp=strdupAtoW(strrchr(file,'\\')+1);
2931         trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) + 
2932                                   strlenW(tmpprefix)+1) * sizeof(WCHAR));
2933
2934         strcpyW(trackname,tmpprefix);
2935         strcatW(trackname,tracknametmp);
2936
2937         track_tempfile(data->package, trackname, trackpath);
2938
2939         HeapFree(GetProcessHeap(),0,trackpath);
2940         HeapFree(GetProcessHeap(),0,trackname);
2941         HeapFree(GetProcessHeap(),0,tracknametmp);
2942
2943         return cabinet_open(file, _O_WRONLY | _O_CREAT, 0);
2944     }
2945     case fdintCLOSE_FILE_INFO:
2946     {
2947         FILETIME ft;
2948             FILETIME ftLocal;
2949         if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
2950             return -1;
2951         if (!LocalFileTimeToFileTime(&ft, &ftLocal))
2952             return -1;
2953         if (!SetFileTime((HANDLE)pfdin->hf, &ftLocal, 0, &ftLocal))
2954             return -1;
2955
2956         cabinet_close(pfdin->hf);
2957         return 1;
2958     }
2959     default:
2960         return 0;
2961     }
2962 }
2963
2964 /***********************************************************************
2965  *            extract_cabinet_file
2966  *
2967  * Extract files from a cab file.
2968  */
2969 static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source, 
2970                                  const WCHAR* path, const WCHAR* file)
2971 {
2972     HFDI hfdi;
2973     ERF erf;
2974     BOOL ret;
2975     char *cabinet;
2976     char *cab_path;
2977     char *file_name;
2978     CabData data;
2979
2980     TRACE("Extracting %s (%s) to %s\n",debugstr_w(source), 
2981                     debugstr_w(file), debugstr_w(path));
2982
2983     hfdi = FDICreate(cabinet_alloc,
2984                      cabinet_free,
2985                      cabinet_open,
2986                      cabinet_read,
2987                      cabinet_write,
2988                      cabinet_close,
2989                      cabinet_seek,
2990                      0,
2991                      &erf);
2992     if (!hfdi)
2993     {
2994         ERR("FDICreate failed\n");
2995         return FALSE;
2996     }
2997
2998     if (!(cabinet = strdupWtoA( source )))
2999     {
3000         FDIDestroy(hfdi);
3001         return FALSE;
3002     }
3003     if (!(cab_path = strdupWtoA( path )))
3004     {
3005         FDIDestroy(hfdi);
3006         HeapFree(GetProcessHeap(), 0, cabinet);
3007         return FALSE;
3008     }
3009
3010     data.package = package;
3011     data.cab_path = cab_path;
3012     file_name = strdupWtoA(file);
3013     data.file_name = file_name;
3014
3015     ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);
3016
3017     if (!ret)
3018         ERR("FDICopy failed\n");
3019
3020     FDIDestroy(hfdi);
3021
3022     HeapFree(GetProcessHeap(), 0, cabinet);
3023     HeapFree(GetProcessHeap(), 0, cab_path);
3024     HeapFree(GetProcessHeap(), 0, file_name);
3025
3026     return ret;
3027 }
3028
3029 static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence, 
3030                                  WCHAR* path, WCHAR* file)
3031 {
3032     UINT rc;
3033     MSIQUERY * view;
3034     MSIRECORD * row = 0;
3035     static WCHAR source[MAX_PATH];
3036     static const WCHAR ExecSeqQuery[] = {
3037         's','e','l','e','c','t',' ','*',' ',
3038         'f','r','o','m',' ','M','e','d','i','a',' ',
3039         'w','h','e','r','e',' ','L','a','s','t','S','e','q','u','e','n','c','e',' ','>','=',' ','%','i',' ',
3040         'o','r','d','e','r',' ','b','y',' ','L','a','s','t','S','e','q','u','e','n','c','e',0};
3041     WCHAR Query[1024];
3042     WCHAR cab[0x100];
3043     DWORD sz=0x100;
3044     INT seq;
3045     static UINT last_sequence = 0; 
3046
3047     if (sequence <= last_sequence)
3048     {
3049         TRACE("Media already ready (%u, %u)\n",sequence,last_sequence);
3050         extract_a_cabinet_file(package, source,path,file);
3051         return ERROR_SUCCESS;
3052     }
3053
3054     sprintfW(Query,ExecSeqQuery,sequence);
3055
3056     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3057     if (rc != ERROR_SUCCESS)
3058         return rc;
3059
3060     rc = MSI_ViewExecute(view, 0);
3061     if (rc != ERROR_SUCCESS)
3062     {
3063         MSI_ViewClose(view);
3064         msiobj_release(&view->hdr);
3065         return rc;
3066     }
3067
3068     rc = MSI_ViewFetch(view,&row);
3069     if (rc != ERROR_SUCCESS)
3070     {
3071         MSI_ViewClose(view);
3072         msiobj_release(&view->hdr);
3073         return rc;
3074     }
3075     seq = MSI_RecordGetInteger(row,2);
3076     last_sequence = seq;
3077
3078     if (!MSI_RecordIsNull(row,4))
3079     {
3080         sz=0x100;
3081         MSI_RecordGetStringW(row,4,cab,&sz);
3082         TRACE("Source is CAB %s\n",debugstr_w(cab));
3083         /* the stream does not contain the # character */
3084         if (cab[0]=='#')
3085         {
3086             writeout_cabinet_stream(package,&cab[1],source);
3087             strcpyW(path,source);
3088             *(strrchrW(path,'\\')+1)=0;
3089         }
3090         else
3091         {
3092             sz = MAX_PATH;
3093             if (MSI_GetPropertyW(package, cszSourceDir, source, &sz))
3094             {
3095                 ERR("No Source dir defined \n");
3096                 rc = ERROR_FUNCTION_FAILED;
3097             }
3098             else
3099             {
3100                 strcpyW(path,source);
3101                 strcatW(source,cab);
3102                 /* extract the cab file into a folder in the temp folder */
3103                 sz = MAX_PATH;
3104                 if (MSI_GetPropertyW(package, cszTempFolder,path, &sz) 
3105                                     != ERROR_SUCCESS)
3106                     GetTempPathW(MAX_PATH,path);
3107             }
3108         }
3109         rc = !extract_a_cabinet_file(package, source,path,file);
3110     }
3111     msiobj_release(&row->hdr);
3112     MSI_ViewClose(view);
3113     msiobj_release(&view->hdr);
3114     return rc;
3115 }
3116
3117 inline static UINT create_component_directory ( MSIPACKAGE* package, INT component)
3118 {
3119     UINT rc;
3120     MSIFOLDER *folder;
3121     LPWSTR install_path;
3122
3123     install_path = resolve_folder(package, package->components[component].Directory,
3124                         FALSE, FALSE, &folder);
3125     if (!install_path)
3126         return ERROR_FUNCTION_FAILED; 
3127
3128     /* create the path */
3129     if (folder->State == 0)
3130     {
3131         create_full_pathW(install_path);
3132         folder->State = 2;
3133     }
3134     HeapFree(GetProcessHeap(), 0, install_path);
3135
3136     return rc;
3137 }
3138
3139 static UINT ACTION_InstallFiles(MSIPACKAGE *package)
3140 {
3141     UINT rc = ERROR_SUCCESS;
3142     DWORD index;
3143     MSIRECORD * uirow;
3144     WCHAR uipath[MAX_PATH];
3145
3146     if (!package)
3147         return ERROR_INVALID_HANDLE;
3148
3149     /* increment progress bar each time action data is sent */
3150     ui_progress(package,1,1,0,0);
3151
3152     for (index = 0; index < package->loaded_files; index++)
3153     {
3154         WCHAR path_to_source[MAX_PATH];
3155         MSIFILE *file;
3156         
3157         file = &package->files[index];
3158
3159         if (file->Temporary)
3160             continue;
3161
3162         if (package->components[file->ComponentIndex].ActionRequest != 
3163              INSTALLSTATE_LOCAL)
3164         {
3165             ui_progress(package,2,file->FileSize,0,0);
3166             TRACE("File %s is not scheduled for install\n",
3167                    debugstr_w(file->File));
3168
3169             continue;
3170         }
3171
3172         if ((file->State == 1) || (file->State == 2))
3173         {
3174             LPWSTR p;
3175             INT len;
3176             MSICOMPONENT* comp = NULL;
3177
3178             TRACE("Installing %s\n",debugstr_w(file->File));
3179             rc = ready_media_for_file(package,file->Sequence,path_to_source,
3180                             file->File);
3181             /* 
3182              * WARNING!
3183              * our file table could change here because a new temp file
3184              * may have been created
3185              */
3186             file = &package->files[index];
3187             if (rc != ERROR_SUCCESS)
3188             {
3189                 ERR("Unable to ready media\n");
3190                 rc = ERROR_FUNCTION_FAILED;
3191                 break;
3192             }
3193
3194             create_component_directory( package, file->ComponentIndex);
3195
3196             /* recalculate file paths because things may have changed */
3197
3198             if (file->ComponentIndex >= 0)
3199                 comp = &package->components[file->ComponentIndex];
3200
3201             p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
3202             if (file->TargetPath)
3203                 HeapFree(GetProcessHeap(),0,file->TargetPath);
3204
3205             file->TargetPath = build_directory_name(2, p, file->FileName);
3206
3207             len = strlenW(path_to_source) + strlenW(file->File) + 2;
3208             file->SourcePath = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
3209             strcpyW(file->SourcePath, path_to_source);
3210             strcatW(file->SourcePath, file->File);
3211
3212             TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
3213                   debugstr_w(file->TargetPath));
3214
3215             /* the UI chunk */
3216             uirow=MSI_CreateRecord(9);
3217             MSI_RecordSetStringW(uirow,1,file->File);
3218             strcpyW(uipath,file->TargetPath);
3219             *(strrchrW(uipath,'\\')+1)=0;
3220             MSI_RecordSetStringW(uirow,9,uipath);
3221             MSI_RecordSetInteger(uirow,6,file->FileSize);
3222             ui_actiondata(package,szInstallFiles,uirow);
3223             msiobj_release( &uirow->hdr );
3224             ui_progress(package,2,file->FileSize,0,0);
3225
3226             if (!MoveFileW(file->SourcePath,file->TargetPath))
3227             {
3228                 rc = GetLastError();
3229                 ERR("Unable to move file (%s -> %s) (error %d)\n",
3230                      debugstr_w(file->SourcePath), debugstr_w(file->TargetPath),
3231                       rc);
3232                 if (rc == ERROR_ALREADY_EXISTS && file->State == 2)
3233                 {
3234                     CopyFileW(file->SourcePath,file->TargetPath,FALSE);
3235                     DeleteFileW(file->SourcePath);
3236                     rc = 0;
3237                 }
3238                 else if (rc == ERROR_FILE_NOT_FOUND)
3239                 {
3240                     ERR("Source File Not Found!  Continueing\n");
3241                     rc = 0;
3242                 }
3243                 else
3244                 {
3245                     ERR("Ignoring Error and continuing...\n");
3246                     rc = 0;
3247                 }
3248             }
3249             else
3250                 file->State = 4;
3251         }
3252     }
3253
3254     return rc;
3255 }
3256
3257 inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key, 
3258                                    LPWSTR* file_source)
3259 {
3260     DWORD index;
3261
3262     if (!package)
3263         return ERROR_INVALID_HANDLE;
3264
3265     for (index = 0; index < package->loaded_files; index ++)
3266     {
3267         if (strcmpW(file_key,package->files[index].File)==0)
3268         {
3269             if (package->files[index].State >= 3)
3270             {
3271                 *file_source = dupstrW(package->files[index].TargetPath);
3272                 return ERROR_SUCCESS;
3273             }
3274             else
3275                 return ERROR_FILE_NOT_FOUND;
3276         }
3277     }
3278
3279     return ERROR_FUNCTION_FAILED;
3280 }
3281
3282 static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
3283 {
3284     UINT rc;
3285     MSIQUERY * view;
3286     MSIRECORD * row = 0;
3287     static const WCHAR ExecSeqQuery[] = {
3288         's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
3289         'D','u','p','l','i','c','a','t','e','F','i','l','e',0};
3290
3291     if (!package)
3292         return ERROR_INVALID_HANDLE;
3293
3294     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3295     if (rc != ERROR_SUCCESS)
3296         return ERROR_SUCCESS;
3297
3298     rc = MSI_ViewExecute(view, 0);
3299     if (rc != ERROR_SUCCESS)
3300     {
3301         MSI_ViewClose(view);
3302         msiobj_release(&view->hdr);
3303         return rc;
3304     }
3305
3306     while (1)
3307     {
3308         WCHAR file_key[0x100];
3309         WCHAR *file_source = NULL;
3310         WCHAR dest_name[0x100];
3311         LPWSTR dest_path, dest;
3312         WCHAR component[0x100];
3313         INT component_index;
3314
3315         DWORD sz=0x100;
3316
3317         rc = MSI_ViewFetch(view,&row);
3318         if (rc != ERROR_SUCCESS)
3319         {
3320             rc = ERROR_SUCCESS;
3321             break;
3322         }
3323
3324         sz=0x100;
3325         rc = MSI_RecordGetStringW(row,2,component,&sz);
3326         if (rc != ERROR_SUCCESS)
3327         {
3328             ERR("Unable to get component\n");
3329             msiobj_release(&row->hdr);
3330             break;
3331         }
3332
3333         component_index = get_loaded_component(package,component);
3334         if (package->components[component_index].ActionRequest != 
3335              INSTALLSTATE_LOCAL)
3336         {
3337             TRACE("Skipping copy due to disabled component\n");
3338             msiobj_release(&row->hdr);
3339             continue;
3340         }
3341
3342         sz=0x100;
3343         rc = MSI_RecordGetStringW(row,3,file_key,&sz);
3344         if (rc != ERROR_SUCCESS)
3345         {
3346             ERR("Unable to get file key\n");
3347             msiobj_release(&row->hdr);
3348             break;
3349         }
3350
3351         rc = get_file_target(package,file_key,&file_source);
3352
3353         if (rc != ERROR_SUCCESS)
3354         {
3355             ERR("Original file unknown %s\n",debugstr_w(file_key));
3356             msiobj_release(&row->hdr);
3357             if (file_source)
3358                 HeapFree(GetProcessHeap(),0,file_source);
3359             break;
3360         }
3361
3362         if (MSI_RecordIsNull(row,4))
3363         {
3364             strcpyW(dest_name,strrchrW(file_source,'\\')+1);
3365         }
3366         else
3367         {
3368             sz=0x100;
3369             MSI_RecordGetStringW(row,4,dest_name,&sz);
3370             reduce_to_longfilename(dest_name);
3371          }
3372
3373         if (MSI_RecordIsNull(row,5))
3374         {
3375             LPWSTR p;
3376             dest_path = dupstrW(file_source);
3377             p = strrchrW(dest_path,'\\');
3378             if (p)
3379                 *p=0;
3380         }
3381         else
3382         {
3383             WCHAR destkey[0x100];
3384             sz=0x100;
3385             MSI_RecordGetStringW(row,5,destkey,&sz);
3386             sz = 0x100;
3387             dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL);
3388             if (!dest_path)
3389             {
3390                 ERR("Unable to get destination folder\n");
3391                 msiobj_release(&row->hdr);
3392                 if (file_source)
3393                     HeapFree(GetProcessHeap(),0,file_source);
3394                 break;
3395             }
3396         }
3397
3398         dest = build_directory_name(2, dest_path, dest_name);
3399         HeapFree(GetProcessHeap(), 0, dest_path);
3400            
3401         TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),
3402               debugstr_w(dest)); 
3403         
3404         if (strcmpW(file_source,dest))
3405             rc = !CopyFileW(file_source,dest,TRUE);
3406         else
3407             rc = ERROR_SUCCESS;
3408         
3409         if (rc != ERROR_SUCCESS)
3410             ERR("Failed to copy file\n");
3411
3412         FIXME("We should track these duplicate files as well\n");   
3413  
3414         msiobj_release(&row->hdr);
3415         HeapFree(GetProcessHeap(),0,dest);
3416         HeapFree(GetProcessHeap(),0,file_source);
3417     }
3418     MSI_ViewClose(view);
3419     msiobj_release(&view->hdr);
3420     return rc;
3421 }
3422
3423
3424 /* OK this value is "interpretted" and then formatted based on the 
3425    first few characters */
3426 static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type, 
3427                          DWORD *size)
3428 {
3429     LPSTR data = NULL;
3430     if (value[0]=='#' && value[1]!='#' && value[1]!='%')
3431     {
3432         if (value[1]=='x')
3433         {
3434             LPWSTR ptr;
3435             CHAR byte[5];
3436             LPWSTR deformated;
3437             int count;
3438
3439             deformat_string(package, &value[2], &deformated);
3440
3441             /* binary value type */
3442             ptr = deformated; 
3443             *type=REG_BINARY;
3444             *size = strlenW(ptr)/2;
3445             data = HeapAlloc(GetProcessHeap(),0,*size);
3446           
3447             byte[0] = '0'; 
3448             byte[1] = 'x'; 
3449             byte[4] = 0; 
3450             count = 0;
3451             while (*ptr)
3452             {
3453                 byte[2]= *ptr;
3454                 ptr++;
3455                 byte[3]= *ptr;
3456                 ptr++;
3457                 data[count] = (BYTE)strtol(byte,NULL,0);
3458                 count ++;
3459             }
3460             HeapFree(GetProcessHeap(),0,deformated);
3461
3462             TRACE("Data %li bytes(%i)\n",*size,count);
3463         }
3464         else
3465         {
3466             LPWSTR deformated;
3467             deformat_string(package, &value[1], &deformated);
3468
3469             *type=REG_DWORD; 
3470             *size = sizeof(DWORD);
3471             data = HeapAlloc(GetProcessHeap(),0,*size);
3472             *(LPDWORD)data = atoiW(deformated); 
3473             TRACE("DWORD %i\n",*data);
3474
3475             HeapFree(GetProcessHeap(),0,deformated);
3476         }
3477     }
3478     else
3479     {
3480         WCHAR *ptr;
3481         *type=REG_SZ;
3482
3483         if (value[0]=='#')
3484         {
3485             if (value[1]=='%')
3486             {
3487                 ptr = &value[2];
3488                 *type=REG_EXPAND_SZ;
3489             }
3490             else
3491                 ptr = &value[1];
3492          }
3493          else
3494             ptr=value;
3495
3496         *size = deformat_string(package, ptr,(LPWSTR*)&data);
3497     }
3498     return data;
3499 }
3500
3501 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
3502 {
3503     UINT rc;
3504     MSIQUERY * view;
3505     MSIRECORD * row = 0;
3506     static const WCHAR ExecSeqQuery[] = {
3507         's','e','l','e','c','t',' ','*',' ',
3508         'f','r','o','m',' ','R','e','g','i','s','t','r','y',0 };
3509
3510     if (!package)
3511         return ERROR_INVALID_HANDLE;
3512
3513     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3514     if (rc != ERROR_SUCCESS)
3515         return ERROR_SUCCESS;
3516
3517     rc = MSI_ViewExecute(view, 0);
3518     if (rc != ERROR_SUCCESS)
3519     {
3520         MSI_ViewClose(view);
3521         msiobj_release(&view->hdr);
3522         return rc;
3523     }
3524
3525     /* increment progress bar each time action data is sent */
3526     ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
3527
3528     while (1)
3529     {
3530         static const WCHAR szHCR[] = 
3531 {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T','\\',0};
3532         static const WCHAR szHCU[] =
3533 {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R','\\',0};
3534         static const WCHAR szHLM[] =
3535 {'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',
3536 '\\',0};
3537         static const WCHAR szHU[] =
3538 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
3539
3540         LPSTR value_data = NULL;
3541         HKEY  root_key, hkey;
3542         DWORD type,size;
3543         LPWSTR value, key, name, component, deformated;
3544         LPCWSTR szRoot;
3545         INT component_index;
3546         MSIRECORD * uirow;
3547         LPWSTR uikey;
3548         INT   root;
3549
3550         rc = MSI_ViewFetch(view,&row);
3551         if (rc != ERROR_SUCCESS)
3552         {
3553             rc = ERROR_SUCCESS;
3554             break;
3555         }
3556         ui_progress(package,2,0,0,0);
3557
3558         value = NULL;
3559         key = NULL;
3560         uikey = NULL;
3561         name = NULL;
3562
3563         component = load_dynamic_stringW(row, 6);
3564         component_index = get_loaded_component(package,component);
3565
3566         if (package->components[component_index].ActionRequest != 
3567              INSTALLSTATE_LOCAL)
3568         {
3569             TRACE("Skipping write due to disabled component\n");
3570             msiobj_release(&row->hdr);
3571             goto next;
3572         }
3573
3574         /* null values have special meanings during uninstalls and such */
3575         
3576         if(MSI_RecordIsNull(row,5))
3577         {
3578             msiobj_release(&row->hdr);
3579             goto next;
3580         }
3581
3582         root = MSI_RecordGetInteger(row,2);
3583         key = load_dynamic_stringW(row, 3);
3584       
3585         name = load_dynamic_stringW(row, 4);
3586    
3587         /* get the root key */
3588         switch (root)
3589         {
3590             case 0:  root_key = HKEY_CLASSES_ROOT; 
3591                      szRoot = szHCR;
3592                      break;
3593             case 1:  root_key = HKEY_CURRENT_USER;
3594                      szRoot = szHCU;
3595                      break;
3596             case 2:  root_key = HKEY_LOCAL_MACHINE;
3597                      szRoot = szHLM;
3598                      break;
3599             case 3:  root_key = HKEY_USERS; 
3600                      szRoot = szHU;
3601                      break;
3602             default:
3603                  ERR("Unknown root %i\n",root);
3604                  root_key=NULL;
3605                  szRoot = NULL;
3606                  break;
3607         }
3608         if (!root_key)
3609         {
3610             msiobj_release(&row->hdr);
3611             goto next;
3612         }
3613
3614         deformat_string(package, key , &deformated);
3615         size = strlenW(deformated) + strlenW(szRoot) + 1;
3616         uikey = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR));
3617         strcpyW(uikey,szRoot);
3618         strcatW(uikey,deformated);
3619
3620         if (RegCreateKeyW( root_key, deformated, &hkey))
3621         {
3622             ERR("Could not create key %s\n",debugstr_w(deformated));
3623             msiobj_release(&row->hdr);
3624             HeapFree(GetProcessHeap(),0,deformated);
3625             goto next;
3626         }
3627         HeapFree(GetProcessHeap(),0,deformated);
3628
3629         value = load_dynamic_stringW(row,5);
3630         value_data = parse_value(package, value, &type, &size); 
3631
3632         deformat_string(package, name, &deformated);
3633
3634         if (value_data)
3635         {
3636             TRACE("Setting value %s\n",debugstr_w(deformated));
3637             RegSetValueExW(hkey, deformated, 0, type, value_data, size);
3638
3639             uirow = MSI_CreateRecord(3);
3640             MSI_RecordSetStringW(uirow,2,deformated);
3641             MSI_RecordSetStringW(uirow,1,uikey);
3642
3643             if (type == REG_SZ)
3644                 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
3645             else
3646                 MSI_RecordSetStringW(uirow,3,value);
3647
3648             ui_actiondata(package,szWriteRegistryValues,uirow);
3649             msiobj_release( &uirow->hdr );
3650
3651             HeapFree(GetProcessHeap(),0,value_data);
3652         }
3653         HeapFree(GetProcessHeap(),0,value);
3654         HeapFree(GetProcessHeap(),0,deformated);
3655
3656         msiobj_release(&row->hdr);
3657         RegCloseKey(hkey);
3658 next:
3659         if (uikey)
3660             HeapFree(GetProcessHeap(),0,uikey);
3661         if (key)
3662             HeapFree(GetProcessHeap(),0,key);
3663         if (name)
3664             HeapFree(GetProcessHeap(),0,name);
3665         if (component)
3666             HeapFree(GetProcessHeap(),0,component);
3667     }
3668     MSI_ViewClose(view);
3669     msiobj_release(&view->hdr);
3670     return rc;
3671 }
3672
3673 /*
3674  * This helper function should probably go alot of places
3675  *
3676  * Thinking about this, maybe this should become yet another Bison file
3677  */
3678 static DWORD deformat_string(MSIPACKAGE *package, WCHAR* ptr,WCHAR** data)
3679 {
3680     WCHAR* mark=NULL;
3681     DWORD size=0;
3682     DWORD chunk=0;
3683     WCHAR key[0x100];
3684     LPWSTR value;
3685     DWORD sz;
3686     UINT rc;
3687
3688     if (ptr==NULL)
3689     {
3690         TRACE("Deformatting NULL string\n");
3691         *data = NULL;
3692         return 0;
3693     }
3694     /* scan for special characters */
3695     if (!strchrW(ptr,'[') || (strchrW(ptr,'[') && !strchrW(ptr,']')))
3696     {
3697         /* not formatted */
3698         size = (strlenW(ptr)+1) * sizeof(WCHAR);
3699         *data = HeapAlloc(GetProcessHeap(),0,size);
3700         strcpyW(*data,ptr);
3701         return size;
3702     }
3703    
3704     /* formatted string located */ 
3705     mark = strchrW(ptr,'[');
3706     if (mark != ptr)
3707     {
3708         INT cnt = (mark - ptr);
3709         TRACE("%i  (%i) characters before marker\n",cnt,(mark-ptr));
3710         size = cnt * sizeof(WCHAR);
3711         size += sizeof(WCHAR);
3712         *data = HeapAlloc(GetProcessHeap(),0,size);
3713         strncpyW(*data,ptr,cnt);
3714         (*data)[cnt]=0;
3715     }
3716     else
3717     {
3718         size = sizeof(WCHAR);
3719         *data = HeapAlloc(GetProcessHeap(),0,size);
3720         (*data)[0]=0;
3721     }
3722     mark++;
3723     strcpyW(key,mark);
3724     *strchrW(key,']')=0;
3725     mark = strchrW(mark,']');
3726     mark++;
3727     TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
3728     sz = 0;
3729     rc = MSI_GetPropertyW(package, key, NULL, &sz);
3730     if ((rc == ERROR_SUCCESS) || (rc == ERROR_MORE_DATA))
3731     {
3732         LPWSTR newdata;
3733
3734         sz++;
3735         value = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR));
3736         MSI_GetPropertyW(package, key, value, &sz);
3737
3738         chunk = (strlenW(value)+1) * sizeof(WCHAR);
3739         size+=chunk;   
3740         newdata = HeapReAlloc(GetProcessHeap(),0,*data,size);
3741         *data = newdata;
3742         strcatW(*data,value);
3743     }
3744     TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
3745     if (*mark!=0)
3746     {
3747         LPWSTR newdata;
3748         chunk = (strlenW(mark)+1) * sizeof(WCHAR);
3749         size+=chunk;
3750         newdata = HeapReAlloc(GetProcessHeap(),0,*data,size);
3751         *data = newdata;
3752         strcatW(*data,mark);
3753     }
3754     (*data)[strlenW(*data)]=0;
3755     TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
3756
3757     /* recursively do this to clean up */
3758     mark = HeapAlloc(GetProcessHeap(),0,size);
3759     strcpyW(mark,*data);
3760     TRACE("String at this point %s\n",debugstr_w(mark));
3761     size = deformat_string(package,mark,data);
3762     HeapFree(GetProcessHeap(),0,mark);
3763     return size;
3764 }
3765
3766 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3767 {
3768     return ERROR_SUCCESS;
3769 }
3770
3771
3772 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3773 {
3774     DWORD progress = 0;
3775     DWORD total = 0;
3776     static const WCHAR q1[]={
3777         'S','E','L','E','C','T',' ','*',' ',
3778         'F','R','O','M',' ','R','e','g','i','s','t','r','y',0};
3779     UINT rc;
3780     MSIQUERY * view;
3781     MSIRECORD * row = 0;
3782     int i;
3783
3784     TRACE(" InstallValidate \n");
3785
3786     rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
3787     if (rc != ERROR_SUCCESS)
3788         return ERROR_SUCCESS;
3789
3790     rc = MSI_ViewExecute(view, 0);
3791     if (rc != ERROR_SUCCESS)
3792     {
3793         MSI_ViewClose(view);
3794         msiobj_release(&view->hdr);
3795         return rc;
3796     }
3797     while (1)
3798     {
3799         rc = MSI_ViewFetch(view,&row);
3800         if (rc != ERROR_SUCCESS)
3801         {
3802             rc = ERROR_SUCCESS;
3803             break;
3804         }
3805         progress +=1;
3806
3807         msiobj_release(&row->hdr);
3808     }
3809     MSI_ViewClose(view);
3810     msiobj_release(&view->hdr);
3811
3812     total = total + progress * REG_PROGRESS_VALUE;
3813     total = total + package->loaded_components * COMPONENT_PROGRESS_VALUE;
3814     for (i=0; i < package->loaded_files; i++)
3815         total += package->files[i].FileSize;
3816     ui_progress(package,0,total,0,0);
3817
3818     return ERROR_SUCCESS;
3819 }
3820
3821 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3822 {
3823     UINT rc;
3824     MSIQUERY * view = NULL;
3825     MSIRECORD * row = 0;
3826     static const WCHAR ExecSeqQuery[] = {
3827         'S','E','L','E','C','T',' ','*',' ',
3828         'f','r','o','m',' ','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n',0};
3829     static const WCHAR title[]=
3830             {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3831
3832     TRACE("Checking launch conditions\n");
3833
3834     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3835     if (rc != ERROR_SUCCESS)
3836         return ERROR_SUCCESS;
3837
3838     rc = MSI_ViewExecute(view, 0);
3839     if (rc != ERROR_SUCCESS)
3840     {
3841         MSI_ViewClose(view);
3842         msiobj_release(&view->hdr);
3843         return rc;
3844     }
3845
3846     rc = ERROR_SUCCESS;
3847     while (rc == ERROR_SUCCESS)
3848     {
3849         LPWSTR cond = NULL; 
3850         LPWSTR message = NULL;
3851
3852         rc = MSI_ViewFetch(view,&row);
3853         if (rc != ERROR_SUCCESS)
3854         {
3855             rc = ERROR_SUCCESS;
3856             break;
3857         }
3858
3859         cond = load_dynamic_stringW(row,1);
3860
3861         if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
3862         {
3863             message = load_dynamic_stringW(row,2);
3864             MessageBoxW(NULL,message,title,MB_OK);
3865             HeapFree(GetProcessHeap(),0,message);
3866             rc = ERROR_FUNCTION_FAILED;
3867         }
3868         HeapFree(GetProcessHeap(),0,cond);
3869         msiobj_release(&row->hdr);
3870     }
3871     MSI_ViewClose(view);
3872     msiobj_release(&view->hdr);
3873     return rc;
3874 }
3875
3876 static LPWSTR resolve_keypath( MSIPACKAGE* package, INT
3877                             component_index)
3878 {
3879     MSICOMPONENT* cmp = &package->components[component_index];
3880
3881     if (cmp->KeyPath[0]==0)
3882     {
3883         LPWSTR p = resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
3884         return p;
3885     }
3886     if ((cmp->Attributes & 0x4) || (cmp->Attributes & 0x20))
3887     {
3888         FIXME("UNIMPLEMENTED keypath as Registry or ODBC Source\n");
3889         return NULL;
3890     }
3891     else
3892     {
3893         int j;
3894         j = get_loaded_file(package,cmp->KeyPath);
3895
3896         if (j>=0)
3897         {
3898             LPWSTR p = dupstrW(package->files[j].TargetPath);
3899             return p;
3900         }
3901     }
3902     return NULL;
3903 }
3904
3905 /*
3906  * Ok further analysis makes me think that this work is
3907  * actually done in the PublishComponents and PublishFeatures
3908  * step, and not here.  It appears like the keypath and all that is
3909  * resolved in this step, however actually written in the Publish steps.
3910  * But we will leave it here for now because it is unclear
3911  */
3912 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3913 {
3914     LPWSTR productcode;
3915     WCHAR squished_pc[0x100];
3916     WCHAR squished_cc[0x100];
3917     UINT rc;
3918     DWORD i;
3919     HKEY hkey=0,hkey2=0,hkey3=0;
3920     static const WCHAR szProductCode[]=
3921          {'P','r','o','d','u','c','t','C','o','d','e',0};
3922     static const WCHAR szInstaller[] = {
3923          'S','o','f','t','w','a','r','e','\\',
3924          'M','i','c','r','o','s','o','f','t','\\',
3925          'W','i','n','d','o','w','s','\\',
3926          'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3927          'I','n','s','t','a','l','l','e','r',0 };
3928     static const WCHAR szFeatures[] = {
3929          'F','e','a','t','u','r','e','s',0 };
3930     static const WCHAR szComponents[] = {
3931          'C','o','m','p','o','n','e','n','t','s',0 };
3932
3933     if (!package)
3934         return ERROR_INVALID_HANDLE;
3935
3936     /* writes the Component and Features values to the registry */
3937     productcode = load_dynamic_property(package,szProductCode,&rc);
3938     if (!productcode)
3939         return rc;
3940
3941     squash_guid(productcode,squished_pc);
3942     rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,szInstaller,&hkey);
3943     if (rc != ERROR_SUCCESS)
3944         goto end;
3945
3946     rc = RegCreateKeyW(hkey,szFeatures,&hkey2);
3947     if (rc != ERROR_SUCCESS)
3948         goto end;
3949
3950     rc = RegCreateKeyW(hkey2,squished_pc,&hkey3);
3951     if (rc != ERROR_SUCCESS)
3952         goto end;
3953
3954     /* here the guids are base 85 encoded */
3955     for (i = 0; i < package->loaded_features; i++)
3956     {
3957         LPWSTR data = NULL;
3958         GUID clsid;
3959         int j;
3960         INT size;
3961
3962         size = package->features[i].ComponentCount*21*sizeof(WCHAR);
3963         data = HeapAlloc(GetProcessHeap(), 0, size);
3964
3965         data[0] = 0;
3966         for (j = 0; j < package->features[i].ComponentCount; j++)
3967         {
3968             WCHAR buf[21];
3969             TRACE("From %s\n",debugstr_w(package->components
3970                             [package->features[i].Components[j]].ComponentId));
3971             CLSIDFromString(package->components
3972                             [package->features[i].Components[j]].ComponentId,
3973                             &clsid);
3974             encode_base85_guid(&clsid,buf);
3975             TRACE("to %s\n",debugstr_w(buf));
3976             strcatW(data,buf);
3977         }
3978
3979         size = strlenW(data)*sizeof(WCHAR);
3980         RegSetValueExW(hkey3,package->features[i].Feature,0,REG_SZ,
3981                        (LPSTR)data,size);
3982         HeapFree(GetProcessHeap(),0,data);
3983     }
3984
3985     RegCloseKey(hkey3);
3986     RegCloseKey(hkey2);
3987
3988     rc = RegCreateKeyW(hkey,szComponents,&hkey2);
3989     if (rc != ERROR_SUCCESS)
3990         goto end;
3991       
3992     ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
3993     for (i = 0; i < package->loaded_components; i++)
3994     {
3995         ui_progress(package,2,0,0,0);
3996         if (package->components[i].ComponentId[0]!=0)
3997         {
3998             WCHAR *keypath = NULL;
3999             MSIRECORD * uirow;
4000
4001             squash_guid(package->components[i].ComponentId,squished_cc);
4002             rc = RegCreateKeyW(hkey2,squished_cc,&hkey3);
4003             if (rc != ERROR_SUCCESS)
4004                 continue;
4005            
4006             keypath = resolve_keypath(package,i);
4007             if (keypath)
4008             {
4009                 RegSetValueExW(hkey3,squished_pc,0,REG_SZ,(LPVOID)keypath,
4010                             (strlenW(keypath)+1)*sizeof(WCHAR));
4011                 RegCloseKey(hkey3);
4012         
4013                 /* UI stuff */
4014                 uirow = MSI_CreateRecord(3);
4015                 MSI_RecordSetStringW(uirow,1,productcode);
4016                 MSI_RecordSetStringW(uirow,2,package->components[i].
4017                                                         ComponentId);
4018                 MSI_RecordSetStringW(uirow,3,keypath);
4019                 ui_actiondata(package,szProcessComponents,uirow);
4020                 msiobj_release( &uirow->hdr );
4021                 HeapFree(GetProcessHeap(),0,keypath);
4022             }
4023         }
4024     } 
4025 end:
4026     HeapFree(GetProcessHeap(), 0, productcode);
4027     RegCloseKey(hkey2);
4028     RegCloseKey(hkey);
4029     return rc;
4030 }
4031
4032 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
4033 {
4034     /* 
4035      * OK this is a bit confusing.. I am given a _Component key and I believe
4036      * that the file that is being registered as a type library is the "key file
4037      * of that component" which I interpret to mean "The file in the KeyPath of
4038      * that component".
4039      */
4040     UINT rc;
4041     MSIQUERY * view;
4042     MSIRECORD * row = 0;
4043     static const WCHAR Query[] = {
4044         'S','E','L','E','C','T',' ','*',' ',
4045         'f','r','o','m',' ','T','y','p','e','L','i','b',0};
4046     ITypeLib *ptLib;
4047     HRESULT res;
4048
4049     if (!package)
4050         return ERROR_INVALID_HANDLE;
4051
4052     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
4053     if (rc != ERROR_SUCCESS)
4054         return ERROR_SUCCESS;
4055
4056     rc = MSI_ViewExecute(view, 0);
4057     if (rc != ERROR_SUCCESS)
4058     {
4059         MSI_ViewClose(view);
4060         msiobj_release(&view->hdr);
4061         return rc;
4062     }
4063
4064     while (1)
4065     {   
4066         WCHAR component[0x100];
4067         DWORD sz;
4068         INT index;
4069
4070         rc = MSI_ViewFetch(view,&row);
4071         if (rc != ERROR_SUCCESS)
4072         {
4073             rc = ERROR_SUCCESS;
4074             break;
4075         }
4076
4077         sz = 0x100;
4078         MSI_RecordGetStringW(row,3,component,&sz);
4079
4080         index = get_loaded_component(package,component);
4081         if (index < 0)
4082         {
4083             msiobj_release(&row->hdr);
4084             continue;
4085         }
4086
4087         if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)
4088         {
4089             TRACE("Skipping typelib reg due to disabled component\n");
4090             msiobj_release(&row->hdr);
4091             continue;
4092         }
4093
4094         index = get_loaded_file(package,package->components[index].KeyPath); 
4095    
4096         if (index < 0)
4097         {
4098             msiobj_release(&row->hdr);
4099             continue;
4100         }
4101
4102         res = LoadTypeLib(package->files[index].TargetPath,&ptLib);
4103         if (SUCCEEDED(res))
4104         {
4105             LPWSTR help;
4106             WCHAR helpid[0x100];
4107
4108             sz = 0x100;
4109             MSI_RecordGetStringW(row,6,helpid,&sz);
4110
4111             help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
4112             res = RegisterTypeLib(ptLib,package->files[index].TargetPath,help);
4113             HeapFree(GetProcessHeap(),0,help);
4114
4115             if (!SUCCEEDED(res))
4116                 ERR("Failed to register type library %s\n",
4117                      debugstr_w(package->files[index].TargetPath));
4118             else
4119             {
4120                 /* Yes the row has more fields than I need, but #1 is 
4121                    correct and the only one I need. Why make a new row? */
4122
4123                 ui_actiondata(package,szRegisterTypeLibraries,row);
4124                 
4125                 TRACE("Registered %s\n",
4126                        debugstr_w(package->files[index].TargetPath));
4127             }
4128
4129             if (ptLib)
4130                 ITypeLib_Release(ptLib);
4131         }
4132         else
4133             ERR("Failed to load type library %s\n",
4134                 debugstr_w(package->files[index].TargetPath));
4135         
4136         msiobj_release(&row->hdr);
4137     }
4138     MSI_ViewClose(view);
4139     msiobj_release(&view->hdr);
4140     return rc;
4141    
4142 }
4143
4144 static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app )
4145 {
4146     static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
4147     UINT rc;
4148     MSIQUERY * view;
4149     MSIRECORD * row = 0;
4150     static const WCHAR ExecSeqQuery[] = 
4151         {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','p','p','I'
4152         ,'d',' ','w','h','e','r','e',' ','A','p','p','I','d','=','`','%','s','`',0};
4153     HKEY hkey2,hkey3;
4154     LPWSTR buffer=0;
4155
4156     if (!package)
4157         return ERROR_INVALID_HANDLE;
4158
4159     rc = ACTION_OpenQuery(package->db, &view, ExecSeqQuery, clsid);
4160     if (rc != ERROR_SUCCESS)
4161         return rc;
4162
4163     rc = MSI_ViewExecute(view, 0);
4164     if (rc != ERROR_SUCCESS)
4165     {
4166         MSI_ViewClose(view);
4167         msiobj_release(&view->hdr);
4168         return rc;
4169     }
4170
4171     RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
4172     RegCreateKeyW(hkey2,clsid,&hkey3);
4173     RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app,
4174                    (strlenW(app)+1)*sizeof(WCHAR));
4175
4176     rc = MSI_ViewFetch(view,&row);
4177     if (rc != ERROR_SUCCESS)
4178     {
4179         MSI_ViewClose(view);
4180         msiobj_release(&view->hdr);
4181         return rc;
4182     }
4183
4184     if (!MSI_RecordIsNull(row,2)) 
4185     {
4186         LPWSTR deformated=0;
4187         UINT size; 
4188         static const WCHAR szRemoteServerName[] =
4189              {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0};
4190         buffer = load_dynamic_stringW(row,2);
4191         size = deformat_string(package,buffer,&deformated);
4192         RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,(LPVOID)deformated,
4193                        size);
4194         HeapFree(GetProcessHeap(),0,deformated);
4195         HeapFree(GetProcessHeap(),0,buffer);
4196     }
4197
4198     if (!MSI_RecordIsNull(row,3)) 
4199     {
4200         static const WCHAR szLocalService[] =
4201              {'L','o','c','a','l','S','e','r','v','i','c','e',0};
4202         UINT size;
4203         buffer = load_dynamic_stringW(row,3);
4204         size = (strlenW(buffer)+1) * sizeof(WCHAR);
4205         RegSetValueExW(hkey3,szLocalService,0,REG_SZ,(LPVOID)buffer,size);
4206         HeapFree(GetProcessHeap(),0,buffer);
4207     }
4208
4209     if (!MSI_RecordIsNull(row,4)) 
4210     {
4211         static const WCHAR szService[] =
4212              {'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0};
4213         UINT size;
4214         buffer = load_dynamic_stringW(row,4);
4215         size = (strlenW(buffer)+1) * sizeof(WCHAR);
4216         RegSetValueExW(hkey3,szService,0,REG_SZ,(LPVOID)buffer,size);
4217         HeapFree(GetProcessHeap(),0,buffer);
4218     }
4219
4220     if (!MSI_RecordIsNull(row,5)) 
4221     {
4222         static const WCHAR szDLL[] =
4223              {'D','l','l','S','u','r','r','o','g','a','t','e',0};
4224         UINT size;
4225         buffer = load_dynamic_stringW(row,5);
4226         size = (strlenW(buffer)+1) * sizeof(WCHAR);
4227         RegSetValueExW(hkey3,szDLL,0,REG_SZ,(LPVOID)buffer,size);
4228         HeapFree(GetProcessHeap(),0,buffer);
4229     }
4230
4231     if (!MSI_RecordIsNull(row,6)) 
4232     {
4233         static const WCHAR szActivate[] =
4234              {'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0};
4235         static const WCHAR szY[] = {'Y',0};
4236
4237         if (MSI_RecordGetInteger(row,6))
4238             RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4);
4239     }
4240
4241     if (!MSI_RecordIsNull(row,7)) 
4242     {
4243         static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
4244         static const WCHAR szUser[] = 
4245              {'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0};
4246
4247         if (MSI_RecordGetInteger(row,7))
4248             RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,34);
4249     }
4250
4251     msiobj_release(&row->hdr);
4252     MSI_ViewClose(view);
4253     msiobj_release(&view->hdr);
4254     RegCloseKey(hkey3);
4255     RegCloseKey(hkey2);
4256     return rc;
4257 }
4258
4259 static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
4260 {
4261     /* 
4262      * Again I am assuming the words, "Whose key file represents" when referring
4263      * to a Component as to meaning that Components KeyPath file
4264      *
4265      * Also there is a very strong connection between ClassInfo and ProgID
4266      * that I am mostly glossing over.  
4267      * What would be more propper is to load the ClassInfo and the ProgID info
4268      * into memory data structures and then be able to enable and disable them
4269      * based on component. 
4270      */
4271     
4272     UINT rc;
4273     MSIQUERY * view;
4274     MSIRECORD * row = 0;
4275     static const WCHAR ExecSeqQuery[] = {
4276         'S','E','L','E','C','T',' ','*',' ',
4277         'f','r','o','m',' ','C','l','a','s','s',0};
4278     static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
4279     static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 };
4280     static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
4281     HKEY hkey,hkey2,hkey3;
4282
4283     if (!package)
4284         return ERROR_INVALID_HANDLE;
4285
4286     rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
4287     if (rc != ERROR_SUCCESS)
4288         return ERROR_FUNCTION_FAILED;
4289
4290     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4291     if (rc != ERROR_SUCCESS)
4292     {
4293         rc = ERROR_SUCCESS;
4294         goto end;
4295     }
4296
4297     rc = MSI_ViewExecute(view, 0);
4298     if (rc != ERROR_SUCCESS)
4299     {
4300         MSI_ViewClose(view);
4301         msiobj_release(&view->hdr);
4302         goto end;
4303     }
4304
4305     while (1)
4306     {
4307         WCHAR clsid[0x100];
4308         WCHAR buffer[0x100];
4309         WCHAR desc[0x100];
4310         DWORD sz;
4311         INT index;
4312      
4313         rc = MSI_ViewFetch(view,&row);
4314         if (rc != ERROR_SUCCESS)
4315         {
4316             rc = ERROR_SUCCESS;
4317             break;
4318         }
4319
4320         sz=0x100;
4321         MSI_RecordGetStringW(row,3,buffer,&sz);
4322
4323         index = get_loaded_component(package,buffer);
4324
4325         if (index < 0)
4326         {
4327             msiobj_release(&row->hdr);
4328             continue;
4329         }
4330
4331         if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)
4332         {
4333             TRACE("Skipping class reg due to disabled component\n");
4334             msiobj_release(&row->hdr);
4335             continue;
4336         }
4337
4338         sz=0x100;
4339         MSI_RecordGetStringW(row,1,clsid,&sz);
4340         RegCreateKeyW(hkey,clsid,&hkey2);
4341
4342         if (!MSI_RecordIsNull(row,5))
4343         {
4344             sz=0x100;
4345             MSI_RecordGetStringW(row,5,desc,&sz);
4346
4347             RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)desc,
4348                            (strlenW(desc)+1)*sizeof(WCHAR));
4349         }
4350         else
4351             desc[0]=0;
4352
4353         sz=0x100;
4354         MSI_RecordGetStringW(row,2,buffer,&sz);
4355
4356         RegCreateKeyW(hkey2,buffer,&hkey3);
4357
4358         index = get_loaded_file(package,package->components[index].KeyPath);
4359         RegSetValueExW(hkey3,NULL,0,REG_SZ,
4360                        (LPVOID)package->files[index].TargetPath,
4361                        (strlenW(package->files[index].TargetPath)+1)
4362                         *sizeof(WCHAR));
4363
4364         RegCloseKey(hkey3);
4365
4366         if (!MSI_RecordIsNull(row,4))
4367         {
4368             sz=0x100;
4369             MSI_RecordGetStringW(row,4,buffer,&sz);
4370
4371             RegCreateKeyW(hkey2,szProgID,&hkey3);
4372     
4373             RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)buffer,
4374                        (strlenW(buffer)+1)*sizeof(WCHAR));
4375
4376             RegCloseKey(hkey3);
4377         }
4378
4379         if (!MSI_RecordIsNull(row,6))
4380         { 
4381             sz=0x100;
4382             MSI_RecordGetStringW(row,6,buffer,&sz);
4383
4384             RegSetValueExW(hkey2,szAppID,0,REG_SZ,(LPVOID)buffer,
4385                        (strlenW(buffer)+1)*sizeof(WCHAR));
4386
4387             register_appid(package,buffer,desc);
4388         }
4389
4390         RegCloseKey(hkey2);
4391
4392         FIXME("Process the rest of the fields >7\n");
4393
4394         ui_actiondata(package,szRegisterClassInfo,row);
4395
4396         msiobj_release(&row->hdr);
4397     }
4398     MSI_ViewClose(view);
4399     msiobj_release(&view->hdr);
4400
4401 end:
4402     RegCloseKey(hkey);
4403     return rc;
4404 }
4405
4406 static UINT register_progid_base(MSIRECORD * row, LPWSTR clsid)
4407 {
4408     static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
4409     HKEY hkey,hkey2;
4410     WCHAR buffer[0x100];
4411     DWORD sz;
4412
4413
4414     sz = 0x100;
4415     MSI_RecordGetStringW(row,1,buffer,&sz);
4416     RegCreateKeyW(HKEY_CLASSES_ROOT,buffer,&hkey);
4417
4418     if (!MSI_RecordIsNull(row,4))
4419     {
4420         sz = 0x100;
4421         MSI_RecordGetStringW(row,4,buffer,&sz);
4422         RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
4423                        sizeof(WCHAR));
4424     }
4425
4426     if (!MSI_RecordIsNull(row,3))
4427     {   
4428         sz = 0x100;
4429     
4430         MSI_RecordGetStringW(row,3,buffer,&sz);
4431         RegCreateKeyW(hkey,szCLSID,&hkey2);
4432         RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
4433                        sizeof(WCHAR));
4434
4435         if (clsid)
4436             strcpyW(clsid,buffer);
4437
4438         RegCloseKey(hkey2);
4439     }
4440     else
4441     {
4442         FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
4443         return ERROR_FUNCTION_FAILED;
4444     }
4445     if (!MSI_RecordIsNull(row,5))
4446         FIXME ("UNHANDLED icon in Progid\n");
4447     return ERROR_SUCCESS;
4448 }
4449
4450 static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid);
4451
4452 static UINT register_parent_progid(MSIPACKAGE *package, LPCWSTR parent, 
4453                                    LPWSTR clsid)
4454 {
4455     UINT rc;
4456     MSIQUERY * view;
4457     MSIRECORD * row = 0;
4458     static const WCHAR Query_t[] = 
4459         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','r','o','g'
4460         ,'I','d',' ','w','h','e','r','e',' ','P','r','o','g','I','d',' ','=',' ','`'
4461         ,'%','s','`',0};
4462
4463     if (!package)
4464         return ERROR_INVALID_HANDLE;
4465
4466     rc = ACTION_OpenQuery(package->db, &view, Query_t, parent);
4467     if (rc != ERROR_SUCCESS)
4468         return rc;
4469
4470     rc = MSI_ViewExecute(view, 0);
4471     if (rc != ERROR_SUCCESS)
4472     {
4473         MSI_ViewClose(view);
4474         msiobj_release(&view->hdr);
4475         return rc;
4476     }
4477
4478     rc = MSI_ViewFetch(view,&row);
4479     if (rc != ERROR_SUCCESS)
4480     {
4481         MSI_ViewClose(view);
4482         msiobj_release(&view->hdr);
4483         return rc;
4484     }
4485
4486     register_progid(package,row,clsid);
4487
4488     msiobj_release(&row->hdr);
4489     MSI_ViewClose(view);
4490     msiobj_release(&view->hdr);
4491     return rc;
4492 }
4493
4494 static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid)
4495 {
4496     UINT rc = ERROR_SUCCESS; 
4497
4498     if (MSI_RecordIsNull(row,2))
4499         rc = register_progid_base(row,clsid);
4500     else
4501     {
4502         WCHAR buffer[0x1000];
4503         DWORD sz, disp;
4504         HKEY hkey,hkey2;
4505         static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
4506
4507         /* check if already registered */
4508         sz = 0x100;
4509         MSI_RecordGetStringW(row,1,buffer,&sz);
4510         RegCreateKeyExW(HKEY_CLASSES_ROOT, buffer, 0, NULL, 0,
4511                         KEY_ALL_ACCESS, NULL, &hkey, &disp );
4512         if (disp == REG_OPENED_EXISTING_KEY)
4513         {
4514             TRACE("Key already registered\n");
4515             RegCloseKey(hkey);
4516             return rc;
4517         }
4518         /* clsid is same as parent */
4519         RegCreateKeyW(hkey,szCLSID,&hkey2);
4520         RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) *
4521                        sizeof(WCHAR));
4522
4523         RegCloseKey(hkey2);
4524
4525         sz = 0x100;
4526         MSI_RecordGetStringW(row,2,buffer,&sz);
4527         rc = register_parent_progid(package,buffer,clsid);
4528
4529         if (!MSI_RecordIsNull(row,4))
4530         {
4531             sz = 0x100;
4532             MSI_RecordGetStringW(row,4,buffer,&sz);
4533             RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer,
4534                            (strlenW(buffer)+1) * sizeof(WCHAR));
4535         }
4536
4537         if (!MSI_RecordIsNull(row,5))
4538             FIXME ("UNHANDLED icon in Progid\n");
4539
4540         RegCloseKey(hkey);
4541     }
4542     return rc;
4543 }
4544
4545 static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
4546 {
4547     /* 
4548      * Sigh, here I am just brute force registering all progids
4549      * this needs to be linked to the Classes that have been registered
4550      * but the easiest way to do that is to load all these stuff into
4551      * memory for easy checking.
4552      *
4553      * Gives me something to continue to work toward.
4554      */
4555     UINT rc;
4556     MSIQUERY * view;
4557     MSIRECORD * row = 0;
4558     static const WCHAR Query[] = {
4559         'S','E','L','E','C','T',' ','*',' ',
4560         'F','R','O','M',' ','P','r','o','g','I','d',0};
4561
4562     if (!package)
4563         return ERROR_INVALID_HANDLE;
4564
4565     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
4566     if (rc != ERROR_SUCCESS)
4567         return ERROR_SUCCESS;
4568
4569     rc = MSI_ViewExecute(view, 0);
4570     if (rc != ERROR_SUCCESS)
4571     {
4572         MSI_ViewClose(view);
4573         msiobj_release(&view->hdr);
4574         return rc;
4575     }
4576
4577     while (1)
4578     {
4579         WCHAR clsid[0x1000];
4580
4581         rc = MSI_ViewFetch(view,&row);
4582         if (rc != ERROR_SUCCESS)
4583         {
4584             rc = ERROR_SUCCESS;
4585             break;
4586         }
4587         
4588         register_progid(package,row,clsid);
4589         ui_actiondata(package,szRegisterProgIdInfo,row);
4590
4591         msiobj_release(&row->hdr);
4592     }
4593     MSI_ViewClose(view);
4594     msiobj_release(&view->hdr);
4595     return rc;
4596 }
4597
4598 static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, 
4599                             LPWSTR *FilePath)
4600 {
4601     LPWSTR ProductCode;
4602     LPWSTR SystemFolder;
4603     LPWSTR dest;
4604     UINT rc;
4605
4606     static const WCHAR szInstaller[] = 
4607         {'I','n','s','t','a','l','l','e','r','\\',0};
4608     static const WCHAR szProductCode[] =
4609         {'P','r','o','d','u','c','t','C','o','d','e',0};
4610     static const WCHAR szFolder[] =
4611         {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
4612
4613     ProductCode = load_dynamic_property(package,szProductCode,&rc);
4614     if (!ProductCode)
4615         return rc;
4616
4617     SystemFolder = load_dynamic_property(package,szFolder,NULL);
4618
4619     dest = build_directory_name(3, SystemFolder, szInstaller, ProductCode);
4620
4621     create_full_pathW(dest);
4622
4623     *FilePath = build_directory_name(2, dest, icon_name);
4624
4625     HeapFree(GetProcessHeap(),0,SystemFolder);
4626     HeapFree(GetProcessHeap(),0,ProductCode);
4627     HeapFree(GetProcessHeap(),0,dest);
4628     return ERROR_SUCCESS;
4629 }
4630
4631 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
4632 {
4633     UINT rc;
4634     MSIQUERY * view;
4635     MSIRECORD * row = 0;
4636     static const WCHAR Query[] = {
4637        'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ',
4638        'S','h','o','r','t','c','u','t',0};
4639     IShellLinkW *sl;
4640     IPersistFile *pf;
4641     HRESULT res;
4642
4643     if (!package)
4644         return ERROR_INVALID_HANDLE;
4645
4646     res = CoInitialize( NULL );
4647     if (FAILED (res))
4648     {
4649         ERR("CoInitialize failed\n");
4650         return ERROR_FUNCTION_FAILED;
4651     }
4652
4653     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
4654     if (rc != ERROR_SUCCESS)
4655         return ERROR_SUCCESS;
4656
4657     rc = MSI_ViewExecute(view, 0);
4658     if (rc != ERROR_SUCCESS)
4659     {
4660         MSI_ViewClose(view);
4661         msiobj_release(&view->hdr);
4662         return rc;
4663     }
4664
4665     while (1)
4666     {
4667         LPWSTR target_file, target_folder;
4668         WCHAR buffer[0x100];
4669         DWORD sz;
4670         DWORD index;
4671         static const WCHAR szlnk[]={'.','l','n','k',0};
4672
4673         rc = MSI_ViewFetch(view,&row);
4674         if (rc != ERROR_SUCCESS)
4675         {
4676             rc = ERROR_SUCCESS;
4677             break;
4678         }
4679         
4680         sz = 0x100;
4681         MSI_RecordGetStringW(row,4,buffer,&sz);
4682
4683         index = get_loaded_component(package,buffer);
4684
4685         if (index < 0)
4686         {
4687             msiobj_release(&row->hdr);
4688             continue;
4689         }
4690
4691         if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)
4692         {
4693             TRACE("Skipping shortcut creation due to disabled component\n");
4694             msiobj_release(&row->hdr);
4695             continue;
4696         }
4697
4698         ui_actiondata(package,szCreateShortcuts,row);
4699
4700         res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
4701                               &IID_IShellLinkW, (LPVOID *) &sl );
4702
4703         if (FAILED(res))
4704         {
4705             ERR("Is IID_IShellLink\n");
4706             msiobj_release(&row->hdr);
4707             continue;
4708         }
4709
4710         res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
4711         if( FAILED( res ) )
4712         {
4713             ERR("Is IID_IPersistFile\n");
4714             msiobj_release(&row->hdr);
4715             continue;
4716         }
4717
4718         sz = 0x100;
4719         MSI_RecordGetStringW(row,2,buffer,&sz);
4720         target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
4721
4722         /* may be needed because of a bug somehwere else */
4723         create_full_pathW(target_folder);
4724
4725         sz = 0x100;
4726         MSI_RecordGetStringW(row,3,buffer,&sz);
4727         reduce_to_longfilename(buffer);
4728         if (!strchrW(buffer,'.') || strcmpiW(strchrW(buffer,'.'),szlnk))
4729             strcatW(buffer,szlnk);
4730         target_file = build_directory_name(2, target_folder, buffer);
4731         HeapFree(GetProcessHeap(),0,target_folder);
4732
4733         sz = 0x100;
4734         MSI_RecordGetStringW(row,5,buffer,&sz);
4735         if (strchrW(buffer,'['))
4736         {
4737             LPWSTR deformated;
4738             deformat_string(package,buffer,&deformated);
4739             IShellLinkW_SetPath(sl,deformated);
4740             HeapFree(GetProcessHeap(),0,deformated);
4741         }
4742         else
4743         {
4744             FIXME("UNHANDLED shortcut format, advertised shortcut\n");
4745             IPersistFile_Release( pf );
4746             IShellLinkW_Release( sl );
4747             msiobj_release(&row->hdr);
4748             continue;
4749         }
4750
4751         if (!MSI_RecordIsNull(row,6))
4752         {
4753             LPWSTR deformated;
4754             sz = 0x100;
4755             MSI_RecordGetStringW(row,6,buffer,&sz);
4756             deformat_string(package,buffer,&deformated);
4757             IShellLinkW_SetArguments(sl,deformated);
4758             HeapFree(GetProcessHeap(),0,deformated);
4759         }
4760
4761         if (!MSI_RecordIsNull(row,7))
4762         {
4763             LPWSTR deformated;
4764             deformated = load_dynamic_stringW(row,7);
4765             IShellLinkW_SetDescription(sl,deformated);
4766             HeapFree(GetProcessHeap(),0,deformated);
4767         }
4768
4769         if (!MSI_RecordIsNull(row,8))
4770             IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
4771
4772         if (!MSI_RecordIsNull(row,9))
4773         {
4774             WCHAR *Path = NULL;
4775             INT index; 
4776
4777             sz = 0x100;
4778             MSI_RecordGetStringW(row,9,buffer,&sz);
4779
4780             build_icon_path(package,buffer,&Path);
4781             index = MSI_RecordGetInteger(row,10);
4782
4783             IShellLinkW_SetIconLocation(sl,Path,index);
4784             HeapFree(GetProcessHeap(),0,Path);
4785         }
4786
4787         if (!MSI_RecordIsNull(row,11))
4788             IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
4789
4790         if (!MSI_RecordIsNull(row,12))
4791         {
4792             LPWSTR Path;
4793             sz = 0x100;
4794             MSI_RecordGetStringW(row,12,buffer,&sz);
4795             Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
4796             IShellLinkW_SetWorkingDirectory(sl,Path);
4797             HeapFree(GetProcessHeap(), 0, Path);
4798         }
4799
4800         TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
4801         IPersistFile_Save(pf,target_file,FALSE);
4802     
4803         HeapFree(GetProcessHeap(),0,target_file);    
4804
4805         IPersistFile_Release( pf );
4806         IShellLinkW_Release( sl );
4807
4808         msiobj_release(&row->hdr);
4809     }
4810     MSI_ViewClose(view);
4811     msiobj_release(&view->hdr);
4812
4813
4814     CoUninitialize();
4815
4816     return rc;
4817 }
4818
4819
4820 /*
4821  * 99% of the work done here is only done for 
4822  * advertised installs. However this is where the
4823  * Icon table is processed and written out
4824  * so that is what I am going to do here.
4825  */
4826 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4827 {
4828     UINT rc;
4829     MSIQUERY * view;
4830     MSIRECORD * row = 0;
4831     static const WCHAR Query[]={
4832         'S','E','L','E','C','T',' ','*',' ',
4833         'f','r','o','m',' ','I','c','o','n',0};
4834     DWORD sz;
4835
4836     if (!package)
4837         return ERROR_INVALID_HANDLE;
4838
4839     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
4840     if (rc != ERROR_SUCCESS)
4841         return ERROR_SUCCESS;
4842
4843     rc = MSI_ViewExecute(view, 0);
4844     if (rc != ERROR_SUCCESS)
4845     {
4846         MSI_ViewClose(view);
4847         msiobj_release(&view->hdr);
4848         return rc;
4849     }
4850
4851     while (1)
4852     {
4853         HANDLE the_file;
4854         WCHAR *FilePath=NULL;
4855         WCHAR *FileName=NULL;
4856         CHAR buffer[1024];
4857
4858         rc = MSI_ViewFetch(view,&row);
4859         if (rc != ERROR_SUCCESS)
4860         {
4861             rc = ERROR_SUCCESS;
4862             break;
4863         }
4864     
4865         FileName = load_dynamic_stringW(row,1);
4866         if (!FileName)
4867         {
4868             ERR("Unable to get FileName\n");
4869             msiobj_release(&row->hdr);
4870             continue;
4871         }
4872
4873         build_icon_path(package,FileName,&FilePath);
4874
4875         HeapFree(GetProcessHeap(),0,FileName);
4876
4877         TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
4878         
4879         the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
4880                            FILE_ATTRIBUTE_NORMAL, NULL);
4881
4882         if (the_file == INVALID_HANDLE_VALUE)
4883         {
4884             ERR("Unable to create file %s\n",debugstr_w(FilePath));
4885             msiobj_release(&row->hdr);
4886             HeapFree(GetProcessHeap(),0,FilePath);
4887             continue;
4888         }
4889
4890         do 
4891         {
4892             DWORD write;
4893             sz = 1024;
4894             rc = MSI_RecordReadStream(row,2,buffer,&sz);
4895             if (rc != ERROR_SUCCESS)
4896             {
4897                 ERR("Failed to get stream\n");
4898                 CloseHandle(the_file);  
4899                 DeleteFileW(FilePath);
4900                 break;
4901             }
4902             WriteFile(the_file,buffer,sz,&write,NULL);
4903         } while (sz == 1024);
4904
4905         HeapFree(GetProcessHeap(),0,FilePath);
4906
4907         CloseHandle(the_file);
4908         msiobj_release(&row->hdr);
4909     }
4910     MSI_ViewClose(view);
4911     msiobj_release(&view->hdr);
4912     return rc;
4913
4914 }
4915
4916 /* Msi functions that seem appropriate here */
4917 UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
4918 {
4919     LPWSTR szwAction;
4920     UINT rc;
4921
4922     TRACE(" exteral attempt at action %s\n",szAction);
4923
4924     if (!szAction)
4925         return ERROR_FUNCTION_FAILED;
4926     if (hInstall == 0)
4927         return ERROR_FUNCTION_FAILED;
4928
4929     szwAction = strdupAtoW(szAction);
4930
4931     if (!szwAction)
4932         return ERROR_FUNCTION_FAILED; 
4933
4934
4935     rc = MsiDoActionW(hInstall, szwAction);
4936     HeapFree(GetProcessHeap(),0,szwAction);
4937     return rc;
4938 }
4939
4940 UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction )
4941 {
4942     MSIPACKAGE *package;
4943     UINT ret = ERROR_INVALID_HANDLE;
4944
4945     TRACE(" external attempt at action %s \n",debugstr_w(szAction));
4946
4947     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4948     if( package )
4949     {
4950         ret = ACTION_PerformAction(package,szAction);
4951         msiobj_release( &package->hdr );
4952     }
4953     return ret;
4954 }
4955
4956 UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder, 
4957                                LPSTR szPathBuf, DWORD* pcchPathBuf) 
4958 {
4959     LPWSTR szwFolder;
4960     LPWSTR szwPathBuf;
4961     UINT rc;
4962
4963     TRACE("getting folder %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
4964
4965     if (!szFolder)
4966         return ERROR_FUNCTION_FAILED;
4967     if (hInstall == 0)
4968         return ERROR_FUNCTION_FAILED;
4969
4970     szwFolder = strdupAtoW(szFolder);
4971
4972     if (!szwFolder)
4973         return ERROR_FUNCTION_FAILED; 
4974
4975     szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
4976
4977     rc = MsiGetTargetPathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
4978
4979     WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
4980                          *pcchPathBuf, NULL, NULL );
4981
4982     HeapFree(GetProcessHeap(),0,szwFolder);
4983     HeapFree(GetProcessHeap(),0,szwPathBuf);
4984
4985     return rc;
4986 }
4987
4988 UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
4989                                 szPathBuf, DWORD* pcchPathBuf) 
4990 {
4991     LPWSTR path;
4992     UINT rc = ERROR_FUNCTION_FAILED;
4993     MSIPACKAGE *package;
4994
4995     TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
4996
4997     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4998     if (!package)
4999         return ERROR_INVALID_HANDLE;
5000     path = resolve_folder(package, szFolder, FALSE, FALSE, NULL);
5001     msiobj_release( &package->hdr );
5002
5003     if (path && (strlenW(path) > *pcchPathBuf))
5004     {
5005         *pcchPathBuf = strlenW(path)+1;
5006         rc = ERROR_MORE_DATA;
5007     }
5008     else if (path)
5009     {
5010         *pcchPathBuf = strlenW(path)+1;
5011         strcpyW(szPathBuf,path);
5012         TRACE("Returning Path %s\n",debugstr_w(path));
5013         rc = ERROR_SUCCESS;
5014     }
5015     HeapFree(GetProcessHeap(),0,path);
5016     
5017     return rc;
5018 }
5019
5020
5021 UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder, 
5022                                LPSTR szPathBuf, DWORD* pcchPathBuf) 
5023 {
5024     LPWSTR szwFolder;
5025     LPWSTR szwPathBuf;
5026     UINT rc;
5027
5028     TRACE("getting source %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
5029
5030     if (!szFolder)
5031         return ERROR_FUNCTION_FAILED;
5032     if (hInstall == 0)
5033         return ERROR_FUNCTION_FAILED;
5034
5035     szwFolder = strdupAtoW(szFolder);
5036     if (!szwFolder)
5037         return ERROR_FUNCTION_FAILED; 
5038
5039     szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
5040
5041     rc = MsiGetSourcePathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
5042
5043     WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
5044                          *pcchPathBuf, NULL, NULL );
5045
5046     HeapFree(GetProcessHeap(),0,szwFolder);
5047     HeapFree(GetProcessHeap(),0,szwPathBuf);
5048
5049     return rc;
5050 }
5051
5052 UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
5053                                 szPathBuf, DWORD* pcchPathBuf) 
5054 {
5055     LPWSTR path;
5056     UINT rc = ERROR_FUNCTION_FAILED;
5057     MSIPACKAGE *package;
5058
5059     TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
5060
5061     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
5062     if( !package )
5063         return ERROR_INVALID_HANDLE;
5064     path = resolve_folder(package, szFolder, TRUE, FALSE, NULL);
5065     msiobj_release( &package->hdr );
5066
5067     if (path && strlenW(path) > *pcchPathBuf)
5068     {
5069         *pcchPathBuf = strlenW(path)+1;
5070         rc = ERROR_MORE_DATA;
5071     }
5072     else if (path)
5073     {
5074         *pcchPathBuf = strlenW(path)+1;
5075         strcpyW(szPathBuf,path);
5076         TRACE("Returning Path %s\n",debugstr_w(path));
5077         rc = ERROR_SUCCESS;
5078     }
5079     HeapFree(GetProcessHeap(),0,path);
5080     
5081     return rc;
5082 }
5083
5084
5085 UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder, 
5086                              LPCSTR szFolderPath)
5087 {
5088     LPWSTR szwFolder;
5089     LPWSTR szwFolderPath;
5090     UINT rc;
5091
5092     if (!szFolder)
5093         return ERROR_FUNCTION_FAILED;
5094     if (hInstall == 0)
5095         return ERROR_FUNCTION_FAILED;
5096
5097     szwFolder = strdupAtoW(szFolder);
5098     if (!szwFolder)
5099         return ERROR_FUNCTION_FAILED; 
5100
5101     szwFolderPath = strdupAtoW(szFolderPath);
5102     if (!szwFolderPath)
5103     {
5104         HeapFree(GetProcessHeap(),0,szwFolder);
5105         return ERROR_FUNCTION_FAILED; 
5106     }
5107
5108     rc = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath);
5109
5110     HeapFree(GetProcessHeap(),0,szwFolder);
5111     HeapFree(GetProcessHeap(),0,szwFolderPath);
5112
5113     return rc;
5114 }
5115
5116 UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder, 
5117                              LPCWSTR szFolderPath)
5118 {
5119     DWORD i;
5120     LPWSTR path = NULL;
5121     LPWSTR path2 = NULL;
5122     INT len;
5123     MSIFOLDER *folder;
5124
5125     TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
5126
5127     if (package==NULL)
5128         return ERROR_INVALID_HANDLE;
5129
5130     if (szFolderPath[0]==0)
5131         return ERROR_FUNCTION_FAILED;
5132
5133     if (GetFileAttributesW(szFolderPath) == INVALID_FILE_ATTRIBUTES)
5134         return ERROR_FUNCTION_FAILED;
5135
5136     path = resolve_folder(package,szFolder,FALSE,FALSE,&folder);
5137
5138     if (!path)
5139         return ERROR_INVALID_PARAMETER;
5140
5141     if (folder->Property)
5142         HeapFree(GetProcessHeap(),0,folder->Property);
5143
5144     len = strlenW(szFolderPath);
5145
5146     if (szFolderPath[len-1]!='\\')
5147     {
5148         len +=2;
5149         folder->Property = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
5150         strcpyW(folder->Property,szFolderPath);
5151         strcatW(folder->Property,cszbs);
5152     }
5153     else
5154         folder->Property = dupstrW(szFolderPath);
5155
5156     if (strcmpiW(path, szFolderPath) == 0)
5157     {
5158         /*
5159          *  Resolved Target has not really changed, so just 
5160          *  set this folder and do not recalculate everything.
5161          */
5162         HeapFree(GetProcessHeap(),0,folder->ResolvedTarget);
5163         folder->ResolvedTarget = NULL;
5164         path2 = resolve_folder(package,szFolder,FALSE,TRUE,NULL);
5165         HeapFree(GetProcessHeap(),0,path2);
5166     }
5167     else
5168     {
5169         for (i = 0; i < package->loaded_folders; i++)
5170         {
5171             if (package->folders[i].ResolvedTarget)
5172                 HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
5173             package->folders[i].ResolvedTarget=NULL;
5174         }
5175
5176         for (i = 0; i < package->loaded_folders; i++)
5177         {
5178             path2=resolve_folder(package, package->folders[i].Directory, FALSE,
5179                        TRUE, NULL);
5180             HeapFree(GetProcessHeap(),0,path2);
5181         }
5182     }
5183     HeapFree(GetProcessHeap(),0,path);
5184
5185     return ERROR_SUCCESS;
5186 }
5187
5188 UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder, 
5189                              LPCWSTR szFolderPath)
5190 {
5191     MSIPACKAGE *package;
5192     UINT ret;
5193
5194     TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
5195
5196     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
5197     ret = MSI_SetTargetPathW( package, szFolder, szFolderPath );
5198     msiobj_release( &package->hdr );
5199     return ret;
5200 }
5201
5202 /***********************************************************************
5203  *           MsiGetMode    (MSI.@)
5204  *
5205  * Returns an internal installer state (if it is running in a mode iRunMode)
5206  *
5207  * PARAMS
5208  *   hInstall    [I]  Handle to the installation
5209  *   hRunMode    [I]  Checking run mode
5210  *        MSIRUNMODE_ADMIN             Administrative mode
5211  *        MSIRUNMODE_ADVERTISE         Advertisement mode
5212  *        MSIRUNMODE_MAINTENANCE       Maintenance mode
5213  *        MSIRUNMODE_ROLLBACKENABLED   Rollback is enabled
5214  *        MSIRUNMODE_LOGENABLED        Log file is writing
5215  *        MSIRUNMODE_OPERATIONS        Operations in progress??
5216  *        MSIRUNMODE_REBOOTATEND       We need to reboot after installation completed
5217  *        MSIRUNMODE_REBOOTNOW         We need to reboot to continue the installation
5218  *        MSIRUNMODE_CABINET           Files from cabinet are installed
5219  *        MSIRUNMODE_SOURCESHORTNAMES  Long names in source files is supressed
5220  *        MSIRUNMODE_TARGETSHORTNAMES  Long names in destination files is supressed
5221  *        MSIRUNMODE_RESERVED11        Reserved
5222  *        MSIRUNMODE_WINDOWS9X         Running under Windows95/98
5223  *        MSIRUNMODE_ZAWENABLED        Demand installation is supported
5224  *        MSIRUNMODE_RESERVED14        Reserved
5225  *        MSIRUNMODE_RESERVED15        Reserved
5226  *        MSIRUNMODE_SCHEDULED         called from install script
5227  *        MSIRUNMODE_ROLLBACK          called from rollback script
5228  *        MSIRUNMODE_COMMIT            called from commit script
5229  *
5230  * RETURNS
5231  *    In the state: TRUE
5232  *    Not in the state: FALSE
5233  *
5234  */
5235
5236 BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
5237 {
5238     FIXME("STUB (iRunMode=%i)\n",iRunMode);
5239     return TRUE;
5240 }
5241
5242 /*
5243  * According to the docs, when this is called it immediately recalculates
5244  * all the component states as well
5245  */
5246 UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
5247                                 INSTALLSTATE iState)
5248 {
5249     LPWSTR szwFeature = NULL;
5250     UINT rc;
5251
5252     szwFeature = strdupAtoW(szFeature);
5253
5254     if (!szwFeature)
5255         return ERROR_FUNCTION_FAILED;
5256    
5257     rc = MsiSetFeatureStateW(hInstall,szwFeature, iState); 
5258
5259     HeapFree(GetProcessHeap(),0,szwFeature);
5260
5261     return rc;
5262 }
5263
5264 UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
5265                                 INSTALLSTATE iState)
5266 {
5267     MSIPACKAGE* package;
5268     INT index;
5269
5270     TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
5271
5272     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
5273     if (!package)
5274         return ERROR_INVALID_HANDLE;
5275
5276     index = get_loaded_feature(package,szFeature);
5277     if (index < 0)
5278         return ERROR_UNKNOWN_FEATURE;
5279
5280     package->features[index].ActionRequest= iState;
5281
5282     return ERROR_SUCCESS;
5283 }
5284
5285 UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPSTR szFeature,
5286                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
5287 {
5288     LPWSTR szwFeature = NULL;
5289     UINT rc;
5290     
5291     szwFeature = strdupAtoW(szFeature);
5292
5293     rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction);
5294
5295     HeapFree( GetProcessHeap(), 0 , szwFeature);
5296
5297     return rc;
5298 }
5299
5300 UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature,
5301                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
5302 {
5303     INT index;
5304
5305     index = get_loaded_feature(package,szFeature);
5306     if (index < 0)
5307         return ERROR_UNKNOWN_FEATURE;
5308
5309     if (piInstalled)
5310         *piInstalled = package->features[index].Installed;
5311
5312     if (piAction)
5313         *piAction = package->features[index].Action;
5314
5315     TRACE("returning %i %i\n",*piInstalled,*piAction);
5316
5317     return ERROR_SUCCESS;
5318 }
5319
5320 UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPWSTR szFeature,
5321                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
5322 {
5323     MSIPACKAGE* package;
5324     UINT ret;
5325
5326     TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled,
5327 piAction);
5328
5329     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
5330     if (!package)
5331         return ERROR_INVALID_HANDLE;
5332     ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction);
5333     msiobj_release( &package->hdr );
5334     return ret;
5335 }
5336
5337 UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPSTR szComponent,
5338                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
5339 {
5340     LPWSTR szwComponent= NULL;
5341     UINT rc;
5342     
5343     szwComponent= strdupAtoW(szComponent);
5344
5345     rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);
5346
5347     HeapFree( GetProcessHeap(), 0 , szwComponent);
5348
5349     return rc;
5350 }
5351
5352 UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPWSTR szComponent,
5353                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
5354 {
5355     INT index;
5356
5357     TRACE("%p %s %p %p\n", package, debugstr_w(szComponent), piInstalled,
5358 piAction);
5359
5360     index = get_loaded_component(package,szComponent);
5361     if (index < 0)
5362         return ERROR_UNKNOWN_COMPONENT;
5363
5364     if (piInstalled)
5365         *piInstalled = package->components[index].Installed;
5366
5367     if (piAction)
5368         *piInstalled = package->components[index].Action;
5369
5370     return ERROR_SUCCESS;
5371 }
5372
5373 UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPWSTR szComponent,
5374                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
5375 {
5376     MSIPACKAGE* package;
5377     UINT ret;
5378
5379     TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szComponent),
5380            piInstalled, piAction);
5381
5382     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
5383     if (!package)
5384         return ERROR_INVALID_HANDLE;
5385     ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);
5386     msiobj_release( &package->hdr );
5387     return ret;
5388 }
5389
5390 #if 0
5391 static UINT ACTION_Template(MSIPACKAGE *package)
5392 {
5393     UINT rc;
5394     MSIQUERY * view;
5395     MSIRECORD * row = 0;
5396     static const WCHAR ExecSeqQuery[] = {0};
5397
5398     rc = MsiDatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5399     if (rc != ERROR_SUCCESS)
5400         return rc;
5401
5402     rc = MsiViewExecute(view, 0);
5403     if (rc != ERROR_SUCCESS)
5404     {
5405         MsiViewClose(view);
5406         msiobj_release(&view->hdr);
5407         return rc;
5408     }
5409
5410     while (1)
5411     {
5412         rc = MsiViewFetch(view,&row);
5413         if (rc != ERROR_SUCCESS)
5414         {
5415             rc = ERROR_SUCCESS;
5416             break;
5417         }
5418
5419         msiobj_release(&row->hdr);
5420     }
5421     MsiViewClose(view);
5422     msiobj_release(&view->hdr);
5423     return rc;
5424 }
5425 #endif