1c2c66affSColin Finck /* 2c2c66affSColin Finck * Implementation of the Microsoft Installer (msi.dll) 3c2c66affSColin Finck * 4c2c66affSColin Finck * Copyright 2004,2005 Aric Stewart for CodeWeavers 5c2c66affSColin Finck * 6c2c66affSColin Finck * This library is free software; you can redistribute it and/or 7c2c66affSColin Finck * modify it under the terms of the GNU Lesser General Public 8c2c66affSColin Finck * License as published by the Free Software Foundation; either 9c2c66affSColin Finck * version 2.1 of the License, or (at your option) any later version. 10c2c66affSColin Finck * 11c2c66affSColin Finck * This library is distributed in the hope that it will be useful, 12c2c66affSColin Finck * but WITHOUT ANY WARRANTY; without even the implied warranty of 13c2c66affSColin Finck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14c2c66affSColin Finck * Lesser General Public License for more details. 15c2c66affSColin Finck * 16c2c66affSColin Finck * You should have received a copy of the GNU Lesser General Public 17c2c66affSColin Finck * License along with this library; if not, write to the Free Software 18c2c66affSColin Finck * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19c2c66affSColin Finck */ 20c2c66affSColin Finck 21c42b133eSAmine Khaldi #include <stdarg.h> 22c42b133eSAmine Khaldi #include "windef.h" 23c42b133eSAmine Khaldi #include "winbase.h" 24c42b133eSAmine Khaldi #include "winerror.h" 25c42b133eSAmine Khaldi #include "winreg.h" 26c42b133eSAmine Khaldi #include "wine/debug.h" 27c2c66affSColin Finck #include "msipriv.h" 28c2c66affSColin Finck 29c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL(msi); 30c2c66affSColin Finck 31c2c66affSColin Finck typedef struct _tagTT_OFFSET_TABLE { 32c2c66affSColin Finck USHORT uMajorVersion; 33c2c66affSColin Finck USHORT uMinorVersion; 34c2c66affSColin Finck USHORT uNumOfTables; 35c2c66affSColin Finck USHORT uSearchRange; 36c2c66affSColin Finck USHORT uEntrySelector; 37c2c66affSColin Finck USHORT uRangeShift; 38c2c66affSColin Finck } TT_OFFSET_TABLE; 39c2c66affSColin Finck 40c2c66affSColin Finck typedef struct _tagTT_TABLE_DIRECTORY { 41c2c66affSColin Finck char szTag[4]; /* table name */ 42c2c66affSColin Finck ULONG uCheckSum; /* Check sum */ 43c2c66affSColin Finck ULONG uOffset; /* Offset from beginning of file */ 44c2c66affSColin Finck ULONG uLength; /* length of the table in bytes */ 45c2c66affSColin Finck } TT_TABLE_DIRECTORY; 46c2c66affSColin Finck 47c2c66affSColin Finck typedef struct _tagTT_NAME_TABLE_HEADER { 48c2c66affSColin Finck USHORT uFSelector; /* format selector. Always 0 */ 49c2c66affSColin Finck USHORT uNRCount; /* Name Records count */ 50c2c66affSColin Finck USHORT uStorageOffset; /* Offset for strings storage, 51c2c66affSColin Finck * from start of the table */ 52c2c66affSColin Finck } TT_NAME_TABLE_HEADER; 53c2c66affSColin Finck 54c2c66affSColin Finck #define NAME_ID_FULL_FONT_NAME 4 55c2c66affSColin Finck #define NAME_ID_VERSION 5 56c2c66affSColin Finck 57c2c66affSColin Finck typedef struct _tagTT_NAME_RECORD { 58c2c66affSColin Finck USHORT uPlatformID; 59c2c66affSColin Finck USHORT uEncodingID; 60c2c66affSColin Finck USHORT uLanguageID; 61c2c66affSColin Finck USHORT uNameID; 62c2c66affSColin Finck USHORT uStringLength; 63c2c66affSColin Finck USHORT uStringOffset; /* from start of storage area */ 64c2c66affSColin Finck } TT_NAME_RECORD; 65c2c66affSColin Finck 66c2c66affSColin Finck #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x)) 67c2c66affSColin Finck #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x))) 68c2c66affSColin Finck 69c2c66affSColin Finck static const WCHAR regfont1[] = 70c2c66affSColin Finck {'S','o','f','t','w','a','r','e','\\', 71c2c66affSColin Finck 'M','i','c','r','o','s','o','f','t','\\', 72c2c66affSColin Finck 'W','i','n','d','o','w','s',' ','N','T','\\', 73c2c66affSColin Finck 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', 74c2c66affSColin Finck 'F','o','n','t','s',0}; 75c2c66affSColin Finck static const WCHAR regfont2[] = 76c2c66affSColin Finck {'S','o','f','t','w','a','r','e','\\', 77c2c66affSColin Finck 'M','i','c','r','o','s','o','f','t','\\', 78c2c66affSColin Finck 'W','i','n','d','o','w','s','\\', 79c2c66affSColin Finck 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', 80c2c66affSColin Finck 'F','o','n','t','s',0}; 81c2c66affSColin Finck 82c2c66affSColin Finck /* 83c2c66affSColin Finck * Code based off of code located here 84c2c66affSColin Finck * http://www.codeproject.com/gdi/fontnamefromfile.asp 85c2c66affSColin Finck */ 86e342f337Swinesync static WCHAR *load_ttf_name_id( MSIPACKAGE *package, const WCHAR *filename, DWORD id ) 87c2c66affSColin Finck { 88c2c66affSColin Finck TT_TABLE_DIRECTORY tblDir; 89c2c66affSColin Finck BOOL bFound = FALSE; 90c2c66affSColin Finck TT_OFFSET_TABLE ttOffsetTable; 91c2c66affSColin Finck TT_NAME_TABLE_HEADER ttNTHeader; 92c2c66affSColin Finck TT_NAME_RECORD ttRecord; 93c2c66affSColin Finck DWORD dwRead; 94c2c66affSColin Finck HANDLE handle; 95c2c66affSColin Finck LPWSTR ret = NULL; 96c2c66affSColin Finck int i; 97c2c66affSColin Finck 98e342f337Swinesync if (package) 99e342f337Swinesync handle = msi_create_file( package, filename, GENERIC_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL ); 100e342f337Swinesync else 101e342f337Swinesync handle = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ); 102c2c66affSColin Finck if (handle == INVALID_HANDLE_VALUE) 103c2c66affSColin Finck { 104c2c66affSColin Finck ERR("Unable to open font file %s\n", debugstr_w(filename)); 105c2c66affSColin Finck return NULL; 106c2c66affSColin Finck } 107c2c66affSColin Finck 108c2c66affSColin Finck if (!ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL)) 109c2c66affSColin Finck goto end; 110c2c66affSColin Finck 111c2c66affSColin Finck ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables); 112c2c66affSColin Finck ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion); 113c2c66affSColin Finck ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion); 114c2c66affSColin Finck 115c2c66affSColin Finck if ((ttOffsetTable.uMajorVersion != 1 || ttOffsetTable.uMinorVersion != 0) && 116c2c66affSColin Finck (ttOffsetTable.uMajorVersion != 0x4f54 || ttOffsetTable.uMinorVersion != 0x544f)) 117c2c66affSColin Finck goto end; 118c2c66affSColin Finck 119c2c66affSColin Finck for (i=0; i< ttOffsetTable.uNumOfTables; i++) 120c2c66affSColin Finck { 121c2c66affSColin Finck if (!ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL)) 122c2c66affSColin Finck break; 123c2c66affSColin Finck if (memcmp(tblDir.szTag,"name",4)==0) 124c2c66affSColin Finck { 125c2c66affSColin Finck bFound = TRUE; 126c2c66affSColin Finck tblDir.uLength = SWAPLONG(tblDir.uLength); 127c2c66affSColin Finck tblDir.uOffset = SWAPLONG(tblDir.uOffset); 128c2c66affSColin Finck break; 129c2c66affSColin Finck } 130c2c66affSColin Finck } 131c2c66affSColin Finck 132c2c66affSColin Finck if (!bFound) 133c2c66affSColin Finck goto end; 134c2c66affSColin Finck 135c2c66affSColin Finck SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN); 136c2c66affSColin Finck if (!ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER), &dwRead,NULL)) 137c2c66affSColin Finck goto end; 138c2c66affSColin Finck 139c2c66affSColin Finck ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount); 140c2c66affSColin Finck ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset); 141c2c66affSColin Finck for(i=0; i<ttNTHeader.uNRCount; i++) 142c2c66affSColin Finck { 143c2c66affSColin Finck if (!ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL)) 144c2c66affSColin Finck break; 145c2c66affSColin Finck 146c2c66affSColin Finck ttRecord.uNameID = SWAPWORD(ttRecord.uNameID); 147c2c66affSColin Finck ttRecord.uPlatformID = SWAPWORD(ttRecord.uPlatformID); 148c2c66affSColin Finck ttRecord.uEncodingID = SWAPWORD(ttRecord.uEncodingID); 149c2c66affSColin Finck if (ttRecord.uNameID == id && ttRecord.uPlatformID == 3 && 150c2c66affSColin Finck (ttRecord.uEncodingID == 0 || ttRecord.uEncodingID == 1)) 151c2c66affSColin Finck { 152c2c66affSColin Finck WCHAR *buf; 153c2c66affSColin Finck unsigned int i; 154c2c66affSColin Finck 155c2c66affSColin Finck ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength); 156c2c66affSColin Finck ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset); 157c2c66affSColin Finck SetFilePointer(handle, tblDir.uOffset + ttRecord.uStringOffset + ttNTHeader.uStorageOffset, 158c2c66affSColin Finck NULL, FILE_BEGIN); 159c2c66affSColin Finck if (!(buf = msi_alloc_zero( ttRecord.uStringLength + sizeof(WCHAR) ))) goto end; 160c2c66affSColin Finck dwRead = 0; 161c2c66affSColin Finck ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL); 162c2c66affSColin Finck if (dwRead % sizeof(WCHAR)) 163c2c66affSColin Finck { 164c2c66affSColin Finck msi_free(buf); 165c2c66affSColin Finck goto end; 166c2c66affSColin Finck } 167c2c66affSColin Finck for (i = 0; i < dwRead / sizeof(WCHAR); i++) buf[i] = SWAPWORD(buf[i]); 168c2c66affSColin Finck ret = strdupW(buf); 169c2c66affSColin Finck msi_free(buf); 170c2c66affSColin Finck break; 171c2c66affSColin Finck } 172c2c66affSColin Finck } 173c2c66affSColin Finck 174c2c66affSColin Finck end: 175c2c66affSColin Finck CloseHandle(handle); 176c2c66affSColin Finck return ret; 177c2c66affSColin Finck } 178c2c66affSColin Finck 179e342f337Swinesync static WCHAR *font_name_from_file( MSIPACKAGE *package, const WCHAR *filename ) 180c2c66affSColin Finck { 181c2c66affSColin Finck static const WCHAR truetypeW[] = {' ','(','T','r','u','e','T','y','p','e',')',0}; 182c2c66affSColin Finck WCHAR *name, *ret = NULL; 183c2c66affSColin Finck 184e342f337Swinesync if ((name = load_ttf_name_id( package, filename, NAME_ID_FULL_FONT_NAME ))) 185c2c66affSColin Finck { 186c2c66affSColin Finck if (!name[0]) 187c2c66affSColin Finck { 188c2c66affSColin Finck WARN("empty font name\n"); 189c2c66affSColin Finck msi_free( name ); 190c2c66affSColin Finck return NULL; 191c2c66affSColin Finck } 192*958f1addSwinesync ret = msi_alloc( (lstrlenW( name ) + lstrlenW( truetypeW ) + 1 ) * sizeof(WCHAR) ); 193*958f1addSwinesync lstrcpyW( ret, name ); 194*958f1addSwinesync lstrcatW( ret, truetypeW ); 195c2c66affSColin Finck msi_free( name ); 196c2c66affSColin Finck } 197c2c66affSColin Finck return ret; 198c2c66affSColin Finck } 199c2c66affSColin Finck 200e342f337Swinesync WCHAR *msi_get_font_file_version( MSIPACKAGE *package, const WCHAR *filename ) 201c2c66affSColin Finck { 202c2c66affSColin Finck static const WCHAR fmtW[] = {'%','u','.','%','u','.','0','.','0',0}; 203c2c66affSColin Finck WCHAR *version, *p, *q, *ret = NULL; 204c2c66affSColin Finck 205e342f337Swinesync if ((version = load_ttf_name_id( package, filename, NAME_ID_VERSION ))) 206c2c66affSColin Finck { 207c2c66affSColin Finck int len, major = 0, minor = 0; 208*958f1addSwinesync if ((p = wcschr( version, ';' ))) *p = 0; 209c2c66affSColin Finck p = version; 210*958f1addSwinesync while (*p && !iswdigit( *p )) p++; 211*958f1addSwinesync if ((q = wcschr( p, '.' ))) 212c2c66affSColin Finck { 213*958f1addSwinesync major = wcstol( p, NULL, 10 ); 214c2c66affSColin Finck p = ++q; 215*958f1addSwinesync while (*q && iswdigit( *q )) q++; 216*958f1addSwinesync if (!*q || *q == ' ') minor = wcstol( p, NULL, 10 ); 217c2c66affSColin Finck else major = 0; 218c2c66affSColin Finck } 219*958f1addSwinesync len = lstrlenW( fmtW ) + 20; 220c2c66affSColin Finck ret = msi_alloc( len * sizeof(WCHAR) ); 221*958f1addSwinesync swprintf( ret, len, fmtW, major, minor ); 222c2c66affSColin Finck msi_free( version ); 223c2c66affSColin Finck } 224c2c66affSColin Finck return ret; 225c2c66affSColin Finck } 226c2c66affSColin Finck 227c2c66affSColin Finck static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param) 228c2c66affSColin Finck { 229c2c66affSColin Finck MSIPACKAGE *package = param; 230c2c66affSColin Finck LPWSTR name; 231c2c66affSColin Finck LPCWSTR filename; 232c2c66affSColin Finck MSIFILE *file; 233c2c66affSColin Finck MSICOMPONENT *comp; 234c2c66affSColin Finck HKEY hkey1, hkey2; 235c2c66affSColin Finck MSIRECORD *uirow; 236c2c66affSColin Finck LPWSTR uipath, p; 237c2c66affSColin Finck 238c2c66affSColin Finck filename = MSI_RecordGetString( row, 1 ); 239c2c66affSColin Finck file = msi_get_loaded_file( package, filename ); 240c2c66affSColin Finck if (!file) 241c2c66affSColin Finck { 242c2c66affSColin Finck WARN("unable to find file %s\n", debugstr_w(filename)); 243c2c66affSColin Finck return ERROR_SUCCESS; 244c2c66affSColin Finck } 245c2c66affSColin Finck comp = msi_get_loaded_component( package, file->Component->Component ); 246c2c66affSColin Finck if (!comp) 247c2c66affSColin Finck { 248c2c66affSColin Finck WARN("unable to find component %s\n", debugstr_w(file->Component->Component)); 249c2c66affSColin Finck return ERROR_SUCCESS; 250c2c66affSColin Finck } 251c2c66affSColin Finck comp->Action = msi_get_component_action( package, comp ); 252c2c66affSColin Finck if (comp->Action != INSTALLSTATE_LOCAL) 253c2c66affSColin Finck { 254c2c66affSColin Finck TRACE("component not scheduled for installation %s\n", debugstr_w(comp->Component)); 255c2c66affSColin Finck return ERROR_SUCCESS; 256c2c66affSColin Finck } 257c2c66affSColin Finck 258c2c66affSColin Finck RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1); 259c2c66affSColin Finck RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2); 260c2c66affSColin Finck 261c2c66affSColin Finck if (MSI_RecordIsNull(row,2)) 262e342f337Swinesync name = font_name_from_file( package, file->TargetPath ); 263c2c66affSColin Finck else 264c2c66affSColin Finck name = msi_dup_record_field(row,2); 265c2c66affSColin Finck 266c2c66affSColin Finck if (name) 267c2c66affSColin Finck { 268c2c66affSColin Finck msi_reg_set_val_str( hkey1, name, file->TargetPath); 269c2c66affSColin Finck msi_reg_set_val_str( hkey2, name, file->TargetPath); 270c2c66affSColin Finck } 271c2c66affSColin Finck 272c2c66affSColin Finck msi_free(name); 273c2c66affSColin Finck RegCloseKey(hkey1); 274c2c66affSColin Finck RegCloseKey(hkey2); 275c2c66affSColin Finck 276c2c66affSColin Finck /* the UI chunk */ 277c2c66affSColin Finck uirow = MSI_CreateRecord( 1 ); 278c2c66affSColin Finck uipath = strdupW( file->TargetPath ); 279*958f1addSwinesync p = wcsrchr(uipath,'\\'); 280c2c66affSColin Finck if (p) p++; 281c2c66affSColin Finck else p = uipath; 282c2c66affSColin Finck MSI_RecordSetStringW( uirow, 1, p ); 28371bffdcdSAmine Khaldi MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 284c2c66affSColin Finck msiobj_release( &uirow->hdr ); 285c2c66affSColin Finck msi_free( uipath ); 286c2c66affSColin Finck /* FIXME: call msi_ui_progress? */ 287c2c66affSColin Finck 288c2c66affSColin Finck return ERROR_SUCCESS; 289c2c66affSColin Finck } 290c2c66affSColin Finck 291c2c66affSColin Finck UINT ACTION_RegisterFonts(MSIPACKAGE *package) 292c2c66affSColin Finck { 293c2c66affSColin Finck static const WCHAR query[] = { 294c2c66affSColin Finck 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','F','o','n','t','`',0}; 295c2c66affSColin Finck MSIQUERY *view; 296c2c66affSColin Finck UINT rc; 297c2c66affSColin Finck 298fd8b07bdSwinesync if (package->script == SCRIPT_NONE) 299fd8b07bdSwinesync return msi_schedule_action(package, SCRIPT_INSTALL, szRegisterFonts); 300fd8b07bdSwinesync 301c2c66affSColin Finck rc = MSI_DatabaseOpenViewW(package->db, query, &view); 302c2c66affSColin Finck if (rc != ERROR_SUCCESS) 303c2c66affSColin Finck return ERROR_SUCCESS; 304c2c66affSColin Finck 305c2c66affSColin Finck rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package); 306c2c66affSColin Finck msiobj_release(&view->hdr); 307c2c66affSColin Finck return rc; 308c2c66affSColin Finck } 309c2c66affSColin Finck 310c2c66affSColin Finck static UINT ITERATE_UnregisterFonts( MSIRECORD *row, LPVOID param ) 311c2c66affSColin Finck { 312c2c66affSColin Finck MSIPACKAGE *package = param; 313c2c66affSColin Finck LPWSTR name; 314c2c66affSColin Finck LPCWSTR filename; 315c2c66affSColin Finck MSIFILE *file; 316c2c66affSColin Finck MSICOMPONENT *comp; 317c2c66affSColin Finck HKEY hkey1, hkey2; 318c2c66affSColin Finck MSIRECORD *uirow; 319c2c66affSColin Finck LPWSTR uipath, p; 320c2c66affSColin Finck 321c2c66affSColin Finck filename = MSI_RecordGetString( row, 1 ); 322c2c66affSColin Finck file = msi_get_loaded_file( package, filename ); 323c2c66affSColin Finck if (!file) 324c2c66affSColin Finck { 325c2c66affSColin Finck WARN("unable to find file %s\n", debugstr_w(filename)); 326c2c66affSColin Finck return ERROR_SUCCESS; 327c2c66affSColin Finck } 328c2c66affSColin Finck comp = msi_get_loaded_component( package, file->Component->Component ); 329c2c66affSColin Finck if (!comp) 330c2c66affSColin Finck { 331c2c66affSColin Finck WARN("unable to find component %s\n", debugstr_w(file->Component->Component)); 332c2c66affSColin Finck return ERROR_SUCCESS; 333c2c66affSColin Finck } 334c2c66affSColin Finck comp->Action = msi_get_component_action( package, comp ); 335c2c66affSColin Finck if (comp->Action != INSTALLSTATE_ABSENT) 336c2c66affSColin Finck { 337c2c66affSColin Finck TRACE("component not scheduled for removal %s\n", debugstr_w(comp->Component)); 338c2c66affSColin Finck return ERROR_SUCCESS; 339c2c66affSColin Finck } 340c2c66affSColin Finck 341c2c66affSColin Finck RegCreateKeyW( HKEY_LOCAL_MACHINE, regfont1, &hkey1 ); 342c2c66affSColin Finck RegCreateKeyW( HKEY_LOCAL_MACHINE, regfont2, &hkey2 ); 343c2c66affSColin Finck 344c2c66affSColin Finck if (MSI_RecordIsNull( row, 2 )) 345e342f337Swinesync name = font_name_from_file( package, file->TargetPath ); 346c2c66affSColin Finck else 347c2c66affSColin Finck name = msi_dup_record_field( row, 2 ); 348c2c66affSColin Finck 349c2c66affSColin Finck if (name) 350c2c66affSColin Finck { 351c2c66affSColin Finck RegDeleteValueW( hkey1, name ); 352c2c66affSColin Finck RegDeleteValueW( hkey2, name ); 353c2c66affSColin Finck } 354c2c66affSColin Finck 355c2c66affSColin Finck msi_free( name ); 356c2c66affSColin Finck RegCloseKey( hkey1 ); 357c2c66affSColin Finck RegCloseKey( hkey2 ); 358c2c66affSColin Finck 359c2c66affSColin Finck /* the UI chunk */ 360c2c66affSColin Finck uirow = MSI_CreateRecord( 1 ); 361c2c66affSColin Finck uipath = strdupW( file->TargetPath ); 362*958f1addSwinesync p = wcsrchr( uipath,'\\' ); 363c2c66affSColin Finck if (p) p++; 364c2c66affSColin Finck else p = uipath; 365c2c66affSColin Finck MSI_RecordSetStringW( uirow, 1, p ); 36671bffdcdSAmine Khaldi MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 367c2c66affSColin Finck msiobj_release( &uirow->hdr ); 368c2c66affSColin Finck msi_free( uipath ); 369c2c66affSColin Finck /* FIXME: call msi_ui_progress? */ 370c2c66affSColin Finck 371c2c66affSColin Finck return ERROR_SUCCESS; 372c2c66affSColin Finck } 373c2c66affSColin Finck 374c2c66affSColin Finck UINT ACTION_UnregisterFonts( MSIPACKAGE *package ) 375c2c66affSColin Finck { 376c2c66affSColin Finck static const WCHAR query[] = { 377c2c66affSColin Finck 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','F','o','n','t','`',0}; 378c2c66affSColin Finck MSIQUERY *view; 379c2c66affSColin Finck UINT r; 380c2c66affSColin Finck 381fd8b07bdSwinesync if (package->script == SCRIPT_NONE) 382fd8b07bdSwinesync return msi_schedule_action(package, SCRIPT_INSTALL, szUnregisterFonts); 383fd8b07bdSwinesync 384c2c66affSColin Finck r = MSI_DatabaseOpenViewW( package->db, query, &view ); 385c2c66affSColin Finck if (r != ERROR_SUCCESS) 386c2c66affSColin Finck return ERROR_SUCCESS; 387c2c66affSColin Finck 388c2c66affSColin Finck r = MSI_IterateRecords( view, NULL, ITERATE_UnregisterFonts, package ); 389c2c66affSColin Finck msiobj_release( &view->hdr ); 390c2c66affSColin Finck return r; 391c2c66affSColin Finck } 392