[MSI] Apply Wine commit fdac39f by Hans Leidekker: Pass correct length to GetDateForm...
[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 #include "msipriv.h"
22
23 #include <wininet.h>
24
25 WINE_DEFAULT_DEBUG_CHANNEL(msi);
26
27 static void free_feature( MSIFEATURE *feature )
28 {
29 struct list *item, *cursor;
30
31 LIST_FOR_EACH_SAFE( item, cursor, &feature->Children )
32 {
33 FeatureList *fl = LIST_ENTRY( item, FeatureList, entry );
34 list_remove( &fl->entry );
35 msi_free( fl );
36 }
37
38 LIST_FOR_EACH_SAFE( item, cursor, &feature->Components )
39 {
40 ComponentList *cl = LIST_ENTRY( item, ComponentList, entry );
41 list_remove( &cl->entry );
42 msi_free( cl );
43 }
44 msi_free( feature->Feature );
45 msi_free( feature->Feature_Parent );
46 msi_free( feature->Directory );
47 msi_free( feature->Description );
48 msi_free( feature->Title );
49 msi_free( feature );
50 }
51
52 static void free_folder( MSIFOLDER *folder )
53 {
54 struct list *item, *cursor;
55
56 LIST_FOR_EACH_SAFE( item, cursor, &folder->children )
57 {
58 FolderList *fl = LIST_ENTRY( item, FolderList, entry );
59 list_remove( &fl->entry );
60 msi_free( fl );
61 }
62 msi_free( folder->Parent );
63 msi_free( folder->Directory );
64 msi_free( folder->TargetDefault );
65 msi_free( folder->SourceLongPath );
66 msi_free( folder->SourceShortPath );
67 msi_free( folder->ResolvedTarget );
68 msi_free( folder->ResolvedSource );
69 msi_free( folder );
70 }
71
72 static void free_extension( MSIEXTENSION *ext )
73 {
74 struct list *item, *cursor;
75
76 LIST_FOR_EACH_SAFE( item, cursor, &ext->verbs )
77 {
78 MSIVERB *verb = LIST_ENTRY( item, MSIVERB, entry );
79
80 list_remove( &verb->entry );
81 msi_free( verb->Verb );
82 msi_free( verb->Command );
83 msi_free( verb->Argument );
84 msi_free( verb );
85 }
86
87 msi_free( ext->Extension );
88 msi_free( ext->ProgIDText );
89 msi_free( ext );
90 }
91
92 static void free_assembly( MSIASSEMBLY *assembly )
93 {
94 msi_free( assembly->feature );
95 msi_free( assembly->manifest );
96 msi_free( assembly->application );
97 msi_free( assembly->display_name );
98 if (assembly->tempdir) RemoveDirectoryW( assembly->tempdir );
99 msi_free( assembly->tempdir );
100 msi_free( assembly );
101 }
102
103 void msi_free_action_script( MSIPACKAGE *package, UINT script )
104 {
105 UINT i;
106 for (i = 0; i < package->script->ActionCount[script]; i++)
107 msi_free( package->script->Actions[script][i] );
108
109 msi_free( package->script->Actions[script] );
110 package->script->Actions[script] = NULL;
111 package->script->ActionCount[script] = 0;
112 }
113
114 static void free_package_structures( MSIPACKAGE *package )
115 {
116 struct list *item, *cursor;
117
118 LIST_FOR_EACH_SAFE( item, cursor, &package->features )
119 {
120 MSIFEATURE *feature = LIST_ENTRY( item, MSIFEATURE, entry );
121 list_remove( &feature->entry );
122 free_feature( feature );
123 }
124
125 LIST_FOR_EACH_SAFE( item, cursor, &package->folders )
126 {
127 MSIFOLDER *folder = LIST_ENTRY( item, MSIFOLDER, entry );
128 list_remove( &folder->entry );
129 free_folder( folder );
130 }
131
132 LIST_FOR_EACH_SAFE( item, cursor, &package->files )
133 {
134 MSIFILE *file = LIST_ENTRY( item, MSIFILE, entry );
135
136 list_remove( &file->entry );
137 msi_free( file->File );
138 msi_free( file->FileName );
139 msi_free( file->ShortName );
140 msi_free( file->LongName );
141 msi_free( file->Version );
142 msi_free( file->Language );
143 if (msi_is_global_assembly( file->Component )) DeleteFileW( file->TargetPath );
144 msi_free( file->TargetPath );
145 msi_free( file );
146 }
147
148 LIST_FOR_EACH_SAFE( item, cursor, &package->components )
149 {
150 MSICOMPONENT *comp = LIST_ENTRY( item, MSICOMPONENT, entry );
151
152 list_remove( &comp->entry );
153 msi_free( comp->Component );
154 msi_free( comp->ComponentId );
155 msi_free( comp->Directory );
156 msi_free( comp->Condition );
157 msi_free( comp->KeyPath );
158 msi_free( comp->FullKeypath );
159 if (comp->assembly) free_assembly( comp->assembly );
160 msi_free( comp );
161 }
162
163 LIST_FOR_EACH_SAFE( item, cursor, &package->filepatches )
164 {
165 MSIFILEPATCH *patch = LIST_ENTRY( item, MSIFILEPATCH, entry );
166
167 list_remove( &patch->entry );
168 msi_free( patch->path );
169 msi_free( patch );
170 }
171
172 /* clean up extension, progid, class and verb structures */
173 LIST_FOR_EACH_SAFE( item, cursor, &package->classes )
174 {
175 MSICLASS *cls = LIST_ENTRY( item, MSICLASS, entry );
176
177 list_remove( &cls->entry );
178 msi_free( cls->clsid );
179 msi_free( cls->Context );
180 msi_free( cls->Description );
181 msi_free( cls->FileTypeMask );
182 msi_free( cls->IconPath );
183 msi_free( cls->DefInprocHandler );
184 msi_free( cls->DefInprocHandler32 );
185 msi_free( cls->Argument );
186 msi_free( cls->ProgIDText );
187 msi_free( cls );
188 }
189
190 LIST_FOR_EACH_SAFE( item, cursor, &package->extensions )
191 {
192 MSIEXTENSION *ext = LIST_ENTRY( item, MSIEXTENSION, entry );
193
194 list_remove( &ext->entry );
195 free_extension( ext );
196 }
197
198 LIST_FOR_EACH_SAFE( item, cursor, &package->progids )
199 {
200 MSIPROGID *progid = LIST_ENTRY( item, MSIPROGID, entry );
201
202 list_remove( &progid->entry );
203 msi_free( progid->ProgID );
204 msi_free( progid->Description );
205 msi_free( progid->IconPath );
206 msi_free( progid );
207 }
208
209 LIST_FOR_EACH_SAFE( item, cursor, &package->mimes )
210 {
211 MSIMIME *mt = LIST_ENTRY( item, MSIMIME, entry );
212
213 list_remove( &mt->entry );
214 msi_free( mt->suffix );
215 msi_free( mt->clsid );
216 msi_free( mt->ContentType );
217 msi_free( mt );
218 }
219
220 LIST_FOR_EACH_SAFE( item, cursor, &package->appids )
221 {
222 MSIAPPID *appid = LIST_ENTRY( item, MSIAPPID, entry );
223
224 list_remove( &appid->entry );
225 msi_free( appid->AppID );
226 msi_free( appid->RemoteServerName );
227 msi_free( appid->LocalServer );
228 msi_free( appid->ServiceParameters );
229 msi_free( appid->DllSurrogate );
230 msi_free( appid );
231 }
232
233 LIST_FOR_EACH_SAFE( item, cursor, &package->sourcelist_info )
234 {
235 MSISOURCELISTINFO *info = LIST_ENTRY( item, MSISOURCELISTINFO, entry );
236
237 list_remove( &info->entry );
238 msi_free( info->value );
239 msi_free( info );
240 }
241
242 LIST_FOR_EACH_SAFE( item, cursor, &package->sourcelist_media )
243 {
244 MSIMEDIADISK *info = LIST_ENTRY( item, MSIMEDIADISK, entry );
245
246 list_remove( &info->entry );
247 msi_free( info->volume_label );
248 msi_free( info->disk_prompt );
249 msi_free( info );
250 }
251
252 if (package->script)
253 {
254 INT i;
255 UINT j;
256
257 for (i = 0; i < SCRIPT_MAX; i++)
258 msi_free_action_script( package, i );
259
260 for (j = 0; j < package->script->UniqueActionsCount; j++)
261 msi_free( package->script->UniqueActions[j] );
262
263 msi_free( package->script->UniqueActions );
264 msi_free( package->script );
265 }
266
267 LIST_FOR_EACH_SAFE( item, cursor, &package->binaries )
268 {
269 MSIBINARY *binary = LIST_ENTRY( item, MSIBINARY, entry );
270
271 list_remove( &binary->entry );
272 if (binary->module)
273 FreeLibrary( binary->module );
274 if (!DeleteFileW( binary->tmpfile ))
275 ERR("failed to delete %s (%u)\n", debugstr_w(binary->tmpfile), GetLastError());
276 msi_free( binary->source );
277 msi_free( binary->tmpfile );
278 msi_free( binary );
279 }
280
281 LIST_FOR_EACH_SAFE( item, cursor, &package->cabinet_streams )
282 {
283 MSICABINETSTREAM *cab = LIST_ENTRY( item, MSICABINETSTREAM, entry );
284
285 list_remove( &cab->entry );
286 IStorage_Release( cab->storage );
287 msi_free( cab->stream );
288 msi_free( cab );
289 }
290
291 LIST_FOR_EACH_SAFE( item, cursor, &package->patches )
292 {
293 MSIPATCHINFO *patch = LIST_ENTRY( item, MSIPATCHINFO, entry );
294
295 list_remove( &patch->entry );
296 if (patch->delete_on_close && !DeleteFileW( patch->localfile ))
297 {
298 ERR("failed to delete %s (%u)\n", debugstr_w(patch->localfile), GetLastError());
299 }
300 msi_free_patchinfo( patch );
301 }
302
303 msi_free( package->BaseURL );
304 msi_free( package->PackagePath );
305 msi_free( package->ProductCode );
306 msi_free( package->ActionFormat );
307 msi_free( package->LastAction );
308 msi_free( package->LastActionTemplate );
309 msi_free( package->langids );
310
311 /* cleanup control event subscriptions */
312 msi_event_cleanup_all_subscriptions( package );
313 }
314
315 static void MSI_FreePackage( MSIOBJECTHDR *arg)
316 {
317 MSIPACKAGE *package = (MSIPACKAGE *)arg;
318
319 msi_destroy_assembly_caches( package );
320
321 if( package->dialog )
322 msi_dialog_destroy( package->dialog );
323
324 msiobj_release( &package->db->hdr );
325 free_package_structures(package);
326 CloseHandle( package->log_file );
327
328 if (package->delete_on_close) DeleteFileW( package->localfile );
329 msi_free( package->localfile );
330 MSI_ProcessMessage(NULL, INSTALLMESSAGE_TERMINATE, 0);
331 }
332
333 static UINT create_temp_property_table(MSIPACKAGE *package)
334 {
335 static const WCHAR query[] = {
336 'C','R','E','A','T','E',' ','T','A','B','L','E',' ',
337 '`','_','P','r','o','p','e','r','t','y','`',' ','(',' ',
338 '`','_','P','r','o','p','e','r','t','y','`',' ',
339 'C','H','A','R','(','5','6',')',' ','N','O','T',' ','N','U','L','L',' ',
340 'T','E','M','P','O','R','A','R','Y',',',' ',
341 '`','V','a','l','u','e','`',' ','C','H','A','R','(','9','8',')',' ',
342 'N','O','T',' ','N','U','L','L',' ','T','E','M','P','O','R','A','R','Y',
343 ' ','P','R','I','M','A','R','Y',' ','K','E','Y',' ',
344 '`','_','P','r','o','p','e','r','t','y','`',')',' ','H','O','L','D',0};
345 MSIQUERY *view;
346 UINT rc;
347
348 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
349 if (rc != ERROR_SUCCESS)
350 return rc;
351
352 rc = MSI_ViewExecute(view, 0);
353 MSI_ViewClose(view);
354 msiobj_release(&view->hdr);
355 return rc;
356 }
357
358 UINT msi_clone_properties( MSIDATABASE *db )
359 {
360 static const WCHAR query_select[] = {
361 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
362 '`','P','r','o','p','e','r','t','y','`',0};
363 static const WCHAR query_insert[] = {
364 'I','N','S','E','R','T',' ','I','N','T','O',' ',
365 '`','_','P','r','o','p','e','r','t','y','`',' ',
366 '(','`','_','P','r','o','p','e','r','t','y','`',',','`','V','a','l','u','e','`',')',' ',
367 'V','A','L','U','E','S',' ','(','?',',','?',')',0};
368 static const WCHAR query_update[] = {
369 'U','P','D','A','T','E',' ','`','_','P','r','o','p','e','r','t','y','`',' ',
370 'S','E','T',' ','`','V','a','l','u','e','`',' ','=',' ','?',' ',
371 'W','H','E','R','E',' ','`','_','P','r','o','p','e','r','t','y','`',' ','=',' ','?',0};
372 MSIQUERY *view_select;
373 UINT rc;
374
375 rc = MSI_DatabaseOpenViewW( db, query_select, &view_select );
376 if (rc != ERROR_SUCCESS)
377 return rc;
378
379 rc = MSI_ViewExecute( view_select, 0 );
380 if (rc != ERROR_SUCCESS)
381 {
382 MSI_ViewClose( view_select );
383 msiobj_release( &view_select->hdr );
384 return rc;
385 }
386
387 while (1)
388 {
389 MSIQUERY *view_insert, *view_update;
390 MSIRECORD *rec_select;
391
392 rc = MSI_ViewFetch( view_select, &rec_select );
393 if (rc != ERROR_SUCCESS)
394 break;
395
396 rc = MSI_DatabaseOpenViewW( db, query_insert, &view_insert );
397 if (rc != ERROR_SUCCESS)
398 {
399 msiobj_release( &rec_select->hdr );
400 continue;
401 }
402
403 rc = MSI_ViewExecute( view_insert, rec_select );
404 MSI_ViewClose( view_insert );
405 msiobj_release( &view_insert->hdr );
406 if (rc != ERROR_SUCCESS)
407 {
408 MSIRECORD *rec_update;
409
410 TRACE("insert failed, trying update\n");
411
412 rc = MSI_DatabaseOpenViewW( db, query_update, &view_update );
413 if (rc != ERROR_SUCCESS)
414 {
415 WARN("open view failed %u\n", rc);
416 msiobj_release( &rec_select->hdr );
417 continue;
418 }
419
420 rec_update = MSI_CreateRecord( 2 );
421 MSI_RecordCopyField( rec_select, 1, rec_update, 2 );
422 MSI_RecordCopyField( rec_select, 2, rec_update, 1 );
423 rc = MSI_ViewExecute( view_update, rec_update );
424 if (rc != ERROR_SUCCESS)
425 WARN("update failed %u\n", rc);
426
427 MSI_ViewClose( view_update );
428 msiobj_release( &view_update->hdr );
429 msiobj_release( &rec_update->hdr );
430 }
431
432 msiobj_release( &rec_select->hdr );
433 }
434
435 MSI_ViewClose( view_select );
436 msiobj_release( &view_select->hdr );
437 return rc;
438 }
439
440 /*
441 * set_installed_prop
442 *
443 * Sets the "Installed" property to indicate that
444 * the product is installed for the current user.
445 */
446 static UINT set_installed_prop( MSIPACKAGE *package )
447 {
448 HKEY hkey;
449 UINT r;
450
451 if (!package->ProductCode) return ERROR_FUNCTION_FAILED;
452
453 r = MSIREG_OpenUninstallKey( package->ProductCode, package->platform, &hkey, FALSE );
454 if (r == ERROR_SUCCESS)
455 {
456 RegCloseKey( hkey );
457 msi_set_property( package->db, szInstalled, szOne, -1 );
458 }
459 return r;
460 }
461
462 static UINT set_user_sid_prop( MSIPACKAGE *package )
463 {
464 SID_NAME_USE use;
465 LPWSTR user_name;
466 LPWSTR sid_str = NULL, dom = NULL;
467 DWORD size, dom_size;
468 PSID psid = NULL;
469 UINT r = ERROR_FUNCTION_FAILED;
470
471 size = 0;
472 GetUserNameW( NULL, &size );
473
474 user_name = msi_alloc( (size + 1) * sizeof(WCHAR) );
475 if (!user_name)
476 return ERROR_OUTOFMEMORY;
477
478 if (!GetUserNameW( user_name, &size ))
479 goto done;
480
481 size = 0;
482 dom_size = 0;
483 LookupAccountNameW( NULL, user_name, NULL, &size, NULL, &dom_size, &use );
484
485 psid = msi_alloc( size );
486 dom = msi_alloc( dom_size*sizeof (WCHAR) );
487 if (!psid || !dom)
488 {
489 r = ERROR_OUTOFMEMORY;
490 goto done;
491 }
492
493 if (!LookupAccountNameW( NULL, user_name, psid, &size, dom, &dom_size, &use ))
494 goto done;
495
496 if (!ConvertSidToStringSidW( psid, &sid_str ))
497 goto done;
498
499 r = msi_set_property( package->db, szUserSID, sid_str, -1 );
500
501 done:
502 LocalFree( sid_str );
503 msi_free( dom );
504 msi_free( psid );
505 msi_free( user_name );
506
507 return r;
508 }
509
510 static LPWSTR get_fusion_filename(MSIPACKAGE *package)
511 {
512 HKEY netsetup;
513 LONG res;
514 LPWSTR file = NULL;
515 DWORD index = 0, size;
516 WCHAR ver[MAX_PATH];
517 WCHAR name[MAX_PATH];
518 WCHAR windir[MAX_PATH];
519
520 static const WCHAR fusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
521 static const WCHAR sub[] = {
522 'S','o','f','t','w','a','r','e','\\',
523 'M','i','c','r','o','s','o','f','t','\\',
524 'N','E','T',' ','F','r','a','m','e','w','o','r','k',' ','S','e','t','u','p','\\',
525 'N','D','P',0
526 };
527 static const WCHAR subdir[] = {
528 'M','i','c','r','o','s','o','f','t','.','N','E','T','\\',
529 'F','r','a','m','e','w','o','r','k','\\',0
530 };
531
532 res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, sub, 0, KEY_ENUMERATE_SUB_KEYS, &netsetup);
533 if (res != ERROR_SUCCESS)
534 return NULL;
535
536 GetWindowsDirectoryW(windir, MAX_PATH);
537
538 ver[0] = '\0';
539 size = MAX_PATH;
540 while (RegEnumKeyExW(netsetup, index, name, &size, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
541 {
542 index++;
543
544 /* verify existence of fusion.dll .Net 3.0 does not install a new one */
545 if (strcmpW( ver, name ) < 0)
546 {
547 LPWSTR check;
548 size = lstrlenW(windir) + lstrlenW(subdir) + lstrlenW(name) +lstrlenW(fusion) + 3;
549 check = msi_alloc(size * sizeof(WCHAR));
550
551 if (!check)
552 {
553 msi_free(file);
554 return NULL;
555 }
556
557 lstrcpyW(check, windir);
558 lstrcatW(check, szBackSlash);
559 lstrcatW(check, subdir);
560 lstrcatW(check, name);
561 lstrcatW(check, szBackSlash);
562 lstrcatW(check, fusion);
563
564 if(GetFileAttributesW(check) != INVALID_FILE_ATTRIBUTES)
565 {
566 msi_free(file);
567 file = check;
568 lstrcpyW(ver, name);
569 }
570 else
571 msi_free(check);
572 }
573 }
574
575 RegCloseKey(netsetup);
576 return file;
577 }
578
579 typedef struct tagLANGANDCODEPAGE
580 {
581 WORD wLanguage;
582 WORD wCodePage;
583 } LANGANDCODEPAGE;
584
585 static void set_msi_assembly_prop(MSIPACKAGE *package)
586 {
587 UINT val_len;
588 DWORD size, handle;
589 LPVOID version = NULL;
590 WCHAR buf[MAX_PATH];
591 LPWSTR fusion, verstr;
592 LANGANDCODEPAGE *translate;
593
594 static const WCHAR netasm[] = {
595 'M','s','i','N','e','t','A','s','s','e','m','b','l','y','S','u','p','p','o','r','t',0
596 };
597 static const WCHAR translation[] = {
598 '\\','V','a','r','F','i','l','e','I','n','f','o',
599 '\\','T','r','a','n','s','l','a','t','i','o','n',0
600 };
601 static const WCHAR verfmt[] = {
602 '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
603 '\\','%','0','4','x','%','0','4','x',
604 '\\','P','r','o','d','u','c','t','V','e','r','s','i','o','n',0
605 };
606
607 fusion = get_fusion_filename(package);
608 if (!fusion)
609 return;
610
611 size = GetFileVersionInfoSizeW(fusion, &handle);
612 if (!size)
613 goto done;
614
615 version = msi_alloc(size);
616 if (!version)
617 goto done;
618
619 if (!GetFileVersionInfoW(fusion, handle, size, version))
620 goto done;
621
622 if (!VerQueryValueW(version, translation, (LPVOID *)&translate, &val_len))
623 goto done;
624
625 sprintfW(buf, verfmt, translate[0].wLanguage, translate[0].wCodePage);
626
627 if (!VerQueryValueW(version, buf, (LPVOID *)&verstr, &val_len))
628 goto done;
629
630 if (!val_len || !verstr)
631 goto done;
632
633 msi_set_property( package->db, netasm, verstr, -1 );
634
635 done:
636 msi_free(fusion);
637 msi_free(version);
638 }
639
640 static VOID set_installer_properties(MSIPACKAGE *package)
641 {
642 WCHAR *ptr;
643 OSVERSIONINFOEXW OSVersion;
644 MEMORYSTATUSEX msex;
645 DWORD verval, len;
646 WCHAR pth[MAX_PATH], verstr[11], bufstr[22];
647 HDC dc;
648 HKEY hkey;
649 LPWSTR username, companyname;
650 SYSTEM_INFO sys_info;
651 LANGID langid;
652
653 static const WCHAR szCommonFilesFolder[] = {'C','o','m','m','o','n','F','i','l','e','s','F','o','l','d','e','r',0};
654 static const WCHAR szProgramFilesFolder[] = {'P','r','o','g','r','a','m','F','i','l','e','s','F','o','l','d','e','r',0};
655 static const WCHAR szCommonAppDataFolder[] = {'C','o','m','m','o','n','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
656 static const WCHAR szFavoritesFolder[] = {'F','a','v','o','r','i','t','e','s','F','o','l','d','e','r',0};
657 static const WCHAR szFontsFolder[] = {'F','o','n','t','s','F','o','l','d','e','r',0};
658 static const WCHAR szSendToFolder[] = {'S','e','n','d','T','o','F','o','l','d','e','r',0};
659 static const WCHAR szStartMenuFolder[] = {'S','t','a','r','t','M','e','n','u','F','o','l','d','e','r',0};
660 static const WCHAR szStartupFolder[] = {'S','t','a','r','t','u','p','F','o','l','d','e','r',0};
661 static const WCHAR szTemplateFolder[] = {'T','e','m','p','l','a','t','e','F','o','l','d','e','r',0};
662 static const WCHAR szDesktopFolder[] = {'D','e','s','k','t','o','p','F','o','l','d','e','r',0};
663 static const WCHAR szProgramMenuFolder[] = {'P','r','o','g','r','a','m','M','e','n','u','F','o','l','d','e','r',0};
664 static const WCHAR szAdminToolsFolder[] = {'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0};
665 static const WCHAR szSystemFolder[] = {'S','y','s','t','e','m','F','o','l','d','e','r',0};
666 static const WCHAR szSystem16Folder[] = {'S','y','s','t','e','m','1','6','F','o','l','d','e','r',0};
667 static const WCHAR szLocalAppDataFolder[] = {'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
668 static const WCHAR szMyPicturesFolder[] = {'M','y','P','i','c','t','u','r','e','s','F','o','l','d','e','r',0};
669 static const WCHAR szPersonalFolder[] = {'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0};
670 static const WCHAR szWindowsVolume[] = {'W','i','n','d','o','w','s','V','o','l','u','m','e',0};
671 static const WCHAR szPrivileged[] = {'P','r','i','v','i','l','e','g','e','d',0};
672 static const WCHAR szVersion9x[] = {'V','e','r','s','i','o','n','9','X',0};
673 static const WCHAR szVersionNT[] = {'V','e','r','s','i','o','n','N','T',0};
674 static const WCHAR szMsiNTProductType[] = {'M','s','i','N','T','P','r','o','d','u','c','t','T','y','p','e',0};
675 static const WCHAR szFormat[] = {'%','u',0};
676 static const WCHAR szFormat2[] = {'%','u','.','%','u',0};
677 static const WCHAR szWindowsBuild[] = {'W','i','n','d','o','w','s','B','u','i','l','d',0};
678 static const WCHAR szServicePackLevel[] = {'S','e','r','v','i','c','e','P','a','c','k','L','e','v','e','l',0};
679 static const WCHAR szVersionMsi[] = { 'V','e','r','s','i','o','n','M','s','i',0 };
680 static const WCHAR szVersionDatabase[] = { 'V','e','r','s','i','o','n','D','a','t','a','b','a','s','e',0 };
681 static const WCHAR szPhysicalMemory[] = { 'P','h','y','s','i','c','a','l','M','e','m','o','r','y',0 };
682 static const WCHAR szScreenX[] = {'S','c','r','e','e','n','X',0};
683 static const WCHAR szScreenY[] = {'S','c','r','e','e','n','Y',0};
684 static const WCHAR szColorBits[] = {'C','o','l','o','r','B','i','t','s',0};
685 static const WCHAR szIntFormat[] = {'%','d',0};
686 static const WCHAR szMsiAMD64[] = { 'M','s','i','A','M','D','6','4',0 };
687 static const WCHAR szMsix64[] = { 'M','s','i','x','6','4',0 };
688 static const WCHAR szSystem64Folder[] = { 'S','y','s','t','e','m','6','4','F','o','l','d','e','r',0 };
689 static const WCHAR szCommonFiles64Folder[] = { 'C','o','m','m','o','n','F','i','l','e','s','6','4','F','o','l','d','e','r',0 };
690 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 };
691 static const WCHAR szVersionNT64[] = { 'V','e','r','s','i','o','n','N','T','6','4',0 };
692 static const WCHAR szUserInfo[] = {
693 'S','O','F','T','W','A','R','E','\\',
694 'M','i','c','r','o','s','o','f','t','\\',
695 'M','S',' ','S','e','t','u','p',' ','(','A','C','M','E',')','\\',
696 'U','s','e','r',' ','I','n','f','o',0
697 };
698 static const WCHAR szDefName[] = { 'D','e','f','N','a','m','e',0 };
699 static const WCHAR szDefCompany[] = { 'D','e','f','C','o','m','p','a','n','y',0 };
700 static const WCHAR szCurrentVersion[] = {
701 'S','O','F','T','W','A','R','E','\\',
702 'M','i','c','r','o','s','o','f','t','\\',
703 'W','i','n','d','o','w','s',' ','N','T','\\',
704 'C','u','r','r','e','n','t','V','e','r','s','i','o','n',0
705 };
706 static const WCHAR szRegisteredUser[] = {'R','e','g','i','s','t','e','r','e','d','O','w','n','e','r',0};
707 static const WCHAR szRegisteredOrganization[] = {
708 'R','e','g','i','s','t','e','r','e','d','O','r','g','a','n','i','z','a','t','i','o','n',0
709 };
710 static const WCHAR szUSERNAME[] = {'U','S','E','R','N','A','M','E',0};
711 static const WCHAR szCOMPANYNAME[] = {'C','O','M','P','A','N','Y','N','A','M','E',0};
712 static const WCHAR szUserLanguageID[] = {'U','s','e','r','L','a','n','g','u','a','g','e','I','D',0};
713 static const WCHAR szSystemLangID[] = {'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0};
714 static const WCHAR szProductState[] = {'P','r','o','d','u','c','t','S','t','a','t','e',0};
715 static const WCHAR szLogonUser[] = {'L','o','g','o','n','U','s','e','r',0};
716 static const WCHAR szNetHoodFolder[] = {'N','e','t','H','o','o','d','F','o','l','d','e','r',0};
717 static const WCHAR szPrintHoodFolder[] = {'P','r','i','n','t','H','o','o','d','F','o','l','d','e','r',0};
718 static const WCHAR szRecentFolder[] = {'R','e','c','e','n','t','F','o','l','d','e','r',0};
719 static const WCHAR szComputerName[] = {'C','o','m','p','u','t','e','r','N','a','m','e',0};
720
721 /*
722 * Other things that probably should be set:
723 *
724 * VirtualMemory ShellAdvSupport DefaultUIFont PackagecodeChanging
725 * CaptionHeight BorderTop BorderSide TextHeight RedirectedDllSupport
726 */
727
728 SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA, NULL, 0, pth);
729 strcatW(pth, szBackSlash);
730 msi_set_property( package->db, szCommonAppDataFolder, pth, -1 );
731
732 SHGetFolderPathW(NULL, CSIDL_FAVORITES, NULL, 0, pth);
733 strcatW(pth, szBackSlash);
734 msi_set_property( package->db, szFavoritesFolder, pth, -1 );
735
736 SHGetFolderPathW(NULL, CSIDL_FONTS, NULL, 0, pth);
737 strcatW(pth, szBackSlash);
738 msi_set_property( package->db, szFontsFolder, pth, -1 );
739
740 SHGetFolderPathW(NULL, CSIDL_SENDTO, NULL, 0, pth);
741 strcatW(pth, szBackSlash);
742 msi_set_property( package->db, szSendToFolder, pth, -1 );
743
744 SHGetFolderPathW(NULL, CSIDL_STARTMENU, NULL, 0, pth);
745 strcatW(pth, szBackSlash);
746 msi_set_property( package->db, szStartMenuFolder, pth, -1 );
747
748 SHGetFolderPathW(NULL, CSIDL_STARTUP, NULL, 0, pth);
749 strcatW(pth, szBackSlash);
750 msi_set_property( package->db, szStartupFolder, pth, -1 );
751
752 SHGetFolderPathW(NULL, CSIDL_TEMPLATES, NULL, 0, pth);
753 strcatW(pth, szBackSlash);
754 msi_set_property( package->db, szTemplateFolder, pth, -1 );
755
756 SHGetFolderPathW(NULL, CSIDL_DESKTOP, NULL, 0, pth);
757 strcatW(pth, szBackSlash);
758 msi_set_property( package->db, szDesktopFolder, pth, -1 );
759
760 /* FIXME: set to AllUsers profile path if ALLUSERS is set */
761 SHGetFolderPathW(NULL, CSIDL_PROGRAMS, NULL, 0, pth);
762 strcatW(pth, szBackSlash);
763 msi_set_property( package->db, szProgramMenuFolder, pth, -1 );
764
765 SHGetFolderPathW(NULL, CSIDL_ADMINTOOLS, NULL, 0, pth);
766 strcatW(pth, szBackSlash);
767 msi_set_property( package->db, szAdminToolsFolder, pth, -1 );
768
769 SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, pth);
770 strcatW(pth, szBackSlash);
771 msi_set_property( package->db, szAppDataFolder, pth, -1 );
772
773 SHGetFolderPathW(NULL, CSIDL_SYSTEM, NULL, 0, pth);
774 strcatW(pth, szBackSlash);
775 msi_set_property( package->db, szSystemFolder, pth, -1 );
776 msi_set_property( package->db, szSystem16Folder, pth, -1 );
777
778 SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, pth);
779 strcatW(pth, szBackSlash);
780 msi_set_property( package->db, szLocalAppDataFolder, pth, -1 );
781
782 SHGetFolderPathW(NULL, CSIDL_MYPICTURES, NULL, 0, pth);
783 strcatW(pth, szBackSlash);
784 msi_set_property( package->db, szMyPicturesFolder, pth, -1 );
785
786 SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, 0, pth);
787 strcatW(pth, szBackSlash);
788 msi_set_property( package->db, szPersonalFolder, pth, -1 );
789
790 SHGetFolderPathW(NULL, CSIDL_WINDOWS, NULL, 0, pth);
791 strcatW(pth, szBackSlash);
792 msi_set_property( package->db, szWindowsFolder, pth, -1 );
793
794 SHGetFolderPathW(NULL, CSIDL_PRINTHOOD, NULL, 0, pth);
795 strcatW(pth, szBackSlash);
796 msi_set_property( package->db, szPrintHoodFolder, pth, -1 );
797
798 SHGetFolderPathW(NULL, CSIDL_NETHOOD, NULL, 0, pth);
799 strcatW(pth, szBackSlash);
800 msi_set_property( package->db, szNetHoodFolder, pth, -1 );
801
802 SHGetFolderPathW(NULL, CSIDL_RECENT, NULL, 0, pth);
803 strcatW(pth, szBackSlash);
804 msi_set_property( package->db, szRecentFolder, pth, -1 );
805
806 /* Physical Memory is specified in MB. Using total amount. */
807 msex.dwLength = sizeof(msex);
808 GlobalMemoryStatusEx( &msex );
809 len = sprintfW( bufstr, szIntFormat, (int)(msex.ullTotalPhys / 1024 / 1024) );
810 msi_set_property( package->db, szPhysicalMemory, bufstr, len );
811
812 SHGetFolderPathW(NULL, CSIDL_WINDOWS, NULL, 0, pth);
813 ptr = strchrW(pth,'\\');
814 if (ptr) *(ptr + 1) = 0;
815 msi_set_property( package->db, szWindowsVolume, pth, -1 );
816
817 len = GetTempPathW(MAX_PATH, pth);
818 msi_set_property( package->db, szTempFolder, pth, len );
819
820 /* in a wine environment the user is always admin and privileged */
821 msi_set_property( package->db, szAdminUser, szOne, -1 );
822 msi_set_property( package->db, szPrivileged, szOne, -1 );
823
824 /* set the os things */
825 OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
826 GetVersionExW((OSVERSIONINFOW *)&OSVersion);
827 verval = OSVersion.dwMinorVersion + OSVersion.dwMajorVersion * 100;
828 len = sprintfW( verstr, szFormat, verval );
829 switch (OSVersion.dwPlatformId)
830 {
831 case VER_PLATFORM_WIN32_WINDOWS:
832 msi_set_property( package->db, szVersion9x, verstr, len );
833 break;
834 case VER_PLATFORM_WIN32_NT:
835 msi_set_property( package->db, szVersionNT, verstr, len );
836 len = sprintfW( bufstr, szFormat,OSVersion.wProductType );
837 msi_set_property( package->db, szMsiNTProductType, bufstr, len );
838 break;
839 }
840 len = sprintfW( bufstr, szFormat, OSVersion.dwBuildNumber );
841 msi_set_property( package->db, szWindowsBuild, bufstr, len );
842 len = sprintfW( bufstr, szFormat, OSVersion.wServicePackMajor );
843 msi_set_property( package->db, szServicePackLevel, bufstr, len );
844
845 len = sprintfW( bufstr, szFormat2, MSI_MAJORVERSION, MSI_MINORVERSION );
846 msi_set_property( package->db, szVersionMsi, bufstr, len );
847 len = sprintfW( bufstr, szFormat, MSI_MAJORVERSION * 100 );
848 msi_set_property( package->db, szVersionDatabase, bufstr, len );
849
850 GetNativeSystemInfo( &sys_info );
851 len = sprintfW( bufstr, szIntFormat, sys_info.wProcessorLevel );
852 msi_set_property( package->db, szIntel, bufstr, len );
853 if (sys_info.u.s.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
854 {
855 GetSystemDirectoryW( pth, MAX_PATH );
856 PathAddBackslashW( pth );
857 msi_set_property( package->db, szSystemFolder, pth, -1 );
858
859 SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES, NULL, 0, pth );
860 PathAddBackslashW( pth );
861 msi_set_property( package->db, szProgramFilesFolder, pth, -1 );
862
863 SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES_COMMON, NULL, 0, pth );
864 PathAddBackslashW( pth );
865 msi_set_property( package->db, szCommonFilesFolder, pth, -1 );
866 }
867 else if (sys_info.u.s.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
868 {
869 msi_set_property( package->db, szMsiAMD64, bufstr, -1 );
870 msi_set_property( package->db, szMsix64, bufstr, -1 );
871 msi_set_property( package->db, szVersionNT64, verstr, -1 );
872
873 GetSystemDirectoryW( pth, MAX_PATH );
874 PathAddBackslashW( pth );
875 msi_set_property( package->db, szSystem64Folder, pth, -1 );
876
877 GetSystemWow64DirectoryW( pth, MAX_PATH );
878 PathAddBackslashW( pth );
879 msi_set_property( package->db, szSystemFolder, pth, -1 );
880
881 SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES, NULL, 0, pth );
882 PathAddBackslashW( pth );
883 msi_set_property( package->db, szProgramFiles64Folder, pth, -1 );
884
885 SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILESX86, NULL, 0, pth );
886 PathAddBackslashW( pth );
887 msi_set_property( package->db, szProgramFilesFolder, pth, -1 );
888
889 SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES_COMMON, NULL, 0, pth );
890 PathAddBackslashW( pth );
891 msi_set_property( package->db, szCommonFiles64Folder, pth, -1 );
892
893 SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES_COMMONX86, NULL, 0, pth );
894 PathAddBackslashW( pth );
895 msi_set_property( package->db, szCommonFilesFolder, pth, -1 );
896 }
897
898 /* Screen properties. */
899 dc = GetDC(0);
900 len = sprintfW( bufstr, szIntFormat, GetDeviceCaps(dc, HORZRES) );
901 msi_set_property( package->db, szScreenX, bufstr, len );
902 len = sprintfW( bufstr, szIntFormat, GetDeviceCaps(dc, VERTRES) );
903 msi_set_property( package->db, szScreenY, bufstr, len );
904 len = sprintfW( bufstr, szIntFormat, GetDeviceCaps(dc, BITSPIXEL) );
905 msi_set_property( package->db, szColorBits, bufstr, len );
906 ReleaseDC(0, dc);
907
908 /* USERNAME and COMPANYNAME */
909 username = msi_dup_property( package->db, szUSERNAME );
910 companyname = msi_dup_property( package->db, szCOMPANYNAME );
911
912 if ((!username || !companyname) &&
913 RegOpenKeyW( HKEY_CURRENT_USER, szUserInfo, &hkey ) == ERROR_SUCCESS)
914 {
915 if (!username &&
916 (username = msi_reg_get_val_str( hkey, szDefName )))
917 msi_set_property( package->db, szUSERNAME, username, -1 );
918 if (!companyname &&
919 (companyname = msi_reg_get_val_str( hkey, szDefCompany )))
920 msi_set_property( package->db, szCOMPANYNAME, companyname, -1 );
921 CloseHandle( hkey );
922 }
923 if ((!username || !companyname) &&
924 RegOpenKeyW( HKEY_LOCAL_MACHINE, szCurrentVersion, &hkey ) == ERROR_SUCCESS)
925 {
926 if (!username &&
927 (username = msi_reg_get_val_str( hkey, szRegisteredUser )))
928 msi_set_property( package->db, szUSERNAME, username, -1 );
929 if (!companyname &&
930 (companyname = msi_reg_get_val_str( hkey, szRegisteredOrganization )))
931 msi_set_property( package->db, szCOMPANYNAME, companyname, -1 );
932 CloseHandle( hkey );
933 }
934 msi_free( username );
935 msi_free( companyname );
936
937 if ( set_user_sid_prop( package ) != ERROR_SUCCESS)
938 ERR("Failed to set the UserSID property\n");
939
940 set_msi_assembly_prop( package );
941
942 langid = GetUserDefaultLangID();
943 len = sprintfW( bufstr, szIntFormat, langid );
944 msi_set_property( package->db, szUserLanguageID, bufstr, len );
945
946 langid = GetSystemDefaultLangID();
947 len = sprintfW( bufstr, szIntFormat, langid );
948 msi_set_property( package->db, szSystemLangID, bufstr, len );
949
950 len = sprintfW( bufstr, szIntFormat, MsiQueryProductStateW(package->ProductCode) );
951 msi_set_property( package->db, szProductState, bufstr, len );
952
953 len = 0;
954 if (!GetUserNameW( NULL, &len ) && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
955 {
956 WCHAR *username;
957 if ((username = msi_alloc( len * sizeof(WCHAR) )))
958 {
959 if (GetUserNameW( username, &len ))
960 msi_set_property( package->db, szLogonUser, username, len - 1 );
961 msi_free( username );
962 }
963 }
964 len = 0;
965 if (!GetComputerNameW( NULL, &len ) && GetLastError() == ERROR_BUFFER_OVERFLOW)
966 {
967 WCHAR *computername;
968 if ((computername = msi_alloc( len * sizeof(WCHAR) )))
969 {
970 if (GetComputerNameW( computername, &len ))
971 msi_set_property( package->db, szComputerName, computername, len );
972 msi_free( computername );
973 }
974 }
975 }
976
977 static MSIPACKAGE *msi_alloc_package( void )
978 {
979 MSIPACKAGE *package;
980
981 package = alloc_msiobject( MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE),
982 MSI_FreePackage );
983 if( package )
984 {
985 list_init( &package->components );
986 list_init( &package->features );
987 list_init( &package->files );
988 list_init( &package->filepatches );
989 list_init( &package->tempfiles );
990 list_init( &package->folders );
991 list_init( &package->subscriptions );
992 list_init( &package->appids );
993 list_init( &package->classes );
994 list_init( &package->mimes );
995 list_init( &package->extensions );
996 list_init( &package->progids );
997 list_init( &package->RunningActions );
998 list_init( &package->sourcelist_info );
999 list_init( &package->sourcelist_media );
1000 list_init( &package->patches );
1001 list_init( &package->binaries );
1002 list_init( &package->cabinet_streams );
1003 }
1004
1005 return package;
1006 }
1007
1008 static UINT msi_load_admin_properties(MSIPACKAGE *package)
1009 {
1010 BYTE *data;
1011 UINT r, sz;
1012
1013 static const WCHAR stmname[] = {'A','d','m','i','n','P','r','o','p','e','r','t','i','e','s',0};
1014
1015 r = read_stream_data(package->db->storage, stmname, FALSE, &data, &sz);
1016 if (r != ERROR_SUCCESS)
1017 return r;
1018
1019 r = msi_parse_command_line(package, (WCHAR *)data, TRUE);
1020
1021 msi_free(data);
1022 return r;
1023 }
1024
1025 void msi_adjust_privilege_properties( MSIPACKAGE *package )
1026 {
1027 /* FIXME: this should depend on the user's privileges */
1028 if (msi_get_property_int( package->db, szAllUsers, 0 ) == 2)
1029 {
1030 TRACE("resetting ALLUSERS property from 2 to 1\n");
1031 msi_set_property( package->db, szAllUsers, szOne, -1 );
1032 }
1033 msi_set_property( package->db, szAdminUser, szOne, -1 );
1034 }
1035
1036 MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPCWSTR base_url )
1037 {
1038 static const WCHAR fmtW[] = {'%','u',0};
1039 MSIPACKAGE *package;
1040 WCHAR uilevel[11];
1041 int len;
1042 UINT r;
1043
1044 TRACE("%p\n", db);
1045
1046 package = msi_alloc_package();
1047 if (package)
1048 {
1049 msiobj_addref( &db->hdr );
1050 package->db = db;
1051
1052 package->LastAction = NULL;
1053 package->LastActionTemplate = NULL;
1054 package->LastActionResult = MSI_NULL_INTEGER;
1055 package->WordCount = 0;
1056 package->PackagePath = strdupW( db->path );
1057 package->BaseURL = strdupW( base_url );
1058
1059 create_temp_property_table( package );
1060 msi_clone_properties( package->db );
1061 msi_adjust_privilege_properties( package );
1062
1063 package->ProductCode = msi_dup_property( package->db, szProductCode );
1064 package->script = msi_alloc_zero( sizeof(MSISCRIPT) );
1065
1066 set_installer_properties( package );
1067
1068 package->ui_level = gUILevel;
1069 len = sprintfW( uilevel, fmtW, gUILevel & INSTALLUILEVEL_MASK );
1070 msi_set_property( package->db, szUILevel, uilevel, len );
1071
1072 r = msi_load_suminfo_properties( package );
1073 if (r != ERROR_SUCCESS)
1074 {
1075 msiobj_release( &package->hdr );
1076 return NULL;
1077 }
1078
1079 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1080 msi_load_admin_properties( package );
1081
1082 package->log_file = INVALID_HANDLE_VALUE;
1083 }
1084 return package;
1085 }
1086
1087 UINT msi_download_file( LPCWSTR szUrl, LPWSTR filename )
1088 {
1089 LPINTERNET_CACHE_ENTRY_INFOW cache_entry;
1090 DWORD size = 0;
1091 HRESULT hr;
1092
1093 /* call will always fail, because size is 0,
1094 * but will return ERROR_FILE_NOT_FOUND first
1095 * if the file doesn't exist
1096 */
1097 GetUrlCacheEntryInfoW( szUrl, NULL, &size );
1098 if ( GetLastError() != ERROR_FILE_NOT_FOUND )
1099 {
1100 cache_entry = msi_alloc( size );
1101 if ( !GetUrlCacheEntryInfoW( szUrl, cache_entry, &size ) )
1102 {
1103 UINT error = GetLastError();
1104 msi_free( cache_entry );
1105 return error;
1106 }
1107
1108 lstrcpyW( filename, cache_entry->lpszLocalFileName );
1109 msi_free( cache_entry );
1110 return ERROR_SUCCESS;
1111 }
1112
1113 hr = URLDownloadToCacheFileW( NULL, szUrl, filename, MAX_PATH, 0, NULL );
1114 if ( FAILED(hr) )
1115 {
1116 WARN("failed to download %s to cache file\n", debugstr_w(szUrl));
1117 return ERROR_FUNCTION_FAILED;
1118 }
1119
1120 return ERROR_SUCCESS;
1121 }
1122
1123 UINT msi_create_empty_local_file( LPWSTR path, LPCWSTR suffix )
1124 {
1125 static const WCHAR szInstaller[] = {
1126 '\\','I','n','s','t','a','l','l','e','r','\\',0};
1127 static const WCHAR fmt[] = {'%','x',0};
1128 DWORD time, len, i, offset;
1129 HANDLE handle;
1130
1131 time = GetTickCount();
1132 GetWindowsDirectoryW( path, MAX_PATH );
1133 strcatW( path, szInstaller );
1134 CreateDirectoryW( path, NULL );
1135
1136 len = strlenW(path);
1137 for (i = 0; i < 0x10000; i++)
1138 {
1139 offset = snprintfW( path + len, MAX_PATH - len, fmt, (time + i) & 0xffff );
1140 memcpy( path + len + offset, suffix, (strlenW( suffix ) + 1) * sizeof(WCHAR) );
1141 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
1142 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1143 if (handle != INVALID_HANDLE_VALUE)
1144 {
1145 CloseHandle(handle);
1146 break;
1147 }
1148 if (GetLastError() != ERROR_FILE_EXISTS &&
1149 GetLastError() != ERROR_SHARING_VIOLATION)
1150 return ERROR_FUNCTION_FAILED;
1151 }
1152
1153 return ERROR_SUCCESS;
1154 }
1155
1156 static enum platform parse_platform( const WCHAR *str )
1157 {
1158 if (!str[0] || !strcmpW( str, szIntel )) return PLATFORM_INTEL;
1159 else if (!strcmpW( str, szIntel64 )) return PLATFORM_INTEL64;
1160 else if (!strcmpW( str, szX64 ) || !strcmpW( str, szAMD64 )) return PLATFORM_X64;
1161 else if (!strcmpW( str, szARM )) return PLATFORM_ARM;
1162 return PLATFORM_UNKNOWN;
1163 }
1164
1165 static UINT parse_suminfo( MSISUMMARYINFO *si, MSIPACKAGE *package )
1166 {
1167 WCHAR *template, *p, *q, *platform;
1168 DWORD i, count;
1169
1170 package->version = msi_suminfo_get_int32( si, PID_PAGECOUNT );
1171 TRACE("version: %d\n", package->version);
1172
1173 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
1174 if (!template)
1175 return ERROR_SUCCESS; /* native accepts missing template property */
1176
1177 TRACE("template: %s\n", debugstr_w(template));
1178
1179 p = strchrW( template, ';' );
1180 if (!p)
1181 {
1182 WARN("invalid template string %s\n", debugstr_w(template));
1183 msi_free( template );
1184 return ERROR_PATCH_PACKAGE_INVALID;
1185 }
1186 *p = 0;
1187 platform = template;
1188 if ((q = strchrW( platform, ',' ))) *q = 0;
1189 package->platform = parse_platform( platform );
1190 while (package->platform == PLATFORM_UNKNOWN && q)
1191 {
1192 platform = q + 1;
1193 if ((q = strchrW( platform, ',' ))) *q = 0;
1194 package->platform = parse_platform( platform );
1195 }
1196 if (package->platform == PLATFORM_UNKNOWN)
1197 {
1198 WARN("unknown platform %s\n", debugstr_w(template));
1199 msi_free( template );
1200 return ERROR_INSTALL_PLATFORM_UNSUPPORTED;
1201 }
1202 p++;
1203 if (!*p)
1204 {
1205 msi_free( template );
1206 return ERROR_SUCCESS;
1207 }
1208 count = 1;
1209 for (q = p; (q = strchrW( q, ',' )); q++) count++;
1210
1211 package->langids = msi_alloc( count * sizeof(LANGID) );
1212 if (!package->langids)
1213 {
1214 msi_free( template );
1215 return ERROR_OUTOFMEMORY;
1216 }
1217
1218 i = 0;
1219 while (*p)
1220 {
1221 q = strchrW( p, ',' );
1222 if (q) *q = 0;
1223 package->langids[i] = atoiW( p );
1224 if (!q) break;
1225 p = q + 1;
1226 i++;
1227 }
1228 package->num_langids = i + 1;
1229
1230 msi_free( template );
1231 return ERROR_SUCCESS;
1232 }
1233
1234 static UINT validate_package( MSIPACKAGE *package )
1235 {
1236 UINT i;
1237
1238 if (package->platform == PLATFORM_INTEL64)
1239 return ERROR_INSTALL_PLATFORM_UNSUPPORTED;
1240 #ifndef __arm__
1241 if (package->platform == PLATFORM_ARM)
1242 return ERROR_INSTALL_PLATFORM_UNSUPPORTED;
1243 #endif
1244 if (package->platform == PLATFORM_X64)
1245 {
1246 if (!is_64bit && !is_wow64)
1247 return ERROR_INSTALL_PLATFORM_UNSUPPORTED;
1248 if (package->version < 200)
1249 return ERROR_INSTALL_PACKAGE_INVALID;
1250 }
1251 if (!package->num_langids)
1252 {
1253 return ERROR_SUCCESS;
1254 }
1255 for (i = 0; i < package->num_langids; i++)
1256 {
1257 LANGID langid = package->langids[i];
1258
1259 if (PRIMARYLANGID( langid ) == LANG_NEUTRAL)
1260 {
1261 langid = MAKELANGID( PRIMARYLANGID( GetSystemDefaultLangID() ), SUBLANGID( langid ) );
1262 }
1263 if (SUBLANGID( langid ) == SUBLANG_NEUTRAL)
1264 {
1265 langid = MAKELANGID( PRIMARYLANGID( langid ), SUBLANGID( GetSystemDefaultLangID() ) );
1266 }
1267 if (IsValidLocale( langid, LCID_INSTALLED ))
1268 return ERROR_SUCCESS;
1269 }
1270 return ERROR_INSTALL_LANGUAGE_UNSUPPORTED;
1271 }
1272
1273 static WCHAR *get_product_code( MSIDATABASE *db )
1274 {
1275 static const WCHAR query[] = {
1276 'S','E','L','E','C','T',' ','`','V','a','l','u','e','`',' ',
1277 'F','R','O','M',' ','`','P','r','o','p','e','r','t','y','`',' ',
1278 'W','H','E','R','E',' ','`','P','r','o','p','e','r','t','y','`','=',
1279 '\'','P','r','o','d','u','c','t','C','o','d','e','\'',0};
1280 MSIQUERY *view;
1281 MSIRECORD *rec;
1282 WCHAR *ret = NULL;
1283
1284 if (MSI_DatabaseOpenViewW( db, query, &view ) != ERROR_SUCCESS)
1285 {
1286 return NULL;
1287 }
1288 if (MSI_ViewExecute( view, 0 ) != ERROR_SUCCESS)
1289 {
1290 MSI_ViewClose( view );
1291 msiobj_release( &view->hdr );
1292 return NULL;
1293 }
1294 if (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
1295 {
1296 ret = strdupW( MSI_RecordGetString( rec, 1 ) );
1297 msiobj_release( &rec->hdr );
1298 }
1299 MSI_ViewClose( view );
1300 msiobj_release( &view->hdr );
1301 return ret;
1302 }
1303
1304 static UINT get_registered_local_package( const WCHAR *product, const WCHAR *package, WCHAR *localfile )
1305 {
1306 MSIINSTALLCONTEXT context;
1307 HKEY product_key, props_key;
1308 WCHAR *registered_package = NULL, unsquashed[GUID_SIZE];
1309 UINT r;
1310
1311 r = msi_locate_product( product, &context );
1312 if (r != ERROR_SUCCESS)
1313 return r;
1314
1315 r = MSIREG_OpenProductKey( product, NULL, context, &product_key, FALSE );
1316 if (r != ERROR_SUCCESS)
1317 return r;
1318
1319 r = MSIREG_OpenInstallProps( product, context, NULL, &props_key, FALSE );
1320 if (r != ERROR_SUCCESS)
1321 {
1322 RegCloseKey( product_key );
1323 return r;
1324 }
1325 r = ERROR_FUNCTION_FAILED;
1326 registered_package = msi_reg_get_val_str( product_key, INSTALLPROPERTY_PACKAGECODEW );
1327 if (!registered_package)
1328 goto done;
1329
1330 unsquash_guid( registered_package, unsquashed );
1331 if (!strcmpiW( package, unsquashed ))
1332 {
1333 WCHAR *filename = msi_reg_get_val_str( props_key, INSTALLPROPERTY_LOCALPACKAGEW );
1334 if (!filename)
1335 goto done;
1336
1337 strcpyW( localfile, filename );
1338 msi_free( filename );
1339 r = ERROR_SUCCESS;
1340 }
1341 done:
1342 msi_free( registered_package );
1343 RegCloseKey( props_key );
1344 RegCloseKey( product_key );
1345 return r;
1346 }
1347
1348 static WCHAR *get_package_code( MSIDATABASE *db )
1349 {
1350 WCHAR *ret;
1351 MSISUMMARYINFO *si;
1352 UINT r;
1353
1354 r = msi_get_suminfo( db->storage, 0, &si );
1355 if (r != ERROR_SUCCESS)
1356 {
1357 r = msi_get_db_suminfo( db, 0, &si );
1358 if (r != ERROR_SUCCESS)
1359 {
1360 WARN("failed to load summary info %u\n", r);
1361 return NULL;
1362 }
1363 }
1364 ret = msi_suminfo_dup_string( si, PID_REVNUMBER );
1365 msiobj_release( &si->hdr );
1366 return ret;
1367 }
1368
1369 static UINT get_local_package( const WCHAR *filename, WCHAR *localfile )
1370 {
1371 WCHAR *product_code, *package_code;
1372 MSIDATABASE *db;
1373 UINT r;
1374
1375 if ((r = MSI_OpenDatabaseW( filename, MSIDBOPEN_READONLY, &db )) != ERROR_SUCCESS)
1376 {
1377 if (GetFileAttributesW( filename ) == INVALID_FILE_ATTRIBUTES)
1378 return ERROR_FILE_NOT_FOUND;
1379 return r;
1380 }
1381 if (!(product_code = get_product_code( db )))
1382 {
1383 msiobj_release( &db->hdr );
1384 return ERROR_INSTALL_PACKAGE_INVALID;
1385 }
1386 if (!(package_code = get_package_code( db )))
1387 {
1388 msi_free( product_code );
1389 msiobj_release( &db->hdr );
1390 return ERROR_INSTALL_PACKAGE_INVALID;
1391 }
1392 r = get_registered_local_package( product_code, package_code, localfile );
1393 msi_free( package_code );
1394 msi_free( product_code );
1395 msiobj_release( &db->hdr );
1396 return r;
1397 }
1398
1399 UINT msi_set_original_database_property( MSIDATABASE *db, const WCHAR *package )
1400 {
1401 UINT r;
1402
1403 if (UrlIsW( package, URLIS_URL ))
1404 r = msi_set_property( db, szOriginalDatabase, package, -1 );
1405 else if (package[0] == '#')
1406 r = msi_set_property( db, szOriginalDatabase, db->path, -1 );
1407 else
1408 {
1409 DWORD len;
1410 WCHAR *path;
1411
1412 if (!(len = GetFullPathNameW( package, 0, NULL, NULL ))) return GetLastError();
1413 if (!(path = msi_alloc( len * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY;
1414 len = GetFullPathNameW( package, len, path, NULL );
1415 r = msi_set_property( db, szOriginalDatabase, path, len );
1416 msi_free( path );
1417 }
1418 return r;
1419 }
1420
1421 UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
1422 {
1423 static const WCHAR dotmsi[] = {'.','m','s','i',0};
1424 MSIDATABASE *db;
1425 MSIPACKAGE *package;
1426 MSIHANDLE handle;
1427 MSIRECORD *data_row, *info_row;
1428 LPWSTR ptr, base_url = NULL;
1429 UINT r;
1430 WCHAR localfile[MAX_PATH], cachefile[MAX_PATH];
1431 LPCWSTR file = szPackage;
1432 DWORD index = 0;
1433 MSISUMMARYINFO *si;
1434 BOOL delete_on_close = FALSE;
1435 LPWSTR productname;
1436 WCHAR *info_template;
1437
1438 TRACE("%s %p\n", debugstr_w(szPackage), pPackage);
1439
1440 MSI_ProcessMessage(NULL, INSTALLMESSAGE_INITIALIZE, 0);
1441
1442 localfile[0] = 0;
1443 if( szPackage[0] == '#' )
1444 {
1445 handle = atoiW(&szPackage[1]);
1446 db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
1447 if( !db )
1448 {
1449 IWineMsiRemoteDatabase *remote_database;
1450
1451 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( handle );
1452 if ( !remote_database )
1453 return ERROR_INVALID_HANDLE;
1454
1455 IWineMsiRemoteDatabase_Release( remote_database );
1456 WARN("MsiOpenPackage not allowed during a custom action!\n");
1457
1458 return ERROR_FUNCTION_FAILED;
1459 }
1460 }
1461 else
1462 {
1463 if ( UrlIsW( szPackage, URLIS_URL ) )
1464 {
1465 r = msi_download_file( szPackage, cachefile );
1466 if (r != ERROR_SUCCESS)
1467 return r;
1468
1469 file = cachefile;
1470
1471 base_url = strdupW( szPackage );
1472 if (!base_url)
1473 return ERROR_OUTOFMEMORY;
1474
1475 ptr = strrchrW( base_url, '/' );
1476 if (ptr) *(ptr + 1) = '\0';
1477 }
1478 r = get_local_package( file, localfile );
1479 if (r != ERROR_SUCCESS || GetFileAttributesW( localfile ) == INVALID_FILE_ATTRIBUTES)
1480 {
1481 r = msi_create_empty_local_file( localfile, dotmsi );
1482 if (r != ERROR_SUCCESS)
1483 {
1484 msi_free ( base_url );
1485 return r;
1486 }
1487
1488 if (!CopyFileW( file, localfile, FALSE ))
1489 {
1490 r = GetLastError();
1491 WARN("unable to copy package %s to %s (%u)\n", debugstr_w(file), debugstr_w(localfile), r);
1492 DeleteFileW( localfile );
1493 msi_free ( base_url );
1494 return r;
1495 }
1496 delete_on_close = TRUE;
1497 }
1498 TRACE("opening package %s\n", debugstr_w( localfile ));
1499 r = MSI_OpenDatabaseW( localfile, MSIDBOPEN_TRANSACT, &db );
1500 if (r != ERROR_SUCCESS)
1501 {
1502 msi_free ( base_url );
1503 return r;
1504 }
1505 }
1506 package = MSI_CreatePackage( db, base_url );
1507 msi_free( base_url );
1508 msiobj_release( &db->hdr );
1509 if (!package) return ERROR_INSTALL_PACKAGE_INVALID;
1510 package->localfile = strdupW( localfile );
1511 package->delete_on_close = delete_on_close;
1512
1513 r = msi_get_suminfo( db->storage, 0, &si );
1514 if (r != ERROR_SUCCESS)
1515 {
1516 r = msi_get_db_suminfo( db, 0, &si );
1517 if (r != ERROR_SUCCESS)
1518 {
1519 WARN("failed to load summary info\n");
1520 msiobj_release( &package->hdr );
1521 return ERROR_INSTALL_PACKAGE_INVALID;
1522 }
1523 }
1524 r = parse_suminfo( si, package );
1525 msiobj_release( &si->hdr );
1526 if (r != ERROR_SUCCESS)
1527 {
1528 WARN("failed to parse summary info %u\n", r);
1529 msiobj_release( &package->hdr );
1530 return r;
1531 }
1532 r = validate_package( package );
1533 if (r != ERROR_SUCCESS)
1534 {
1535 msiobj_release( &package->hdr );
1536 return r;
1537 }
1538 msi_set_property( package->db, szDatabase, db->path, -1 );
1539 set_installed_prop( package );
1540 msi_set_context( package );
1541
1542 while (1)
1543 {
1544 WCHAR patch_code[GUID_SIZE];
1545 r = MsiEnumPatchesExW( package->ProductCode, NULL, package->Context,
1546 MSIPATCHSTATE_APPLIED, index, patch_code, NULL, NULL, NULL, NULL );
1547 if (r != ERROR_SUCCESS)
1548 break;
1549
1550 TRACE("found registered patch %s\n", debugstr_w(patch_code));
1551
1552 r = msi_apply_registered_patch( package, patch_code );
1553 if (r != ERROR_SUCCESS)
1554 {
1555 ERR("registered patch failed to apply %u\n", r);
1556 msiobj_release( &package->hdr );
1557 return r;
1558 }
1559 index++;
1560 }
1561 if (index) msi_adjust_privilege_properties( package );
1562
1563 r = msi_set_original_database_property( package->db, szPackage );
1564 if (r != ERROR_SUCCESS)
1565 {
1566 msiobj_release( &package->hdr );
1567 return r;
1568 }
1569 if (gszLogFile)
1570 package->log_file = CreateFileW( gszLogFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1571 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
1572
1573 /* FIXME: when should these messages be sent? */
1574 data_row = MSI_CreateRecord(3);
1575 if (!data_row)
1576 return ERROR_OUTOFMEMORY;
1577 MSI_RecordSetStringW(data_row, 0, NULL);
1578 MSI_RecordSetInteger(data_row, 1, 0);
1579 MSI_RecordSetInteger(data_row, 2, package->num_langids ? package->langids[0] : 0);
1580 MSI_RecordSetInteger(data_row, 3, msi_get_string_table_codepage(package->db->strings));
1581 MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_COMMONDATA, data_row);
1582
1583 info_row = MSI_CreateRecord(0);
1584 if (!info_row)
1585 {
1586 msiobj_release(&data_row->hdr);
1587 return ERROR_OUTOFMEMORY;
1588 }
1589 info_template = msi_get_error_message(package->db, MSIERR_INFO_LOGGINGSTART);
1590 MSI_RecordSetStringW(info_row, 0, info_template);
1591 msi_free(info_template);
1592 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO|MB_ICONHAND, info_row);
1593
1594 MSI_ProcessMessage(package, INSTALLMESSAGE_COMMONDATA, data_row);
1595
1596 productname = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
1597 MSI_RecordSetInteger(data_row, 1, 1);
1598 MSI_RecordSetStringW(data_row, 2, productname);
1599 MSI_RecordSetStringW(data_row, 3, NULL);
1600 MSI_ProcessMessage(package, INSTALLMESSAGE_COMMONDATA, data_row);
1601
1602 msi_free(productname);
1603 msiobj_release(&info_row->hdr);
1604 msiobj_release(&data_row->hdr);
1605
1606 *pPackage = package;
1607 return ERROR_SUCCESS;
1608 }
1609
1610 UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
1611 {
1612 MSIPACKAGE *package = NULL;
1613 UINT ret;
1614
1615 TRACE("%s %08x %p\n", debugstr_w(szPackage), dwOptions, phPackage );
1616
1617 if( !szPackage || !phPackage )
1618 return ERROR_INVALID_PARAMETER;
1619
1620 if ( !*szPackage )
1621 {
1622 FIXME("Should create an empty database and package\n");
1623 return ERROR_FUNCTION_FAILED;
1624 }
1625
1626 if( dwOptions )
1627 FIXME("dwOptions %08x not supported\n", dwOptions);
1628
1629 ret = MSI_OpenPackageW( szPackage, &package );
1630 if( ret == ERROR_SUCCESS )
1631 {
1632 *phPackage = alloc_msihandle( &package->hdr );
1633 if (! *phPackage)
1634 ret = ERROR_NOT_ENOUGH_MEMORY;
1635 msiobj_release( &package->hdr );
1636 }
1637 else
1638 MSI_ProcessMessage(NULL, INSTALLMESSAGE_TERMINATE, 0);
1639
1640 return ret;
1641 }
1642
1643 UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
1644 {
1645 return MsiOpenPackageExW( szPackage, 0, phPackage );
1646 }
1647
1648 UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
1649 {
1650 LPWSTR szwPack = NULL;
1651 UINT ret;
1652
1653 if( szPackage )
1654 {
1655 szwPack = strdupAtoW( szPackage );
1656 if( !szwPack )
1657 return ERROR_OUTOFMEMORY;
1658 }
1659
1660 ret = MsiOpenPackageExW( szwPack, dwOptions, phPackage );
1661
1662 msi_free( szwPack );
1663
1664 return ret;
1665 }
1666
1667 UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
1668 {
1669 return MsiOpenPackageExA( szPackage, 0, phPackage );
1670 }
1671
1672 MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
1673 {
1674 MSIPACKAGE *package;
1675 MSIHANDLE handle = 0;
1676 IUnknown *remote_unk;
1677 IWineMsiRemotePackage *remote_package;
1678
1679 TRACE("(%d)\n",hInstall);
1680
1681 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
1682 if( package)
1683 {
1684 handle = alloc_msihandle( &package->db->hdr );
1685 msiobj_release( &package->hdr );
1686 }
1687 else if ((remote_unk = msi_get_remote(hInstall)))
1688 {
1689 if (IUnknown_QueryInterface(remote_unk, &IID_IWineMsiRemotePackage,
1690 (LPVOID *)&remote_package) == S_OK)
1691 {
1692 IWineMsiRemotePackage_GetActiveDatabase(remote_package, &handle);
1693 IWineMsiRemotePackage_Release(remote_package);
1694 }
1695 else
1696 {
1697 WARN("remote handle %d is not a package\n", hInstall);
1698 }
1699 IUnknown_Release(remote_unk);
1700 }
1701
1702 return handle;
1703 }
1704
1705 static INT internal_ui_handler(MSIPACKAGE *package, INSTALLMESSAGE eMessageType, MSIRECORD *record, LPCWSTR message)
1706 {
1707 static const WCHAR szActionData[] = {'A','c','t','i','o','n','D','a','t','a',0};
1708 static const WCHAR szActionText[] = {'A','c','t','i','o','n','T','e','x','t',0};
1709 static const WCHAR szSetProgress[] = {'S','e','t','P','r','o','g','r','e','s','s',0};
1710 static const WCHAR szWindows_Installer[] =
1711 {'W','i','n','d','o','w','s',' ','I','n','s','t','a','l','l','e','r',0};
1712
1713 if (!package || (package->ui_level & INSTALLUILEVEL_MASK) == INSTALLUILEVEL_NONE)
1714 return 0;
1715
1716 /* todo: check if message needs additional styles (topmost/foreground/modality?) */
1717
1718 switch (eMessageType & 0xff000000)
1719 {
1720 case INSTALLMESSAGE_FATALEXIT:
1721 case INSTALLMESSAGE_ERROR:
1722 case INSTALLMESSAGE_OUTOFDISKSPACE:
1723 if (package->ui_level & INSTALLUILEVEL_PROGRESSONLY) return 0;
1724 if (!(eMessageType & MB_ICONMASK))
1725 eMessageType |= MB_ICONEXCLAMATION;
1726 return MessageBoxW(gUIhwnd, message, szWindows_Installer, eMessageType & 0x00ffffff);
1727 case INSTALLMESSAGE_WARNING:
1728 if (package->ui_level & INSTALLUILEVEL_PROGRESSONLY) return 0;
1729 if (!(eMessageType & MB_ICONMASK))
1730 eMessageType |= MB_ICONASTERISK;
1731 return MessageBoxW(gUIhwnd, message, szWindows_Installer, eMessageType & 0x00ffffff);
1732 case INSTALLMESSAGE_USER:
1733 if (package->ui_level & INSTALLUILEVEL_PROGRESSONLY) return 0;
1734 if (!(eMessageType & MB_ICONMASK))
1735 eMessageType |= MB_USERICON;
1736 return MessageBoxW(gUIhwnd, message, szWindows_Installer, eMessageType & 0x00ffffff);
1737 case INSTALLMESSAGE_INFO:
1738 case INSTALLMESSAGE_INITIALIZE:
1739 case INSTALLMESSAGE_TERMINATE:
1740 return 0;
1741 case INSTALLMESSAGE_SHOWDIALOG:
1742 {
1743 LPWSTR dialog = msi_dup_record_field(record, 0);
1744 INT rc = ACTION_DialogBox(package, dialog);
1745 msi_free(dialog);
1746 return rc;
1747 }
1748 case INSTALLMESSAGE_ACTIONSTART:
1749 {
1750 LPWSTR deformatted;
1751 MSIRECORD *uirow = MSI_CreateRecord(1);
1752 if (!uirow) return -1;
1753 deformat_string(package, MSI_RecordGetString(record, 2), &deformatted);
1754 MSI_RecordSetStringW(uirow, 1, deformatted);
1755 msi_event_fire(package, szActionText, uirow);
1756
1757 msi_free(deformatted);
1758 msiobj_release(&uirow->hdr);
1759 return 1;
1760 }
1761 case INSTALLMESSAGE_ACTIONDATA:
1762 {
1763 MSIRECORD *uirow = MSI_CreateRecord(1);
1764 if (!uirow) return -1;
1765 MSI_RecordSetStringW(uirow, 1, message);
1766 msi_event_fire(package, szActionData, uirow);
1767 msiobj_release(&uirow->hdr);
1768
1769 if (package->action_progress_increment)
1770 {
1771 uirow = MSI_CreateRecord(2);
1772 if (!uirow) return -1;
1773 MSI_RecordSetInteger(uirow, 1, 2);
1774 MSI_RecordSetInteger(uirow, 2, package->action_progress_increment);
1775 msi_event_fire(package, szSetProgress, uirow);
1776 msiobj_release(&uirow->hdr);
1777 }
1778 return 1;
1779 }
1780 case INSTALLMESSAGE_PROGRESS:
1781 msi_event_fire(package, szSetProgress, record);
1782 return 1;
1783 case INSTALLMESSAGE_COMMONDATA:
1784 switch (MSI_RecordGetInteger(record, 1))
1785 {
1786 case 0:
1787 case 1:
1788 /* do nothing */
1789 return 0;
1790 default:
1791 /* fall through */
1792 ;
1793 }
1794 default:
1795 FIXME("internal UI not implemented for message 0x%08x (UI level = %x)\n", eMessageType, package->ui_level);
1796 return 0;
1797 }
1798 }
1799
1800 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};
1801
1802 static const struct
1803 {
1804 int id;
1805 const WCHAR *text;
1806 }
1807 internal_errors[] =
1808 {
1809 {2726, szActionNotFound},
1810 {0}
1811 };
1812
1813 static LPCWSTR get_internal_error_message(int error)
1814 {
1815 int i = 0;
1816
1817 while (internal_errors[i].id != 0)
1818 {
1819 if (internal_errors[i].id == error)
1820 return internal_errors[i].text;
1821 i++;
1822 }
1823
1824 FIXME("missing error message %d\n", error);
1825 return NULL;
1826 }
1827
1828 /* Returned string must be freed */
1829 LPWSTR msi_get_error_message(MSIDATABASE *db, int error)
1830 {
1831 static const WCHAR query[] =
1832 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
1833 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
1834 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
1835 MSIRECORD *record;
1836 LPWSTR ret = NULL;
1837
1838 if ((record = MSI_QueryGetRecord(db, query, error)))
1839 {
1840 ret = msi_dup_record_field(record, 1);
1841 msiobj_release(&record->hdr);
1842 }
1843 else if (error < 2000)
1844 {
1845 int len = LoadStringW(msi_hInstance, IDS_ERROR_BASE + error, (LPWSTR) &ret, 0);
1846 if (len)
1847 {
1848 ret = msi_alloc((len + 1) * sizeof(WCHAR));
1849 LoadStringW(msi_hInstance, IDS_ERROR_BASE + error, ret, len + 1);
1850 }
1851 else
1852 ret = NULL;
1853 }
1854
1855 return ret;
1856 }
1857
1858 INT MSI_ProcessMessageVerbatim(MSIPACKAGE *package, INSTALLMESSAGE eMessageType, MSIRECORD *record)
1859 {
1860 LPWSTR message = {0};
1861 DWORD len, log_type = 0;
1862 UINT res;
1863 INT rc = 0;
1864 char *msg;
1865
1866 TRACE("%x\n", eMessageType);
1867 if (TRACE_ON(msi)) dump_record(record);
1868
1869 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_FATALEXIT)
1870 log_type |= INSTALLLOGMODE_FATALEXIT;
1871 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR)
1872 log_type |= INSTALLLOGMODE_ERROR;
1873 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_WARNING)
1874 log_type |= INSTALLLOGMODE_WARNING;
1875 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_USER)
1876 log_type |= INSTALLLOGMODE_USER;
1877 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INFO)
1878 log_type |= INSTALLLOGMODE_INFO;
1879 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_RESOLVESOURCE)
1880 log_type |= INSTALLLOGMODE_RESOLVESOURCE;
1881 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_OUTOFDISKSPACE)
1882 log_type |= INSTALLLOGMODE_OUTOFDISKSPACE;
1883 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA)
1884 log_type |= INSTALLLOGMODE_COMMONDATA;
1885 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
1886 log_type |= INSTALLLOGMODE_ACTIONSTART;
1887 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONDATA)
1888 log_type |= INSTALLLOGMODE_ACTIONDATA;
1889 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS)
1890 log_type |= INSTALLLOGMODE_PROGRESS;
1891 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INITIALIZE)
1892 log_type |= INSTALLLOGMODE_INITIALIZE;
1893 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_TERMINATE)
1894 log_type |= INSTALLLOGMODE_TERMINATE;
1895 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_SHOWDIALOG)
1896 log_type |= INSTALLLOGMODE_SHOWDIALOG;
1897
1898 if (!package || !record)
1899 message = NULL;
1900 else {
1901 res = MSI_FormatRecordW(package, record, message, &len);
1902 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
1903 return res;
1904 len++;
1905 message = msi_alloc(len * sizeof(WCHAR));
1906 if (!message) return ERROR_OUTOFMEMORY;
1907 MSI_FormatRecordW(package, record, message, &len);
1908 }
1909
1910 /* convert it to ASCII */
1911 len = WideCharToMultiByte( CP_ACP, 0, message, -1, NULL, 0, NULL, NULL );
1912 msg = msi_alloc( len );
1913 WideCharToMultiByte( CP_ACP, 0, message, -1, msg, len, NULL, NULL );
1914
1915 if (gUIHandlerRecord && (gUIFilterRecord & log_type))
1916 {
1917 MSIHANDLE rec = alloc_msihandle(&record->hdr);
1918 TRACE("Calling UI handler %p(pvContext=%p, iMessageType=%08x, hRecord=%u)\n",
1919 gUIHandlerRecord, gUIContextRecord, eMessageType, rec);
1920 rc = gUIHandlerRecord( gUIContextRecord, eMessageType, rec );
1921 MsiCloseHandle( rec );
1922 }
1923 if (!rc && gUIHandlerW && (gUIFilter & log_type))
1924 {
1925 TRACE("Calling UI handler %p(pvContext=%p, iMessageType=%08x, szMessage=%s)\n",
1926 gUIHandlerW, gUIContext, eMessageType, debugstr_w(message));
1927 rc = gUIHandlerW( gUIContext, eMessageType, message );
1928 }
1929 else if (!rc && gUIHandlerA && (gUIFilter & log_type))
1930 {
1931 TRACE("Calling UI handler %p(pvContext=%p, iMessageType=%08x, szMessage=%s)\n",
1932 gUIHandlerA, gUIContext, eMessageType, debugstr_a(msg));
1933 rc = gUIHandlerA( gUIContext, eMessageType, msg );
1934 }
1935
1936 if (!rc)
1937 rc = internal_ui_handler(package, eMessageType, record, message);
1938
1939 if (!rc && package && package->log_file != INVALID_HANDLE_VALUE &&
1940 (eMessageType & 0xff000000) != INSTALLMESSAGE_PROGRESS)
1941 {
1942 DWORD written;
1943 WriteFile( package->log_file, msg, len - 1, &written, NULL );
1944 WriteFile( package->log_file, "\n", 1, &written, NULL );
1945 }
1946 msi_free( msg );
1947 msi_free( message );
1948
1949 return rc;
1950 }
1951
1952 INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType, MSIRECORD *record )
1953 {
1954 switch (eMessageType & 0xff000000)
1955 {
1956 case INSTALLMESSAGE_FATALEXIT:
1957 case INSTALLMESSAGE_ERROR:
1958 case INSTALLMESSAGE_WARNING:
1959 case INSTALLMESSAGE_USER:
1960 case INSTALLMESSAGE_INFO:
1961 case INSTALLMESSAGE_OUTOFDISKSPACE:
1962 if (MSI_RecordGetInteger(record, 1) != MSI_NULL_INTEGER)
1963 {
1964 /* error message */
1965
1966 LPWSTR template;
1967 LPWSTR template_rec = NULL, template_prefix = NULL;
1968 int error = MSI_RecordGetInteger(record, 1);
1969
1970 if (MSI_RecordIsNull(record, 0))
1971 {
1972 if (error >= 32)
1973 {
1974 template_rec = msi_get_error_message(package->db, error);
1975
1976 if (!template_rec && error >= 2000)
1977 {
1978 /* internal error, not localized */
1979 if ((template_rec = (LPWSTR) get_internal_error_message(error)))
1980 {
1981 MSI_RecordSetStringW(record, 0, template_rec);
1982 MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_INFO, record);
1983 }
1984 template_rec = msi_get_error_message(package->db, MSIERR_INSTALLERROR);
1985 MSI_RecordSetStringW(record, 0, template_rec);
1986 MSI_ProcessMessageVerbatim(package, eMessageType, record);
1987 msi_free(template_rec);
1988 return 0;
1989 }
1990 }
1991 }
1992 else
1993 template_rec = msi_dup_record_field(record, 0);
1994
1995 template_prefix = msi_get_error_message(package->db, eMessageType >> 24);
1996 if (!template_prefix) template_prefix = strdupW(szEmpty);
1997
1998 if (!template_rec)
1999 {
2000 /* always returns 0 */
2001 MSI_RecordSetStringW(record, 0, template_prefix);
2002 MSI_ProcessMessageVerbatim(package, eMessageType, record);
2003 msi_free(template_prefix);
2004 return 0;
2005 }
2006
2007 template = msi_alloc((strlenW(template_rec) + strlenW(template_prefix) + 1) * sizeof(WCHAR));
2008 if (!template) return ERROR_OUTOFMEMORY;
2009
2010 strcpyW(template, template_prefix);
2011 strcatW(template, template_rec);
2012 MSI_RecordSetStringW(record, 0, template);
2013
2014 msi_free(template_prefix);
2015 msi_free(template_rec);
2016 msi_free(template);
2017 }
2018 break;
2019 case INSTALLMESSAGE_ACTIONSTART:
2020 {
2021 WCHAR *template = msi_get_error_message(package->db, MSIERR_ACTIONSTART);
2022 MSI_RecordSetStringW(record, 0, template);
2023 msi_free(template);
2024
2025 msi_free(package->LastAction);
2026 msi_free(package->LastActionTemplate);
2027 package->LastAction = msi_dup_record_field(record, 1);
2028 if (!package->LastAction) package->LastAction = strdupW(szEmpty);
2029 package->LastActionTemplate = msi_dup_record_field(record, 3);
2030 break;
2031 }
2032 case INSTALLMESSAGE_ACTIONDATA:
2033 if (package->LastAction && package->LastActionTemplate)
2034 {
2035 static const WCHAR template_s[] =
2036 {'{','{','%','s',':',' ','}','}','%','s',0};
2037 WCHAR *template;
2038
2039 template = msi_alloc((strlenW(package->LastAction) + strlenW(package->LastActionTemplate) + 7) * sizeof(WCHAR));
2040 if (!template) return ERROR_OUTOFMEMORY;
2041 sprintfW(template, template_s, package->LastAction, package->LastActionTemplate);
2042 MSI_RecordSetStringW(record, 0, template);
2043 msi_free(template);
2044 }
2045 break;
2046 case INSTALLMESSAGE_COMMONDATA:
2047 {
2048 WCHAR *template = msi_get_error_message(package->db, MSIERR_COMMONDATA);
2049 MSI_RecordSetStringW(record, 0, template);
2050 msi_free(template);
2051 }
2052 break;
2053 }
2054
2055 return MSI_ProcessMessageVerbatim(package, eMessageType, record);
2056 }
2057
2058 INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
2059 MSIHANDLE hRecord)
2060 {
2061 UINT ret = ERROR_INVALID_HANDLE;
2062 MSIPACKAGE *package = NULL;
2063 MSIRECORD *record = NULL;
2064
2065 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INITIALIZE ||
2066 (eMessageType & 0xff000000) == INSTALLMESSAGE_TERMINATE)
2067 return -1;
2068
2069 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA &&
2070 MsiRecordGetInteger(hRecord, 1) != 2)
2071 return -1;
2072
2073 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
2074 if( !package )
2075 {
2076 HRESULT hr;
2077 IWineMsiRemotePackage *remote_package;
2078
2079 remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
2080 if (!remote_package)
2081 return ERROR_INVALID_HANDLE;
2082
2083 hr = IWineMsiRemotePackage_ProcessMessage( remote_package, eMessageType, hRecord );
2084
2085 IWineMsiRemotePackage_Release( remote_package );
2086
2087 if (FAILED(hr))
2088 {
2089 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
2090 return HRESULT_CODE(hr);
2091
2092 return ERROR_FUNCTION_FAILED;
2093 }
2094
2095 return ERROR_SUCCESS;
2096 }
2097
2098 record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
2099 if( !record )
2100 goto out;
2101
2102 ret = MSI_ProcessMessage( package, eMessageType, record );
2103
2104 out:
2105 msiobj_release( &package->hdr );
2106 if( record )
2107 msiobj_release( &record->hdr );
2108
2109 return ret;
2110 }
2111
2112 /* property code */
2113
2114 UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue )
2115 {
2116 LPWSTR szwName = NULL, szwValue = NULL;
2117 UINT r = ERROR_OUTOFMEMORY;
2118
2119 szwName = strdupAtoW( szName );
2120 if( szName && !szwName )
2121 goto end;
2122
2123 szwValue = strdupAtoW( szValue );
2124 if( szValue && !szwValue )
2125 goto end;
2126
2127 r = MsiSetPropertyW( hInstall, szwName, szwValue);
2128
2129 end:
2130 msi_free( szwName );
2131 msi_free( szwValue );
2132
2133 return r;
2134 }
2135
2136 void msi_reset_folders( MSIPACKAGE *package, BOOL source )
2137 {
2138 MSIFOLDER *folder;
2139
2140 LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
2141 {
2142 if ( source )
2143 {
2144 msi_free( folder->ResolvedSource );
2145 folder->ResolvedSource = NULL;
2146 }
2147 else
2148 {
2149 msi_free( folder->ResolvedTarget );
2150 folder->ResolvedTarget = NULL;
2151 }
2152 }
2153 }
2154
2155 UINT msi_set_property( MSIDATABASE *db, const WCHAR *name, const WCHAR *value, int len )
2156 {
2157 static const WCHAR insert_query[] = {
2158 'I','N','S','E','R','T',' ','I','N','T','O',' ',
2159 '`','_','P','r','o','p','e','r','t','y','`',' ',
2160 '(','`','_','P','r','o','p','e','r','t','y','`',',','`','V','a','l','u','e','`',')',' ',
2161 'V','A','L','U','E','S',' ','(','?',',','?',')',0};
2162 static const WCHAR update_query[] = {
2163 'U','P','D','A','T','E',' ','`','_','P','r','o','p','e','r','t','y','`',' ',
2164 'S','E','T',' ','`','V','a','l','u','e','`',' ','=',' ','?',' ','W','H','E','R','E',' ',
2165 '`','_','P','r','o','p','e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
2166 static const WCHAR delete_query[] = {
2167 'D','E','L','E','T','E',' ','F','R','O','M',' ',
2168 '`','_','P','r','o','p','e','r','t','y','`',' ','W','H','E','R','E',' ',
2169 '`','_','P','r','o','p','e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
2170 MSIQUERY *view;
2171 MSIRECORD *row = NULL;
2172 DWORD sz = 0;
2173 WCHAR query[1024];
2174 UINT rc;
2175
2176 TRACE("%p %s %s %d\n", db, debugstr_w(name), debugstr_wn(value, len), len);
2177
2178 if (!name)
2179 return ERROR_INVALID_PARAMETER;
2180
2181 /* this one is weird... */
2182 if (!name[0])
2183 return value ? ERROR_FUNCTION_FAILED : ERROR_SUCCESS;
2184
2185 if (value && len < 0) len = strlenW( value );
2186
2187 rc = msi_get_property( db, name, 0, &sz );
2188 if (!value || (!*value && !len))
2189 {
2190 sprintfW( query, delete_query, name );
2191 }
2192 else if (rc == ERROR_MORE_DATA || rc == ERROR_SUCCESS)
2193 {
2194 sprintfW( query, update_query, name );
2195 row = MSI_CreateRecord(1);
2196 msi_record_set_string( row, 1, value, len );
2197 }
2198 else
2199 {
2200 strcpyW( query, insert_query );
2201 row = MSI_CreateRecord(2);
2202 msi_record_set_string( row, 1, name, -1 );
2203 msi_record_set_string( row, 2, value, len );
2204 }
2205
2206 rc = MSI_DatabaseOpenViewW(db, query, &view);
2207 if (rc == ERROR_SUCCESS)
2208 {
2209 rc = MSI_ViewExecute(view, row);
2210 MSI_ViewClose(view);
2211 msiobj_release(&view->hdr);
2212 }
2213 if (row) msiobj_release(&row->hdr);
2214 return rc;
2215 }
2216
2217 UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
2218 {
2219 MSIPACKAGE *package;
2220 UINT ret;
2221
2222 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
2223 if( !package )
2224 {
2225 HRESULT hr;
2226 BSTR name = NULL, value = NULL;
2227 IWineMsiRemotePackage *remote_package;
2228
2229 remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
2230 if (!remote_package)
2231 return ERROR_INVALID_HANDLE;
2232
2233 name = SysAllocString( szName );
2234 value = SysAllocString( szValue );
2235 if ((!name && szName) || (!value && szValue))
2236 {
2237 SysFreeString( name );
2238 SysFreeString( value );
2239 IWineMsiRemotePackage_Release( remote_package );
2240 return ERROR_OUTOFMEMORY;
2241 }
2242
2243 hr = IWineMsiRemotePackage_SetProperty( remote_package, name, value );
2244
2245 SysFreeString( name );
2246 SysFreeString( value );
2247 IWineMsiRemotePackage_Release( remote_package );
2248
2249 if (FAILED(hr))
2250 {
2251 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
2252 return HRESULT_CODE(hr);
2253
2254 return ERROR_FUNCTION_FAILED;
2255 }
2256
2257 return ERROR_SUCCESS;
2258 }
2259
2260 ret = msi_set_property( package->db, szName, szValue, -1 );
2261 if (ret == ERROR_SUCCESS && !strcmpW( szName, szSourceDir ))
2262 msi_reset_folders( package, TRUE );
2263
2264 msiobj_release( &package->hdr );
2265 return ret;
2266 }
2267
2268 static MSIRECORD *msi_get_property_row( MSIDATABASE *db, LPCWSTR name )
2269 {
2270 static const WCHAR query[]= {
2271 'S','E','L','E','C','T',' ','`','V','a','l','u','e','`',' ',
2272 'F','R','O','M',' ' ,'`','_','P','r','o','p','e','r','t','y','`',' ',
2273 'W','H','E','R','E',' ' ,'`','_','P','r','o','p','e','r','t','y','`','=','?',0};
2274 MSIRECORD *rec, *row = NULL;
2275 MSIQUERY *view;
2276 UINT r;
2277
2278 static const WCHAR szDate[] = {'D','a','t','e',0};
2279 static const WCHAR szTime[] = {'T','i','m','e',0};
2280 WCHAR *buffer;
2281 int length;
2282
2283 if (!name || !*name)
2284 return NULL;
2285
2286 if (!strcmpW(name, szDate))
2287 {
2288 length = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, NULL, 0);
2289 if (!length)
2290 return NULL;
2291 buffer = msi_alloc(length * sizeof(WCHAR));
2292 GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, buffer, length);
2293
2294 row = MSI_CreateRecord(1);
2295 if (!row)
2296 return NULL;
2297 MSI_RecordSetStringW(row, 1, buffer);
2298 msi_free(buffer);
2299 return row;
2300 }
2301 else if (!strcmpW(name, szTime))
2302 {
2303 length = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOTIMEMARKER, NULL, NULL, NULL, 0);
2304 if (!length)
2305 return NULL;
2306 buffer = msi_alloc(length * sizeof(WCHAR));
2307 GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOTIMEMARKER, NULL, NULL, buffer, length);
2308
2309 row = MSI_CreateRecord(1);
2310 if (!row)
2311 return NULL;
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