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