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