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