Sweden-Number/dlls/msi/package.c

541 lines
14 KiB
C
Raw Normal View History

2004-06-30 21:38:36 +02:00
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2004 Aric Stewart for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define NONAMELESSUNION
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "winnls.h"
#include "shlwapi.h"
#include "wine/debug.h"
#include "msi.h"
#include "msiquery.h"
#include "msipriv.h"
#include "objidl.h"
#include "wincrypt.h"
#include "winuser.h"
#include "shlobj.h"
#include "wine/unicode.h"
#include "objbase.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
/*
* The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR,
* which is a problem because LPCTSTR isn't defined when compiling wine.
* To work around this problem, we need to define LPCTSTR as LPCWSTR here,
* and make sure to only use it in W functions.
*/
#define LPCTSTR LPCWSTR
void MSI_FreePackage( VOID *arg);
typedef struct tagMSIPACKAGE
{
MSIHANDLE db;
} MSIPACKAGE;
void MSI_FreePackage( VOID *arg)
{
MSIPACKAGE *package= arg;
MsiCloseHandle(package->db);
}
UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
{
LPWSTR szwPack = NULL;
UINT len, ret;
TRACE("%s %p\n",debugstr_a(szPackage), phPackage);
if( szPackage )
{
len = MultiByteToWideChar( CP_ACP, 0, szPackage, -1, NULL, 0 );
szwPack = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
if( szwPack )
MultiByteToWideChar( CP_ACP, 0, szPackage, -1, szwPack, len );
}
ret = MsiOpenPackageW( szwPack, phPackage );
if( szwPack )
HeapFree( GetProcessHeap(), 0, szwPack );
return ret;
}
static const void clone_properties(MSIHANDLE db)
{
MSIHANDLE view;
UINT rc;
static const CHAR CreateSql[] = "CREATE TABLE `_Property` ( `_Property` "
"CHAR(56) NOT NULL, `Value` CHAR(98) NOT NULL PRIMARY KEY `_Property`)";
static const CHAR Query[] = "SELECT * from Property";
static const CHAR Insert[] =
"INSERT into `_Property` (`_Property`,`Value`) VALUES (?)";
/* create the temporary properties table */
MsiDatabaseOpenViewA(db, CreateSql, &view);
MsiViewExecute(view,0);
MsiViewClose(view);
MsiCloseHandle(view);
/* clone the existing properties */
MsiDatabaseOpenViewA(db, Query, &view);
MsiViewExecute(view, 0);
while (1)
{
MSIHANDLE row;
MSIHANDLE view2;
rc = MsiViewFetch(view,&row);
if (rc != ERROR_SUCCESS)
break;
MsiDatabaseOpenViewA(db,Insert,&view2);
MsiViewExecute(view2,row);
MsiViewClose(view2);
MsiCloseHandle(view2);
MsiCloseHandle(row);
}
MsiViewClose(view);
MsiCloseHandle(view);
}
/*
* There are a whole slew of these we need to set
*
*
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/properties.asp
*/
static VOID set_installer_properties(MSIHANDLE hPackage)
{
WCHAR pth[MAX_PATH];
static const WCHAR cszbs[]={'\\',0};
static const WCHAR CFF[] =
{'C','o','m','m','o','n','F','i','l','e','s','F','o','l','d','e','r',0};
static const WCHAR PFF[] =
{'P','r','o','g','r','a','m','F','i','l','e','s','F','o','l','d','e','r',0};
static const WCHAR CADF[] =
{'C','o','m','m','o','n','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
static const WCHAR ATF[] =
{'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0};
static const WCHAR ADF[] =
{'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
static const WCHAR SF[] =
{'S','y','s','t','e','m','F','o','l','d','e','r',0};
static const WCHAR LADF[] =
{'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
static const WCHAR MPF[] =
{'M','y','P','i','c','t','u','r','e','s','F','o','l','d','e','r',0};
static const WCHAR PF[] =
{'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0};
static const WCHAR WF[] =
{'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
static const WCHAR TF[]=
{'T','e','m','p','F','o','l','d','e','r',0};
/* Not yet set ... but needed by iTunes
*
DesktopFolder
FavoritesFolder
FontsFolder
PrimaryVolumePath
ProgramFiles64Folder
ProgramMenuFolder
SendToFolder
StartMenuFolder
StartupFolder
System16Folder
System64Folder
TemplateFolder
*/
/* asked for by iTunes ... but are they installer set?
*
* GlobalAssemblyCache
*/
/*
* Other things i notice set
*
ScreenY
ScreenX
SystemLanguageID
ComputerName
UserLanguageID
LogonUser
VirtualMemory
PhysicalMemory
Intel
ShellAdvSupport
ServicePackLevel
WindowsBuild
Version9x
Version95
VersionNT
AdminUser
DefaultUIFont
VersionMsi
VersionDatabase
PackagecodeChanging
ProductState
CaptionHeight
BorderTop
BorderSide
TextHeight
ColorBits
RedirectedDllSupport
Time
Date
Privilaged
DATABASE
OriginalDatabase
UILevel
*/
SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth);
strcatW(pth,cszbs);
MsiSetPropertyW(hPackage, CFF, pth);
SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES,NULL,0,pth);
strcatW(pth,cszbs);
MsiSetPropertyW(hPackage, PFF, pth);
SHGetFolderPathW(NULL,CSIDL_COMMON_APPDATA,NULL,0,pth);
strcatW(pth,cszbs);
MsiSetPropertyW(hPackage, CADF, pth);
SHGetFolderPathW(NULL,CSIDL_ADMINTOOLS,NULL,0,pth);
strcatW(pth,cszbs);
MsiSetPropertyW(hPackage, ATF, pth);
SHGetFolderPathW(NULL,CSIDL_APPDATA,NULL,0,pth);
strcatW(pth,cszbs);
MsiSetPropertyW(hPackage, ADF, pth);
SHGetFolderPathW(NULL,CSIDL_SYSTEM,NULL,0,pth);
strcatW(pth,cszbs);
MsiSetPropertyW(hPackage, SF, pth);
SHGetFolderPathW(NULL,CSIDL_LOCAL_APPDATA,NULL,0,pth);
strcatW(pth,cszbs);
MsiSetPropertyW(hPackage, LADF, pth);
SHGetFolderPathW(NULL,CSIDL_MYPICTURES,NULL,0,pth);
strcatW(pth,cszbs);
MsiSetPropertyW(hPackage, MPF, pth);
SHGetFolderPathW(NULL,CSIDL_PERSONAL,NULL,0,pth);
strcatW(pth,cszbs);
MsiSetPropertyW(hPackage, PF, pth);
SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
strcatW(pth,cszbs);
MsiSetPropertyW(hPackage, WF, pth);
GetTempPathW(MAX_PATH,pth);
MsiSetPropertyW(hPackage, TF, pth);
}
UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
{
UINT rc;
MSIHANDLE handle;
MSIHANDLE db;
MSIPACKAGE *package;
static const WCHAR OriginalDatabase[] =
{'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
static const WCHAR Database[] =
{'D','A','T','A','B','A','S','E',0};
TRACE("%s %p\n",debugstr_w(szPackage), phPackage);
rc = MsiOpenDatabaseW(szPackage, MSIDBOPEN_READONLY, &db);
if (rc != ERROR_SUCCESS)
return ERROR_FUNCTION_FAILED;
handle = alloc_msihandle(MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE),
MSI_FreePackage, (void**)&package);
if (!handle)
{
MsiCloseHandle(db);
return ERROR_FUNCTION_FAILED;
}
package->db = db;
/* ok here is where we do a slew of things to the database to
* prep for all that is to come as a package */
clone_properties(db);
set_installer_properties(handle);
MsiSetPropertyW(handle, OriginalDatabase, szPackage);
MsiSetPropertyW(handle, Database, szPackage);
*phPackage = handle;
return ERROR_SUCCESS;
}
UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
{
FIXME("%s 0x%08lx %p\n",debugstr_a(szPackage), dwOptions, phPackage);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
{
FIXME("%s 0x%08lx %p\n",debugstr_w(szPackage), dwOptions, phPackage);
return ERROR_CALL_NOT_IMPLEMENTED;
}
MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
{
MSIPACKAGE *package;
TRACE("(%i)\n",(INT)hInstall);
package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
if( !package)
return ERROR_INVALID_HANDLE;
msihandle_addref(package->db);
return package->db;
}
INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
MSIHANDLE hRecord)
{
FIXME("STUB: \n");
return ERROR_SUCCESS;
}
/* property code */
UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue)
{
LPWSTR szwName = NULL, szwValue = NULL;
UINT hr = ERROR_INSTALL_FAILURE;
UINT len;
if (0 == hInstall) {
return ERROR_INVALID_HANDLE;
}
if (NULL == szName) {
return ERROR_INVALID_PARAMETER;
}
if (NULL == szValue) {
return ERROR_INVALID_PARAMETER;
}
len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
if( !szwName )
goto end;
MultiByteToWideChar( CP_ACP, 0, szName, -1, szwName, len );
len = MultiByteToWideChar( CP_ACP, 0, szValue, -1, NULL, 0 );
szwValue = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
if( !szwValue)
goto end;
MultiByteToWideChar( CP_ACP, 0, szValue , -1, szwValue, len );
hr = MsiSetPropertyW( hInstall, szwName, szwValue);
end:
if( szwName )
HeapFree( GetProcessHeap(), 0, szwName );
if( szwValue )
HeapFree( GetProcessHeap(), 0, szwValue );
return hr;
}
UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
{
MSIPACKAGE *package;
MSIHANDLE view,row;
UINT rc;
DWORD sz = 0;
static const CHAR Insert[]=
"INSERT into `_Property` (`_Property`,`Value`) VALUES (?)";
TRACE("Setting property (%s %s)\n",debugstr_w(szName),
debugstr_w(szValue));
if (!hInstall)
return ERROR_INVALID_HANDLE;
if (MsiGetPropertyW(hInstall,szName,0,&sz)==ERROR_MORE_DATA)
{
FIXME("Cannot set exising properties! FIXME MIKE!\n");
return ERROR_FUNCTION_FAILED;
}
package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
if( !package)
return ERROR_INVALID_HANDLE;
rc = MsiDatabaseOpenViewA(package->db,Insert,&view);
if (rc!= ERROR_SUCCESS)
return rc;
row = MsiCreateRecord(2);
MsiRecordSetStringW(row,1,szName);
MsiRecordSetStringW(row,2,szValue);
rc = MsiViewExecute(view,row);
MsiCloseHandle(row);
MsiViewClose(view);
MsiCloseHandle(view);
return rc;
}
UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, DWORD* pchValueBuf)
{
LPWSTR szwName = NULL, szwValueBuf = NULL;
UINT hr = ERROR_INSTALL_FAILURE;
if (0 == hInstall) {
return ERROR_INVALID_HANDLE;
}
if (NULL == szName) {
return ERROR_INVALID_PARAMETER;
}
TRACE("%lu %s %lu\n", hInstall, debugstr_a(szName), *pchValueBuf);
if (NULL != szValueBuf && NULL == pchValueBuf) {
return ERROR_INVALID_PARAMETER;
}
if( szName )
{
UINT len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
if( !szwName )
goto end;
MultiByteToWideChar( CP_ACP, 0, szName, -1, szwName, len );
} else {
return ERROR_INVALID_PARAMETER;
}
if( szValueBuf )
{
szwValueBuf = HeapAlloc( GetProcessHeap(), 0, (*pchValueBuf) * sizeof(WCHAR) );
if( !szwValueBuf )
goto end;
}
hr = MsiGetPropertyW( hInstall, szwName, szwValueBuf, pchValueBuf );
if( *pchValueBuf > 0 )
{
WideCharToMultiByte(CP_ACP, 0, szwValueBuf, -1, szValueBuf, *pchValueBuf, NULL, NULL);
}
end:
if( szwName )
HeapFree( GetProcessHeap(), 0, szwName );
if( szwValueBuf )
HeapFree( GetProcessHeap(), 0, szwValueBuf );
return hr;
}
UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName,
LPWSTR szValueBuf, DWORD* pchValueBuf)
{
MSIHANDLE view,row;
UINT rc;
WCHAR Query[1024]=
{'s','e','l','e','c','t',' ','V','a','l','u','e',' ','f','r','o','m',' '
,'_','P','r','o','p','e','r','t','y',' ','w','h','e','r','e',' '
,'_','P','r','o','p','e','r','t','y','=','`',0};
static const WCHAR szEnd[]={'`',0};
MSIPACKAGE *package;
if (0 == hInstall) {
return ERROR_INVALID_HANDLE;
}
if (NULL == szName) {
return ERROR_INVALID_PARAMETER;
}
package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
if( !package)
return ERROR_INVALID_HANDLE;
strcatW(Query,szName);
strcatW(Query,szEnd);
rc = MsiDatabaseOpenViewW(package->db, Query, &view);
if (rc == ERROR_SUCCESS)
{
DWORD sz;
WCHAR value[0x100];
rc = MsiViewExecute(view, 0);
if (rc != ERROR_SUCCESS)
{
MsiViewClose(view);
MsiCloseHandle(view);
return rc;
}
rc = MsiViewFetch(view,&row);
if (rc == ERROR_SUCCESS)
{
sz=0x100;
rc = MsiRecordGetStringW(row,1,value,&sz);
strncpyW(szValueBuf,value,min(sz+1,*pchValueBuf));
*pchValueBuf = sz+1;
MsiCloseHandle(row);
}
MsiViewClose(view);
MsiCloseHandle(view);
}
if (rc == ERROR_SUCCESS)
TRACE("returning %s for property %s\n", debugstr_w(szValueBuf),
debugstr_w(szName));
else
{
*pchValueBuf = 0;
TRACE("property not found\n");
}
return rc;
}