xref: /reactos/dll/win32/msi/font.c (revision 958f1add)
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