2017-05-09 7 views
0

私は、カスタムプロジェクトのプロパティのカップルのためのプロジェクトの設計者にタブを追加するVSIXパッケージを開発しようとしています。 this postに記載されているCfgPropertyPagesGuidsAddCSharpを使用して、VS 2013で動作するパッケージを用意しました。ただし、VSIXプロジェクトをVS 2010に移植した後、カスタムプロパティページが読み込まれません。 2011年から代替2010

This questionは答えを持っていません。 another questionへの答えは、カスタムプロジェクトサブタイプの作成を示唆していますが、GUIからいくつかの追加のプロジェクトプロパティを編集できるだけの仕事のようです。これは初めてのVSIXパッケージで作業しているので、できるだけシンプルにするよう努めています。

私は.NET project systemのソースを閲覧しようとしましたが、私は適切にページを登録することを探していると思います正確に何か分かりません。どんな指導も大変ありがとう。

ありがとうございました。

答えて

0

私は予想以上に簡単だったパッケージ、プロジェクトのためのサブタイプを作成することになりました。大きな課題は、異なるSDKバージョンを参照するため、VS2013パッケージとVS2010パッケージの間でアプリケーションコードを共有する方法を見つけ出すことでした。私は、2つの別々のプロジェクトファイルを作成し、各プロジェクトのリンク参照として共有コードを組み込みました。

IPropertyPageの実装をPropPageBasePropPageUserControlBaseでモデル化しました。マイクロソフトが提供するコードはより複雑であるため、そのコードの一部を参考にしました。

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を書きました。おそらくあなたはそれが役に立つと思うかもしれません。