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
31*f4be6dc3SMikhail struct offset_table
32*f4be6dc3SMikhail {
33c2c66affSColin Finck USHORT uMajorVersion;
34c2c66affSColin Finck USHORT uMinorVersion;
35c2c66affSColin Finck USHORT uNumOfTables;
36c2c66affSColin Finck USHORT uSearchRange;
37c2c66affSColin Finck USHORT uEntrySelector;
38c2c66affSColin Finck USHORT uRangeShift;
39*f4be6dc3SMikhail };
40c2c66affSColin Finck
41*f4be6dc3SMikhail struct table_directory
42*f4be6dc3SMikhail {
43c2c66affSColin Finck char szTag[4]; /* table name */
44c2c66affSColin Finck ULONG uCheckSum; /* Check sum */
45c2c66affSColin Finck ULONG uOffset; /* Offset from beginning of file */
46c2c66affSColin Finck ULONG uLength; /* length of the table in bytes */
47*f4be6dc3SMikhail };
48c2c66affSColin Finck
49*f4be6dc3SMikhail struct name_table_header
50*f4be6dc3SMikhail {
51c2c66affSColin Finck USHORT uFSelector; /* format selector. Always 0 */
52c2c66affSColin Finck USHORT uNRCount; /* Name Records count */
53*f4be6dc3SMikhail USHORT uStorageOffset; /* Offset for strings storage from start of the table */
54*f4be6dc3SMikhail };
55c2c66affSColin Finck
56c2c66affSColin Finck #define NAME_ID_FULL_FONT_NAME 4
57c2c66affSColin Finck #define NAME_ID_VERSION 5
58c2c66affSColin Finck
59*f4be6dc3SMikhail struct name_record
60*f4be6dc3SMikhail {
61c2c66affSColin Finck USHORT uPlatformID;
62c2c66affSColin Finck USHORT uEncodingID;
63c2c66affSColin Finck USHORT uLanguageID;
64c2c66affSColin Finck USHORT uNameID;
65c2c66affSColin Finck USHORT uStringLength;
66c2c66affSColin Finck USHORT uStringOffset; /* from start of storage area */
67*f4be6dc3SMikhail };
68c2c66affSColin Finck
69c2c66affSColin Finck #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
70c2c66affSColin Finck #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
71c2c66affSColin Finck
72c2c66affSColin Finck /*
73c2c66affSColin Finck * Code based off of code located here
74c2c66affSColin Finck * http://www.codeproject.com/gdi/fontnamefromfile.asp
75c2c66affSColin Finck */
load_ttf_name_id(MSIPACKAGE * package,const WCHAR * filename,DWORD id)76e342f337Swinesync static WCHAR *load_ttf_name_id( MSIPACKAGE *package, const WCHAR *filename, DWORD id )
77c2c66affSColin Finck {
78*f4be6dc3SMikhail struct table_directory tblDir;
79c2c66affSColin Finck BOOL bFound = FALSE;
80*f4be6dc3SMikhail struct offset_table ttOffsetTable;
81*f4be6dc3SMikhail struct name_table_header ttNTHeader;
82*f4be6dc3SMikhail struct name_record ttRecord;
83c2c66affSColin Finck DWORD dwRead;
84c2c66affSColin Finck HANDLE handle;
85c2c66affSColin Finck LPWSTR ret = NULL;
86c2c66affSColin Finck int i;
87c2c66affSColin Finck
88e342f337Swinesync if (package)
89e342f337Swinesync handle = msi_create_file( package, filename, GENERIC_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL );
90e342f337Swinesync else
91e342f337Swinesync handle = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 );
92c2c66affSColin Finck if (handle == INVALID_HANDLE_VALUE)
93c2c66affSColin Finck {
94c2c66affSColin Finck ERR("Unable to open font file %s\n", debugstr_w(filename));
95c2c66affSColin Finck return NULL;
96c2c66affSColin Finck }
97c2c66affSColin Finck
98*f4be6dc3SMikhail if (!ReadFile(handle,&ttOffsetTable, sizeof(struct offset_table),&dwRead,NULL))
99c2c66affSColin Finck goto end;
100c2c66affSColin Finck
101c2c66affSColin Finck ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
102c2c66affSColin Finck ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
103c2c66affSColin Finck ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
104c2c66affSColin Finck
105c2c66affSColin Finck if ((ttOffsetTable.uMajorVersion != 1 || ttOffsetTable.uMinorVersion != 0) &&
106c2c66affSColin Finck (ttOffsetTable.uMajorVersion != 0x4f54 || ttOffsetTable.uMinorVersion != 0x544f))
107c2c66affSColin Finck goto end;
108c2c66affSColin Finck
109c2c66affSColin Finck for (i=0; i< ttOffsetTable.uNumOfTables; i++)
110c2c66affSColin Finck {
111*f4be6dc3SMikhail if (!ReadFile(handle, &tblDir, sizeof(tblDir), &dwRead, NULL))
112c2c66affSColin Finck break;
113c2c66affSColin Finck if (memcmp(tblDir.szTag,"name",4)==0)
114c2c66affSColin Finck {
115c2c66affSColin Finck bFound = TRUE;
116c2c66affSColin Finck tblDir.uLength = SWAPLONG(tblDir.uLength);
117c2c66affSColin Finck tblDir.uOffset = SWAPLONG(tblDir.uOffset);
118c2c66affSColin Finck break;
119c2c66affSColin Finck }
120c2c66affSColin Finck }
121c2c66affSColin Finck
122c2c66affSColin Finck if (!bFound)
123c2c66affSColin Finck goto end;
124c2c66affSColin Finck
125c2c66affSColin Finck SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
126*f4be6dc3SMikhail if (!ReadFile(handle, &ttNTHeader, sizeof(ttNTHeader), &dwRead, NULL))
127c2c66affSColin Finck goto end;
128c2c66affSColin Finck
129c2c66affSColin Finck ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
130c2c66affSColin Finck ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
131c2c66affSColin Finck for(i=0; i<ttNTHeader.uNRCount; i++)
132c2c66affSColin Finck {
133*f4be6dc3SMikhail if (!ReadFile(handle, &ttRecord, sizeof(ttRecord), &dwRead, NULL))
134c2c66affSColin Finck break;
135c2c66affSColin Finck
136c2c66affSColin Finck ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
137c2c66affSColin Finck ttRecord.uPlatformID = SWAPWORD(ttRecord.uPlatformID);
138c2c66affSColin Finck ttRecord.uEncodingID = SWAPWORD(ttRecord.uEncodingID);
139c2c66affSColin Finck if (ttRecord.uNameID == id && ttRecord.uPlatformID == 3 &&
140c2c66affSColin Finck (ttRecord.uEncodingID == 0 || ttRecord.uEncodingID == 1))
141c2c66affSColin Finck {
142c2c66affSColin Finck WCHAR *buf;
143c2c66affSColin Finck unsigned int i;
144c2c66affSColin Finck
145c2c66affSColin Finck ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
146c2c66affSColin Finck ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
147c2c66affSColin Finck SetFilePointer(handle, tblDir.uOffset + ttRecord.uStringOffset + ttNTHeader.uStorageOffset,
148c2c66affSColin Finck NULL, FILE_BEGIN);
149*f4be6dc3SMikhail if (!(buf = calloc(ttRecord.uStringLength, sizeof(WCHAR)))) goto end;
150c2c66affSColin Finck dwRead = 0;
151c2c66affSColin Finck ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
152c2c66affSColin Finck if (dwRead % sizeof(WCHAR))
153c2c66affSColin Finck {
154*f4be6dc3SMikhail free(buf);
155c2c66affSColin Finck goto end;
156c2c66affSColin Finck }
157c2c66affSColin Finck for (i = 0; i < dwRead / sizeof(WCHAR); i++) buf[i] = SWAPWORD(buf[i]);
158*f4be6dc3SMikhail ret = wcsdup(buf);
159*f4be6dc3SMikhail free(buf);
160c2c66affSColin Finck break;
161c2c66affSColin Finck }
162c2c66affSColin Finck }
163c2c66affSColin Finck
164c2c66affSColin Finck end:
165c2c66affSColin Finck CloseHandle(handle);
166c2c66affSColin Finck return ret;
167c2c66affSColin Finck }
168c2c66affSColin Finck
font_name_from_file(MSIPACKAGE * package,const WCHAR * filename)169e342f337Swinesync static WCHAR *font_name_from_file( MSIPACKAGE *package, const WCHAR *filename )
170c2c66affSColin Finck {
171c2c66affSColin Finck WCHAR *name, *ret = NULL;
172c2c66affSColin Finck
173e342f337Swinesync if ((name = load_ttf_name_id( package, filename, NAME_ID_FULL_FONT_NAME )))
174c2c66affSColin Finck {
175c2c66affSColin Finck if (!name[0])
176c2c66affSColin Finck {
177c2c66affSColin Finck WARN("empty font name\n");
178*f4be6dc3SMikhail free( name );
179c2c66affSColin Finck return NULL;
180c2c66affSColin Finck }
181*f4be6dc3SMikhail ret = malloc( wcslen( name ) * sizeof(WCHAR) + sizeof( L" (TrueType)" ) );
182958f1addSwinesync lstrcpyW( ret, name );
18374f53b4bSwinesync lstrcatW( ret, L" (TrueType)" );
184*f4be6dc3SMikhail free( name );
185c2c66affSColin Finck }
186c2c66affSColin Finck return ret;
187c2c66affSColin Finck }
188c2c66affSColin Finck
msi_get_font_file_version(MSIPACKAGE * package,const WCHAR * filename)189e342f337Swinesync WCHAR *msi_get_font_file_version( MSIPACKAGE *package, const WCHAR *filename )
190c2c66affSColin Finck {
191c2c66affSColin Finck WCHAR *version, *p, *q, *ret = NULL;
192c2c66affSColin Finck
193e342f337Swinesync if ((version = load_ttf_name_id( package, filename, NAME_ID_VERSION )))
194c2c66affSColin Finck {
195c2c66affSColin Finck int len, major = 0, minor = 0;
196958f1addSwinesync if ((p = wcschr( version, ';' ))) *p = 0;
197c2c66affSColin Finck p = version;
198958f1addSwinesync while (*p && !iswdigit( *p )) p++;
199958f1addSwinesync if ((q = wcschr( p, '.' )))
200c2c66affSColin Finck {
201958f1addSwinesync major = wcstol( p, NULL, 10 );
202c2c66affSColin Finck p = ++q;
203958f1addSwinesync while (*q && iswdigit( *q )) q++;
204958f1addSwinesync if (!*q || *q == ' ') minor = wcstol( p, NULL, 10 );
205c2c66affSColin Finck else major = 0;
206c2c66affSColin Finck }
20774f53b4bSwinesync len = lstrlenW( L"%u.%u.0.0" ) + 20;
208*f4be6dc3SMikhail ret = malloc( len * sizeof(WCHAR) );
20974f53b4bSwinesync swprintf( ret, len, L"%u.%u.0.0", major, minor );
210*f4be6dc3SMikhail free( version );
211c2c66affSColin Finck }
212c2c66affSColin Finck return ret;
213c2c66affSColin Finck }
214c2c66affSColin Finck
ITERATE_RegisterFonts(MSIRECORD * row,LPVOID param)215c2c66affSColin Finck static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
216c2c66affSColin Finck {
217c2c66affSColin Finck MSIPACKAGE *package = param;
218c2c66affSColin Finck LPWSTR name;
219c2c66affSColin Finck LPCWSTR filename;
220c2c66affSColin Finck MSIFILE *file;
221c2c66affSColin Finck MSICOMPONENT *comp;
222c2c66affSColin Finck HKEY hkey1, hkey2;
223c2c66affSColin Finck MSIRECORD *uirow;
224c2c66affSColin Finck LPWSTR uipath, p;
225c2c66affSColin Finck
226c2c66affSColin Finck filename = MSI_RecordGetString( row, 1 );
227c2c66affSColin Finck file = msi_get_loaded_file( package, filename );
228c2c66affSColin Finck if (!file)
229c2c66affSColin Finck {
230c2c66affSColin Finck WARN("unable to find file %s\n", debugstr_w(filename));
231c2c66affSColin Finck return ERROR_SUCCESS;
232c2c66affSColin Finck }
233c2c66affSColin Finck comp = msi_get_loaded_component( package, file->Component->Component );
234c2c66affSColin Finck if (!comp)
235c2c66affSColin Finck {
236c2c66affSColin Finck WARN("unable to find component %s\n", debugstr_w(file->Component->Component));
237c2c66affSColin Finck return ERROR_SUCCESS;
238c2c66affSColin Finck }
239c2c66affSColin Finck comp->Action = msi_get_component_action( package, comp );
240c2c66affSColin Finck if (comp->Action != INSTALLSTATE_LOCAL)
241c2c66affSColin Finck {
242c2c66affSColin Finck TRACE("component not scheduled for installation %s\n", debugstr_w(comp->Component));
243c2c66affSColin Finck return ERROR_SUCCESS;
244c2c66affSColin Finck }
245c2c66affSColin Finck
24674f53b4bSwinesync RegCreateKeyW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts" ,&hkey1 );
24774f53b4bSwinesync RegCreateKeyW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Fonts", &hkey2 );
248c2c66affSColin Finck
249c2c66affSColin Finck if (MSI_RecordIsNull(row,2))
250e342f337Swinesync name = font_name_from_file( package, file->TargetPath );
251c2c66affSColin Finck else
252c2c66affSColin Finck name = msi_dup_record_field(row,2);
253c2c66affSColin Finck
254c2c66affSColin Finck if (name)
255c2c66affSColin Finck {
256c2c66affSColin Finck msi_reg_set_val_str( hkey1, name, file->TargetPath);
257c2c66affSColin Finck msi_reg_set_val_str( hkey2, name, file->TargetPath);
258c2c66affSColin Finck }
259c2c66affSColin Finck
260*f4be6dc3SMikhail free(name);
261c2c66affSColin Finck RegCloseKey(hkey1);
262c2c66affSColin Finck RegCloseKey(hkey2);
263c2c66affSColin Finck
264c2c66affSColin Finck /* the UI chunk */
265c2c66affSColin Finck uirow = MSI_CreateRecord( 1 );
266*f4be6dc3SMikhail uipath = wcsdup( file->TargetPath );
267958f1addSwinesync p = wcsrchr(uipath,'\\');
268c2c66affSColin Finck if (p) p++;
269c2c66affSColin Finck else p = uipath;
270c2c66affSColin Finck MSI_RecordSetStringW( uirow, 1, p );
27171bffdcdSAmine Khaldi MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
272c2c66affSColin Finck msiobj_release( &uirow->hdr );
273*f4be6dc3SMikhail free( uipath );
274c2c66affSColin Finck /* FIXME: call msi_ui_progress? */
275c2c66affSColin Finck
276c2c66affSColin Finck return ERROR_SUCCESS;
277c2c66affSColin Finck }
278c2c66affSColin Finck
ACTION_RegisterFonts(MSIPACKAGE * package)279c2c66affSColin Finck UINT ACTION_RegisterFonts(MSIPACKAGE *package)
280c2c66affSColin Finck {
281c2c66affSColin Finck MSIQUERY *view;
282c2c66affSColin Finck UINT rc;
283c2c66affSColin Finck
284fd8b07bdSwinesync if (package->script == SCRIPT_NONE)
28574f53b4bSwinesync return msi_schedule_action(package, SCRIPT_INSTALL, L"RegisterFonts");
286fd8b07bdSwinesync
28774f53b4bSwinesync rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `Font`", &view);
288c2c66affSColin Finck if (rc != ERROR_SUCCESS)
289c2c66affSColin Finck return ERROR_SUCCESS;
290c2c66affSColin Finck
291c2c66affSColin Finck rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
292c2c66affSColin Finck msiobj_release(&view->hdr);
293c2c66affSColin Finck return rc;
294c2c66affSColin Finck }
295c2c66affSColin Finck
ITERATE_UnregisterFonts(MSIRECORD * row,LPVOID param)296c2c66affSColin Finck static UINT ITERATE_UnregisterFonts( MSIRECORD *row, LPVOID param )
297c2c66affSColin Finck {
298c2c66affSColin Finck MSIPACKAGE *package = param;
299c2c66affSColin Finck LPWSTR name;
300c2c66affSColin Finck LPCWSTR filename;
301c2c66affSColin Finck MSIFILE *file;
302c2c66affSColin Finck MSICOMPONENT *comp;
303c2c66affSColin Finck HKEY hkey1, hkey2;
304c2c66affSColin Finck MSIRECORD *uirow;
305c2c66affSColin Finck LPWSTR uipath, p;
306c2c66affSColin Finck
307c2c66affSColin Finck filename = MSI_RecordGetString( row, 1 );
308c2c66affSColin Finck file = msi_get_loaded_file( package, filename );
309c2c66affSColin Finck if (!file)
310c2c66affSColin Finck {
311c2c66affSColin Finck WARN("unable to find file %s\n", debugstr_w(filename));
312c2c66affSColin Finck return ERROR_SUCCESS;
313c2c66affSColin Finck }
314c2c66affSColin Finck comp = msi_get_loaded_component( package, file->Component->Component );
315c2c66affSColin Finck if (!comp)
316c2c66affSColin Finck {
317c2c66affSColin Finck WARN("unable to find component %s\n", debugstr_w(file->Component->Component));
318c2c66affSColin Finck return ERROR_SUCCESS;
319c2c66affSColin Finck }
320c2c66affSColin Finck comp->Action = msi_get_component_action( package, comp );
321c2c66affSColin Finck if (comp->Action != INSTALLSTATE_ABSENT)
322c2c66affSColin Finck {
323c2c66affSColin Finck TRACE("component not scheduled for removal %s\n", debugstr_w(comp->Component));
324c2c66affSColin Finck return ERROR_SUCCESS;
325c2c66affSColin Finck }
326c2c66affSColin Finck
32774f53b4bSwinesync RegCreateKeyW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", &hkey1 );
32874f53b4bSwinesync RegCreateKeyW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Fonts", &hkey2 );
329c2c66affSColin Finck
330c2c66affSColin Finck if (MSI_RecordIsNull( row, 2 ))
331e342f337Swinesync name = font_name_from_file( package, file->TargetPath );
332c2c66affSColin Finck else
333c2c66affSColin Finck name = msi_dup_record_field( row, 2 );
334c2c66affSColin Finck
335c2c66affSColin Finck if (name)
336c2c66affSColin Finck {
337c2c66affSColin Finck RegDeleteValueW( hkey1, name );
338c2c66affSColin Finck RegDeleteValueW( hkey2, name );
339c2c66affSColin Finck }
340c2c66affSColin Finck
341*f4be6dc3SMikhail free( name );
342c2c66affSColin Finck RegCloseKey( hkey1 );
343c2c66affSColin Finck RegCloseKey( hkey2 );
344c2c66affSColin Finck
345c2c66affSColin Finck /* the UI chunk */
346c2c66affSColin Finck uirow = MSI_CreateRecord( 1 );
347*f4be6dc3SMikhail uipath = wcsdup( file->TargetPath );
348958f1addSwinesync p = wcsrchr( uipath,'\\' );
349c2c66affSColin Finck if (p) p++;
350c2c66affSColin Finck else p = uipath;
351c2c66affSColin Finck MSI_RecordSetStringW( uirow, 1, p );
35271bffdcdSAmine Khaldi MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
353c2c66affSColin Finck msiobj_release( &uirow->hdr );
354*f4be6dc3SMikhail free( uipath );
355c2c66affSColin Finck /* FIXME: call msi_ui_progress? */
356c2c66affSColin Finck
357c2c66affSColin Finck return ERROR_SUCCESS;
358c2c66affSColin Finck }
359c2c66affSColin Finck
ACTION_UnregisterFonts(MSIPACKAGE * package)360c2c66affSColin Finck UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
361c2c66affSColin Finck {
362c2c66affSColin Finck MSIQUERY *view;
363c2c66affSColin Finck UINT r;
364c2c66affSColin Finck
365fd8b07bdSwinesync if (package->script == SCRIPT_NONE)
36674f53b4bSwinesync return msi_schedule_action(package, SCRIPT_INSTALL, L"UnregisterFonts");
367fd8b07bdSwinesync
36874f53b4bSwinesync r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Font`", &view );
369c2c66affSColin Finck if (r != ERROR_SUCCESS)
370c2c66affSColin Finck return ERROR_SUCCESS;
371c2c66affSColin Finck
372c2c66affSColin Finck r = MSI_IterateRecords( view, NULL, ITERATE_UnregisterFonts, package );
373c2c66affSColin Finck msiobj_release( &view->hdr );
374c2c66affSColin Finck return r;
375c2c66affSColin Finck }
376