/// <summary> /// Initialize 'resolvedInfo' by having MSBuild resolve the assembly in the context of the current project /// </summary> /// <param name="assemblyInclude">Either a full path to a file on disk, or a simple name or fusion name</param> /// <param name="isAlreadyInProjectFile">Pass true for this parameter, as well as the evaluated include for the other parameter, if you are trying to discover the MSBuild resolution of an existing ProjectElement</param> private void AddToProjectFileAndTryResolve(string assemblyInclude) { Action <string> Trace = (s) => FSharpTrace.PrintLine("ProjectSystemReferenceResolution", () => "ResolveAssemblyReferenceCore: " + s); Trace("starting: \"" + assemblyInclude + "\""); ProjectInstance instance = null; instance = this.ProjectMgr.BuildProject.CreateProjectInstance(); // use a fresh instance... instance.AddItem(ProjectFileConstants.Reference, assemblyInclude); // ...and mutate it as through there were another <Reference Include="blah"> there Trace("instance[Configuration]=" + instance.GetPropertyValue("Configuration")); Trace("instance[Platform]=" + instance.GetPropertyValue("Platform")); var result = BuildInstance(this.ProjectMgr, ref instance, MsBuildTarget.ResolveAssemblyReferences); this.ResolveFromBuiltProject(assemblyInclude, result); Trace("finished without finding original item: \"" + assemblyInclude + "\""); }
private void ResolveFromBuiltProject(string assemblyInclude, BuildResult buildResult) { Action <string> Trace = (s) => FSharpTrace.PrintLine("ProjectSystemReferenceResolution", () => "ResolveAssemblyReferenceCore: " + s); Trace("starting: \"" + assemblyInclude + "\""); if (!buildResult.IsSuccessful) { Trace("ResolveAssemblyReferences build failed."); return; } System.Collections.Generic.IEnumerable <ProjectItemInstance> group = buildResult.ProjectInstance.GetItems(ProjectFileConstants.ReferencePath); if (group != null) { foreach (var item in group) { // TODO, the logic here is too brittle - if a user adds a 'logical duplicate' assembly with a different name, it may not find resolution // and then wind up with wrong diagnostic later because it failed to resolve (when in fact it would resolve if not for duplicate) if (0 == string.Compare(assemblyInclude, MSBuildItem.GetMetadataValue(item, "OriginalItemSpec"), StringComparison.Ordinal)) { var fusionName = MSBuildItem.GetMetadataValue(item, "FusionName"); if (!string.IsNullOrEmpty(fusionName)) { this.resolvedInfo.ResolvedAssemblyName = new System.Reflection.AssemblyName(fusionName); this.resolvedInfo.AssemblyName = this.resolvedInfo.ResolvedAssemblyName; } this.resolvedInfo.IsPlatformAssembly = 0 == string.Compare(MSBuildItem.GetMetadataValue(item, ProjectFileConstants.ResolvedFrom), "{TargetFrameworkDirectory}", StringComparison.OrdinalIgnoreCase); this.resolvedInfo.IsNoPIA = 0 == string.Compare(MSBuildItem.GetMetadataValue(item, ProjectFileConstants.EmbedInteropTypes), "true", StringComparison.OrdinalIgnoreCase); this.resolvedInfo.CopyLocalDefault = 0 == string.Compare(MSBuildItem.GetMetadataValue(item, ProjectFileConstants.CopyLocal), "true", StringComparison.OrdinalIgnoreCase); this.resolvedInfo.WasSuccessfullyResolved = true; this.myAssemblyPath = MSBuildItem.GetEvaluatedInclude(item); if (!Path.IsPathRooted(this.myAssemblyPath)) { this.myAssemblyPath = Path.Combine(this.ProjectMgr.ProjectFolder, this.myAssemblyPath); } Trace("finished and found original item: \"" + assemblyInclude + "\""); return; } } } Trace("finished without finding original item: \"" + assemblyInclude + "\""); }
private void ResolveAssemblyReferenceByFullPath(string assemblyFullPath, AddReferenceDialogTab tab) { if (this.ProjectMgr == null || this.ProjectMgr.IsClosed) { return; } bool isValidPath = false; try { isValidPath = Path.IsPathRooted(assemblyFullPath); } catch (ArgumentException) { } Debug.Assert(isValidPath, string.Format("Expected assemblyFullPath to be a full path, but it was {0}", assemblyFullPath)); // AddComPlusReferenceByFullPath Action <string> Trace = (s) => FSharpTrace.PrintLine("ProjectSystemReferenceResolution", () => "ResolveAssemblyReferenceByFullPath: " + s); Trace("starting: \"" + assemblyFullPath + "\""); this.msbuildProjectionInfo.WantHintPath = false; this.msbuildProjectionInfo.WantFusionName = false; this.msbuildProjectionInfo.WantSpecificVersion = null; try { var simpleName = System.IO.Path.GetFileNameWithoutExtension(assemblyFullPath); AddToProjectFileAndTryResolve(simpleName); } catch (Exception) { } if (!this.resolvedInfo.WasSuccessfullyResolved) { Trace("simple name resolution did not succeed"); this.msbuildProjectionInfo.WantHintPath = true; AddToProjectFileAndTryResolve(assemblyFullPath); } else { this.myAssemblyPath = assemblyFullPath; Trace("simple name resolution succeeded"); // we successfully resolved it via simple name if (!this.resolvedInfo.IsPlatformAssembly) { Trace("not a platform assembly"); if (resolvedInfo.AssemblyName != null) { // Project file contains different reference than picked/shown in UI // code in this class tries to mimic the behavior in vsproject\langbuild\langref.cpp\785480\langref.cpp // it also uses simple name for initial resolution attempt // however after that it repopulates ComPlus attributes from the source assembly via SetComPlusAttributesFromFullPath // this part was previously skipped - as a result AssemblyName contained invalid data var assemblyName = AssemblyName.GetAssemblyName(assemblyFullPath); resolvedInfo.AssemblyName = assemblyName; resolvedInfo.ResolvedAssemblyName = assemblyName; } if (tab == AddReferenceDialogTab.DotNetTab) { Trace("from .Net tab"); this.msbuildProjectionInfo.WantFusionName = true; this.msbuildProjectionInfo.WantSpecificVersion = true; } else { Debug.Assert(tab == AddReferenceDialogTab.BrowseTab); Trace("not from .Net tab"); this.msbuildProjectionInfo.WantHintPath = true; } } else { // platform assemblies can just resolve to simple name Trace("it was a platform assembly"); } } // TODO - not accounting for case described below // if <re-resolving fusion name with SpecificVersion fails> then // { // this is possible if this reference is being added through automation // in which case the file passed may have a different fusion name than // the assembly in the target framework/fx extensions. // in that case just add with a hint path // wantHintPath = true; // } if (this.msbuildProjectionInfo.WantHintPath) { this.msbuildProjectionInfo.WantSpecificVersion = false; } if (this.myAssemblyPath == null) { this.myAssemblyPath = assemblyFullPath; } if (!this.resolvedInfo.WasSuccessfullyResolved) { this.ProjectMgr.AddReferenceCouldNotBeAddedErrorMessage(assemblyFullPath); } Trace("finished: \"" + assemblyFullPath + "\""); }