vcomp/tests: Add tests for atomic double functions.
[wine.git] / dlls / msi / assembly.c
blob7151a8bd564dc5bdc11dd5205b6b1a8181c74e1f
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 * );
41 static HRESULT (WINAPI *pCreateAssemblyNameObject)( IAssemblyName **, LPCWSTR, DWORD, LPVOID );
42 static HRESULT (WINAPI *pCreateAssemblyEnum)( IAssemblyEnum **, IUnknown *, IAssemblyName *, DWORD, LPVOID );
44 static HMODULE hfusion10, hfusion11, hfusion20, hfusion40, hmscoree, hsxs;
46 static BOOL init_function_pointers( void )
48 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
49 static const WCHAR szMscoree[] = {'\\','m','s','c','o','r','e','e','.','d','l','l',0};
50 static const WCHAR szSxs[] = {'s','x','s','.','d','l','l',0};
51 static const WCHAR szVersion10[] = {'v','1','.','0','.','3','7','0','5',0};
52 static const WCHAR szVersion11[] = {'v','1','.','1','.','4','3','2','2',0};
53 static const WCHAR szVersion20[] = {'v','2','.','0','.','5','0','7','2','7',0};
54 static const WCHAR szVersion40[] = {'v','4','.','0','.','3','0','3','1','9',0};
55 WCHAR path[MAX_PATH];
56 DWORD len = GetSystemDirectoryW( path, MAX_PATH );
58 if (!hsxs && !(hsxs = LoadLibraryW( szSxs ))) return FALSE;
59 if (!(pCreateAssemblyCacheSxs = (void *)GetProcAddress( hsxs, "CreateAssemblyCache" )))
61 FreeLibrary( hsxs );
62 hsxs = NULL;
63 return FALSE;
65 strcpyW( path + len, szMscoree );
66 if (hmscoree || !(hmscoree = LoadLibraryW( path ))) return TRUE;
67 pGetFileVersion = (void *)GetProcAddress( hmscoree, "GetFileVersion" ); /* missing from v1.0.3705 */
68 if (!(pLoadLibraryShim = (void *)GetProcAddress( hmscoree, "LoadLibraryShim" )))
70 FreeLibrary( hmscoree );
71 hmscoree = NULL;
72 return TRUE;
74 if (!pLoadLibraryShim( szFusion, szVersion10, NULL, &hfusion10 ))
75 pCreateAssemblyCacheNet10 = (void *)GetProcAddress( hfusion10, "CreateAssemblyCache" );
77 if (!pLoadLibraryShim( szFusion, szVersion11, NULL, &hfusion11 ))
78 pCreateAssemblyCacheNet11 = (void *)GetProcAddress( hfusion11, "CreateAssemblyCache" );
80 if (!pLoadLibraryShim( szFusion, szVersion20, NULL, &hfusion20 ))
81 pCreateAssemblyCacheNet20 = (void *)GetProcAddress( hfusion20, "CreateAssemblyCache" );
83 if (!pLoadLibraryShim( szFusion, szVersion40, NULL, &hfusion40 ))
85 pCreateAssemblyCacheNet40 = (void *)GetProcAddress( hfusion40, "CreateAssemblyCache" );
86 pCreateAssemblyNameObject = (void *)GetProcAddress( hfusion40, "CreateAssemblyNameObject" );
87 pCreateAssemblyEnum = (void *)GetProcAddress( hfusion40, "CreateAssemblyEnum" );
89 return TRUE;
92 BOOL msi_init_assembly_caches( MSIPACKAGE *package )
94 if (!init_function_pointers()) return FALSE;
95 if (pCreateAssemblyCacheSxs( &package->cache_sxs, 0 ) != S_OK) return FALSE;
96 if (pCreateAssemblyCacheNet10) pCreateAssemblyCacheNet10( &package->cache_net[CLR_VERSION_V10], 0 );
97 if (pCreateAssemblyCacheNet11) pCreateAssemblyCacheNet11( &package->cache_net[CLR_VERSION_V11], 0 );
98 if (pCreateAssemblyCacheNet20) pCreateAssemblyCacheNet20( &package->cache_net[CLR_VERSION_V20], 0 );
99 if (pCreateAssemblyCacheNet40) pCreateAssemblyCacheNet40( &package->cache_net[CLR_VERSION_V40], 0 );
100 return TRUE;
103 void msi_destroy_assembly_caches( MSIPACKAGE *package )
105 UINT i;
107 if (package->cache_sxs)
109 IAssemblyCache_Release( package->cache_sxs );
110 package->cache_sxs = NULL;
112 for (i = 0; i < CLR_VERSION_MAX; i++)
114 if (package->cache_net[i])
116 IAssemblyCache_Release( package->cache_net[i] );
117 package->cache_net[i] = NULL;
120 pCreateAssemblyCacheNet10 = NULL;
121 pCreateAssemblyCacheNet11 = NULL;
122 pCreateAssemblyCacheNet20 = NULL;
123 pCreateAssemblyCacheNet40 = NULL;
124 FreeLibrary( hfusion10 );
125 FreeLibrary( hfusion11 );
126 FreeLibrary( hfusion20 );
127 FreeLibrary( hfusion40 );
128 FreeLibrary( hmscoree );
129 FreeLibrary( hsxs );
130 hfusion10 = NULL;
131 hfusion11 = NULL;
132 hfusion20 = NULL;
133 hfusion40 = NULL;
134 hmscoree = NULL;
135 hsxs = NULL;
138 static MSIRECORD *get_assembly_record( MSIPACKAGE *package, const WCHAR *comp )
140 static const WCHAR query[] = {
141 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
142 '`','M','s','i','A','s','s','e','m','b','l','y','`',' ',
143 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
144 ' ','=',' ','\'','%','s','\'',0};
145 MSIQUERY *view;
146 MSIRECORD *rec;
147 UINT r;
149 r = MSI_OpenQuery( package->db, &view, query, comp );
150 if (r != ERROR_SUCCESS)
151 return NULL;
153 r = MSI_ViewExecute( view, NULL );
154 if (r != ERROR_SUCCESS)
156 msiobj_release( &view->hdr );
157 return NULL;
159 r = MSI_ViewFetch( view, &rec );
160 if (r != ERROR_SUCCESS)
162 msiobj_release( &view->hdr );
163 return NULL;
165 if (!MSI_RecordGetString( rec, 4 ))
166 TRACE("component is a global assembly\n");
168 msiobj_release( &view->hdr );
169 return rec;
172 struct assembly_name
174 UINT count;
175 UINT index;
176 WCHAR **attrs;
179 static UINT get_assembly_name_attribute( MSIRECORD *rec, LPVOID param )
181 static const WCHAR fmtW[] = {'%','s','=','"','%','s','"',0};
182 static const WCHAR nameW[] = {'n','a','m','e',0};
183 struct assembly_name *name = param;
184 const WCHAR *attr = MSI_RecordGetString( rec, 2 );
185 const WCHAR *value = MSI_RecordGetString( rec, 3 );
186 int len = strlenW( fmtW ) + strlenW( attr ) + strlenW( value );
188 if (!(name->attrs[name->index] = msi_alloc( len * sizeof(WCHAR) )))
189 return ERROR_OUTOFMEMORY;
191 if (!strcmpiW( attr, nameW )) strcpyW( name->attrs[name->index++], value );
192 else sprintfW( name->attrs[name->index++], fmtW, attr, value );
193 return ERROR_SUCCESS;
196 static WCHAR *get_assembly_display_name( MSIDATABASE *db, const WCHAR *comp, MSIASSEMBLY *assembly )
198 static const WCHAR commaW[] = {',',0};
199 static const WCHAR queryW[] = {
200 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
201 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
202 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
203 ' ','=',' ','\'','%','s','\'',0};
204 struct assembly_name name;
205 WCHAR *display_name = NULL;
206 MSIQUERY *view;
207 UINT i, r;
208 int len;
210 r = MSI_OpenQuery( db, &view, queryW, comp );
211 if (r != ERROR_SUCCESS)
212 return NULL;
214 name.count = 0;
215 name.index = 0;
216 name.attrs = NULL;
217 MSI_IterateRecords( view, &name.count, NULL, NULL );
218 if (!name.count) goto done;
220 name.attrs = msi_alloc( name.count * sizeof(WCHAR *) );
221 if (!name.attrs) goto done;
223 MSI_IterateRecords( view, NULL, get_assembly_name_attribute, &name );
225 len = 0;
226 for (i = 0; i < name.count; i++) len += strlenW( name.attrs[i] ) + 1;
228 display_name = msi_alloc( (len + 1) * sizeof(WCHAR) );
229 if (display_name)
231 display_name[0] = 0;
232 for (i = 0; i < name.count; i++)
234 strcatW( display_name, name.attrs[i] );
235 if (i < name.count - 1) strcatW( display_name, commaW );
239 done:
240 msiobj_release( &view->hdr );
241 if (name.attrs)
243 for (i = 0; i < name.count; i++) msi_free( name.attrs[i] );
244 msi_free( name.attrs );
246 return display_name;
249 static BOOL is_assembly_installed( IAssemblyCache *cache, const WCHAR *display_name )
251 HRESULT hr;
252 ASSEMBLY_INFO info;
254 if (!cache) return FALSE;
256 memset( &info, 0, sizeof(info) );
257 info.cbAssemblyInfo = sizeof(info);
258 hr = IAssemblyCache_QueryAssemblyInfo( cache, 0, display_name, &info );
259 if (hr == S_OK /* sxs version */ || hr == E_NOT_SUFFICIENT_BUFFER)
261 return (info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
263 TRACE("QueryAssemblyInfo returned 0x%08x\n", hr);
264 return FALSE;
267 WCHAR *msi_get_assembly_path( MSIPACKAGE *package, const WCHAR *displayname )
269 HRESULT hr;
270 ASSEMBLY_INFO info;
271 IAssemblyCache *cache = package->cache_net[CLR_VERSION_V40];
273 if (!cache) return NULL;
275 memset( &info, 0, sizeof(info) );
276 info.cbAssemblyInfo = sizeof(info);
277 hr = IAssemblyCache_QueryAssemblyInfo( cache, 0, displayname, &info );
278 if (hr != E_NOT_SUFFICIENT_BUFFER) return NULL;
280 if (!(info.pszCurrentAssemblyPathBuf = msi_alloc( info.cchBuf * sizeof(WCHAR) ))) return NULL;
282 hr = IAssemblyCache_QueryAssemblyInfo( cache, 0, displayname, &info );
283 if (FAILED( hr ))
285 msi_free( info.pszCurrentAssemblyPathBuf );
286 return NULL;
288 TRACE("returning %s\n", debugstr_w(info.pszCurrentAssemblyPathBuf));
289 return info.pszCurrentAssemblyPathBuf;
292 IAssemblyEnum *msi_create_assembly_enum( MSIPACKAGE *package, const WCHAR *displayname )
294 HRESULT hr;
295 IAssemblyName *name;
296 IAssemblyEnum *ret;
297 WCHAR *str;
298 UINT len = 0;
300 if (!pCreateAssemblyNameObject || !pCreateAssemblyEnum) return NULL;
302 hr = pCreateAssemblyNameObject( &name, displayname, CANOF_PARSE_DISPLAY_NAME, NULL );
303 if (FAILED( hr )) return NULL;
305 hr = IAssemblyName_GetName( name, &len, NULL );
306 if (hr != E_NOT_SUFFICIENT_BUFFER || !(str = msi_alloc( len * sizeof(WCHAR) )))
308 IAssemblyName_Release( name );
309 return NULL;
312 hr = IAssemblyName_GetName( name, &len, str );
313 IAssemblyName_Release( name );
314 if (FAILED( hr ))
316 msi_free( str );
317 return NULL;
320 hr = pCreateAssemblyNameObject( &name, str, 0, NULL );
321 msi_free( str );
322 if (FAILED( hr )) return NULL;
324 hr = pCreateAssemblyEnum( &ret, NULL, name, ASM_CACHE_GAC, NULL );
325 IAssemblyName_Release( name );
326 if (FAILED( hr )) return NULL;
328 return ret;
331 static const WCHAR clr_version_v10[] = {'v','1','.','0','.','3','7','0','5',0};
332 static const WCHAR clr_version_v11[] = {'v','1','.','1','.','4','3','2','2',0};
333 static const WCHAR clr_version_v20[] = {'v','2','.','0','.','5','0','7','2','7',0};
334 static const WCHAR clr_version_v40[] = {'v','4','.','0','.','3','0','3','1','9',0};
335 static const WCHAR clr_version_unknown[] = {'u','n','k','n','o','w','n',0};
337 static const WCHAR *clr_version[] =
339 clr_version_v10,
340 clr_version_v11,
341 clr_version_v20,
342 clr_version_v40
345 static const WCHAR *get_clr_version_str( enum clr_version version )
347 if (version >= sizeof(clr_version)/sizeof(clr_version[0])) return clr_version_unknown;
348 return clr_version[version];
351 /* assembly caches must be initialized */
352 MSIASSEMBLY *msi_load_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
354 MSIRECORD *rec;
355 MSIASSEMBLY *a;
357 if (!(rec = get_assembly_record( package, comp->Component ))) return NULL;
358 if (!(a = msi_alloc_zero( sizeof(MSIASSEMBLY) )))
360 msiobj_release( &rec->hdr );
361 return NULL;
363 a->feature = strdupW( MSI_RecordGetString( rec, 2 ) );
364 TRACE("feature %s\n", debugstr_w(a->feature));
366 a->manifest = strdupW( MSI_RecordGetString( rec, 3 ) );
367 TRACE("manifest %s\n", debugstr_w(a->manifest));
369 a->application = strdupW( MSI_RecordGetString( rec, 4 ) );
370 TRACE("application %s\n", debugstr_w(a->application));
372 a->attributes = MSI_RecordGetInteger( rec, 5 );
373 TRACE("attributes %u\n", a->attributes);
375 if (!(a->display_name = get_assembly_display_name( package->db, comp->Component, a )))
377 WARN("can't get display name\n");
378 msiobj_release( &rec->hdr );
379 msi_free( a->feature );
380 msi_free( a->manifest );
381 msi_free( a->application );
382 msi_free( a );
383 return NULL;
385 TRACE("display name %s\n", debugstr_w(a->display_name));
387 if (a->application)
389 /* We can't check the manifest here because the target path may still change.
390 So we assume that the assembly is not installed and lean on the InstallFiles
391 action to determine which files need to be installed.
393 a->installed = FALSE;
395 else
397 if (a->attributes == msidbAssemblyAttributesWin32)
398 a->installed = is_assembly_installed( package->cache_sxs, a->display_name );
399 else
401 UINT i;
402 for (i = 0; i < CLR_VERSION_MAX; i++)
404 a->clr_version[i] = is_assembly_installed( package->cache_net[i], a->display_name );
405 if (a->clr_version[i])
407 TRACE("runtime version %s\n", debugstr_w(get_clr_version_str( i )));
408 a->installed = TRUE;
409 break;
414 TRACE("assembly is %s\n", a->installed ? "installed" : "not installed");
415 msiobj_release( &rec->hdr );
416 return a;
419 static enum clr_version get_clr_version( const WCHAR *filename )
421 DWORD len;
422 HRESULT hr;
423 enum clr_version version = CLR_VERSION_V11;
424 WCHAR *strW;
426 if (!pGetFileVersion) return CLR_VERSION_V10;
428 hr = pGetFileVersion( filename, NULL, 0, &len );
429 if (hr != E_NOT_SUFFICIENT_BUFFER) return CLR_VERSION_V11;
430 if ((strW = msi_alloc( len * sizeof(WCHAR) )))
432 hr = pGetFileVersion( filename, strW, len, &len );
433 if (hr == S_OK)
435 UINT i;
436 for (i = 0; i < CLR_VERSION_MAX; i++)
437 if (!strcmpW( strW, clr_version[i] )) version = i;
439 msi_free( strW );
441 return version;
444 UINT msi_install_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
446 HRESULT hr;
447 const WCHAR *manifest;
448 IAssemblyCache *cache;
449 MSIASSEMBLY *assembly = comp->assembly;
450 MSIFEATURE *feature = NULL;
452 if (comp->assembly->feature)
453 feature = msi_get_loaded_feature( package, comp->assembly->feature );
455 if (assembly->application)
457 if (feature) feature->Action = INSTALLSTATE_LOCAL;
458 return ERROR_SUCCESS;
460 if (assembly->attributes == msidbAssemblyAttributesWin32)
462 if (!assembly->manifest)
464 WARN("no manifest\n");
465 return ERROR_FUNCTION_FAILED;
467 manifest = msi_get_loaded_file( package, assembly->manifest )->TargetPath;
468 cache = package->cache_sxs;
470 else
472 manifest = msi_get_loaded_file( package, comp->KeyPath )->TargetPath;
473 cache = package->cache_net[get_clr_version( manifest )];
474 if (!cache) return ERROR_SUCCESS;
476 TRACE("installing assembly %s\n", debugstr_w(manifest));
478 hr = IAssemblyCache_InstallAssembly( cache, 0, manifest, NULL );
479 if (hr != S_OK)
481 ERR("Failed to install assembly %s (0x%08x)\n", debugstr_w(manifest), hr);
482 return ERROR_FUNCTION_FAILED;
484 if (feature) feature->Action = INSTALLSTATE_LOCAL;
485 assembly->installed = TRUE;
486 return ERROR_SUCCESS;
489 UINT msi_uninstall_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
491 HRESULT hr;
492 IAssemblyCache *cache;
493 MSIASSEMBLY *assembly = comp->assembly;
494 MSIFEATURE *feature = NULL;
496 if (comp->assembly->feature)
497 feature = msi_get_loaded_feature( package, comp->assembly->feature );
499 if (assembly->application)
501 if (feature) feature->Action = INSTALLSTATE_ABSENT;
502 return ERROR_SUCCESS;
504 TRACE("removing %s\n", debugstr_w(assembly->display_name));
506 if (assembly->attributes == msidbAssemblyAttributesWin32)
508 cache = package->cache_sxs;
509 hr = IAssemblyCache_UninstallAssembly( cache, 0, assembly->display_name, NULL, NULL );
510 if (FAILED( hr )) WARN("failed to uninstall assembly 0x%08x\n", hr);
512 else
514 unsigned int i;
515 for (i = 0; i < CLR_VERSION_MAX; i++)
517 if (!assembly->clr_version[i]) continue;
518 cache = package->cache_net[i];
519 if (cache)
521 hr = IAssemblyCache_UninstallAssembly( cache, 0, assembly->display_name, NULL, NULL );
522 if (FAILED( hr )) WARN("failed to uninstall assembly 0x%08x\n", hr);
526 if (feature) feature->Action = INSTALLSTATE_ABSENT;
527 assembly->installed = FALSE;
528 return ERROR_SUCCESS;
531 static WCHAR *build_local_assembly_path( const WCHAR *filename )
533 UINT i;
534 WCHAR *ret;
536 if (!(ret = msi_alloc( (strlenW( filename ) + 1) * sizeof(WCHAR) )))
537 return NULL;
539 for (i = 0; filename[i]; i++)
541 if (filename[i] == '\\' || filename[i] == '/') ret[i] = '|';
542 else ret[i] = filename[i];
544 ret[i] = 0;
545 return ret;
548 static LONG open_assemblies_key( UINT context, BOOL win32, HKEY *hkey )
550 static const WCHAR path_win32[] =
551 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
552 '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};
553 static const WCHAR path_dotnet[] =
554 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
555 'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',0};
556 static const WCHAR classes_path_win32[] =
557 {'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};
558 static const WCHAR classes_path_dotnet[] =
559 {'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',0};
560 HKEY root;
561 const WCHAR *path;
563 if (context == MSIINSTALLCONTEXT_MACHINE)
565 root = HKEY_CLASSES_ROOT;
566 if (win32) path = classes_path_win32;
567 else path = classes_path_dotnet;
569 else
571 root = HKEY_CURRENT_USER;
572 if (win32) path = path_win32;
573 else path = path_dotnet;
575 return RegCreateKeyW( root, path, hkey );
578 static LONG open_local_assembly_key( UINT context, BOOL win32, const WCHAR *filename, HKEY *hkey )
580 LONG res;
581 HKEY root;
582 WCHAR *path;
584 if (!(path = build_local_assembly_path( filename )))
585 return ERROR_OUTOFMEMORY;
587 if ((res = open_assemblies_key( context, win32, &root )))
589 msi_free( path );
590 return res;
592 res = RegCreateKeyW( root, path, hkey );
593 RegCloseKey( root );
594 msi_free( path );
595 return res;
598 static LONG delete_local_assembly_key( UINT context, BOOL win32, const WCHAR *filename )
600 LONG res;
601 HKEY root;
602 WCHAR *path;
604 if (!(path = build_local_assembly_path( filename )))
605 return ERROR_OUTOFMEMORY;
607 if ((res = open_assemblies_key( context, win32, &root )))
609 msi_free( path );
610 return res;
612 res = RegDeleteKeyW( root, path );
613 RegCloseKey( root );
614 msi_free( path );
615 return res;
618 static LONG open_global_assembly_key( UINT context, BOOL win32, HKEY *hkey )
620 static const WCHAR path_win32[] =
621 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
622 'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',
623 'G','l','o','b','a','l',0};
624 static const WCHAR path_dotnet[] =
625 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
626 'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',
627 'G','l','o','b','a','l',0};
628 static const WCHAR classes_path_win32[] =
629 {'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',
630 'G','l','o','b','a','l',0};
631 static const WCHAR classes_path_dotnet[] =
632 {'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};
633 HKEY root;
634 const WCHAR *path;
636 if (context == MSIINSTALLCONTEXT_MACHINE)
638 root = HKEY_CLASSES_ROOT;
639 if (win32) path = classes_path_win32;
640 else path = classes_path_dotnet;
642 else
644 root = HKEY_CURRENT_USER;
645 if (win32) path = path_win32;
646 else path = path_dotnet;
648 return RegCreateKeyW( root, path, hkey );
651 UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
653 MSICOMPONENT *comp;
655 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
657 LONG res;
658 HKEY hkey;
659 GUID guid;
660 DWORD size;
661 WCHAR buffer[43];
662 MSIRECORD *uirow;
663 MSIASSEMBLY *assembly = comp->assembly;
664 BOOL win32;
666 if (!assembly || !comp->ComponentId) continue;
668 comp->Action = msi_get_component_action( package, comp );
669 if (comp->Action != INSTALLSTATE_LOCAL)
671 TRACE("component not scheduled for installation %s\n", debugstr_w(comp->Component));
672 continue;
674 TRACE("publishing %s\n", debugstr_w(comp->Component));
676 CLSIDFromString( package->ProductCode, &guid );
677 encode_base85_guid( &guid, buffer );
678 buffer[20] = '>';
679 CLSIDFromString( comp->ComponentId, &guid );
680 encode_base85_guid( &guid, buffer + 21 );
681 buffer[42] = 0;
683 win32 = assembly->attributes & msidbAssemblyAttributesWin32;
684 if (assembly->application)
686 MSIFILE *file = msi_get_loaded_file( package, assembly->application );
687 if ((res = open_local_assembly_key( package->Context, win32, file->TargetPath, &hkey )))
689 WARN("failed to open local assembly key %d\n", res);
690 return ERROR_FUNCTION_FAILED;
693 else
695 if ((res = open_global_assembly_key( package->Context, win32, &hkey )))
697 WARN("failed to open global assembly key %d\n", res);
698 return ERROR_FUNCTION_FAILED;
701 size = sizeof(buffer);
702 if ((res = RegSetValueExW( hkey, assembly->display_name, 0, REG_MULTI_SZ, (const BYTE *)buffer, size )))
704 WARN("failed to set assembly value %d\n", res);
706 RegCloseKey( hkey );
708 uirow = MSI_CreateRecord( 2 );
709 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
710 msi_ui_actiondata( package, szMsiPublishAssemblies, uirow );
711 msiobj_release( &uirow->hdr );
713 return ERROR_SUCCESS;
716 UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
718 MSICOMPONENT *comp;
720 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
722 LONG res;
723 MSIRECORD *uirow;
724 MSIASSEMBLY *assembly = comp->assembly;
725 BOOL win32;
727 if (!assembly || !comp->ComponentId) continue;
729 comp->Action = msi_get_component_action( package, comp );
730 if (comp->Action != INSTALLSTATE_ABSENT)
732 TRACE("component not scheduled for removal %s\n", debugstr_w(comp->Component));
733 continue;
735 TRACE("unpublishing %s\n", debugstr_w(comp->Component));
737 win32 = assembly->attributes & msidbAssemblyAttributesWin32;
738 if (assembly->application)
740 MSIFILE *file = msi_get_loaded_file( package, assembly->application );
741 if ((res = delete_local_assembly_key( package->Context, win32, file->TargetPath )))
742 WARN("failed to delete local assembly key %d\n", res);
744 else
746 HKEY hkey;
747 if ((res = open_global_assembly_key( package->Context, win32, &hkey )))
748 WARN("failed to delete global assembly key %d\n", res);
749 else
751 if ((res = RegDeleteValueW( hkey, assembly->display_name )))
752 WARN("failed to delete global assembly value %d\n", res);
753 RegCloseKey( hkey );
757 uirow = MSI_CreateRecord( 2 );
758 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
759 msi_ui_actiondata( package, szMsiPublishAssemblies, uirow );
760 msiobj_release( &uirow->hdr );
762 return ERROR_SUCCESS;