1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
3 *
4 * Copyright 2010 Hans Leidekker for CodeWeavers
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winreg.h"
28 #include "wine/debug.h"
29 #include "msipriv.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(msi);
32
load_fusion_dlls(MSIPACKAGE * package)33 static void load_fusion_dlls( MSIPACKAGE *package )
34 {
35 HRESULT (WINAPI *pLoadLibraryShim)( const WCHAR *, const WCHAR *, void *, HMODULE * );
36 WCHAR path[MAX_PATH];
37 DWORD len = GetSystemDirectoryW( path, MAX_PATH );
38
39 lstrcpyW( path + len, L"\\mscoree.dll" );
40 if (!package->hmscoree && !(package->hmscoree = LoadLibraryW( path ))) return;
41 if (!(pLoadLibraryShim = (void *)GetProcAddress( package->hmscoree, "LoadLibraryShim" )))
42 {
43 FreeLibrary( package->hmscoree );
44 package->hmscoree = NULL;
45 return;
46 }
47
48 if (!package->hfusion10) pLoadLibraryShim( L"fusion.dll", L"v1.0.3705", NULL, &package->hfusion10 );
49 if (!package->hfusion11) pLoadLibraryShim( L"fusion.dll", L"v1.1.4322", NULL, &package->hfusion11 );
50 if (!package->hfusion20) pLoadLibraryShim( L"fusion.dll", L"v2.0.50727", NULL, &package->hfusion20 );
51 if (!package->hfusion40) pLoadLibraryShim( L"fusion.dll", L"v4.0.30319", NULL, &package->hfusion40 );
52 }
53
init_assembly_caches(MSIPACKAGE * package)54 static BOOL init_assembly_caches( MSIPACKAGE *package )
55 {
56 HRESULT (WINAPI *pCreateAssemblyCache)( IAssemblyCache **, DWORD );
57
58 if (!package->cache_sxs && CreateAssemblyCache( &package->cache_sxs, 0 ) != S_OK) return FALSE;
59
60 load_fusion_dlls( package );
61 package->pGetFileVersion = (void *)GetProcAddress( package->hmscoree, "GetFileVersion" ); /* missing from v1.0.3705 */
62
63 if (package->hfusion10 && !package->cache_net[CLR_VERSION_V10])
64 {
65 pCreateAssemblyCache = (void *)GetProcAddress( package->hfusion10, "CreateAssemblyCache" );
66 pCreateAssemblyCache( &package->cache_net[CLR_VERSION_V10], 0 );
67 }
68 if (package->hfusion11 && !package->cache_net[CLR_VERSION_V11])
69 {
70 pCreateAssemblyCache = (void *)GetProcAddress( package->hfusion11, "CreateAssemblyCache" );
71 pCreateAssemblyCache( &package->cache_net[CLR_VERSION_V11], 0 );
72 }
73 if (package->hfusion20 && !package->cache_net[CLR_VERSION_V20])
74 {
75 pCreateAssemblyCache = (void *)GetProcAddress( package->hfusion20, "CreateAssemblyCache" );
76 pCreateAssemblyCache( &package->cache_net[CLR_VERSION_V20], 0 );
77 }
78 if (package->hfusion40 && !package->cache_net[CLR_VERSION_V40])
79 {
80 pCreateAssemblyCache = (void *)GetProcAddress( package->hfusion40, "CreateAssemblyCache" );
81 pCreateAssemblyCache( &package->cache_net[CLR_VERSION_V40], 0 );
82 package->pCreateAssemblyNameObject = (void *)GetProcAddress( package->hfusion40, "CreateAssemblyNameObject" );
83 package->pCreateAssemblyEnum = (void *)GetProcAddress( package->hfusion40, "CreateAssemblyEnum" );
84 }
85
86 return TRUE;
87 }
88
msi_destroy_assembly_caches(MSIPACKAGE * package)89 void msi_destroy_assembly_caches( MSIPACKAGE *package )
90 {
91 UINT i;
92
93 if (package->cache_sxs)
94 {
95 IAssemblyCache_Release( package->cache_sxs );
96 package->cache_sxs = NULL;
97 }
98 for (i = 0; i < CLR_VERSION_MAX; i++)
99 {
100 if (package->cache_net[i])
101 {
102 IAssemblyCache_Release( package->cache_net[i] );
103 package->cache_net[i] = NULL;
104 }
105 }
106 package->pGetFileVersion = NULL;
107 package->pCreateAssemblyNameObject = NULL;
108 package->pCreateAssemblyEnum = NULL;
109 FreeLibrary( package->hfusion10 );
110 FreeLibrary( package->hfusion11 );
111 FreeLibrary( package->hfusion20 );
112 FreeLibrary( package->hfusion40 );
113 FreeLibrary( package->hmscoree );
114 package->hfusion10 = NULL;
115 package->hfusion11 = NULL;
116 package->hfusion20 = NULL;
117 package->hfusion40 = NULL;
118 package->hmscoree = NULL;
119 }
120
get_assembly_record(MSIPACKAGE * package,const WCHAR * comp)121 static MSIRECORD *get_assembly_record( MSIPACKAGE *package, const WCHAR *comp )
122 {
123 MSIQUERY *view;
124 MSIRECORD *rec;
125 UINT r;
126
127 r = MSI_OpenQuery( package->db, &view, L"SELECT * FROM `MsiAssembly` WHERE `Component_` = '%s'", comp );
128 if (r != ERROR_SUCCESS)
129 return NULL;
130
131 r = MSI_ViewExecute( view, NULL );
132 if (r != ERROR_SUCCESS)
133 {
134 msiobj_release( &view->hdr );
135 return NULL;
136 }
137 r = MSI_ViewFetch( view, &rec );
138 if (r != ERROR_SUCCESS)
139 {
140 msiobj_release( &view->hdr );
141 return NULL;
142 }
143 if (!MSI_RecordGetString( rec, 4 ))
144 TRACE("component is a global assembly\n");
145
146 msiobj_release( &view->hdr );
147 return rec;
148 }
149
150 struct assembly_name
151 {
152 DWORD count;
153 UINT index;
154 WCHAR **attrs;
155 };
156
get_assembly_name_attribute(MSIRECORD * rec,LPVOID param)157 static UINT get_assembly_name_attribute( MSIRECORD *rec, LPVOID param )
158 {
159 struct assembly_name *name = param;
160 const WCHAR *attr = MSI_RecordGetString( rec, 2 );
161 const WCHAR *value = MSI_RecordGetString( rec, 3 );
162 int len = lstrlenW( L"%s=\"%s\"" ) + lstrlenW( attr ) + lstrlenW( value );
163
164 if (!(name->attrs[name->index] = malloc( len * sizeof(WCHAR) )))
165 return ERROR_OUTOFMEMORY;
166
167 if (!wcsicmp( attr, L"name" )) lstrcpyW( name->attrs[name->index++], value );
168 else swprintf( name->attrs[name->index++], len, L"%s=\"%s\"", attr, value );
169 return ERROR_SUCCESS;
170 }
171
get_assembly_display_name(MSIDATABASE * db,const WCHAR * comp,MSIASSEMBLY * assembly)172 static WCHAR *get_assembly_display_name( MSIDATABASE *db, const WCHAR *comp, MSIASSEMBLY *assembly )
173 {
174 struct assembly_name name;
175 WCHAR *display_name = NULL;
176 MSIQUERY *view;
177 UINT i, r;
178 int len;
179
180 r = MSI_OpenQuery( db, &view, L"SELECT * FROM `MsiAssemblyName` WHERE `Component_` = '%s'", comp );
181 if (r != ERROR_SUCCESS)
182 return NULL;
183
184 name.count = 0;
185 name.index = 0;
186 name.attrs = NULL;
187 MSI_IterateRecords( view, &name.count, NULL, NULL );
188 if (!name.count) goto done;
189
190 name.attrs = malloc( name.count * sizeof(WCHAR *) );
191 if (!name.attrs) goto done;
192
193 MSI_IterateRecords( view, NULL, get_assembly_name_attribute, &name );
194
195 len = 0;
196 for (i = 0; i < name.count; i++) len += lstrlenW( name.attrs[i] ) + 1;
197
198 display_name = malloc( (len + 1) * sizeof(WCHAR) );
199 if (display_name)
200 {
201 display_name[0] = 0;
202 for (i = 0; i < name.count; i++)
203 {
204 lstrcatW( display_name, name.attrs[i] );
205 if (i < name.count - 1) lstrcatW( display_name, L"," );
206 }
207 }
208
209 done:
210 msiobj_release( &view->hdr );
211 if (name.attrs)
212 {
213 for (i = 0; i < name.count; i++) free( name.attrs[i] );
214 free( name.attrs );
215 }
216 return display_name;
217 }
218
msi_get_assembly_path(MSIPACKAGE * package,const WCHAR * displayname)219 WCHAR *msi_get_assembly_path( MSIPACKAGE *package, const WCHAR *displayname )
220 {
221 HRESULT hr;
222 ASSEMBLY_INFO info;
223 IAssemblyCache *cache;
224
225 if (!init_assembly_caches( package ) || !(cache = package->cache_net[CLR_VERSION_V40])) return NULL;
226
227 memset( &info, 0, sizeof(info) );
228 info.cbAssemblyInfo = sizeof(info);
229 hr = IAssemblyCache_QueryAssemblyInfo( cache, 0, displayname, &info );
230 if (hr != E_NOT_SUFFICIENT_BUFFER) return NULL;
231
232 if (!(info.pszCurrentAssemblyPathBuf = malloc( info.cchBuf * sizeof(WCHAR) ))) return NULL;
233
234 hr = IAssemblyCache_QueryAssemblyInfo( cache, 0, displayname, &info );
235 if (FAILED( hr ))
236 {
237 free( info.pszCurrentAssemblyPathBuf );
238 return NULL;
239 }
240 TRACE("returning %s\n", debugstr_w(info.pszCurrentAssemblyPathBuf));
241 return info.pszCurrentAssemblyPathBuf;
242 }
243
msi_create_assembly_enum(MSIPACKAGE * package,const WCHAR * displayname)244 IAssemblyEnum *msi_create_assembly_enum( MSIPACKAGE *package, const WCHAR *displayname )
245 {
246 HRESULT hr;
247 IAssemblyName *name;
248 IAssemblyEnum *ret;
249 WCHAR *str;
250 DWORD len = 0;
251
252 if (!init_assembly_caches( package ) || !package->pCreateAssemblyNameObject || !package->pCreateAssemblyEnum)
253 return NULL;
254
255 hr = package->pCreateAssemblyNameObject( &name, displayname, CANOF_PARSE_DISPLAY_NAME, NULL );
256 if (FAILED( hr )) return NULL;
257
258 hr = IAssemblyName_GetName( name, &len, NULL );
259 if (hr != E_NOT_SUFFICIENT_BUFFER || !(str = malloc( len * sizeof(WCHAR) )))
260 {
261 IAssemblyName_Release( name );
262 return NULL;
263 }
264
265 hr = IAssemblyName_GetName( name, &len, str );
266 IAssemblyName_Release( name );
267 if (FAILED( hr ))
268 {
269 free( str );
270 return NULL;
271 }
272
273 hr = package->pCreateAssemblyNameObject( &name, str, 0, NULL );
274 free( str );
275 if (FAILED( hr )) return NULL;
276
277 hr = package->pCreateAssemblyEnum( &ret, NULL, name, ASM_CACHE_GAC, NULL );
278 IAssemblyName_Release( name );
279 if (FAILED( hr )) return NULL;
280
281 return ret;
282 }
283
284 static const WCHAR *clr_version[] =
285 {
286 L"v1.0.3705",
287 L"v1.2.4322",
288 L"v2.0.50727",
289 L"v4.0.30319"
290 };
291
msi_load_assembly(MSIPACKAGE * package,MSICOMPONENT * comp)292 MSIASSEMBLY *msi_load_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
293 {
294 MSIRECORD *rec;
295 MSIASSEMBLY *a;
296
297 if (!(rec = get_assembly_record( package, comp->Component ))) return NULL;
298 if (!(a = calloc( 1, sizeof(MSIASSEMBLY) )))
299 {
300 msiobj_release( &rec->hdr );
301 return NULL;
302 }
303 a->feature = wcsdup( MSI_RecordGetString( rec, 2 ) );
304 TRACE("feature %s\n", debugstr_w(a->feature));
305
306 a->manifest = wcsdup( MSI_RecordGetString( rec, 3 ) );
307 TRACE("manifest %s\n", debugstr_w(a->manifest));
308
309 a->application = wcsdup( MSI_RecordGetString( rec, 4 ) );
310 TRACE("application %s\n", debugstr_w(a->application));
311
312 a->attributes = MSI_RecordGetInteger( rec, 5 );
313 TRACE( "attributes %lu\n", a->attributes );
314
315 if (!(a->display_name = get_assembly_display_name( package->db, comp->Component, a )))
316 {
317 WARN("can't get display name\n");
318 msiobj_release( &rec->hdr );
319 free( a->feature );
320 free( a->manifest );
321 free( a->application );
322 free( a );
323 return NULL;
324 }
325 TRACE("display name %s\n", debugstr_w(a->display_name));
326
327 msiobj_release( &rec->hdr );
328 return a;
329 }
330
get_clr_version(MSIPACKAGE * package,const WCHAR * filename)331 static enum clr_version get_clr_version( MSIPACKAGE *package, const WCHAR *filename )
332 {
333 DWORD len;
334 HRESULT hr;
335 enum clr_version version = CLR_VERSION_V11;
336 WCHAR *strW;
337
338 if (!package->pGetFileVersion) return CLR_VERSION_V10;
339
340 hr = package->pGetFileVersion( filename, NULL, 0, &len );
341 if (hr != E_NOT_SUFFICIENT_BUFFER) return CLR_VERSION_V11;
342 if ((strW = malloc( len * sizeof(WCHAR) )))
343 {
344 hr = package->pGetFileVersion( filename, strW, len, &len );
345 if (hr == S_OK)
346 {
347 UINT i;
348 for (i = 0; i < CLR_VERSION_MAX; i++)
349 if (!wcscmp( strW, clr_version[i] )) version = i;
350 }
351 free( strW );
352 }
353 return version;
354 }
355
msi_install_assembly(MSIPACKAGE * package,MSICOMPONENT * comp)356 UINT msi_install_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
357 {
358 HRESULT hr;
359 const WCHAR *manifest;
360 IAssemblyCache *cache;
361 MSIASSEMBLY *assembly = comp->assembly;
362 MSIFEATURE *feature = NULL;
363
364 if (!init_assembly_caches( package )) return ERROR_FUNCTION_FAILED;
365
366 if (comp->assembly->feature)
367 feature = msi_get_loaded_feature( package, comp->assembly->feature );
368
369 if (assembly->application)
370 {
371 if (feature) feature->Action = INSTALLSTATE_LOCAL;
372 return ERROR_SUCCESS;
373 }
374 if (assembly->attributes == msidbAssemblyAttributesWin32)
375 {
376 if (!assembly->manifest)
377 {
378 WARN("no manifest\n");
379 return ERROR_FUNCTION_FAILED;
380 }
381 manifest = msi_get_loaded_file( package, assembly->manifest )->TargetPath;
382 cache = package->cache_sxs;
383 }
384 else
385 {
386 manifest = msi_get_loaded_file( package, comp->KeyPath )->TargetPath;
387 cache = package->cache_net[get_clr_version( package, manifest )];
388 if (!cache) return ERROR_SUCCESS;
389 }
390 TRACE("installing assembly %s\n", debugstr_w(manifest));
391
392 hr = IAssemblyCache_InstallAssembly( cache, 0, manifest, NULL );
393 if (hr != S_OK)
394 {
395 ERR( "failed to install assembly %s (%#lx)\n", debugstr_w(manifest), hr );
396 return ERROR_FUNCTION_FAILED;
397 }
398 if (feature) feature->Action = INSTALLSTATE_LOCAL;
399 return ERROR_SUCCESS;
400 }
401
msi_uninstall_assembly(MSIPACKAGE * package,MSICOMPONENT * comp)402 UINT msi_uninstall_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
403 {
404 HRESULT hr;
405 IAssemblyCache *cache;
406 MSIASSEMBLY *assembly = comp->assembly;
407 MSIFEATURE *feature = NULL;
408
409 if (!init_assembly_caches( package )) return ERROR_FUNCTION_FAILED;
410
411 if (comp->assembly->feature)
412 feature = msi_get_loaded_feature( package, comp->assembly->feature );
413
414 if (assembly->application)
415 {
416 if (feature) feature->Action = INSTALLSTATE_ABSENT;
417 return ERROR_SUCCESS;
418 }
419 TRACE("removing %s\n", debugstr_w(assembly->display_name));
420
421 if (assembly->attributes == msidbAssemblyAttributesWin32)
422 {
423 cache = package->cache_sxs;
424 hr = IAssemblyCache_UninstallAssembly( cache, 0, assembly->display_name, NULL, NULL );
425 if (FAILED( hr )) WARN( "failed to uninstall assembly %#lx\n", hr );
426 }
427 else
428 {
429 unsigned int i;
430 for (i = 0; i < CLR_VERSION_MAX; i++)
431 {
432 if (!assembly->clr_version[i]) continue;
433 cache = package->cache_net[i];
434 if (cache)
435 {
436 hr = IAssemblyCache_UninstallAssembly( cache, 0, assembly->display_name, NULL, NULL );
437 if (FAILED( hr )) WARN( "failed to uninstall assembly %#lx\n", hr );
438 }
439 }
440 }
441 if (feature) feature->Action = INSTALLSTATE_ABSENT;
442 return ERROR_SUCCESS;
443 }
444
build_local_assembly_path(const WCHAR * filename)445 static WCHAR *build_local_assembly_path( const WCHAR *filename )
446 {
447 UINT i;
448 WCHAR *ret;
449
450 if (!(ret = malloc( (wcslen( filename ) + 1) * sizeof(WCHAR) )))
451 return NULL;
452
453 for (i = 0; filename[i]; i++)
454 {
455 if (filename[i] == '\\' || filename[i] == '/') ret[i] = '|';
456 else ret[i] = filename[i];
457 }
458 ret[i] = 0;
459 return ret;
460 }
461
open_assemblies_key(UINT context,BOOL win32,HKEY * hkey)462 static LONG open_assemblies_key( UINT context, BOOL win32, HKEY *hkey )
463 {
464 HKEY root;
465 const WCHAR *path;
466
467 if (context == MSIINSTALLCONTEXT_MACHINE)
468 {
469 root = HKEY_CLASSES_ROOT;
470 if (win32) path = L"Installer\\Win32Assemblies\\";
471 else path = L"Installer\\Assemblies\\";
472 }
473 else
474 {
475 root = HKEY_CURRENT_USER;
476 if (win32) path = L"Software\\Microsoft\\Installer\\Win32Assemblies\\";
477 else path = L"Software\\Microsoft\\Installer\\Assemblies\\";
478 }
479 return RegCreateKeyW( root, path, hkey );
480 }
481
open_local_assembly_key(UINT context,BOOL win32,const WCHAR * filename,HKEY * hkey)482 static LONG open_local_assembly_key( UINT context, BOOL win32, const WCHAR *filename, HKEY *hkey )
483 {
484 LONG res;
485 HKEY root;
486 WCHAR *path;
487
488 if (!(path = build_local_assembly_path( filename )))
489 return ERROR_OUTOFMEMORY;
490
491 if ((res = open_assemblies_key( context, win32, &root )))
492 {
493 free( path );
494 return res;
495 }
496 res = RegCreateKeyW( root, path, hkey );
497 RegCloseKey( root );
498 free( path );
499 return res;
500 }
501
delete_local_assembly_key(UINT context,BOOL win32,const WCHAR * filename)502 static LONG delete_local_assembly_key( UINT context, BOOL win32, const WCHAR *filename )
503 {
504 LONG res;
505 HKEY root;
506 WCHAR *path;
507
508 if (!(path = build_local_assembly_path( filename )))
509 return ERROR_OUTOFMEMORY;
510
511 if ((res = open_assemblies_key( context, win32, &root )))
512 {
513 free( path );
514 return res;
515 }
516 res = RegDeleteKeyW( root, path );
517 RegCloseKey( root );
518 free( path );
519 return res;
520 }
521
open_global_assembly_key(UINT context,BOOL win32,HKEY * hkey)522 static LONG open_global_assembly_key( UINT context, BOOL win32, HKEY *hkey )
523 {
524 HKEY root;
525 const WCHAR *path;
526
527 if (context == MSIINSTALLCONTEXT_MACHINE)
528 {
529 root = HKEY_CLASSES_ROOT;
530 if (win32) path = L"Installer\\Win32Assemblies\\Global";
531 else path = L"Installer\\Assemblies\\Global";
532 }
533 else
534 {
535 root = HKEY_CURRENT_USER;
536 if (win32) path = L"Software\\Microsoft\\Installer\\Win32Assemblies\\Global";
537 else path = L"Software\\Microsoft\\Installer\\Assemblies\\Global";
538 }
539 return RegCreateKeyW( root, path, hkey );
540 }
541
ACTION_MsiPublishAssemblies(MSIPACKAGE * package)542 UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
543 {
544 MSICOMPONENT *comp;
545
546 if (package->script == SCRIPT_NONE)
547 return msi_schedule_action(package, SCRIPT_INSTALL, L"MsiPublishAssemblies");
548
549 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
550 {
551 LONG res;
552 HKEY hkey;
553 GUID guid;
554 DWORD size;
555 WCHAR buffer[43];
556 MSIRECORD *uirow;
557 MSIASSEMBLY *assembly = comp->assembly;
558 BOOL win32;
559
560 if (!assembly || !comp->ComponentId) continue;
561
562 comp->Action = msi_get_component_action( package, comp );
563 if (comp->Action != INSTALLSTATE_LOCAL)
564 {
565 TRACE("component not scheduled for installation %s\n", debugstr_w(comp->Component));
566 continue;
567 }
568 TRACE("publishing %s\n", debugstr_w(comp->Component));
569
570 CLSIDFromString( package->ProductCode, &guid );
571 encode_base85_guid( &guid, buffer );
572 buffer[20] = '>';
573 CLSIDFromString( comp->ComponentId, &guid );
574 encode_base85_guid( &guid, buffer + 21 );
575 buffer[42] = 0;
576
577 win32 = assembly->attributes & msidbAssemblyAttributesWin32;
578 if (assembly->application)
579 {
580 MSIFILE *file = msi_get_loaded_file( package, assembly->application );
581 if (!file)
582 {
583 WARN("no matching file %s for local assembly\n", debugstr_w(assembly->application));
584 continue;
585 }
586 if ((res = open_local_assembly_key( package->Context, win32, file->TargetPath, &hkey )))
587 {
588 WARN( "failed to open local assembly key %ld\n", res );
589 return ERROR_FUNCTION_FAILED;
590 }
591 }
592 else
593 {
594 if ((res = open_global_assembly_key( package->Context, win32, &hkey )))
595 {
596 WARN( "failed to open global assembly key %ld\n", res );
597 return ERROR_FUNCTION_FAILED;
598 }
599 }
600 size = sizeof(buffer);
601 if ((res = RegSetValueExW( hkey, assembly->display_name, 0, REG_MULTI_SZ, (const BYTE *)buffer, size )))
602 {
603 WARN( "failed to set assembly value %ld\n", res );
604 }
605 RegCloseKey( hkey );
606
607 uirow = MSI_CreateRecord( 2 );
608 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
609 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
610 msiobj_release( &uirow->hdr );
611 }
612 return ERROR_SUCCESS;
613 }
614
ACTION_MsiUnpublishAssemblies(MSIPACKAGE * package)615 UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
616 {
617 MSICOMPONENT *comp;
618
619 if (package->script == SCRIPT_NONE)
620 return msi_schedule_action(package, SCRIPT_INSTALL, L"MsiUnpublishAssemblies");
621
622 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
623 {
624 LONG res;
625 MSIRECORD *uirow;
626 MSIASSEMBLY *assembly = comp->assembly;
627 BOOL win32;
628
629 if (!assembly || !comp->ComponentId) continue;
630
631 comp->Action = msi_get_component_action( package, comp );
632 if (comp->Action != INSTALLSTATE_ABSENT)
633 {
634 TRACE("component not scheduled for removal %s\n", debugstr_w(comp->Component));
635 continue;
636 }
637 TRACE("unpublishing %s\n", debugstr_w(comp->Component));
638
639 win32 = assembly->attributes & msidbAssemblyAttributesWin32;
640 if (assembly->application)
641 {
642 MSIFILE *file = msi_get_loaded_file( package, assembly->application );
643 if (!file)
644 {
645 WARN("no matching file %s for local assembly\n", debugstr_w(assembly->application));
646 continue;
647 }
648 if ((res = delete_local_assembly_key( package->Context, win32, file->TargetPath )))
649 WARN( "failed to delete local assembly key %ld\n", res );
650 }
651 else
652 {
653 HKEY hkey;
654 if ((res = open_global_assembly_key( package->Context, win32, &hkey )))
655 WARN( "failed to delete global assembly key %ld\n", res );
656 else
657 {
658 if ((res = RegDeleteValueW( hkey, assembly->display_name )))
659 WARN( "failed to delete global assembly value %ld\n", res );
660 RegCloseKey( hkey );
661 }
662 }
663
664 uirow = MSI_CreateRecord( 2 );
665 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
666 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
667 msiobj_release( &uirow->hdr );
668 }
669 return ERROR_SUCCESS;
670 }
671