Skip to content

Commit

Permalink
fix add file reference (com dll)
Browse files Browse the repository at this point in the history
lcid is an integer
fix typelib registry path, the lcid part is the hexadecimal string representation of the lcid value
added exception on failed add reference
fix nre on if registry key not found

fixes #278
closes #281

commit 64185d2
Author: enricosada <[email protected]>
Date:   Tue Mar 3 21:45:40 2015 +0100

    add test

commit c4fb65d
Author: enricosada <[email protected]>
Date:   Fri Feb 27 19:31:29 2015 +0100

    remove unused try/catch

commit 4a05993
Author: enricosada <[email protected]>
Date:   Fri Feb 27 18:47:03 2015 +0100

    fix add file reference (com dll)

    lcid is an integer
    fix typelib registry path, the lcid part is the hexadecimal string representation of the lcid value
    added exception on failed add reference
    fix nre on if registry key not found

    fix #278
  • Loading branch information
enricosada authored and latkin committed Mar 5, 2015
1 parent 62fccd8 commit 68da61f
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 23 deletions.
59 changes: 58 additions & 1 deletion vsintegration/src/unittests/Tests.ProjectSystem.References.fs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ open UnitTests.TestLib.ProjectSystem
open Microsoft.VisualStudio.FSharp.ProjectSystem
open Microsoft.VisualStudio.Shell.Interop
open Microsoft.Win32
open System.Xml.Linq

[<TestFixture>]
type References() =
Expand Down Expand Up @@ -618,4 +619,60 @@ type References() =
// look for the new property inside of the project file
let contents = File.ReadAllText(newProjFileName)
AssertContains contents newPropVal
)
)


[<Test>]
member public this.``AddReference.COM`` () =
DoWithTempFile "Test.fsproj" (fun projFile ->
File.AppendAllText(projFile, TheTests.SimpleFsprojText([], [], ""))
use project = TheTests.CreateProject(projFile)

let guid = Guid("50a7e9b0-70ef-11d1-b75a-00a0c90564fe")

let selectorData = VSCOMPONENTSELECTORDATA (
``type`` = VSCOMPONENTTYPE.VSCOMPONENTTYPE_Com2,
guidTypeLibrary = guid,
wTypeLibraryMinorVersion = 0us,
wTypeLibraryMajorVersion = 1us,
bstrTitle = "Microsoft Shell Controls And Automation" )
let refContainer = GetReferenceContainerNode(project)

let comReference = refContainer.AddReferenceFromSelectorData(selectorData)

// check reference node properties
Assert.IsNotNull comReference
Assert.IsInstanceOf(typeof<ComReferenceNode>, comReference)
let comRef = comReference :?> ComReferenceNode
Assert.AreEqual(1, comRef.MajorVersionNumber)
Assert.AreEqual(0, comRef.MinorVersionNumber)
Assert.AreEqual(guid, comRef.TypeGuid)
Assert.AreEqual("Microsoft Shell Controls And Automation", comRef.Caption)
let sysDirectory = Environment.GetFolderPath(Environment.SpecialFolder.SystemX86)
StringAssert.AreEqualIgnoringCase(Path.Combine(sysDirectory, "shell32.dll"), comRef.InstalledFilePath)

// check node exists under references
let l = new List<ComReferenceNode>()
project.FindNodesOfType(l)

Assert.AreEqual(1, l.Count)
let referenceNode = l.[0]
Assert.AreSame(comRef, referenceNode)

// check saved msbuild item
SaveProject(project)
let fsproj = XDocument.Load(project.FileName)
printfn "%O" fsproj
let xn s = fsproj.Root.GetDefaultNamespace().GetName(s)
let comReferencesXml = fsproj.Descendants(xn "COMReference") |> Seq.toList

Assert.AreEqual(1, comReferencesXml |> List.length)

let comRefXml = comReferencesXml |> List.head

Assert.AreEqual("Microsoft Shell Controls And Automation", comRefXml.Attribute(XName.Get("Include")).Value)
Assert.AreEqual(guid, Guid(comRefXml.Element(xn "Guid").Value))
Assert.AreEqual("1", comRefXml.Element(xn "VersionMajor").Value)
Assert.AreEqual("0", comRefXml.Element(xn "VersionMinor").Value)
Assert.AreEqual("0", comRefXml.Element(xn "Lcid").Value)
)
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,8 @@ public override string Culture
{
get
{
int locale = 0;
try
{
locale = int.Parse(BaseReferenceNode.LCID, CultureInfo.InvariantCulture);
}
catch (System.FormatException)
{
// Do Nothing
}
var locale = BaseReferenceNode.LCID;

if (0 == locale)
{
return string.Empty;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ [ DllImport( "oleaut32.dll", CharSet = CharSet.Unicode, PreserveSig = false )]
private string installedFilePath;
private string minorVersionNumber;
private string majorVersionNumber;
private string lcid;
private readonly int lcid;
#endregion

#region properties
Expand Down Expand Up @@ -76,7 +76,7 @@ public string InstalledFilePath
}

[SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "LCID")]
public string LCID
public int LCID
{
get { return lcid; }
}
Expand Down Expand Up @@ -133,7 +133,7 @@ internal ComReferenceNode(ProjectNode root, ProjectElement element)

this.majorVersionNumber = this.ItemNode.GetMetadata(ProjectFileConstants.VersionMajor);
this.minorVersionNumber = this.ItemNode.GetMetadata(ProjectFileConstants.VersionMinor);
this.lcid = this.ItemNode.GetMetadata(ProjectFileConstants.Lcid);
this.lcid = int.Parse(this.ItemNode.GetMetadata(ProjectFileConstants.Lcid));
this.SetProjectItemsThatRelyOnReferencesToBeResolved(false);
this.SetInstalledFilePath();
}
Expand Down Expand Up @@ -161,14 +161,15 @@ internal ComReferenceNode(ProjectNode root, VSCOMPONENTSELECTORDATA selectorData
this.typeGuid = selectorData.guidTypeLibrary;
this.majorVersionNumber = selectorData.wTypeLibraryMajorVersion.ToString(CultureInfo.InvariantCulture);
this.minorVersionNumber = selectorData.wTypeLibraryMinorVersion.ToString(CultureInfo.InvariantCulture);
this.lcid = selectorData.lcidTypeLibrary.ToString(CultureInfo.InvariantCulture);
this.lcid = (int) selectorData.lcidTypeLibrary;

// Check to see if the COM object actually exists.
this.SetInstalledFilePath();
// If the value cannot be set throw.
if (String.IsNullOrEmpty(this.installedFilePath))
{
throw new ArgumentException();
var message = string.Format(SR.GetString(SR.ReferenceCouldNotBeAdded, CultureInfo.CurrentUICulture), selectorData.bstrTitle);
throw new InvalidOperationException(message);
}
}

Expand All @@ -195,14 +196,15 @@ internal ComReferenceNode(ProjectNode root, string filePath)
this.typeGuid = typeAttr.guid;
this.majorVersionNumber = typeAttr.wMajorVerNum.ToString(CultureInfo.InvariantCulture);
this.minorVersionNumber = typeAttr.wMinorVerNum.ToString(CultureInfo.InvariantCulture);
this.lcid = typeAttr.lcid.ToString(CultureInfo.InvariantCulture);
this.lcid = typeAttr.lcid;

// Check to see if the COM object actually exists.
this.SetInstalledFilePath();
// If the value cannot be set throw.
if (String.IsNullOrEmpty(this.installedFilePath))
{
throw new ArgumentException();
var message = string.Format(SR.GetString(SR.ReferenceCouldNotBeAdded, CultureInfo.CurrentUICulture), filePath);
throw new InvalidOperationException(message);
}
}
finally
Expand Down Expand Up @@ -281,21 +283,20 @@ internal ComReferenceNode(ProjectNode root, string filePath)
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase")]
private ProjectElement GetProjectElementBasedOnInputFromComponentSelectorData()
{

ProjectElement element = new ProjectElement(this.ProjectMgr, this.typeName, ProjectFileConstants.COMReference);

// Set the basic information regarding this COM component
element.SetMetadata(ProjectFileConstants.Guid, this.typeGuid.ToString("B"));
element.SetMetadata(ProjectFileConstants.VersionMajor, this.majorVersionNumber);
element.SetMetadata(ProjectFileConstants.VersionMinor, this.minorVersionNumber);
element.SetMetadata(ProjectFileConstants.Lcid, this.lcid);
element.SetMetadata(ProjectFileConstants.Lcid, this.lcid.ToString());
element.SetMetadata(ProjectFileConstants.Isolated, false.ToString());

// See if a PIA exist for this component
TypeLibConverter typelib = new TypeLibConverter();
string assemblyName;
string assemblyCodeBase;
if (typelib.GetPrimaryInteropAssembly(this.typeGuid, Int32.Parse(this.majorVersionNumber, CultureInfo.InvariantCulture), Int32.Parse(this.minorVersionNumber, CultureInfo.InvariantCulture), Int32.Parse(this.lcid, CultureInfo.InvariantCulture), out assemblyName, out assemblyCodeBase))
if (typelib.GetPrimaryInteropAssembly(this.typeGuid, Int32.Parse(this.majorVersionNumber, CultureInfo.InvariantCulture), Int32.Parse(this.minorVersionNumber, CultureInfo.InvariantCulture), this.lcid, out assemblyName, out assemblyCodeBase))
{
element.SetMetadata(ProjectFileConstants.WrapperTool, WrapperToolAttributeValue.Primary.ToString().ToLowerInvariant());
}
Expand Down Expand Up @@ -325,7 +326,7 @@ private void SetProjectItemsThatRelyOnReferencesToBeResolved(bool renameItemNode
if (String.Compare(MSBuildItem.GetMetadataValue(reference, ProjectFileConstants.Guid), this.typeGuid.ToString("B"), StringComparison.OrdinalIgnoreCase) == 0
&& String.Compare(MSBuildItem.GetMetadataValue(reference, ProjectFileConstants.VersionMajor), this.majorVersionNumber, StringComparison.OrdinalIgnoreCase) == 0
&& String.Compare(MSBuildItem.GetMetadataValue(reference, ProjectFileConstants.VersionMinor), this.minorVersionNumber, StringComparison.OrdinalIgnoreCase) == 0
&& String.Compare(MSBuildItem.GetMetadataValue(reference, ProjectFileConstants.Lcid), this.lcid, StringComparison.OrdinalIgnoreCase) == 0)
&& String.Compare(MSBuildItem.GetMetadataValue(reference, ProjectFileConstants.Lcid), this.lcid.ToString(), StringComparison.OrdinalIgnoreCase) == 0)
{
string name = MSBuildItem.GetEvaluatedInclude(reference);
if (Path.IsPathRooted(name))
Expand Down Expand Up @@ -365,9 +366,16 @@ private void SetInstalledFilePath()
this.typeName = typeLib.GetValue(string.Empty) as string;
}
// Now get the path to the file that contains this type library.
using (RegistryKey installKey = typeLib.OpenSubKey(string.Format(CultureInfo.InvariantCulture, @"{0}\win32", this.lcid)))

// lcid
// The hexadecimal string representation of the locale identifier (LCID).
// It is one to four hexadecimal digits with no 0x prefix and no leading zeros.
using (RegistryKey installKey = typeLib.OpenSubKey(string.Format(CultureInfo.InvariantCulture, @"{0:X}\win32", this.lcid)))
{
this.installedFilePath = installKey.GetValue(String.Empty) as String;
if (installKey != null)
{
this.installedFilePath = installKey.GetValue(String.Empty) as String;
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ protected override string GetLocalizedString(string value)
/*internal, but public for FSharp.Project.dll*/ public const string ProjectProperties = "ProjectProperties";
/*internal, but public for FSharp.Project.dll*/ public const string Quiet = "Quiet";
/*internal, but public for FSharp.Project.dll*/ public const string QueryReloadNestedProject = "QueryReloadNestedProject";
/*internal, but public for FSharp.Project.dll*/ public const string ReferenceCouldNotBeAdded = "ReferenceCouldNotBeAdded";
/*internal, but public for FSharp.Project.dll*/ public const string ReferenceAlreadyExists = "ReferenceAlreadyExists";
/*internal, but public for FSharp.Project.dll*/ public const string ReferenceWithAssemblyNameAlreadyExists = "ReferenceWithAssemblyNameAlreadyExists";
/*internal, but public for FSharp.Project.dll*/ public const string ReferencesNodeName = "ReferencesNodeName";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@
<value>Advanced</value>
<comment>Project Property Page Caption</comment>
</data>
<data name="ReferenceCouldNotBeAdded" xml:space="preserve">
<value>A reference to '{0}' could not be added.</value>
<comment>ReferenceCouldNotBeAdded error message</comment>
</data>
<data name="ReferenceAlreadyExists" xml:space="preserve">
<value>A reference to '{0}' could not be added. A reference to the component '{1}' already exists in the project.</value>
<comment>ReferenceAlreadyExists error message</comment>
Expand Down

0 comments on commit 68da61f

Please sign in to comment.