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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #define NONAMELESSUNION
30 #include "wine/debug.h"
38 #include "wine/unicode.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(msi);
44 * The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR,
45 * which is a problem because LPCTSTR isn't defined when compiling wine.
46 * To work around this problem, we need to define LPCTSTR as LPCWSTR here,
47 * and make sure to only use it in W functions.
49 #define LPCTSTR LPCWSTR
51 void MSI_FreePackage( VOID *arg);
53 void MSI_FreePackage( VOID *arg)
55 MSIPACKAGE *package= arg;
57 MsiCloseHandle(package->db);
59 ACTION_remove_tracked_tempfiles(package);
61 if (package->features && package->loaded_features > 0)
62 HeapFree(GetProcessHeap(),0,package->features);
64 if (package->folders && package->loaded_folders > 0)
65 HeapFree(GetProcessHeap(),0,package->folders);
67 if (package->components && package->loaded_components > 0)
68 HeapFree(GetProcessHeap(),0,package->components);
70 if (package->files && package->loaded_files > 0)
71 HeapFree(GetProcessHeap(),0,package->files);
74 UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
76 LPWSTR szwPack = NULL;
79 TRACE("%s %p\n",debugstr_a(szPackage), phPackage);
83 len = MultiByteToWideChar( CP_ACP, 0, szPackage, -1, NULL, 0 );
84 szwPack = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
86 MultiByteToWideChar( CP_ACP, 0, szPackage, -1, szwPack, len );
89 ret = MsiOpenPackageW( szwPack, phPackage );
92 HeapFree( GetProcessHeap(), 0, szwPack );
98 static const void clone_properties(MSIHANDLE db)
102 static const CHAR CreateSql[] = "CREATE TABLE `_Property` ( `_Property` "
103 "CHAR(56) NOT NULL, `Value` CHAR(98) NOT NULL PRIMARY KEY `_Property`)";
104 static const CHAR Query[] = "SELECT * from Property";
105 static const CHAR Insert[] =
106 "INSERT into `_Property` (`_Property`,`Value`) VALUES (?)";
108 /* create the temporary properties table */
109 MsiDatabaseOpenViewA(db, CreateSql, &view);
110 MsiViewExecute(view,0);
112 MsiCloseHandle(view);
114 /* clone the existing properties */
115 MsiDatabaseOpenViewA(db, Query, &view);
117 MsiViewExecute(view, 0);
123 rc = MsiViewFetch(view,&row);
124 if (rc != ERROR_SUCCESS)
127 MsiDatabaseOpenViewA(db,Insert,&view2);
128 MsiViewExecute(view2,row);
130 MsiCloseHandle(view2);
135 MsiCloseHandle(view);
140 * There are a whole slew of these we need to set
143 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/properties.asp
145 static VOID set_installer_properties(MSIHANDLE hPackage)
148 OSVERSIONINFOA OSVersion;
152 static const WCHAR cszbs[]={'\\',0};
153 static const WCHAR CFF[] =
154 {'C','o','m','m','o','n','F','i','l','e','s','F','o','l','d','e','r',0};
155 static const WCHAR PFF[] =
156 {'P','r','o','g','r','a','m','F','i','l','e','s','F','o','l','d','e','r',0};
157 static const WCHAR CADF[] =
158 {'C','o','m','m','o','n','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
159 static const WCHAR ATF[] =
160 {'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0};
161 static const WCHAR ADF[] =
162 {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
163 static const WCHAR SF[] =
164 {'S','y','s','t','e','m','F','o','l','d','e','r',0};
165 static const WCHAR LADF[] =
166 {'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
167 static const WCHAR MPF[] =
168 {'M','y','P','i','c','t','u','r','e','s','F','o','l','d','e','r',0};
169 static const WCHAR PF[] =
170 {'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0};
171 static const WCHAR WF[] =
172 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
173 static const WCHAR TF[]=
174 {'T','e','m','p','F','o','l','d','e','r',0};
176 /* Not yet set ... but needed by iTunes
192 /* asked for by iTunes ... but are they installer set?
194 * GlobalAssemblyCache
198 * Other things i notice set
226 SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth);
228 MsiSetPropertyW(hPackage, CFF, pth);
230 SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES,NULL,0,pth);
232 MsiSetPropertyW(hPackage, PFF, pth);
234 SHGetFolderPathW(NULL,CSIDL_COMMON_APPDATA,NULL,0,pth);
236 MsiSetPropertyW(hPackage, CADF, pth);
238 SHGetFolderPathW(NULL,CSIDL_ADMINTOOLS,NULL,0,pth);
240 MsiSetPropertyW(hPackage, ATF, pth);
242 SHGetFolderPathW(NULL,CSIDL_APPDATA,NULL,0,pth);
244 MsiSetPropertyW(hPackage, ADF, pth);
246 SHGetFolderPathW(NULL,CSIDL_SYSTEM,NULL,0,pth);
248 MsiSetPropertyW(hPackage, SF, pth);
250 SHGetFolderPathW(NULL,CSIDL_LOCAL_APPDATA,NULL,0,pth);
252 MsiSetPropertyW(hPackage, LADF, pth);
254 SHGetFolderPathW(NULL,CSIDL_MYPICTURES,NULL,0,pth);
256 MsiSetPropertyW(hPackage, MPF, pth);
258 SHGetFolderPathW(NULL,CSIDL_PERSONAL,NULL,0,pth);
260 MsiSetPropertyW(hPackage, PF, pth);
262 SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
264 MsiSetPropertyW(hPackage, WF, pth);
266 GetTempPathW(MAX_PATH,pth);
267 MsiSetPropertyW(hPackage, TF, pth);
269 /* in a wine enviroment the user is always admin and privlaged */
270 MsiSetPropertyA(hPackage,"AdminUser","1");
271 MsiSetPropertyA(hPackage,"Privileged","1");
273 /* set the os things */
274 OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
275 GetVersionExA(&OSVersion);
276 verval = OSVersion.dwMinorVersion+OSVersion.dwMajorVersion*100;
277 sprintf(verstr,"%li",verval);
278 switch (OSVersion.dwPlatformId)
280 case VER_PLATFORM_WIN32_WINDOWS:
281 MsiSetPropertyA(hPackage,"Version9X",verstr);
283 case VER_PLATFORM_WIN32_NT:
284 MsiSetPropertyA(hPackage,"VersionNT",verstr);
287 sprintf(verstr,"%li",OSVersion.dwBuildNumber);
288 MsiSetPropertyA(hPackage,"WindowsBuild",verstr);
289 /* just fudge this */
290 MsiSetPropertyA(hPackage,"ServicePackLevel","6");
294 UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
302 static const WCHAR OriginalDatabase[] =
303 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
304 static const WCHAR Database[] =
305 {'D','A','T','A','B','A','S','E',0};
307 TRACE("%s %p\n",debugstr_w(szPackage), phPackage);
309 rc = MsiOpenDatabaseW(szPackage, MSIDBOPEN_READONLY, &db);
311 if (rc != ERROR_SUCCESS)
312 return ERROR_FUNCTION_FAILED;
314 handle = alloc_msihandle(MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE),
315 MSI_FreePackage, (void**)&package);
320 return ERROR_FUNCTION_FAILED;
324 package->features = NULL;
325 package->folders = NULL;
326 package->components = NULL;
327 package->files = NULL;
328 package->loaded_features = 0;
329 package->loaded_folders = 0;
330 package->loaded_components= 0;
331 package->loaded_files = 0;
333 /* ok here is where we do a slew of things to the database to
334 * prep for all that is to come as a package */
336 clone_properties(db);
337 set_installer_properties(handle);
338 MsiSetPropertyW(handle, OriginalDatabase, szPackage);
339 MsiSetPropertyW(handle, Database, szPackage);
340 sprintf(uilevel,"%i",gUILevel);
341 MsiSetPropertyA(handle, "UILevel", uilevel);
345 return ERROR_SUCCESS;
348 UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
350 FIXME("%s 0x%08lx %p\n",debugstr_a(szPackage), dwOptions, phPackage);
351 return ERROR_CALL_NOT_IMPLEMENTED;
354 UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
356 FIXME("%s 0x%08lx %p\n",debugstr_w(szPackage), dwOptions, phPackage);
357 return ERROR_CALL_NOT_IMPLEMENTED;
360 MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
364 TRACE("(%ld)\n",hInstall);
366 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
369 return ERROR_INVALID_HANDLE;
371 msihandle_addref(package->db);
375 INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
381 DWORD total_size = 0;
384 FIXME("STUB: %x \n",eMessageType);
386 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR)
387 log_type |= INSTALLLOGMODE_ERROR;
388 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_WARNING)
389 log_type |= INSTALLLOGMODE_WARNING;
390 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_USER)
391 log_type |= INSTALLLOGMODE_USER;
392 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INFO)
393 log_type |= INSTALLLOGMODE_INFO;
394 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA)
395 log_type |= INSTALLLOGMODE_COMMONDATA;
396 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
397 log_type |= INSTALLLOGMODE_ACTIONSTART;
398 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONDATA)
399 log_type |= INSTALLLOGMODE_ACTIONDATA;
401 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS)
404 message = HeapAlloc(GetProcessHeap(),0,1);
406 msg_field = MsiRecordGetFieldCount(hRecord);
407 for (i = 1; i <= msg_field; i++)
412 MsiRecordGetStringA(hRecord,i,NULL,&sz);
415 tmp = HeapAlloc(GetProcessHeap(),0,sz);
416 message = HeapReAlloc(GetProcessHeap(),0,message,total_size);
418 MsiRecordGetStringA(hRecord,i,tmp,&sz);
422 sprintf(number," %i: ",i);
423 strcat(message,number);
426 HeapFree(GetProcessHeap(),0,tmp);
429 TRACE("(%p %lx %lx %s)\n",gUIHandler, gUIFilter, log_type,
430 debugstr_a(message));
432 if (gUIHandler && (gUIFilter & log_type))
433 gUIHandler(gUIContext,eMessageType,message);
435 HeapFree(GetProcessHeap(),0,message);
436 return ERROR_SUCCESS;
440 UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue)
442 LPWSTR szwName = NULL, szwValue = NULL;
443 UINT hr = ERROR_INSTALL_FAILURE;
447 return ERROR_INVALID_HANDLE;
449 if (NULL == szName) {
450 return ERROR_INVALID_PARAMETER;
452 if (NULL == szValue) {
453 return ERROR_INVALID_PARAMETER;
456 len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
457 szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
460 MultiByteToWideChar( CP_ACP, 0, szName, -1, szwName, len );
462 len = MultiByteToWideChar( CP_ACP, 0, szValue, -1, NULL, 0 );
463 szwValue = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
466 MultiByteToWideChar( CP_ACP, 0, szValue , -1, szwValue, len );
468 hr = MsiSetPropertyW( hInstall, szwName, szwValue);
472 HeapFree( GetProcessHeap(), 0, szwName );
474 HeapFree( GetProcessHeap(), 0, szwValue );
479 UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
485 static const WCHAR Insert[]=
486 {'I','N','S','E','R','T',' ','i','n','t','o',' ','`','_','P','r','o','p'
487 ,'e','r','t','y','`',' ','(','`','_','P','r','o','p','e','r','t','y','`'
488 ,',','`','V','a','l','u','e','`',')',' ','V','A','L','U','E','S'
490 static const WCHAR Update[]=
491 {'U','P','D','A','T','E',' ','_','P','r','o','p','e'
492 ,'r','t','y',' ','s','e','t',' ','`','V','a','l','u','e','`',' ','='
493 ,' ','?',' ','w','h','e','r','e',' ','`','_','P','r','o','p'
494 ,'e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
497 TRACE("Setting property (%s %s)\n",debugstr_w(szName),
498 debugstr_w(szValue));
501 return ERROR_INVALID_HANDLE;
503 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
505 return ERROR_INVALID_HANDLE;
507 rc = MsiGetPropertyW(hInstall,szName,0,&sz);
508 if (rc==ERROR_MORE_DATA || rc == ERROR_SUCCESS)
510 sprintfW(Query,Update,szName);
512 row = MsiCreateRecord(1);
513 MsiRecordSetStringW(row,1,szValue);
518 strcpyW(Query,Insert);
520 row = MsiCreateRecord(2);
521 MsiRecordSetStringW(row,1,szName);
522 MsiRecordSetStringW(row,2,szValue);
526 rc = MsiDatabaseOpenViewW(package->db,Query,&view);
527 if (rc!= ERROR_SUCCESS)
533 rc = MsiViewExecute(view,row);
537 MsiCloseHandle(view);
542 UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, DWORD* pchValueBuf)
544 LPWSTR szwName = NULL, szwValueBuf = NULL;
545 UINT hr = ERROR_INSTALL_FAILURE;
548 return ERROR_INVALID_HANDLE;
550 if (NULL == szName) {
551 return ERROR_INVALID_PARAMETER;
554 TRACE("%lu %s %lu\n", hInstall, debugstr_a(szName), *pchValueBuf);
556 if (NULL != szValueBuf && NULL == pchValueBuf) {
557 return ERROR_INVALID_PARAMETER;
561 UINT len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
562 szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
565 MultiByteToWideChar( CP_ACP, 0, szName, -1, szwName, len );
567 return ERROR_INVALID_PARAMETER;
571 szwValueBuf = HeapAlloc( GetProcessHeap(), 0, (*pchValueBuf) * sizeof(WCHAR) );
576 hr = MsiGetPropertyW( hInstall, szwName, szwValueBuf, pchValueBuf );
578 if( *pchValueBuf > 0 )
580 WideCharToMultiByte(CP_ACP, 0, szwValueBuf, -1, szValueBuf, *pchValueBuf, NULL, NULL);
585 HeapFree( GetProcessHeap(), 0, szwName );
587 HeapFree( GetProcessHeap(), 0, szwValueBuf );
592 UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName,
593 LPWSTR szValueBuf, DWORD* pchValueBuf)
598 {'s','e','l','e','c','t',' ','V','a','l','u','e',' ','f','r','o','m',' '
599 ,'_','P','r','o','p','e','r','t','y',' ','w','h','e','r','e',' '
600 ,'_','P','r','o','p','e','r','t','y','=','`',0};
602 static const WCHAR szEnd[]={'`',0};
606 return ERROR_INVALID_HANDLE;
608 if (NULL == szName) {
609 return ERROR_INVALID_PARAMETER;
612 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
614 return ERROR_INVALID_HANDLE;
616 strcatW(Query,szName);
617 strcatW(Query,szEnd);
619 rc = MsiDatabaseOpenViewW(package->db, Query, &view);
620 if (rc == ERROR_SUCCESS)
625 rc = MsiViewExecute(view, 0);
626 if (rc != ERROR_SUCCESS)
629 MsiCloseHandle(view);
633 rc = MsiViewFetch(view,&row);
634 if (rc == ERROR_SUCCESS)
637 rc = MsiRecordGetStringW(row,1,value,&sz);
638 strncpyW(szValueBuf,value,min(sz+1,*pchValueBuf));
643 MsiCloseHandle(view);
646 if (rc == ERROR_SUCCESS)
647 TRACE("returning %s for property %s\n", debugstr_w(szValueBuf),
652 TRACE("property not found\n");