2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2010 Hans Leidekker for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
25 static HRESULT (WINAPI
*pCreateAssemblyCacheNet10
)( IAssemblyCache
**, DWORD
);
26 static HRESULT (WINAPI
*pCreateAssemblyCacheNet11
)( IAssemblyCache
**, DWORD
);
27 static HRESULT (WINAPI
*pCreateAssemblyCacheNet20
)( IAssemblyCache
**, DWORD
);
28 static HRESULT (WINAPI
*pCreateAssemblyCacheNet40
)( IAssemblyCache
**, DWORD
);
29 static HRESULT (WINAPI
*pCreateAssemblyCacheSxs
)( IAssemblyCache
**, DWORD
);
30 static HRESULT (WINAPI
*pLoadLibraryShim
)( LPCWSTR
, LPCWSTR
, LPVOID
, HMODULE
* );
31 static HRESULT (WINAPI
*pGetFileVersion
)( LPCWSTR
, LPWSTR
, DWORD
, DWORD
* );
32 static HRESULT (WINAPI
*pCreateAssemblyNameObject
)( IAssemblyName
**, LPCWSTR
, DWORD
, LPVOID
);
33 static HRESULT (WINAPI
*pCreateAssemblyEnum
)( IAssemblyEnum
**, IUnknown
*, IAssemblyName
*, DWORD
, LPVOID
);
35 static HMODULE hfusion10
, hfusion11
, hfusion20
, hfusion40
, hmscoree
, hsxs
;
37 static BOOL
init_function_pointers( void )
39 static const WCHAR szFusion
[] = {'f','u','s','i','o','n','.','d','l','l',0};
40 static const WCHAR szMscoree
[] = {'\\','m','s','c','o','r','e','e','.','d','l','l',0};
41 static const WCHAR szSxs
[] = {'s','x','s','.','d','l','l',0};
42 static const WCHAR szVersion10
[] = {'v','1','.','0','.','3','7','0','5',0};
43 static const WCHAR szVersion11
[] = {'v','1','.','1','.','4','3','2','2',0};
44 static const WCHAR szVersion20
[] = {'v','2','.','0','.','5','0','7','2','7',0};
45 static const WCHAR szVersion40
[] = {'v','4','.','0','.','3','0','3','1','9',0};
47 DWORD len
= GetSystemDirectoryW( path
, MAX_PATH
);
49 if (!hsxs
&& !(hsxs
= LoadLibraryW( szSxs
))) return FALSE
;
50 if (!(pCreateAssemblyCacheSxs
= (void *)GetProcAddress( hsxs
, "CreateAssemblyCache" )))
56 strcpyW( path
+ len
, szMscoree
);
57 if (hmscoree
|| !(hmscoree
= LoadLibraryW( path
))) return TRUE
;
58 pGetFileVersion
= (void *)GetProcAddress( hmscoree
, "GetFileVersion" ); /* missing from v1.0.3705 */
59 if (!(pLoadLibraryShim
= (void *)GetProcAddress( hmscoree
, "LoadLibraryShim" )))
61 FreeLibrary( hmscoree
);
65 if (!pLoadLibraryShim( szFusion
, szVersion10
, NULL
, &hfusion10
))
66 pCreateAssemblyCacheNet10
= (void *)GetProcAddress( hfusion10
, "CreateAssemblyCache" );
68 if (!pLoadLibraryShim( szFusion
, szVersion11
, NULL
, &hfusion11
))
69 pCreateAssemblyCacheNet11
= (void *)GetProcAddress( hfusion11
, "CreateAssemblyCache" );
71 if (!pLoadLibraryShim( szFusion
, szVersion20
, NULL
, &hfusion20
))
72 pCreateAssemblyCacheNet20
= (void *)GetProcAddress( hfusion20
, "CreateAssemblyCache" );
74 if (!pLoadLibraryShim( szFusion
, szVersion40
, NULL
, &hfusion40
))
76 pCreateAssemblyCacheNet40
= (void *)GetProcAddress( hfusion40
, "CreateAssemblyCache" );
77 pCreateAssemblyNameObject
= (void *)GetProcAddress( hfusion40
, "CreateAssemblyNameObject" );
78 pCreateAssemblyEnum
= (void *)GetProcAddress( hfusion40
, "CreateAssemblyEnum" );
83 BOOL
msi_init_assembly_caches( MSIPACKAGE
*package
)
85 if (!init_function_pointers()) return FALSE
;
86 if (pCreateAssemblyCacheSxs( &package
->cache_sxs
, 0 ) != S_OK
) return FALSE
;
87 if (pCreateAssemblyCacheNet10
) pCreateAssemblyCacheNet10( &package
->cache_net
[CLR_VERSION_V10
], 0 );
88 if (pCreateAssemblyCacheNet11
) pCreateAssemblyCacheNet11( &package
->cache_net
[CLR_VERSION_V11
], 0 );
89 if (pCreateAssemblyCacheNet20
) pCreateAssemblyCacheNet20( &package
->cache_net
[CLR_VERSION_V20
], 0 );
90 if (pCreateAssemblyCacheNet40
) pCreateAssemblyCacheNet40( &package
->cache_net
[CLR_VERSION_V40
], 0 );
94 void msi_destroy_assembly_caches( MSIPACKAGE
*package
)
98 if (package
->cache_sxs
)
100 IAssemblyCache_Release( package
->cache_sxs
);
101 package
->cache_sxs
= NULL
;
103 for (i
= 0; i
< CLR_VERSION_MAX
; i
++)
105 if (package
->cache_net
[i
])
107 IAssemblyCache_Release( package
->cache_net
[i
] );
108 package
->cache_net
[i
] = NULL
;
111 pCreateAssemblyCacheNet10
= NULL
;
112 pCreateAssemblyCacheNet11
= NULL
;
113 pCreateAssemblyCacheNet20
= NULL
;
114 pCreateAssemblyCacheNet40
= NULL
;
115 FreeLibrary( hfusion10
);
116 FreeLibrary( hfusion11
);
117 FreeLibrary( hfusion20
);
118 FreeLibrary( hfusion40
);
119 FreeLibrary( hmscoree
);
129 static MSIRECORD
*get_assembly_record( MSIPACKAGE
*package
, const WCHAR
*comp
)
131 static const WCHAR query
[] = {
132 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
133 '`','M','s','i','A','s','s','e','m','b','l','y','`',' ',
134 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
135 ' ','=',' ','\'','%','s','\'',0};
140 r
= MSI_OpenQuery( package
->db
, &view
, query
, comp
);
141 if (r
!= ERROR_SUCCESS
)
144 r
= MSI_ViewExecute( view
, NULL
);
145 if (r
!= ERROR_SUCCESS
)
147 msiobj_release( &view
->hdr
);
150 r
= MSI_ViewFetch( view
, &rec
);
151 if (r
!= ERROR_SUCCESS
)
153 msiobj_release( &view
->hdr
);
156 if (!MSI_RecordGetString( rec
, 4 ))
157 TRACE("component is a global assembly\n");
159 msiobj_release( &view
->hdr
);
170 static UINT
get_assembly_name_attribute( MSIRECORD
*rec
, LPVOID param
)
172 static const WCHAR fmtW
[] = {'%','s','=','"','%','s','"',0};
173 static const WCHAR nameW
[] = {'n','a','m','e',0};
174 struct assembly_name
*name
= param
;
175 const WCHAR
*attr
= MSI_RecordGetString( rec
, 2 );
176 const WCHAR
*value
= MSI_RecordGetString( rec
, 3 );
177 int len
= strlenW( fmtW
) + strlenW( attr
) + strlenW( value
);
179 if (!(name
->attrs
[name
->index
] = msi_alloc( len
* sizeof(WCHAR
) )))
180 return ERROR_OUTOFMEMORY
;
182 if (!strcmpiW( attr
, nameW
)) strcpyW( name
->attrs
[name
->index
++], value
);
183 else sprintfW( name
->attrs
[name
->index
++], fmtW
, attr
, value
);
184 return ERROR_SUCCESS
;
187 static WCHAR
*get_assembly_display_name( MSIDATABASE
*db
, const WCHAR
*comp
, MSIASSEMBLY
*assembly
)
189 static const WCHAR commaW
[] = {',',0};
190 static const WCHAR queryW
[] = {
191 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
192 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
193 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
194 ' ','=',' ','\'','%','s','\'',0};
195 struct assembly_name name
;
196 WCHAR
*display_name
= NULL
;
201 r
= MSI_OpenQuery( db
, &view
, queryW
, comp
);
202 if (r
!= ERROR_SUCCESS
)
208 MSI_IterateRecords( view
, &name
.count
, NULL
, NULL
);
209 if (!name
.count
) goto done
;
211 name
.attrs
= msi_alloc( name
.count
* sizeof(WCHAR
*) );
212 if (!name
.attrs
) goto done
;
214 MSI_IterateRecords( view
, NULL
, get_assembly_name_attribute
, &name
);
217 for (i
= 0; i
< name
.count
; i
++) len
+= strlenW( name
.attrs
[i
] ) + 1;
219 display_name
= msi_alloc( (len
+ 1) * sizeof(WCHAR
) );
223 for (i
= 0; i
< name
.count
; i
++)
225 strcatW( display_name
, name
.attrs
[i
] );
226 if (i
< name
.count
- 1) strcatW( display_name
, commaW
);
231 msiobj_release( &view
->hdr
);
234 for (i
= 0; i
< name
.count
; i
++) msi_free( name
.attrs
[i
] );
235 msi_free( name
.attrs
);
240 static BOOL
is_assembly_installed( IAssemblyCache
*cache
, const WCHAR
*display_name
)
245 if (!cache
) return FALSE
;
247 memset( &info
, 0, sizeof(info
) );
248 info
.cbAssemblyInfo
= sizeof(info
);
249 hr
= IAssemblyCache_QueryAssemblyInfo( cache
, 0, display_name
, &info
);
250 if (hr
== S_OK
/* sxs version */ || hr
== E_NOT_SUFFICIENT_BUFFER
)
252 return (info
.dwAssemblyFlags
== ASSEMBLYINFO_FLAG_INSTALLED
);
254 TRACE("QueryAssemblyInfo returned 0x%08x\n", hr
);
258 WCHAR
*msi_get_assembly_path( MSIPACKAGE
*package
, const WCHAR
*displayname
)
262 IAssemblyCache
*cache
= package
->cache_net
[CLR_VERSION_V40
];
264 if (!cache
) return NULL
;
266 memset( &info
, 0, sizeof(info
) );
267 info
.cbAssemblyInfo
= sizeof(info
);
268 hr
= IAssemblyCache_QueryAssemblyInfo( cache
, 0, displayname
, &info
);
269 if (hr
!= E_NOT_SUFFICIENT_BUFFER
) return NULL
;
271 if (!(info
.pszCurrentAssemblyPathBuf
= msi_alloc( info
.cchBuf
* sizeof(WCHAR
) ))) return NULL
;
273 hr
= IAssemblyCache_QueryAssemblyInfo( cache
, 0, displayname
, &info
);
276 msi_free( info
.pszCurrentAssemblyPathBuf
);
279 TRACE("returning %s\n", debugstr_w(info
.pszCurrentAssemblyPathBuf
));
280 return info
.pszCurrentAssemblyPathBuf
;
283 IAssemblyEnum
*msi_create_assembly_enum( MSIPACKAGE
*package
, const WCHAR
*displayname
)
291 if (!pCreateAssemblyNameObject
|| !pCreateAssemblyEnum
) return NULL
;
293 hr
= pCreateAssemblyNameObject( &name
, displayname
, CANOF_PARSE_DISPLAY_NAME
, NULL
);
294 if (FAILED( hr
)) return NULL
;
296 hr
= IAssemblyName_GetName( name
, &len
, NULL
);
297 if (hr
!= E_NOT_SUFFICIENT_BUFFER
|| !(str
= msi_alloc( len
* sizeof(WCHAR
) )))
299 IAssemblyName_Release( name
);
303 hr
= IAssemblyName_GetName( name
, &len
, str
);
304 IAssemblyName_Release( name
);
311 hr
= pCreateAssemblyNameObject( &name
, str
, 0, NULL
);
313 if (FAILED( hr
)) return NULL
;
315 hr
= pCreateAssemblyEnum( &ret
, NULL
, name
, ASM_CACHE_GAC
, NULL
);
316 IAssemblyName_Release( name
);
317 if (FAILED( hr
)) return NULL
;
322 static const WCHAR clr_version_v10
[] = {'v','1','.','0','.','3','7','0','5',0};
323 static const WCHAR clr_version_v11
[] = {'v','1','.','1','.','4','3','2','2',0};
324 static const WCHAR clr_version_v20
[] = {'v','2','.','0','.','5','0','7','2','7',0};
325 static const WCHAR clr_version_v40
[] = {'v','4','.','0','.','3','0','3','1','9',0};
326 static const WCHAR clr_version_unknown
[] = {'u','n','k','n','o','w','n',0};
328 static const WCHAR
*clr_version
[] =
336 static const WCHAR
*get_clr_version_str( enum clr_version version
)
338 if (version
>= sizeof(clr_version
)/sizeof(clr_version
[0])) return clr_version_unknown
;
339 return clr_version
[version
];
342 /* assembly caches must be initialized */
343 MSIASSEMBLY
*msi_load_assembly( MSIPACKAGE
*package
, MSICOMPONENT
*comp
)
348 if (!(rec
= get_assembly_record( package
, comp
->Component
))) return NULL
;
349 if (!(a
= msi_alloc_zero( sizeof(MSIASSEMBLY
) )))
351 msiobj_release( &rec
->hdr
);
354 a
->feature
= strdupW( MSI_RecordGetString( rec
, 2 ) );
355 TRACE("feature %s\n", debugstr_w(a
->feature
));
357 a
->manifest
= strdupW( MSI_RecordGetString( rec
, 3 ) );
358 TRACE("manifest %s\n", debugstr_w(a
->manifest
));
360 a
->application
= strdupW( MSI_RecordGetString( rec
, 4 ) );
361 TRACE("application %s\n", debugstr_w(a
->application
));
363 a
->attributes
= MSI_RecordGetInteger( rec
, 5 );
364 TRACE("attributes %u\n", a
->attributes
);
366 if (!(a
->display_name
= get_assembly_display_name( package
->db
, comp
->Component
, a
)))
368 WARN("can't get display name\n");
369 msiobj_release( &rec
->hdr
);
370 msi_free( a
->feature
);
371 msi_free( a
->manifest
);
372 msi_free( a
->application
);
376 TRACE("display name %s\n", debugstr_w(a
->display_name
));
380 /* We can't check the manifest here because the target path may still change.
381 So we assume that the assembly is not installed and lean on the InstallFiles
382 action to determine which files need to be installed.
384 a
->installed
= FALSE
;
388 if (a
->attributes
== msidbAssemblyAttributesWin32
)
389 a
->installed
= is_assembly_installed( package
->cache_sxs
, a
->display_name
);
393 for (i
= 0; i
< CLR_VERSION_MAX
; i
++)
395 a
->clr_version
[i
] = is_assembly_installed( package
->cache_net
[i
], a
->display_name
);
396 if (a
->clr_version
[i
])
398 TRACE("runtime version %s\n", debugstr_w(get_clr_version_str( i
)));
405 TRACE("assembly is %s\n", a
->installed
? "installed" : "not installed");
406 msiobj_release( &rec
->hdr
);
410 static enum clr_version
get_clr_version( const WCHAR
*filename
)
414 enum clr_version version
= CLR_VERSION_V11
;
417 if (!pGetFileVersion
) return CLR_VERSION_V10
;
419 hr
= pGetFileVersion( filename
, NULL
, 0, &len
);
420 if (hr
!= E_NOT_SUFFICIENT_BUFFER
) return CLR_VERSION_V11
;
421 if ((strW
= msi_alloc( len
* sizeof(WCHAR
) )))
423 hr
= pGetFileVersion( filename
, strW
, len
, &len
);
427 for (i
= 0; i
< CLR_VERSION_MAX
; i
++)
428 if (!strcmpW( strW
, clr_version
[i
] )) version
= i
;
435 UINT
msi_install_assembly( MSIPACKAGE
*package
, MSICOMPONENT
*comp
)
438 const WCHAR
*manifest
;
439 IAssemblyCache
*cache
;
440 MSIASSEMBLY
*assembly
= comp
->assembly
;
441 MSIFEATURE
*feature
= NULL
;
443 if (comp
->assembly
->feature
)
444 feature
= msi_get_loaded_feature( package
, comp
->assembly
->feature
);
446 if (assembly
->application
)
448 if (feature
) feature
->Action
= INSTALLSTATE_LOCAL
;
449 return ERROR_SUCCESS
;
451 if (assembly
->attributes
== msidbAssemblyAttributesWin32
)
453 if (!assembly
->manifest
)
455 WARN("no manifest\n");
456 return ERROR_FUNCTION_FAILED
;
458 manifest
= msi_get_loaded_file( package
, assembly
->manifest
)->TargetPath
;
459 cache
= package
->cache_sxs
;
463 manifest
= msi_get_loaded_file( package
, comp
->KeyPath
)->TargetPath
;
464 cache
= package
->cache_net
[get_clr_version( manifest
)];
465 if (!cache
) return ERROR_SUCCESS
;
467 TRACE("installing assembly %s\n", debugstr_w(manifest
));
469 hr
= IAssemblyCache_InstallAssembly( cache
, 0, manifest
, NULL
);
472 ERR("Failed to install assembly %s (0x%08x)\n", debugstr_w(manifest
), hr
);
473 return ERROR_FUNCTION_FAILED
;
475 if (feature
) feature
->Action
= INSTALLSTATE_LOCAL
;
476 assembly
->installed
= TRUE
;
477 return ERROR_SUCCESS
;
480 UINT
msi_uninstall_assembly( MSIPACKAGE
*package
, MSICOMPONENT
*comp
)
483 IAssemblyCache
*cache
;
484 MSIASSEMBLY
*assembly
= comp
->assembly
;
485 MSIFEATURE
*feature
= NULL
;
487 if (comp
->assembly
->feature
)
488 feature
= msi_get_loaded_feature( package
, comp
->assembly
->feature
);
490 if (assembly
->application
)
492 if (feature
) feature
->Action
= INSTALLSTATE_ABSENT
;
493 return ERROR_SUCCESS
;
495 TRACE("removing %s\n", debugstr_w(assembly
->display_name
));
497 if (assembly
->attributes
== msidbAssemblyAttributesWin32
)
499 cache
= package
->cache_sxs
;
500 hr
= IAssemblyCache_UninstallAssembly( cache
, 0, assembly
->display_name
, NULL
, NULL
);
501 if (FAILED( hr
)) WARN("failed to uninstall assembly 0x%08x\n", hr
);
506 for (i
= 0; i
< CLR_VERSION_MAX
; i
++)
508 if (!assembly
->clr_version
[i
]) continue;
509 cache
= package
->cache_net
[i
];
512 hr
= IAssemblyCache_UninstallAssembly( cache
, 0, assembly
->display_name
, NULL
, NULL
);
513 if (FAILED( hr
)) WARN("failed to uninstall assembly 0x%08x\n", hr
);
517 if (feature
) feature
->Action
= INSTALLSTATE_ABSENT
;
518 assembly
->installed
= FALSE
;
519 return ERROR_SUCCESS
;
522 static WCHAR
*build_local_assembly_path( const WCHAR
*filename
)
527 if (!(ret
= msi_alloc( (strlenW( filename
) + 1) * sizeof(WCHAR
) )))
530 for (i
= 0; filename
[i
]; i
++)
532 if (filename
[i
] == '\\' || filename
[i
] == '/') ret
[i
] = '|';
533 else ret
[i
] = filename
[i
];
539 static LONG
open_assemblies_key( UINT context
, BOOL win32
, HKEY
*hkey
)
541 static const WCHAR path_win32
[] =
542 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
543 'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',0};
544 static const WCHAR path_dotnet
[] =
545 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
546 'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',0};
547 static const WCHAR classes_path_win32
[] =
548 {'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',0};
549 static const WCHAR classes_path_dotnet
[] =
550 {'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',0};
554 if (context
== MSIINSTALLCONTEXT_MACHINE
)
556 root
= HKEY_CLASSES_ROOT
;
557 if (win32
) path
= classes_path_win32
;
558 else path
= classes_path_dotnet
;
562 root
= HKEY_CURRENT_USER
;
563 if (win32
) path
= path_win32
;
564 else path
= path_dotnet
;
566 return RegCreateKeyW( root
, path
, hkey
);
569 static LONG
open_local_assembly_key( UINT context
, BOOL win32
, const WCHAR
*filename
, HKEY
*hkey
)
575 if (!(path
= build_local_assembly_path( filename
)))
576 return ERROR_OUTOFMEMORY
;
578 if ((res
= open_assemblies_key( context
, win32
, &root
)))
583 res
= RegCreateKeyW( root
, path
, hkey
);
589 static LONG
delete_local_assembly_key( UINT context
, BOOL win32
, const WCHAR
*filename
)
595 if (!(path
= build_local_assembly_path( filename
)))
596 return ERROR_OUTOFMEMORY
;
598 if ((res
= open_assemblies_key( context
, win32
, &root
)))
603 res
= RegDeleteKeyW( root
, path
);
609 static LONG
open_global_assembly_key( UINT context
, BOOL win32
, HKEY
*hkey
)
611 static const WCHAR path_win32
[] =
612 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
613 'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',
614 'G','l','o','b','a','l',0};
615 static const WCHAR path_dotnet
[] =
616 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
617 'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',
618 'G','l','o','b','a','l',0};
619 static const WCHAR classes_path_win32
[] =
620 {'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',
621 'G','l','o','b','a','l',0};
622 static const WCHAR classes_path_dotnet
[] =
623 {'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\','G','l','o','b','a','l',0};
627 if (context
== MSIINSTALLCONTEXT_MACHINE
)
629 root
= HKEY_CLASSES_ROOT
;
630 if (win32
) path
= classes_path_win32
;
631 else path
= classes_path_dotnet
;
635 root
= HKEY_CURRENT_USER
;
636 if (win32
) path
= path_win32
;
637 else path
= path_dotnet
;
639 return RegCreateKeyW( root
, path
, hkey
);
642 UINT
ACTION_MsiPublishAssemblies( MSIPACKAGE
*package
)
646 LIST_FOR_EACH_ENTRY(comp
, &package
->components
, MSICOMPONENT
, entry
)
654 MSIASSEMBLY
*assembly
= comp
->assembly
;
657 if (!assembly
|| !comp
->ComponentId
) continue;
659 comp
->Action
= msi_get_component_action( package
, comp
);
660 if (comp
->Action
!= INSTALLSTATE_LOCAL
)
662 TRACE("component not scheduled for installation %s\n", debugstr_w(comp
->Component
));
665 TRACE("publishing %s\n", debugstr_w(comp
->Component
));
667 CLSIDFromString( package
->ProductCode
, &guid
);
668 encode_base85_guid( &guid
, buffer
);
670 CLSIDFromString( comp
->ComponentId
, &guid
);
671 encode_base85_guid( &guid
, buffer
+ 21 );
674 win32
= assembly
->attributes
& msidbAssemblyAttributesWin32
;
675 if (assembly
->application
)
677 MSIFILE
*file
= msi_get_loaded_file( package
, assembly
->application
);
678 if ((res
= open_local_assembly_key( package
->Context
, win32
, file
->TargetPath
, &hkey
)))
680 WARN("failed to open local assembly key %d\n", res
);
681 return ERROR_FUNCTION_FAILED
;
686 if ((res
= open_global_assembly_key( package
->Context
, win32
, &hkey
)))
688 WARN("failed to open global assembly key %d\n", res
);
689 return ERROR_FUNCTION_FAILED
;
692 size
= sizeof(buffer
);
693 if ((res
= RegSetValueExW( hkey
, assembly
->display_name
, 0, REG_MULTI_SZ
, (const BYTE
*)buffer
, size
)))
695 WARN("failed to set assembly value %d\n", res
);
699 uirow
= MSI_CreateRecord( 2 );
700 MSI_RecordSetStringW( uirow
, 2, assembly
->display_name
);
701 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONDATA
, uirow
);
702 msiobj_release( &uirow
->hdr
);
704 return ERROR_SUCCESS
;
707 UINT
ACTION_MsiUnpublishAssemblies( MSIPACKAGE
*package
)
711 LIST_FOR_EACH_ENTRY(comp
, &package
->components
, MSICOMPONENT
, entry
)
715 MSIASSEMBLY
*assembly
= comp
->assembly
;
718 if (!assembly
|| !comp
->ComponentId
) continue;
720 comp
->Action
= msi_get_component_action( package
, comp
);
721 if (comp
->Action
!= INSTALLSTATE_ABSENT
)
723 TRACE("component not scheduled for removal %s\n", debugstr_w(comp
->Component
));
726 TRACE("unpublishing %s\n", debugstr_w(comp
->Component
));
728 win32
= assembly
->attributes
& msidbAssemblyAttributesWin32
;
729 if (assembly
->application
)
731 MSIFILE
*file
= msi_get_loaded_file( package
, assembly
->application
);
732 if ((res
= delete_local_assembly_key( package
->Context
, win32
, file
->TargetPath
)))
733 WARN("failed to delete local assembly key %d\n", res
);
738 if ((res
= open_global_assembly_key( package
->Context
, win32
, &hkey
)))
739 WARN("failed to delete global assembly key %d\n", res
);
742 if ((res
= RegDeleteValueW( hkey
, assembly
->display_name
)))
743 WARN("failed to delete global assembly value %d\n", res
);
748 uirow
= MSI_CreateRecord( 2 );
749 MSI_RecordSetStringW( uirow
, 2, assembly
->display_name
);
750 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONDATA
, uirow
);
751 msiobj_release( &uirow
->hdr
);
753 return ERROR_SUCCESS
;