2017-05-09 2 views
0

몇 가지 사용자 지정 프로젝트 속성에 대한 탭을 프로젝트 디자이너에 추가하는 VSIX 패키지를 개발하려고합니다. this post에 설명 된대로 CfgPropertyPagesGuidsAddCSharp을 사용하여 VS 2013에서 작동하는 패키지를 보유하고 있습니다. 그러나 VSIX 프로젝트를 VS 2010으로 이식하면 사용자 지정 속성 페이지가로드되지 않습니다.Visual Studio 2010에 대한 CfgPropertyPagesGuidsAddCSharp의 대안

This question 2011 년에는 답변이 없습니다. another question에 대한 대답은 사용자 정의 프로젝트 부속 유형을 만드는 것이지만 GUI에서 일부 추가 프로젝트 특성을 편집 할 수있는 엄청난 양의 작업처럼 보입니다. VSIX 패키지를 처음 사용하기 때문에 가능한 한 간단하게 유지하려고합니다.

나는 .NET project system에 대한 출처를 통해 검색을 시도했지만 정확히 내가 페이지를 제대로 등록하기 위해 무엇을 찾고 있는지 확실하지 않습니다. 어떤 지침이라도 대단히 감사 할 것입니다.

감사합니다.

답변

0

패키지의 프로젝트 하위 유형이 만들어져 예상보다 쉬웠습니다. 더 큰 문제는 다른 SDK 버전을 참조하기 때문에 VS2013과 VS2010 패키지간에 애플리케이션 코드를 공유하는 방법을 찾는 것이 었습니다. 결국 두 개의 프로젝트 파일을 만들고 각 프로젝트의 링크 참조로 공유 코드를 작성했습니다.

나는 PropPageBasePropPageUserControlBase으로 모델링 한 내 IPropertyPage 구현을 만들었습니다. Microsoft 제공 코드가 더 복잡하기 때문에이 코드의 일부를 참조 용으로 포함 시켰습니다.

Imports System 
Imports System.Collections.Generic 
Imports System.ComponentModel 
Imports System.Diagnostics 
Imports System.Diagnostics.CodeAnalysis 
Imports System.Runtime.InteropServices 
Imports System.Windows.Forms 
Imports Microsoft.VisualStudio 
Imports Microsoft.VisualStudio.OLE.Interop 
Imports Microsoft.VisualStudio.Shell.Interop 

Imports ControlPosition = System.Drawing.Point 
Imports ControlSize = System.Drawing.Size 

<ComVisible(True)> 
Public MustInherit Class PropertyPageProviderBase 
    Implements IPropertyPage, IDisposable 

    Private ReadOnly _dirtyProperties As New Dictionary(Of String, String)() 

    Private _control As Control 
    Private _defaultSize As System.Drawing.Size? 
    Private _hostedInNative As Boolean 
    Private _objects As Object() 
    Private _pageSite As IPropertyPageSite 

    <SuppressMessage(_ 
     "Microsoft.Reliability", _ 
     "CA2006:UseSafeHandleToEncapsulateNativeResources", _ 
     Justification:="Handle is not owned by us, we are just tracking a reference")> 
    Private _previousParent As IntPtr 

    Protected Sub New() 
    End Sub 

    ' ... 

    Protected Property [Property](propertyName As String) As String 
     Get 
      If String.IsNullOrEmpty(propertyName) Then 
       If propertyName Is Nothing Then 
        Throw New ArgumentNullException("propertyName") 
       End If 
       Throw New ArgumentException(_ 
        "Empty property name is invalid", _ 
        "propertyName") 
      End If 
      Dim dirtyValue As String = Nothing 
      If _dirtyProperties.TryGetValue(propertyName, dirtyValue) Then 
       Return dirtyValue 
      End If 
      Return ReadProperty(propertyName) 
     End Get 
     Set(value As String) 
      If String.IsNullOrEmpty(propertyName) Then 
       If propertyName Is Nothing Then 
        Throw New ArgumentNullException("propertyName") 
       End If 
       Throw New ArgumentException(_ 
        "Empty property name is invalid", _ 
        "propertyName") 
      End If 
      If _objects IsNot Nothing Then 
       _dirtyProperties.Item(propertyName) = value 
       If _pageSite IsNot Nothing Then 
        _pageSite.OnStatusChange(PROPPAGESTATUS.DIRTY) 
       End If 
      Else 
       Debug.Fail("Accessing property while not bound to project") 
      End If 
     End Set 
    End Property 

    ' ... 

    Protected Overridable Sub Apply() 
     If _objects Is Nothing Then 
      If _dirtyProperties.Count <> 0 Then 
       Debug.Fail("Cannot save changes. Not bound to project") 
      End If 
      Exit Sub 
     End If 
     For Each dirtyProperty As KeyValuePair(Of String, String) In _dirtyProperties 
      WriteProperty(dirtyProperty.Key, dirtyProperty.Value) 
     Next 
     _dirtyProperties.Clear() 
     If _pageSite IsNot Nothing Then 
      _pageSite.OnStatusChange(PROPPAGESTATUS.CLEAN) 
     End If 
    End Sub 

    ' ... 

    Private Shared Function ContainsMultipleProjects(vsObjects As Object()) As Boolean 
     Debug.Assert(vsObjects IsNot Nothing) 
     If vsObjects IsNot Nothing AndAlso vsObjects.Length > 1 Then 
      Dim first As IVsHierarchy = GetProjectHierarchy(vsObjects(0)) 
      For i As Integer = 1 To vsObjects.Length - 1 
       Dim current As IVsHierarchy = GetProjectHierarchy(vsObjects(i)) 
       If current IsNot first Then 
        Return True 
       End If 
      Next 
     End If 
     Return False 
    End Function 

    ' ... 

    Private Shared Function GetProjectHierarchy(vsObject As Object) As IVsHierarchy 
     Dim hierarchy As IVsHierarchy = Nothing 
     Dim itemId As UInteger 
     Dim vsCfgBrowsable As IVsCfgBrowseObject = TryCast(vsObject, IVsCfgBrowseObject) 
     If vsCfgBrowsable IsNot Nothing Then 
      ErrorHandler.ThrowOnFailure(vsCfgBrowsable.GetProjectItem(hierarchy, itemId)) 
      Return hierarchy 
     End If 
     Dim vsBrowsable As IVsBrowseObject = TryCast(vsObject, IVsBrowseObject) 
     If vsBrowsable IsNot Nothing Then 
      ErrorHandler.ThrowOnFailure(vsBrowsable.GetProjectItem(hierarchy, itemId)) 
      Return hierarchy 
     End If 
     Throw New NotSupportedException("Unsupported VS object type") 
    End Function 

    ' ... 

    Private Shared Sub WriteProperty(vsObject As Object, propertyName As String, propertyValue As String) 
     Dim hierarchy As IVsHierarchy = GetProjectHierarchy(vsObject) 
     Dim buildStorage As IVsBuildPropertyStorage = TryCast(hierarchy, IVsBuildPropertyStorage) 
     If buildStorage Is Nothing Then 
      Debug.Fail("Unsupported VS object") 
      Exit Sub 
     End If 
     ErrorHandler.ThrowOnFailure(buildStorage.SetPropertyValue(_ 
            propertyName, _ 
            String.Empty, _ 
            STORAGETYPE.PROJECT_FILE, _ 
            propertyValue)) 
    End Sub 

    ' ... 

    Private Sub _SetObjects(cObjects As UInteger, ppunk() As Object) Implements IPropertyPage.SetObjects 
     If cObjects = 0 OrElse ppunk Is Nothing OrElse ppunk.Length = 0 Then 
      SetObjects(Nothing) 
      Exit Sub 
     End If 
     If ContainsMultipleProjects(ppunk) Then 
      SetObjects(Nothing) 
      Exit Sub 
     End If 
     Debug.Assert(cObjects = CUInt(ppunk.Length), "Huh?") 
     SetObjects(ppunk) 
    End Sub 

    ' ... 

    Private Sub SetObjects(vsObjects As Object()) 
     _dirtyProperties.Clear() 
     _objects = vsObjects 
     OnObjectsChanged(EventArgs.Empty) 
    End Sub 

    ' ... 

    Private Sub WriteProperty(propertyName As String, propertyValue As String) 
     If _objects Is Nothing Then 
      Debug.Fail("Accessing property while not bound to project") 
      Exit Sub 
     End If 
     Debug.Assert(_objects.Length <> 0, "Should never have zero objects if collection is non-null") 
     For i As Integer = 0 To _objects.Length - 1 
      WriteProperty(_objects(i), propertyName, propertyValue) 
     Next 
    End Sub 

End Class 

패키지 만들기는 매우 간단합니다. 초기화 단계에서 RegisterProjectFactory으로 전화하십시오.

Imports System 
Imports System.Diagnostics 
Imports System.Runtime.InteropServices 
Imports Microsoft.VisualStudio.Modeling.Shell 
Imports Microsoft.VisualStudio.Shell 
Imports Microsoft.VisualStudio.Shell.Interop 

<ComVisible(True)> 
<ProvideBindingPath()> 
<Guid(Guids.MyCustomPackage)> 
<PackageRegistration(_ 
    UseManagedResourcesOnly:=True)> 
<ProvideAutoLoad(UIContextGuids.SolutionExists)> 
<ProvideProjectFactory(_ 
    GetType(MyCustomProjectFactory), _ 
    Nothing, _ 
    Nothing, _ 
    Nothing, _ 
    Nothing, _ 
    Nothing)> 
<ProvideObject(_ 
    GetType(MyCustomPropertyPageProvider))> 
Public Class MyCustomPackage 
    Inherits Package 
    Protected Overrides Sub Initialize() 
     MyBase.Initialize() 
     Dim factory As New MyCustomProjectFactory(Me) 
     Try 
      Me.RegisterProjectFactory(factory) 
     Catch ex As ArgumentException 
      Debug.Fail(ex.Message, ex.ToString()) 
     End Try 
    End Sub 
End Class 

나는 MPF isn't designed for project sub-types 때문에, MPF ProjectFactory 클래스를 사용하지 않았다. 대신, 나는 FlavoredProjectFactoryBase에서 직접 물려 받았습니다.

Imports System 
Imports System.Diagnostics.CodeAnalysis 
Imports System.Runtime.InteropServices 
Imports Microsoft.VisualStudio.Shell.Flavor 

<SuppressMessage(_ 
    "Microsoft.Interoperability", _ 
    "CA1405:ComVisibleTypeBaseTypesShouldBeComVisible", _ 
    Justification:="Blame Microsoft? No other way around this")> 
<ComVisible(True)> 
<Guid(Guids.MyCustomProjectFactory)> 
Public Class MyCustomProjectFactory 
    Inherits FlavoredProjectFactoryBase 

    Private ReadOnly _package As MyCustomPackage 

    Public Sub New() 
     Me.New(Nothing) 
    End Sub 

    Public Sub New(package As MyCustomPackage) 
     If package Is Nothing Then 
      Throw New ArgumentNullException("package") 
     End If 
     _package = package 
    End Sub 

    Protected Overrides Function PreCreateForOuter(outerProjectIUnknown As IntPtr) As Object 
     Return New MyCustomProject(_package) 
    End Function 

End Class 

프로젝트 클래스는 사용자 지정 속성 페이지의 GUID를 속성 페이지 GUID 목록에 추가해야합니다. 당신은 XML 편집기에서 프로젝트 파일을 열고 수동으로 빌드 속성 중 일부를 조정해야합니다 : 문제가 점점 사물이 작동하는 데있어 사람을 위해

Imports System 
Imports System.Collections.Generic 
Imports System.Diagnostics.CodeAnalysis 
Imports System.Runtime.InteropServices 
Imports Microsoft.VisualStudio 
Imports Microsoft.VisualStudio.Shell.Flavor 
Imports Microsoft.VisualStudio.Shell.Interop 

<SuppressMessage(_ 
    "Microsoft.Interoperability", _ 
    "CA1405:ComVisibleTypeBaseTypesShouldBeComVisible", _ 
    Justification:="Blame Microsoft? No other way around this")> 
<ComVisible(True)> 
<Guid(Guids.MyCustomProject)> 
Public Class MyCustomProject 
    Inherits FlavoredProjectBase 

    Private Const GuidFormat As String = "B" 

    Private Shared ReadOnly PageSeparators As String() = {";"} 

    Private ReadOnly _package As MyCustomPackage 

    Public Sub New() 
     Me.New(Nothing) 
    End Sub 

    Public Sub New(package As MyCustomPackage) 
     If package Is Nothing Then 
      Throw New ArgumentNullException("package") 
     End If 
     _package = package 
    End Sub 

    Protected Overrides Function GetProperty(itemId As UInteger, propId As Integer, ByRef [property] As Object) As Integer 
     If propId = CInt(__VSHPROPID2.VSHPROPID_PropertyPagesCLSIDList) Then 
      ErrorHandler.ThrowOnFailure(MyBase.GetProperty(itemId, propId, [property])) 
      Dim pages As New HashSet(Of String)() 

      If [property] IsNot Nothing Then 
       For Each page As String In CStr([property]).Split(PageSeparators, StringSplitOptions.RemoveEmptyEntries) 
        Dim blah As Guid = Nothing 
        If Guid.TryParseExact(page, GuidFormat, blah) Then 
         pages.Add(page) 
        End If 
       Next 
      End If 

      pages.Add(Guids.MyCustomPropertyPageProviderGuid.ToString(GuidFormat)) 
      [property] = String.Join(PageSeparators(0), pages) 
      Return VSConstants.S_OK 
     End If 
     Return MyBase.GetProperty(itemId, propId, [property]) 
    End Function 

    Protected Overrides Sub SetInnerProject(innerIUnknown As IntPtr) 
     If MyBase.serviceProvider Is Nothing Then 
      MyBase.serviceProvider = _package 
     End If 
     MyBase.SetInnerProject(innerIUnknown) 
    End Sub 

End Class 

마지막 힌트. 최소한 GeneratePkgDefFileIncludeAssemblyInVSIXContainertrue으로 설정해야합니다.

0

얼마 전에 CfgPropertyPagesGuidsAddCSharp 속성을 사용하여 사용자 지정 속성 페이지를 추가하는 방법을 설명하는 blog post을 작성했습니다. 아마 당신은 그것을 유용하다고 생각할 수 있습니다.

관련 문제