xref: /reactos/dll/win32/msi/package.c (revision 02f995b2)
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/debug.h"
54 #include "wine/exception.h"
55 
56 #include "msipriv.h"
57 #include "winemsi_s.h"
58 #include "resource.h"
59 
60 WINE_DEFAULT_DEBUG_CHANNEL(msi);
61 
62 static void free_feature( MSIFEATURE *feature )
63 {
64     struct list *item, *cursor;
65 
66     LIST_FOR_EACH_SAFE( item, cursor, &feature->Children )
67     {
68         FeatureList *fl = LIST_ENTRY( item, FeatureList, entry );
69         list_remove( &fl->entry );
70         msi_free( fl );
71     }
72 
73     LIST_FOR_EACH_SAFE( item, cursor, &feature->Components )
74     {
75         ComponentList *cl = LIST_ENTRY( item, ComponentList, entry );
76         list_remove( &cl->entry );
77         msi_free( cl );
78     }
79     msi_free( feature->Feature );
80     msi_free( feature->Feature_Parent );
81     msi_free( feature->Directory );
82     msi_free( feature->Description );
83     msi_free( feature->Title );
84     msi_free( feature );
85 }
86 
87 static void free_folder( MSIFOLDER *folder )
88 {
89     struct list *item, *cursor;
90 
91     LIST_FOR_EACH_SAFE( item, cursor, &folder->children )
92     {
93         FolderList *fl = LIST_ENTRY( item, FolderList, entry );
94         list_remove( &fl->entry );
95         msi_free( fl );
96     }
97     msi_free( folder->Parent );
98     msi_free( folder->Directory );
99     msi_free( folder->TargetDefault );
100     msi_free( folder->SourceLongPath );
101     msi_free( folder->SourceShortPath );
102     msi_free( folder->ResolvedTarget );
103     msi_free( folder->ResolvedSource );
104     msi_free( folder );
105 }
106 
107 static void free_extension( MSIEXTENSION *ext )
108 {
109     struct list *item, *cursor;
110 
111     LIST_FOR_EACH_SAFE( item, cursor, &ext->verbs )
112     {
113         MSIVERB *verb = LIST_ENTRY( item, MSIVERB, entry );
114 
115         list_remove( &verb->entry );
116         msi_free( verb->Verb );
117         msi_free( verb->Command );
118         msi_free( verb->Argument );
119         msi_free( verb );
120     }
121 
122     msi_free( ext->Extension );
123     msi_free( ext->ProgIDText );
124     msi_free( ext );
125 }
126 
127 static void free_assembly( MSIASSEMBLY *assembly )
128 {
129     msi_free( assembly->feature );
130     msi_free( assembly->manifest );
131     msi_free( assembly->application );
132     msi_free( assembly->display_name );
133     if (assembly->tempdir) RemoveDirectoryW( assembly->tempdir );
134     msi_free( assembly->tempdir );
135     msi_free( assembly );
136 }
137 
138 void msi_free_action_script( MSIPACKAGE *package, UINT script )
139 {
140     UINT i;
141     for (i = 0; i < package->script_actions_count[script]; i++)
142         msi_free( package->script_actions[script][i] );
143 
144     msi_free( package->script_actions[script] );
145     package->script_actions[script] = NULL;
146     package->script_actions_count[script] = 0;
147 }
148 
149 static void free_package_structures( MSIPACKAGE *package )
150 {
151     struct list *item, *cursor;
152     int i;
153 
154     LIST_FOR_EACH_SAFE( item, cursor, &package->features )
155     {
156         MSIFEATURE *feature = LIST_ENTRY( item, MSIFEATURE, entry );
157         list_remove( &feature->entry );
158         free_feature( feature );
159     }
160 
161     LIST_FOR_EACH_SAFE( item, cursor, &package->folders )
162     {
163         MSIFOLDER *folder = LIST_ENTRY( item, MSIFOLDER, entry );
164         list_remove( &folder->entry );
165         free_folder( folder );
166     }
167 
168     LIST_FOR_EACH_SAFE( item, cursor, &package->files )
169     {
170         MSIFILE *file = LIST_ENTRY( item, MSIFILE, entry );
171 
172         list_remove( &file->entry );
173         msi_free( file->File );
174         msi_free( file->FileName );
175         msi_free( file->ShortName );
176         msi_free( file->LongName );
177         msi_free( file->Version );
178         msi_free( file->Language );
179         if (msi_is_global_assembly( file->Component )) DeleteFileW( file->TargetPath );
180         msi_free( file->TargetPath );
181         msi_free( file );
182     }
183 
184     LIST_FOR_EACH_SAFE( item, cursor, &package->components )
185     {
186         MSICOMPONENT *comp = LIST_ENTRY( item, MSICOMPONENT, entry );
187 
188         list_remove( &comp->entry );
189         msi_free( comp->Component );
190         msi_free( comp->ComponentId );
191         msi_free( comp->Directory );
192         msi_free( comp->Condition );
193         msi_free( comp->KeyPath );
194         msi_free( comp->FullKeypath );
195         if (comp->assembly) free_assembly( comp->assembly );
196         msi_free( comp );
197     }
198 
199     LIST_FOR_EACH_SAFE( item, cursor, &package->filepatches )
200     {
201         MSIFILEPATCH *patch = LIST_ENTRY( item, MSIFILEPATCH, entry );
202 
203         list_remove( &patch->entry );
204         msi_free( patch->path );
205         msi_free( patch );
206     }
207 
208     /* clean up extension, progid, class and verb structures */
209     LIST_FOR_EACH_SAFE( item, cursor, &package->classes )
210     {
211         MSICLASS *cls = LIST_ENTRY( item, MSICLASS, entry );
212 
213         list_remove( &cls->entry );
214         msi_free( cls->clsid );
215         msi_free( cls->Context );
216         msi_free( cls->Description );
217         msi_free( cls->FileTypeMask );
218         msi_free( cls->IconPath );
219         msi_free( cls->DefInprocHandler );
220         msi_free( cls->DefInprocHandler32 );
221         msi_free( cls->Argument );
222         msi_free( cls->ProgIDText );
223         msi_free( cls );
224     }
225 
226     LIST_FOR_EACH_SAFE( item, cursor, &package->extensions )
227     {
228         MSIEXTENSION *ext = LIST_ENTRY( item, MSIEXTENSION, entry );
229 
230         list_remove( &ext->entry );
231         free_extension( ext );
232     }
233 
234     LIST_FOR_EACH_SAFE( item, cursor, &package->progids )
235     {
236         MSIPROGID *progid = LIST_ENTRY( item, MSIPROGID, entry );
237 
238         list_remove( &progid->entry );
239         msi_free( progid->ProgID );
240         msi_free( progid->Description );
241         msi_free( progid->IconPath );
242         msi_free( progid );
243     }
244 
245     LIST_FOR_EACH_SAFE( item, cursor, &package->mimes )
246     {
247         MSIMIME *mt = LIST_ENTRY( item, MSIMIME, entry );
248 
249         list_remove( &mt->entry );
250         msi_free( mt->suffix );
251         msi_free( mt->clsid );
252         msi_free( mt->ContentType );
253         msi_free( mt );
254     }
255 
256     LIST_FOR_EACH_SAFE( item, cursor, &package->appids )
257     {
258         MSIAPPID *appid = LIST_ENTRY( item, MSIAPPID, entry );
259 
260         list_remove( &appid->entry );
261         msi_free( appid->AppID );
262         msi_free( appid->RemoteServerName );
263         msi_free( appid->LocalServer );
264         msi_free( appid->ServiceParameters );
265         msi_free( appid->DllSurrogate );
266         msi_free( appid );
267     }
268 
269     LIST_FOR_EACH_SAFE( item, cursor, &package->sourcelist_info )
270     {
271         MSISOURCELISTINFO *info = LIST_ENTRY( item, MSISOURCELISTINFO, entry );
272 
273         list_remove( &info->entry );
274         msi_free( info->value );
275         msi_free( info );
276     }
277 
278     LIST_FOR_EACH_SAFE( item, cursor, &package->sourcelist_media )
279     {
280         MSIMEDIADISK *info = LIST_ENTRY( item, MSIMEDIADISK, entry );
281 
282         list_remove( &info->entry );
283         msi_free( info->volume_label );
284         msi_free( info->disk_prompt );
285         msi_free( info );
286     }
287 
288     for (i = 0; i < SCRIPT_MAX; i++)
289         msi_free_action_script( package, i );
290 
291     for (i = 0; i < package->unique_actions_count; i++)
292         msi_free( package->unique_actions[i] );
293     msi_free( package->unique_actions);
294 
295     LIST_FOR_EACH_SAFE( item, cursor, &package->binaries )
296     {
297         MSIBINARY *binary = LIST_ENTRY( item, MSIBINARY, entry );
298 
299         list_remove( &binary->entry );
300         if (!DeleteFileW( binary->tmpfile ))
301             ERR( "failed to delete %s (%lu)\n", debugstr_w(binary->tmpfile), GetLastError() );
302         msi_free( binary->source );
303         msi_free( binary->tmpfile );
304         msi_free( binary );
305     }
306 
307     LIST_FOR_EACH_SAFE( item, cursor, &package->cabinet_streams )
308     {
309         MSICABINETSTREAM *cab = LIST_ENTRY( item, MSICABINETSTREAM, entry );
310 
311         list_remove( &cab->entry );
312         IStorage_Release( cab->storage );
313         msi_free( cab->stream );
314         msi_free( cab );
315     }
316 
317     LIST_FOR_EACH_SAFE( item, cursor, &package->patches )
318     {
319         MSIPATCHINFO *patch = LIST_ENTRY( item, MSIPATCHINFO, entry );
320 
321         list_remove( &patch->entry );
322         if (patch->delete_on_close && !DeleteFileW( patch->localfile ))
323         {
324             ERR( "failed to delete %s (%lu)\n", debugstr_w(patch->localfile), GetLastError() );
325         }
326         msi_free_patchinfo( patch );
327     }
328 
329     msi_free( package->PackagePath );
330     msi_free( package->ProductCode );
331     msi_free( package->ActionFormat );
332     msi_free( package->LastAction );
333     msi_free( package->LastActionTemplate );
334     msi_free( package->langids );
335 
336     /* cleanup control event subscriptions */
337     msi_event_cleanup_all_subscriptions( package );
338 }
339 
340 static void MSI_FreePackage( MSIOBJECTHDR *arg)
341 {
342     MSIPACKAGE *package = (MSIPACKAGE *)arg;
343 
344     msi_destroy_assembly_caches( package );
345 
346     if( package->dialog )
347         msi_dialog_destroy( package->dialog );
348 
349     msiobj_release( &package->db->hdr );
350     free_package_structures(package);
351     CloseHandle( package->log_file );
352     if (package->rpc_server_started)
353         RpcServerUnregisterIf(s_IWineMsiRemote_v0_0_s_ifspec, NULL, FALSE);
354     if (rpc_handle)
355         RpcBindingFree(&rpc_handle);
356     if (package->custom_server_32_process)
357         custom_stop_server(package->custom_server_32_process, package->custom_server_32_pipe);
358     if (package->custom_server_64_process)
359         custom_stop_server(package->custom_server_64_process, package->custom_server_64_pipe);
360 
361     if (package->delete_on_close) DeleteFileW( package->localfile );
362     msi_free( package->localfile );
363     MSI_ProcessMessage(NULL, INSTALLMESSAGE_TERMINATE, 0);
364 }
365 
366 static UINT create_temp_property_table(MSIPACKAGE *package)
367 {
368     MSIQUERY *view;
369     UINT rc;
370 
371     rc = MSI_DatabaseOpenViewW(package->db, L"CREATE TABLE `_Property` ( `_Property` CHAR(56) NOT NULL TEMPORARY, "
372                                             L"`Value` CHAR(98) NOT NULL TEMPORARY PRIMARY KEY `_Property`) HOLD", &view);
373     if (rc != ERROR_SUCCESS)
374         return rc;
375 
376     rc = MSI_ViewExecute(view, 0);
377     MSI_ViewClose(view);
378     msiobj_release(&view->hdr);
379     return rc;
380 }
381 
382 UINT msi_clone_properties( MSIDATABASE *db )
383 {
384     MSIQUERY *view_select;
385     UINT rc;
386 
387     rc = MSI_DatabaseOpenViewW( db, L"SELECT * FROM `Property`", &view_select );
388     if (rc != ERROR_SUCCESS)
389         return rc;
390 
391     rc = MSI_ViewExecute( view_select, 0 );
392     if (rc != ERROR_SUCCESS)
393     {
394         MSI_ViewClose( view_select );
395         msiobj_release( &view_select->hdr );
396         return rc;
397     }
398 
399     while (1)
400     {
401         MSIQUERY *view_insert, *view_update;
402         MSIRECORD *rec_select;
403 
404         rc = MSI_ViewFetch( view_select, &rec_select );
405         if (rc != ERROR_SUCCESS)
406             break;
407 
408         rc = MSI_DatabaseOpenViewW( db, L"INSERT INTO `_Property` (`_Property`,`Value`) VALUES (?,?)", &view_insert );
409         if (rc != ERROR_SUCCESS)
410         {
411             msiobj_release( &rec_select->hdr );
412             continue;
413         }
414 
415         rc = MSI_ViewExecute( view_insert, rec_select );
416         MSI_ViewClose( view_insert );
417         msiobj_release( &view_insert->hdr );
418         if (rc != ERROR_SUCCESS)
419         {
420             MSIRECORD *rec_update;
421 
422             TRACE("insert failed, trying update\n");
423 
424             rc = MSI_DatabaseOpenViewW( db, L"UPDATE `_Property` SET `Value` = ? WHERE `_Property` = ?", &view_update );
425             if (rc != ERROR_SUCCESS)
426             {
427                 WARN("open view failed %u\n", rc);
428                 msiobj_release( &rec_select->hdr );
429                 continue;
430             }
431 
432             rec_update = MSI_CreateRecord( 2 );
433             MSI_RecordCopyField( rec_select, 1, rec_update, 2 );
434             MSI_RecordCopyField( rec_select, 2, rec_update, 1 );
435             rc = MSI_ViewExecute( view_update, rec_update );
436             if (rc != ERROR_SUCCESS)
437                 WARN("update failed %u\n", rc);
438 
439             MSI_ViewClose( view_update );
440             msiobj_release( &view_update->hdr );
441             msiobj_release( &rec_update->hdr );
442         }
443 
444         msiobj_release( &rec_select->hdr );
445     }
446 
447     MSI_ViewClose( view_select );
448     msiobj_release( &view_select->hdr );
449     return rc;
450 }
451 
452 /*
453  * set_installed_prop
454  *
455  * Sets the "Installed" property to indicate that
456  *  the product is installed for the current user.
457  */
458 static UINT set_installed_prop( MSIPACKAGE *package )
459 {
460     HKEY hkey;
461     UINT r;
462 
463     if (!package->ProductCode) return ERROR_FUNCTION_FAILED;
464 
465     r = MSIREG_OpenUninstallKey( package->ProductCode, package->platform, &hkey, FALSE );
466     if (r == ERROR_SUCCESS)
467     {
468         RegCloseKey( hkey );
469         msi_set_property( package->db, L"Installed", L"1", -1 );
470     }
471     return r;
472 }
473 
474 static UINT set_user_sid_prop( MSIPACKAGE *package )
475 {
476     SID_NAME_USE use;
477     LPWSTR user_name;
478     LPWSTR sid_str = NULL, dom = NULL;
479     DWORD size, dom_size;
480     PSID psid = NULL;
481     UINT r = ERROR_FUNCTION_FAILED;
482 
483     size = 0;
484     GetUserNameW( NULL, &size );
485 
486     user_name = msi_alloc( (size + 1) * sizeof(WCHAR) );
487     if (!user_name)
488         return ERROR_OUTOFMEMORY;
489 
490     if (!GetUserNameW( user_name, &size ))
491         goto done;
492 
493     size = 0;
494     dom_size = 0;
495     LookupAccountNameW( NULL, user_name, NULL, &size, NULL, &dom_size, &use );
496 
497     psid = msi_alloc( size );
498     dom = msi_alloc( dom_size*sizeof (WCHAR) );
499     if (!psid || !dom)
500     {
501         r = ERROR_OUTOFMEMORY;
502         goto done;
503     }
504 
505     if (!LookupAccountNameW( NULL, user_name, psid, &size, dom, &dom_size, &use ))
506         goto done;
507 
508     if (!ConvertSidToStringSidW( psid, &sid_str ))
509         goto done;
510 
511     r = msi_set_property( package->db, L"UserSID", sid_str, -1 );
512 
513 done:
514     LocalFree( sid_str );
515     msi_free( dom );
516     msi_free( psid );
517     msi_free( user_name );
518 
519     return r;
520 }
521 
522 static LPWSTR get_fusion_filename(MSIPACKAGE *package)
523 {
524     HKEY netsetup, hkey;
525     LONG res;
526     DWORD size, len, type;
527     WCHAR windir[MAX_PATH], path[MAX_PATH], *filename = NULL;
528 
529     res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\NET Framework Setup\\NDP", 0, KEY_CREATE_SUB_KEY,
530                         &netsetup);
531     if (res != ERROR_SUCCESS)
532         return NULL;
533 
534     if (!RegCreateKeyExW(netsetup, L"v4\\Client", 0, NULL, 0, KEY_QUERY_VALUE, NULL, &hkey, NULL))
535     {
536         size = sizeof(path);
537         if (!RegQueryValueExW(hkey, L"InstallPath", NULL, &type, (BYTE *)path, &size))
538         {
539             len = lstrlenW(path) + lstrlenW(L"fusion.dll") + 2;
540             if (!(filename = msi_alloc(len * sizeof(WCHAR)))) return NULL;
541 
542             lstrcpyW(filename, path);
543             lstrcatW(filename, L"\\");
544             lstrcatW(filename, L"fusion.dll");
545             if (GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
546             {
547                 TRACE( "found %s\n", debugstr_w(filename) );
548                 RegCloseKey(hkey);
549                 RegCloseKey(netsetup);
550                 return filename;
551             }
552         }
553         RegCloseKey(hkey);
554     }
555 
556     if (!RegCreateKeyExW(netsetup, L"v2.0.50727", 0, NULL, 0, KEY_QUERY_VALUE, NULL, &hkey, NULL))
557     {
558         RegCloseKey(hkey);
559         GetWindowsDirectoryW(windir, MAX_PATH);
560         len = lstrlenW(windir) + lstrlenW(L"Microsoft.NET\\Framework\\") + lstrlenW(L"v2.0.50727") +
561               lstrlenW(L"fusion.dll") + 3;
562         msi_free(filename);
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( const WCHAR *szPackage, DWORD dwOptions, MSIHANDLE *phPackage )
1557 {
1558     MSIPACKAGE *package = NULL;
1559     UINT ret;
1560 
1561     TRACE( "%s, %#lx, %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 %#lx 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( "%lu\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 = %#x, hRecord = %lu)\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 = %#x, 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 = %#x, 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 %lu sized buffer for %s\n", *pchValueBuf, debugstr_w(szName) );
2218     else
2219     {
2220         *pchValueBuf = 0;
2221         TRACE("property %s not found\n", debugstr_w(szName));
2222     }
2223 
2224     return rc;
2225 }
2226 
2227 LPWSTR msi_dup_property(MSIDATABASE *db, LPCWSTR prop)
2228 {
2229     DWORD sz = 0;
2230     LPWSTR str;
2231     UINT r;
2232 
2233     r = msi_get_property(db, prop, NULL, &sz);
2234     if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
2235         return NULL;
2236 
2237     sz++;
2238     str = msi_alloc(sz * sizeof(WCHAR));
2239     r = msi_get_property(db, prop, str, &sz);
2240     if (r != ERROR_SUCCESS)
2241     {
2242         msi_free(str);
2243         str = NULL;
2244     }
2245 
2246     return str;
2247 }
2248 
2249 int msi_get_property_int( MSIDATABASE *db, LPCWSTR prop, int def )
2250 {
2251     LPWSTR str = msi_dup_property( db, prop );
2252     int val = str ? wcstol(str, NULL, 10) : def;
2253     msi_free(str);
2254     return val;
2255 }
2256 
2257 UINT WINAPI MsiGetPropertyA(MSIHANDLE hinst, const char *name, char *buf, DWORD *sz)
2258 {
2259     const WCHAR *value = L"";
2260     MSIPACKAGE *package;
2261     MSIRECORD *row;
2262     WCHAR *nameW;
2263     int len = 0;
2264     UINT r;
2265 
2266     if (!name)
2267         return ERROR_INVALID_PARAMETER;
2268 
2269     if (!(nameW = strdupAtoW(name)))
2270         return ERROR_OUTOFMEMORY;
2271 
2272     package = msihandle2msiinfo(hinst, MSIHANDLETYPE_PACKAGE);
2273     if (!package)
2274     {
2275         WCHAR *value = NULL, *tmp;
2276         MSIHANDLE remote;
2277         DWORD len;
2278 
2279         if (!(remote = msi_get_remote(hinst)))
2280         {
2281             free(nameW);
2282             return ERROR_INVALID_HANDLE;
2283         }
2284 
2285         __TRY
2286         {
2287             r = remote_GetProperty(remote, nameW, &value, &len);
2288         }
2289         __EXCEPT(rpc_filter)
2290         {
2291             r = GetExceptionCode();
2292         }
2293         __ENDTRY
2294 
2295         free(nameW);
2296 
2297         if (!r)
2298         {
2299             /* String might contain embedded nulls.
2300              * Native returns the correct size but truncates the string. */
2301             tmp = calloc(1, (len + 1) * sizeof(WCHAR));
2302             if (!tmp)
2303             {
2304                 midl_user_free(value);
2305                 return ERROR_OUTOFMEMORY;
2306             }
2307             lstrcpyW(tmp, value);
2308 
2309             r = msi_strncpyWtoA(tmp, len, buf, sz, TRUE);
2310 
2311             free(tmp);
2312         }
2313         midl_user_free(value);
2314         return r;
2315     }
2316 
2317     row = msi_get_property_row(package->db, nameW);
2318     if (row)
2319         value = msi_record_get_string(row, 1, &len);
2320 
2321     r = msi_strncpyWtoA(value, len, buf, sz, FALSE);
2322 
2323     free(nameW);
2324     if (row) msiobj_release(&row->hdr);
2325     msiobj_release(&package->hdr);
2326     return r;
2327 }
2328 
2329 UINT WINAPI MsiGetPropertyW(MSIHANDLE hinst, const WCHAR *name, WCHAR *buf, DWORD *sz)
2330 {
2331     const WCHAR *value = L"";
2332     MSIPACKAGE *package;
2333     MSIRECORD *row;
2334     int len = 0;
2335     UINT r;
2336 
2337     if (!name)
2338         return ERROR_INVALID_PARAMETER;
2339 
2340     package = msihandle2msiinfo(hinst, MSIHANDLETYPE_PACKAGE);
2341     if (!package)
2342     {
2343         WCHAR *value = NULL, *tmp;
2344         MSIHANDLE remote;
2345         DWORD len;
2346 
2347         if (!(remote = msi_get_remote(hinst)))
2348             return ERROR_INVALID_HANDLE;
2349 
2350         __TRY
2351         {
2352             r = remote_GetProperty(remote, name, &value, &len);
2353         }
2354         __EXCEPT(rpc_filter)
2355         {
2356             r = GetExceptionCode();
2357         }
2358         __ENDTRY
2359 
2360         if (!r)
2361         {
2362             /* String might contain embedded nulls.
2363              * Native returns the correct size but truncates the string. */
2364             tmp = calloc(1, (len + 1) * sizeof(WCHAR));
2365             if (!tmp)
2366             {
2367                 midl_user_free(value);
2368                 return ERROR_OUTOFMEMORY;
2369             }
2370             lstrcpyW(tmp, value);
2371 
2372             r = msi_strncpyW(tmp, len, buf, sz);
2373 
2374             free(tmp);
2375         }
2376         midl_user_free(value);
2377         return r;
2378     }
2379 
2380     row = msi_get_property_row(package->db, name);
2381     if (row)
2382         value = msi_record_get_string(row, 1, &len);
2383 
2384     r = msi_strncpyW(value, len, buf, sz);
2385 
2386     if (row) msiobj_release(&row->hdr);
2387     msiobj_release(&package->hdr);
2388     return r;
2389 }
2390 
2391 MSIHANDLE __cdecl s_remote_GetActiveDatabase(MSIHANDLE hinst)
2392 {
2393     return MsiGetActiveDatabase(hinst);
2394 }
2395 
2396 UINT __cdecl s_remote_GetProperty(MSIHANDLE hinst, LPCWSTR property, LPWSTR *value, DWORD *size)
2397 {
2398     WCHAR empty[1];
2399     UINT r;
2400 
2401     *size = 0;
2402     r = MsiGetPropertyW(hinst, property, empty, size);
2403     if (r == ERROR_MORE_DATA)
2404     {
2405         ++*size;
2406         *value = midl_user_allocate(*size * sizeof(WCHAR));
2407         if (!*value)
2408             return ERROR_OUTOFMEMORY;
2409         r = MsiGetPropertyW(hinst, property, *value, size);
2410     }
2411     return r;
2412 }
2413 
2414 UINT __cdecl s_remote_SetProperty(MSIHANDLE hinst, LPCWSTR property, LPCWSTR value)
2415 {
2416     return MsiSetPropertyW(hinst, property, value);
2417 }
2418 
2419 int __cdecl s_remote_ProcessMessage(MSIHANDLE hinst, INSTALLMESSAGE message, struct wire_record *remote_rec)
2420 {
2421     MSIHANDLE rec;
2422     int ret;
2423     UINT r;
2424 
2425     if ((r = unmarshal_record(remote_rec, &rec)))
2426         return r;
2427 
2428     ret = MsiProcessMessage(hinst, message, rec);
2429 
2430     MsiCloseHandle(rec);
2431     return ret;
2432 }
2433 
2434 UINT __cdecl s_remote_DoAction(MSIHANDLE hinst, LPCWSTR action)
2435 {
2436     return MsiDoActionW(hinst, action);
2437 }
2438 
2439 UINT __cdecl s_remote_Sequence(MSIHANDLE hinst, LPCWSTR table, int sequence)
2440 {
2441     return MsiSequenceW(hinst, table, sequence);
2442 }
2443 
2444 UINT __cdecl s_remote_GetTargetPath(MSIHANDLE hinst, LPCWSTR folder, LPWSTR *value)
2445 {
2446     WCHAR empty[1];
2447     DWORD size = 0;
2448     UINT r;
2449 
2450     r = MsiGetTargetPathW(hinst, folder, empty, &size);
2451     if (r == ERROR_MORE_DATA)
2452     {
2453         *value = midl_user_allocate(++size * sizeof(WCHAR));
2454         if (!*value)
2455             return ERROR_OUTOFMEMORY;
2456         r = MsiGetTargetPathW(hinst, folder, *value, &size);
2457     }
2458     return r;
2459 }
2460 
2461 UINT __cdecl s_remote_SetTargetPath(MSIHANDLE hinst, LPCWSTR folder, LPCWSTR value)
2462 {
2463     return MsiSetTargetPathW(hinst, folder, value);
2464 }
2465 
2466 UINT __cdecl s_remote_GetSourcePath(MSIHANDLE hinst, LPCWSTR folder, LPWSTR *value)
2467 {
2468     WCHAR empty[1];
2469     DWORD size = 1;
2470     UINT r;
2471 
2472     r = MsiGetSourcePathW(hinst, folder, empty, &size);
2473     if (r == ERROR_MORE_DATA)
2474     {
2475         *value = midl_user_allocate(++size * sizeof(WCHAR));
2476         if (!*value)
2477             return ERROR_OUTOFMEMORY;
2478         r = MsiGetSourcePathW(hinst, folder, *value, &size);
2479     }
2480     return r;
2481 }
2482 
2483 BOOL __cdecl s_remote_GetMode(MSIHANDLE hinst, MSIRUNMODE mode)
2484 {
2485     return MsiGetMode(hinst, mode);
2486 }
2487 
2488 UINT __cdecl s_remote_SetMode(MSIHANDLE hinst, MSIRUNMODE mode, BOOL state)
2489 {
2490     return MsiSetMode(hinst, mode, state);
2491 }
2492 
2493 UINT __cdecl s_remote_GetFeatureState(MSIHANDLE hinst, LPCWSTR feature,
2494                                     INSTALLSTATE *installed, INSTALLSTATE *action)
2495 {
2496     return MsiGetFeatureStateW(hinst, feature, installed, action);
2497 }
2498 
2499 UINT __cdecl s_remote_SetFeatureState(MSIHANDLE hinst, LPCWSTR feature, INSTALLSTATE state)
2500 {
2501     return MsiSetFeatureStateW(hinst, feature, state);
2502 }
2503 
2504 UINT __cdecl s_remote_GetComponentState(MSIHANDLE hinst, LPCWSTR component,
2505                                       INSTALLSTATE *installed, INSTALLSTATE *action)
2506 {
2507     return MsiGetComponentStateW(hinst, component, installed, action);
2508 }
2509 
2510 UINT __cdecl s_remote_SetComponentState(MSIHANDLE hinst, LPCWSTR component, INSTALLSTATE state)
2511 {
2512     return MsiSetComponentStateW(hinst, component, state);
2513 }
2514 
2515 LANGID __cdecl s_remote_GetLanguage(MSIHANDLE hinst)
2516 {
2517     return MsiGetLanguage(hinst);
2518 }
2519 
2520 UINT __cdecl s_remote_SetInstallLevel(MSIHANDLE hinst, int level)
2521 {
2522     return MsiSetInstallLevel(hinst, level);
2523 }
2524 
2525 UINT __cdecl s_remote_FormatRecord(MSIHANDLE hinst, struct wire_record *remote_rec, LPWSTR *value)
2526 {
2527     WCHAR empty[1];
2528     DWORD size = 0;
2529     MSIHANDLE rec;
2530     UINT r;
2531 
2532     if ((r = unmarshal_record(remote_rec, &rec)))
2533         return r;
2534 
2535     r = MsiFormatRecordW(hinst, rec, empty, &size);
2536     if (r == ERROR_MORE_DATA)
2537     {
2538         *value = midl_user_allocate(++size * sizeof(WCHAR));
2539         if (!*value)
2540         {
2541             MsiCloseHandle(rec);
2542             return ERROR_OUTOFMEMORY;
2543         }
2544         r = MsiFormatRecordW(hinst, rec, *value, &size);
2545     }
2546 
2547     MsiCloseHandle(rec);
2548     return r;
2549 }
2550 
2551 MSICONDITION __cdecl s_remote_EvaluateCondition(MSIHANDLE hinst, LPCWSTR condition)
2552 {
2553     return MsiEvaluateConditionW(hinst, condition);
2554 }
2555 
2556 UINT __cdecl s_remote_GetFeatureCost(MSIHANDLE hinst, LPCWSTR feature,
2557     MSICOSTTREE cost_tree, INSTALLSTATE state, INT *cost)
2558 {
2559     return MsiGetFeatureCostW(hinst, feature, cost_tree, state, cost);
2560 }
2561 
2562 UINT __cdecl s_remote_EnumComponentCosts(MSIHANDLE hinst, LPCWSTR component,
2563     DWORD index, INSTALLSTATE state, LPWSTR drive, INT *cost, INT *temp)
2564 {
2565     DWORD size = 3;
2566     return MsiEnumComponentCostsW(hinst, component, index, state, drive, &size, cost, temp);
2567 }
2568 
2569 UINT msi_package_add_info(MSIPACKAGE *package, DWORD context, DWORD options,
2570                           LPCWSTR property, LPWSTR value)
2571 {
2572     MSISOURCELISTINFO *info;
2573 
2574     LIST_FOR_EACH_ENTRY( info, &package->sourcelist_info, MSISOURCELISTINFO, entry )
2575     {
2576         if (!wcscmp( info->value, value )) return ERROR_SUCCESS;
2577     }
2578 
2579     info = msi_alloc(sizeof(MSISOURCELISTINFO));
2580     if (!info)
2581         return ERROR_OUTOFMEMORY;
2582 
2583     info->context = context;
2584     info->options = options;
2585     info->property = property;
2586     info->value = strdupW(value);
2587     list_add_head(&package->sourcelist_info, &info->entry);
2588 
2589     return ERROR_SUCCESS;
2590 }
2591 
2592 UINT msi_package_add_media_disk(MSIPACKAGE *package, DWORD context, DWORD options,
2593                                 DWORD disk_id, LPWSTR volume_label, LPWSTR disk_prompt)
2594 {
2595     MSIMEDIADISK *disk;
2596 
2597     LIST_FOR_EACH_ENTRY( disk, &package->sourcelist_media, MSIMEDIADISK, entry )
2598     {
2599         if (disk->disk_id == disk_id) return ERROR_SUCCESS;
2600     }
2601 
2602     disk = msi_alloc(sizeof(MSIMEDIADISK));
2603     if (!disk)
2604         return ERROR_OUTOFMEMORY;
2605 
2606     disk->context = context;
2607     disk->options = options;
2608     disk->disk_id = disk_id;
2609     disk->volume_label = strdupW(volume_label);
2610     disk->disk_prompt = strdupW(disk_prompt);
2611     list_add_head(&package->sourcelist_media, &disk->entry);
2612 
2613     return ERROR_SUCCESS;
2614 }
2615