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