include: Move InterlockedCompareExchange128 next to the other InterlockedCompareExcha...
[wine.git] / dlls / msi / package.c
blob2483d99e2b518aeab7ddd6f16ccbc2d8f06d788b
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004 Aric Stewart for CodeWeavers
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.
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.
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
21 #define NONAMELESSUNION
22 #define NONAMELESSSTRUCT
23 #define COBJMACROS
25 #include <stdarg.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "winnls.h"
30 #include "winternl.h"
31 #include "shlwapi.h"
32 #include "wingdi.h"
33 #include "msi.h"
34 #include "msiquery.h"
35 #include "objidl.h"
36 #include "wincrypt.h"
37 #include "winuser.h"
38 #include "wininet.h"
39 #include "winver.h"
40 #include "urlmon.h"
41 #include "shlobj.h"
42 #include "objbase.h"
43 #include "msidefs.h"
44 #include "sddl.h"
46 #include "wine/heap.h"
47 #include "wine/debug.h"
48 #include "wine/exception.h"
50 #include "msipriv.h"
51 #include "winemsi.h"
52 #include "resource.h"
54 WINE_DEFAULT_DEBUG_CHANNEL(msi);
56 static void free_feature( MSIFEATURE *feature )
58 struct list *item, *cursor;
60 LIST_FOR_EACH_SAFE( item, cursor, &feature->Children )
62 FeatureList *fl = LIST_ENTRY( item, FeatureList, entry );
63 list_remove( &fl->entry );
64 msi_free( fl );
67 LIST_FOR_EACH_SAFE( item, cursor, &feature->Components )
69 ComponentList *cl = LIST_ENTRY( item, ComponentList, entry );
70 list_remove( &cl->entry );
71 msi_free( cl );
73 msi_free( feature->Feature );
74 msi_free( feature->Feature_Parent );
75 msi_free( feature->Directory );
76 msi_free( feature->Description );
77 msi_free( feature->Title );
78 msi_free( feature );
81 static void free_folder( MSIFOLDER *folder )
83 struct list *item, *cursor;
85 LIST_FOR_EACH_SAFE( item, cursor, &folder->children )
87 FolderList *fl = LIST_ENTRY( item, FolderList, entry );
88 list_remove( &fl->entry );
89 msi_free( fl );
91 msi_free( folder->Parent );
92 msi_free( folder->Directory );
93 msi_free( folder->TargetDefault );
94 msi_free( folder->SourceLongPath );
95 msi_free( folder->SourceShortPath );
96 msi_free( folder->ResolvedTarget );
97 msi_free( folder->ResolvedSource );
98 msi_free( folder );
101 static void free_extension( MSIEXTENSION *ext )
103 struct list *item, *cursor;
105 LIST_FOR_EACH_SAFE( item, cursor, &ext->verbs )
107 MSIVERB *verb = LIST_ENTRY( item, MSIVERB, entry );
109 list_remove( &verb->entry );
110 msi_free( verb->Verb );
111 msi_free( verb->Command );
112 msi_free( verb->Argument );
113 msi_free( verb );
116 msi_free( ext->Extension );
117 msi_free( ext->ProgIDText );
118 msi_free( ext );
121 static void free_assembly( MSIASSEMBLY *assembly )
123 msi_free( assembly->feature );
124 msi_free( assembly->manifest );
125 msi_free( assembly->application );
126 msi_free( assembly->display_name );
127 if (assembly->tempdir) RemoveDirectoryW( assembly->tempdir );
128 msi_free( assembly->tempdir );
129 msi_free( assembly );
132 void msi_free_action_script( MSIPACKAGE *package, UINT script )
134 UINT i;
135 for (i = 0; i < package->script_actions_count[script]; i++)
136 msi_free( package->script_actions[script][i] );
138 msi_free( package->script_actions[script] );
139 package->script_actions[script] = NULL;
140 package->script_actions_count[script] = 0;
143 static void free_package_structures( MSIPACKAGE *package )
145 struct list *item, *cursor;
146 int i;
148 LIST_FOR_EACH_SAFE( item, cursor, &package->features )
150 MSIFEATURE *feature = LIST_ENTRY( item, MSIFEATURE, entry );
151 list_remove( &feature->entry );
152 free_feature( feature );
155 LIST_FOR_EACH_SAFE( item, cursor, &package->folders )
157 MSIFOLDER *folder = LIST_ENTRY( item, MSIFOLDER, entry );
158 list_remove( &folder->entry );
159 free_folder( folder );
162 LIST_FOR_EACH_SAFE( item, cursor, &package->files )
164 MSIFILE *file = LIST_ENTRY( item, MSIFILE, entry );
166 list_remove( &file->entry );
167 msi_free( file->File );
168 msi_free( file->FileName );
169 msi_free( file->ShortName );
170 msi_free( file->LongName );
171 msi_free( file->Version );
172 msi_free( file->Language );
173 if (msi_is_global_assembly( file->Component )) DeleteFileW( file->TargetPath );
174 msi_free( file->TargetPath );
175 msi_free( file );
178 LIST_FOR_EACH_SAFE( item, cursor, &package->components )
180 MSICOMPONENT *comp = LIST_ENTRY( item, MSICOMPONENT, entry );
182 list_remove( &comp->entry );
183 msi_free( comp->Component );
184 msi_free( comp->ComponentId );
185 msi_free( comp->Directory );
186 msi_free( comp->Condition );
187 msi_free( comp->KeyPath );
188 msi_free( comp->FullKeypath );
189 if (comp->assembly) free_assembly( comp->assembly );
190 msi_free( comp );
193 LIST_FOR_EACH_SAFE( item, cursor, &package->filepatches )
195 MSIFILEPATCH *patch = LIST_ENTRY( item, MSIFILEPATCH, entry );
197 list_remove( &patch->entry );
198 msi_free( patch->path );
199 msi_free( patch );
202 /* clean up extension, progid, class and verb structures */
203 LIST_FOR_EACH_SAFE( item, cursor, &package->classes )
205 MSICLASS *cls = LIST_ENTRY( item, MSICLASS, entry );
207 list_remove( &cls->entry );
208 msi_free( cls->clsid );
209 msi_free( cls->Context );
210 msi_free( cls->Description );
211 msi_free( cls->FileTypeMask );
212 msi_free( cls->IconPath );
213 msi_free( cls->DefInprocHandler );
214 msi_free( cls->DefInprocHandler32 );
215 msi_free( cls->Argument );
216 msi_free( cls->ProgIDText );
217 msi_free( cls );
220 LIST_FOR_EACH_SAFE( item, cursor, &package->extensions )
222 MSIEXTENSION *ext = LIST_ENTRY( item, MSIEXTENSION, entry );
224 list_remove( &ext->entry );
225 free_extension( ext );
228 LIST_FOR_EACH_SAFE( item, cursor, &package->progids )
230 MSIPROGID *progid = LIST_ENTRY( item, MSIPROGID, entry );
232 list_remove( &progid->entry );
233 msi_free( progid->ProgID );
234 msi_free( progid->Description );
235 msi_free( progid->IconPath );
236 msi_free( progid );
239 LIST_FOR_EACH_SAFE( item, cursor, &package->mimes )
241 MSIMIME *mt = LIST_ENTRY( item, MSIMIME, entry );
243 list_remove( &mt->entry );
244 msi_free( mt->suffix );
245 msi_free( mt->clsid );
246 msi_free( mt->ContentType );
247 msi_free( mt );
250 LIST_FOR_EACH_SAFE( item, cursor, &package->appids )
252 MSIAPPID *appid = LIST_ENTRY( item, MSIAPPID, entry );
254 list_remove( &appid->entry );
255 msi_free( appid->AppID );
256 msi_free( appid->RemoteServerName );
257 msi_free( appid->LocalServer );
258 msi_free( appid->ServiceParameters );
259 msi_free( appid->DllSurrogate );
260 msi_free( appid );
263 LIST_FOR_EACH_SAFE( item, cursor, &package->sourcelist_info )
265 MSISOURCELISTINFO *info = LIST_ENTRY( item, MSISOURCELISTINFO, entry );
267 list_remove( &info->entry );
268 msi_free( info->value );
269 msi_free( info );
272 LIST_FOR_EACH_SAFE( item, cursor, &package->sourcelist_media )
274 MSIMEDIADISK *info = LIST_ENTRY( item, MSIMEDIADISK, entry );
276 list_remove( &info->entry );
277 msi_free( info->volume_label );
278 msi_free( info->disk_prompt );
279 msi_free( info );
282 for (i = 0; i < SCRIPT_MAX; i++)
283 msi_free_action_script( package, i );
285 for (i = 0; i < package->unique_actions_count; i++)
286 msi_free( package->unique_actions[i] );
287 msi_free( package->unique_actions);
289 LIST_FOR_EACH_SAFE( item, cursor, &package->binaries )
291 MSIBINARY *binary = LIST_ENTRY( item, MSIBINARY, entry );
293 list_remove( &binary->entry );
294 if (!DeleteFileW( binary->tmpfile ))
295 ERR("failed to delete %s (%u)\n", debugstr_w(binary->tmpfile), GetLastError());
296 msi_free( binary->source );
297 msi_free( binary->tmpfile );
298 msi_free( binary );
301 LIST_FOR_EACH_SAFE( item, cursor, &package->cabinet_streams )
303 MSICABINETSTREAM *cab = LIST_ENTRY( item, MSICABINETSTREAM, entry );
305 list_remove( &cab->entry );
306 IStorage_Release( cab->storage );
307 msi_free( cab->stream );
308 msi_free( cab );
311 LIST_FOR_EACH_SAFE( item, cursor, &package->patches )
313 MSIPATCHINFO *patch = LIST_ENTRY( item, MSIPATCHINFO, entry );
315 list_remove( &patch->entry );
316 if (patch->delete_on_close && !DeleteFileW( patch->localfile ))
318 ERR("failed to delete %s (%u)\n", debugstr_w(patch->localfile), GetLastError());
320 msi_free_patchinfo( patch );
323 msi_free( package->PackagePath );
324 msi_free( package->ProductCode );
325 msi_free( package->ActionFormat );
326 msi_free( package->LastAction );
327 msi_free( package->LastActionTemplate );
328 msi_free( package->langids );
330 /* cleanup control event subscriptions */
331 msi_event_cleanup_all_subscriptions( package );
334 static void MSI_FreePackage( MSIOBJECTHDR *arg)
336 MSIPACKAGE *package = (MSIPACKAGE *)arg;
338 msi_destroy_assembly_caches( package );
340 if( package->dialog )
341 msi_dialog_destroy( package->dialog );
343 msiobj_release( &package->db->hdr );
344 free_package_structures(package);
345 CloseHandle( package->log_file );
346 if (package->rpc_server_started)
347 RpcServerUnregisterIf(s_IWineMsiRemote_v0_0_s_ifspec, NULL, FALSE);
348 if (rpc_handle)
349 RpcBindingFree(&rpc_handle);
350 if (package->custom_server_32_process)
351 custom_stop_server(package->custom_server_32_process, package->custom_server_32_pipe);
352 if (package->custom_server_64_process)
353 custom_stop_server(package->custom_server_64_process, package->custom_server_64_pipe);
355 if (package->delete_on_close) DeleteFileW( package->localfile );
356 msi_free( package->localfile );
357 MSI_ProcessMessage(NULL, INSTALLMESSAGE_TERMINATE, 0);
360 static UINT create_temp_property_table(MSIPACKAGE *package)
362 MSIQUERY *view;
363 UINT rc;
365 rc = MSI_DatabaseOpenViewW(package->db, L"CREATE TABLE `_Property` ( `_Property` CHAR(56) NOT NULL TEMPORARY, "
366 L"`Value` CHAR(98) NOT NULL TEMPORARY PRIMARY KEY `_Property`) HOLD", &view);
367 if (rc != ERROR_SUCCESS)
368 return rc;
370 rc = MSI_ViewExecute(view, 0);
371 MSI_ViewClose(view);
372 msiobj_release(&view->hdr);
373 return rc;
376 UINT msi_clone_properties( MSIDATABASE *db )
378 MSIQUERY *view_select;
379 UINT rc;
381 rc = MSI_DatabaseOpenViewW( db, L"SELECT * FROM `Property`", &view_select );
382 if (rc != ERROR_SUCCESS)
383 return rc;
385 rc = MSI_ViewExecute( view_select, 0 );
386 if (rc != ERROR_SUCCESS)
388 MSI_ViewClose( view_select );
389 msiobj_release( &view_select->hdr );
390 return rc;
393 while (1)
395 MSIQUERY *view_insert, *view_update;
396 MSIRECORD *rec_select;
398 rc = MSI_ViewFetch( view_select, &rec_select );
399 if (rc != ERROR_SUCCESS)
400 break;
402 rc = MSI_DatabaseOpenViewW( db, L"INSERT INTO `_Property` (`_Property`,`Value`) VALUES (?,?)", &view_insert );
403 if (rc != ERROR_SUCCESS)
405 msiobj_release( &rec_select->hdr );
406 continue;
409 rc = MSI_ViewExecute( view_insert, rec_select );
410 MSI_ViewClose( view_insert );
411 msiobj_release( &view_insert->hdr );
412 if (rc != ERROR_SUCCESS)
414 MSIRECORD *rec_update;
416 TRACE("insert failed, trying update\n");
418 rc = MSI_DatabaseOpenViewW( db, L"UPDATE `_Property` SET `Value` = ? WHERE `_Property` = ?", &view_update );
419 if (rc != ERROR_SUCCESS)
421 WARN("open view failed %u\n", rc);
422 msiobj_release( &rec_select->hdr );
423 continue;
426 rec_update = MSI_CreateRecord( 2 );
427 MSI_RecordCopyField( rec_select, 1, rec_update, 2 );
428 MSI_RecordCopyField( rec_select, 2, rec_update, 1 );
429 rc = MSI_ViewExecute( view_update, rec_update );
430 if (rc != ERROR_SUCCESS)
431 WARN("update failed %u\n", rc);
433 MSI_ViewClose( view_update );
434 msiobj_release( &view_update->hdr );
435 msiobj_release( &rec_update->hdr );
438 msiobj_release( &rec_select->hdr );
441 MSI_ViewClose( view_select );
442 msiobj_release( &view_select->hdr );
443 return rc;
447 * set_installed_prop
449 * Sets the "Installed" property to indicate that
450 * the product is installed for the current user.
452 static UINT set_installed_prop( MSIPACKAGE *package )
454 HKEY hkey;
455 UINT r;
457 if (!package->ProductCode) return ERROR_FUNCTION_FAILED;
459 r = MSIREG_OpenUninstallKey( package->ProductCode, package->platform, &hkey, FALSE );
460 if (r == ERROR_SUCCESS)
462 RegCloseKey( hkey );
463 msi_set_property( package->db, L"Installed", L"1", -1 );
465 return r;
468 static UINT set_user_sid_prop( MSIPACKAGE *package )
470 SID_NAME_USE use;
471 LPWSTR user_name;
472 LPWSTR sid_str = NULL, dom = NULL;
473 DWORD size, dom_size;
474 PSID psid = NULL;
475 UINT r = ERROR_FUNCTION_FAILED;
477 size = 0;
478 GetUserNameW( NULL, &size );
480 user_name = msi_alloc( (size + 1) * sizeof(WCHAR) );
481 if (!user_name)
482 return ERROR_OUTOFMEMORY;
484 if (!GetUserNameW( user_name, &size ))
485 goto done;
487 size = 0;
488 dom_size = 0;
489 LookupAccountNameW( NULL, user_name, NULL, &size, NULL, &dom_size, &use );
491 psid = msi_alloc( size );
492 dom = msi_alloc( dom_size*sizeof (WCHAR) );
493 if (!psid || !dom)
495 r = ERROR_OUTOFMEMORY;
496 goto done;
499 if (!LookupAccountNameW( NULL, user_name, psid, &size, dom, &dom_size, &use ))
500 goto done;
502 if (!ConvertSidToStringSidW( psid, &sid_str ))
503 goto done;
505 r = msi_set_property( package->db, L"UserSID", sid_str, -1 );
507 done:
508 LocalFree( sid_str );
509 msi_free( dom );
510 msi_free( psid );
511 msi_free( user_name );
513 return r;
516 static LPWSTR get_fusion_filename(MSIPACKAGE *package)
518 HKEY netsetup, hkey;
519 LONG res;
520 DWORD size, len, type;
521 WCHAR windir[MAX_PATH], path[MAX_PATH], *filename = NULL;
523 res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\NET Framework Setup\\NDP", 0, KEY_CREATE_SUB_KEY,
524 &netsetup);
525 if (res != ERROR_SUCCESS)
526 return NULL;
528 if (!RegCreateKeyExW(netsetup, L"v4\\Client", 0, NULL, 0, KEY_QUERY_VALUE, NULL, &hkey, NULL))
530 size = ARRAY_SIZE(path);
531 if (!RegQueryValueExW(hkey, L"InstallPath", NULL, &type, (BYTE *)path, &size))
533 len = lstrlenW(path) + lstrlenW(L"fusion.dll") + 2;
534 if (!(filename = msi_alloc(len * sizeof(WCHAR)))) return NULL;
536 lstrcpyW(filename, path);
537 lstrcpyW(filename, L"\\");
538 lstrcatW(filename, L"fusion.dll");
539 if (GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
541 TRACE( "found %s\n", debugstr_w(filename) );
542 RegCloseKey(hkey);
543 RegCloseKey(netsetup);
544 return filename;
547 RegCloseKey(hkey);
550 if (!RegCreateKeyExW(netsetup, L"v2.0.50727", 0, NULL, 0, KEY_QUERY_VALUE, NULL, &hkey, NULL))
552 RegCloseKey(hkey);
553 GetWindowsDirectoryW(windir, MAX_PATH);
554 len = lstrlenW(windir) + lstrlenW(L"Microsoft.NET\\Framework\\") + lstrlenW(L"v2.0.50727") +
555 lstrlenW(L"fusion.dll") + 3;
556 if (!(filename = msi_alloc(len * sizeof(WCHAR)))) return NULL;
558 lstrcpyW(filename, windir);
559 lstrcatW(filename, L"\\");
560 lstrcatW(filename, L"Microsoft.NET\\Framework\\");
561 lstrcatW(filename, L"v2.0.50727");
562 lstrcatW(filename, L"\\");
563 lstrcatW(filename, L"fusion.dll");
564 if (GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
566 TRACE( "found %s\n", debugstr_w(filename) );
567 RegCloseKey(netsetup);
568 return filename;
572 RegCloseKey(netsetup);
573 return filename;
576 typedef struct tagLANGANDCODEPAGE
578 WORD wLanguage;
579 WORD wCodePage;
580 } LANGANDCODEPAGE;
582 static void set_msi_assembly_prop(MSIPACKAGE *package)
584 UINT val_len;
585 DWORD size, handle;
586 LPVOID version = NULL;
587 WCHAR buf[MAX_PATH];
588 LPWSTR fusion, verstr;
589 LANGANDCODEPAGE *translate;
591 fusion = get_fusion_filename(package);
592 if (!fusion)
593 return;
595 size = GetFileVersionInfoSizeW(fusion, &handle);
596 if (!size)
597 goto done;
599 version = msi_alloc(size);
600 if (!version)
601 goto done;
603 if (!GetFileVersionInfoW(fusion, handle, size, version))
604 goto done;
606 if (!VerQueryValueW(version, L"\\VarFileInfo\\Translation", (LPVOID *)&translate, &val_len))
607 goto done;
609 swprintf(buf, ARRAY_SIZE(buf), L"\\StringFileInfo\\%04x%04x\\ProductVersion", translate[0].wLanguage,
610 translate[0].wCodePage);
612 if (!VerQueryValueW(version, buf, (LPVOID *)&verstr, &val_len))
613 goto done;
615 if (!val_len || !verstr)
616 goto done;
618 msi_set_property( package->db, L"MsiNetAssemblySupport", verstr, -1 );
620 done:
621 msi_free(fusion);
622 msi_free(version);
625 static VOID set_installer_properties(MSIPACKAGE *package)
627 WCHAR *ptr;
628 RTL_OSVERSIONINFOEXW OSVersion;
629 MEMORYSTATUSEX msex;
630 DWORD verval, len, type;
631 WCHAR pth[MAX_PATH], verstr[11], bufstr[22];
632 HDC dc;
633 HKEY hkey;
634 LPWSTR username, companyname;
635 SYSTEM_INFO sys_info;
636 LANGID langid;
639 * Other things that probably should be set:
641 * VirtualMemory ShellAdvSupport DefaultUIFont PackagecodeChanging
642 * CaptionHeight BorderTop BorderSide TextHeight RedirectedDllSupport
645 SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA, NULL, 0, pth);
646 lstrcatW(pth, L"\\");
647 msi_set_property( package->db, L"CommonAppDataFolder", pth, -1 );
649 SHGetFolderPathW(NULL, CSIDL_FAVORITES, NULL, 0, pth);
650 lstrcatW(pth, L"\\");
651 msi_set_property( package->db, L"FavoritesFolder", pth, -1 );
653 SHGetFolderPathW(NULL, CSIDL_FONTS, NULL, 0, pth);
654 lstrcatW(pth, L"\\");
655 msi_set_property( package->db, L"FontsFolder", pth, -1 );
657 SHGetFolderPathW(NULL, CSIDL_SENDTO, NULL, 0, pth);
658 lstrcatW(pth, L"\\");
659 msi_set_property( package->db, L"SendToFolder", pth, -1 );
661 SHGetFolderPathW(NULL, CSIDL_STARTMENU, NULL, 0, pth);
662 lstrcatW(pth, L"\\");
663 msi_set_property( package->db, L"StartMenuFolder", pth, -1 );
665 SHGetFolderPathW(NULL, CSIDL_STARTUP, NULL, 0, pth);
666 lstrcatW(pth, L"\\");
667 msi_set_property( package->db, L"StartupFolder", pth, -1 );
669 SHGetFolderPathW(NULL, CSIDL_TEMPLATES, NULL, 0, pth);
670 lstrcatW(pth, L"\\");
671 msi_set_property( package->db, L"TemplateFolder", pth, -1 );
673 SHGetFolderPathW(NULL, CSIDL_DESKTOP, NULL, 0, pth);
674 lstrcatW(pth, L"\\");
675 msi_set_property( package->db, L"DesktopFolder", pth, -1 );
677 /* FIXME: set to AllUsers profile path if ALLUSERS is set */
678 SHGetFolderPathW(NULL, CSIDL_PROGRAMS, NULL, 0, pth);
679 lstrcatW(pth, L"\\");
680 msi_set_property( package->db, L"ProgramMenuFolder", pth, -1 );
682 SHGetFolderPathW(NULL, CSIDL_ADMINTOOLS, NULL, 0, pth);
683 lstrcatW(pth, L"\\");
684 msi_set_property( package->db, L"AdminToolsFolder", pth, -1 );
686 SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, pth);
687 lstrcatW(pth, L"\\");
688 msi_set_property( package->db, L"AppDataFolder", pth, -1 );
690 SHGetFolderPathW(NULL, CSIDL_SYSTEM, NULL, 0, pth);
691 lstrcatW(pth, L"\\");
692 msi_set_property( package->db, L"SystemFolder", pth, -1 );
693 msi_set_property( package->db, L"System16Folder", pth, -1 );
695 SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, pth);
696 lstrcatW(pth, L"\\");
697 msi_set_property( package->db, L"LocalAppDataFolder", pth, -1 );
699 SHGetFolderPathW(NULL, CSIDL_MYPICTURES, NULL, 0, pth);
700 lstrcatW(pth, L"\\");
701 msi_set_property( package->db, L"MyPicturesFolder", pth, -1 );
703 SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, 0, pth);
704 lstrcatW(pth, L"\\");
705 msi_set_property( package->db, L"PersonalFolder", pth, -1 );
707 SHGetFolderPathW(NULL, CSIDL_WINDOWS, NULL, 0, pth);
708 lstrcatW(pth, L"\\");
709 msi_set_property( package->db, L"WindowsFolder", pth, -1 );
711 SHGetFolderPathW(NULL, CSIDL_PRINTHOOD, NULL, 0, pth);
712 lstrcatW(pth, L"\\");
713 msi_set_property( package->db, L"PrintHoodFolder", pth, -1 );
715 SHGetFolderPathW(NULL, CSIDL_NETHOOD, NULL, 0, pth);
716 lstrcatW(pth, L"\\");
717 msi_set_property( package->db, L"NetHoodFolder", pth, -1 );
719 SHGetFolderPathW(NULL, CSIDL_RECENT, NULL, 0, pth);
720 lstrcatW(pth, L"\\");
721 msi_set_property( package->db, L"RecentFolder", pth, -1 );
723 /* Physical Memory is specified in MB. Using total amount. */
724 msex.dwLength = sizeof(msex);
725 GlobalMemoryStatusEx( &msex );
726 len = swprintf( bufstr, ARRAY_SIZE(bufstr), L"%d", (int)(msex.ullTotalPhys / 1024 / 1024) );
727 msi_set_property( package->db, L"PhysicalMemory", bufstr, len );
729 SHGetFolderPathW(NULL, CSIDL_WINDOWS, NULL, 0, pth);
730 ptr = wcschr(pth,'\\');
731 if (ptr) *(ptr + 1) = 0;
732 msi_set_property( package->db, L"WindowsVolume", pth, -1 );
734 len = GetTempPathW(MAX_PATH, pth);
735 msi_set_property( package->db, L"TempFolder", pth, len );
737 /* in a wine environment the user is always admin and privileged */
738 msi_set_property( package->db, L"AdminUser", L"1", -1 );
739 msi_set_property( package->db, L"Privileged", L"1", -1 );
741 /* set the os things */
742 OSVersion.dwOSVersionInfoSize = sizeof(OSVersion);
743 RtlGetVersion(&OSVersion);
744 verval = OSVersion.dwMinorVersion + OSVersion.dwMajorVersion * 100;
745 if (verval > 603)
747 verval = 603;
748 OSVersion.dwBuildNumber = 9600;
750 len = swprintf( verstr, ARRAY_SIZE(verstr), L"%u", verval );
751 switch (OSVersion.dwPlatformId)
753 case VER_PLATFORM_WIN32_WINDOWS:
754 msi_set_property( package->db, L"Version9X", verstr, len );
755 break;
756 case VER_PLATFORM_WIN32_NT:
757 msi_set_property( package->db, L"VersionNT", verstr, len );
758 len = swprintf( bufstr, ARRAY_SIZE(bufstr), L"%u", OSVersion.wProductType );
759 msi_set_property( package->db, L"MsiNTProductType", bufstr, len );
760 break;
762 len = swprintf( bufstr, ARRAY_SIZE(bufstr), L"%u", OSVersion.dwBuildNumber );
763 msi_set_property( package->db, L"WindowsBuild", bufstr, len );
764 len = swprintf( bufstr, ARRAY_SIZE(bufstr), L"%u", OSVersion.wServicePackMajor );
765 msi_set_property( package->db, L"ServicePackLevel", bufstr, len );
767 len = swprintf( bufstr, ARRAY_SIZE(bufstr), L"%u.%u", MSI_MAJORVERSION, MSI_MINORVERSION );
768 msi_set_property( package->db, L"VersionMsi", bufstr, len );
769 len = swprintf( bufstr, ARRAY_SIZE(bufstr), L"%u", MSI_MAJORVERSION * 100 );
770 msi_set_property( package->db, L"VersionDatabase", bufstr, len );
772 RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion", 0,
773 KEY_QUERY_VALUE | KEY_WOW64_64KEY, &hkey);
775 GetNativeSystemInfo( &sys_info );
776 len = swprintf( bufstr, ARRAY_SIZE(bufstr), L"%d", sys_info.wProcessorLevel );
777 msi_set_property( package->db, L"Intel", bufstr, len );
778 if (sys_info.u.s.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
780 GetSystemDirectoryW( pth, MAX_PATH );
781 PathAddBackslashW( pth );
782 msi_set_property( package->db, L"SystemFolder", pth, -1 );
784 len = MAX_PATH;
785 RegQueryValueExW(hkey, L"ProgramFilesDir", 0, &type, (BYTE *)pth, &len);
786 PathAddBackslashW( pth );
787 msi_set_property( package->db, L"ProgramFilesFolder", pth, -1 );
789 len = MAX_PATH;
790 RegQueryValueExW(hkey, L"CommonFilesDir", 0, &type, (BYTE *)pth, &len);
791 PathAddBackslashW( pth );
792 msi_set_property( package->db, L"CommonFilesFolder", pth, -1 );
794 else if (sys_info.u.s.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
796 msi_set_property( package->db, L"MsiAMD64", bufstr, -1 );
797 msi_set_property( package->db, L"Msix64", bufstr, -1 );
798 msi_set_property( package->db, L"VersionNT64", verstr, -1 );
800 GetSystemDirectoryW( pth, MAX_PATH );
801 PathAddBackslashW( pth );
802 msi_set_property( package->db, L"System64Folder", pth, -1 );
804 GetSystemWow64DirectoryW( pth, MAX_PATH );
805 PathAddBackslashW( pth );
806 msi_set_property( package->db, L"SystemFolder", pth, -1 );
808 len = MAX_PATH;
809 RegQueryValueExW(hkey, L"ProgramFilesDir", 0, &type, (BYTE *)pth, &len);
810 PathAddBackslashW( pth );
811 msi_set_property( package->db, L"ProgramFiles64Folder", pth, -1 );
813 len = MAX_PATH;
814 RegQueryValueExW(hkey, L"ProgramFilesDir (x86)", 0, &type, (BYTE *)pth, &len);
815 PathAddBackslashW( pth );
816 msi_set_property( package->db, L"ProgramFilesFolder", pth, -1 );
818 len = MAX_PATH;
819 RegQueryValueExW(hkey, L"CommonFilesDir", 0, &type, (BYTE *)pth, &len);
820 PathAddBackslashW( pth );
821 msi_set_property( package->db, L"CommonFiles64Folder", pth, -1 );
823 len = MAX_PATH;
824 RegQueryValueExW(hkey, L"CommonFilesDir (x86)", 0, &type, (BYTE *)pth, &len);
825 PathAddBackslashW( pth );
826 msi_set_property( package->db, L"CommonFilesFolder", pth, -1 );
829 RegCloseKey(hkey);
831 /* Screen properties. */
832 dc = GetDC(0);
833 len = swprintf( bufstr, ARRAY_SIZE(bufstr), L"%d", GetDeviceCaps(dc, HORZRES) );
834 msi_set_property( package->db, L"ScreenX", bufstr, len );
835 len = swprintf( bufstr, ARRAY_SIZE(bufstr), L"%d", GetDeviceCaps(dc, VERTRES) );
836 msi_set_property( package->db, L"ScreenY", bufstr, len );
837 len = swprintf( bufstr, ARRAY_SIZE(bufstr), L"%d", GetDeviceCaps(dc, BITSPIXEL) );
838 msi_set_property( package->db, L"ColorBits", bufstr, len );
839 ReleaseDC(0, dc);
841 /* USERNAME and COMPANYNAME */
842 username = msi_dup_property( package->db, L"USERNAME" );
843 companyname = msi_dup_property( package->db, L"COMPANYNAME" );
845 if ((!username || !companyname) &&
846 RegOpenKeyW( HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\MS Setup (ACME)\\User Info", &hkey ) == ERROR_SUCCESS)
848 if (!username &&
849 (username = msi_reg_get_val_str( hkey, L"DefName" )))
850 msi_set_property( package->db, L"USERNAME", username, -1 );
851 if (!companyname &&
852 (companyname = msi_reg_get_val_str( hkey, L"DefCompany" )))
853 msi_set_property( package->db, L"COMPANYNAME", companyname, -1 );
854 CloseHandle( hkey );
856 if ((!username || !companyname) &&
857 RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0,
858 KEY_QUERY_VALUE|KEY_WOW64_64KEY, &hkey ) == ERROR_SUCCESS)
860 if (!username &&
861 (username = msi_reg_get_val_str( hkey, L"RegisteredOwner" )))
862 msi_set_property( package->db, L"USERNAME", username, -1 );
863 if (!companyname &&
864 (companyname = msi_reg_get_val_str( hkey, L"RegisteredOrganization" )))
865 msi_set_property( package->db, L"COMPANYNAME", companyname, -1 );
866 CloseHandle( hkey );
868 msi_free( username );
869 msi_free( companyname );
871 if ( set_user_sid_prop( package ) != ERROR_SUCCESS)
872 ERR("Failed to set the UserSID property\n");
874 set_msi_assembly_prop( package );
876 langid = GetUserDefaultLangID();
877 len = swprintf( bufstr, ARRAY_SIZE(bufstr), L"%d", langid );
878 msi_set_property( package->db, L"UserLanguageID", bufstr, len );
880 langid = GetSystemDefaultLangID();
881 len = swprintf( bufstr, ARRAY_SIZE(bufstr), L"%d", langid );
882 msi_set_property( package->db, L"SystemLanguageID", bufstr, len );
884 len = swprintf( bufstr, ARRAY_SIZE(bufstr), L"%d", MsiQueryProductStateW(package->ProductCode) );
885 msi_set_property( package->db, L"ProductState", bufstr, len );
887 len = 0;
888 if (!GetUserNameW( NULL, &len ) && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
890 WCHAR *username;
891 if ((username = msi_alloc( len * sizeof(WCHAR) )))
893 if (GetUserNameW( username, &len ))
894 msi_set_property( package->db, L"LogonUser", username, len - 1 );
895 msi_free( username );
898 len = 0;
899 if (!GetComputerNameW( NULL, &len ) && GetLastError() == ERROR_BUFFER_OVERFLOW)
901 WCHAR *computername;
902 if ((computername = msi_alloc( len * sizeof(WCHAR) )))
904 if (GetComputerNameW( computername, &len ))
905 msi_set_property( package->db, L"ComputerName", computername, len );
906 msi_free( computername );
911 static MSIPACKAGE *msi_alloc_package( void )
913 MSIPACKAGE *package;
915 package = alloc_msiobject( MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE),
916 MSI_FreePackage );
917 if( package )
919 list_init( &package->components );
920 list_init( &package->features );
921 list_init( &package->files );
922 list_init( &package->filepatches );
923 list_init( &package->tempfiles );
924 list_init( &package->folders );
925 list_init( &package->subscriptions );
926 list_init( &package->appids );
927 list_init( &package->classes );
928 list_init( &package->mimes );
929 list_init( &package->extensions );
930 list_init( &package->progids );
931 list_init( &package->RunningActions );
932 list_init( &package->sourcelist_info );
933 list_init( &package->sourcelist_media );
934 list_init( &package->patches );
935 list_init( &package->binaries );
936 list_init( &package->cabinet_streams );
939 return package;
942 static UINT msi_load_admin_properties(MSIPACKAGE *package)
944 BYTE *data;
945 UINT r, sz;
947 r = read_stream_data(package->db->storage, L"AdminProperties", FALSE, &data, &sz);
948 if (r != ERROR_SUCCESS)
949 return r;
951 r = msi_parse_command_line(package, (WCHAR *)data, TRUE);
953 msi_free(data);
954 return r;
957 void msi_adjust_privilege_properties( MSIPACKAGE *package )
959 /* FIXME: this should depend on the user's privileges */
960 if (msi_get_property_int( package->db, L"ALLUSERS", 0 ) == 2)
962 TRACE("resetting ALLUSERS property from 2 to 1\n");
963 msi_set_property( package->db, L"ALLUSERS", L"1", -1 );
965 msi_set_property( package->db, L"AdminUser", L"1", -1 );
968 MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db )
970 MSIPACKAGE *package;
971 WCHAR uilevel[11];
972 int len;
973 UINT r;
975 TRACE("%p\n", db);
977 package = msi_alloc_package();
978 if (package)
980 msiobj_addref( &db->hdr );
981 package->db = db;
983 package->LastAction = NULL;
984 package->LastActionTemplate = NULL;
985 package->LastActionResult = MSI_NULL_INTEGER;
986 package->WordCount = 0;
987 package->PackagePath = strdupW( db->path );
989 create_temp_property_table( package );
990 msi_clone_properties( package->db );
991 msi_adjust_privilege_properties( package );
993 package->ProductCode = msi_dup_property( package->db, L"ProductCode" );
995 set_installer_properties( package );
997 package->ui_level = gUILevel;
998 len = swprintf( uilevel, ARRAY_SIZE(uilevel), L"%u", gUILevel & INSTALLUILEVEL_MASK );
999 msi_set_property( package->db, L"UILevel", uilevel, len );
1001 r = msi_load_suminfo_properties( package );
1002 if (r != ERROR_SUCCESS)
1004 msiobj_release( &package->hdr );
1005 return NULL;
1008 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1009 msi_load_admin_properties( package );
1011 package->log_file = INVALID_HANDLE_VALUE;
1012 package->script = SCRIPT_NONE;
1014 return package;
1017 UINT msi_download_file( LPCWSTR szUrl, LPWSTR filename )
1019 LPINTERNET_CACHE_ENTRY_INFOW cache_entry;
1020 DWORD size = 0;
1021 HRESULT hr;
1023 /* call will always fail, because size is 0,
1024 * but will return ERROR_FILE_NOT_FOUND first
1025 * if the file doesn't exist
1027 GetUrlCacheEntryInfoW( szUrl, NULL, &size );
1028 if ( GetLastError() != ERROR_FILE_NOT_FOUND )
1030 cache_entry = msi_alloc( size );
1031 if ( !GetUrlCacheEntryInfoW( szUrl, cache_entry, &size ) )
1033 UINT error = GetLastError();
1034 msi_free( cache_entry );
1035 return error;
1038 lstrcpyW( filename, cache_entry->lpszLocalFileName );
1039 msi_free( cache_entry );
1040 return ERROR_SUCCESS;
1043 hr = URLDownloadToCacheFileW( NULL, szUrl, filename, MAX_PATH, 0, NULL );
1044 if ( FAILED(hr) )
1046 WARN("failed to download %s to cache file\n", debugstr_w(szUrl));
1047 return ERROR_FUNCTION_FAILED;
1050 return ERROR_SUCCESS;
1053 UINT msi_create_empty_local_file( LPWSTR path, LPCWSTR suffix )
1055 DWORD time, len, i, offset;
1056 HANDLE handle;
1058 time = GetTickCount();
1059 GetWindowsDirectoryW( path, MAX_PATH );
1060 lstrcatW( path, L"\\Installer\\" );
1061 CreateDirectoryW( path, NULL );
1063 len = lstrlenW(path);
1064 for (i = 0; i < 0x10000; i++)
1066 offset = swprintf( path + len, MAX_PATH - len, L"%x", (time + i) & 0xffff );
1067 memcpy( path + len + offset, suffix, (lstrlenW( suffix ) + 1) * sizeof(WCHAR) );
1068 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
1069 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1070 if (handle != INVALID_HANDLE_VALUE)
1072 CloseHandle(handle);
1073 break;
1075 if (GetLastError() != ERROR_FILE_EXISTS &&
1076 GetLastError() != ERROR_SHARING_VIOLATION)
1077 return ERROR_FUNCTION_FAILED;
1080 return ERROR_SUCCESS;
1083 static enum platform parse_platform( const WCHAR *str )
1085 if (!str[0] || !wcscmp( str, L"Intel" )) return PLATFORM_INTEL;
1086 else if (!wcscmp( str, L"Intel64" )) return PLATFORM_INTEL64;
1087 else if (!wcscmp( str, L"x64" ) || !wcscmp( str, L"AMD64" )) return PLATFORM_X64;
1088 else if (!wcscmp( str, L"Arm" )) return PLATFORM_ARM;
1089 else if (!wcscmp( str, L"Arm64" )) return PLATFORM_ARM64;
1090 return PLATFORM_UNRECOGNIZED;
1093 static UINT parse_suminfo( MSISUMMARYINFO *si, MSIPACKAGE *package )
1095 WCHAR *template, *p, *q, *platform;
1096 DWORD i, count;
1098 package->version = msi_suminfo_get_int32( si, PID_PAGECOUNT );
1099 TRACE("version: %d\n", package->version);
1101 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
1102 if (!template)
1103 return ERROR_SUCCESS; /* native accepts missing template property */
1105 TRACE("template: %s\n", debugstr_w(template));
1107 p = wcschr( template, ';' );
1108 if (!p)
1110 WARN("invalid template string %s\n", debugstr_w(template));
1111 msi_free( template );
1112 return ERROR_PATCH_PACKAGE_INVALID;
1114 *p = 0;
1115 platform = template;
1116 if ((q = wcschr( platform, ',' ))) *q = 0;
1117 package->platform = parse_platform( platform );
1118 while (package->platform == PLATFORM_UNRECOGNIZED && q)
1120 platform = q + 1;
1121 if ((q = wcschr( platform, ',' ))) *q = 0;
1122 package->platform = parse_platform( platform );
1124 if (package->platform == PLATFORM_UNRECOGNIZED)
1126 WARN("unknown platform %s\n", debugstr_w(template));
1127 msi_free( template );
1128 return ERROR_INSTALL_PLATFORM_UNSUPPORTED;
1130 p++;
1131 if (!*p)
1133 msi_free( template );
1134 return ERROR_SUCCESS;
1136 count = 1;
1137 for (q = p; (q = wcschr( q, ',' )); q++) count++;
1139 package->langids = msi_alloc( count * sizeof(LANGID) );
1140 if (!package->langids)
1142 msi_free( template );
1143 return ERROR_OUTOFMEMORY;
1146 i = 0;
1147 while (*p)
1149 q = wcschr( p, ',' );
1150 if (q) *q = 0;
1151 package->langids[i] = wcstol( p, NULL, 10 );
1152 if (!q) break;
1153 p = q + 1;
1154 i++;
1156 package->num_langids = i + 1;
1158 msi_free( template );
1159 return ERROR_SUCCESS;
1162 static UINT validate_package( MSIPACKAGE *package )
1164 UINT i;
1166 if (package->platform == PLATFORM_INTEL64)
1167 return ERROR_INSTALL_PLATFORM_UNSUPPORTED;
1168 #ifndef __arm__
1169 if (package->platform == PLATFORM_ARM)
1170 return ERROR_INSTALL_PLATFORM_UNSUPPORTED;
1171 #endif
1172 #ifndef __aarch64__
1173 if (package->platform == PLATFORM_ARM64)
1174 return ERROR_INSTALL_PLATFORM_UNSUPPORTED;
1175 #endif
1176 if (package->platform == PLATFORM_X64)
1178 if (!is_64bit && !is_wow64)
1179 return ERROR_INSTALL_PLATFORM_UNSUPPORTED;
1180 if (package->version < 200)
1181 return ERROR_INSTALL_PACKAGE_INVALID;
1183 if (!package->num_langids)
1185 return ERROR_SUCCESS;
1187 for (i = 0; i < package->num_langids; i++)
1189 LANGID langid = package->langids[i];
1191 if (PRIMARYLANGID( langid ) == LANG_NEUTRAL)
1193 langid = MAKELANGID( PRIMARYLANGID( GetSystemDefaultLangID() ), SUBLANGID( langid ) );
1195 if (SUBLANGID( langid ) == SUBLANG_NEUTRAL)
1197 langid = MAKELANGID( PRIMARYLANGID( langid ), SUBLANGID( GetSystemDefaultLangID() ) );
1199 if (IsValidLocale( langid, LCID_INSTALLED ))
1200 return ERROR_SUCCESS;
1202 return ERROR_INSTALL_LANGUAGE_UNSUPPORTED;
1205 static WCHAR *get_property( MSIDATABASE *db, const WCHAR *prop )
1207 WCHAR query[MAX_PATH];
1208 MSIQUERY *view;
1209 MSIRECORD *rec;
1210 WCHAR *ret = NULL;
1212 swprintf(query, ARRAY_SIZE(query), L"SELECT `Value` FROM `Property` WHERE `Property`='%s'", prop);
1213 if (MSI_DatabaseOpenViewW( db, query, &view ) != ERROR_SUCCESS)
1215 return NULL;
1217 if (MSI_ViewExecute( view, 0 ) != ERROR_SUCCESS)
1219 MSI_ViewClose( view );
1220 msiobj_release( &view->hdr );
1221 return NULL;
1223 if (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
1225 ret = strdupW( MSI_RecordGetString( rec, 1 ) );
1226 msiobj_release( &rec->hdr );
1228 MSI_ViewClose( view );
1229 msiobj_release( &view->hdr );
1230 return ret;
1233 static WCHAR *get_product_code( MSIDATABASE *db )
1235 return get_property( db, L"ProductCode" );
1238 static WCHAR *get_product_version( MSIDATABASE *db )
1240 return get_property( db, L"ProductVersion" );
1243 static UINT get_registered_local_package( const WCHAR *product, WCHAR *localfile )
1245 MSIINSTALLCONTEXT context;
1246 WCHAR *filename;
1247 HKEY props_key;
1248 UINT r;
1250 r = msi_locate_product( product, &context );
1251 if (r != ERROR_SUCCESS)
1252 return r;
1254 r = MSIREG_OpenInstallProps( product, context, NULL, &props_key, FALSE );
1255 if (r != ERROR_SUCCESS)
1256 return r;
1258 filename = msi_reg_get_val_str( props_key, INSTALLPROPERTY_LOCALPACKAGEW );
1259 RegCloseKey( props_key );
1260 if (!filename)
1261 return ERROR_FUNCTION_FAILED;
1263 lstrcpyW( localfile, filename );
1264 msi_free( filename );
1265 return ERROR_SUCCESS;
1268 WCHAR *msi_get_package_code( MSIDATABASE *db )
1270 WCHAR *ret;
1271 MSISUMMARYINFO *si;
1272 UINT r;
1274 r = msi_get_suminfo( db->storage, 0, &si );
1275 if (r != ERROR_SUCCESS)
1277 r = msi_get_db_suminfo( db, 0, &si );
1278 if (r != ERROR_SUCCESS)
1280 WARN("failed to load summary info %u\n", r);
1281 return NULL;
1284 ret = msi_suminfo_dup_string( si, PID_REVNUMBER );
1285 msiobj_release( &si->hdr );
1286 return ret;
1289 static UINT get_local_package( MSIDATABASE *db, WCHAR *localfile )
1291 WCHAR *product_code;
1292 UINT r;
1294 if (!(product_code = get_product_code( db )))
1295 return ERROR_INSTALL_PACKAGE_INVALID;
1296 r = get_registered_local_package( product_code, localfile );
1297 msi_free( product_code );
1298 return r;
1301 UINT msi_set_original_database_property( MSIDATABASE *db, const WCHAR *package )
1303 UINT r;
1305 if (UrlIsW( package, URLIS_URL ))
1306 r = msi_set_property( db, L"OriginalDatabase", package, -1 );
1307 else if (package[0] == '#')
1308 r = msi_set_property( db, L"OriginalDatabase", db->path, -1 );
1309 else
1311 DWORD len;
1312 WCHAR *path;
1314 if (!(len = GetFullPathNameW( package, 0, NULL, NULL ))) return GetLastError();
1315 if (!(path = msi_alloc( len * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY;
1316 len = GetFullPathNameW( package, len, path, NULL );
1317 r = msi_set_property( db, L"OriginalDatabase", path, len );
1318 msi_free( path );
1320 return r;
1323 UINT MSI_OpenPackageW(LPCWSTR szPackage, DWORD dwOptions, MSIPACKAGE **pPackage)
1325 MSIDATABASE *db;
1326 MSIPACKAGE *package;
1327 MSIHANDLE handle;
1328 MSIRECORD *data_row, *info_row;
1329 UINT r;
1330 WCHAR localfile[MAX_PATH], cachefile[MAX_PATH];
1331 LPCWSTR file = szPackage;
1332 DWORD index = 0;
1333 MSISUMMARYINFO *si;
1334 BOOL delete_on_close = FALSE;
1335 WCHAR *info_template, *productname, *product_code;
1336 MSIINSTALLCONTEXT context;
1338 TRACE("%s %p\n", debugstr_w(szPackage), pPackage);
1340 MSI_ProcessMessage(NULL, INSTALLMESSAGE_INITIALIZE, 0);
1342 localfile[0] = 0;
1343 if( szPackage[0] == '#' )
1345 handle = wcstol(&szPackage[1], NULL, 10);
1346 if (!(db = msihandle2msiinfo(handle, MSIHANDLETYPE_DATABASE)))
1347 return ERROR_INVALID_HANDLE;
1349 else
1351 WCHAR *product_version = NULL;
1353 if ( UrlIsW( szPackage, URLIS_URL ) )
1355 r = msi_download_file( szPackage, cachefile );
1356 if (r != ERROR_SUCCESS)
1357 return r;
1359 file = cachefile;
1361 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &db );
1362 if (r != ERROR_SUCCESS)
1364 if (GetFileAttributesW( file ) == INVALID_FILE_ATTRIBUTES)
1365 return ERROR_FILE_NOT_FOUND;
1366 return r;
1368 r = get_local_package( db, localfile );
1369 if (r != ERROR_SUCCESS || GetFileAttributesW( localfile ) == INVALID_FILE_ATTRIBUTES)
1371 r = msi_create_empty_local_file( localfile, L".msi" );
1372 if (r != ERROR_SUCCESS)
1374 msiobj_release( &db->hdr );
1375 return r;
1378 if (!CopyFileW( file, localfile, FALSE ))
1380 r = GetLastError();
1381 WARN("unable to copy package %s to %s (%u)\n", debugstr_w(file), debugstr_w(localfile), r);
1382 DeleteFileW( localfile );
1383 msiobj_release( &db->hdr );
1384 return r;
1386 delete_on_close = TRUE;
1388 else if (dwOptions & WINE_OPENPACKAGEFLAGS_RECACHE)
1390 if (!CopyFileW( file, localfile, FALSE ))
1392 r = GetLastError();
1393 WARN("unable to update cached package (%u)\n", r);
1394 msiobj_release( &db->hdr );
1395 return r;
1398 else
1399 product_version = get_product_version( db );
1400 msiobj_release( &db->hdr );
1401 TRACE("opening package %s\n", debugstr_w( localfile ));
1402 r = MSI_OpenDatabaseW( localfile, MSIDBOPEN_TRANSACT, &db );
1403 if (r != ERROR_SUCCESS)
1404 return r;
1406 if (product_version)
1408 WCHAR *cache_version = get_product_version( db );
1409 if (!product_version != !cache_version ||
1410 (product_version && wcscmp(product_version, cache_version)))
1412 msiobj_release( &db->hdr );
1413 msi_free(product_version);
1414 msi_free(cache_version);
1415 return ERROR_PRODUCT_VERSION;
1417 msi_free(product_version);
1418 msi_free(cache_version);
1421 package = MSI_CreatePackage( db );
1422 msiobj_release( &db->hdr );
1423 if (!package) return ERROR_INSTALL_PACKAGE_INVALID;
1424 package->localfile = strdupW( localfile );
1425 package->delete_on_close = delete_on_close;
1427 r = msi_get_suminfo( db->storage, 0, &si );
1428 if (r != ERROR_SUCCESS)
1430 r = msi_get_db_suminfo( db, 0, &si );
1431 if (r != ERROR_SUCCESS)
1433 WARN("failed to load summary info\n");
1434 msiobj_release( &package->hdr );
1435 return ERROR_INSTALL_PACKAGE_INVALID;
1438 r = parse_suminfo( si, package );
1439 msiobj_release( &si->hdr );
1440 if (r != ERROR_SUCCESS)
1442 WARN("failed to parse summary info %u\n", r);
1443 msiobj_release( &package->hdr );
1444 return r;
1446 r = validate_package( package );
1447 if (r != ERROR_SUCCESS)
1449 msiobj_release( &package->hdr );
1450 return r;
1452 msi_set_property( package->db, L"DATABASE", db->path, -1 );
1453 set_installed_prop( package );
1454 msi_set_context( package );
1456 product_code = get_product_code( db );
1457 if (msi_locate_product( product_code, &context ) == ERROR_SUCCESS)
1459 TRACE("product already registered\n");
1460 msi_set_property( package->db, L"ProductToBeRegistered", L"1", -1 );
1462 msi_free(product_code);
1464 while (1)
1466 WCHAR patch_code[GUID_SIZE];
1467 r = MsiEnumPatchesExW( package->ProductCode, NULL, package->Context,
1468 MSIPATCHSTATE_APPLIED, index, patch_code, NULL, NULL, NULL, NULL );
1469 if (r != ERROR_SUCCESS)
1470 break;
1472 TRACE("found registered patch %s\n", debugstr_w(patch_code));
1474 r = msi_apply_registered_patch( package, patch_code );
1475 if (r != ERROR_SUCCESS)
1477 ERR("registered patch failed to apply %u\n", r);
1478 msiobj_release( &package->hdr );
1479 return r;
1481 index++;
1483 if (index) msi_adjust_privilege_properties( package );
1485 r = msi_set_original_database_property( package->db, szPackage );
1486 if (r != ERROR_SUCCESS)
1488 msiobj_release( &package->hdr );
1489 return r;
1491 if (gszLogFile)
1492 package->log_file = CreateFileW( gszLogFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1493 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
1495 if (!msi_init_assembly_caches( package ))
1497 ERR("can't initialize assembly caches\n");
1498 msiobj_release( &package->hdr );
1499 return ERROR_FUNCTION_FAILED;
1502 /* FIXME: when should these messages be sent? */
1503 data_row = MSI_CreateRecord(3);
1504 if (!data_row)
1505 return ERROR_OUTOFMEMORY;
1506 MSI_RecordSetStringW(data_row, 0, NULL);
1507 MSI_RecordSetInteger(data_row, 1, 0);
1508 MSI_RecordSetInteger(data_row, 2, package->num_langids ? package->langids[0] : 0);
1509 MSI_RecordSetInteger(data_row, 3, msi_get_string_table_codepage(package->db->strings));
1510 MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_COMMONDATA, data_row);
1512 info_row = MSI_CreateRecord(0);
1513 if (!info_row)
1515 msiobj_release(&data_row->hdr);
1516 return ERROR_OUTOFMEMORY;
1518 info_template = msi_get_error_message(package->db, MSIERR_INFO_LOGGINGSTART);
1519 MSI_RecordSetStringW(info_row, 0, info_template);
1520 msi_free(info_template);
1521 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO|MB_ICONHAND, info_row);
1523 MSI_ProcessMessage(package, INSTALLMESSAGE_COMMONDATA, data_row);
1525 productname = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
1526 MSI_RecordSetInteger(data_row, 1, 1);
1527 MSI_RecordSetStringW(data_row, 2, productname);
1528 MSI_RecordSetStringW(data_row, 3, NULL);
1529 MSI_ProcessMessage(package, INSTALLMESSAGE_COMMONDATA, data_row);
1531 msi_free(productname);
1532 msiobj_release(&info_row->hdr);
1533 msiobj_release(&data_row->hdr);
1535 *pPackage = package;
1536 return ERROR_SUCCESS;
1539 UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
1541 MSIPACKAGE *package = NULL;
1542 UINT ret;
1544 TRACE("%s %08x %p\n", debugstr_w(szPackage), dwOptions, phPackage );
1546 if( !szPackage || !phPackage )
1547 return ERROR_INVALID_PARAMETER;
1549 if ( !*szPackage )
1551 FIXME("Should create an empty database and package\n");
1552 return ERROR_FUNCTION_FAILED;
1555 if( dwOptions )
1556 FIXME("dwOptions %08x not supported\n", dwOptions);
1558 ret = MSI_OpenPackageW( szPackage, 0, &package );
1559 if( ret == ERROR_SUCCESS )
1561 *phPackage = alloc_msihandle( &package->hdr );
1562 if (! *phPackage)
1563 ret = ERROR_NOT_ENOUGH_MEMORY;
1564 msiobj_release( &package->hdr );
1566 else
1567 MSI_ProcessMessage(NULL, INSTALLMESSAGE_TERMINATE, 0);
1569 return ret;
1572 UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
1574 return MsiOpenPackageExW( szPackage, 0, phPackage );
1577 UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
1579 LPWSTR szwPack = NULL;
1580 UINT ret;
1582 if( szPackage )
1584 szwPack = strdupAtoW( szPackage );
1585 if( !szwPack )
1586 return ERROR_OUTOFMEMORY;
1589 ret = MsiOpenPackageExW( szwPack, dwOptions, phPackage );
1591 msi_free( szwPack );
1593 return ret;
1596 UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
1598 return MsiOpenPackageExA( szPackage, 0, phPackage );
1601 MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
1603 MSIPACKAGE *package;
1604 MSIHANDLE handle = 0;
1605 MSIHANDLE remote;
1607 TRACE("(%d)\n",hInstall);
1609 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
1610 if( package)
1612 handle = alloc_msihandle( &package->db->hdr );
1613 msiobj_release( &package->hdr );
1615 else if ((remote = msi_get_remote(hInstall)))
1617 __TRY
1619 handle = remote_GetActiveDatabase(remote);
1620 handle = alloc_msi_remote_handle(handle);
1622 __EXCEPT(rpc_filter)
1624 handle = 0;
1626 __ENDTRY
1629 return handle;
1632 static INT internal_ui_handler(MSIPACKAGE *package, INSTALLMESSAGE eMessageType, MSIRECORD *record, LPCWSTR message)
1634 if (!package || (package->ui_level & INSTALLUILEVEL_MASK) == INSTALLUILEVEL_NONE)
1635 return 0;
1637 /* todo: check if message needs additional styles (topmost/foreground/modality?) */
1639 switch (eMessageType & 0xff000000)
1641 case INSTALLMESSAGE_FATALEXIT:
1642 case INSTALLMESSAGE_ERROR:
1643 case INSTALLMESSAGE_OUTOFDISKSPACE:
1644 if (package->ui_level & INSTALLUILEVEL_PROGRESSONLY) return 0;
1645 if (!(eMessageType & MB_ICONMASK))
1646 eMessageType |= MB_ICONEXCLAMATION;
1647 return MessageBoxW(gUIhwnd, message, L"Windows Installer", eMessageType & 0x00ffffff);
1648 case INSTALLMESSAGE_WARNING:
1649 if (package->ui_level & INSTALLUILEVEL_PROGRESSONLY) return 0;
1650 if (!(eMessageType & MB_ICONMASK))
1651 eMessageType |= MB_ICONASTERISK;
1652 return MessageBoxW(gUIhwnd, message, L"Windows Installer", eMessageType & 0x00ffffff);
1653 case INSTALLMESSAGE_USER:
1654 if (package->ui_level & INSTALLUILEVEL_PROGRESSONLY) return 0;
1655 if (!(eMessageType & MB_ICONMASK))
1656 eMessageType |= MB_USERICON;
1657 return MessageBoxW(gUIhwnd, message, L"Windows Installer", eMessageType & 0x00ffffff);
1658 case INSTALLMESSAGE_INFO:
1659 case INSTALLMESSAGE_INITIALIZE:
1660 case INSTALLMESSAGE_TERMINATE:
1661 case INSTALLMESSAGE_INSTALLSTART:
1662 case INSTALLMESSAGE_INSTALLEND:
1663 return 0;
1664 case INSTALLMESSAGE_SHOWDIALOG:
1666 LPWSTR dialog = msi_dup_record_field(record, 0);
1667 INT rc = ACTION_DialogBox(package, dialog);
1668 msi_free(dialog);
1669 return rc;
1671 case INSTALLMESSAGE_ACTIONSTART:
1673 LPWSTR deformatted;
1674 MSIRECORD *uirow = MSI_CreateRecord(1);
1675 if (!uirow) return -1;
1676 deformat_string(package, MSI_RecordGetString(record, 2), &deformatted);
1677 MSI_RecordSetStringW(uirow, 1, deformatted);
1678 msi_event_fire(package, L"ActionText", uirow);
1680 msi_free(deformatted);
1681 msiobj_release(&uirow->hdr);
1682 return 1;
1684 case INSTALLMESSAGE_ACTIONDATA:
1686 MSIRECORD *uirow = MSI_CreateRecord(1);
1687 if (!uirow) return -1;
1688 MSI_RecordSetStringW(uirow, 1, message);
1689 msi_event_fire(package, L"ActionData", uirow);
1690 msiobj_release(&uirow->hdr);
1692 if (package->action_progress_increment)
1694 uirow = MSI_CreateRecord(2);
1695 if (!uirow) return -1;
1696 MSI_RecordSetInteger(uirow, 1, 2);
1697 MSI_RecordSetInteger(uirow, 2, package->action_progress_increment);
1698 msi_event_fire(package, L"SetProgress", uirow);
1699 msiobj_release(&uirow->hdr);
1701 return 1;
1703 case INSTALLMESSAGE_PROGRESS:
1704 msi_event_fire(package, L"SetProgress", record);
1705 return 1;
1706 case INSTALLMESSAGE_COMMONDATA:
1707 switch (MSI_RecordGetInteger(record, 1))
1709 case 0:
1710 case 1:
1711 /* do nothing */
1712 return 0;
1713 default:
1714 /* fall through */
1717 default:
1718 FIXME("internal UI not implemented for message 0x%08x (UI level = %x)\n", eMessageType, package->ui_level);
1719 return 0;
1723 static const struct
1725 int id;
1726 const WCHAR *text;
1728 internal_errors[] =
1730 {2726, L"DEBUG: Error [1]: Action not found: [2]"},
1734 static LPCWSTR get_internal_error_message(int error)
1736 int i = 0;
1738 while (internal_errors[i].id != 0)
1740 if (internal_errors[i].id == error)
1741 return internal_errors[i].text;
1742 i++;
1745 FIXME("missing error message %d\n", error);
1746 return NULL;
1749 /* Returned string must be freed */
1750 LPWSTR msi_get_error_message(MSIDATABASE *db, int error)
1752 MSIRECORD *record;
1753 LPWSTR ret = NULL;
1755 if ((record = MSI_QueryGetRecord(db, L"SELECT `Message` FROM `Error` WHERE `Error` = %d", error)))
1757 ret = msi_dup_record_field(record, 1);
1758 msiobj_release(&record->hdr);
1760 else if (error < 2000)
1762 int len = LoadStringW(msi_hInstance, IDS_ERROR_BASE + error, (LPWSTR) &ret, 0);
1763 if (len)
1765 ret = msi_alloc((len + 1) * sizeof(WCHAR));
1766 LoadStringW(msi_hInstance, IDS_ERROR_BASE + error, ret, len + 1);
1768 else
1769 ret = NULL;
1772 return ret;
1775 INT MSI_ProcessMessageVerbatim(MSIPACKAGE *package, INSTALLMESSAGE eMessageType, MSIRECORD *record)
1777 LPWSTR message = {0};
1778 DWORD len;
1779 DWORD log_type = 1 << (eMessageType >> 24);
1780 UINT res;
1781 INT rc = 0;
1782 char *msg;
1784 TRACE("%x\n", eMessageType);
1785 if (TRACE_ON(msi)) dump_record(record);
1787 if (!package || !record)
1788 message = NULL;
1789 else {
1790 res = MSI_FormatRecordW(package, record, message, &len);
1791 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
1792 return res;
1793 len++;
1794 message = msi_alloc(len * sizeof(WCHAR));
1795 if (!message) return ERROR_OUTOFMEMORY;
1796 MSI_FormatRecordW(package, record, message, &len);
1799 /* convert it to ASCII */
1800 len = WideCharToMultiByte( CP_ACP, 0, message, -1, NULL, 0, NULL, NULL );
1801 msg = msi_alloc( len );
1802 WideCharToMultiByte( CP_ACP, 0, message, -1, msg, len, NULL, NULL );
1804 if (gUIHandlerRecord && (gUIFilterRecord & log_type))
1806 MSIHANDLE rec = alloc_msihandle(&record->hdr);
1807 TRACE("Calling UI handler %p(pvContext=%p, iMessageType=%08x, hRecord=%u)\n",
1808 gUIHandlerRecord, gUIContextRecord, eMessageType, rec);
1809 rc = gUIHandlerRecord( gUIContextRecord, eMessageType, rec );
1810 MsiCloseHandle( rec );
1812 if (!rc && gUIHandlerW && (gUIFilter & log_type))
1814 TRACE("Calling UI handler %p(pvContext=%p, iMessageType=%08x, szMessage=%s)\n",
1815 gUIHandlerW, gUIContext, eMessageType, debugstr_w(message));
1816 rc = gUIHandlerW( gUIContext, eMessageType, message );
1818 else if (!rc && gUIHandlerA && (gUIFilter & log_type))
1820 TRACE("Calling UI handler %p(pvContext=%p, iMessageType=%08x, szMessage=%s)\n",
1821 gUIHandlerA, gUIContext, eMessageType, debugstr_a(msg));
1822 rc = gUIHandlerA( gUIContext, eMessageType, msg );
1825 if (!rc)
1826 rc = internal_ui_handler(package, eMessageType, record, message);
1828 if (!rc && package && package->log_file != INVALID_HANDLE_VALUE &&
1829 (eMessageType & 0xff000000) != INSTALLMESSAGE_PROGRESS)
1831 DWORD written;
1832 WriteFile( package->log_file, msg, len - 1, &written, NULL );
1833 WriteFile( package->log_file, "\n", 1, &written, NULL );
1835 msi_free( msg );
1836 msi_free( message );
1838 return rc;
1841 INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType, MSIRECORD *record )
1843 switch (eMessageType & 0xff000000)
1845 case INSTALLMESSAGE_FATALEXIT:
1846 case INSTALLMESSAGE_ERROR:
1847 case INSTALLMESSAGE_WARNING:
1848 case INSTALLMESSAGE_USER:
1849 case INSTALLMESSAGE_INFO:
1850 case INSTALLMESSAGE_OUTOFDISKSPACE:
1851 if (MSI_RecordGetInteger(record, 1) != MSI_NULL_INTEGER)
1853 /* error message */
1855 LPWSTR template;
1856 LPWSTR template_rec = NULL, template_prefix = NULL;
1857 int error = MSI_RecordGetInteger(record, 1);
1859 if (MSI_RecordIsNull(record, 0))
1861 if (error >= 32)
1863 template_rec = msi_get_error_message(package->db, error);
1865 if (!template_rec && error >= 2000)
1867 /* internal error, not localized */
1868 if ((template_rec = (LPWSTR) get_internal_error_message(error)))
1870 MSI_RecordSetStringW(record, 0, template_rec);
1871 MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_INFO, record);
1873 template_rec = msi_get_error_message(package->db, MSIERR_INSTALLERROR);
1874 MSI_RecordSetStringW(record, 0, template_rec);
1875 MSI_ProcessMessageVerbatim(package, eMessageType, record);
1876 msi_free(template_rec);
1877 return 0;
1881 else
1882 template_rec = msi_dup_record_field(record, 0);
1884 template_prefix = msi_get_error_message(package->db, eMessageType >> 24);
1885 if (!template_prefix) template_prefix = strdupW(L"");
1887 if (!template_rec)
1889 /* always returns 0 */
1890 MSI_RecordSetStringW(record, 0, template_prefix);
1891 MSI_ProcessMessageVerbatim(package, eMessageType, record);
1892 msi_free(template_prefix);
1893 return 0;
1896 template = msi_alloc((lstrlenW(template_rec) + lstrlenW(template_prefix) + 1) * sizeof(WCHAR));
1897 if (!template) return ERROR_OUTOFMEMORY;
1899 lstrcpyW(template, template_prefix);
1900 lstrcatW(template, template_rec);
1901 MSI_RecordSetStringW(record, 0, template);
1903 msi_free(template_prefix);
1904 msi_free(template_rec);
1905 msi_free(template);
1907 break;
1908 case INSTALLMESSAGE_ACTIONSTART:
1910 WCHAR *template = msi_get_error_message(package->db, MSIERR_ACTIONSTART);
1911 MSI_RecordSetStringW(record, 0, template);
1912 msi_free(template);
1914 msi_free(package->LastAction);
1915 msi_free(package->LastActionTemplate);
1916 package->LastAction = msi_dup_record_field(record, 1);
1917 if (!package->LastAction) package->LastAction = strdupW(L"");
1918 package->LastActionTemplate = msi_dup_record_field(record, 3);
1919 break;
1921 case INSTALLMESSAGE_ACTIONDATA:
1922 if (package->LastAction && package->LastActionTemplate)
1924 size_t len = lstrlenW(package->LastAction) + lstrlenW(package->LastActionTemplate) + 7;
1925 WCHAR *template = msi_alloc(len * sizeof(WCHAR));
1926 if (!template) return ERROR_OUTOFMEMORY;
1927 swprintf(template, len, L"{{%s: }}%s", package->LastAction, package->LastActionTemplate);
1928 MSI_RecordSetStringW(record, 0, template);
1929 msi_free(template);
1931 break;
1932 case INSTALLMESSAGE_COMMONDATA:
1934 WCHAR *template = msi_get_error_message(package->db, MSIERR_COMMONDATA);
1935 MSI_RecordSetStringW(record, 0, template);
1936 msi_free(template);
1938 break;
1941 return MSI_ProcessMessageVerbatim(package, eMessageType, record);
1944 INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
1945 MSIHANDLE hRecord)
1947 UINT ret = ERROR_INVALID_HANDLE;
1948 MSIPACKAGE *package = NULL;
1949 MSIRECORD *record = NULL;
1951 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INITIALIZE ||
1952 (eMessageType & 0xff000000) == INSTALLMESSAGE_TERMINATE)
1953 return -1;
1955 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA &&
1956 MsiRecordGetInteger(hRecord, 1) != 2)
1957 return -1;
1959 record = msihandle2msiinfo(hRecord, MSIHANDLETYPE_RECORD);
1960 if (!record)
1961 return ERROR_INVALID_HANDLE;
1963 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
1964 if( !package )
1966 MSIHANDLE remote;
1968 if (!(remote = msi_get_remote(hInstall)))
1969 return ERROR_INVALID_HANDLE;
1971 __TRY
1973 ret = remote_ProcessMessage(remote, eMessageType, (struct wire_record *)&record->count);
1975 __EXCEPT(rpc_filter)
1977 ret = GetExceptionCode();
1979 __ENDTRY
1981 msiobj_release(&record->hdr);
1982 return ret;
1985 ret = MSI_ProcessMessage( package, eMessageType, record );
1987 msiobj_release( &record->hdr );
1988 msiobj_release( &package->hdr );
1989 return ret;
1992 /* property code */
1994 UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue )
1996 LPWSTR szwName = NULL, szwValue = NULL;
1997 UINT r = ERROR_OUTOFMEMORY;
1999 szwName = strdupAtoW( szName );
2000 if( szName && !szwName )
2001 goto end;
2003 szwValue = strdupAtoW( szValue );
2004 if( szValue && !szwValue )
2005 goto end;
2007 r = MsiSetPropertyW( hInstall, szwName, szwValue);
2009 end:
2010 msi_free( szwName );
2011 msi_free( szwValue );
2013 return r;
2016 void msi_reset_source_folders( MSIPACKAGE *package )
2018 MSIFOLDER *folder;
2020 LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
2022 msi_free( folder->ResolvedSource );
2023 folder->ResolvedSource = NULL;
2027 UINT msi_set_property( MSIDATABASE *db, const WCHAR *name, const WCHAR *value, int len )
2029 MSIQUERY *view;
2030 MSIRECORD *row = NULL;
2031 DWORD sz = 0;
2032 WCHAR query[1024];
2033 UINT rc;
2035 TRACE("%p %s %s %d\n", db, debugstr_w(name), debugstr_wn(value, len), len);
2037 if (!name)
2038 return ERROR_INVALID_PARAMETER;
2040 /* this one is weird... */
2041 if (!name[0])
2042 return value ? ERROR_FUNCTION_FAILED : ERROR_SUCCESS;
2044 if (value && len < 0) len = lstrlenW( value );
2046 rc = msi_get_property( db, name, 0, &sz );
2047 if (!value || (!*value && !len))
2049 swprintf( query, ARRAY_SIZE(query), L"DELETE FROM `_Property` WHERE `_Property` = '%s'", name );
2051 else if (rc == ERROR_MORE_DATA || rc == ERROR_SUCCESS)
2053 swprintf( query, ARRAY_SIZE(query), L"UPDATE `_Property` SET `Value` = ? WHERE `_Property` = '%s'", name );
2054 row = MSI_CreateRecord(1);
2055 msi_record_set_string( row, 1, value, len );
2057 else
2059 lstrcpyW( query, L"INSERT INTO `_Property` (`_Property`,`Value`) VALUES (?,?)" );
2060 row = MSI_CreateRecord(2);
2061 msi_record_set_string( row, 1, name, -1 );
2062 msi_record_set_string( row, 2, value, len );
2065 rc = MSI_DatabaseOpenViewW(db, query, &view);
2066 if (rc == ERROR_SUCCESS)
2068 rc = MSI_ViewExecute(view, row);
2069 MSI_ViewClose(view);
2070 msiobj_release(&view->hdr);
2072 if (row) msiobj_release(&row->hdr);
2073 return rc;
2076 UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
2078 MSIPACKAGE *package;
2079 UINT ret;
2081 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
2082 if( !package )
2084 MSIHANDLE remote;
2086 if (!(remote = msi_get_remote(hInstall)))
2087 return ERROR_INVALID_HANDLE;
2089 __TRY
2091 ret = remote_SetProperty(remote, szName, szValue);
2093 __EXCEPT(rpc_filter)
2095 ret = GetExceptionCode();
2097 __ENDTRY
2099 return ret;
2102 ret = msi_set_property( package->db, szName, szValue, -1 );
2103 if (ret == ERROR_SUCCESS && !wcscmp( szName, L"SourceDir" ))
2104 msi_reset_source_folders( package );
2106 msiobj_release( &package->hdr );
2107 return ret;
2110 static MSIRECORD *msi_get_property_row( MSIDATABASE *db, LPCWSTR name )
2112 MSIRECORD *rec, *row = NULL;
2113 MSIQUERY *view;
2114 UINT r;
2115 WCHAR *buffer;
2116 int length;
2118 if (!name || !*name)
2119 return NULL;
2121 if (!wcscmp(name, L"Date"))
2123 length = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, NULL, 0);
2124 if (!length)
2125 return NULL;
2126 buffer = msi_alloc(length * sizeof(WCHAR));
2127 GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, buffer, length);
2129 row = MSI_CreateRecord(1);
2130 if (!row)
2132 msi_free(buffer);
2133 return NULL;
2135 MSI_RecordSetStringW(row, 1, buffer);
2136 msi_free(buffer);
2137 return row;
2139 else if (!wcscmp(name, L"Time"))
2141 length = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOTIMEMARKER, NULL, NULL, NULL, 0);
2142 if (!length)
2143 return NULL;
2144 buffer = msi_alloc(length * sizeof(WCHAR));
2145 GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOTIMEMARKER, NULL, NULL, buffer, length);
2147 row = MSI_CreateRecord(1);
2148 if (!row)
2150 msi_free(buffer);
2151 return NULL;
2153 MSI_RecordSetStringW(row, 1, buffer);
2154 msi_free(buffer);
2155 return row;
2158 rec = MSI_CreateRecord(1);
2159 if (!rec)
2160 return NULL;
2162 MSI_RecordSetStringW(rec, 1, name);
2164 r = MSI_DatabaseOpenViewW(db, L"SELECT `Value` FROM `_Property` WHERE `_Property`=?", &view);
2165 if (r == ERROR_SUCCESS)
2167 MSI_ViewExecute(view, rec);
2168 MSI_ViewFetch(view, &row);
2169 MSI_ViewClose(view);
2170 msiobj_release(&view->hdr);
2172 msiobj_release(&rec->hdr);
2173 return row;
2176 /* internal function, not compatible with MsiGetPropertyW */
2177 UINT msi_get_property( MSIDATABASE *db, LPCWSTR szName,
2178 LPWSTR szValueBuf, LPDWORD pchValueBuf )
2180 MSIRECORD *row;
2181 UINT rc = ERROR_FUNCTION_FAILED;
2183 TRACE("%p %s %p %p\n", db, debugstr_w(szName), szValueBuf, pchValueBuf);
2185 row = msi_get_property_row( db, szName );
2187 if (*pchValueBuf > 0)
2188 szValueBuf[0] = 0;
2190 if (row)
2192 rc = MSI_RecordGetStringW(row, 1, szValueBuf, pchValueBuf);
2193 msiobj_release(&row->hdr);
2196 if (rc == ERROR_SUCCESS)
2197 TRACE("returning %s for property %s\n", debugstr_wn(szValueBuf, *pchValueBuf),
2198 debugstr_w(szName));
2199 else if (rc == ERROR_MORE_DATA)
2200 TRACE("need %d sized buffer for %s\n", *pchValueBuf,
2201 debugstr_w(szName));
2202 else
2204 *pchValueBuf = 0;
2205 TRACE("property %s not found\n", debugstr_w(szName));
2208 return rc;
2211 LPWSTR msi_dup_property(MSIDATABASE *db, LPCWSTR prop)
2213 DWORD sz = 0;
2214 LPWSTR str;
2215 UINT r;
2217 r = msi_get_property(db, prop, NULL, &sz);
2218 if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
2219 return NULL;
2221 sz++;
2222 str = msi_alloc(sz * sizeof(WCHAR));
2223 r = msi_get_property(db, prop, str, &sz);
2224 if (r != ERROR_SUCCESS)
2226 msi_free(str);
2227 str = NULL;
2230 return str;
2233 int msi_get_property_int( MSIDATABASE *db, LPCWSTR prop, int def )
2235 LPWSTR str = msi_dup_property( db, prop );
2236 int val = str ? wcstol(str, NULL, 10) : def;
2237 msi_free(str);
2238 return val;
2241 UINT WINAPI MsiGetPropertyA(MSIHANDLE hinst, const char *name, char *buf, DWORD *sz)
2243 const WCHAR *value = L"";
2244 MSIPACKAGE *package;
2245 MSIRECORD *row;
2246 WCHAR *nameW;
2247 int len = 0;
2248 UINT r;
2250 if (!name)
2251 return ERROR_INVALID_PARAMETER;
2253 if (!(nameW = strdupAtoW(name)))
2254 return ERROR_OUTOFMEMORY;
2256 package = msihandle2msiinfo(hinst, MSIHANDLETYPE_PACKAGE);
2257 if (!package)
2259 WCHAR *value = NULL, *tmp;
2260 MSIHANDLE remote;
2261 DWORD len;
2263 if (!(remote = msi_get_remote(hinst)))
2265 heap_free(nameW);
2266 return ERROR_INVALID_HANDLE;
2269 __TRY
2271 r = remote_GetProperty(remote, nameW, &value, &len);
2273 __EXCEPT(rpc_filter)
2275 r = GetExceptionCode();
2277 __ENDTRY
2279 heap_free(nameW);
2281 if (!r)
2283 /* String might contain embedded nulls.
2284 * Native returns the correct size but truncates the string. */
2285 tmp = heap_alloc_zero((len + 1) * sizeof(WCHAR));
2286 if (!tmp)
2288 midl_user_free(value);
2289 return ERROR_OUTOFMEMORY;
2291 lstrcpyW(tmp, value);
2293 r = msi_strncpyWtoA(tmp, len, buf, sz, TRUE);
2295 heap_free(tmp);
2297 midl_user_free(value);
2298 return r;
2301 row = msi_get_property_row(package->db, nameW);
2302 if (row)
2303 value = msi_record_get_string(row, 1, &len);
2305 r = msi_strncpyWtoA(value, len, buf, sz, FALSE);
2307 heap_free(nameW);
2308 if (row) msiobj_release(&row->hdr);
2309 msiobj_release(&package->hdr);
2310 return r;
2313 UINT WINAPI MsiGetPropertyW(MSIHANDLE hinst, const WCHAR *name, WCHAR *buf, DWORD *sz)
2315 const WCHAR *value = L"";
2316 MSIPACKAGE *package;
2317 MSIRECORD *row;
2318 int len = 0;
2319 UINT r;
2321 if (!name)
2322 return ERROR_INVALID_PARAMETER;
2324 package = msihandle2msiinfo(hinst, MSIHANDLETYPE_PACKAGE);
2325 if (!package)
2327 WCHAR *value = NULL, *tmp;
2328 MSIHANDLE remote;
2329 DWORD len;
2331 if (!(remote = msi_get_remote(hinst)))
2332 return ERROR_INVALID_HANDLE;
2334 __TRY
2336 r = remote_GetProperty(remote, name, &value, &len);
2338 __EXCEPT(rpc_filter)
2340 r = GetExceptionCode();
2342 __ENDTRY
2344 if (!r)
2346 /* String might contain embedded nulls.
2347 * Native returns the correct size but truncates the string. */
2348 tmp = heap_alloc_zero((len + 1) * sizeof(WCHAR));
2349 if (!tmp)
2351 midl_user_free(value);
2352 return ERROR_OUTOFMEMORY;
2354 lstrcpyW(tmp, value);
2356 r = msi_strncpyW(tmp, len, buf, sz);
2358 heap_free(tmp);
2360 midl_user_free(value);
2361 return r;
2364 row = msi_get_property_row(package->db, name);
2365 if (row)
2366 value = msi_record_get_string(row, 1, &len);
2368 r = msi_strncpyW(value, len, buf, sz);
2370 if (row) msiobj_release(&row->hdr);
2371 msiobj_release(&package->hdr);
2372 return r;
2375 MSIHANDLE __cdecl s_remote_GetActiveDatabase(MSIHANDLE hinst)
2377 return MsiGetActiveDatabase(hinst);
2380 UINT __cdecl s_remote_GetProperty(MSIHANDLE hinst, LPCWSTR property, LPWSTR *value, DWORD *size)
2382 WCHAR empty[1];
2383 UINT r;
2385 *size = 0;
2386 r = MsiGetPropertyW(hinst, property, empty, size);
2387 if (r == ERROR_MORE_DATA)
2389 ++*size;
2390 *value = midl_user_allocate(*size * sizeof(WCHAR));
2391 if (!*value)
2392 return ERROR_OUTOFMEMORY;
2393 r = MsiGetPropertyW(hinst, property, *value, size);
2395 return r;
2398 UINT __cdecl s_remote_SetProperty(MSIHANDLE hinst, LPCWSTR property, LPCWSTR value)
2400 return MsiSetPropertyW(hinst, property, value);
2403 int __cdecl s_remote_ProcessMessage(MSIHANDLE hinst, INSTALLMESSAGE message, struct wire_record *remote_rec)
2405 MSIHANDLE rec;
2406 int ret;
2407 UINT r;
2409 if ((r = unmarshal_record(remote_rec, &rec)))
2410 return r;
2412 ret = MsiProcessMessage(hinst, message, rec);
2414 MsiCloseHandle(rec);
2415 return ret;
2418 UINT __cdecl s_remote_DoAction(MSIHANDLE hinst, LPCWSTR action)
2420 return MsiDoActionW(hinst, action);
2423 UINT __cdecl s_remote_Sequence(MSIHANDLE hinst, LPCWSTR table, int sequence)
2425 return MsiSequenceW(hinst, table, sequence);
2428 UINT __cdecl s_remote_GetTargetPath(MSIHANDLE hinst, LPCWSTR folder, LPWSTR *value)
2430 WCHAR empty[1];
2431 DWORD size = 0;
2432 UINT r;
2434 r = MsiGetTargetPathW(hinst, folder, empty, &size);
2435 if (r == ERROR_MORE_DATA)
2437 *value = midl_user_allocate(++size * sizeof(WCHAR));
2438 if (!*value)
2439 return ERROR_OUTOFMEMORY;
2440 r = MsiGetTargetPathW(hinst, folder, *value, &size);
2442 return r;
2445 UINT __cdecl s_remote_SetTargetPath(MSIHANDLE hinst, LPCWSTR folder, LPCWSTR value)
2447 return MsiSetTargetPathW(hinst, folder, value);
2450 UINT __cdecl s_remote_GetSourcePath(MSIHANDLE hinst, LPCWSTR folder, LPWSTR *value)
2452 WCHAR empty[1];
2453 DWORD size = 1;
2454 UINT r;
2456 r = MsiGetSourcePathW(hinst, folder, empty, &size);
2457 if (r == ERROR_MORE_DATA)
2459 *value = midl_user_allocate(++size * sizeof(WCHAR));
2460 if (!*value)
2461 return ERROR_OUTOFMEMORY;
2462 r = MsiGetSourcePathW(hinst, folder, *value, &size);
2464 return r;
2467 BOOL __cdecl s_remote_GetMode(MSIHANDLE hinst, MSIRUNMODE mode)
2469 return MsiGetMode(hinst, mode);
2472 UINT __cdecl s_remote_SetMode(MSIHANDLE hinst, MSIRUNMODE mode, BOOL state)
2474 return MsiSetMode(hinst, mode, state);
2477 UINT __cdecl s_remote_GetFeatureState(MSIHANDLE hinst, LPCWSTR feature,
2478 INSTALLSTATE *installed, INSTALLSTATE *action)
2480 return MsiGetFeatureStateW(hinst, feature, installed, action);
2483 UINT __cdecl s_remote_SetFeatureState(MSIHANDLE hinst, LPCWSTR feature, INSTALLSTATE state)
2485 return MsiSetFeatureStateW(hinst, feature, state);
2488 UINT __cdecl s_remote_GetComponentState(MSIHANDLE hinst, LPCWSTR component,
2489 INSTALLSTATE *installed, INSTALLSTATE *action)
2491 return MsiGetComponentStateW(hinst, component, installed, action);
2494 UINT __cdecl s_remote_SetComponentState(MSIHANDLE hinst, LPCWSTR component, INSTALLSTATE state)
2496 return MsiSetComponentStateW(hinst, component, state);
2499 LANGID __cdecl s_remote_GetLanguage(MSIHANDLE hinst)
2501 return MsiGetLanguage(hinst);
2504 UINT __cdecl s_remote_SetInstallLevel(MSIHANDLE hinst, int level)
2506 return MsiSetInstallLevel(hinst, level);
2509 UINT __cdecl s_remote_FormatRecord(MSIHANDLE hinst, struct wire_record *remote_rec, LPWSTR *value)
2511 WCHAR empty[1];
2512 DWORD size = 0;
2513 MSIHANDLE rec;
2514 UINT r;
2516 if ((r = unmarshal_record(remote_rec, &rec)))
2517 return r;
2519 r = MsiFormatRecordW(hinst, rec, empty, &size);
2520 if (r == ERROR_MORE_DATA)
2522 *value = midl_user_allocate(++size * sizeof(WCHAR));
2523 if (!*value)
2525 MsiCloseHandle(rec);
2526 return ERROR_OUTOFMEMORY;
2528 r = MsiFormatRecordW(hinst, rec, *value, &size);
2531 MsiCloseHandle(rec);
2532 return r;
2535 MSICONDITION __cdecl s_remote_EvaluateCondition(MSIHANDLE hinst, LPCWSTR condition)
2537 return MsiEvaluateConditionW(hinst, condition);
2540 UINT __cdecl s_remote_GetFeatureCost(MSIHANDLE hinst, LPCWSTR feature,
2541 MSICOSTTREE cost_tree, INSTALLSTATE state, INT *cost)
2543 return MsiGetFeatureCostW(hinst, feature, cost_tree, state, cost);
2546 UINT __cdecl s_remote_EnumComponentCosts(MSIHANDLE hinst, LPCWSTR component,
2547 DWORD index, INSTALLSTATE state, LPWSTR drive, INT *cost, INT *temp)
2549 DWORD size = 3;
2550 return MsiEnumComponentCostsW(hinst, component, index, state, drive, &size, cost, temp);
2553 UINT msi_package_add_info(MSIPACKAGE *package, DWORD context, DWORD options,
2554 LPCWSTR property, LPWSTR value)
2556 MSISOURCELISTINFO *info;
2558 LIST_FOR_EACH_ENTRY( info, &package->sourcelist_info, MSISOURCELISTINFO, entry )
2560 if (!wcscmp( info->value, value )) return ERROR_SUCCESS;
2563 info = msi_alloc(sizeof(MSISOURCELISTINFO));
2564 if (!info)
2565 return ERROR_OUTOFMEMORY;
2567 info->context = context;
2568 info->options = options;
2569 info->property = property;
2570 info->value = strdupW(value);
2571 list_add_head(&package->sourcelist_info, &info->entry);
2573 return ERROR_SUCCESS;
2576 UINT msi_package_add_media_disk(MSIPACKAGE *package, DWORD context, DWORD options,
2577 DWORD disk_id, LPWSTR volume_label, LPWSTR disk_prompt)
2579 MSIMEDIADISK *disk;
2581 LIST_FOR_EACH_ENTRY( disk, &package->sourcelist_media, MSIMEDIADISK, entry )
2583 if (disk->disk_id == disk_id) return ERROR_SUCCESS;
2586 disk = msi_alloc(sizeof(MSIMEDIADISK));
2587 if (!disk)
2588 return ERROR_OUTOFMEMORY;
2590 disk->context = context;
2591 disk->options = options;
2592 disk->disk_id = disk_id;
2593 disk->volume_label = strdupW(volume_label);
2594 disk->disk_prompt = strdupW(disk_prompt);
2595 list_add_head(&package->sourcelist_media, &disk->entry);
2597 return ERROR_SUCCESS;