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