diff options
| author | Rob Mensching <rob@firegiant.com> | 2018-12-26 12:40:58 -0800 |
|---|---|---|
| committer | Rob Mensching <rob@robmensching.com> | 2018-12-26 14:03:10 -0800 |
| commit | 232176210981a8e21793f6096dd651eba29caf8e (patch) | |
| tree | 5880b1b9c968f494fbab3f78c07cba95ed309c40 /src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs | |
| parent | 758bcf4bb6d61dd9d6471d9f9629d4f7b18d43cb (diff) | |
| download | wix-232176210981a8e21793f6096dd651eba29caf8e.tar.gz wix-232176210981a8e21793f6096dd651eba29caf8e.tar.bz2 wix-232176210981a8e21793f6096dd651eba29caf8e.zip | |
Populate MsiAssemblyName table
Fixes wixtoolset/issues#5865
Diffstat (limited to 'src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs')
| -rw-r--r-- | src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs | 256 |
1 files changed, 47 insertions, 209 deletions
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs index 10eae8f8..81300322 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs | |||
| @@ -8,9 +8,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
| 8 | using System.Globalization; | 8 | using System.Globalization; |
| 9 | using System.IO; | 9 | using System.IO; |
| 10 | using System.Linq; | 10 | using System.Linq; |
| 11 | using System.Xml; | ||
| 12 | using System.Xml.XPath; | ||
| 13 | using WixToolset.Clr.Interop; | ||
| 14 | using WixToolset.Core.Bind; | 11 | using WixToolset.Core.Bind; |
| 15 | using WixToolset.Data; | 12 | using WixToolset.Data; |
| 16 | using WixToolset.Data.Tuples; | 13 | using WixToolset.Data.Tuples; |
| @@ -45,7 +42,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
| 45 | 42 | ||
| 46 | public void Execute() | 43 | public void Execute() |
| 47 | { | 44 | { |
| 48 | foreach (FileFacade file in this.UpdateFileFacades) | 45 | foreach (var file in this.UpdateFileFacades) |
| 49 | { | 46 | { |
| 50 | this.UpdateFileFacade(file); | 47 | this.UpdateFileFacade(file); |
| 51 | } | 48 | } |
| @@ -86,7 +83,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
| 86 | return; | 83 | return; |
| 87 | } | 84 | } |
| 88 | 85 | ||
| 89 | using (FileStream fileStream = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.Read)) | 86 | using (var fileStream = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.Read)) |
| 90 | { | 87 | { |
| 91 | if (Int32.MaxValue < fileStream.Length) | 88 | if (Int32.MaxValue < fileStream.Length) |
| 92 | { | 89 | { |
| @@ -224,136 +221,47 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
| 224 | // If this is a CLR assembly, load the assembly and get the assembly name information | 221 | // If this is a CLR assembly, load the assembly and get the assembly name information |
| 225 | if (FileAssemblyType.DotNetAssembly == file.WixFile.AssemblyType) | 222 | if (FileAssemblyType.DotNetAssembly == file.WixFile.AssemblyType) |
| 226 | { | 223 | { |
| 227 | bool targetNetfx1 = false; | 224 | try |
| 228 | var assemblyNameValues = new Dictionary<string, string>(); | ||
| 229 | |||
| 230 | Guid referenceIdentityGuid = ClrInterop.ReferenceIdentityGuid; | ||
| 231 | var result = ClrInterop.GetAssemblyIdentityFromFile(fileInfo.FullName, ref referenceIdentityGuid, out var referenceIdentity); | ||
| 232 | if (0 == result && null != referenceIdentity) | ||
| 233 | { | 225 | { |
| 234 | var imageRuntimeVersion = referenceIdentity.GetAttribute(null, "ImageRuntimeVersion"); | 226 | var assemblyName = AssemblyNameReader.ReadAssembly(file.File.SourceLineNumbers, fileInfo.FullName, version); |
| 235 | if (null != imageRuntimeVersion) | ||
| 236 | { | ||
| 237 | targetNetfx1 = imageRuntimeVersion.StartsWith("v1", StringComparison.OrdinalIgnoreCase); | ||
| 238 | } | ||
| 239 | 227 | ||
| 240 | string culture = referenceIdentity.GetAttribute(null, "Culture") ?? "neutral"; | 228 | this.SetMsiAssemblyName(assemblyNameTuples, file, "name", assemblyName.Name); |
| 241 | assemblyNameValues.Add("Culture", culture); | 229 | this.SetMsiAssemblyName(assemblyNameTuples, file, "culture", assemblyName.Culture); |
| 230 | this.SetMsiAssemblyName(assemblyNameTuples, file, "version", assemblyName.Version); | ||
| 242 | 231 | ||
| 243 | string name = referenceIdentity.GetAttribute(null, "Name"); | 232 | if (!String.IsNullOrEmpty(assemblyName.Architecture)) |
| 244 | if (null != name) | ||
| 245 | { | 233 | { |
| 246 | assemblyNameValues.Add("Name", name); | 234 | this.SetMsiAssemblyName(assemblyNameTuples, file, "processorArchitecture", assemblyName.Architecture); |
| 247 | } | 235 | } |
| 236 | // TODO: WiX v3 seemed to do this but not clear it should actually be done. | ||
| 237 | //else if (!String.IsNullOrEmpty(file.WixFile.ProcessorArchitecture)) | ||
| 238 | //{ | ||
| 239 | // this.SetMsiAssemblyName(assemblyNameTuples, file, "processorArchitecture", file.WixFile.ProcessorArchitecture); | ||
| 240 | //} | ||
| 248 | 241 | ||
| 249 | string processorArchitecture = referenceIdentity.GetAttribute(null, "ProcessorArchitecture"); | 242 | if (assemblyName.StrongNamedSigned) |
| 250 | if (null != processorArchitecture) | ||
| 251 | { | 243 | { |
| 252 | assemblyNameValues.Add("ProcessorArchitecture", processorArchitecture); | 244 | this.SetMsiAssemblyName(assemblyNameTuples, file, "publicKeyToken", assemblyName.PublicKeyToken); |
| 253 | } | ||
| 254 | |||
| 255 | string publicKeyToken = referenceIdentity.GetAttribute(null, "PublicKeyToken"); | ||
| 256 | if (null != publicKeyToken) | ||
| 257 | { | ||
| 258 | bool publicKeyIsNeutral = (String.Equals(publicKeyToken, "neutral", StringComparison.OrdinalIgnoreCase)); | ||
| 259 | |||
| 260 | // Managed code expects "null" instead of "neutral", and | ||
| 261 | // this won't be installed to the GAC since it's not signed anyway. | ||
| 262 | assemblyNameValues.Add("publicKeyToken", publicKeyIsNeutral ? "null" : publicKeyToken.ToUpperInvariant()); | ||
| 263 | assemblyNameValues.Add("publicKeyTokenPreservedCase", publicKeyIsNeutral ? "null" : publicKeyToken); | ||
| 264 | } | 245 | } |
| 265 | else if (file.WixFile.File_AssemblyApplication == null) | 246 | else if (file.WixFile.File_AssemblyApplication == null) |
| 266 | { | 247 | { |
| 267 | throw new WixException(ErrorMessages.GacAssemblyNoStrongName(file.File.SourceLineNumbers, fileInfo.FullName, file.File.Component_)); | 248 | throw new WixException(ErrorMessages.GacAssemblyNoStrongName(file.File.SourceLineNumbers, fileInfo.FullName, file.File.Component_)); |
| 268 | } | 249 | } |
| 269 | 250 | ||
| 270 | string assemblyVersion = referenceIdentity.GetAttribute(null, "Version"); | 251 | if (!String.IsNullOrEmpty(assemblyName.FileVersion)) |
| 271 | if (null != version) | ||
| 272 | { | 252 | { |
| 273 | assemblyNameValues.Add("Version", assemblyVersion); | 253 | this.SetMsiAssemblyName(assemblyNameTuples, file, "fileVersion", assemblyName.FileVersion); |
| 274 | } | 254 | } |
| 275 | } | ||
| 276 | else | ||
| 277 | { | ||
| 278 | this.Messaging.Write(ErrorMessages.InvalidAssemblyFile(file.File.SourceLineNumbers, fileInfo.FullName, String.Format(CultureInfo.InvariantCulture, "HRESULT: 0x{0:x8}", result))); | ||
| 279 | return; | ||
| 280 | } | ||
| 281 | |||
| 282 | if (assemblyNameValues.TryGetValue("name", out var value)) | ||
| 283 | { | ||
| 284 | this.SetMsiAssemblyName(assemblyNameTuples, file, "name", value); | ||
| 285 | } | ||
| 286 | |||
| 287 | if (!String.IsNullOrEmpty(version)) | ||
| 288 | { | ||
| 289 | this.SetMsiAssemblyName(assemblyNameTuples, file, "fileVersion", version); | ||
| 290 | } | ||
| 291 | 255 | ||
| 292 | if (assemblyNameValues.ContainsKey("version")) | 256 | // add the assembly name to the information cache |
| 293 | { | 257 | if (null != this.VariableCache) |
| 294 | string assemblyVersion = assemblyNameValues["version"]; | ||
| 295 | |||
| 296 | if (!targetNetfx1) | ||
| 297 | { | 258 | { |
| 298 | // There is a bug in v1 fusion that requires the assembly's "version" attribute | 259 | this.VariableCache[$"assemblyfullname.{file.File.File}"] = assemblyName.GetFullName(); |
| 299 | // to be equal to or longer than the "fileVersion" in length when its present; | ||
| 300 | // the workaround is to prepend zeroes to the last version number in the assembly | ||
| 301 | // version. | ||
| 302 | if (null != version && version.Length > assemblyVersion.Length) | ||
| 303 | { | ||
| 304 | string padding = new string('0', version.Length - assemblyVersion.Length); | ||
| 305 | string[] assemblyVersionNumbers = assemblyVersion.Split('.'); | ||
| 306 | |||
| 307 | if (assemblyVersionNumbers.Length > 0) | ||
| 308 | { | ||
| 309 | assemblyVersionNumbers[assemblyVersionNumbers.Length - 1] = String.Concat(padding, assemblyVersionNumbers[assemblyVersionNumbers.Length - 1]); | ||
| 310 | assemblyVersion = String.Join(".", assemblyVersionNumbers); | ||
| 311 | } | ||
| 312 | } | ||
| 313 | } | 260 | } |
| 314 | |||
| 315 | this.SetMsiAssemblyName(assemblyNameTuples, file, "version", assemblyVersion); | ||
| 316 | } | ||
| 317 | |||
| 318 | if (assemblyNameValues.ContainsKey("culture")) | ||
| 319 | { | ||
| 320 | this.SetMsiAssemblyName(assemblyNameTuples, file, "culture", assemblyNameValues["culture"]); | ||
| 321 | } | ||
| 322 | |||
| 323 | if (assemblyNameValues.ContainsKey("publicKeyToken")) | ||
| 324 | { | ||
| 325 | this.SetMsiAssemblyName(assemblyNameTuples, file, "publicKeyToken", assemblyNameValues["publicKeyToken"]); | ||
| 326 | } | ||
| 327 | |||
| 328 | if (!String.IsNullOrEmpty(file.WixFile.ProcessorArchitecture)) | ||
| 329 | { | ||
| 330 | this.SetMsiAssemblyName(assemblyNameTuples, file, "processorArchitecture", file.WixFile.ProcessorArchitecture); | ||
| 331 | } | ||
| 332 | |||
| 333 | if (assemblyNameValues.ContainsKey("processorArchitecture")) | ||
| 334 | { | ||
| 335 | this.SetMsiAssemblyName(assemblyNameTuples, file, "processorArchitecture", assemblyNameValues["processorArchitecture"]); | ||
| 336 | } | 261 | } |
| 337 | 262 | catch (WixException e) | |
| 338 | // add the assembly name to the information cache | ||
| 339 | if (null != this.VariableCache) | ||
| 340 | { | 263 | { |
| 341 | string fileId = file.File.File; | 264 | this.Messaging.Write(e.Error); |
| 342 | string key = String.Concat("assemblyfullname.", fileId); | ||
| 343 | string assemblyName = String.Concat(assemblyNameValues["name"], ", version=", assemblyNameValues["version"], ", culture=", assemblyNameValues["culture"], ", publicKeyToken=", String.IsNullOrEmpty(assemblyNameValues["publicKeyToken"]) ? "null" : assemblyNameValues["publicKeyToken"]); | ||
| 344 | if (assemblyNameValues.ContainsKey("processorArchitecture")) | ||
| 345 | { | ||
| 346 | assemblyName = String.Concat(assemblyName, ", processorArchitecture=", assemblyNameValues["processorArchitecture"]); | ||
| 347 | } | ||
| 348 | |||
| 349 | this.VariableCache[key] = assemblyName; | ||
| 350 | |||
| 351 | // Add entries with the preserved case publicKeyToken | ||
| 352 | string pcAssemblyNameKey = String.Concat("assemblyfullnamepreservedcase.", fileId); | ||
| 353 | this.VariableCache[pcAssemblyNameKey] = (assemblyNameValues["publicKeyToken"] == assemblyNameValues["publicKeyTokenPreservedCase"]) ? assemblyName : assemblyName.Replace(assemblyNameValues["publicKeyToken"], assemblyNameValues["publicKeyTokenPreservedCase"]); | ||
| 354 | |||
| 355 | string pcPublicKeyTokenKey = String.Concat("assemblypublickeytokenpreservedcase.", fileId); | ||
| 356 | this.VariableCache[pcPublicKeyTokenKey] = assemblyNameValues["publicKeyTokenPreservedCase"]; | ||
| 357 | } | 265 | } |
| 358 | } | 266 | } |
| 359 | else if (FileAssemblyType.Win32Assembly == file.WixFile.AssemblyType) | 267 | else if (FileAssemblyType.Win32Assembly == file.WixFile.AssemblyType) |
| @@ -361,114 +269,44 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
| 361 | // TODO: Consider passing in the this.FileFacades as an indexed collection instead of searching through | 269 | // TODO: Consider passing in the this.FileFacades as an indexed collection instead of searching through |
| 362 | // all files like this. Even though this is a rare case it looks like we might be able to index the | 270 | // all files like this. Even though this is a rare case it looks like we might be able to index the |
| 363 | // file earlier. | 271 | // file earlier. |
| 364 | FileFacade fileManifest = this.FileFacades.SingleOrDefault(r => r.File.File.Equals(file.WixFile.File_AssemblyManifest, StringComparison.Ordinal)); | 272 | var fileManifest = this.FileFacades.SingleOrDefault(r => r.File.File.Equals(file.WixFile.File_AssemblyManifest, StringComparison.Ordinal)); |
| 365 | if (null == fileManifest) | 273 | if (null == fileManifest) |
| 366 | { | 274 | { |
| 367 | this.Messaging.Write(ErrorMessages.MissingManifestForWin32Assembly(file.File.SourceLineNumbers, file.File.File, file.WixFile.File_AssemblyManifest)); | 275 | this.Messaging.Write(ErrorMessages.MissingManifestForWin32Assembly(file.File.SourceLineNumbers, file.File.File, file.WixFile.File_AssemblyManifest)); |
| 368 | } | 276 | } |
| 369 | 277 | ||
| 370 | string win32Type = null; | ||
| 371 | string win32Name = null; | ||
| 372 | string win32Version = null; | ||
| 373 | string win32ProcessorArchitecture = null; | ||
| 374 | string win32PublicKeyToken = null; | ||
| 375 | |||
| 376 | // loading the dom is expensive we want more performant APIs than the DOM | ||
| 377 | // Navigator is cheaper than dom. Perhaps there is a cheaper API still. | ||
| 378 | try | 278 | try |
| 379 | { | 279 | { |
| 380 | XPathDocument doc = new XPathDocument(fileManifest.WixFile.Source.Path); | 280 | var assemblyName = AssemblyNameReader.ReadAssemblyManifest(file.File.SourceLineNumbers, fileManifest.WixFile.Source.Path); |
| 381 | XPathNavigator nav = doc.CreateNavigator(); | ||
| 382 | nav.MoveToRoot(); | ||
| 383 | |||
| 384 | // this assumes a particular schema for a win32 manifest and does not | ||
| 385 | // provide error checking if the file does not conform to schema. | ||
| 386 | // The fallback case here is that nothing is added to the MsiAssemblyName | ||
| 387 | // table for an out of tolerance Win32 manifest. Perhaps warnings needed. | ||
| 388 | if (nav.MoveToFirstChild()) | ||
| 389 | { | ||
| 390 | while (nav.NodeType != XPathNodeType.Element || nav.Name != "assembly") | ||
| 391 | { | ||
| 392 | nav.MoveToNext(); | ||
| 393 | } | ||
| 394 | 281 | ||
| 395 | if (nav.MoveToFirstChild()) | 282 | if (!String.IsNullOrEmpty(assemblyName.Name)) |
| 396 | { | 283 | { |
| 397 | bool hasNextSibling = true; | 284 | this.SetMsiAssemblyName(assemblyNameTuples, file, "name", assemblyName.Name); |
| 398 | while (nav.NodeType != XPathNodeType.Element || nav.Name != "assemblyIdentity" && hasNextSibling) | ||
| 399 | { | ||
| 400 | hasNextSibling = nav.MoveToNext(); | ||
| 401 | } | ||
| 402 | if (!hasNextSibling) | ||
| 403 | { | ||
| 404 | this.Messaging.Write(ErrorMessages.InvalidManifestContent(file.File.SourceLineNumbers, fileManifest.WixFile.Source.Path)); | ||
| 405 | return; | ||
| 406 | } | ||
| 407 | |||
| 408 | if (nav.MoveToAttribute("type", String.Empty)) | ||
| 409 | { | ||
| 410 | win32Type = nav.Value; | ||
| 411 | nav.MoveToParent(); | ||
| 412 | } | ||
| 413 | |||
| 414 | if (nav.MoveToAttribute("name", String.Empty)) | ||
| 415 | { | ||
| 416 | win32Name = nav.Value; | ||
| 417 | nav.MoveToParent(); | ||
| 418 | } | ||
| 419 | |||
| 420 | if (nav.MoveToAttribute("version", String.Empty)) | ||
| 421 | { | ||
| 422 | win32Version = nav.Value; | ||
| 423 | nav.MoveToParent(); | ||
| 424 | } | ||
| 425 | |||
| 426 | if (nav.MoveToAttribute("processorArchitecture", String.Empty)) | ||
| 427 | { | ||
| 428 | win32ProcessorArchitecture = nav.Value; | ||
| 429 | nav.MoveToParent(); | ||
| 430 | } | ||
| 431 | |||
| 432 | if (nav.MoveToAttribute("publicKeyToken", String.Empty)) | ||
| 433 | { | ||
| 434 | win32PublicKeyToken = nav.Value; | ||
| 435 | nav.MoveToParent(); | ||
| 436 | } | ||
| 437 | } | ||
| 438 | } | 285 | } |
| 439 | } | ||
| 440 | catch (FileNotFoundException fe) | ||
| 441 | { | ||
| 442 | this.Messaging.Write(ErrorMessages.FileNotFound(new SourceLineNumber(fileManifest.WixFile.Source.Path), fe.FileName, "AssemblyManifest")); | ||
| 443 | } | ||
| 444 | catch (XmlException xe) | ||
| 445 | { | ||
| 446 | this.Messaging.Write(ErrorMessages.InvalidXml(new SourceLineNumber(fileManifest.WixFile.Source.Path), "manifest", xe.Message)); | ||
| 447 | } | ||
| 448 | 286 | ||
| 449 | if (!String.IsNullOrEmpty(win32Name)) | 287 | if (!String.IsNullOrEmpty(assemblyName.Version)) |
| 450 | { | 288 | { |
| 451 | this.SetMsiAssemblyName(assemblyNameTuples, file, "name", win32Name); | 289 | this.SetMsiAssemblyName(assemblyNameTuples, file, "version", assemblyName.Version); |
| 452 | } | 290 | } |
| 453 | 291 | ||
| 454 | if (!String.IsNullOrEmpty(win32Version)) | 292 | if (!String.IsNullOrEmpty(assemblyName.Type)) |
| 455 | { | 293 | { |
| 456 | this.SetMsiAssemblyName(assemblyNameTuples, file, "version", win32Version); | 294 | this.SetMsiAssemblyName(assemblyNameTuples, file, "type", assemblyName.Type); |
| 457 | } | 295 | } |
| 458 | 296 | ||
| 459 | if (!String.IsNullOrEmpty(win32Type)) | 297 | if (!String.IsNullOrEmpty(assemblyName.Architecture)) |
| 460 | { | 298 | { |
| 461 | this.SetMsiAssemblyName(assemblyNameTuples, file, "type", win32Type); | 299 | this.SetMsiAssemblyName(assemblyNameTuples, file, "processorArchitecture", assemblyName.Architecture); |
| 462 | } | 300 | } |
| 463 | 301 | ||
| 464 | if (!String.IsNullOrEmpty(win32ProcessorArchitecture)) | 302 | if (!String.IsNullOrEmpty(assemblyName.PublicKeyToken)) |
| 465 | { | 303 | { |
| 466 | this.SetMsiAssemblyName(assemblyNameTuples, file, "processorArchitecture", win32ProcessorArchitecture); | 304 | this.SetMsiAssemblyName(assemblyNameTuples, file, "publicKeyToken", assemblyName.PublicKeyToken); |
| 305 | } | ||
| 467 | } | 306 | } |
| 468 | 307 | catch (WixException e) | |
| 469 | if (!String.IsNullOrEmpty(win32PublicKeyToken)) | ||
| 470 | { | 308 | { |
| 471 | this.SetMsiAssemblyName(assemblyNameTuples, file, "publicKeyToken", win32PublicKeyToken); | 309 | this.Messaging.Write(e.Error); |
| 472 | } | 310 | } |
| 473 | } | 311 | } |
| 474 | } | 312 | } |
| @@ -500,7 +338,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
| 500 | 338 | ||
| 501 | // override directly authored value | 339 | // override directly authored value |
| 502 | var lookup = String.Concat(file.File.Component_, "/", name); | 340 | var lookup = String.Concat(file.File.Component_, "/", name); |
| 503 | if (assemblyNameTuples.TryGetValue(lookup, out var assemblyNameRow)) | 341 | if (!assemblyNameTuples.TryGetValue(lookup, out var assemblyNameRow)) |
| 504 | { | 342 | { |
| 505 | assemblyNameRow = new MsiAssemblyNameTuple(file.File.SourceLineNumbers); | 343 | assemblyNameRow = new MsiAssemblyNameTuple(file.File.SourceLineNumbers); |
| 506 | assemblyNameRow.Component_ = file.File.Component_; | 344 | assemblyNameRow.Component_ = file.File.Component_; |
