Implement asn.1 encoding/decoding of times, with tests.
[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 "msidefs.h"
43 #include "msvcrt/fcntl.h"
44 #include "objbase.h"
45 #include "objidl.h"
46 #include "msipriv.h"
47 #include "winnls.h"
48 #include "winuser.h"
49 #include "shlobj.h"
50 #include "wine/unicode.h"
51 #include "winver.h"
52 #include "action.h"
53
54 #define REG_PROGRESS_VALUE 13200
55 #define COMPONENT_PROGRESS_VALUE 24000
56
57 WINE_DEFAULT_DEBUG_CHANNEL(msi);
58
59 /*
60  * Prototypes
61  */
62 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
63 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
64 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
65 static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, 
66                             LPWSTR *FilePath);
67
68 /* 
69  * action handlers
70  */
71 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
72
73 static UINT ACTION_LaunchConditions(MSIPACKAGE *package);
74 static UINT ACTION_CostInitialize(MSIPACKAGE *package);
75 static UINT ACTION_CreateFolders(MSIPACKAGE *package);
76 static UINT ACTION_CostFinalize(MSIPACKAGE *package);
77 static UINT ACTION_FileCost(MSIPACKAGE *package);
78 static UINT ACTION_InstallFiles(MSIPACKAGE *package);
79 static UINT ACTION_DuplicateFiles(MSIPACKAGE *package);
80 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package);
81 static UINT ACTION_InstallInitialize(MSIPACKAGE *package);
82 static UINT ACTION_InstallValidate(MSIPACKAGE *package);
83 static UINT ACTION_ProcessComponents(MSIPACKAGE *package);
84 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package);
85 static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package);
86 static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package);
87 static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package);
88 static UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package);
89 static UINT ACTION_RegisterUser(MSIPACKAGE *package);
90 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package);
91 static UINT ACTION_PublishProduct(MSIPACKAGE *package);
92 static UINT ACTION_WriteIniValues(MSIPACKAGE *package);
93 static UINT ACTION_SelfRegModules(MSIPACKAGE *package);
94 static UINT ACTION_PublishFeatures(MSIPACKAGE *package);
95 static UINT ACTION_RegisterProduct(MSIPACKAGE *package);
96 static UINT ACTION_InstallExecute(MSIPACKAGE *package);
97 static UINT ACTION_InstallFinalize(MSIPACKAGE *package);
98 static UINT ACTION_ForceReboot(MSIPACKAGE *package);
99 static UINT ACTION_ResolveSource(MSIPACKAGE *package);
100 static UINT ACTION_ExecuteAction(MSIPACKAGE *package);
101 static UINT ACTION_RegisterFonts(MSIPACKAGE *package);
102 static UINT ACTION_PublishComponents(MSIPACKAGE *package);
103
104  
105 /*
106  * consts and values used
107  */
108 static const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0};
109 static const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0};
110 static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0};
111 static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
112 static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0};
113 static const WCHAR c_colon[] = {'C',':','\\',0};
114 static const WCHAR szProductCode[]=
115     {'P','r','o','d','u','c','t','C','o','d','e',0};
116 static const WCHAR cszbs[]={'\\',0};
117 const static WCHAR szCreateFolders[] =
118     {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
119 const static WCHAR szCostFinalize[] =
120     {'C','o','s','t','F','i','n','a','l','i','z','e',0};
121 const static WCHAR szInstallFiles[] =
122     {'I','n','s','t','a','l','l','F','i','l','e','s',0};
123 const static WCHAR szDuplicateFiles[] =
124     {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
125 const static WCHAR szWriteRegistryValues[] =
126     {'W','r','i','t','e','R','e','g','i','s','t','r','y',
127             'V','a','l','u','e','s',0};
128 const static WCHAR szCostInitialize[] =
129     {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
130 const static WCHAR szFileCost[] = 
131     {'F','i','l','e','C','o','s','t',0};
132 const static WCHAR szInstallInitialize[] = 
133     {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
134 const static WCHAR szInstallValidate[] = 
135     {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
136 const static WCHAR szLaunchConditions[] = 
137     {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
138 const static WCHAR szProcessComponents[] = 
139     {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
140 const static WCHAR szRegisterTypeLibraries[] = 
141     {'R','e','g','i','s','t','e','r','T','y','p','e',
142             'L','i','b','r','a','r','i','e','s',0};
143 const static WCHAR szRegisterClassInfo[] = 
144     {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
145 const static WCHAR szRegisterProgIdInfo[] = 
146     {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
147 const static WCHAR szCreateShortcuts[] = 
148     {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
149 const static WCHAR szPublishProduct[] = 
150     {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
151 const static WCHAR szWriteIniValues[] = 
152     {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
153 const static WCHAR szSelfRegModules[] = 
154     {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
155 const static WCHAR szPublishFeatures[] = 
156     {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
157 const static WCHAR szRegisterProduct[] = 
158     {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
159 const static WCHAR szInstallExecute[] = 
160     {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
161 const static WCHAR szInstallExecuteAgain[] = 
162     {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
163             'A','g','a','i','n',0};
164 const static WCHAR szInstallFinalize[] = 
165     {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
166 const static WCHAR szForceReboot[] = 
167     {'F','o','r','c','e','R','e','b','o','o','t',0};
168 const static WCHAR szResolveSource[] =
169     {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
170 const static WCHAR szAppSearch[] = 
171     {'A','p','p','S','e','a','r','c','h',0};
172 const static WCHAR szAllocateRegistrySpace[] = 
173     {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
174             'S','p','a','c','e',0};
175 const static WCHAR szBindImage[] = 
176     {'B','i','n','d','I','m','a','g','e',0};
177 const static WCHAR szCCPSearch[] = 
178     {'C','C','P','S','e','a','r','c','h',0};
179 const static WCHAR szDeleteServices[] = 
180     {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
181 const static WCHAR szDisableRollback[] = 
182     {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
183 const static WCHAR szExecuteAction[] = 
184     {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
185 const static WCHAR szFindRelatedProducts[] = 
186     {'F','i','n','d','R','e','l','a','t','e','d',
187             'P','r','o','d','u','c','t','s',0};
188 const static WCHAR szInstallAdminPackage[] = 
189     {'I','n','s','t','a','l','l','A','d','m','i','n',
190             'P','a','c','k','a','g','e',0};
191 const static WCHAR szInstallSFPCatalogFile[] = 
192     {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
193             'F','i','l','e',0};
194 const static WCHAR szIsolateComponents[] = 
195     {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
196 const static WCHAR szMigrateFeatureStates[] = 
197     {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
198             'S','t','a','t','e','s',0};
199 const static WCHAR szMoveFiles[] = 
200     {'M','o','v','e','F','i','l','e','s',0};
201 const static WCHAR szMsiPublishAssemblies[] = 
202     {'M','s','i','P','u','b','l','i','s','h',
203             'A','s','s','e','m','b','l','i','e','s',0};
204 const static WCHAR szMsiUnpublishAssemblies[] = 
205     {'M','s','i','U','n','p','u','b','l','i','s','h',
206             'A','s','s','e','m','b','l','i','e','s',0};
207 const static WCHAR szInstallODBC[] = 
208     {'I','n','s','t','a','l','l','O','D','B','C',0};
209 const static WCHAR szInstallServices[] = 
210     {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
211 const static WCHAR szPatchFiles[] = 
212     {'P','a','t','c','h','F','i','l','e','s',0};
213 const static WCHAR szPublishComponents[] = 
214     {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
215 const static WCHAR szRegisterComPlus[] =
216     {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
217 const static WCHAR szRegisterExtensionInfo[] =
218     {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
219             'I','n','f','o',0};
220 const static WCHAR szRegisterFonts[] =
221     {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
222 const static WCHAR szRegisterMIMEInfo[] =
223     {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
224 const static WCHAR szRegisterUser[] =
225     {'R','e','g','i','s','t','e','r','U','s','e','r',0};
226 const static WCHAR szRemoveDuplicateFiles[] =
227     {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
228             'F','i','l','e','s',0};
229 const static WCHAR szRemoveEnvironmentStrings[] =
230     {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
231             'S','t','r','i','n','g','s',0};
232 const static WCHAR szRemoveExistingProducts[] =
233     {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
234             'P','r','o','d','u','c','t','s',0};
235 const static WCHAR szRemoveFiles[] =
236     {'R','e','m','o','v','e','F','i','l','e','s',0};
237 const static WCHAR szRemoveFolders[] =
238     {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
239 const static WCHAR szRemoveIniValues[] =
240     {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
241 const static WCHAR szRemoveODBC[] =
242     {'R','e','m','o','v','e','O','D','B','C',0};
243 const static WCHAR szRemoveRegistryValues[] =
244     {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
245             'V','a','l','u','e','s',0};
246 const static WCHAR szRemoveShortcuts[] =
247     {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
248 const static WCHAR szRMCCPSearch[] =
249     {'R','M','C','C','P','S','e','a','r','c','h',0};
250 const static WCHAR szScheduleReboot[] =
251     {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
252 const static WCHAR szSelfUnregModules[] =
253     {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
254 const static WCHAR szSetODBCFolders[] =
255     {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
256 const static WCHAR szStartServices[] =
257     {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
258 const static WCHAR szStopServices[] =
259     {'S','t','o','p','S','e','r','v','i','c','e','s',0};
260 const static WCHAR szUnpublishComponents[] =
261     {'U','n','p','u','b','l','i','s','h',
262             'C','o','m','p','o','n','e','n','t','s',0};
263 const static WCHAR szUnpublishFeatures[] =
264     {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
265 const static WCHAR szUnregisterClassInfo[] =
266     {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
267             'I','n','f','o',0};
268 const static WCHAR szUnregisterComPlus[] =
269     {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
270 const static WCHAR szUnregisterExtensionInfo[] =
271     {'U','n','r','e','g','i','s','t','e','r',
272             'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
273 const static WCHAR szUnregisterFonts[] =
274     {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
275 const static WCHAR szUnregisterMIMEInfo[] =
276     {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
277 const static WCHAR szUnregisterProgIdInfo[] =
278     {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
279             'I','n','f','o',0};
280 const static WCHAR szUnregisterTypeLibraries[] =
281     {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
282             'L','i','b','r','a','r','i','e','s',0};
283 const static WCHAR szValidateProductID[] =
284     {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
285 const static WCHAR szWriteEnvironmentStrings[] =
286     {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
287             'S','t','r','i','n','g','s',0};
288
289 struct _actions {
290     LPCWSTR action;
291     STANDARDACTIONHANDLER handler;
292 };
293
294 static struct _actions StandardActions[] = {
295     { szAllocateRegistrySpace, NULL},
296     { szAppSearch, ACTION_AppSearch },
297     { szBindImage, NULL},
298     { szCCPSearch, NULL},
299     { szCostFinalize, ACTION_CostFinalize },
300     { szCostInitialize, ACTION_CostInitialize },
301     { szCreateFolders, ACTION_CreateFolders },
302     { szCreateShortcuts, ACTION_CreateShortcuts },
303     { szDeleteServices, NULL},
304     { szDisableRollback, NULL},
305     { szDuplicateFiles, ACTION_DuplicateFiles },
306     { szExecuteAction, ACTION_ExecuteAction },
307     { szFileCost, ACTION_FileCost },
308     { szFindRelatedProducts, NULL},
309     { szForceReboot, ACTION_ForceReboot },
310     { szInstallAdminPackage, NULL},
311     { szInstallExecute, ACTION_InstallExecute },
312     { szInstallExecuteAgain, ACTION_InstallExecute },
313     { szInstallFiles, ACTION_InstallFiles},
314     { szInstallFinalize, ACTION_InstallFinalize },
315     { szInstallInitialize, ACTION_InstallInitialize },
316     { szInstallSFPCatalogFile, NULL},
317     { szInstallValidate, ACTION_InstallValidate },
318     { szIsolateComponents, NULL},
319     { szLaunchConditions, ACTION_LaunchConditions },
320     { szMigrateFeatureStates, NULL},
321     { szMoveFiles, NULL},
322     { szMsiPublishAssemblies, NULL},
323     { szMsiUnpublishAssemblies, NULL},
324     { szInstallODBC, NULL},
325     { szInstallServices, NULL},
326     { szPatchFiles, NULL},
327     { szProcessComponents, ACTION_ProcessComponents },
328     { szPublishComponents, ACTION_PublishComponents },
329     { szPublishFeatures, ACTION_PublishFeatures },
330     { szPublishProduct, ACTION_PublishProduct },
331     { szRegisterClassInfo, ACTION_RegisterClassInfo },
332     { szRegisterComPlus, NULL},
333     { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
334     { szRegisterFonts, ACTION_RegisterFonts },
335     { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
336     { szRegisterProduct, ACTION_RegisterProduct },
337     { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
338     { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
339     { szRegisterUser, ACTION_RegisterUser},
340     { szRemoveDuplicateFiles, NULL},
341     { szRemoveEnvironmentStrings, NULL},
342     { szRemoveExistingProducts, NULL},
343     { szRemoveFiles, NULL},
344     { szRemoveFolders, NULL},
345     { szRemoveIniValues, NULL},
346     { szRemoveODBC, NULL},
347     { szRemoveRegistryValues, NULL},
348     { szRemoveShortcuts, NULL},
349     { szResolveSource, ACTION_ResolveSource},
350     { szRMCCPSearch, NULL},
351     { szScheduleReboot, NULL},
352     { szSelfRegModules, ACTION_SelfRegModules },
353     { szSelfUnregModules, NULL},
354     { szSetODBCFolders, NULL},
355     { szStartServices, NULL},
356     { szStopServices, NULL},
357     { szUnpublishComponents, NULL},
358     { szUnpublishFeatures, NULL},
359     { szUnregisterClassInfo, NULL},
360     { szUnregisterComPlus, NULL},
361     { szUnregisterExtensionInfo, NULL},
362     { szUnregisterFonts, NULL},
363     { szUnregisterMIMEInfo, NULL},
364     { szUnregisterProgIdInfo, NULL},
365     { szUnregisterTypeLibraries, NULL},
366     { szValidateProductID, NULL},
367     { szWriteEnvironmentStrings, NULL},
368     { szWriteIniValues, ACTION_WriteIniValues },
369     { szWriteRegistryValues, ACTION_WriteRegistryValues},
370     { NULL, NULL},
371 };
372
373
374 /******************************************************** 
375  * helper functions to get around current HACKS and such
376  ********************************************************/
377 inline static void reduce_to_longfilename(WCHAR* filename)
378 {
379     LPWSTR p = strchrW(filename,'|');
380     if (p)
381         memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR));
382 }
383
384 inline static void reduce_to_shortfilename(WCHAR* filename)
385 {
386     LPWSTR p = strchrW(filename,'|');
387     if (p)
388         *p = 0;
389 }
390
391 WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index)
392 {
393     UINT rc;
394     DWORD sz;
395     LPWSTR ret;
396    
397     sz = 0; 
398     if (MSI_RecordIsNull(row,index))
399         return NULL;
400
401     rc = MSI_RecordGetStringW(row,index,NULL,&sz);
402
403     /* having an empty string is different than NULL */
404     if (sz == 0)
405     {
406         ret = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR));
407         ret[0] = 0;
408         return ret;
409     }
410
411     sz ++;
412     ret = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR));
413     rc = MSI_RecordGetStringW(row,index,ret,&sz);
414     if (rc!=ERROR_SUCCESS)
415     {
416         ERR("Unable to load dynamic string\n");
417         HeapFree(GetProcessHeap(), 0, ret);
418         ret = NULL;
419     }
420     return ret;
421 }
422
423 LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, UINT* rc)
424 {
425     DWORD sz = 0;
426     LPWSTR str;
427     UINT r;
428
429     r = MSI_GetPropertyW(package, prop, NULL, &sz);
430     if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
431     {
432         if (rc)
433             *rc = r;
434         return NULL;
435     }
436     sz++;
437     str = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
438     r = MSI_GetPropertyW(package, prop, str, &sz);
439     if (r != ERROR_SUCCESS)
440     {
441         HeapFree(GetProcessHeap(),0,str);
442         str = NULL;
443     }
444     if (rc)
445         *rc = r;
446     return str;
447 }
448
449 int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component )
450 {
451     int rc = -1;
452     DWORD i;
453
454     for (i = 0; i < package->loaded_components; i++)
455     {
456         if (strcmpW(Component,package->components[i].Component)==0)
457         {
458             rc = i;
459             break;
460         }
461     }
462     return rc;
463 }
464
465 int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature )
466 {
467     int rc = -1;
468     DWORD i;
469
470     for (i = 0; i < package->loaded_features; i++)
471     {
472         if (strcmpW(Feature,package->features[i].Feature)==0)
473         {
474             rc = i;
475             break;
476         }
477     }
478     return rc;
479 }
480
481 int get_loaded_file(MSIPACKAGE* package, LPCWSTR file)
482 {
483     int rc = -1;
484     DWORD i;
485
486     for (i = 0; i < package->loaded_files; i++)
487     {
488         if (strcmpW(file,package->files[i].File)==0)
489         {
490             rc = i;
491             break;
492         }
493     }
494     return rc;
495 }
496
497 int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path)
498 {
499     DWORD i;
500     DWORD index;
501
502     if (!package)
503         return -2;
504
505     for (i=0; i < package->loaded_files; i++)
506         if (strcmpW(package->files[i].File,name)==0)
507             return -1;
508
509     index = package->loaded_files;
510     package->loaded_files++;
511     if (package->loaded_files== 1)
512         package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
513     else
514         package->files = HeapReAlloc(GetProcessHeap(),0,
515             package->files , package->loaded_files * sizeof(MSIFILE));
516
517     memset(&package->files[index],0,sizeof(MSIFILE));
518
519     package->files[index].File = strdupW(name);
520     package->files[index].TargetPath = strdupW(path);
521     package->files[index].Temporary = TRUE;
522
523     TRACE("Tracking tempfile (%s)\n",debugstr_w(package->files[index].File));  
524
525     return 0;
526 }
527
528 static void remove_tracked_tempfiles(MSIPACKAGE* package)
529 {
530     DWORD i;
531
532     if (!package)
533         return;
534
535     for (i = 0; i < package->loaded_files; i++)
536     {
537         if (package->files[i].Temporary)
538         {
539             TRACE("Cleaning up %s\n",debugstr_w(package->files[i].TargetPath));
540             DeleteFileW(package->files[i].TargetPath);
541         }
542
543     }
544 }
545
546 /* wrapper to resist a need for a full rewrite right now */
547 DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data )
548 {
549     if (ptr)
550     {
551         MSIRECORD *rec = MSI_CreateRecord(1);
552         DWORD size = 0;
553
554         MSI_RecordSetStringW(rec,0,ptr);
555         MSI_FormatRecordW(package,rec,NULL,&size);
556         if (size >= 0)
557         {
558             size++;
559             *data = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
560             if (size > 1)
561                 MSI_FormatRecordW(package,rec,*data,&size);
562             else
563                 *data[0] = 0;
564             msiobj_release( &rec->hdr );
565             return sizeof(WCHAR)*size;
566         }
567         msiobj_release( &rec->hdr );
568     }
569
570     *data = NULL;
571     return 0;
572 }
573
574 /* Called when the package is being closed */
575 void ACTION_free_package_structures( MSIPACKAGE* package)
576 {
577     INT i;
578     
579     TRACE("Freeing package action data\n");
580
581     remove_tracked_tempfiles(package);
582
583     /* No dynamic buffers in features */
584     if (package->features && package->loaded_features > 0)
585         HeapFree(GetProcessHeap(),0,package->features);
586
587     for (i = 0; i < package->loaded_folders; i++)
588     {
589         HeapFree(GetProcessHeap(),0,package->folders[i].Directory);
590         HeapFree(GetProcessHeap(),0,package->folders[i].TargetDefault);
591         HeapFree(GetProcessHeap(),0,package->folders[i].SourceDefault);
592         HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
593         HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedSource);
594         HeapFree(GetProcessHeap(),0,package->folders[i].Property);
595     }
596     if (package->folders && package->loaded_folders > 0)
597         HeapFree(GetProcessHeap(),0,package->folders);
598
599     for (i = 0; i < package->loaded_components; i++)
600         HeapFree(GetProcessHeap(),0,package->components[i].FullKeypath);
601
602     if (package->components && package->loaded_components > 0)
603         HeapFree(GetProcessHeap(),0,package->components);
604
605     for (i = 0; i < package->loaded_files; i++)
606     {
607         HeapFree(GetProcessHeap(),0,package->files[i].File);
608         HeapFree(GetProcessHeap(),0,package->files[i].FileName);
609         HeapFree(GetProcessHeap(),0,package->files[i].ShortName);
610         HeapFree(GetProcessHeap(),0,package->files[i].Version);
611         HeapFree(GetProcessHeap(),0,package->files[i].Language);
612         HeapFree(GetProcessHeap(),0,package->files[i].SourcePath);
613         HeapFree(GetProcessHeap(),0,package->files[i].TargetPath);
614     }
615
616     if (package->files && package->loaded_files > 0)
617         HeapFree(GetProcessHeap(),0,package->files);
618
619     /* clean up extension, progid, class and verb structures */
620     for (i = 0; i < package->loaded_classes; i++)
621     {
622         HeapFree(GetProcessHeap(),0,package->classes[i].Description);
623         HeapFree(GetProcessHeap(),0,package->classes[i].FileTypeMask);
624         HeapFree(GetProcessHeap(),0,package->classes[i].IconPath);
625         HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler);
626         HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler32);
627         HeapFree(GetProcessHeap(),0,package->classes[i].Argument);
628         HeapFree(GetProcessHeap(),0,package->classes[i].ProgIDText);
629     }
630
631     if (package->classes && package->loaded_classes > 0)
632         HeapFree(GetProcessHeap(),0,package->classes);
633
634     for (i = 0; i < package->loaded_extensions; i++)
635     {
636         HeapFree(GetProcessHeap(),0,package->extensions[i].ProgIDText);
637     }
638
639     if (package->extensions && package->loaded_extensions > 0)
640         HeapFree(GetProcessHeap(),0,package->extensions);
641
642     for (i = 0; i < package->loaded_progids; i++)
643     {
644         HeapFree(GetProcessHeap(),0,package->progids[i].ProgID);
645         HeapFree(GetProcessHeap(),0,package->progids[i].Description);
646         HeapFree(GetProcessHeap(),0,package->progids[i].IconPath);
647     }
648
649     if (package->progids && package->loaded_progids > 0)
650         HeapFree(GetProcessHeap(),0,package->progids);
651
652     for (i = 0; i < package->loaded_verbs; i++)
653     {
654         HeapFree(GetProcessHeap(),0,package->verbs[i].Verb);
655         HeapFree(GetProcessHeap(),0,package->verbs[i].Command);
656         HeapFree(GetProcessHeap(),0,package->verbs[i].Argument);
657     }
658
659     if (package->verbs && package->loaded_verbs > 0)
660         HeapFree(GetProcessHeap(),0,package->verbs);
661
662     for (i = 0; i < package->loaded_mimes; i++)
663         HeapFree(GetProcessHeap(),0,package->mimes[i].ContentType);
664
665     if (package->mimes && package->loaded_mimes > 0)
666         HeapFree(GetProcessHeap(),0,package->mimes);
667
668     for (i = 0; i < package->loaded_appids; i++)
669     {
670         HeapFree(GetProcessHeap(),0,package->appids[i].RemoteServerName);
671         HeapFree(GetProcessHeap(),0,package->appids[i].LocalServer);
672         HeapFree(GetProcessHeap(),0,package->appids[i].ServiceParameters);
673         HeapFree(GetProcessHeap(),0,package->appids[i].DllSurrogate);
674     }
675
676     if (package->appids && package->loaded_appids > 0)
677         HeapFree(GetProcessHeap(),0,package->appids);
678
679     if (package->script)
680     {
681         for (i = 0; i < TOTAL_SCRIPTS; i++)
682         {
683             int j;
684             for (j = 0; j < package->script->ActionCount[i]; j++)
685                 HeapFree(GetProcessHeap(),0,package->script->Actions[i][j]);
686         
687             HeapFree(GetProcessHeap(),0,package->script->Actions[i]);
688         }
689         HeapFree(GetProcessHeap(),0,package->script);
690     }
691
692     HeapFree(GetProcessHeap(),0,package->PackagePath);
693
694     /* cleanup control event subscriptions */
695     ControlEvent_CleanupSubscriptions(package);
696 }
697
698 static void ce_actiontext(MSIPACKAGE* package, LPCWSTR action)
699 {
700     static const WCHAR szActionText[] = 
701         {'A','c','t','i','o','n','T','e','x','t',0};
702     MSIRECORD *row;
703
704     row = MSI_CreateRecord(1);
705     MSI_RecordSetStringW(row,1,action);
706     ControlEvent_FireSubscribedEvent(package,szActionText, row);
707     msiobj_release(&row->hdr);
708 }
709
710 static void ui_progress(MSIPACKAGE *package, int a, int b, int c, int d )
711 {
712     MSIRECORD * row;
713
714     row = MSI_CreateRecord(4);
715     MSI_RecordSetInteger(row,1,a);
716     MSI_RecordSetInteger(row,2,b);
717     MSI_RecordSetInteger(row,3,c);
718     MSI_RecordSetInteger(row,4,d);
719     MSI_ProcessMessage(package, INSTALLMESSAGE_PROGRESS, row);
720     msiobj_release(&row->hdr);
721
722     msi_dialog_check_messages(NULL);
723 }
724
725 static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
726 {
727     static const WCHAR Query_t[] = 
728         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
729          '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
730          'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=', 
731          ' ','\'','%','s','\'',0};
732     WCHAR message[1024];
733     MSIRECORD * row = 0;
734     DWORD size;
735     static const WCHAR szActionData[] = 
736         {'A','c','t','i','o','n','D','a','t','a',0};
737
738     if (!package->LastAction || strcmpW(package->LastAction,action))
739     {
740         row = MSI_QueryGetRecord(package->db, Query_t, action);
741         if (!row)
742             return;
743
744         if (MSI_RecordIsNull(row,3))
745         {
746             msiobj_release(&row->hdr);
747             return;
748         }
749
750         /* update the cached actionformat */
751         HeapFree(GetProcessHeap(),0,package->ActionFormat);
752         package->ActionFormat = load_dynamic_stringW(row,3);
753
754         HeapFree(GetProcessHeap(),0,package->LastAction);
755         package->LastAction = strdupW(action);
756
757         msiobj_release(&row->hdr);
758     }
759
760     MSI_RecordSetStringW(record,0,package->ActionFormat);
761     size = 1024;
762     MSI_FormatRecordW(package,record,message,&size);
763
764     row = MSI_CreateRecord(1);
765     MSI_RecordSetStringW(row,1,message);
766  
767     MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
768
769     ControlEvent_FireSubscribedEvent(package,szActionData, row);
770
771     msiobj_release(&row->hdr);
772 }
773
774
775 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
776 {
777     static const WCHAR template_s[]=
778         {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ', '%','s',
779          '.',0};
780     static const WCHAR format[] = 
781         {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
782     static const WCHAR Query_t[] = 
783         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
784          '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
785          'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=', 
786          ' ','\'','%','s','\'',0};
787     WCHAR message[1024];
788     WCHAR timet[0x100];
789     MSIRECORD * row = 0;
790     LPCWSTR ActionText;
791
792     GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
793
794     row = MSI_QueryGetRecord( package->db, Query_t, action );
795     if (!row)
796         return;
797
798     ActionText = MSI_RecordGetString(row,2);
799
800     sprintfW(message,template_s,timet,action,ActionText);
801     msiobj_release(&row->hdr);
802
803     row = MSI_CreateRecord(1);
804     MSI_RecordSetStringW(row,1,message);
805  
806     MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
807     msiobj_release(&row->hdr);
808 }
809
810 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start, 
811                           UINT rc)
812 {
813     MSIRECORD * row;
814     static const WCHAR template_s[]=
815         {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
816          '%','s', '.',0};
817     static const WCHAR template_e[]=
818         {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
819          '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
820          '%','i','.',0};
821     static const WCHAR format[] = 
822         {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
823     WCHAR message[1024];
824     WCHAR timet[0x100];
825
826     GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
827     if (start)
828         sprintfW(message,template_s,timet,action);
829     else
830         sprintfW(message,template_e,timet,action,rc);
831     
832     row = MSI_CreateRecord(1);
833     MSI_RecordSetStringW(row,1,message);
834  
835     MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
836     msiobj_release(&row->hdr);
837 }
838
839 /*
840  *  build_directory_name()
841  *
842  *  This function is to save messing round with directory names
843  *  It handles adding backslashes between path segments, 
844  *   and can add \ at the end of the directory name if told to.
845  *
846  *  It takes a variable number of arguments.
847  *  It always allocates a new string for the result, so make sure
848  *   to free the return value when finished with it.
849  *
850  *  The first arg is the number of path segments that follow.
851  *  The arguments following count are a list of path segments.
852  *  A path segment may be NULL.
853  *
854  *  Path segments will be added with a \ separating them.
855  *  A \ will not be added after the last segment, however if the
856  *    last segment is NULL, then the last character will be a \
857  * 
858  */
859 static LPWSTR build_directory_name(DWORD count, ...)
860 {
861     DWORD sz = 1, i;
862     LPWSTR dir;
863     va_list va;
864
865     va_start(va,count);
866     for(i=0; i<count; i++)
867     {
868         LPCWSTR str = va_arg(va,LPCWSTR);
869         if (str)
870             sz += strlenW(str) + 1;
871     }
872     va_end(va);
873
874     dir = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR));
875     dir[0]=0;
876
877     va_start(va,count);
878     for(i=0; i<count; i++)
879     {
880         LPCWSTR str = va_arg(va,LPCWSTR);
881         if (!str)
882             continue;
883         strcatW(dir, str);
884         if( ((i+1)!=count) && dir[strlenW(dir)-1]!='\\')
885             strcatW(dir, cszbs);
886     }
887     return dir;
888 }
889
890 static BOOL ACTION_VerifyComponentForAction(MSIPACKAGE* package, INT index, 
891                                             INSTALLSTATE check )
892 {
893     if (package->components[index].Installed == check)
894         return FALSE;
895
896     if (package->components[index].ActionRequest == check)
897         return TRUE;
898     else
899         return FALSE;
900 }
901
902 static BOOL ACTION_VerifyFeatureForAction(MSIPACKAGE* package, INT index, 
903                                             INSTALLSTATE check )
904 {
905     if (package->features[index].Installed == check)
906         return FALSE;
907
908     if (package->features[index].ActionRequest == check)
909         return TRUE;
910     else
911         return FALSE;
912 }
913
914
915 /****************************************************
916  * TOP level entry points 
917  *****************************************************/
918
919 UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath,
920                               LPCWSTR szCommandLine)
921 {
922     DWORD sz;
923     WCHAR buffer[10];
924     UINT rc;
925     BOOL ui = FALSE;
926     static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
927     static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
928     static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
929
930     MSI_SetPropertyW(package, szAction, szInstall);
931
932     package->script = HeapAlloc(GetProcessHeap(),0,sizeof(MSISCRIPT));
933     memset(package->script,0,sizeof(MSISCRIPT));
934
935     if (szPackagePath)   
936     {
937         LPWSTR p, check, path;
938  
939         package->PackagePath = strdupW(szPackagePath);
940         path = strdupW(szPackagePath);
941         p = strrchrW(path,'\\');    
942         if (p)
943         {
944             p++;
945             *p=0;
946         }
947         else
948         {
949             HeapFree(GetProcessHeap(),0,path);
950             path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR));
951             GetCurrentDirectoryW(MAX_PATH,path);
952             strcatW(path,cszbs);
953         }
954
955         check = load_dynamic_property(package, cszSourceDir,NULL);
956         if (!check)
957             MSI_SetPropertyW(package, cszSourceDir, path);
958         else
959             HeapFree(GetProcessHeap(), 0, check);
960
961         HeapFree(GetProcessHeap(), 0, path);
962     }
963
964     if (szCommandLine)
965     {
966         LPWSTR ptr,ptr2;
967         ptr = (LPWSTR)szCommandLine;
968        
969         while (*ptr)
970         {
971             WCHAR *prop = NULL;
972             WCHAR *val = NULL;
973
974             TRACE("Looking at %s\n",debugstr_w(ptr));
975
976             ptr2 = strchrW(ptr,'=');
977             if (ptr2)
978             {
979                 BOOL quote=FALSE;
980                 DWORD len = 0;
981
982                 while (*ptr == ' ') ptr++;
983                 len = ptr2-ptr;
984                 prop = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
985                 memcpy(prop,ptr,len*sizeof(WCHAR));
986                 prop[len]=0;
987                 ptr2++;
988            
989                 len = 0; 
990                 ptr = ptr2; 
991                 while (*ptr && (quote || (!quote && *ptr!=' ')))
992                 {
993                     if (*ptr == '"')
994                         quote = !quote;
995                     ptr++;
996                     len++;
997                 }
998                
999                 if (*ptr2=='"')
1000                 {
1001                     ptr2++;
1002                     len -= 2;
1003                 }
1004                 val = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
1005                 memcpy(val,ptr2,len*sizeof(WCHAR));
1006                 val[len] = 0;
1007
1008                 if (strlenW(prop) > 0)
1009                 {
1010                     TRACE("Found commandline property (%s) = (%s)\n", 
1011                                        debugstr_w(prop), debugstr_w(val));
1012                     MSI_SetPropertyW(package,prop,val);
1013                 }
1014                 HeapFree(GetProcessHeap(),0,val);
1015                 HeapFree(GetProcessHeap(),0,prop);
1016             }
1017             ptr++;
1018         }
1019     }
1020   
1021     sz = 10; 
1022     if (MSI_GetPropertyW(package,szUILevel,buffer,&sz) == ERROR_SUCCESS)
1023     {
1024         if (atoiW(buffer) >= INSTALLUILEVEL_REDUCED)
1025         {
1026             rc = ACTION_ProcessUISequence(package);
1027             ui = TRUE;
1028             if (rc == ERROR_SUCCESS)
1029                 rc = ACTION_ProcessExecSequence(package,TRUE);
1030         }
1031         else
1032             rc = ACTION_ProcessExecSequence(package,FALSE);
1033     }
1034     else
1035         rc = ACTION_ProcessExecSequence(package,FALSE);
1036     
1037     if (rc == -1)
1038     {
1039         /* install was halted but should be considered a success */
1040         rc = ERROR_SUCCESS;
1041     }
1042
1043     package->script->CurrentlyScripting= FALSE;
1044
1045     /* process the ending type action */
1046     if (rc == ERROR_SUCCESS)
1047         ACTION_PerformActionSequence(package,-1,ui);
1048     else if (rc == ERROR_INSTALL_USEREXIT) 
1049         ACTION_PerformActionSequence(package,-2,ui);
1050     else if (rc == ERROR_INSTALL_SUSPEND) 
1051         ACTION_PerformActionSequence(package,-4,ui);
1052     else  /* failed */
1053         ACTION_PerformActionSequence(package,-3,ui);
1054
1055     /* finish up running custom actions */
1056     ACTION_FinishCustomActions(package);
1057     
1058     return rc;
1059 }
1060
1061 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
1062 {
1063     UINT rc = ERROR_SUCCESS;
1064     MSIRECORD * row = 0;
1065     static const WCHAR ExecSeqQuery[] =
1066         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1067          '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
1068          'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
1069          '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
1070
1071     static const WCHAR UISeqQuery[] =
1072         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1073      '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
1074      '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
1075          ' ', '=',' ','%','i',0};
1076
1077     if (UI)
1078         row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
1079     else
1080         row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
1081
1082     if (row)
1083     {
1084         LPCWSTR action, cond;
1085
1086         TRACE("Running the actions\n"); 
1087
1088         /* check conditions */
1089         cond = MSI_RecordGetString(row,2);
1090         if (cond)
1091         {
1092             /* this is a hack to skip errors in the condition code */
1093             if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
1094                 goto end;
1095         }
1096
1097         action = MSI_RecordGetString(row,1);
1098         if (!action)
1099         {
1100             ERR("failed to fetch action\n");
1101             rc = ERROR_FUNCTION_FAILED;
1102             goto end;
1103         }
1104
1105         if (UI)
1106             rc = ACTION_PerformUIAction(package,action);
1107         else
1108             rc = ACTION_PerformAction(package,action,FALSE);
1109 end:
1110         msiobj_release(&row->hdr);
1111     }
1112     else
1113         rc = ERROR_SUCCESS;
1114
1115     return rc;
1116 }
1117
1118 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
1119 {
1120     MSIQUERY * view;
1121     UINT rc;
1122     static const WCHAR ExecSeqQuery[] =
1123         {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1124          '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
1125          'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
1126          '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
1127          'O','R','D','E','R',' ', 'B','Y',' ',
1128          '`','S','e','q','u','e','n','c','e','`',0 };
1129     MSIRECORD * row = 0;
1130     static const WCHAR IVQuery[] =
1131         {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
1132          ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
1133          'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
1134          'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
1135          ' ','\'', 'I','n','s','t','a','l','l',
1136          'V','a','l','i','d','a','t','e','\'', 0};
1137     INT seq = 0;
1138
1139
1140     if (package->script->ExecuteSequenceRun)
1141     {
1142         TRACE("Execute Sequence already Run\n");
1143         return ERROR_SUCCESS;
1144     }
1145
1146     package->script->ExecuteSequenceRun = TRUE;
1147     
1148     /* get the sequence number */
1149     if (UIran)
1150     {
1151         row = MSI_QueryGetRecord(package->db, IVQuery);
1152         if( !row )
1153             return ERROR_FUNCTION_FAILED;
1154         seq = MSI_RecordGetInteger(row,1);
1155         msiobj_release(&row->hdr);
1156     }
1157
1158     rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
1159     if (rc == ERROR_SUCCESS)
1160     {
1161         rc = MSI_ViewExecute(view, 0);
1162
1163         if (rc != ERROR_SUCCESS)
1164         {
1165             MSI_ViewClose(view);
1166             msiobj_release(&view->hdr);
1167             goto end;
1168         }
1169        
1170         TRACE("Running the actions\n"); 
1171
1172         while (1)
1173         {
1174             LPCWSTR cond, action;
1175
1176             rc = MSI_ViewFetch(view,&row);
1177             if (rc != ERROR_SUCCESS)
1178             {
1179                 rc = ERROR_SUCCESS;
1180                 break;
1181             }
1182
1183             action = MSI_RecordGetString(row,1);
1184             if (!action)
1185             {
1186                 rc = ERROR_FUNCTION_FAILED;
1187                 msiobj_release(&row->hdr);
1188                 break;
1189             }
1190
1191             /* check conditions */
1192             cond = MSI_RecordGetString(row,2);
1193             if (cond)
1194             {
1195                 /* this is a hack to skip errors in the condition code */
1196                 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
1197                 {
1198                     msiobj_release(&row->hdr);
1199                     TRACE("Skipping action: %s (condition is false)\n",
1200                           debugstr_w(action));
1201                     continue; 
1202                 }
1203             }
1204
1205             rc = ACTION_PerformAction(package,action,FALSE);
1206
1207             if (rc == ERROR_FUNCTION_NOT_CALLED)
1208                 rc = ERROR_SUCCESS;
1209
1210             if (rc != ERROR_SUCCESS)
1211             {
1212                 ERR("Execution halted due to error (%i)\n",rc);
1213                 msiobj_release(&row->hdr);
1214                 break;
1215             }
1216
1217             msiobj_release(&row->hdr);
1218         }
1219
1220         MSI_ViewClose(view);
1221         msiobj_release(&view->hdr);
1222     }
1223
1224 end:
1225     return rc;
1226 }
1227
1228
1229 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
1230 {
1231     MSIQUERY * view;
1232     UINT rc;
1233     static const WCHAR ExecSeqQuery [] =
1234         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1235          '`','I','n','s','t','a','l','l',
1236          'U','I','S','e','q','u','e','n','c','e','`',
1237          ' ','W','H','E','R','E',' ', 
1238          '`','S','e','q','u','e','n','c','e','`',' ',
1239          '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1240          '`','S','e','q','u','e','n','c','e','`',0};
1241     
1242     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1243     
1244     if (rc == ERROR_SUCCESS)
1245     {
1246         rc = MSI_ViewExecute(view, 0);
1247
1248         if (rc != ERROR_SUCCESS)
1249         {
1250             MSI_ViewClose(view);
1251             msiobj_release(&view->hdr);
1252             goto end;
1253         }
1254        
1255         TRACE("Running the actions \n"); 
1256
1257         while (1)
1258         {
1259             LPCWSTR action, cond;
1260             MSIRECORD * row = 0;
1261
1262             rc = MSI_ViewFetch(view,&row);
1263             if (rc != ERROR_SUCCESS)
1264             {
1265                 rc = ERROR_SUCCESS;
1266                 break;
1267             }
1268
1269             action = MSI_RecordGetString(row,1);
1270             if (!action)
1271             {
1272                 ERR("failed to fetch action\n");
1273                 rc = ERROR_FUNCTION_FAILED;
1274                 msiobj_release(&row->hdr);
1275                 break;
1276             }
1277
1278             /* check conditions */
1279             cond = MSI_RecordGetString(row,2);
1280             if (cond)
1281             {
1282                 /* this is a hack to skip errors in the condition code */
1283                 if (MSI_EvaluateConditionW(package,cond) == MSICONDITION_FALSE)
1284                 {
1285                     msiobj_release(&row->hdr);
1286                     TRACE("Skipping action: %s (condition is false)\n",
1287                           debugstr_w(action));
1288                     continue; 
1289                 }
1290             }
1291
1292             rc = ACTION_PerformUIAction(package,action);
1293
1294             if (rc == ERROR_FUNCTION_NOT_CALLED)
1295                 rc = ERROR_SUCCESS;
1296
1297             if (rc != ERROR_SUCCESS)
1298             {
1299                 ERR("Execution halted due to error (%i)\n",rc);
1300                 msiobj_release(&row->hdr);
1301                 break;
1302             }
1303
1304             msiobj_release(&row->hdr);
1305         }
1306
1307         MSI_ViewClose(view);
1308         msiobj_release(&view->hdr);
1309     }
1310
1311 end:
1312     return rc;
1313 }
1314
1315 /********************************************************
1316  * ACTION helper functions and functions that perform the actions
1317  *******************************************************/
1318 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, 
1319                                         UINT* rc, BOOL force )
1320 {
1321     BOOL ret = FALSE; 
1322     BOOL run = force;
1323     int i;
1324
1325     if (!run && !package->script->CurrentlyScripting)
1326         run = TRUE;
1327    
1328     if (!run)
1329     {
1330         if (strcmpW(action,szInstallFinalize) == 0 ||
1331             strcmpW(action,szInstallExecute) == 0 ||
1332             strcmpW(action,szInstallExecuteAgain) == 0) 
1333                 run = TRUE;
1334     }
1335     
1336     i = 0;
1337     while (StandardActions[i].action != NULL)
1338     {
1339         if (strcmpW(StandardActions[i].action, action)==0)
1340         {
1341             ce_actiontext(package, action);
1342             if (!run)
1343             {
1344                 ui_actioninfo(package, action, TRUE, 0);
1345                 *rc = schedule_action(package,INSTALL_SCRIPT,action);
1346                 ui_actioninfo(package, action, FALSE, *rc);
1347             }
1348             else
1349             {
1350                 ui_actionstart(package, action);
1351                 if (StandardActions[i].handler)
1352                 {
1353                     *rc = StandardActions[i].handler(package);
1354                 }
1355                 else
1356                 {
1357                     FIXME("UNHANDLED Standard Action %s\n",debugstr_w(action));
1358                     *rc = ERROR_SUCCESS;
1359                 }
1360             }
1361             ret = TRUE;
1362             break;
1363         }
1364         i++;
1365     }
1366     return ret;
1367 }
1368
1369 static BOOL ACTION_HandleDialogBox( MSIPACKAGE *package, LPCWSTR dialog, UINT* rc )
1370 {
1371     BOOL ret = FALSE;
1372
1373     if (ACTION_DialogBox(package,dialog) == ERROR_SUCCESS)
1374     {
1375         *rc = package->CurrentInstallState;
1376         ret = TRUE;
1377     }
1378     return ret;
1379 }
1380
1381 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
1382                                        UINT* rc, BOOL force )
1383 {
1384     BOOL ret=FALSE;
1385     UINT arc;
1386
1387     arc = ACTION_CustomAction(package,action, force);
1388
1389     if (arc != ERROR_CALL_NOT_IMPLEMENTED)
1390     {
1391         *rc = arc;
1392         ret = TRUE;
1393     }
1394     return ret;
1395 }
1396
1397 /* 
1398  * A lot of actions are really important even if they don't do anything
1399  * explicit... Lots of properties are set at the beginning of the installation
1400  * CostFinalize does a bunch of work to translate the directories and such
1401  * 
1402  * But until I get write access to the database that is hard, so I am going to
1403  * hack it to see if I can get something to run.
1404  */
1405 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
1406 {
1407     UINT rc = ERROR_SUCCESS; 
1408     BOOL handled;
1409
1410     TRACE("Performing action (%s)\n",debugstr_w(action));
1411
1412     handled = ACTION_HandleStandardAction(package, action, &rc, force);
1413
1414     if (!handled)
1415         handled = ACTION_HandleCustomAction(package, action, &rc, force);
1416
1417     if (!handled)
1418     {
1419         FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action));
1420         rc = ERROR_FUNCTION_NOT_CALLED;
1421     }
1422
1423     package->CurrentInstallState = rc;
1424     return rc;
1425 }
1426
1427 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
1428 {
1429     UINT rc = ERROR_SUCCESS;
1430     BOOL handled = FALSE;
1431
1432     TRACE("Performing action (%s)\n",debugstr_w(action));
1433
1434     handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1435
1436     if (!handled)
1437         handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
1438
1439     if (!handled)
1440         handled = ACTION_HandleDialogBox(package, action, &rc);
1441
1442     msi_dialog_check_messages( NULL );
1443
1444     if (!handled)
1445     {
1446         FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action));
1447         rc = ERROR_FUNCTION_NOT_CALLED;
1448     }
1449
1450     package->CurrentInstallState = rc;
1451     return rc;
1452 }
1453
1454 /***********************************************************************
1455  *            create_full_pathW
1456  *
1457  * Recursively create all directories in the path.
1458  *
1459  * shamelessly stolen from setupapi/queue.c
1460  */
1461 static BOOL create_full_pathW(const WCHAR *path)
1462 {
1463     BOOL ret = TRUE;
1464     int len;
1465     WCHAR *new_path;
1466
1467     new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) *
1468                                               sizeof(WCHAR));
1469
1470     strcpyW(new_path, path);
1471
1472     while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
1473     new_path[len - 1] = 0;
1474
1475     while(!CreateDirectoryW(new_path, NULL))
1476     {
1477         WCHAR *slash;
1478         DWORD last_error = GetLastError();
1479         if(last_error == ERROR_ALREADY_EXISTS)
1480             break;
1481
1482         if(last_error != ERROR_PATH_NOT_FOUND)
1483         {
1484             ret = FALSE;
1485             break;
1486         }
1487
1488         if(!(slash = strrchrW(new_path, '\\')))
1489         {
1490             ret = FALSE;
1491             break;
1492         }
1493
1494         len = slash - new_path;
1495         new_path[len] = 0;
1496         if(!create_full_pathW(new_path))
1497         {
1498             ret = FALSE;
1499             break;
1500         }
1501         new_path[len] = '\\';
1502     }
1503
1504     HeapFree(GetProcessHeap(), 0, new_path);
1505     return ret;
1506 }
1507
1508 /*
1509  * Also we cannot enable/disable components either, so for now I am just going 
1510  * to do all the directories for all the components.
1511  */
1512 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1513 {
1514     static const WCHAR ExecSeqQuery[] =
1515         {'S','E','L','E','C','T',' ',
1516          '`','D','i','r','e','c','t','o','r','y','_','`',
1517          ' ','F','R','O','M',' ',
1518          '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1519     UINT rc;
1520     MSIQUERY *view;
1521     MSIFOLDER *folder;
1522
1523     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1524     if (rc != ERROR_SUCCESS)
1525         return ERROR_SUCCESS;
1526
1527     rc = MSI_ViewExecute(view, 0);
1528     if (rc != ERROR_SUCCESS)
1529     {
1530         MSI_ViewClose(view);
1531         msiobj_release(&view->hdr);
1532         return rc;
1533     }
1534     
1535     while (1)
1536     {
1537         WCHAR dir[0x100];
1538         LPWSTR full_path;
1539         DWORD sz;
1540         MSIRECORD *row = NULL, *uirow;
1541
1542         rc = MSI_ViewFetch(view,&row);
1543         if (rc != ERROR_SUCCESS)
1544         {
1545             rc = ERROR_SUCCESS;
1546             break;
1547         }
1548
1549         sz=0x100;
1550         rc = MSI_RecordGetStringW(row,1,dir,&sz);
1551
1552         if (rc!= ERROR_SUCCESS)
1553         {
1554             ERR("Unable to get folder id \n");
1555             msiobj_release(&row->hdr);
1556             continue;
1557         }
1558
1559         sz = MAX_PATH;
1560         full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1561         if (!full_path)
1562         {
1563             ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1564             msiobj_release(&row->hdr);
1565             continue;
1566         }
1567
1568         TRACE("Folder is %s\n",debugstr_w(full_path));
1569
1570         /* UI stuff */
1571         uirow = MSI_CreateRecord(1);
1572         MSI_RecordSetStringW(uirow,1,full_path);
1573         ui_actiondata(package,szCreateFolders,uirow);
1574         msiobj_release( &uirow->hdr );
1575
1576         if (folder->State == 0)
1577             create_full_pathW(full_path);
1578
1579         folder->State = 3;
1580
1581         msiobj_release(&row->hdr);
1582         HeapFree(GetProcessHeap(),0,full_path);
1583     }
1584     MSI_ViewClose(view);
1585     msiobj_release(&view->hdr);
1586    
1587     return rc;
1588 }
1589
1590 static int load_component(MSIPACKAGE* package, MSIRECORD * row)
1591 {
1592     int index = package->loaded_components;
1593     DWORD sz;
1594
1595     /* fill in the data */
1596
1597     package->loaded_components++;
1598     if (package->loaded_components == 1)
1599         package->components = HeapAlloc(GetProcessHeap(),0,
1600                                         sizeof(MSICOMPONENT));
1601     else
1602         package->components = HeapReAlloc(GetProcessHeap(),0,
1603             package->components, package->loaded_components * 
1604             sizeof(MSICOMPONENT));
1605
1606     memset(&package->components[index],0,sizeof(MSICOMPONENT));
1607
1608     sz = IDENTIFIER_SIZE;       
1609     MSI_RecordGetStringW(row,1,package->components[index].Component,&sz);
1610
1611     TRACE("Loading Component %s\n",
1612            debugstr_w(package->components[index].Component));
1613
1614     sz = 0x100;
1615     if (!MSI_RecordIsNull(row,2))
1616         MSI_RecordGetStringW(row,2,package->components[index].ComponentId,&sz);
1617             
1618     sz = IDENTIFIER_SIZE;       
1619     MSI_RecordGetStringW(row,3,package->components[index].Directory,&sz);
1620
1621     package->components[index].Attributes = MSI_RecordGetInteger(row,4);
1622
1623     sz = 0x100;       
1624     MSI_RecordGetStringW(row,5,package->components[index].Condition,&sz);
1625
1626     sz = IDENTIFIER_SIZE;       
1627     MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz);
1628
1629     package->components[index].Installed = INSTALLSTATE_ABSENT;
1630     package->components[index].Action = INSTALLSTATE_UNKNOWN;
1631     package->components[index].ActionRequest = INSTALLSTATE_UNKNOWN;
1632
1633     package->components[index].Enabled = TRUE;
1634
1635     return index;
1636 }
1637
1638 static void load_feature(MSIPACKAGE* package, MSIRECORD * row)
1639 {
1640     int index = package->loaded_features;
1641     DWORD sz;
1642     static const WCHAR Query1[] = 
1643         {'S','E','L','E','C','T',' ',
1644          '`','C','o','m','p','o','n','e','n','t','_','`',
1645          ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1646          'C','o','m','p','o','n','e','n','t','s','`',' ',
1647          'W','H','E','R','E',' ',
1648          '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1649     static const WCHAR Query2[] = 
1650         {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ', 
1651          '`','C','o','m','p','o','n','e','n','t','`',' ',
1652          'W','H','E','R','E',' ', 
1653          '`','C','o','m','p','o','n','e','n','t','`',' ',
1654          '=','\'','%','s','\'',0};
1655     MSIQUERY * view;
1656     MSIQUERY * view2;
1657     MSIRECORD * row2;
1658     MSIRECORD * row3;
1659     UINT    rc;
1660
1661     /* fill in the data */
1662
1663     package->loaded_features ++;
1664     if (package->loaded_features == 1)
1665         package->features = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFEATURE));
1666     else
1667         package->features = HeapReAlloc(GetProcessHeap(),0,package->features,
1668                                 package->loaded_features * sizeof(MSIFEATURE));
1669
1670     memset(&package->features[index],0,sizeof(MSIFEATURE));
1671     
1672     sz = IDENTIFIER_SIZE;       
1673     MSI_RecordGetStringW(row,1,package->features[index].Feature,&sz);
1674
1675     TRACE("Loading feature %s\n",debugstr_w(package->features[index].Feature));
1676
1677     sz = IDENTIFIER_SIZE;
1678     if (!MSI_RecordIsNull(row,2))
1679         MSI_RecordGetStringW(row,2,package->features[index].Feature_Parent,&sz);
1680
1681     sz = 0x100;
1682      if (!MSI_RecordIsNull(row,3))
1683         MSI_RecordGetStringW(row,3,package->features[index].Title,&sz);
1684
1685      sz = 0x100;
1686      if (!MSI_RecordIsNull(row,4))
1687         MSI_RecordGetStringW(row,4,package->features[index].Description,&sz);
1688
1689     if (!MSI_RecordIsNull(row,5))
1690         package->features[index].Display = MSI_RecordGetInteger(row,5);
1691   
1692     package->features[index].Level= MSI_RecordGetInteger(row,6);
1693
1694      sz = IDENTIFIER_SIZE;
1695      if (!MSI_RecordIsNull(row,7))
1696         MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz);
1697
1698     package->features[index].Attributes= MSI_RecordGetInteger(row,8);
1699
1700     package->features[index].Installed = INSTALLSTATE_ABSENT;
1701     package->features[index].Action = INSTALLSTATE_UNKNOWN;
1702     package->features[index].ActionRequest = INSTALLSTATE_UNKNOWN;
1703
1704     /* load feature components */
1705
1706     rc = MSI_OpenQuery(package->db, &view, Query1, package->features[index].Feature);
1707     if (rc != ERROR_SUCCESS)
1708         return;
1709     rc = MSI_ViewExecute(view,0);
1710     if (rc != ERROR_SUCCESS)
1711     {
1712         MSI_ViewClose(view);
1713         msiobj_release(&view->hdr);
1714         return;
1715     }
1716     while (1)
1717     {
1718         DWORD sz = 0x100;
1719         WCHAR buffer[0x100];
1720         DWORD rc;
1721         INT c_indx;
1722         INT cnt = package->features[index].ComponentCount;
1723
1724         rc = MSI_ViewFetch(view,&row2);
1725         if (rc != ERROR_SUCCESS)
1726             break;
1727
1728         sz = 0x100;
1729         MSI_RecordGetStringW(row2,1,buffer,&sz);
1730
1731         /* check to see if the component is already loaded */
1732         c_indx = get_loaded_component(package,buffer);
1733         if (c_indx != -1)
1734         {
1735             TRACE("Component %s already loaded at %i\n", debugstr_w(buffer),
1736                   c_indx);
1737             package->features[index].Components[cnt] = c_indx;
1738             package->features[index].ComponentCount ++;
1739             msiobj_release( &row2->hdr );
1740             continue;
1741         }
1742
1743         rc = MSI_OpenQuery(package->db, &view2, Query2, buffer);
1744         if (rc != ERROR_SUCCESS)
1745         {
1746             msiobj_release( &row2->hdr );
1747             continue;
1748         }
1749         rc = MSI_ViewExecute(view2,0);
1750         if (rc != ERROR_SUCCESS)
1751         {
1752             msiobj_release( &row2->hdr );
1753             MSI_ViewClose(view2);
1754             msiobj_release( &view2->hdr );  
1755             continue;
1756         }
1757         while (1)
1758         {
1759             DWORD rc;
1760
1761             rc = MSI_ViewFetch(view2,&row3);
1762             if (rc != ERROR_SUCCESS)
1763                 break;
1764             c_indx = load_component(package,row3);
1765             msiobj_release( &row3->hdr );
1766
1767             package->features[index].Components[cnt] = c_indx;
1768             package->features[index].ComponentCount ++;
1769             TRACE("Loaded new component to index %i\n",c_indx);
1770         }
1771         MSI_ViewClose(view2);
1772         msiobj_release( &view2->hdr );
1773         msiobj_release( &row2->hdr );
1774     }
1775     MSI_ViewClose(view);
1776     msiobj_release(&view->hdr);
1777 }
1778
1779 static UINT load_file(MSIPACKAGE* package, MSIRECORD * row)
1780 {
1781     DWORD index = package->loaded_files;
1782     DWORD i;
1783     LPWSTR buffer;
1784
1785     /* fill in the data */
1786
1787     package->loaded_files++;
1788     if (package->loaded_files== 1)
1789         package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
1790     else
1791         package->files = HeapReAlloc(GetProcessHeap(),0,
1792             package->files , package->loaded_files * sizeof(MSIFILE));
1793
1794     memset(&package->files[index],0,sizeof(MSIFILE));
1795  
1796     package->files[index].File = load_dynamic_stringW(row, 1);
1797     buffer = load_dynamic_stringW(row, 2);
1798
1799     package->files[index].ComponentIndex = -1;
1800     for (i = 0; i < package->loaded_components; i++)
1801         if (strcmpW(package->components[i].Component,buffer)==0)
1802         {
1803             package->files[index].ComponentIndex = i;
1804             break;
1805         }
1806     if (package->files[index].ComponentIndex == -1)
1807         ERR("Unfound Component %s\n",debugstr_w(buffer));
1808     HeapFree(GetProcessHeap(), 0, buffer);
1809
1810     package->files[index].FileName = load_dynamic_stringW(row,3);
1811     reduce_to_longfilename(package->files[index].FileName);
1812
1813     package->files[index].ShortName = load_dynamic_stringW(row,3);
1814     reduce_to_shortfilename(package->files[index].ShortName);
1815     
1816     package->files[index].FileSize = MSI_RecordGetInteger(row,4);
1817     package->files[index].Version = load_dynamic_stringW(row, 5);
1818     package->files[index].Language = load_dynamic_stringW(row, 6);
1819     package->files[index].Attributes= MSI_RecordGetInteger(row,7);
1820     package->files[index].Sequence= MSI_RecordGetInteger(row,8);
1821
1822     package->files[index].Temporary = FALSE;
1823     package->files[index].State = 0;
1824
1825     TRACE("File Loaded (%s)\n",debugstr_w(package->files[index].File));  
1826  
1827     return ERROR_SUCCESS;
1828 }
1829
1830 static UINT load_all_files(MSIPACKAGE *package)
1831 {
1832     MSIQUERY * view;
1833     MSIRECORD * row;
1834     UINT rc;
1835     static const WCHAR Query[] =
1836         {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1837          '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1838          '`','S','e','q','u','e','n','c','e','`', 0};
1839
1840     if (!package)
1841         return ERROR_INVALID_HANDLE;
1842
1843     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1844     if (rc != ERROR_SUCCESS)
1845         return ERROR_SUCCESS;
1846    
1847     rc = MSI_ViewExecute(view, 0);
1848     if (rc != ERROR_SUCCESS)
1849     {
1850         MSI_ViewClose(view);
1851         msiobj_release(&view->hdr);
1852         return ERROR_SUCCESS;
1853     }
1854
1855     while (1)
1856     {
1857         rc = MSI_ViewFetch(view,&row);
1858         if (rc != ERROR_SUCCESS)
1859         {
1860             rc = ERROR_SUCCESS;
1861             break;
1862         }
1863         load_file(package,row);
1864         msiobj_release(&row->hdr);
1865     }
1866     MSI_ViewClose(view);
1867     msiobj_release(&view->hdr);
1868
1869     return ERROR_SUCCESS;
1870 }
1871
1872
1873 /*
1874  * I am not doing any of the costing functionality yet. 
1875  * Mostly looking at doing the Component and Feature loading
1876  *
1877  * The native MSI does A LOT of modification to tables here. Mostly adding
1878  * a lot of temporary columns to the Feature and Component tables. 
1879  *
1880  *    note: Native msi also tracks the short filename. But I am only going to
1881  *          track the long ones.  Also looking at this directory table
1882  *          it appears that the directory table does not get the parents
1883  *          resolved base on property only based on their entries in the 
1884  *          directory table.
1885  */
1886 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1887 {
1888     MSIQUERY * view;
1889     MSIRECORD * row;
1890     UINT rc;
1891     static const WCHAR Query_all[] =
1892         {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1893          '`','F','e','a','t','u','r','e','`',0};
1894     static const WCHAR szCosting[] =
1895         {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1896     static const WCHAR szZero[] = { '0', 0 };
1897     WCHAR buffer[3];
1898     DWORD sz = 3;
1899
1900     MSI_GetPropertyW(package, szCosting, buffer, &sz);
1901     if (buffer[0]=='1')
1902         return ERROR_SUCCESS;
1903     
1904     MSI_SetPropertyW(package, szCosting, szZero);
1905     MSI_SetPropertyW(package, cszRootDrive , c_colon);
1906
1907     rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
1908     if (rc != ERROR_SUCCESS)
1909         return rc;
1910     rc = MSI_ViewExecute(view,0);
1911     if (rc != ERROR_SUCCESS)
1912     {
1913         MSI_ViewClose(view);
1914         msiobj_release(&view->hdr);
1915         return rc;
1916     }
1917     while (1)
1918     {
1919         DWORD rc;
1920
1921         rc = MSI_ViewFetch(view,&row);
1922         if (rc != ERROR_SUCCESS)
1923             break;
1924        
1925         load_feature(package,row); 
1926         msiobj_release(&row->hdr);
1927     }
1928     MSI_ViewClose(view);
1929     msiobj_release(&view->hdr);
1930
1931     load_all_files(package);
1932
1933     return ERROR_SUCCESS;
1934 }
1935
1936 UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action)
1937 {
1938     UINT count;
1939     LPWSTR *newbuf = NULL;
1940     if (script >= TOTAL_SCRIPTS)
1941     {
1942         FIXME("Unknown script requested %i\n",script);
1943         return ERROR_FUNCTION_FAILED;
1944     }
1945     TRACE("Scheduling Action %s in script %i\n",debugstr_w(action), script);
1946     
1947     count = package->script->ActionCount[script];
1948     package->script->ActionCount[script]++;
1949     if (count != 0)
1950         newbuf = HeapReAlloc(GetProcessHeap(),0,
1951                         package->script->Actions[script],
1952                         package->script->ActionCount[script]* sizeof(LPWSTR));
1953     else
1954         newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR));
1955
1956     newbuf[count] = strdupW(action);
1957     package->script->Actions[script] = newbuf;
1958
1959    return ERROR_SUCCESS;
1960 }
1961
1962 static UINT execute_script(MSIPACKAGE *package, UINT script )
1963 {
1964     int i;
1965     UINT rc = ERROR_SUCCESS;
1966
1967     TRACE("Executing Script %i\n",script);
1968
1969     for (i = 0; i < package->script->ActionCount[script]; i++)
1970     {
1971         LPWSTR action;
1972         action = package->script->Actions[script][i];
1973         ui_actionstart(package, action);
1974         TRACE("Executing Action (%s)\n",debugstr_w(action));
1975         rc = ACTION_PerformAction(package, action, TRUE);
1976         HeapFree(GetProcessHeap(),0,package->script->Actions[script][i]);
1977         if (rc != ERROR_SUCCESS)
1978             break;
1979     }
1980     HeapFree(GetProcessHeap(),0,package->script->Actions[script]);
1981
1982     package->script->ActionCount[script] = 0;
1983     package->script->Actions[script] = NULL;
1984     return rc;
1985 }
1986
1987 static UINT ACTION_FileCost(MSIPACKAGE *package)
1988 {
1989     return ERROR_SUCCESS;
1990 }
1991
1992
1993 static INT load_folder(MSIPACKAGE *package, const WCHAR* dir)
1994 {
1995     static const WCHAR Query[] =
1996         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1997          '`','D','i','r','e','c', 't','o','r','y','`',' ',
1998          'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1999          ' ','=',' ','\'','%','s','\'',
2000          0};
2001     LPWSTR ptargetdir, targetdir, parent, srcdir;
2002     LPWSTR shortname = NULL;
2003     MSIRECORD * row = 0;
2004     INT index = -1;
2005     DWORD i;
2006
2007     TRACE("Looking for dir %s\n",debugstr_w(dir));
2008
2009     for (i = 0; i < package->loaded_folders; i++)
2010     {
2011         if (strcmpW(package->folders[i].Directory,dir)==0)
2012         {
2013             TRACE(" %s retuning on index %lu\n",debugstr_w(dir),i);
2014             return i;
2015         }
2016     }
2017
2018     TRACE("Working to load %s\n",debugstr_w(dir));
2019
2020     index = package->loaded_folders++;
2021     if (package->loaded_folders==1)
2022         package->folders = HeapAlloc(GetProcessHeap(),0,
2023                                         sizeof(MSIFOLDER));
2024     else
2025         package->folders= HeapReAlloc(GetProcessHeap(),0,
2026             package->folders, package->loaded_folders* 
2027             sizeof(MSIFOLDER));
2028
2029     memset(&package->folders[index],0,sizeof(MSIFOLDER));
2030
2031     package->folders[index].Directory = strdupW(dir);
2032
2033     row = MSI_QueryGetRecord(package->db, Query, dir);
2034     if (!row)
2035         return -1;
2036
2037     ptargetdir = targetdir = load_dynamic_stringW(row,3);
2038
2039     /* split src and target dir */
2040     if (strchrW(targetdir,':'))
2041     {
2042         srcdir=strchrW(targetdir,':');
2043         *srcdir=0;
2044         srcdir ++;
2045     }
2046     else
2047         srcdir=NULL;
2048
2049     /* for now only pick long filename versions */
2050     if (strchrW(targetdir,'|'))
2051     {
2052         shortname = targetdir;
2053         targetdir = strchrW(targetdir,'|'); 
2054         *targetdir = 0;
2055         targetdir ++;
2056     }
2057     /* for the sourcedir pick the short filename */
2058     if (srcdir && strchrW(srcdir,'|'))
2059     {
2060         LPWSTR p = strchrW(srcdir,'|'); 
2061         *p = 0;
2062     }
2063
2064     /* now check for root dirs */
2065     if (targetdir[0] == '.' && targetdir[1] == 0)
2066         targetdir = NULL;
2067         
2068     if (srcdir && srcdir[0] == '.' && srcdir[1] == 0)
2069         srcdir = NULL;
2070
2071     if (targetdir)
2072     {
2073         TRACE("   TargetDefault = %s\n",debugstr_w(targetdir));
2074         HeapFree(GetProcessHeap(),0, package->folders[index].TargetDefault);
2075         package->folders[index].TargetDefault = strdupW(targetdir);
2076     }
2077
2078     if (srcdir)
2079         package->folders[index].SourceDefault = strdupW(srcdir);
2080     else if (shortname)
2081         package->folders[index].SourceDefault = strdupW(shortname);
2082     else if (targetdir)
2083         package->folders[index].SourceDefault = strdupW(targetdir);
2084     HeapFree(GetProcessHeap(), 0, ptargetdir);
2085         TRACE("   SourceDefault = %s\n",debugstr_w(package->folders[index].SourceDefault));
2086
2087     parent = load_dynamic_stringW(row,2);
2088     if (parent) 
2089     {
2090         i = load_folder(package,parent);
2091         package->folders[index].ParentIndex = i;
2092         TRACE("Parent is index %i... %s %s\n",
2093                     package->folders[index].ParentIndex,
2094         debugstr_w(package->folders[package->folders[index].ParentIndex].Directory),
2095                     debugstr_w(parent));
2096     }
2097     else
2098         package->folders[index].ParentIndex = -2;
2099     HeapFree(GetProcessHeap(), 0, parent);
2100
2101     package->folders[index].Property = load_dynamic_property(package, dir,NULL);
2102
2103     msiobj_release(&row->hdr);
2104     TRACE(" %s retuning on index %i\n",debugstr_w(dir),index);
2105     return index;
2106 }
2107
2108
2109 LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, 
2110                       BOOL set_prop, MSIFOLDER **folder)
2111 {
2112     DWORD i;
2113     LPWSTR p, path = NULL;
2114
2115     TRACE("Working to resolve %s\n",debugstr_w(name));
2116
2117     /* special resolving for Target and Source root dir */
2118     if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0)
2119     {
2120         if (!source)
2121         {
2122             path = load_dynamic_property(package,cszTargetDir,NULL);
2123             if (!path)
2124             {
2125                 path = load_dynamic_property(package,cszRootDrive,NULL);
2126                 if (set_prop)
2127                     MSI_SetPropertyW(package,cszTargetDir,path);
2128             }
2129             if (folder)
2130             {
2131                 for (i = 0; i < package->loaded_folders; i++)
2132                 {
2133                     if (strcmpW(package->folders[i].Directory,name)==0)
2134                         break;
2135                 }
2136                 *folder = &(package->folders[i]);
2137             }
2138             return path;
2139         }
2140         else
2141         {
2142             path = load_dynamic_property(package,cszSourceDir,NULL);
2143             if (!path)
2144             {
2145                 path = load_dynamic_property(package,cszDatabase,NULL);
2146                 if (path)
2147                 {
2148                     p = strrchrW(path,'\\');
2149                     if (p)
2150                         *(p+1) = 0;
2151                 }
2152             }
2153             if (folder)
2154             {
2155                 for (i = 0; i < package->loaded_folders; i++)
2156                 {
2157                     if (strcmpW(package->folders[i].Directory,name)==0)
2158                         break;
2159                 }
2160                 *folder = &(package->folders[i]);
2161             }
2162             return path;
2163         }
2164     }
2165
2166     for (i = 0; i < package->loaded_folders; i++)
2167     {
2168         if (strcmpW(package->folders[i].Directory,name)==0)
2169             break;
2170     }
2171
2172     if (i >= package->loaded_folders)
2173         return NULL;
2174
2175     if (folder)
2176         *folder = &(package->folders[i]);
2177
2178     if (!source && package->folders[i].ResolvedTarget)
2179     {
2180         path = strdupW(package->folders[i].ResolvedTarget);
2181         TRACE("   already resolved to %s\n",debugstr_w(path));
2182         return path;
2183     }
2184     else if (source && package->folders[i].ResolvedSource)
2185     {
2186         path = strdupW(package->folders[i].ResolvedSource);
2187         TRACE("   (source)already resolved to %s\n",debugstr_w(path));
2188         return path;
2189     }
2190     else if (!source && package->folders[i].Property)
2191     {
2192         path = build_directory_name(2, package->folders[i].Property, NULL);
2193                     
2194         TRACE("   internally set to %s\n",debugstr_w(path));
2195         if (set_prop)
2196             MSI_SetPropertyW(package,name,path);
2197         return path;
2198     }
2199
2200     if (package->folders[i].ParentIndex >= 0)
2201     {
2202         LPWSTR parent = package->folders[package->folders[i].ParentIndex].Directory;
2203
2204         TRACE(" ! Parent is %s\n", debugstr_w(parent));
2205
2206         p = resolve_folder(package, parent, source, set_prop, NULL);
2207         if (!source)
2208         {
2209             TRACE("   TargetDefault = %s\n",debugstr_w(package->folders[i].TargetDefault));
2210             path = build_directory_name(3, p, package->folders[i].TargetDefault, NULL);
2211             package->folders[i].ResolvedTarget = strdupW(path);
2212             TRACE("   resolved into %s\n",debugstr_w(path));
2213             if (set_prop)
2214                 MSI_SetPropertyW(package,name,path);
2215         }
2216         else 
2217         {
2218             path = build_directory_name(3, p, package->folders[i].SourceDefault, NULL);
2219             TRACE("   (source)resolved into %s\n",debugstr_w(path));
2220             package->folders[i].ResolvedSource = strdupW(path);
2221         }
2222         HeapFree(GetProcessHeap(),0,p);
2223     }
2224     return path;
2225 }
2226
2227 /* scan for and update current install states */
2228 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
2229 {
2230     int i;
2231     LPWSTR productcode;
2232
2233     productcode = load_dynamic_property(package,szProductCode,NULL);
2234
2235     for (i = 0; i < package->loaded_components; i++)
2236     {
2237         INSTALLSTATE res;
2238         res = MsiGetComponentPathW(productcode, 
2239                         package->components[i].ComponentId , NULL, NULL);
2240         if (res < 0)
2241             res = INSTALLSTATE_ABSENT;
2242         package->components[i].Installed = res;
2243     }
2244
2245     for (i = 0; i < package->loaded_features; i++)
2246     {
2247         INSTALLSTATE res = -10;
2248         int j;
2249         for (j = 0; j < package->features[i].ComponentCount; j++)
2250         {
2251             MSICOMPONENT* component = &package->components[package->features[i].
2252                                                            Components[j]];
2253             if (res == -10)
2254                 res = component->Installed;
2255             else
2256             {
2257                 if (res == component->Installed)
2258                     continue;
2259
2260                 if (res != component->Installed)
2261                         res = INSTALLSTATE_INCOMPLETE;
2262             }
2263         }
2264     }
2265 }
2266
2267 /* update compoennt state based on a feature change */
2268 void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
2269 {
2270     int i;
2271     INSTALLSTATE newstate;
2272     MSIFEATURE *feature;
2273
2274     i = get_loaded_feature(package,szFeature);
2275     if (i < 0)
2276         return;
2277
2278     feature = &package->features[i];
2279     newstate = feature->ActionRequest;
2280
2281     for( i = 0; i < feature->ComponentCount; i++)
2282     {
2283         MSICOMPONENT* component = &package->components[feature->Components[i]];
2284
2285         TRACE("MODIFYING(%i): Component %s (Installed %i, Action %i, Request %i)\n",
2286             newstate, debugstr_w(component->Component), component->Installed, 
2287             component->Action, component->ActionRequest);
2288         
2289         if (!component->Enabled)
2290             continue;
2291         else
2292         {
2293             if (newstate == INSTALLSTATE_LOCAL)
2294             {
2295                 component->ActionRequest = INSTALLSTATE_LOCAL;
2296                 component->Action = INSTALLSTATE_LOCAL;
2297             }
2298             else 
2299             {
2300                 int j,k;
2301
2302                 component->ActionRequest = newstate;
2303                 component->Action = newstate;
2304
2305                 /*if any other feature wants is local we need to set it local*/
2306                 for (j = 0; 
2307                      j < package->loaded_features &&
2308                      component->ActionRequest != INSTALLSTATE_LOCAL; 
2309                      j++)
2310                 {
2311                     for (k = 0; k < package->features[j].ComponentCount; k++)
2312                         if ( package->features[j].Components[k] ==
2313                              feature->Components[i] )
2314                         {
2315                             if (package->features[j].ActionRequest == 
2316                                 INSTALLSTATE_LOCAL)
2317                             {
2318                                 TRACE("Saved by %s\n", debugstr_w(package->features[j].Feature));
2319                                 component->ActionRequest = INSTALLSTATE_LOCAL;
2320                                 component->Action = INSTALLSTATE_LOCAL;
2321                             }
2322                             break;
2323                         }
2324                 }
2325             }
2326         }
2327         TRACE("Result (%i): Component %s (Installed %i, Action %i, Request %i)\n",
2328             newstate, debugstr_w(component->Component), component->Installed, 
2329             component->Action, component->ActionRequest);
2330     } 
2331 }
2332
2333 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property, 
2334                                     INSTALLSTATE state)
2335 {
2336     static const WCHAR all[]={'A','L','L',0};
2337     LPWSTR override = NULL;
2338     INT i;
2339     BOOL rc = FALSE;
2340
2341     override = load_dynamic_property(package, property, NULL);
2342     if (override)
2343     {
2344         rc = TRUE;
2345         for(i = 0; i < package->loaded_features; i++)
2346         {
2347             if (strcmpiW(override,all)==0)
2348             {
2349                 package->features[i].ActionRequest= state;
2350                 package->features[i].Action = state;
2351             }
2352             else
2353             {
2354                 LPWSTR ptr = override;
2355                 LPWSTR ptr2 = strchrW(override,',');
2356
2357                 while (ptr)
2358                 {
2359                     if ((ptr2 && 
2360                         strncmpW(ptr,package->features[i].Feature, ptr2-ptr)==0)
2361                         || (!ptr2 &&
2362                         strcmpW(ptr,package->features[i].Feature)==0))
2363                     {
2364                         package->features[i].ActionRequest= state;
2365                         package->features[i].Action = state;
2366                         break;
2367                     }
2368                     if (ptr2)
2369                     {
2370                         ptr=ptr2+1;
2371                         ptr2 = strchrW(ptr,',');
2372                     }
2373                     else
2374                         break;
2375                 }
2376             }
2377         }
2378         HeapFree(GetProcessHeap(),0,override);
2379     } 
2380
2381     return rc;
2382 }
2383
2384 static UINT SetFeatureStates(MSIPACKAGE *package)
2385 {
2386     LPWSTR level;
2387     INT install_level;
2388     DWORD i;
2389     INT j;
2390     static const WCHAR szlevel[] =
2391         {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2392     static const WCHAR szAddLocal[] =
2393         {'A','D','D','L','O','C','A','L',0};
2394     static const WCHAR szRemove[] =
2395         {'R','E','M','O','V','E',0};
2396     BOOL override = FALSE;
2397
2398     /* I do not know if this is where it should happen.. but */
2399
2400     TRACE("Checking Install Level\n");
2401
2402     level = load_dynamic_property(package,szlevel,NULL);
2403     if (level)
2404     {
2405         install_level = atoiW(level);
2406         HeapFree(GetProcessHeap(), 0, level);
2407     }
2408     else
2409         install_level = 1;
2410
2411     /* ok hereis the _real_ rub
2412      * all these activation/deactivation things happen in order and things
2413      * later on the list override things earlier on the list.
2414      * 1) INSTALLLEVEL processing
2415      * 2) ADDLOCAL
2416      * 3) REMOVE
2417      * 4) ADDSOURCE
2418      * 5) ADDDEFAULT
2419      * 6) REINSTALL
2420      * 7) COMPADDLOCAL
2421      * 8) COMPADDSOURCE
2422      * 9) FILEADDLOCAL
2423      * 10) FILEADDSOURCE
2424      * 11) FILEADDDEFAULT
2425      * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
2426      * ignored for all the features. seems strange, especially since it is not
2427      * documented anywhere, but it is how it works. 
2428      *
2429      * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
2430      * REMOVE are the big ones, since we don't handle administrative installs
2431      * yet anyway.
2432      */
2433     override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
2434     override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
2435
2436     if (!override)
2437     {
2438         for(i = 0; i < package->loaded_features; i++)
2439         {
2440             BOOL feature_state = ((package->features[i].Level > 0) &&
2441                              (package->features[i].Level <= install_level));
2442
2443             if ((feature_state) && 
2444                (package->features[i].Action == INSTALLSTATE_UNKNOWN))
2445             {
2446                 if (package->features[i].Attributes & 
2447                                 msidbFeatureAttributesFavorSource)
2448                 {
2449                     package->features[i].ActionRequest = INSTALLSTATE_SOURCE;
2450                     package->features[i].Action = INSTALLSTATE_SOURCE;
2451                 }
2452                 else if (package->features[i].Attributes &
2453                                 msidbFeatureAttributesFavorAdvertise)
2454                 {
2455                     package->features[i].ActionRequest =INSTALLSTATE_ADVERTISED;
2456                     package->features[i].Action =INSTALLSTATE_ADVERTISED;
2457                 }
2458                 else
2459                 {
2460                     package->features[i].ActionRequest = INSTALLSTATE_LOCAL;
2461                     package->features[i].Action = INSTALLSTATE_LOCAL;
2462                 }
2463             }
2464         }
2465     }
2466
2467     /*
2468      * now we want to enable or disable components base on feature 
2469     */
2470
2471     for(i = 0; i < package->loaded_features; i++)
2472     {
2473         MSIFEATURE* feature = &package->features[i];
2474         TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
2475             debugstr_w(feature->Feature), feature->Installed, feature->Action,
2476             feature->ActionRequest);
2477
2478         for( j = 0; j < feature->ComponentCount; j++)
2479         {
2480             MSICOMPONENT* component = &package->components[
2481                                                     feature->Components[j]];
2482
2483             if (!component->Enabled)
2484             {
2485                 component->Action = INSTALLSTATE_UNKNOWN;
2486                 component->ActionRequest = INSTALLSTATE_UNKNOWN;
2487             }
2488             else
2489             {
2490                 if (feature->Action == INSTALLSTATE_LOCAL)
2491                 {
2492                     component->Action = INSTALLSTATE_LOCAL;
2493                     component->ActionRequest = INSTALLSTATE_LOCAL;
2494                 }
2495                 else if (feature->ActionRequest == INSTALLSTATE_SOURCE)
2496                 {
2497                     if ((component->Action == INSTALLSTATE_UNKNOWN) ||
2498                         (component->Action == INSTALLSTATE_ABSENT) ||
2499                         (component->Action == INSTALLSTATE_ADVERTISED))
2500                            
2501                     {
2502                         component->Action = INSTALLSTATE_SOURCE;
2503                         component->ActionRequest = INSTALLSTATE_SOURCE;
2504                     }
2505                 }
2506                 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
2507                 {
2508                     if ((component->Action == INSTALLSTATE_UNKNOWN) ||
2509                         (component->Action == INSTALLSTATE_ABSENT))
2510                            
2511                     {
2512                         component->Action = INSTALLSTATE_ADVERTISED;
2513                         component->ActionRequest = INSTALLSTATE_ADVERTISED;
2514                     }
2515                 }
2516                 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
2517                 {
2518                     if (component->Action == INSTALLSTATE_UNKNOWN)
2519                     {
2520                         component->Action = INSTALLSTATE_ABSENT;
2521                         component->ActionRequest = INSTALLSTATE_ABSENT;
2522                     }
2523                 }
2524             }
2525         }
2526     } 
2527
2528     for(i = 0; i < package->loaded_components; i++)
2529     {
2530         MSICOMPONENT* component= &package->components[i];
2531
2532         TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
2533             debugstr_w(component->Component), component->Installed, 
2534             component->Action, component->ActionRequest);
2535     }
2536
2537
2538     return ERROR_SUCCESS;
2539 }
2540
2541 /* 
2542  * A lot is done in this function aside from just the costing.
2543  * The costing needs to be implemented at some point but for now I am going
2544  * to focus on the directory building
2545  *
2546  */
2547 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2548 {
2549     static const WCHAR ExecSeqQuery[] =
2550         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2551          '`','D','i','r','e','c','t','o','r','y','`',0};
2552     static const WCHAR ConditionQuery[] =
2553         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2554          '`','C','o','n','d','i','t','i','o','n','`',0};
2555     static const WCHAR szCosting[] =
2556         {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2557     static const WCHAR szlevel[] =
2558         {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2559     static const WCHAR szOne[] = { '1', 0 };
2560     UINT rc;
2561     MSIQUERY * view;
2562     DWORD i;
2563     LPWSTR level;
2564     DWORD sz = 3;
2565     WCHAR buffer[3];
2566
2567     MSI_GetPropertyW(package, szCosting, buffer, &sz);
2568     if (buffer[0]=='1')
2569         return ERROR_SUCCESS;
2570
2571     TRACE("Building Directory properties\n");
2572
2573     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2574     if (rc == ERROR_SUCCESS)
2575     {
2576         rc = MSI_ViewExecute(view, 0);
2577         if (rc != ERROR_SUCCESS)
2578         {
2579             MSI_ViewClose(view);
2580             msiobj_release(&view->hdr);
2581             return rc;
2582         }
2583
2584         while (1)
2585         {
2586             WCHAR name[0x100];
2587             LPWSTR path;
2588             MSIRECORD * row = 0;
2589             DWORD sz;
2590
2591             rc = MSI_ViewFetch(view,&row);
2592             if (rc != ERROR_SUCCESS)
2593             {
2594                 rc = ERROR_SUCCESS;
2595                 break;
2596             }
2597
2598             sz=0x100;
2599             MSI_RecordGetStringW(row,1,name,&sz);
2600
2601             /* This helper function now does ALL the work */
2602             TRACE("Dir %s ...\n",debugstr_w(name));
2603             load_folder(package,name);
2604             path = resolve_folder(package,name,FALSE,TRUE,NULL);
2605             TRACE("resolves to %s\n",debugstr_w(path));
2606             HeapFree( GetProcessHeap(), 0, path);
2607
2608             msiobj_release(&row->hdr);
2609         }
2610         MSI_ViewClose(view);
2611         msiobj_release(&view->hdr);
2612     }
2613
2614     TRACE("File calculations %i files\n",package->loaded_files);
2615
2616     for (i = 0; i < package->loaded_files; i++)
2617     {
2618         MSICOMPONENT* comp = NULL;
2619         MSIFILE* file= NULL;
2620
2621         file = &package->files[i];
2622         if (file->ComponentIndex >= 0)
2623             comp = &package->components[file->ComponentIndex];
2624
2625         if (file->Temporary == TRUE)
2626             continue;
2627
2628         if (comp)
2629         {
2630             LPWSTR p;
2631
2632             /* calculate target */
2633             p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
2634
2635             HeapFree(GetProcessHeap(),0,file->TargetPath);
2636
2637             TRACE("file %s is named %s\n",
2638                    debugstr_w(file->File),debugstr_w(file->FileName));       
2639
2640             file->TargetPath = build_directory_name(2, p, file->FileName);
2641
2642             HeapFree(GetProcessHeap(),0,p);
2643
2644             TRACE("file %s resolves to %s\n",
2645                    debugstr_w(file->File),debugstr_w(file->TargetPath));       
2646
2647             if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2648             {
2649                 file->State = 1;
2650                 comp->Cost += file->FileSize;
2651             }
2652             else
2653             {
2654                 if (file->Version)
2655                 {
2656                     DWORD handle;
2657                     DWORD versize;
2658                     UINT sz;
2659                     LPVOID version;
2660                     static const WCHAR name[] = 
2661                         {'\\',0};
2662                     static const WCHAR name_fmt[] = 
2663                         {'%','u','.','%','u','.','%','u','.','%','u',0};
2664                     WCHAR filever[0x100];
2665                     VS_FIXEDFILEINFO *lpVer;
2666
2667                     TRACE("Version comparison.. \n");
2668                     versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
2669                     version = HeapAlloc(GetProcessHeap(),0,versize);
2670                     GetFileVersionInfoW(file->TargetPath, 0, versize, version);
2671
2672                     VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
2673
2674                     sprintfW(filever,name_fmt,
2675                         HIWORD(lpVer->dwFileVersionMS),
2676                         LOWORD(lpVer->dwFileVersionMS),
2677                         HIWORD(lpVer->dwFileVersionLS),
2678                         LOWORD(lpVer->dwFileVersionLS));
2679
2680                     TRACE("new %s old %s\n", debugstr_w(file->Version),
2681                           debugstr_w(filever));
2682                     if (strcmpiW(filever,file->Version)<0)
2683                     {
2684                         file->State = 2;
2685                         FIXME("cost should be diff in size\n");
2686                         comp->Cost += file->FileSize;
2687                     }
2688                     else
2689                         file->State = 3;
2690                     HeapFree(GetProcessHeap(),0,version);
2691                 }
2692                 else
2693                     file->State = 3;
2694             }
2695         } 
2696     }
2697
2698     TRACE("Evaluating Condition Table\n");
2699
2700     rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2701     if (rc == ERROR_SUCCESS)
2702     {
2703         rc = MSI_ViewExecute(view, 0);
2704         if (rc != ERROR_SUCCESS)
2705         {
2706             MSI_ViewClose(view);
2707             msiobj_release(&view->hdr);
2708             return rc;
2709         }
2710     
2711         while (1)
2712         {
2713             WCHAR Feature[0x100];
2714             MSIRECORD * row = 0;
2715             DWORD sz;
2716             int feature_index;
2717
2718             rc = MSI_ViewFetch(view,&row);
2719
2720             if (rc != ERROR_SUCCESS)
2721             {
2722                 rc = ERROR_SUCCESS;
2723                 break;
2724             }
2725
2726             sz = 0x100;
2727             MSI_RecordGetStringW(row,1,Feature,&sz);
2728
2729             feature_index = get_loaded_feature(package,Feature);
2730             if (feature_index < 0)
2731                 ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature));
2732             else
2733             {
2734                 LPWSTR Condition;
2735                 Condition = load_dynamic_stringW(row,3);
2736
2737                 if (MSI_EvaluateConditionW(package,Condition) == 
2738                     MSICONDITION_TRUE)
2739                 {
2740                     int level = MSI_RecordGetInteger(row,2);
2741                     TRACE("Reseting feature %s to level %i\n",
2742                            debugstr_w(Feature), level);
2743                     package->features[feature_index].Level = level;
2744                 }
2745                 HeapFree(GetProcessHeap(),0,Condition);
2746             }
2747
2748             msiobj_release(&row->hdr);
2749         }
2750         MSI_ViewClose(view);
2751         msiobj_release(&view->hdr);
2752     }
2753
2754     TRACE("Enabling or Disabling Components\n");
2755     for (i = 0; i < package->loaded_components; i++)
2756     {
2757         if (package->components[i].Condition[0])
2758         {
2759             if (MSI_EvaluateConditionW(package,
2760                 package->components[i].Condition) == MSICONDITION_FALSE)
2761             {
2762                 TRACE("Disabling component %s\n",
2763                       debugstr_w(package->components[i].Component));
2764                 package->components[i].Enabled = FALSE;
2765             }
2766         }
2767     }
2768
2769     MSI_SetPropertyW(package,szCosting,szOne);
2770     /* set default run level if not set */
2771     level = load_dynamic_property(package,szlevel,NULL);
2772     if (!level)
2773         MSI_SetPropertyW(package,szlevel, szOne);
2774     else
2775         HeapFree(GetProcessHeap(),0,level);
2776
2777     ACTION_UpdateInstallStates(package);
2778
2779     return SetFeatureStates(package);
2780 }
2781
2782 /*
2783  * This is a helper function for handling embedded cabinet media
2784  */
2785 static UINT writeout_cabinet_stream(MSIPACKAGE *package, WCHAR* stream_name,
2786                                     WCHAR* source)
2787 {
2788     UINT rc;
2789     USHORT* data;
2790     UINT    size;
2791     DWORD   write;
2792     HANDLE  the_file;
2793     WCHAR tmp[MAX_PATH];
2794
2795     rc = read_raw_stream_data(package->db,stream_name,&data,&size); 
2796     if (rc != ERROR_SUCCESS)
2797         return rc;
2798
2799     write = MAX_PATH;
2800     if (MSI_GetPropertyW(package, cszTempFolder, tmp, &write))
2801         GetTempPathW(MAX_PATH,tmp);
2802
2803     GetTempFileNameW(tmp,stream_name,0,source);
2804
2805     track_tempfile(package,strrchrW(source,'\\'), source);
2806     the_file = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2807                            FILE_ATTRIBUTE_NORMAL, NULL);
2808
2809     if (the_file == INVALID_HANDLE_VALUE)
2810     {
2811         ERR("Unable to create file %s\n",debugstr_w(source));
2812         rc = ERROR_FUNCTION_FAILED;
2813         goto end;
2814     }
2815
2816     WriteFile(the_file,data,size,&write,NULL);
2817     CloseHandle(the_file);
2818     TRACE("wrote %li bytes to %s\n",write,debugstr_w(source));
2819 end:
2820     HeapFree(GetProcessHeap(),0,data);
2821     return rc;
2822 }
2823
2824
2825 /* Support functions for FDI functions */
2826 typedef struct
2827 {
2828     MSIPACKAGE* package;
2829     LPCSTR cab_path;
2830     LPCSTR file_name;
2831 } CabData;
2832
2833 static void * cabinet_alloc(ULONG cb)
2834 {
2835     return HeapAlloc(GetProcessHeap(), 0, cb);
2836 }
2837
2838 static void cabinet_free(void *pv)
2839 {
2840     HeapFree(GetProcessHeap(), 0, pv);
2841 }
2842
2843 static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode)
2844 {
2845     DWORD dwAccess = 0;
2846     DWORD dwShareMode = 0;
2847     DWORD dwCreateDisposition = OPEN_EXISTING;
2848     switch (oflag & _O_ACCMODE)
2849     {
2850     case _O_RDONLY:
2851         dwAccess = GENERIC_READ;
2852         dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;
2853         break;
2854     case _O_WRONLY:
2855         dwAccess = GENERIC_WRITE;
2856         dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2857         break;
2858     case _O_RDWR:
2859         dwAccess = GENERIC_READ | GENERIC_WRITE;
2860         dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2861         break;
2862     }
2863     if ((oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))
2864         dwCreateDisposition = CREATE_NEW;
2865     else if (oflag & _O_CREAT)
2866         dwCreateDisposition = CREATE_ALWAYS;
2867     return (INT_PTR)CreateFileA(pszFile, dwAccess, dwShareMode, NULL, 
2868                                 dwCreateDisposition, 0, NULL);
2869 }
2870
2871 static UINT cabinet_read(INT_PTR hf, void *pv, UINT cb)
2872 {
2873     DWORD dwRead;
2874     if (ReadFile((HANDLE)hf, pv, cb, &dwRead, NULL))
2875         return dwRead;
2876     return 0;
2877 }
2878
2879 static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb)
2880 {
2881     DWORD dwWritten;
2882     if (WriteFile((HANDLE)hf, pv, cb, &dwWritten, NULL))
2883         return dwWritten;
2884     return 0;
2885 }
2886
2887 static int cabinet_close(INT_PTR hf)
2888 {
2889     return CloseHandle((HANDLE)hf) ? 0 : -1;
2890 }
2891
2892 static long cabinet_seek(INT_PTR hf, long dist, int seektype)
2893 {
2894     /* flags are compatible and so are passed straight through */
2895     return SetFilePointer((HANDLE)hf, dist, NULL, seektype);
2896 }
2897
2898 static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
2899 {
2900     /* FIXME: try to do more processing in this function */
2901     switch (fdint)
2902     {
2903     case fdintCOPY_FILE:
2904     {
2905         CabData *data = (CabData*) pfdin->pv;
2906         ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1);
2907         char *file;
2908
2909         LPWSTR trackname;
2910         LPWSTR trackpath;
2911         LPWSTR tracknametmp;
2912         static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0};
2913        
2914         if (data->file_name && lstrcmpiA(data->file_name,pfdin->psz1))
2915                 return 0;
2916         
2917         file = cabinet_alloc((len+1)*sizeof(char));
2918         strcpy(file, data->cab_path);
2919         strcat(file, pfdin->psz1);
2920
2921         TRACE("file: %s\n", debugstr_a(file));
2922
2923         /* track this file so it can be deleted if not installed */
2924         trackpath=strdupAtoW(file);
2925         tracknametmp=strdupAtoW(strrchr(file,'\\')+1);
2926         trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) + 
2927                                   strlenW(tmpprefix)+1) * sizeof(WCHAR));
2928
2929         strcpyW(trackname,tmpprefix);
2930         strcatW(trackname,tracknametmp);
2931
2932         track_tempfile(data->package, trackname, trackpath);
2933
2934         HeapFree(GetProcessHeap(),0,trackpath);
2935         HeapFree(GetProcessHeap(),0,trackname);
2936         HeapFree(GetProcessHeap(),0,tracknametmp);
2937
2938         return cabinet_open(file, _O_WRONLY | _O_CREAT, 0);
2939     }
2940     case fdintCLOSE_FILE_INFO:
2941     {
2942         FILETIME ft;
2943             FILETIME ftLocal;
2944         if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
2945             return -1;
2946         if (!LocalFileTimeToFileTime(&ft, &ftLocal))
2947             return -1;
2948         if (!SetFileTime((HANDLE)pfdin->hf, &ftLocal, 0, &ftLocal))
2949             return -1;
2950
2951         cabinet_close(pfdin->hf);
2952         return 1;
2953     }
2954     default:
2955         return 0;
2956     }
2957 }
2958
2959 /***********************************************************************
2960  *            extract_cabinet_file
2961  *
2962  * Extract files from a cab file.
2963  */
2964 static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source, 
2965                                  const WCHAR* path, const WCHAR* file)
2966 {
2967     HFDI hfdi;
2968     ERF erf;
2969     BOOL ret;
2970     char *cabinet;
2971     char *cab_path;
2972     char *file_name;
2973     CabData data;
2974
2975     TRACE("Extracting %s (%s) to %s\n",debugstr_w(source), 
2976                     debugstr_w(file), debugstr_w(path));
2977
2978     hfdi = FDICreate(cabinet_alloc,
2979                      cabinet_free,
2980                      cabinet_open,
2981                      cabinet_read,
2982                      cabinet_write,
2983                      cabinet_close,
2984                      cabinet_seek,
2985                      0,
2986                      &erf);
2987     if (!hfdi)
2988     {
2989         ERR("FDICreate failed\n");
2990         return FALSE;
2991     }
2992
2993     if (!(cabinet = strdupWtoA( source )))
2994     {
2995         FDIDestroy(hfdi);
2996         return FALSE;
2997     }
2998     if (!(cab_path = strdupWtoA( path )))
2999     {
3000         FDIDestroy(hfdi);
3001         HeapFree(GetProcessHeap(), 0, cabinet);
3002         return FALSE;
3003     }
3004
3005     data.package = package;
3006     data.cab_path = cab_path;
3007     if (file)
3008         file_name = strdupWtoA(file);
3009     else
3010         file_name = NULL;
3011     data.file_name = file_name;
3012
3013     ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);
3014
3015     if (!ret)
3016         ERR("FDICopy failed\n");
3017
3018     FDIDestroy(hfdi);
3019
3020     HeapFree(GetProcessHeap(), 0, cabinet);
3021     HeapFree(GetProcessHeap(), 0, cab_path);
3022     HeapFree(GetProcessHeap(), 0, file_name);
3023
3024     return ret;
3025 }
3026
3027 static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path, 
3028                                  MSIFILE* file)
3029 {
3030     UINT rc = ERROR_SUCCESS;
3031     MSIRECORD * row = 0;
3032     static WCHAR source[MAX_PATH];
3033     static const WCHAR ExecSeqQuery[] =
3034         {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3035          '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3036          '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',
3037          ' ','%', 'i',' ','O','R','D','E','R',' ','B','Y',' ',
3038          '`','L','a','s','t','S','e','q','u','e','n','c','e','`',0};
3039     WCHAR cab[0x100];
3040     DWORD sz=0x100;
3041     INT seq;
3042     static UINT last_sequence = 0; 
3043
3044     if (file->Attributes & msidbFileAttributesNoncompressed)
3045     {
3046         TRACE("Uncompressed File, no media to ready.\n");
3047         return ERROR_SUCCESS;
3048     }
3049
3050     if (file->Sequence <= last_sequence)
3051     {
3052         TRACE("Media already ready (%u, %u)\n",file->Sequence,last_sequence);
3053         /*extract_a_cabinet_file(package, source,path,file->File); */
3054         return ERROR_SUCCESS;
3055     }
3056
3057     row = MSI_QueryGetRecord(package->db, ExecSeqQuery, file->Sequence);
3058     if (!row)
3059         return ERROR_FUNCTION_FAILED;
3060
3061     seq = MSI_RecordGetInteger(row,2);
3062     last_sequence = seq;
3063
3064     if (!MSI_RecordIsNull(row,4))
3065     {
3066         sz=0x100;
3067         MSI_RecordGetStringW(row,4,cab,&sz);
3068         TRACE("Source is CAB %s\n",debugstr_w(cab));
3069         /* the stream does not contain the # character */
3070         if (cab[0]=='#')
3071         {
3072             writeout_cabinet_stream(package,&cab[1],source);
3073             strcpyW(path,source);
3074             *(strrchrW(path,'\\')+1)=0;
3075         }
3076         else
3077         {
3078             sz = MAX_PATH;
3079             if (MSI_GetPropertyW(package, cszSourceDir, source, &sz))
3080             {
3081                 ERR("No Source dir defined \n");
3082                 rc = ERROR_FUNCTION_FAILED;
3083             }
3084             else
3085             {
3086                 strcpyW(path,source);
3087                 strcatW(source,cab);
3088                 /* extract the cab file into a folder in the temp folder */
3089                 sz = MAX_PATH;
3090                 if (MSI_GetPropertyW(package, cszTempFolder,path, &sz) 
3091                                     != ERROR_SUCCESS)
3092                     GetTempPathW(MAX_PATH,path);
3093             }
3094         }
3095         rc = !extract_a_cabinet_file(package, source,path,NULL);
3096     }
3097     else
3098     {
3099         sz = MAX_PATH;
3100         MSI_GetPropertyW(package,cszSourceDir,source,&sz);
3101         strcpyW(path,source);
3102     }
3103     msiobj_release(&row->hdr);
3104     return rc;
3105 }
3106
3107 inline static UINT create_component_directory ( MSIPACKAGE* package, INT component)
3108 {
3109     UINT rc = ERROR_SUCCESS;
3110     MSIFOLDER *folder;
3111     LPWSTR install_path;
3112
3113     install_path = resolve_folder(package, package->components[component].Directory,
3114                         FALSE, FALSE, &folder);
3115     if (!install_path)
3116         return ERROR_FUNCTION_FAILED; 
3117
3118     /* create the path */
3119     if (folder->State == 0)
3120     {
3121         create_full_pathW(install_path);
3122         folder->State = 2;
3123     }
3124     HeapFree(GetProcessHeap(), 0, install_path);
3125
3126     return rc;
3127 }
3128
3129 static UINT ACTION_InstallFiles(MSIPACKAGE *package)
3130 {
3131     UINT rc = ERROR_SUCCESS;
3132     DWORD index;
3133     MSIRECORD * uirow;
3134     WCHAR uipath[MAX_PATH];
3135
3136     if (!package)
3137         return ERROR_INVALID_HANDLE;
3138
3139     /* increment progress bar each time action data is sent */
3140     ui_progress(package,1,1,0,0);
3141
3142     for (index = 0; index < package->loaded_files; index++)
3143     {
3144         WCHAR path_to_source[MAX_PATH];
3145         MSIFILE *file;
3146         
3147         file = &package->files[index];
3148
3149         if (file->Temporary)
3150             continue;
3151
3152
3153         if (!ACTION_VerifyComponentForAction(package, file->ComponentIndex, 
3154                                        INSTALLSTATE_LOCAL))
3155         {
3156             ui_progress(package,2,file->FileSize,0,0);
3157             TRACE("File %s is not scheduled for install\n",
3158                    debugstr_w(file->File));
3159
3160             continue;
3161         }
3162
3163         if ((file->State == 1) || (file->State == 2))
3164         {
3165             LPWSTR p;
3166             MSICOMPONENT* comp = NULL;
3167
3168             TRACE("Installing %s\n",debugstr_w(file->File));
3169             rc = ready_media_for_file(package, path_to_source, file);
3170             /* 
3171              * WARNING!
3172              * our file table could change here because a new temp file
3173              * may have been created
3174              */
3175             file = &package->files[index];
3176             if (rc != ERROR_SUCCESS)
3177             {
3178                 ERR("Unable to ready media\n");
3179                 rc = ERROR_FUNCTION_FAILED;
3180                 break;
3181             }
3182
3183             create_component_directory( package, file->ComponentIndex);
3184
3185             /* recalculate file paths because things may have changed */
3186
3187             if (file->ComponentIndex >= 0)
3188                 comp = &package->components[file->ComponentIndex];
3189
3190             p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
3191             HeapFree(GetProcessHeap(),0,file->TargetPath);
3192
3193             file->TargetPath = build_directory_name(2, p, file->FileName);
3194             HeapFree(GetProcessHeap(),0,p);
3195
3196             if (file->Attributes & msidbFileAttributesNoncompressed)
3197             {
3198                 p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
3199                 file->SourcePath = build_directory_name(2, p, file->ShortName);
3200                 HeapFree(GetProcessHeap(),0,p);
3201             }
3202             else
3203                 file->SourcePath = build_directory_name(2, path_to_source, 
3204                             file->File);
3205
3206
3207             TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
3208                   debugstr_w(file->TargetPath));
3209
3210             /* the UI chunk */
3211             uirow=MSI_CreateRecord(9);
3212             MSI_RecordSetStringW(uirow,1,file->File);
3213             strcpyW(uipath,file->TargetPath);
3214             *(strrchrW(uipath,'\\')+1)=0;
3215             MSI_RecordSetStringW(uirow,9,uipath);
3216             MSI_RecordSetInteger(uirow,6,file->FileSize);
3217             ui_actiondata(package,szInstallFiles,uirow);
3218             msiobj_release( &uirow->hdr );
3219             ui_progress(package,2,file->FileSize,0,0);
3220
3221             
3222             if (file->Attributes & msidbFileAttributesNoncompressed)
3223                 rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE);
3224             else
3225                 rc = MoveFileW(file->SourcePath, file->TargetPath);
3226
3227             if (!rc)
3228             {
3229                 rc = GetLastError();
3230                 ERR("Unable to move/copy file (%s -> %s) (error %d)\n",
3231                      debugstr_w(file->SourcePath), debugstr_w(file->TargetPath),
3232                       rc);
3233                 if (rc == ERROR_ALREADY_EXISTS && file->State == 2)
3234                 {
3235                     if (!CopyFileW(file->SourcePath,file->TargetPath,FALSE))
3236                         ERR("Unable to copy file (%s -> %s) (error %ld)\n",
3237                             debugstr_w(file->SourcePath), 
3238                             debugstr_w(file->TargetPath), GetLastError());
3239                     if (!(file->Attributes & msidbFileAttributesNoncompressed))
3240                         DeleteFileW(file->SourcePath);
3241                     rc = 0;
3242                 }
3243                 else if (rc == ERROR_FILE_NOT_FOUND)
3244                 {
3245                     ERR("Source File Not Found!  Continuing\n");
3246                     rc = 0;
3247                 }
3248                 else if (file->Attributes & msidbFileAttributesVital)
3249                 {
3250                     ERR("Ignoring Error and continuing (nonvital file)...\n");
3251                     rc = 0;
3252                 }
3253             }
3254             else
3255             {
3256                 file->State = 4;
3257                 rc = ERROR_SUCCESS;
3258             }
3259         }
3260     }
3261
3262     return rc;
3263 }
3264
3265 inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key, 
3266                                    LPWSTR* file_source)
3267 {
3268     DWORD index;
3269
3270     if (!package)
3271         return ERROR_INVALID_HANDLE;
3272
3273     for (index = 0; index < package->loaded_files; index ++)
3274     {
3275         if (strcmpW(file_key,package->files[index].File)==0)
3276         {
3277             if (package->files[index].State >= 2)
3278             {
3279                 *file_source = strdupW(package->files[index].TargetPath);
3280                 return ERROR_SUCCESS;
3281             }
3282             else
3283                 return ERROR_FILE_NOT_FOUND;
3284         }
3285     }
3286
3287     return ERROR_FUNCTION_FAILED;
3288 }
3289
3290 static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
3291 {
3292     UINT rc;
3293     MSIQUERY * view;
3294     MSIRECORD * row = 0;
3295     static const WCHAR ExecSeqQuery[] =
3296         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3297          '`','D','u','p','l','i','c','a','t','e','F','i','l','e','`',0};
3298
3299     if (!package)
3300         return ERROR_INVALID_HANDLE;
3301
3302     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3303     if (rc != ERROR_SUCCESS)
3304         return ERROR_SUCCESS;
3305
3306     rc = MSI_ViewExecute(view, 0);
3307     if (rc != ERROR_SUCCESS)
3308     {
3309         MSI_ViewClose(view);
3310         msiobj_release(&view->hdr);
3311         return rc;
3312     }
3313
3314     while (1)
3315     {
3316         WCHAR file_key[0x100];
3317         WCHAR *file_source = NULL;
3318         WCHAR dest_name[0x100];
3319         LPWSTR dest_path, dest;
3320         WCHAR component[0x100];
3321         INT component_index;
3322
3323         DWORD sz=0x100;
3324
3325         rc = MSI_ViewFetch(view,&row);
3326         if (rc != ERROR_SUCCESS)
3327         {
3328             rc = ERROR_SUCCESS;
3329             break;
3330         }
3331
3332         sz=0x100;
3333         rc = MSI_RecordGetStringW(row,2,component,&sz);
3334         if (rc != ERROR_SUCCESS)
3335         {
3336             ERR("Unable to get component\n");
3337             msiobj_release(&row->hdr);
3338             break;
3339         }
3340
3341         component_index = get_loaded_component(package,component);
3342
3343         if (!ACTION_VerifyComponentForAction(package, component_index, 
3344                                        INSTALLSTATE_LOCAL))
3345         {
3346             TRACE("Skipping copy due to disabled component\n");
3347
3348             /* the action taken was the same as the current install state */        
3349             package->components[component_index].Action =
3350                 package->components[component_index].Installed;
3351
3352             msiobj_release(&row->hdr);
3353             continue;
3354         }
3355
3356         package->components[component_index].Action = INSTALLSTATE_LOCAL;
3357
3358         sz=0x100;
3359         rc = MSI_RecordGetStringW(row,3,file_key,&sz);
3360         if (rc != ERROR_SUCCESS)
3361         {
3362             ERR("Unable to get file key\n");
3363             msiobj_release(&row->hdr);
3364             break;
3365         }
3366
3367         rc = get_file_target(package,file_key,&file_source);
3368
3369         if (rc != ERROR_SUCCESS)
3370         {
3371             ERR("Original file unknown %s\n",debugstr_w(file_key));
3372             msiobj_release(&row->hdr);
3373             HeapFree(GetProcessHeap(),0,file_source);
3374             continue;
3375         }
3376
3377         if (MSI_RecordIsNull(row,4))
3378         {
3379             strcpyW(dest_name,strrchrW(file_source,'\\')+1);
3380         }
3381         else
3382         {
3383             sz=0x100;
3384             MSI_RecordGetStringW(row,4,dest_name,&sz);
3385             reduce_to_longfilename(dest_name);
3386          }
3387
3388         if (MSI_RecordIsNull(row,5))
3389         {
3390             LPWSTR p;
3391             dest_path = strdupW(file_source);
3392             p = strrchrW(dest_path,'\\');
3393             if (p)
3394                 *p=0;
3395         }
3396         else
3397         {
3398             WCHAR destkey[0x100];
3399             sz=0x100;
3400             MSI_RecordGetStringW(row,5,destkey,&sz);
3401             sz = 0x100;
3402             dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL);
3403             if (!dest_path)
3404             {
3405                 ERR("Unable to get destination folder\n");
3406                 msiobj_release(&row->hdr);
3407                 HeapFree(GetProcessHeap(),0,file_source);
3408                 break;
3409             }
3410         }
3411
3412         dest = build_directory_name(2, dest_path, dest_name);
3413            
3414         TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),
3415               debugstr_w(dest)); 
3416         
3417         if (strcmpW(file_source,dest))
3418             rc = !CopyFileW(file_source,dest,TRUE);
3419         else
3420             rc = ERROR_SUCCESS;
3421         
3422         if (rc != ERROR_SUCCESS)
3423             ERR("Failed to copy file %s -> %s, last error %ld\n", debugstr_w(file_source), debugstr_w(dest_path), GetLastError());
3424
3425         FIXME("We should track these duplicate files as well\n");   
3426  
3427         msiobj_release(&row->hdr);
3428         HeapFree(GetProcessHeap(),0,dest_path);
3429         HeapFree(GetProcessHeap(),0,dest);
3430         HeapFree(GetProcessHeap(),0,file_source);
3431     }
3432     MSI_ViewClose(view);
3433     msiobj_release(&view->hdr);
3434     return rc;
3435 }
3436
3437
3438 /* OK this value is "interpreted" and then formatted based on the 
3439    first few characters */
3440 static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type, 
3441                          DWORD *size)
3442 {
3443     LPSTR data = NULL;
3444     if (value[0]=='#' && value[1]!='#' && value[1]!='%')
3445     {
3446         if (value[1]=='x')
3447         {
3448             LPWSTR ptr;
3449             CHAR byte[5];
3450             LPWSTR deformated = NULL;
3451             int count;
3452
3453             deformat_string(package, &value[2], &deformated);
3454
3455             /* binary value type */
3456             ptr = deformated;
3457             *type = REG_BINARY;
3458             if (strlenW(ptr)%2)
3459                 *size = (strlenW(ptr)/2)+1;
3460             else
3461                 *size = strlenW(ptr)/2;
3462
3463             data = HeapAlloc(GetProcessHeap(),0,*size);
3464
3465             byte[0] = '0'; 
3466             byte[1] = 'x'; 
3467             byte[4] = 0; 
3468             count = 0;
3469             /* if uneven pad with a zero in front */
3470             if (strlenW(ptr)%2)
3471             {
3472                 byte[2]= '0';
3473                 byte[3]= *ptr;
3474                 ptr++;
3475                 data[count] = (BYTE)strtol(byte,NULL,0);
3476                 count ++;
3477                 TRACE("Uneven byte count\n");
3478             }
3479             while (*ptr)
3480             {
3481                 byte[2]= *ptr;
3482                 ptr++;
3483                 byte[3]= *ptr;
3484                 ptr++;
3485                 data[count] = (BYTE)strtol(byte,NULL,0);
3486                 count ++;
3487             }
3488             HeapFree(GetProcessHeap(),0,deformated);
3489
3490             TRACE("Data %li bytes(%i)\n",*size,count);
3491         }
3492         else
3493         {
3494             LPWSTR deformated;
3495             LPWSTR p;
3496             DWORD d = 0;
3497             deformat_string(package, &value[1], &deformated);
3498
3499             *type=REG_DWORD; 
3500             *size = sizeof(DWORD);
3501             data = HeapAlloc(GetProcessHeap(),0,*size);
3502             p = deformated;
3503             if (*p == '-')
3504                 p++;
3505             while (*p)
3506             {
3507                 if ( (*p < '0') || (*p > '9') )
3508                     break;
3509                 d *= 10;
3510                 d += (*p - '0');
3511                 p++;
3512             }
3513             if (deformated[0] == '-')
3514                 d = -d;
3515             *(LPDWORD)data = d;
3516             TRACE("DWORD %li\n",*(LPDWORD)data);
3517
3518             HeapFree(GetProcessHeap(),0,deformated);
3519         }
3520     }
3521     else
3522     {
3523         static const WCHAR szMulti[] = {'[','~',']',0};
3524         WCHAR *ptr;
3525         *type=REG_SZ;
3526
3527         if (value[0]=='#')
3528         {
3529             if (value[1]=='%')
3530             {
3531                 ptr = &value[2];
3532                 *type=REG_EXPAND_SZ;
3533             }
3534             else
3535                 ptr = &value[1];
3536          }
3537          else
3538             ptr=value;
3539
3540         if (strstrW(value,szMulti))
3541             *type = REG_MULTI_SZ;
3542
3543         *size = deformat_string(package, ptr,(LPWSTR*)&data);
3544     }
3545     return data;
3546 }
3547
3548 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
3549 {
3550     UINT rc;
3551     MSIQUERY * view;
3552     MSIRECORD * row = 0;
3553     static const WCHAR ExecSeqQuery[] =
3554         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3555          '`','R','e','g','i','s','t','r','y','`',0 };
3556
3557     if (!package)
3558         return ERROR_INVALID_HANDLE;
3559
3560     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3561     if (rc != ERROR_SUCCESS)
3562         return ERROR_SUCCESS;
3563
3564     rc = MSI_ViewExecute(view, 0);
3565     if (rc != ERROR_SUCCESS)
3566     {
3567         MSI_ViewClose(view);
3568         msiobj_release(&view->hdr);
3569         return rc;
3570     }
3571
3572     /* increment progress bar each time action data is sent */
3573     ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
3574
3575     while (1)
3576     {
3577         static const WCHAR szHCR[] = 
3578             {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
3579              'R','O','O','T','\\',0};
3580         static const WCHAR szHCU[] =
3581             {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
3582              'U','S','E','R','\\',0};
3583         static const WCHAR szHLM[] =
3584             {'H','K','E','Y','_','L','O','C','A','L','_',
3585              'M','A','C','H','I','N','E','\\',0};
3586         static const WCHAR szHU[] =
3587             {'H','K','E','Y','_','U','S','E','R','S','\\',0};
3588
3589         LPSTR value_data = NULL;
3590         HKEY  root_key, hkey;
3591         DWORD type,size;
3592         LPWSTR value, key, name, component, deformated;
3593         LPCWSTR szRoot;
3594         INT component_index;
3595         MSIRECORD * uirow;
3596         LPWSTR uikey;
3597         INT   root;
3598         BOOL check_first = FALSE;
3599
3600         rc = MSI_ViewFetch(view,&row);
3601         if (rc != ERROR_SUCCESS)
3602         {
3603             rc = ERROR_SUCCESS;
3604             break;
3605         }
3606         ui_progress(package,2,0,0,0);
3607
3608         value = NULL;
3609         key = NULL;
3610         uikey = NULL;
3611         name = NULL;
3612
3613         component = load_dynamic_stringW(row, 6);
3614         component_index = get_loaded_component(package,component);
3615
3616         if (!ACTION_VerifyComponentForAction(package, component_index, 
3617                                        INSTALLSTATE_LOCAL))
3618         {
3619             TRACE("Skipping write due to disabled component\n");
3620             msiobj_release(&row->hdr);
3621
3622             package->components[component_index].Action =
3623                 package->components[component_index].Installed;
3624
3625             goto next;
3626         }
3627
3628         package->components[component_index].Action = INSTALLSTATE_LOCAL;
3629
3630         name = load_dynamic_stringW(row, 4);
3631         if( MSI_RecordIsNull(row,5) && name )
3632         {
3633             /* null values can have special meanings */
3634             if (name[0]=='-' && name[1] == 0)
3635             {
3636                 msiobj_release(&row->hdr);
3637                 goto next;
3638             }
3639             else if ((name[0]=='+' && name[1] == 0) || 
3640                      (name[0] == '*' && name[1] == 0))
3641             {
3642                 HeapFree(GetProcessHeap(),0,name);
3643                 name = NULL;
3644                 check_first = TRUE;
3645             }
3646         }
3647
3648         root = MSI_RecordGetInteger(row,2);
3649         key = load_dynamic_stringW(row, 3);
3650       
3651    
3652         /* get the root key */
3653         switch (root)
3654         {
3655             case 0:  root_key = HKEY_CLASSES_ROOT; 
3656                      szRoot = szHCR;
3657                      break;
3658             case 1:  root_key = HKEY_CURRENT_USER;
3659                      szRoot = szHCU;
3660                      break;
3661             case 2:  root_key = HKEY_LOCAL_MACHINE;
3662                      szRoot = szHLM;
3663                      break;
3664             case 3:  root_key = HKEY_USERS; 
3665                      szRoot = szHU;
3666                      break;
3667             default:
3668                  ERR("Unknown root %i\n",root);
3669                  root_key=NULL;
3670                  szRoot = NULL;
3671                  break;
3672         }
3673         if (!root_key)
3674         {
3675             msiobj_release(&row->hdr);
3676             goto next;
3677         }
3678
3679         deformat_string(package, key , &deformated);
3680         size = strlenW(deformated) + strlenW(szRoot) + 1;
3681         uikey = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR));
3682         strcpyW(uikey,szRoot);
3683         strcatW(uikey,deformated);
3684
3685         if (RegCreateKeyW( root_key, deformated, &hkey))
3686         {
3687             ERR("Could not create key %s\n",debugstr_w(deformated));
3688             msiobj_release(&row->hdr);
3689             HeapFree(GetProcessHeap(),0,deformated);
3690             goto next;
3691         }
3692         HeapFree(GetProcessHeap(),0,deformated);
3693
3694         value = load_dynamic_stringW(row,5);
3695         if (value)
3696             value_data = parse_value(package, value, &type, &size); 
3697         else
3698         {
3699             static const WCHAR szEmpty[] = {0};
3700             value_data = (LPSTR)strdupW(szEmpty);
3701             size = 0;
3702             type = REG_SZ;
3703         }
3704
3705         deformat_string(package, name, &deformated);
3706
3707         /* get the double nulls to terminate SZ_MULTI */
3708         if (type == REG_MULTI_SZ)
3709             size +=sizeof(WCHAR);
3710
3711         if (!check_first)
3712         {
3713             TRACE("Setting value %s of %s\n",debugstr_w(deformated),
3714                             debugstr_w(uikey));
3715             RegSetValueExW(hkey, deformated, 0, type, value_data, size);
3716         }
3717         else
3718         {
3719             DWORD sz = 0;
3720             rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
3721             if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
3722             {
3723                 TRACE("value %s of %s checked already exists\n",
3724                                 debugstr_w(deformated), debugstr_w(uikey));
3725             }
3726             else
3727             {
3728                 TRACE("Checked and setting value %s of %s\n",
3729                                 debugstr_w(deformated), debugstr_w(uikey));
3730                 RegSetValueExW(hkey, deformated, 0, type, value_data, size);
3731             }
3732         }
3733
3734         uirow = MSI_CreateRecord(3);
3735         MSI_RecordSetStringW(uirow,2,deformated);
3736         MSI_RecordSetStringW(uirow,1,uikey);
3737
3738         if (type == REG_SZ)
3739             MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
3740         else
3741             MSI_RecordSetStringW(uirow,3,value);
3742
3743         ui_actiondata(package,szWriteRegistryValues,uirow);
3744         msiobj_release( &uirow->hdr );
3745
3746         HeapFree(GetProcessHeap(),0,value_data);
3747         HeapFree(GetProcessHeap(),0,value);
3748         HeapFree(GetProcessHeap(),0,deformated);
3749
3750         msiobj_release(&row->hdr);
3751         RegCloseKey(hkey);
3752 next:
3753         HeapFree(GetProcessHeap(),0,uikey);
3754         HeapFree(GetProcessHeap(),0,key);
3755         HeapFree(GetProcessHeap(),0,name);
3756         HeapFree(GetProcessHeap(),0,component);
3757     }
3758     MSI_ViewClose(view);
3759     msiobj_release(&view->hdr);
3760     return rc;
3761 }
3762
3763 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3764 {
3765     package->script->CurrentlyScripting = TRUE;
3766
3767     return ERROR_SUCCESS;
3768 }
3769
3770
3771 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3772 {
3773     DWORD progress = 0;
3774     DWORD total = 0;
3775     static const WCHAR q1[]=
3776         {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3777          '`','R','e','g','i','s','t','r','y','`',0};
3778     UINT rc;
3779     MSIQUERY * view;
3780     MSIRECORD * row = 0;
3781     int i;
3782
3783     TRACE(" InstallValidate \n");
3784
3785     rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
3786     if (rc != ERROR_SUCCESS)
3787         return ERROR_SUCCESS;
3788
3789     rc = MSI_ViewExecute(view, 0);
3790     if (rc != ERROR_SUCCESS)
3791     {
3792         MSI_ViewClose(view);
3793         msiobj_release(&view->hdr);
3794         return rc;
3795     }
3796     while (1)
3797     {
3798         rc = MSI_ViewFetch(view,&row);
3799         if (rc != ERROR_SUCCESS)
3800         {
3801             rc = ERROR_SUCCESS;
3802             break;
3803         }
3804         progress +=1;
3805
3806         msiobj_release(&row->hdr);
3807     }
3808     MSI_ViewClose(view);
3809     msiobj_release(&view->hdr);
3810
3811     total = total + progress * REG_PROGRESS_VALUE;
3812     total = total + package->loaded_components * COMPONENT_PROGRESS_VALUE;
3813     for (i=0; i < package->loaded_files; i++)
3814         total += package->files[i].FileSize;
3815     ui_progress(package,0,total,0,0);
3816
3817     for(i = 0; i < package->loaded_features; i++)
3818     {
3819         MSIFEATURE* feature = &package->features[i];
3820         TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
3821             debugstr_w(feature->Feature), feature->Installed, feature->Action,
3822             feature->ActionRequest);
3823     }
3824     
3825     return ERROR_SUCCESS;
3826 }
3827
3828 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3829 {
3830     UINT rc;
3831     MSIQUERY * view = NULL;
3832     MSIRECORD * row = 0;
3833     static const WCHAR ExecSeqQuery[] =
3834         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3835          '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3836     static const WCHAR title[]=
3837         {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3838
3839     TRACE("Checking launch conditions\n");
3840
3841     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3842     if (rc != ERROR_SUCCESS)
3843         return ERROR_SUCCESS;
3844
3845     rc = MSI_ViewExecute(view, 0);
3846     if (rc != ERROR_SUCCESS)
3847     {
3848         MSI_ViewClose(view);
3849         msiobj_release(&view->hdr);
3850         return rc;
3851     }
3852
3853     rc = ERROR_SUCCESS;
3854     while (rc == ERROR_SUCCESS)
3855     {
3856         LPWSTR cond = NULL; 
3857         LPWSTR message = NULL;
3858
3859         rc = MSI_ViewFetch(view,&row);
3860         if (rc != ERROR_SUCCESS)
3861         {
3862             rc = ERROR_SUCCESS;
3863             break;
3864         }
3865
3866         cond = load_dynamic_stringW(row,1);
3867
3868         if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
3869         {
3870             LPWSTR deformated;
3871             message = load_dynamic_stringW(row,2);
3872             deformat_string(package,message,&deformated); 
3873             MessageBoxW(NULL,deformated,title,MB_OK);
3874             HeapFree(GetProcessHeap(),0,message);
3875             HeapFree(GetProcessHeap(),0,deformated);
3876             rc = ERROR_FUNCTION_FAILED;
3877         }
3878         HeapFree(GetProcessHeap(),0,cond);
3879         msiobj_release(&row->hdr);
3880     }
3881     MSI_ViewClose(view);
3882     msiobj_release(&view->hdr);
3883     return rc;
3884 }
3885
3886 static LPWSTR resolve_keypath( MSIPACKAGE* package, INT
3887                             component_index)
3888 {
3889     MSICOMPONENT* cmp = &package->components[component_index];
3890
3891     if (cmp->KeyPath[0]==0)
3892     {
3893         LPWSTR p = resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
3894         return p;
3895     }
3896     if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3897     {
3898         MSIRECORD * row = 0;
3899         UINT root,len;
3900         LPWSTR key,deformated,buffer,name,deformated_name;
3901         static const WCHAR ExecSeqQuery[] =
3902             {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3903              '`','R','e','g','i','s','t','r','y','`',' ',
3904              'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
3905              ' ','=',' ' ,'\'','%','s','\'',0 };
3906         static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
3907         static const WCHAR fmt2[]=
3908             {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3909
3910         row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
3911         if (!row)
3912             return NULL;
3913
3914         root = MSI_RecordGetInteger(row,2);
3915         key = load_dynamic_stringW(row, 3);
3916         name = load_dynamic_stringW(row, 4);
3917         deformat_string(package, key , &deformated);
3918         deformat_string(package, name, &deformated_name);
3919
3920         len = strlenW(deformated) + 6;
3921         if (deformated_name)
3922             len+=strlenW(deformated_name);
3923
3924         buffer = HeapAlloc(GetProcessHeap(),0, len *sizeof(WCHAR));
3925
3926         if (deformated_name)
3927             sprintfW(buffer,fmt2,root,deformated,deformated_name);
3928         else
3929             sprintfW(buffer,fmt,root,deformated);
3930
3931         HeapFree(GetProcessHeap(),0,key);
3932         HeapFree(GetProcessHeap(),0,deformated);
3933         HeapFree(GetProcessHeap(),0,name);
3934         HeapFree(GetProcessHeap(),0,deformated_name);
3935         msiobj_release(&row->hdr);
3936
3937         return buffer;
3938     }
3939     else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3940     {
3941         FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3942         return NULL;
3943     }
3944     else
3945     {
3946         int j;
3947         j = get_loaded_file(package,cmp->KeyPath);
3948
3949         if (j>=0)
3950         {
3951             LPWSTR p = strdupW(package->files[j].TargetPath);
3952             return p;
3953         }
3954     }
3955     return NULL;
3956 }
3957
3958 static HKEY openSharedDLLsKey()
3959 {
3960     HKEY hkey=0;
3961     static const WCHAR path[] =
3962         {'S','o','f','t','w','a','r','e','\\',
3963          'M','i','c','r','o','s','o','f','t','\\',
3964          'W','i','n','d','o','w','s','\\',
3965          'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3966          'S','h','a','r','e','d','D','L','L','s',0};
3967
3968     RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3969     return hkey;
3970 }
3971
3972 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3973 {
3974     HKEY hkey;
3975     DWORD count=0;
3976     DWORD type;
3977     DWORD sz = sizeof(count);
3978     DWORD rc;
3979     
3980     hkey = openSharedDLLsKey();
3981     rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3982     if (rc != ERROR_SUCCESS)
3983         count = 0;
3984     RegCloseKey(hkey);
3985     return count;
3986 }
3987
3988 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3989 {
3990     HKEY hkey;
3991
3992     hkey = openSharedDLLsKey();
3993     if (count > 0)
3994         RegSetValueExW(hkey,path,0,REG_DWORD,
3995                     (LPBYTE)&count,sizeof(count));
3996     else
3997         RegDeleteValueW(hkey,path);
3998     RegCloseKey(hkey);
3999     return count;
4000 }
4001
4002 /*
4003  * Return TRUE if the count should be written out and FALSE if not
4004  */
4005 static void ACTION_RefCountComponent( MSIPACKAGE* package, UINT index)
4006 {
4007     INT count = 0;
4008     BOOL write = FALSE;
4009     INT j;
4010
4011     /* only refcount DLLs */
4012     if (package->components[index].KeyPath[0]==0 || 
4013         package->components[index].Attributes & 
4014             msidbComponentAttributesRegistryKeyPath || 
4015         package->components[index].Attributes & 
4016             msidbComponentAttributesODBCDataSource)
4017         write = FALSE;
4018     else
4019     {
4020         count = ACTION_GetSharedDLLsCount(package->components[index].
4021                         FullKeypath);
4022         write = (count > 0);
4023
4024         if (package->components[index].Attributes & 
4025                     msidbComponentAttributesSharedDllRefCount)
4026             write = TRUE;
4027     }
4028
4029     /* increment counts */
4030     for (j = 0; j < package->loaded_features; j++)
4031     {
4032         int i;
4033
4034         if (!ACTION_VerifyFeatureForAction(package,j,INSTALLSTATE_LOCAL))
4035             continue;
4036
4037         for (i = 0; i < package->features[j].ComponentCount; i++)
4038         {
4039             if (package->features[j].Components[i] == index)
4040                 count++;
4041         }
4042     }
4043     /* decrement counts */
4044     for (j = 0; j < package->loaded_features; j++)
4045     {
4046         int i;
4047         if (!ACTION_VerifyFeatureForAction(package,j,INSTALLSTATE_ABSENT))
4048             continue;
4049
4050         for (i = 0; i < package->features[j].ComponentCount; i++)
4051         {
4052             if (package->features[j].Components[i] == index)
4053                 count--;
4054         }
4055     }
4056
4057     /* ref count all the files in the component */
4058     if (write)
4059         for (j = 0; j < package->loaded_files; j++)
4060         {
4061             if (package->files[j].Temporary)
4062                 continue;
4063             if (package->files[j].ComponentIndex == index)
4064                 ACTION_WriteSharedDLLsCount(package->files[j].TargetPath,count);
4065         }
4066     
4067     /* add a count for permenent */
4068     if (package->components[index].Attributes &
4069                                 msidbComponentAttributesPermanent)
4070         count ++;
4071     
4072     package->components[index].RefCount = count;
4073
4074     if (write)
4075         ACTION_WriteSharedDLLsCount(package->components[index].FullKeypath,
4076             package->components[index].RefCount);
4077 }
4078
4079 /*
4080  * Ok further analysis makes me think that this work is
4081  * actually done in the PublishComponents and PublishFeatures
4082  * step, and not here.  It appears like the keypath and all that is
4083  * resolved in this step, however actually written in the Publish steps.
4084  * But we will leave it here for now because it is unclear
4085  */
4086 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
4087 {
4088     LPWSTR productcode;
4089     WCHAR squished_pc[GUID_SIZE];
4090     WCHAR squished_cc[GUID_SIZE];
4091     UINT rc;
4092     DWORD i;
4093     HKEY hkey=0,hkey2=0;
4094
4095     if (!package)
4096         return ERROR_INVALID_HANDLE;
4097
4098     /* writes the Component and Features values to the registry */
4099     productcode = load_dynamic_property(package,szProductCode,&rc);
4100     if (!productcode)
4101         return rc;
4102
4103     rc = MSIREG_OpenComponents(&hkey);
4104     if (rc != ERROR_SUCCESS)
4105         goto end;
4106       
4107     squash_guid(productcode,squished_pc);
4108     ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
4109     for (i = 0; i < package->loaded_components; i++)
4110     {
4111         ui_progress(package,2,0,0,0);
4112         if (package->components[i].ComponentId[0]!=0)
4113         {
4114             WCHAR *keypath = NULL;
4115             MSIRECORD * uirow;
4116
4117             squash_guid(package->components[i].ComponentId,squished_cc);
4118            
4119             keypath = resolve_keypath(package,i);
4120             package->components[i].FullKeypath = keypath;
4121
4122             /* do the refcounting */
4123             ACTION_RefCountComponent( package, i);
4124
4125             TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n", 
4126                             debugstr_w(package->components[i].Component),
4127                             debugstr_w(squished_cc),
4128                             debugstr_w(package->components[i].FullKeypath), 
4129                             package->components[i].RefCount);
4130             /*
4131             * Write the keypath out if the component is to be registered
4132             * and delete the key if the component is to be deregistered
4133             */
4134             if (ACTION_VerifyComponentForAction(package, i,
4135                                     INSTALLSTATE_LOCAL))
4136             {
4137                 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
4138                 if (rc != ERROR_SUCCESS)
4139                     continue;
4140
4141                 if (keypath)
4142                 {
4143                     RegSetValueExW(hkey2,squished_pc,0,REG_SZ,(LPVOID)keypath,
4144                                 (strlenW(keypath)+1)*sizeof(WCHAR));
4145
4146                     if (package->components[i].Attributes & 
4147                                 msidbComponentAttributesPermanent)
4148                     {
4149                         static const WCHAR szPermKey[] =
4150                             { '0','0','0','0','0','0','0','0','0','0','0','0',
4151                               '0','0','0','0','0','0','0', '0','0','0','0','0',
4152                               '0','0','0','0','0','0','0','0',0};
4153
4154                         RegSetValueExW(hkey2,szPermKey,0,REG_SZ,
4155                                         (LPVOID)keypath,
4156                                         (strlenW(keypath)+1)*sizeof(WCHAR));
4157                     }
4158                     
4159                     RegCloseKey(hkey2);
4160         
4161                     /* UI stuff */
4162                     uirow = MSI_CreateRecord(3);
4163                     MSI_RecordSetStringW(uirow,1,productcode);
4164                     MSI_RecordSetStringW(uirow,2,package->components[i].
4165                                                             ComponentId);
4166                     MSI_RecordSetStringW(uirow,3,keypath);
4167                     ui_actiondata(package,szProcessComponents,uirow);
4168                     msiobj_release( &uirow->hdr );
4169                }
4170             }
4171             else if (ACTION_VerifyComponentForAction(package, i,
4172                                     INSTALLSTATE_ABSENT))
4173             {
4174                 DWORD res;
4175
4176                 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
4177                 if (rc != ERROR_SUCCESS)
4178                     continue;
4179
4180                 RegDeleteValueW(hkey2,squished_pc);
4181
4182                 /* if the key is empty delete it */
4183                 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
4184                 RegCloseKey(hkey2);
4185                 if (res == ERROR_NO_MORE_ITEMS)
4186                     RegDeleteKeyW(hkey,squished_cc);
4187         
4188                 /* UI stuff */
4189                 uirow = MSI_CreateRecord(2);
4190                 MSI_RecordSetStringW(uirow,1,productcode);
4191                 MSI_RecordSetStringW(uirow,2,package->components[i].
4192                                 ComponentId);
4193                 ui_actiondata(package,szProcessComponents,uirow);
4194                 msiobj_release( &uirow->hdr );
4195             }
4196         }
4197     } 
4198 end:
4199     HeapFree(GetProcessHeap(), 0, productcode);
4200     RegCloseKey(hkey);
4201     return rc;
4202 }
4203
4204 typedef struct {
4205     CLSID       clsid;
4206     LPWSTR      source;
4207
4208     LPWSTR      path;
4209     ITypeLib    *ptLib;
4210 } typelib_struct;
4211
4212 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType, 
4213                                        LPWSTR lpszName, LONG_PTR lParam)
4214 {
4215     TLIBATTR *attr;
4216     typelib_struct *tl_struct = (typelib_struct*) lParam;
4217     static const WCHAR fmt[] = {'%','s','\\','%','i',0};
4218     int sz; 
4219     HRESULT res;
4220
4221     if (!IS_INTRESOURCE(lpszName))
4222     {
4223         ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
4224         return TRUE;
4225     }
4226
4227     sz = strlenW(tl_struct->source)+4;
4228     sz *= sizeof(WCHAR);
4229
4230     if ((INT)lpszName == 1)
4231         tl_struct->path = strdupW(tl_struct->source);
4232     else
4233     {
4234         tl_struct->path = HeapAlloc(GetProcessHeap(),0,sz);
4235         sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
4236     }
4237
4238     TRACE("trying %s\n", debugstr_w(tl_struct->path));
4239     res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
4240     if (!SUCCEEDED(res))
4241     {
4242         HeapFree(GetProcessHeap(),0,tl_struct->path);
4243         tl_struct->path = NULL;
4244
4245         return TRUE;
4246     }
4247
4248     ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
4249     if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
4250     {
4251         ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
4252         return FALSE;
4253     }
4254
4255     HeapFree(GetProcessHeap(),0,tl_struct->path);
4256     tl_struct->path = NULL;
4257
4258     ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
4259     ITypeLib_Release(tl_struct->ptLib);
4260
4261     return TRUE;
4262 }
4263
4264 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
4265 {
4266     /* 
4267      * OK this is a bit confusing.. I am given a _Component key and I believe
4268      * that the file that is being registered as a type library is the "key file
4269      * of that component" which I interpret to mean "The file in the KeyPath of
4270      * that component".
4271      */
4272     UINT rc;
4273     MSIQUERY * view;
4274     MSIRECORD * row = 0;
4275     static const WCHAR Query[] =
4276         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4277          '`','T','y','p','e','L','i','b','`',0};
4278
4279     if (!package)
4280         return ERROR_INVALID_HANDLE;
4281
4282     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
4283     if (rc != ERROR_SUCCESS)
4284         return ERROR_SUCCESS;
4285
4286     rc = MSI_ViewExecute(view, 0);
4287     if (rc != ERROR_SUCCESS)
4288     {
4289         MSI_ViewClose(view);
4290         msiobj_release(&view->hdr);
4291         return rc;
4292     }
4293
4294     while (1)
4295     {   
4296         WCHAR component[0x100];
4297         DWORD sz;
4298         INT index;
4299         LPWSTR guid;
4300         typelib_struct tl_struct;
4301         HMODULE module;
4302         static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
4303
4304         rc = MSI_ViewFetch(view,&row);
4305         if (rc != ERROR_SUCCESS)
4306         {
4307             rc = ERROR_SUCCESS;
4308             break;
4309         }
4310
4311         sz = 0x100;
4312         MSI_RecordGetStringW(row,3,component,&sz);
4313
4314         index = get_loaded_component(package,component);
4315         if (index < 0)
4316         {
4317             msiobj_release(&row->hdr);
4318             continue;
4319         }
4320
4321         if (!ACTION_VerifyComponentForAction(package, index,
4322                                 INSTALLSTATE_LOCAL))
4323         {
4324             TRACE("Skipping typelib reg due to disabled component\n");
4325             msiobj_release(&row->hdr);
4326
4327             package->components[index].Action =
4328                 package->components[index].Installed;
4329
4330             continue;
4331         }
4332
4333         package->components[index].Action = INSTALLSTATE_LOCAL;
4334
4335         index = get_loaded_file(package,package->components[index].KeyPath); 
4336    
4337         if (index < 0)
4338         {
4339             msiobj_release(&row->hdr);
4340             continue;
4341         }
4342
4343         guid = load_dynamic_stringW(row,1);
4344         module = LoadLibraryExW(package->files[index].TargetPath, NULL,
4345                         LOAD_LIBRARY_AS_DATAFILE);
4346         if (module != NULL)
4347         {
4348             CLSIDFromString(guid, &tl_struct.clsid);
4349             tl_struct.source = strdupW(package->files[index].TargetPath);
4350             tl_struct.path = NULL;
4351
4352             EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc, 
4353                                (LONG_PTR)&tl_struct);
4354
4355             if (tl_struct.path != NULL)
4356             {
4357                 LPWSTR help;
4358                 WCHAR helpid[0x100];
4359                 HRESULT res;
4360
4361                 sz = 0x100;
4362                 MSI_RecordGetStringW(row,6,helpid,&sz);
4363
4364                 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
4365                 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
4366                 HeapFree(GetProcessHeap(),0,help);
4367
4368                 if (!SUCCEEDED(res))
4369                     ERR("Failed to register type library %s\n", 
4370                             debugstr_w(tl_struct.path));
4371                 else
4372                 {
4373                     ui_actiondata(package,szRegisterTypeLibraries,row);
4374                 
4375                     TRACE("Registered %s\n", debugstr_w(tl_struct.path));
4376                 }
4377
4378                 ITypeLib_Release(tl_struct.ptLib);
4379                 HeapFree(GetProcessHeap(),0,tl_struct.path);
4380             }
4381             else
4382                 ERR("Failed to load type library %s\n", 
4383                     debugstr_w(tl_struct.source));
4384        
4385             FreeLibrary(module);
4386             HeapFree(GetProcessHeap(),0,tl_struct.source);
4387         }
4388         else
4389             ERR("Could not load file! %s\n",
4390                     debugstr_w(package->files[index].TargetPath));
4391         msiobj_release(&row->hdr);
4392     }
4393     MSI_ViewClose(view);
4394     msiobj_release(&view->hdr);
4395     return rc;
4396 }
4397
4398 static INT load_appid(MSIPACKAGE* package, MSIRECORD *row)
4399 {
4400     DWORD index = package->loaded_appids;
4401     DWORD sz;
4402     LPWSTR buffer;
4403
4404     /* fill in the data */
4405
4406     package->loaded_appids++;
4407     if (package->loaded_appids == 1)
4408         package->appids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIAPPID));
4409     else
4410         package->appids = HeapReAlloc(GetProcessHeap(),0,
4411             package->appids, package->loaded_appids * sizeof(MSIAPPID));
4412
4413     memset(&package->appids[index],0,sizeof(MSIAPPID));
4414     
4415     sz = IDENTIFIER_SIZE;
4416     MSI_RecordGetStringW(row, 1, package->appids[index].AppID, &sz);
4417     TRACE("loading appid %s\n",debugstr_w(package->appids[index].AppID));
4418
4419     buffer = load_dynamic_stringW(row,2);
4420     deformat_string(package,buffer,&package->appids[index].RemoteServerName);
4421     HeapFree(GetProcessHeap(),0,buffer);
4422
4423     package->appids[index].LocalServer = load_dynamic_stringW(row,3);
4424     package->appids[index].ServiceParameters = load_dynamic_stringW(row,4);
4425     package->appids[index].DllSurrogate = load_dynamic_stringW(row,5);
4426
4427     package->appids[index].ActivateAtStorage = !MSI_RecordIsNull(row,6);
4428     package->appids[index].RunAsInteractiveUser = !MSI_RecordIsNull(row,7);
4429     
4430     return index;
4431 }
4432
4433 static INT load_given_appid(MSIPACKAGE *package, LPCWSTR appid)
4434 {
4435     INT rc;
4436     MSIRECORD *row;
4437     INT i;
4438     static const WCHAR ExecSeqQuery[] =
4439         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4440          '`','A','p','p','I','d','`',' ','W','H','E','R','E',' ',
4441          '`','A','p','p','I','d','`',' ','=',' ','\'','%','s','\'',0};
4442
4443     if (!appid)
4444         return -1;
4445
4446     /* check for appids already loaded */
4447     for (i = 0; i < package->loaded_appids; i++)
4448         if (strcmpiW(package->appids[i].AppID,appid)==0)
4449         {
4450             TRACE("found appid %s at index %i\n",debugstr_w(appid),i);
4451             return i;
4452         }
4453     
4454     row = MSI_QueryGetRecord(package->db, ExecSeqQuery, appid);
4455     if (!row)
4456         return -1;
4457
4458     rc = load_appid(package, row);
4459     msiobj_release(&row->hdr);
4460
4461     return rc;
4462 }
4463
4464 static INT load_given_progid(MSIPACKAGE *package, LPCWSTR progid);
4465 static INT load_given_class(MSIPACKAGE *package, LPCWSTR classid);
4466
4467 static INT load_progid(MSIPACKAGE* package, MSIRECORD *row)
4468 {
4469     DWORD index = package->loaded_progids;
4470     LPWSTR buffer;
4471
4472     /* fill in the data */
4473
4474     package->loaded_progids++;
4475     if (package->loaded_progids == 1)
4476         package->progids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIPROGID));
4477     else
4478         package->progids = HeapReAlloc(GetProcessHeap(),0,
4479             package->progids , package->loaded_progids * sizeof(MSIPROGID));
4480
4481     memset(&package->progids[index],0,sizeof(MSIPROGID));
4482
4483     package->progids[index].ProgID = load_dynamic_stringW(row,1);
4484     TRACE("loading progid %s\n",debugstr_w(package->progids[index].ProgID));
4485
4486     buffer = load_dynamic_stringW(row,2);
4487     package->progids[index].ParentIndex = load_given_progid(package,buffer);
4488     if (package->progids[index].ParentIndex < 0 && buffer)
4489         FIXME("Unknown parent ProgID %s\n",debugstr_w(buffer));
4490     HeapFree(GetProcessHeap(),0,buffer);
4491
4492     buffer = load_dynamic_stringW(row,3);
4493     package->progids[index].ClassIndex = load_given_class(package,buffer);
4494     if (package->progids[index].ClassIndex< 0 && buffer)
4495         FIXME("Unknown class %s\n",debugstr_w(buffer));
4496     HeapFree(GetProcessHeap(),0,buffer);
4497
4498     package->progids[index].Description = load_dynamic_stringW(row,4);
4499
4500     if (!MSI_RecordIsNull(row,6))
4501     {
4502         INT icon_index = MSI_RecordGetInteger(row,6); 
4503         LPWSTR FileName = load_dynamic_stringW(row,5);
4504         LPWSTR FilePath;
4505         static const WCHAR fmt[] = {'%','s',',','%','i',0};
4506
4507         build_icon_path(package,FileName,&FilePath);
4508        
4509         package->progids[index].IconPath = 
4510                 HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+10)*
4511                                 sizeof(WCHAR));
4512
4513         sprintfW(package->progids[index].IconPath,fmt,FilePath,icon_index);
4514
4515         HeapFree(GetProcessHeap(),0,FilePath);
4516         HeapFree(GetProcessHeap(),0,FileName);
4517     }
4518     else
4519     {
4520         buffer = load_dynamic_stringW(row,5);
4521         if (buffer)
4522             build_icon_path(package,buffer,&(package->progids[index].IconPath));
4523         HeapFree(GetProcessHeap(),0,buffer);
4524     }
4525
4526     package->progids[index].CurVerIndex = -1;
4527     package->progids[index].VersionIndIndex = -1;
4528
4529     /* if we have a parent then we may be that parents CurVer */
4530     if (package->progids[index].ParentIndex >= 0 && 
4531         package->progids[index].ParentIndex != index)
4532     {
4533         int pindex = package->progids[index].ParentIndex;
4534         while (package->progids[pindex].ParentIndex>= 0 && 
4535                package->progids[pindex].ParentIndex != pindex)
4536             pindex = package->progids[pindex].ParentIndex;
4537
4538         FIXME("BAD BAD need to determing if we are really the CurVer\n");
4539
4540         package->progids[index].CurVerIndex = pindex;
4541         package->progids[pindex].VersionIndIndex = index;
4542     }
4543     
4544     return index;
4545 }
4546
4547 static INT load_given_progid(MSIPACKAGE *package, LPCWSTR progid)
4548 {
4549     INT rc;
4550     MSIRECORD *row;
4551     INT i;
4552     static const WCHAR ExecSeqQuery[] =
4553         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4554          '`','P','r','o','g','I','d','`',' ','W','H','E','R','E',' ',
4555          '`','P','r','o','g','I','d','`',' ','=',' ','\'','%','s','\'',0};
4556
4557     if (!progid)
4558         return -1;
4559
4560     /* check for progids already loaded */
4561     for (i = 0; i < package->loaded_progids; i++)
4562         if (strcmpiW(package->progids[i].ProgID,progid)==0)
4563         {
4564             TRACE("found progid %s at index %i\n",debugstr_w(progid), i);
4565             return i;
4566         }
4567     
4568     row = MSI_QueryGetRecord(package->db, ExecSeqQuery, progid);
4569     if(!row)
4570         return -1;
4571
4572     rc = load_progid(package, row);
4573     msiobj_release(&row->hdr);
4574
4575     return rc;
4576 }
4577
4578 static INT load_class(MSIPACKAGE* package, MSIRECORD *row)
4579 {
4580     DWORD index = package->loaded_classes;
4581     DWORD sz,i;
4582     LPWSTR buffer;
4583
4584     /* fill in the data */
4585
4586     package->loaded_classes++;
4587     if (package->loaded_classes== 1)
4588         package->classes = HeapAlloc(GetProcessHeap(),0,sizeof(MSICLASS));
4589     else
4590         package->classes = HeapReAlloc(GetProcessHeap(),0,
4591             package->classes, package->loaded_classes * sizeof(MSICLASS));
4592
4593     memset(&package->classes[index],0,sizeof(MSICLASS));
4594
4595     sz = IDENTIFIER_SIZE;
4596     MSI_RecordGetStringW(row, 1, package->classes[index].CLSID, &sz);
4597     TRACE("loading class %s\n",debugstr_w(package->classes[index].CLSID));
4598     sz = IDENTIFIER_SIZE;
4599     MSI_RecordGetStringW(row, 2, package->classes[index].Context, &sz);
4600     buffer = load_dynamic_stringW(row,3);
4601     package->classes[index].ComponentIndex = get_loaded_component(package, 
4602                     buffer);
4603     HeapFree(GetProcessHeap(),0,buffer);
4604
4605     package->classes[index].ProgIDText = load_dynamic_stringW(row,4);
4606     package->classes[index].ProgIDIndex = 
4607                 load_given_progid(package, package->classes[index].ProgIDText);
4608
4609     package->classes[index].Description = load_dynamic_stringW(row,5);
4610
4611     buffer = load_dynamic_stringW(row,6);
4612     if (buffer)
4613         package->classes[index].AppIDIndex = 
4614                 load_given_appid(package, buffer);
4615     else
4616         package->classes[index].AppIDIndex = -1;
4617     HeapFree(GetProcessHeap(),0,buffer);
4618
4619     package->classes[index].FileTypeMask = load_dynamic_stringW(row,7);
4620
4621     if (!MSI_RecordIsNull(row,9))
4622     {
4623
4624         INT icon_index = MSI_RecordGetInteger(row,9); 
4625         LPWSTR FileName = load_dynamic_stringW(row,8);
4626         LPWSTR FilePath;
4627         static const WCHAR fmt[] = {'%','s',',','%','i',0};
4628
4629         build_icon_path(package,FileName,&FilePath);
4630        
4631         package->classes[index].IconPath = 
4632                 HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+5)*
4633                                 sizeof(WCHAR));
4634
4635         sprintfW(package->classes[index].IconPath,fmt,FilePath,icon_index);
4636
4637         HeapFree(GetProcessHeap(),0,FilePath);
4638         HeapFree(GetProcessHeap(),0,FileName);
4639     }
4640     else
4641     {
4642         buffer = load_dynamic_stringW(row,8);
4643         if (buffer)
4644             build_icon_path(package,buffer,&(package->classes[index].IconPath));
4645         HeapFree(GetProcessHeap(),0,buffer);
4646     }
4647
4648     if (!MSI_RecordIsNull(row,10))
4649     {
4650         i = MSI_RecordGetInteger(row,10);
4651         if (i != MSI_NULL_INTEGER && i > 0 &&  i < 4)
4652         {
4653             static const WCHAR ole2[] = {'o','l','e','2','.','d','l','l',0};
4654             static const WCHAR ole32[] = {'o','l','e','3','2','.','d','l','l',0};
4655
4656             switch(i)
4657             {
4658                 case 1:
4659                     package->classes[index].DefInprocHandler = strdupW(ole2);
4660                     break;
4661                 case 2:
4662                     package->classes[index].DefInprocHandler32 = strdupW(ole32);
4663                     break;
4664                 case 3:
4665                     package->classes[index].DefInprocHandler = strdupW(ole2);
4666                     package->classes[index].DefInprocHandler32 = strdupW(ole32);
4667                     break;
4668             }
4669         }
4670         else
4671         {
4672             package->classes[index].DefInprocHandler32 = load_dynamic_stringW(
4673                             row, 10);
4674             reduce_to_longfilename(package->classes[index].DefInprocHandler32);
4675         }
4676     }
4677     buffer = load_dynamic_stringW(row,11);
4678     deformat_string(package,buffer,&package->classes[index].Argument);
4679     HeapFree(GetProcessHeap(),0,buffer);
4680
4681     buffer = load_dynamic_stringW(row,12);
4682     package->classes[index].FeatureIndex = get_loaded_feature(package,buffer);
4683     HeapFree(GetProcessHeap(),0,buffer);
4684
4685     package->classes[index].Attributes = MSI_RecordGetInteger(row,13);
4686     
4687     return index;
4688 }
4689
4690 /*
4691  * the Class table has 3 primary keys. Generally it is only 
4692  * referenced through the first CLSID key. However when loading
4693  * all of the classes we need to make sure we do not ignore rows
4694  * with other Context and ComponentIndexs 
4695  */
4696 static INT load_given_class(MSIPACKAGE *package, LPCWSTR classid)
4697 {
4698     INT rc;
4699     MSIRECORD *row;
4700     INT i;
4701     static const WCHAR ExecSeqQuery[] =
4702         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4703          '`','C','l','a','s','s','`',' ','W','H','E','R','E',' ',
4704          '`','C','L','S','I','D','`',' ','=',' ','\'','%','s','\'',0};
4705
4706
4707     if (!classid)
4708         return -1;
4709     
4710     /* check for classes already loaded */
4711     for (i = 0; i < package->loaded_classes; i++)
4712         if (strcmpiW(package->classes[i].CLSID,classid)==0)
4713         {
4714             TRACE("found class %s at index %i\n",debugstr_w(classid), i);
4715             return i;
4716         }
4717     
4718     row = MSI_QueryGetRecord(package->db, ExecSeqQuery, classid);
4719     if (!row)
4720         return -1;
4721
4722     rc = load_class(package, row);
4723     msiobj_release(&row->hdr);
4724
4725     return rc;
4726 }
4727
4728 static INT load_given_extension(MSIPACKAGE *package, LPCWSTR extension);
4729
4730 static INT load_mime(MSIPACKAGE* package, MSIRECORD *row)
4731 {
4732     DWORD index = package->loaded_mimes;
4733     DWORD sz;
4734     LPWSTR buffer;
4735
4736     /* fill in the data */
4737
4738     package->loaded_mimes++;
4739     if (package->loaded_mimes== 1)
4740         package->mimes= HeapAlloc(GetProcessHeap(),0,sizeof(MSIMIME));
4741     else
4742         package->mimes= HeapReAlloc(GetProcessHeap(),0,
4743             package->mimes, package->loaded_mimes* 
4744             sizeof(MSIMIME));
4745
4746     memset(&package->mimes[index],0,sizeof(MSIMIME));
4747
4748     package->mimes[index].ContentType = load_dynamic_stringW(row,1); 
4749     TRACE("loading mime %s\n",debugstr_w(package->mimes[index].ContentType));
4750
4751     buffer = load_dynamic_stringW(row,2);
4752     package->mimes[index].ExtensionIndex = load_given_extension(package,
4753                     buffer);
4754     HeapFree(GetProcessHeap(),0,buffer);
4755
4756     sz = IDENTIFIER_SIZE;
4757     MSI_RecordGetStringW(row,3,package->mimes[index].CLSID,&sz);
4758     package->mimes[index].ClassIndex= load_given_class(package,
4759                     package->mimes[index].CLSID);
4760     
4761     return index;
4762 }
4763
4764 static INT load_given_mime(MSIPACKAGE *package, LPCWSTR mime)
4765 {
4766     INT rc;
4767     MSIRECORD *row;
4768     INT i;
4769     static const WCHAR ExecSeqQuery[] =
4770         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4771          '`','M','I','M','E','`',' ','W','H','E','R','E',' ',
4772          '`','C','o','n','t','e','n','t','T','y','p','e','`',' ','=',' ',
4773          '\'','%','s','\'',0};
4774
4775     if (!mime)
4776         return -1;
4777     
4778     /* check for mime already loaded */
4779     for (i = 0; i < package->loaded_mimes; i++)
4780         if (strcmpiW(package->mimes[i].ContentType,mime)==0)
4781         {
4782             TRACE("found mime %s at index %i\n",debugstr_w(mime), i);
4783             return i;
4784         }
4785     
4786     row = MSI_QueryGetRecord(package->db, ExecSeqQuery, mime);
4787     if (!row)
4788         return -1;
4789
4790     rc = load_mime(package, row);
4791     msiobj_release(&row->hdr);
4792
4793     return rc;
4794 }
4795
4796 static INT load_extension(MSIPACKAGE* package, MSIRECORD *row)
4797 {
4798     DWORD index = package->loaded_extensions;
4799     DWORD sz;
4800     LPWSTR buffer;
4801
4802     /* fill in the data */
4803
4804     package->loaded_extensions++;
4805     if (package->loaded_extensions == 1)
4806         package->extensions = HeapAlloc(GetProcessHeap(),0,sizeof(MSIEXTENSION));
4807     else
4808         package->extensions = HeapReAlloc(GetProcessHeap(),0,
4809             package->extensions, package->loaded_extensions* 
4810             sizeof(MSIEXTENSION));
4811
4812     memset(&package->extensions[index],0,sizeof(MSIEXTENSION));
4813
4814     sz = 256;
4815     MSI_RecordGetStringW(row,1,package->extensions[index].Extension,&sz);
4816     TRACE("loading extension %s\n",
4817                     debugstr_w(package->extensions[index].Extension));
4818
4819     buffer = load_dynamic_stringW(row,2);
4820     package->extensions[index].ComponentIndex = 
4821             get_loaded_component(package,buffer);
4822     HeapFree(GetProcessHeap(),0,buffer);
4823
4824     package->extensions[index].ProgIDText = load_dynamic_stringW(row,3);
4825     package->extensions[index].ProgIDIndex = load_given_progid(package,
4826                     package->extensions[index].ProgIDText);
4827
4828     buffer = load_dynamic_stringW(row,4);
4829     package->extensions[index].MIMEIndex = load_given_mime(package,buffer);
4830     HeapFree(GetProcessHeap(),0,buffer);
4831
4832     buffer = load_dynamic_stringW(row,5);
4833     package->extensions[index].FeatureIndex = 
4834             get_loaded_feature(package,buffer);
4835     HeapFree(GetProcessHeap(),0,buffer);
4836
4837     return index;
4838 }
4839
4840 /*
4841  * While the extension table has 2 primary keys, this function is only looking
4842  * at the Extension key which is what is referenced as a forign key 
4843  */
4844 static INT load_given_extension(MSIPACKAGE *package, LPCWSTR extension)
4845 {
4846     INT rc;
4847     MSIRECORD *row;
4848     INT i;
4849     static const WCHAR ExecSeqQuery[] =
4850         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4851          '`','E','x','t','e','n','s','i','o','n','`',' ',
4852          'W','H','E','R','E',' ',
4853          '`','E','x','t','e','n','s','i','o','n','`',' ','=',' ',
4854          '\'','%','s','\'',0};
4855
4856     if (!extension)
4857         return -1;
4858
4859     /* check for extensions already loaded */
4860     for (i = 0; i < package->loaded_extensions; i++)
4861         if (strcmpiW(package->extensions[i].Extension,extension)==0)
4862         {
4863             TRACE("extension %s already loaded at %i\n",debugstr_w(extension),
4864                             i);
4865             return i;
4866         }
4867     
4868     row = MSI_QueryGetRecord(package->db, ExecSeqQuery, extension);
4869     if (!row)
4870         return -1;
4871
4872     rc = load_extension(package, row);
4873     msiobj_release(&row->hdr);
4874
4875     return rc;
4876 }
4877
4878 static UINT iterate_load_verb(MSIRECORD *row, LPVOID param)
4879 {
4880     MSIPACKAGE* package = (MSIPACKAGE*)param;
4881     DWORD index = package->loaded_verbs;
4882     LPWSTR buffer;
4883
4884     /* fill in the data */
4885
4886     package->loaded_verbs++;
4887     if (package->loaded_verbs == 1)
4888         package->verbs = HeapAlloc(GetProcessHeap(),0,sizeof(MSIVERB));
4889     else
4890         package->verbs = HeapReAlloc(GetProcessHeap(),0,
4891             package->verbs , package->loaded_verbs * sizeof(MSIVERB));
4892
4893     memset(&package->verbs[index],0,sizeof(MSIVERB));
4894
4895     buffer = load_dynamic_stringW(row,1);
4896     package->verbs[index].ExtensionIndex = load_given_extension(package,buffer);
4897     if (package->verbs[index].ExtensionIndex < 0 && buffer)
4898         ERR("Verb unable to find loaded extension %s\n", debugstr_w(buffer));
4899     HeapFree(GetProcessHeap(),0,buffer);
4900
4901     package->verbs[index].Verb = load_dynamic_stringW(row,2);
4902     TRACE("loading verb %s\n",debugstr_w(package->verbs[index].Verb));
4903     package->verbs[index].Sequence = MSI_RecordGetInteger(row,3);
4904
4905     buffer = load_dynamic_stringW(row,4);
4906     deformat_string(package,buffer,&package->verbs[index].Command);
4907     HeapFree(GetProcessHeap(),0,buffer);
4908
4909     buffer = load_dynamic_stringW(row,5);
4910     deformat_string(package,buffer,&package->verbs[index].Argument);
4911     HeapFree(GetProcessHeap(),0,buffer);
4912
4913     /* assosiate the verb with the correct extension */
4914     if (package->verbs[index].ExtensionIndex >= 0)
4915     {
4916         MSIEXTENSION* extension = &package->extensions[package->verbs[index].
4917                 ExtensionIndex];
4918         int count = extension->VerbCount;
4919
4920         if (count >= 99)
4921             FIXME("Exceeding max verb count! Increase that limit!!!\n");
4922         else
4923         {
4924             extension->VerbCount++;
4925             extension->Verbs[count] = index;
4926         }
4927     }
4928     
4929     return ERROR_SUCCESS;
4930 }
4931
4932 static UINT iterate_all_classes(MSIRECORD *rec, LPVOID param)
4933 {
4934     LPWSTR clsid;
4935     LPWSTR context;
4936     LPWSTR buffer;
4937     INT    component_index;
4938     MSIPACKAGE* package =(MSIPACKAGE*)param;
4939     INT i;
4940     BOOL match = FALSE;
4941
4942     clsid = load_dynamic_stringW(rec,1);
4943     context = load_dynamic_stringW(rec,2);
4944     buffer = load_dynamic_stringW(rec,3);
4945     component_index = get_loaded_component(package,buffer);
4946
4947     for (i = 0; i < package->loaded_classes; i++)
4948     {
4949         if (strcmpiW(clsid,package->classes[i].CLSID))
4950             continue;
4951         if (strcmpW(context,package->classes[i].Context))
4952             continue;
4953         if (component_index == package->classes[i].ComponentIndex)
4954         {
4955             match = TRUE;
4956             break;
4957         }
4958     }
4959     
4960     HeapFree(GetProcessHeap(),0,buffer);
4961     HeapFree(GetProcessHeap(),0,clsid);
4962     HeapFree(GetProcessHeap(),0,context);
4963
4964     if (!match)
4965         load_class(package, rec);
4966
4967     return ERROR_SUCCESS;
4968 }
4969
4970 static VOID load_all_classes(MSIPACKAGE *package)
4971 {
4972     UINT rc = ERROR_SUCCESS;
4973     MSIQUERY *view;
4974
4975     static const WCHAR ExecSeqQuery[] =
4976         {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
4977          '`','C','l','a','s','s','`',0};
4978
4979     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4980     if (rc != ERROR_SUCCESS)
4981         return;
4982
4983     rc = MSI_IterateRecords(view, NULL, iterate_all_classes, package);
4984     msiobj_release(&view->hdr);
4985 }
4986
4987 static UINT iterate_all_extensions(MSIRECORD *rec, LPVOID param)
4988 {
4989     LPWSTR buffer;
4990     LPWSTR extension;
4991     INT    component_index;
4992     MSIPACKAGE* package =(MSIPACKAGE*)param;
4993     BOOL match = FALSE;
4994     INT i;
4995
4996     extension = load_dynamic_stringW(rec,1);
4997     buffer = load_dynamic_stringW(rec,2);
4998     component_index = get_loaded_component(package,buffer);
4999
5000     for (i = 0; i < package->loaded_extensions; i++)
5001     {
5002         if (strcmpiW(extension,package->extensions[i].Extension))
5003             continue;
5004         if (component_index == package->extensions[i].ComponentIndex)
5005         {
5006             match = TRUE;
5007             break;
5008         }
5009     }
5010
5011     HeapFree(GetProcessHeap(),0,buffer);
5012     HeapFree(GetProcessHeap(),0,extension);
5013
5014     if (!match)
5015         load_extension(package, rec);
5016
5017     return ERROR_SUCCESS;
5018 }
5019
5020 static VOID load_all_extensions(MSIPACKAGE *package)
5021 {
5022     UINT rc = ERROR_SUCCESS;
5023     MSIQUERY *view;
5024
5025     static const WCHAR ExecSeqQuery[] =
5026         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5027          '`','E','x','t','e','n','s','i','o','n','`',0};
5028
5029     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5030     if (rc != ERROR_SUCCESS)
5031         return;
5032
5033     rc = MSI_IterateRecords(view, NULL, iterate_all_extensions, package);
5034     msiobj_release(&view->hdr);
5035 }
5036
5037 static UINT iterate_all_progids(MSIRECORD *rec, LPVOID param)
5038 {
5039     LPWSTR buffer;
5040     MSIPACKAGE* package =(MSIPACKAGE*)param;
5041
5042     buffer = load_dynamic_stringW(rec,1);
5043     load_given_progid(package,buffer);
5044     HeapFree(GetProcessHeap(),0,buffer);
5045     return ERROR_SUCCESS;
5046 }
5047
5048 static VOID load_all_progids(MSIPACKAGE *package)
5049 {
5050     UINT rc = ERROR_SUCCESS;
5051     MSIQUERY *view;
5052
5053     static const WCHAR ExecSeqQuery[] =
5054         {'S','E','L','E','C','T',' ','`','P','r','o','g','I','d','`',' ',
5055          'F','R','O','M',' ', '`','P','r','o','g','I','d','`',0};
5056
5057     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5058     if (rc != ERROR_SUCCESS)
5059         return;
5060
5061     rc = MSI_IterateRecords(view, NULL, iterate_all_progids, package);
5062     msiobj_release(&view->hdr);
5063 }
5064
5065 static VOID load_all_verbs(MSIPACKAGE *package)
5066 {
5067     UINT rc = ERROR_SUCCESS;
5068     MSIQUERY *view;
5069
5070     static const WCHAR ExecSeqQuery[] =
5071         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5072          '`','V','e','r','b','`',0};
5073
5074     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5075     if (rc != ERROR_SUCCESS)
5076         return;
5077
5078     rc = MSI_IterateRecords(view, NULL, iterate_load_verb, package);
5079     msiobj_release(&view->hdr);
5080 }
5081
5082 static UINT iterate_all_mimes(MSIRECORD *rec, LPVOID param)
5083 {
5084     LPWSTR buffer;
5085     MSIPACKAGE* package =(MSIPACKAGE*)param;
5086
5087     buffer = load_dynamic_stringW(rec,1);
5088     load_given_mime(package,buffer);
5089     HeapFree(GetProcessHeap(),0,buffer);
5090     return ERROR_SUCCESS;
5091 }
5092
5093 static VOID load_all_mimes(MSIPACKAGE *package)
5094 {
5095     UINT rc = ERROR_SUCCESS;
5096     MSIQUERY *view;
5097
5098     static const WCHAR ExecSeqQuery[] =
5099         {'S','E','L','E','C','T',' ',
5100          '`','C','o','n','t','e','n','t','T','y','p','e','`',
5101          ' ','F','R','O','M',' ',
5102          '`','M','I','M','E','`',0};
5103
5104     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5105     if (rc != ERROR_SUCCESS)
5106         return;
5107
5108     rc = MSI_IterateRecords(view, NULL, iterate_all_mimes, package);
5109     msiobj_release(&view->hdr);
5110 }
5111
5112 static void load_classes_and_such(MSIPACKAGE *package)
5113 {
5114     TRACE("Loading all the class info and related tables\n");
5115
5116     /* check if already loaded */
5117     if (package->classes || package->extensions || package->progids || 
5118         package->verbs || package->mimes)
5119         return;
5120
5121     load_all_classes(package);
5122     load_all_extensions(package);
5123     load_all_progids(package);
5124     /* these loads must come after the other loads */
5125     load_all_verbs(package);
5126     load_all_mimes(package);
5127 }
5128
5129 static void mark_progid_for_install(MSIPACKAGE* package, INT index)
5130 {
5131     MSIPROGID* progid;
5132     int i;
5133
5134     if (index < 0 || index >= package->loaded_progids)
5135         return;
5136
5137     progid = &package->progids[index];
5138
5139     if (progid->InstallMe == TRUE)
5140         return;
5141
5142     progid->InstallMe = TRUE;
5143
5144     /* all children if this is a parent also install */
5145    for (i = 0; i < package->loaded_progids; i++)
5146         if (package->progids[i].ParentIndex == index)
5147             mark_progid_for_install(package,i);
5148 }
5149
5150 static void mark_mime_for_install(MSIPACKAGE* package, INT index)
5151 {
5152     MSIMIME* mime;
5153
5154     if (index < 0 || index >= package->loaded_mimes)
5155         return;
5156
5157     mime = &package->mimes[index];
5158
5159     if (mime->InstallMe == TRUE)
5160         return;
5161
5162     mime->InstallMe = TRUE;
5163 }
5164
5165 static UINT register_appid(MSIPACKAGE *package, int appidIndex, LPCWSTR app )
5166 {
5167     static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
5168     HKEY hkey2,hkey3;
5169
5170     if (!package)
5171         return ERROR_INVALID_HANDLE;
5172
5173     RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
5174     RegCreateKeyW(hkey2,package->appids[appidIndex].AppID,&hkey3);
5175     RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app,
5176                    (strlenW(app)+1)*sizeof(WCHAR));
5177
5178     if (package->appids[appidIndex].RemoteServerName)
5179     {
5180         UINT size; 
5181         static const WCHAR szRemoteServerName[] =
5182              {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',
5183               0};
5184
5185         size = (strlenW(package->appids[appidIndex].RemoteServerName)+1) * 
5186                 sizeof(WCHAR);
5187
5188         RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,
5189                         (LPVOID)package->appids[appidIndex].RemoteServerName,
5190                         size);
5191     }
5192
5193     if (package->appids[appidIndex].LocalServer)
5194     {
5195         static const WCHAR szLocalService[] =
5196              {'L','o','c','a','l','S','e','r','v','i','c','e',0};
5197         UINT size;
5198         size = (strlenW(package->appids[appidIndex].LocalServer)+1) * 
5199                 sizeof(WCHAR);
5200
5201         RegSetValueExW(hkey3,szLocalService,0,REG_SZ,
5202                         (LPVOID)package->appids[appidIndex].LocalServer,size);
5203     }
5204
5205     if (package->appids[appidIndex].ServiceParameters)
5206     {
5207         static const WCHAR szService[] =
5208              {'S','e','r','v','i','c','e',
5209               'P','a','r','a','m','e','t','e','r','s',0};
5210         UINT size;
5211         size = (strlenW(package->appids[appidIndex].ServiceParameters)+1) * 
5212                 sizeof(WCHAR);
5213         RegSetValueExW(hkey3,szService,0,REG_SZ,
5214                         (LPVOID)package->appids[appidIndex].ServiceParameters,
5215                         size);
5216     }
5217
5218     if (package->appids[appidIndex].DllSurrogate)
5219     {
5220         static const WCHAR szDLL[] =
5221              {'D','l','l','S','u','r','r','o','g','a','t','e',0};
5222         UINT size;
5223         size = (strlenW(package->appids[appidIndex].DllSurrogate)+1) * 
5224                 sizeof(WCHAR);
5225         RegSetValueExW(hkey3,szDLL,0,REG_SZ,
5226                         (LPVOID)package->appids[appidIndex].DllSurrogate,size);
5227     }
5228
5229     if (package->appids[appidIndex].ActivateAtStorage)
5230     {
5231         static const WCHAR szActivate[] =
5232              {'A','c','t','i','v','a','t','e','A','s',
5233               'S','t','o','r','a','g','e',0};
5234         static const WCHAR szY[] = {'Y',0};
5235
5236         RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4);
5237     }
5238
5239     if (package->appids[appidIndex].RunAsInteractiveUser)
5240     {
5241         static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
5242         static const WCHAR szUser[] = 
5243              {'I','n','t','e','r','a','c','t','i','v','e',' ',
5244               'U','s','e','r',0};
5245
5246         RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,sizeof(szUser));
5247     }
5248
5249     RegCloseKey(hkey3);
5250     RegCloseKey(hkey2);
5251     return ERROR_SUCCESS;
5252 }
5253
5254 static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
5255 {
5256     /* 
5257      * Again I am assuming the words, "Whose key file represents" when referring
5258      * to a Component as to meaning that Components KeyPath file
5259      */
5260     
5261     UINT rc;
5262     MSIRECORD *uirow;
5263     static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
5264     static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 };
5265     static const WCHAR szVIProgID[] = { 'V','e','r','s','i','o','n','I','n','d','e','p','e','n','d','e','n','t','P','r','o','g','I','D',0 };
5266     static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
5267     static const WCHAR szSpace[] = {' ',0};
5268     static const WCHAR szInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
5269     static const WCHAR szFileType_fmt[] = {'F','i','l','e','T','y','p','e','\\','%','s','\\','%','i',0};
5270     HKEY hkey,hkey2,hkey3;
5271     BOOL install_on_demand = FALSE;
5272     int i;
5273
5274     if (!package)
5275         return ERROR_INVALID_HANDLE;
5276
5277     load_classes_and_such(package);
5278     rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
5279     if (rc != ERROR_SUCCESS)
5280         return ERROR_FUNCTION_FAILED;
5281
5282     /* install_on_demand should be set if OLE supports install on demand OLE
5283      * servers. For now i am defaulting to FALSE because i do not know how to
5284      * check, and i am told our builtin OLE does not support it
5285      */
5286     
5287     for (i = 0; i < package->loaded_classes; i++)
5288     {
5289         INT index,f_index;
5290         DWORD size, sz;
5291         LPWSTR argument;
5292
5293         if (package->classes[i].ComponentIndex < 0)
5294         {
5295             continue;
5296         }
5297
5298         index = package->classes[i].ComponentIndex;
5299         f_index = package->classes[i].FeatureIndex;
5300
5301         /* 
5302          * yes. MSDN says that these are based on _Feature_ not on
5303          * Component.  So verify the feature is to be installed
5304          */
5305         if ((!ACTION_VerifyFeatureForAction(package, f_index,
5306                                 INSTALLSTATE_LOCAL)) &&
5307              !(install_on_demand && ACTION_VerifyFeatureForAction(package,
5308                              f_index, INSTALLSTATE_ADVERTISED)))
5309         {
5310             TRACE("Skipping class %s reg due to disabled feature %s\n", 
5311                             debugstr_w(package->classes[i].CLSID), 
5312                             debugstr_w(package->features[f_index].Feature));
5313
5314             continue;
5315         }
5316
5317         TRACE("Registering index %i  class %s\n",i,
5318                         debugstr_w(package->classes[i].CLSID));
5319
5320         package->classes[i].Installed = TRUE;
5321         if (package->classes[i].ProgIDIndex >= 0)
5322             mark_progid_for_install(package, package->classes[i].ProgIDIndex);
5323
5324         RegCreateKeyW(hkey,package->classes[i].CLSID,&hkey2);
5325
5326         if (package->classes[i].Description)
5327             RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)package->classes[i].
5328                             Description, (strlenW(package->classes[i].
5329                                      Description)+1)*sizeof(WCHAR));
5330
5331         RegCreateKeyW(hkey2,package->classes[i].Context,&hkey3);
5332         index = get_loaded_file(package,package->components[index].KeyPath);
5333
5334
5335         /* the context server is a short path name 
5336          * except for if it is InprocServer32... 
5337          */
5338         if (strcmpiW(package->classes[i].Context,szInprocServer32)!=0)
5339         {
5340             sz = 0;
5341             sz = GetShortPathNameW(package->files[index].TargetPath, NULL, 0);
5342             if (sz == 0)
5343             {
5344                 ERR("Unable to find short path for CLSID COM Server\n");
5345                 argument = NULL;
5346             }
5347             else
5348             {
5349                 size = sz * sizeof(WCHAR);
5350
5351                 if (package->classes[i].Argument)
5352                 {
5353                     size += strlenW(package->classes[i].Argument) * 
5354                             sizeof(WCHAR);
5355                     size += sizeof(WCHAR);
5356                 }
5357
5358                 argument = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR));
5359                 GetShortPathNameW(package->files[index].TargetPath, argument, 
5360                                 sz);
5361
5362                 if (package->classes[i].Argument)
5363                 {
5364                     strcatW(argument,szSpace);
5365                     strcatW(argument,package->classes[i].Argument);
5366                 }
5367             }
5368         }
5369         else
5370         {
5371             size = lstrlenW(package->files[index].TargetPath) * sizeof(WCHAR);
5372
5373             if (package->classes[i].Argument)
5374             {
5375                 size += strlenW(package->classes[i].Argument) * sizeof(WCHAR);
5376                 size += sizeof(WCHAR);
5377             }
5378
5379             argument = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR));
5380             strcpyW(argument, package->files[index].TargetPath);
5381
5382             if (package->classes[i].Argument)
5383             {
5384                 strcatW(argument,szSpace);
5385                 strcatW(argument,package->classes[i].Argument);
5386             }
5387         }
5388
5389         if (argument)
5390         {
5391             RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size);
5392             HeapFree(GetProcessHeap(),0,argument);
5393         }
5394
5395         RegCloseKey(hkey3);
5396
5397         if (package->classes[i].ProgIDIndex >= 0 || 
5398             package->classes[i].ProgIDText)
5399         {
5400             LPCWSTR progid;
5401
5402             if (package->classes[i].ProgIDIndex >= 0)
5403                 progid = package->progids[
5404                         package->classes[i].ProgIDIndex].ProgID;
5405             else
5406                 progid = package->classes[i].ProgIDText;
5407
5408             RegCreateKeyW(hkey2,szProgID,&hkey3);
5409             RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)progid,
5410                             (strlenW(progid)+1) *sizeof(WCHAR));
5411             RegCloseKey(hkey3);
5412
5413             if (package->classes[i].ProgIDIndex >= 0 &&
5414                 package->progids[package->classes[i].ProgIDIndex].
5415                                 VersionIndIndex >= 0)
5416             {
5417                 LPWSTR viprogid = strdupW(package->progids[package->progids[
5418                         package->classes[i].ProgIDIndex].VersionIndIndex].
5419                         ProgID);
5420                 RegCreateKeyW(hkey2,szVIProgID,&hkey3);
5421                 RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)viprogid,
5422                             (strlenW(viprogid)+1) *sizeof(WCHAR));
5423                 RegCloseKey(hkey3);
5424                 HeapFree(GetProcessHeap(), 0, viprogid);
5425             }
5426         }
5427
5428         if (package->classes[i].AppIDIndex >= 0)
5429         { 
5430             RegSetValueExW(hkey2,szAppID,0,REG_SZ,
5431              (LPVOID)package->appids[package->classes[i].AppIDIndex].AppID,
5432              (strlenW(package->appids[package->classes[i].AppIDIndex].AppID)+1)
5433              *sizeof(WCHAR));
5434
5435             register_appid(package,package->classes[i].AppIDIndex,
5436                             package->classes[i].Description);
5437         }
5438
5439         if (package->classes[i].IconPath)
5440         {
5441             static const WCHAR szDefaultIcon[] = 
5442                 {'D','e','f','a','u','l','t','I','c','o','n',0};
5443
5444             RegCreateKeyW(hkey2,szDefaultIcon,&hkey3);
5445
5446             RegSetValueExW(hkey3,NULL,0,REG_SZ,
5447                            (LPVOID)package->classes[i].IconPath,
5448                            (strlenW(package->classes[i].IconPath)+1) * 
5449                            sizeof(WCHAR));
5450
5451             RegCloseKey(hkey3);
5452         }
5453
5454         if (package->classes[i].DefInprocHandler)
5455         {
5456             static const WCHAR szInproc[] =
5457                 {'I','n','p','r','o','c','H','a','n','d','l','e','r',0};
5458
5459             size = (strlenW(package->classes[i].DefInprocHandler) + 1) * 
5460                     sizeof(WCHAR);
5461             RegCreateKeyW(hkey2,szInproc,&hkey3);
5462             RegSetValueExW(hkey3,NULL,0,REG_SZ, 
5463                             (LPVOID)package->classes[i].DefInprocHandler, size);
5464             RegCloseKey(hkey3);
5465         }
5466
5467         if (package->classes[i].DefInprocHandler32)
5468         {
5469             static const WCHAR szInproc32[] =
5470                 {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',
5471                  0};
5472             size = (strlenW(package->classes[i].DefInprocHandler32) + 1) * 
5473                     sizeof(WCHAR);
5474
5475             RegCreateKeyW(hkey2,szInproc32,&hkey3);
5476             RegSetValueExW(hkey3,NULL,0,REG_SZ, 
5477                            (LPVOID)package->classes[i].DefInprocHandler32,size);
5478             RegCloseKey(hkey3);
5479         }
5480         
5481         RegCloseKey(hkey2);
5482
5483         /* if there is a FileTypeMask, register the FileType */
5484         if (package->classes[i].FileTypeMask)
5485         {
5486             LPWSTR ptr, ptr2;
5487             LPWSTR keyname;
5488             INT index = 0;
5489             ptr = package->classes[i].FileTypeMask;
5490             while (ptr && *ptr)
5491             {
5492                 ptr2 = strchrW(ptr,';');
5493                 if (ptr2)
5494                     *ptr2 = 0;
5495                 keyname = HeapAlloc(GetProcessHeap(),0,(strlenW(szFileType_fmt)+
5496                                         strlenW(package->classes[i].CLSID) + 4)
5497                                 * sizeof(WCHAR));
5498                 sprintfW(keyname,szFileType_fmt, package->classes[i].CLSID, 
5499                         index);
5500
5501                 RegCreateKeyW(HKEY_CLASSES_ROOT,keyname,&hkey2);
5502                 RegSetValueExW(hkey2,NULL,0,REG_SZ, (LPVOID)ptr,
5503                         strlenW(ptr)*sizeof(WCHAR));
5504                 RegCloseKey(hkey2);
5505                 HeapFree(GetProcessHeap(), 0, keyname);
5506
5507                 if (ptr2)
5508                     ptr = ptr2+1;
5509                 else
5510                     ptr = NULL;
5511
5512                 index ++;
5513             }
5514         }
5515         
5516         uirow = MSI_CreateRecord(1);
5517
5518         MSI_RecordSetStringW(uirow,1,package->classes[i].CLSID);
5519         ui_actiondata(package,szRegisterClassInfo,uirow);
5520         msiobj_release(&uirow->hdr);
5521     }
5522
5523     RegCloseKey(hkey);
5524     return rc;
5525 }
5526
5527 static UINT register_progid_base(MSIPACKAGE* package, MSIPROGID* progid,
5528                                  LPWSTR clsid)
5529 {
5530     static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
5531     static const WCHAR szDefaultIcon[] =
5532         {'D','e','f','a','u','l','t','I','c','o','n',0};
5533     HKEY hkey,hkey2;
5534
5535     RegCreateKeyW(HKEY_CLASSES_ROOT,progid->ProgID,&hkey);
5536
5537     if (progid->Description)
5538     {
5539         RegSetValueExW(hkey,NULL,0,REG_SZ,
5540                         (LPVOID)progid->Description, 
5541                         (strlenW(progid->Description)+1) *
5542                        sizeof(WCHAR));
5543     }
5544
5545     if (progid->ClassIndex >= 0)
5546     {   
5547         RegCreateKeyW(hkey,szCLSID,&hkey2);
5548         RegSetValueExW(hkey2,NULL,0,REG_SZ,
5549                         (LPVOID)package->classes[progid->ClassIndex].CLSID, 
5550                         (strlenW(package->classes[progid->ClassIndex].CLSID)+1)
5551                         * sizeof(WCHAR));
5552
5553         if (clsid)
5554             strcpyW(clsid,package->classes[progid->ClassIndex].CLSID);
5555
5556         RegCloseKey(hkey2);
5557     }
5558     else
5559     {
5560         FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
5561     }
5562
5563     if (progid->IconPath)
5564     {
5565         RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
5566
5567         RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath,
5568                            (strlenW(progid->IconPath)+1) * sizeof(WCHAR));
5569         RegCloseKey(hkey2);
5570     }
5571     return ERROR_SUCCESS;
5572 }
5573
5574 static UINT register_progid(MSIPACKAGE *package, MSIPROGID* progid, 
5575                 LPWSTR clsid)
5576 {
5577     UINT rc = ERROR_SUCCESS; 
5578
5579     if (progid->ParentIndex < 0)
5580         rc = register_progid_base(package, progid, clsid);
5581     else
5582     {
5583         DWORD disp;
5584         HKEY hkey,hkey2;
5585         static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
5586         static const WCHAR szDefaultIcon[] =
5587             {'D','e','f','a','u','l','t','I','c','o','n',0};
5588         static const WCHAR szCurVer[] =
5589             {'C','u','r','V','e','r',0};
5590
5591         /* check if already registered */
5592         RegCreateKeyExW(HKEY_CLASSES_ROOT, progid->ProgID, 0, NULL, 0,
5593                         KEY_ALL_ACCESS, NULL, &hkey, &disp );
5594         if (disp == REG_OPENED_EXISTING_KEY)
5595         {
5596             TRACE("Key already registered\n");
5597             RegCloseKey(hkey);
5598             return rc;
5599         }
5600
5601         TRACE("Registering Parent %s index %i\n",
5602                     debugstr_w(package->progids[progid->ParentIndex].ProgID), 
5603                     progid->ParentIndex);
5604         rc = register_progid(package,&package->progids[progid->ParentIndex],
5605                         clsid);
5606
5607         /* clsid is same as parent */
5608         RegCreateKeyW(hkey,szCLSID,&hkey2);
5609         RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) *
5610                        sizeof(WCHAR));
5611
5612         RegCloseKey(hkey2);
5613
5614
5615         if (progid->Description)
5616         {
5617             RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid->Description,
5618                            (strlenW(progid->Description)+1) * sizeof(WCHAR));
5619         }
5620
5621         if (progid->IconPath)
5622         {
5623             RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
5624             RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath,
5625                            (strlenW(progid->IconPath)+1) * sizeof(WCHAR));
5626             RegCloseKey(hkey2);
5627         }
5628
5629         /* write out the current version */
5630         if (progid->CurVerIndex >= 0)
5631         {
5632             RegCreateKeyW(hkey,szCurVer,&hkey2);
5633             RegSetValueExW(hkey2,NULL,0,REG_SZ,
5634                 (LPVOID)package->progids[progid->CurVerIndex].ProgID,
5635                 (strlenW(package->progids[progid->CurVerIndex].ProgID)+1) * 
5636                 sizeof(WCHAR));
5637             RegCloseKey(hkey2);
5638         }
5639
5640         RegCloseKey(hkey);
5641     }
5642     return rc;
5643 }
5644
5645 static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
5646 {
5647     INT i;
5648     MSIRECORD *uirow;
5649
5650     if (!package)
5651         return ERROR_INVALID_HANDLE;
5652
5653     load_classes_and_such(package);
5654
5655     for (i = 0; i < package->loaded_progids; i++)
5656     {
5657         WCHAR clsid[0x1000];
5658
5659         /* check if this progid is to be installed */
5660         package->progids[i].InstallMe =  ((package->progids[i].InstallMe) ||
5661               (package->progids[i].ClassIndex >= 0 &&
5662               package->classes[package->progids[i].ClassIndex].Installed));
5663
5664         if (!package->progids[i].InstallMe)
5665         {
5666             TRACE("progid %s not scheduled to be installed\n",
5667                              debugstr_w(package->progids[i].ProgID));
5668             continue;
5669         }
5670        
5671         TRACE("Registering progid %s index %i\n",
5672                         debugstr_w(package->progids[i].ProgID), i);
5673
5674         register_progid(package,&package->progids[i],clsid);
5675
5676         uirow = MSI_CreateRecord(1);
5677         MSI_RecordSetStringW(uirow,1,package->progids[i].ProgID);
5678         ui_actiondata(package,szRegisterProgIdInfo,uirow);
5679         msiobj_release(&uirow->hdr);
5680     }
5681
5682     return ERROR_SUCCESS;
5683 }
5684
5685 static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, 
5686                             LPWSTR *FilePath)
5687 {
5688     LPWSTR ProductCode;
5689     LPWSTR SystemFolder;
5690     LPWSTR dest;
5691     UINT rc;
5692
5693     static const WCHAR szInstaller[] = 
5694         {'M','i','c','r','o','s','o','f','t','\\',
5695          'I','n','s','t','a','l','l','e','r','\\',0};
5696     static const WCHAR szFolder[] =
5697         {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
5698
5699     ProductCode = load_dynamic_property(package,szProductCode,&rc);
5700     if (!ProductCode)
5701         return rc;
5702
5703     SystemFolder = load_dynamic_property(package,szFolder,NULL);
5704
5705     dest = build_directory_name(3, SystemFolder, szInstaller, ProductCode);
5706
5707     create_full_pathW(dest);
5708
5709     *FilePath = build_directory_name(2, dest, icon_name);
5710
5711     HeapFree(GetProcessHeap(),0,SystemFolder);
5712     HeapFree(GetProcessHeap(),0,ProductCode);
5713     HeapFree(GetProcessHeap(),0,dest);
5714     return ERROR_SUCCESS;
5715 }
5716
5717 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
5718 {
5719     UINT rc;
5720     MSIQUERY * view;
5721     MSIRECORD * row = 0;
5722     static const WCHAR Query[] =
5723         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5724          '`','S','h','o','r','t','c','u','t','`',0};
5725     IShellLinkW *sl;
5726     IPersistFile *pf;
5727     HRESULT res;
5728
5729     if (!package)
5730         return ERROR_INVALID_HANDLE;
5731
5732     res = CoInitialize( NULL );
5733     if (FAILED (res))
5734     {
5735         ERR("CoInitialize failed\n");
5736         return ERROR_FUNCTION_FAILED;
5737     }
5738
5739     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
5740     if (rc != ERROR_SUCCESS)
5741         return ERROR_SUCCESS;
5742
5743     rc = MSI_ViewExecute(view, 0);
5744     if (rc != ERROR_SUCCESS)
5745     {
5746         MSI_ViewClose(view);
5747         msiobj_release(&view->hdr);
5748         return rc;
5749     }
5750
5751     while (1)
5752     {
5753         LPWSTR target_file, target_folder;
5754         WCHAR buffer[0x100];
5755         DWORD sz;
5756         DWORD index;
5757         static const WCHAR szlnk[]={'.','l','n','k',0};
5758
5759         rc = MSI_ViewFetch(view,&row);
5760         if (rc != ERROR_SUCCESS)
5761         {
5762             rc = ERROR_SUCCESS;
5763             break;
5764         }
5765         
5766         sz = 0x100;
5767         MSI_RecordGetStringW(row,4,buffer,&sz);
5768
5769         index = get_loaded_component(package,buffer);
5770
5771         if (index < 0)
5772         {
5773             msiobj_release(&row->hdr);
5774             continue;
5775         }
5776
5777         if (!ACTION_VerifyComponentForAction(package, index,
5778                                 INSTALLSTATE_LOCAL))
5779         {
5780             TRACE("Skipping shortcut creation due to disabled component\n");
5781             msiobj_release(&row->hdr);
5782
5783             package->components[index].Action =
5784                 package->components[index].Installed;
5785
5786             continue;
5787         }
5788
5789         package->components[index].Action = INSTALLSTATE_LOCAL;
5790
5791         ui_actiondata(package,szCreateShortcuts,row);
5792
5793         res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
5794                               &IID_IShellLinkW, (LPVOID *) &sl );
5795
5796         if (FAILED(res))
5797         {
5798             ERR("Is IID_IShellLink\n");
5799             msiobj_release(&row->hdr);
5800             continue;
5801         }
5802
5803         res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
5804         if( FAILED( res ) )
5805         {
5806             ERR("Is IID_IPersistFile\n");
5807             msiobj_release(&row->hdr);
5808             continue;
5809         }
5810
5811         sz = 0x100;
5812         MSI_RecordGetStringW(row,2,buffer,&sz);
5813         target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
5814
5815         /* may be needed because of a bug somehwere else */
5816         create_full_pathW(target_folder);
5817
5818         sz = 0x100;
5819         MSI_RecordGetStringW(row,3,buffer,&sz);
5820         reduce_to_longfilename(buffer);
5821         if (!strchrW(buffer,'.') || strcmpiW(strchrW(buffer,'.'),szlnk))
5822             strcatW(buffer,szlnk);
5823         target_file = build_directory_name(2, target_folder, buffer);
5824         HeapFree(GetProcessHeap(),0,target_folder);
5825
5826         sz = 0x100;
5827         MSI_RecordGetStringW(row,5,buffer,&sz);
5828         if (strchrW(buffer,'['))
5829         {
5830             LPWSTR deformated;
5831             deformat_string(package,buffer,&deformated);
5832             IShellLinkW_SetPath(sl,deformated);
5833             HeapFree(GetProcessHeap(),0,deformated);
5834         }
5835         else
5836         {
5837             LPWSTR keypath;
5838             FIXME("poorly handled shortcut format, advertised shortcut\n");
5839             keypath = strdupW(package->components[index].FullKeypath);
5840             IShellLinkW_SetPath(sl,keypath);
5841             HeapFree(GetProcessHeap(),0,keypath);
5842         }
5843
5844         if (!MSI_RecordIsNull(row,6))
5845         {
5846             LPWSTR deformated;
5847             sz = 0x100;
5848             MSI_RecordGetStringW(row,6,buffer,&sz);
5849             deformat_string(package,buffer,&deformated);
5850             IShellLinkW_SetArguments(sl,deformated);
5851             HeapFree(GetProcessHeap(),0,deformated);
5852         }
5853
5854         if (!MSI_RecordIsNull(row,7))
5855         {
5856             LPWSTR deformated;
5857             deformated = load_dynamic_stringW(row,7);
5858             IShellLinkW_SetDescription(sl,deformated);
5859             HeapFree(GetProcessHeap(),0,deformated);
5860         }
5861
5862         if (!MSI_RecordIsNull(row,8))
5863             IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
5864
5865         if (!MSI_RecordIsNull(row,9))
5866         {
5867             WCHAR *Path = NULL;
5868             INT index; 
5869
5870             sz = 0x100;
5871             MSI_RecordGetStringW(row,9,buffer,&sz);
5872
5873             build_icon_path(package,buffer,&Path);
5874             index = MSI_RecordGetInteger(row,10);
5875
5876             IShellLinkW_SetIconLocation(sl,Path,index);
5877             HeapFree(GetProcessHeap(),0,Path);
5878         }
5879
5880         if (!MSI_RecordIsNull(row,11))
5881             IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
5882
5883         if (!MSI_RecordIsNull(row,12))
5884         {
5885             LPWSTR Path;
5886             sz = 0x100;
5887             MSI_RecordGetStringW(row,12,buffer,&sz);
5888             Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
5889             IShellLinkW_SetWorkingDirectory(sl,Path);
5890             HeapFree(GetProcessHeap(), 0, Path);
5891         }
5892
5893         TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
5894         IPersistFile_Save(pf,target_file,FALSE);
5895     
5896         HeapFree(GetProcessHeap(),0,target_file);    
5897
5898         IPersistFile_Release( pf );
5899         IShellLinkW_Release( sl );
5900
5901         msiobj_release(&row->hdr);
5902     }
5903     MSI_ViewClose(view);
5904     msiobj_release(&view->hdr);
5905
5906
5907     CoUninitialize();
5908
5909     return rc;
5910 }
5911
5912
5913 /*
5914  * 99% of the work done here is only done for 
5915  * advertised installs. However this is where the
5916  * Icon table is processed and written out
5917  * so that is what I am going to do here.
5918  */
5919 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
5920 {
5921     UINT rc;
5922     MSIQUERY * view;
5923     MSIRECORD * row = 0;
5924     static const WCHAR Query[]=
5925         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5926          '`','I','c','o','n','`',0};
5927     DWORD sz;
5928     /* for registry stuff */
5929     LPWSTR productcode;
5930     HKEY hkey=0;
5931     HKEY hukey=0;
5932     static const WCHAR szProductName[] =
5933         {'P','r','o','d','u','c','t','N','a','m','e',0};
5934     static const WCHAR szPackageCode[] =
5935         {'P','a','c','k','a','g','e','C','o','d','e',0};
5936     LPWSTR buffer;
5937     DWORD size;
5938     MSIHANDLE hDb, hSumInfo;
5939
5940     if (!package)
5941         return ERROR_INVALID_HANDLE;
5942
5943     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
5944     if (rc != ERROR_SUCCESS)
5945         goto next;
5946
5947     rc = MSI_ViewExecute(view, 0);
5948     if (rc != ERROR_SUCCESS)
5949     {
5950         MSI_ViewClose(view);
5951         msiobj_release(&view->hdr);
5952         goto next;
5953     }
5954
5955     while (1)
5956     {
5957         HANDLE the_file;
5958         WCHAR *FilePath=NULL;
5959         WCHAR *FileName=NULL;
5960         CHAR buffer[1024];
5961
5962         rc = MSI_ViewFetch(view,&row);
5963         if (rc != ERROR_SUCCESS)
5964         {
5965             rc = ERROR_SUCCESS;
5966             break;
5967         }
5968     
5969         FileName = load_dynamic_stringW(row,1);
5970         if (!FileName)
5971         {
5972             ERR("Unable to get FileName\n");
5973             msiobj_release(&row->hdr);
5974             continue;
5975         }
5976
5977         build_icon_path(package,FileName,&FilePath);
5978
5979         HeapFree(GetProcessHeap(),0,FileName);
5980
5981         TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
5982         
5983         the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
5984                            FILE_ATTRIBUTE_NORMAL, NULL);
5985
5986         if (the_file == INVALID_HANDLE_VALUE)
5987         {
5988             ERR("Unable to create file %s\n",debugstr_w(FilePath));
5989             msiobj_release(&row->hdr);
5990             HeapFree(GetProcessHeap(),0,FilePath);
5991             continue;
5992         }
5993
5994         do 
5995         {
5996             DWORD write;
5997             sz = 1024;
5998             rc = MSI_RecordReadStream(row,2,buffer,&sz);
5999             if (rc != ERROR_SUCCESS)
6000             {
6001                 ERR("Failed to get stream\n");
6002                 CloseHandle(the_file);  
6003                 DeleteFileW(FilePath);
6004                 break;
6005             }
6006             WriteFile(the_file,buffer,sz,&write,NULL);
6007         } while (sz == 1024);
6008
6009         HeapFree(GetProcessHeap(),0,FilePath);
6010
6011         CloseHandle(the_file);
6012         msiobj_release(&row->hdr);
6013     }
6014     MSI_ViewClose(view);
6015     msiobj_release(&view->hdr);
6016
6017 next:
6018     /* ok there is a lot more done here but i need to figure out what */
6019     productcode = load_dynamic_property(package,szProductCode,&rc);
6020     if (!productcode)
6021         return rc;
6022
6023     rc = MSIREG_OpenProductsKey(productcode,&hkey,TRUE);
6024     if (rc != ERROR_SUCCESS)
6025         goto end;
6026
6027     rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE);
6028     if (rc != ERROR_SUCCESS)
6029         goto end;
6030
6031
6032     buffer = load_dynamic_property(package,szProductName,NULL);
6033     size = strlenW(buffer)*sizeof(WCHAR);
6034     RegSetValueExW(hukey,szProductName,0,REG_SZ, (LPSTR)buffer,size);
6035     HeapFree(GetProcessHeap(),0,buffer);
6036     FIXME("Need to write more keys to the user registry\n");
6037   
6038     hDb= alloc_msihandle( &package->db->hdr );
6039     rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo); 
6040     MsiCloseHandle(hDb);
6041     if (rc == ERROR_SUCCESS)
6042     {
6043         WCHAR guidbuffer[0x200];
6044         size = 0x200;
6045         rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
6046                                         guidbuffer, &size);
6047         if (rc == ERROR_SUCCESS)
6048         {
6049             WCHAR squashed[GUID_SIZE];
6050             /* for now we only care about the first guid */
6051             LPWSTR ptr = strchrW(guidbuffer,';');
6052             if (ptr) *ptr = 0;
6053             squash_guid(guidbuffer,squashed);
6054             size = strlenW(squashed)*sizeof(WCHAR);
6055             RegSetValueExW(hukey,szPackageCode,0,REG_SZ, (LPSTR)squashed,
6056                            size);
6057         }
6058         else
6059         {
6060             ERR("Unable to query Revision_Number... \n");
6061             rc = ERROR_SUCCESS;
6062         }
6063         MsiCloseHandle(hSumInfo);
6064     }
6065     else
6066     {
6067         ERR("Unable to open Summary Information\n");
6068         rc = ERROR_SUCCESS;
6069     }
6070
6071 end:
6072
6073     HeapFree(GetProcessHeap(),0,productcode);    
6074     RegCloseKey(hkey);
6075     RegCloseKey(hukey);
6076
6077     return rc;
6078 }
6079
6080 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
6081 {
6082     UINT rc;
6083     MSIQUERY * view;
6084     MSIRECORD * row = 0;
6085     static const WCHAR ExecSeqQuery[] = 
6086         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6087          '`','I','n','i','F','i','l','e','`',0};
6088     static const WCHAR szWindowsFolder[] =
6089           {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
6090
6091     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6092     if (rc != ERROR_SUCCESS)
6093     {
6094         TRACE("no IniFile table\n");
6095         return ERROR_SUCCESS;
6096     }
6097
6098     rc = MSI_ViewExecute(view, 0);
6099     if (rc != ERROR_SUCCESS)
6100     {
6101         MSI_ViewClose(view);
6102         msiobj_release(&view->hdr);
6103         return rc;
6104     }
6105
6106     while (1)
6107     {
6108         LPWSTR component,filename,dirproperty,section,key,value,identifier;
6109         LPWSTR deformated_section, deformated_key, deformated_value;
6110         LPWSTR folder, fullname = NULL;
6111         MSIRECORD * uirow;
6112         INT component_index,action;
6113
6114         rc = MSI_ViewFetch(view,&row);
6115         if (rc != ERROR_SUCCESS)
6116         {
6117             rc = ERROR_SUCCESS;
6118             break;
6119         }
6120
6121         component = load_dynamic_stringW(row, 8);
6122         component_index = get_loaded_component(package,component);
6123         HeapFree(GetProcessHeap(),0,component);
6124
6125         if (!ACTION_VerifyComponentForAction(package, component_index,
6126                                 INSTALLSTATE_LOCAL))
6127         {
6128             TRACE("Skipping ini file due to disabled component\n");
6129             msiobj_release(&row->hdr);
6130
6131             package->components[component_index].Action =
6132                 package->components[component_index].Installed;
6133
6134             continue;
6135         }
6136
6137         package->components[component_index].Action = INSTALLSTATE_LOCAL;
6138    
6139         identifier = load_dynamic_stringW(row,1); 
6140         filename = load_dynamic_stringW(row,2);
6141         dirproperty = load_dynamic_stringW(row,3);
6142         section = load_dynamic_stringW(row,4);
6143         key = load_dynamic_stringW(row,5);
6144         value = load_dynamic_stringW(row,6);
6145         action = MSI_RecordGetInteger(row,7);
6146
6147         deformat_string(package,section,&deformated_section);
6148         deformat_string(package,key,&deformated_key);
6149         deformat_string(package,value,&deformated_value);
6150
6151         if (dirproperty)
6152         {
6153             folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
6154             if (!folder)
6155                 folder = load_dynamic_property(package,dirproperty,NULL);
6156         }
6157         else
6158             folder = load_dynamic_property(package, szWindowsFolder, NULL);
6159
6160         if (!folder)
6161         {
6162             ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
6163             goto cleanup;
6164         }
6165
6166         fullname = build_directory_name(3, folder, filename, NULL);
6167
6168         if (action == 0)
6169         {
6170             TRACE("Adding value %s to section %s in %s\n",
6171                 debugstr_w(deformated_key), debugstr_w(deformated_section),
6172                 debugstr_w(fullname));
6173             WritePrivateProfileStringW(deformated_section, deformated_key,
6174                                        deformated_value, fullname);
6175         }
6176         else if (action == 1)
6177         {
6178             WCHAR returned[10];
6179             GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
6180                                      returned, 10, fullname);
6181             if (returned[0] == 0)
6182             {
6183                 TRACE("Adding value %s to section %s in %s\n",
6184                     debugstr_w(deformated_key), debugstr_w(deformated_section),
6185                     debugstr_w(fullname));
6186
6187                 WritePrivateProfileStringW(deformated_section, deformated_key,
6188                                        deformated_value, fullname);
6189             }
6190         }
6191         else if (action == 3)
6192         {
6193             FIXME("Append to existing section not yet implemented\n");
6194         }
6195         
6196         uirow = MSI_CreateRecord(4);
6197         MSI_RecordSetStringW(uirow,1,identifier);
6198         MSI_RecordSetStringW(uirow,2,deformated_section);
6199         MSI_RecordSetStringW(uirow,3,deformated_key);
6200         MSI_RecordSetStringW(uirow,4,deformated_value);
6201         ui_actiondata(package,szWriteIniValues,uirow);
6202         msiobj_release( &uirow->hdr );
6203 cleanup:
6204         HeapFree(GetProcessHeap(),0,identifier);
6205         HeapFree(GetProcessHeap(),0,fullname);
6206         HeapFree(GetProcessHeap(),0,filename);
6207         HeapFree(GetProcessHeap(),0,key);
6208         HeapFree(GetProcessHeap(),0,value);
6209         HeapFree(GetProcessHeap(),0,section);
6210         HeapFree(GetProcessHeap(),0,dirproperty);
6211         HeapFree(GetProcessHeap(),0,folder);
6212         HeapFree(GetProcessHeap(),0,deformated_key);
6213         HeapFree(GetProcessHeap(),0,deformated_value);
6214         HeapFree(GetProcessHeap(),0,deformated_section);
6215         msiobj_release(&row->hdr);
6216     }
6217     MSI_ViewClose(view);
6218     msiobj_release(&view->hdr);
6219     return rc;
6220 }
6221
6222 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
6223 {
6224     UINT rc;
6225     MSIQUERY * view;
6226     MSIRECORD * row = 0;
6227     static const WCHAR ExecSeqQuery[] = 
6228         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6229          '`','S','e','l','f','R','e','g','`',0};
6230
6231     static const WCHAR ExeStr[] =
6232         {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
6233     static const WCHAR close[] =  {'\"',0};
6234     STARTUPINFOW si;
6235     PROCESS_INFORMATION info;
6236     BOOL brc;
6237
6238     memset(&si,0,sizeof(STARTUPINFOW));
6239
6240     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6241     if (rc != ERROR_SUCCESS)
6242     {
6243         TRACE("no SelfReg table\n");
6244         return ERROR_SUCCESS;
6245     }
6246
6247     rc = MSI_ViewExecute(view, 0);
6248     if (rc != ERROR_SUCCESS)
6249     {
6250         MSI_ViewClose(view);
6251         msiobj_release(&view->hdr);
6252         return rc;
6253     }
6254
6255     while (1)
6256     {
6257         LPWSTR filename;
6258         INT index;
6259         DWORD len;
6260
6261         rc = MSI_ViewFetch(view,&row);
6262         if (rc != ERROR_SUCCESS)
6263         {
6264             rc = ERROR_SUCCESS;
6265             break;
6266         }
6267
6268         filename = load_dynamic_stringW(row,1);
6269         index = get_loaded_file(package,filename);
6270
6271         if (index < 0)
6272         {
6273             ERR("Unable to find file id %s\n",debugstr_w(filename));
6274             HeapFree(GetProcessHeap(),0,filename);
6275             msiobj_release(&row->hdr);
6276             continue;
6277         }
6278         HeapFree(GetProcessHeap(),0,filename);
6279
6280         len = strlenW(ExeStr);
6281         len += strlenW(package->files[index].TargetPath);
6282         len +=2;
6283
6284         filename = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
6285         strcpyW(filename,ExeStr);
6286         strcatW(filename,package->files[index].TargetPath);
6287         strcatW(filename,close);
6288
6289         TRACE("Registering %s\n",debugstr_w(filename));
6290         brc = CreateProcessW(NULL, filename, NULL, NULL, FALSE, 0, NULL,
6291                   c_colon, &si, &info);
6292
6293         if (brc)
6294             msi_dialog_check_messages(info.hProcess);
6295  
6296         HeapFree(GetProcessHeap(),0,filename);
6297         msiobj_release(&row->hdr);
6298     }
6299     MSI_ViewClose(view);
6300     msiobj_release(&view->hdr);
6301     return rc;
6302 }
6303
6304 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
6305 {
6306     LPWSTR productcode;
6307     UINT rc;
6308     DWORD i;
6309     HKEY hkey=0;
6310     HKEY hukey=0;
6311     
6312     if (!package)
6313         return ERROR_INVALID_HANDLE;
6314
6315     productcode = load_dynamic_property(package,szProductCode,&rc);
6316     if (!productcode)
6317         return rc;
6318
6319     rc = MSIREG_OpenFeaturesKey(productcode,&hkey,TRUE);
6320     if (rc != ERROR_SUCCESS)
6321         goto end;
6322
6323     rc = MSIREG_OpenUserFeaturesKey(productcode,&hukey,TRUE);
6324     if (rc != ERROR_SUCCESS)
6325         goto end;
6326
6327     /* here the guids are base 85 encoded */
6328     for (i = 0; i < package->loaded_features; i++)
6329     {
6330         LPWSTR data = NULL;
6331         GUID clsid;
6332         int j;
6333         INT size;
6334         BOOL absent = FALSE;
6335
6336         if (!ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_LOCAL) &&
6337             !ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_SOURCE) &&
6338             !ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_ADVERTISED))
6339             absent = TRUE;
6340
6341         size = package->features[i].ComponentCount*21;
6342         size +=1;
6343         if (package->features[i].Feature_Parent[0])
6344             size += strlenW(package->features[i].Feature_Parent)+2;
6345
6346         data = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
6347
6348         data[0] = 0;
6349         for (j = 0; j < package->features[i].ComponentCount; j++)
6350         {
6351             WCHAR buf[21];
6352             memset(buf,0,sizeof(buf));
6353             if (package->components
6354                 [package->features[i].Components[j]].ComponentId[0]!=0)
6355             {
6356                 TRACE("From %s\n",debugstr_w(package->components
6357                             [package->features[i].Components[j]].ComponentId));
6358                 CLSIDFromString(package->components
6359                             [package->features[i].Components[j]].ComponentId,
6360                             &clsid);
6361                 encode_base85_guid(&clsid,buf);
6362                 TRACE("to %s\n",debugstr_w(buf));
6363                 strcatW(data,buf);
6364             }
6365         }
6366         if (package->features[i].Feature_Parent[0])
6367         {
6368             static const WCHAR sep[] = {'\2',0};
6369             strcatW(data,sep);
6370             strcatW(data,package->features[i].Feature_Parent);
6371         }
6372
6373         size = (strlenW(data)+1)*sizeof(WCHAR);
6374         RegSetValueExW(hkey,package->features[i].Feature,0,REG_SZ,
6375                        (LPSTR)data,size);
6376         HeapFree(GetProcessHeap(),0,data);
6377
6378         if (!absent)
6379         {
6380             size = strlenW(package->features[i].Feature_Parent)*sizeof(WCHAR);
6381             RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ,
6382                        (LPSTR)package->features[i].Feature_Parent,size);
6383         }
6384         else
6385         {
6386             size = (strlenW(package->features[i].Feature_Parent)+2)*
6387                     sizeof(WCHAR);
6388             data = HeapAlloc(GetProcessHeap(),0,size);
6389             data[0] = 0x6;
6390             strcpyW(&data[1],package->features[i].Feature_Parent);
6391             RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ,
6392                        (LPSTR)data,size);
6393             HeapFree(GetProcessHeap(),0,data);
6394         }
6395     }
6396
6397 end:
6398     RegCloseKey(hkey);
6399     RegCloseKey(hukey);
6400     HeapFree(GetProcessHeap(), 0, productcode);
6401     return rc;
6402 }
6403
6404 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
6405 {
6406     HKEY hkey=0;
6407     LPWSTR buffer;
6408     LPWSTR productcode;
6409     UINT rc,i;
6410     DWORD size;
6411     static WCHAR szNONE[] = {0};
6412     static const WCHAR szWindowsInstaler[] = 
6413     {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
6414     static const WCHAR szPropKeys[][80] = 
6415     {
6416 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0},
6417 {'A','R','P','C','O','N','T','A','C','T',0},
6418 {'A','R','P','C','O','M','M','E','N','T','S',0},
6419 {'P','r','o','d','u','c','t','N','a','m','e',0},
6420 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0},
6421 {'A','R','P','H','E','L','P','L','I','N','K',0},
6422 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0},
6423 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0},
6424 {'S','o','u','r','c','e','D','i','r',0},
6425 {'M','a','n','u','f','a','c','t','u','r','e','r',0},
6426 {'A','R','P','R','E','A','D','M','E',0},
6427 {'A','R','P','S','I','Z','E',0},
6428 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0},
6429 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0},
6430 {0},
6431     };
6432
6433     static const WCHAR szRegKeys[][80] = 
6434     {
6435 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0},
6436 {'C','o','n','t','a','c','t',0},
6437 {'C','o','m','m','e','n','t','s',0},
6438 {'D','i','s','p','l','a','y','N','a','m','e',0},
6439 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0},
6440 {'H','e','l','p','L','i','n','k',0},
6441 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0},
6442 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0},
6443 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0},
6444 {'P','u','b','l','i','s','h','e','r',0},
6445 {'R','e','a','d','m','e',0},
6446 {'S','i','z','e',0},
6447 {'U','R','L','I','n','f','o','A','b','o','u','t',0},
6448 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0},
6449 {0},
6450     };
6451
6452     static const WCHAR installerPathFmt[] = {
6453     '%','s','\\',
6454     'I','n','s','t','a','l','l','e','r','\\',0};
6455     static const WCHAR fmt[] = {
6456     '%','s','\\',
6457     'I','n','s','t','a','l','l','e','r','\\',
6458     '%','x','.','m','s','i',0};
6459     static const WCHAR szLocalPackage[]=
6460          {'L','o','c','a','l','P','a','c','k','a','g','e',0};
6461     WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
6462     INT num,start;
6463
6464     if (!package)
6465         return ERROR_INVALID_HANDLE;
6466
6467     productcode = load_dynamic_property(package,szProductCode,&rc);
6468     if (!productcode)
6469         return rc;
6470
6471     rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE);
6472     if (rc != ERROR_SUCCESS)
6473         goto end;
6474
6475     /* dump all the info i can grab */
6476     FIXME("Flesh out more information \n");
6477
6478     i = 0;
6479     while (szPropKeys[i][0]!=0)
6480     {
6481         buffer = load_dynamic_property(package,szPropKeys[i],&rc);
6482         if (rc != ERROR_SUCCESS)
6483             buffer = szNONE;
6484         size = strlenW(buffer)*sizeof(WCHAR);
6485         RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size);
6486         i++;
6487     }
6488
6489     rc = 0x1;
6490     size = sizeof(rc);
6491     RegSetValueExW(hkey,szWindowsInstaler,0,REG_DWORD,(LPSTR)&rc,size);
6492     
6493     /* copy the package locally */
6494     num = GetTickCount() & 0xffff;
6495     if (!num) 
6496         num = 1;
6497     start = num;
6498     GetWindowsDirectoryW(windir, sizeof(windir) / sizeof(windir[0]));
6499     snprintfW(packagefile,sizeof(packagefile)/sizeof(packagefile[0]),fmt,
6500      windir,num);
6501     do 
6502     {
6503         HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
6504                                   CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
6505         if (handle != INVALID_HANDLE_VALUE)
6506         {
6507             CloseHandle(handle);
6508             break;
6509         }
6510         if (GetLastError() != ERROR_FILE_EXISTS &&
6511             GetLastError() != ERROR_SHARING_VIOLATION)
6512             break;
6513         if (!(++num & 0xffff)) num = 1;
6514         sprintfW(packagefile,fmt,num);
6515     } while (num != start);
6516
6517     snprintfW(path,sizeof(path)/sizeof(path[0]),installerPathFmt,windir);
6518     create_full_pathW(path);
6519     TRACE("Copying to local package %s\n",debugstr_w(packagefile));
6520     if (!CopyFileW(package->PackagePath,packagefile,FALSE))
6521         ERR("Unable to copy package (%s -> %s) (error %ld)\n",
6522             debugstr_w(package->PackagePath), debugstr_w(packagefile),
6523             GetLastError());
6524     size = strlenW(packagefile)*sizeof(WCHAR);
6525     RegSetValueExW(hkey,szLocalPackage,0,REG_SZ,(LPSTR)packagefile,size);
6526     
6527 end:
6528     HeapFree(GetProcessHeap(),0,productcode);
6529     RegCloseKey(hkey);
6530
6531     return ERROR_SUCCESS;
6532 }
6533
6534 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
6535 {
6536     UINT rc;
6537
6538     if (!package)
6539         return ERROR_INVALID_HANDLE;
6540
6541     rc = execute_script(package,INSTALL_SCRIPT);
6542
6543     return rc;
6544 }
6545
6546 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
6547 {
6548     UINT rc;
6549
6550     if (!package)
6551         return ERROR_INVALID_HANDLE;
6552
6553     /* turn off scheduleing */
6554     package->script->CurrentlyScripting= FALSE;
6555
6556     /* first do the same as an InstallExecute */
6557     rc = ACTION_InstallExecute(package);
6558     if (rc != ERROR_SUCCESS)
6559         return rc;
6560
6561     /* then handle Commit Actions */
6562     rc = execute_script(package,COMMIT_SCRIPT);
6563
6564     return rc;
6565 }
6566
6567 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
6568 {
6569     static const WCHAR RunOnce[] = {
6570     'S','o','f','t','w','a','r','e','\\',
6571     'M','i','c','r','o','s','o','f','t','\\',
6572     'W','i','n','d','o','w','s','\\',
6573     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
6574     'R','u','n','O','n','c','e',0};
6575     static const WCHAR InstallRunOnce[] = {
6576     'S','o','f','t','w','a','r','e','\\',
6577     'M','i','c','r','o','s','o','f','t','\\',
6578     'W','i','n','d','o','w','s','\\',
6579     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
6580     'I','n','s','t','a','l','l','e','r','\\',
6581     'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
6582
6583     static const WCHAR msiexec_fmt[] = {
6584     '%','s',
6585     '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
6586     '\"','%','s','\"',0};
6587     static const WCHAR install_fmt[] = {
6588     '/','I',' ','\"','%','s','\"',' ',
6589     'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
6590     'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
6591     WCHAR buffer[256], sysdir[MAX_PATH];
6592     HKEY hkey,hukey;
6593     LPWSTR productcode;
6594     WCHAR  squished_pc[100];
6595     INT rc;
6596     DWORD size;
6597     static const WCHAR szLUS[] = {
6598          'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0};
6599     static const WCHAR szSourceList[] = {
6600          'S','o','u','r','c','e','L','i','s','t',0};
6601     static const WCHAR szPackageName[] = { 
6602         'P','a','c','k','a','g','e','N','a','m','e',0};
6603
6604     if (!package)
6605         return ERROR_INVALID_HANDLE;
6606
6607     productcode = load_dynamic_property(package,szProductCode,&rc);
6608     if (!productcode)
6609         return rc;
6610
6611     squash_guid(productcode,squished_pc);
6612
6613     GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
6614     RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
6615     snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
6616      squished_pc);
6617
6618     size = strlenW(buffer)*sizeof(WCHAR);
6619     RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size);
6620     RegCloseKey(hkey);
6621
6622     TRACE("Reboot command %s\n",debugstr_w(buffer));
6623
6624     RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
6625     sprintfW(buffer,install_fmt,productcode,squished_pc);
6626
6627     size = strlenW(buffer)*sizeof(WCHAR);
6628     RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size);
6629     RegCloseKey(hkey);
6630
6631     rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE);
6632     if (rc == ERROR_SUCCESS)
6633     {
6634         HKEY hukey2;
6635         LPWSTR buf;
6636         RegCreateKeyW(hukey, szSourceList, &hukey2);
6637         buf = load_dynamic_property(package,cszSourceDir,NULL);
6638         size = strlenW(buf)*sizeof(WCHAR);
6639         RegSetValueExW(hukey2,szLUS,0,REG_SZ,(LPSTR)buf,size);
6640         HeapFree(GetProcessHeap(),0,buf); 
6641
6642         buf = strrchrW(package->PackagePath,'\\');
6643         if (buf)
6644         {
6645             buf++;
6646             size = strlenW(buf)*sizeof(WCHAR);
6647             RegSetValueExW(hukey2,szPackageName,0,REG_SZ,(LPSTR)buf,size);
6648         }
6649
6650         RegCloseKey(hukey2);
6651     }
6652     HeapFree(GetProcessHeap(),0,productcode);
6653
6654     return ERROR_INSTALL_SUSPEND;
6655 }
6656
6657 UINT ACTION_ResolveSource(MSIPACKAGE* package)
6658 {
6659     /*
6660      * we are currently doing what should be done here in the top level Install
6661      * however for Adminastrative and uninstalls this step will be needed
6662      */
6663     return ERROR_SUCCESS;
6664 }
6665
6666 static LPWSTR create_component_advertise_string(MSIPACKAGE* package, 
6667                 MSICOMPONENT* component, LPCWSTR feature)
6668 {
6669     LPWSTR productid=NULL;
6670     GUID clsid;
6671     WCHAR productid_85[21];
6672     WCHAR component_85[21];
6673     /*
6674      * I have a fair bit of confusion as to when a < is used and when a > is
6675      * used. I do not think i have it right...
6676      *
6677      * Ok it appears that the > is used if there is a guid for the compoenent
6678      * and the < is used if not.
6679      */
6680     static WCHAR fmt1[] = {'%','s','%','s','<',0,0};
6681     static WCHAR fmt2[] = {'%','s','%','s','>','%','s',0,0};
6682     LPWSTR output = NULL;
6683     DWORD sz = 0;
6684
6685     memset(productid_85,0,sizeof(productid_85));
6686     memset(component_85,0,sizeof(component_85));
6687
6688     productid = load_dynamic_property(package,szProductCode,NULL);
6689     CLSIDFromString(productid, &clsid);
6690     
6691     encode_base85_guid(&clsid,productid_85);
6692
6693     CLSIDFromString(component->ComponentId, &clsid);
6694     encode_base85_guid(&clsid,component_85);
6695
6696     TRACE("Doing something with this... %s %s %s\n", 
6697             debugstr_w(productid_85), debugstr_w(feature),
6698             debugstr_w(component_85));
6699  
6700     sz = lstrlenW(productid_85) + lstrlenW(feature);
6701     if (component)
6702         sz += lstrlenW(component_85);
6703
6704     sz+=3;
6705     sz *= sizeof(WCHAR);
6706            
6707     output = HeapAlloc(GetProcessHeap(),0,sz);
6708     memset(output,0,sz);
6709
6710     if (component)
6711         sprintfW(output,fmt2,productid_85,feature,component_85);
6712     else
6713         sprintfW(output,fmt1,productid_85,feature);
6714
6715     HeapFree(GetProcessHeap(),0,productid);
6716     
6717     return output;
6718 }
6719
6720 static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid, 
6721                 MSICOMPONENT* component, MSIEXTENSION* extension,
6722                 MSIVERB* verb, INT* Sequence )
6723 {
6724     LPWSTR keyname;
6725     HKEY key;
6726     static const WCHAR szShell[] = {'s','h','e','l','l',0};
6727     static const WCHAR szCommand[] = {'c','o','m','m','a','n','d',0};
6728     static const WCHAR fmt[] = {'\"','%','s','\"',' ','%','s',0};
6729     static const WCHAR fmt2[] = {'\"','%','s','\"',0};
6730     LPWSTR command;
6731     DWORD size;
6732     LPWSTR advertise;
6733
6734     keyname = build_directory_name(4, progid, szShell, verb->Verb, szCommand);
6735
6736     TRACE("Making Key %s\n",debugstr_w(keyname));
6737     RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
6738     size = strlenW(component->FullKeypath);
6739     if (verb->Argument)
6740         size += strlenW(verb->Argument);
6741      size += 4;
6742
6743      command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR));
6744      if (verb->Argument)
6745         sprintfW(command, fmt, component->FullKeypath, verb->Argument);
6746      else
6747         sprintfW(command, fmt2, component->FullKeypath);
6748
6749      RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)command, (strlenW(command)+1)*
6750                      sizeof(WCHAR));
6751      HeapFree(GetProcessHeap(),0,command);
6752
6753      advertise = create_component_advertise_string(package, component, 
6754                         package->features[extension->FeatureIndex].Feature);
6755
6756      size = strlenW(advertise);
6757
6758      if (verb->Argument)
6759         size += strlenW(verb->Argument);
6760      size += 4;
6761
6762      command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR));
6763      memset(command,0,size*sizeof(WCHAR));
6764
6765      strcpyW(command,advertise);
6766      if (verb->Argument)
6767      {
6768         static const WCHAR szSpace[] = {' ',0};
6769          strcatW(command,szSpace);
6770          strcatW(command,verb->Argument);
6771      }
6772
6773      RegSetValueExW(key, szCommand, 0, REG_MULTI_SZ, (LPBYTE)command,
6774                         (strlenW(command)+2)*sizeof(WCHAR));
6775      
6776      RegCloseKey(key);
6777      HeapFree(GetProcessHeap(),0,keyname);
6778      HeapFree(GetProcessHeap(),0,advertise);
6779      HeapFree(GetProcessHeap(),0,command);
6780
6781      if (verb->Command)
6782      {
6783         keyname = build_directory_name(3, progid, szShell, verb->Verb);
6784         RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
6785         RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Command,
6786                                     (strlenW(verb->Command)+1) *sizeof(WCHAR));
6787         RegCloseKey(key);
6788         HeapFree(GetProcessHeap(),0,keyname);
6789      }
6790
6791      if (verb->Sequence != MSI_NULL_INTEGER)
6792      {
6793         if (*Sequence == MSI_NULL_INTEGER || verb->Sequence < *Sequence)
6794         {
6795             *Sequence = verb->Sequence;
6796             keyname = build_directory_name(2, progid, szShell);
6797             RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
6798             RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Verb,
6799                             (strlenW(verb->Verb)+1) *sizeof(WCHAR));
6800             RegCloseKey(key);
6801             HeapFree(GetProcessHeap(),0,keyname);
6802         }
6803     }
6804     return ERROR_SUCCESS;
6805 }
6806
6807 static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
6808 {
6809     static const WCHAR szContentType[] = 
6810         {'C','o','n','t','e','n','t',' ','T','y','p','e',0 };
6811     HKEY hkey;
6812     INT i;
6813     MSIRECORD *uirow;
6814     BOOL install_on_demand = TRUE;
6815
6816     if (!package)
6817         return ERROR_INVALID_HANDLE;
6818
6819     load_classes_and_such(package);
6820
6821     /* We need to set install_on_demand based on if the shell handles advertised
6822      * shortcuts and the like. Because Mike McCormack is working on this i am
6823      * going to default to TRUE
6824      */
6825     
6826     for (i = 0; i < package->loaded_extensions; i++)
6827     {
6828         WCHAR extension[257];
6829         INT index,f_index;
6830      
6831         index = package->extensions[i].ComponentIndex;
6832         f_index = package->extensions[i].FeatureIndex;
6833
6834         if (index < 0)
6835             continue;
6836
6837         /* 
6838          * yes. MSDN says that these are based on _Feature_ not on
6839          * Component.  So verify the feature is to be installed
6840          */
6841         if ((!ACTION_VerifyFeatureForAction(package, f_index,
6842                                 INSTALLSTATE_LOCAL)) &&
6843              !(install_on_demand && ACTION_VerifyFeatureForAction(package,
6844                              f_index, INSTALLSTATE_ADVERTISED)))
6845         {
6846             TRACE("Skipping extension  %s reg due to disabled feature %s\n",
6847                             debugstr_w(package->extensions[i].Extension),
6848                             debugstr_w(package->features[f_index].Feature));
6849
6850             continue;
6851         }
6852
6853         TRACE("Registering extension %s index %i\n",
6854                         debugstr_w(package->extensions[i].Extension), i);
6855
6856         package->extensions[i].Installed = TRUE;
6857
6858         /* this is only registered if the extension has at least 1 verb
6859          * according to MSDN
6860          */
6861         if (package->extensions[i].ProgIDIndex >= 0 &&
6862                 package->extensions[i].VerbCount > 0)
6863            mark_progid_for_install(package, package->extensions[i].ProgIDIndex);
6864
6865         if (package->extensions[i].MIMEIndex >= 0)
6866            mark_mime_for_install(package, package->extensions[i].MIMEIndex);
6867
6868         extension[0] = '.';
6869         extension[1] = 0;
6870         strcatW(extension,package->extensions[i].Extension);
6871
6872         RegCreateKeyW(HKEY_CLASSES_ROOT,extension,&hkey);
6873
6874         if (package->extensions[i].MIMEIndex >= 0)
6875         {
6876             RegSetValueExW(hkey,szContentType,0,REG_SZ,
6877                             (LPVOID)package->mimes[package->extensions[i].
6878                                 MIMEIndex].ContentType,
6879                            (strlenW(package->mimes[package->extensions[i].
6880                                     MIMEIndex].ContentType)+1)*sizeof(WCHAR));
6881         }
6882
6883         if (package->extensions[i].ProgIDIndex >= 0 || 
6884             package->extensions[i].ProgIDText)
6885         {
6886             static const WCHAR szSN[] = 
6887                 {'\\','S','h','e','l','l','N','e','w',0};
6888             HKEY hkey2;
6889             LPWSTR newkey;
6890             LPCWSTR progid;
6891             INT v;
6892             INT Sequence = MSI_NULL_INTEGER;
6893             
6894             if (package->extensions[i].ProgIDIndex >= 0)
6895                 progid = package->progids[package->extensions[i].
6896                     ProgIDIndex].ProgID;
6897             else
6898                 progid = package->extensions[i].ProgIDText;
6899
6900             RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid,
6901                            (strlenW(progid)+1)*sizeof(WCHAR));
6902
6903             newkey = HeapAlloc(GetProcessHeap(),0,
6904                            (strlenW(progid)+strlenW(szSN)+1) * sizeof(WCHAR)); 
6905
6906             strcpyW(newkey,progid);
6907             strcatW(newkey,szSN);
6908             RegCreateKeyW(hkey,newkey,&hkey2);
6909             RegCloseKey(hkey2);
6910
6911             HeapFree(GetProcessHeap(),0,newkey);
6912
6913             /* do all the verbs */
6914             for (v = 0; v < package->extensions[i].VerbCount; v++)
6915                 register_verb(package, progid, 
6916                               &package->components[index],
6917                               &package->extensions[i],
6918                               &package->verbs[package->extensions[i].Verbs[v]], 
6919                               &Sequence);
6920         }
6921         
6922         RegCloseKey(hkey);
6923
6924         uirow = MSI_CreateRecord(1);
6925         MSI_RecordSetStringW(uirow,1,package->extensions[i].Extension);
6926         ui_actiondata(package,szRegisterExtensionInfo,uirow);
6927         msiobj_release(&uirow->hdr);
6928     }
6929
6930     return ERROR_SUCCESS;
6931 }
6932
6933 static UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package)
6934 {
6935     static const WCHAR szExten[] = 
6936         {'E','x','t','e','n','s','i','o','n',0 };
6937     HKEY hkey;
6938     INT i;
6939     MSIRECORD *uirow;
6940
6941     if (!package)
6942         return ERROR_INVALID_HANDLE;
6943
6944     load_classes_and_such(package);
6945
6946     for (i = 0; i < package->loaded_mimes; i++)
6947     {
6948         WCHAR extension[257];
6949         LPCWSTR exten;
6950         LPCWSTR mime;
6951         static const WCHAR fmt[] = 
6952             {'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\',
6953              'C','o','n','t','e','n','t',' ','T','y','p','e','\\', '%','s',0};
6954         LPWSTR key;
6955
6956         /* 
6957          * check if the MIME is to be installed. Either as requesed by an
6958          * extension or Class
6959          */
6960         package->mimes[i].InstallMe =  ((package->mimes[i].InstallMe) ||
6961               (package->mimes[i].ClassIndex >= 0 &&
6962               package->classes[package->mimes[i].ClassIndex].Installed) ||
6963               (package->mimes[i].ExtensionIndex >=0 &&
6964               package->extensions[package->mimes[i].ExtensionIndex].Installed));
6965
6966         if (!package->mimes[i].InstallMe)
6967         {
6968             TRACE("MIME %s not scheduled to be installed\n",
6969                              debugstr_w(package->mimes[i].ContentType));
6970             continue;
6971         }
6972         
6973         mime = package->mimes[i].ContentType;
6974         exten = package->extensions[package->mimes[i].ExtensionIndex].Extension;
6975         extension[0] = '.';
6976         extension[1] = 0;
6977         strcatW(extension,exten);
6978
6979         key = HeapAlloc(GetProcessHeap(),0,(strlenW(mime)+strlenW(fmt)+1) *
6980                                             sizeof(WCHAR));
6981         sprintfW(key,fmt,mime);
6982         RegCreateKeyW(HKEY_CLASSES_ROOT,key,&hkey);
6983         RegSetValueExW(hkey,szExten,0,REG_SZ,(LPVOID)extension,
6984                            (strlenW(extension)+1)*sizeof(WCHAR));
6985
6986         HeapFree(GetProcessHeap(),0,key);
6987
6988         if (package->mimes[i].CLSID[0])
6989         {
6990             FIXME("Handle non null for field 3\n");
6991         }
6992
6993         RegCloseKey(hkey);
6994
6995         uirow = MSI_CreateRecord(2);
6996         MSI_RecordSetStringW(uirow,1,package->mimes[i].ContentType);
6997         MSI_RecordSetStringW(uirow,2,exten);
6998         ui_actiondata(package,szRegisterMIMEInfo,uirow);
6999         msiobj_release(&uirow->hdr);
7000     }
7001
7002     return ERROR_SUCCESS;
7003 }
7004
7005 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
7006 {
7007     static const WCHAR szProductID[]=
7008          {'P','r','o','d','u','c','t','I','D',0};
7009     HKEY hkey=0;
7010     LPWSTR buffer;
7011     LPWSTR productcode;
7012     LPWSTR productid;
7013     UINT rc,i;
7014     DWORD size;
7015
7016     static const WCHAR szPropKeys[][80] = 
7017     {
7018         {'P','r','o','d','u','c','t','I','D',0},
7019         {'U','S','E','R','N','A','M','E',0},
7020         {'C','O','M','P','A','N','Y','N','A','M','E',0},
7021         {0},
7022     };
7023
7024     static const WCHAR szRegKeys[][80] = 
7025     {
7026         {'P','r','o','d','u','c','t','I','D',0},
7027         {'R','e','g','O','w','n','e','r',0},
7028         {'R','e','g','C','o','m','p','a','n','y',0},
7029         {0},
7030     };
7031
7032     if (!package)
7033         return ERROR_INVALID_HANDLE;
7034
7035     productid = load_dynamic_property(package,szProductID,&rc);
7036     if (!productid)
7037         return ERROR_SUCCESS;
7038
7039     productcode = load_dynamic_property(package,szProductCode,&rc);
7040     if (!productcode)
7041         return rc;
7042
7043     rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE);
7044     if (rc != ERROR_SUCCESS)
7045         goto end;
7046
7047     i = 0;
7048     while (szPropKeys[i][0]!=0)
7049     {
7050         buffer = load_dynamic_property(package,szPropKeys[i],&rc);
7051         if (rc == ERROR_SUCCESS)
7052         {
7053             size = strlenW(buffer)*sizeof(WCHAR);
7054             RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size);
7055         }
7056         else
7057             RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,NULL,0);
7058         i++;
7059     }
7060
7061 end:
7062     HeapFree(GetProcessHeap(),0,productcode);
7063     HeapFree(GetProcessHeap(),0,productid);
7064     RegCloseKey(hkey);
7065
7066     return ERROR_SUCCESS;
7067 }
7068
7069
7070 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
7071 {
7072     UINT rc;
7073     rc = ACTION_ProcessExecSequence(package,FALSE);
7074     return rc;
7075 }
7076
7077
7078 /*
7079  * Code based off of code located here
7080  * http://www.codeproject.com/gdi/fontnamefromfile.asp
7081  *
7082  * Using string index 4 (full font name) instead of 1 (family name)
7083  */
7084 static LPWSTR load_ttfname_from(LPCWSTR filename)
7085 {
7086     HANDLE handle;
7087     LPWSTR ret = NULL;
7088     int i;
7089
7090     typedef struct _tagTT_OFFSET_TABLE{
7091         USHORT uMajorVersion;
7092         USHORT uMinorVersion;
7093         USHORT uNumOfTables;
7094         USHORT uSearchRange;
7095         USHORT uEntrySelector;
7096         USHORT uRangeShift;
7097     }TT_OFFSET_TABLE;
7098
7099     typedef struct _tagTT_TABLE_DIRECTORY{
7100         char szTag[4]; /* table name */
7101         ULONG uCheckSum; /* Check sum */
7102         ULONG uOffset; /* Offset from beginning of file */
7103         ULONG uLength; /* length of the table in bytes */
7104     }TT_TABLE_DIRECTORY;
7105
7106     typedef struct _tagTT_NAME_TABLE_HEADER{
7107     USHORT uFSelector; /* format selector. Always 0 */
7108     USHORT uNRCount; /* Name Records count */
7109     USHORT uStorageOffset; /* Offset for strings storage, 
7110                             * from start of the table */
7111     }TT_NAME_TABLE_HEADER;
7112    
7113     typedef struct _tagTT_NAME_RECORD{
7114         USHORT uPlatformID;
7115         USHORT uEncodingID;
7116         USHORT uLanguageID;
7117         USHORT uNameID;
7118         USHORT uStringLength;
7119         USHORT uStringOffset; /* from start of storage area */
7120     }TT_NAME_RECORD;
7121
7122 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
7123 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
7124
7125     handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
7126                     FILE_ATTRIBUTE_NORMAL, 0 );
7127     if (handle != INVALID_HANDLE_VALUE)
7128     {
7129         TT_TABLE_DIRECTORY tblDir;
7130         BOOL bFound = FALSE;
7131         TT_OFFSET_TABLE ttOffsetTable;
7132
7133         ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),NULL,NULL);
7134         ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
7135         ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
7136         ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
7137         
7138         if (ttOffsetTable.uMajorVersion != 1 || 
7139                         ttOffsetTable.uMinorVersion != 0)
7140             return NULL;
7141
7142         for (i=0; i< ttOffsetTable.uNumOfTables; i++)
7143         {
7144             ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),NULL,NULL);
7145             if (strncmp(tblDir.szTag,"name",4)==0)
7146             {
7147                 bFound = TRUE;
7148                 tblDir.uLength = SWAPLONG(tblDir.uLength);
7149                 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
7150                 break;
7151             }
7152         }
7153
7154         if (bFound)
7155         {
7156             TT_NAME_TABLE_HEADER ttNTHeader;
7157             TT_NAME_RECORD ttRecord;
7158
7159             SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
7160             ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
7161                             NULL,NULL);
7162
7163             ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
7164             ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
7165             bFound = FALSE;
7166             for(i=0; i<ttNTHeader.uNRCount; i++)
7167             {
7168                 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),NULL,NULL);
7169                 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
7170                 /* 4 is the Full Font Name */
7171                 if(ttRecord.uNameID == 4)
7172                 {
7173                     int nPos;
7174                     LPSTR buf;
7175                     static LPCSTR tt = " (TrueType)";
7176
7177                     ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
7178                     ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
7179                     nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
7180                     SetFilePointer(handle, tblDir.uOffset + 
7181                                     ttRecord.uStringOffset + 
7182                                     ttNTHeader.uStorageOffset,
7183                                     NULL, FILE_BEGIN);
7184                     buf = HeapAlloc(GetProcessHeap(), 0, 
7185                                     ttRecord.uStringLength + 1 + strlen(tt));
7186                     memset(buf, 0, ttRecord.uStringLength + 1 + strlen(tt));
7187                     ReadFile(handle, buf, ttRecord.uStringLength, NULL, NULL);
7188                     if (strlen(buf) > 0)
7189                     {
7190                         strcat(buf,tt);
7191                         ret = strdupAtoW(buf);
7192                         HeapFree(GetProcessHeap(),0,buf);
7193                         break;
7194                     }
7195
7196                     HeapFree(GetProcessHeap(),0,buf);
7197                     SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
7198                 }
7199             }
7200         }
7201         CloseHandle(handle);
7202     }
7203     else
7204         ERR("Unable to open font file %s\n", debugstr_w(filename));
7205
7206     TRACE("Returning fontname %s\n",debugstr_w(ret));
7207     return ret;
7208 }
7209
7210 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
7211 {
7212     UINT rc;
7213     MSIQUERY * view;
7214     MSIRECORD * row = 0;
7215     static const WCHAR ExecSeqQuery[] =
7216         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7217          '`','F','o','n','t','`',0};
7218     static const WCHAR regfont1[] =
7219         {'S','o','f','t','w','a','r','e','\\',
7220          'M','i','c','r','o','s','o','f','t','\\',
7221          'W','i','n','d','o','w','s',' ','N','T','\\',
7222          'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
7223          'F','o','n','t','s',0};
7224     static const WCHAR regfont2[] =
7225         {'S','o','f','t','w','a','r','e','\\',
7226          'M','i','c','r','o','s','o','f','t','\\',
7227          'W','i','n','d','o','w','s','\\',
7228          'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
7229          'F','o','n','t','s',0};
7230     HKEY hkey1;
7231     HKEY hkey2;
7232
7233     TRACE("%p\n", package);
7234
7235     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
7236     if (rc != ERROR_SUCCESS)
7237     {
7238         TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
7239         return ERROR_SUCCESS;
7240     }
7241
7242     rc = MSI_ViewExecute(view, 0);
7243     if (rc != ERROR_SUCCESS)
7244     {
7245         MSI_ViewClose(view);
7246         msiobj_release(&view->hdr);
7247         TRACE("MSI_ViewExecute returned %d\n", rc);
7248         return ERROR_SUCCESS;
7249     }
7250
7251     RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
7252     RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
7253     
7254     while (1)
7255     {
7256         LPWSTR name;
7257         LPWSTR file;
7258         UINT index;
7259         DWORD size;
7260
7261         rc = MSI_ViewFetch(view,&row);
7262         if (rc != ERROR_SUCCESS)
7263         {
7264             rc = ERROR_SUCCESS;
7265             break;
7266         }
7267
7268         file = load_dynamic_stringW(row,1);
7269         index = get_loaded_file(package,file);
7270         if (index < 0)
7271         {
7272             ERR("Unable to load file\n");
7273             HeapFree(GetProcessHeap(),0,file);
7274             continue;
7275         }
7276
7277         /* check to make sure that component is installed */
7278         if (!ACTION_VerifyComponentForAction(package, 
7279                 package->files[index].ComponentIndex, INSTALLSTATE_LOCAL))
7280         {
7281             TRACE("Skipping: Component not scheduled for install\n");
7282             HeapFree(GetProcessHeap(),0,file);
7283
7284             msiobj_release(&row->hdr);
7285
7286             continue;
7287         }
7288
7289         if (MSI_RecordIsNull(row,2))
7290             name = load_ttfname_from(package->files[index].TargetPath);
7291         else
7292             name = load_dynamic_stringW(row,2);
7293
7294         if (name)
7295         {
7296             size = strlenW(package->files[index].FileName) * sizeof(WCHAR);
7297             RegSetValueExW(hkey1,name,0,REG_SZ,
7298                         (LPBYTE)package->files[index].FileName,size);
7299             RegSetValueExW(hkey2,name,0,REG_SZ,
7300                         (LPBYTE)package->files[index].FileName,size);
7301         }
7302         
7303         HeapFree(GetProcessHeap(),0,file);
7304         HeapFree(GetProcessHeap(),0,name);
7305         msiobj_release(&row->hdr);
7306     }
7307     MSI_ViewClose(view);
7308     msiobj_release(&view->hdr);
7309
7310     RegCloseKey(hkey1);
7311     RegCloseKey(hkey2);
7312
7313     TRACE("returning %d\n", rc);
7314     return rc;
7315 }
7316
7317 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
7318 {
7319     MSIPACKAGE *package = (MSIPACKAGE*)param;
7320     LPWSTR compgroupid=NULL;
7321     LPWSTR feature=NULL;
7322     LPWSTR text = NULL;
7323     LPWSTR qualifier = NULL;
7324     LPWSTR component = NULL;
7325     LPWSTR advertise = NULL;
7326     LPWSTR output = NULL;
7327     HKEY hkey;
7328     UINT rc = ERROR_SUCCESS;
7329     UINT index;
7330     DWORD sz = 0;
7331
7332     component = load_dynamic_stringW(rec,3);
7333     index = get_loaded_component(package,component);
7334
7335     if (!ACTION_VerifyComponentForAction(package, index,
7336                             INSTALLSTATE_LOCAL) && 
7337        !ACTION_VerifyComponentForAction(package, index,
7338                             INSTALLSTATE_SOURCE) &&
7339        !ACTION_VerifyComponentForAction(package, index,
7340                             INSTALLSTATE_ADVERTISED))
7341     {
7342         TRACE("Skipping: Component %s not scheduled for install\n",
7343                         debugstr_w(component));
7344
7345         HeapFree(GetProcessHeap(),0,component);
7346         return ERROR_SUCCESS;
7347     }
7348
7349     compgroupid = load_dynamic_stringW(rec,1);
7350
7351     rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
7352     if (rc != ERROR_SUCCESS)
7353         goto end;
7354     
7355     text = load_dynamic_stringW(rec,4);
7356     qualifier = load_dynamic_stringW(rec,2);
7357     feature = load_dynamic_stringW(rec,5);
7358   
7359     advertise = create_component_advertise_string(package, 
7360                     &package->components[index], feature);
7361
7362     sz = strlenW(advertise);
7363
7364     if (text)
7365         sz += lstrlenW(text);
7366
7367     sz+=3;
7368     sz *= sizeof(WCHAR);
7369            
7370     output = HeapAlloc(GetProcessHeap(),0,sz);
7371     memset(output,0,sz);
7372     strcpyW(output,advertise);
7373
7374     if (text)
7375         strcatW(output,text);
7376
7377     sz = (lstrlenW(output)+2) * sizeof(WCHAR);
7378     RegSetValueExW(hkey, qualifier,0,REG_MULTI_SZ, (LPBYTE)output, sz);
7379     
7380 end:
7381     RegCloseKey(hkey);
7382     HeapFree(GetProcessHeap(),0,output);
7383     HeapFree(GetProcessHeap(),0,compgroupid);
7384     HeapFree(GetProcessHeap(),0,component);
7385     HeapFree(GetProcessHeap(),0,feature);
7386     HeapFree(GetProcessHeap(),0,text);
7387     HeapFree(GetProcessHeap(),0,qualifier);
7388     
7389     return rc;
7390 }
7391
7392 /*
7393  * At present I am ignorning the advertised components part of this and only
7394  * focusing on the qualified component sets
7395  */
7396 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
7397 {
7398     UINT rc;
7399     MSIQUERY * view;
7400     static const WCHAR ExecSeqQuery[] =
7401         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7402          '`','P','u','b','l','i','s','h',
7403          'C','o','m','p','o','n','e','n','t','`',0};
7404     
7405     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
7406     if (rc != ERROR_SUCCESS)
7407         return ERROR_SUCCESS;
7408
7409     rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
7410     msiobj_release(&view->hdr);
7411
7412     return rc;
7413 }
7414
7415 /* Msi functions that seem appropriate here */
7416
7417 /***********************************************************************
7418  * MsiDoActionA       (MSI.@)
7419  */
7420 UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
7421 {
7422     LPWSTR szwAction;
7423     UINT rc;
7424
7425     TRACE(" exteral attempt at action %s\n",szAction);
7426
7427     if (!szAction)
7428         return ERROR_FUNCTION_FAILED;
7429     if (hInstall == 0)
7430         return ERROR_FUNCTION_FAILED;
7431
7432     szwAction = strdupAtoW(szAction);
7433
7434     if (!szwAction)
7435         return ERROR_FUNCTION_FAILED; 
7436
7437
7438     rc = MsiDoActionW(hInstall, szwAction);
7439     HeapFree(GetProcessHeap(),0,szwAction);
7440     return rc;
7441 }
7442
7443 /***********************************************************************
7444  * MsiDoActionW       (MSI.@)
7445  */
7446 UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction )
7447 {
7448     MSIPACKAGE *package;
7449     UINT ret = ERROR_INVALID_HANDLE;
7450
7451     TRACE(" external attempt at action %s \n",debugstr_w(szAction));
7452
7453     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
7454     if( package )
7455     {
7456         ret = ACTION_PerformUIAction(package,szAction);
7457         msiobj_release( &package->hdr );
7458     }
7459     return ret;
7460 }
7461
7462 UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder, 
7463                                LPSTR szPathBuf, DWORD* pcchPathBuf) 
7464 {
7465     LPWSTR szwFolder;
7466     LPWSTR szwPathBuf;
7467     UINT rc;
7468
7469     TRACE("getting folder %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
7470
7471     if (!szFolder)
7472         return ERROR_FUNCTION_FAILED;
7473     if (hInstall == 0)
7474         return ERROR_FUNCTION_FAILED;
7475
7476     szwFolder = strdupAtoW(szFolder);
7477
7478     if (!szwFolder)
7479         return ERROR_FUNCTION_FAILED; 
7480
7481     szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
7482
7483     rc = MsiGetTargetPathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
7484
7485     WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
7486                          *pcchPathBuf, NULL, NULL );
7487
7488     HeapFree(GetProcessHeap(),0,szwFolder);
7489     HeapFree(GetProcessHeap(),0,szwPathBuf);
7490
7491     return rc;
7492 }
7493
7494 UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
7495                                 szPathBuf, DWORD* pcchPathBuf) 
7496 {
7497     LPWSTR path;
7498     UINT rc = ERROR_FUNCTION_FAILED;
7499     MSIPACKAGE *package;
7500
7501     TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
7502
7503     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
7504     if (!package)
7505         return ERROR_INVALID_HANDLE;
7506     path = resolve_folder(package, szFolder, FALSE, FALSE, NULL);
7507     msiobj_release( &package->hdr );
7508
7509     if (path && (strlenW(path) > *pcchPathBuf))
7510     {
7511         *pcchPathBuf = strlenW(path)+1;
7512         rc = ERROR_MORE_DATA;
7513     }
7514     else if (path)
7515     {
7516         *pcchPathBuf = strlenW(path)+1;
7517         strcpyW(szPathBuf,path);
7518         TRACE("Returning Path %s\n",debugstr_w(path));
7519         rc = ERROR_SUCCESS;
7520     }
7521     HeapFree(GetProcessHeap(),0,path);
7522     
7523     return rc;
7524 }
7525
7526
7527 UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder, 
7528                                LPSTR szPathBuf, DWORD* pcchPathBuf) 
7529 {
7530     LPWSTR szwFolder;
7531     LPWSTR szwPathBuf;
7532     UINT rc;
7533
7534     TRACE("getting source %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
7535
7536     if (!szFolder)
7537         return ERROR_FUNCTION_FAILED;
7538     if (hInstall == 0)
7539         return ERROR_FUNCTION_FAILED;
7540
7541     szwFolder = strdupAtoW(szFolder);
7542     if (!szwFolder)
7543         return ERROR_FUNCTION_FAILED; 
7544
7545     szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
7546
7547     rc = MsiGetSourcePathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
7548
7549     WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
7550                          *pcchPathBuf, NULL, NULL );
7551
7552     HeapFree(GetProcessHeap(),0,szwFolder);
7553     HeapFree(GetProcessHeap(),0,szwPathBuf);
7554
7555     return rc;
7556 }
7557
7558 UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
7559                                 szPathBuf, DWORD* pcchPathBuf) 
7560 {
7561     LPWSTR path;
7562     UINT rc = ERROR_FUNCTION_FAILED;
7563     MSIPACKAGE *package;
7564
7565     TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
7566
7567     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
7568     if( !package )
7569         return ERROR_INVALID_HANDLE;
7570     path = resolve_folder(package, szFolder, TRUE, FALSE, NULL);
7571     msiobj_release( &package->hdr );
7572
7573     if (path && strlenW(path) > *pcchPathBuf)
7574     {
7575         *pcchPathBuf = strlenW(path)+1;
7576         rc = ERROR_MORE_DATA;
7577     }
7578     else if (path)
7579     {
7580         *pcchPathBuf = strlenW(path)+1;
7581         strcpyW(szPathBuf,path);
7582         TRACE("Returning Path %s\n",debugstr_w(path));
7583         rc = ERROR_SUCCESS;
7584     }
7585     HeapFree(GetProcessHeap(),0,path);
7586     
7587     return rc;
7588 }
7589
7590
7591 /***********************************************************************
7592  * MsiSetTargetPathA  (MSI.@)
7593  */
7594 UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder, 
7595                              LPCSTR szFolderPath)
7596 {
7597     LPWSTR szwFolder;
7598     LPWSTR szwFolderPath;
7599     UINT rc;
7600
7601     if (!szFolder)
7602         return ERROR_FUNCTION_FAILED;
7603     if (hInstall == 0)
7604         return ERROR_FUNCTION_FAILED;
7605
7606     szwFolder = strdupAtoW(szFolder);
7607     if (!szwFolder)
7608         return ERROR_FUNCTION_FAILED; 
7609
7610     szwFolderPath = strdupAtoW(szFolderPath);
7611     if (!szwFolderPath)
7612     {
7613         HeapFree(GetProcessHeap(),0,szwFolder);
7614         return ERROR_FUNCTION_FAILED; 
7615     }
7616
7617     rc = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath);
7618
7619     HeapFree(GetProcessHeap(),0,szwFolder);
7620     HeapFree(GetProcessHeap(),0,szwFolderPath);
7621
7622     return rc;
7623 }
7624
7625 UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder, 
7626                              LPCWSTR szFolderPath)
7627 {
7628     DWORD i;
7629     LPWSTR path = NULL;
7630     LPWSTR path2 = NULL;
7631     MSIFOLDER *folder;
7632
7633     TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
7634
7635     if (package==NULL)
7636         return ERROR_INVALID_HANDLE;
7637
7638     if (szFolderPath[0]==0)
7639         return ERROR_FUNCTION_FAILED;
7640
7641     if (GetFileAttributesW(szFolderPath) == INVALID_FILE_ATTRIBUTES)
7642         return ERROR_FUNCTION_FAILED;
7643
7644     path = resolve_folder(package,szFolder,FALSE,FALSE,&folder);
7645
7646     if (!path)
7647         return ERROR_INVALID_PARAMETER;
7648
7649     HeapFree(GetProcessHeap(),0,folder->Property);
7650     folder->Property = build_directory_name(2, szFolderPath, NULL);
7651
7652     if (lstrcmpiW(path, folder->Property) == 0)
7653     {
7654         /*
7655          *  Resolved Target has not really changed, so just 
7656          *  set this folder and do not recalculate everything.
7657          */
7658         HeapFree(GetProcessHeap(),0,folder->ResolvedTarget);
7659         folder->ResolvedTarget = NULL;
7660         path2 = resolve_folder(package,szFolder,FALSE,TRUE,NULL);
7661         HeapFree(GetProcessHeap(),0,path2);
7662     }
7663     else
7664     {
7665         for (i = 0; i < package->loaded_folders; i++)
7666         {
7667             HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
7668             package->folders[i].ResolvedTarget=NULL;
7669         }
7670
7671         for (i = 0; i < package->loaded_folders; i++)
7672         {
7673             path2=resolve_folder(package, package->folders[i].Directory, FALSE,
7674                        TRUE, NULL);
7675             HeapFree(GetProcessHeap(),0,path2);
7676         }
7677     }
7678     HeapFree(GetProcessHeap(),0,path);
7679
7680     return ERROR_SUCCESS;
7681 }
7682
7683 /***********************************************************************
7684  * MsiSetTargetPathW  (MSI.@)
7685  */
7686 UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder, 
7687                              LPCWSTR szFolderPath)
7688 {
7689     MSIPACKAGE *package;
7690     UINT ret;
7691
7692     TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
7693
7694     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
7695     ret = MSI_SetTargetPathW( package, szFolder, szFolderPath );
7696     msiobj_release( &package->hdr );
7697     return ret;
7698 }
7699
7700 /***********************************************************************
7701  *           MsiGetMode    (MSI.@)
7702  *
7703  * Returns an internal installer state (if it is running in a mode iRunMode)
7704  *
7705  * PARAMS
7706  *   hInstall    [I]  Handle to the installation
7707  *   hRunMode    [I]  Checking run mode
7708  *        MSIRUNMODE_ADMIN             Administrative mode
7709  *        MSIRUNMODE_ADVERTISE         Advertisement mode
7710  *        MSIRUNMODE_MAINTENANCE       Maintenance mode
7711  *        MSIRUNMODE_ROLLBACKENABLED   Rollback is enabled
7712  *        MSIRUNMODE_LOGENABLED        Log file is writing
7713  *        MSIRUNMODE_OPERATIONS        Operations in progress??
7714  *        MSIRUNMODE_REBOOTATEND       We need to reboot after installation completed
7715  *        MSIRUNMODE_REBOOTNOW         We need to reboot to continue the installation
7716  *        MSIRUNMODE_CABINET           Files from cabinet are installed
7717  *        MSIRUNMODE_SOURCESHORTNAMES  Long names in source files is suppressed
7718  *        MSIRUNMODE_TARGETSHORTNAMES  Long names in destination files is suppressed
7719  *        MSIRUNMODE_RESERVED11        Reserved
7720  *        MSIRUNMODE_WINDOWS9X         Running under Windows95/98
7721  *        MSIRUNMODE_ZAWENABLED        Demand installation is supported
7722  *        MSIRUNMODE_RESERVED14        Reserved
7723  *        MSIRUNMODE_RESERVED15        Reserved
7724  *        MSIRUNMODE_SCHEDULED         called from install script
7725  *        MSIRUNMODE_ROLLBACK          called from rollback script
7726  *        MSIRUNMODE_COMMIT            called from commit script
7727  *
7728  * RETURNS
7729  *    In the state: TRUE
7730  *    Not in the state: FALSE
7731  *
7732  */
7733
7734 BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
7735 {
7736     FIXME("STUB (iRunMode=%i)\n",iRunMode);
7737     return TRUE;
7738 }
7739
7740 /***********************************************************************
7741  * MsiSetFeatureStateA (MSI.@)
7742  *
7743  * According to the docs, when this is called it immediately recalculates
7744  * all the component states as well
7745  */
7746 UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
7747                                 INSTALLSTATE iState)
7748 {
7749     LPWSTR szwFeature = NULL;
7750     UINT rc;
7751
7752     szwFeature = strdupAtoW(szFeature);
7753
7754     if (!szwFeature)
7755         return ERROR_FUNCTION_FAILED;
7756    
7757     rc = MsiSetFeatureStateW(hInstall,szwFeature, iState); 
7758
7759     HeapFree(GetProcessHeap(),0,szwFeature);
7760
7761     return rc;
7762 }
7763
7764
7765
7766 UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature,
7767                                 INSTALLSTATE iState)
7768 {
7769     INT index, i;
7770     UINT rc = ERROR_SUCCESS;
7771
7772     TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
7773
7774     index = get_loaded_feature(package,szFeature);
7775     if (index < 0)
7776         return ERROR_UNKNOWN_FEATURE;
7777
7778     if (iState == INSTALLSTATE_ADVERTISED && 
7779         package->features[index].Attributes & 
7780             msidbFeatureAttributesDisallowAdvertise)
7781         return ERROR_FUNCTION_FAILED;
7782
7783     package->features[index].ActionRequest= iState;
7784     package->features[index].Action= iState;
7785
7786     ACTION_UpdateComponentStates(package,szFeature);
7787
7788     /* update all the features that are children of this feature */
7789     for (i = 0; i < package->loaded_features; i++)
7790     {
7791         if (strcmpW(szFeature, package->features[i].Feature_Parent) == 0)
7792             MSI_SetFeatureStateW(package, package->features[i].Feature, iState);
7793     }
7794     
7795     return rc;
7796 }
7797
7798 /***********************************************************************
7799  * MsiSetFeatureStateW (MSI.@)
7800  */
7801 UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
7802                                 INSTALLSTATE iState)
7803 {
7804     MSIPACKAGE* package;
7805     UINT rc = ERROR_SUCCESS;
7806
7807     TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
7808
7809     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
7810     if (!package)
7811         return ERROR_INVALID_HANDLE;
7812
7813     rc = MSI_SetFeatureStateW(package,szFeature,iState);
7814
7815     msiobj_release( &package->hdr );
7816     return rc;
7817 }
7818
7819 UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPSTR szFeature,
7820                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
7821 {
7822     LPWSTR szwFeature = NULL;
7823     UINT rc;
7824     
7825     szwFeature = strdupAtoW(szFeature);
7826
7827     rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction);
7828
7829     HeapFree( GetProcessHeap(), 0 , szwFeature);
7830
7831     return rc;
7832 }
7833
7834 UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature,
7835                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
7836 {
7837     INT index;
7838
7839     index = get_loaded_feature(package,szFeature);
7840     if (index < 0)
7841         return ERROR_UNKNOWN_FEATURE;
7842
7843     if (piInstalled)
7844         *piInstalled = package->features[index].Installed;
7845
7846     if (piAction)
7847         *piAction = package->features[index].Action;
7848
7849     TRACE("returning %i %i\n",*piInstalled,*piAction);
7850
7851     return ERROR_SUCCESS;
7852 }
7853
7854 UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPWSTR szFeature,
7855                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
7856 {
7857     MSIPACKAGE* package;
7858     UINT ret;
7859
7860     TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled,
7861 piAction);
7862
7863     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
7864     if (!package)
7865         return ERROR_INVALID_HANDLE;
7866     ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction);
7867     msiobj_release( &package->hdr );
7868     return ret;
7869 }
7870
7871 /***********************************************************************
7872  * MsiGetComponentStateA (MSI.@)
7873  */
7874 UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPSTR szComponent,
7875                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
7876 {
7877     LPWSTR szwComponent= NULL;
7878     UINT rc;
7879     
7880     szwComponent= strdupAtoW(szComponent);
7881
7882     rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);
7883
7884     HeapFree( GetProcessHeap(), 0 , szwComponent);
7885
7886     return rc;
7887 }
7888
7889 UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPWSTR szComponent,
7890                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
7891 {
7892     INT index;
7893
7894     TRACE("%p %s %p %p\n", package, debugstr_w(szComponent), piInstalled,
7895 piAction);
7896
7897     index = get_loaded_component(package,szComponent);
7898     if (index < 0)
7899         return ERROR_UNKNOWN_COMPONENT;
7900
7901     if (piInstalled)
7902         *piInstalled = package->components[index].Installed;
7903
7904     if (piAction)
7905         *piAction = package->components[index].Action;
7906
7907     TRACE("states (%i, %i)\n",
7908 (piInstalled)?*piInstalled:-1,(piAction)?*piAction:-1);
7909
7910     return ERROR_SUCCESS;
7911 }
7912
7913 /***********************************************************************
7914  * MsiGetComponentStateW (MSI.@)
7915  */
7916 UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPWSTR szComponent,
7917                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
7918 {
7919     MSIPACKAGE* package;
7920     UINT ret;
7921
7922     TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szComponent),
7923            piInstalled, piAction);
7924
7925     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
7926     if (!package)
7927         return ERROR_INVALID_HANDLE;
7928     ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);
7929     msiobj_release( &package->hdr );
7930     return ret;
7931 }