编写VS.NET的Add-in帮助程序调试

18 篇文章 0 订阅
16 篇文章 0 订阅

Visual Studio .NETIDE中利用中断进行程序调试时,一般只有简单的局部变量或表达式可以直接看到结果。如果是一个DataSet之类的对象,在Locals窗口中能够做到的只是一级一级地展开,最后看到一堆零散的属性值,其中大多数属性对排错用处并不大。真正有用的是ADO.NET的查询结果,如果能够将一个DataSet变量中的DataTable用一个 DataGrid完整显示出来,是不是很诱人?

Visual Studio .NET提供的Add-in扩展机制,为我们编写自己的调试工具提供了可能。下面是一个利用Debugger对象,将被调试程序中的局部变量或表达式结果显示出来的简单例子。

一、实现步骤:

(一)创建Add-in类型的VB Project

创建Add-in类型的Project可以借助VS.NET提供的Wizard。这个Wizard的最大帮助是做好了一个 Connect类,并且OnConnection等函数都写好了基本代码,其中的核心是添加一个IDE环境Tools菜单的新命令,用来调出Add-in DLL中的命令。

以下是Connect.vb的代码片断:

 

Public Class Connect

         Implements Extensibility.IDTExtensibility2

         Implements IDTCommandTarget

        

         Dim applicationObject As EnvDTE.DTE

Dim addInInstance As EnvDTE.AddIn

' 为了便于其他部分调用IDE中的对象,定义一个静态变量DTE

    Public Shared DTE As EnvDTE.DTE ' Shared among other modules

...

Public Sub OnConnection(ByVal application As Object, ByVal connectMode As Extensibility.ext_ConnectMode, ByVal addInInst As Object, ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnConnection

... 

Try

          CommandObj = applicationObject.Commands.AddNamedCommand(objAddIn, "DebugHelper", "Debug Helper", "Executes the command for DebugHelper", True, 59, Nothing, 1 + 2)

 ' 这是在添加一个Tools菜单的命令,用于执行Add-in的功能

                CommandObj.AddControl(applicationObject.CommandBars.Item("Tools"))

            Catch e As System.Exception

                MessageBox.Show(e.ToString)

            End Try

        End If

    End Sub

 

    Public Sub Exec(ByVal cmdName As String, ByVal executeOption As vsCommandExecOption, ByRef varIn As Object, ByRef varOut As Object, ByRef handled As Boolean) Implements IDTCommandTarget.Exec

        handled = False

        If (executeOption = vsCommandExecOption.vsCommandExecOptionDoDefault) Then

            If cmdName = "DebugHelper.Connect.DebugHelper" Then

                handled = True

                ' 下面这个函数是自己写的,用于调出DebugHelper的主操作画面

                ShowMainForm()

                Exit Sub

            End If

        End If

    End Sub

 

ShowMainForm函数的功能,是显示一个调试操作画面,其功能是在调试进入中断状态时,输入一个DataSet变量名,然后通过ShowIt按钮将DataSet中的某个DataTable完整地显示在画面下方的DataGrid中。

 

(二)从调试环境中取得整个DataSet变量的内容

如何从调试器中取得一个对象型变量的完整内容呢?Add-in编程接口提供的Debugger对象有一个GetExpression方法,可以将一个字符串转换成一个Expression对象,而Expression对象的Value属性可返回表达式的值。

例如,下面的代码可以将调试者输入的变量名或者表达式的值显示出来:

Private _debugger As EnvDTE.Debugger

_debugger = Connect.DTE.Debugger

Dim expr As EnvDTE.Expression

expr = _debugger.GetExpression(txtExpression.Text)

MessageBox.Show(expr.Value)

但是,很遗憾,Expression对象的Value属性只能返回简单数据类型的值(诸如整数、字符串、日期等),如果输入一个DataSet变量,这个Value属性返回的仅仅是一个表示其类型的字符串:{System.Data.DataSet}

为了解决这个问题,我们想到一个最笨的办法:因为DataSet中的接口信息是确定的,就用Expression对象求取不同的表达式的值,然后自己“捏造”一个DataSetDataGrid显示,具体步骤(比如说用户输入的DataSet变量是ds):

取表达式ds.DataSetName的值,并据此创建一个新的DataSet对象

取表达式ds.Tables.Count的值,确定一个循环的次数

用循环取表达式ds.Tables(I).Columns.Count的值,得到各个DataTable中的字段数

再次循环取表达式ds.Tables(I).Columns(I).ColumnName.DataType等的值,DataSetSchema就确定下来了

用类似的办法,取出ds.Tables(I).Rows(J)(K)的值,每条记录的每个字段值就拿到了。

最后,将自己新创建的DataSet与界面上的DataGrid绑定,用户就可以看到ds变量中每个DataTable的全部记录了。

以下为实现核心功能的两个函数的代码:

 

    Private Function BuildDataSetByExpression(ByVal expr As EnvDTE.Expression) As Data.DataSet

        ' The expr should be a variable such as dsData.

        ' The Expression object in Debugger only provides one-level value evaluation.

        ' You cannot get the Tables(0) from dsData Expression.

        ' This function uses own expressions to build a new DataSet.

        ' For example, in order to get the table count in the DataSet

        ' It used the dsData.Tables.Count expression.

        Dim dsData As Data.DataSet = New Data.DataSet

        Try

            If Not IsDataSet(expr) Then Return Nothing ' For in case the parameter is invalid

 

            ' Get the DataSet name from variable/expression

            dsData.DataSetName = EvaluateExpression(expr.Name + ".DataSetName")

 

            ' Get the number of DataTables in the DataSet

            Dim tableCount As Integer = CType(EvaluateExpression(expr.Name + ".Tables.Count"), Integer) ' The return value from the function is a string so CType...

 

            ' Get the DataTables with a loop

            Dim I As Integer

            Dim J As Integer

            Dim K As Integer

            Dim dTable As Data.DataTable

            Dim columnCount As Integer

            Dim dColumn As Data.DataColumn

            Dim rowCount As Integer

            Dim itemArray() As Object

 

            For I = 0 To tableCount - 1

                ' Create a new DataTable

                dTable = New DataTable

                ' Get the table name with expression

                Dim tableName As String = EvaluateExpression(expr.Name + ".Tables(" & I & ").TableName")

                dTable.TableName() = tableName.Substring(1, tableName.Length - 2) ' Remove the double quotation marks

 

                ' Get the Column count from the variable

                columnCount = CType(EvaluateExpression(expr.Name + ".Tables(" & I & ").Columns.Count"), Integer)

 

                ' Add the Columns to DataTable object

                For J = 0 To columnCount - 1

                    dColumn = New DataColumn

                    Dim columnName As String = EvaluateExpression(expr.Name + ".Tables(" & I & ").Columns(" & J & ").ColumnName")

                    dColumn.ColumnName = columnName.Substring(1, columnName.Length - 2)

                    Dim dataTypeName As String = EvaluateExpression(expr.Name + ".Tables(" & I & ").Columns(" & J & ").DataType.Name")

                    ' The return value includes 2 double quotation marks, string -> "string"

                    dataTypeName = dataTypeName.Substring(1, dataTypeName.Length - 2)

                    dColumn.DataType = Type.GetType("System." & dataTypeName, True, True) ' GetType needs the full name of Type

                    dTable.Columns.Add(dColumn)

                Next

 

                ' Get the Row count from the variable

                rowCount = CType(EvaluateExpression(expr.Name + ".Tables(" & I & ").Rows.Count"), Integer)

 

                ' Add the rows of this table

                For K = 0 To rowCount - 1

                    ' Get the ItemArray of each column

                    ReDim itemArray(columnCount - 1) ' Clear the old contents

                    For J = 0 To columnCount - 1

                        ' The expression used to get the value of the current column in current row

                        Dim columnValueExpression As String = expr.Name + ".Tables(" & I & ").Rows(" & K & ").ItemArray(" & J & ").ToString"

                        Dim valueString As String = EvaluateExpression(columnValueExpression)

                        valueString = valueString.Substring(1, valueString.Length - 2)

                        If Not valueString = "" Then ' If the column value is System.DBNull

                            itemArray(J) = valueString

                        End If

                    Next

                    ' Add the new row to the Rows

                    dTable.Rows.Add(itemArray)

                Next

                ' Add the table into the dataset

                dsData.Tables.Add(dTable)

            Next

 

        Catch ex As Exception

            MessageBox.Show(ex.ToString, "Debug Helper")

        End Try

        Return dsData

    End Function

 

    Private Function EvaluateExpression(ByVal expression As String) As String

        Try

            Dim anyExpression As EnvDTE.Expression

            anyExpression = _debugger.GetExpression(expression)

            Return anyExpression.Value ' It is a string !!!

        Catch ex As Exception

            Return "" ' Return an empty string on error

        End Try

    End Function

 

 

二、Add-in的用法:

使用这个Add-in程序的方法很简单:

(一)安装

创建Add-in Project时,Wizard会帮忙建好一个制作Setup程序的配套ProjectBuild这个Setup Project,可以得到一个.msi文件。

运行这个.msi文件,然后打开Visual Studio.NETIDE,就将看到Tools菜单下多出一个DebugHelper命令。

(二)调出其他Solution,调试进入中断。

(三)选择Tools菜单中的DebugHelper命令,调出操作画面。

(四)输入一个DataSet变量名,然后点击ShowIt按钮,该DataSet中的第一个DataTable就会显示在表格中,选择ComboBox中的其他DataTable即可察看其他结果表中的数据。

(五)如果发现Tools菜单中没有DebugHelper命令,可以用一个Wizard生成的ReCreateCommands.reg文件重建该命令,该文件内容如下:

REGEDIT4

[HKEY_CURRENT_USER/SOFTWARE/Microsoft/VSA/7.1/PreloadAddinState]

"DebugHelper.Connect"=dword:1

[HKEY_CURRENT_USER/SOFTWARE/Microsoft/VisualStudio/7.1/PreloadAddinState]

"DebugHelper.Connect"=dword:1

 

注:本程序使用Visual Studio.NET 2003编写,但是在Visual Studio.NET 2002上也应该没有问题。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值