Add a stubbed out implementation of IAdviseSink and advise the
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #define NONAMELESSUNION
22
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winreg.h"
28 #include "winnls.h"
29 #include "shlwapi.h"
30 #include "wingdi.h"
31 #include "wine/debug.h"
32 #include "msi.h"
33 #include "msiquery.h"
34 #include "msipriv.h"
35 #include "objidl.h"
36 #include "wincrypt.h"
37 #include "winuser.h"
38 #include "shlobj.h"
39 #include "wine/unicode.h"
40 #include "objbase.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(msi);
43
44 /*
45  * The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR,
46  *  which is a problem because LPCTSTR isn't defined when compiling wine.
47  * To work around this problem, we need to define LPCTSTR as LPCWSTR here,
48  *  and make sure to only use it in W functions.
49  */
50 #define LPCTSTR LPCWSTR
51
52 static void MSI_FreePackage( MSIOBJECTHDR *arg)
53 {
54     MSIPACKAGE *package= (MSIPACKAGE*) arg;
55
56     if( package->dialog )
57         msi_dialog_destroy( package->dialog );
58     ACTION_free_package_structures(package);
59
60     msiobj_release( &package->db->hdr );
61 }
62
63 static UINT clone_properties(MSIDATABASE *db)
64 {
65     MSIQUERY * view = NULL;
66     UINT rc;
67     static const WCHAR CreateSql[] = {
68        'C','R','E','A','T','E',' ','T','A','B','L','E',' ','`','_','P','r','o',
69        'p','e','r','t','y','`',' ','(',' ','`','_','P','r','o','p','e','r','t',
70        'y','`',' ','C','H','A','R','(','5','6',')',' ','N','O','T',' ','N','U',
71        'L','L',',',' ','`','V','a','l','u','e','`',' ','C','H','A','R','(','9',
72        '8',')',' ','N','O','T',' ','N','U','L','L',' ','P','R','I','M','A','R',
73        'Y',' ','K','E','Y',' ','`','_','P','r','o','p','e','r','t','y','`',')',0};
74     static const WCHAR Query[] = {
75        'S','E','L','E','C','T',' ','*',' ',
76        'F','R','O','M',' ','`','P','r','o','p','e','r','t','y','`',0};
77     static const WCHAR Insert[] = {
78        'I','N','S','E','R','T',' ','i','n','t','o',' ',
79        '`','_','P','r','o','p','e','r','t','y','`',' ',
80        '(','`','_','P','r','o','p','e','r','t','y','`',',',
81        '`','V','a','l','u','e','`',')',' ',
82        'V','A','L','U','E','S',' ','(','?',',','?',')',0};
83
84     /* create the temporary properties table */
85     rc = MSI_DatabaseOpenViewW(db, CreateSql, &view);
86     if (rc != ERROR_SUCCESS)
87         return rc;
88     rc = MSI_ViewExecute(view,0);   
89     MSI_ViewClose(view);
90     msiobj_release(&view->hdr); 
91     if (rc != ERROR_SUCCESS)
92         return rc;
93
94     /* clone the existing properties */
95     rc = MSI_DatabaseOpenViewW(db, Query, &view);
96     if (rc != ERROR_SUCCESS)
97         return rc;
98
99     rc = MSI_ViewExecute(view, 0);
100     if (rc != ERROR_SUCCESS)
101     {
102         MSI_ViewClose(view);
103         msiobj_release(&view->hdr); 
104         return rc;
105     }
106     while (1)
107     {
108         MSIRECORD * row;
109         MSIQUERY * view2;
110
111         rc = MSI_ViewFetch(view,&row);
112         if (rc != ERROR_SUCCESS)
113             break;
114
115         rc = MSI_DatabaseOpenViewW(db,Insert,&view2);  
116         if (rc!= ERROR_SUCCESS)
117             continue;
118         rc = MSI_ViewExecute(view2,row);
119         MSI_ViewClose(view2);
120         msiobj_release(&view2->hdr);
121  
122         if (rc == ERROR_SUCCESS) 
123             msiobj_release(&row->hdr); 
124     }
125     MSI_ViewClose(view);
126     msiobj_release(&view->hdr);
127     
128     return rc;
129 }
130
131 /*
132  * There are a whole slew of these we need to set
133  *
134  *
135 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/properties.asp
136  */
137 static VOID set_installer_properties(MSIPACKAGE *package)
138 {
139     WCHAR pth[MAX_PATH];
140     WCHAR *ptr;
141     OSVERSIONINFOA OSVersion;
142     MEMORYSTATUSEX msex;
143     DWORD verval;
144     WCHAR verstr[10], bufstr[20];
145     HDC dc;
146
147     static const WCHAR cszbs[]={'\\',0};
148     static const WCHAR CFF[] = 
149 {'C','o','m','m','o','n','F','i','l','e','s','F','o','l','d','e','r',0};
150     static const WCHAR PFF[] = 
151 {'P','r','o','g','r','a','m','F','i','l','e','s','F','o','l','d','e','r',0};
152     static const WCHAR CADF[] = 
153 {'C','o','m','m','o','n','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
154     static const WCHAR FaF[] = 
155 {'F','a','v','o','r','i','t','e','s','F','o','l','d','e','r',0};
156     static const WCHAR FoF[] = 
157 {'F','o','n','t','s','F','o','l','d','e','r',0};
158     static const WCHAR SendTF[] = 
159 {'S','e','n','d','T','o','F','o','l','d','e','r',0};
160     static const WCHAR SMF[] = 
161 {'S','t','a','r','t','M','e','n','u','F','o','l','d','e','r',0};
162     static const WCHAR StF[] = 
163 {'S','t','a','r','t','u','p','F','o','l','d','e','r',0};
164     static const WCHAR TemplF[] = 
165 {'T','e','m','p','l','a','t','e','F','o','l','d','e','r',0};
166     static const WCHAR DF[] = 
167 {'D','e','s','k','t','o','p','F','o','l','d','e','r',0};
168     static const WCHAR PMF[] = 
169 {'P','r','o','g','r','a','m','M','e','n','u','F','o','l','d','e','r',0};
170     static const WCHAR ATF[] = 
171 {'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0};
172     static const WCHAR ADF[] = 
173 {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
174     static const WCHAR SF[] = 
175 {'S','y','s','t','e','m','F','o','l','d','e','r',0};
176     static const WCHAR SF16[] = 
177 {'S','y','s','t','e','m','1','6','F','o','l','d','e','r',0};
178     static const WCHAR LADF[] = 
179 {'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
180     static const WCHAR MPF[] = 
181 {'M','y','P','i','c','t','u','r','e','s','F','o','l','d','e','r',0};
182     static const WCHAR PF[] = 
183 {'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0};
184     static const WCHAR WF[] = 
185 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
186     static const WCHAR WV[] = 
187 {'W','i','n','d','o','w','s','V','o','l','u','m','e',0};
188     static const WCHAR TF[]=
189 {'T','e','m','p','F','o','l','d','e','r',0};
190     static const WCHAR szAdminUser[] =
191 {'A','d','m','i','n','U','s','e','r',0};
192     static const WCHAR szPriv[] =
193 {'P','r','i','v','i','l','e','g','e','d',0};
194     static const WCHAR szOne[] =
195 {'1',0};
196     static const WCHAR v9x[] = { 'V','e','r','s','i','o','n','9','X',0 };
197     static const WCHAR vNT[] = { 'V','e','r','s','i','o','n','N','T',0 };
198     static const WCHAR szFormat[] = {'%','l','i',0};
199     static const WCHAR szWinBuild[] =
200 {'W','i','n','d','o','w','s','B','u','i','l','d', 0 };
201     static const WCHAR szSPL[] = 
202 {'S','e','r','v','i','c','e','P','a','c','k','L','e','v','e','l',0 };
203     static const WCHAR szSix[] = {'6',0 };
204
205     static const WCHAR szVersionMsi[] = { 'V','e','r','s','i','o','n','M','s','i',0 };
206     static const WCHAR szPhysicalMemory[] = { 'P','h','y','s','i','c','a','l','M','e','m','o','r','y',0 };
207     static const WCHAR szFormat2[] = {'%','l','i','.','%','l','i',0};
208 /* Screen properties */
209     static const WCHAR szScreenX[] = {'S','c','r','e','e','n','X',0};
210     static const WCHAR szScreenY[] = {'S','c','r','e','e','n','Y',0};
211     static const WCHAR szColorBits[] = {'C','o','l','o','r','B','i','t','s',0};
212     static const WCHAR szScreenFormat[] = {'%','d',0};
213
214 /*
215  * Other things I notice set
216  *
217 SystemLanguageID
218 ComputerName
219 UserLanguageID
220 LogonUser
221 VirtualMemory
222 Intel
223 ShellAdvSupport
224 DefaultUIFont
225 VersionDatabase
226 PackagecodeChanging
227 ProductState
228 CaptionHeight
229 BorderTop
230 BorderSide
231 TextHeight
232 RedirectedDllSupport
233 Time
234 Date
235 Privileged
236 */
237
238     SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth);
239     strcatW(pth,cszbs);
240     MSI_SetPropertyW(package, CFF, pth);
241
242     SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES,NULL,0,pth);
243     strcatW(pth,cszbs);
244     MSI_SetPropertyW(package, PFF, pth);
245
246     SHGetFolderPathW(NULL,CSIDL_COMMON_APPDATA,NULL,0,pth);
247     strcatW(pth,cszbs);
248     MSI_SetPropertyW(package, CADF, pth);
249
250     SHGetFolderPathW(NULL,CSIDL_FAVORITES,NULL,0,pth);
251     strcatW(pth,cszbs);
252     MSI_SetPropertyW(package, FaF, pth);
253
254     SHGetFolderPathW(NULL,CSIDL_FONTS,NULL,0,pth);
255     strcatW(pth,cszbs);
256     MSI_SetPropertyW(package, FoF, pth);
257
258     SHGetFolderPathW(NULL,CSIDL_SENDTO,NULL,0,pth);
259     strcatW(pth,cszbs);
260     MSI_SetPropertyW(package, SendTF, pth);
261
262     SHGetFolderPathW(NULL,CSIDL_STARTMENU,NULL,0,pth);
263     strcatW(pth,cszbs);
264     MSI_SetPropertyW(package, SMF, pth);
265
266     SHGetFolderPathW(NULL,CSIDL_STARTUP,NULL,0,pth);
267     strcatW(pth,cszbs);
268     MSI_SetPropertyW(package, StF, pth);
269
270     SHGetFolderPathW(NULL,CSIDL_TEMPLATES,NULL,0,pth);
271     strcatW(pth,cszbs);
272     MSI_SetPropertyW(package, TemplF, pth);
273
274     SHGetFolderPathW(NULL,CSIDL_DESKTOP,NULL,0,pth);
275     strcatW(pth,cszbs);
276     MSI_SetPropertyW(package, DF, pth);
277
278     SHGetFolderPathW(NULL,CSIDL_PROGRAMS,NULL,0,pth);
279     strcatW(pth,cszbs);
280     MSI_SetPropertyW(package, PMF, pth);
281
282     SHGetFolderPathW(NULL,CSIDL_ADMINTOOLS,NULL,0,pth);
283     strcatW(pth,cszbs);
284     MSI_SetPropertyW(package, ATF, pth);
285
286     SHGetFolderPathW(NULL,CSIDL_APPDATA,NULL,0,pth);
287     strcatW(pth,cszbs);
288     MSI_SetPropertyW(package, ADF, pth);
289
290     SHGetFolderPathW(NULL,CSIDL_SYSTEM,NULL,0,pth);
291     strcatW(pth,cszbs);
292     MSI_SetPropertyW(package, SF, pth);
293     MSI_SetPropertyW(package, SF16, pth);
294
295     SHGetFolderPathW(NULL,CSIDL_LOCAL_APPDATA,NULL,0,pth);
296     strcatW(pth,cszbs);
297     MSI_SetPropertyW(package, LADF, pth);
298
299     SHGetFolderPathW(NULL,CSIDL_MYPICTURES,NULL,0,pth);
300     strcatW(pth,cszbs);
301     MSI_SetPropertyW(package, MPF, pth);
302
303     SHGetFolderPathW(NULL,CSIDL_PERSONAL,NULL,0,pth);
304     strcatW(pth,cszbs);
305     MSI_SetPropertyW(package, PF, pth);
306
307     SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
308     strcatW(pth,cszbs);
309     MSI_SetPropertyW(package, WF, pth);
310     
311     /* Physical Memory is specified in MB. Using total amount. */
312     msex.dwLength = sizeof(msex);
313     GlobalMemoryStatusEx( &msex );
314     sprintfW( bufstr, szScreenFormat, (int)(msex.ullTotalPhys/1024/1024));
315     MSI_SetPropertyW(package, szPhysicalMemory, bufstr);
316
317     SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
318     ptr = strchrW(pth,'\\');
319     if (ptr)
320         *(ptr+1) = 0;
321     MSI_SetPropertyW(package, WV, pth);
322     
323     GetTempPathW(MAX_PATH,pth);
324     MSI_SetPropertyW(package, TF, pth);
325
326
327     /* in a wine environment the user is always admin and privileged */
328     MSI_SetPropertyW(package,szAdminUser,szOne);
329     MSI_SetPropertyW(package,szPriv,szOne);
330
331     /* set the os things */
332     OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
333     GetVersionExA(&OSVersion);
334     verval = OSVersion.dwMinorVersion+OSVersion.dwMajorVersion*100;
335     sprintfW(verstr,szFormat,verval);
336     switch (OSVersion.dwPlatformId)
337     {
338         case VER_PLATFORM_WIN32_WINDOWS:    
339             MSI_SetPropertyW(package,v9x,verstr);
340             break;
341         case VER_PLATFORM_WIN32_NT:
342             MSI_SetPropertyW(package,vNT,verstr);
343             break;
344     }
345     sprintfW(verstr,szFormat,OSVersion.dwBuildNumber);
346     MSI_SetPropertyW(package,szWinBuild,verstr);
347     /* just fudge this */
348     MSI_SetPropertyW(package,szSPL,szSix);
349
350     sprintfW( bufstr, szFormat2, MSI_MAJORVERSION, MSI_MINORVERSION);
351     MSI_SetPropertyW( package, szVersionMsi, bufstr );
352
353     /* Screen properties. */
354     dc = GetDC(0);
355     sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, HORZRES ) );
356     MSI_SetPropertyW( package, szScreenX, bufstr );
357     sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, VERTRES ));
358     MSI_SetPropertyW( package, szScreenY, bufstr );
359     sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, BITSPIXEL ));
360     MSI_SetPropertyW( package, szColorBits, bufstr );
361     ReleaseDC(0, dc);
362 }
363
364 MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db )
365 {
366     static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 };
367     static const WCHAR szpi[] = {'%','i',0};
368     MSIPACKAGE *package = NULL;
369     WCHAR uilevel[10];
370
371     TRACE("%p\n", db);
372
373     package = alloc_msiobject( MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE),
374                                MSI_FreePackage );
375     if( package )
376     {
377         msiobj_addref( &db->hdr );
378
379         package->db = db;
380         list_init( &package->components );
381         list_init( &package->features );
382         list_init( &package->files );
383         list_init( &package->tempfiles );
384         list_init( &package->folders );
385         package->ActionFormat = NULL;
386         package->LastAction = NULL;
387         package->dialog = NULL;
388         package->next_dialog = NULL;
389         list_init( &package->subscriptions );
390         list_init( &package->appids );
391         list_init( &package->classes );
392         list_init( &package->mimes );
393         list_init( &package->extensions );
394         list_init( &package->progids );
395         list_init( &package->RunningActions );
396
397         /* OK, here is where we do a slew of things to the database to 
398          * prep for all that is to come as a package */
399
400         clone_properties(db);
401         set_installer_properties(package);
402         sprintfW(uilevel,szpi,gUILevel);
403         MSI_SetPropertyW(package, szLevel, uilevel);
404     }
405
406     return package;
407 }
408
409 /*
410  * copy_package_to_temp   [internal]
411  *
412  * copy the msi file to a temp file to prevent locking a CD
413  * with a multi disc install 
414  *
415  * FIXME: I think this is wrong, and instead of copying the package,
416  *        we should read all the tables to memory, then open the
417  *        database to read binary streams on demand.
418  */ 
419 static LPCWSTR copy_package_to_temp( LPCWSTR szPackage, LPWSTR filename )
420 {
421     WCHAR path[MAX_PATH];
422     static const WCHAR szMSI[] = {'M','S','I',0};
423
424     GetTempPathW( MAX_PATH, path );
425     GetTempFileNameW( path, szMSI, 0, filename );
426
427     if( !CopyFileW( szPackage, filename, FALSE ) )
428     {
429         ERR("failed to copy package to temp path %s\n", debugstr_w(filename) );
430         return szPackage;
431     }
432
433     TRACE("Opening relocated package %s\n", debugstr_w( filename ));
434     return filename;
435 }
436
437 UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
438 {
439     MSIDATABASE *db = NULL;
440     MSIPACKAGE *package;
441     MSIHANDLE handle;
442     DWORD size;
443     static const WCHAR szProductCode[]= {'P','r','o','d','u','c','t','C','o','d','e',0};
444     UINT r;
445
446     TRACE("%s %p\n", debugstr_w(szPackage), pPackage);
447
448     if( szPackage[0] == '#' )
449     {
450         handle = atoiW(&szPackage[1]);
451         db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
452         if( !db )
453             return ERROR_INVALID_HANDLE;
454     }
455     else
456     {
457         WCHAR temppath[MAX_PATH];
458         LPCWSTR file = copy_package_to_temp( szPackage, temppath );
459
460         r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &db );
461
462         if (file != szPackage)
463             DeleteFileW( file );
464
465         if( r != ERROR_SUCCESS )
466             return r;
467     }
468
469     package = MSI_CreatePackage( db );
470     msiobj_release( &db->hdr );
471     if( !package )
472         return ERROR_FUNCTION_FAILED;
473
474     /* 
475      * FIXME:  I don't think this is right.  Maybe we should be storing the
476      * name of the database in the MSIDATABASE structure and fetching this
477      * info from there, or maybe this is only relevant to cached databases.
478      */
479     if( szPackage[0] != '#' )
480     {
481         static const WCHAR OriginalDatabase[] =
482           {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
483         static const WCHAR Database[] = {'D','A','T','A','B','A','S','E',0};
484
485         MSI_SetPropertyW( package, OriginalDatabase, szPackage );
486         MSI_SetPropertyW( package, Database, szPackage );
487     }
488
489     /* this property must exist */
490     size  = 0;
491     MSI_GetPropertyW(package,szProductCode,NULL,&size);
492     size ++;
493     package->ProductCode = msi_alloc(size * sizeof(WCHAR));
494     MSI_GetPropertyW(package,szProductCode,package->ProductCode, &size);
495     
496     *pPackage = package;
497
498     return ERROR_SUCCESS;
499 }
500
501 UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
502 {
503     MSIPACKAGE *package = NULL;
504     UINT ret;
505
506     TRACE("%s %08lx %p\n", debugstr_w(szPackage), dwOptions, phPackage );
507
508     if( dwOptions )
509         FIXME("dwOptions %08lx not supported\n", dwOptions);
510
511     ret = MSI_OpenPackageW( szPackage, &package );
512     if( ret == ERROR_SUCCESS )
513     {
514         *phPackage = alloc_msihandle( &package->hdr );
515         msiobj_release( &package->hdr );
516     }
517
518     return ret;
519 }
520
521 UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
522 {
523     return MsiOpenPackageExW( szPackage, 0, phPackage );
524 }
525
526 UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
527 {
528     LPWSTR szwPack = NULL;
529     UINT ret;
530
531     if( szPackage )
532     {
533         szwPack = strdupAtoW( szPackage );
534         if( !szwPack )
535             return ERROR_OUTOFMEMORY;
536     }
537
538     ret = MsiOpenPackageExW( szwPack, dwOptions, phPackage );
539
540     msi_free( szwPack );
541
542     return ret;
543 }
544
545 UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
546 {
547     return MsiOpenPackageExA( szPackage, 0, phPackage );
548 }
549
550 MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
551 {
552     MSIPACKAGE *package;
553     MSIHANDLE handle = 0;
554
555     TRACE("(%ld)\n",hInstall);
556
557     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
558     if( package)
559     {
560         handle = alloc_msihandle( &package->db->hdr );
561         msiobj_release( &package->hdr );
562     }
563
564     return handle;
565 }
566
567 INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
568                                MSIRECORD *record)
569 {
570     DWORD log_type = 0;
571     LPWSTR message;
572     DWORD sz;
573     DWORD total_size = 0;
574     INT msg_field=1;
575     INT i;
576     INT rc;
577     char *msg;
578     int len;
579
580     TRACE("%x \n",eMessageType);
581     rc = 0;
582
583     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR)
584         log_type |= INSTALLLOGMODE_ERROR;
585     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_WARNING)
586         log_type |= INSTALLLOGMODE_WARNING;
587     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_USER)
588         log_type |= INSTALLLOGMODE_USER;
589     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INFO)
590         log_type |= INSTALLLOGMODE_INFO;
591     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA)
592         log_type |= INSTALLLOGMODE_COMMONDATA;
593     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
594         log_type |= INSTALLLOGMODE_ACTIONSTART;
595     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONDATA)
596         log_type |= INSTALLLOGMODE_ACTIONDATA;
597     /* just a guess */
598     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS)
599         log_type |= 0x800;
600
601     message = msi_alloc(1*sizeof (WCHAR));
602     message[0]=0;
603     msg_field = MSI_RecordGetFieldCount(record);
604     for (i = 1; i <= msg_field; i++)
605     {
606         LPWSTR tmp;
607         WCHAR number[3];
608         const static WCHAR format[] = { '%','i',':',' ',0};
609         const static WCHAR space[] = { ' ',0};
610         sz = 0;
611         MSI_RecordGetStringW(record,i,NULL,&sz);
612         sz+=4;
613         total_size+=sz*sizeof(WCHAR);
614         tmp = msi_alloc(sz*sizeof(WCHAR));
615         message = msi_realloc(message,total_size*sizeof (WCHAR));
616
617         MSI_RecordGetStringW(record,i,tmp,&sz);
618
619         if (msg_field > 1)
620         {
621             sprintfW(number,format,i);
622             strcatW(message,number);
623         }
624         strcatW(message,tmp);
625         if (msg_field > 1)
626             strcatW(message,space);
627
628         msi_free(tmp);
629     }
630
631     TRACE("(%p %lx %lx %s)\n",gUIHandlerA, gUIFilter, log_type,
632                              debugstr_w(message));
633
634     /* convert it to ASCII */
635     len = WideCharToMultiByte( CP_ACP, 0, message, -1,
636                                NULL, 0, NULL, NULL );
637     msg = msi_alloc( len );
638     WideCharToMultiByte( CP_ACP, 0, message, -1,
639                          msg, len, NULL, NULL );
640
641     if (gUIHandlerA && (gUIFilter & log_type))
642     {
643         rc = gUIHandlerA(gUIContext,eMessageType,msg);
644     }
645
646     if ((!rc) && (gszLogFile[0]) && !((eMessageType & 0xff000000) ==
647                                       INSTALLMESSAGE_PROGRESS))
648     {
649         DWORD write;
650         HANDLE log_file = CreateFileW(gszLogFile,GENERIC_WRITE, 0, NULL,
651                                   OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
652
653         if (log_file != INVALID_HANDLE_VALUE)
654         {
655             SetFilePointer(log_file,0, NULL, FILE_END);
656             WriteFile(log_file,msg,strlen(msg),&write,NULL);
657             WriteFile(log_file,"\n",1,&write,NULL);
658             CloseHandle(log_file);
659         }
660     }
661     msi_free( msg );
662     
663     msi_free( message);
664     return ERROR_SUCCESS;
665 }
666
667 INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
668                               MSIHANDLE hRecord)
669 {
670     UINT ret = ERROR_INVALID_HANDLE;
671     MSIPACKAGE *package = NULL;
672     MSIRECORD *record = NULL;
673
674     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
675     if( !package )
676         return ERROR_INVALID_HANDLE;
677
678     record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
679     if( !record )
680         goto out;
681
682     ret = MSI_ProcessMessage( package, eMessageType, record );
683
684 out:
685     msiobj_release( &package->hdr );
686     if( record )
687         msiobj_release( &record->hdr );
688
689     return ret;
690 }
691
692 /* property code */
693 UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue)
694 {
695     LPWSTR szwName = NULL, szwValue = NULL;
696     UINT hr = ERROR_INSTALL_FAILURE;
697
698     if( szName )
699     {
700         szwName = strdupAtoW( szName );
701         if( !szwName )
702             goto end;
703     }
704
705     if( szValue )
706     {
707         szwValue = strdupAtoW( szValue );
708         if( !szwValue)
709             goto end;
710     }
711
712     hr = MsiSetPropertyW( hInstall, szwName, szwValue);
713
714 end:
715     msi_free( szwName );
716     msi_free( szwValue );
717
718     return hr;
719 }
720
721 UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
722 {
723     MSIQUERY *view;
724     MSIRECORD *row;
725     UINT rc;
726     DWORD sz = 0;
727     static const WCHAR Insert[]=
728      {'I','N','S','E','R','T',' ','i','n','t','o',' ','`','_','P','r','o','p'
729 ,'e','r','t','y','`',' ','(','`','_','P','r','o','p','e','r','t','y','`'
730 ,',','`','V','a','l','u','e','`',')',' ','V','A','L','U','E','S'
731 ,' ','(','?',',','?',')',0};
732     static const WCHAR Update[]=
733      {'U','P','D','A','T','E',' ','_','P','r','o','p','e'
734 ,'r','t','y',' ','s','e','t',' ','`','V','a','l','u','e','`',' ','='
735 ,' ','?',' ','w','h','e','r','e',' ','`','_','P','r','o','p'
736 ,'e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
737     WCHAR Query[1024];
738
739     TRACE("Setting property (%s %s)\n",debugstr_w(szName),
740           debugstr_w(szValue));
741
742     rc = MSI_GetPropertyW(package,szName,0,&sz);
743     if (rc==ERROR_MORE_DATA || rc == ERROR_SUCCESS)
744     {
745         sprintfW(Query,Update,szName);
746
747         row = MSI_CreateRecord(1);
748         MSI_RecordSetStringW(row,1,szValue);
749
750     }
751     else
752     {
753         strcpyW(Query,Insert);
754
755         row = MSI_CreateRecord(2);
756         MSI_RecordSetStringW(row,1,szName);
757         MSI_RecordSetStringW(row,2,szValue);
758     }
759
760     rc = MSI_DatabaseOpenViewW(package->db,Query,&view);
761     if (rc == ERROR_SUCCESS)
762     {
763         rc = MSI_ViewExecute(view,row);
764
765         MSI_ViewClose(view);
766         msiobj_release(&view->hdr);
767     }
768     msiobj_release(&row->hdr);
769
770     return rc;
771 }
772
773 UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
774 {
775     MSIPACKAGE *package;
776     UINT ret;
777
778     if (NULL == szName)
779         return ERROR_INVALID_PARAMETER;
780     if (NULL == szValue)
781         return ERROR_INVALID_PARAMETER;
782
783     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
784     if( !package )
785         return ERROR_INVALID_HANDLE;
786     ret = MSI_SetPropertyW( package, szName, szValue);
787     msiobj_release( &package->hdr );
788     return ret;
789 }
790
791 static UINT MSI_GetPropertyRow(MSIPACKAGE *package, LPCWSTR szName, MSIRECORD **row)
792 {
793     MSIQUERY *view;
794     UINT rc, sz;
795     static const WCHAR select[]=
796     {'S','E','L','E','C','T',' ','`','V','a','l','u','e','`',' ',
797      'F','R','O','M',' ' ,'`','_','P','r','o','p','e','r','t','y','`',
798      ' ','W','H','E','R','E',' ' ,'`','_','P','r','o','p','e','r','t','y','`',
799      '=','\'','%','s','\'',0};
800     LPWSTR query;
801
802     if (!szName)
803         return ERROR_INVALID_PARAMETER;
804
805     sz = sizeof select + strlenW(szName)*sizeof(WCHAR);
806     query = msi_alloc( sz);
807     sprintfW(query,select,szName);
808
809     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
810     msi_free(query);
811     if (rc == ERROR_SUCCESS)
812     {
813         rc = MSI_ViewExecute(view, 0);
814         if (rc == ERROR_SUCCESS)
815             rc = MSI_ViewFetch(view,row);
816
817         MSI_ViewClose(view);
818         msiobj_release(&view->hdr);
819     }
820
821     return rc;
822 }
823
824 UINT MSI_GetPropertyW(MSIPACKAGE *package, LPCWSTR szName, 
825                            LPWSTR szValueBuf, DWORD* pchValueBuf)
826 {
827     MSIRECORD *row;
828     UINT rc;
829
830     rc = MSI_GetPropertyRow(package, szName, &row);
831
832     if (*pchValueBuf > 0)
833         szValueBuf[0] = 0;
834
835     if (rc == ERROR_SUCCESS)
836     {
837         rc = MSI_RecordGetStringW(row,1,szValueBuf,pchValueBuf);
838         msiobj_release(&row->hdr);
839     }
840
841     if (rc == ERROR_SUCCESS)
842         TRACE("returning %s for property %s\n", debugstr_w(szValueBuf),
843             debugstr_w(szName));
844     else if (rc == ERROR_MORE_DATA)
845         TRACE("need %li sized buffer for %s\n", *pchValueBuf,
846             debugstr_w(szName));
847     else
848     {
849         *pchValueBuf = 0;
850         TRACE("property %s not found\n", debugstr_w(szName));
851     }
852
853     return rc;
854 }
855
856 UINT MSI_GetPropertyA(MSIPACKAGE *package, LPCSTR szName, 
857                            LPSTR szValueBuf, DWORD* pchValueBuf)
858 {
859     MSIRECORD *row;
860     UINT rc;
861     LPWSTR szwName = NULL;
862
863     if (*pchValueBuf > 0)
864         szValueBuf[0] = 0;
865     
866     if( szName )
867     {
868         szwName = strdupAtoW( szName );
869         if (!szwName)
870             return ERROR_NOT_ENOUGH_MEMORY;
871     }
872
873     rc = MSI_GetPropertyRow(package, szwName, &row);
874     if (rc == ERROR_SUCCESS)
875     {
876         rc = MSI_RecordGetStringA(row,1,szValueBuf,pchValueBuf);
877         msiobj_release(&row->hdr);
878     }
879
880     if (rc == ERROR_SUCCESS)
881         TRACE("returning %s for property %s\n", debugstr_a(szValueBuf),
882             debugstr_a(szName));
883     else if (rc == ERROR_MORE_DATA)
884         TRACE("need %ld sized buffer for %s\n", *pchValueBuf,
885             debugstr_a(szName));
886     else
887     {
888         *pchValueBuf = 0;
889         TRACE("property not found\n");
890     }
891     msi_free( szwName );
892
893     return rc;
894 }
895
896 UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, DWORD* pchValueBuf) 
897 {
898     MSIPACKAGE *package;
899     UINT ret;
900
901     TRACE("%lu %s %p\n", hInstall, debugstr_a(szName), pchValueBuf);
902
903     if (0 == hInstall)
904         return ERROR_INVALID_HANDLE;
905     if (NULL == szName)
906         return ERROR_INVALID_PARAMETER;
907     if (NULL != szValueBuf && NULL == pchValueBuf)
908         return ERROR_INVALID_PARAMETER;
909
910     /* This was tested against native msi */
911     if (NULL == szValueBuf && NULL != pchValueBuf)
912         *pchValueBuf = 0;
913
914     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
915     if (!package)
916         return ERROR_INVALID_HANDLE;
917     ret = MSI_GetPropertyA(package, szName, szValueBuf, pchValueBuf );
918     msiobj_release( &package->hdr );
919
920     /* MsiGetProperty does not return error codes on missing properties */
921     if (ret != ERROR_MORE_DATA)
922         ret = ERROR_SUCCESS;
923
924     return ret;
925 }
926
927   
928 UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName, 
929                            LPWSTR szValueBuf, DWORD* pchValueBuf)
930 {
931     MSIPACKAGE *package;
932     UINT ret;
933
934     TRACE("%lu %s %p\n", hInstall, debugstr_w(szName), pchValueBuf);
935
936     if (0 == hInstall)
937         return ERROR_INVALID_HANDLE;
938     if (NULL == szName)
939         return ERROR_INVALID_PARAMETER;
940     if (NULL != szValueBuf && NULL == pchValueBuf)
941         return ERROR_INVALID_PARAMETER;
942
943     /* This was tested against native msi */
944     if (NULL == szValueBuf && NULL != pchValueBuf)
945         *pchValueBuf = 0;
946
947     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
948     if (!package)
949         return ERROR_INVALID_HANDLE;
950     ret = MSI_GetPropertyW(package, szName, szValueBuf, pchValueBuf );
951     msiobj_release( &package->hdr );
952
953     /* MsiGetProperty does not return error codes on missing properties */
954     if (ret != ERROR_MORE_DATA)
955         ret = ERROR_SUCCESS;
956
957     return ret;
958 }