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