新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> XML与各种文件格式的相互转换及相关工具。 word to xml, xml to word, html to xml, xml to pdf,
    csv to xml, rtf to xml, text to xml, xml to text, xls to xml, xml to xls
    FOP
    [返回] 中文XML论坛 - 专业的XML技术讨论区XML.ORG.CN讨论区 - XML技术『 WORD to XML, HTML to XML 』 → [求助]请问 用 c# 怎样把 html 转化为 xml ? 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 21458 个阅读者浏览上一篇主题  刷新本主题   平板显示贴子 浏览下一篇主题
     * 贴子主题: [求助]请问 用 c# 怎样把 html 转化为 xml ? 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     simonking 帅哥哟,离线,有人找我吗?
      
      
      等级:大一(猛啃高等数学)
      文章:7
      积分:102
      门派:XML.ORG.CN
      注册:2005/5/6

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给simonking发送一个短消息 把simonking加入好友 查看simonking的个人资料 搜索simonking在『 WORD to XML, HTML to XML 』的所有贴子 引用回复这个贴子 回复这个贴子 查看simonking的博客楼主
    发贴心情 



      

    演练:生成启用HTML Tidy的Visual Studio .NET2003外接程序项目的方法

    Microsoft Corporation
    Hank Davis 和 Todd Grunke
    Visual Studio Team
    Microsoft Corporation
    2003年5月
    摘要:Dave Raggett 开发的 HTML Tidy 实用程序可以识别和纠正常见的 HTML 标记错误,还可以调整标记的格式。Microsoft® Visual Studio® .NET HTML 设计器提供了一个默认的标记格式化程序和各种“自动设置格式”选项。喜欢使用 HTML Tidy 来纠正和设置 HTML 标记格式的 Web 开发人员,可以安装 Visual Studio .NET 2003 外接程序项目,该项目调用 Tidy 可执行程序或 HTML 设计器来执行自动设置格式。本文介绍如何生成、安装和运行 Visual Studio .NET 2003 外接程序项目,并提供了以多种开发语言编写的示例代码。

    目录
    简介
    HTML 有效性验证和自动设置格式
    HTML Tidy
    Visual Studio .NET 2003 外接程序项目

    过程
    下载并安装 Tidy 可执行文件
    生成 Visual Studio .NET 2003 外接程序项目
    使用 HTML Tidy 外接程序
    示例代码
    Visual Basic .NET 示例代码
    Visual C# .NET 示例代码
    Visual C++ .NET/ATL 示例代码
    Managed Extensions for C++ 示例代码
    小结
    更多信息
    简介
    以下各节介绍 HTML 设计器、Tidy 实用程序和 Visual Studio .NET 2003 外接程序项目中的 HTML 有效性验证和格式设置。每一节都提供了指向更多信息的链接。

    HTML 有效性验证和自动设置格式
    当 HTML Specific, HTML/XML, Text Editor, Options Dialog Box(英文)中启用 HTML 有效性验证后,HTML 语法错误就会在 Task List Window(英文)中列出。要显示这些错误,请在 HTML 视图中打开要编辑的 HTML 网页或 Web 窗体,设置页面的 targetSchema(英文)属性,然后从 View(视图)菜单中选择 Show Tasks(显示任务)并选择 Build Errors(生成错误)。根据选定的方案筛选出的任何无效 HTML 标记都会引发 Build Error(生成错误)条目。双击 Task List(任务列表)中的条目,可以跳到 HTML 编辑器中出现所述问题的行。在编辑器中,错误标记用红色波浪下划线标出。有关更多信息,请参阅 Task List Views(英文)和 Setting the targetSchema Property of an HTML Document(英文)。

    在 Visual Studio .NET 2003 中,可以在 Format, HTML/XML, Text Editor, Options Dialog Box(英文)中设置“自动设置格式”选项。这些可用选项使得编辑 Web 页时,可以使用集成开发环境 (IDE) 来纠正和重新设置 HTML 标记的格化,然后在设计视图中保存页面或切换到 HTML 视图。在 HTML 视图中,还可以通过从 Edit(编辑)菜单运行 Format Document(设置文档格式)命令或选择 HTML 编辑器工具栏上的 Format(格式)按钮,来手动纠正和重新设置标记的格式。文本编辑器和 HTML 设计器中的许多选项设置确定了默认的格式化程序调整标记的方式。有关这些选项的详细信息,请参阅帮助主题 Options that Affect Existing HTML, CSS, or XML Markup(英文)和 VB Specific, Basic, Text Editor, Options Dialog Box(英文)。

    HTML Tidy
    HTML Tidy 实用程序是由 Dave Raggett 为万维网协会 (W3C) 而开发的。HTML Tidy 用各种有用的方法来规范 HTML 标记,包括:

    检测丢失的或不匹配的结束标记。
    将嵌入元素的结束标记放在封闭型元素的结束标记中。
    纠正缺少“/”或“>”字符的结束标记。
    将属性值放在引号内。
    为特定字符提供 HTML 实体名称。
    将元素缩进以使标记易于阅读。
    HTML Tidy 文档定义了各种参数,这些参数指定此实用程序的运行方式。例如,-config 选项指导 Tidy 使用配置文件,Raggett 认为这是“配置 Tidy 最方便的方法”。Tidy 配置文件中可以定义页面的 <BODY> 中的其他内嵌元素或块元素。高级用户可能希望通过在“Tidy.cfg”文件中定义自定义 XML 元素来增强 Tidy 对 XML 的有限支持。

    使用 -clean 选项设置后,HTML Tidy 用 CSS 样式属性替换不适合的 <FONT> 和 <CENTER> 元素以及 <NOBR> 扩展。Tidy 不知道如何处理 ASP.NET Web 窗体中的所有标记,但是它能够识别 Web 窗体 (.aspx) 文件中伪元素语法内包含的内嵌预处理器指示 (<% ...%>),并由 Web 服务器来解释这些指示。

    Tidy.exe 可执行文件和文档可以从 http://tidy.sourceforge.net (英文)下载,该 Web 站点现在维护此实用程序。HTML Tidy 的发行说明可以从 http://www.w3.org/People/Raggett/tidy (英文)在线获得,html-tidy@w3.org (英文)中有公开的、HTML Tidy 专用的电子邮件列表。

    Visual Studio .NET 2003 外接程序项目
    Visual Studio .NET 被设计成可扩展,也就是说,具有增强和扩展集成开发环境 (IDE) 功能的能力。外接程序项目是经过编译的应用程序,可以修改菜单、命令和 IDE 的行为。Add-in Wizard(英文)可以自动执行建立 Visual Studio .NET 外接应用程序模板的过程。

    本文后面将介绍从 Add New Project Dialog Box(英文)运行外接程序向导的过程。使用此向导生成基本代码框架后,可以粘贴到示例代码中以完成 HTML Tidy 外接应用程序。本文包含可以插入到 Visual Basic .NET、Visual C# .NET 和 Visual C++/活动模板库 (ATL) 外接程序项目模板中的代码,还包含生成 Managed Extensions for C++ 类库外接程序项目的过程和代码。

    创建并安装外接程序项目后,可以使用 Add-in Manager Dialog Box(英文)来立即启用 HTML Tidy。有关外接程序项目的更多信息,请参阅 Add-in and Customization User Interface Elements(英文)和 Creating Add-ins and Wizards(英文)。

    过程
    以下过程显示如何:

    下载并安装 Tidy.exe 可执行文件。
    创建一个 Visual Studio .NET 2003 外接程序项目。
    添加所需的示例代码以完成外接应用程序。
    使用外接程序管理器,并用 HTML Tidy 设置 HTML 标记的格式。
    Visual Studio .NET 2003 外接程序向导可为 Visual Basic .NET 和 Visual C# .NET 外接程序创建模板项目。有关将 HTML Tidy 外接程序的 Visual Basic .NET 示例代码或 Visual C# .NET 示例代码添加到这些模板的默认“连接”文件中的说明,请参阅生成 Visual Studio .NET 2003 外接程序项目一节中的“如何修改外接程序项目模板的连接文件”过程。

    外接程序向导也为 Visual C++/ATL 外接程序提供了一个模板。要使用非托管 C++/ATL 代码来创建 Tidy 外接程序,请将 Visual C++ .NET/ATL 示例代码粘贴到此模板项目默认的“Connect.cpp”源文件和“Connect.h”头文件中。有关为 Managed Extensions for C++ 类库项目生成 HTML Tidy 外接程序的过程和代码,请参阅 Managed Extensions for C++ 示例代码。

    下载并安装 Tidy 可执行文件
    首先,下载并安装 HTML Tidy 可执行文件。

    如何下载并安装 Tidy 文件

    从 http://tidy.sourceforge.net(英文)Web 站点下载适用于您操作系统的 Tidy 可执行文件和 Tidy 文档版本。
    将 Tidy 可执行文件存储在本地驱动器上的某个文件夹中,您用来开发的计算机的 PATH 变量中需要包含该驱动器。
    PATH 系统变量列出操作系统要在其中搜索可执行文件的目录。因此,存储 HTML Tidy 可执行文件的目录的路径必须包含在 PATH 变量中。

    如果为 Tidy 可执行文件创建了一个新目录,例如,C:\Program Files\HTMLTidy,可以使用控制面板将此目录添加到 PATH 变量中。

    如何将 Tidy 目录添加到系统 PATH 中

    在“控制面板”中,选择“系统”。
    在“高级”选项卡上,选择“环境变量”。
    将打开“环境变量”对话框。

    在“系统变量”列表中,选择“Path”变量并选择“编辑”。
    将打开“编辑系统变量”对话框,其中显示了现有的路径。

    将所需的文件路径追加到“变量值”字段中,与前面的文件路径用分号 (;) 分隔。
    例如,;C:\PROGRA~1\HTMLTidy 告诉系统在 C:\Program Files\HTMLTidy 文件夹中查找 Tidy.exe 可执行文件。

    选择“确定”保存条目并关闭所有对话框。
    有关向 PATH 变量添加目录的更多信息,请参阅 Windows 帮助中的“控制面板”。

    生成 Visual Studio .NET 2003 外接程序项目
    接下来,创建一个 Visual Studio .NET 2003 外接程序项目。有关使用外接程序向导的更多信息,请参阅 Creating an Add-In(英文)。

    注意:HTML Tidy 外接程序项目需要安装 Visual Studio .NET 2003 和兼容的 .NET Framework 版本。如果在 Visual Studio .NET 2002 中安装,则此外接程序将无法正常工作。
    如何创建外接程序项目

    从 File(文件)菜单选择 New(新建),并选择 Project(项目)。
    将打开 New Project Dialog Box(英文)。

    在 Project Types(项目类型)窗格中,展开 Other Projects(其他项目)文件夹,并选择 Extensibility Projects(扩展性项目)文件夹。
    在 Templates(模板)窗格中,选择 Visual Studio .NET Add-in(Visual Studio .NET 外接程序)图标。
    键入外接程序项目的文件名称(例如,“HTMLTidyAddIn”),选择存储该项目的文件夹的路径,然后选择 OK(确定)。
    将打开外接程序向导的欢迎页面。

    选择 Next(下一步)。
    选择所需的开发语言,并选择 Next(下一步)。
    选中 Microsoft Visual Studio .NET(Microsoft Visual Studio .NET)复选框,清除 Microsoft VSMacros IDE(Microsoft VSMacros IDE)复选框,并选择 Next(下一步)。
    在 Add-in Manager Dialog Box(英文)中键入名称(“HTMLTidy”)和说明(“HTML Tidy 格式化程序”),并选择 Next(下一步)。
    无需选择任何选项。要想在启动 Visual Studio .NET 时自动加载外接程序,请选中该选项旁边的复选框。清除所有其他选项,选择 Next(下一步)。
    清除该选项以创建一个“关于”框,并选择 Next(下一步)。
    选择 Finish(完成)。
    接下来,需要修改默认项目模板中默认的“Connect.vb”(Visual Basic .NET) 或“Connect.cs”(Visual C# .NET) 文件。

    如何修改外接程序项目模板中的连接文件

    对于此过程中的每一步,都可以将 Visual Basic .NET 示例代码或 Visual C# .NET 示例代码复制和粘贴到您的外接程序项目的 Connect.vb 文件(VB 模板)或 Connect.cs 文件(VC# 模板)中。

    在连接文件中定义的顶级命名空间的开头处,添加一个语句,来导入 System Namespace(英文)和 System.IO Namespace(英文)。如果要使用 Windows 窗体,例如 System.Windows.Forms.MessageBox Class(英文),还应该导入 System.Windows.Forms Namespace(英文)。
    Solution Explorer(解决方案资源管理器)显示外接程序项目的 References(引用)。默认情况下,外接程序向导提供对 System.dll 的项目引用,其中包含 System 和 System.IO 命名空间。如果还打算使用 Windows 窗体,必须添加对 System.Windows.Forms.dll 的引用。

    在 Solution Explorer(解决方案资源管理器)中,右击外接程序项目的 References(引用)节点,选择 Add Reference(添加引用)。
    将打开 Add Reference Dialog Box(英文)。

    在 .NET (.NET) 选项卡上,从 Components(组件)列表中选择“System.Windows.Forms.dll”,然后单击 Select(选择)和 OK(确定)按钮,以向动态链接库 (.dll) 文件添加项目引用。
    在 Connect 类的顶部,声明一个 commandEvents 变量。
    该变量用于存储 prettyFormatCommandID 以备以后进行匹配。

    用修改后的 OnConnection() 方法替换默认的 OnConnection() 方法。
    如果修改后的方法与指定的 prettyFormatCommandID 相匹配,则调用 BeforeExecute() 方法。

    用修改后的 OnDisconnection() 方法替换默认的 OnDisconnection() 方法。
    修改后的方法允许您启用或禁用 Tidy 格式化程序,方法是选中或清除 Add-in Manager Dialog Box(英文)中外接程序名称旁边的复选框。

    添加自定义的 BeforeExecute() 方法。
    添加的这个方法的代码段最长,使得 HTML 视图编辑器使用 HTML Tidy 来纠正并重新设置 HTML 标记的格式。

    添加所需的任何 HTML Tidy 命令行参数。
    例如,-config 参数指导 Tidy 使用外部配置文件。HTML Tidy Quick Reference 提供了一个配置选项列表。

    如果您捕获了错误(这通常是一个好的做法),则添加一个命令或子例程来显示这些错误。
    例如,可以使用 .NET Framework MessageBox.Show Method (String)(英文)在标准 Windows MessageBox 中显示错误消息。或者,要将错误消息保存在方便的滚动窗口中,可以添加一个将例外和其他 HTML Tidy 消息写到 Output Window(英文)的子例程。

    当生成外接程序项目时,将创建一个经过编译的外接应用程序。当生成安装程序项目时,将为外接程序创建一个 Windows Installer 程序。

    如何生成和调试 HTML Tidy 外接程序项目

    从 Build(编译)菜单中,选择 Configuration Manager(配置管理器)。
    将打开 Configuration Manager Dialog Box(英文)。

    配置 Debug 解决方案配置,可以只编译外接程序项目的 Debug 配置。配置 Release 解决方案配置,可以编译外接程序和安装程序项目的 Release 配置。有关更多信息,请参阅 Build Configurations(英文)。
    生成 Debug 解决方案编译配置。
    修正 Task List Window(英文)中识别出的任何错误。
    重新生成 Debug 解决方案编译配置,直到外接程序项目中的所有错误都被修正为止。
    生成 Release 解决方案编译配置。
    现在,您用来开发的计算机上就可以使用外接程序项目了。但是,可能还需要启动 Setup.exe,该程序运行由安装程序项目生成的 Windows Installer (.msi) 文件。遇到以下某种情形需要这样做:

    在其他计算机上安装 HTML Tidy 外接程序。
    当询问是否要删除此外接程序时,您选择了 Yes(是)。
    安装外接程序的计算机的注册表已破坏。
    如何在您用来开发的计算机上运行 HTML Tidy 安装程序

    在您用来开发的计算机上打开 HTML Tidy 外接程序的安装程序项目。
    在 Solution Explorer(解决方案资源管理器)中,右击 Setup(安装程序)项目并选择 Properties(属性)。
    将打开 Build, Configuration Properties, Deployment Project Properties Dialog Box(英文)。

    选择 Output file name(输出文件名称)字段旁边的 Browse(浏览)按钮,浏览到生成 Windows Installer (.msi) 文件和 Setup.exe 的目录。
    在 Package(程序包)文件下拉菜单中,选择“In setup file”(在安装程序文件中)。此值指定外接应用程序、注册表项和安装说明将被打包在 Windows Installer (.msi) 文件中。
    生成同时包含外接程序和安装程序项目的 Retail 解决方案配置。
    右击 Solution Explorer(解决方案资源管理器)中的 Setup(安装程序)项目,从快捷菜单中选择 Install(安装)。
    这将启动 HTML Tidy 外接程序项目的安装向导。

    如何在另一台计算机上安装 HTML Tidy

    如果需要在另一台计算机上安装外接程序,请确保目标计算机上安装有 Visual Studio .NET 2003、兼容的 .NET Framework 版本和 Tidy 可执行文件。
    注意:如果目标计算机中没有安装所需的软件,安装将被回滚而且计算机会返回到安装前的状态。
    将用来开发的计算机上的 Output 文件目录中的 Windows Installer (.msi) 和 Setup.exe 文件复制到目标计算机上的某个目录中。
    在目标计算机上,使用 Windows 资源管理器浏览到包含 Setup.exe 和 Windows Installer 文件的目录。
    双击 Setup.exe,以运行 HTML Tidy 外接程序项目的安装向导。
    注意:在目标计算机上,要运行 Windows Installer,您必须具有安装权限。
    安装向导根据外接程序的需要来配置目标计算机的注册表。有关更多信息,请参阅 Setup Projects(英文)和 Walkthrough:Deploying a Windows Application(英文)。

    如何修改 HTML Tidy 外接程序

    在使用 HTML Tidy 外接程序之后再对其进行修改,必须首先禁用该外接程序。

    在 Tools(工具)菜单中,选择 Add-in Manager(外接程序管理器);或者按组合键 ALT+T,然后按 A 键。
    将打开 Add-in Manager Dialog Box(英文)。

    清除外接程序名称左侧的复选框,以禁用 HTML Tidy。
    关闭将要部署外接应用程序的计算机上运行的所有 Visual Studio .NET 实例。
    如果您在用来开发的计算机上已经安装并运行了外接程序,则必须关闭并重新启动 Visual Studio .NET 后,才能修改外接程序。

    在用来开发的计算机上编辑外接程序项目。
    重新生成外接程序和安装程序项目。
    要在另一台计算机上重新安装经过修改的 HTML Tidy 外接程序,请将安装程序项目生成的 Setup.exe 和 Windows Installer (.msi) 文件复制到目标计算机中,然后在该计算机上运行 Setup.exe。
    有关更多信息,请参阅 Setup Projects(英文)和 Walkthrough:Deploying a Windows Application(英文)。

    使用 HTML Tidy 外接程序
    HTML Tidy 外接程序创建完成后,Visual Studio .NET 2003 可以立即运行该程序。使用 Add-in Manager Dialog Box(英文)可以打开和关闭 HTML Tidy。

    如何打开和关闭 HTML Tidy

    启动目标计算机上的 Visual Studio .NET 2003。
    在 Tools(工具)菜单中,选择 Add-in Manager(外接程序管理器);或者按组合键 ALT+T,然后按 A 键。
    将打开 Add-in Manager Dialog Box(英文)。

    选中外接程序名称左侧的复选框,以启用 HTML Tidy。
    - 或者 -

    清除此复选框,以启用默认的 HTML 标记格式化程序。

    如何纠正和设置 HTML 标记的格式

    使用 Add-in Manager(外接程序管理器)来选择所需的标记格式化程序。
    在 Visual Studio .NET 2003 中打开一个 Web 项目。
    在 HTML 设计器中打开要编辑的 HTML 网页或 Web 窗体。
    使用 Automatic Formatting(自动设置格式)或手动 Format Document(设置文档格式)命令来调整标记。
    要使用 Automatic Formatting(自动设置格式)选项:

    在 Format, HTML/XML, Text Editor, Options Dialog Box(英文)中选择所需的 Automatic Formatting(自动设置格式)选项。
    编辑文档。例如,在设计视图面上移动一个控件。
    在设计视图中保存文档或切换到 HTML 视图。
    要使用手动 Format Document(设置文档格式)命令:

    清除 Format, HTML/XML, Text Editor, Options Dialog Box(英文)中的 Automatic Formatting(自动设置格式)选项。
    编辑文档。
    如果处于设计视图中,请切换到 HTML 视图。
    使用以下某种方法来运行 Format Document(设置文档格式)命令:
    从 Edit(编辑)菜单中选择 Advanced(高级),然后选择 Format Document(设置文档格式)。
    选择 HTML 编辑器工具栏上的 Format(格式)按钮。
    按组合键 CTRL+K、CTRL+D。
    Visual Basic .NET 示例代码
    以下是生成 Visual Studio .NET 2003 外接程序项目一节的“如何修改外接程序项目模板的连接文件”过程中各步骤所使用的 Visual Basic .NET 代码段。

    VB 步骤 1:导入 System、System.IO 和 System.Windows.Forms
    添加的命名空间以粗体显示。

       Imports System
       Imports Microsoft.Office.Core
       Imports Extensibility
       Imports System.Runtime.InteropServices
       Imports EnvDTE
       Imports System.IO
       Imports System.Windows.Forms
    VB 步骤 2:声明 commandEvents 变量
    添加的声明以粗体显示。

       public class Connect
    Implements Extensibility.IDTExtensibility2
          <System.ContextStaticAttribute()> Public WithEvents _
    CommandEvents As EnvDTE.CommandEvents
    VB 步骤 3:替换 OnConnection() 方法
    自定义的这个方法创建了一个事件处理程序,当该程序接收到 prettyFormatCommandID 时,会调用添加的 BeforeExecute() 方法(请参阅步骤 5)。表示 Visual Studio .NET 集成开发环境 (IDE) 和 HTML Tidy 外接应用程序的活动实例的两个对象变量,作为 application 和 addInInst 参数传递给这个 OnConnection() 方法。

          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

             applicationObject = CType(application, EnvDTE.DTE)
             addInInstance = CType(addInInst, EnvDTE.AddIn)

             Dim vsCommandGroup As String = _
             "{1496a755-94de-11d0-8c3f-00c04fc2aae2}"
             Dim prettyFormatCommandID As Integer = 319

             ' 创建处理 prettyFormatCommandID 的命令事件,
             '   该事件在默认处理程序之前接到通知。
             CommandEvents = _
    applicationObject.Events.CommandEvents(vsCommandGroup, _
    prettyFormatCommandID)
          End Sub
    VB 步骤 4:替换 OnDisconnection() 方法
    自定义的这个方法允许您打开或关闭 HTML Tidy 实用程序,方法是选中或清除 Add-in Manager Dialog Box(英文)中外接程序名称左侧的复选框。

          Public Sub OnDisconnection( _
    ByVal RemoveMode As Extensibility.ext_DisconnectMode, _
    ByRef custom As System.Array) _
    Implements Extensibility.IDTExtensibility2.OnDisconnection
             commandEvents = Nothing
          End Sub
    VB 步骤 5:添加 BeforeExecute() 方法
    添加的这个方法将 HTML 格式的 IDE 调用定向到 HTML Tidy 实用程序,该方法还捕捉和显示例外及其他 HTML Tidy 消息。

    注意:在这个方法中,UseShellExecute 属性被设置成 False, 这允许代码重定向输入、输出和错误流。当此属性被设置成 False 时,则无法使用 WorkingDirectory 属性来定位 Tidy 可执行文件。有关更多信息,请参阅 ProcessStartInfo.UseShellExecute Property(英文)和 ProcessStartInfo.WorkingDirectory Property(英文)。
          Private Sub BeforeExecute(ByVal Guid As String, _
    ByVal ID As Integer, ByVal CustomIn As Object, _
    ByVal CustomOut As Object, ByRef CancelDefault As Boolean) _
    Handles commandEvents.BeforeExecute
             ' 表示已经处理了此命令事件,
             '   因此,无需再处理该事件。
             CancelDefault = True

             Try
                Dim doc As Document = _
    applicationObject.Documents.Item(CustomIn)
                Dim td As TextDocument = _
    CType(doc.Object("TextDocument"), TextDocument)
                Dim sp As TextPoint = td.StartPoint
                Dim ep As TextPoint = td.EndPoint
                Dim editStartPt As EditPoint = sp.CreateEditPoint()
                Dim editEndPt As EditPoint = ep.CreateEditPoint()

                ' 获取文档内容。
                Dim txtHTMLDoc As String = editStartPt.GetText(editEndPt)

                ' 设置进程信息。
                Dim psi As New System.Diagnostics.ProcessStartInfo
                psi.FileName = "tidy.exe"
                psi.Arguments = "-i"
                psi.CreateNoWindow = True
                psi.UseShellExecute = False
                psi.RedirectStandardInput = True
                psi.RedirectStandardOutput = True
                psi.RedirectStandardError = True

                ' 创建进程。
                Dim p As New System.Diagnostics.Process

                ' 将进程信息与进程相关联。
                p.StartInfo = psi

                ' 运行进程。
                Dim fStarted As Boolean = p.Start()
                If Not fStarted Then _
    Throw New Exception("Unable to start Tidy process.")

                ' 设置流以与进程的标准输入/标准输出进行交互。
                Dim sw As StreamWriter = p.StandardInput
                Dim sr As StreamReader = p.StandardOutput
                Dim strFormattedDoc As String = Nothing

                ' 将 HTML 文档的内容写到进程的标准输入。
                sw.Write(txtHTMLDoc)
                sw.Close()

                ' 读取进程的标准输出并存储在 strFormattedDoc 中。
                strFormattedDoc = sr.ReadToEnd()
                sr.Close()

                ' 处理非标准输出文字,而不显示错误文字。
                If strFormattedDoc = "" Then
                   Dim srError As StreamReader = p.StandardError
                   Dim strError As String = srError.ReadToEnd()
                   srError.Close()
                   Throw New Exception("Tidy failed with error " _
    & "information: " & strError)
                End If

                ' 用进程的输出替换文档的原始文字。
                editStartPt.ReplaceText(editEndPt, strFormattedDoc, _
    CInt(vsEPReplaceTextOptions.vsEPReplaceTextTabsSpaces))

             Catch ex As Exception
                System.Windows.Forms.MessageBox.Show(ex.ToString())
             End Try
          End Sub
    VB 步骤 6:添加您喜欢的 HTML Tidy 配置选项
    要指定 HTML Tidy 的运行方式,请在步骤 5 示例代码的 BeforeExecute() 方法中,将配置选项添加到指定给 psi.Arguments 属性的字符串值中:

                psi.Arguments = "-i";
    在以下示例中,添加了 -config 选项。此选项告诉 Tidy 使用名为“config.txt”的外部配置文件:

                psi.Arguments = "-config config.txt -i";
    注意:确保将 -i 选项放在参数字符串的末尾。
    HTML Tidy Quick Reference 提供了一个配置选项列表。

    VB 步骤 7:捕捉和显示任何例外
    如果抛出例外,请记住添加代码来捕捉和显示这些例外。在步骤 5 示例代码的 BeforeExecute() 方法中,Catch 语句使用 .NET Framework MessageBox.Show Method (String)(英文)将每个 Tidy 消息显示在一个标准的 Windows MessageBox 中:

             Catch ex As Exception
                System.Windows.Forms.MessageBox.Show(ex.ToString())
    您可能更希望将来自 HTML Tidy [sunyan1]的例外和其他消息显示在滚动的 Output Window(英文)中。如果是这样,请调用错误处理子例程来替换 Catch 语句:

             Catch ex As Exception
                ErrToOutputWindow(ex)
    然后,将上面提到的方法添加到 Connect 类中。以下示例方法向输出窗口添加一个新窗格,并将例外 ex 的文字写到这个新窗格中:

          Sub ErrToOutputWindow(ByVal ex As Exception)
             ' 为输出窗口创建工具窗口句柄。
             Dim win As Window = _
    applicationObject.Windows.Item(EnvDTE.Constants.vsWindowKindOutput)
             ' 访问输出窗口。
             Dim OW As OutputWindow = win.Object
             ' 向输出窗口添加新窗格。
             Dim OWp As OutputWindowPane = _
    OW.OutputWindowPanes.Add("HTML Tidy Add-in")
             ' 将例外文字写到这个新窗格中。
             OWp.OutputString(ex.ToString())
          End Sub
    有关更多信息,请参阅 Controlling the Output Window(英文)、Exception Handling Fundamentals(英文)、Using the Try/Catch Block to Catch Exceptions(英文)、Try...Catch...Finally Statements(英文)和 Visual Basic .NET Code Sample:Try-Catch-Finally(英文)。

    Visual C# .NET 示例代码
    以下是“生成 Visual Studio .NET 2003 外接程序项目”一节的“如何修改外接程序项目模板的连接文件”过程中各步骤所使用的 Visual C# .NET 代码段。

    VC# 步骤 1:导入 System、System.IO 和 System.Windows.Forms
    添加的命名空间以粗体显示。

       using System;
       using Microsoft.Office.Core;
       using Extensibility;
       using System.Runtime.InteropServices;
       using EnvDTE;
       using System.IO;
       using System.Windows.Forms;
    VC# 步骤 2:声明 commandEvents 变量
    添加的声明以粗体显示。

       public class Connect : Object, Extensibility.IDTExtensibility2
       {
          CommandEvents commandEvents;
    VC# 步骤 3:替换 OnConnection() 方法
    自定义的这个方法创建了一个事件处理程序,当该程序接收到 prettyFormatCommandID 时,会调用添加的 BeforeExecute() 方法(请参阅步骤 5)。表示 Visual Studio .NET 集成开发环境 (IDE) 和 HTML Tidy 外接应用程序的活动实例的两个对象变量,作为 application 和 addInInst 参数传递给这个 OnConnection() 方法。

          public void OnConnection(object application,
    Extensibility.ext_ConnectMode connectMode,
    object addInInst, ref System.Array custom)
          {
             applicationObject = (_DTE)application;
             addInInstance = (AddIn)addInInst;
             
             string vsCommandGroup = "{1496a755-94de-11d0-8c3f-00c04fc2aae2}";
             int prettyFormatCommandID = 319;

             // 创建处理 prettyFormatCommandID 的命令事件,
             //   该事件在默认处理程序之前接到通知。
             commandEvents =
    applicationObject.Events.get_CommandEvents(vsCommandGroup,
    prettyFormatCommandID);
             commandEvents.BeforeExecute += new
    _dispCommandEvents_BeforeExecuteEventHandler(BeforeExecute);
          }
    VC# 步骤 4:替换 OnDisconnection() 方法
    自定义的这个方法允许您打开或关闭 HTML Tidy 实用程序,方法是选中或清除 Add-in Manager Dialog Box(英文)中外接程序名称左侧的复选框。

          public void OnDisconnection(Extensibility.ext_DisconnectMode
    disconnectMode, ref System.Array custom)
          {
             commandEvents.BeforeExecute -= new
    _dispCommandEvents_BeforeExecuteEventHandler(BeforeExecute);
             commandEvents = null;
          }
    VC# 步骤 5:添加 BeforeExecute() 方法
    添加的这个方法将 HTML 格式的 IDE 调用定向到 HTML Tidy 实用程序,该方法还捕捉和显示例外及其他 HTML Tidy 消息。

    注意:在这个方法中,UseShellExecute 属性被设置成 False。这允许代码重定向输入、输出和错误流。当此属性被设置成 False 时,则无法使用 WorkingDirectory 属性来定位 Tidy 可执行文件。有关更多信息,请参阅 ProcessStartInfo.UseShellExecute Property(英文)和 ProcessStartInfo.WorkingDirectory Property(英文)。
          private void BeforeExecute(string Guid, int ID,
    object CustomIn, object CustomOut, ref bool CancelDefault)
          {
             // 表示已经处理了此命令事件,
             //   因此,无需再处理该事件。
             CancelDefault = true;

             try
             {
                Document doc = applicationObject.Documents.Item(CustomIn);
                TextDocument td = (TextDocument) doc.Object("TextDocument");

                TextPoint sp = td.StartPoint;
                TextPoint ep = td.EndPoint;
                EditPoint editStartPt = sp.CreateEditPoint();
                EditPoint editEndPt = ep.CreateEditPoint();

                // 获取文档内容。
                string txtHTMLDoc = editStartPt.GetText(editEndPt);
                
                // 设置进程信息。
                System.Diagnostics.ProcessStartInfo psi =
    new System.Diagnostics.ProcessStartInfo();
                psi.FileName = "tidy.exe";
                psi.Arguments = "-i";
                psi.CreateNoWindow = true;
                psi.UseShellExecute = false;
                psi.RedirectStandardInput = true;
                psi.RedirectStandardOutput = true;
                psi.RedirectStandardError = true;

                // 创建进程。
                System.Diagnostics.Process p =
    new System.Diagnostics.Process();
                
                // 将进程信息与进程相关联。
                p.StartInfo = psi;

                // 运行进程。
                bool fStarted = p.Start();

                if (!fStarted)
                   throw new Exception("Unable to start Tidy process");

                // 设置流以与进程的标准输入/标准输出进行交互。
                StreamWriter sw = p.StandardInput;
                StreamReader sr = p.StandardOutput;
                string strFormattedDoc = null;

                // 将 HTML 文档的内容写到进程的标准输入中。
                sw.Write(txtHTMLDoc);
                sw.Close();

                // 读取进程的标准输出并存储在 strFormattedDoc 中。
                strFormattedDoc = sr.ReadToEnd();
                sr.Close();

                // 处理非标准输出文字,而不显示标准错误文字。
                if (strFormattedDoc == "")
                {
                   StreamReader srError = p.StandardError;

                   string strError = srError.ReadToEnd();
                   srError.Close();

                   throw new Exception("Tidy 失败,错误信息为 "
    + ": " + strError);
                }
                
                // 用进程的输出替换文档的原始文字。
                editStartPt.ReplaceText(editEndPt, strFormattedDoc,
    (int) vsEPReplaceTextOptions.vsEPReplaceTextTabsSpaces);
             }
             catch (Exception ex)
             {
                System.Windows.Forms.MessageBox.Show(ex.ToString());
             }
          }   
    VC# 步骤 6:添加您喜欢的 HTML Tidy 配置选项
    要指定 HTML Tidy 的运行方式,请在步骤 5 示例代码的 BeforeExecute() 方法中,将配置选项添加到指定给 psi.Arguments 属性的字符串值中:

                psi.Arguments = "-i";
    在以下示例中,添加了 -config 选项。此选项告诉 Tidy 使用名为“config.txt”的外部配置文件:

                psi.Arguments = "-config config.txt -i";
    注意:确保将 -i 选项放在参数字符串的末尾。
    HTML Tidy Quick Reference 提供了一个配置选项列表。

    VC# 步骤 7:捕捉和显示任何例外
    如果抛出例外,请记住添加代码来捕捉和显示这些例外。在步骤 5 示例代码的 BeforeExecute() 方法中,Catch 语句使用 .NET Framework MessageBox.Show Method (String)(英文)将每个 Tidy 消息显示在一个标准的 Windows MessageBox 中:

             catch (Exception ex)
             {
                System.Windows.Forms.MessageBox.Show(ex.ToString());
             }
    您可能更希望将来自 HTML Tidy 的例外和其他消息显示在滚动的 Output Window(英文)中。如果是这样,请调用错误处理子例程来替换 Catch 语句:

             catch (Exception ex)
             {
                ErrToOutputWindow(ex);
             }
    然后,将上面提到的方法添加到 Connect 类中。以下示例方法向输出窗口添加一个新窗格,并将例外 ex 的文字写到这个新窗格中:

          private void ErrToOutputWindow(Exception ex)
          {
             // 为输出窗口创建工具窗口句柄。
             Window win =
    applicationObject.Windows.Item(EnvDTE.Constants.vsWindowKindOutput);
             // 访问输出窗口。
             OutputWindow OW = (OutputWindow) win.Object;
             // 向输出窗口添加新窗格。
             OutputWindowPane OWp =
    OW.OutputWindowPanes.Add("HTML Tidy Add-in");
             // 将例外文字写到这个新窗格中。
             OWp.OutputString(ex.ToString());
          }
    有关更多信息,请参阅 Exception Handling Fundamentals(英文)、Using the Try/Catch Block to Catch Exceptions(英文)、Exception Handling Statements(英文)和 try-catch(英文)。

    Visual C++ .NET/ATL 示例代码
    外接程序向导提供了一个用非托管 Visual C++ .NET/活动模板库 (ATL) 代码编写的项目模板。但是,您可以不遵循生成 Visual Studio .NET 2003 外接程序项目一节中的“如何修改外接程序项目模板的连接文件”过程。

    有关如何使用非托管的 C++/ATL 代码或 Managed Extensions for C++ 来开发 Visual Studio .NET 外接程序的更多信息,请参阅 Peter Huene 编写的教程,该教程可从 DevHood Web 站点 http://www.devhood.com (英文)上获得。

    VC++/ATL:Connect.cpp
    用以下代码替换外接程序向导的“C++/ATL 外接程序”模板中包含的 Connect.cpp 源文件。它是非托管的本机代码。

    此版本的 HTML Tidy 外接程序只适用于 ASCII 编码的文件。在一个头注释中显示了 HTML Tidy 处理其他编码时所需的步骤。请注意,此代码使用一个包装类来减少 CloseHandle() 的调用次数。一个子例程将来自 Tidy 的例外和其他消息显示在 Output Window(英文)中。

    // Connect.cpp:CConnect 的实现

    #include "stdafx.h"

    #include "AddIn.h"

    #include "Connect.h"

    #include <atlstr.h>

    extern CAddInModule _AtlModule;

    /*   请注意:

    * 编写本程序时,tidy.exe 含有一个错误,

    * 即无法输出 UTF16 文件。由于这个

    * Tidy 错误,本代码不能正确处理非 ASCII 编码的文件

    * 。当解决这个 Tidy 问题后,需要使用以下步骤

    * 来使本示例能够处理 UTF16 编码的文件:

    * 1) 必须将 -utf16 开关而不是 -ascii 传递给 Tidy.exe。

    * 2) 必须将字节顺序标记 (BOM) 0xFEFF 写到 Tidy.exe 中

    *       文件数据的前面。

    * 3) 包含文档中的 HTML 文字的 BSTR 必须

    *       按原样在 BOM 之后写出。   

    * 4) 必须将 Tidy.exe 的响应读取到一个字节数组中

    *       以进行处理。

    * 5) 根据响应的 BOM,有可能需要对

    *       整个响应进行重新排序,以使响应从 0xFEFF 开始。

    * 6) 然后,调用 SysAllocStringByteLen API,从得到的字节数组中分配 BSTR

    *       (减去 BOM)。

    * 7) 调用 ReplaceText() 时将使用步骤 6 中

    *       生成的 BSTR。

    */

    // CConnect

    STDMETHODIMP CConnect::OnConnection(IDispatch *pApplication, \
    AddInDesignerObjects::ext_ConnectMode ConnectMode,

                               IDispatch *pAddInInst, SAFEARRAY** custom)

    {

       HRESULT hr = S_OK;

       pApplication->QueryInterface(__uuidof(EnvDTE::_DTE), \
    (LPVOID*)&m_pDTE);

       pAddInInst->QueryInterface(__uuidof(EnvDTE::AddIn), \
    (LPVOID*)&m_pAddInInstance);

       // 如果命令事件尚未被初始化。

       if (m_spCommandEvents == NULL)

       {

          CComPtr<EnvDTE::Events> spEvents;

          hr = m_pDTE->get_Events(&spEvents);

          if (FAILED(hr))

             return hr;

          // 创建一个命令事件来处理 prettyFormatCommandID,

          //   该事件在默认处理程序之前收到通知。

          CComBSTR bstrCommandGroup = \
    L"{1496a755-94de-11d0-8c3f-00c04fc2aae2}";

          int prettyFormatCommandID = 319;

          hr = spEvents->get_CommandEvents(bstrCommandGroup, \
    prettyFormatCommandID, &m_spCommandEvents);

          if (FAILED(hr))

             return hr;

          // 有关命令事件的建议。

          CommandEvents::DispEventAdvise(m_spCommandEvents);

       }

       

       return hr;

    }

    STDMETHODIMP \
    CConnect::OnDisconnection(AddInDesignerObjects::ext_DisconnectMode \
    /*RemoveMode*/,

             SAFEARRAY ** /*自定义*/ )

    {

       CommandEvents::DispEventUnadvise(m_spCommandEvents);

       m_pDTE = NULL;

       m_spCommandEvents = NULL;

       return S_OK;

    }

    HRESULT CConnect::GetDocumentText(VARIANT Document, \
    EnvDTE::EditPoint** EditStartPoint, EnvDTE::EditPoint** \
    EditEndPoint, BSTR* Text)

    {

       if (m_pDTE == NULL || EditStartPoint == NULL || \
    EditEndPoint == NULL || Text == NULL)

          return E_FAIL;

       HRESULT hr;

       *EditStartPoint = NULL;

       *EditEndPoint = NULL;

       *Text = NULL;

       // 获取文档集合。

       CComPtr<EnvDTE::Documents> spDocuments;

       hr = m_pDTE->get_Documents(&spDocuments);

       if (FAILED(hr) || spDocuments == NULL)

          return E_FAIL;

       // 获取指定的文档。

       CComPtr<EnvDTE::Document> spDoc;

       hr = spDocuments->Item(Document, &spDoc);

       if (FAILED(hr) || spDoc == NULL)

          return E_FAIL;

       // 获取文本文档对象。

       CComPtr<IDispatch> spTextDocumentDisp;

       hr = spDoc->Object(CComBSTR(L"TextDocument"), &spTextDocumentDisp);

       CComQIPtr<EnvDTE::TextDocument> spTextDoc = spTextDocumentDisp;

       if (FAILED(hr) || spTextDoc == NULL)

          return E_FAIL;

       // 获取起始点。

       CComPtr<EnvDTE::TextPoint> spStartPoint;

       hr = spTextDoc->get_StartPoint(&spStartPoint);

       if (FAILED(hr) || spStartPoint == NULL)

          return E_FAIL;

       // 获取结束点。

       CComPtr<EnvDTE::TextPoint> spEndPoint;

       hr = spTextDoc->get_EndPoint(&spEndPoint);

       if (FAILED(hr) || spEndPoint == NULL)

          return E_FAIL;

       

       // 在起始点处创建一个编辑点。

       hr = spStartPoint->CreateEditPoint(EditStartPoint);

       if (FAILED(hr) || *EditStartPoint == NULL)

          return E_FAIL;

       // 在结束点处创建一个编辑点。

       hr = spEndPoint->CreateEditPoint(EditEndPoint);

       if (FAILED(hr) || *EditEndPoint == NULL)

          return E_FAIL;

       // 获取起始点与结束点之间的文字。

       hr = (*EditStartPoint)->GetText(CComVariant(*EditEndPoint), \
    Text);

       if (FAILED(hr) || *Text == NULL)

          return E_FAIL;

       return S_OK;

    }

    HRESULT CConnect::CreateTidyProcess(HANDLE* StdIn, \
    HANDLE* StdOut, HANDLE* StdErr)

    {

       if (StdIn == NULL || StdOut == NULL || StdErr == NULL)

          return E_FAIL;

       SECURITY_ATTRIBUTES sa;

       ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));

       sa.nLength = sizeof(SECURITY_ATTRIBUTES);

       sa.bInheritHandle = TRUE;

       sa.lpSecurityDescriptor = NULL;


       // 为子进程创建标准输入管道。

        CSmartHandle hChildStdinRd, hChildStdinWr;

       if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &sa, 0))

          return E_FAIL;

       

       // 复制写句柄,使其不能被继承。

       CSmartHandle hChildStdinWrDup;

       if (!DuplicateHandle(GetCurrentProcess(), hChildStdinWr, \
    GetCurrentProcess(),

             &hChildStdinWrDup, 0, FALSE, DUPLICATE_SAME_ACCESS))

          return E_FAIL;

       // 关闭可继承写句柄。

       hChildStdinWr.Close();

       // 为子进程创建标准输出管道。

       CSmartHandle hChildStdoutRd, hChildStdoutWr;

       if (!CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &sa, 0))

          return E_FAIL;

       // 复制读句柄,使其不能被继承。

       CSmartHandle hChildStdoutRdDup;

       if (!DuplicateHandle(GetCurrentProcess(), \
    hChildStdoutRd, GetCurrentProcess(),

             &hChildStdoutRdDup, 0, FALSE, DUPLICATE_SAME_ACCESS))

          return E_FAIL;

       // 关闭可继承读句柄。

       hChildStdoutRd.Close();

       // 为子进程创建标准错误管道。

       CSmartHandle hChildStderrRd, hChildStderrWr;

       if (!CreatePipe(&hChildStderrRd, &hChildStderrWr, &sa, 0))

          return E_FAIL;

       // 复制读句柄,使其不能被继承。

       CSmartHandle hChildStderrRdDup;

       if (!DuplicateHandle(GetCurrentProcess(), \
    hChildStderrRd, GetCurrentProcess(),

             &hChildStderrRdDup, 0, FALSE, DUPLICATE_SAME_ACCESS))

          return E_FAIL;

       // 关闭可继承读句柄。

       hChildStderrRd.Close();

       

       STARTUPINFO si;

       ZeroMemory(&si, sizeof(STARTUPINFO));

       // 设置起始信息(通过重定向 I/O 隐藏窗口)。

       si.cb = sizeof(STARTUPINFO);

       si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;

       si.hStdOutput = (HANDLE) hChildStdoutWr;

       si.hStdInput = (HANDLE) hChildStdinRd;

       si.hStdError = (HANDLE) hChildStderrWr;

        si.wShowWindow = SW_HIDE;

       // 繁衍 Tidy 进程。

       PROCESS_INFORMATION pi;

       ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));

       if (!CreateProcess(NULL, "tidy.exe -i -ascii", NULL, \
    NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))

          return E_FAIL;

       

       *StdIn = hChildStdinWrDup.Detach();

       *StdOut = hChildStdoutRdDup.Detach();

       *StdErr = hChildStderrRdDup.Detach();

       return S_OK;

    }

    HRESULT CConnect::WriteTextToTidy(HANDLE hTidyStdIn, \
    BSTR bstrText)

    {

       // 获取字符串的字节长度。

       DWORD dwWritten;

       // 转换成 ASCII(注意:由非 ASCII 文件断开!)。

       CStringA strTest(bstrText);

       

       BYTE* pBuffer = (BYTE*) strTest.GetBuffer();

       DWORD dwTotalLen = strTest.GetLength();

       

       // 如果还有要写到子进程的资料。

       for (DWORD dwTotalWritten = 0; dwTotalWritten < dwTotalLen; \
    dwTotalWritten += dwWritten)

       {

          // 写出所有可以写出的信息。

          if (!WriteFile(hTidyStdIn, &pBuffer[dwTotalWritten], \
    dwTotalLen - dwTotalWritten, &dwWritten, NULL))

             return E_FAIL;

       }

       

       strTest.ReleaseBuffer();

       return S_OK;

    }

    HRESULT CConnect::ReadResponseFromTidy(HANDLE hTidyStdOut, \
    BSTR* bstrText)

    {

       DWORD      dwRead;

       BYTE      byteBuf[4096 + 1];   // +1 代表 NULL

       CStringW   strBuffer;

       if (bstrText == NULL)

          return E_FAIL;

       while (true)

       {

          // 从子进程读取部分输出。

          if (!ReadFile(hTidyStdOut, byteBuf, 4096, &dwRead, NULL))

          {

             if (GetLastError() != ERROR_SUCCESS && \
    GetLastError() != ERROR_BROKEN_PIPE)

                return E_FAIL;

          }

          

          // 如果没有读取到任何信息,则完成。

          if (dwRead == 0)

             break;

          byteBuf[dwRead] = 0;

          // 注意:此处假定 Tidy 进程的输出为 ASCII!

          strBuffer += (LPSTR) byteBuf;

       }

       *bstrText = strBuffer.AllocSysString();

       return S_OK;

    }

    STDMETHODIMP CConnect::BeforeExecute(BSTR Guid, long ID, \
    VARIANT CustomIn, VARIANT CustomOut,

             VARIANT_BOOL* CancelDefault)

    {

       // 表示已经处理了此命令事件,

       //   因此,无需再处理该事件。

       *CancelDefault = VARIANT_TRUE;

       // 我们希望输入为传址方式 VARIANT。

       if (CustomIn.vt != (VT_VARIANT | VT_BYREF))

          return E_UNEXPECTED;

       HRESULT hr;

       // 获取 HTML 文字。

       CComBSTR bstrHTMLDoc;

       CComPtr<EnvDTE::EditPoint> spEditStartPoint;

       CComPtr<EnvDTE::EditPoint> spEditEndPoint;

       hr = GetDocumentText(*CustomIn.pvarVal, \
    &spEditStartPoint, &spEditEndPoint, &bstrHTMLDoc);

       if (FAILED(hr) || bstrHTMLDoc == NULL)

       {

          StringToOutputWindow(CComBSTR(L"Error: could not \
    get the HTML document text from the editor."));

          return E_FAIL;

       }

       // 通过重定向 I/O 创建 Tidy 进程。

       HANDLE hTidyStdIn, hTidyStdOut, hTidyStdErr;

       hr = CreateTidyProcess(&hTidyStdIn, &hTidyStdOut, &hTidyStdErr);

       if (FAILED(hr))

       {

          StringToOutputWindow(CComBSTR(L"Error: could not \
    spawn Tidy process. Make sure the executable lies in your \
    %PATH% environment variable."));

          return E_FAIL;

       }

       // 将 HTML 文字写到 Tidy 进程中并关闭

       //   输入句柄,使其知道已经完成。

       hr = WriteTextToTidy(hTidyStdIn, bstrHTMLDoc);

       CloseHandle(hTidyStdIn);

       if (FAILED(hr))

       {

          CloseHandle(hTidyStdOut);

          StringToOutputWindow(CComBSTR(L"Error: could not write \
    the HTML document to the Tidy process."));

          return E_FAIL;

       }

       // 获取 Tidy 进程的响应并关闭输出句柄。

       CComBSTR bstrResponse;

       hr = ReadResponseFromTidy(hTidyStdOut, &bstrResponse);

       CloseHandle(hTidyStdOut);

       if (FAILED(hr))

       {

          StringToOutputWindow(CComBSTR(L"Error: could not \
    read the response from the Tidy process."));

          return E_FAIL;

       }

       // 如果有响应,用进程输出替换文档的原始文字

       //   。

       if (bstrResponse != L"")

       {

          spEditStartPoint->ReplaceText(CComVariant(spEditEndPoint), \
    bstrResponse, (int) EnvDTE::vsEPReplaceTextTabsSpaces);

       }

       // 不管是成功还是失败,获取错误响应并

       //   将错误响应放在输出窗口中。即使 Tidy 成功,

       //   标准错误中仍有可能输出某些重要信息。

       CComBSTR bstrErrResponse;

       hr = ReadResponseFromTidy(hTidyStdErr, &bstrErrResponse);

       CloseHandle(hTidyStdErr);

       if (FAILED(hr))

       {

          StringToOutputWindow(CComBSTR(L"Error: could not \
    read the error response from the Tidy process."));

          return E_FAIL;

       }

       StringToOutputWindow(bstrErrResponse);

       return S_OK;

    }

    void CConnect::StringToOutputWindow(BSTR bstrText)

    {

       HRESULT hr;

       CComPtr<EnvDTE::Windows> spWindows;

       hr = m_pDTE->get_Windows(&spWindows);

       if (FAILED(hr) || spWindows == NULL)

          return;

       CComPtr<EnvDTE::Window> spWindow;

       hr = spWindows->Item(CComVariant(CComBSTR(EnvDTE::\

    vsWindowKindOutput)), &spWindow);

       if (FAILED(hr) || spWindow == NULL)

          return;

       CComPtr<IDispatch> spOutputWindowDisp;

       hr = spWindow->get_Object(&spOutputWindowDisp);

       if (FAILED(hr) || spOutputWindowDisp == NULL)

          return;

       CComQIPtr<EnvDTE::OutputWindow> spOutputWindow = \
    spOutputWindowDisp;

       if (spOutputWindow == NULL)

          return;

       CComPtr<EnvDTE::OutputWindowPanes> spOutputWindowPanes;

       hr = spOutputWindow->get_OutputWindowPanes(\
    &spOutputWindowPanes);

       if (FAILED(hr) || spOutputWindowPanes == NULL)

          return;

       CComPtr<EnvDTE::OutputWindowPane> spOutputWindowPane;

       hr = spOutputWindowPanes->Add(CComBSTR(L"HTML Tidy \
    Add-in"), &spOutputWindowPane);

       if (FAILED(hr) || spOutputWindowPane == NULL)

          return;

       spOutputWindowPane->OutputString(bstrText);

    }

    STDMETHODIMP CConnect::AfterExecute(BSTR Guid, long ID, \
    VARIANT CustomIn, VARIANT CustomOut)

    {

       return S_OK;

    }

    STDMETHODIMP CConnect::OnAddInsUpdate (SAFEARRAY ** /*自定义*/ )

    {

       return S_OK;

    }

    STDMETHODIMP CConnect::OnStartupComplete (SAFEARRAY ** /*自定义*/ )

    {

       return S_OK;

    }

    STDMETHODIMP CConnect::OnBeginShutdown (SAFEARRAY ** /*自定义*/ )

    {

       return S_OK;

    }

    VC/ATL:Connect.h
    用以下代码替换外接程序向导的“C++/ATL 外接程序”模板中包含的 Connect.h 头文件。它是非托管的本机代码。

    // Connect.h:CConnect 的声明

    #pragma once
    #include "resource.h"       // 主要符号

    #pragma warning( disable : 4278 )
    //以下 #import 根据 LIBID 导入 DTE。
    #import "libid:80cc9f66-e7d8-4ddd-85b6-d9e6cd0e93e2" \
    version("7.0") lcid("0") raw_interfaces_only named_guids
    #pragma warning( default : 4278 )

    class CConnect;

    typedef IDispEventImpl<0, CConnect, \
    &EnvDTE::DIID__dispCommandEvents, \
    &EnvDTE::LIBID_EnvDTE, 7, 0> CommandEvents;

    class CSmartHandle
    {
    public:
       CSmartHandle() : m_hHandle(NULL) { }
       ~CSmartHandle() { Close(); }

       operator HANDLE() const { return m_hHandle; }

       HANDLE* operator &() { return &m_hHandle; }

       void Close() { if (m_hHandle != NULL) \
    CloseHandle(m_hHandle); m_hHandle = NULL; }

       HANDLE Detach() { HANDLE hRet = m_hHandle; \
    m_hHandle = NULL; return hRet; }

    private:
       HANDLE m_hHandle;
    };

    // CConnect
    class ATL_NO_VTABLE CConnect :
       public CComObjectRootEx<CComSingleThreadModel>,
       public CComCoClass<CConnect, &CLSID_Connect>,
       public IDispatchImpl<AddInDesignerObjects::\
    _IDTExtensibility2, &AddInDesignerObjects::\
    IID__IDTExtensibility2, &AddInDesignerObjects::\
    LIBID_AddInDesignerObjects, 1, 0>,
       public CommandEvents
    {
    public:
       CConnect()
       {
       }

    DECLARE_REGISTRY_RESOURCEID(IDR_ADDIN)
    DECLARE_NOT_AGGREGATABLE(CConnect)

    BEGIN_COM_MAP(CConnect)
       COM_INTERFACE_ENTRY(IDispatch)
       COM_INTERFACE_ENTRY(AddInDesignerObjects::\
    IDTExtensibility2)
    END_COM_MAP()

    BEGIN_SINK_MAP(CConnect)
       SINK_ENTRY_EX(0, EnvDTE::DIID__dispCommandEvents, \
    0x1, BeforeExecute)
       SINK_ENTRY_EX(0, EnvDTE::DIID__dispCommandEvents, \
    0x2, AfterExecute)
    END_SINK_MAP()

       DECLARE_PROTECT_FINAL_CONSTRUCT()

    public:
       //IDTExtensibility2 实现:
       STDMETHOD(OnConnection)(IDispatch * Application, \
    AddInDesignerObjects::ext_ConnectMode ConnectMode, \
    IDispatch *AddInInst, SAFEARRAY **custom);
       STDMETHOD(OnDisconnection)(AddInDesignerObjects::\
    ext_DisconnectMode RemoveMode, SAFEARRAY **custom);
       STDMETHOD(OnAddInsUpdate)(SAFEARRAY **custom);
       STDMETHOD(OnStartupComplete)(SAFEARRAY **custom);
       STDMETHOD(OnBeginShutdown)(SAFEARRAY **custom);

    // EnvDTE::_CommandEvents
    public:
       STDMETHOD(BeforeExecute)(BSTR Guid, long ID, \
    VARIANT CustomIn, VARIANT CustomOut, VARIANT_BOOL* CancelDefault);
       STDMETHOD(AfterExecute)(BSTR Guid, long ID, \
    VARIANT CustomIn, VARIANT CustomOut);

    // Helper 方法
    private:
       HRESULT GetDocumentText(VARIANT Document, \
    EnvDTE::EditPoint** EditStartPoint, EnvDTE::EditPoint** \
    EditEndPoint, BSTR* Text);
       HRESULT CreateTidyProcess(HANDLE* StdIn, \
    HANDLE* StdOut, HANDLE* StdErr);
       HRESULT WriteTextToTidy(HANDLE hTidyStdIn, BSTR bstrText);
       HRESULT ReadResponseFromTidy(HANDLE hTidyStdOut, \
    BSTR* bstrText);
       void StringToOutputWindow(BSTR bstrText);
       
       CComPtr<EnvDTE::_DTE>            m_pDTE;
       CComPtr<EnvDTE::AddIn>            m_pAddInInstance;
       CComPtr<EnvDTE::_CommandEvents>      m_spCommandEvents;
    };

    OBJECT_ENTRY_AUTO(__uuidof(Connect), CConnect)
    Managed Extensions for C++ 示例代码
    外接程序向导没有提供使用 Managed Extensions for C++ 的项目模板,因此您可以不遵循生成 Visual Studio .NET 2003 外接程序项目一节中的“如何修改外接程序项目模板的连接文件”过程。

    随后的代码示例不能直接编译成外接应用程序。要使用 Managed Extensions for C++ 来创建 HTML Tidy 外接程序,必须执行其他开发任务:

    如何使用 Managed Extensions for C++ 来创建 HTML Tidy 外接程序

    创建一个新的 Managed Extensions for C++ 类库项目。
    向项目添加一个新的 C++ 源文件和一个新的 C++ 头文件。
    注意:这些文件的示例代码将源文件称为“ManagedCAddin.cpp”,将头文件称为“ManagedCAddin.h”。
    将本节后面给出的示例代码复制到步骤 2 创建的文件中。
    在 Connect 类定义之前,添加以下属性:
    [Guid(S"A069C016-BAAC-4d46-A843-8D52DE4DA9A5"), \
    ProgId(S"ManagedCAddin.Connect")]

    注意:用 guidgen.exe 生成的新值替换 GUID,并使用您自己的外接应用程序的 ProgID。
    添加一个后编译事件。将其命令属性设置成:
    regasm /silent /codebase "$(TargetPath)"

    注意:这将引发一个消息,指出部件没有被严格命名。您可以忽略此消息。
    将后编译事件的描述属性设置成:

    “导出类型库并进行注册...”

    生成项目。
    使用注册表文件 regedit.exe 或 VisualStudio.NET 安装程序项目,在 HKEY_CURRENT_USER 下添加以下注册表项:
    “HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\7.1\AddIns\<PROGID>”

    对于 <PROGID>,替换外接程序的 ProgID(与步骤 4 使用相同的值)。

    注意:要使目标计算机上的所有 Visual Studio .NET 用户都可以访问此外接程序,请在 HKEY_LOCAL_MACHINE 项下而不是 HKEY_CURRENT_USER 项下添加此注册表项。
    在步骤 7 中创建的注册表项下,添加以下两个字符串值:
    Description = "Description goes here"

    FriendlyName = "Friendly name goes here"

    可选:要为 VS Macro IDE 注册外接程序,请将键值路径中的“VisualStudio”更改为“VSA”,然后重复步骤 7 和步骤 8。
    当这些附加开发任务执行完成后,您的 HTML Tidy 外接程序就可以使用了。

    有关如何使用非托管的 C++/ATL 代码或 Managed Extensions for C++ 来开发 Visual Studio .NET 外接程序的更多信息,请参阅 Peter Huene 编写的教程,该教程可从 DevHood Web 站点 http://www.devhood.com (英文)上获得。

    Managed C++:ManagedCAddin.cpp
    将此代码放在您的 Managed Extensions for C++ 类库项目的源 (.cpp) 文件中。

    // 这是主 DLL 文件。

    #include "stdafx.h"

    #include "ManagedCAddin.h"
    Managed C++:ManagedCAddin.h
    将此代码放在您的 Managed Extensions for C++ 类库项目的头 (.h) 文件中。

    // ManagedCAddin.h

    #pragma once

    using namespace System;
    using namespace Microsoft::Office::Core;
    using namespace Extensibility;
    using namespace System::Runtime::InteropServices;
    using namespace EnvDTE;
    using namespace System::IO;
    using namespace System::Windows::Forms;

    namespace ManagedCAddin
    {
       public __gc class Connect : public Extensibility::IDTExtensibility2
       {
          CommandEvents* commandEvents;
          _dispCommandEvents_BeforeExecuteEventHandler* \
    beforeExecuteHandler;

          public: void OnConnection(Object* application, \
    Extensibility::ext_ConnectMode connectMode, Object* addInInst, \
    Array** custom)
          {
             applicationObject = __try_cast<_DTE*>(application);
             addInInstance = __try_cast<AddIn*>(addInInst);

             String* vsCommandGroup = \
    S"{1496a755-94de-11d0-8c3f-00c04fc2aae2}";

             int prettyFormatCommandID = 319;

             // 创建一个命令事件来处理 prettyFormatCommandID,
             //   该事件在默认处理程序之前收到通知。
             commandEvents = applicationObject->\
    Events->get_CommandEvents(vsCommandGroup, prettyFormatCommandID);

             beforeExecuteHandler = new \
    _dispCommandEvents_BeforeExecuteEventHandler(this, BeforeExecute);
             commandEvents->add_BeforeExecute(beforeExecuteHandler);
          }

          public: void OnDisconnection(Extensibility::ext_DisconnectMode \
    disconnectMode, Array** custom)
          {
             if (beforeExecuteHandler)
                commandEvents->remove_BeforeExecute(beforeExecuteHandler);

             commandEvents = 0;
          }

          public: void OnAddInsUpdate(Array** custom)
          {
          }

          public: void OnStartupComplete(Array** custom)
          {
          }

          public: void OnBeginShutdown(Array** custom)
          {
          }

          private: void BeforeExecute(String* Guid, int ID, \
    Object* CustomIn, Object* CustomOut, Boolean* CancelDefault)
          {
             // 表示已经处理了此命令事件,
             //   因此,无需再处理该事件。
             (*CancelDefault) = true;

             try
             {
                Document* doc = applicationObject->Documents->\
    Item(CustomIn);
                TextDocument* td = __try_cast<TextDocument*>\
    (doc->Object(S"TextDocument"));

                TextPoint* sp = td->StartPoint;
                TextPoint* ep = td->EndPoint;

                EditPoint* editStartPt = sp->CreateEditPoint();
                EditPoint* editEndPt = ep->CreateEditPoint();

                // 获取文档内容。
                String* txtHTMLDoc = editStartPt->\
    GetText(editEndPt);

                // 设置进程信息。
                System::Diagnostics::ProcessStartInfo* psi = \
    new System::Diagnostics::ProcessStartInfo();

                psi->FileName = S"tidy.exe";
                psi->Arguments = S"-i";
                psi->CreateNoWindow = true;
                psi->UseShellExecute = false;
                psi->RedirectStandardInput = true;
                psi->RedirectStandardOutput = true;
                psi->RedirectStandardError = true;

                // 创建进程。
                System::Diagnostics::Process* p = \
    new System::Diagnostics::Process();

                // 将进程信息与进程相关联。
                p->StartInfo = psi;

                // 运行进程。
                bool fStarted = p->Start();

                if (!fStarted)
                   throw new Exception(S"Unable to start tidy process");

                // 设置流以与进程的标准输入/标准输出进行交互。
                StreamWriter* sw = p->StandardInput;
                StreamReader* sr = p->StandardOutput;
                String* strFormattedDoc = 0;

                // 将 HTML 文档的内容写到进程的标准输入中
                //   。
                sw->Write(txtHTMLDoc);
                sw->Close();

                // 读取进程的标准输出并存储在 strFormattedDoc 中。
                strFormattedDoc = sr->ReadToEnd();
                sr->Close();

                // 处理非标准输出文字,而不显示标准错误文字。
                if (strFormattedDoc->Equals(S""))
                {
                   StreamReader* srError = p->StandardError;
                   String* strError = srError->ReadToEnd();

                   srError->Close();

                   throw new Exception(S\
    "Tidy failed with error information: "->Concat(strError));
                }

                // 用进程的输出替换文档的原始文字。
                editStartPt->ReplaceText(editEndPt, strFormattedDoc, \
    (int) vsEPReplaceTextOptions::vsEPReplaceTextTabsSpaces);
             }
             catch (Exception* ex)
             {
                System::Windows::Forms::MessageBox::Show(ex->ToString());
             }
          }

          private: _DTE* applicationObject;
          private: AddIn* addInInstance;

       };
    }
    Managed C++:捕捉和显示任何例外
    如果抛出例外,请记住添加代码来捕捉和显示这些例外。在“ManagedCAddin.h”示例代码中,Catch 语句使用 .NET Framework MessageBox.Show Method (String)(英文)将每个 Tidy 消息显示在一个标准的 Windows MessageBox 中:

             catch (Exception* ex)
             {
                System::Windows::Forms::MessageBox::Show(ex->ToString());
             }
    您可能更希望将来自 HTML Tidy 的例外和其他消息显示在滚动的 Output Window(英文)中。如果是这样,请调用错误处理子例程来替换 Catch 语句:

             catch (Exception* ex)
             {
                ErrToOutputWindow(ex);
             }
    然后,将上面提到的方法添加到 Connect 类中。以下示例方法向输出窗口添加一个新窗格,并将例外 ex 的文字写到这个新窗格中:

          private: void ErrToOutputWindow(Exception* ex)
          {
             // 为输出窗口创建工具窗口句柄。
             Window* win = applicationObject->\
    Windows->Item(EnvDTE::Constants::vsWindowKindOutput);
             // 访问输出窗口。
             OutputWindow* OW = __try_cast<OutputWindow*>(win->Object);
             // 向输出窗口添加新窗格。
             OutputWindowPane* OWp = OW->OutputWindowPanes->\
    Add(S"HTML Tidy Add-in");
             // 将例外文字写到这个新窗格中。
             OWp->OutputString(ex->ToString());
          }
    小结
    本项目演示了 Visual Studio .NET 2003 的可扩展设计及大量的工具。通过 HTML Tidy 外接程序,在 HTML 视图编辑器中可以使用外部 HTML Tidy 实用程序来纠正和设置 HTML 标记的格式。借助 Visual Studio .NET 2003 外接程序向导提供的项目模板,生成、启动和运行外接程序项目所需的编程时间非常短。

    建议您比较本文中 HTML Tidy 外接程序的并行代码示例,来了解各种开发语言中处理常见编程任务的方式。您可以自己判断在应用程序中使用托管或非托管代码的利弊。Visual Studio .NET 允许您选择最恰当的方法,并根据自己的经验和本地工作环境来选择最合适的开发路径。

    致谢
    HTML Tidy 是 Dave Raggett 为万维网协会创建的。Todd Grunke 为 Visual Studio .NET 2003 中的 Visual C# .NET 开发了 HTML Tidy 外接程序。Van Kichline 提供了该外接程序的 Visual Basic .NET 版本。Huizhong Long 和 Kemp Brown 参与了输出窗口代码的开发。Peter Huene 使用非托管 Visual C++/ATL 代码和 Managed Extensions for C++ 开发了该外接程序的多种版本。Craig Skibo、Glen Kowalski 和 Yugang Wang 审阅了文字和运行了代码,并对两者进行了改进。本文由 Hank Davis 执笔,他为编写本文进行了大量研究。

    更多信息
    HTML Tidy:
    下载:http://tidy.sourceforge.net(英文)
    发行说明:http://www.w3.org/People/Raggett/tidy(英文)

    外接程序项目:
    Add-in and Customization User Interface Elements(英文)
    Creating Add-ins and Wizards(英文)
    Creating an Add-In(英文)
    Add New Project Dialog Box(英文)
    Add-in Manager Dialog Box(英文)
    Setup Projects(英文)
    Walkthrough:Deploying a Windows Application(英文)。

    .NET Framework:
    .NET Framework Class Library in Visual Studio(英文)
    .NET Framework Class Library(英文)

    开发语言:
    Visual Basic and Visual C#(英文)
    Visual C++(英文)
    ATL(英文)
    Managed Extensions for C++ Programming(英文)

    例外处理:
    Exception Handling Fundamentals(英文)
    Exception Handling Statements(英文)
    try-catch(英文)。

    HTML 设计器:
    Editing HTML(英文)
    Editing HTML Pages in Design View(英文)
    Building CSS Styles(英文)
    Editing Code, HTML, and Text(英文)
    Outlining and Hiding Code(英文)

    选项:
    Options that Affect Existing HTML, CSS, or XML Markup(英文)
    Format, HTML/XML, Text Editor, Options Dialog Box(英文)
    HTML Specific, HTML/XML, Text Editor, Options Dialog Box(英文)

    属性:
    HTML Document Properties, Properties Window(英文)
    General Tab, DOCUMENT Property Pages Dialog Box(英文)
    Setting the targetSchema Property of an HTML Document(英文)
    Setting the pageLayout Property of an HTML Document(英文)

    任务列表:
    Task List Window(英文)
    Task List Views(英文)

    工具箱:
    HTML Tab, Toolbox(英文)
    Web Forms Tab, Toolbox(英文)

    HTML 元素和 CSS 样式:
    DHTML References(英文)
    CSS Attributes Reference(英文)

    Web 服务器控件:
    Controls You Can Use on Web Forms Pages(英文)
    ASP.NET Server Controls by Function(英文)
    System.Web.UI.HtmlControls Namespace(英文)
    System.Web.UI.WebControls Namespace(英文)

    Web 窗体:
    Web Forms Pages(英文)
    Creating and Managing Web Forms(英文)
    Inserting a Form into a Project(英文)
    Controls You Can Use on Web Forms Pages(英文)
    Adding Web Server Controls to a Web Forms Page(英文)

    脚本(服务器):
    Server Event Handling in Web Forms(英文)
    Code for Web Applications(英文)
    Creating Event Handlers in Web Forms Pages(英文)
    Understanding the Event Model(英文)
    Web Forms Code Model(英文)

    HTML 窗体:
    Forms Overview(英文)
    Working with HTML Forms in Internet Explorer(英文)
    Working with HTML Forms in Internet Explorer, Part 2(英文)

    脚本(客户端):
    Creating Scripts and Editing Event Handlers in HTML Designer(英文)
    Event Handling in HTML Elements Sample(英文)
    DHTML Events(英文)
    Handling HTML Element Events(英文)
    Client and Server Scripting in Web Pages(英文)

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2005/5/11 10:14:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 WORD to XML, HTML to XML 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2022/12/9 22:29:51

    本主题贴数6,分页: [1]

     *树形目录 (最近20个回帖) 顶端 
    主题:  [求助]请问 用 c# 怎样把 html 转化为 xml ?(214字) - simonking,2005年5月9日
        回复:  要是htnl格式不严格怎么办那(26字) - zixia_athena,2005年5月15日
        回复:  这么好的贴 也没人顶啊(21字) - simonking,2005年5月13日
        回复:  演练:生成启用HTML Tidy的Visual Studio .NET2003外..(58407字) - simonking,2005年5月11日
        回复:  好冷啊!。。。有没有人啊(28字) - simonking,2005年5月10日
        回复:  顶。。。(8字) - simonking,2005年5月9日

    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    171.875ms