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
27 #include "wine/debug.h"
28 #include "wine/unicode.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
33 static HRESULT (WINAPI
*pCreateAssemblyCacheNet
)( IAssemblyCache
**, DWORD
);
34 static HRESULT (WINAPI
*pCreateAssemblyCacheSxs
)( IAssemblyCache
**, DWORD
);
35 static HRESULT (WINAPI
*pLoadLibraryShim
)( LPCWSTR
, LPCWSTR
, LPVOID
, HMODULE
* );
37 static BOOL
init_function_pointers( void )
39 static const WCHAR szFusion
[] = {'f','u','s','i','o','n','.','d','l','l',0};
40 HMODULE hfusion
, hmscoree
, hsxs
;
43 if (pCreateAssemblyCacheNet
) return TRUE
;
45 if (!(hmscoree
= LoadLibraryA( "mscoree.dll" )))
47 WARN("mscoree.dll not available\n");
50 if (!(pLoadLibraryShim
= (void *)GetProcAddress( hmscoree
, "LoadLibraryShim" )))
52 WARN("LoadLibraryShim not available\n");
53 FreeLibrary( hmscoree
);
56 hr
= pLoadLibraryShim( szFusion
, NULL
, NULL
, &hfusion
);
59 WARN("fusion.dll not available 0x%08x\n", hr
);
60 FreeLibrary( hmscoree
);
63 pCreateAssemblyCacheNet
= (void *)GetProcAddress( hfusion
, "CreateAssemblyCache" );
64 FreeLibrary( hmscoree
);
65 if (!(hsxs
= LoadLibraryA( "sxs.dll" )))
67 WARN("sxs.dll not available\n");
68 FreeLibrary( hfusion
);
71 pCreateAssemblyCacheSxs
= (void *)GetProcAddress( hsxs
, "CreateAssemblyCache" );
75 static BOOL
init_assembly_caches( MSIPACKAGE
*package
)
79 if (!init_function_pointers()) return FALSE
;
80 if (package
->cache_net
) return TRUE
;
82 hr
= pCreateAssemblyCacheNet( &package
->cache_net
, 0 );
83 if (hr
!= S_OK
) return FALSE
;
85 hr
= pCreateAssemblyCacheSxs( &package
->cache_sxs
, 0 );
88 IAssemblyCache_Release( package
->cache_net
);
89 package
->cache_net
= NULL
;
95 MSIRECORD
*get_assembly_record( MSIPACKAGE
*package
, const WCHAR
*comp
)
97 static const WCHAR query
[] = {
98 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
99 '`','M','s','i','A','s','s','e','m','b','l','y','`',' ',
100 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
101 ' ','=',' ','\'','%','s','\'',0};
106 r
= MSI_OpenQuery( package
->db
, &view
, query
, comp
);
107 if (r
!= ERROR_SUCCESS
)
110 r
= MSI_ViewExecute( view
, NULL
);
111 if (r
!= ERROR_SUCCESS
)
113 msiobj_release( &view
->hdr
);
116 r
= MSI_ViewFetch( view
, &rec
);
117 if (r
!= ERROR_SUCCESS
)
119 msiobj_release( &view
->hdr
);
122 if (!MSI_RecordGetString( rec
, 4 ))
123 TRACE("component is a global assembly\n");
125 msiobj_release( &view
->hdr
);
139 static UINT
get_assembly_name_attribute( MSIRECORD
*rec
, LPVOID param
)
141 static const WCHAR typeW
[] = {'t','y','p','e',0};
142 static const WCHAR nameW
[] = {'n','a','m','e',0};
143 static const WCHAR versionW
[] = {'v','e','r','s','i','o','n',0};
144 static const WCHAR cultureW
[] = {'c','u','l','t','u','r','e',0};
145 static const WCHAR tokenW
[] = {'p','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
146 static const WCHAR archW
[] = {'p','r','o','c','e','s','s','o','r','A','r','c','h','i','t','e','c','t','u','r','e',0};
147 struct assembly_name
*name
= param
;
148 const WCHAR
*attr
= MSI_RecordGetString( rec
, 2 );
149 WCHAR
*value
= msi_dup_record_field( rec
, 3 );
151 if (!strcmpiW( attr
, typeW
))
153 else if (!strcmpiW( attr
, nameW
))
155 else if (!strcmpiW( attr
, versionW
))
156 name
->version
= value
;
157 else if (!strcmpiW( attr
, cultureW
))
158 name
->culture
= value
;
159 else if (!strcmpiW( attr
, tokenW
))
161 else if (!strcmpiW( attr
, archW
))
166 return ERROR_SUCCESS
;
169 static WCHAR
*get_assembly_display_name( MSIDATABASE
*db
, const WCHAR
*comp
, MSIASSEMBLY
*assembly
)
171 static const WCHAR fmt_netW
[] = {
172 '%','s',',',' ','v','e','r','s','i','o','n','=','%','s',',',' ',
173 'c','u','l','t','u','r','e','=','%','s',',',' ',
174 'p','u','b','l','i','c','K','e','y','T','o','k','e','n','=','%','s',0};
175 static const WCHAR fmt_sxsW
[] = {
176 '%','s',',',' ','v','e','r','s','i','o','n','=','%','s',',',' ',
177 'p','u','b','l','i','c','K','e','y','T','o','k','e','n','=','%','s',',',' ',
178 'p','r','o','c','e','s','s','o','r','A','r','c','h','i','t','e','c','t','u','r','e','=','%','s',0};
179 static const WCHAR fmt_sxs_localW
[] = {
180 '%','s',',',' ','v','e','r','s','i','o','n','=','%','s',',',' ',
181 'c','u','l','t','u','r','e','=','%','s',',',' ',
182 'p','u','b','l','i','c','K','e','y','T','o','k','e','n','=','%','s',0};
183 static const WCHAR queryW
[] = {
184 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
185 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
186 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
187 ' ','=',' ','\'','%','s','\'',0};
188 struct assembly_name name
;
189 WCHAR
*display_name
= NULL
;
194 memset( &name
, 0, sizeof(name
) );
196 r
= MSI_OpenQuery( db
, &view
, queryW
, comp
);
197 if (r
!= ERROR_SUCCESS
)
200 MSI_IterateRecords( view
, NULL
, get_assembly_name_attribute
, &name
);
201 msiobj_release( &view
->hdr
);
203 if (assembly
->attributes
== msidbAssemblyAttributesWin32
)
205 if (!assembly
->application
)
207 if (!name
.type
|| !name
.name
|| !name
.version
|| !name
.token
|| !name
.arch
)
209 WARN("invalid global win32 assembly name\n");
212 len
= strlenW( fmt_sxsW
);
213 len
+= strlenW( name
.name
);
214 len
+= strlenW( name
.version
);
215 len
+= strlenW( name
.token
);
216 len
+= strlenW( name
.arch
);
217 if (!(display_name
= msi_alloc( len
* sizeof(WCHAR
) ))) goto done
;
218 sprintfW( display_name
, fmt_sxsW
, name
.name
, name
.version
, name
.token
, name
.arch
);
222 if (!name
.name
|| !name
.version
|| !name
.culture
|| !name
.token
)
224 WARN("invalid local win32 assembly name\n");
227 len
= strlenW( fmt_sxs_localW
);
228 len
+= strlenW( name
.name
);
229 len
+= strlenW( name
.version
);
230 len
+= strlenW( name
.culture
);
231 len
+= strlenW( name
.token
);
232 if (!(display_name
= msi_alloc( len
* sizeof(WCHAR
) ))) goto done
;
233 sprintfW( display_name
, fmt_sxs_localW
, name
.name
, name
.version
, name
.culture
, name
.token
);
238 if (!name
.name
|| !name
.version
|| !name
.culture
|| !name
.token
)
240 WARN("invalid assembly name\n");
243 len
= strlenW( fmt_netW
);
244 len
+= strlenW( name
.name
);
245 len
+= strlenW( name
.version
);
246 len
+= strlenW( name
.culture
);
247 len
+= strlenW( name
.token
);
248 if (!(display_name
= msi_alloc( len
* sizeof(WCHAR
) ))) goto done
;
249 sprintfW( display_name
, fmt_netW
, name
.name
, name
.version
, name
.culture
, name
.token
);
253 msi_free( name
.type
);
254 msi_free( name
.name
);
255 msi_free( name
.version
);
256 msi_free( name
.culture
);
257 msi_free( name
.token
);
258 msi_free( name
.arch
);
263 static BOOL
check_assembly_installed( MSIPACKAGE
*package
, MSIASSEMBLY
*assembly
)
265 IAssemblyCache
*cache
;
269 if (assembly
->application
)
271 /* FIXME: we should probably check the manifest file here */
275 if (!init_assembly_caches( package
))
278 if (assembly
->attributes
== msidbAssemblyAttributesWin32
)
279 cache
= package
->cache_sxs
;
281 cache
= package
->cache_net
;
283 memset( &info
, 0, sizeof(info
) );
284 info
.cbAssemblyInfo
= sizeof(info
);
285 hr
= IAssemblyCache_QueryAssemblyInfo( cache
, QUERYASMINFO_FLAG_VALIDATE
, assembly
->display_name
, &info
);
289 return (info
.dwAssemblyFlags
== ASSEMBLYINFO_FLAG_INSTALLED
);
292 MSIASSEMBLY
*load_assembly( MSIPACKAGE
*package
, MSICOMPONENT
*comp
)
297 if (!(rec
= get_assembly_record( package
, comp
->Component
)))
300 if (!(a
= msi_alloc_zero( sizeof(MSIASSEMBLY
) )))
302 msiobj_release( &rec
->hdr
);
305 a
->feature
= strdupW( MSI_RecordGetString( rec
, 2 ) );
306 TRACE("feature %s\n", debugstr_w(a
->feature
));
308 a
->manifest
= strdupW( MSI_RecordGetString( rec
, 3 ) );
309 TRACE("manifest %s\n", debugstr_w(a
->manifest
));
311 a
->application
= strdupW( MSI_RecordGetString( rec
, 4 ) );
312 TRACE("application %s\n", debugstr_w(a
->application
));
314 a
->attributes
= MSI_RecordGetInteger( rec
, 5 );
315 TRACE("attributes %u\n", a
->attributes
);
317 if (!(a
->display_name
= get_assembly_display_name( package
->db
, comp
->Component
, a
)))
319 WARN("can't get display name\n");
320 msiobj_release( &rec
->hdr
);
324 TRACE("display name %s\n", debugstr_w(a
->display_name
));
326 a
->installed
= check_assembly_installed( package
, a
);
327 TRACE("assembly is %s\n", a
->installed
? "installed" : "not installed");
329 msiobj_release( &rec
->hdr
);
333 UINT
install_assembly( MSIPACKAGE
*package
, MSICOMPONENT
*comp
)
336 const WCHAR
*manifest
;
337 IAssemblyCache
*cache
;
338 MSIASSEMBLY
*assembly
= comp
->assembly
;
339 MSIFEATURE
*feature
= NULL
;
341 if (comp
->assembly
->feature
)
342 feature
= get_loaded_feature( package
, comp
->assembly
->feature
);
344 if (assembly
->application
)
346 if (feature
) feature
->Action
= INSTALLSTATE_LOCAL
;
347 return ERROR_SUCCESS
;
349 if (assembly
->attributes
== msidbAssemblyAttributesWin32
)
351 if (!assembly
->manifest
)
353 WARN("no manifest\n");
354 return ERROR_FUNCTION_FAILED
;
356 manifest
= get_loaded_file( package
, assembly
->manifest
)->TargetPath
;
357 cache
= package
->cache_sxs
;
361 manifest
= get_loaded_file( package
, comp
->KeyPath
)->TargetPath
;
362 cache
= package
->cache_net
;
364 TRACE("installing assembly %s\n", debugstr_w(manifest
));
366 hr
= IAssemblyCache_InstallAssembly( cache
, 0, manifest
, NULL
);
369 ERR("Failed to install assembly %s (0x%08x)\n", debugstr_w(manifest
), hr
);
370 return ERROR_FUNCTION_FAILED
;
372 if (feature
) feature
->Action
= INSTALLSTATE_LOCAL
;
373 assembly
->installed
= TRUE
;
374 return ERROR_SUCCESS
;
377 UINT
ACTION_MsiPublishAssemblies( MSIPACKAGE
*package
)
382 LIST_FOR_EACH_ENTRY(comp
, &package
->components
, MSICOMPONENT
, entry
)
384 if (!comp
->assembly
|| !comp
->Enabled
)
387 /* FIXME: write assembly registry values */
389 uirow
= MSI_CreateRecord( 2 );
390 MSI_RecordSetStringW( uirow
, 2, comp
->assembly
->display_name
);
391 ui_actiondata( package
, szMsiPublishAssemblies
, uirow
);
392 msiobj_release( &uirow
->hdr
);
394 return ERROR_SUCCESS
;