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