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