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"
30 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
32 typedef struct _tagTT_OFFSET_TABLE
{
37 USHORT uEntrySelector
;
41 typedef struct _tagTT_TABLE_DIRECTORY
{
42 char szTag
[4]; /* table name */
43 ULONG uCheckSum
; /* Check sum */
44 ULONG uOffset
; /* Offset from beginning of file */
45 ULONG uLength
; /* length of the table in bytes */
48 typedef struct _tagTT_NAME_TABLE_HEADER
{
49 USHORT uFSelector
; /* format selector. Always 0 */
50 USHORT uNRCount
; /* Name Records count */
51 USHORT uStorageOffset
; /* Offset for strings storage,
52 * from start of the table */
53 } TT_NAME_TABLE_HEADER
;
55 typedef struct _tagTT_NAME_RECORD
{
61 USHORT uStringOffset
; /* from start of storage area */
64 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
65 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
67 static const WCHAR regfont1
[] =
68 {'S','o','f','t','w','a','r','e','\\',
69 'M','i','c','r','o','s','o','f','t','\\',
70 'W','i','n','d','o','w','s',' ','N','T','\\',
71 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
72 'F','o','n','t','s',0};
73 static const WCHAR regfont2
[] =
74 {'S','o','f','t','w','a','r','e','\\',
75 'M','i','c','r','o','s','o','f','t','\\',
76 'W','i','n','d','o','w','s','\\',
77 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
78 'F','o','n','t','s',0};
81 * Code based off of code located here
82 * http://www.codeproject.com/gdi/fontnamefromfile.asp
84 * Using string index 4 (full font name) instead of 1 (family name)
86 static LPWSTR
load_ttfname_from(LPCWSTR filename
)
88 TT_TABLE_DIRECTORY tblDir
;
90 TT_OFFSET_TABLE ttOffsetTable
;
91 TT_NAME_TABLE_HEADER ttNTHeader
;
92 TT_NAME_RECORD ttRecord
;
98 handle
= CreateFileW(filename
,GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
99 FILE_ATTRIBUTE_NORMAL
, 0 );
100 if (handle
== INVALID_HANDLE_VALUE
)
102 ERR("Unable to open font file %s\n", debugstr_w(filename
));
106 if (!ReadFile(handle
,&ttOffsetTable
, sizeof(TT_OFFSET_TABLE
),&dwRead
,NULL
))
109 ttOffsetTable
.uNumOfTables
= SWAPWORD(ttOffsetTable
.uNumOfTables
);
110 ttOffsetTable
.uMajorVersion
= SWAPWORD(ttOffsetTable
.uMajorVersion
);
111 ttOffsetTable
.uMinorVersion
= SWAPWORD(ttOffsetTable
.uMinorVersion
);
113 if (ttOffsetTable
.uMajorVersion
!= 1 || ttOffsetTable
.uMinorVersion
!= 0)
116 for (i
=0; i
< ttOffsetTable
.uNumOfTables
; i
++)
118 if (!ReadFile(handle
,&tblDir
, sizeof(TT_TABLE_DIRECTORY
),&dwRead
,NULL
))
120 if (memcmp(tblDir
.szTag
,"name",4)==0)
123 tblDir
.uLength
= SWAPLONG(tblDir
.uLength
);
124 tblDir
.uOffset
= SWAPLONG(tblDir
.uOffset
);
132 SetFilePointer(handle
, tblDir
.uOffset
, NULL
, FILE_BEGIN
);
133 if (!ReadFile(handle
,&ttNTHeader
, sizeof(TT_NAME_TABLE_HEADER
), &dwRead
,NULL
))
136 ttNTHeader
.uNRCount
= SWAPWORD(ttNTHeader
.uNRCount
);
137 ttNTHeader
.uStorageOffset
= SWAPWORD(ttNTHeader
.uStorageOffset
);
139 for(i
=0; i
<ttNTHeader
.uNRCount
; i
++)
141 if (!ReadFile(handle
,&ttRecord
, sizeof(TT_NAME_RECORD
),&dwRead
,NULL
))
144 ttRecord
.uNameID
= SWAPWORD(ttRecord
.uNameID
);
145 /* 4 is the Full Font Name */
146 if(ttRecord
.uNameID
== 4)
150 static const char tt
[] = " (TrueType)";
152 ttRecord
.uStringLength
= SWAPWORD(ttRecord
.uStringLength
);
153 ttRecord
.uStringOffset
= SWAPWORD(ttRecord
.uStringOffset
);
154 nPos
= SetFilePointer(handle
, 0, NULL
, FILE_CURRENT
);
155 SetFilePointer(handle
, tblDir
.uOffset
+
156 ttRecord
.uStringOffset
+
157 ttNTHeader
.uStorageOffset
,
159 buf
= msi_alloc_zero( ttRecord
.uStringLength
+ 1 + strlen(tt
) );
160 ReadFile(handle
, buf
, ttRecord
.uStringLength
, &dwRead
, NULL
);
164 ret
= strdupAtoW(buf
);
170 SetFilePointer(handle
,nPos
, NULL
, FILE_BEGIN
);
177 TRACE("Returning fontname %s\n",debugstr_w(ret
));
181 static UINT
ITERATE_RegisterFonts(MSIRECORD
*row
, LPVOID param
)
183 MSIPACKAGE
*package
= param
;
191 filename
= MSI_RecordGetString( row
, 1 );
192 file
= get_loaded_file( package
, filename
);
195 ERR("Unable to load file\n");
196 return ERROR_SUCCESS
;
199 if (file
->Component
->ActionRequest
!= INSTALLSTATE_LOCAL
)
201 TRACE("Component not scheduled for installation\n");
202 return ERROR_SUCCESS
;
205 RegCreateKeyW(HKEY_LOCAL_MACHINE
,regfont1
,&hkey1
);
206 RegCreateKeyW(HKEY_LOCAL_MACHINE
,regfont2
,&hkey2
);
208 if (MSI_RecordIsNull(row
,2))
209 name
= load_ttfname_from( file
->TargetPath
);
211 name
= msi_dup_record_field(row
,2);
215 msi_reg_set_val_str( hkey1
, name
, file
->TargetPath
);
216 msi_reg_set_val_str( hkey2
, name
, file
->TargetPath
);
224 uirow
= MSI_CreateRecord( 1 );
225 uipath
= strdupW( file
->TargetPath
);
226 p
= strrchrW(uipath
,'\\');
229 MSI_RecordSetStringW( uirow
, 1, p
);
230 ui_actiondata( package
, szRegisterFonts
, uirow
);
231 msiobj_release( &uirow
->hdr
);
233 /* FIXME: call ui_progress? */
235 return ERROR_SUCCESS
;
238 UINT
ACTION_RegisterFonts(MSIPACKAGE
*package
)
242 static const WCHAR ExecSeqQuery
[] =
243 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
244 '`','F','o','n','t','`',0};
246 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
247 if (rc
!= ERROR_SUCCESS
)
249 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc
);
250 return ERROR_SUCCESS
;
253 MSI_IterateRecords(view
, NULL
, ITERATE_RegisterFonts
, package
);
254 msiobj_release(&view
->hdr
);
256 return ERROR_SUCCESS
;
259 static UINT
ITERATE_UnregisterFonts( MSIRECORD
*row
, LPVOID param
)
261 MSIPACKAGE
*package
= param
;
269 filename
= MSI_RecordGetString( row
, 1 );
270 file
= get_loaded_file( package
, filename
);
273 ERR("Unable to load file\n");
274 return ERROR_SUCCESS
;
277 if (file
->Component
->ActionRequest
!= INSTALLSTATE_ABSENT
)
279 TRACE("Component not scheduled for removal\n");
280 return ERROR_SUCCESS
;
283 RegCreateKeyW( HKEY_LOCAL_MACHINE
, regfont1
, &hkey1
);
284 RegCreateKeyW( HKEY_LOCAL_MACHINE
, regfont2
, &hkey2
);
286 if (MSI_RecordIsNull( row
, 2 ))
287 name
= load_ttfname_from( file
->TargetPath
);
289 name
= msi_dup_record_field( row
, 2 );
293 RegDeleteValueW( hkey1
, name
);
294 RegDeleteValueW( hkey2
, name
);
298 RegCloseKey( hkey1
);
299 RegCloseKey( hkey2
);
302 uirow
= MSI_CreateRecord( 1 );
303 uipath
= strdupW( file
->TargetPath
);
304 p
= strrchrW( uipath
,'\\' );
307 MSI_RecordSetStringW( uirow
, 1, p
);
308 ui_actiondata( package
, szUnregisterFonts
, uirow
);
309 msiobj_release( &uirow
->hdr
);
311 /* FIXME: call ui_progress? */
313 return ERROR_SUCCESS
;
316 UINT
ACTION_UnregisterFonts( MSIPACKAGE
*package
)
320 static const WCHAR query
[] =
321 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
322 '`','F','o','n','t','`',0};
324 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
325 if (r
!= ERROR_SUCCESS
)
327 TRACE("MSI_DatabaseOpenViewW failed: %u\n", r
);
328 return ERROR_SUCCESS
;
331 MSI_IterateRecords( view
, NULL
, ITERATE_UnregisterFonts
, package
);
332 msiobj_release( &view
->hdr
);
334 return ERROR_SUCCESS
;