/* * Implementation of the Microsoft Installer (msi.dll) * * Copyright 2002,2003,2004 Mike McCormack 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 */ #include #define COBJMACROS #define NONAMELESSUNION #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 "wine/unicode.h" #include "objbase.h" #include "winver.h" #include "initguid.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 DEFINE_GUID( CLSID_MsiDatabase, 0x000c1084, 0x0000, 0x0000, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); static const WCHAR szInstaller[] = { 'S','o','f','t','w','a','r','e','\\', 'M','i','c','r','o','s','o','f','t','\\', 'W','i','n','d','o','w','s','\\', 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', 'I','n','s','t','a','l','l','e','r',0 }; static const WCHAR szFeatures[] = { 'F','e','a','t','u','r','e','s',0 }; static const WCHAR szComponents[] = { 'C','o','m','p','o','n','e','n','t','s',0 }; /* the UI level */ INSTALLUILEVEL gUILevel; HWND gUIhwnd; INSTALLUI_HANDLERA gUIHandler; INSTALLUI_HANDLERW gUIHandlerW; DWORD gUIFilter; LPVOID gUIContext; WCHAR gszLogFile[MAX_PATH]; /* * .MSI file format * * A .msi file is a structured storage file. * It should contain a number of streams. */ BOOL unsquash_guid(LPCWSTR in, LPWSTR out) { DWORD i,n=0; out[n++]='{'; for(i=0; i<8; i++) out[n++] = in[7-i]; out[n++]='-'; for(i=0; i<4; i++) out[n++] = in[11-i]; out[n++]='-'; for(i=0; i<4; i++) out[n++] = in[15-i]; out[n++]='-'; for(i=0; i<2; i++) { out[n++] = in[17+i*2]; out[n++] = in[16+i*2]; } out[n++]='-'; for( ; i<8; i++) { out[n++] = in[17+i*2]; out[n++] = in[16+i*2]; } out[n++]='}'; out[n]=0; return TRUE; } BOOL squash_guid(LPCWSTR in, LPWSTR out) { DWORD i,n=0; if(in[n++] != '{') return FALSE; for(i=0; i<8; i++) out[7-i] = in[n++]; if(in[n++] != '-') return FALSE; for(i=0; i<4; i++) out[11-i] = in[n++]; if(in[n++] != '-') return FALSE; for(i=0; i<4; i++) out[15-i] = in[n++]; if(in[n++] != '-') return FALSE; for(i=0; i<2; i++) { out[17+i*2] = in[n++]; out[16+i*2] = in[n++]; } if(in[n++] != '-') return FALSE; for( ; i<8; i++) { out[17+i*2] = in[n++]; out[16+i*2] = in[n++]; } out[32]=0; if(in[n++] != '}') return FALSE; if(in[n]) return FALSE; return TRUE; } /* tables for encoding and decoding base85 */ static const unsigned char table_dec85[0x80] = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x00,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0xff, 0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0xff,0xff,0xff,0x16,0xff,0x17, 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0x34,0x35,0x36, 0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46, 0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0xff,0x53,0x54,0xff, }; static const char table_enc85[] = "!$%&'()*+,-.0123456789=?@ABCDEFGHIJKLMNO" "PQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwx" "yz{}~"; /* * Converts a base85 encoded guid into a GUID pointer * Base85 encoded GUIDs should be 20 characters long. * * returns TRUE if successful, FALSE if not */ BOOL decode_base85_guid( LPCWSTR str, GUID *guid ) { DWORD i, val = 0, base = 1, *p; p = (DWORD*) guid; for( i=0; i<20; i++ ) { if( (i%5) == 0 ) { val = 0; base = 1; } val += table_dec85[str[i]] * base; if( str[i] >= 0x80 ) return FALSE; if( table_dec85[str[i]] == 0xff ) return FALSE; if( (i%5) == 4 ) p[i/5] = val; base *= 85; } return TRUE; } /* * Encodes a base85 guid given a GUID pointer * Caller should provide a 21 character buffer for the encoded string. * * returns TRUE if successful, FALSE if not */ BOOL encode_base85_guid( GUID *guid, LPWSTR str ) { unsigned int x, *p, i; p = (unsigned int*) guid; for( i=0; i<4; i++ ) { x = p[i]; *str++ = table_enc85[x%85]; x = x/85; *str++ = table_enc85[x%85]; x = x/85; *str++ = table_enc85[x%85]; x = x/85; *str++ = table_enc85[x%85]; x = x/85; *str++ = table_enc85[x%85]; } *str = 0; return TRUE; } VOID MSI_CloseDatabase( MSIOBJECTHDR *arg ) { MSIDATABASE *db = (MSIDATABASE *) arg; free_cached_tables( db ); IStorage_Release( db->storage ); } UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb) { IStorage *stg = NULL; HRESULT r; MSIDATABASE *db = NULL; UINT ret = ERROR_FUNCTION_FAILED; LPWSTR szMode; STATSTG stat; TRACE("%s %s\n",debugstr_w(szDBPath),debugstr_w(szPersist) ); if( !pdb ) return ERROR_INVALID_PARAMETER; szMode = (LPWSTR) szPersist; if( HIWORD( szPersist ) ) { /* UINT len = lstrlenW( szPerist ) + 1; */ FIXME("don't support persist files yet\b"); return ERROR_INVALID_PARAMETER; /* szMode = HeapAlloc( GetProcessHeap(), 0, len * sizeof (DWORD) ); */ } else if( szPersist == MSIDBOPEN_READONLY ) { r = StgOpenStorage( szDBPath, NULL, STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg); } else if( szPersist == MSIDBOPEN_CREATE ) { r = StgCreateDocfile( szDBPath, STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, &stg); if( r == ERROR_SUCCESS ) { IStorage_SetClass( stg, &CLSID_MsiDatabase ); r = init_string_table( stg ); } } else if( szPersist == MSIDBOPEN_TRANSACT ) { r = StgOpenStorage( szDBPath, NULL, STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg); } else { ERR("unknown flag %p\n",szPersist); return ERROR_INVALID_PARAMETER; } if( FAILED( r ) ) { FIXME("open failed r = %08lx!\n",r); return ERROR_FUNCTION_FAILED; } r = IStorage_Stat( stg, &stat, STATFLAG_NONAME ); if( FAILED( r ) ) { FIXME("Failed to stat storage\n"); goto end; } if( memcmp( &stat.clsid, &CLSID_MsiDatabase, sizeof (GUID) ) ) { ERR("storage GUID is not a MSI database GUID %s\n", debugstr_guid(&stat.clsid) ); goto end; } db = alloc_msiobject( MSIHANDLETYPE_DATABASE, sizeof (MSIDATABASE), MSI_CloseDatabase ); if( !db ) { FIXME("Failed to allocate a handle\n"); goto end; } if( TRACE_ON( msi ) ) enum_stream_names( stg ); db->storage = stg; db->mode = szMode; ret = load_string_table( db ); if( ret != ERROR_SUCCESS ) goto end; msiobj_addref( &db->hdr ); IStorage_AddRef( stg ); *pdb = db; end: if( db ) msiobj_release( &db->hdr ); if( stg ) IStorage_Release( stg ); return ret; } UINT WINAPI MsiOpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIHANDLE *phDB) { MSIDATABASE *db; UINT ret; TRACE("%s %s %p\n",debugstr_w(szDBPath),debugstr_w(szPersist), phDB); ret = MSI_OpenDatabaseW( szDBPath, szPersist, &db ); if( ret == ERROR_SUCCESS ) { *phDB = alloc_msihandle( &db->hdr ); msiobj_release( &db->hdr ); } return ret; } UINT WINAPI MsiOpenDatabaseA(LPCSTR szDBPath, LPCSTR szPersist, MSIHANDLE *phDB) { HRESULT r = ERROR_FUNCTION_FAILED; LPWSTR szwDBPath = NULL, szwPersist = NULL; UINT len; TRACE("%s %s %p\n", debugstr_a(szDBPath), debugstr_a(szPersist), phDB); if( szDBPath ) { len = MultiByteToWideChar( CP_ACP, 0, szDBPath, -1, NULL, 0 ); szwDBPath = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); if( !szwDBPath ) goto end; MultiByteToWideChar( CP_ACP, 0, szDBPath, -1, szwDBPath, len ); } if( HIWORD(szPersist) ) { len = MultiByteToWideChar( CP_ACP, 0, szPersist, -1, NULL, 0 ); szwPersist = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); if( !szwPersist ) goto end; MultiByteToWideChar( CP_ACP, 0, szPersist, -1, szwPersist, len ); } else szwPersist = (LPWSTR) szPersist; r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB ); end: if( szwPersist ) HeapFree( GetProcessHeap(), 0, szwPersist ); if( szwDBPath ) HeapFree( GetProcessHeap(), 0, szwDBPath ); return r; } UINT WINAPI MsiOpenProductA(LPCSTR szProduct, MSIHANDLE *phProduct) { UINT len, ret; LPWSTR szwProd = NULL; TRACE("%s %p\n",debugstr_a(szProduct), phProduct); if( szProduct ) { len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 ); szwProd = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) ); if( szwProd ) MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProd, len ); } ret = MsiOpenProductW( szwProd, phProduct ); if( szwProd ) HeapFree( GetProcessHeap(), 0, szwProd ); return ret; } UINT WINAPI MsiOpenProductW(LPCWSTR szProduct, MSIHANDLE *phProduct) { static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\', 'M','i','c','r','o','s','o','f','t','\\', 'W','i','n','d','o','w','s','\\', 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', 'U','n','i','n','s','t','a','l','l',0 }; static const WCHAR szLocalPackage[] = { 'L','o','c','a','l','P','a','c','k','a','g','e', 0 }; LPWSTR path = NULL; UINT r; HKEY hKeyProduct = NULL, hKeyUninstall = NULL; DWORD count, type; TRACE("%s %p\n",debugstr_w(szProduct), phProduct); r = RegOpenKeyW( HKEY_LOCAL_MACHINE, szKey, &hKeyUninstall ); if( r != ERROR_SUCCESS ) return ERROR_UNKNOWN_PRODUCT; r = RegOpenKeyW( hKeyUninstall, szProduct, &hKeyProduct ); if( r != ERROR_SUCCESS ) { r = ERROR_UNKNOWN_PRODUCT; goto end; } /* find the size of the path */ type = count = 0; r = RegQueryValueExW( hKeyProduct, szLocalPackage, NULL, &type, NULL, &count ); if( r != ERROR_SUCCESS ) { r = ERROR_UNKNOWN_PRODUCT; goto end; } /* now alloc and fetch the path of the database to open */ path = HeapAlloc( GetProcessHeap(), 0, count ); if( !path ) goto end; r = RegQueryValueExW( hKeyProduct, szLocalPackage, NULL, &type, (LPBYTE) path, &count ); if( r != ERROR_SUCCESS ) { r = ERROR_UNKNOWN_PRODUCT; goto end; } r = MsiOpenPackageW( path, phProduct ); end: if( path ) HeapFree( GetProcessHeap(), 0, path ); if( hKeyProduct ) RegCloseKey( hKeyProduct ); RegCloseKey( hKeyUninstall ); return r; } UINT WINAPI MsiAdvertiseProductA(LPCSTR szPackagePath, LPCSTR szScriptfilePath, LPCSTR szTransforms, LANGID lgidLanguage) { FIXME("%s %s %s 0x%08x\n",debugstr_a(szPackagePath), debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiAdvertiseProductW(LPCWSTR szPackagePath, LPCWSTR szScriptfilePath, LPCWSTR szTransforms, LANGID lgidLanguage) { FIXME("%s %s %s 0x%08x\n",debugstr_w(szPackagePath), debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiAdvertiseProductExA(LPCSTR szPackagePath, LPCSTR szScriptfilePath, LPCSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions) { FIXME("%s %s %s 0x%08x 0x%08lx 0x%08lx\n", debugstr_a(szPackagePath), debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage, dwPlatform, dwOptions); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiAdvertiseProductExW( LPCWSTR szPackagePath, LPCWSTR szScriptfilePath, LPCWSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions) { FIXME("%s %s %s 0x%08x 0x%08lx 0x%08lx\n", debugstr_w(szPackagePath), debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage, dwPlatform, dwOptions); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiInstallProductA(LPCSTR szPackagePath, LPCSTR szCommandLine) { LPWSTR szwPath = NULL, szwCommand = NULL; UINT r = ERROR_FUNCTION_FAILED; /* FIXME: check return code */ TRACE("%s %s\n",debugstr_a(szPackagePath), debugstr_a(szCommandLine)); if( szPackagePath ) { UINT len = MultiByteToWideChar( CP_ACP, 0, szPackagePath, -1, NULL, 0 ); szwPath = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); if( !szwPath ) goto end; MultiByteToWideChar( CP_ACP, 0, szPackagePath, -1, szwPath, len ); } if( szCommandLine ) { UINT len = MultiByteToWideChar( CP_ACP, 0, szCommandLine, -1, NULL, 0 ); szwCommand = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); if( !szwCommand ) goto end; MultiByteToWideChar( CP_ACP, 0, szCommandLine, -1, szwCommand, len ); } r = MsiInstallProductW( szwPath, szwCommand ); end: if( szwPath ) HeapFree( GetProcessHeap(), 0, szwPath ); if( szwCommand ) HeapFree( GetProcessHeap(), 0, szwCommand ); return r; } UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine) { MSIPACKAGE *package = NULL; UINT rc = ERROR_SUCCESS; MSIHANDLE handle; FIXME("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine)); rc = MsiVerifyPackageW(szPackagePath); if (rc != ERROR_SUCCESS) return rc; rc = MSI_OpenPackageW(szPackagePath,&package); if (rc != ERROR_SUCCESS) return rc; handle = alloc_msihandle( &package->hdr ); rc = ACTION_DoTopLevelINSTALL(package, szPackagePath, szCommandLine); MsiCloseHandle(handle); msiobj_release( &package->hdr ); return rc; } UINT WINAPI MsiReinstallProductA(LPCSTR szProduct, DWORD dwReinstallMode) { FIXME("%s 0x%08lx\n", debugstr_a(szProduct), dwReinstallMode); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiReinstallProductW(LPCWSTR szProduct, DWORD dwReinstallMode) { FIXME("%s 0x%08lx\n", debugstr_w(szProduct), dwReinstallMode); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiApplyPatchA(LPCSTR szPatchPackage, LPCSTR szInstallPackage, INSTALLTYPE eInstallType, LPCSTR szCommandLine) { FIXME("%s %s %d %s\n", debugstr_a(szPatchPackage), debugstr_a(szInstallPackage), eInstallType, debugstr_a(szCommandLine)); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szInstallPackage, INSTALLTYPE eInstallType, LPCWSTR szCommandLine) { FIXME("%s %s %d %s\n", debugstr_w(szPatchPackage), debugstr_w(szInstallPackage), eInstallType, debugstr_w(szCommandLine)); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState, LPCWSTR szCommandLine) { MSIHANDLE handle; MSIPACKAGE* package; UINT rc; WCHAR squished_pc[0x100]; HKEY hkey=0,hkey2=0,hkey3=0,hkey4=0; static const WCHAR szInstaller[] = { 'S','o','f','t','w','a','r','e','\\', 'M','i','c','r','o','s','o','f','t','\\', 'I','n','s','t','a','l','l','e','r',0 }; static const WCHAR szProducts[] = { 'P','r','o','d','u','c','t','s',0 }; DWORD sz; static const WCHAR szSouceList[] = { 'S','o','u','r','c','e','L','i','s','t',0}; static const WCHAR szLUS[] = { 'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0}; WCHAR sourcepath[0x200]; static const WCHAR szInstalled[] = { ' ','I','n','s','t','a','l','l','e','d','=','1',0}; LPWSTR commandline; FIXME("%s %d %d %s\n",debugstr_w(szProduct), iInstallLevel, eInstallState, debugstr_w(szCommandLine)); if (eInstallState != INSTALLSTATE_LOCAL) { FIXME("Not implemented for anything other than local installs\n"); return ERROR_CALL_NOT_IMPLEMENTED; } squash_guid(szProduct,squished_pc); TRACE("squished (%s)\n", debugstr_w(squished_pc)); rc = RegOpenKeyW(HKEY_CURRENT_USER,szInstaller,&hkey); if (rc != ERROR_SUCCESS) goto end; /* check the products key for the product */ rc = RegOpenKeyW(hkey,szProducts,&hkey2); if (rc != ERROR_SUCCESS) goto end; rc = RegOpenKeyW(hkey2,squished_pc,&hkey3); if (rc != ERROR_SUCCESS) goto end; rc = RegOpenKeyW(hkey3,szSouceList,&hkey4); if (rc != ERROR_SUCCESS) goto end; sz = sizeof(sourcepath); rc = RegQueryValueExW(hkey4, szLUS, NULL, NULL,(LPBYTE)sourcepath, &sz); if (rc != ERROR_SUCCESS) goto end; /* * ok 1, we need to find the msi file for this product. * 2, find the source dir for the files * 3, do the configure/install. 4, cleanupany runonce entry. */ rc = MsiOpenProductW(szProduct,&handle); if (rc != ERROR_SUCCESS) goto end; package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE); sz = strlenW(szInstalled); if (szCommandLine) sz += strlenW(szCommandLine); commandline = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR)); if (szCommandLine) strcpyW(commandline,szCommandLine); else commandline[0] = 0; if (MsiQueryProductStateW(szProduct) == iInstallLevel) strcatW(commandline,szInstalled); rc = ACTION_DoTopLevelINSTALL(package, sourcepath, commandline); HeapFree(GetProcessHeap(),0,commandline); end: RegCloseKey(hkey3); RegCloseKey(hkey2); RegCloseKey(hkey); return rc; } UINT WINAPI MsiConfigureProductA(LPCSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState) { LPWSTR szwProduct = NULL; UINT hr = ERROR_SUCCESS; FIXME("%s %d %d\n",debugstr_a(szProduct), iInstallLevel, eInstallState); if( szProduct ) { UINT len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 ); szwProduct = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); if( !szwProduct ) goto end; MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProduct, len ); } hr = MsiConfigureProductW( szwProduct, iInstallLevel, eInstallState ); end: if( szwProduct ) HeapFree( GetProcessHeap(), 0, szwProduct ); return hr; } UINT WINAPI MsiConfigureProductW(LPCWSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState) { FIXME("%s %d %d\n",debugstr_w(szProduct), iInstallLevel, eInstallState); return MsiConfigureProductExW(szProduct, iInstallLevel, eInstallState, NULL); } UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer) { LPWSTR szwComponent = NULL, szwBuffer = NULL; UINT hr = ERROR_INSTALL_FAILURE; FIXME("%s %s\n",debugstr_a(szComponent), debugstr_a(szBuffer)); if( szComponent ) { UINT len = MultiByteToWideChar( CP_ACP, 0, szComponent, -1, NULL, 0 ); szwComponent = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); if( !szwComponent ) goto end; MultiByteToWideChar( CP_ACP, 0, szComponent, -1, szwComponent, len ); } else { return ERROR_INVALID_PARAMETER; } { szwBuffer = HeapAlloc( GetProcessHeap(), 0, GUID_SIZE * sizeof(WCHAR) ); if( !szwBuffer ) goto end; } hr = MsiGetProductCodeW( szwComponent, szwBuffer ); if( ERROR_SUCCESS == hr ) { WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, GUID_SIZE, NULL, NULL); } end: if( szwComponent ) HeapFree( GetProcessHeap(), 0, szwComponent ); if( szwBuffer ) HeapFree( GetProcessHeap(), 0, szwBuffer ); return hr; } UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer) { FIXME("%s %s\n",debugstr_w(szComponent), debugstr_w(szBuffer)); if (NULL == szComponent) { return ERROR_INVALID_PARAMETER; } return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute, LPSTR szBuffer, DWORD *pcchValueBuf) { LPWSTR szwProduct = NULL, szwAttribute = NULL, szwBuffer = NULL; UINT hr = ERROR_INSTALL_FAILURE; FIXME("%s %s %p %p\n",debugstr_a(szProduct), debugstr_a(szAttribute), szBuffer, pcchValueBuf); if (NULL != szBuffer && NULL == pcchValueBuf) { return ERROR_INVALID_PARAMETER; } if( szProduct ) { UINT len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 ); szwProduct = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); if( !szwProduct ) goto end; MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProduct, len ); } else { return ERROR_INVALID_PARAMETER; } if( szAttribute ) { UINT len = MultiByteToWideChar( CP_ACP, 0, szAttribute, -1, NULL, 0 ); szwAttribute = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); if( !szwAttribute ) goto end; MultiByteToWideChar( CP_ACP, 0, szAttribute, -1, szwAttribute, len ); } else { hr = ERROR_INVALID_PARAMETER; goto end; } if( szBuffer ) { szwBuffer = HeapAlloc( GetProcessHeap(), 0, (*pcchValueBuf) * sizeof(WCHAR) ); if( !szwBuffer ) goto end; } hr = MsiGetProductInfoW( szwProduct, szwAttribute, szwBuffer, pcchValueBuf ); if( ERROR_SUCCESS == hr ) { WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, *pcchValueBuf, NULL, NULL); } end: if( szwProduct ) HeapFree( GetProcessHeap(), 0, szwProduct ); if( szwAttribute ) HeapFree( GetProcessHeap(), 0, szwAttribute ); if( szwBuffer ) HeapFree( GetProcessHeap(), 0, szwBuffer ); return hr; } UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szBuffer, DWORD *pcchValueBuf) { MSIHANDLE hProduct; UINT hr; FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szAttribute), szBuffer, pcchValueBuf); if (NULL != szBuffer && NULL == pcchValueBuf) { return ERROR_INVALID_PARAMETER; } if (NULL == szProduct || NULL == szAttribute) { return ERROR_INVALID_PARAMETER; } hr = MsiOpenProductW(szProduct, &hProduct); if (ERROR_SUCCESS != hr) return hr; hr = MsiGetPropertyW(hProduct, szAttribute, szBuffer, pcchValueBuf); MsiCloseHandle(hProduct); return hr; } UINT WINAPI MsiDatabaseImportA(LPCSTR szFolderPath, LPCSTR szFilename) { FIXME("%s %s\n",debugstr_a(szFolderPath), debugstr_a(szFilename)); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiDatabaseImportW(LPCWSTR szFolderPath, LPCWSTR szFilename) { FIXME("%s %s\n",debugstr_w(szFolderPath), debugstr_w(szFilename)); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes) { LPWSTR szwLogFile = NULL; UINT hr = ERROR_INSTALL_FAILURE; FIXME("%08lx %s %08lx\n", dwLogMode, debugstr_a(szLogFile), attributes); if( szLogFile ) { UINT len = MultiByteToWideChar( CP_ACP, 0, szLogFile, -1, NULL, 0 ); szwLogFile = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); if( !szwLogFile ) goto end; MultiByteToWideChar( CP_ACP, 0, szLogFile, -1, szwLogFile, len ); } else { return ERROR_INVALID_PARAMETER; } hr = MsiEnableLogW( dwLogMode, szwLogFile, attributes ); end: if( szwLogFile ) HeapFree( GetProcessHeap(), 0, szwLogFile ); return hr; } UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes) { HANDLE the_file = INVALID_HANDLE_VALUE; TRACE("%08lx %s %08lx\n", dwLogMode, debugstr_w(szLogFile), attributes); strcpyW(gszLogFile,szLogFile); if (!(attributes & INSTALLLOGATTRIBUTES_APPEND)) DeleteFileW(szLogFile); the_file = CreateFileW(szLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (the_file != INVALID_HANDLE_VALUE) CloseHandle(the_file); else ERR("Unable to enable log %s\n",debugstr_w(szLogFile)); return ERROR_SUCCESS; } INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct) { LPWSTR szwProduct; UINT len; INSTALLSTATE rc; len = MultiByteToWideChar(CP_ACP,0,szProduct,-1,NULL,0); szwProduct = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); MultiByteToWideChar(CP_ACP,0,szProduct,-1,szwProduct,len); rc = MsiQueryProductStateW(szwProduct); HeapFree(GetProcessHeap(),0,szwProduct); return rc; } INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct) { WCHAR squished_pc[0x100]; UINT rc; INSTALLSTATE rrc = INSTALLSTATE_UNKNOWN; HKEY hkey=0,hkey2=0,hkey3=0; static const WCHAR szInstaller[] = { 'S','o','f','t','w','a','r','e','\\', 'M','i','c','r','o','s','o','f','t','\\', 'I','n','s','t','a','l','l','e','r',0 }; static const WCHAR szUninstaller[] = { 'S','o','f','t','w','a','r','e','\\', 'M','i','c','r','o','s','o','f','t','\\', 'W','i','n','d','o','w','s','\\', 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', 'U','n','i','n','s','t','a','l','l',0 }; static const WCHAR szProducts[] = { 'P','r','o','d','u','c','t','s',0 }; static const WCHAR szWindowsInstaller[] = { 'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0 }; DWORD sz; TRACE("%s\n", debugstr_w(szProduct)); squash_guid(szProduct,squished_pc); TRACE("squished (%s)\n", debugstr_w(squished_pc)); rc = RegOpenKeyW(HKEY_CURRENT_USER,szInstaller,&hkey); if (rc != ERROR_SUCCESS) goto end; /* check the products key for the product */ rc = RegOpenKeyW(hkey,szProducts,&hkey2); if (rc != ERROR_SUCCESS) goto end; rc = RegOpenKeyW(hkey2,squished_pc,&hkey3); if (rc != ERROR_SUCCESS) goto end; RegCloseKey(hkey3); RegCloseKey(hkey2); RegCloseKey(hkey); rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,szUninstaller,&hkey); if (rc != ERROR_SUCCESS) goto end; rc = RegOpenKeyW(hkey,szProduct,&hkey2); if (rc != ERROR_SUCCESS) goto end; sz = sizeof(rrc); rc = RegQueryValueExW(hkey2,szWindowsInstaller,NULL,NULL,(LPVOID)&rrc, &sz); if (rc != ERROR_SUCCESS) goto end; switch (rrc) { case 1: /* default */ rrc = INSTALLSTATE_DEFAULT; break; default: FIXME("Unknown install state read from registry (%i)\n",rrc); rrc = INSTALLSTATE_UNKNOWN; break; } end: RegCloseKey(hkey3); RegCloseKey(hkey2); RegCloseKey(hkey); return rrc; } INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd) { INSTALLUILEVEL old = gUILevel; HWND oldwnd = gUIhwnd; TRACE("%08x %p\n", dwUILevel, phWnd); gUILevel = dwUILevel; if (phWnd) { gUIhwnd = *phWnd; *phWnd = oldwnd; } return old; } INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler, DWORD dwMessageFilter, LPVOID pvContext) { INSTALLUI_HANDLERA prev = gUIHandler; TRACE("(%p %lx %p)\n",puiHandler, dwMessageFilter,pvContext); gUIHandler = puiHandler; gUIFilter = dwMessageFilter; gUIContext = pvContext; return prev; } INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler, DWORD dwMessageFilter, LPVOID pvContext) { INSTALLUI_HANDLERW prev = gUIHandlerW; TRACE("(%p %lx %p)\n",puiHandler,dwMessageFilter,pvContext); gUIHandlerW = puiHandler; gUIFilter = dwMessageFilter; gUIContext = pvContext; return prev; } UINT WINAPI MsiLoadStringA(HINSTANCE hInstance, UINT uID, LPSTR lpBuffer, int nBufferMax, DWORD e) { /*FIXME("%08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e);*/ FIXME("%p %u %p %d %08lx\n",hInstance,uID,lpBuffer,nBufferMax,e); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiLoadStringW(HINSTANCE hInstance, UINT uID, LPWSTR lpBuffer, int nBufferMax, DWORD e) { FIXME("%p %u %p %d %08lx\n",hInstance,uID,lpBuffer,nBufferMax,e); /* int ret = LoadStringW(hInstance,uID,lpBuffer,nBufferMax); FIXME("%s\n",debugstr_w(lpBuffer)); return ret; */ return ERROR_CALL_NOT_IMPLEMENTED; } INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf, DWORD *pcchBuf) { FIXME("%s %p %08lx\n", debugstr_a(szComponent), lpPathBuf, *pcchBuf); return INSTALLSTATE_UNKNOWN; } INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPSTR lpPathBuf, DWORD *pcchBuf) { FIXME("%s %p %08lx\n", debugstr_w(szComponent), lpPathBuf, *pcchBuf); return INSTALLSTATE_UNKNOWN; } #include "winuser.h" UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType, WORD wLanguageId, DWORD f) { FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_a(lpText),debugstr_a(lpCaption),uType,wLanguageId,f); /* MessageBoxExA(hWnd,lpText,lpCaption,uType|MB_OK,wLanguageId); */ return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType, WORD wLanguageId, DWORD f) { /*FIXME("%08lx %08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e,f);*/ FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_w(lpText),debugstr_w(lpCaption),uType,wLanguageId,f); /* MessageBoxExW(hWnd,lpText,lpCaption,uType|MB_OK,wLanguageId); */ return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid) { DWORD r; WCHAR szwGuid[GUID_SIZE]; TRACE("%ld %p\n",index,lpguid); if (NULL == lpguid) { return ERROR_INVALID_PARAMETER; } r = MsiEnumProductsW(index, szwGuid); if( r == ERROR_SUCCESS ) WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL); return r; } UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid) { HKEY hkey = 0, hkeyFeatures = 0; DWORD r; WCHAR szKeyName[33]; TRACE("%ld %p\n",index,lpguid); if (NULL == lpguid) { return ERROR_INVALID_PARAMETER; } r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey); if( r != ERROR_SUCCESS ) goto end; r = RegOpenKeyW(hkey, szFeatures, &hkeyFeatures); if( r != ERROR_SUCCESS ) goto end; r = RegEnumKeyW(hkeyFeatures, index, szKeyName, GUID_SIZE); unsquash_guid(szKeyName, lpguid); end: if( hkeyFeatures ) RegCloseKey(hkeyFeatures); if( hkey ) RegCloseKey(hkey); return r; } UINT WINAPI MsiEnumFeaturesA(LPCSTR szProduct, DWORD index, LPSTR szFeature, LPSTR szParent) { DWORD r; WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE]; LPWSTR szwProduct = NULL; TRACE("%s %ld %p %p\n",debugstr_a(szProduct),index,szFeature,szParent); if( szProduct ) { UINT len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 ); szwProduct = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) ); if( szwProduct ) MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProduct, len ); else return ERROR_FUNCTION_FAILED; } r = MsiEnumFeaturesW(szwProduct, index, szwFeature, szwParent); if( r == ERROR_SUCCESS ) { WideCharToMultiByte(CP_ACP, 0, szwFeature, -1, szFeature, GUID_SIZE, NULL, NULL); WideCharToMultiByte(CP_ACP, 0, szwParent, -1, szParent, GUID_SIZE, NULL, NULL); } if( szwProduct ) HeapFree( GetProcessHeap(), 0, szwProduct); return r; } UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index, LPWSTR szFeature, LPWSTR szParent) { HKEY hkey = 0, hkeyFeatures = 0, hkeyProduct = 0; DWORD r, sz; WCHAR szRegName[GUID_SIZE]; TRACE("%s %ld %p %p\n",debugstr_w(szProduct),index,szFeature,szParent); if( !squash_guid(szProduct, szRegName) ) return ERROR_INVALID_PARAMETER; r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey); if( r != ERROR_SUCCESS ) goto end; r = RegOpenKeyW(hkey, szFeatures, &hkeyFeatures); if( r != ERROR_SUCCESS ) goto end; r = RegOpenKeyW(hkeyFeatures, szRegName, &hkeyProduct); if( r != ERROR_SUCCESS ) goto end; sz = GUID_SIZE; r = RegEnumValueW(hkeyProduct, index, szFeature, &sz, NULL, NULL, NULL, NULL); end: if( hkeyProduct ) RegCloseKey(hkeyProduct); if( hkeyFeatures ) RegCloseKey(hkeyFeatures); if( hkey ) RegCloseKey(hkey); return r; } UINT WINAPI MsiEnumComponentsA(DWORD index, LPSTR lpguid) { DWORD r; WCHAR szwGuid[GUID_SIZE]; TRACE("%ld %p\n",index,lpguid); r = MsiEnumComponentsW(index, szwGuid); if( r == ERROR_SUCCESS ) WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL); return r; } UINT WINAPI MsiEnumComponentsW(DWORD index, LPWSTR lpguid) { HKEY hkey = 0, hkeyComponents = 0; DWORD r; WCHAR szKeyName[33]; TRACE("%ld %p\n",index,lpguid); r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey); if( r != ERROR_SUCCESS ) goto end; r = RegOpenKeyW(hkey, szComponents, &hkeyComponents); if( r != ERROR_SUCCESS ) goto end; r = RegEnumKeyW(hkeyComponents, index, szKeyName, GUID_SIZE); unsquash_guid(szKeyName, lpguid); end: if( hkeyComponents ) RegCloseKey(hkeyComponents); if( hkey ) RegCloseKey(hkey); return r; } UINT WINAPI MsiEnumClientsA(LPCSTR szComponent, DWORD index, LPSTR szProduct) { DWORD r; WCHAR szwProduct[GUID_SIZE]; LPWSTR szwComponent = NULL; TRACE("%s %ld %p\n",debugstr_a(szComponent),index,szProduct); if( szComponent ) { UINT len = MultiByteToWideChar( CP_ACP, 0, szComponent, -1, NULL, 0 ); szwComponent = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) ); if( szwComponent ) MultiByteToWideChar( CP_ACP, 0, szComponent, -1, szwComponent, len ); else return ERROR_FUNCTION_FAILED; } r = MsiEnumClientsW(szComponent?szwComponent:NULL, index, szwProduct); if( r == ERROR_SUCCESS ) { WideCharToMultiByte(CP_ACP, 0, szwProduct, -1, szProduct, GUID_SIZE, NULL, NULL); } if( szwComponent ) HeapFree( GetProcessHeap(), 0, szwComponent); return r; } UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct) { HKEY hkey = 0, hkeyComponents = 0, hkeyComp = 0; DWORD r, sz; WCHAR szRegName[GUID_SIZE], szValName[GUID_SIZE]; TRACE("%s %ld %p\n",debugstr_w(szComponent),index,szProduct); if( !squash_guid(szComponent, szRegName) ) return ERROR_INVALID_PARAMETER; r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey); if( r != ERROR_SUCCESS ) goto end; r = RegOpenKeyW(hkey, szComponents, &hkeyComponents); if( r != ERROR_SUCCESS ) goto end; r = RegOpenKeyW(hkeyComponents, szRegName, &hkeyComp); if( r != ERROR_SUCCESS ) goto end; sz = GUID_SIZE; r = RegEnumValueW(hkeyComp, index, szValName, &sz, NULL, NULL, NULL, NULL); if( r != ERROR_SUCCESS ) goto end; unsquash_guid(szValName, szProduct); end: if( hkeyComp ) RegCloseKey(hkeyComp); if( hkeyComponents ) RegCloseKey(hkeyComponents); if( hkey ) RegCloseKey(hkey); return r; } UINT WINAPI MsiEnumComponentQualifiersA( LPSTR szComponent, DWORD iIndex, LPSTR lpQualifierBuf, DWORD* pcchQualifierBuf, LPSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf) { FIXME("%s 0x%08lx %p %p %p %p\n", debugstr_a(szComponent), iIndex, lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, pcchApplicationDataBuf); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiEnumComponentQualifiersW( LPWSTR szComponent, DWORD iIndex, LPWSTR lpQualifierBuf, DWORD* pcchQualifierBuf, LPWSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf) { FIXME("%s 0x%08lx %p %p %p %p\n", debugstr_w(szComponent), iIndex, lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, pcchApplicationDataBuf); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext, DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf, DWORD* pcchPathBuf) { FIXME("%s %s 0x%08lx 0x%08lx %p %p\n", debugstr_a(szAssemblyName), debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf, pcchPathBuf); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiProvideAssemblyW( LPCWSTR szAssemblyName, LPCWSTR szAppContext, DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf, DWORD* pcchPathBuf) { FIXME("%s %s 0x%08lx 0x%08lx %p %p\n", debugstr_w(szAssemblyName), debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf, pcchPathBuf); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor, LPSTR szPath, DWORD *pcchPath, DWORD *pcchArgs ) { FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs ); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor, LPWSTR szPath, DWORD *pcchPath, DWORD *pcchArgs ) { FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs ); return ERROR_CALL_NOT_IMPLEMENTED; } HRESULT WINAPI MsiGetFileSignatureInformationA( LPCSTR szSignedObjectPath, DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData, DWORD* pcbHashData) { FIXME("%s 0x%08lx %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags, ppcCertContext, pbHashData, pcbHashData); return ERROR_CALL_NOT_IMPLEMENTED; } HRESULT WINAPI MsiGetFileSignatureInformationW( LPCWSTR szSignedObjectPath, DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData, DWORD* pcbHashData) { FIXME("%s 0x%08lx %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags, ppcCertContext, pbHashData, pcbHashData); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiGetProductPropertyA( MSIHANDLE hProduct, LPCSTR szProperty, LPSTR szValue, DWORD *pccbValue ) { FIXME("%ld %s %p %p\n", hProduct, debugstr_a(szProperty), szValue, pccbValue); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiGetProductPropertyW( MSIHANDLE hProduct, LPCWSTR szProperty, LPWSTR szValue, DWORD *pccbValue ) { FIXME("%ld %s %p %p\n", hProduct, debugstr_w(szProperty), szValue, pccbValue); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage ) { UINT r, len; LPWSTR szPack = NULL; TRACE("%s\n", debugstr_a(szPackage) ); if( szPackage ) { len = MultiByteToWideChar( CP_ACP, 0, szPackage, -1, NULL, 0 ); szPack = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); if( !szPack ) return ERROR_OUTOFMEMORY; MultiByteToWideChar( CP_ACP, 0, szPackage, -1, szPack, len ); } r = MsiVerifyPackageW( szPack ); HeapFree( GetProcessHeap(), 0, szPack ); return r; } UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage ) { MSIHANDLE handle; UINT r; TRACE("%s\n", debugstr_w(szPackage) ); r = MsiOpenDatabaseW( szPackage, MSIDBOPEN_READONLY, &handle ); MsiCloseHandle( handle ); return r; } INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent, LPSTR lpPathBuf, DWORD* pcchBuf) { INSTALLSTATE rc; UINT len,incoming_len; LPWSTR szwProduct= NULL; LPWSTR szwComponent= NULL; LPWSTR lpwPathBuf= NULL; if( szProduct) { len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 ); szwProduct= HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); if( !szwProduct) return ERROR_OUTOFMEMORY; MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProduct, len ); } if( szComponent) { len = MultiByteToWideChar( CP_ACP, 0, szComponent, -1, NULL, 0 ); szwComponent= HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); if( !szwComponent) { HeapFree( GetProcessHeap(), 0, szwProduct); return ERROR_OUTOFMEMORY; } MultiByteToWideChar( CP_ACP, 0, szComponent, -1, szwComponent, len ); } if (pcchBuf && *pcchBuf > 0) lpwPathBuf = HeapAlloc( GetProcessHeap(), 0, *pcchBuf * sizeof(WCHAR)); else lpwPathBuf = NULL; incoming_len = *pcchBuf; rc = MsiGetComponentPathW(szwProduct, szwComponent, lpwPathBuf, pcchBuf); HeapFree( GetProcessHeap(), 0, szwProduct); HeapFree( GetProcessHeap(), 0, szwComponent); if (lpwPathBuf) { if (rc != INSTALLSTATE_UNKNOWN) WideCharToMultiByte(CP_ACP, 0, lpwPathBuf, incoming_len, lpPathBuf, incoming_len, NULL, NULL); HeapFree( GetProcessHeap(), 0, lpwPathBuf); } return rc; } INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent, LPWSTR lpPathBuf, DWORD* pcchBuf) { WCHAR squished_pc[0x100]; WCHAR squished_cc[0x100]; UINT rc; INSTALLSTATE rrc = INSTALLSTATE_UNKNOWN; HKEY hkey=0,hkey2=0,hkey3=0; static const WCHAR szInstaller[] = { 'S','o','f','t','w','a','r','e','\\', 'M','i','c','r','o','s','o','f','t','\\', 'W','i','n','d','o','w','s','\\', 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', 'I','n','s','t','a','l','l','e','r',0 }; static const WCHAR szComponents[] = { 'C','o','m','p','o','n','e','n','t','s',0 }; static const WCHAR szProducts[] = { 'P','r','o','d','u','c','t','s',0 }; TRACE("(%s %s %p %p)\n", debugstr_w(szProduct), debugstr_w(szComponent), lpPathBuf, pcchBuf); squash_guid(szProduct,squished_pc); squash_guid(szComponent,squished_cc); TRACE("squished (%s:%s)\n", debugstr_w(squished_cc), debugstr_w(squished_pc)); rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,szInstaller,&hkey); if (rc != ERROR_SUCCESS) goto end; /* check the products key for the product */ rc = RegOpenKeyW(hkey,szProducts,&hkey2); if (rc != ERROR_SUCCESS) goto end; rc = RegOpenKeyW(hkey2,squished_pc,&hkey3); if (rc != ERROR_SUCCESS) goto end; RegCloseKey(hkey3); RegCloseKey(hkey2); rc = RegOpenKeyW(hkey,szComponents,&hkey2); if (rc != ERROR_SUCCESS) goto end; rc = RegOpenKeyW(hkey2,squished_cc,&hkey3); if (rc != ERROR_SUCCESS) goto end; *pcchBuf *= sizeof(WCHAR); rc = RegQueryValueExW(hkey3,squished_pc,NULL,NULL,(LPVOID)lpPathBuf, pcchBuf); *pcchBuf /= sizeof(WCHAR); if (rc!= ERROR_SUCCESS) goto end; TRACE("found path of (%s:%s)(%s)\n", debugstr_w(squished_cc), debugstr_w(squished_pc), debugstr_w(lpPathBuf)); FIXME("Only working for installed files, not registry keys\n"); if (GetFileAttributesW(lpPathBuf) != INVALID_FILE_ATTRIBUTES) rrc = INSTALLSTATE_LOCAL; else rrc = INSTALLSTATE_ABSENT; end: RegCloseKey(hkey3); RegCloseKey(hkey2); RegCloseKey(hkey); return rrc; } INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature) { INSTALLSTATE rc; UINT len; LPWSTR szwProduct= NULL; LPWSTR szwFeature= NULL; if( szProduct) { len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 ); szwProduct= HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); if( !szwProduct) return ERROR_OUTOFMEMORY; MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProduct, len ); } if( szFeature) { len = MultiByteToWideChar( CP_ACP, 0, szFeature, -1, NULL, 0 ); szwFeature= HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); if( !szwFeature) { HeapFree( GetProcessHeap(), 0, szwProduct); return ERROR_OUTOFMEMORY; } MultiByteToWideChar( CP_ACP, 0, szFeature, -1, szwFeature, len ); } rc = MsiQueryFeatureStateW(szwProduct, szwFeature); HeapFree( GetProcessHeap(), 0, szwProduct); HeapFree( GetProcessHeap(), 0, szwFeature); return rc; } INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature) { FIXME("STUB: (%s %s)\n", debugstr_w(szProduct), debugstr_w(szFeature)); return INSTALLSTATE_UNKNOWN; } UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf, DWORD* pcchVersionBuf, LPSTR lpLangBuf, DWORD* pcchLangBuf) { UINT len; UINT ret; LPWSTR szwFilePath = NULL; LPWSTR lpwVersionBuff = NULL; LPWSTR lpwLangBuff = NULL; if(szFilePath) { len = MultiByteToWideChar( CP_ACP, 0, szFilePath, -1, NULL, 0 ); szwFilePath = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); if( !szwFilePath) return ERROR_OUTOFMEMORY; MultiByteToWideChar( CP_ACP, 0, szFilePath, -1, szwFilePath, len ); } if(lpVersionBuf && pcchVersionBuf && *pcchVersionBuf) { lpwVersionBuff = HeapAlloc(GetProcessHeap(), 0, *pcchVersionBuf * sizeof(WCHAR)); if( !lpwVersionBuff) { ret = ERROR_OUTOFMEMORY; goto end; } } if(lpLangBuf && pcchLangBuf && *pcchLangBuf) { lpwLangBuff = HeapAlloc(GetProcessHeap(), 0, *pcchVersionBuf * sizeof(WCHAR)); if( !lpwLangBuff) { ret = ERROR_OUTOFMEMORY; goto end; } } ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf, lpwLangBuff, pcchLangBuf); if(lpwVersionBuff) WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1, lpVersionBuf, *pcchVersionBuf, NULL, NULL); if(lpwLangBuff) WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1, lpLangBuf, *pcchLangBuf, NULL, NULL); end: if(szwFilePath) HeapFree(GetProcessHeap(), 0, szwFilePath); if(lpwVersionBuff) HeapFree(GetProcessHeap(), 0, lpwVersionBuff); if(lpwLangBuff) HeapFree(GetProcessHeap(), 0, lpwLangBuff); return ret; } UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf, DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf) { static const WCHAR szVersionResource[] = {'\\',0}; static const WCHAR szVersionFormat[] = {'%','d','.','%','d','.','%','d','.','%','d',0}; static const WCHAR szLangFormat[] = {'%','d',0}; UINT ret = 0; DWORD dwVerLen; LPVOID lpVer = NULL; VS_FIXEDFILEINFO *ffi; UINT puLen; WCHAR tmp[32]; TRACE("(%s,%p,%ld,%p,%ld)\n", debugstr_w(szFilePath), lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0, lpLangBuf, pcchLangBuf?*pcchLangBuf:0); dwVerLen = GetFileVersionInfoSizeW(szFilePath, NULL); if(!dwVerLen) return GetLastError(); lpVer = HeapAlloc(GetProcessHeap(), 0, dwVerLen); if(!lpVer) { ret = ERROR_OUTOFMEMORY; goto end; } if(!GetFileVersionInfoW(szFilePath, 0, dwVerLen, lpVer)) { ret = GetLastError(); goto end; } if(lpVersionBuf && pcchVersionBuf && *pcchVersionBuf) { if(VerQueryValueW(lpVer, szVersionResource, (LPVOID*)&ffi, &puLen) && puLen > 0) { wsprintfW(tmp, szVersionFormat, HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS), HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS)); lstrcpynW(lpVersionBuf, tmp, *pcchVersionBuf); *pcchVersionBuf = strlenW(lpVersionBuf); } else { *lpVersionBuf = 0; *pcchVersionBuf = 0; } } if(lpLangBuf && pcchLangBuf && *pcchLangBuf) { DWORD lang = GetUserDefaultLangID(); FIXME("Retrieve language from file\n"); wsprintfW(tmp, szLangFormat, lang); lstrcpynW(lpLangBuf, tmp, *pcchLangBuf); *pcchLangBuf = strlenW(lpLangBuf); } end: if(lpVer) HeapFree(GetProcessHeap(), 0, lpVer); return ret; } /****************************************************************** * DllMain * * @todo: maybe we can check here if MsiServer service is declared no ? */ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { if (fdwReason == DLL_PROCESS_ATTACH) { DisableThreadLibraryCalls(hinstDLL); /* * UI Initialization */ gUILevel = INSTALLUILEVEL_BASIC; gUIhwnd = 0; gUIHandler = NULL; gUIFilter = 0; gUIContext = NULL; gszLogFile[0]=0; /* FIXME: Initialisation */ } else if (fdwReason == DLL_PROCESS_DETACH) { /* FIXME: Cleanup */ } /* static const WCHAR szMSIServerSvc[] = { 'M','S','I','S','e','r','v','e','r',0 }; static const WCHAR szNull[] = { 0 }; if (!strcmpW(lpServiceName, szMSIServerSvc)) { hKey = CreateServiceW(hSCManager, szMSIServerSvc, szMSIServerSvc, SC_MANAGER_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_IGNORE, szNull, NULL, NULL, NULL, NULL, szNull); */ return TRUE; } typedef struct { /* IUnknown fields */ IClassFactoryVtbl *lpVtbl; DWORD ref; } IClassFactoryImpl; static HRESULT WINAPI MsiCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) { IClassFactoryImpl *This = (IClassFactoryImpl *)iface; FIXME("(%p, %s, %p): stub\n",This,debugstr_guid(riid),ppobj); return E_NOINTERFACE; } static ULONG WINAPI MsiCF_AddRef(LPCLASSFACTORY iface) { IClassFactoryImpl *This = (IClassFactoryImpl *)iface; return InterlockedIncrement(&This->ref); } static ULONG WINAPI MsiCF_Release(LPCLASSFACTORY iface) { IClassFactoryImpl *This = (IClassFactoryImpl *)iface; /* static class, won't be freed */ return InterlockedDecrement(&This->ref); } static HRESULT WINAPI MsiCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj) { IClassFactoryImpl *This = (IClassFactoryImpl *)iface; FIXME ("(%p, %p, %s, %p): to implement\n", This, pOuter, debugstr_guid(riid), ppobj); return 0; } static HRESULT WINAPI MsiCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) { IClassFactoryImpl *This = (IClassFactoryImpl *)iface; FIXME("(%p, %d): stub\n", This, dolock); return S_OK; } static IClassFactoryVtbl MsiCF_Vtbl = { MsiCF_QueryInterface, MsiCF_AddRef, MsiCF_Release, MsiCF_CreateInstance, MsiCF_LockServer }; static IClassFactoryImpl Msi_CF = {&MsiCF_Vtbl, 1 }; /****************************************************************** * DllGetClassObject (MSI.@) */ HRESULT WINAPI MSI_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) { FIXME("(%s, %s, %p): almost a stub.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); if (IsEqualCLSID (rclsid, &CLSID_IMsiServer)) { *ppv = (LPVOID) &Msi_CF; IClassFactory_AddRef((IClassFactory*)*ppv); return S_OK; } else if (IsEqualCLSID (rclsid, &CLSID_IMsiServerMessage)) { *ppv = (LPVOID) &Msi_CF; IClassFactory_AddRef((IClassFactory*)*ppv); return S_OK; } else if (IsEqualCLSID (rclsid, &CLSID_IMsiServerX1)) { *ppv = (LPVOID) &Msi_CF; IClassFactory_AddRef((IClassFactory*)*ppv); return S_OK; } else if (IsEqualCLSID (rclsid, &CLSID_IMsiServerX2)) { *ppv = (LPVOID) &Msi_CF; IClassFactory_AddRef((IClassFactory*)*ppv); return S_OK; } else if (IsEqualCLSID (rclsid, &CLSID_IMsiServerX3)) { *ppv = (LPVOID) &Msi_CF; IClassFactory_AddRef((IClassFactory*)*ppv); return S_OK; } WARN("(%s, %s, %p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); return CLASS_E_CLASSNOTAVAILABLE; } /****************************************************************** * DllGetVersion (MSI.@) */ HRESULT WINAPI MSI_DllGetVersion(DLLVERSIONINFO *pdvi) { TRACE("%p\n",pdvi); if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) return E_INVALIDARG; pdvi->dwMajorVersion = MSI_MAJORVERSION; pdvi->dwMinorVersion = MSI_MINORVERSION; pdvi->dwBuildNumber = MSI_BUILDNUMBER; pdvi->dwPlatformID = 1; return S_OK; } /****************************************************************** * DllCanUnloadNow (MSI.@) */ BOOL WINAPI MSI_DllCanUnloadNow(void) { return S_FALSE; } UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR szUpgradeCode, DWORD dwReserved, DWORD iProductIndex, LPWSTR lpProductBuf) { FIXME("%s %lu %lu %p\n", debugstr_w(szUpgradeCode), dwReserved, iProductIndex, lpProductBuf); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiEnumRelatedProductsA(LPCSTR szUpgradeCode, DWORD dwReserved, DWORD iProductIndex, LPSTR lpProductBuf) { FIXME("%s %lu %lu %p\n", debugstr_a(szUpgradeCode), dwReserved, iProductIndex, lpProductBuf); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiGetFeatureUsageW(LPCWSTR szProduct, LPCWSTR szFeature, DWORD* pdwUseCount, WORD* pwDateUsed) { FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature), pdwUseCount, pwDateUsed); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiGetFeatureUsageA(LPCSTR szProduct, LPCSTR szFeature, DWORD* pdwUseCount, WORD* pwDateUsed) { FIXME("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature), pdwUseCount, pwDateUsed); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiUseFeatureExW(LPCWSTR szProduct, LPCWSTR szFeature, DWORD dwInstallMode, DWORD dwReserved) { FIXME("%s %s %li %li\n", debugstr_w(szProduct), debugstr_w(szFeature), dwInstallMode, dwReserved); return INSTALLSTATE_LOCAL; } UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent, LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR szProduct, DWORD Unused1, DWORD Unused2 , LPWSTR lpPathBuf, DWORD* pcchPathBuf) { FIXME("%s %s %li %s %li %li %p %p\n", debugstr_w(szComponent), debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct), Unused1, Unused2, lpPathBuf, pcchPathBuf); return ERROR_INDEX_ABSENT; } UINT WINAPI MsiGetUserInfoW(LPCWSTR szProduct, LPWSTR lpUserNameBuf, DWORD* pcchUserNameBuf, LPWSTR lpOrgNameBuf, DWORD* pcchOrgNameBuf, LPWSTR lpSerialBuf, DWORD* pcchSerialBuf) { FIXME("%s, %p %p %p %p %p %p\n",debugstr_w(szProduct), lpUserNameBuf, pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf, pcchSerialBuf); return USERINFOSTATE_UNKNOWN; } UINT WINAPI MsiCollectUserInfoW(LPWSTR szProduct) { FIXME("%s\n",debugstr_w(szProduct)); return ERROR_FUNCTION_FAILED; }