ntprint: Implement PSetupCreateMonitorInfo.
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define NONAMELESSUNION
22 #define NONAMELESSSTRUCT
23
24 #include <stdarg.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 "objidl.h"
35 #include "wincrypt.h"
36 #include "winuser.h"
37 #include "wininet.h"
38 #include "winver.h"
39 #include "urlmon.h"
40 #include "shlobj.h"
41 #include "wine/unicode.h"
42 #include "objbase.h"
43 #include "msidefs.h"
44 #include "sddl.h"
45
46 #include "msipriv.h"
47
48 WINE_DEFAULT_DEBUG_CHANNEL(msi);
49
50 static void MSI_FreePackage( MSIOBJECTHDR *arg)
51 {
52     MSIPACKAGE *package= (MSIPACKAGE*) arg;
53
54     if( package->dialog )
55         msi_dialog_destroy( package->dialog );
56
57     msiobj_release( &package->db->hdr );
58     ACTION_free_package_structures(package);
59 }
60
61 static UINT clone_properties(MSIPACKAGE *package)
62 {
63     MSIQUERY * view = NULL;
64     UINT rc;
65     static const WCHAR CreateSql[] = {
66        'C','R','E','A','T','E',' ','T','A','B','L','E',' ','`','_','P','r','o',
67        'p','e','r','t','y','`',' ','(',' ','`','_','P','r','o','p','e','r','t',
68        'y','`',' ','C','H','A','R','(','5','6',')',' ','N','O','T',' ','N','U',
69        'L','L',' ','T','E','M','P','O','R','A','R','Y',',',' ','`','V','a','l',
70        'u','e','`',' ','C','H','A','R','(','9','8',')',' ','N','O','T',' ','N',
71        'U','L','L',' ','T','E','M','P','O','R','A','R','Y',' ','P','R','I','M',
72        'A','R','Y',' ','K','E','Y',' ','`','_','P','r','o','p','e','r','t','y',
73         '`',')',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(package->db, CreateSql, &view);
86     if (rc != ERROR_SUCCESS)
87         return rc;
88
89     rc = MSI_ViewExecute(view, 0);
90     MSI_ViewClose(view);
91     msiobj_release(&view->hdr);
92     if (rc != ERROR_SUCCESS)
93         return rc;
94
95     /* clone the existing properties */
96     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
97     if (rc != ERROR_SUCCESS)
98         return rc;
99
100     rc = MSI_ViewExecute(view, 0);
101     if (rc != ERROR_SUCCESS)
102     {
103         MSI_ViewClose(view);
104         msiobj_release(&view->hdr);
105         return rc;
106     }
107
108     while (1)
109     {
110         MSIRECORD *row;
111         MSIQUERY *view2;
112
113         rc = MSI_ViewFetch(view, &row);
114         if (rc != ERROR_SUCCESS)
115             break;
116
117         rc = MSI_DatabaseOpenViewW(package->db, Insert, &view2);
118         if (rc!= ERROR_SUCCESS)
119             continue;
120
121         rc = MSI_ViewExecute(view2, row);
122         MSI_ViewClose(view2);
123         msiobj_release(&view2->hdr);
124
125         if (rc == ERROR_SUCCESS)
126             msiobj_release(&row->hdr);
127     }
128
129     MSI_ViewClose(view);
130     msiobj_release(&view->hdr);
131
132     return rc;
133 }
134
135 /*
136  * set_installed_prop
137  *
138  * Sets the "Installed" property to indicate that
139  *  the product is installed for the current user.
140  */
141 static UINT set_installed_prop( MSIPACKAGE *package )
142 {
143     static const WCHAR szInstalled[] = {
144         'I','n','s','t','a','l','l','e','d',0 };
145     WCHAR val[2] = { '1', 0 };
146     HKEY hkey = 0;
147     UINT r;
148
149     r = MSIREG_OpenUninstallKey( package->ProductCode, &hkey, FALSE );
150     if (r == ERROR_SUCCESS)
151     {
152         RegCloseKey( hkey );
153         MSI_SetPropertyW( package, szInstalled, val );
154     }
155
156     return r;
157 }
158
159 static UINT set_user_sid_prop( MSIPACKAGE *package )
160 {
161     SID_NAME_USE use;
162     LPWSTR user_name;
163     LPWSTR sid_str = NULL, dom = NULL;
164     DWORD size, dom_size;
165     PSID psid = NULL;
166     UINT r = ERROR_FUNCTION_FAILED;
167
168     static const WCHAR user_sid[] = {'U','s','e','r','S','I','D',0};
169
170     size = 0;
171     GetUserNameW( NULL, &size );
172
173     user_name = msi_alloc( (size + 1) * sizeof(WCHAR) );
174     if (!user_name)
175         return ERROR_OUTOFMEMORY;
176
177     if (!GetUserNameW( user_name, &size ))
178         goto done;
179
180     size = 0;
181     dom_size = 0;
182     LookupAccountNameW( NULL, user_name, NULL, &size, NULL, &dom_size, &use );
183
184     psid = msi_alloc( size );
185     dom = msi_alloc( dom_size*sizeof (WCHAR) );
186     if (!psid || !dom)
187     {
188         r = ERROR_OUTOFMEMORY;
189         goto done;
190     }
191
192     if (!LookupAccountNameW( NULL, user_name, psid, &size, dom, &dom_size, &use ))
193         goto done;
194
195     if (!ConvertSidToStringSidW( psid, &sid_str ))
196         goto done;
197
198     r = MSI_SetPropertyW( package, user_sid, sid_str );
199
200 done:
201     LocalFree( sid_str );
202     msi_free( dom );
203     msi_free( psid );
204     msi_free( user_name );
205
206     return r;
207 }
208
209 static LPWSTR get_fusion_filename(MSIPACKAGE *package)
210 {
211     HKEY netsetup;
212     LONG res;
213     LPWSTR file;
214     DWORD index = 0, size;
215     WCHAR ver[MAX_PATH];
216     WCHAR name[MAX_PATH];
217     WCHAR windir[MAX_PATH];
218
219     static const WCHAR backslash[] = {'\\',0};
220     static const WCHAR fusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
221     static const WCHAR sub[] = {
222         'S','o','f','t','w','a','r','e','\\',
223         'M','i','c','r','o','s','o','f','t','\\',
224         'N','E','T',' ','F','r','a','m','e','w','o','r','k',' ','S','e','t','u','p','\\',
225         'N','D','P',0
226     };
227     static const WCHAR subdir[] = {
228         'M','i','c','r','o','s','o','f','t','.','N','E','T','\\',
229         'F','r','a','m','e','w','o','r','k','\\',0
230     };
231
232     res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, sub, 0, KEY_ENUMERATE_SUB_KEYS, &netsetup);
233     if (res != ERROR_SUCCESS)
234         return NULL;
235
236     ver[0] = '\0';
237     size = MAX_PATH;
238     while (RegEnumKeyExW(netsetup, index, name, &size, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
239     {
240         index++;
241         if (lstrcmpW(ver, name) < 0)
242             lstrcpyW(ver, name);
243     }
244
245     RegCloseKey(netsetup);
246
247     if (!index)
248         return NULL;
249
250     GetWindowsDirectoryW(windir, MAX_PATH);
251
252     size = lstrlenW(windir) + lstrlenW(subdir) + lstrlenW(ver) +lstrlenW(fusion) + 3;
253     file = msi_alloc(size * sizeof(WCHAR));
254     if (!file)
255         return NULL;
256
257     lstrcpyW(file, windir);
258     lstrcatW(file, backslash);
259     lstrcatW(file, subdir);
260     lstrcatW(file, ver);
261     lstrcatW(file, backslash);
262     lstrcatW(file, fusion);
263
264     return file;
265 }
266
267 typedef struct tagLANGANDCODEPAGE
268 {
269   WORD wLanguage;
270   WORD wCodePage;
271 } LANGANDCODEPAGE;
272
273 static void set_msi_assembly_prop(MSIPACKAGE *package)
274 {
275     UINT val_len;
276     DWORD size, handle;
277     LPVOID version = NULL;
278     WCHAR buf[MAX_PATH];
279     LPWSTR fusion, verstr;
280     LANGANDCODEPAGE *translate;
281
282     static const WCHAR netasm[] = {
283         'M','s','i','N','e','t','A','s','s','e','m','b','l','y','S','u','p','p','o','r','t',0
284     };
285     static const WCHAR translation[] = {
286         '\\','V','a','r','F','i','l','e','I','n','f','o',
287         '\\','T','r','a','n','s','l','a','t','i','o','n',0
288     };
289     static const WCHAR verfmt[] = {
290         '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
291         '\\','%','0','4','x','%','0','4','x',
292         '\\','P','r','o','d','u','c','t','V','e','r','s','i','o','n',0
293     };
294
295     fusion = get_fusion_filename(package);
296     if (!fusion)
297         return;
298
299     size = GetFileVersionInfoSizeW(fusion, &handle);
300     if (!size) return;
301
302     version = msi_alloc(size);
303     if (!version) return;
304
305     if (!GetFileVersionInfoW(fusion, handle, size, version))
306         goto done;
307
308     if (!VerQueryValueW(version, translation, (LPVOID *)&translate, &val_len))
309         goto done;
310
311     sprintfW(buf, verfmt, translate[0].wLanguage, translate[0].wCodePage);
312
313     if (!VerQueryValueW(version, buf, (LPVOID *)&verstr, &val_len))
314         goto done;
315
316     if (!val_len || !verstr)
317         goto done;
318
319     MSI_SetPropertyW(package, netasm, verstr);
320
321 done:
322     msi_free(fusion);
323     msi_free(version);
324 }
325
326 /*
327  * There are a whole slew of these we need to set
328  *
329  *
330 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/properties.asp
331  */
332 static VOID set_installer_properties(MSIPACKAGE *package)
333 {
334     WCHAR pth[MAX_PATH];
335     WCHAR *ptr;
336     OSVERSIONINFOEXW OSVersion;
337     MEMORYSTATUSEX msex;
338     DWORD verval;
339     WCHAR verstr[10], bufstr[20];
340     HDC dc;
341     LPWSTR check;
342     HKEY hkey;
343     LONG res;
344     SYSTEM_INFO sys_info;
345     SYSTEMTIME systemtime;
346
347     static const WCHAR cszbs[]={'\\',0};
348     static const WCHAR CFF[] = 
349 {'C','o','m','m','o','n','F','i','l','e','s','F','o','l','d','e','r',0};
350     static const WCHAR PFF[] = 
351 {'P','r','o','g','r','a','m','F','i','l','e','s','F','o','l','d','e','r',0};
352     static const WCHAR CADF[] = 
353 {'C','o','m','m','o','n','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
354     static const WCHAR FaF[] = 
355 {'F','a','v','o','r','i','t','e','s','F','o','l','d','e','r',0};
356     static const WCHAR FoF[] = 
357 {'F','o','n','t','s','F','o','l','d','e','r',0};
358     static const WCHAR SendTF[] = 
359 {'S','e','n','d','T','o','F','o','l','d','e','r',0};
360     static const WCHAR SMF[] = 
361 {'S','t','a','r','t','M','e','n','u','F','o','l','d','e','r',0};
362     static const WCHAR StF[] = 
363 {'S','t','a','r','t','u','p','F','o','l','d','e','r',0};
364     static const WCHAR TemplF[] = 
365 {'T','e','m','p','l','a','t','e','F','o','l','d','e','r',0};
366     static const WCHAR DF[] = 
367 {'D','e','s','k','t','o','p','F','o','l','d','e','r',0};
368     static const WCHAR PMF[] = 
369 {'P','r','o','g','r','a','m','M','e','n','u','F','o','l','d','e','r',0};
370     static const WCHAR ATF[] = 
371 {'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0};
372     static const WCHAR ADF[] = 
373 {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
374     static const WCHAR SF[] = 
375 {'S','y','s','t','e','m','F','o','l','d','e','r',0};
376     static const WCHAR SF16[] = 
377 {'S','y','s','t','e','m','1','6','F','o','l','d','e','r',0};
378     static const WCHAR LADF[] = 
379 {'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
380     static const WCHAR MPF[] = 
381 {'M','y','P','i','c','t','u','r','e','s','F','o','l','d','e','r',0};
382     static const WCHAR PF[] = 
383 {'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0};
384     static const WCHAR WF[] = 
385 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
386     static const WCHAR WV[] = 
387 {'W','i','n','d','o','w','s','V','o','l','u','m','e',0};
388     static const WCHAR TF[]=
389 {'T','e','m','p','F','o','l','d','e','r',0};
390     static const WCHAR szAdminUser[] =
391 {'A','d','m','i','n','U','s','e','r',0};
392     static const WCHAR szPriv[] =
393 {'P','r','i','v','i','l','e','g','e','d',0};
394     static const WCHAR szOne[] =
395 {'1',0};
396     static const WCHAR v9x[] = { 'V','e','r','s','i','o','n','9','X',0 };
397     static const WCHAR vNT[] = { 'V','e','r','s','i','o','n','N','T',0 };
398     static const WCHAR szMsiNTProductType[] = { 'M','s','i','N','T','P','r','o','d','u','c','t','T','y','p','e',0 };
399     static const WCHAR szFormat[] = {'%','l','i',0};
400     static const WCHAR szWinBuild[] =
401 {'W','i','n','d','o','w','s','B','u','i','l','d', 0 };
402     static const WCHAR szSPL[] = 
403 {'S','e','r','v','i','c','e','P','a','c','k','L','e','v','e','l',0 };
404     static const WCHAR szSix[] = {'6',0 };
405
406     static const WCHAR szVersionMsi[] = { 'V','e','r','s','i','o','n','M','s','i',0 };
407     static const WCHAR szVersionDatabase[] = { 'V','e','r','s','i','o','n','D','a','t','a','b','a','s','e',0 };
408     static const WCHAR szPhysicalMemory[] = { 'P','h','y','s','i','c','a','l','M','e','m','o','r','y',0 };
409     static const WCHAR szFormat2[] = {'%','l','i','.','%','l','i',0};
410 /* Screen properties */
411     static const WCHAR szScreenX[] = {'S','c','r','e','e','n','X',0};
412     static const WCHAR szScreenY[] = {'S','c','r','e','e','n','Y',0};
413     static const WCHAR szColorBits[] = {'C','o','l','o','r','B','i','t','s',0};
414     static const WCHAR szScreenFormat[] = {'%','d',0};
415     static const WCHAR szIntel[] = { 'I','n','t','e','l',0 };
416     static const WCHAR szAllUsers[] = { 'A','L','L','U','S','E','R','S',0 };
417     static const WCHAR szCurrentVersion[] = {
418         'S','O','F','T','W','A','R','E','\\',
419         'M','i','c','r','o','s','o','f','t','\\',
420         'W','i','n','d','o','w','s',' ','N','T','\\',
421         'C','u','r','r','e','n','t','V','e','r','s','i','o','n',0
422     };
423     static const WCHAR szRegisteredUser[] = {'R','e','g','i','s','t','e','r','e','d','O','w','n','e','r',0};
424     static const WCHAR szRegisteredOrg[] = {
425         'R','e','g','i','s','t','e','r','e','d','O','r','g','a','n','i','z','a','t','i','o','n',0
426     };
427     static const WCHAR szUSERNAME[] = {'U','S','E','R','N','A','M','E',0};
428     static const WCHAR szCOMPANYNAME[] = {'C','O','M','P','A','N','Y','N','A','M','E',0};
429     static const WCHAR szDate[] = {'D','a','t','e',0};
430     static const WCHAR szTime[] = {'T','i','m','e',0};
431
432     /*
433      * Other things that probably should be set:
434      *
435      * SystemLanguageID ComputerName UserLanguageID LogonUser VirtualMemory
436      * ShellAdvSupport DefaultUIFont PackagecodeChanging
437      * ProductState CaptionHeight BorderTop BorderSide TextHeight
438      * RedirectedDllSupport
439      */
440
441     SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth);
442     strcatW(pth,cszbs);
443     MSI_SetPropertyW(package, CFF, pth);
444
445     SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES,NULL,0,pth);
446     strcatW(pth,cszbs);
447     MSI_SetPropertyW(package, PFF, pth);
448
449     SHGetFolderPathW(NULL,CSIDL_COMMON_APPDATA,NULL,0,pth);
450     strcatW(pth,cszbs);
451     MSI_SetPropertyW(package, CADF, pth);
452
453     SHGetFolderPathW(NULL,CSIDL_FAVORITES,NULL,0,pth);
454     strcatW(pth,cszbs);
455     MSI_SetPropertyW(package, FaF, pth);
456
457     SHGetFolderPathW(NULL,CSIDL_FONTS,NULL,0,pth);
458     strcatW(pth,cszbs);
459     MSI_SetPropertyW(package, FoF, pth);
460
461     SHGetFolderPathW(NULL,CSIDL_SENDTO,NULL,0,pth);
462     strcatW(pth,cszbs);
463     MSI_SetPropertyW(package, SendTF, pth);
464
465     SHGetFolderPathW(NULL,CSIDL_STARTMENU,NULL,0,pth);
466     strcatW(pth,cszbs);
467     MSI_SetPropertyW(package, SMF, pth);
468
469     SHGetFolderPathW(NULL,CSIDL_STARTUP,NULL,0,pth);
470     strcatW(pth,cszbs);
471     MSI_SetPropertyW(package, StF, pth);
472
473     SHGetFolderPathW(NULL,CSIDL_TEMPLATES,NULL,0,pth);
474     strcatW(pth,cszbs);
475     MSI_SetPropertyW(package, TemplF, pth);
476
477     SHGetFolderPathW(NULL,CSIDL_DESKTOP,NULL,0,pth);
478     strcatW(pth,cszbs);
479     MSI_SetPropertyW(package, DF, pth);
480
481     SHGetFolderPathW(NULL,CSIDL_PROGRAMS,NULL,0,pth);
482     strcatW(pth,cszbs);
483     MSI_SetPropertyW(package, PMF, pth);
484
485     SHGetFolderPathW(NULL,CSIDL_ADMINTOOLS,NULL,0,pth);
486     strcatW(pth,cszbs);
487     MSI_SetPropertyW(package, ATF, pth);
488
489     SHGetFolderPathW(NULL,CSIDL_APPDATA,NULL,0,pth);
490     strcatW(pth,cszbs);
491     MSI_SetPropertyW(package, ADF, pth);
492
493     SHGetFolderPathW(NULL,CSIDL_SYSTEM,NULL,0,pth);
494     strcatW(pth,cszbs);
495     MSI_SetPropertyW(package, SF, pth);
496     MSI_SetPropertyW(package, SF16, pth);
497
498     SHGetFolderPathW(NULL,CSIDL_LOCAL_APPDATA,NULL,0,pth);
499     strcatW(pth,cszbs);
500     MSI_SetPropertyW(package, LADF, pth);
501
502     SHGetFolderPathW(NULL,CSIDL_MYPICTURES,NULL,0,pth);
503     strcatW(pth,cszbs);
504     MSI_SetPropertyW(package, MPF, pth);
505
506     SHGetFolderPathW(NULL,CSIDL_PERSONAL,NULL,0,pth);
507     strcatW(pth,cszbs);
508     MSI_SetPropertyW(package, PF, pth);
509
510     SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
511     strcatW(pth,cszbs);
512     MSI_SetPropertyW(package, WF, pth);
513     
514     /* Physical Memory is specified in MB. Using total amount. */
515     msex.dwLength = sizeof(msex);
516     GlobalMemoryStatusEx( &msex );
517     sprintfW( bufstr, szScreenFormat, (int)(msex.ullTotalPhys/1024/1024));
518     MSI_SetPropertyW(package, szPhysicalMemory, bufstr);
519
520     SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
521     ptr = strchrW(pth,'\\');
522     if (ptr)
523         *(ptr+1) = 0;
524     MSI_SetPropertyW(package, WV, pth);
525     
526     GetTempPathW(MAX_PATH,pth);
527     MSI_SetPropertyW(package, TF, pth);
528
529
530     /* in a wine environment the user is always admin and privileged */
531     MSI_SetPropertyW(package,szAdminUser,szOne);
532     MSI_SetPropertyW(package,szPriv,szOne);
533     MSI_SetPropertyW(package, szAllUsers, szOne);
534
535     /* set the os things */
536     OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
537     GetVersionExW((OSVERSIONINFOW *)&OSVersion);
538     verval = OSVersion.dwMinorVersion+OSVersion.dwMajorVersion*100;
539     sprintfW(verstr,szFormat,verval);
540     switch (OSVersion.dwPlatformId)
541     {
542         case VER_PLATFORM_WIN32_WINDOWS:    
543             MSI_SetPropertyW(package,v9x,verstr);
544             break;
545         case VER_PLATFORM_WIN32_NT:
546             MSI_SetPropertyW(package,vNT,verstr);
547             sprintfW(verstr,szFormat,OSVersion.wProductType);
548             MSI_SetPropertyW(package,szMsiNTProductType,verstr);
549             break;
550     }
551     sprintfW(verstr,szFormat,OSVersion.dwBuildNumber);
552     MSI_SetPropertyW(package,szWinBuild,verstr);
553     /* just fudge this */
554     MSI_SetPropertyW(package,szSPL,szSix);
555
556     sprintfW( bufstr, szFormat2, MSI_MAJORVERSION, MSI_MINORVERSION);
557     MSI_SetPropertyW( package, szVersionMsi, bufstr );
558     sprintfW( bufstr, szFormat, MSI_MAJORVERSION * 100);
559     MSI_SetPropertyW( package, szVersionDatabase, bufstr );
560
561     GetSystemInfo( &sys_info );
562     if (sys_info.u.s.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
563     {
564         sprintfW( bufstr, szScreenFormat, sys_info.wProcessorLevel );
565         MSI_SetPropertyW( package, szIntel, bufstr );
566     }
567
568     /* Screen properties. */
569     dc = GetDC(0);
570     sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, HORZRES ) );
571     MSI_SetPropertyW( package, szScreenX, bufstr );
572     sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, VERTRES ));
573     MSI_SetPropertyW( package, szScreenY, bufstr );
574     sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, BITSPIXEL ));
575     MSI_SetPropertyW( package, szColorBits, bufstr );
576     ReleaseDC(0, dc);
577
578     /* USERNAME and COMPANYNAME */
579     res = RegOpenKeyW( HKEY_LOCAL_MACHINE, szCurrentVersion, &hkey );
580     if (res != ERROR_SUCCESS)
581         return;
582
583     check = msi_dup_property( package, szUSERNAME );
584     if (!check)
585     {
586         LPWSTR user = msi_reg_get_val_str( hkey, szRegisteredUser );
587         MSI_SetPropertyW( package, szUSERNAME, user );
588         msi_free( user );
589     }
590
591     msi_free( check );
592
593     check = msi_dup_property( package, szCOMPANYNAME );
594     if (!check)
595     {
596         LPWSTR company = msi_reg_get_val_str( hkey, szRegisteredOrg );
597         MSI_SetPropertyW( package, szCOMPANYNAME, company );
598         msi_free( company );
599     }
600
601     if ( set_user_sid_prop( package ) != ERROR_SUCCESS)
602         ERR("Failed to set the UserSID property\n");
603
604     /* Date and time properties */
605     GetSystemTime( &systemtime );
606     if (GetDateFormatW( LOCALE_USER_DEFAULT, DATE_SHORTDATE, &systemtime,
607                         NULL, bufstr, sizeof(bufstr)/sizeof(bufstr[0]) ))
608         MSI_SetPropertyW( package, szDate, bufstr );
609     else
610         ERR("Couldn't set Date property: GetDateFormat failed with error %d\n", GetLastError());
611
612     if (GetTimeFormatW( LOCALE_USER_DEFAULT,
613                         TIME_FORCE24HOURFORMAT | TIME_NOTIMEMARKER,
614                         &systemtime, NULL, bufstr,
615                         sizeof(bufstr)/sizeof(bufstr[0]) ))
616         MSI_SetPropertyW( package, szTime, bufstr );
617     else
618         ERR("Couldn't set Time property: GetTimeFormat failed with error %d\n", GetLastError());
619
620     set_msi_assembly_prop( package );
621
622     msi_free( check );
623     CloseHandle( hkey );
624 }
625
626 static UINT msi_load_summary_properties( MSIPACKAGE *package )
627 {
628     UINT rc;
629     MSIHANDLE suminfo;
630     MSIHANDLE hdb = alloc_msihandle( &package->db->hdr );
631     INT word_count;
632     DWORD len;
633     LPWSTR package_code;
634     static const WCHAR szPackageCode[] = {
635         'P','a','c','k','a','g','e','C','o','d','e',0};
636
637     if (!hdb) {
638         ERR("Unable to allocate handle\n");
639         return 0;
640     }
641     rc = MsiGetSummaryInformationW( hdb, NULL, 0, &suminfo );
642     MsiCloseHandle(hdb);
643     if (rc != ERROR_SUCCESS)
644     {
645         ERR("Unable to open Summary Information\n");
646         return rc;
647     }
648
649     /* load package attributes */
650     rc = MsiSummaryInfoGetPropertyW( suminfo, PID_WORDCOUNT, NULL,
651                                      &word_count, NULL, NULL, NULL );
652     if (rc == ERROR_SUCCESS)
653         package->WordCount = word_count;
654     else
655         WARN("Unable to query word count\n");
656
657     /* load package code property */
658     len = 0;
659     rc = MsiSummaryInfoGetPropertyW( suminfo, PID_REVNUMBER, NULL,
660                                      NULL, NULL, NULL, &len );
661     if (rc == ERROR_MORE_DATA)
662     {
663         len++;
664         package_code = msi_alloc( len * sizeof(WCHAR) );
665         rc = MsiSummaryInfoGetPropertyW( suminfo, PID_REVNUMBER, NULL,
666                                          NULL, NULL, package_code, &len );
667         if (rc == ERROR_SUCCESS)
668             MSI_SetPropertyW( package, szPackageCode, package_code );
669         else
670             WARN("Unable to query rev number, %d\n", rc);
671         msi_free( package_code );
672     }
673     else
674         WARN("Unable to query rev number, %d\n", rc);
675
676     MsiCloseHandle(suminfo);
677     return ERROR_SUCCESS;
678 }
679
680 static MSIPACKAGE *msi_alloc_package( void )
681 {
682     MSIPACKAGE *package;
683
684     package = alloc_msiobject( MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE),
685                                MSI_FreePackage );
686     if( package )
687     {
688         list_init( &package->components );
689         list_init( &package->features );
690         list_init( &package->files );
691         list_init( &package->tempfiles );
692         list_init( &package->folders );
693         list_init( &package->subscriptions );
694         list_init( &package->appids );
695         list_init( &package->classes );
696         list_init( &package->mimes );
697         list_init( &package->extensions );
698         list_init( &package->progids );
699         list_init( &package->RunningActions );
700
701         package->ActionFormat = NULL;
702         package->LastAction = NULL;
703         package->dialog = NULL;
704         package->next_dialog = NULL;
705     }
706
707     return package;
708 }
709
710 MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPCWSTR base_url )
711 {
712     static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 };
713     static const WCHAR szpi[] = {'%','i',0};
714     static const WCHAR szProductCode[] = {
715         'P','r','o','d','u','c','t','C','o','d','e',0};
716     MSIPACKAGE *package;
717     WCHAR uilevel[10];
718
719     TRACE("%p\n", db);
720
721     package = msi_alloc_package();
722     if (package)
723     {
724         msiobj_addref( &db->hdr );
725         package->db = db;
726
727         package->WordCount = 0;
728         package->PackagePath = strdupW( db->path );
729         package->BaseURL = strdupW( base_url );
730
731         clone_properties( package );
732         set_installer_properties(package);
733         sprintfW(uilevel,szpi,gUILevel);
734         MSI_SetPropertyW(package, szLevel, uilevel);
735
736         package->ProductCode = msi_dup_property( package, szProductCode );
737         set_installed_prop( package );
738         msi_load_summary_properties( package );
739     }
740
741     return package;
742 }
743
744 /*
745  * copy_package_to_temp   [internal]
746  *
747  * copy the msi file to a temp file to prevent locking a CD
748  * with a multi disc install 
749  *
750  * FIXME: I think this is wrong, and instead of copying the package,
751  *        we should read all the tables to memory, then open the
752  *        database to read binary streams on demand.
753  */ 
754 static LPCWSTR copy_package_to_temp( LPCWSTR szPackage, LPWSTR filename )
755 {
756     WCHAR path[MAX_PATH];
757     static const WCHAR szMSI[] = {'m','s','i',0};
758
759     GetTempPathW( MAX_PATH, path );
760     GetTempFileNameW( path, szMSI, 0, filename );
761
762     if( !CopyFileW( szPackage, filename, FALSE ) )
763     {
764         DeleteFileW( filename );
765         ERR("failed to copy package %s\n", debugstr_w(szPackage) );
766         return szPackage;
767     }
768
769     TRACE("Opening relocated package %s\n", debugstr_w( filename ));
770     return filename;
771 }
772
773 LPCWSTR msi_download_file( LPCWSTR szUrl, LPWSTR filename )
774 {
775     LPINTERNET_CACHE_ENTRY_INFOW cache_entry;
776     DWORD size = 0;
777     HRESULT hr;
778
779     /* call will always fail, becase size is 0,
780      * but will return ERROR_FILE_NOT_FOUND first
781      * if the file doesn't exist
782      */
783     GetUrlCacheEntryInfoW( szUrl, NULL, &size );
784     if ( GetLastError() != ERROR_FILE_NOT_FOUND )
785     {
786         cache_entry = HeapAlloc( GetProcessHeap(), 0, size );
787         if ( !GetUrlCacheEntryInfoW( szUrl, cache_entry, &size ) )
788         {
789             HeapFree( GetProcessHeap(), 0, cache_entry );
790             return szUrl;
791         }
792
793         lstrcpyW( filename, cache_entry->lpszLocalFileName );
794         HeapFree( GetProcessHeap(), 0, cache_entry );
795         return filename;
796     }
797
798     hr = URLDownloadToCacheFileW( NULL, szUrl, filename, MAX_PATH, 0, NULL );
799     if ( FAILED(hr) )
800         return szUrl;
801
802     return filename;
803 }
804
805 UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
806 {
807     static const WCHAR OriginalDatabase[] =
808         {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
809     static const WCHAR Database[] = {'D','A','T','A','B','A','S','E',0};
810     MSIDATABASE *db = NULL;
811     MSIPACKAGE *package;
812     MSIHANDLE handle;
813     LPWSTR ptr, base_url = NULL;
814     UINT r;
815     WCHAR temppath[MAX_PATH];
816     LPCWSTR file = szPackage;
817
818     TRACE("%s %p\n", debugstr_w(szPackage), pPackage);
819
820     if( szPackage[0] == '#' )
821     {
822         handle = atoiW(&szPackage[1]);
823         db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
824         if( !db )
825             return ERROR_INVALID_HANDLE;
826     }
827     else
828     {
829         if ( UrlIsW( szPackage, URLIS_URL ) )
830         {
831             file = msi_download_file( szPackage, temppath );
832
833             base_url = strdupW( szPackage );
834             if ( !base_url )
835                 return ERROR_OUTOFMEMORY;
836
837             ptr = strrchrW( base_url, '/' );
838             if (ptr) *(ptr + 1) = '\0';
839         }
840         else
841             file = copy_package_to_temp( szPackage, temppath );
842
843         r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &db );
844         if( r != ERROR_SUCCESS )
845         {
846             if (GetLastError() == ERROR_FILE_NOT_FOUND)
847                 msi_ui_error( 4, MB_OK | MB_ICONWARNING );
848             if (file != szPackage)
849                 DeleteFileW( file );
850
851             return r;
852         }
853     }
854
855     package = MSI_CreatePackage( db, base_url );
856     msi_free( base_url );
857     msiobj_release( &db->hdr );
858     if( !package )
859     {
860         if (file != szPackage)
861             DeleteFileW( file );
862         return ERROR_FUNCTION_FAILED;
863     }
864
865     if( file != szPackage )
866         track_tempfile( package, file );
867
868     if( szPackage[0] != '#' )
869     {
870         MSI_SetPropertyW( package, OriginalDatabase, szPackage );
871         MSI_SetPropertyW( package, Database, szPackage );
872     }
873     else
874     {
875         MSI_SetPropertyW( package, OriginalDatabase, db->path );
876         MSI_SetPropertyW( package, Database, db->path );
877     }
878
879     *pPackage = package;
880
881     return ERROR_SUCCESS;
882 }
883
884 UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
885 {
886     MSIPACKAGE *package = NULL;
887     UINT ret;
888
889     TRACE("%s %08x %p\n", debugstr_w(szPackage), dwOptions, phPackage );
890
891     if( szPackage == NULL )
892         return ERROR_INVALID_PARAMETER;
893
894     if( dwOptions )
895         FIXME("dwOptions %08x not supported\n", dwOptions);
896
897     ret = MSI_OpenPackageW( szPackage, &package );
898     if( ret == ERROR_SUCCESS )
899     {
900         *phPackage = alloc_msihandle( &package->hdr );
901         if (! *phPackage)
902             ret = ERROR_NOT_ENOUGH_MEMORY;
903         msiobj_release( &package->hdr );
904     }
905
906     return ret;
907 }
908
909 UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
910 {
911     return MsiOpenPackageExW( szPackage, 0, phPackage );
912 }
913
914 UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
915 {
916     LPWSTR szwPack = NULL;
917     UINT ret;
918
919     if( szPackage )
920     {
921         szwPack = strdupAtoW( szPackage );
922         if( !szwPack )
923             return ERROR_OUTOFMEMORY;
924     }
925
926     ret = MsiOpenPackageExW( szwPack, dwOptions, phPackage );
927
928     msi_free( szwPack );
929
930     return ret;
931 }
932
933 UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
934 {
935     return MsiOpenPackageExA( szPackage, 0, phPackage );
936 }
937
938 MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
939 {
940     MSIPACKAGE *package;
941     MSIHANDLE handle = 0;
942
943     TRACE("(%ld)\n",hInstall);
944
945     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
946     if( package)
947     {
948         handle = alloc_msihandle( &package->db->hdr );
949         msiobj_release( &package->hdr );
950     }
951
952     return handle;
953 }
954
955 INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
956                                MSIRECORD *record)
957 {
958     static const WCHAR szActionData[] =
959         {'A','c','t','i','o','n','D','a','t','a',0};
960     static const WCHAR szSetProgress[] =
961         {'S','e','t','P','r','o','g','r','e','s','s',0};
962     static const WCHAR szActionText[] =
963         {'A','c','t','i','o','n','T','e','x','t',0};
964     DWORD log_type = 0;
965     LPWSTR message;
966     DWORD sz;
967     DWORD total_size = 0;
968     INT i;
969     INT rc;
970     char *msg;
971     int len;
972
973     TRACE("%x\n", eMessageType);
974     rc = 0;
975
976     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR)
977         log_type |= INSTALLLOGMODE_ERROR;
978     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_WARNING)
979         log_type |= INSTALLLOGMODE_WARNING;
980     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_USER)
981         log_type |= INSTALLLOGMODE_USER;
982     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INFO)
983         log_type |= INSTALLLOGMODE_INFO;
984     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA)
985         log_type |= INSTALLLOGMODE_COMMONDATA;
986     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
987         log_type |= INSTALLLOGMODE_ACTIONSTART;
988     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONDATA)
989         log_type |= INSTALLLOGMODE_ACTIONDATA;
990     /* just a guess */
991     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS)
992         log_type |= 0x800;
993
994     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
995     {
996         static const WCHAR template_s[]=
997             {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ',0};
998         static const WCHAR format[] = 
999             {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
1000         WCHAR timet[0x100];
1001         LPCWSTR action_text, action;
1002         LPWSTR deformatted = NULL;
1003
1004         GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
1005
1006         action = MSI_RecordGetString(record, 1);
1007         action_text = MSI_RecordGetString(record, 2);
1008
1009         if (!action || !action_text)
1010             return IDOK;
1011
1012         deformat_string(package, action_text, &deformatted);
1013
1014         len = strlenW(timet) + strlenW(action) + strlenW(template_s);
1015         if (deformatted)
1016             len += strlenW(deformatted);
1017         message = msi_alloc(len*sizeof(WCHAR));
1018         sprintfW(message, template_s, timet, action);
1019         if (deformatted)
1020             strcatW(message, deformatted);
1021         msi_free(deformatted);
1022     }
1023     else
1024     {
1025         INT msg_field=1;
1026         message = msi_alloc(1*sizeof (WCHAR));
1027         message[0]=0;
1028         msg_field = MSI_RecordGetFieldCount(record);
1029         for (i = 1; i <= msg_field; i++)
1030         {
1031             LPWSTR tmp;
1032             WCHAR number[3];
1033             static const WCHAR format[] = { '%','i',':',' ',0};
1034             static const WCHAR space[] = { ' ',0};
1035             sz = 0;
1036             MSI_RecordGetStringW(record,i,NULL,&sz);
1037             sz+=4;
1038             total_size+=sz*sizeof(WCHAR);
1039             tmp = msi_alloc(sz*sizeof(WCHAR));
1040             message = msi_realloc(message,total_size*sizeof (WCHAR));
1041
1042             MSI_RecordGetStringW(record,i,tmp,&sz);
1043
1044             if (msg_field > 1)
1045             {
1046                 sprintfW(number,format,i);
1047                 strcatW(message,number);
1048             }
1049             strcatW(message,tmp);
1050             if (msg_field > 1)
1051                 strcatW(message,space);
1052
1053             msi_free(tmp);
1054         }
1055     }
1056
1057     TRACE("(%p %x %x %s)\n", gUIHandlerA, gUIFilter, log_type,
1058                              debugstr_w(message));
1059
1060     /* convert it to ASCII */
1061     len = WideCharToMultiByte( CP_ACP, 0, message, -1,
1062                                NULL, 0, NULL, NULL );
1063     msg = msi_alloc( len );
1064     WideCharToMultiByte( CP_ACP, 0, message, -1,
1065                          msg, len, NULL, NULL );
1066
1067     if (gUIHandlerA && (gUIFilter & log_type))
1068     {
1069         rc = gUIHandlerA(gUIContext,eMessageType,msg);
1070     }
1071
1072     if ((!rc) && (gszLogFile[0]) && !((eMessageType & 0xff000000) ==
1073                                       INSTALLMESSAGE_PROGRESS))
1074     {
1075         DWORD write;
1076         HANDLE log_file = CreateFileW(gszLogFile,GENERIC_WRITE, 0, NULL,
1077                                   OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1078
1079         if (log_file != INVALID_HANDLE_VALUE)
1080         {
1081             SetFilePointer(log_file,0, NULL, FILE_END);
1082             WriteFile(log_file,msg,strlen(msg),&write,NULL);
1083             WriteFile(log_file,"\n",1,&write,NULL);
1084             CloseHandle(log_file);
1085         }
1086     }
1087     msi_free( msg );
1088
1089     msi_free( message);
1090
1091     switch (eMessageType & 0xff000000)
1092     {
1093     case INSTALLMESSAGE_ACTIONDATA:
1094         /* FIXME: format record here instead of in ui_actiondata to get the
1095          * correct action data for external scripts */
1096         ControlEvent_FireSubscribedEvent(package, szActionData, record);
1097         break;
1098     case INSTALLMESSAGE_ACTIONSTART:
1099     {
1100         MSIRECORD *uirow;
1101         LPWSTR deformated;
1102         LPCWSTR action_text = MSI_RecordGetString(record, 2);
1103
1104         deformat_string(package, action_text, &deformated);
1105         uirow = MSI_CreateRecord(1);
1106         MSI_RecordSetStringW(uirow, 1, deformated);
1107         TRACE("INSTALLMESSAGE_ACTIONSTART: %s\n", debugstr_w(deformated));
1108         msi_free(deformated);
1109
1110         ControlEvent_FireSubscribedEvent(package, szActionText, uirow);
1111
1112         msiobj_release(&uirow->hdr);
1113         break;
1114     }
1115     case INSTALLMESSAGE_PROGRESS:
1116         ControlEvent_FireSubscribedEvent(package, szSetProgress, record);
1117         break;
1118     }
1119
1120     return ERROR_SUCCESS;
1121 }
1122
1123 INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
1124                               MSIHANDLE hRecord)
1125 {
1126     UINT ret = ERROR_INVALID_HANDLE;
1127     MSIPACKAGE *package = NULL;
1128     MSIRECORD *record = NULL;
1129
1130     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
1131     if( !package )
1132         return ERROR_INVALID_HANDLE;
1133
1134     record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
1135     if( !record )
1136         goto out;
1137
1138     ret = MSI_ProcessMessage( package, eMessageType, record );
1139
1140 out:
1141     msiobj_release( &package->hdr );
1142     if( record )
1143         msiobj_release( &record->hdr );
1144
1145     return ret;
1146 }
1147
1148 /* property code */
1149
1150 UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue )
1151 {
1152     LPWSTR szwName = NULL, szwValue = NULL;
1153     UINT r = ERROR_OUTOFMEMORY;
1154
1155     szwName = strdupAtoW( szName );
1156     if( szName && !szwName )
1157         goto end;
1158
1159     szwValue = strdupAtoW( szValue );
1160     if( szValue && !szwValue )
1161         goto end;
1162
1163     r = MsiSetPropertyW( hInstall, szwName, szwValue);
1164
1165 end:
1166     msi_free( szwName );
1167     msi_free( szwValue );
1168
1169     return r;
1170 }
1171
1172 UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
1173 {
1174     MSIQUERY *view;
1175     MSIRECORD *row = NULL;
1176     UINT rc;
1177     DWORD sz = 0;
1178     WCHAR Query[1024];
1179
1180     static const WCHAR Insert[] = {
1181         'I','N','S','E','R','T',' ','i','n','t','o',' ',
1182         '`','_','P','r','o','p','e','r','t','y','`',' ','(',
1183         '`','_','P','r','o','p','e','r','t','y','`',',',
1184         '`','V','a','l','u','e','`',')',' ','V','A','L','U','E','S'
1185         ,' ','(','?',',','?',')',0};
1186     static const WCHAR Update[] = {
1187         'U','P','D','A','T','E',' ','`','_','P','r','o','p','e','r','t','y','`',
1188         ' ','s','e','t',' ','`','V','a','l','u','e','`',' ','=',' ','?',' ',
1189         'w','h','e','r','e',' ','`','_','P','r','o','p','e','r','t','y','`',
1190         ' ','=',' ','\'','%','s','\'',0};
1191     static const WCHAR Delete[] = {
1192         'D','E','L','E','T','E',' ','F','R','O','M',' ',
1193         '`','_','P','r','o','p','e','r','t','y','`',' ','W','H','E','R','E',' ',
1194         '`','_','P','r','o','p','e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
1195
1196     TRACE("%p %s %s\n", package, debugstr_w(szName), debugstr_w(szValue));
1197
1198     if (!szName)
1199         return ERROR_INVALID_PARAMETER;
1200
1201     /* this one is weird... */
1202     if (!szName[0])
1203         return szValue ? ERROR_FUNCTION_FAILED : ERROR_SUCCESS;
1204
1205     rc = MSI_GetPropertyW(package, szName, 0, &sz);
1206     if (!szValue || !*szValue)
1207     {
1208         sprintfW(Query, Delete, szName);
1209     }
1210     else if (rc == ERROR_MORE_DATA || rc == ERROR_SUCCESS)
1211     {
1212         sprintfW(Query, Update, szName);
1213
1214         row = MSI_CreateRecord(1);
1215         MSI_RecordSetStringW(row, 1, szValue);
1216     }
1217     else
1218     {
1219         strcpyW(Query, Insert);
1220
1221         row = MSI_CreateRecord(2);
1222         MSI_RecordSetStringW(row, 1, szName);
1223         MSI_RecordSetStringW(row, 2, szValue);
1224     }
1225
1226     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1227     if (rc == ERROR_SUCCESS)
1228     {
1229         rc = MSI_ViewExecute(view, row);
1230         MSI_ViewClose(view);
1231         msiobj_release(&view->hdr);
1232     }
1233
1234     msiobj_release(&row->hdr);
1235
1236     return rc;
1237 }
1238
1239 UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
1240 {
1241     MSIPACKAGE *package;
1242     UINT ret;
1243
1244     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
1245     if( !package )
1246         return ERROR_INVALID_HANDLE;
1247     ret = MSI_SetPropertyW( package, szName, szValue);
1248     msiobj_release( &package->hdr );
1249     return ret;
1250 }
1251
1252 static MSIRECORD *MSI_GetPropertyRow( MSIPACKAGE *package, LPCWSTR name )
1253 {
1254     static const WCHAR query[]= {
1255         'S','E','L','E','C','T',' ','`','V','a','l','u','e','`',' ',
1256         'F','R','O','M',' ' ,'`','_','P','r','o','p','e','r','t','y','`',
1257         ' ','W','H','E','R','E',' ' ,'`','_','P','r','o','p','e','r','t','y','`',
1258         '=','\'','%','s','\'',0};
1259
1260     if (!name || !*name)
1261         return NULL;
1262
1263     return MSI_QueryGetRecord( package->db, query, name );
1264 }
1265
1266 /* internal function, not compatible with MsiGetPropertyW */
1267 UINT MSI_GetPropertyW( MSIPACKAGE *package, LPCWSTR szName, 
1268                        LPWSTR szValueBuf, DWORD* pchValueBuf )
1269 {
1270     MSIRECORD *row;
1271     UINT rc = ERROR_FUNCTION_FAILED;
1272
1273     row = MSI_GetPropertyRow( package, szName );
1274
1275     if (*pchValueBuf > 0)
1276         szValueBuf[0] = 0;
1277
1278     if (row)
1279     {
1280         rc = MSI_RecordGetStringW(row, 1, szValueBuf, pchValueBuf);
1281         msiobj_release(&row->hdr);
1282     }
1283
1284     if (rc == ERROR_SUCCESS)
1285         TRACE("returning %s for property %s\n", debugstr_w(szValueBuf),
1286             debugstr_w(szName));
1287     else if (rc == ERROR_MORE_DATA)
1288         TRACE("need %d sized buffer for %s\n", *pchValueBuf,
1289             debugstr_w(szName));
1290     else
1291     {
1292         *pchValueBuf = 0;
1293         TRACE("property %s not found\n", debugstr_w(szName));
1294     }
1295
1296     return rc;
1297 }
1298
1299 LPWSTR msi_dup_property(MSIPACKAGE *package, LPCWSTR prop)
1300 {
1301     DWORD sz = 0;
1302     LPWSTR str;
1303     UINT r;
1304
1305     r = MSI_GetPropertyW(package, prop, NULL, &sz);
1306     if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
1307         return NULL;
1308
1309     sz++;
1310     str = msi_alloc(sz * sizeof(WCHAR));
1311     r = MSI_GetPropertyW(package, prop, str, &sz);
1312     if (r != ERROR_SUCCESS)
1313     {
1314         msi_free(str);
1315         str = NULL;
1316     }
1317
1318     return str;
1319 }
1320
1321 int msi_get_property_int(MSIPACKAGE *package, LPCWSTR prop, int def)
1322 {
1323     LPWSTR str = msi_dup_property(package, prop);
1324     int val = str ? atoiW(str) : def;
1325     msi_free(str);
1326     return val;
1327 }
1328
1329 static UINT MSI_GetProperty( MSIHANDLE handle, LPCWSTR name,
1330                              awstring *szValueBuf, DWORD* pchValueBuf )
1331 {
1332     static const WCHAR empty[] = {0};
1333     MSIPACKAGE *package;
1334     MSIRECORD *row = NULL;
1335     UINT r;
1336     LPCWSTR val = NULL;
1337
1338     TRACE("%lu %s %p %p\n", handle, debugstr_w(name),
1339           szValueBuf->str.w, pchValueBuf );
1340
1341     if (!name)
1342         return ERROR_INVALID_PARAMETER;
1343
1344     package = msihandle2msiinfo( handle, MSIHANDLETYPE_PACKAGE );
1345     if (!package)
1346         return ERROR_INVALID_HANDLE;
1347
1348     row = MSI_GetPropertyRow( package, name );
1349     if (row)
1350         val = MSI_RecordGetString( row, 1 );
1351
1352     if (!val)
1353         val = empty;
1354
1355     r = msi_strcpy_to_awstring( val, szValueBuf, pchValueBuf );
1356
1357     if (row)
1358         msiobj_release( &row->hdr );
1359     msiobj_release( &package->hdr );
1360
1361     return r;
1362 }
1363
1364 UINT WINAPI MsiGetPropertyA( MSIHANDLE hInstall, LPCSTR szName,
1365                              LPSTR szValueBuf, DWORD* pchValueBuf )
1366 {
1367     awstring val;
1368     LPWSTR name;
1369     UINT r;
1370
1371     val.unicode = FALSE;
1372     val.str.a = szValueBuf;
1373
1374     name = strdupAtoW( szName );
1375     if (szName && !name)
1376         return ERROR_OUTOFMEMORY;
1377
1378     r = MSI_GetProperty( hInstall, name, &val, pchValueBuf );
1379     msi_free( name );
1380     return r;
1381 }
1382
1383 UINT WINAPI MsiGetPropertyW( MSIHANDLE hInstall, LPCWSTR szName,
1384                              LPWSTR szValueBuf, DWORD* pchValueBuf )
1385 {
1386     awstring val;
1387
1388     val.unicode = TRUE;
1389     val.str.w = szValueBuf;
1390
1391     return MSI_GetProperty( hInstall, szName, &val, pchValueBuf );
1392 }