xref: /reactos/dll/win32/msi/package.c (revision c7bba39a)
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2004 Aric Stewart for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #define NONAMELESSUNION
22 #define NONAMELESSSTRUCT
23 #define COBJMACROS
24 
25 #include <stdarg.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "winnls.h"
30 #include "shlwapi.h"
31 #include "wingdi.h"
32 #include "wine/debug.h"
33 #include "msi.h"
34 #include "msiquery.h"
35 #include "objidl.h"
36 #include "wincrypt.h"
37 #include "winuser.h"
38 #include "wininet.h"
39 #include "winver.h"
40 #include "urlmon.h"
41 #include "shlobj.h"
42 #include "wine/unicode.h"
43 #include "objbase.h"
44 #include "msidefs.h"
45 #include "sddl.h"
46 
47 #include "msipriv.h"
48 #include "msiserver.h"
49 #include "resource.h"
50 
51 WINE_DEFAULT_DEBUG_CHANNEL(msi);
52 
53 static void free_feature( MSIFEATURE *feature )
54 {
55     struct list *item, *cursor;
56 
57     LIST_FOR_EACH_SAFE( item, cursor, &feature->Children )
58     {
59         FeatureList *fl = LIST_ENTRY( item, FeatureList, entry );
60         list_remove( &fl->entry );
61         msi_free( fl );
62     }
63 
64     LIST_FOR_EACH_SAFE( item, cursor, &feature->Components )
65     {
66         ComponentList *cl = LIST_ENTRY( item, ComponentList, entry );
67         list_remove( &cl->entry );
68         msi_free( cl );
69     }
70     msi_free( feature->Feature );
71     msi_free( feature->Feature_Parent );
72     msi_free( feature->Directory );
73     msi_free( feature->Description );
74     msi_free( feature->Title );
75     msi_free( feature );
76 }
77 
78 static void free_folder( MSIFOLDER *folder )
79 {
80     struct list *item, *cursor;
81 
82     LIST_FOR_EACH_SAFE( item, cursor, &folder->children )
83     {
84         FolderList *fl = LIST_ENTRY( item, FolderList, entry );
85         list_remove( &fl->entry );
86         msi_free( fl );
87     }
88     msi_free( folder->Parent );
89     msi_free( folder->Directory );
90     msi_free( folder->TargetDefault );
91     msi_free( folder->SourceLongPath );
92     msi_free( folder->SourceShortPath );
93     msi_free( folder->ResolvedTarget );
94     msi_free( folder->ResolvedSource );
95     msi_free( folder );
96 }
97 
98 static void free_extension( MSIEXTENSION *ext )
99 {
100     struct list *item, *cursor;
101 
102     LIST_FOR_EACH_SAFE( item, cursor, &ext->verbs )
103     {
104         MSIVERB *verb = LIST_ENTRY( item, MSIVERB, entry );
105 
106         list_remove( &verb->entry );
107         msi_free( verb->Verb );
108         msi_free( verb->Command );
109         msi_free( verb->Argument );
110         msi_free( verb );
111     }
112 
113     msi_free( ext->Extension );
114     msi_free( ext->ProgIDText );
115     msi_free( ext );
116 }
117 
118 static void free_assembly( MSIASSEMBLY *assembly )
119 {
120     msi_free( assembly->feature );
121     msi_free( assembly->manifest );
122     msi_free( assembly->application );
123     msi_free( assembly->display_name );
124     if (assembly->tempdir) RemoveDirectoryW( assembly->tempdir );
125     msi_free( assembly->tempdir );
126     msi_free( assembly );
127 }
128 
129 void msi_free_action_script( MSIPACKAGE *package, UINT script )
130 {
131     UINT i;
132     for (i = 0; i < package->script_actions_count[script]; i++)
133         msi_free( package->script_actions[script][i] );
134 
135     msi_free( package->script_actions[script] );
136     package->script_actions[script] = NULL;
137     package->script_actions_count[script] = 0;
138 }
139 
140 static void free_package_structures( MSIPACKAGE *package )
141 {
142     struct list *item, *cursor;
143     int i;
144 
145     LIST_FOR_EACH_SAFE( item, cursor, &package->features )
146     {
147         MSIFEATURE *feature = LIST_ENTRY( item, MSIFEATURE, entry );
148         list_remove( &feature->entry );
149         free_feature( feature );
150     }
151 
152     LIST_FOR_EACH_SAFE( item, cursor, &package->folders )
153     {
154         MSIFOLDER *folder = LIST_ENTRY( item, MSIFOLDER, entry );
155         list_remove( &folder->entry );
156         free_folder( folder );
157     }
158 
159     LIST_FOR_EACH_SAFE( item, cursor, &package->files )
160     {
161         MSIFILE *file = LIST_ENTRY( item, MSIFILE, entry );
162 
163         list_remove( &file->entry );
164         msi_free( file->File );
165         msi_free( file->FileName );
166         msi_free( file->ShortName );
167         msi_free( file->LongName );
168         msi_free( file->Version );
169         msi_free( file->Language );
170         if (msi_is_global_assembly( file->Component )) DeleteFileW( file->TargetPath );
171         msi_free( file->TargetPath );
172         msi_free( file );
173     }
174 
175     LIST_FOR_EACH_SAFE( item, cursor, &package->components )
176     {
177         MSICOMPONENT *comp = LIST_ENTRY( item, MSICOMPONENT, entry );
178 
179         list_remove( &comp->entry );
180         msi_free( comp->Component );
181         msi_free( comp->ComponentId );
182         msi_free( comp->Directory );
183         msi_free( comp->Condition );
184         msi_free( comp->KeyPath );
185         msi_free( comp->FullKeypath );
186         if (comp->assembly) free_assembly( comp->assembly );
187         msi_free( comp );
188     }
189 
190     LIST_FOR_EACH_SAFE( item, cursor, &package->filepatches )
191     {
192         MSIFILEPATCH *patch = LIST_ENTRY( item, MSIFILEPATCH, entry );
193 
194         list_remove( &patch->entry );
195         msi_free( patch->path );
196         msi_free( patch );
197     }
198 
199     /* clean up extension, progid, class and verb structures */
200     LIST_FOR_EACH_SAFE( item, cursor, &package->classes )
201     {
202         MSICLASS *cls = LIST_ENTRY( item, MSICLASS, entry );
203 
204         list_remove( &cls->entry );
205         msi_free( cls->clsid );
206         msi_free( cls->Context );
207         msi_free( cls->Description );
208         msi_free( cls->FileTypeMask );
209         msi_free( cls->IconPath );
210         msi_free( cls->DefInprocHandler );
211         msi_free( cls->DefInprocHandler32 );
212         msi_free( cls->Argument );
213         msi_free( cls->ProgIDText );
214         msi_free( cls );
215     }
216 
217     LIST_FOR_EACH_SAFE( item, cursor, &package->extensions )
218     {
219         MSIEXTENSION *ext = LIST_ENTRY( item, MSIEXTENSION, entry );
220 
221         list_remove( &ext->entry );
222         free_extension( ext );
223     }
224 
225     LIST_FOR_EACH_SAFE( item, cursor, &package->progids )
226     {
227         MSIPROGID *progid = LIST_ENTRY( item, MSIPROGID, entry );
228 
229         list_remove( &progid->entry );
230         msi_free( progid->ProgID );
231         msi_free( progid->Description );
232         msi_free( progid->IconPath );
233         msi_free( progid );
234     }
235 
236     LIST_FOR_EACH_SAFE( item, cursor, &package->mimes )
237     {
238         MSIMIME *mt = LIST_ENTRY( item, MSIMIME, entry );
239 
240         list_remove( &mt->entry );
241         msi_free( mt->suffix );
242         msi_free( mt->clsid );
243         msi_free( mt->ContentType );
244         msi_free( mt );
245     }
246 
247     LIST_FOR_EACH_SAFE( item, cursor, &package->appids )
248     {
249         MSIAPPID *appid = LIST_ENTRY( item, MSIAPPID, entry );
250 
251         list_remove( &appid->entry );
252         msi_free( appid->AppID );
253         msi_free( appid->RemoteServerName );
254         msi_free( appid->LocalServer );
255         msi_free( appid->ServiceParameters );
256         msi_free( appid->DllSurrogate );
257         msi_free( appid );
258     }
259 
260     LIST_FOR_EACH_SAFE( item, cursor, &package->sourcelist_info )
261     {
262         MSISOURCELISTINFO *info = LIST_ENTRY( item, MSISOURCELISTINFO, entry );
263 
264         list_remove( &info->entry );
265         msi_free( info->value );
266         msi_free( info );
267     }
268 
269     LIST_FOR_EACH_SAFE( item, cursor, &package->sourcelist_media )
270     {
271         MSIMEDIADISK *info = LIST_ENTRY( item, MSIMEDIADISK, entry );
272 
273         list_remove( &info->entry );
274         msi_free( info->volume_label );
275         msi_free( info->disk_prompt );
276         msi_free( info );
277     }
278 
279     for (i = 0; i < SCRIPT_MAX; i++)
280         msi_free_action_script( package, i );
281 
282     for (i = 0; i < package->unique_actions_count; i++)
283         msi_free( package->unique_actions[i] );
284     msi_free( package->unique_actions);
285 
286     LIST_FOR_EACH_SAFE( item, cursor, &package->binaries )
287     {
288         MSIBINARY *binary = LIST_ENTRY( item, MSIBINARY, entry );
289 
290         list_remove( &binary->entry );
291         if (binary->module)
292             FreeLibrary( binary->module );
293         if (!DeleteFileW( binary->tmpfile ))
294             ERR("failed to delete %s (%u)\n", debugstr_w(binary->tmpfile), GetLastError());
295         msi_free( binary->source );
296         msi_free( binary->tmpfile );
297         msi_free( binary );
298     }
299 
300     LIST_FOR_EACH_SAFE( item, cursor, &package->cabinet_streams )
301     {
302         MSICABINETSTREAM *cab = LIST_ENTRY( item, MSICABINETSTREAM, entry );
303 
304         list_remove( &cab->entry );
305         IStorage_Release( cab->storage );
306         msi_free( cab->stream );
307         msi_free( cab );
308     }
309 
310     LIST_FOR_EACH_SAFE( item, cursor, &package->patches )
311     {
312         MSIPATCHINFO *patch = LIST_ENTRY( item, MSIPATCHINFO, entry );
313 
314         list_remove( &patch->entry );
315         if (patch->delete_on_close && !DeleteFileW( patch->localfile ))
316         {
317             ERR("failed to delete %s (%u)\n", debugstr_w(patch->localfile), GetLastError());
318         }
319         msi_free_patchinfo( patch );
320     }
321 
322     msi_free( package->BaseURL );
323     msi_free( package->PackagePath );
324     msi_free( package->ProductCode );
325     msi_free( package->ActionFormat );
326     msi_free( package->LastAction );
327     msi_free( package->LastActionTemplate );
328     msi_free( package->langids );
329 
330     /* cleanup control event subscriptions */
331     msi_event_cleanup_all_subscriptions( package );
332 }
333 
334 static void MSI_FreePackage( MSIOBJECTHDR *arg)
335 {
336     MSIPACKAGE *package = (MSIPACKAGE *)arg;
337 
338     msi_destroy_assembly_caches( package );
339 
340     if( package->dialog )
341         msi_dialog_destroy( package->dialog );
342 
343     msiobj_release( &package->db->hdr );
344     free_package_structures(package);
345     CloseHandle( package->log_file );
346 
347     if (package->delete_on_close) DeleteFileW( package->localfile );
348     msi_free( package->localfile );
349     MSI_ProcessMessage(NULL, INSTALLMESSAGE_TERMINATE, 0);
350 }
351 
352 static UINT create_temp_property_table(MSIPACKAGE *package)
353 {
354     static const WCHAR query[] = {
355         'C','R','E','A','T','E',' ','T','A','B','L','E',' ',
356         '`','_','P','r','o','p','e','r','t','y','`',' ','(',' ',
357         '`','_','P','r','o','p','e','r','t','y','`',' ',
358         'C','H','A','R','(','5','6',')',' ','N','O','T',' ','N','U','L','L',' ',
359         'T','E','M','P','O','R','A','R','Y',',',' ',
360         '`','V','a','l','u','e','`',' ','C','H','A','R','(','9','8',')',' ',
361         'N','O','T',' ','N','U','L','L',' ','T','E','M','P','O','R','A','R','Y',
362         ' ','P','R','I','M','A','R','Y',' ','K','E','Y',' ',
363         '`','_','P','r','o','p','e','r','t','y','`',')',' ','H','O','L','D',0};
364     MSIQUERY *view;
365     UINT rc;
366 
367     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
368     if (rc != ERROR_SUCCESS)
369         return rc;
370 
371     rc = MSI_ViewExecute(view, 0);
372     MSI_ViewClose(view);
373     msiobj_release(&view->hdr);
374     return rc;
375 }
376 
377 UINT msi_clone_properties( MSIDATABASE *db )
378 {
379     static const WCHAR query_select[] = {
380         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
381         '`','P','r','o','p','e','r','t','y','`',0};
382     static const WCHAR query_insert[] = {
383         'I','N','S','E','R','T',' ','I','N','T','O',' ',
384         '`','_','P','r','o','p','e','r','t','y','`',' ',
385         '(','`','_','P','r','o','p','e','r','t','y','`',',','`','V','a','l','u','e','`',')',' ',
386         'V','A','L','U','E','S',' ','(','?',',','?',')',0};
387     static const WCHAR query_update[] = {
388         'U','P','D','A','T','E',' ','`','_','P','r','o','p','e','r','t','y','`',' ',
389         'S','E','T',' ','`','V','a','l','u','e','`',' ','=',' ','?',' ',
390         'W','H','E','R','E',' ','`','_','P','r','o','p','e','r','t','y','`',' ','=',' ','?',0};
391     MSIQUERY *view_select;
392     UINT rc;
393 
394     rc = MSI_DatabaseOpenViewW( db, query_select, &view_select );
395     if (rc != ERROR_SUCCESS)
396         return rc;
397 
398     rc = MSI_ViewExecute( view_select, 0 );
399     if (rc != ERROR_SUCCESS)
400     {
401         MSI_ViewClose( view_select );
402         msiobj_release( &view_select->hdr );
403         return rc;
404     }
405 
406     while (1)
407     {
408         MSIQUERY *view_insert, *view_update;
409         MSIRECORD *rec_select;
410 
411         rc = MSI_ViewFetch( view_select, &rec_select );
412         if (rc != ERROR_SUCCESS)
413             break;
414 
415         rc = MSI_DatabaseOpenViewW( db, query_insert, &view_insert );
416         if (rc != ERROR_SUCCESS)
417         {
418             msiobj_release( &rec_select->hdr );
419             continue;
420         }
421 
422         rc = MSI_ViewExecute( view_insert, rec_select );
423         MSI_ViewClose( view_insert );
424         msiobj_release( &view_insert->hdr );
425         if (rc != ERROR_SUCCESS)
426         {
427             MSIRECORD *rec_update;
428 
429             TRACE("insert failed, trying update\n");
430 
431             rc = MSI_DatabaseOpenViewW( db, query_update, &view_update );
432             if (rc != ERROR_SUCCESS)
433             {
434                 WARN("open view failed %u\n", rc);
435                 msiobj_release( &rec_select->hdr );
436                 continue;
437             }
438 
439             rec_update = MSI_CreateRecord( 2 );
440             MSI_RecordCopyField( rec_select, 1, rec_update, 2 );
441             MSI_RecordCopyField( rec_select, 2, rec_update, 1 );
442             rc = MSI_ViewExecute( view_update, rec_update );
443             if (rc != ERROR_SUCCESS)
444                 WARN("update failed %u\n", rc);
445 
446             MSI_ViewClose( view_update );
447             msiobj_release( &view_update->hdr );
448             msiobj_release( &rec_update->hdr );
449         }
450 
451         msiobj_release( &rec_select->hdr );
452     }
453 
454     MSI_ViewClose( view_select );
455     msiobj_release( &view_select->hdr );
456     return rc;
457 }
458 
459 /*
460  * set_installed_prop
461  *
462  * Sets the "Installed" property to indicate that
463  *  the product is installed for the current user.
464  */
465 static UINT set_installed_prop( MSIPACKAGE *package )
466 {
467     HKEY hkey;
468     UINT r;
469 
470     if (!package->ProductCode) return ERROR_FUNCTION_FAILED;
471 
472     r = MSIREG_OpenUninstallKey( package->ProductCode, package->platform, &hkey, FALSE );
473     if (r == ERROR_SUCCESS)
474     {
475         RegCloseKey( hkey );
476         msi_set_property( package->db, szInstalled, szOne, -1 );
477     }
478     return r;
479 }
480 
481 static UINT set_user_sid_prop( MSIPACKAGE *package )
482 {
483     SID_NAME_USE use;
484     LPWSTR user_name;
485     LPWSTR sid_str = NULL, dom = NULL;
486     DWORD size, dom_size;
487     PSID psid = NULL;
488     UINT r = ERROR_FUNCTION_FAILED;
489 
490     size = 0;
491     GetUserNameW( NULL, &size );
492 
493     user_name = msi_alloc( (size + 1) * sizeof(WCHAR) );
494     if (!user_name)
495         return ERROR_OUTOFMEMORY;
496 
497     if (!GetUserNameW( user_name, &size ))
498         goto done;
499 
500     size = 0;
501     dom_size = 0;
502     LookupAccountNameW( NULL, user_name, NULL, &size, NULL, &dom_size, &use );
503 
504     psid = msi_alloc( size );
505     dom = msi_alloc( dom_size*sizeof (WCHAR) );
506     if (!psid || !dom)
507     {
508         r = ERROR_OUTOFMEMORY;
509         goto done;
510     }
511 
512     if (!LookupAccountNameW( NULL, user_name, psid, &size, dom, &dom_size, &use ))
513         goto done;
514 
515     if (!ConvertSidToStringSidW( psid, &sid_str ))
516         goto done;
517 
518     r = msi_set_property( package->db, szUserSID, sid_str, -1 );
519 
520 done:
521     LocalFree( sid_str );
522     msi_free( dom );
523     msi_free( psid );
524     msi_free( user_name );
525 
526     return r;
527 }
528 
529 static LPWSTR get_fusion_filename(MSIPACKAGE *package)
530 {
531     static const WCHAR fusion[] =
532         {'f','u','s','i','o','n','.','d','l','l',0};
533     static const WCHAR subkey[] =
534         {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
535          'N','E','T',' ','F','r','a','m','e','w','o','r','k',' ','S','e','t','u','p','\\','N','D','P',0};
536     static const WCHAR subdir[] =
537         {'M','i','c','r','o','s','o','f','t','.','N','E','T','\\','F','r','a','m','e','w','o','r','k','\\',0};
538     static const WCHAR v2050727[] =
539         {'v','2','.','0','.','5','0','7','2','7',0};
540     static const WCHAR v4client[] =
541         {'v','4','\\','C','l','i','e','n','t',0};
542     static const WCHAR installpath[] =
543         {'I','n','s','t','a','l','l','P','a','t','h',0};
544     HKEY netsetup, hkey;
545     LONG res;
546     DWORD size, len, type;
547     WCHAR windir[MAX_PATH], path[MAX_PATH], *filename = NULL;
548 
549     res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, subkey, 0, KEY_CREATE_SUB_KEY, &netsetup);
550     if (res != ERROR_SUCCESS)
551         return NULL;
552 
553     if (!RegCreateKeyExW(netsetup, v4client, 0, NULL, 0, KEY_QUERY_VALUE, NULL, &hkey, NULL))
554     {
555         size = sizeof(path)/sizeof(path[0]);
556         if (!RegQueryValueExW(hkey, installpath, NULL, &type, (BYTE *)path, &size))
557         {
558             len = strlenW(path) + strlenW(fusion) + 2;
559             if (!(filename = msi_alloc(len * sizeof(WCHAR)))) return NULL;
560 
561             strcpyW(filename, path);
562             strcatW(filename, szBackSlash);
563             strcatW(filename, fusion);
564             if (GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
565             {
566                 TRACE( "found %s\n", debugstr_w(filename) );
567                 RegCloseKey(hkey);
568                 RegCloseKey(netsetup);
569                 return filename;
570             }
571         }
572         RegCloseKey(hkey);
573     }
574 
575     if (!RegCreateKeyExW(netsetup, v2050727, 0, NULL, 0, KEY_QUERY_VALUE, NULL, &hkey, NULL))
576     {
577         RegCloseKey(hkey);
578         GetWindowsDirectoryW(windir, MAX_PATH);
579         len = strlenW(windir) + strlenW(subdir) + strlenW(v2050727) + strlenW(fusion) + 3;
580         if (!(filename = msi_alloc(len * sizeof(WCHAR)))) return NULL;
581 
582         strcpyW(filename, windir);
583         strcatW(filename, szBackSlash);
584         strcatW(filename, subdir);
585         strcatW(filename, v2050727);
586         strcatW(filename, szBackSlash);
587         strcatW(filename, fusion);
588         if (GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
589         {
590             TRACE( "found %s\n", debugstr_w(filename) );
591             RegCloseKey(netsetup);
592             return filename;
593         }
594     }
595 
596     RegCloseKey(netsetup);
597     return filename;
598 }
599 
600 typedef struct tagLANGANDCODEPAGE
601 {
602   WORD wLanguage;
603   WORD wCodePage;
604 } LANGANDCODEPAGE;
605 
606 static void set_msi_assembly_prop(MSIPACKAGE *package)
607 {
608     UINT val_len;
609     DWORD size, handle;
610     LPVOID version = NULL;
611     WCHAR buf[MAX_PATH];
612     LPWSTR fusion, verstr;
613     LANGANDCODEPAGE *translate;
614 
615     static const WCHAR netasm[] = {
616         'M','s','i','N','e','t','A','s','s','e','m','b','l','y','S','u','p','p','o','r','t',0
617     };
618     static const WCHAR translation[] = {
619         '\\','V','a','r','F','i','l','e','I','n','f','o',
620         '\\','T','r','a','n','s','l','a','t','i','o','n',0
621     };
622     static const WCHAR verfmt[] = {
623         '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
624         '\\','%','0','4','x','%','0','4','x',
625         '\\','P','r','o','d','u','c','t','V','e','r','s','i','o','n',0
626     };
627 
628     fusion = get_fusion_filename(package);
629     if (!fusion)
630         return;
631 
632     size = GetFileVersionInfoSizeW(fusion, &handle);
633     if (!size)
634         goto done;
635 
636     version = msi_alloc(size);
637     if (!version)
638         goto done;
639 
640     if (!GetFileVersionInfoW(fusion, handle, size, version))
641         goto done;
642 
643     if (!VerQueryValueW(version, translation, (LPVOID *)&translate, &val_len))
644         goto done;
645 
646     sprintfW(buf, verfmt, translate[0].wLanguage, translate[0].wCodePage);
647 
648     if (!VerQueryValueW(version, buf, (LPVOID *)&verstr, &val_len))
649         goto done;
650 
651     if (!val_len || !verstr)
652         goto done;
653 
654     msi_set_property( package->db, netasm, verstr, -1 );
655 
656 done:
657     msi_free(fusion);
658     msi_free(version);
659 }
660 
661 static VOID set_installer_properties(MSIPACKAGE *package)
662 {
663     WCHAR *ptr;
664     OSVERSIONINFOEXW OSVersion;
665     MEMORYSTATUSEX msex;
666     DWORD verval, len;
667     WCHAR pth[MAX_PATH], verstr[11], bufstr[22];
668     HDC dc;
669     HKEY hkey;
670     LPWSTR username, companyname;
671     SYSTEM_INFO sys_info;
672     LANGID langid;
673 
674     static const WCHAR szCommonFilesFolder[] = {'C','o','m','m','o','n','F','i','l','e','s','F','o','l','d','e','r',0};
675     static const WCHAR szProgramFilesFolder[] = {'P','r','o','g','r','a','m','F','i','l','e','s','F','o','l','d','e','r',0};
676     static const WCHAR szCommonAppDataFolder[] = {'C','o','m','m','o','n','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
677     static const WCHAR szFavoritesFolder[] = {'F','a','v','o','r','i','t','e','s','F','o','l','d','e','r',0};
678     static const WCHAR szFontsFolder[] = {'F','o','n','t','s','F','o','l','d','e','r',0};
679     static const WCHAR szSendToFolder[] = {'S','e','n','d','T','o','F','o','l','d','e','r',0};
680     static const WCHAR szStartMenuFolder[] = {'S','t','a','r','t','M','e','n','u','F','o','l','d','e','r',0};
681     static const WCHAR szStartupFolder[] = {'S','t','a','r','t','u','p','F','o','l','d','e','r',0};
682     static const WCHAR szTemplateFolder[] = {'T','e','m','p','l','a','t','e','F','o','l','d','e','r',0};
683     static const WCHAR szDesktopFolder[] = {'D','e','s','k','t','o','p','F','o','l','d','e','r',0};
684     static const WCHAR szProgramMenuFolder[] = {'P','r','o','g','r','a','m','M','e','n','u','F','o','l','d','e','r',0};
685     static const WCHAR szAdminToolsFolder[] = {'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0};
686     static const WCHAR szSystemFolder[] = {'S','y','s','t','e','m','F','o','l','d','e','r',0};
687     static const WCHAR szSystem16Folder[] = {'S','y','s','t','e','m','1','6','F','o','l','d','e','r',0};
688     static const WCHAR szLocalAppDataFolder[] = {'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
689     static const WCHAR szMyPicturesFolder[] = {'M','y','P','i','c','t','u','r','e','s','F','o','l','d','e','r',0};
690     static const WCHAR szPersonalFolder[] = {'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0};
691     static const WCHAR szWindowsVolume[] = {'W','i','n','d','o','w','s','V','o','l','u','m','e',0};
692     static const WCHAR szPrivileged[] = {'P','r','i','v','i','l','e','g','e','d',0};
693     static const WCHAR szVersion9x[] = {'V','e','r','s','i','o','n','9','X',0};
694     static const WCHAR szVersionNT[] = {'V','e','r','s','i','o','n','N','T',0};
695     static const WCHAR szMsiNTProductType[] = {'M','s','i','N','T','P','r','o','d','u','c','t','T','y','p','e',0};
696     static const WCHAR szFormat[] = {'%','u',0};
697     static const WCHAR szFormat2[] = {'%','u','.','%','u',0};
698     static const WCHAR szWindowsBuild[] = {'W','i','n','d','o','w','s','B','u','i','l','d',0};
699     static const WCHAR szServicePackLevel[] = {'S','e','r','v','i','c','e','P','a','c','k','L','e','v','e','l',0};
700     static const WCHAR szVersionMsi[] = { 'V','e','r','s','i','o','n','M','s','i',0 };
701     static const WCHAR szVersionDatabase[] = { 'V','e','r','s','i','o','n','D','a','t','a','b','a','s','e',0 };
702     static const WCHAR szPhysicalMemory[] = { 'P','h','y','s','i','c','a','l','M','e','m','o','r','y',0 };
703     static const WCHAR szScreenX[] = {'S','c','r','e','e','n','X',0};
704     static const WCHAR szScreenY[] = {'S','c','r','e','e','n','Y',0};
705     static const WCHAR szColorBits[] = {'C','o','l','o','r','B','i','t','s',0};
706     static const WCHAR szIntFormat[] = {'%','d',0};
707     static const WCHAR szMsiAMD64[] = { 'M','s','i','A','M','D','6','4',0 };
708     static const WCHAR szMsix64[] = { 'M','s','i','x','6','4',0 };
709     static const WCHAR szSystem64Folder[] = { 'S','y','s','t','e','m','6','4','F','o','l','d','e','r',0 };
710     static const WCHAR szCommonFiles64Folder[] = { 'C','o','m','m','o','n','F','i','l','e','s','6','4','F','o','l','d','e','r',0 };
711     static const WCHAR szProgramFiles64Folder[] = { 'P','r','o','g','r','a','m','F','i','l','e','s','6','4','F','o','l','d','e','r',0 };
712     static const WCHAR szVersionNT64[] = { 'V','e','r','s','i','o','n','N','T','6','4',0 };
713     static const WCHAR szUserInfo[] = {
714         'S','O','F','T','W','A','R','E','\\',
715         'M','i','c','r','o','s','o','f','t','\\',
716         'M','S',' ','S','e','t','u','p',' ','(','A','C','M','E',')','\\',
717         'U','s','e','r',' ','I','n','f','o',0
718     };
719     static const WCHAR szDefName[] = { 'D','e','f','N','a','m','e',0 };
720     static const WCHAR szDefCompany[] = { 'D','e','f','C','o','m','p','a','n','y',0 };
721     static const WCHAR szCurrentVersion[] = {
722         'S','O','F','T','W','A','R','E','\\',
723         'M','i','c','r','o','s','o','f','t','\\',
724         'W','i','n','d','o','w','s',' ','N','T','\\',
725         'C','u','r','r','e','n','t','V','e','r','s','i','o','n',0
726     };
727     static const WCHAR szRegisteredUser[] = {'R','e','g','i','s','t','e','r','e','d','O','w','n','e','r',0};
728     static const WCHAR szRegisteredOrganization[] = {
729         'R','e','g','i','s','t','e','r','e','d','O','r','g','a','n','i','z','a','t','i','o','n',0
730     };
731     static const WCHAR szUSERNAME[] = {'U','S','E','R','N','A','M','E',0};
732     static const WCHAR szCOMPANYNAME[] = {'C','O','M','P','A','N','Y','N','A','M','E',0};
733     static const WCHAR szUserLanguageID[] = {'U','s','e','r','L','a','n','g','u','a','g','e','I','D',0};
734     static const WCHAR szSystemLangID[] = {'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0};
735     static const WCHAR szProductState[] = {'P','r','o','d','u','c','t','S','t','a','t','e',0};
736     static const WCHAR szLogonUser[] = {'L','o','g','o','n','U','s','e','r',0};
737     static const WCHAR szNetHoodFolder[] = {'N','e','t','H','o','o','d','F','o','l','d','e','r',0};
738     static const WCHAR szPrintHoodFolder[] = {'P','r','i','n','t','H','o','o','d','F','o','l','d','e','r',0};
739     static const WCHAR szRecentFolder[] = {'R','e','c','e','n','t','F','o','l','d','e','r',0};
740     static const WCHAR szComputerName[] = {'C','o','m','p','u','t','e','r','N','a','m','e',0};
741 
742     /*
743      * Other things that probably should be set:
744      *
745      * VirtualMemory ShellAdvSupport DefaultUIFont PackagecodeChanging
746      * CaptionHeight BorderTop BorderSide TextHeight RedirectedDllSupport
747      */
748 
749     SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA, NULL, 0, pth);
750     strcatW(pth, szBackSlash);
751     msi_set_property( package->db, szCommonAppDataFolder, pth, -1 );
752 
753     SHGetFolderPathW(NULL, CSIDL_FAVORITES, NULL, 0, pth);
754     strcatW(pth, szBackSlash);
755     msi_set_property( package->db, szFavoritesFolder, pth, -1 );
756 
757     SHGetFolderPathW(NULL, CSIDL_FONTS, NULL, 0, pth);
758     strcatW(pth, szBackSlash);
759     msi_set_property( package->db, szFontsFolder, pth, -1 );
760 
761     SHGetFolderPathW(NULL, CSIDL_SENDTO, NULL, 0, pth);
762     strcatW(pth, szBackSlash);
763     msi_set_property( package->db, szSendToFolder, pth, -1 );
764 
765     SHGetFolderPathW(NULL, CSIDL_STARTMENU, NULL, 0, pth);
766     strcatW(pth, szBackSlash);
767     msi_set_property( package->db, szStartMenuFolder, pth, -1 );
768 
769     SHGetFolderPathW(NULL, CSIDL_STARTUP, NULL, 0, pth);
770     strcatW(pth, szBackSlash);
771     msi_set_property( package->db, szStartupFolder, pth, -1 );
772 
773     SHGetFolderPathW(NULL, CSIDL_TEMPLATES, NULL, 0, pth);
774     strcatW(pth, szBackSlash);
775     msi_set_property( package->db, szTemplateFolder, pth, -1 );
776 
777     SHGetFolderPathW(NULL, CSIDL_DESKTOP, NULL, 0, pth);
778     strcatW(pth, szBackSlash);
779     msi_set_property( package->db, szDesktopFolder, pth, -1 );
780 
781     /* FIXME: set to AllUsers profile path if ALLUSERS is set */
782     SHGetFolderPathW(NULL, CSIDL_PROGRAMS, NULL, 0, pth);
783     strcatW(pth, szBackSlash);
784     msi_set_property( package->db, szProgramMenuFolder, pth, -1 );
785 
786     SHGetFolderPathW(NULL, CSIDL_ADMINTOOLS, NULL, 0, pth);
787     strcatW(pth, szBackSlash);
788     msi_set_property( package->db, szAdminToolsFolder, pth, -1 );
789 
790     SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, pth);
791     strcatW(pth, szBackSlash);
792     msi_set_property( package->db, szAppDataFolder, pth, -1 );
793 
794     SHGetFolderPathW(NULL, CSIDL_SYSTEM, NULL, 0, pth);
795     strcatW(pth, szBackSlash);
796     msi_set_property( package->db, szSystemFolder, pth, -1 );
797     msi_set_property( package->db, szSystem16Folder, pth, -1 );
798 
799     SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, pth);
800     strcatW(pth, szBackSlash);
801     msi_set_property( package->db, szLocalAppDataFolder, pth, -1 );
802 
803     SHGetFolderPathW(NULL, CSIDL_MYPICTURES, NULL, 0, pth);
804     strcatW(pth, szBackSlash);
805     msi_set_property( package->db, szMyPicturesFolder, pth, -1 );
806 
807     SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, 0, pth);
808     strcatW(pth, szBackSlash);
809     msi_set_property( package->db, szPersonalFolder, pth, -1 );
810 
811     SHGetFolderPathW(NULL, CSIDL_WINDOWS, NULL, 0, pth);
812     strcatW(pth, szBackSlash);
813     msi_set_property( package->db, szWindowsFolder, pth, -1 );
814 
815     SHGetFolderPathW(NULL, CSIDL_PRINTHOOD, NULL, 0, pth);
816     strcatW(pth, szBackSlash);
817     msi_set_property( package->db, szPrintHoodFolder, pth, -1 );
818 
819     SHGetFolderPathW(NULL, CSIDL_NETHOOD, NULL, 0, pth);
820     strcatW(pth, szBackSlash);
821     msi_set_property( package->db, szNetHoodFolder, pth, -1 );
822 
823     SHGetFolderPathW(NULL, CSIDL_RECENT, NULL, 0, pth);
824     strcatW(pth, szBackSlash);
825     msi_set_property( package->db, szRecentFolder, pth, -1 );
826 
827     /* Physical Memory is specified in MB. Using total amount. */
828     msex.dwLength = sizeof(msex);
829     GlobalMemoryStatusEx( &msex );
830     len = sprintfW( bufstr, szIntFormat, (int)(msex.ullTotalPhys / 1024 / 1024) );
831     msi_set_property( package->db, szPhysicalMemory, bufstr, len );
832 
833     SHGetFolderPathW(NULL, CSIDL_WINDOWS, NULL, 0, pth);
834     ptr = strchrW(pth,'\\');
835     if (ptr) *(ptr + 1) = 0;
836     msi_set_property( package->db, szWindowsVolume, pth, -1 );
837 
838     len = GetTempPathW(MAX_PATH, pth);
839     msi_set_property( package->db, szTempFolder, pth, len );
840 
841     /* in a wine environment the user is always admin and privileged */
842     msi_set_property( package->db, szAdminUser, szOne, -1 );
843     msi_set_property( package->db, szPrivileged, szOne, -1 );
844 
845     /* set the os things */
846     OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
847     GetVersionExW((OSVERSIONINFOW *)&OSVersion);
848     verval = OSVersion.dwMinorVersion + OSVersion.dwMajorVersion * 100;
849     len = sprintfW( verstr, szFormat, verval );
850     switch (OSVersion.dwPlatformId)
851     {
852         case VER_PLATFORM_WIN32_WINDOWS:
853             msi_set_property( package->db, szVersion9x, verstr, len );
854             break;
855         case VER_PLATFORM_WIN32_NT:
856             msi_set_property( package->db, szVersionNT, verstr, len );
857             len = sprintfW( bufstr, szFormat,OSVersion.wProductType );
858             msi_set_property( package->db, szMsiNTProductType, bufstr, len );
859             break;
860     }
861     len = sprintfW( bufstr, szFormat, OSVersion.dwBuildNumber );
862     msi_set_property( package->db, szWindowsBuild, bufstr, len );
863     len = sprintfW( bufstr, szFormat, OSVersion.wServicePackMajor );
864     msi_set_property( package->db, szServicePackLevel, bufstr, len );
865 
866     len = sprintfW( bufstr, szFormat2, MSI_MAJORVERSION, MSI_MINORVERSION );
867     msi_set_property( package->db, szVersionMsi, bufstr, len );
868     len = sprintfW( bufstr, szFormat, MSI_MAJORVERSION * 100 );
869     msi_set_property( package->db, szVersionDatabase, bufstr, len );
870 
871     GetNativeSystemInfo( &sys_info );
872     len = sprintfW( bufstr, szIntFormat, sys_info.wProcessorLevel );
873     msi_set_property( package->db, szIntel, bufstr, len );
874     if (sys_info.u.s.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
875     {
876         GetSystemDirectoryW( pth, MAX_PATH );
877         PathAddBackslashW( pth );
878         msi_set_property( package->db, szSystemFolder, pth, -1 );
879 
880         SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES, NULL, 0, pth );
881         PathAddBackslashW( pth );
882         msi_set_property( package->db, szProgramFilesFolder, pth, -1 );
883 
884         SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES_COMMON, NULL, 0, pth );
885         PathAddBackslashW( pth );
886         msi_set_property( package->db, szCommonFilesFolder, pth, -1 );
887     }
888     else if (sys_info.u.s.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
889     {
890         msi_set_property( package->db, szMsiAMD64, bufstr, -1 );
891         msi_set_property( package->db, szMsix64, bufstr, -1 );
892         msi_set_property( package->db, szVersionNT64, verstr, -1 );
893 
894         GetSystemDirectoryW( pth, MAX_PATH );
895         PathAddBackslashW( pth );
896         msi_set_property( package->db, szSystem64Folder, pth, -1 );
897 
898         GetSystemWow64DirectoryW( pth, MAX_PATH );
899         PathAddBackslashW( pth );
900         msi_set_property( package->db, szSystemFolder, pth, -1 );
901 
902         SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES, NULL, 0, pth );
903         PathAddBackslashW( pth );
904         msi_set_property( package->db, szProgramFiles64Folder, pth, -1 );
905 
906         SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILESX86, NULL, 0, pth );
907         PathAddBackslashW( pth );
908         msi_set_property( package->db, szProgramFilesFolder, pth, -1 );
909 
910         SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES_COMMON, NULL, 0, pth );
911         PathAddBackslashW( pth );
912         msi_set_property( package->db, szCommonFiles64Folder, pth, -1 );
913 
914         SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES_COMMONX86, NULL, 0, pth );
915         PathAddBackslashW( pth );
916         msi_set_property( package->db, szCommonFilesFolder, pth, -1 );
917     }
918 
919     /* Screen properties. */
920     dc = GetDC(0);
921     len = sprintfW( bufstr, szIntFormat, GetDeviceCaps(dc, HORZRES) );
922     msi_set_property( package->db, szScreenX, bufstr, len );
923     len = sprintfW( bufstr, szIntFormat, GetDeviceCaps(dc, VERTRES) );
924     msi_set_property( package->db, szScreenY, bufstr, len );
925     len = sprintfW( bufstr, szIntFormat, GetDeviceCaps(dc, BITSPIXEL) );
926     msi_set_property( package->db, szColorBits, bufstr, len );
927     ReleaseDC(0, dc);
928 
929     /* USERNAME and COMPANYNAME */
930     username = msi_dup_property( package->db, szUSERNAME );
931     companyname = msi_dup_property( package->db, szCOMPANYNAME );
932 
933     if ((!username || !companyname) &&
934         RegOpenKeyW( HKEY_CURRENT_USER, szUserInfo, &hkey ) == ERROR_SUCCESS)
935     {
936         if (!username &&
937             (username = msi_reg_get_val_str( hkey, szDefName )))
938             msi_set_property( package->db, szUSERNAME, username, -1 );
939         if (!companyname &&
940             (companyname = msi_reg_get_val_str( hkey, szDefCompany )))
941             msi_set_property( package->db, szCOMPANYNAME, companyname, -1 );
942         CloseHandle( hkey );
943     }
944     if ((!username || !companyname) &&
945         RegOpenKeyW( HKEY_LOCAL_MACHINE, szCurrentVersion, &hkey ) == ERROR_SUCCESS)
946     {
947         if (!username &&
948             (username = msi_reg_get_val_str( hkey, szRegisteredUser )))
949             msi_set_property( package->db, szUSERNAME, username, -1 );
950         if (!companyname &&
951             (companyname = msi_reg_get_val_str( hkey, szRegisteredOrganization )))
952             msi_set_property( package->db, szCOMPANYNAME, companyname, -1 );
953         CloseHandle( hkey );
954     }
955     msi_free( username );
956     msi_free( companyname );
957 
958     if ( set_user_sid_prop( package ) != ERROR_SUCCESS)
959         ERR("Failed to set the UserSID property\n");
960 
961     set_msi_assembly_prop( package );
962 
963     langid = GetUserDefaultLangID();
964     len = sprintfW( bufstr, szIntFormat, langid );
965     msi_set_property( package->db, szUserLanguageID, bufstr, len );
966 
967     langid = GetSystemDefaultLangID();
968     len = sprintfW( bufstr, szIntFormat, langid );
969     msi_set_property( package->db, szSystemLangID, bufstr, len );
970 
971     len = sprintfW( bufstr, szIntFormat, MsiQueryProductStateW(package->ProductCode) );
972     msi_set_property( package->db, szProductState, bufstr, len );
973 
974     len = 0;
975     if (!GetUserNameW( NULL, &len ) && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
976     {
977         WCHAR *username;
978         if ((username = msi_alloc( len * sizeof(WCHAR) )))
979         {
980             if (GetUserNameW( username, &len ))
981                 msi_set_property( package->db, szLogonUser, username, len - 1 );
982             msi_free( username );
983         }
984     }
985     len = 0;
986     if (!GetComputerNameW( NULL, &len ) && GetLastError() == ERROR_BUFFER_OVERFLOW)
987     {
988         WCHAR *computername;
989         if ((computername = msi_alloc( len * sizeof(WCHAR) )))
990         {
991             if (GetComputerNameW( computername, &len ))
992                 msi_set_property( package->db, szComputerName, computername, len );
993             msi_free( computername );
994         }
995     }
996 }
997 
998 static MSIPACKAGE *msi_alloc_package( void )
999 {
1000     MSIPACKAGE *package;
1001 
1002     package = alloc_msiobject( MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE),
1003                                MSI_FreePackage );
1004     if( package )
1005     {
1006         list_init( &package->components );
1007         list_init( &package->features );
1008         list_init( &package->files );
1009         list_init( &package->filepatches );
1010         list_init( &package->tempfiles );
1011         list_init( &package->folders );
1012         list_init( &package->subscriptions );
1013         list_init( &package->appids );
1014         list_init( &package->classes );
1015         list_init( &package->mimes );
1016         list_init( &package->extensions );
1017         list_init( &package->progids );
1018         list_init( &package->RunningActions );
1019         list_init( &package->sourcelist_info );
1020         list_init( &package->sourcelist_media );
1021         list_init( &package->patches );
1022         list_init( &package->binaries );
1023         list_init( &package->cabinet_streams );
1024     }
1025 
1026     return package;
1027 }
1028 
1029 static UINT msi_load_admin_properties(MSIPACKAGE *package)
1030 {
1031     BYTE *data;
1032     UINT r, sz;
1033 
1034     static const WCHAR stmname[] = {'A','d','m','i','n','P','r','o','p','e','r','t','i','e','s',0};
1035 
1036     r = read_stream_data(package->db->storage, stmname, FALSE, &data, &sz);
1037     if (r != ERROR_SUCCESS)
1038         return r;
1039 
1040     r = msi_parse_command_line(package, (WCHAR *)data, TRUE);
1041 
1042     msi_free(data);
1043     return r;
1044 }
1045 
1046 void msi_adjust_privilege_properties( MSIPACKAGE *package )
1047 {
1048     /* FIXME: this should depend on the user's privileges */
1049     if (msi_get_property_int( package->db, szAllUsers, 0 ) == 2)
1050     {
1051         TRACE("resetting ALLUSERS property from 2 to 1\n");
1052         msi_set_property( package->db, szAllUsers, szOne, -1 );
1053     }
1054     msi_set_property( package->db, szAdminUser, szOne, -1 );
1055 }
1056 
1057 MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPCWSTR base_url )
1058 {
1059     static const WCHAR fmtW[] = {'%','u',0};
1060     MSIPACKAGE *package;
1061     WCHAR uilevel[11];
1062     int len;
1063     UINT r;
1064 
1065     TRACE("%p\n", db);
1066 
1067     package = msi_alloc_package();
1068     if (package)
1069     {
1070         msiobj_addref( &db->hdr );
1071         package->db = db;
1072 
1073         package->LastAction = NULL;
1074         package->LastActionTemplate = NULL;
1075         package->LastActionResult = MSI_NULL_INTEGER;
1076         package->WordCount = 0;
1077         package->PackagePath = strdupW( db->path );
1078         package->BaseURL = strdupW( base_url );
1079 
1080         create_temp_property_table( package );
1081         msi_clone_properties( package->db );
1082         msi_adjust_privilege_properties( package );
1083 
1084         package->ProductCode = msi_dup_property( package->db, szProductCode );
1085 
1086         set_installer_properties( package );
1087 
1088         package->ui_level = gUILevel;
1089         len = sprintfW( uilevel, fmtW, gUILevel & INSTALLUILEVEL_MASK );
1090         msi_set_property( package->db, szUILevel, uilevel, len );
1091 
1092         r = msi_load_suminfo_properties( package );
1093         if (r != ERROR_SUCCESS)
1094         {
1095             msiobj_release( &package->hdr );
1096             return NULL;
1097         }
1098 
1099         if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1100             msi_load_admin_properties( package );
1101 
1102         package->log_file = INVALID_HANDLE_VALUE;
1103     }
1104     return package;
1105 }
1106 
1107 UINT msi_download_file( LPCWSTR szUrl, LPWSTR filename )
1108 {
1109     LPINTERNET_CACHE_ENTRY_INFOW cache_entry;
1110     DWORD size = 0;
1111     HRESULT hr;
1112 
1113     /* call will always fail, because size is 0,
1114      * but will return ERROR_FILE_NOT_FOUND first
1115      * if the file doesn't exist
1116      */
1117     GetUrlCacheEntryInfoW( szUrl, NULL, &size );
1118     if ( GetLastError() != ERROR_FILE_NOT_FOUND )
1119     {
1120         cache_entry = msi_alloc( size );
1121         if ( !GetUrlCacheEntryInfoW( szUrl, cache_entry, &size ) )
1122         {
1123             UINT error = GetLastError();
1124             msi_free( cache_entry );
1125             return error;
1126         }
1127 
1128         lstrcpyW( filename, cache_entry->lpszLocalFileName );
1129         msi_free( cache_entry );
1130         return ERROR_SUCCESS;
1131     }
1132 
1133     hr = URLDownloadToCacheFileW( NULL, szUrl, filename, MAX_PATH, 0, NULL );
1134     if ( FAILED(hr) )
1135     {
1136         WARN("failed to download %s to cache file\n", debugstr_w(szUrl));
1137         return ERROR_FUNCTION_FAILED;
1138     }
1139 
1140     return ERROR_SUCCESS;
1141 }
1142 
1143 UINT msi_create_empty_local_file( LPWSTR path, LPCWSTR suffix )
1144 {
1145     static const WCHAR szInstaller[] = {
1146         '\\','I','n','s','t','a','l','l','e','r','\\',0};
1147     static const WCHAR fmt[] = {'%','x',0};
1148     DWORD time, len, i, offset;
1149     HANDLE handle;
1150 
1151     time = GetTickCount();
1152     GetWindowsDirectoryW( path, MAX_PATH );
1153     strcatW( path, szInstaller );
1154     CreateDirectoryW( path, NULL );
1155 
1156     len = strlenW(path);
1157     for (i = 0; i < 0x10000; i++)
1158     {
1159         offset = snprintfW( path + len, MAX_PATH - len, fmt, (time + i) & 0xffff );
1160         memcpy( path + len + offset, suffix, (strlenW( suffix ) + 1) * sizeof(WCHAR) );
1161         handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
1162                               CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1163         if (handle != INVALID_HANDLE_VALUE)
1164         {
1165             CloseHandle(handle);
1166             break;
1167         }
1168         if (GetLastError() != ERROR_FILE_EXISTS &&
1169             GetLastError() != ERROR_SHARING_VIOLATION)
1170             return ERROR_FUNCTION_FAILED;
1171     }
1172 
1173     return ERROR_SUCCESS;
1174 }
1175 
1176 static enum platform parse_platform( const WCHAR *str )
1177 {
1178     if (!str[0] || !strcmpW( str, szIntel )) return PLATFORM_INTEL;
1179     else if (!strcmpW( str, szIntel64 )) return PLATFORM_INTEL64;
1180     else if (!strcmpW( str, szX64 ) || !strcmpW( str, szAMD64 )) return PLATFORM_X64;
1181     else if (!strcmpW( str, szARM )) return PLATFORM_ARM;
1182     return PLATFORM_UNKNOWN;
1183 }
1184 
1185 static UINT parse_suminfo( MSISUMMARYINFO *si, MSIPACKAGE *package )
1186 {
1187     WCHAR *template, *p, *q, *platform;
1188     DWORD i, count;
1189 
1190     package->version = msi_suminfo_get_int32( si, PID_PAGECOUNT );
1191     TRACE("version: %d\n", package->version);
1192 
1193     template = msi_suminfo_dup_string( si, PID_TEMPLATE );
1194     if (!template)
1195         return ERROR_SUCCESS; /* native accepts missing template property */
1196 
1197     TRACE("template: %s\n", debugstr_w(template));
1198 
1199     p = strchrW( template, ';' );
1200     if (!p)
1201     {
1202         WARN("invalid template string %s\n", debugstr_w(template));
1203         msi_free( template );
1204         return ERROR_PATCH_PACKAGE_INVALID;
1205     }
1206     *p = 0;
1207     platform = template;
1208     if ((q = strchrW( platform, ',' ))) *q = 0;
1209     package->platform = parse_platform( platform );
1210     while (package->platform == PLATFORM_UNKNOWN && q)
1211     {
1212         platform = q + 1;
1213         if ((q = strchrW( platform, ',' ))) *q = 0;
1214         package->platform = parse_platform( platform );
1215     }
1216     if (package->platform == PLATFORM_UNKNOWN)
1217     {
1218         WARN("unknown platform %s\n", debugstr_w(template));
1219         msi_free( template );
1220         return ERROR_INSTALL_PLATFORM_UNSUPPORTED;
1221     }
1222     p++;
1223     if (!*p)
1224     {
1225         msi_free( template );
1226         return ERROR_SUCCESS;
1227     }
1228     count = 1;
1229     for (q = p; (q = strchrW( q, ',' )); q++) count++;
1230 
1231     package->langids = msi_alloc( count * sizeof(LANGID) );
1232     if (!package->langids)
1233     {
1234         msi_free( template );
1235         return ERROR_OUTOFMEMORY;
1236     }
1237 
1238     i = 0;
1239     while (*p)
1240     {
1241         q = strchrW( p, ',' );
1242         if (q) *q = 0;
1243         package->langids[i] = atoiW( p );
1244         if (!q) break;
1245         p = q + 1;
1246         i++;
1247     }
1248     package->num_langids = i + 1;
1249 
1250     msi_free( template );
1251     return ERROR_SUCCESS;
1252 }
1253 
1254 static UINT validate_package( MSIPACKAGE *package )
1255 {
1256     UINT i;
1257 
1258     if (package->platform == PLATFORM_INTEL64)
1259         return ERROR_INSTALL_PLATFORM_UNSUPPORTED;
1260 #ifndef __arm__
1261     if (package->platform == PLATFORM_ARM)
1262         return ERROR_INSTALL_PLATFORM_UNSUPPORTED;
1263 #endif
1264     if (package->platform == PLATFORM_X64)
1265     {
1266         if (!is_64bit && !is_wow64)
1267             return ERROR_INSTALL_PLATFORM_UNSUPPORTED;
1268         if (package->version < 200)
1269             return ERROR_INSTALL_PACKAGE_INVALID;
1270     }
1271     if (!package->num_langids)
1272     {
1273         return ERROR_SUCCESS;
1274     }
1275     for (i = 0; i < package->num_langids; i++)
1276     {
1277         LANGID langid = package->langids[i];
1278 
1279         if (PRIMARYLANGID( langid ) == LANG_NEUTRAL)
1280         {
1281             langid = MAKELANGID( PRIMARYLANGID( GetSystemDefaultLangID() ), SUBLANGID( langid ) );
1282         }
1283         if (SUBLANGID( langid ) == SUBLANG_NEUTRAL)
1284         {
1285             langid = MAKELANGID( PRIMARYLANGID( langid ), SUBLANGID( GetSystemDefaultLangID() ) );
1286         }
1287         if (IsValidLocale( langid, LCID_INSTALLED ))
1288             return ERROR_SUCCESS;
1289     }
1290     return ERROR_INSTALL_LANGUAGE_UNSUPPORTED;
1291 }
1292 
1293 static WCHAR *get_product_code( MSIDATABASE *db )
1294 {
1295     static const WCHAR query[] = {
1296         'S','E','L','E','C','T',' ','`','V','a','l','u','e','`',' ',
1297         'F','R','O','M',' ','`','P','r','o','p','e','r','t','y','`',' ',
1298         'W','H','E','R','E',' ','`','P','r','o','p','e','r','t','y','`','=',
1299         '\'','P','r','o','d','u','c','t','C','o','d','e','\'',0};
1300     MSIQUERY *view;
1301     MSIRECORD *rec;
1302     WCHAR *ret = NULL;
1303 
1304     if (MSI_DatabaseOpenViewW( db, query, &view ) != ERROR_SUCCESS)
1305     {
1306         return NULL;
1307     }
1308     if (MSI_ViewExecute( view, 0 ) != ERROR_SUCCESS)
1309     {
1310         MSI_ViewClose( view );
1311         msiobj_release( &view->hdr );
1312         return NULL;
1313     }
1314     if (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
1315     {
1316         ret = strdupW( MSI_RecordGetString( rec, 1 ) );
1317         msiobj_release( &rec->hdr );
1318     }
1319     MSI_ViewClose( view );
1320     msiobj_release( &view->hdr );
1321     return ret;
1322 }
1323 
1324 static UINT get_registered_local_package( const WCHAR *product, const WCHAR *package, WCHAR *localfile )
1325 {
1326     MSIINSTALLCONTEXT context;
1327     HKEY product_key, props_key;
1328     WCHAR *registered_package = NULL, unsquashed[GUID_SIZE];
1329     UINT r;
1330 
1331     r = msi_locate_product( product, &context );
1332     if (r != ERROR_SUCCESS)
1333         return r;
1334 
1335     r = MSIREG_OpenProductKey( product, NULL, context, &product_key, FALSE );
1336     if (r != ERROR_SUCCESS)
1337         return r;
1338 
1339     r = MSIREG_OpenInstallProps( product, context, NULL, &props_key, FALSE );
1340     if (r != ERROR_SUCCESS)
1341     {
1342         RegCloseKey( product_key );
1343         return r;
1344     }
1345     r = ERROR_FUNCTION_FAILED;
1346     registered_package = msi_reg_get_val_str( product_key, INSTALLPROPERTY_PACKAGECODEW );
1347     if (!registered_package)
1348         goto done;
1349 
1350     unsquash_guid( registered_package, unsquashed );
1351     if (!strcmpiW( package, unsquashed ))
1352     {
1353         WCHAR *filename = msi_reg_get_val_str( props_key, INSTALLPROPERTY_LOCALPACKAGEW );
1354         if (!filename)
1355             goto done;
1356 
1357         strcpyW( localfile, filename );
1358         msi_free( filename );
1359         r = ERROR_SUCCESS;
1360     }
1361 done:
1362     msi_free( registered_package );
1363     RegCloseKey( props_key );
1364     RegCloseKey( product_key );
1365     return r;
1366 }
1367 
1368 static WCHAR *get_package_code( MSIDATABASE *db )
1369 {
1370     WCHAR *ret;
1371     MSISUMMARYINFO *si;
1372     UINT r;
1373 
1374     r = msi_get_suminfo( db->storage, 0, &si );
1375     if (r != ERROR_SUCCESS)
1376     {
1377         r = msi_get_db_suminfo( db, 0, &si );
1378         if (r != ERROR_SUCCESS)
1379         {
1380             WARN("failed to load summary info %u\n", r);
1381             return NULL;
1382         }
1383     }
1384     ret = msi_suminfo_dup_string( si, PID_REVNUMBER );
1385     msiobj_release( &si->hdr );
1386     return ret;
1387 }
1388 
1389 static UINT get_local_package( const WCHAR *filename, WCHAR *localfile )
1390 {
1391     WCHAR *product_code, *package_code;
1392     MSIDATABASE *db;
1393     UINT r;
1394 
1395     if ((r = MSI_OpenDatabaseW( filename, MSIDBOPEN_READONLY, &db )) != ERROR_SUCCESS)
1396     {
1397         if (GetFileAttributesW( filename ) == INVALID_FILE_ATTRIBUTES)
1398             return ERROR_FILE_NOT_FOUND;
1399         return r;
1400     }
1401     if (!(product_code = get_product_code( db )))
1402     {
1403         msiobj_release( &db->hdr );
1404         return ERROR_INSTALL_PACKAGE_INVALID;
1405     }
1406     if (!(package_code = get_package_code( db )))
1407     {
1408         msi_free( product_code );
1409         msiobj_release( &db->hdr );
1410         return ERROR_INSTALL_PACKAGE_INVALID;
1411     }
1412     r = get_registered_local_package( product_code, package_code, localfile );
1413     msi_free( package_code );
1414     msi_free( product_code );
1415     msiobj_release( &db->hdr );
1416     return r;
1417 }
1418 
1419 UINT msi_set_original_database_property( MSIDATABASE *db, const WCHAR *package )
1420 {
1421     UINT r;
1422 
1423     if (UrlIsW( package, URLIS_URL ))
1424         r = msi_set_property( db, szOriginalDatabase, package, -1 );
1425     else if (package[0] == '#')
1426         r = msi_set_property( db, szOriginalDatabase, db->path, -1 );
1427     else
1428     {
1429         DWORD len;
1430         WCHAR *path;
1431 
1432         if (!(len = GetFullPathNameW( package, 0, NULL, NULL ))) return GetLastError();
1433         if (!(path = msi_alloc( len * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY;
1434         len = GetFullPathNameW( package, len, path, NULL );
1435         r = msi_set_property( db, szOriginalDatabase, path, len );
1436         msi_free( path );
1437     }
1438     return r;
1439 }
1440 
1441 UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
1442 {
1443     static const WCHAR dotmsi[] = {'.','m','s','i',0};
1444     MSIDATABASE *db;
1445     MSIPACKAGE *package;
1446     MSIHANDLE handle;
1447     MSIRECORD *data_row, *info_row;
1448     LPWSTR ptr, base_url = NULL;
1449     UINT r;
1450     WCHAR localfile[MAX_PATH], cachefile[MAX_PATH];
1451     LPCWSTR file = szPackage;
1452     DWORD index = 0;
1453     MSISUMMARYINFO *si;
1454     BOOL delete_on_close = FALSE;
1455     LPWSTR productname;
1456     WCHAR *info_template;
1457 
1458     TRACE("%s %p\n", debugstr_w(szPackage), pPackage);
1459 
1460     MSI_ProcessMessage(NULL, INSTALLMESSAGE_INITIALIZE, 0);
1461 
1462     localfile[0] = 0;
1463     if( szPackage[0] == '#' )
1464     {
1465         handle = atoiW(&szPackage[1]);
1466         db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
1467         if( !db )
1468         {
1469             IWineMsiRemoteDatabase *remote_database;
1470 
1471             remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( handle );
1472             if ( !remote_database )
1473                 return ERROR_INVALID_HANDLE;
1474 
1475             IWineMsiRemoteDatabase_Release( remote_database );
1476             WARN("MsiOpenPackage not allowed during a custom action!\n");
1477 
1478             return ERROR_FUNCTION_FAILED;
1479         }
1480     }
1481     else
1482     {
1483         if ( UrlIsW( szPackage, URLIS_URL ) )
1484         {
1485             r = msi_download_file( szPackage, cachefile );
1486             if (r != ERROR_SUCCESS)
1487                 return r;
1488 
1489             file = cachefile;
1490 
1491             base_url = strdupW( szPackage );
1492             if (!base_url)
1493                 return ERROR_OUTOFMEMORY;
1494 
1495             ptr = strrchrW( base_url, '/' );
1496             if (ptr) *(ptr + 1) = '\0';
1497         }
1498         r = get_local_package( file, localfile );
1499         if (r != ERROR_SUCCESS || GetFileAttributesW( localfile ) == INVALID_FILE_ATTRIBUTES)
1500         {
1501             r = msi_create_empty_local_file( localfile, dotmsi );
1502             if (r != ERROR_SUCCESS)
1503             {
1504                 msi_free ( base_url );
1505                 return r;
1506             }
1507 
1508             if (!CopyFileW( file, localfile, FALSE ))
1509             {
1510                 r = GetLastError();
1511                 WARN("unable to copy package %s to %s (%u)\n", debugstr_w(file), debugstr_w(localfile), r);
1512                 DeleteFileW( localfile );
1513                 msi_free ( base_url );
1514                 return r;
1515             }
1516             delete_on_close = TRUE;
1517         }
1518         TRACE("opening package %s\n", debugstr_w( localfile ));
1519         r = MSI_OpenDatabaseW( localfile, MSIDBOPEN_TRANSACT, &db );
1520         if (r != ERROR_SUCCESS)
1521         {
1522             msi_free ( base_url );
1523             return r;
1524         }
1525     }
1526     package = MSI_CreatePackage( db, base_url );
1527     msi_free( base_url );
1528     msiobj_release( &db->hdr );
1529     if (!package) return ERROR_INSTALL_PACKAGE_INVALID;
1530     package->localfile = strdupW( localfile );
1531     package->delete_on_close = delete_on_close;
1532 
1533     r = msi_get_suminfo( db->storage, 0, &si );
1534     if (r != ERROR_SUCCESS)
1535     {
1536         r = msi_get_db_suminfo( db, 0, &si );
1537         if (r != ERROR_SUCCESS)
1538         {
1539             WARN("failed to load summary info\n");
1540             msiobj_release( &package->hdr );
1541             return ERROR_INSTALL_PACKAGE_INVALID;
1542         }
1543     }
1544     r = parse_suminfo( si, package );
1545     msiobj_release( &si->hdr );
1546     if (r != ERROR_SUCCESS)
1547     {
1548         WARN("failed to parse summary info %u\n", r);
1549         msiobj_release( &package->hdr );
1550         return r;
1551     }
1552     r = validate_package( package );
1553     if (r != ERROR_SUCCESS)
1554     {
1555         msiobj_release( &package->hdr );
1556         return r;
1557     }
1558     msi_set_property( package->db, szDatabase, db->path, -1 );
1559     set_installed_prop( package );
1560     msi_set_context( package );
1561 
1562     while (1)
1563     {
1564         WCHAR patch_code[GUID_SIZE];
1565         r = MsiEnumPatchesExW( package->ProductCode, NULL, package->Context,
1566                                MSIPATCHSTATE_APPLIED, index, patch_code, NULL, NULL, NULL, NULL );
1567         if (r != ERROR_SUCCESS)
1568             break;
1569 
1570         TRACE("found registered patch %s\n", debugstr_w(patch_code));
1571 
1572         r = msi_apply_registered_patch( package, patch_code );
1573         if (r != ERROR_SUCCESS)
1574         {
1575             ERR("registered patch failed to apply %u\n", r);
1576             msiobj_release( &package->hdr );
1577             return r;
1578         }
1579         index++;
1580     }
1581     if (index) msi_adjust_privilege_properties( package );
1582 
1583     r = msi_set_original_database_property( package->db, szPackage );
1584     if (r != ERROR_SUCCESS)
1585     {
1586         msiobj_release( &package->hdr );
1587         return r;
1588     }
1589     if (gszLogFile)
1590         package->log_file = CreateFileW( gszLogFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1591                                          OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
1592 
1593     /* FIXME: when should these messages be sent? */
1594     data_row = MSI_CreateRecord(3);
1595     if (!data_row)
1596 	return ERROR_OUTOFMEMORY;
1597     MSI_RecordSetStringW(data_row, 0, NULL);
1598     MSI_RecordSetInteger(data_row, 1, 0);
1599     MSI_RecordSetInteger(data_row, 2, package->num_langids ? package->langids[0] : 0);
1600     MSI_RecordSetInteger(data_row, 3, msi_get_string_table_codepage(package->db->strings));
1601     MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_COMMONDATA, data_row);
1602 
1603     info_row = MSI_CreateRecord(0);
1604     if (!info_row)
1605     {
1606 	msiobj_release(&data_row->hdr);
1607 	return ERROR_OUTOFMEMORY;
1608     }
1609     info_template = msi_get_error_message(package->db, MSIERR_INFO_LOGGINGSTART);
1610     MSI_RecordSetStringW(info_row, 0, info_template);
1611     msi_free(info_template);
1612     MSI_ProcessMessage(package, INSTALLMESSAGE_INFO|MB_ICONHAND, info_row);
1613 
1614     MSI_ProcessMessage(package, INSTALLMESSAGE_COMMONDATA, data_row);
1615 
1616     productname = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
1617     MSI_RecordSetInteger(data_row, 1, 1);
1618     MSI_RecordSetStringW(data_row, 2, productname);
1619     MSI_RecordSetStringW(data_row, 3, NULL);
1620     MSI_ProcessMessage(package, INSTALLMESSAGE_COMMONDATA, data_row);
1621 
1622     msi_free(productname);
1623     msiobj_release(&info_row->hdr);
1624     msiobj_release(&data_row->hdr);
1625 
1626     *pPackage = package;
1627     return ERROR_SUCCESS;
1628 }
1629 
1630 UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
1631 {
1632     MSIPACKAGE *package = NULL;
1633     UINT ret;
1634 
1635     TRACE("%s %08x %p\n", debugstr_w(szPackage), dwOptions, phPackage );
1636 
1637     if( !szPackage || !phPackage )
1638         return ERROR_INVALID_PARAMETER;
1639 
1640     if ( !*szPackage )
1641     {
1642         FIXME("Should create an empty database and package\n");
1643         return ERROR_FUNCTION_FAILED;
1644     }
1645 
1646     if( dwOptions )
1647         FIXME("dwOptions %08x not supported\n", dwOptions);
1648 
1649     ret = MSI_OpenPackageW( szPackage, &package );
1650     if( ret == ERROR_SUCCESS )
1651     {
1652         *phPackage = alloc_msihandle( &package->hdr );
1653         if (! *phPackage)
1654             ret = ERROR_NOT_ENOUGH_MEMORY;
1655         msiobj_release( &package->hdr );
1656     }
1657     else
1658         MSI_ProcessMessage(NULL, INSTALLMESSAGE_TERMINATE, 0);
1659 
1660     return ret;
1661 }
1662 
1663 UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
1664 {
1665     return MsiOpenPackageExW( szPackage, 0, phPackage );
1666 }
1667 
1668 UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
1669 {
1670     LPWSTR szwPack = NULL;
1671     UINT ret;
1672 
1673     if( szPackage )
1674     {
1675         szwPack = strdupAtoW( szPackage );
1676         if( !szwPack )
1677             return ERROR_OUTOFMEMORY;
1678     }
1679 
1680     ret = MsiOpenPackageExW( szwPack, dwOptions, phPackage );
1681 
1682     msi_free( szwPack );
1683 
1684     return ret;
1685 }
1686 
1687 UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
1688 {
1689     return MsiOpenPackageExA( szPackage, 0, phPackage );
1690 }
1691 
1692 MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
1693 {
1694     MSIPACKAGE *package;
1695     MSIHANDLE handle = 0;
1696     IUnknown *remote_unk;
1697     IWineMsiRemotePackage *remote_package;
1698 
1699     TRACE("(%d)\n",hInstall);
1700 
1701     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
1702     if( package)
1703     {
1704         handle = alloc_msihandle( &package->db->hdr );
1705         msiobj_release( &package->hdr );
1706     }
1707     else if ((remote_unk = msi_get_remote(hInstall)))
1708     {
1709         if (IUnknown_QueryInterface(remote_unk, &IID_IWineMsiRemotePackage,
1710                                         (LPVOID *)&remote_package) == S_OK)
1711         {
1712             IWineMsiRemotePackage_GetActiveDatabase(remote_package, &handle);
1713             IWineMsiRemotePackage_Release(remote_package);
1714         }
1715         else
1716         {
1717             WARN("remote handle %d is not a package\n", hInstall);
1718         }
1719         IUnknown_Release(remote_unk);
1720     }
1721 
1722     return handle;
1723 }
1724 
1725 static INT internal_ui_handler(MSIPACKAGE *package, INSTALLMESSAGE eMessageType, MSIRECORD *record, LPCWSTR message)
1726 {
1727     static const WCHAR szActionData[] = {'A','c','t','i','o','n','D','a','t','a',0};
1728     static const WCHAR szActionText[] = {'A','c','t','i','o','n','T','e','x','t',0};
1729     static const WCHAR szSetProgress[] = {'S','e','t','P','r','o','g','r','e','s','s',0};
1730     static const WCHAR szWindows_Installer[] =
1731         {'W','i','n','d','o','w','s',' ','I','n','s','t','a','l','l','e','r',0};
1732 
1733     if (!package || (package->ui_level & INSTALLUILEVEL_MASK) == INSTALLUILEVEL_NONE)
1734         return 0;
1735 
1736     /* todo: check if message needs additional styles (topmost/foreground/modality?) */
1737 
1738     switch (eMessageType & 0xff000000)
1739     {
1740     case INSTALLMESSAGE_FATALEXIT:
1741     case INSTALLMESSAGE_ERROR:
1742     case INSTALLMESSAGE_OUTOFDISKSPACE:
1743         if (package->ui_level & INSTALLUILEVEL_PROGRESSONLY) return 0;
1744         if (!(eMessageType & MB_ICONMASK))
1745             eMessageType |= MB_ICONEXCLAMATION;
1746         return MessageBoxW(gUIhwnd, message, szWindows_Installer, eMessageType & 0x00ffffff);
1747     case INSTALLMESSAGE_WARNING:
1748         if (package->ui_level & INSTALLUILEVEL_PROGRESSONLY) return 0;
1749         if (!(eMessageType & MB_ICONMASK))
1750             eMessageType |= MB_ICONASTERISK;
1751         return MessageBoxW(gUIhwnd, message, szWindows_Installer, eMessageType & 0x00ffffff);
1752     case INSTALLMESSAGE_USER:
1753         if (package->ui_level & INSTALLUILEVEL_PROGRESSONLY) return 0;
1754         if (!(eMessageType & MB_ICONMASK))
1755             eMessageType |= MB_USERICON;
1756         return MessageBoxW(gUIhwnd, message, szWindows_Installer, eMessageType & 0x00ffffff);
1757     case INSTALLMESSAGE_INFO:
1758     case INSTALLMESSAGE_INITIALIZE:
1759     case INSTALLMESSAGE_TERMINATE:
1760     case INSTALLMESSAGE_INSTALLSTART:
1761     case INSTALLMESSAGE_INSTALLEND:
1762         return 0;
1763     case INSTALLMESSAGE_SHOWDIALOG:
1764     {
1765         LPWSTR dialog = msi_dup_record_field(record, 0);
1766         INT rc = ACTION_DialogBox(package, dialog);
1767         msi_free(dialog);
1768         return rc;
1769     }
1770     case INSTALLMESSAGE_ACTIONSTART:
1771     {
1772         LPWSTR deformatted;
1773         MSIRECORD *uirow = MSI_CreateRecord(1);
1774         if (!uirow) return -1;
1775         deformat_string(package, MSI_RecordGetString(record, 2), &deformatted);
1776         MSI_RecordSetStringW(uirow, 1, deformatted);
1777         msi_event_fire(package, szActionText, uirow);
1778 
1779         msi_free(deformatted);
1780         msiobj_release(&uirow->hdr);
1781         return 1;
1782     }
1783     case INSTALLMESSAGE_ACTIONDATA:
1784     {
1785         MSIRECORD *uirow = MSI_CreateRecord(1);
1786         if (!uirow) return -1;
1787         MSI_RecordSetStringW(uirow, 1, message);
1788         msi_event_fire(package, szActionData, uirow);
1789         msiobj_release(&uirow->hdr);
1790 
1791         if (package->action_progress_increment)
1792         {
1793             uirow = MSI_CreateRecord(2);
1794             if (!uirow) return -1;
1795             MSI_RecordSetInteger(uirow, 1, 2);
1796             MSI_RecordSetInteger(uirow, 2, package->action_progress_increment);
1797             msi_event_fire(package, szSetProgress, uirow);
1798             msiobj_release(&uirow->hdr);
1799         }
1800         return 1;
1801     }
1802     case INSTALLMESSAGE_PROGRESS:
1803         msi_event_fire(package, szSetProgress, record);
1804         return 1;
1805     case INSTALLMESSAGE_COMMONDATA:
1806         switch (MSI_RecordGetInteger(record, 1))
1807         {
1808         case 0:
1809         case 1:
1810             /* do nothing */
1811             return 0;
1812         default:
1813             /* fall through */
1814             ;
1815         }
1816     default:
1817         FIXME("internal UI not implemented for message 0x%08x (UI level = %x)\n", eMessageType, package->ui_level);
1818         return 0;
1819     }
1820 }
1821 
1822 static const WCHAR szActionNotFound[] = {'D','E','B','U','G',':',' ','E','r','r','o','r',' ','[','1',']',':',' ',' ','A','c','t','i','o','n',' ','n','o','t',' ','f','o','u','n','d',':',' ','[','2',']',0};
1823 
1824 static const struct
1825 {
1826     int id;
1827     const WCHAR *text;
1828 }
1829 internal_errors[] =
1830 {
1831     {2726, szActionNotFound},
1832     {0}
1833 };
1834 
1835 static LPCWSTR get_internal_error_message(int error)
1836 {
1837     int i = 0;
1838 
1839     while (internal_errors[i].id != 0)
1840     {
1841         if (internal_errors[i].id == error)
1842             return internal_errors[i].text;
1843         i++;
1844     }
1845 
1846     FIXME("missing error message %d\n", error);
1847     return NULL;
1848 }
1849 
1850 /* Returned string must be freed */
1851 LPWSTR msi_get_error_message(MSIDATABASE *db, int error)
1852 {
1853     static const WCHAR query[] =
1854         {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
1855          'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
1856          '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
1857     MSIRECORD *record;
1858     LPWSTR ret = NULL;
1859 
1860     if ((record = MSI_QueryGetRecord(db, query, error)))
1861     {
1862         ret = msi_dup_record_field(record, 1);
1863         msiobj_release(&record->hdr);
1864     }
1865     else if (error < 2000)
1866     {
1867         int len = LoadStringW(msi_hInstance, IDS_ERROR_BASE + error, (LPWSTR) &ret, 0);
1868         if (len)
1869         {
1870             ret = msi_alloc((len + 1) * sizeof(WCHAR));
1871             LoadStringW(msi_hInstance, IDS_ERROR_BASE + error, ret, len + 1);
1872         }
1873         else
1874             ret = NULL;
1875     }
1876 
1877     return ret;
1878 }
1879 
1880 INT MSI_ProcessMessageVerbatim(MSIPACKAGE *package, INSTALLMESSAGE eMessageType, MSIRECORD *record)
1881 {
1882     LPWSTR message = {0};
1883     DWORD len;
1884     DWORD log_type = 1 << (eMessageType >> 24);
1885     UINT res;
1886     INT rc = 0;
1887     char *msg;
1888 
1889     TRACE("%x\n", eMessageType);
1890     if (TRACE_ON(msi)) dump_record(record);
1891 
1892     if (!package || !record)
1893         message = NULL;
1894     else {
1895         res = MSI_FormatRecordW(package, record, message, &len);
1896         if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
1897             return res;
1898         len++;
1899         message = msi_alloc(len * sizeof(WCHAR));
1900         if (!message) return ERROR_OUTOFMEMORY;
1901         MSI_FormatRecordW(package, record, message, &len);
1902     }
1903 
1904     /* convert it to ASCII */
1905     len = WideCharToMultiByte( CP_ACP, 0, message, -1, NULL, 0, NULL, NULL );
1906     msg = msi_alloc( len );
1907     WideCharToMultiByte( CP_ACP, 0, message, -1, msg, len, NULL, NULL );
1908 
1909     if (gUIHandlerRecord && (gUIFilterRecord & log_type))
1910     {
1911         MSIHANDLE rec = alloc_msihandle(&record->hdr);
1912         TRACE("Calling UI handler %p(pvContext=%p, iMessageType=%08x, hRecord=%u)\n",
1913               gUIHandlerRecord, gUIContextRecord, eMessageType, rec);
1914         rc = gUIHandlerRecord( gUIContextRecord, eMessageType, rec );
1915         MsiCloseHandle( rec );
1916     }
1917     if (!rc && gUIHandlerW && (gUIFilter & log_type))
1918     {
1919         TRACE("Calling UI handler %p(pvContext=%p, iMessageType=%08x, szMessage=%s)\n",
1920               gUIHandlerW, gUIContext, eMessageType, debugstr_w(message));
1921         rc = gUIHandlerW( gUIContext, eMessageType, message );
1922     }
1923     else if (!rc && gUIHandlerA && (gUIFilter & log_type))
1924     {
1925         TRACE("Calling UI handler %p(pvContext=%p, iMessageType=%08x, szMessage=%s)\n",
1926               gUIHandlerA, gUIContext, eMessageType, debugstr_a(msg));
1927         rc = gUIHandlerA( gUIContext, eMessageType, msg );
1928     }
1929 
1930     if (!rc)
1931         rc = internal_ui_handler(package, eMessageType, record, message);
1932 
1933     if (!rc && package && package->log_file != INVALID_HANDLE_VALUE &&
1934         (eMessageType & 0xff000000) != INSTALLMESSAGE_PROGRESS)
1935     {
1936         DWORD written;
1937         WriteFile( package->log_file, msg, len - 1, &written, NULL );
1938         WriteFile( package->log_file, "\n", 1, &written, NULL );
1939     }
1940     msi_free( msg );
1941     msi_free( message );
1942 
1943     return rc;
1944 }
1945 
1946 INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType, MSIRECORD *record )
1947 {
1948     switch (eMessageType & 0xff000000)
1949     {
1950     case INSTALLMESSAGE_FATALEXIT:
1951     case INSTALLMESSAGE_ERROR:
1952     case INSTALLMESSAGE_WARNING:
1953     case INSTALLMESSAGE_USER:
1954     case INSTALLMESSAGE_INFO:
1955     case INSTALLMESSAGE_OUTOFDISKSPACE:
1956         if (MSI_RecordGetInteger(record, 1) != MSI_NULL_INTEGER)
1957         {
1958             /* error message */
1959 
1960             LPWSTR template;
1961             LPWSTR template_rec = NULL, template_prefix = NULL;
1962             int error = MSI_RecordGetInteger(record, 1);
1963 
1964             if (MSI_RecordIsNull(record, 0))
1965             {
1966                 if (error >= 32)
1967                 {
1968                     template_rec = msi_get_error_message(package->db, error);
1969 
1970                     if (!template_rec && error >= 2000)
1971                     {
1972                         /* internal error, not localized */
1973                         if ((template_rec = (LPWSTR) get_internal_error_message(error)))
1974                         {
1975                             MSI_RecordSetStringW(record, 0, template_rec);
1976                             MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_INFO, record);
1977                         }
1978                         template_rec = msi_get_error_message(package->db, MSIERR_INSTALLERROR);
1979                         MSI_RecordSetStringW(record, 0, template_rec);
1980                         MSI_ProcessMessageVerbatim(package, eMessageType, record);
1981                         msi_free(template_rec);
1982                         return 0;
1983                     }
1984                 }
1985             }
1986             else
1987                 template_rec = msi_dup_record_field(record, 0);
1988 
1989             template_prefix = msi_get_error_message(package->db, eMessageType >> 24);
1990             if (!template_prefix) template_prefix = strdupW(szEmpty);
1991 
1992             if (!template_rec)
1993             {
1994                 /* always returns 0 */
1995                 MSI_RecordSetStringW(record, 0, template_prefix);
1996                 MSI_ProcessMessageVerbatim(package, eMessageType, record);
1997                 msi_free(template_prefix);
1998                 return 0;
1999             }
2000 
2001             template = msi_alloc((strlenW(template_rec) + strlenW(template_prefix) + 1) * sizeof(WCHAR));
2002             if (!template) return ERROR_OUTOFMEMORY;
2003 
2004             strcpyW(template, template_prefix);
2005             strcatW(template, template_rec);
2006             MSI_RecordSetStringW(record, 0, template);
2007 
2008             msi_free(template_prefix);
2009             msi_free(template_rec);
2010             msi_free(template);
2011         }
2012         break;
2013     case INSTALLMESSAGE_ACTIONSTART:
2014     {
2015         WCHAR *template = msi_get_error_message(package->db, MSIERR_ACTIONSTART);
2016         MSI_RecordSetStringW(record, 0, template);
2017         msi_free(template);
2018 
2019         msi_free(package->LastAction);
2020         msi_free(package->LastActionTemplate);
2021         package->LastAction = msi_dup_record_field(record, 1);
2022         if (!package->LastAction) package->LastAction = strdupW(szEmpty);
2023         package->LastActionTemplate = msi_dup_record_field(record, 3);
2024         break;
2025     }
2026     case INSTALLMESSAGE_ACTIONDATA:
2027         if (package->LastAction && package->LastActionTemplate)
2028         {
2029             static const WCHAR template_s[] =
2030                 {'{','{','%','s',':',' ','}','}','%','s',0};
2031             WCHAR *template;
2032 
2033             template = msi_alloc((strlenW(package->LastAction) + strlenW(package->LastActionTemplate) + 7) * sizeof(WCHAR));
2034             if (!template) return ERROR_OUTOFMEMORY;
2035             sprintfW(template, template_s, package->LastAction, package->LastActionTemplate);
2036             MSI_RecordSetStringW(record, 0, template);
2037             msi_free(template);
2038         }
2039         break;
2040     case INSTALLMESSAGE_COMMONDATA:
2041     {
2042         WCHAR *template = msi_get_error_message(package->db, MSIERR_COMMONDATA);
2043         MSI_RecordSetStringW(record, 0, template);
2044         msi_free(template);
2045     }
2046     break;
2047     }
2048 
2049     return MSI_ProcessMessageVerbatim(package, eMessageType, record);
2050 }
2051 
2052 INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
2053                               MSIHANDLE hRecord)
2054 {
2055     UINT ret = ERROR_INVALID_HANDLE;
2056     MSIPACKAGE *package = NULL;
2057     MSIRECORD *record = NULL;
2058 
2059     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INITIALIZE ||
2060         (eMessageType & 0xff000000) == INSTALLMESSAGE_TERMINATE)
2061         return -1;
2062 
2063     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA &&
2064         MsiRecordGetInteger(hRecord, 1) != 2)
2065         return -1;
2066 
2067     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
2068     if( !package )
2069     {
2070         HRESULT hr;
2071         IWineMsiRemotePackage *remote_package;
2072 
2073         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
2074         if (!remote_package)
2075             return ERROR_INVALID_HANDLE;
2076 
2077         hr = IWineMsiRemotePackage_ProcessMessage( remote_package, eMessageType, hRecord );
2078 
2079         IWineMsiRemotePackage_Release( remote_package );
2080 
2081         if (FAILED(hr))
2082         {
2083             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
2084                 return HRESULT_CODE(hr);
2085 
2086             return ERROR_FUNCTION_FAILED;
2087         }
2088 
2089         return ERROR_SUCCESS;
2090     }
2091 
2092     record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
2093     if( !record )
2094         goto out;
2095 
2096     ret = MSI_ProcessMessage( package, eMessageType, record );
2097 
2098 out:
2099     msiobj_release( &package->hdr );
2100     if( record )
2101         msiobj_release( &record->hdr );
2102 
2103     return ret;
2104 }
2105 
2106 /* property code */
2107 
2108 UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue )
2109 {
2110     LPWSTR szwName = NULL, szwValue = NULL;
2111     UINT r = ERROR_OUTOFMEMORY;
2112 
2113     szwName = strdupAtoW( szName );
2114     if( szName && !szwName )
2115         goto end;
2116 
2117     szwValue = strdupAtoW( szValue );
2118     if( szValue && !szwValue )
2119         goto end;
2120 
2121     r = MsiSetPropertyW( hInstall, szwName, szwValue);
2122 
2123 end:
2124     msi_free( szwName );
2125     msi_free( szwValue );
2126 
2127     return r;
2128 }
2129 
2130 void msi_reset_folders( MSIPACKAGE *package, BOOL source )
2131 {
2132     MSIFOLDER *folder;
2133 
2134     LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
2135     {
2136         if ( source )
2137         {
2138             msi_free( folder->ResolvedSource );
2139             folder->ResolvedSource = NULL;
2140         }
2141         else
2142         {
2143             msi_free( folder->ResolvedTarget );
2144             folder->ResolvedTarget = NULL;
2145         }
2146     }
2147 }
2148 
2149 UINT msi_set_property( MSIDATABASE *db, const WCHAR *name, const WCHAR *value, int len )
2150 {
2151     static const WCHAR insert_query[] = {
2152         'I','N','S','E','R','T',' ','I','N','T','O',' ',
2153         '`','_','P','r','o','p','e','r','t','y','`',' ',
2154         '(','`','_','P','r','o','p','e','r','t','y','`',',','`','V','a','l','u','e','`',')',' ',
2155         'V','A','L','U','E','S',' ','(','?',',','?',')',0};
2156     static const WCHAR update_query[] = {
2157         'U','P','D','A','T','E',' ','`','_','P','r','o','p','e','r','t','y','`',' ',
2158         'S','E','T',' ','`','V','a','l','u','e','`',' ','=',' ','?',' ','W','H','E','R','E',' ',
2159         '`','_','P','r','o','p','e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
2160     static const WCHAR delete_query[] = {
2161         'D','E','L','E','T','E',' ','F','R','O','M',' ',
2162         '`','_','P','r','o','p','e','r','t','y','`',' ','W','H','E','R','E',' ',
2163         '`','_','P','r','o','p','e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
2164     MSIQUERY *view;
2165     MSIRECORD *row = NULL;
2166     DWORD sz = 0;
2167     WCHAR query[1024];
2168     UINT rc;
2169 
2170     TRACE("%p %s %s %d\n", db, debugstr_w(name), debugstr_wn(value, len), len);
2171 
2172     if (!name)
2173         return ERROR_INVALID_PARAMETER;
2174 
2175     /* this one is weird... */
2176     if (!name[0])
2177         return value ? ERROR_FUNCTION_FAILED : ERROR_SUCCESS;
2178 
2179     if (value && len < 0) len = strlenW( value );
2180 
2181     rc = msi_get_property( db, name, 0, &sz );
2182     if (!value || (!*value && !len))
2183     {
2184         sprintfW( query, delete_query, name );
2185     }
2186     else if (rc == ERROR_MORE_DATA || rc == ERROR_SUCCESS)
2187     {
2188         sprintfW( query, update_query, name );
2189         row = MSI_CreateRecord(1);
2190         msi_record_set_string( row, 1, value, len );
2191     }
2192     else
2193     {
2194         strcpyW( query, insert_query );
2195         row = MSI_CreateRecord(2);
2196         msi_record_set_string( row, 1, name, -1 );
2197         msi_record_set_string( row, 2, value, len );
2198     }
2199 
2200     rc = MSI_DatabaseOpenViewW(db, query, &view);
2201     if (rc == ERROR_SUCCESS)
2202     {
2203         rc = MSI_ViewExecute(view, row);
2204         MSI_ViewClose(view);
2205         msiobj_release(&view->hdr);
2206     }
2207     if (row) msiobj_release(&row->hdr);
2208     return rc;
2209 }
2210 
2211 UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
2212 {
2213     MSIPACKAGE *package;
2214     UINT ret;
2215 
2216     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
2217     if( !package )
2218     {
2219         HRESULT hr;
2220         BSTR name = NULL, value = NULL;
2221         IWineMsiRemotePackage *remote_package;
2222 
2223         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
2224         if (!remote_package)
2225             return ERROR_INVALID_HANDLE;
2226 
2227         name = SysAllocString( szName );
2228         value = SysAllocString( szValue );
2229         if ((!name && szName) || (!value && szValue))
2230         {
2231             SysFreeString( name );
2232             SysFreeString( value );
2233             IWineMsiRemotePackage_Release( remote_package );
2234             return ERROR_OUTOFMEMORY;
2235         }
2236 
2237         hr = IWineMsiRemotePackage_SetProperty( remote_package, name, value );
2238 
2239         SysFreeString( name );
2240         SysFreeString( value );
2241         IWineMsiRemotePackage_Release( remote_package );
2242 
2243         if (FAILED(hr))
2244         {
2245             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
2246                 return HRESULT_CODE(hr);
2247 
2248             return ERROR_FUNCTION_FAILED;
2249         }
2250 
2251         return ERROR_SUCCESS;
2252     }
2253 
2254     ret = msi_set_property( package->db, szName, szValue, -1 );
2255     if (ret == ERROR_SUCCESS && !strcmpW( szName, szSourceDir ))
2256         msi_reset_folders( package, TRUE );
2257 
2258     msiobj_release( &package->hdr );
2259     return ret;
2260 }
2261 
2262 static MSIRECORD *msi_get_property_row( MSIDATABASE *db, LPCWSTR name )
2263 {
2264     static const WCHAR query[]= {
2265         'S','E','L','E','C','T',' ','`','V','a','l','u','e','`',' ',
2266         'F','R','O','M',' ' ,'`','_','P','r','o','p','e','r','t','y','`',' ',
2267         'W','H','E','R','E',' ' ,'`','_','P','r','o','p','e','r','t','y','`','=','?',0};
2268     MSIRECORD *rec, *row = NULL;
2269     MSIQUERY *view;
2270     UINT r;
2271 
2272     static const WCHAR szDate[] = {'D','a','t','e',0};
2273     static const WCHAR szTime[] = {'T','i','m','e',0};
2274     WCHAR *buffer;
2275     int length;
2276 
2277     if (!name || !*name)
2278         return NULL;
2279 
2280     if (!strcmpW(name, szDate))
2281     {
2282         length = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, NULL, 0);
2283         if (!length)
2284             return NULL;
2285         buffer = msi_alloc(length * sizeof(WCHAR));
2286         GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, buffer, length);
2287 
2288         row = MSI_CreateRecord(1);
2289         if (!row)
2290         {
2291             msi_free(buffer);
2292             return NULL;
2293         }
2294         MSI_RecordSetStringW(row, 1, buffer);
2295         msi_free(buffer);
2296         return row;
2297     }
2298     else if (!strcmpW(name, szTime))
2299     {
2300         length = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOTIMEMARKER, NULL, NULL, NULL, 0);
2301         if (!length)
2302             return NULL;
2303         buffer = msi_alloc(length * sizeof(WCHAR));
2304         GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOTIMEMARKER, NULL, NULL, buffer, length);
2305 
2306         row = MSI_CreateRecord(1);
2307         if (!row)
2308         {
2309             msi_free(buffer);
2310             return NULL;
2311         }
2312         MSI_RecordSetStringW(row, 1, buffer);
2313         msi_free(buffer);
2314         return row;
2315     }
2316 
2317     rec = MSI_CreateRecord(1);
2318     if (!rec)
2319         return NULL;
2320 
2321     MSI_RecordSetStringW(rec, 1, name);
2322 
2323     r = MSI_DatabaseOpenViewW(db, query, &view);
2324     if (r == ERROR_SUCCESS)
2325     {
2326         MSI_ViewExecute(view, rec);
2327         MSI_ViewFetch(view, &row);
2328         MSI_ViewClose(view);
2329         msiobj_release(&view->hdr);
2330     }
2331     msiobj_release(&rec->hdr);
2332     return row;
2333 }
2334 
2335 /* internal function, not compatible with MsiGetPropertyW */
2336 UINT msi_get_property( MSIDATABASE *db, LPCWSTR szName,
2337                        LPWSTR szValueBuf, LPDWORD pchValueBuf )
2338 {
2339     MSIRECORD *row;
2340     UINT rc = ERROR_FUNCTION_FAILED;
2341 
2342     TRACE("%p %s %p %p\n", db, debugstr_w(szName), szValueBuf, pchValueBuf);
2343 
2344     row = msi_get_property_row( db, szName );
2345 
2346     if (*pchValueBuf > 0)
2347         szValueBuf[0] = 0;
2348 
2349     if (row)
2350     {
2351         rc = MSI_RecordGetStringW(row, 1, szValueBuf, pchValueBuf);
2352         msiobj_release(&row->hdr);
2353     }
2354 
2355     if (rc == ERROR_SUCCESS)
2356         TRACE("returning %s for property %s\n", debugstr_wn(szValueBuf, *pchValueBuf),
2357             debugstr_w(szName));
2358     else if (rc == ERROR_MORE_DATA)
2359         TRACE("need %d sized buffer for %s\n", *pchValueBuf,
2360             debugstr_w(szName));
2361     else
2362     {
2363         *pchValueBuf = 0;
2364         TRACE("property %s not found\n", debugstr_w(szName));
2365     }
2366 
2367     return rc;
2368 }
2369 
2370 LPWSTR msi_dup_property(MSIDATABASE *db, LPCWSTR prop)
2371 {
2372     DWORD sz = 0;
2373     LPWSTR str;
2374     UINT r;
2375 
2376     r = msi_get_property(db, prop, NULL, &sz);
2377     if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
2378         return NULL;
2379 
2380     sz++;
2381     str = msi_alloc(sz * sizeof(WCHAR));
2382     r = msi_get_property(db, prop, str, &sz);
2383     if (r != ERROR_SUCCESS)
2384     {
2385         msi_free(str);
2386         str = NULL;
2387     }
2388 
2389     return str;
2390 }
2391 
2392 int msi_get_property_int( MSIDATABASE *db, LPCWSTR prop, int def )
2393 {
2394     LPWSTR str = msi_dup_property( db, prop );
2395     int val = str ? atoiW(str) : def;
2396     msi_free(str);
2397     return val;
2398 }
2399 
2400 static UINT MSI_GetProperty( MSIHANDLE handle, LPCWSTR name,
2401                              awstring *szValueBuf, LPDWORD pchValueBuf )
2402 {
2403     MSIPACKAGE *package;
2404     MSIRECORD *row = NULL;
2405     UINT r = ERROR_FUNCTION_FAILED;
2406     LPCWSTR val = NULL;
2407     DWORD len = 0;
2408 
2409     TRACE("%u %s %p %p\n", handle, debugstr_w(name),
2410           szValueBuf->str.w, pchValueBuf );
2411 
2412     if (!name)
2413         return ERROR_INVALID_PARAMETER;
2414 
2415     package = msihandle2msiinfo( handle, MSIHANDLETYPE_PACKAGE );
2416     if (!package)
2417     {
2418         HRESULT hr;
2419         IWineMsiRemotePackage *remote_package;
2420         LPWSTR value = NULL;
2421         BSTR bname;
2422 
2423         remote_package = (IWineMsiRemotePackage *)msi_get_remote( handle );
2424         if (!remote_package)
2425             return ERROR_INVALID_HANDLE;
2426 
2427         bname = SysAllocString( name );
2428         if (!bname)
2429         {
2430             IWineMsiRemotePackage_Release( remote_package );
2431             return ERROR_OUTOFMEMORY;
2432         }
2433 
2434         hr = IWineMsiRemotePackage_GetProperty( remote_package, bname, NULL, &len );
2435         if (FAILED(hr))
2436             goto done;
2437 
2438         len++;
2439         value = msi_alloc(len * sizeof(WCHAR));
2440         if (!value)
2441         {
2442             r = ERROR_OUTOFMEMORY;
2443             goto done;
2444         }
2445 
2446         hr = IWineMsiRemotePackage_GetProperty( remote_package, bname, value, &len );
2447         if (FAILED(hr))
2448             goto done;
2449 
2450         r = msi_strcpy_to_awstring( value, len, szValueBuf, pchValueBuf );
2451 
2452         /* Bug required by Adobe installers */
2453         if (!szValueBuf->unicode && !szValueBuf->str.a)
2454             *pchValueBuf *= sizeof(WCHAR);
2455 
2456 done:
2457         IWineMsiRemotePackage_Release(remote_package);
2458         SysFreeString(bname);
2459         msi_free(value);
2460 
2461         if (FAILED(hr))
2462         {
2463             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
2464                 return HRESULT_CODE(hr);
2465 
2466             return ERROR_FUNCTION_FAILED;
2467         }
2468 
2469         return r;
2470     }
2471 
2472     row = msi_get_property_row( package->db, name );
2473     if (row)
2474         val = msi_record_get_string( row, 1, (int *)&len );
2475 
2476     if (!val)
2477         val = szEmpty;
2478 
2479     r = msi_strcpy_to_awstring( val, len, szValueBuf, pchValueBuf );
2480 
2481     if (row)
2482         msiobj_release( &row->hdr );
2483     msiobj_release( &package->hdr );
2484 
2485     return r;
2486 }
2487 
2488 UINT WINAPI MsiGetPropertyA( MSIHANDLE hInstall, LPCSTR szName,
2489                              LPSTR szValueBuf, LPDWORD pchValueBuf )
2490 {
2491     awstring val;
2492     LPWSTR name;
2493     UINT r;
2494 
2495     val.unicode = FALSE;
2496     val.str.a = szValueBuf;
2497 
2498     name = strdupAtoW( szName );
2499     if (szName && !name)
2500         return ERROR_OUTOFMEMORY;
2501 
2502     r = MSI_GetProperty( hInstall, name, &val, pchValueBuf );
2503     msi_free( name );
2504     return r;
2505 }
2506 
2507 UINT WINAPI MsiGetPropertyW( MSIHANDLE hInstall, LPCWSTR szName,
2508                              LPWSTR szValueBuf, LPDWORD pchValueBuf )
2509 {
2510     awstring val;
2511 
2512     val.unicode = TRUE;
2513     val.str.w = szValueBuf;
2514 
2515     return MSI_GetProperty( hInstall, szName, &val, pchValueBuf );
2516 }
2517 
2518 typedef struct _msi_remote_package_impl {
2519     IWineMsiRemotePackage IWineMsiRemotePackage_iface;
2520     MSIHANDLE package;
2521     LONG refs;
2522 } msi_remote_package_impl;
2523 
2524 static inline msi_remote_package_impl *impl_from_IWineMsiRemotePackage( IWineMsiRemotePackage *iface )
2525 {
2526     return CONTAINING_RECORD(iface, msi_remote_package_impl, IWineMsiRemotePackage_iface);
2527 }
2528 
2529 static HRESULT WINAPI mrp_QueryInterface( IWineMsiRemotePackage *iface,
2530                 REFIID riid,LPVOID *ppobj)
2531 {
2532     if( IsEqualCLSID( riid, &IID_IUnknown ) ||
2533         IsEqualCLSID( riid, &IID_IWineMsiRemotePackage ) )
2534     {
2535         IWineMsiRemotePackage_AddRef( iface );
2536         *ppobj = iface;
2537         return S_OK;
2538     }
2539 
2540     return E_NOINTERFACE;
2541 }
2542 
2543 static ULONG WINAPI mrp_AddRef( IWineMsiRemotePackage *iface )
2544 {
2545     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2546 
2547     return InterlockedIncrement( &This->refs );
2548 }
2549 
2550 static ULONG WINAPI mrp_Release( IWineMsiRemotePackage *iface )
2551 {
2552     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2553     ULONG r;
2554 
2555     r = InterlockedDecrement( &This->refs );
2556     if (r == 0)
2557     {
2558         MsiCloseHandle( This->package );
2559         msi_free( This );
2560     }
2561     return r;
2562 }
2563 
2564 static HRESULT WINAPI mrp_SetMsiHandle( IWineMsiRemotePackage *iface, MSIHANDLE handle )
2565 {
2566     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2567     This->package = handle;
2568     return S_OK;
2569 }
2570 
2571 static HRESULT WINAPI mrp_GetActiveDatabase( IWineMsiRemotePackage *iface, MSIHANDLE *handle )
2572 {
2573     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2574     IWineMsiRemoteDatabase *rdb = NULL;
2575     HRESULT hr;
2576     MSIHANDLE hdb;
2577 
2578     hr = create_msi_remote_database( NULL, (LPVOID *)&rdb );
2579     if (FAILED(hr) || !rdb)
2580     {
2581         ERR("Failed to create remote database\n");
2582         return hr;
2583     }
2584 
2585     hdb = MsiGetActiveDatabase(This->package);
2586 
2587     hr = IWineMsiRemoteDatabase_SetMsiHandle( rdb, hdb );
2588     if (FAILED(hr))
2589     {
2590         ERR("Failed to set the database handle\n");
2591         return hr;
2592     }
2593 
2594     *handle = alloc_msi_remote_handle( (IUnknown *)rdb );
2595     return S_OK;
2596 }
2597 
2598 static HRESULT WINAPI mrp_GetProperty( IWineMsiRemotePackage *iface, BSTR property, BSTR value, DWORD *size )
2599 {
2600     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2601     UINT r = MsiGetPropertyW(This->package, property, value, size);
2602     if (r != ERROR_SUCCESS) return HRESULT_FROM_WIN32(r);
2603     return S_OK;
2604 }
2605 
2606 static HRESULT WINAPI mrp_SetProperty( IWineMsiRemotePackage *iface, BSTR property, BSTR value )
2607 {
2608     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2609     UINT r = MsiSetPropertyW(This->package, property, value);
2610     return HRESULT_FROM_WIN32(r);
2611 }
2612 
2613 static HRESULT WINAPI mrp_ProcessMessage( IWineMsiRemotePackage *iface, INSTALLMESSAGE message, MSIHANDLE record )
2614 {
2615     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2616     UINT r = MsiProcessMessage(This->package, message, record);
2617     return HRESULT_FROM_WIN32(r);
2618 }
2619 
2620 static HRESULT WINAPI mrp_DoAction( IWineMsiRemotePackage *iface, BSTR action )
2621 {
2622     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2623     UINT r = MsiDoActionW(This->package, action);
2624     return HRESULT_FROM_WIN32(r);
2625 }
2626 
2627 static HRESULT WINAPI mrp_Sequence( IWineMsiRemotePackage *iface, BSTR table, int sequence )
2628 {
2629     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2630     UINT r = MsiSequenceW(This->package, table, sequence);
2631     return HRESULT_FROM_WIN32(r);
2632 }
2633 
2634 static HRESULT WINAPI mrp_GetTargetPath( IWineMsiRemotePackage *iface, BSTR folder, BSTR value, DWORD *size )
2635 {
2636     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2637     UINT r = MsiGetTargetPathW(This->package, folder, value, size);
2638     return HRESULT_FROM_WIN32(r);
2639 }
2640 
2641 static HRESULT WINAPI mrp_SetTargetPath( IWineMsiRemotePackage *iface, BSTR folder, BSTR value)
2642 {
2643     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2644     UINT r = MsiSetTargetPathW(This->package, folder, value);
2645     return HRESULT_FROM_WIN32(r);
2646 }
2647 
2648 static HRESULT WINAPI mrp_GetSourcePath( IWineMsiRemotePackage *iface, BSTR folder, BSTR value, DWORD *size )
2649 {
2650     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2651     UINT r = MsiGetSourcePathW(This->package, folder, value, size);
2652     return HRESULT_FROM_WIN32(r);
2653 }
2654 
2655 static HRESULT WINAPI mrp_GetMode( IWineMsiRemotePackage *iface, MSIRUNMODE mode, BOOL *ret )
2656 {
2657     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2658     *ret = MsiGetMode(This->package, mode);
2659     return S_OK;
2660 }
2661 
2662 static HRESULT WINAPI mrp_SetMode( IWineMsiRemotePackage *iface, MSIRUNMODE mode, BOOL state )
2663 {
2664     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2665     UINT r = MsiSetMode(This->package, mode, state);
2666     return HRESULT_FROM_WIN32(r);
2667 }
2668 
2669 static HRESULT WINAPI mrp_GetFeatureState( IWineMsiRemotePackage *iface, BSTR feature,
2670                                     INSTALLSTATE *installed, INSTALLSTATE *action )
2671 {
2672     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2673     UINT r = MsiGetFeatureStateW(This->package, feature, installed, action);
2674     return HRESULT_FROM_WIN32(r);
2675 }
2676 
2677 static HRESULT WINAPI mrp_SetFeatureState( IWineMsiRemotePackage *iface, BSTR feature, INSTALLSTATE state )
2678 {
2679     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2680     UINT r = MsiSetFeatureStateW(This->package, feature, state);
2681     return HRESULT_FROM_WIN32(r);
2682 }
2683 
2684 static HRESULT WINAPI mrp_GetComponentState( IWineMsiRemotePackage *iface, BSTR component,
2685                                       INSTALLSTATE *installed, INSTALLSTATE *action )
2686 {
2687     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2688     UINT r = MsiGetComponentStateW(This->package, component, installed, action);
2689     return HRESULT_FROM_WIN32(r);
2690 }
2691 
2692 static HRESULT WINAPI mrp_SetComponentState( IWineMsiRemotePackage *iface, BSTR component, INSTALLSTATE state )
2693 {
2694     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2695     UINT r = MsiSetComponentStateW(This->package, component, state);
2696     return HRESULT_FROM_WIN32(r);
2697 }
2698 
2699 static HRESULT WINAPI mrp_GetLanguage( IWineMsiRemotePackage *iface, LANGID *language )
2700 {
2701     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2702     *language = MsiGetLanguage(This->package);
2703     return S_OK;
2704 }
2705 
2706 static HRESULT WINAPI mrp_SetInstallLevel( IWineMsiRemotePackage *iface, int level )
2707 {
2708     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2709     UINT r = MsiSetInstallLevel(This->package, level);
2710     return HRESULT_FROM_WIN32(r);
2711 }
2712 
2713 static HRESULT WINAPI mrp_FormatRecord( IWineMsiRemotePackage *iface, MSIHANDLE record,
2714                                         BSTR *value)
2715 {
2716     DWORD size = 0;
2717     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2718     UINT r = MsiFormatRecordW(This->package, record, NULL, &size);
2719     if (r == ERROR_SUCCESS)
2720     {
2721         *value = SysAllocStringLen(NULL, size);
2722         if (!*value)
2723             return E_OUTOFMEMORY;
2724         size++;
2725         r = MsiFormatRecordW(This->package, record, *value, &size);
2726     }
2727     return HRESULT_FROM_WIN32(r);
2728 }
2729 
2730 static HRESULT WINAPI mrp_EvaluateCondition( IWineMsiRemotePackage *iface, BSTR condition )
2731 {
2732     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2733     UINT r = MsiEvaluateConditionW(This->package, condition);
2734     return HRESULT_FROM_WIN32(r);
2735 }
2736 
2737 static HRESULT WINAPI mrp_GetFeatureCost( IWineMsiRemotePackage *iface, BSTR feature,
2738                                           INT cost_tree, INSTALLSTATE state, INT *cost )
2739 {
2740     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2741     UINT r = MsiGetFeatureCostW(This->package, feature, cost_tree, state, cost);
2742     return HRESULT_FROM_WIN32(r);
2743 }
2744 
2745 static HRESULT WINAPI mrp_EnumComponentCosts( IWineMsiRemotePackage *iface, BSTR component,
2746                                               DWORD index, INSTALLSTATE state, BSTR drive,
2747                                               DWORD *buflen, INT *cost, INT *temp )
2748 {
2749     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2750     UINT r = MsiEnumComponentCostsW(This->package, component, index, state, drive, buflen, cost, temp);
2751     return HRESULT_FROM_WIN32(r);
2752 }
2753 
2754 static const IWineMsiRemotePackageVtbl msi_remote_package_vtbl =
2755 {
2756     mrp_QueryInterface,
2757     mrp_AddRef,
2758     mrp_Release,
2759     mrp_SetMsiHandle,
2760     mrp_GetActiveDatabase,
2761     mrp_GetProperty,
2762     mrp_SetProperty,
2763     mrp_ProcessMessage,
2764     mrp_DoAction,
2765     mrp_Sequence,
2766     mrp_GetTargetPath,
2767     mrp_SetTargetPath,
2768     mrp_GetSourcePath,
2769     mrp_GetMode,
2770     mrp_SetMode,
2771     mrp_GetFeatureState,
2772     mrp_SetFeatureState,
2773     mrp_GetComponentState,
2774     mrp_SetComponentState,
2775     mrp_GetLanguage,
2776     mrp_SetInstallLevel,
2777     mrp_FormatRecord,
2778     mrp_EvaluateCondition,
2779     mrp_GetFeatureCost,
2780     mrp_EnumComponentCosts
2781 };
2782 
2783 HRESULT create_msi_remote_package( IUnknown *pOuter, LPVOID *ppObj )
2784 {
2785     msi_remote_package_impl* This;
2786 
2787     This = msi_alloc( sizeof *This );
2788     if (!This)
2789         return E_OUTOFMEMORY;
2790 
2791     This->IWineMsiRemotePackage_iface.lpVtbl = &msi_remote_package_vtbl;
2792     This->package = 0;
2793     This->refs = 1;
2794 
2795     *ppObj = &This->IWineMsiRemotePackage_iface;
2796 
2797     return S_OK;
2798 }
2799 
2800 UINT msi_package_add_info(MSIPACKAGE *package, DWORD context, DWORD options,
2801                           LPCWSTR property, LPWSTR value)
2802 {
2803     MSISOURCELISTINFO *info;
2804 
2805     LIST_FOR_EACH_ENTRY( info, &package->sourcelist_info, MSISOURCELISTINFO, entry )
2806     {
2807         if (!strcmpW( info->value, value )) return ERROR_SUCCESS;
2808     }
2809 
2810     info = msi_alloc(sizeof(MSISOURCELISTINFO));
2811     if (!info)
2812         return ERROR_OUTOFMEMORY;
2813 
2814     info->context = context;
2815     info->options = options;
2816     info->property = property;
2817     info->value = strdupW(value);
2818     list_add_head(&package->sourcelist_info, &info->entry);
2819 
2820     return ERROR_SUCCESS;
2821 }
2822 
2823 UINT msi_package_add_media_disk(MSIPACKAGE *package, DWORD context, DWORD options,
2824                                 DWORD disk_id, LPWSTR volume_label, LPWSTR disk_prompt)
2825 {
2826     MSIMEDIADISK *disk;
2827 
2828     LIST_FOR_EACH_ENTRY( disk, &package->sourcelist_media, MSIMEDIADISK, entry )
2829     {
2830         if (disk->disk_id == disk_id) return ERROR_SUCCESS;
2831     }
2832 
2833     disk = msi_alloc(sizeof(MSIMEDIADISK));
2834     if (!disk)
2835         return ERROR_OUTOFMEMORY;
2836 
2837     disk->context = context;
2838     disk->options = options;
2839     disk->disk_id = disk_id;
2840     disk->volume_label = strdupW(volume_label);
2841     disk->disk_prompt = strdupW(disk_prompt);
2842     list_add_head(&package->sourcelist_media, &disk->entry);
2843 
2844     return ERROR_SUCCESS;
2845 }
2846