65.9K
CodeProject 正在变化。 阅读更多。
Home

修改 SQLServer 2005 最近列表

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (2投票s)

2010年3月15日

CPOL

2分钟阅读

viewsIcon

26391

downloadIcon

226

演示如何使用 Reflection 和 SQL 程序集调整 SQL2005 MRU。

引言

我的 Microsoft SQL Server Management Studio 服务器列表中有很多服务器已经无法访问,为了避免完全重建列表,我首先在 ServerFault 上提问,询问是否可以编辑 SQL Server Management Studio 的 MRU(最近使用)列表。得到的回复是不可能的,但我决定调查一下是否真的如此。于是我启动了 Reflector,查看了 SQL Management Studio DLL 内部的代码,结果发现… 实际上是可以的。

Using the Code

由于这段代码需要包含在 Microsoft SQL Server Management Studio 中的一些库,我无法重新分发它们。但是,如果您打开项目并添加对这些库的引用,您就可以编译它了。

需要添加的引用可以来自 SSMS Express 或 Full 版本 2005。(我已经在 CheckAssembly.vb 中记录了这些位置。)

'Express - 'C:\Program Files\Microsoft SQL Server\90\Tools\Binn\
VSShell\Common7\IDE\Microsoft.SqlServer.Express.ConnectionDlg.dll

'Full - C:\Program Files\Microsoft SQL Server\90\Tools\Binn\
VSShell\Common7\IDE\ConnectiondDlg.dll	 

请注意,要找到有关组件内部使用的属性和对象的信息,我们需要使用 Reflector。

reflectoroutput.png

一旦我们知道如何找到感兴趣的属性和方法,我们就需要实际连接到它们,以便使用它们。重要的是要注意,由于许多对象在库内部声明为私有,我们无法使用强类型,因此我们只需使用 GetType 来确保一切按预期工作。

For Each pp As PropertyInfo In _
  GetType(ConnectionDlg.Personalization).GetProperties_
	(BindingFlags.Static Or BindingFlags.NonPublic)
    If String.Equals(pp.Name, "Instance") Then
        t = CType(pp.GetValue(GetType(ConnectionDlg.Personalization), Nothing), _
         ConnectionDlg.Personalization)
        Exit For
    End If
Next

现在我们已经找到了反射的内部实例 Object,我们可以开始对其进行操作,以构建屏幕上的服务器列表,该列表可以被使用。EnumObject 方法是我调用反射方法的方式,并启用了从同一列表中删除的功能。

 Dim d As System.Collections.Specialized.HybridDictionary = Nothing

For Each ff As FieldInfo In t.GetType.GetFields_
	(BindingFlags.NonPublic Or BindingFlags.Instance)
    Debug.Print(ff.Name)

    Select Case ff.Name
        Case "typeTable"
            d = CType(ff.GetValue(t), System.Collections.Specialized.HybridDictionary)
    End Select
Next

If d IsNot Nothing Then
    sl = d.Item(g)
    EnumObject(sl, False)
End If

EnumObject 是递归的,因为该列表是一个链表,我们需要能够遍历该列表以找到实际数据,因为原始对象有一个 String 方法,它只是返回数据的副本,而不是实际对象。

Private Sub EnumObject(ByVal o As Object, ByVal remove As Boolean)
    Dim head As Object
    Dim nextitem As Object

    If o Is Nothing Then Return

    'Debug.Print("Enum object - " & o.GetType.ToString & " (Fields)")
    For Each ff As FieldInfo In o.GetType.GetFields_
	(BindingFlags.NonPublic Or BindingFlags.Instance)
        If String.Equals(ff.Name, "head", StringComparison.OrdinalIgnoreCase) Then
            head = ff.GetValue(o)
            EnumObject(head, remove)
        End If

        If String.Equals(ff.Name, "next", StringComparison.OrdinalIgnoreCase) Then
            nextitem = ff.GetValue(o)

            EnumObject(nextitem, remove)
        End If

    Next   
    
    'more code here about actually getting the data
End Sub

最后,一旦我们将服务器列表显示给用户,我们允许他们从 Listbox 中选择一个,然后单击“删除”。这将再次调用 EnumObjects ,但启用记录的删除。

关注点

由于所有方法和类在 SQL 库内部都是 Private ,因此访问它们的唯一方法就是使用反射。

请注意,这只在 SQL2005 上进行了测试,而且我只是为了解决我自己的特定问题而做的。

如果您选择运行此程序,请确保在运行之前关闭 SQL Server Management Studio,因为我不确定谁以及何时写入该文件。

历史

  • 2010-03-11 首次发布
© . All rights reserved.