2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/debug.h"
28 #include "wine/unicode.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(msi);
33 typedef struct _tagTT_OFFSET_TABLE {
38 USHORT uEntrySelector;
42 typedef struct _tagTT_TABLE_DIRECTORY {
43 char szTag[4]; /* table name */
44 ULONG uCheckSum; /* Check sum */
45 ULONG uOffset; /* Offset from beginning of file */
46 ULONG uLength; /* length of the table in bytes */
49 typedef struct _tagTT_NAME_TABLE_HEADER {
50 USHORT uFSelector; /* format selector. Always 0 */
51 USHORT uNRCount; /* Name Records count */
52 USHORT uStorageOffset; /* Offset for strings storage,
53 * from start of the table */
54 } TT_NAME_TABLE_HEADER;
56 typedef struct _tagTT_NAME_RECORD {
62 USHORT uStringOffset; /* from start of storage area */
65 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
66 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
68 static const WCHAR szRegisterFonts[] =
69 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
72 * Code based off of code located here
73 * http://www.codeproject.com/gdi/fontnamefromfile.asp
75 * Using string index 4 (full font name) instead of 1 (family name)
77 static LPWSTR load_ttfname_from(LPCWSTR filename)
79 TT_TABLE_DIRECTORY tblDir;
81 TT_OFFSET_TABLE ttOffsetTable;
82 TT_NAME_TABLE_HEADER ttNTHeader;
83 TT_NAME_RECORD ttRecord;
89 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
90 FILE_ATTRIBUTE_NORMAL, 0 );
91 if (handle == INVALID_HANDLE_VALUE)
93 ERR("Unable to open font file %s\n", debugstr_w(filename));
97 if (!ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL))
100 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
101 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
102 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
104 if (ttOffsetTable.uMajorVersion != 1 || ttOffsetTable.uMinorVersion != 0)
107 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
109 if (!ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL))
111 if (memcmp(tblDir.szTag,"name",4)==0)
114 tblDir.uLength = SWAPLONG(tblDir.uLength);
115 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
123 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
124 if (!ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER), &dwRead,NULL))
127 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
128 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
130 for(i=0; i<ttNTHeader.uNRCount; i++)
132 if (!ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL))
135 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
136 /* 4 is the Full Font Name */
137 if(ttRecord.uNameID == 4)
141 static LPCSTR tt = " (TrueType)";
143 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
144 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
145 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
146 SetFilePointer(handle, tblDir.uOffset +
147 ttRecord.uStringOffset +
148 ttNTHeader.uStorageOffset,
150 buf = msi_alloc_zero( ttRecord.uStringLength + 1 + strlen(tt) );
151 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
155 ret = strdupAtoW(buf);
161 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
168 TRACE("Returning fontname %s\n",debugstr_w(ret));
172 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
174 MSIPACKAGE *package = (MSIPACKAGE*)param;
178 static const WCHAR regfont1[] =
179 {'S','o','f','t','w','a','r','e','\\',
180 'M','i','c','r','o','s','o','f','t','\\',
181 'W','i','n','d','o','w','s',' ','N','T','\\',
182 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
183 'F','o','n','t','s',0};
184 static const WCHAR regfont2[] =
185 {'S','o','f','t','w','a','r','e','\\',
186 'M','i','c','r','o','s','o','f','t','\\',
187 'W','i','n','d','o','w','s','\\',
188 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
189 'F','o','n','t','s',0};
195 filename = MSI_RecordGetString( row, 1 );
196 file = get_loaded_file( package, filename );
199 ERR("Unable to load file\n");
200 return ERROR_SUCCESS;
203 /* check to make sure that component is installed */
204 if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
206 TRACE("Skipping: Component not scheduled for install\n");
207 return ERROR_SUCCESS;
210 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
211 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
213 if (MSI_RecordIsNull(row,2))
214 name = load_ttfname_from( file->TargetPath );
216 name = msi_dup_record_field(row,2);
220 msi_reg_set_val_str( hkey1, name, file->FileName );
221 msi_reg_set_val_str( hkey2, name, file->FileName );
229 uirow = MSI_CreateRecord( 1 );
230 uipath = strdupW( file->TargetPath );
231 p = strrchrW(uipath,'\\');
234 MSI_RecordSetStringW( uirow, 1, p );
235 ui_actiondata( package, szRegisterFonts, uirow);
236 msiobj_release( &uirow->hdr );
238 /* FIXME: call ui_progress? */
240 return ERROR_SUCCESS;
243 UINT ACTION_RegisterFonts(MSIPACKAGE *package)
247 static const WCHAR ExecSeqQuery[] =
248 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
249 '`','F','o','n','t','`',0};
251 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
252 if (rc != ERROR_SUCCESS)
254 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
255 return ERROR_SUCCESS;
258 MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
259 msiobj_release(&view->hdr);
261 return ERROR_SUCCESS;