Fixed gcc 4.0 warnings.
[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 UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
410 {
411     MSIDATABASE *db = NULL;
412     MSIPACKAGE *package;
413     MSIHANDLE handle;
414     DWORD size;
415     static const WCHAR szProductCode[]= {'P','r','o','d','u','c','t','C','o','d','e',0};
416
417     TRACE("%s %p\n", debugstr_w(szPackage), pPackage);
418
419     if( szPackage[0] == '#' )
420     {
421         handle = atoiW(&szPackage[1]);
422         db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
423         if( !db )
424             return ERROR_INVALID_HANDLE;
425     }
426     else
427     {
428         UINT r = MSI_OpenDatabaseW(szPackage, MSIDBOPEN_READONLY, &db);
429         if( r != ERROR_SUCCESS )
430             return r;
431     }
432
433     package = MSI_CreatePackage( db );
434     msiobj_release( &db->hdr );
435     if( !package )
436         return ERROR_FUNCTION_FAILED;
437
438     /* 
439      * FIXME:  I don't think this is right.  Maybe we should be storing the
440      * name of the database in the MSIDATABASE structure and fetching this
441      * info from there, or maybe this is only relevant to cached databases.
442      */
443     if( szPackage[0] != '#' )
444     {
445         static const WCHAR OriginalDatabase[] =
446           {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
447         static const WCHAR Database[] = {'D','A','T','A','B','A','S','E',0};
448
449         MSI_SetPropertyW( package, OriginalDatabase, szPackage );
450         MSI_SetPropertyW( package, Database, szPackage );
451     }
452
453     /* this property must exist */
454     size  = 0;
455     MSI_GetPropertyW(package,szProductCode,NULL,&size);
456     size ++;
457     package->ProductCode = HeapAlloc(GetProcessHeap(),0,size * sizeof(WCHAR));
458     MSI_GetPropertyW(package,szProductCode,package->ProductCode, &size);
459     
460     *pPackage = package;
461
462     return ERROR_SUCCESS;
463 }
464
465 UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
466 {
467     MSIPACKAGE *package = NULL;
468     UINT ret;
469     WCHAR path[MAX_PATH];
470     WCHAR filename[MAX_PATH];
471     static const WCHAR szMSI[] = {'M','S','I',0};
472
473     TRACE("%s %08lx %p\n",debugstr_w(szPackage), dwOptions, phPackage);
474
475     /* copy the msi file to a temp file to pervent locking a CD
476      * with a multi disc install 
477      */ 
478     if( szPackage[0] == '#' )
479         strcpyW(filename,szPackage);
480     else
481     {
482         GetTempPathW(MAX_PATH, path);
483         GetTempFileNameW(path, szMSI, 0, filename);
484
485         CopyFileW(szPackage, filename, FALSE);
486
487         TRACE("Opening relocated package %s\n",debugstr_w(filename));
488     }
489     
490     if( dwOptions )
491         FIXME("dwOptions %08lx not supported\n", dwOptions);
492
493     ret = MSI_OpenPackageW( filename, &package);
494     if( ret == ERROR_SUCCESS )
495     {
496         *phPackage = alloc_msihandle( &package->hdr );
497         msiobj_release( &package->hdr );
498     }
499
500     if( szPackage[0] != '#' )
501         DeleteFileW(filename);
502
503     return ret;
504 }
505
506 UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
507 {
508     return MsiOpenPackageExW( szPackage, 0, phPackage );
509 }
510
511 UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
512 {
513     LPWSTR szwPack = NULL;
514     UINT ret;
515
516     if( szPackage )
517     {
518         szwPack = strdupAtoW( szPackage );
519         if( !szwPack )
520             return ERROR_OUTOFMEMORY;
521     }
522
523     ret = MsiOpenPackageExW( szwPack, dwOptions, phPackage );
524
525     HeapFree( GetProcessHeap(), 0, szwPack );
526
527     return ret;
528 }
529
530 UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
531 {
532     return MsiOpenPackageExA( szPackage, 0, phPackage );
533 }
534
535 MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
536 {
537     MSIPACKAGE *package;
538     MSIHANDLE handle = 0;
539
540     TRACE("(%ld)\n",hInstall);
541
542     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
543     if( package)
544     {
545         handle = alloc_msihandle( &package->db->hdr );
546         msiobj_release( &package->hdr );
547     }
548
549     return handle;
550 }
551
552 INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
553                                MSIRECORD *record)
554 {
555     DWORD log_type = 0;
556     LPWSTR message;
557     DWORD sz;
558     DWORD total_size = 0;
559     INT msg_field=1;
560     INT i;
561     INT rc;
562     char *msg;
563     int len;
564
565     TRACE("%x \n",eMessageType);
566     rc = 0;
567
568     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR)
569         log_type |= INSTALLLOGMODE_ERROR;
570     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_WARNING)
571         log_type |= INSTALLLOGMODE_WARNING;
572     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_USER)
573         log_type |= INSTALLLOGMODE_USER;
574     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INFO)
575         log_type |= INSTALLLOGMODE_INFO;
576     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA)
577         log_type |= INSTALLLOGMODE_COMMONDATA;
578     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
579         log_type |= INSTALLLOGMODE_ACTIONSTART;
580     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONDATA)
581         log_type |= INSTALLLOGMODE_ACTIONDATA;
582     /* just a guess */
583     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS)
584         log_type |= 0x800;
585
586     message = HeapAlloc(GetProcessHeap(),0,1*sizeof (WCHAR));
587     message[0]=0;
588     msg_field = MSI_RecordGetFieldCount(record);
589     for (i = 1; i <= msg_field; i++)
590     {
591         LPWSTR tmp;
592         WCHAR number[3];
593         const static WCHAR format[] = { '%','i',':',' ',0};
594         const static WCHAR space[] = { ' ',0};
595         sz = 0;
596         MSI_RecordGetStringW(record,i,NULL,&sz);
597         sz+=4;
598         total_size+=sz*sizeof(WCHAR);
599         tmp = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
600         message = HeapReAlloc(GetProcessHeap(),0,message,total_size*sizeof (WCHAR));
601
602         MSI_RecordGetStringW(record,i,tmp,&sz);
603
604         if (msg_field > 1)
605         {
606             sprintfW(number,format,i);
607             strcatW(message,number);
608         }
609         strcatW(message,tmp);
610         if (msg_field > 1)
611             strcatW(message,space);
612
613         HeapFree(GetProcessHeap(),0,tmp);
614     }
615
616     TRACE("(%p %lx %lx %s)\n",gUIHandlerA, gUIFilter, log_type,
617                              debugstr_w(message));
618
619     /* convert it to ASCII */
620     len = WideCharToMultiByte( CP_ACP, 0, message, -1,
621                                NULL, 0, NULL, NULL );
622     msg = HeapAlloc( GetProcessHeap(), 0, len );
623     WideCharToMultiByte( CP_ACP, 0, message, -1,
624                          msg, len, NULL, NULL );
625
626     if (gUIHandlerA && (gUIFilter & log_type))
627     {
628         rc = gUIHandlerA(gUIContext,eMessageType,msg);
629     }
630
631     if ((!rc) && (gszLogFile[0]) && !((eMessageType & 0xff000000) ==
632                                       INSTALLMESSAGE_PROGRESS))
633     {
634         DWORD write;
635         HANDLE log_file = CreateFileW(gszLogFile,GENERIC_WRITE, 0, NULL,
636                                   OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
637
638         if (log_file != INVALID_HANDLE_VALUE)
639         {
640             SetFilePointer(log_file,0, NULL, FILE_END);
641             WriteFile(log_file,msg,strlen(msg),&write,NULL);
642             WriteFile(log_file,"\n",1,&write,NULL);
643             CloseHandle(log_file);
644         }
645     }
646     HeapFree( GetProcessHeap(), 0, msg );
647     
648     HeapFree(GetProcessHeap(),0,message);
649     return ERROR_SUCCESS;
650 }
651
652 INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
653                               MSIHANDLE hRecord)
654 {
655     UINT ret = ERROR_INVALID_HANDLE;
656     MSIPACKAGE *package = NULL;
657     MSIRECORD *record = NULL;
658
659     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
660     if( !package )
661         return ERROR_INVALID_HANDLE;
662
663     record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
664     if( !record )
665         goto out;
666
667     ret = MSI_ProcessMessage( package, eMessageType, record );
668
669 out:
670     msiobj_release( &package->hdr );
671     if( record )
672         msiobj_release( &record->hdr );
673
674     return ret;
675 }
676
677 /* property code */
678 UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue)
679 {
680     LPWSTR szwName = NULL, szwValue = NULL;
681     UINT hr = ERROR_INSTALL_FAILURE;
682
683     if( szName )
684     {
685         szwName = strdupAtoW( szName );
686         if( !szwName )
687             goto end;
688     }
689
690     if( szValue )
691     {
692         szwValue = strdupAtoW( szValue );
693         if( !szwValue)
694             goto end;
695     }
696
697     hr = MsiSetPropertyW( hInstall, szwName, szwValue);
698
699 end:
700     HeapFree( GetProcessHeap(), 0, szwName );
701     HeapFree( GetProcessHeap(), 0, szwValue );
702
703     return hr;
704 }
705
706 UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
707 {
708     MSIQUERY *view;
709     MSIRECORD *row;
710     UINT rc;
711     DWORD sz = 0;
712     static const WCHAR Insert[]=
713      {'I','N','S','E','R','T',' ','i','n','t','o',' ','`','_','P','r','o','p'
714 ,'e','r','t','y','`',' ','(','`','_','P','r','o','p','e','r','t','y','`'
715 ,',','`','V','a','l','u','e','`',')',' ','V','A','L','U','E','S'
716 ,' ','(','?',',','?',')',0};
717     static const WCHAR Update[]=
718      {'U','P','D','A','T','E',' ','_','P','r','o','p','e'
719 ,'r','t','y',' ','s','e','t',' ','`','V','a','l','u','e','`',' ','='
720 ,' ','?',' ','w','h','e','r','e',' ','`','_','P','r','o','p'
721 ,'e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
722     WCHAR Query[1024];
723
724     TRACE("Setting property (%s %s)\n",debugstr_w(szName),
725           debugstr_w(szValue));
726
727     rc = MSI_GetPropertyW(package,szName,0,&sz);
728     if (rc==ERROR_MORE_DATA || rc == ERROR_SUCCESS)
729     {
730         sprintfW(Query,Update,szName);
731
732         row = MSI_CreateRecord(1);
733         MSI_RecordSetStringW(row,1,szValue);
734
735     }
736     else
737     {
738         strcpyW(Query,Insert);
739
740         row = MSI_CreateRecord(2);
741         MSI_RecordSetStringW(row,1,szName);
742         MSI_RecordSetStringW(row,2,szValue);
743     }
744
745
746     rc = MSI_DatabaseOpenViewW(package->db,Query,&view);
747     if (rc!= ERROR_SUCCESS)
748     {
749         msiobj_release(&row->hdr);
750         return rc;
751     }
752
753     rc = MSI_ViewExecute(view,row);
754
755     msiobj_release(&row->hdr);
756     MSI_ViewClose(view);
757     msiobj_release(&view->hdr);
758
759     return rc;
760 }
761
762 UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
763 {
764     MSIPACKAGE *package;
765     UINT ret;
766
767     if (NULL == szName)
768         return ERROR_INVALID_PARAMETER;
769     if (NULL == szValue)
770         return ERROR_INVALID_PARAMETER;
771
772     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
773     if( !package )
774         return ERROR_INVALID_HANDLE;
775     ret = MSI_SetPropertyW( package, szName, szValue);
776     msiobj_release( &package->hdr );
777     return ret;
778 }
779
780 static UINT MSI_GetPropertyRow(MSIPACKAGE *package, LPCWSTR szName, MSIRECORD **row)
781 {
782     MSIQUERY *view;
783     UINT rc, sz;
784     static const WCHAR select[]=
785     {'S','E','L','E','C','T',' ','`','V','a','l','u','e','`',' ',
786      'F','R','O','M',' ' ,'`','_','P','r','o','p','e','r','t','y','`',
787      ' ','W','H','E','R','E',' ' ,'`','_','P','r','o','p','e','r','t','y','`',
788      '=','\'','%','s','\'',0};
789     LPWSTR query;
790
791     if (!szName)
792         return ERROR_INVALID_PARAMETER;
793
794     sz = sizeof select + strlenW(szName)*sizeof(WCHAR);
795     query = HeapAlloc(GetProcessHeap(), 0, sz);
796     sprintfW(query,select,szName);
797
798     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
799     HeapFree(GetProcessHeap(), 0, query);
800     if (rc == ERROR_SUCCESS)
801     {
802         rc = MSI_ViewExecute(view, 0);
803         if (rc == ERROR_SUCCESS)
804             rc = MSI_ViewFetch(view,row);
805
806         MSI_ViewClose(view);
807         msiobj_release(&view->hdr);
808     }
809
810     return rc;
811 }
812
813 UINT MSI_GetPropertyW(MSIPACKAGE *package, LPCWSTR szName, 
814                            LPWSTR szValueBuf, DWORD* pchValueBuf)
815 {
816     MSIRECORD *row;
817     UINT rc;
818
819     rc = MSI_GetPropertyRow(package, szName, &row);
820
821     if (*pchValueBuf > 0)
822         szValueBuf[0] = 0;
823
824     if (rc == ERROR_SUCCESS)
825     {
826         rc = MSI_RecordGetStringW(row,1,szValueBuf,pchValueBuf);
827         msiobj_release(&row->hdr);
828     }
829
830     if (rc == ERROR_SUCCESS)
831         TRACE("returning %s for property %s\n", debugstr_w(szValueBuf),
832             debugstr_w(szName));
833     else if (rc == ERROR_MORE_DATA)
834         TRACE("need %li sized buffer for %s\n", *pchValueBuf,
835             debugstr_w(szName));
836     else
837     {
838         *pchValueBuf = 0;
839         TRACE("property %s not found\n", debugstr_w(szName));
840     }
841
842     return rc;
843 }
844
845 UINT MSI_GetPropertyA(MSIPACKAGE *package, LPCSTR szName, 
846                            LPSTR szValueBuf, DWORD* pchValueBuf)
847 {
848     MSIRECORD *row;
849     UINT rc;
850     LPWSTR szwName = NULL;
851
852     if (*pchValueBuf > 0)
853         szValueBuf[0] = 0;
854     
855     if( szName )
856     {
857         szwName = strdupAtoW( szName );
858         if (!szwName)
859             return ERROR_NOT_ENOUGH_MEMORY;
860     }
861
862     rc = MSI_GetPropertyRow(package, szwName, &row);
863     if (rc == ERROR_SUCCESS)
864     {
865         rc = MSI_RecordGetStringA(row,1,szValueBuf,pchValueBuf);
866         msiobj_release(&row->hdr);
867     }
868
869     if (rc == ERROR_SUCCESS)
870         TRACE("returning %s for property %s\n", debugstr_a(szValueBuf),
871             debugstr_a(szName));
872     else if (rc == ERROR_MORE_DATA)
873         TRACE("need %ld sized buffer for %s\n", *pchValueBuf,
874             debugstr_a(szName));
875     else
876     {
877         *pchValueBuf = 0;
878         TRACE("property not found\n");
879     }
880     HeapFree( GetProcessHeap(), 0, szwName );
881
882     return rc;
883 }
884
885 UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, DWORD* pchValueBuf) 
886 {
887     MSIPACKAGE *package;
888     UINT ret;
889
890     TRACE("%lu %s %p\n", hInstall, debugstr_a(szName), pchValueBuf);
891
892     if (0 == hInstall)
893         return ERROR_INVALID_HANDLE;
894     if (NULL == szName)
895         return ERROR_INVALID_PARAMETER;
896     if (NULL != szValueBuf && NULL == pchValueBuf)
897         return ERROR_INVALID_PARAMETER;
898
899     /* This was tested against native msi */
900     if (NULL == szValueBuf && NULL != pchValueBuf)
901         *pchValueBuf = 0;
902
903     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
904     if (!package)
905         return ERROR_INVALID_HANDLE;
906     ret = MSI_GetPropertyA(package, szName, szValueBuf, pchValueBuf );
907     msiobj_release( &package->hdr );
908
909     /* MsiGetProperty does not return error codes on missing properties */
910     if (ret != ERROR_MORE_DATA)
911         ret = ERROR_SUCCESS;
912
913     return ret;
914 }
915
916   
917 UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName, 
918                            LPWSTR szValueBuf, DWORD* pchValueBuf)
919 {
920     MSIPACKAGE *package;
921     UINT ret;
922
923     TRACE("%lu %s %p\n", hInstall, debugstr_w(szName), pchValueBuf);
924
925     if (0 == hInstall)
926         return ERROR_INVALID_HANDLE;
927     if (NULL == szName)
928         return ERROR_INVALID_PARAMETER;
929     if (NULL != szValueBuf && NULL == pchValueBuf)
930         return ERROR_INVALID_PARAMETER;
931
932     /* This was tested against native msi */
933     if (NULL == szValueBuf && NULL != pchValueBuf)
934         *pchValueBuf = 0;
935
936     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
937     if (!package)
938         return ERROR_INVALID_HANDLE;
939     ret = MSI_GetPropertyW(package, szName, szValueBuf, pchValueBuf );
940     msiobj_release( &package->hdr );
941
942     /* MsiGetProperty does not return error codes on missing properties */
943     if (ret != ERROR_MORE_DATA)
944         ret = ERROR_SUCCESS;
945
946     return ret;
947 }