/// <summary>
        /// Get the value of an attribute on a project element
        /// </summary>
        /// <param name="attributeName">Name of the attribute to get the value for</param>
        /// <returns>Value of the attribute</returns>
        public string GetMetadata(string attributeName)
        {
            if (this.IsVirtual)
            {
                // For virtual items, use our virtual property collection
                if (!virtualProperties.ContainsKey(attributeName))
                {
                    return(String.Empty);
                }
                return(virtualProperties[attributeName]);
            }

            // cannot ask MSBuild for Include, so intercept it and return the corresponding property
            if (String.Compare(attributeName, ProjectFileConstants.Include, StringComparison.OrdinalIgnoreCase) == 0)
            {
                return(MSBuildItem.GetEvaluatedInclude(item));
            }

            // Build Action is the type, not a property, so intercept this one as well
            if (String.Compare(attributeName, ProjectFileConstants.BuildAction, StringComparison.OrdinalIgnoreCase) == 0)
            {
                return(MSBuildItem.GetItemType(item));
            }

            return(MSBuildItem.GetMetadataValue(item, attributeName));
        }
        private void SetProjectItemsThatRelyOnReferencesToBeResolved(bool renameItemNode)
        {
            // Call MSBuild to build the target ResolveComReferences
            bool success;

            ErrorHandler.ThrowOnFailure(this.ProjectMgr.BuildTarget(MsBuildTarget.ResolveComReferences, out success));
            if (!success)
            {
                throw new InvalidOperationException();
            }

            // Now loop through the generated COM References to find the corresponding one
            var instance = this.ProjectMgr.ProjectInstance;

            AssemblyReferenceNode.BuildInstance(this.ProjectMgr, instance, MsBuildTarget.ResolveAssemblyReferences);
            var comReferences = MSBuildProjectInstance.GetItems(instance, MsBuildGeneratedItemType.ComReferenceWrappers);

            foreach (var reference in comReferences)
            {
                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 name = MSBuildItem.GetEvaluatedInclude(reference);
                    if (Path.IsPathRooted(name))
                    {
                        this.projectRelativeFilePath = name;
                    }
                    else
                    {
                        this.projectRelativeFilePath = Path.Combine(this.ProjectMgr.ProjectFolder, name);
                    }

                    if (renameItemNode)
                    {
                        this.ItemNode.Rename(Path.GetFileNameWithoutExtension(name));
                    }
                    break;
                }
            }
        }
        private void SetHintPathAndPrivateValue(ProjectInstance instance)
        {
            // Private means local copy; we want to know if it is already set to not override the default
            string privateValue = this.ItemNode.GetMetadata(ProjectFileConstants.Private);

            // Get the list of items which require HintPath
            IEnumerable <ProjectItemInstance> references = MSBuildProjectInstance.GetItems(instance, MsBuildGeneratedItemType.ReferenceCopyLocalPaths);

            // Remove the HintPath, we will re-add it below if it is needed
            if (!String.IsNullOrEmpty(this.assemblyPath))
            {
                this.ItemNode.SetMetadata(ProjectFileConstants.HintPath, null);
            }

            // Now loop through the generated References to find the corresponding one
            foreach (ProjectItemInstance reference in references)
            {
                string fileName = Path.GetFileNameWithoutExtension(MSBuildItem.GetEvaluatedInclude(reference));
                if (String.Compare(fileName, this.assemblyName.Name, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    // We found it, now set some properties based on this.

                    string hintPath = MSBuildItem.GetMetadataValue(reference, ProjectFileConstants.HintPath);
                    if (!String.IsNullOrEmpty(hintPath))
                    {
                        if (Path.IsPathRooted(hintPath))
                        {
                            hintPath = PackageUtilities.GetPathDistance(this.ProjectMgr.BaseURI.Uri, new Uri(hintPath));
                        }

                        this.ItemNode.SetMetadata(ProjectFileConstants.HintPath, hintPath);
                        // If this is not already set, we default to true
                        if (String.IsNullOrEmpty(privateValue))
                        {
                            this.ItemNode.SetMetadata(ProjectFileConstants.Private, true.ToString());
                        }
                    }
                    break;
                }
            }
        }
        /// <summary>
        /// Does the actual job of resolving an assembly reference. We need a private method that does not violate
        /// calling virtual method from the constructor.
        /// </summary>
        private void ResolveAssemblyReference()
        {
            if (this.ProjectMgr == null || this.ProjectMgr.IsClosed)
            {
                return;
            }

            var instance = this.ProjectMgr.ProjectInstance;

            BuildInstance(this.ProjectMgr, instance, MsBuildTarget.ResolveAssemblyReferences);
            IEnumerable <ProjectItemInstance> group = MSBuildProjectInstance.GetItems(instance, ProjectFileConstants.ReferencePath);

            if (group != null)
            {
                foreach (var item in group)
                {
                    string fullPath = this.GetFullPathFromPath(MSBuildItem.GetEvaluatedInclude(item));
                    System.Reflection.AssemblyName name = System.Reflection.AssemblyName.GetAssemblyName(fullPath);

                    // Try with full assembly name and then with weak assembly name.
                    if (String.Compare(name.FullName, this.assemblyName.FullName, StringComparison.OrdinalIgnoreCase) == 0 || String.Compare(name.Name, this.assemblyName.Name, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        if (!NativeMethods.IsSamePath(fullPath, this.assemblyPath))
                        {
                            // set the full path now.
                            this.assemblyPath = fullPath;

                            // We have a new item to listen too, since the assembly reference is resolved from a different place.
                            this.fileChangeListener.ObserveItem(this.assemblyPath);
                        }

                        this.resolvedAssemblyName = name;

                        // No hint path is needed since the assembly path will always be resolved.
                        return;
                    }
                }
            }
        }