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