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