msi: Allocate a buffer in WCHARs not CHARs.
[wine/wine64.git] / dlls / msi / package.c
blobb78910df5d1cf3107558cae1c44033ba84b91112
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004 Aric Stewart for CodeWeavers
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.
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.
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
21 #define NONAMELESSUNION
22 #define NONAMELESSSTRUCT
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "winnls.h"
30 #include "shlwapi.h"
31 #include "wingdi.h"
32 #include "wine/debug.h"
33 #include "msi.h"
34 #include "msiquery.h"
35 #include "objidl.h"
36 #include "wincrypt.h"
37 #include "winuser.h"
38 #include "wininet.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"
46 #include "msipriv.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(msi);
50 static void msi_free_properties( MSIPACKAGE *package );
52 static void MSI_FreePackage( MSIOBJECTHDR *arg)
54 MSIPACKAGE *package= (MSIPACKAGE*) arg;
56 if( package->dialog )
57 msi_dialog_destroy( package->dialog );
59 msiobj_release( &package->db->hdr );
60 ACTION_free_package_structures(package);
61 msi_free_properties( package );
64 static UINT iterate_clone_props(MSIRECORD *row, LPVOID param)
66 MSIPACKAGE *package = param;
67 LPCWSTR name, value;
69 name = MSI_RecordGetString( row, 1 );
70 value = MSI_RecordGetString( row, 2 );
71 MSI_SetPropertyW( package, name, value );
73 return ERROR_SUCCESS;
76 static UINT clone_properties( MSIPACKAGE *package )
78 static const WCHAR Query[] = {
79 'S','E','L','E','C','T',' ','*',' ',
80 'F','R','O','M',' ','`','P','r','o','p','e','r','t','y','`',0};
81 MSIQUERY *view = NULL;
82 UINT r;
84 r = MSI_OpenQuery( package->db, &view, Query );
85 if (r == ERROR_SUCCESS)
87 r = MSI_IterateRecords( view, NULL, iterate_clone_props, package );
88 msiobj_release(&view->hdr);
90 return r;
94 * set_installed_prop
96 * Sets the "Installed" property to indicate that
97 * the product is installed for the current user.
99 static UINT set_installed_prop( MSIPACKAGE *package )
101 static const WCHAR szInstalled[] = {
102 'I','n','s','t','a','l','l','e','d',0 };
103 WCHAR val[2] = { '1', 0 };
104 HKEY hkey = 0;
105 UINT r;
107 r = MSIREG_OpenUninstallKey( package->ProductCode, &hkey, FALSE );
108 if (r == ERROR_SUCCESS)
110 RegCloseKey( hkey );
111 MSI_SetPropertyW( package, szInstalled, val );
114 return r;
117 static UINT set_user_sid_prop( MSIPACKAGE *package )
119 SID_NAME_USE use;
120 LPWSTR user_name;
121 LPWSTR sid_str = NULL, dom = NULL;
122 DWORD size, dom_size;
123 PSID psid = NULL;
124 UINT r = ERROR_FUNCTION_FAILED;
126 static const WCHAR user_sid[] = {'U','s','e','r','S','I','D',0};
128 size = 0;
129 GetUserNameW( NULL, &size );
131 user_name = msi_alloc( (size + 1) * sizeof(WCHAR) );
132 if (!user_name)
133 return ERROR_OUTOFMEMORY;
135 if (!GetUserNameW( user_name, &size ))
136 goto done;
138 size = 0;
139 dom_size = 0;
140 LookupAccountNameW( NULL, user_name, NULL, &size, NULL, &dom_size, &use );
142 psid = msi_alloc( size );
143 dom = msi_alloc( dom_size*sizeof (WCHAR) );
144 if (!psid || !dom)
146 r = ERROR_OUTOFMEMORY;
147 goto done;
150 if (!LookupAccountNameW( NULL, user_name, psid, &size, dom, &dom_size, &use ))
151 goto done;
153 if (!ConvertSidToStringSidW( psid, &sid_str ))
154 goto done;
156 r = MSI_SetPropertyW( package, user_sid, sid_str );
158 done:
159 LocalFree( sid_str );
160 msi_free( dom );
161 msi_free( psid );
162 msi_free( user_name );
164 return r;
168 * There are a whole slew of these we need to set
171 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/properties.asp
173 static VOID set_installer_properties(MSIPACKAGE *package)
175 WCHAR pth[MAX_PATH];
176 WCHAR *ptr;
177 OSVERSIONINFOA OSVersion;
178 MEMORYSTATUSEX msex;
179 DWORD verval;
180 WCHAR verstr[10], bufstr[20];
181 HDC dc;
182 LPWSTR check;
183 HKEY hkey;
184 LONG res;
186 static const WCHAR cszbs[]={'\\',0};
187 static const WCHAR CFF[] =
188 {'C','o','m','m','o','n','F','i','l','e','s','F','o','l','d','e','r',0};
189 static const WCHAR PFF[] =
190 {'P','r','o','g','r','a','m','F','i','l','e','s','F','o','l','d','e','r',0};
191 static const WCHAR CADF[] =
192 {'C','o','m','m','o','n','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
193 static const WCHAR FaF[] =
194 {'F','a','v','o','r','i','t','e','s','F','o','l','d','e','r',0};
195 static const WCHAR FoF[] =
196 {'F','o','n','t','s','F','o','l','d','e','r',0};
197 static const WCHAR SendTF[] =
198 {'S','e','n','d','T','o','F','o','l','d','e','r',0};
199 static const WCHAR SMF[] =
200 {'S','t','a','r','t','M','e','n','u','F','o','l','d','e','r',0};
201 static const WCHAR StF[] =
202 {'S','t','a','r','t','u','p','F','o','l','d','e','r',0};
203 static const WCHAR TemplF[] =
204 {'T','e','m','p','l','a','t','e','F','o','l','d','e','r',0};
205 static const WCHAR DF[] =
206 {'D','e','s','k','t','o','p','F','o','l','d','e','r',0};
207 static const WCHAR PMF[] =
208 {'P','r','o','g','r','a','m','M','e','n','u','F','o','l','d','e','r',0};
209 static const WCHAR ATF[] =
210 {'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0};
211 static const WCHAR ADF[] =
212 {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
213 static const WCHAR SF[] =
214 {'S','y','s','t','e','m','F','o','l','d','e','r',0};
215 static const WCHAR SF16[] =
216 {'S','y','s','t','e','m','1','6','F','o','l','d','e','r',0};
217 static const WCHAR LADF[] =
218 {'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
219 static const WCHAR MPF[] =
220 {'M','y','P','i','c','t','u','r','e','s','F','o','l','d','e','r',0};
221 static const WCHAR PF[] =
222 {'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0};
223 static const WCHAR WF[] =
224 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
225 static const WCHAR WV[] =
226 {'W','i','n','d','o','w','s','V','o','l','u','m','e',0};
227 static const WCHAR TF[]=
228 {'T','e','m','p','F','o','l','d','e','r',0};
229 static const WCHAR szAdminUser[] =
230 {'A','d','m','i','n','U','s','e','r',0};
231 static const WCHAR szPriv[] =
232 {'P','r','i','v','i','l','e','g','e','d',0};
233 static const WCHAR szOne[] =
234 {'1',0};
235 static const WCHAR v9x[] = { 'V','e','r','s','i','o','n','9','X',0 };
236 static const WCHAR vNT[] = { 'V','e','r','s','i','o','n','N','T',0 };
237 static const WCHAR szFormat[] = {'%','l','i',0};
238 static const WCHAR szWinBuild[] =
239 {'W','i','n','d','o','w','s','B','u','i','l','d', 0 };
240 static const WCHAR szSPL[] =
241 {'S','e','r','v','i','c','e','P','a','c','k','L','e','v','e','l',0 };
242 static const WCHAR szSix[] = {'6',0 };
244 static const WCHAR szVersionMsi[] = { 'V','e','r','s','i','o','n','M','s','i',0 };
245 static const WCHAR szPhysicalMemory[] = { 'P','h','y','s','i','c','a','l','M','e','m','o','r','y',0 };
246 static const WCHAR szFormat2[] = {'%','l','i','.','%','l','i',0};
247 /* Screen properties */
248 static const WCHAR szScreenX[] = {'S','c','r','e','e','n','X',0};
249 static const WCHAR szScreenY[] = {'S','c','r','e','e','n','Y',0};
250 static const WCHAR szColorBits[] = {'C','o','l','o','r','B','i','t','s',0};
251 static const WCHAR szScreenFormat[] = {'%','d',0};
252 static const WCHAR szIntel[] = { 'I','n','t','e','l',0 };
253 static const WCHAR szAllUsers[] = { 'A','L','L','U','S','E','R','S',0 };
254 static const WCHAR szCurrentVersion[] = {
255 'S','O','F','T','W','A','R','E','\\',
256 'M','i','c','r','o','s','o','f','t','\\',
257 'W','i','n','d','o','w','s',' ','N','T','\\',
258 'C','u','r','r','e','n','t','V','e','r','s','i','o','n',0
260 static const WCHAR szRegisteredUser[] = {'R','e','g','i','s','t','e','r','e','d','O','w','n','e','r',0};
261 static const WCHAR szRegisteredOrg[] = {
262 'R','e','g','i','s','t','e','r','e','d','O','r','g','a','n','i','z','a','t','i','o','n',0
264 static const WCHAR szUSERNAME[] = {'U','S','E','R','N','A','M','E',0};
265 static const WCHAR szCOMPANYNAME[] = {'C','O','M','P','A','N','Y','N','A','M','E',0};
266 SYSTEM_INFO sys_info;
269 * Other things that probably should be set:
271 * SystemLanguageID ComputerName UserLanguageID LogonUser VirtualMemory
272 * Intel ShellAdvSupport DefaultUIFont VersionDatabase PackagecodeChanging
273 * ProductState CaptionHeight BorderTop BorderSide TextHeight
274 * RedirectedDllSupport Time Date Privileged
277 SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth);
278 strcatW(pth,cszbs);
279 MSI_SetPropertyW(package, CFF, pth);
281 SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES,NULL,0,pth);
282 strcatW(pth,cszbs);
283 MSI_SetPropertyW(package, PFF, pth);
285 SHGetFolderPathW(NULL,CSIDL_COMMON_APPDATA,NULL,0,pth);
286 strcatW(pth,cszbs);
287 MSI_SetPropertyW(package, CADF, pth);
289 SHGetFolderPathW(NULL,CSIDL_FAVORITES,NULL,0,pth);
290 strcatW(pth,cszbs);
291 MSI_SetPropertyW(package, FaF, pth);
293 SHGetFolderPathW(NULL,CSIDL_FONTS,NULL,0,pth);
294 strcatW(pth,cszbs);
295 MSI_SetPropertyW(package, FoF, pth);
297 SHGetFolderPathW(NULL,CSIDL_SENDTO,NULL,0,pth);
298 strcatW(pth,cszbs);
299 MSI_SetPropertyW(package, SendTF, pth);
301 SHGetFolderPathW(NULL,CSIDL_STARTMENU,NULL,0,pth);
302 strcatW(pth,cszbs);
303 MSI_SetPropertyW(package, SMF, pth);
305 SHGetFolderPathW(NULL,CSIDL_STARTUP,NULL,0,pth);
306 strcatW(pth,cszbs);
307 MSI_SetPropertyW(package, StF, pth);
309 SHGetFolderPathW(NULL,CSIDL_TEMPLATES,NULL,0,pth);
310 strcatW(pth,cszbs);
311 MSI_SetPropertyW(package, TemplF, pth);
313 SHGetFolderPathW(NULL,CSIDL_DESKTOP,NULL,0,pth);
314 strcatW(pth,cszbs);
315 MSI_SetPropertyW(package, DF, pth);
317 SHGetFolderPathW(NULL,CSIDL_PROGRAMS,NULL,0,pth);
318 strcatW(pth,cszbs);
319 MSI_SetPropertyW(package, PMF, pth);
321 SHGetFolderPathW(NULL,CSIDL_ADMINTOOLS,NULL,0,pth);
322 strcatW(pth,cszbs);
323 MSI_SetPropertyW(package, ATF, pth);
325 SHGetFolderPathW(NULL,CSIDL_APPDATA,NULL,0,pth);
326 strcatW(pth,cszbs);
327 MSI_SetPropertyW(package, ADF, pth);
329 SHGetFolderPathW(NULL,CSIDL_SYSTEM,NULL,0,pth);
330 strcatW(pth,cszbs);
331 MSI_SetPropertyW(package, SF, pth);
332 MSI_SetPropertyW(package, SF16, pth);
334 SHGetFolderPathW(NULL,CSIDL_LOCAL_APPDATA,NULL,0,pth);
335 strcatW(pth,cszbs);
336 MSI_SetPropertyW(package, LADF, pth);
338 SHGetFolderPathW(NULL,CSIDL_MYPICTURES,NULL,0,pth);
339 strcatW(pth,cszbs);
340 MSI_SetPropertyW(package, MPF, pth);
342 SHGetFolderPathW(NULL,CSIDL_PERSONAL,NULL,0,pth);
343 strcatW(pth,cszbs);
344 MSI_SetPropertyW(package, PF, pth);
346 SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
347 strcatW(pth,cszbs);
348 MSI_SetPropertyW(package, WF, pth);
350 /* Physical Memory is specified in MB. Using total amount. */
351 msex.dwLength = sizeof(msex);
352 GlobalMemoryStatusEx( &msex );
353 sprintfW( bufstr, szScreenFormat, (int)(msex.ullTotalPhys/1024/1024));
354 MSI_SetPropertyW(package, szPhysicalMemory, bufstr);
356 SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
357 ptr = strchrW(pth,'\\');
358 if (ptr)
359 *(ptr+1) = 0;
360 MSI_SetPropertyW(package, WV, pth);
362 GetTempPathW(MAX_PATH,pth);
363 MSI_SetPropertyW(package, TF, pth);
366 /* in a wine environment the user is always admin and privileged */
367 MSI_SetPropertyW(package,szAdminUser,szOne);
368 MSI_SetPropertyW(package,szPriv,szOne);
369 MSI_SetPropertyW(package, szAllUsers, szOne);
371 /* set the os things */
372 OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
373 GetVersionExA(&OSVersion);
374 verval = OSVersion.dwMinorVersion+OSVersion.dwMajorVersion*100;
375 sprintfW(verstr,szFormat,verval);
376 switch (OSVersion.dwPlatformId)
378 case VER_PLATFORM_WIN32_WINDOWS:
379 MSI_SetPropertyW(package,v9x,verstr);
380 break;
381 case VER_PLATFORM_WIN32_NT:
382 MSI_SetPropertyW(package,vNT,verstr);
383 break;
385 sprintfW(verstr,szFormat,OSVersion.dwBuildNumber);
386 MSI_SetPropertyW(package,szWinBuild,verstr);
387 /* just fudge this */
388 MSI_SetPropertyW(package,szSPL,szSix);
390 sprintfW( bufstr, szFormat2, MSI_MAJORVERSION, MSI_MINORVERSION);
391 MSI_SetPropertyW( package, szVersionMsi, bufstr );
393 GetSystemInfo( &sys_info );
394 if (sys_info.u.s.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
396 sprintfW( bufstr, szScreenFormat, sys_info.wProcessorLevel );
397 MSI_SetPropertyW( package, szIntel, bufstr );
400 /* Screen properties. */
401 dc = GetDC(0);
402 sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, HORZRES ) );
403 MSI_SetPropertyW( package, szScreenX, bufstr );
404 sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, VERTRES ));
405 MSI_SetPropertyW( package, szScreenY, bufstr );
406 sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, BITSPIXEL ));
407 MSI_SetPropertyW( package, szColorBits, bufstr );
408 ReleaseDC(0, dc);
410 /* USERNAME and COMPANYNAME */
411 res = RegOpenKeyW( HKEY_LOCAL_MACHINE, szCurrentVersion, &hkey );
412 if (res != ERROR_SUCCESS)
413 return;
415 check = msi_dup_property( package, szUSERNAME );
416 if (!check)
418 LPWSTR user = msi_reg_get_val_str( hkey, szRegisteredUser );
419 MSI_SetPropertyW( package, szUSERNAME, user );
420 msi_free( user );
423 msi_free( check );
425 check = msi_dup_property( package, szCOMPANYNAME );
426 if (!check)
428 LPWSTR company = msi_reg_get_val_str( hkey, szRegisteredOrg );
429 MSI_SetPropertyW( package, szCOMPANYNAME, company );
430 msi_free( company );
433 if ( set_user_sid_prop( package ) != ERROR_SUCCESS)
434 ERR("Failed to set the UserSID property\n");
436 msi_free( check );
437 CloseHandle( hkey );
440 static UINT msi_get_word_count( MSIPACKAGE *package )
442 UINT rc;
443 INT word_count;
444 MSIHANDLE suminfo;
445 MSIHANDLE hdb = alloc_msihandle( &package->db->hdr );
447 if (!hdb) {
448 ERR("Unable to allocate handle\n");
449 return 0;
451 rc = MsiGetSummaryInformationW( hdb, NULL, 0, &suminfo );
452 MsiCloseHandle(hdb);
453 if (rc != ERROR_SUCCESS)
455 ERR("Unable to open Summary Information\n");
456 return 0;
459 rc = MsiSummaryInfoGetPropertyW( suminfo, PID_WORDCOUNT, NULL,
460 &word_count, NULL, NULL, NULL );
461 if (rc != ERROR_SUCCESS)
463 ERR("Unable to query word count\n");
464 MsiCloseHandle(suminfo);
465 return 0;
468 MsiCloseHandle(suminfo);
469 return word_count;
472 static MSIPACKAGE *msi_alloc_package( void )
474 MSIPACKAGE *package;
475 int i;
477 package = alloc_msiobject( MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE),
478 MSI_FreePackage );
479 if( package )
481 list_init( &package->components );
482 list_init( &package->features );
483 list_init( &package->files );
484 list_init( &package->tempfiles );
485 list_init( &package->folders );
486 list_init( &package->subscriptions );
487 list_init( &package->appids );
488 list_init( &package->classes );
489 list_init( &package->mimes );
490 list_init( &package->extensions );
491 list_init( &package->progids );
492 list_init( &package->RunningActions );
494 for (i=0; i<PROPERTY_HASH_SIZE; i++)
495 list_init( &package->props[i] );
497 package->ActionFormat = NULL;
498 package->LastAction = NULL;
499 package->dialog = NULL;
500 package->next_dialog = NULL;
503 return package;
506 MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPWSTR base_url )
508 static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 };
509 static const WCHAR szpi[] = {'%','i',0};
510 static const WCHAR szProductCode[] = {
511 'P','r','o','d','u','c','t','C','o','d','e',0};
512 MSIPACKAGE *package;
513 WCHAR uilevel[10];
515 TRACE("%p\n", db);
517 package = msi_alloc_package();
518 if (package)
520 msiobj_addref( &db->hdr );
521 package->db = db;
523 package->WordCount = msi_get_word_count( package );
524 package->PackagePath = strdupW( db->path );
525 package->BaseURL = strdupW( base_url );
527 clone_properties( package );
528 set_installer_properties(package);
529 sprintfW(uilevel,szpi,gUILevel);
530 MSI_SetPropertyW(package, szLevel, uilevel);
532 package->ProductCode = msi_dup_property( package, szProductCode );
533 set_installed_prop( package );
536 return package;
540 * copy_package_to_temp [internal]
542 * copy the msi file to a temp file to prevent locking a CD
543 * with a multi disc install
545 * FIXME: I think this is wrong, and instead of copying the package,
546 * we should read all the tables to memory, then open the
547 * database to read binary streams on demand.
549 static LPCWSTR copy_package_to_temp( LPCWSTR szPackage, LPWSTR filename )
551 WCHAR path[MAX_PATH];
552 static const WCHAR szMSI[] = {'m','s','i',0};
554 GetTempPathW( MAX_PATH, path );
555 GetTempFileNameW( path, szMSI, 0, filename );
557 if( !CopyFileW( szPackage, filename, FALSE ) )
559 DeleteFileW( filename );
560 ERR("failed to copy package %s\n", debugstr_w(szPackage) );
561 return szPackage;
564 TRACE("Opening relocated package %s\n", debugstr_w( filename ));
565 return filename;
568 LPCWSTR msi_download_file( LPCWSTR szUrl, LPWSTR filename )
570 LPINTERNET_CACHE_ENTRY_INFOW cache_entry;
571 DWORD size = 0;
572 HRESULT hr;
574 /* call will always fail, becase size is 0,
575 * but will return ERROR_FILE_NOT_FOUND first
576 * if the file doesn't exist
578 GetUrlCacheEntryInfoW( szUrl, NULL, &size );
579 if ( GetLastError() != ERROR_FILE_NOT_FOUND )
581 cache_entry = HeapAlloc( GetProcessHeap(), 0, size );
582 if ( !GetUrlCacheEntryInfoW( szUrl, cache_entry, &size ) )
584 HeapFree( GetProcessHeap(), 0, cache_entry );
585 return szUrl;
588 lstrcpyW( filename, cache_entry->lpszLocalFileName );
589 HeapFree( GetProcessHeap(), 0, cache_entry );
590 return filename;
593 hr = URLDownloadToCacheFileW( NULL, szUrl, filename, MAX_PATH, 0, NULL );
594 if ( FAILED(hr) )
595 return szUrl;
597 return filename;
600 UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
602 static const WCHAR OriginalDatabase[] =
603 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
604 static const WCHAR Database[] = {'D','A','T','A','B','A','S','E',0};
605 MSIDATABASE *db = NULL;
606 MSIPACKAGE *package;
607 MSIHANDLE handle;
608 LPWSTR ptr, base_url = NULL;
609 UINT r;
610 WCHAR temppath[MAX_PATH];
611 LPCWSTR file = szPackage;
613 TRACE("%s %p\n", debugstr_w(szPackage), pPackage);
615 if( szPackage[0] == '#' )
617 handle = atoiW(&szPackage[1]);
618 db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
619 if( !db )
620 return ERROR_INVALID_HANDLE;
622 else
624 if ( UrlIsW( szPackage, URLIS_URL ) )
626 file = msi_download_file( szPackage, temppath );
628 base_url = strdupW( szPackage );
629 if ( !base_url )
630 return ERROR_OUTOFMEMORY;
632 ptr = strrchrW( base_url, '/' );
633 if (ptr) *(ptr + 1) = '\0';
635 else
636 file = copy_package_to_temp( szPackage, temppath );
638 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &db );
639 if( r != ERROR_SUCCESS )
641 if (GetLastError() == ERROR_FILE_NOT_FOUND)
642 msi_ui_error( 4, MB_OK | MB_ICONWARNING );
643 if (file != szPackage)
644 DeleteFileW( file );
646 return r;
650 package = MSI_CreatePackage( db, base_url );
651 msi_free( base_url );
652 msiobj_release( &db->hdr );
653 if( !package )
655 if (file != szPackage)
656 DeleteFileW( file );
657 return ERROR_FUNCTION_FAILED;
660 if( file != szPackage )
661 track_tempfile( package, file );
663 if( szPackage[0] != '#' )
665 MSI_SetPropertyW( package, OriginalDatabase, szPackage );
666 MSI_SetPropertyW( package, Database, szPackage );
668 else
670 MSI_SetPropertyW( package, OriginalDatabase, db->path );
671 MSI_SetPropertyW( package, Database, db->path );
674 *pPackage = package;
676 return ERROR_SUCCESS;
679 UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
681 MSIPACKAGE *package = NULL;
682 UINT ret;
684 TRACE("%s %08x %p\n", debugstr_w(szPackage), dwOptions, phPackage );
686 if( szPackage == NULL )
687 return ERROR_INVALID_PARAMETER;
689 if( dwOptions )
690 FIXME("dwOptions %08x not supported\n", dwOptions);
692 ret = MSI_OpenPackageW( szPackage, &package );
693 if( ret == ERROR_SUCCESS )
695 *phPackage = alloc_msihandle( &package->hdr );
696 if (! *phPackage)
697 ret = ERROR_NOT_ENOUGH_MEMORY;
698 msiobj_release( &package->hdr );
701 return ret;
704 UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
706 return MsiOpenPackageExW( szPackage, 0, phPackage );
709 UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
711 LPWSTR szwPack = NULL;
712 UINT ret;
714 if( szPackage )
716 szwPack = strdupAtoW( szPackage );
717 if( !szwPack )
718 return ERROR_OUTOFMEMORY;
721 ret = MsiOpenPackageExW( szwPack, dwOptions, phPackage );
723 msi_free( szwPack );
725 return ret;
728 UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
730 return MsiOpenPackageExA( szPackage, 0, phPackage );
733 MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
735 MSIPACKAGE *package;
736 MSIHANDLE handle = 0;
738 TRACE("(%ld)\n",hInstall);
740 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
741 if( package)
743 handle = alloc_msihandle( &package->db->hdr );
744 msiobj_release( &package->hdr );
747 return handle;
750 INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
751 MSIRECORD *record)
753 static const WCHAR szActionData[] =
754 {'A','c','t','i','o','n','D','a','t','a',0};
755 static const WCHAR szSetProgress[] =
756 {'S','e','t','P','r','o','g','r','e','s','s',0};
757 static const WCHAR szActionText[] =
758 {'A','c','t','i','o','n','T','e','x','t',0};
759 DWORD log_type = 0;
760 LPWSTR message;
761 DWORD sz;
762 DWORD total_size = 0;
763 INT i;
764 INT rc;
765 char *msg;
766 int len;
768 TRACE("%x\n", eMessageType);
769 rc = 0;
771 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR)
772 log_type |= INSTALLLOGMODE_ERROR;
773 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_WARNING)
774 log_type |= INSTALLLOGMODE_WARNING;
775 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_USER)
776 log_type |= INSTALLLOGMODE_USER;
777 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INFO)
778 log_type |= INSTALLLOGMODE_INFO;
779 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA)
780 log_type |= INSTALLLOGMODE_COMMONDATA;
781 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
782 log_type |= INSTALLLOGMODE_ACTIONSTART;
783 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONDATA)
784 log_type |= INSTALLLOGMODE_ACTIONDATA;
785 /* just a guess */
786 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS)
787 log_type |= 0x800;
789 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
791 static const WCHAR template_s[]=
792 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ',0};
793 static const WCHAR format[] =
794 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
795 WCHAR timet[0x100];
796 LPCWSTR action_text, action;
797 LPWSTR deformatted = NULL;
799 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
801 action = MSI_RecordGetString(record, 1);
802 action_text = MSI_RecordGetString(record, 2);
804 if (!action || !action_text)
805 return IDOK;
807 deformat_string(package, action_text, &deformatted);
809 len = strlenW(timet) + strlenW(action) + strlenW(template_s);
810 if (deformatted)
811 len += strlenW(deformatted);
812 message = msi_alloc(len*sizeof(WCHAR));
813 sprintfW(message, template_s, timet, action);
814 if (deformatted)
815 strcatW(message, deformatted);
816 msi_free(deformatted);
818 else
820 INT msg_field=1;
821 message = msi_alloc(1*sizeof (WCHAR));
822 message[0]=0;
823 msg_field = MSI_RecordGetFieldCount(record);
824 for (i = 1; i <= msg_field; i++)
826 LPWSTR tmp;
827 WCHAR number[3];
828 static const WCHAR format[] = { '%','i',':',' ',0};
829 static const WCHAR space[] = { ' ',0};
830 sz = 0;
831 MSI_RecordGetStringW(record,i,NULL,&sz);
832 sz+=4;
833 total_size+=sz*sizeof(WCHAR);
834 tmp = msi_alloc(sz*sizeof(WCHAR));
835 message = msi_realloc(message,total_size*sizeof (WCHAR));
837 MSI_RecordGetStringW(record,i,tmp,&sz);
839 if (msg_field > 1)
841 sprintfW(number,format,i);
842 strcatW(message,number);
844 strcatW(message,tmp);
845 if (msg_field > 1)
846 strcatW(message,space);
848 msi_free(tmp);
852 TRACE("(%p %x %x %s)\n", gUIHandlerA, gUIFilter, log_type,
853 debugstr_w(message));
855 /* convert it to ASCII */
856 len = WideCharToMultiByte( CP_ACP, 0, message, -1,
857 NULL, 0, NULL, NULL );
858 msg = msi_alloc( len );
859 WideCharToMultiByte( CP_ACP, 0, message, -1,
860 msg, len, NULL, NULL );
862 if (gUIHandlerA && (gUIFilter & log_type))
864 rc = gUIHandlerA(gUIContext,eMessageType,msg);
867 if ((!rc) && (gszLogFile[0]) && !((eMessageType & 0xff000000) ==
868 INSTALLMESSAGE_PROGRESS))
870 DWORD write;
871 HANDLE log_file = CreateFileW(gszLogFile,GENERIC_WRITE, 0, NULL,
872 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
874 if (log_file != INVALID_HANDLE_VALUE)
876 SetFilePointer(log_file,0, NULL, FILE_END);
877 WriteFile(log_file,msg,strlen(msg),&write,NULL);
878 WriteFile(log_file,"\n",1,&write,NULL);
879 CloseHandle(log_file);
882 msi_free( msg );
884 msi_free( message);
886 switch (eMessageType & 0xff000000)
888 case INSTALLMESSAGE_ACTIONDATA:
889 /* FIXME: format record here instead of in ui_actiondata to get the
890 * correct action data for external scripts */
891 ControlEvent_FireSubscribedEvent(package, szActionData, record);
892 break;
893 case INSTALLMESSAGE_ACTIONSTART:
895 MSIRECORD *uirow;
896 LPWSTR deformated;
897 LPCWSTR action_text = MSI_RecordGetString(record, 2);
899 deformat_string(package, action_text, &deformated);
900 uirow = MSI_CreateRecord(1);
901 MSI_RecordSetStringW(uirow, 1, deformated);
902 TRACE("INSTALLMESSAGE_ACTIONSTART: %s\n", debugstr_w(deformated));
903 msi_free(deformated);
905 ControlEvent_FireSubscribedEvent(package, szActionText, uirow);
907 msiobj_release(&uirow->hdr);
908 break;
910 case INSTALLMESSAGE_PROGRESS:
911 ControlEvent_FireSubscribedEvent(package, szSetProgress, record);
912 break;
915 return ERROR_SUCCESS;
918 INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
919 MSIHANDLE hRecord)
921 UINT ret = ERROR_INVALID_HANDLE;
922 MSIPACKAGE *package = NULL;
923 MSIRECORD *record = NULL;
925 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
926 if( !package )
927 return ERROR_INVALID_HANDLE;
929 record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
930 if( !record )
931 goto out;
933 ret = MSI_ProcessMessage( package, eMessageType, record );
935 out:
936 msiobj_release( &package->hdr );
937 if( record )
938 msiobj_release( &record->hdr );
940 return ret;
943 /* property code */
945 typedef struct msi_property {
946 struct list entry;
947 LPWSTR key;
948 LPWSTR value;
949 } msi_property;
951 static UINT msi_prop_makehash( const WCHAR *str )
953 UINT hash = 0;
955 if (str==NULL)
956 return hash;
958 while( *str )
960 hash ^= *str++;
961 hash *= 53;
962 hash = (hash<<5) | (hash>>27);
964 return hash % PROPERTY_HASH_SIZE;
967 static msi_property *msi_prop_find( MSIPACKAGE *package, LPCWSTR key )
969 UINT hash = msi_prop_makehash( key );
970 msi_property *prop;
972 LIST_FOR_EACH_ENTRY( prop, &package->props[hash], msi_property, entry )
973 if (!lstrcmpW( prop->key, key ))
974 return prop;
975 return NULL;
978 static msi_property *msi_prop_add( MSIPACKAGE *package, LPCWSTR key )
980 UINT hash = msi_prop_makehash( key );
981 msi_property *prop;
983 prop = msi_alloc( sizeof *prop );
984 if (prop)
986 prop->key = strdupW( key );
987 prop->value = NULL;
988 list_add_head( &package->props[hash], &prop->entry );
990 return prop;
993 static void msi_delete_property( msi_property *prop )
995 list_remove( &prop->entry );
996 msi_free( prop->key );
997 msi_free( prop->value );
998 msi_free( prop );
1001 static void msi_free_properties( MSIPACKAGE *package )
1003 int i;
1005 for ( i=0; i<PROPERTY_HASH_SIZE; i++ )
1007 while ( !list_empty(&package->props[i]) )
1009 msi_property *prop;
1010 prop = LIST_ENTRY( list_head( &package->props[i] ),
1011 msi_property, entry );
1012 msi_delete_property( prop );
1017 UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue )
1019 LPWSTR szwName = NULL, szwValue = NULL;
1020 UINT r = ERROR_OUTOFMEMORY;
1022 szwName = strdupAtoW( szName );
1023 if( szName && !szwName )
1024 goto end;
1026 szwValue = strdupAtoW( szValue );
1027 if( szValue && !szwValue )
1028 goto end;
1030 r = MsiSetPropertyW( hInstall, szwName, szwValue);
1032 end:
1033 msi_free( szwName );
1034 msi_free( szwValue );
1036 return r;
1039 UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
1041 msi_property *prop;
1043 TRACE("%p %s %s\n", package, debugstr_w(szName), debugstr_w(szValue));
1045 if (!szName)
1046 return ERROR_INVALID_PARAMETER;
1048 /* this one is weird... */
1049 if (!szName[0])
1050 return szValue ? ERROR_FUNCTION_FAILED : ERROR_SUCCESS;
1052 prop = msi_prop_find( package, szName );
1053 if (!prop)
1054 prop = msi_prop_add( package, szName );
1056 if (!prop)
1057 return ERROR_OUTOFMEMORY;
1059 if (szValue)
1061 msi_free( prop->value );
1062 prop->value = strdupW( szValue );
1064 else
1065 msi_delete_property( prop );
1067 return ERROR_SUCCESS;
1070 UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
1072 MSIPACKAGE *package;
1073 UINT ret;
1075 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
1076 if( !package )
1077 return ERROR_INVALID_HANDLE;
1078 ret = MSI_SetPropertyW( package, szName, szValue);
1079 msiobj_release( &package->hdr );
1080 return ret;
1083 /* internal function, not compatible with MsiGetPropertyW */
1084 UINT MSI_GetPropertyW( MSIPACKAGE *package, LPCWSTR szName,
1085 LPWSTR szValueBuf, DWORD* pchValueBuf )
1087 msi_property *prop;
1088 UINT r, len;
1090 if (*pchValueBuf > 0)
1091 szValueBuf[0] = 0;
1093 prop = msi_prop_find( package, szName );
1094 if (!prop)
1096 *pchValueBuf = 0;
1097 TRACE("property %s not found\n", debugstr_w(szName));
1098 return ERROR_FUNCTION_FAILED;
1101 if (prop->value)
1103 len = lstrlenW( prop->value );
1104 lstrcpynW(szValueBuf, prop->value, *pchValueBuf);
1106 else
1108 len = 1;
1109 if( *pchValueBuf > 0 )
1110 szValueBuf[0] = 0;
1113 TRACE("%s -> %s\n", debugstr_w(szName), debugstr_w(szValueBuf));
1115 if ( *pchValueBuf <= len )
1117 TRACE("have %u, need %u -> ERROR_MORE_DATA\n", *pchValueBuf, len);
1118 r = ERROR_MORE_DATA;
1120 else
1121 r = ERROR_SUCCESS;
1123 *pchValueBuf = len;
1125 return r;
1128 LPWSTR msi_dup_property( MSIPACKAGE *package, LPCWSTR szName )
1130 msi_property *prop;
1131 LPWSTR value = NULL;
1133 prop = msi_prop_find( package, szName );
1134 if (prop)
1135 value = strdupW( prop->value );
1137 return value;
1140 int msi_get_property_int( MSIPACKAGE *package, LPCWSTR name, int value )
1142 msi_property *prop;
1144 prop = msi_prop_find( package, name );
1145 if (prop)
1146 value = atoiW( prop->value );
1147 return value;
1150 static UINT MSI_GetProperty( MSIHANDLE handle, LPCWSTR name,
1151 awstring *szValueBuf, DWORD* pchValueBuf )
1153 static const WCHAR empty[] = {0};
1154 msi_property *prop;
1155 MSIPACKAGE *package;
1156 UINT r;
1157 LPCWSTR val = NULL;
1159 TRACE("%lu %s %p %p\n", handle, debugstr_w(name),
1160 szValueBuf->str.w, pchValueBuf );
1162 if (!name)
1163 return ERROR_INVALID_PARAMETER;
1165 package = msihandle2msiinfo( handle, MSIHANDLETYPE_PACKAGE );
1166 if (!package)
1167 return ERROR_INVALID_HANDLE;
1169 prop = msi_prop_find( package, name );
1170 if (prop)
1171 val = prop->value;
1173 if (!val)
1174 val = empty;
1176 r = msi_strcpy_to_awstring( val, szValueBuf, pchValueBuf );
1178 msiobj_release( &package->hdr );
1180 return r;
1183 UINT WINAPI MsiGetPropertyA( MSIHANDLE hInstall, LPCSTR szName,
1184 LPSTR szValueBuf, DWORD* pchValueBuf )
1186 awstring val;
1187 LPWSTR name;
1188 UINT r;
1190 val.unicode = FALSE;
1191 val.str.a = szValueBuf;
1193 name = strdupAtoW( szName );
1194 if (szName && !name)
1195 return ERROR_OUTOFMEMORY;
1197 r = MSI_GetProperty( hInstall, name, &val, pchValueBuf );
1198 msi_free( name );
1199 return r;
1202 UINT WINAPI MsiGetPropertyW( MSIHANDLE hInstall, LPCWSTR szName,
1203 LPWSTR szValueBuf, DWORD* pchValueBuf )
1205 awstring val;
1207 val.unicode = TRUE;
1208 val.str.w = szValueBuf;
1210 return MSI_GetProperty( hInstall, szName, &val, pchValueBuf );