Visual Studio 扩展开发:自定义类向导

Visual Studio中开发扩展时,经常需要创建新的类或修改现有的类。这个过程可以通过使用Visual Studio的向导功能来简化。本文将介绍如何自定义类向导,以及如何使用JScript和CodeModel进行操作。

自定义类向导的动机

在开发过程中,每当需要在命名空间中添加一个类时,都需要手动选择“新建项目”->“新建类”,然后在文件的开始和结束处手动添加命名空间。这个过程非常繁琐,因此决定编辑原始向导,以便在其中包含命名空间字段(以及用于选择基类的类似选择器)。

向导文件的创建

在CodeProject上,已经写过关于向导的文章,创建向导文件的过程非常简单。但是,使用向导时遇到的问题不在于了解文件格式,而在于如何使用脚本。MSDN上的文档非常分散,即使需要编写JScript文件,大多数MSDN示例都是用VB或C#编写的。由于几乎不使用JScript(除了在向导中),所以找到需要的内容以及如何使用它们非常无聊。

JScript基础

将从基础开始;示例中的字符串数组等都是用Java语法编写的(显然)。可以在MSDN页面上找到所有可以在它们上使用的功能(以及其他功能)。在左侧的目录中,还有两个有用的部分(JScript函数和JScript对象)。链接的部分包括所有对象方法。也可以在那里找到JScript语法。

JScript DOM类

EnvDTE命名空间是一个通用的命名空间,CodeModel接口用于在Visual Studio内部访问代码模型,而更高级的VCCodeModel接口用于在Visual Studio 8内部访问代码模型。

CodeModel的使用

如果使用VCCodeModel功能,将能够更方便地访问CodeDOM。例如,可以执行以下操作:

function OnFinish(selProj, selObj) { // 获取项目的全局命名空间集合。 var nss = selProj.CodeModel.Namespaces; // 获取第一个全局命名空间的命名空间集合。 var nss2 = nss.Item(1).Namespaces; // 获取第一个子命名空间中的第一个类。 var cl1 = nss2.Classes.Item(1); }

Visual Studio的新版本(8)中,DOM提供了更用户友好的方式来访问代码模型。在以前的版本中,需要检索CodeModels集合,然后检查每个CodeModel的类型。需要注意的是,CodeModel是按照正常的DOM组织的,每个节点都有子节点,并且有一个主要的节点集合,通过它可以访问子节点,如上面的示例所示,selProj.CodeModel.Namespaces不是一个包含所有命名空间的通用列表,而只是全局命名空间,每个命名空间都包含子节点(即包含在命名空间内的CodeModels),这些子节点可以是类、接口,也可以是其他命名空间。

向导中的HTML和JScript文件

在每个向导中,可能已经知道,有一个实现接口的HTML文件和.js JScript文件(两者都命名为default.ext)。可以通过在htm文件中调用全局变量'window'的'window.external'和在js文件中的'wizard'来访问向导。

搜索命名空间和类的代码

由于没有保存在编辑向导时找到的其他有用资源或链接,所以不能提供更多的帮助,因为不记得它们了。但是,如果好奇,下面是用来搜索的代码,以及一个命名空间和类的列表,即使它不是一个很好的代码(正如所说的,根本不了解JScript)。也因为写得非常快,想着,“哦,请做工作脚本”,可能会发现一些行对目的是有用的(或者至少是有趣的)。

function InitDocument(document) { if (window.external.ProjectObject) { var proj = window.external.ProjectObject; var codeModel = proj.CodeModel; var nssArr, nsArr = new Array(); GetNamespaces(codeModel.Namespaces, nsArr, ""); nssArr = nsArr.sort(); for (var i = 0; i < nssArr.length; i++) { var oOption = document.createElement("OPTION"); oOption.value = nssArr[i]; oOption.text = nssArr[i]; NAMESPACE.add(oOption); } var oOption = document.createElement("OPTION"); oOption.value = ""; oOption.text = ""; NAMESPACE.add(oOption); var cllArr, clArr = new Array(); GetClasses(codeModel.Classes, clArr, ""); GetNamespaceClasses(codeModel.Namespaces, clArr, ""); clArr = clArr.sort(); cllArr = clArr.sort(SortClasses); for (var i = 0; i < cllArr.length; i++) { var oOption = document.createElement("OPTION"); oOption.value = cllArr[i]; oOption.text = cllArr[i]; BASE_CLASSES.add(oOption); } var oOption = document.createElement("OPTION"); oOption.value = ""; oOption.text = ""; BASE_CLASSES.add(oOption); } } function GetNamespaces(nss, nsArr, name) { for (var i = 1; i <= nss.Count; i++) { var ns = nss.Item(i); var l = 0; var nname = ns.Name; if (name != "") { nname = name + "::" + nname; } for (l = 0; l < nsArr.length; l++) { if (nsArr[l] == nname) { break; } } if (l == nsArr.length) { nsArr[l] = nname; } GetNamespaces(ns.Namespaces, nsArr, nname); } } function GetClasses(cls, clArr, name) { for (var i = 1; i <= cls.Count; i++) { var cl = cls.Item(i); var l = 0; var nname = cl.Name; if (name != "") { nname = name + "::" + nname; } for (l = 0; l < clArr.length; l++) { if (clArr[l] == nname) { break; } } if (l == clArr.length) { clArr[l] = nname; } GetClasses(cl.Classes, clArr, nname); } } function GetNamespaceClasses(nss, clArr, name) { for (var i = 1; i <= nss.Count; i++) { var ns = nss.Item(i); var l = 0; var nname = ns.Name; if (name != "") { nname = name + "::" + nname; } GetClasses(ns.Classes, clArr, nname); GetNamespaceClasses(ns.Namespaces, clArr, nname); } } function SortClasses(arr1, arr2) { var arr = arr1.split("::"); var arrs = arr2.split("::"); if (arr.length > arrs.length) { return 1; } else if (arrs.length > arr.length) { return -1; } else { var i; for (i = 0; i < arr.length - 1; i++) { if (arrs[i] != arr[i]) { break; } } if (i == (arrs.length - 1)) { var l = 0; while (arr[i][l] == arrs[i][l] && l < arr[i].length && l < arrs[i].length) { l++; } if (l < arr[i].length || l < arrs[i].length) { if (arr[i][l] > arrs[i][l]) { return 1; } else { return -1; } } else { return 0; } } else { return 0; } } }

排序函数还不完美,但对来说已经足够了。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485