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