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