xref: /reactos/dll/win32/msi/classes.c (revision c42b133e)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * Implementation of the Microsoft Installer (msi.dll)
3c2c66affSColin Finck  *
4c2c66affSColin Finck  * Copyright 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 
21c2c66affSColin Finck /* Actions handled in this module:
22c2c66affSColin Finck  *
23c2c66affSColin Finck  * RegisterClassInfo
24c2c66affSColin Finck  * RegisterProgIdInfo
25c2c66affSColin Finck  * RegisterExtensionInfo
26c2c66affSColin Finck  * RegisterMIMEInfo
27c2c66affSColin Finck  * UnregisterClassInfo
28c2c66affSColin Finck  * UnregisterProgIdInfo
29c2c66affSColin Finck  * UnregisterExtensionInfo
30c2c66affSColin Finck  * UnregisterMIMEInfo
31c2c66affSColin Finck  */
32c2c66affSColin Finck 
33*c42b133eSAmine Khaldi #include <stdarg.h>
34*c42b133eSAmine Khaldi 
35*c42b133eSAmine Khaldi #include "windef.h"
36*c42b133eSAmine Khaldi #include "winbase.h"
37*c42b133eSAmine Khaldi #include "winerror.h"
38*c42b133eSAmine Khaldi #include "winreg.h"
39*c42b133eSAmine Khaldi #include "wine/debug.h"
40c2c66affSColin Finck #include "msipriv.h"
41*c42b133eSAmine Khaldi #include "winuser.h"
42*c42b133eSAmine Khaldi #include "wine/unicode.h"
43c2c66affSColin Finck 
44c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL(msi);
45c2c66affSColin Finck 
46c2c66affSColin Finck static MSIAPPID *load_appid( MSIPACKAGE* package, MSIRECORD *row )
47c2c66affSColin Finck {
48c2c66affSColin Finck     LPCWSTR buffer;
49c2c66affSColin Finck     MSIAPPID *appid;
50c2c66affSColin Finck 
51c2c66affSColin Finck     /* fill in the data */
52c2c66affSColin Finck 
53c2c66affSColin Finck     appid = msi_alloc_zero( sizeof(MSIAPPID) );
54c2c66affSColin Finck     if (!appid)
55c2c66affSColin Finck         return NULL;
56c2c66affSColin Finck 
57c2c66affSColin Finck     appid->AppID = msi_dup_record_field( row, 1 );
58c2c66affSColin Finck     TRACE("loading appid %s\n", debugstr_w( appid->AppID ));
59c2c66affSColin Finck 
60c2c66affSColin Finck     buffer = MSI_RecordGetString(row,2);
61c2c66affSColin Finck     deformat_string( package, buffer, &appid->RemoteServerName );
62c2c66affSColin Finck 
63c2c66affSColin Finck     appid->LocalServer = msi_dup_record_field(row,3);
64c2c66affSColin Finck     appid->ServiceParameters = msi_dup_record_field(row,4);
65c2c66affSColin Finck     appid->DllSurrogate = msi_dup_record_field(row,5);
66c2c66affSColin Finck 
67c2c66affSColin Finck     appid->ActivateAtStorage = !MSI_RecordIsNull(row,6);
68c2c66affSColin Finck     appid->RunAsInteractiveUser = !MSI_RecordIsNull(row,7);
69c2c66affSColin Finck 
70c2c66affSColin Finck     list_add_tail( &package->appids, &appid->entry );
71c2c66affSColin Finck 
72c2c66affSColin Finck     return appid;
73c2c66affSColin Finck }
74c2c66affSColin Finck 
75c2c66affSColin Finck static MSIAPPID *load_given_appid( MSIPACKAGE *package, LPCWSTR name )
76c2c66affSColin Finck {
77c2c66affSColin Finck     static const WCHAR query[] = {
78c2c66affSColin Finck         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
79c2c66affSColin Finck         '`','A','p','p','I','d','`',' ','W','H','E','R','E',' ',
80c2c66affSColin Finck         '`','A','p','p','I','d','`',' ','=',' ','\'','%','s','\'',0};
81c2c66affSColin Finck     MSIRECORD *row;
82c2c66affSColin Finck     MSIAPPID *appid;
83c2c66affSColin Finck 
84c2c66affSColin Finck     if (!name)
85c2c66affSColin Finck         return NULL;
86c2c66affSColin Finck 
87c2c66affSColin Finck     /* check for appids already loaded */
88c2c66affSColin Finck     LIST_FOR_EACH_ENTRY( appid, &package->appids, MSIAPPID, entry )
89c2c66affSColin Finck     {
90c2c66affSColin Finck         if (!strcmpiW( appid->AppID, name ))
91c2c66affSColin Finck         {
92c2c66affSColin Finck             TRACE("found appid %s %p\n", debugstr_w(name), appid);
93c2c66affSColin Finck             return appid;
94c2c66affSColin Finck         }
95c2c66affSColin Finck     }
96c2c66affSColin Finck 
97c2c66affSColin Finck     row = MSI_QueryGetRecord(package->db, query, name);
98c2c66affSColin Finck     if (!row)
99c2c66affSColin Finck         return NULL;
100c2c66affSColin Finck 
101c2c66affSColin Finck     appid = load_appid(package, row);
102c2c66affSColin Finck     msiobj_release(&row->hdr);
103c2c66affSColin Finck     return appid;
104c2c66affSColin Finck }
105c2c66affSColin Finck 
106c2c66affSColin Finck static MSIPROGID *load_given_progid(MSIPACKAGE *package, LPCWSTR progid);
107c2c66affSColin Finck static MSICLASS *load_given_class( MSIPACKAGE *package, LPCWSTR classid );
108c2c66affSColin Finck 
109c2c66affSColin Finck static MSIPROGID *load_progid( MSIPACKAGE* package, MSIRECORD *row )
110c2c66affSColin Finck {
111c2c66affSColin Finck     MSIPROGID *progid;
112c2c66affSColin Finck     LPCWSTR buffer;
113c2c66affSColin Finck 
114c2c66affSColin Finck     /* fill in the data */
115c2c66affSColin Finck 
116c2c66affSColin Finck     progid = msi_alloc_zero( sizeof(MSIPROGID) );
117c2c66affSColin Finck     if (!progid)
118c2c66affSColin Finck         return NULL;
119c2c66affSColin Finck 
120c2c66affSColin Finck     list_add_tail( &package->progids, &progid->entry );
121c2c66affSColin Finck 
122c2c66affSColin Finck     progid->ProgID = msi_dup_record_field(row,1);
123c2c66affSColin Finck     TRACE("loading progid %s\n",debugstr_w(progid->ProgID));
124c2c66affSColin Finck 
125c2c66affSColin Finck     buffer = MSI_RecordGetString(row,2);
126c2c66affSColin Finck     progid->Parent = load_given_progid(package,buffer);
127c2c66affSColin Finck     if (progid->Parent == NULL && buffer)
128c2c66affSColin Finck         FIXME("Unknown parent ProgID %s\n",debugstr_w(buffer));
129c2c66affSColin Finck 
130c2c66affSColin Finck     buffer = MSI_RecordGetString(row,3);
131c2c66affSColin Finck     progid->Class = load_given_class(package,buffer);
132c2c66affSColin Finck     if (progid->Class == NULL && buffer)
133c2c66affSColin Finck         FIXME("Unknown class %s\n",debugstr_w(buffer));
134c2c66affSColin Finck 
135c2c66affSColin Finck     progid->Description = msi_dup_record_field(row,4);
136c2c66affSColin Finck 
137c2c66affSColin Finck     if (!MSI_RecordIsNull(row,6))
138c2c66affSColin Finck     {
139c2c66affSColin Finck         INT icon_index = MSI_RecordGetInteger(row,6);
140c2c66affSColin Finck         LPCWSTR FileName = MSI_RecordGetString(row,5);
141c2c66affSColin Finck         LPWSTR FilePath;
142c2c66affSColin Finck         static const WCHAR fmt[] = {'%','s',',','%','i',0};
143c2c66affSColin Finck 
144c2c66affSColin Finck         FilePath = msi_build_icon_path(package, FileName);
145c2c66affSColin Finck 
146c2c66affSColin Finck         progid->IconPath = msi_alloc( (strlenW(FilePath)+10)* sizeof(WCHAR) );
147c2c66affSColin Finck 
148c2c66affSColin Finck         sprintfW(progid->IconPath,fmt,FilePath,icon_index);
149c2c66affSColin Finck 
150c2c66affSColin Finck         msi_free(FilePath);
151c2c66affSColin Finck     }
152c2c66affSColin Finck     else
153c2c66affSColin Finck     {
154c2c66affSColin Finck         buffer = MSI_RecordGetString(row,5);
155c2c66affSColin Finck         if (buffer)
156c2c66affSColin Finck             progid->IconPath = msi_build_icon_path(package, buffer);
157c2c66affSColin Finck     }
158c2c66affSColin Finck 
159c2c66affSColin Finck     progid->CurVer = NULL;
160c2c66affSColin Finck     progid->VersionInd = NULL;
161c2c66affSColin Finck 
162c2c66affSColin Finck     /* if we have a parent then we may be that parents CurVer */
163c2c66affSColin Finck     if (progid->Parent && progid->Parent != progid)
164c2c66affSColin Finck     {
165c2c66affSColin Finck         MSIPROGID *parent = progid->Parent;
166c2c66affSColin Finck 
167c2c66affSColin Finck         while (parent->Parent && parent->Parent != parent)
168c2c66affSColin Finck             parent = parent->Parent;
169c2c66affSColin Finck 
170c2c66affSColin Finck         /* FIXME: need to determine if we are really the CurVer */
171c2c66affSColin Finck 
172c2c66affSColin Finck         progid->CurVer = parent;
173c2c66affSColin Finck         parent->VersionInd = progid;
174c2c66affSColin Finck     }
175c2c66affSColin Finck 
176c2c66affSColin Finck     return progid;
177c2c66affSColin Finck }
178c2c66affSColin Finck 
179c2c66affSColin Finck static MSIPROGID *load_given_progid(MSIPACKAGE *package, LPCWSTR name)
180c2c66affSColin Finck {
181c2c66affSColin Finck     static const WCHAR query[] = {
182c2c66affSColin Finck         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
183c2c66affSColin Finck         '`','P','r','o','g','I','d','`',' ','W','H','E','R','E',' ',
184c2c66affSColin Finck         '`','P','r','o','g','I','d','`',' ','=',' ','\'','%','s','\'',0};
185c2c66affSColin Finck     MSIPROGID *progid;
186c2c66affSColin Finck     MSIRECORD *row;
187c2c66affSColin Finck 
188c2c66affSColin Finck     if (!name)
189c2c66affSColin Finck         return NULL;
190c2c66affSColin Finck 
191c2c66affSColin Finck     /* check for progids already loaded */
192c2c66affSColin Finck     LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry )
193c2c66affSColin Finck     {
194c2c66affSColin Finck         if (!strcmpiW( progid->ProgID, name ))
195c2c66affSColin Finck         {
196c2c66affSColin Finck             TRACE("found progid %s (%p)\n",debugstr_w(name), progid );
197c2c66affSColin Finck             return progid;
198c2c66affSColin Finck         }
199c2c66affSColin Finck     }
200c2c66affSColin Finck 
201c2c66affSColin Finck     row = MSI_QueryGetRecord( package->db, query, name );
202c2c66affSColin Finck     if (!row)
203c2c66affSColin Finck         return NULL;
204c2c66affSColin Finck 
205c2c66affSColin Finck     progid = load_progid(package, row);
206c2c66affSColin Finck     msiobj_release(&row->hdr);
207c2c66affSColin Finck     return progid;
208c2c66affSColin Finck }
209c2c66affSColin Finck 
210c2c66affSColin Finck static MSICLASS *load_class( MSIPACKAGE* package, MSIRECORD *row )
211c2c66affSColin Finck {
212c2c66affSColin Finck     MSICLASS *cls;
213c2c66affSColin Finck     DWORD i;
214c2c66affSColin Finck     LPCWSTR buffer;
215c2c66affSColin Finck 
216c2c66affSColin Finck     /* fill in the data */
217c2c66affSColin Finck 
218c2c66affSColin Finck     cls = msi_alloc_zero( sizeof(MSICLASS) );
219c2c66affSColin Finck     if (!cls)
220c2c66affSColin Finck         return NULL;
221c2c66affSColin Finck 
222c2c66affSColin Finck     list_add_tail( &package->classes, &cls->entry );
223c2c66affSColin Finck 
224c2c66affSColin Finck     cls->clsid = msi_dup_record_field( row, 1 );
225c2c66affSColin Finck     TRACE("loading class %s\n",debugstr_w(cls->clsid));
226c2c66affSColin Finck     cls->Context = msi_dup_record_field( row, 2 );
227c2c66affSColin Finck     buffer = MSI_RecordGetString(row,3);
228c2c66affSColin Finck     cls->Component = msi_get_loaded_component( package, buffer );
229c2c66affSColin Finck 
230c2c66affSColin Finck     cls->ProgIDText = msi_dup_record_field(row,4);
231c2c66affSColin Finck     cls->ProgID = load_given_progid(package, cls->ProgIDText);
232c2c66affSColin Finck 
233c2c66affSColin Finck     cls->Description = msi_dup_record_field(row,5);
234c2c66affSColin Finck 
235c2c66affSColin Finck     buffer = MSI_RecordGetString(row,6);
236c2c66affSColin Finck     if (buffer)
237c2c66affSColin Finck         cls->AppID = load_given_appid(package, buffer);
238c2c66affSColin Finck 
239c2c66affSColin Finck     cls->FileTypeMask = msi_dup_record_field(row,7);
240c2c66affSColin Finck 
241c2c66affSColin Finck     if (!MSI_RecordIsNull(row,9))
242c2c66affSColin Finck     {
243c2c66affSColin Finck 
244c2c66affSColin Finck         INT icon_index = MSI_RecordGetInteger(row,9);
245c2c66affSColin Finck         LPCWSTR FileName = MSI_RecordGetString(row,8);
246c2c66affSColin Finck         LPWSTR FilePath;
247c2c66affSColin Finck         static const WCHAR fmt[] = {'%','s',',','%','i',0};
248c2c66affSColin Finck 
249c2c66affSColin Finck         FilePath = msi_build_icon_path(package, FileName);
250c2c66affSColin Finck 
251c2c66affSColin Finck         cls->IconPath = msi_alloc( (strlenW(FilePath)+5)* sizeof(WCHAR) );
252c2c66affSColin Finck 
253c2c66affSColin Finck         sprintfW(cls->IconPath,fmt,FilePath,icon_index);
254c2c66affSColin Finck 
255c2c66affSColin Finck         msi_free(FilePath);
256c2c66affSColin Finck     }
257c2c66affSColin Finck     else
258c2c66affSColin Finck     {
259c2c66affSColin Finck         buffer = MSI_RecordGetString(row,8);
260c2c66affSColin Finck         if (buffer)
261c2c66affSColin Finck             cls->IconPath = msi_build_icon_path(package, buffer);
262c2c66affSColin Finck     }
263c2c66affSColin Finck 
264c2c66affSColin Finck     if (!MSI_RecordIsNull(row,10))
265c2c66affSColin Finck     {
266c2c66affSColin Finck         i = MSI_RecordGetInteger(row,10);
267c2c66affSColin Finck         if (i != MSI_NULL_INTEGER && i > 0 &&  i < 4)
268c2c66affSColin Finck         {
269c2c66affSColin Finck             static const WCHAR ole2[] = {'o','l','e','2','.','d','l','l',0};
270c2c66affSColin Finck             static const WCHAR ole32[] = {'o','l','e','3','2','.','d','l','l',0};
271c2c66affSColin Finck 
272c2c66affSColin Finck             switch(i)
273c2c66affSColin Finck             {
274c2c66affSColin Finck                 case 1:
275c2c66affSColin Finck                     cls->DefInprocHandler = strdupW(ole2);
276c2c66affSColin Finck                     break;
277c2c66affSColin Finck                 case 2:
278c2c66affSColin Finck                     cls->DefInprocHandler32 = strdupW(ole32);
279c2c66affSColin Finck                     break;
280c2c66affSColin Finck                 case 3:
281c2c66affSColin Finck                     cls->DefInprocHandler = strdupW(ole2);
282c2c66affSColin Finck                     cls->DefInprocHandler32 = strdupW(ole32);
283c2c66affSColin Finck                     break;
284c2c66affSColin Finck             }
285c2c66affSColin Finck         }
286c2c66affSColin Finck         else
287c2c66affSColin Finck         {
288c2c66affSColin Finck             cls->DefInprocHandler32 = msi_dup_record_field( row, 10 );
289c2c66affSColin Finck             msi_reduce_to_long_filename( cls->DefInprocHandler32 );
290c2c66affSColin Finck         }
291c2c66affSColin Finck     }
292c2c66affSColin Finck     buffer = MSI_RecordGetString(row,11);
293c2c66affSColin Finck     deformat_string(package,buffer,&cls->Argument);
294c2c66affSColin Finck 
295c2c66affSColin Finck     buffer = MSI_RecordGetString(row,12);
296c2c66affSColin Finck     cls->Feature = msi_get_loaded_feature(package, buffer);
297c2c66affSColin Finck 
298c2c66affSColin Finck     cls->Attributes = MSI_RecordGetInteger(row,13);
299c2c66affSColin Finck     cls->action = INSTALLSTATE_UNKNOWN;
300c2c66affSColin Finck     return cls;
301c2c66affSColin Finck }
302c2c66affSColin Finck 
303c2c66affSColin Finck /*
304c2c66affSColin Finck  * the Class table has 3 primary keys. Generally it is only
305c2c66affSColin Finck  * referenced through the first CLSID key. However when loading
306c2c66affSColin Finck  * all of the classes we need to make sure we do not ignore rows
307c2c66affSColin Finck  * with other Context and ComponentIndexs
308c2c66affSColin Finck  */
309c2c66affSColin Finck static MSICLASS *load_given_class(MSIPACKAGE *package, LPCWSTR classid)
310c2c66affSColin Finck {
311c2c66affSColin Finck     static const WCHAR query[] = {
312c2c66affSColin Finck         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
313c2c66affSColin Finck         '`','C','l','a','s','s','`',' ','W','H','E','R','E',' ',
314c2c66affSColin Finck         '`','C','L','S','I','D','`',' ','=',' ','\'','%','s','\'',0};
315c2c66affSColin Finck     MSICLASS *cls;
316c2c66affSColin Finck     MSIRECORD *row;
317c2c66affSColin Finck 
318c2c66affSColin Finck     if (!classid)
319c2c66affSColin Finck         return NULL;
320c2c66affSColin Finck 
321c2c66affSColin Finck     /* check for classes already loaded */
322c2c66affSColin Finck     LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry )
323c2c66affSColin Finck     {
324c2c66affSColin Finck         if (!strcmpiW( cls->clsid, classid ))
325c2c66affSColin Finck         {
326c2c66affSColin Finck             TRACE("found class %s (%p)\n",debugstr_w(classid), cls);
327c2c66affSColin Finck             return cls;
328c2c66affSColin Finck         }
329c2c66affSColin Finck     }
330c2c66affSColin Finck 
331c2c66affSColin Finck     row = MSI_QueryGetRecord(package->db, query, classid);
332c2c66affSColin Finck     if (!row)
333c2c66affSColin Finck         return NULL;
334c2c66affSColin Finck 
335c2c66affSColin Finck     cls = load_class(package, row);
336c2c66affSColin Finck     msiobj_release(&row->hdr);
337c2c66affSColin Finck     return cls;
338c2c66affSColin Finck }
339c2c66affSColin Finck 
340c2c66affSColin Finck static MSIEXTENSION *load_given_extension( MSIPACKAGE *package, LPCWSTR extension );
341c2c66affSColin Finck 
342c2c66affSColin Finck static MSIMIME *load_mime( MSIPACKAGE* package, MSIRECORD *row )
343c2c66affSColin Finck {
344c2c66affSColin Finck     LPCWSTR extension;
345c2c66affSColin Finck     MSIMIME *mt;
346c2c66affSColin Finck 
347c2c66affSColin Finck     /* fill in the data */
348c2c66affSColin Finck 
349c2c66affSColin Finck     mt = msi_alloc_zero( sizeof(MSIMIME) );
350c2c66affSColin Finck     if (!mt)
351c2c66affSColin Finck         return mt;
352c2c66affSColin Finck 
353c2c66affSColin Finck     mt->ContentType = msi_dup_record_field( row, 1 );
354c2c66affSColin Finck     TRACE("loading mime %s\n", debugstr_w(mt->ContentType));
355c2c66affSColin Finck 
356c2c66affSColin Finck     extension = MSI_RecordGetString( row, 2 );
357c2c66affSColin Finck     mt->Extension = load_given_extension( package, extension );
358c2c66affSColin Finck     mt->suffix = strdupW( extension );
359c2c66affSColin Finck 
360c2c66affSColin Finck     mt->clsid = msi_dup_record_field( row, 3 );
361c2c66affSColin Finck     mt->Class = load_given_class( package, mt->clsid );
362c2c66affSColin Finck 
363c2c66affSColin Finck     list_add_tail( &package->mimes, &mt->entry );
364c2c66affSColin Finck 
365c2c66affSColin Finck     return mt;
366c2c66affSColin Finck }
367c2c66affSColin Finck 
368c2c66affSColin Finck static MSIMIME *load_given_mime( MSIPACKAGE *package, LPCWSTR mime )
369c2c66affSColin Finck {
370c2c66affSColin Finck     static const WCHAR query[] = {
371c2c66affSColin Finck         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
372c2c66affSColin Finck         '`','M','I','M','E','`',' ','W','H','E','R','E',' ',
373c2c66affSColin Finck         '`','C','o','n','t','e','n','t','T','y','p','e','`',' ','=',' ','\'','%','s','\'',0};
374c2c66affSColin Finck     MSIRECORD *row;
375c2c66affSColin Finck     MSIMIME *mt;
376c2c66affSColin Finck 
377c2c66affSColin Finck     if (!mime)
378c2c66affSColin Finck         return NULL;
379c2c66affSColin Finck 
380c2c66affSColin Finck     /* check for mime already loaded */
381c2c66affSColin Finck     LIST_FOR_EACH_ENTRY( mt, &package->mimes, MSIMIME, entry )
382c2c66affSColin Finck     {
383c2c66affSColin Finck         if (!strcmpiW( mt->ContentType, mime ))
384c2c66affSColin Finck         {
385c2c66affSColin Finck             TRACE("found mime %s (%p)\n",debugstr_w(mime), mt);
386c2c66affSColin Finck             return mt;
387c2c66affSColin Finck         }
388c2c66affSColin Finck     }
389c2c66affSColin Finck 
390c2c66affSColin Finck     row = MSI_QueryGetRecord(package->db, query, mime);
391c2c66affSColin Finck     if (!row)
392c2c66affSColin Finck         return NULL;
393c2c66affSColin Finck 
394c2c66affSColin Finck     mt = load_mime(package, row);
395c2c66affSColin Finck     msiobj_release(&row->hdr);
396c2c66affSColin Finck     return mt;
397c2c66affSColin Finck }
398c2c66affSColin Finck 
399c2c66affSColin Finck static MSIEXTENSION *load_extension( MSIPACKAGE* package, MSIRECORD *row )
400c2c66affSColin Finck {
401c2c66affSColin Finck     MSIEXTENSION *ext;
402c2c66affSColin Finck     LPCWSTR buffer;
403c2c66affSColin Finck 
404c2c66affSColin Finck     /* fill in the data */
405c2c66affSColin Finck 
406c2c66affSColin Finck     ext = msi_alloc_zero( sizeof(MSIEXTENSION) );
407c2c66affSColin Finck     if (!ext)
408c2c66affSColin Finck         return NULL;
409c2c66affSColin Finck 
410c2c66affSColin Finck     list_init( &ext->verbs );
411c2c66affSColin Finck 
412c2c66affSColin Finck     list_add_tail( &package->extensions, &ext->entry );
413c2c66affSColin Finck 
414c2c66affSColin Finck     ext->Extension = msi_dup_record_field( row, 1 );
415c2c66affSColin Finck     TRACE("loading extension %s\n", debugstr_w(ext->Extension));
416c2c66affSColin Finck 
417c2c66affSColin Finck     buffer = MSI_RecordGetString( row, 2 );
418c2c66affSColin Finck     ext->Component = msi_get_loaded_component( package, buffer );
419c2c66affSColin Finck 
420c2c66affSColin Finck     ext->ProgIDText = msi_dup_record_field( row, 3 );
421c2c66affSColin Finck     ext->ProgID = load_given_progid( package, ext->ProgIDText );
422c2c66affSColin Finck 
423c2c66affSColin Finck     buffer = MSI_RecordGetString( row, 4 );
424c2c66affSColin Finck     ext->Mime = load_given_mime( package, buffer );
425c2c66affSColin Finck 
426c2c66affSColin Finck     buffer = MSI_RecordGetString(row,5);
427c2c66affSColin Finck     ext->Feature = msi_get_loaded_feature( package, buffer );
428c2c66affSColin Finck     ext->action = INSTALLSTATE_UNKNOWN;
429c2c66affSColin Finck     return ext;
430c2c66affSColin Finck }
431c2c66affSColin Finck 
432c2c66affSColin Finck /*
433c2c66affSColin Finck  * While the extension table has 2 primary keys, this function is only looking
434c2c66affSColin Finck  * at the Extension key which is what is referenced as a foreign key
435c2c66affSColin Finck  */
436c2c66affSColin Finck static MSIEXTENSION *load_given_extension( MSIPACKAGE *package, LPCWSTR name )
437c2c66affSColin Finck {
438c2c66affSColin Finck     static const WCHAR query[] = {
439c2c66affSColin Finck         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
440c2c66affSColin Finck         '`','E','x','t','e','n','s','i','o','n','`',' ','W','H','E','R','E',' ',
441c2c66affSColin Finck         '`','E','x','t','e','n','s','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
442c2c66affSColin Finck     MSIEXTENSION *ext;
443c2c66affSColin Finck     MSIRECORD *row;
444c2c66affSColin Finck 
445c2c66affSColin Finck     if (!name)
446c2c66affSColin Finck         return NULL;
447c2c66affSColin Finck 
448c2c66affSColin Finck     if (name[0] == '.')
449c2c66affSColin Finck         name++;
450c2c66affSColin Finck 
451c2c66affSColin Finck     /* check for extensions already loaded */
452c2c66affSColin Finck     LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry )
453c2c66affSColin Finck     {
454c2c66affSColin Finck         if (!strcmpiW( ext->Extension, name ))
455c2c66affSColin Finck         {
456c2c66affSColin Finck             TRACE("extension %s already loaded %p\n", debugstr_w(name), ext);
457c2c66affSColin Finck             return ext;
458c2c66affSColin Finck         }
459c2c66affSColin Finck     }
460c2c66affSColin Finck 
461c2c66affSColin Finck     row = MSI_QueryGetRecord( package->db, query, name );
462c2c66affSColin Finck     if (!row)
463c2c66affSColin Finck         return NULL;
464c2c66affSColin Finck 
465c2c66affSColin Finck     ext = load_extension(package, row);
466c2c66affSColin Finck     msiobj_release(&row->hdr);
467c2c66affSColin Finck     return ext;
468c2c66affSColin Finck }
469c2c66affSColin Finck 
470c2c66affSColin Finck static UINT iterate_load_verb(MSIRECORD *row, LPVOID param)
471c2c66affSColin Finck {
472c2c66affSColin Finck     MSIPACKAGE* package = param;
473c2c66affSColin Finck     MSIVERB *verb;
474c2c66affSColin Finck     LPCWSTR buffer;
475c2c66affSColin Finck     MSIEXTENSION *extension;
476c2c66affSColin Finck 
477c2c66affSColin Finck     buffer = MSI_RecordGetString(row,1);
478c2c66affSColin Finck     extension = load_given_extension( package, buffer );
479c2c66affSColin Finck     if (!extension)
480c2c66affSColin Finck     {
481c2c66affSColin Finck         ERR("Verb unable to find loaded extension %s\n", debugstr_w(buffer));
482c2c66affSColin Finck         return ERROR_SUCCESS;
483c2c66affSColin Finck     }
484c2c66affSColin Finck 
485c2c66affSColin Finck     /* fill in the data */
486c2c66affSColin Finck 
487c2c66affSColin Finck     verb = msi_alloc_zero( sizeof(MSIVERB) );
488c2c66affSColin Finck     if (!verb)
489c2c66affSColin Finck         return ERROR_OUTOFMEMORY;
490c2c66affSColin Finck 
491c2c66affSColin Finck     verb->Verb = msi_dup_record_field(row,2);
492c2c66affSColin Finck     TRACE("loading verb %s\n",debugstr_w(verb->Verb));
493c2c66affSColin Finck     verb->Sequence = MSI_RecordGetInteger(row,3);
494c2c66affSColin Finck 
495c2c66affSColin Finck     buffer = MSI_RecordGetString(row,4);
496c2c66affSColin Finck     deformat_string(package,buffer,&verb->Command);
497c2c66affSColin Finck 
498c2c66affSColin Finck     buffer = MSI_RecordGetString(row,5);
499c2c66affSColin Finck     deformat_string(package,buffer,&verb->Argument);
500c2c66affSColin Finck 
501c2c66affSColin Finck     /* associate the verb with the correct extension */
502c2c66affSColin Finck     list_add_tail( &extension->verbs, &verb->entry );
503c2c66affSColin Finck 
504c2c66affSColin Finck     return ERROR_SUCCESS;
505c2c66affSColin Finck }
506c2c66affSColin Finck 
507c2c66affSColin Finck static UINT iterate_all_classes(MSIRECORD *rec, LPVOID param)
508c2c66affSColin Finck {
509c2c66affSColin Finck     MSICOMPONENT *comp;
510c2c66affSColin Finck     LPCWSTR clsid;
511c2c66affSColin Finck     LPCWSTR context;
512c2c66affSColin Finck     LPCWSTR buffer;
513c2c66affSColin Finck     MSIPACKAGE* package = param;
514c2c66affSColin Finck     MSICLASS *cls;
515c2c66affSColin Finck     BOOL match = FALSE;
516c2c66affSColin Finck 
517c2c66affSColin Finck     clsid = MSI_RecordGetString(rec,1);
518c2c66affSColin Finck     context = MSI_RecordGetString(rec,2);
519c2c66affSColin Finck     buffer = MSI_RecordGetString(rec,3);
520c2c66affSColin Finck     comp = msi_get_loaded_component(package, buffer);
521c2c66affSColin Finck 
522c2c66affSColin Finck     LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry )
523c2c66affSColin Finck     {
524c2c66affSColin Finck         if (strcmpiW( clsid, cls->clsid ))
525c2c66affSColin Finck             continue;
526c2c66affSColin Finck         if (strcmpW( context, cls->Context ))
527c2c66affSColin Finck             continue;
528c2c66affSColin Finck         if (comp == cls->Component)
529c2c66affSColin Finck         {
530c2c66affSColin Finck             match = TRUE;
531c2c66affSColin Finck             break;
532c2c66affSColin Finck         }
533c2c66affSColin Finck     }
534c2c66affSColin Finck 
535c2c66affSColin Finck     if (!match)
536c2c66affSColin Finck         load_class(package, rec);
537c2c66affSColin Finck 
538c2c66affSColin Finck     return ERROR_SUCCESS;
539c2c66affSColin Finck }
540c2c66affSColin Finck 
541c2c66affSColin Finck static UINT load_all_classes( MSIPACKAGE *package )
542c2c66affSColin Finck {
543c2c66affSColin Finck     static const WCHAR query[] = {
544c2c66affSColin Finck         'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ','`','C','l','a','s','s','`',0};
545c2c66affSColin Finck     MSIQUERY *view;
546c2c66affSColin Finck     UINT rc;
547c2c66affSColin Finck 
548c2c66affSColin Finck     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
549c2c66affSColin Finck     if (rc != ERROR_SUCCESS)
550c2c66affSColin Finck         return ERROR_SUCCESS;
551c2c66affSColin Finck 
552c2c66affSColin Finck     rc = MSI_IterateRecords(view, NULL, iterate_all_classes, package);
553c2c66affSColin Finck     msiobj_release(&view->hdr);
554c2c66affSColin Finck     return rc;
555c2c66affSColin Finck }
556c2c66affSColin Finck 
557c2c66affSColin Finck static UINT iterate_all_extensions(MSIRECORD *rec, LPVOID param)
558c2c66affSColin Finck {
559c2c66affSColin Finck     MSICOMPONENT *comp;
560c2c66affSColin Finck     LPCWSTR buffer;
561c2c66affSColin Finck     LPCWSTR extension;
562c2c66affSColin Finck     MSIPACKAGE* package = param;
563c2c66affSColin Finck     BOOL match = FALSE;
564c2c66affSColin Finck     MSIEXTENSION *ext;
565c2c66affSColin Finck 
566c2c66affSColin Finck     extension = MSI_RecordGetString(rec,1);
567c2c66affSColin Finck     buffer = MSI_RecordGetString(rec,2);
568c2c66affSColin Finck     comp = msi_get_loaded_component(package, buffer);
569c2c66affSColin Finck 
570c2c66affSColin Finck     LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry )
571c2c66affSColin Finck     {
572c2c66affSColin Finck         if (strcmpiW(extension, ext->Extension))
573c2c66affSColin Finck             continue;
574c2c66affSColin Finck         if (comp == ext->Component)
575c2c66affSColin Finck         {
576c2c66affSColin Finck             match = TRUE;
577c2c66affSColin Finck             break;
578c2c66affSColin Finck         }
579c2c66affSColin Finck     }
580c2c66affSColin Finck 
581c2c66affSColin Finck     if (!match)
582c2c66affSColin Finck         load_extension(package, rec);
583c2c66affSColin Finck 
584c2c66affSColin Finck     return ERROR_SUCCESS;
585c2c66affSColin Finck }
586c2c66affSColin Finck 
587c2c66affSColin Finck static UINT load_all_extensions( MSIPACKAGE *package )
588c2c66affSColin Finck {
589c2c66affSColin Finck     static const WCHAR query[] = {
590c2c66affSColin Finck         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','E','x','t','e','n','s','i','o','n','`',0};
591c2c66affSColin Finck     MSIQUERY *view;
592c2c66affSColin Finck     UINT rc;
593c2c66affSColin Finck 
594c2c66affSColin Finck     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
595c2c66affSColin Finck     if (rc != ERROR_SUCCESS)
596c2c66affSColin Finck         return ERROR_SUCCESS;
597c2c66affSColin Finck 
598c2c66affSColin Finck     rc = MSI_IterateRecords(view, NULL, iterate_all_extensions, package);
599c2c66affSColin Finck     msiobj_release(&view->hdr);
600c2c66affSColin Finck     return rc;
601c2c66affSColin Finck }
602c2c66affSColin Finck 
603c2c66affSColin Finck static UINT iterate_all_progids(MSIRECORD *rec, LPVOID param)
604c2c66affSColin Finck {
605c2c66affSColin Finck     LPCWSTR buffer;
606c2c66affSColin Finck     MSIPACKAGE* package = param;
607c2c66affSColin Finck 
608c2c66affSColin Finck     buffer = MSI_RecordGetString(rec,1);
609c2c66affSColin Finck     load_given_progid(package,buffer);
610c2c66affSColin Finck     return ERROR_SUCCESS;
611c2c66affSColin Finck }
612c2c66affSColin Finck 
613c2c66affSColin Finck static UINT load_all_progids( MSIPACKAGE *package )
614c2c66affSColin Finck {
615c2c66affSColin Finck     static const WCHAR query[] = {
616c2c66affSColin Finck         'S','E','L','E','C','T',' ','`','P','r','o','g','I','d','`',' ','F','R','O','M',' ',
617c2c66affSColin Finck         '`','P','r','o','g','I','d','`',0};
618c2c66affSColin Finck     MSIQUERY *view;
619c2c66affSColin Finck     UINT rc;
620c2c66affSColin Finck 
621c2c66affSColin Finck     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
622c2c66affSColin Finck     if (rc != ERROR_SUCCESS)
623c2c66affSColin Finck         return ERROR_SUCCESS;
624c2c66affSColin Finck 
625c2c66affSColin Finck     rc = MSI_IterateRecords(view, NULL, iterate_all_progids, package);
626c2c66affSColin Finck     msiobj_release(&view->hdr);
627c2c66affSColin Finck     return rc;
628c2c66affSColin Finck }
629c2c66affSColin Finck 
630c2c66affSColin Finck static UINT load_all_verbs( MSIPACKAGE *package )
631c2c66affSColin Finck {
632c2c66affSColin Finck     static const WCHAR query[] = {
633c2c66affSColin Finck         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','V','e','r','b','`',0};
634c2c66affSColin Finck     MSIQUERY *view;
635c2c66affSColin Finck     UINT rc;
636c2c66affSColin Finck 
637c2c66affSColin Finck     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
638c2c66affSColin Finck     if (rc != ERROR_SUCCESS)
639c2c66affSColin Finck         return ERROR_SUCCESS;
640c2c66affSColin Finck 
641c2c66affSColin Finck     rc = MSI_IterateRecords(view, NULL, iterate_load_verb, package);
642c2c66affSColin Finck     msiobj_release(&view->hdr);
643c2c66affSColin Finck     return rc;
644c2c66affSColin Finck }
645c2c66affSColin Finck 
646c2c66affSColin Finck static UINT iterate_all_mimes(MSIRECORD *rec, LPVOID param)
647c2c66affSColin Finck {
648c2c66affSColin Finck     LPCWSTR buffer;
649c2c66affSColin Finck     MSIPACKAGE* package = param;
650c2c66affSColin Finck 
651c2c66affSColin Finck     buffer = MSI_RecordGetString(rec,1);
652c2c66affSColin Finck     load_given_mime(package,buffer);
653c2c66affSColin Finck     return ERROR_SUCCESS;
654c2c66affSColin Finck }
655c2c66affSColin Finck 
656c2c66affSColin Finck static UINT load_all_mimes( MSIPACKAGE *package )
657c2c66affSColin Finck {
658c2c66affSColin Finck     static const WCHAR query[] = {
659c2c66affSColin Finck         'S','E','L','E','C','T',' ','`','C','o','n','t','e','n','t','T','y','p','e','`',' ',
660c2c66affSColin Finck         'F','R','O','M',' ','`','M','I','M','E','`',0};
661c2c66affSColin Finck     MSIQUERY *view;
662c2c66affSColin Finck     UINT rc;
663c2c66affSColin Finck 
664c2c66affSColin Finck     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
665c2c66affSColin Finck     if (rc != ERROR_SUCCESS)
666c2c66affSColin Finck         return ERROR_SUCCESS;
667c2c66affSColin Finck 
668c2c66affSColin Finck     rc = MSI_IterateRecords(view, NULL, iterate_all_mimes, package);
669c2c66affSColin Finck     msiobj_release(&view->hdr);
670c2c66affSColin Finck     return rc;
671c2c66affSColin Finck }
672c2c66affSColin Finck 
673c2c66affSColin Finck static UINT load_classes_and_such( MSIPACKAGE *package )
674c2c66affSColin Finck {
675c2c66affSColin Finck     UINT r;
676c2c66affSColin Finck 
677c2c66affSColin Finck     TRACE("Loading all the class info and related tables\n");
678c2c66affSColin Finck 
679c2c66affSColin Finck     /* check if already loaded */
680c2c66affSColin Finck     if (!list_empty( &package->classes ) ||
681c2c66affSColin Finck         !list_empty( &package->mimes ) ||
682c2c66affSColin Finck         !list_empty( &package->extensions ) ||
683c2c66affSColin Finck         !list_empty( &package->progids )) return ERROR_SUCCESS;
684c2c66affSColin Finck 
685c2c66affSColin Finck     r = load_all_classes( package );
686c2c66affSColin Finck     if (r != ERROR_SUCCESS) return r;
687c2c66affSColin Finck 
688c2c66affSColin Finck     r = load_all_extensions( package );
689c2c66affSColin Finck     if (r != ERROR_SUCCESS) return r;
690c2c66affSColin Finck 
691c2c66affSColin Finck     r = load_all_progids( package );
692c2c66affSColin Finck     if (r != ERROR_SUCCESS) return r;
693c2c66affSColin Finck 
694c2c66affSColin Finck     /* these loads must come after the other loads */
695c2c66affSColin Finck     r = load_all_verbs( package );
696c2c66affSColin Finck     if (r != ERROR_SUCCESS) return r;
697c2c66affSColin Finck 
698c2c66affSColin Finck     return load_all_mimes( package );
699c2c66affSColin Finck }
700c2c66affSColin Finck 
701c2c66affSColin Finck static UINT register_appid(const MSIAPPID *appid, LPCWSTR app )
702c2c66affSColin Finck {
703c2c66affSColin Finck     static const WCHAR szRemoteServerName[] =
704c2c66affSColin Finck          {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0};
705c2c66affSColin Finck     static const WCHAR szLocalService[] =
706c2c66affSColin Finck          {'L','o','c','a','l','S','e','r','v','i','c','e',0};
707c2c66affSColin Finck     static const WCHAR szService[] =
708c2c66affSColin Finck          {'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0};
709c2c66affSColin Finck     static const WCHAR szDLL[] =
710c2c66affSColin Finck          {'D','l','l','S','u','r','r','o','g','a','t','e',0};
711c2c66affSColin Finck     static const WCHAR szActivate[] =
712c2c66affSColin Finck          {'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0};
713c2c66affSColin Finck     static const WCHAR szY[] = {'Y',0};
714c2c66affSColin Finck     static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
715c2c66affSColin Finck     static const WCHAR szUser[] =
716c2c66affSColin Finck          {'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0};
717c2c66affSColin Finck 
718c2c66affSColin Finck     HKEY hkey2,hkey3;
719c2c66affSColin Finck 
720c2c66affSColin Finck     RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
721c2c66affSColin Finck     RegCreateKeyW( hkey2, appid->AppID, &hkey3 );
722c2c66affSColin Finck     RegCloseKey(hkey2);
723c2c66affSColin Finck     msi_reg_set_val_str( hkey3, NULL, app );
724c2c66affSColin Finck 
725c2c66affSColin Finck     if (appid->RemoteServerName)
726c2c66affSColin Finck         msi_reg_set_val_str( hkey3, szRemoteServerName, appid->RemoteServerName );
727c2c66affSColin Finck 
728c2c66affSColin Finck     if (appid->LocalServer)
729c2c66affSColin Finck         msi_reg_set_val_str( hkey3, szLocalService, appid->LocalServer );
730c2c66affSColin Finck 
731c2c66affSColin Finck     if (appid->ServiceParameters)
732c2c66affSColin Finck         msi_reg_set_val_str( hkey3, szService, appid->ServiceParameters );
733c2c66affSColin Finck 
734c2c66affSColin Finck     if (appid->DllSurrogate)
735c2c66affSColin Finck         msi_reg_set_val_str( hkey3, szDLL, appid->DllSurrogate );
736c2c66affSColin Finck 
737c2c66affSColin Finck     if (appid->ActivateAtStorage)
738c2c66affSColin Finck         msi_reg_set_val_str( hkey3, szActivate, szY );
739c2c66affSColin Finck 
740c2c66affSColin Finck     if (appid->RunAsInteractiveUser)
741c2c66affSColin Finck         msi_reg_set_val_str( hkey3, szRunAs, szUser );
742c2c66affSColin Finck 
743c2c66affSColin Finck     RegCloseKey(hkey3);
744c2c66affSColin Finck     return ERROR_SUCCESS;
745c2c66affSColin Finck }
746c2c66affSColin Finck 
747c2c66affSColin Finck UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
748c2c66affSColin Finck {
749c2c66affSColin Finck     static const WCHAR szFileType_fmt[] = {'F','i','l','e','T','y','p','e','\\','%','s','\\','%','i',0};
750c2c66affSColin Finck     const WCHAR *keypath;
751c2c66affSColin Finck     MSIRECORD *uirow;
752c2c66affSColin Finck     HKEY hkey, hkey2, hkey3;
753c2c66affSColin Finck     MSICLASS *cls;
754c2c66affSColin Finck     UINT r;
755c2c66affSColin Finck 
756c2c66affSColin Finck     r = load_classes_and_such( package );
757c2c66affSColin Finck     if (r != ERROR_SUCCESS)
758c2c66affSColin Finck         return r;
759c2c66affSColin Finck 
760c2c66affSColin Finck     if (is_64bit && package->platform == PLATFORM_INTEL)
761c2c66affSColin Finck         keypath = szWow6432NodeCLSID;
762c2c66affSColin Finck     else
763c2c66affSColin Finck         keypath = szCLSID;
764c2c66affSColin Finck 
765c2c66affSColin Finck     if (RegCreateKeyW(HKEY_CLASSES_ROOT, keypath, &hkey) != ERROR_SUCCESS)
766c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
767c2c66affSColin Finck 
768c2c66affSColin Finck     LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry )
769c2c66affSColin Finck     {
770c2c66affSColin Finck         MSICOMPONENT *comp;
771c2c66affSColin Finck         MSIFILE *file;
772c2c66affSColin Finck         DWORD size;
773c2c66affSColin Finck         LPWSTR argument;
774c2c66affSColin Finck         MSIFEATURE *feature;
775c2c66affSColin Finck 
776c2c66affSColin Finck         comp = cls->Component;
777c2c66affSColin Finck         if ( !comp )
778c2c66affSColin Finck             continue;
779c2c66affSColin Finck 
780c2c66affSColin Finck         if (!comp->Enabled)
781c2c66affSColin Finck         {
782c2c66affSColin Finck             TRACE("component is disabled\n");
783c2c66affSColin Finck             continue;
784c2c66affSColin Finck         }
785c2c66affSColin Finck 
786c2c66affSColin Finck         feature = cls->Feature;
787c2c66affSColin Finck         if (!feature)
788c2c66affSColin Finck             continue;
789c2c66affSColin Finck 
790c2c66affSColin Finck         feature->Action = msi_get_feature_action( package, feature );
791c2c66affSColin Finck         if (feature->Action != INSTALLSTATE_LOCAL &&
792c2c66affSColin Finck             feature->Action != INSTALLSTATE_ADVERTISED )
793c2c66affSColin Finck         {
794c2c66affSColin Finck             TRACE("feature %s not scheduled for installation, skipping registration of class %s\n",
795c2c66affSColin Finck                   debugstr_w(feature->Feature), debugstr_w(cls->clsid));
796c2c66affSColin Finck             continue;
797c2c66affSColin Finck         }
798c2c66affSColin Finck 
799c2c66affSColin Finck         if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
800c2c66affSColin Finck         {
801c2c66affSColin Finck             TRACE("COM server not provided, skipping class %s\n", debugstr_w(cls->clsid));
802c2c66affSColin Finck             continue;
803c2c66affSColin Finck         }
804c2c66affSColin Finck         TRACE("Registering class %s (%p)\n", debugstr_w(cls->clsid), cls);
805c2c66affSColin Finck 
806c2c66affSColin Finck         cls->action = INSTALLSTATE_LOCAL;
807c2c66affSColin Finck 
808c2c66affSColin Finck         RegCreateKeyW( hkey, cls->clsid, &hkey2 );
809c2c66affSColin Finck 
810c2c66affSColin Finck         if (cls->Description)
811c2c66affSColin Finck             msi_reg_set_val_str( hkey2, NULL, cls->Description );
812c2c66affSColin Finck 
813c2c66affSColin Finck         RegCreateKeyW( hkey2, cls->Context, &hkey3 );
814c2c66affSColin Finck 
815c2c66affSColin Finck         /*
816c2c66affSColin Finck          * FIXME: Implement install on demand (advertised components).
817c2c66affSColin Finck          *
818c2c66affSColin Finck          * ole32.dll should call msi.MsiProvideComponentFromDescriptor()
819c2c66affSColin Finck          *  when it needs an InProcServer that doesn't exist.
820c2c66affSColin Finck          * The component advertise string should be in the "InProcServer" value.
821c2c66affSColin Finck          */
822c2c66affSColin Finck         size = lstrlenW( file->TargetPath )+1;
823c2c66affSColin Finck         if (cls->Argument)
824c2c66affSColin Finck             size += lstrlenW(cls->Argument)+1;
825c2c66affSColin Finck 
826c2c66affSColin Finck         argument = msi_alloc( size * sizeof(WCHAR) );
827c2c66affSColin Finck         lstrcpyW( argument, file->TargetPath );
828c2c66affSColin Finck 
829c2c66affSColin Finck         if (cls->Argument)
830c2c66affSColin Finck         {
831c2c66affSColin Finck             lstrcatW( argument, szSpace );
832c2c66affSColin Finck             lstrcatW( argument, cls->Argument );
833c2c66affSColin Finck         }
834c2c66affSColin Finck 
835c2c66affSColin Finck         msi_reg_set_val_str( hkey3, NULL, argument );
836c2c66affSColin Finck         msi_free(argument);
837c2c66affSColin Finck 
838c2c66affSColin Finck         RegCloseKey(hkey3);
839c2c66affSColin Finck 
840c2c66affSColin Finck         if (cls->ProgID || cls->ProgIDText)
841c2c66affSColin Finck         {
842c2c66affSColin Finck             LPCWSTR progid;
843c2c66affSColin Finck 
844c2c66affSColin Finck             if (cls->ProgID)
845c2c66affSColin Finck                 progid = cls->ProgID->ProgID;
846c2c66affSColin Finck             else
847c2c66affSColin Finck                 progid = cls->ProgIDText;
848c2c66affSColin Finck 
849c2c66affSColin Finck             msi_reg_set_subkey_val( hkey2, szProgID, NULL, progid );
850c2c66affSColin Finck 
851c2c66affSColin Finck             if (cls->ProgID && cls->ProgID->VersionInd)
852c2c66affSColin Finck             {
853c2c66affSColin Finck                 msi_reg_set_subkey_val( hkey2, szVIProgID, NULL,
854c2c66affSColin Finck                                         cls->ProgID->VersionInd->ProgID );
855c2c66affSColin Finck             }
856c2c66affSColin Finck         }
857c2c66affSColin Finck 
858c2c66affSColin Finck         if (cls->AppID)
859c2c66affSColin Finck         {
860c2c66affSColin Finck             MSIAPPID *appid = cls->AppID;
861c2c66affSColin Finck             msi_reg_set_val_str( hkey2, szAppID, appid->AppID );
862c2c66affSColin Finck             register_appid( appid, cls->Description );
863c2c66affSColin Finck         }
864c2c66affSColin Finck 
865c2c66affSColin Finck         if (cls->IconPath)
866c2c66affSColin Finck             msi_reg_set_subkey_val( hkey2, szDefaultIcon, NULL, cls->IconPath );
867c2c66affSColin Finck 
868c2c66affSColin Finck         if (cls->DefInprocHandler)
869c2c66affSColin Finck             msi_reg_set_subkey_val( hkey2, szInprocHandler, NULL, cls->DefInprocHandler );
870c2c66affSColin Finck 
871c2c66affSColin Finck         if (cls->DefInprocHandler32)
872c2c66affSColin Finck             msi_reg_set_subkey_val( hkey2, szInprocHandler32, NULL, cls->DefInprocHandler32 );
873c2c66affSColin Finck 
874c2c66affSColin Finck         RegCloseKey(hkey2);
875c2c66affSColin Finck 
876c2c66affSColin Finck         /* if there is a FileTypeMask, register the FileType */
877c2c66affSColin Finck         if (cls->FileTypeMask)
878c2c66affSColin Finck         {
879c2c66affSColin Finck             LPWSTR ptr, ptr2;
880c2c66affSColin Finck             LPWSTR keyname;
881c2c66affSColin Finck             INT index = 0;
882c2c66affSColin Finck             ptr = cls->FileTypeMask;
883c2c66affSColin Finck             while (ptr && *ptr)
884c2c66affSColin Finck             {
885c2c66affSColin Finck                 ptr2 = strchrW(ptr,';');
886c2c66affSColin Finck                 if (ptr2)
887c2c66affSColin Finck                     *ptr2 = 0;
888c2c66affSColin Finck                 keyname = msi_alloc( (strlenW(szFileType_fmt) + strlenW(cls->clsid) + 4) * sizeof(WCHAR));
889c2c66affSColin Finck                 sprintfW( keyname, szFileType_fmt, cls->clsid, index );
890c2c66affSColin Finck 
891c2c66affSColin Finck                 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, keyname, NULL, ptr );
892c2c66affSColin Finck                 msi_free(keyname);
893c2c66affSColin Finck 
894c2c66affSColin Finck                 if (ptr2)
895c2c66affSColin Finck                     ptr = ptr2+1;
896c2c66affSColin Finck                 else
897c2c66affSColin Finck                     ptr = NULL;
898c2c66affSColin Finck 
899c2c66affSColin Finck                 index ++;
900c2c66affSColin Finck             }
901c2c66affSColin Finck         }
902c2c66affSColin Finck 
903c2c66affSColin Finck         uirow = MSI_CreateRecord(1);
904c2c66affSColin Finck         MSI_RecordSetStringW( uirow, 1, cls->clsid );
90571bffdcdSAmine Khaldi         MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
906c2c66affSColin Finck         msiobj_release(&uirow->hdr);
907c2c66affSColin Finck     }
908c2c66affSColin Finck     RegCloseKey(hkey);
909c2c66affSColin Finck     return ERROR_SUCCESS;
910c2c66affSColin Finck }
911c2c66affSColin Finck 
912c2c66affSColin Finck UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
913c2c66affSColin Finck {
914c2c66affSColin Finck     static const WCHAR szFileType[] = {'F','i','l','e','T','y','p','e','\\',0};
915c2c66affSColin Finck     const WCHAR *keypath;
916c2c66affSColin Finck     MSIRECORD *uirow;
917c2c66affSColin Finck     MSICLASS *cls;
918c2c66affSColin Finck     HKEY hkey, hkey2;
919c2c66affSColin Finck     UINT r;
920c2c66affSColin Finck 
921c2c66affSColin Finck     r = load_classes_and_such( package );
922c2c66affSColin Finck     if (r != ERROR_SUCCESS)
923c2c66affSColin Finck         return r;
924c2c66affSColin Finck 
925c2c66affSColin Finck     if (is_64bit && package->platform == PLATFORM_INTEL)
926c2c66affSColin Finck         keypath = szWow6432NodeCLSID;
927c2c66affSColin Finck     else
928c2c66affSColin Finck         keypath = szCLSID;
929c2c66affSColin Finck 
930c2c66affSColin Finck     if (RegOpenKeyW( HKEY_CLASSES_ROOT, keypath, &hkey ) != ERROR_SUCCESS)
931c2c66affSColin Finck         return ERROR_SUCCESS;
932c2c66affSColin Finck 
933c2c66affSColin Finck     LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry )
934c2c66affSColin Finck     {
935c2c66affSColin Finck         MSIFEATURE *feature;
936c2c66affSColin Finck         MSICOMPONENT *comp;
937c2c66affSColin Finck         LPWSTR filetype;
938c2c66affSColin Finck         LONG res;
939c2c66affSColin Finck 
940c2c66affSColin Finck         comp = cls->Component;
941c2c66affSColin Finck         if (!comp)
942c2c66affSColin Finck             continue;
943c2c66affSColin Finck 
944c2c66affSColin Finck         if (!comp->Enabled)
945c2c66affSColin Finck         {
946c2c66affSColin Finck             TRACE("component is disabled\n");
947c2c66affSColin Finck             continue;
948c2c66affSColin Finck         }
949c2c66affSColin Finck 
950c2c66affSColin Finck         feature = cls->Feature;
951c2c66affSColin Finck         if (!feature)
952c2c66affSColin Finck             continue;
953c2c66affSColin Finck 
954c2c66affSColin Finck         feature->Action = msi_get_feature_action( package, feature );
955c2c66affSColin Finck         if (feature->Action != INSTALLSTATE_ABSENT)
956c2c66affSColin Finck         {
957c2c66affSColin Finck             TRACE("feature %s not scheduled for removal, skipping unregistration of class %s\n",
958c2c66affSColin Finck                   debugstr_w(feature->Feature), debugstr_w(cls->clsid));
959c2c66affSColin Finck             continue;
960c2c66affSColin Finck         }
961c2c66affSColin Finck         TRACE("Unregistering class %s (%p)\n", debugstr_w(cls->clsid), cls);
962c2c66affSColin Finck 
963c2c66affSColin Finck         cls->action = INSTALLSTATE_ABSENT;
964c2c66affSColin Finck 
965c2c66affSColin Finck         res = RegDeleteTreeW( hkey, cls->clsid );
966c2c66affSColin Finck         if (res != ERROR_SUCCESS)
967c2c66affSColin Finck             WARN("Failed to delete class key %d\n", res);
968c2c66affSColin Finck 
969c2c66affSColin Finck         if (cls->AppID)
970c2c66affSColin Finck         {
971c2c66affSColin Finck             res = RegOpenKeyW( HKEY_CLASSES_ROOT, szAppID, &hkey2 );
972c2c66affSColin Finck             if (res == ERROR_SUCCESS)
973c2c66affSColin Finck             {
974c2c66affSColin Finck                 res = RegDeleteKeyW( hkey2, cls->AppID->AppID );
975c2c66affSColin Finck                 if (res != ERROR_SUCCESS)
976c2c66affSColin Finck                     WARN("Failed to delete appid key %d\n", res);
977c2c66affSColin Finck                 RegCloseKey( hkey2 );
978c2c66affSColin Finck             }
979c2c66affSColin Finck         }
980c2c66affSColin Finck         if (cls->FileTypeMask)
981c2c66affSColin Finck         {
982c2c66affSColin Finck             filetype = msi_alloc( (strlenW( szFileType ) + strlenW( cls->clsid ) + 1) * sizeof(WCHAR) );
983c2c66affSColin Finck             if (filetype)
984c2c66affSColin Finck             {
985c2c66affSColin Finck                 strcpyW( filetype, szFileType );
986c2c66affSColin Finck                 strcatW( filetype, cls->clsid );
987c2c66affSColin Finck                 res = RegDeleteTreeW( HKEY_CLASSES_ROOT, filetype );
988c2c66affSColin Finck                 msi_free( filetype );
989c2c66affSColin Finck 
990c2c66affSColin Finck                 if (res != ERROR_SUCCESS)
991c2c66affSColin Finck                     WARN("Failed to delete file type %d\n", res);
992c2c66affSColin Finck             }
993c2c66affSColin Finck         }
994c2c66affSColin Finck 
995c2c66affSColin Finck         uirow = MSI_CreateRecord( 1 );
996c2c66affSColin Finck         MSI_RecordSetStringW( uirow, 1, cls->clsid );
99771bffdcdSAmine Khaldi         MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
998c2c66affSColin Finck         msiobj_release( &uirow->hdr );
999c2c66affSColin Finck     }
1000c2c66affSColin Finck     RegCloseKey( hkey );
1001c2c66affSColin Finck     return ERROR_SUCCESS;
1002c2c66affSColin Finck }
1003c2c66affSColin Finck 
1004c2c66affSColin Finck static LPCWSTR get_clsid_of_progid( const MSIPROGID *progid )
1005c2c66affSColin Finck {
1006c2c66affSColin Finck     while (progid)
1007c2c66affSColin Finck     {
1008c2c66affSColin Finck         if (progid->Class)
1009c2c66affSColin Finck             return progid->Class->clsid;
1010c2c66affSColin Finck         if (progid->Parent == progid)
1011c2c66affSColin Finck             break;
1012c2c66affSColin Finck         progid = progid->Parent;
1013c2c66affSColin Finck     }
1014c2c66affSColin Finck     return NULL;
1015c2c66affSColin Finck }
1016c2c66affSColin Finck 
1017c2c66affSColin Finck static UINT register_progid( const MSIPROGID* progid )
1018c2c66affSColin Finck {
1019c2c66affSColin Finck     static const WCHAR szCurVer[] = {'C','u','r','V','e','r',0};
1020c2c66affSColin Finck     HKEY hkey = 0;
1021c2c66affSColin Finck     UINT rc;
1022c2c66affSColin Finck 
1023c2c66affSColin Finck     rc = RegCreateKeyW( HKEY_CLASSES_ROOT, progid->ProgID, &hkey );
1024c2c66affSColin Finck     if (rc == ERROR_SUCCESS)
1025c2c66affSColin Finck     {
1026c2c66affSColin Finck         LPCWSTR clsid = get_clsid_of_progid( progid );
1027c2c66affSColin Finck 
1028c2c66affSColin Finck         if (clsid)
1029c2c66affSColin Finck             msi_reg_set_subkey_val( hkey, szCLSID, NULL, clsid );
1030c2c66affSColin Finck         else
1031c2c66affSColin Finck             TRACE("%s has no class\n", debugstr_w( progid->ProgID ) );
1032c2c66affSColin Finck 
1033c2c66affSColin Finck         if (progid->Description)
1034c2c66affSColin Finck             msi_reg_set_val_str( hkey, NULL, progid->Description );
1035c2c66affSColin Finck 
1036c2c66affSColin Finck         if (progid->IconPath)
1037c2c66affSColin Finck             msi_reg_set_subkey_val( hkey, szDefaultIcon, NULL, progid->IconPath );
1038c2c66affSColin Finck 
1039c2c66affSColin Finck         /* write out the current version */
1040c2c66affSColin Finck         if (progid->CurVer)
1041c2c66affSColin Finck             msi_reg_set_subkey_val( hkey, szCurVer, NULL, progid->CurVer->ProgID );
1042c2c66affSColin Finck 
1043c2c66affSColin Finck         RegCloseKey(hkey);
1044c2c66affSColin Finck     }
1045c2c66affSColin Finck     else
1046c2c66affSColin Finck         ERR("failed to create key %s\n", debugstr_w( progid->ProgID ) );
1047c2c66affSColin Finck 
1048c2c66affSColin Finck     return rc;
1049c2c66affSColin Finck }
1050c2c66affSColin Finck 
1051c2c66affSColin Finck static const MSICLASS *get_progid_class( const MSIPROGID *progid )
1052c2c66affSColin Finck {
1053c2c66affSColin Finck     while (progid)
1054c2c66affSColin Finck     {
1055c2c66affSColin Finck         if (progid->Parent) progid = progid->Parent;
1056c2c66affSColin Finck         if (progid->Class) return progid->Class;
1057c2c66affSColin Finck         if (!progid->Parent || progid->Parent == progid) break;
1058c2c66affSColin Finck     }
1059c2c66affSColin Finck     return NULL;
1060c2c66affSColin Finck }
1061c2c66affSColin Finck 
1062c2c66affSColin Finck static BOOL has_class_installed( const MSIPROGID *progid )
1063c2c66affSColin Finck {
1064c2c66affSColin Finck     const MSICLASS *class = get_progid_class( progid );
1065c2c66affSColin Finck     if (!class || !class->ProgID) return FALSE;
1066c2c66affSColin Finck     return (class->action == INSTALLSTATE_LOCAL);
1067c2c66affSColin Finck }
1068c2c66affSColin Finck 
1069c2c66affSColin Finck static BOOL has_one_extension_installed( const MSIPACKAGE *package, const MSIPROGID *progid )
1070c2c66affSColin Finck {
1071c2c66affSColin Finck     const MSIEXTENSION *extension;
1072c2c66affSColin Finck     LIST_FOR_EACH_ENTRY( extension, &package->extensions, MSIEXTENSION, entry )
1073c2c66affSColin Finck     {
1074c2c66affSColin Finck         if (extension->ProgID == progid && !list_empty( &extension->verbs ) &&
1075c2c66affSColin Finck             extension->action == INSTALLSTATE_LOCAL) return TRUE;
1076c2c66affSColin Finck     }
1077c2c66affSColin Finck     return FALSE;
1078c2c66affSColin Finck }
1079c2c66affSColin Finck 
1080c2c66affSColin Finck UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
1081c2c66affSColin Finck {
1082c2c66affSColin Finck     MSIPROGID *progid;
1083c2c66affSColin Finck     MSIRECORD *uirow;
1084c2c66affSColin Finck     UINT r;
1085c2c66affSColin Finck 
1086c2c66affSColin Finck     r = load_classes_and_such( package );
1087c2c66affSColin Finck     if (r != ERROR_SUCCESS)
1088c2c66affSColin Finck         return r;
1089c2c66affSColin Finck 
1090c2c66affSColin Finck     LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry )
1091c2c66affSColin Finck     {
1092c2c66affSColin Finck         if (!has_class_installed( progid ) && !has_one_extension_installed( package, progid ))
1093c2c66affSColin Finck         {
1094c2c66affSColin Finck             TRACE("progid %s not scheduled to be installed\n", debugstr_w(progid->ProgID));
1095c2c66affSColin Finck             continue;
1096c2c66affSColin Finck         }
1097c2c66affSColin Finck         TRACE("Registering progid %s\n", debugstr_w(progid->ProgID));
1098c2c66affSColin Finck 
1099c2c66affSColin Finck         register_progid( progid );
1100c2c66affSColin Finck 
1101c2c66affSColin Finck         uirow = MSI_CreateRecord( 1 );
1102c2c66affSColin Finck         MSI_RecordSetStringW( uirow, 1, progid->ProgID );
110371bffdcdSAmine Khaldi         MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
1104c2c66affSColin Finck         msiobj_release( &uirow->hdr );
1105c2c66affSColin Finck     }
1106c2c66affSColin Finck     return ERROR_SUCCESS;
1107c2c66affSColin Finck }
1108c2c66affSColin Finck 
1109c2c66affSColin Finck static BOOL has_class_removed( const MSIPROGID *progid )
1110c2c66affSColin Finck {
1111c2c66affSColin Finck     const MSICLASS *class = get_progid_class( progid );
1112c2c66affSColin Finck     if (!class || !class->ProgID) return FALSE;
1113c2c66affSColin Finck     return (class->action == INSTALLSTATE_ABSENT);
1114c2c66affSColin Finck }
1115c2c66affSColin Finck 
1116c2c66affSColin Finck static BOOL has_extensions( const MSIPACKAGE *package, const MSIPROGID *progid )
1117c2c66affSColin Finck {
1118c2c66affSColin Finck     const MSIEXTENSION *extension;
1119c2c66affSColin Finck     LIST_FOR_EACH_ENTRY( extension, &package->extensions, MSIEXTENSION, entry )
1120c2c66affSColin Finck     {
1121c2c66affSColin Finck         if (extension->ProgID == progid && !list_empty( &extension->verbs )) return TRUE;
1122c2c66affSColin Finck     }
1123c2c66affSColin Finck     return FALSE;
1124c2c66affSColin Finck }
1125c2c66affSColin Finck 
1126c2c66affSColin Finck static BOOL has_all_extensions_removed( const MSIPACKAGE *package, const MSIPROGID *progid )
1127c2c66affSColin Finck {
1128c2c66affSColin Finck     BOOL ret = FALSE;
1129c2c66affSColin Finck     const MSIEXTENSION *extension;
1130c2c66affSColin Finck     LIST_FOR_EACH_ENTRY( extension, &package->extensions, MSIEXTENSION, entry )
1131c2c66affSColin Finck     {
1132c2c66affSColin Finck         if (extension->ProgID == progid && !list_empty( &extension->verbs ) &&
1133c2c66affSColin Finck             extension->action == INSTALLSTATE_ABSENT) ret = TRUE;
1134c2c66affSColin Finck         else ret = FALSE;
1135c2c66affSColin Finck     }
1136c2c66affSColin Finck     return ret;
1137c2c66affSColin Finck }
1138c2c66affSColin Finck 
1139c2c66affSColin Finck UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
1140c2c66affSColin Finck {
1141c2c66affSColin Finck     MSIPROGID *progid;
1142c2c66affSColin Finck     MSIRECORD *uirow;
1143c2c66affSColin Finck     LONG res;
1144c2c66affSColin Finck     UINT r;
1145c2c66affSColin Finck 
1146c2c66affSColin Finck     r = load_classes_and_such( package );
1147c2c66affSColin Finck     if (r != ERROR_SUCCESS)
1148c2c66affSColin Finck         return r;
1149c2c66affSColin Finck 
1150c2c66affSColin Finck     LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry )
1151c2c66affSColin Finck     {
1152c2c66affSColin Finck         if (!has_class_removed( progid ) ||
1153c2c66affSColin Finck             (has_extensions( package, progid ) && !has_all_extensions_removed( package, progid )))
1154c2c66affSColin Finck         {
1155c2c66affSColin Finck             TRACE("progid %s not scheduled to be removed\n", debugstr_w(progid->ProgID));
1156c2c66affSColin Finck             continue;
1157c2c66affSColin Finck         }
1158c2c66affSColin Finck         TRACE("Unregistering progid %s\n", debugstr_w(progid->ProgID));
1159c2c66affSColin Finck 
1160c2c66affSColin Finck         res = RegDeleteTreeW( HKEY_CLASSES_ROOT, progid->ProgID );
1161c2c66affSColin Finck         if (res != ERROR_SUCCESS)
1162c2c66affSColin Finck             TRACE("Failed to delete progid key %d\n", res);
1163c2c66affSColin Finck 
1164c2c66affSColin Finck         uirow = MSI_CreateRecord( 1 );
1165c2c66affSColin Finck         MSI_RecordSetStringW( uirow, 1, progid->ProgID );
116671bffdcdSAmine Khaldi         MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
1167c2c66affSColin Finck         msiobj_release( &uirow->hdr );
1168c2c66affSColin Finck     }
1169c2c66affSColin Finck     return ERROR_SUCCESS;
1170c2c66affSColin Finck }
1171c2c66affSColin Finck 
1172c2c66affSColin Finck static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid,
1173c2c66affSColin Finck                 MSICOMPONENT* component, const MSIEXTENSION* extension,
1174c2c66affSColin Finck                 MSIVERB* verb, INT* Sequence )
1175c2c66affSColin Finck {
1176c2c66affSColin Finck     LPWSTR keyname;
1177c2c66affSColin Finck     HKEY key;
1178c2c66affSColin Finck     static const WCHAR szShell[] = {'s','h','e','l','l',0};
1179c2c66affSColin Finck     static const WCHAR szCommand[] = {'c','o','m','m','a','n','d',0};
1180c2c66affSColin Finck     static const WCHAR fmt[] = {'\"','%','s','\"',' ','%','s',0};
1181c2c66affSColin Finck     static const WCHAR fmt2[] = {'\"','%','s','\"',0};
1182c2c66affSColin Finck     LPWSTR command;
1183c2c66affSColin Finck     DWORD size;
1184c2c66affSColin Finck     LPWSTR advertise;
1185c2c66affSColin Finck 
1186c2c66affSColin Finck     keyname = msi_build_directory_name(4, progid, szShell, verb->Verb, szCommand);
1187c2c66affSColin Finck 
1188c2c66affSColin Finck     TRACE("Making Key %s\n",debugstr_w(keyname));
1189c2c66affSColin Finck     RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
1190c2c66affSColin Finck     size = strlenW(component->FullKeypath);
1191c2c66affSColin Finck     if (verb->Argument)
1192c2c66affSColin Finck         size += strlenW(verb->Argument);
1193c2c66affSColin Finck      size += 4;
1194c2c66affSColin Finck 
1195c2c66affSColin Finck      command = msi_alloc(size * sizeof (WCHAR));
1196c2c66affSColin Finck      if (verb->Argument)
1197c2c66affSColin Finck         sprintfW(command, fmt, component->FullKeypath, verb->Argument);
1198c2c66affSColin Finck      else
1199c2c66affSColin Finck         sprintfW(command, fmt2, component->FullKeypath);
1200c2c66affSColin Finck 
1201c2c66affSColin Finck      msi_reg_set_val_str( key, NULL, command );
1202c2c66affSColin Finck      msi_free(command);
1203c2c66affSColin Finck 
1204c2c66affSColin Finck      advertise = msi_create_component_advertise_string(package, component,
1205c2c66affSColin Finck                                                        extension->Feature->Feature);
1206c2c66affSColin Finck      size = strlenW(advertise);
1207c2c66affSColin Finck 
1208c2c66affSColin Finck      if (verb->Argument)
1209c2c66affSColin Finck          size += strlenW(verb->Argument);
1210c2c66affSColin Finck      size += 4;
1211c2c66affSColin Finck 
1212c2c66affSColin Finck      command = msi_alloc_zero(size * sizeof (WCHAR));
1213c2c66affSColin Finck 
1214c2c66affSColin Finck      strcpyW(command,advertise);
1215c2c66affSColin Finck      if (verb->Argument)
1216c2c66affSColin Finck      {
1217c2c66affSColin Finck          strcatW(command,szSpace);
1218c2c66affSColin Finck          strcatW(command,verb->Argument);
1219c2c66affSColin Finck      }
1220c2c66affSColin Finck 
1221c2c66affSColin Finck      msi_reg_set_val_multi_str( key, szCommand, command );
1222c2c66affSColin Finck 
1223c2c66affSColin Finck      RegCloseKey(key);
1224c2c66affSColin Finck      msi_free(keyname);
1225c2c66affSColin Finck      msi_free(advertise);
1226c2c66affSColin Finck      msi_free(command);
1227c2c66affSColin Finck 
1228c2c66affSColin Finck      if (verb->Command)
1229c2c66affSColin Finck      {
1230c2c66affSColin Finck         keyname = msi_build_directory_name( 3, progid, szShell, verb->Verb );
1231c2c66affSColin Finck         msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, keyname, NULL, verb->Command );
1232c2c66affSColin Finck         msi_free(keyname);
1233c2c66affSColin Finck      }
1234c2c66affSColin Finck 
1235c2c66affSColin Finck      if (verb->Sequence != MSI_NULL_INTEGER)
1236c2c66affSColin Finck      {
1237c2c66affSColin Finck         if (*Sequence == MSI_NULL_INTEGER || verb->Sequence < *Sequence)
1238c2c66affSColin Finck         {
1239c2c66affSColin Finck             *Sequence = verb->Sequence;
1240c2c66affSColin Finck             keyname = msi_build_directory_name( 2, progid, szShell );
1241c2c66affSColin Finck             msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, keyname, NULL, verb->Verb );
1242c2c66affSColin Finck             msi_free(keyname);
1243c2c66affSColin Finck         }
1244c2c66affSColin Finck     }
1245c2c66affSColin Finck     return ERROR_SUCCESS;
1246c2c66affSColin Finck }
1247c2c66affSColin Finck 
1248c2c66affSColin Finck UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
1249c2c66affSColin Finck {
1250c2c66affSColin Finck     static const WCHAR szContentType[] = {'C','o','n','t','e','n','t',' ','T','y','p','e',0};
1251c2c66affSColin Finck     HKEY hkey = NULL;
1252c2c66affSColin Finck     MSIEXTENSION *ext;
1253c2c66affSColin Finck     MSIRECORD *uirow;
1254c2c66affSColin Finck     BOOL install_on_demand = TRUE;
1255c2c66affSColin Finck     LONG res;
1256c2c66affSColin Finck     UINT r;
1257c2c66affSColin Finck 
1258c2c66affSColin Finck     r = load_classes_and_such( package );
1259c2c66affSColin Finck     if (r != ERROR_SUCCESS)
1260c2c66affSColin Finck         return r;
1261c2c66affSColin Finck 
1262c2c66affSColin Finck     /* We need to set install_on_demand based on if the shell handles advertised
1263c2c66affSColin Finck      * shortcuts and the like. Because Mike McCormack is working on this i am
1264c2c66affSColin Finck      * going to default to TRUE
1265c2c66affSColin Finck      */
1266c2c66affSColin Finck 
1267c2c66affSColin Finck     LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry )
1268c2c66affSColin Finck     {
1269c2c66affSColin Finck         LPWSTR extension;
1270c2c66affSColin Finck         MSIFEATURE *feature;
1271c2c66affSColin Finck 
1272c2c66affSColin Finck         if (!ext->Component)
1273c2c66affSColin Finck             continue;
1274c2c66affSColin Finck 
1275c2c66affSColin Finck         if (!ext->Component->Enabled)
1276c2c66affSColin Finck         {
1277c2c66affSColin Finck             TRACE("component is disabled\n");
1278c2c66affSColin Finck             continue;
1279c2c66affSColin Finck         }
1280c2c66affSColin Finck 
1281c2c66affSColin Finck         feature = ext->Feature;
1282c2c66affSColin Finck         if (!feature)
1283c2c66affSColin Finck             continue;
1284c2c66affSColin Finck 
1285c2c66affSColin Finck         /*
1286c2c66affSColin Finck          * yes. MSDN says that these are based on _Feature_ not on
1287c2c66affSColin Finck          * Component.  So verify the feature is to be installed
1288c2c66affSColin Finck          */
1289c2c66affSColin Finck         feature->Action = msi_get_feature_action( package, feature );
1290c2c66affSColin Finck         if (feature->Action != INSTALLSTATE_LOCAL &&
1291c2c66affSColin Finck             !(install_on_demand && feature->Action == INSTALLSTATE_ADVERTISED))
1292c2c66affSColin Finck         {
1293c2c66affSColin Finck             TRACE("feature %s not scheduled for installation, skipping registration of extension %s\n",
1294c2c66affSColin Finck                   debugstr_w(feature->Feature), debugstr_w(ext->Extension));
1295c2c66affSColin Finck             continue;
1296c2c66affSColin Finck         }
1297c2c66affSColin Finck         TRACE("Registering extension %s (%p)\n", debugstr_w(ext->Extension), ext);
1298c2c66affSColin Finck 
1299c2c66affSColin Finck         ext->action = INSTALLSTATE_LOCAL;
1300c2c66affSColin Finck 
1301c2c66affSColin Finck         extension = msi_alloc( (strlenW( ext->Extension ) + 2) * sizeof(WCHAR) );
1302c2c66affSColin Finck         if (extension)
1303c2c66affSColin Finck         {
1304c2c66affSColin Finck             extension[0] = '.';
1305c2c66affSColin Finck             strcpyW( extension + 1, ext->Extension );
1306c2c66affSColin Finck             res = RegCreateKeyW( HKEY_CLASSES_ROOT, extension, &hkey );
1307c2c66affSColin Finck             msi_free( extension );
1308c2c66affSColin Finck             if (res != ERROR_SUCCESS)
1309c2c66affSColin Finck                 WARN("Failed to create extension key %d\n", res);
1310c2c66affSColin Finck         }
1311c2c66affSColin Finck 
1312c2c66affSColin Finck         if (ext->Mime)
1313c2c66affSColin Finck             msi_reg_set_val_str( hkey, szContentType, ext->Mime->ContentType );
1314c2c66affSColin Finck 
1315c2c66affSColin Finck         if (ext->ProgID || ext->ProgIDText)
1316c2c66affSColin Finck         {
1317c2c66affSColin Finck             static const WCHAR szSN[] =
1318c2c66affSColin Finck                 {'\\','S','h','e','l','l','N','e','w',0};
1319c2c66affSColin Finck             HKEY hkey2;
1320c2c66affSColin Finck             LPWSTR newkey;
1321c2c66affSColin Finck             LPCWSTR progid;
1322c2c66affSColin Finck             MSIVERB *verb;
1323c2c66affSColin Finck             INT Sequence = MSI_NULL_INTEGER;
1324c2c66affSColin Finck 
1325c2c66affSColin Finck             if (ext->ProgID)
1326c2c66affSColin Finck                 progid = ext->ProgID->ProgID;
1327c2c66affSColin Finck             else
1328c2c66affSColin Finck                 progid = ext->ProgIDText;
1329c2c66affSColin Finck 
1330c2c66affSColin Finck             msi_reg_set_val_str( hkey, NULL, progid );
1331c2c66affSColin Finck 
1332c2c66affSColin Finck             newkey = msi_alloc( (strlenW(progid)+strlenW(szSN)+1) * sizeof(WCHAR));
1333c2c66affSColin Finck 
1334c2c66affSColin Finck             strcpyW(newkey,progid);
1335c2c66affSColin Finck             strcatW(newkey,szSN);
1336c2c66affSColin Finck             RegCreateKeyW(hkey,newkey,&hkey2);
1337c2c66affSColin Finck             RegCloseKey(hkey2);
1338c2c66affSColin Finck 
1339c2c66affSColin Finck             msi_free(newkey);
1340c2c66affSColin Finck 
1341c2c66affSColin Finck             /* do all the verbs */
1342c2c66affSColin Finck             LIST_FOR_EACH_ENTRY( verb, &ext->verbs, MSIVERB, entry )
1343c2c66affSColin Finck             {
1344c2c66affSColin Finck                 register_verb( package, progid, ext->Component,
1345c2c66affSColin Finck                                ext, verb, &Sequence);
1346c2c66affSColin Finck             }
1347c2c66affSColin Finck         }
1348c2c66affSColin Finck 
1349c2c66affSColin Finck         RegCloseKey(hkey);
1350c2c66affSColin Finck 
1351c2c66affSColin Finck         uirow = MSI_CreateRecord(1);
1352c2c66affSColin Finck         MSI_RecordSetStringW( uirow, 1, ext->Extension );
135371bffdcdSAmine Khaldi         MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
1354c2c66affSColin Finck         msiobj_release(&uirow->hdr);
1355c2c66affSColin Finck     }
1356c2c66affSColin Finck     return ERROR_SUCCESS;
1357c2c66affSColin Finck }
1358c2c66affSColin Finck 
1359c2c66affSColin Finck UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
1360c2c66affSColin Finck {
1361c2c66affSColin Finck     MSIEXTENSION *ext;
1362c2c66affSColin Finck     MSIRECORD *uirow;
1363c2c66affSColin Finck     LONG res;
1364c2c66affSColin Finck     UINT r;
1365c2c66affSColin Finck 
1366c2c66affSColin Finck     r = load_classes_and_such( package );
1367c2c66affSColin Finck     if (r != ERROR_SUCCESS)
1368c2c66affSColin Finck         return r;
1369c2c66affSColin Finck 
1370c2c66affSColin Finck     LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry )
1371c2c66affSColin Finck     {
1372c2c66affSColin Finck         LPWSTR extension;
1373c2c66affSColin Finck         MSIFEATURE *feature;
1374c2c66affSColin Finck 
1375c2c66affSColin Finck         if (!ext->Component)
1376c2c66affSColin Finck             continue;
1377c2c66affSColin Finck 
1378c2c66affSColin Finck         if (!ext->Component->Enabled)
1379c2c66affSColin Finck         {
1380c2c66affSColin Finck             TRACE("component is disabled\n");
1381c2c66affSColin Finck             continue;
1382c2c66affSColin Finck         }
1383c2c66affSColin Finck 
1384c2c66affSColin Finck         feature = ext->Feature;
1385c2c66affSColin Finck         if (!feature)
1386c2c66affSColin Finck             continue;
1387c2c66affSColin Finck 
1388c2c66affSColin Finck         feature->Action = msi_get_feature_action( package, feature );
1389c2c66affSColin Finck         if (feature->Action != INSTALLSTATE_ABSENT)
1390c2c66affSColin Finck         {
1391c2c66affSColin Finck             TRACE("feature %s not scheduled for removal, skipping unregistration of extension %s\n",
1392c2c66affSColin Finck                   debugstr_w(feature->Feature), debugstr_w(ext->Extension));
1393c2c66affSColin Finck             continue;
1394c2c66affSColin Finck         }
1395c2c66affSColin Finck         TRACE("Unregistering extension %s\n", debugstr_w(ext->Extension));
1396c2c66affSColin Finck 
1397c2c66affSColin Finck         ext->action = INSTALLSTATE_ABSENT;
1398c2c66affSColin Finck 
1399c2c66affSColin Finck         extension = msi_alloc( (strlenW( ext->Extension ) + 2) * sizeof(WCHAR) );
1400c2c66affSColin Finck         if (extension)
1401c2c66affSColin Finck         {
1402c2c66affSColin Finck             extension[0] = '.';
1403c2c66affSColin Finck             strcpyW( extension + 1, ext->Extension );
1404c2c66affSColin Finck             res = RegDeleteTreeW( HKEY_CLASSES_ROOT, extension );
1405c2c66affSColin Finck             msi_free( extension );
1406c2c66affSColin Finck             if (res != ERROR_SUCCESS)
1407c2c66affSColin Finck                 WARN("Failed to delete extension key %d\n", res);
1408c2c66affSColin Finck         }
1409c2c66affSColin Finck 
1410c2c66affSColin Finck         if (ext->ProgID || ext->ProgIDText)
1411c2c66affSColin Finck         {
1412c2c66affSColin Finck             static const WCHAR shellW[] = {'\\','s','h','e','l','l',0};
1413c2c66affSColin Finck             LPCWSTR progid;
1414c2c66affSColin Finck             LPWSTR progid_shell;
1415c2c66affSColin Finck 
1416c2c66affSColin Finck             if (ext->ProgID)
1417c2c66affSColin Finck                 progid = ext->ProgID->ProgID;
1418c2c66affSColin Finck             else
1419c2c66affSColin Finck                 progid = ext->ProgIDText;
1420c2c66affSColin Finck 
1421c2c66affSColin Finck             progid_shell = msi_alloc( (strlenW( progid ) + strlenW( shellW ) + 1) * sizeof(WCHAR) );
1422c2c66affSColin Finck             if (progid_shell)
1423c2c66affSColin Finck             {
1424c2c66affSColin Finck                 strcpyW( progid_shell, progid );
1425c2c66affSColin Finck                 strcatW( progid_shell, shellW );
1426c2c66affSColin Finck                 res = RegDeleteTreeW( HKEY_CLASSES_ROOT, progid_shell );
1427c2c66affSColin Finck                 msi_free( progid_shell );
1428c2c66affSColin Finck                 if (res != ERROR_SUCCESS)
1429c2c66affSColin Finck                     WARN("Failed to delete shell key %d\n", res);
1430c2c66affSColin Finck                 RegDeleteKeyW( HKEY_CLASSES_ROOT, progid );
1431c2c66affSColin Finck             }
1432c2c66affSColin Finck         }
1433c2c66affSColin Finck 
1434c2c66affSColin Finck         uirow = MSI_CreateRecord( 1 );
1435c2c66affSColin Finck         MSI_RecordSetStringW( uirow, 1, ext->Extension );
143671bffdcdSAmine Khaldi         MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
1437c2c66affSColin Finck         msiobj_release( &uirow->hdr );
1438c2c66affSColin Finck     }
1439c2c66affSColin Finck     return ERROR_SUCCESS;
1440c2c66affSColin Finck }
1441c2c66affSColin Finck 
1442c2c66affSColin Finck UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package)
1443c2c66affSColin Finck {
1444c2c66affSColin Finck     static const WCHAR szExtension[] = {'E','x','t','e','n','s','i','o','n',0};
1445c2c66affSColin Finck     MSIRECORD *uirow;
1446c2c66affSColin Finck     MSIMIME *mt;
1447c2c66affSColin Finck     UINT r;
1448c2c66affSColin Finck 
1449c2c66affSColin Finck     r = load_classes_and_such( package );
1450c2c66affSColin Finck     if (r != ERROR_SUCCESS)
1451c2c66affSColin Finck         return r;
1452c2c66affSColin Finck 
1453c2c66affSColin Finck     LIST_FOR_EACH_ENTRY( mt, &package->mimes, MSIMIME, entry )
1454c2c66affSColin Finck     {
1455c2c66affSColin Finck         LPWSTR extension = NULL, key;
1456c2c66affSColin Finck 
1457c2c66affSColin Finck         /*
1458c2c66affSColin Finck          * check if the MIME is to be installed. Either as requested by an
1459c2c66affSColin Finck          * extension or Class
1460c2c66affSColin Finck          */
1461c2c66affSColin Finck         if ((!mt->Class || mt->Class->action != INSTALLSTATE_LOCAL) &&
1462c2c66affSColin Finck             (!mt->Extension || mt->Extension->action != INSTALLSTATE_LOCAL))
1463c2c66affSColin Finck         {
1464c2c66affSColin Finck             TRACE("MIME %s not scheduled to be installed\n", debugstr_w(mt->ContentType));
1465c2c66affSColin Finck             continue;
1466c2c66affSColin Finck         }
1467c2c66affSColin Finck 
1468c2c66affSColin Finck         TRACE("Registering MIME type %s\n", debugstr_w(mt->ContentType));
1469c2c66affSColin Finck 
1470c2c66affSColin Finck         if (mt->Extension) extension = msi_alloc( (strlenW( mt->Extension->Extension ) + 2) * sizeof(WCHAR) );
1471c2c66affSColin Finck         key = msi_alloc( (strlenW( mt->ContentType ) + strlenW( szMIMEDatabase ) + 1) * sizeof(WCHAR) );
1472c2c66affSColin Finck 
1473c2c66affSColin Finck         if (extension && key)
1474c2c66affSColin Finck         {
1475c2c66affSColin Finck             extension[0] = '.';
1476c2c66affSColin Finck             strcpyW( extension + 1, mt->Extension->Extension );
1477c2c66affSColin Finck 
1478c2c66affSColin Finck             strcpyW( key, szMIMEDatabase );
1479c2c66affSColin Finck             strcatW( key, mt->ContentType );
1480c2c66affSColin Finck             msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, key, szExtension, extension );
1481c2c66affSColin Finck 
1482c2c66affSColin Finck             if (mt->clsid)
1483c2c66affSColin Finck                 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, key, szCLSID, mt->clsid );
1484c2c66affSColin Finck         }
1485c2c66affSColin Finck         msi_free( extension );
1486c2c66affSColin Finck         msi_free( key );
1487c2c66affSColin Finck 
1488c2c66affSColin Finck         uirow = MSI_CreateRecord( 2 );
1489c2c66affSColin Finck         MSI_RecordSetStringW( uirow, 1, mt->ContentType );
1490c2c66affSColin Finck         MSI_RecordSetStringW( uirow, 2, mt->suffix );
149171bffdcdSAmine Khaldi         MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
1492c2c66affSColin Finck         msiobj_release( &uirow->hdr );
1493c2c66affSColin Finck     }
1494c2c66affSColin Finck     return ERROR_SUCCESS;
1495c2c66affSColin Finck }
1496c2c66affSColin Finck 
1497c2c66affSColin Finck UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
1498c2c66affSColin Finck {
1499c2c66affSColin Finck     MSIRECORD *uirow;
1500c2c66affSColin Finck     MSIMIME *mime;
1501c2c66affSColin Finck     UINT r;
1502c2c66affSColin Finck 
1503c2c66affSColin Finck     r = load_classes_and_such( package );
1504c2c66affSColin Finck     if (r != ERROR_SUCCESS)
1505c2c66affSColin Finck         return r;
1506c2c66affSColin Finck 
1507c2c66affSColin Finck     LIST_FOR_EACH_ENTRY( mime, &package->mimes, MSIMIME, entry )
1508c2c66affSColin Finck     {
1509c2c66affSColin Finck         LONG res;
1510c2c66affSColin Finck         LPWSTR mime_key;
1511c2c66affSColin Finck 
1512c2c66affSColin Finck         if ((!mime->Class || mime->Class->action != INSTALLSTATE_ABSENT) &&
1513c2c66affSColin Finck             (!mime->Extension || mime->Extension->action != INSTALLSTATE_ABSENT))
1514c2c66affSColin Finck         {
1515c2c66affSColin Finck             TRACE("MIME %s not scheduled to be removed\n", debugstr_w(mime->ContentType));
1516c2c66affSColin Finck             continue;
1517c2c66affSColin Finck         }
1518c2c66affSColin Finck 
1519c2c66affSColin Finck         TRACE("Unregistering MIME type %s\n", debugstr_w(mime->ContentType));
1520c2c66affSColin Finck 
1521c2c66affSColin Finck         mime_key = msi_alloc( (strlenW( szMIMEDatabase ) + strlenW( mime->ContentType ) + 1) * sizeof(WCHAR) );
1522c2c66affSColin Finck         if (mime_key)
1523c2c66affSColin Finck         {
1524c2c66affSColin Finck             strcpyW( mime_key, szMIMEDatabase );
1525c2c66affSColin Finck             strcatW( mime_key, mime->ContentType );
1526c2c66affSColin Finck             res = RegDeleteKeyW( HKEY_CLASSES_ROOT, mime_key );
1527c2c66affSColin Finck             if (res != ERROR_SUCCESS)
1528c2c66affSColin Finck                 WARN("Failed to delete MIME key %d\n", res);
1529c2c66affSColin Finck             msi_free( mime_key );
1530c2c66affSColin Finck         }
1531c2c66affSColin Finck 
1532c2c66affSColin Finck         uirow = MSI_CreateRecord( 2 );
1533c2c66affSColin Finck         MSI_RecordSetStringW( uirow, 1, mime->ContentType );
1534c2c66affSColin Finck         MSI_RecordSetStringW( uirow, 2, mime->suffix );
153571bffdcdSAmine Khaldi         MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
1536c2c66affSColin Finck         msiobj_release( &uirow->hdr );
1537c2c66affSColin Finck     }
1538c2c66affSColin Finck     return ERROR_SUCCESS;
1539c2c66affSColin Finck }
1540