msi: Implement deferral for standard and custom actions.
[wine.git] / dlls / msi / assembly.c
blob59fd332d253ade694e933c9a06d223ce2eaffd59
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 if (package->script == SCRIPT_NONE)
656 return msi_schedule_action(package, SCRIPT_INSTALL, szMsiPublishAssemblies);
658 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
660 LONG res;
661 HKEY hkey;
662 GUID guid;
663 DWORD size;
664 WCHAR buffer[43];
665 MSIRECORD *uirow;
666 MSIASSEMBLY *assembly = comp->assembly;
667 BOOL win32;
669 if (!assembly || !comp->ComponentId) continue;
671 comp->Action = msi_get_component_action( package, comp );
672 if (comp->Action != INSTALLSTATE_LOCAL)
674 TRACE("component not scheduled for installation %s\n", debugstr_w(comp->Component));
675 continue;
677 TRACE("publishing %s\n", debugstr_w(comp->Component));
679 CLSIDFromString( package->ProductCode, &guid );
680 encode_base85_guid( &guid, buffer );
681 buffer[20] = '>';
682 CLSIDFromString( comp->ComponentId, &guid );
683 encode_base85_guid( &guid, buffer + 21 );
684 buffer[42] = 0;
686 win32 = assembly->attributes & msidbAssemblyAttributesWin32;
687 if (assembly->application)
689 MSIFILE *file = msi_get_loaded_file( package, assembly->application );
690 if ((res = open_local_assembly_key( package->Context, win32, file->TargetPath, &hkey )))
692 WARN("failed to open local assembly key %d\n", res);
693 return ERROR_FUNCTION_FAILED;
696 else
698 if ((res = open_global_assembly_key( package->Context, win32, &hkey )))
700 WARN("failed to open global assembly key %d\n", res);
701 return ERROR_FUNCTION_FAILED;
704 size = sizeof(buffer);
705 if ((res = RegSetValueExW( hkey, assembly->display_name, 0, REG_MULTI_SZ, (const BYTE *)buffer, size )))
707 WARN("failed to set assembly value %d\n", res);
709 RegCloseKey( hkey );
711 uirow = MSI_CreateRecord( 2 );
712 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
713 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
714 msiobj_release( &uirow->hdr );
716 return ERROR_SUCCESS;
719 UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
721 MSICOMPONENT *comp;
723 if (package->script == SCRIPT_NONE)
724 return msi_schedule_action(package, SCRIPT_INSTALL, szMsiUnpublishAssemblies);
726 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
728 LONG res;
729 MSIRECORD *uirow;
730 MSIASSEMBLY *assembly = comp->assembly;
731 BOOL win32;
733 if (!assembly || !comp->ComponentId) continue;
735 comp->Action = msi_get_component_action( package, comp );
736 if (comp->Action != INSTALLSTATE_ABSENT)
738 TRACE("component not scheduled for removal %s\n", debugstr_w(comp->Component));
739 continue;
741 TRACE("unpublishing %s\n", debugstr_w(comp->Component));
743 win32 = assembly->attributes & msidbAssemblyAttributesWin32;
744 if (assembly->application)
746 MSIFILE *file = msi_get_loaded_file( package, assembly->application );
747 if ((res = delete_local_assembly_key( package->Context, win32, file->TargetPath )))
748 WARN("failed to delete local assembly key %d\n", res);
750 else
752 HKEY hkey;
753 if ((res = open_global_assembly_key( package->Context, win32, &hkey )))
754 WARN("failed to delete global assembly key %d\n", res);
755 else
757 if ((res = RegDeleteValueW( hkey, assembly->display_name )))
758 WARN("failed to delete global assembly value %d\n", res);
759 RegCloseKey( hkey );
763 uirow = MSI_CreateRecord( 2 );
764 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
765 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
766 msiobj_release( &uirow->hdr );
768 return ERROR_SUCCESS;