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