ntdll: Get the unix tid on DragonFly BSD.
[wine/multimedia.git] / dlls / msi / assembly.c
blobd38400332f5b482a060ecfbb4ce3ee5e96da8e0c
1 /*
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
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winreg.h"
28 #include "wine/debug.h"
29 #include "wine/unicode.h"
30 #include "msipriv.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(msi);
34 static HRESULT (WINAPI *pCreateAssemblyCacheNet10)( IAssemblyCache **, DWORD );
35 static HRESULT (WINAPI *pCreateAssemblyCacheNet11)( IAssemblyCache **, DWORD );
36 static HRESULT (WINAPI *pCreateAssemblyCacheNet20)( IAssemblyCache **, DWORD );
37 static HRESULT (WINAPI *pCreateAssemblyCacheNet40)( IAssemblyCache **, DWORD );
38 static HRESULT (WINAPI *pCreateAssemblyCacheSxs)( IAssemblyCache **, DWORD );
39 static HRESULT (WINAPI *pLoadLibraryShim)( LPCWSTR, LPCWSTR, LPVOID, HMODULE * );
40 static HRESULT (WINAPI *pGetFileVersion)( LPCWSTR, LPWSTR, DWORD, DWORD * );
42 static HMODULE hfusion10, hfusion11, hfusion20, hfusion40, hmscoree, hsxs;
44 static BOOL init_function_pointers( void )
46 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
47 static const WCHAR szVersion10[] = {'v','1','.','0','.','3','7','0','5',0};
48 static const WCHAR szVersion11[] = {'v','1','.','1','.','4','3','2','2',0};
49 static const WCHAR szVersion20[] = {'v','2','.','0','.','5','0','7','2','7',0};
50 static const WCHAR szVersion40[] = {'v','4','.','0','.','3','0','3','1','9',0};
52 if (pCreateAssemblyCacheNet10 || pCreateAssemblyCacheNet11 || pCreateAssemblyCacheNet20 ||
53 pCreateAssemblyCacheNet40 ) return TRUE;
55 if (!(hmscoree = LoadLibraryA( "mscoree.dll" ))) return FALSE;
56 pGetFileVersion = (void *)GetProcAddress( hmscoree, "GetFileVersion" ); /* missing from v1.0.3705 */
57 if (!(pLoadLibraryShim = (void *)GetProcAddress( hmscoree, "LoadLibraryShim" ))) goto error;
59 if (!pLoadLibraryShim( szFusion, szVersion10, NULL, &hfusion10 ))
60 pCreateAssemblyCacheNet10 = (void *)GetProcAddress( hfusion10, "CreateAssemblyCache" );
62 if (!pLoadLibraryShim( szFusion, szVersion11, NULL, &hfusion11 ))
63 pCreateAssemblyCacheNet11 = (void *)GetProcAddress( hfusion11, "CreateAssemblyCache" );
65 if (!pLoadLibraryShim( szFusion, szVersion20, NULL, &hfusion20 ))
66 pCreateAssemblyCacheNet20 = (void *)GetProcAddress( hfusion20, "CreateAssemblyCache" );
68 if (!pLoadLibraryShim( szFusion, szVersion40, NULL, &hfusion40 ))
69 pCreateAssemblyCacheNet40 = (void *)GetProcAddress( hfusion40, "CreateAssemblyCache" );
71 if (!pCreateAssemblyCacheNet10 && !pCreateAssemblyCacheNet11 && !pCreateAssemblyCacheNet20
72 && !pCreateAssemblyCacheNet40) goto error;
74 if (!(hsxs = LoadLibraryA( "sxs.dll" ))) goto error;
75 if (!(pCreateAssemblyCacheSxs = (void *)GetProcAddress( hsxs, "CreateAssemblyCache" ))) goto error;
76 return TRUE;
78 error:
79 pCreateAssemblyCacheNet10 = NULL;
80 pCreateAssemblyCacheNet11 = NULL;
81 pCreateAssemblyCacheNet20 = NULL;
82 pCreateAssemblyCacheNet40 = NULL;
83 FreeLibrary( hfusion10 );
84 FreeLibrary( hfusion11 );
85 FreeLibrary( hfusion20 );
86 FreeLibrary( hfusion40 );
87 FreeLibrary( hmscoree );
88 return FALSE;
91 BOOL msi_init_assembly_caches( MSIPACKAGE *package )
93 if (!init_function_pointers()) return FALSE;
94 if (package->cache_net[CLR_VERSION_V10] ||
95 package->cache_net[CLR_VERSION_V11] ||
96 package->cache_net[CLR_VERSION_V20] ||
97 package->cache_net[CLR_VERSION_V40]) return TRUE;
98 if (pCreateAssemblyCacheSxs( &package->cache_sxs, 0 ) != S_OK) return FALSE;
100 if (pCreateAssemblyCacheNet10) pCreateAssemblyCacheNet10( &package->cache_net[CLR_VERSION_V10], 0 );
101 if (pCreateAssemblyCacheNet11) pCreateAssemblyCacheNet11( &package->cache_net[CLR_VERSION_V11], 0 );
102 if (pCreateAssemblyCacheNet20) pCreateAssemblyCacheNet20( &package->cache_net[CLR_VERSION_V20], 0 );
103 if (pCreateAssemblyCacheNet40) pCreateAssemblyCacheNet40( &package->cache_net[CLR_VERSION_V40], 0 );
105 if (package->cache_net[CLR_VERSION_V10] ||
106 package->cache_net[CLR_VERSION_V11] ||
107 package->cache_net[CLR_VERSION_V20] ||
108 package->cache_net[CLR_VERSION_V40])
110 return TRUE;
112 if (package->cache_net[CLR_VERSION_V10])
114 IAssemblyCache_Release( package->cache_net[CLR_VERSION_V10] );
115 package->cache_net[CLR_VERSION_V10] = NULL;
117 if (package->cache_net[CLR_VERSION_V11])
119 IAssemblyCache_Release( package->cache_net[CLR_VERSION_V11] );
120 package->cache_net[CLR_VERSION_V11] = NULL;
122 if (package->cache_net[CLR_VERSION_V20])
124 IAssemblyCache_Release( package->cache_net[CLR_VERSION_V20] );
125 package->cache_net[CLR_VERSION_V20] = NULL;
127 if (package->cache_net[CLR_VERSION_V40])
129 IAssemblyCache_Release( package->cache_net[CLR_VERSION_V40] );
130 package->cache_net[CLR_VERSION_V40] = NULL;
132 IAssemblyCache_Release( package->cache_sxs );
133 package->cache_sxs = NULL;
134 return FALSE;
137 void msi_destroy_assembly_caches( MSIPACKAGE *package )
139 UINT i;
141 for (i = 0; i < CLR_VERSION_MAX; i++)
143 if (package->cache_net[i])
145 IAssemblyCache_Release( package->cache_net[i] );
146 package->cache_net[i] = NULL;
149 if (package->cache_sxs)
151 IAssemblyCache_Release( package->cache_sxs );
152 package->cache_sxs = NULL;
154 pCreateAssemblyCacheNet10 = NULL;
155 pCreateAssemblyCacheNet11 = NULL;
156 pCreateAssemblyCacheNet20 = NULL;
157 pCreateAssemblyCacheNet40 = NULL;
158 FreeLibrary( hfusion10 );
159 FreeLibrary( hfusion11 );
160 FreeLibrary( hfusion20 );
161 FreeLibrary( hfusion40 );
162 FreeLibrary( hmscoree );
163 FreeLibrary( hsxs );
166 static MSIRECORD *get_assembly_record( MSIPACKAGE *package, const WCHAR *comp )
168 static const WCHAR query[] = {
169 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
170 '`','M','s','i','A','s','s','e','m','b','l','y','`',' ',
171 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
172 ' ','=',' ','\'','%','s','\'',0};
173 MSIQUERY *view;
174 MSIRECORD *rec;
175 UINT r;
177 r = MSI_OpenQuery( package->db, &view, query, comp );
178 if (r != ERROR_SUCCESS)
179 return NULL;
181 r = MSI_ViewExecute( view, NULL );
182 if (r != ERROR_SUCCESS)
184 msiobj_release( &view->hdr );
185 return NULL;
187 r = MSI_ViewFetch( view, &rec );
188 if (r != ERROR_SUCCESS)
190 msiobj_release( &view->hdr );
191 return NULL;
193 if (!MSI_RecordGetString( rec, 4 ))
194 TRACE("component is a global assembly\n");
196 msiobj_release( &view->hdr );
197 return rec;
200 struct assembly_name
202 UINT count;
203 UINT index;
204 WCHAR **attrs;
207 static UINT get_assembly_name_attribute( MSIRECORD *rec, LPVOID param )
209 static const WCHAR fmtW[] = {'%','s','=','"','%','s','"',0};
210 static const WCHAR nameW[] = {'n','a','m','e',0};
211 struct assembly_name *name = param;
212 const WCHAR *attr = MSI_RecordGetString( rec, 2 );
213 const WCHAR *value = MSI_RecordGetString( rec, 3 );
214 int len = strlenW( fmtW ) + strlenW( attr ) + strlenW( value );
216 if (!(name->attrs[name->index] = msi_alloc( len * sizeof(WCHAR) )))
217 return ERROR_OUTOFMEMORY;
219 if (!strcmpiW( attr, nameW )) strcpyW( name->attrs[name->index++], value );
220 else sprintfW( name->attrs[name->index++], fmtW, attr, value );
221 return ERROR_SUCCESS;
224 static WCHAR *get_assembly_display_name( MSIDATABASE *db, const WCHAR *comp, MSIASSEMBLY *assembly )
226 static const WCHAR commaW[] = {',',0};
227 static const WCHAR queryW[] = {
228 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
229 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
230 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
231 ' ','=',' ','\'','%','s','\'',0};
232 struct assembly_name name;
233 WCHAR *display_name = NULL;
234 MSIQUERY *view;
235 UINT i, r;
236 int len;
238 r = MSI_OpenQuery( db, &view, queryW, comp );
239 if (r != ERROR_SUCCESS)
240 return NULL;
242 name.count = 0;
243 name.index = 0;
244 name.attrs = NULL;
245 MSI_IterateRecords( view, &name.count, NULL, NULL );
246 if (!name.count) goto done;
248 name.attrs = msi_alloc( name.count * sizeof(WCHAR *) );
249 if (!name.attrs) goto done;
251 MSI_IterateRecords( view, NULL, get_assembly_name_attribute, &name );
253 len = 0;
254 for (i = 0; i < name.count; i++) len += strlenW( name.attrs[i] ) + 1;
256 display_name = msi_alloc( (len + 1) * sizeof(WCHAR) );
257 if (display_name)
259 display_name[0] = 0;
260 for (i = 0; i < name.count; i++)
262 strcatW( display_name, name.attrs[i] );
263 if (i < name.count - 1) strcatW( display_name, commaW );
267 done:
268 msiobj_release( &view->hdr );
269 if (name.attrs)
271 for (i = 0; i < name.count; i++) msi_free( name.attrs[i] );
272 msi_free( name.attrs );
274 return display_name;
277 static BOOL is_assembly_installed( IAssemblyCache *cache, const WCHAR *display_name )
279 HRESULT hr;
280 ASSEMBLY_INFO info;
282 memset( &info, 0, sizeof(info) );
283 info.cbAssemblyInfo = sizeof(info);
284 hr = IAssemblyCache_QueryAssemblyInfo( cache, 0, display_name, &info );
285 if (hr == S_OK /* sxs version */ || hr == HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ))
287 return (info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
289 TRACE("QueryAssemblyInfo returned 0x%08x\n", hr);
290 return FALSE;
293 static const WCHAR clr_version_v10[] = {'v','1','.','0','.','3','7','0','5',0};
294 static const WCHAR clr_version_v11[] = {'v','1','.','1','.','4','3','2','2',0};
295 static const WCHAR clr_version_v20[] = {'v','2','.','0','.','5','0','7','2','7',0};
296 static const WCHAR clr_version_v40[] = {'v','4','.','0','.','3','0','3','1','9',0};
297 static const WCHAR clr_version_unknown[] = {'u','n','k','n','o','w','n',0};
299 static const WCHAR *clr_version[] =
301 clr_version_v10,
302 clr_version_v11,
303 clr_version_v20,
304 clr_version_v40
307 static const WCHAR *get_clr_version_str( enum clr_version version )
309 if (version >= sizeof(clr_version)/sizeof(clr_version[0])) return clr_version_unknown;
310 return clr_version[version];
313 /* assembly caches must be initialized */
314 MSIASSEMBLY *msi_load_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
316 MSIRECORD *rec;
317 MSIASSEMBLY *a;
319 if (!(rec = get_assembly_record( package, comp->Component ))) return NULL;
320 if (!(a = msi_alloc_zero( sizeof(MSIASSEMBLY) )))
322 msiobj_release( &rec->hdr );
323 return NULL;
325 a->feature = strdupW( MSI_RecordGetString( rec, 2 ) );
326 TRACE("feature %s\n", debugstr_w(a->feature));
328 a->manifest = strdupW( MSI_RecordGetString( rec, 3 ) );
329 TRACE("manifest %s\n", debugstr_w(a->manifest));
331 a->application = strdupW( MSI_RecordGetString( rec, 4 ) );
332 TRACE("application %s\n", debugstr_w(a->application));
334 a->attributes = MSI_RecordGetInteger( rec, 5 );
335 TRACE("attributes %u\n", a->attributes);
337 if (!(a->display_name = get_assembly_display_name( package->db, comp->Component, a )))
339 WARN("can't get display name\n");
340 msiobj_release( &rec->hdr );
341 msi_free( a->feature );
342 msi_free( a->manifest );
343 msi_free( a->application );
344 msi_free( a );
345 return NULL;
347 TRACE("display name %s\n", debugstr_w(a->display_name));
349 if (a->application)
351 /* We can't check the manifest here because the target path may still change.
352 So we assume that the assembly is not installed and lean on the InstallFiles
353 action to determine which files need to be installed.
355 a->installed = FALSE;
357 else
359 if (a->attributes == msidbAssemblyAttributesWin32)
360 a->installed = is_assembly_installed( package->cache_sxs, a->display_name );
361 else
363 UINT i;
364 for (i = 0; i < CLR_VERSION_MAX; i++)
366 a->clr_version[i] = is_assembly_installed( package->cache_net[i], a->display_name );
367 if (a->clr_version[i])
369 TRACE("runtime version %s\n", debugstr_w(get_clr_version_str( i )));
370 a->installed = TRUE;
371 break;
376 TRACE("assembly is %s\n", a->installed ? "installed" : "not installed");
377 msiobj_release( &rec->hdr );
378 return a;
381 static enum clr_version get_clr_version( const WCHAR *filename )
383 DWORD len;
384 HRESULT hr;
385 enum clr_version version = CLR_VERSION_V11;
386 WCHAR *strW;
388 if (!pGetFileVersion) return CLR_VERSION_V10;
390 hr = pGetFileVersion( filename, NULL, 0, &len );
391 if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) return CLR_VERSION_V11;
392 if ((strW = msi_alloc( len * sizeof(WCHAR) )))
394 hr = pGetFileVersion( filename, strW, len, &len );
395 if (hr == S_OK)
397 UINT i;
398 for (i = 0; i < CLR_VERSION_MAX; i++)
399 if (!strcmpW( strW, clr_version[i] )) version = i;
401 msi_free( strW );
403 return version;
406 UINT msi_install_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
408 HRESULT hr;
409 const WCHAR *manifest;
410 IAssemblyCache *cache;
411 MSIASSEMBLY *assembly = comp->assembly;
412 MSIFEATURE *feature = NULL;
414 if (comp->assembly->feature)
415 feature = msi_get_loaded_feature( package, comp->assembly->feature );
417 if (assembly->application)
419 if (feature) feature->Action = INSTALLSTATE_LOCAL;
420 return ERROR_SUCCESS;
422 if (assembly->attributes == msidbAssemblyAttributesWin32)
424 if (!assembly->manifest)
426 WARN("no manifest\n");
427 return ERROR_FUNCTION_FAILED;
429 manifest = msi_get_loaded_file( package, assembly->manifest )->TargetPath;
430 cache = package->cache_sxs;
432 else
434 manifest = msi_get_loaded_file( package, comp->KeyPath )->TargetPath;
435 cache = package->cache_net[get_clr_version( manifest )];
437 TRACE("installing assembly %s\n", debugstr_w(manifest));
439 hr = IAssemblyCache_InstallAssembly( cache, 0, manifest, NULL );
440 if (hr != S_OK)
442 ERR("Failed to install assembly %s (0x%08x)\n", debugstr_w(manifest), hr);
443 return ERROR_FUNCTION_FAILED;
445 if (feature) feature->Action = INSTALLSTATE_LOCAL;
446 assembly->installed = TRUE;
447 return ERROR_SUCCESS;
450 UINT msi_uninstall_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
452 HRESULT hr;
453 IAssemblyCache *cache;
454 MSIASSEMBLY *assembly = comp->assembly;
455 MSIFEATURE *feature = NULL;
457 if (comp->assembly->feature)
458 feature = msi_get_loaded_feature( package, comp->assembly->feature );
460 if (assembly->application)
462 if (feature) feature->Action = INSTALLSTATE_ABSENT;
463 return ERROR_SUCCESS;
465 TRACE("removing %s\n", debugstr_w(assembly->display_name));
467 if (assembly->attributes == msidbAssemblyAttributesWin32)
469 cache = package->cache_sxs;
470 hr = IAssemblyCache_UninstallAssembly( cache, 0, assembly->display_name, NULL, NULL );
471 if (FAILED( hr )) WARN("failed to uninstall assembly 0x%08x\n", hr);
473 else
475 unsigned int i;
476 for (i = 0; i < CLR_VERSION_MAX; i++)
478 if (!assembly->clr_version[i]) continue;
479 cache = package->cache_net[i];
480 hr = IAssemblyCache_UninstallAssembly( cache, 0, assembly->display_name, NULL, NULL );
481 if (FAILED( hr )) WARN("failed to uninstall assembly 0x%08x\n", hr);
484 if (feature) feature->Action = INSTALLSTATE_ABSENT;
485 assembly->installed = FALSE;
486 return ERROR_SUCCESS;
489 static WCHAR *build_local_assembly_path( const WCHAR *filename )
491 UINT i;
492 WCHAR *ret;
494 if (!(ret = msi_alloc( (strlenW( filename ) + 1) * sizeof(WCHAR) )))
495 return NULL;
497 for (i = 0; filename[i]; i++)
499 if (filename[i] == '\\' || filename[i] == '/') ret[i] = '|';
500 else ret[i] = filename[i];
502 ret[i] = 0;
503 return ret;
506 static LONG open_assemblies_key( UINT context, BOOL win32, HKEY *hkey )
508 static const WCHAR path_win32[] =
509 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
510 '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};
511 static const WCHAR path_dotnet[] =
512 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
513 'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',0};
514 static const WCHAR classes_path_win32[] =
515 {'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};
516 static const WCHAR classes_path_dotnet[] =
517 {'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',0};
518 HKEY root;
519 const WCHAR *path;
521 if (context == MSIINSTALLCONTEXT_MACHINE)
523 root = HKEY_CLASSES_ROOT;
524 if (win32) path = classes_path_win32;
525 else path = classes_path_dotnet;
527 else
529 root = HKEY_CURRENT_USER;
530 if (win32) path = path_win32;
531 else path = path_dotnet;
533 return RegCreateKeyW( root, path, hkey );
536 static LONG open_local_assembly_key( UINT context, BOOL win32, const WCHAR *filename, HKEY *hkey )
538 LONG res;
539 HKEY root;
540 WCHAR *path;
542 if (!(path = build_local_assembly_path( filename )))
543 return ERROR_OUTOFMEMORY;
545 if ((res = open_assemblies_key( context, win32, &root )))
547 msi_free( path );
548 return res;
550 res = RegCreateKeyW( root, path, hkey );
551 RegCloseKey( root );
552 msi_free( path );
553 return res;
556 static LONG delete_local_assembly_key( UINT context, BOOL win32, const WCHAR *filename )
558 LONG res;
559 HKEY root;
560 WCHAR *path;
562 if (!(path = build_local_assembly_path( filename )))
563 return ERROR_OUTOFMEMORY;
565 if ((res = open_assemblies_key( context, win32, &root )))
567 msi_free( path );
568 return res;
570 res = RegDeleteKeyW( root, path );
571 RegCloseKey( root );
572 msi_free( path );
573 return res;
576 static LONG open_global_assembly_key( UINT context, BOOL win32, HKEY *hkey )
578 static const WCHAR path_win32[] =
579 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
580 'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',
581 'G','l','o','b','a','l',0};
582 static const WCHAR path_dotnet[] =
583 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
584 'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',
585 'G','l','o','b','a','l',0};
586 static const WCHAR classes_path_win32[] =
587 {'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',
588 'G','l','o','b','a','l',0};
589 static const WCHAR classes_path_dotnet[] =
590 {'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};
591 HKEY root;
592 const WCHAR *path;
594 if (context == MSIINSTALLCONTEXT_MACHINE)
596 root = HKEY_CLASSES_ROOT;
597 if (win32) path = classes_path_win32;
598 else path = classes_path_dotnet;
600 else
602 root = HKEY_CURRENT_USER;
603 if (win32) path = path_win32;
604 else path = path_dotnet;
606 return RegCreateKeyW( root, path, hkey );
609 UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
611 MSICOMPONENT *comp;
613 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
615 LONG res;
616 HKEY hkey;
617 GUID guid;
618 DWORD size;
619 WCHAR buffer[43];
620 MSIRECORD *uirow;
621 MSIASSEMBLY *assembly = comp->assembly;
622 BOOL win32;
624 if (!assembly || !comp->ComponentId) continue;
626 comp->Action = msi_get_component_action( package, comp );
627 if (comp->Action != INSTALLSTATE_LOCAL)
629 TRACE("component not scheduled for installation %s\n", debugstr_w(comp->Component));
630 continue;
632 TRACE("publishing %s\n", debugstr_w(comp->Component));
634 CLSIDFromString( package->ProductCode, &guid );
635 encode_base85_guid( &guid, buffer );
636 buffer[20] = '>';
637 CLSIDFromString( comp->ComponentId, &guid );
638 encode_base85_guid( &guid, buffer + 21 );
639 buffer[42] = 0;
641 win32 = assembly->attributes & msidbAssemblyAttributesWin32;
642 if (assembly->application)
644 MSIFILE *file = msi_get_loaded_file( package, assembly->application );
645 if ((res = open_local_assembly_key( package->Context, win32, file->TargetPath, &hkey )))
647 WARN("failed to open local assembly key %d\n", res);
648 return ERROR_FUNCTION_FAILED;
651 else
653 if ((res = open_global_assembly_key( package->Context, win32, &hkey )))
655 WARN("failed to open global assembly key %d\n", res);
656 return ERROR_FUNCTION_FAILED;
659 size = sizeof(buffer);
660 if ((res = RegSetValueExW( hkey, assembly->display_name, 0, REG_MULTI_SZ, (const BYTE *)buffer, size )))
662 WARN("failed to set assembly value %d\n", res);
664 RegCloseKey( hkey );
666 uirow = MSI_CreateRecord( 2 );
667 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
668 msi_ui_actiondata( package, szMsiPublishAssemblies, uirow );
669 msiobj_release( &uirow->hdr );
671 return ERROR_SUCCESS;
674 UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
676 MSICOMPONENT *comp;
678 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
680 LONG res;
681 MSIRECORD *uirow;
682 MSIASSEMBLY *assembly = comp->assembly;
683 BOOL win32;
685 if (!assembly || !comp->ComponentId) continue;
687 comp->Action = msi_get_component_action( package, comp );
688 if (comp->Action != INSTALLSTATE_ABSENT)
690 TRACE("component not scheduled for removal %s\n", debugstr_w(comp->Component));
691 continue;
693 TRACE("unpublishing %s\n", debugstr_w(comp->Component));
695 win32 = assembly->attributes & msidbAssemblyAttributesWin32;
696 if (assembly->application)
698 MSIFILE *file = msi_get_loaded_file( package, assembly->application );
699 if ((res = delete_local_assembly_key( package->Context, win32, file->TargetPath )))
700 WARN("failed to delete local assembly key %d\n", res);
702 else
704 HKEY hkey;
705 if ((res = open_global_assembly_key( package->Context, win32, &hkey )))
706 WARN("failed to delete global assembly key %d\n", res);
707 else
709 if ((res = RegDeleteValueW( hkey, assembly->display_name )))
710 WARN("failed to delete global assembly value %d\n", res);
711 RegCloseKey( hkey );
715 uirow = MSI_CreateRecord( 2 );
716 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
717 msi_ui_actiondata( package, szMsiPublishAssemblies, uirow );
718 msiobj_release( &uirow->hdr );
720 return ERROR_SUCCESS;