xref: /reactos/dll/win32/msi/package.c (revision 171a9206)
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             DWORD localfile_attr;
1502 
1503             r = msi_create_empty_local_file( localfile, dotmsi );
1504             if (r != ERROR_SUCCESS)
1505             {
1506                 msi_free ( base_url );
1507                 return r;
1508             }
1509 
1510             if (!CopyFileW( file, localfile, FALSE ))
1511             {
1512                 r = GetLastError();
1513                 WARN("unable to copy package %s to %s (%u)\n", debugstr_w(file), debugstr_w(localfile), r);
1514                 DeleteFileW( localfile );
1515                 msi_free ( base_url );
1516                 return r;
1517             }
1518             delete_on_close = TRUE;
1519 
1520             /* Remove read-only bit, we are opening it with write access in MSI_OpenDatabaseW below. */
1521             localfile_attr = GetFileAttributesW( localfile );
1522             if (localfile_attr & FILE_ATTRIBUTE_READONLY)
1523                 SetFileAttributesW( localfile, localfile_attr & ~FILE_ATTRIBUTE_READONLY);
1524         }
1525         TRACE("opening package %s\n", debugstr_w( localfile ));
1526         r = MSI_OpenDatabaseW( localfile, MSIDBOPEN_TRANSACT, &db );
1527         if (r != ERROR_SUCCESS)
1528         {
1529             msi_free ( base_url );
1530             return r;
1531         }
1532     }
1533     package = MSI_CreatePackage( db, base_url );
1534     msi_free( base_url );
1535     msiobj_release( &db->hdr );
1536     if (!package) return ERROR_INSTALL_PACKAGE_INVALID;
1537     package->localfile = strdupW( localfile );
1538     package->delete_on_close = delete_on_close;
1539 
1540     r = msi_get_suminfo( db->storage, 0, &si );
1541     if (r != ERROR_SUCCESS)
1542     {
1543         r = msi_get_db_suminfo( db, 0, &si );
1544         if (r != ERROR_SUCCESS)
1545         {
1546             WARN("failed to load summary info\n");
1547             msiobj_release( &package->hdr );
1548             return ERROR_INSTALL_PACKAGE_INVALID;
1549         }
1550     }
1551     r = parse_suminfo( si, package );
1552     msiobj_release( &si->hdr );
1553     if (r != ERROR_SUCCESS)
1554     {
1555         WARN("failed to parse summary info %u\n", r);
1556         msiobj_release( &package->hdr );
1557         return r;
1558     }
1559     r = validate_package( package );
1560     if (r != ERROR_SUCCESS)
1561     {
1562         msiobj_release( &package->hdr );
1563         return r;
1564     }
1565     msi_set_property( package->db, szDatabase, db->path, -1 );
1566     set_installed_prop( package );
1567     msi_set_context( package );
1568 
1569     while (1)
1570     {
1571         WCHAR patch_code[GUID_SIZE];
1572         r = MsiEnumPatchesExW( package->ProductCode, NULL, package->Context,
1573                                MSIPATCHSTATE_APPLIED, index, patch_code, NULL, NULL, NULL, NULL );
1574         if (r != ERROR_SUCCESS)
1575             break;
1576 
1577         TRACE("found registered patch %s\n", debugstr_w(patch_code));
1578 
1579         r = msi_apply_registered_patch( package, patch_code );
1580         if (r != ERROR_SUCCESS)
1581         {
1582             ERR("registered patch failed to apply %u\n", r);
1583             msiobj_release( &package->hdr );
1584             return r;
1585         }
1586         index++;
1587     }
1588     if (index) msi_adjust_privilege_properties( package );
1589 
1590     r = msi_set_original_database_property( package->db, szPackage );
1591     if (r != ERROR_SUCCESS)
1592     {
1593         msiobj_release( &package->hdr );
1594         return r;
1595     }
1596     if (gszLogFile)
1597         package->log_file = CreateFileW( gszLogFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1598                                          OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
1599 
1600     /* FIXME: when should these messages be sent? */
1601     data_row = MSI_CreateRecord(3);
1602     if (!data_row)
1603 	return ERROR_OUTOFMEMORY;
1604     MSI_RecordSetStringW(data_row, 0, NULL);
1605     MSI_RecordSetInteger(data_row, 1, 0);
1606     MSI_RecordSetInteger(data_row, 2, package->num_langids ? package->langids[0] : 0);
1607     MSI_RecordSetInteger(data_row, 3, msi_get_string_table_codepage(package->db->strings));
1608     MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_COMMONDATA, data_row);
1609 
1610     info_row = MSI_CreateRecord(0);
1611     if (!info_row)
1612     {
1613 	msiobj_release(&data_row->hdr);
1614 	return ERROR_OUTOFMEMORY;
1615     }
1616     info_template = msi_get_error_message(package->db, MSIERR_INFO_LOGGINGSTART);
1617     MSI_RecordSetStringW(info_row, 0, info_template);
1618     msi_free(info_template);
1619     MSI_ProcessMessage(package, INSTALLMESSAGE_INFO|MB_ICONHAND, info_row);
1620 
1621     MSI_ProcessMessage(package, INSTALLMESSAGE_COMMONDATA, data_row);
1622 
1623     productname = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
1624     MSI_RecordSetInteger(data_row, 1, 1);
1625     MSI_RecordSetStringW(data_row, 2, productname);
1626     MSI_RecordSetStringW(data_row, 3, NULL);
1627     MSI_ProcessMessage(package, INSTALLMESSAGE_COMMONDATA, data_row);
1628 
1629     msi_free(productname);
1630     msiobj_release(&info_row->hdr);
1631     msiobj_release(&data_row->hdr);
1632 
1633     *pPackage = package;
1634     return ERROR_SUCCESS;
1635 }
1636 
1637 UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
1638 {
1639     MSIPACKAGE *package = NULL;
1640     UINT ret;
1641 
1642     TRACE("%s %08x %p\n", debugstr_w(szPackage), dwOptions, phPackage );
1643 
1644     if( !szPackage || !phPackage )
1645         return ERROR_INVALID_PARAMETER;
1646 
1647     if ( !*szPackage )
1648     {
1649         FIXME("Should create an empty database and package\n");
1650         return ERROR_FUNCTION_FAILED;
1651     }
1652 
1653     if( dwOptions )
1654         FIXME("dwOptions %08x not supported\n", dwOptions);
1655 
1656     ret = MSI_OpenPackageW( szPackage, &package );
1657     if( ret == ERROR_SUCCESS )
1658     {
1659         *phPackage = alloc_msihandle( &package->hdr );
1660         if (! *phPackage)
1661             ret = ERROR_NOT_ENOUGH_MEMORY;
1662         msiobj_release( &package->hdr );
1663     }
1664     else
1665         MSI_ProcessMessage(NULL, INSTALLMESSAGE_TERMINATE, 0);
1666 
1667     return ret;
1668 }
1669 
1670 UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
1671 {
1672     return MsiOpenPackageExW( szPackage, 0, phPackage );
1673 }
1674 
1675 UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
1676 {
1677     LPWSTR szwPack = NULL;
1678     UINT ret;
1679 
1680     if( szPackage )
1681     {
1682         szwPack = strdupAtoW( szPackage );
1683         if( !szwPack )
1684             return ERROR_OUTOFMEMORY;
1685     }
1686 
1687     ret = MsiOpenPackageExW( szwPack, dwOptions, phPackage );
1688 
1689     msi_free( szwPack );
1690 
1691     return ret;
1692 }
1693 
1694 UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
1695 {
1696     return MsiOpenPackageExA( szPackage, 0, phPackage );
1697 }
1698 
1699 MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
1700 {
1701     MSIPACKAGE *package;
1702     MSIHANDLE handle = 0;
1703     IUnknown *remote_unk;
1704     IWineMsiRemotePackage *remote_package;
1705 
1706     TRACE("(%d)\n",hInstall);
1707 
1708     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
1709     if( package)
1710     {
1711         handle = alloc_msihandle( &package->db->hdr );
1712         msiobj_release( &package->hdr );
1713     }
1714     else if ((remote_unk = msi_get_remote(hInstall)))
1715     {
1716         if (IUnknown_QueryInterface(remote_unk, &IID_IWineMsiRemotePackage,
1717                                         (LPVOID *)&remote_package) == S_OK)
1718         {
1719             IWineMsiRemotePackage_GetActiveDatabase(remote_package, &handle);
1720             IWineMsiRemotePackage_Release(remote_package);
1721         }
1722         else
1723         {
1724             WARN("remote handle %d is not a package\n", hInstall);
1725         }
1726         IUnknown_Release(remote_unk);
1727     }
1728 
1729     return handle;
1730 }
1731 
1732 static INT internal_ui_handler(MSIPACKAGE *package, INSTALLMESSAGE eMessageType, MSIRECORD *record, LPCWSTR message)
1733 {
1734     static const WCHAR szActionData[] = {'A','c','t','i','o','n','D','a','t','a',0};
1735     static const WCHAR szActionText[] = {'A','c','t','i','o','n','T','e','x','t',0};
1736     static const WCHAR szSetProgress[] = {'S','e','t','P','r','o','g','r','e','s','s',0};
1737     static const WCHAR szWindows_Installer[] =
1738         {'W','i','n','d','o','w','s',' ','I','n','s','t','a','l','l','e','r',0};
1739 
1740     if (!package || (package->ui_level & INSTALLUILEVEL_MASK) == INSTALLUILEVEL_NONE)
1741         return 0;
1742 
1743     /* todo: check if message needs additional styles (topmost/foreground/modality?) */
1744 
1745     switch (eMessageType & 0xff000000)
1746     {
1747     case INSTALLMESSAGE_FATALEXIT:
1748     case INSTALLMESSAGE_ERROR:
1749     case INSTALLMESSAGE_OUTOFDISKSPACE:
1750         if (package->ui_level & INSTALLUILEVEL_PROGRESSONLY) return 0;
1751         if (!(eMessageType & MB_ICONMASK))
1752             eMessageType |= MB_ICONEXCLAMATION;
1753         return MessageBoxW(gUIhwnd, message, szWindows_Installer, eMessageType & 0x00ffffff);
1754     case INSTALLMESSAGE_WARNING:
1755         if (package->ui_level & INSTALLUILEVEL_PROGRESSONLY) return 0;
1756         if (!(eMessageType & MB_ICONMASK))
1757             eMessageType |= MB_ICONASTERISK;
1758         return MessageBoxW(gUIhwnd, message, szWindows_Installer, eMessageType & 0x00ffffff);
1759     case INSTALLMESSAGE_USER:
1760         if (package->ui_level & INSTALLUILEVEL_PROGRESSONLY) return 0;
1761         if (!(eMessageType & MB_ICONMASK))
1762             eMessageType |= MB_USERICON;
1763         return MessageBoxW(gUIhwnd, message, szWindows_Installer, eMessageType & 0x00ffffff);
1764     case INSTALLMESSAGE_INFO:
1765     case INSTALLMESSAGE_INITIALIZE:
1766     case INSTALLMESSAGE_TERMINATE:
1767     case INSTALLMESSAGE_INSTALLSTART:
1768     case INSTALLMESSAGE_INSTALLEND:
1769         return 0;
1770     case INSTALLMESSAGE_SHOWDIALOG:
1771     {
1772         LPWSTR dialog = msi_dup_record_field(record, 0);
1773         INT rc = ACTION_DialogBox(package, dialog);
1774         msi_free(dialog);
1775         return rc;
1776     }
1777     case INSTALLMESSAGE_ACTIONSTART:
1778     {
1779         LPWSTR deformatted;
1780         MSIRECORD *uirow = MSI_CreateRecord(1);
1781         if (!uirow) return -1;
1782         deformat_string(package, MSI_RecordGetString(record, 2), &deformatted);
1783         MSI_RecordSetStringW(uirow, 1, deformatted);
1784         msi_event_fire(package, szActionText, uirow);
1785 
1786         msi_free(deformatted);
1787         msiobj_release(&uirow->hdr);
1788         return 1;
1789     }
1790     case INSTALLMESSAGE_ACTIONDATA:
1791     {
1792         MSIRECORD *uirow = MSI_CreateRecord(1);
1793         if (!uirow) return -1;
1794         MSI_RecordSetStringW(uirow, 1, message);
1795         msi_event_fire(package, szActionData, uirow);
1796         msiobj_release(&uirow->hdr);
1797 
1798         if (package->action_progress_increment)
1799         {
1800             uirow = MSI_CreateRecord(2);
1801             if (!uirow) return -1;
1802             MSI_RecordSetInteger(uirow, 1, 2);
1803             MSI_RecordSetInteger(uirow, 2, package->action_progress_increment);
1804             msi_event_fire(package, szSetProgress, uirow);
1805             msiobj_release(&uirow->hdr);
1806         }
1807         return 1;
1808     }
1809     case INSTALLMESSAGE_PROGRESS:
1810         msi_event_fire(package, szSetProgress, record);
1811         return 1;
1812     case INSTALLMESSAGE_COMMONDATA:
1813         switch (MSI_RecordGetInteger(record, 1))
1814         {
1815         case 0:
1816         case 1:
1817             /* do nothing */
1818             return 0;
1819         default:
1820             /* fall through */
1821             ;
1822         }
1823     default:
1824         FIXME("internal UI not implemented for message 0x%08x (UI level = %x)\n", eMessageType, package->ui_level);
1825         return 0;
1826     }
1827 }
1828 
1829 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};
1830 
1831 static const struct
1832 {
1833     int id;
1834     const WCHAR *text;
1835 }
1836 internal_errors[] =
1837 {
1838     {2726, szActionNotFound},
1839     {0}
1840 };
1841 
1842 static LPCWSTR get_internal_error_message(int error)
1843 {
1844     int i = 0;
1845 
1846     while (internal_errors[i].id != 0)
1847     {
1848         if (internal_errors[i].id == error)
1849             return internal_errors[i].text;
1850         i++;
1851     }
1852 
1853     FIXME("missing error message %d\n", error);
1854     return NULL;
1855 }
1856 
1857 /* Returned string must be freed */
1858 LPWSTR msi_get_error_message(MSIDATABASE *db, int error)
1859 {
1860     static const WCHAR query[] =
1861         {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
1862          'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
1863          '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
1864     MSIRECORD *record;
1865     LPWSTR ret = NULL;
1866 
1867     if ((record = MSI_QueryGetRecord(db, query, error)))
1868     {
1869         ret = msi_dup_record_field(record, 1);
1870         msiobj_release(&record->hdr);
1871     }
1872     else if (error < 2000)
1873     {
1874         int len = LoadStringW(msi_hInstance, IDS_ERROR_BASE + error, (LPWSTR) &ret, 0);
1875         if (len)
1876         {
1877             ret = msi_alloc((len + 1) * sizeof(WCHAR));
1878             LoadStringW(msi_hInstance, IDS_ERROR_BASE + error, ret, len + 1);
1879         }
1880         else
1881             ret = NULL;
1882     }
1883 
1884     return ret;
1885 }
1886 
1887 INT MSI_ProcessMessageVerbatim(MSIPACKAGE *package, INSTALLMESSAGE eMessageType, MSIRECORD *record)
1888 {
1889     LPWSTR message = {0};
1890     DWORD len;
1891     DWORD log_type = 1 << (eMessageType >> 24);
1892     UINT res;
1893     INT rc = 0;
1894     char *msg;
1895 
1896     TRACE("%x\n", eMessageType);
1897     if (TRACE_ON(msi)) dump_record(record);
1898 
1899     if (!package || !record)
1900         message = NULL;
1901     else {
1902         res = MSI_FormatRecordW(package, record, message, &len);
1903         if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
1904             return res;
1905         len++;
1906         message = msi_alloc(len * sizeof(WCHAR));
1907         if (!message) return ERROR_OUTOFMEMORY;
1908         MSI_FormatRecordW(package, record, message, &len);
1909     }
1910 
1911     /* convert it to ASCII */
1912     len = WideCharToMultiByte( CP_ACP, 0, message, -1, NULL, 0, NULL, NULL );
1913     msg = msi_alloc( len );
1914     WideCharToMultiByte( CP_ACP, 0, message, -1, msg, len, NULL, NULL );
1915 
1916     if (gUIHandlerRecord && (gUIFilterRecord & log_type))
1917     {
1918         MSIHANDLE rec = alloc_msihandle(&record->hdr);
1919         TRACE("Calling UI handler %p(pvContext=%p, iMessageType=%08x, hRecord=%u)\n",
1920               gUIHandlerRecord, gUIContextRecord, eMessageType, rec);
1921         rc = gUIHandlerRecord( gUIContextRecord, eMessageType, rec );
1922         MsiCloseHandle( rec );
1923     }
1924     if (!rc && gUIHandlerW && (gUIFilter & log_type))
1925     {
1926         TRACE("Calling UI handler %p(pvContext=%p, iMessageType=%08x, szMessage=%s)\n",
1927               gUIHandlerW, gUIContext, eMessageType, debugstr_w(message));
1928         rc = gUIHandlerW( gUIContext, eMessageType, message );
1929     }
1930     else if (!rc && gUIHandlerA && (gUIFilter & log_type))
1931     {
1932         TRACE("Calling UI handler %p(pvContext=%p, iMessageType=%08x, szMessage=%s)\n",
1933               gUIHandlerA, gUIContext, eMessageType, debugstr_a(msg));
1934         rc = gUIHandlerA( gUIContext, eMessageType, msg );
1935     }
1936 
1937     if (!rc)
1938         rc = internal_ui_handler(package, eMessageType, record, message);
1939 
1940     if (!rc && package && package->log_file != INVALID_HANDLE_VALUE &&
1941         (eMessageType & 0xff000000) != INSTALLMESSAGE_PROGRESS)
1942     {
1943         DWORD written;
1944         WriteFile( package->log_file, msg, len - 1, &written, NULL );
1945         WriteFile( package->log_file, "\n", 1, &written, NULL );
1946     }
1947     msi_free( msg );
1948     msi_free( message );
1949 
1950     return rc;
1951 }
1952 
1953 INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType, MSIRECORD *record )
1954 {
1955     switch (eMessageType & 0xff000000)
1956     {
1957     case INSTALLMESSAGE_FATALEXIT:
1958     case INSTALLMESSAGE_ERROR:
1959     case INSTALLMESSAGE_WARNING:
1960     case INSTALLMESSAGE_USER:
1961     case INSTALLMESSAGE_INFO:
1962     case INSTALLMESSAGE_OUTOFDISKSPACE:
1963         if (MSI_RecordGetInteger(record, 1) != MSI_NULL_INTEGER)
1964         {
1965             /* error message */
1966 
1967             LPWSTR template;
1968             LPWSTR template_rec = NULL, template_prefix = NULL;
1969             int error = MSI_RecordGetInteger(record, 1);
1970 
1971             if (MSI_RecordIsNull(record, 0))
1972             {
1973                 if (error >= 32)
1974                 {
1975                     template_rec = msi_get_error_message(package->db, error);
1976 
1977                     if (!template_rec && error >= 2000)
1978                     {
1979                         /* internal error, not localized */
1980                         if ((template_rec = (LPWSTR) get_internal_error_message(error)))
1981                         {
1982                             MSI_RecordSetStringW(record, 0, template_rec);
1983                             MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_INFO, record);
1984                         }
1985                         template_rec = msi_get_error_message(package->db, MSIERR_INSTALLERROR);
1986                         MSI_RecordSetStringW(record, 0, template_rec);
1987                         MSI_ProcessMessageVerbatim(package, eMessageType, record);
1988                         msi_free(template_rec);
1989                         return 0;
1990                     }
1991                 }
1992             }
1993             else
1994                 template_rec = msi_dup_record_field(record, 0);
1995 
1996             template_prefix = msi_get_error_message(package->db, eMessageType >> 24);
1997             if (!template_prefix) template_prefix = strdupW(szEmpty);
1998 
1999             if (!template_rec)
2000             {
2001                 /* always returns 0 */
2002                 MSI_RecordSetStringW(record, 0, template_prefix);
2003                 MSI_ProcessMessageVerbatim(package, eMessageType, record);
2004                 msi_free(template_prefix);
2005                 return 0;
2006             }
2007 
2008             template = msi_alloc((strlenW(template_rec) + strlenW(template_prefix) + 1) * sizeof(WCHAR));
2009             if (!template) return ERROR_OUTOFMEMORY;
2010 
2011             strcpyW(template, template_prefix);
2012             strcatW(template, template_rec);
2013             MSI_RecordSetStringW(record, 0, template);
2014 
2015             msi_free(template_prefix);
2016             msi_free(template_rec);
2017             msi_free(template);
2018         }
2019         break;
2020     case INSTALLMESSAGE_ACTIONSTART:
2021     {
2022         WCHAR *template = msi_get_error_message(package->db, MSIERR_ACTIONSTART);
2023         MSI_RecordSetStringW(record, 0, template);
2024         msi_free(template);
2025 
2026         msi_free(package->LastAction);
2027         msi_free(package->LastActionTemplate);
2028         package->LastAction = msi_dup_record_field(record, 1);
2029         if (!package->LastAction) package->LastAction = strdupW(szEmpty);
2030         package->LastActionTemplate = msi_dup_record_field(record, 3);
2031         break;
2032     }
2033     case INSTALLMESSAGE_ACTIONDATA:
2034         if (package->LastAction && package->LastActionTemplate)
2035         {
2036             static const WCHAR template_s[] =
2037                 {'{','{','%','s',':',' ','}','}','%','s',0};
2038             WCHAR *template;
2039 
2040             template = msi_alloc((strlenW(package->LastAction) + strlenW(package->LastActionTemplate) + 7) * sizeof(WCHAR));
2041             if (!template) return ERROR_OUTOFMEMORY;
2042             sprintfW(template, template_s, package->LastAction, package->LastActionTemplate);
2043             MSI_RecordSetStringW(record, 0, template);
2044             msi_free(template);
2045         }
2046         break;
2047     case INSTALLMESSAGE_COMMONDATA:
2048     {
2049         WCHAR *template = msi_get_error_message(package->db, MSIERR_COMMONDATA);
2050         MSI_RecordSetStringW(record, 0, template);
2051         msi_free(template);
2052     }
2053     break;
2054     }
2055 
2056     return MSI_ProcessMessageVerbatim(package, eMessageType, record);
2057 }
2058 
2059 INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
2060                               MSIHANDLE hRecord)
2061 {
2062     UINT ret = ERROR_INVALID_HANDLE;
2063     MSIPACKAGE *package = NULL;
2064     MSIRECORD *record = NULL;
2065 
2066     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INITIALIZE ||
2067         (eMessageType & 0xff000000) == INSTALLMESSAGE_TERMINATE)
2068         return -1;
2069 
2070     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA &&
2071         MsiRecordGetInteger(hRecord, 1) != 2)
2072         return -1;
2073 
2074     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
2075     if( !package )
2076     {
2077         HRESULT hr;
2078         IWineMsiRemotePackage *remote_package;
2079 
2080         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
2081         if (!remote_package)
2082             return ERROR_INVALID_HANDLE;
2083 
2084         hr = IWineMsiRemotePackage_ProcessMessage( remote_package, eMessageType, hRecord );
2085 
2086         IWineMsiRemotePackage_Release( remote_package );
2087 
2088         if (FAILED(hr))
2089         {
2090             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
2091                 return HRESULT_CODE(hr);
2092 
2093             return ERROR_FUNCTION_FAILED;
2094         }
2095 
2096         return ERROR_SUCCESS;
2097     }
2098 
2099     record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
2100     if( !record )
2101         goto out;
2102 
2103     ret = MSI_ProcessMessage( package, eMessageType, record );
2104 
2105 out:
2106     msiobj_release( &package->hdr );
2107     if( record )
2108         msiobj_release( &record->hdr );
2109 
2110     return ret;
2111 }
2112 
2113 /* property code */
2114 
2115 UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue )
2116 {
2117     LPWSTR szwName = NULL, szwValue = NULL;
2118     UINT r = ERROR_OUTOFMEMORY;
2119 
2120     szwName = strdupAtoW( szName );
2121     if( szName && !szwName )
2122         goto end;
2123 
2124     szwValue = strdupAtoW( szValue );
2125     if( szValue && !szwValue )
2126         goto end;
2127 
2128     r = MsiSetPropertyW( hInstall, szwName, szwValue);
2129 
2130 end:
2131     msi_free( szwName );
2132     msi_free( szwValue );
2133 
2134     return r;
2135 }
2136 
2137 void msi_reset_folders( MSIPACKAGE *package, BOOL source )
2138 {
2139     MSIFOLDER *folder;
2140 
2141     LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
2142     {
2143         if ( source )
2144         {
2145             msi_free( folder->ResolvedSource );
2146             folder->ResolvedSource = NULL;
2147         }
2148         else
2149         {
2150             msi_free( folder->ResolvedTarget );
2151             folder->ResolvedTarget = NULL;
2152         }
2153     }
2154 }
2155 
2156 UINT msi_set_property( MSIDATABASE *db, const WCHAR *name, const WCHAR *value, int len )
2157 {
2158     static const WCHAR insert_query[] = {
2159         'I','N','S','E','R','T',' ','I','N','T','O',' ',
2160         '`','_','P','r','o','p','e','r','t','y','`',' ',
2161         '(','`','_','P','r','o','p','e','r','t','y','`',',','`','V','a','l','u','e','`',')',' ',
2162         'V','A','L','U','E','S',' ','(','?',',','?',')',0};
2163     static const WCHAR update_query[] = {
2164         'U','P','D','A','T','E',' ','`','_','P','r','o','p','e','r','t','y','`',' ',
2165         'S','E','T',' ','`','V','a','l','u','e','`',' ','=',' ','?',' ','W','H','E','R','E',' ',
2166         '`','_','P','r','o','p','e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
2167     static const WCHAR delete_query[] = {
2168         'D','E','L','E','T','E',' ','F','R','O','M',' ',
2169         '`','_','P','r','o','p','e','r','t','y','`',' ','W','H','E','R','E',' ',
2170         '`','_','P','r','o','p','e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
2171     MSIQUERY *view;
2172     MSIRECORD *row = NULL;
2173     DWORD sz = 0;
2174     WCHAR query[1024];
2175     UINT rc;
2176 
2177     TRACE("%p %s %s %d\n", db, debugstr_w(name), debugstr_wn(value, len), len);
2178 
2179     if (!name)
2180         return ERROR_INVALID_PARAMETER;
2181 
2182     /* this one is weird... */
2183     if (!name[0])
2184         return value ? ERROR_FUNCTION_FAILED : ERROR_SUCCESS;
2185 
2186     if (value && len < 0) len = strlenW( value );
2187 
2188     rc = msi_get_property( db, name, 0, &sz );
2189     if (!value || (!*value && !len))
2190     {
2191         sprintfW( query, delete_query, name );
2192     }
2193     else if (rc == ERROR_MORE_DATA || rc == ERROR_SUCCESS)
2194     {
2195         sprintfW( query, update_query, name );
2196         row = MSI_CreateRecord(1);
2197         msi_record_set_string( row, 1, value, len );
2198     }
2199     else
2200     {
2201         strcpyW( query, insert_query );
2202         row = MSI_CreateRecord(2);
2203         msi_record_set_string( row, 1, name, -1 );
2204         msi_record_set_string( row, 2, value, len );
2205     }
2206 
2207     rc = MSI_DatabaseOpenViewW(db, query, &view);
2208     if (rc == ERROR_SUCCESS)
2209     {
2210         rc = MSI_ViewExecute(view, row);
2211         MSI_ViewClose(view);
2212         msiobj_release(&view->hdr);
2213     }
2214     if (row) msiobj_release(&row->hdr);
2215     return rc;
2216 }
2217 
2218 UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
2219 {
2220     MSIPACKAGE *package;
2221     UINT ret;
2222 
2223     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
2224     if( !package )
2225     {
2226         HRESULT hr;
2227         BSTR name = NULL, value = NULL;
2228         IWineMsiRemotePackage *remote_package;
2229 
2230         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
2231         if (!remote_package)
2232             return ERROR_INVALID_HANDLE;
2233 
2234         name = SysAllocString( szName );
2235         value = SysAllocString( szValue );
2236         if ((!name && szName) || (!value && szValue))
2237         {
2238             SysFreeString( name );
2239             SysFreeString( value );
2240             IWineMsiRemotePackage_Release( remote_package );
2241             return ERROR_OUTOFMEMORY;
2242         }
2243 
2244         hr = IWineMsiRemotePackage_SetProperty( remote_package, name, value );
2245 
2246         SysFreeString( name );
2247         SysFreeString( value );
2248         IWineMsiRemotePackage_Release( remote_package );
2249 
2250         if (FAILED(hr))
2251         {
2252             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
2253                 return HRESULT_CODE(hr);
2254 
2255             return ERROR_FUNCTION_FAILED;
2256         }
2257 
2258         return ERROR_SUCCESS;
2259     }
2260 
2261     ret = msi_set_property( package->db, szName, szValue, -1 );
2262     if (ret == ERROR_SUCCESS && !strcmpW( szName, szSourceDir ))
2263         msi_reset_folders( package, TRUE );
2264 
2265     msiobj_release( &package->hdr );
2266     return ret;
2267 }
2268 
2269 static MSIRECORD *msi_get_property_row( MSIDATABASE *db, LPCWSTR name )
2270 {
2271     static const WCHAR query[]= {
2272         'S','E','L','E','C','T',' ','`','V','a','l','u','e','`',' ',
2273         'F','R','O','M',' ' ,'`','_','P','r','o','p','e','r','t','y','`',' ',
2274         'W','H','E','R','E',' ' ,'`','_','P','r','o','p','e','r','t','y','`','=','?',0};
2275     MSIRECORD *rec, *row = NULL;
2276     MSIQUERY *view;
2277     UINT r;
2278 
2279     static const WCHAR szDate[] = {'D','a','t','e',0};
2280     static const WCHAR szTime[] = {'T','i','m','e',0};
2281     WCHAR *buffer;
2282     int length;
2283 
2284     if (!name || !*name)
2285         return NULL;
2286 
2287     if (!strcmpW(name, szDate))
2288     {
2289         length = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, NULL, 0);
2290         if (!length)
2291             return NULL;
2292         buffer = msi_alloc(length * sizeof(WCHAR));
2293         GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, buffer, length);
2294 
2295         row = MSI_CreateRecord(1);
2296         if (!row)
2297         {
2298             msi_free(buffer);
2299             return NULL;
2300         }
2301         MSI_RecordSetStringW(row, 1, buffer);
2302         msi_free(buffer);
2303         return row;
2304     }
2305     else if (!strcmpW(name, szTime))
2306     {
2307         length = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOTIMEMARKER, NULL, NULL, NULL, 0);
2308         if (!length)
2309             return NULL;
2310         buffer = msi_alloc(length * sizeof(WCHAR));
2311         GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOTIMEMARKER, NULL, NULL, buffer, length);
2312 
2313         row = MSI_CreateRecord(1);
2314         if (!row)
2315         {
2316             msi_free(buffer);
2317             return NULL;
2318         }
2319         MSI_RecordSetStringW(row, 1, buffer);
2320         msi_free(buffer);
2321         return row;
2322     }
2323 
2324     rec = MSI_CreateRecord(1);
2325     if (!rec)
2326         return NULL;
2327 
2328     MSI_RecordSetStringW(rec, 1, name);
2329 
2330     r = MSI_DatabaseOpenViewW(db, query, &view);
2331     if (r == ERROR_SUCCESS)
2332     {
2333         MSI_ViewExecute(view, rec);
2334         MSI_ViewFetch(view, &row);
2335         MSI_ViewClose(view);
2336         msiobj_release(&view->hdr);
2337     }
2338     msiobj_release(&rec->hdr);
2339     return row;
2340 }
2341 
2342 /* internal function, not compatible with MsiGetPropertyW */
2343 UINT msi_get_property( MSIDATABASE *db, LPCWSTR szName,
2344                        LPWSTR szValueBuf, LPDWORD pchValueBuf )
2345 {
2346     MSIRECORD *row;
2347     UINT rc = ERROR_FUNCTION_FAILED;
2348 
2349     TRACE("%p %s %p %p\n", db, debugstr_w(szName), szValueBuf, pchValueBuf);
2350 
2351     row = msi_get_property_row( db, szName );
2352 
2353     if (*pchValueBuf > 0)
2354         szValueBuf[0] = 0;
2355 
2356     if (row)
2357     {
2358         rc = MSI_RecordGetStringW(row, 1, szValueBuf, pchValueBuf);
2359         msiobj_release(&row->hdr);
2360     }
2361 
2362     if (rc == ERROR_SUCCESS)
2363         TRACE("returning %s for property %s\n", debugstr_wn(szValueBuf, *pchValueBuf),
2364             debugstr_w(szName));
2365     else if (rc == ERROR_MORE_DATA)
2366         TRACE("need %d sized buffer for %s\n", *pchValueBuf,
2367             debugstr_w(szName));
2368     else
2369     {
2370         *pchValueBuf = 0;
2371         TRACE("property %s not found\n", debugstr_w(szName));
2372     }
2373 
2374     return rc;
2375 }
2376 
2377 LPWSTR msi_dup_property(MSIDATABASE *db, LPCWSTR prop)
2378 {
2379     DWORD sz = 0;
2380     LPWSTR str;
2381     UINT r;
2382 
2383     r = msi_get_property(db, prop, NULL, &sz);
2384     if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
2385         return NULL;
2386 
2387     sz++;
2388     str = msi_alloc(sz * sizeof(WCHAR));
2389     r = msi_get_property(db, prop, str, &sz);
2390     if (r != ERROR_SUCCESS)
2391     {
2392         msi_free(str);
2393         str = NULL;
2394     }
2395 
2396     return str;
2397 }
2398 
2399 int msi_get_property_int( MSIDATABASE *db, LPCWSTR prop, int def )
2400 {
2401     LPWSTR str = msi_dup_property( db, prop );
2402     int val = str ? atoiW(str) : def;
2403     msi_free(str);
2404     return val;
2405 }
2406 
2407 static UINT MSI_GetProperty( MSIHANDLE handle, LPCWSTR name,
2408                              awstring *szValueBuf, LPDWORD pchValueBuf )
2409 {
2410     MSIPACKAGE *package;
2411     MSIRECORD *row = NULL;
2412     UINT r = ERROR_FUNCTION_FAILED;
2413     LPCWSTR val = NULL;
2414     DWORD len = 0;
2415 
2416     TRACE("%u %s %p %p\n", handle, debugstr_w(name),
2417           szValueBuf->str.w, pchValueBuf );
2418 
2419     if (!name)
2420         return ERROR_INVALID_PARAMETER;
2421 
2422     package = msihandle2msiinfo( handle, MSIHANDLETYPE_PACKAGE );
2423     if (!package)
2424     {
2425         HRESULT hr;
2426         IWineMsiRemotePackage *remote_package;
2427         LPWSTR value = NULL;
2428         BSTR bname;
2429 
2430         remote_package = (IWineMsiRemotePackage *)msi_get_remote( handle );
2431         if (!remote_package)
2432             return ERROR_INVALID_HANDLE;
2433 
2434         bname = SysAllocString( name );
2435         if (!bname)
2436         {
2437             IWineMsiRemotePackage_Release( remote_package );
2438             return ERROR_OUTOFMEMORY;
2439         }
2440 
2441         hr = IWineMsiRemotePackage_GetProperty( remote_package, bname, NULL, &len );
2442         if (FAILED(hr))
2443             goto done;
2444 
2445         len++;
2446         value = msi_alloc(len * sizeof(WCHAR));
2447         if (!value)
2448         {
2449             r = ERROR_OUTOFMEMORY;
2450             goto done;
2451         }
2452 
2453         hr = IWineMsiRemotePackage_GetProperty( remote_package, bname, value, &len );
2454         if (FAILED(hr))
2455             goto done;
2456 
2457         r = msi_strcpy_to_awstring( value, len, szValueBuf, pchValueBuf );
2458 
2459         /* Bug required by Adobe installers */
2460         if (!szValueBuf->unicode && !szValueBuf->str.a)
2461             *pchValueBuf *= sizeof(WCHAR);
2462 
2463 done:
2464         IWineMsiRemotePackage_Release(remote_package);
2465         SysFreeString(bname);
2466         msi_free(value);
2467 
2468         if (FAILED(hr))
2469         {
2470             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
2471                 return HRESULT_CODE(hr);
2472 
2473             return ERROR_FUNCTION_FAILED;
2474         }
2475 
2476         return r;
2477     }
2478 
2479     row = msi_get_property_row( package->db, name );
2480     if (row)
2481         val = msi_record_get_string( row, 1, (int *)&len );
2482 
2483     if (!val)
2484         val = szEmpty;
2485 
2486     r = msi_strcpy_to_awstring( val, len, szValueBuf, pchValueBuf );
2487 
2488     if (row)
2489         msiobj_release( &row->hdr );
2490     msiobj_release( &package->hdr );
2491 
2492     return r;
2493 }
2494 
2495 UINT WINAPI MsiGetPropertyA( MSIHANDLE hInstall, LPCSTR szName,
2496                              LPSTR szValueBuf, LPDWORD pchValueBuf )
2497 {
2498     awstring val;
2499     LPWSTR name;
2500     UINT r;
2501 
2502     val.unicode = FALSE;
2503     val.str.a = szValueBuf;
2504 
2505     name = strdupAtoW( szName );
2506     if (szName && !name)
2507         return ERROR_OUTOFMEMORY;
2508 
2509     r = MSI_GetProperty( hInstall, name, &val, pchValueBuf );
2510     msi_free( name );
2511     return r;
2512 }
2513 
2514 UINT WINAPI MsiGetPropertyW( MSIHANDLE hInstall, LPCWSTR szName,
2515                              LPWSTR szValueBuf, LPDWORD pchValueBuf )
2516 {
2517     awstring val;
2518 
2519     val.unicode = TRUE;
2520     val.str.w = szValueBuf;
2521 
2522     return MSI_GetProperty( hInstall, szName, &val, pchValueBuf );
2523 }
2524 
2525 typedef struct _msi_remote_package_impl {
2526     IWineMsiRemotePackage IWineMsiRemotePackage_iface;
2527     MSIHANDLE package;
2528     LONG refs;
2529 } msi_remote_package_impl;
2530 
2531 static inline msi_remote_package_impl *impl_from_IWineMsiRemotePackage( IWineMsiRemotePackage *iface )
2532 {
2533     return CONTAINING_RECORD(iface, msi_remote_package_impl, IWineMsiRemotePackage_iface);
2534 }
2535 
2536 static HRESULT WINAPI mrp_QueryInterface( IWineMsiRemotePackage *iface,
2537                 REFIID riid,LPVOID *ppobj)
2538 {
2539     if( IsEqualCLSID( riid, &IID_IUnknown ) ||
2540         IsEqualCLSID( riid, &IID_IWineMsiRemotePackage ) )
2541     {
2542         IWineMsiRemotePackage_AddRef( iface );
2543         *ppobj = iface;
2544         return S_OK;
2545     }
2546 
2547     return E_NOINTERFACE;
2548 }
2549 
2550 static ULONG WINAPI mrp_AddRef( IWineMsiRemotePackage *iface )
2551 {
2552     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2553 
2554     return InterlockedIncrement( &This->refs );
2555 }
2556 
2557 static ULONG WINAPI mrp_Release( IWineMsiRemotePackage *iface )
2558 {
2559     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2560     ULONG r;
2561 
2562     r = InterlockedDecrement( &This->refs );
2563     if (r == 0)
2564     {
2565         MsiCloseHandle( This->package );
2566         msi_free( This );
2567     }
2568     return r;
2569 }
2570 
2571 static HRESULT WINAPI mrp_SetMsiHandle( IWineMsiRemotePackage *iface, MSIHANDLE handle )
2572 {
2573     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2574     This->package = handle;
2575     return S_OK;
2576 }
2577 
2578 static HRESULT WINAPI mrp_GetActiveDatabase( IWineMsiRemotePackage *iface, MSIHANDLE *handle )
2579 {
2580     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2581     IWineMsiRemoteDatabase *rdb = NULL;
2582     HRESULT hr;
2583     MSIHANDLE hdb;
2584 
2585     hr = create_msi_remote_database( NULL, (LPVOID *)&rdb );
2586     if (FAILED(hr) || !rdb)
2587     {
2588         ERR("Failed to create remote database\n");
2589         return hr;
2590     }
2591 
2592     hdb = MsiGetActiveDatabase(This->package);
2593 
2594     hr = IWineMsiRemoteDatabase_SetMsiHandle( rdb, hdb );
2595     if (FAILED(hr))
2596     {
2597         ERR("Failed to set the database handle\n");
2598         return hr;
2599     }
2600 
2601     *handle = alloc_msi_remote_handle( (IUnknown *)rdb );
2602     return S_OK;
2603 }
2604 
2605 static HRESULT WINAPI mrp_GetProperty( IWineMsiRemotePackage *iface, BSTR property, BSTR value, DWORD *size )
2606 {
2607     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2608     UINT r = MsiGetPropertyW(This->package, property, value, size);
2609     if (r != ERROR_SUCCESS) return HRESULT_FROM_WIN32(r);
2610     return S_OK;
2611 }
2612 
2613 static HRESULT WINAPI mrp_SetProperty( IWineMsiRemotePackage *iface, BSTR property, BSTR value )
2614 {
2615     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2616     UINT r = MsiSetPropertyW(This->package, property, value);
2617     return HRESULT_FROM_WIN32(r);
2618 }
2619 
2620 static HRESULT WINAPI mrp_ProcessMessage( IWineMsiRemotePackage *iface, INSTALLMESSAGE message, MSIHANDLE record )
2621 {
2622     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2623     UINT r = MsiProcessMessage(This->package, message, record);
2624     return HRESULT_FROM_WIN32(r);
2625 }
2626 
2627 static HRESULT WINAPI mrp_DoAction( IWineMsiRemotePackage *iface, BSTR action )
2628 {
2629     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2630     UINT r = MsiDoActionW(This->package, action);
2631     return HRESULT_FROM_WIN32(r);
2632 }
2633 
2634 static HRESULT WINAPI mrp_Sequence( IWineMsiRemotePackage *iface, BSTR table, int sequence )
2635 {
2636     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2637     UINT r = MsiSequenceW(This->package, table, sequence);
2638     return HRESULT_FROM_WIN32(r);
2639 }
2640 
2641 static HRESULT WINAPI mrp_GetTargetPath( IWineMsiRemotePackage *iface, BSTR folder, BSTR value, DWORD *size )
2642 {
2643     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2644     UINT r = MsiGetTargetPathW(This->package, folder, value, size);
2645     return HRESULT_FROM_WIN32(r);
2646 }
2647 
2648 static HRESULT WINAPI mrp_SetTargetPath( IWineMsiRemotePackage *iface, BSTR folder, BSTR value)
2649 {
2650     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2651     UINT r = MsiSetTargetPathW(This->package, folder, value);
2652     return HRESULT_FROM_WIN32(r);
2653 }
2654 
2655 static HRESULT WINAPI mrp_GetSourcePath( IWineMsiRemotePackage *iface, BSTR folder, BSTR value, DWORD *size )
2656 {
2657     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2658     UINT r = MsiGetSourcePathW(This->package, folder, value, size);
2659     return HRESULT_FROM_WIN32(r);
2660 }
2661 
2662 static HRESULT WINAPI mrp_GetMode( IWineMsiRemotePackage *iface, MSIRUNMODE mode, BOOL *ret )
2663 {
2664     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2665     *ret = MsiGetMode(This->package, mode);
2666     return S_OK;
2667 }
2668 
2669 static HRESULT WINAPI mrp_SetMode( IWineMsiRemotePackage *iface, MSIRUNMODE mode, BOOL state )
2670 {
2671     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2672     UINT r = MsiSetMode(This->package, mode, state);
2673     return HRESULT_FROM_WIN32(r);
2674 }
2675 
2676 static HRESULT WINAPI mrp_GetFeatureState( IWineMsiRemotePackage *iface, BSTR feature,
2677                                     INSTALLSTATE *installed, INSTALLSTATE *action )
2678 {
2679     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2680     UINT r = MsiGetFeatureStateW(This->package, feature, installed, action);
2681     return HRESULT_FROM_WIN32(r);
2682 }
2683 
2684 static HRESULT WINAPI mrp_SetFeatureState( IWineMsiRemotePackage *iface, BSTR feature, INSTALLSTATE state )
2685 {
2686     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2687     UINT r = MsiSetFeatureStateW(This->package, feature, state);
2688     return HRESULT_FROM_WIN32(r);
2689 }
2690 
2691 static HRESULT WINAPI mrp_GetComponentState( IWineMsiRemotePackage *iface, BSTR component,
2692                                       INSTALLSTATE *installed, INSTALLSTATE *action )
2693 {
2694     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2695     UINT r = MsiGetComponentStateW(This->package, component, installed, action);
2696     return HRESULT_FROM_WIN32(r);
2697 }
2698 
2699 static HRESULT WINAPI mrp_SetComponentState( IWineMsiRemotePackage *iface, BSTR component, INSTALLSTATE state )
2700 {
2701     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2702     UINT r = MsiSetComponentStateW(This->package, component, state);
2703     return HRESULT_FROM_WIN32(r);
2704 }
2705 
2706 static HRESULT WINAPI mrp_GetLanguage( IWineMsiRemotePackage *iface, LANGID *language )
2707 {
2708     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2709     *language = MsiGetLanguage(This->package);
2710     return S_OK;
2711 }
2712 
2713 static HRESULT WINAPI mrp_SetInstallLevel( IWineMsiRemotePackage *iface, int level )
2714 {
2715     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2716     UINT r = MsiSetInstallLevel(This->package, level);
2717     return HRESULT_FROM_WIN32(r);
2718 }
2719 
2720 static HRESULT WINAPI mrp_FormatRecord( IWineMsiRemotePackage *iface, MSIHANDLE record,
2721                                         BSTR *value)
2722 {
2723     DWORD size = 0;
2724     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2725     UINT r = MsiFormatRecordW(This->package, record, NULL, &size);
2726     if (r == ERROR_SUCCESS)
2727     {
2728         *value = SysAllocStringLen(NULL, size);
2729         if (!*value)
2730             return E_OUTOFMEMORY;
2731         size++;
2732         r = MsiFormatRecordW(This->package, record, *value, &size);
2733     }
2734     return HRESULT_FROM_WIN32(r);
2735 }
2736 
2737 static HRESULT WINAPI mrp_EvaluateCondition( IWineMsiRemotePackage *iface, BSTR condition )
2738 {
2739     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2740     UINT r = MsiEvaluateConditionW(This->package, condition);
2741     return HRESULT_FROM_WIN32(r);
2742 }
2743 
2744 static HRESULT WINAPI mrp_GetFeatureCost( IWineMsiRemotePackage *iface, BSTR feature,
2745                                           INT cost_tree, INSTALLSTATE state, INT *cost )
2746 {
2747     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2748     UINT r = MsiGetFeatureCostW(This->package, feature, cost_tree, state, cost);
2749     return HRESULT_FROM_WIN32(r);
2750 }
2751 
2752 static HRESULT WINAPI mrp_EnumComponentCosts( IWineMsiRemotePackage *iface, BSTR component,
2753                                               DWORD index, INSTALLSTATE state, BSTR drive,
2754                                               DWORD *buflen, INT *cost, INT *temp )
2755 {
2756     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
2757     UINT r = MsiEnumComponentCostsW(This->package, component, index, state, drive, buflen, cost, temp);
2758     return HRESULT_FROM_WIN32(r);
2759 }
2760 
2761 static const IWineMsiRemotePackageVtbl msi_remote_package_vtbl =
2762 {
2763     mrp_QueryInterface,
2764     mrp_AddRef,
2765     mrp_Release,
2766     mrp_SetMsiHandle,
2767     mrp_GetActiveDatabase,
2768     mrp_GetProperty,
2769     mrp_SetProperty,
2770     mrp_ProcessMessage,
2771     mrp_DoAction,
2772     mrp_Sequence,
2773     mrp_GetTargetPath,
2774     mrp_SetTargetPath,
2775     mrp_GetSourcePath,
2776     mrp_GetMode,
2777     mrp_SetMode,
2778     mrp_GetFeatureState,
2779     mrp_SetFeatureState,
2780     mrp_GetComponentState,
2781     mrp_SetComponentState,
2782     mrp_GetLanguage,
2783     mrp_SetInstallLevel,
2784     mrp_FormatRecord,
2785     mrp_EvaluateCondition,
2786     mrp_GetFeatureCost,
2787     mrp_EnumComponentCosts
2788 };
2789 
2790 HRESULT create_msi_remote_package( IUnknown *pOuter, LPVOID *ppObj )
2791 {
2792     msi_remote_package_impl* This;
2793 
2794     This = msi_alloc( sizeof *This );
2795     if (!This)
2796         return E_OUTOFMEMORY;
2797 
2798     This->IWineMsiRemotePackage_iface.lpVtbl = &msi_remote_package_vtbl;
2799     This->package = 0;
2800     This->refs = 1;
2801 
2802     *ppObj = &This->IWineMsiRemotePackage_iface;
2803 
2804     return S_OK;
2805 }
2806 
2807 UINT msi_package_add_info(MSIPACKAGE *package, DWORD context, DWORD options,
2808                           LPCWSTR property, LPWSTR value)
2809 {
2810     MSISOURCELISTINFO *info;
2811 
2812     LIST_FOR_EACH_ENTRY( info, &package->sourcelist_info, MSISOURCELISTINFO, entry )
2813     {
2814         if (!strcmpW( info->value, value )) return ERROR_SUCCESS;
2815     }
2816 
2817     info = msi_alloc(sizeof(MSISOURCELISTINFO));
2818     if (!info)
2819         return ERROR_OUTOFMEMORY;
2820 
2821     info->context = context;
2822     info->options = options;
2823     info->property = property;
2824     info->value = strdupW(value);
2825     list_add_head(&package->sourcelist_info, &info->entry);
2826 
2827     return ERROR_SUCCESS;
2828 }
2829 
2830 UINT msi_package_add_media_disk(MSIPACKAGE *package, DWORD context, DWORD options,
2831                                 DWORD disk_id, LPWSTR volume_label, LPWSTR disk_prompt)
2832 {
2833     MSIMEDIADISK *disk;
2834 
2835     LIST_FOR_EACH_ENTRY( disk, &package->sourcelist_media, MSIMEDIADISK, entry )
2836     {
2837         if (disk->disk_id == disk_id) return ERROR_SUCCESS;
2838     }
2839 
2840     disk = msi_alloc(sizeof(MSIMEDIADISK));
2841     if (!disk)
2842         return ERROR_OUTOFMEMORY;
2843 
2844     disk->context = context;
2845     disk->options = options;
2846     disk->disk_id = disk_id;
2847     disk->volume_label = strdupW(volume_label);
2848     disk->disk_prompt = strdupW(disk_prompt);
2849     list_add_head(&package->sourcelist_media, &disk->entry);
2850 
2851     return ERROR_SUCCESS;
2852 }
2853