使用 .net 框架类替代 api 调用 升级到 microsoft .net

通过学习 microsoft .net 框架中某些特定而有用的类,能够减少您对 win32 api 调用的依赖。本文讨论的每个类都能够代替一个或多个 win32 api 调用,而在 microsoft visual basic 6.0 中,您必须调用一个或多个 win32 api 才能完成相同的任务。
目标
查找现有 win32 api 调用的特定替代品。
了解 registry 类。
使用 fileversioninfo 类。
使用环境信息和系统信息。
目录
避免使用 win32 api
使用注册表
使用常用对话框
检索文档版本信息
检索环境信息
总结
避免使用 win32 api

假如您是一位 microsoft visual basic? 6.0 研发人员,您就无法避免调用 win32 api。研发人员有太多的任务需要完成,而 visual basic 却不能提供任何实现方法。例如,在 visual basic 6.0 中,您很难完成以下任务:
确定文档版本信息。
在注册表的任何位置进行读取和写入操作。
确定用户的特定文档夹,例如 microsoft windows? 收藏夹或个人文档夹。
检索任何可用驱动器的列表。
查找用户的登录名或电脑名。
检索任何打开窗口的列表。

假如仅使用 visual basic 6.0 中提供的工具,您不可能解决上述任何问题。对于每个问题,研发人员都需要使用 windows api。许多研发人员使用 windows api 已找到了完成这些(连同许多其他)任务的方法。
windows api 存在什么问题?

为什么不继续在 .net 环境中使用 windows api 呢?假如使用 .net 平台调用服务(称为“p/invoke”),您当然能够这样做。从 visual basic 研发人员的角度来说,调用 windows api 并不比使用他们所熟悉的 declare 语句困难。但是,在 .net 环境中使用 windows api 存在一些比较严重的缺陷,您可能需要考虑采取任何可行的措施来避免这些问题。例如:
.net 公共语言运行时不会受平台影响。当您使用 windows api 调用时,您将代码绑定到编写代码的特定平台上(即,相对于其他操作系统的某个特定 windows 版本或 windows 本身)。必要时,您需要将代码转换到另一个平台上,而这样做就需要修改使用 api 调用的每行代码。
从 .net 中调用 windows api(或 dll 中的任何非托管代码)不像在 visual basic 6.0 中那样简单。例如,对结构的工作方式的限制使得很难将结构传递给 api 调用。此外,由于数据类型的更改连同更严格的类型转换,visual basic 6.0 的 api 声明也需要进行更改。
根据语言的不同,使用 windows api(连同通常情况下使用的外部代码)的技巧也不尽相同。假如您打算在多 .net 语言环境中工作,则需要掌控各种语言的不同技巧。
调用 windows api 的代码需要调用这些代码的用户具备执行此操作的权限。这将影响应用程式的安全保护方案,您需要对此需要提前做出安排。

这个问题很简单:尽管您能够在 visual basic .net 应用程式中继续使用 windows api,但通常情况下,您应当尽可能寻找由 .net 框架提供的替代品。虽然 .net 框架的目的并不是要阻止您直接使用 windows 的功能,但框架的确提供了大量的类,能够帮助您放弃对 windows api 调用的依赖。
假如能够给出一个完整列表,列出 win32 api 调用连同在 .net 框架中完成相同任务的相应方法(假如有),可能会很方便,但是本文不涉及此任务。在本文中,您将了解到一些由 .net 框架提供的特定且很有用的类,他们能够解决您的问题。在每个示例中,本文所讨论的类都能够用来替代一个或多个 win32 api 调用,而在 microsoft visual basic 6.0 中,您必须调用一个或多个 win32 api 才能完成相同的任务。
使用注册表

假如您和大多数 visual basic 6.0 研发人员相同,您会发现 microsoft visual basic for applications (vba) 中内置的 savesetting、getsetting、getallsettings 和 deletesetting 方法有点儿用处,但却很可能被他们的局限性弄得精疲力尽。任何这些方法都只能在注册表的 hkey_current_user/software/vb 和 vba program settings 下的项中使用。假如您要在注册表的其他地方读取或写入注册表项或注册表值,则必须使用复杂的 api 调用,或依靠别人的代码来处理此问题。
.net 框架在 microsoft.win32 名称空间中提供了一对功能强大的类(registry 和 registrykey),从而简化了注册表的使用,即不再需要 api 调用!
作为演示,请在示例项目的主窗体上单击 work with the registry(使用注册表)按钮。此窗体提供了 software/microsoft/windows/currentversion/run 项的 hkey_local_machine 配置单元中任何注册表值的列表。您能够右键单击列表中的任何项,然后选择插入新项,或编辑或删除选定项,如图 1 所示。
提示:示例窗体也已过设计,在列表框中按下 enter 键时,能够编辑当前选定的项。按下 delete 键能够删除选定项,按下 insert 键能够添加一个新值。这些项对应于列表框的上下文菜单中的项。


图 1:使用 registry 和 registrykey 类轻松检索和修改 windows 注册表中的信息
.net 框架提供了两个很有用的类,使您能够轻松使用 windows 注册表。第一个类是 registry,他提供的字段和标准 registry 配置单元的各字段相对应:
classesroot (hkey_classes_root)
currentconfig (hkey_current_config)
currentuser (hkey_current_user)
dyndata (hkey_dyn_data)
localmachine (hkey_local_machine)
performancedata (hkey_performance_data)
users (hkey_users)

要使用 registry 类,只需检索所需配置单元的引用。示例窗体的 loadlist 过程中包含如下代码,以便使用注册表中的 hkey_local_machine 配置单元:
imports microsoft.win32dim reg as registrykey = registry.localmachine

另一个类是 registrykey,他能够完成任何工作。他提供了一组使用 registry 的方法。表 1 列出了 registrykey 类的任何有用方法。
表 1:registrykey 类方法方法 说明
createsubkey 创建新子项或打开现有子项
deletesubkey 删除指定子项。
deletesubkeytree 以递归方式删除子项和该子项的任何子项。
deletevalue 从该项中删除指定项值。
getsubkeynames 检索包含任何子项名称的字符串数组。
getvalue 检索指定的值。
getvaluenames 检索包含和此项相关联的任何项值名称的字符串数组。
opensubkey 检索指定子项,具备可选的写入权限。
setvalue 配置指定的值。

registrykey 类还提供以下三个属性:
name:检索项的名称。
subkeycount:检索和该项相关联的子项的数量。
valuecount:检索和该项相关联的项值的数量。

示例窗体的 listload 过程将检索所请求项中的任何值,并将检索到的值添加到窗体的列表框中:
private const conregkey as string = _ "software/microsoft/windows/currentversion/run"private structure regdata    public value as string    public data as string    public overrides _     function tostring() as string        return me.value    end functionend structureprivate sub listload()    dim reg as registrykey = registry.localmachine    dim astrvalues() as string    dim strvalue as string    dim rd as regdata     清除列表框中的现有项。    lstitems.beginupdate()    lstitems.items.clear()     打开注册表项,然后使用     该项的值加载列表框。    reg = reg.opensubkey(conregkey)    astrvalues = reg.getvaluenames()    for each strvalue in astrvalues        rd.value = strvalue.tostring        rd.data = reg.getvalue(strvalue)        lstitems.items.add(rd)    next    lstitems.endupdate()end sub

要编辑示例窗体中的值或添加新值,需要运行以下代码:
private sub addoredit( _ byval rd as regdata, _ byval mode as frmaddvalue.accessmode)    dim reg as registrykey = registry.localmachine    dim frm as new frmaddvalue(mode)    frm.keyname = rd.value    frm.keydata = rd.data    if frm.showdialog() = dialogresult.ok then        if frm.keyname <> string.empty then            reg = reg.opensubkey(conregkey, true)            reg.setvalue(frm.keyname, frm.keydata)            listload()        end if    end ifend sub

此代码将再次打开注册表项,这次将请求写入项值的权限(此请求由 opensubkey 的第二个参数发出)。然后,代码将调用 setvalue 方法,传递图 1 所示的对话框窗体中的项名和项值。为简化工作,能够使用 setvalue 方法添加新值或修改现有值。假如项值不存在,setvalue 方法将添加一个项值。
要删除项值,示例窗体将调用以下代码:
private sub deletekey(byval rd as regdata)    dim strtext as string    dim reg as registrykey = registry.localmachine    if lstitems.selectedindex = -1 then        exit sub    end if     删除选定的项。    strtext = string.format( _     "are you sure you want to delete ""{0}""?", _     rd.value)    if messagebox.show(strtext, _     "delete registry value", _     messageboxbuttons.yesno, _     messageboxicon.question) = dialogresult.yes then         打开项,允许写入。        reg = reg.opensubkey(conregkey, true)        reg.deletevalue(rd.value)         重新加载列表框。        listload()    end ifend sub

此代码将打开项并请求对其执行写入操作,然后将调用 deletevalue 方法删除选定的值。
有了示例窗体提供的信息和 .net 框架附带的文档,便能够轻松地完成和注册表相关的任何任务,而不必使用 windows api。这是个简单的对象模型,但他提供的功能比 visual basic 6.0 研发人员先前所拥有的功能更强大。
提示:假如具备必要的权限,您还能够使用远程电脑上的注册表。您能够调用 registrykey.openremotebasekey 方法检索其他电脑上的基本项,而不是简单地使用其中一个 registry 类属性,来代表您自己电脑上的 registry 配置单元。
使用常用对话框

windows 提供了一组常用对话框,使研发人员能够方便地请求用户信息。您肯定见过并且使用过打开和保存文档、颜色、打印机和字体配置等常用对话框。visual basic 6.0 研发人员在使用这些对话框时有两种选择。他们能够:
使用一个 microsoft activex? 控件,该控件提供了一个包含常用对话框的简单对象模型,但是由于控件有多个不同的版本且底层 dll 不同,因此该控件存在严重的部署问题。(对于很多 visual basic 6.0 研发人员来说,这个问题是最致命的 dll 问题。)
直接使用 windows api 发送消息并提供回叫功能,以管理各个常用对话框。

两个解决方案都不是完美无缺的,而且由于对 .net 框架进行了增补,这两个解决方案当前都不是必需的。查看 system.windows.forms 名称空间时,您会发现 colordialog、filedialog、fontdialog 和 printdialog 类。这些类都集成在框架中(也就是说,既无需使用 api 调用,也无需使用 activex 控件),这样能够方便地将这些标准功能合并到您的应用程式中。
每个类都提供了一系列属性,您能够使用类的 showdialog 方法在显示对话框之前配置这些属性。本文将不对每个类进行周详讨论,但在示例项目中使用了 filedialog 类,使您能够选择文档。假如您在主窗体上选择了 file version info(文档版本信息)按钮,则能够使用演示窗体上的 select a file(选择文档)按钮显示 file open(打开文档)对话框,如图 2 所示。

图 2:使用 filedialog 类显示 windows 常用对话框
虽然 filedialog 类不像直接使用 windows api 那样灵活,但他提供了大量的属性,您能够使用这些属性控制对话框的操作。您能够决定文档的来源,选择一个或多个文档,还能够检索选定的文档名。表 2 列出了可能会用到的 filedialog 类的部分属性和方法。
表 2:filedialog 对象的属性和方法属性/方法 说明
addextension 指示当用户省略扩展名时,对话框是否自动为文档添加一个扩展名。
checkfileexists 指示当用户指定的文档名不存在时,对话框是否显示警告信息。
checkpathexists 指示当用户指定的路径不存在时,对话框是否显示警告信息。
defaultext 默认文档扩展名。
dereferencelinks 指示对话框是否返回快捷方式所引用的文档的位置,或是否返回快捷方式 (.lnk) 所在的位置。
filename 在文档对话框中选定的文档名。
filenames (只读)对话框中任何选定文档的文档名。
filter 当前文档名筛选字符串,确定对话框的“save as file type”(另存为文档类型)或“files of type”(文档类型)框中显示的选项。
filterindex 文档对话框中当前选定的筛选器的索引。
initialdirectory 文档对话框显示的初始目录。
restoredirectory 指示对话框在关闭之前是否还原当前目录。
showhelp 指示文档对话框中是否显示 help(帮助)按钮。
title 文档对话框标题。
validatenames 指示对话框是否只接受有效文档名。
reset (method) 将任何属性重置为默认值。
showdialog (method) 显示文档对话框。假如用户按 ok(确定),将返回 dialogresult.ok,否则返回 dialogresult.cancel。

单击 select a file(选择文档)时,示例窗体 frmfileversioninfo 将调用以下代码:
private sub btnselectfile_click( _ byval sender as system.object, _ byval e as system.eventargs) _ handles btnselectfile.click    dim ofd as openfiledialog = new openfiledialog()    ofd.filter = _        "executable files (*.exe;*.dll;*.ocx)|" & _        "*.exe;*.dll;*.ocx|" & _        "drivers (*.sys;*.drv;*.fnt)|" & _        "*.sys;*.drv;*.fnt|" & _        "all files (*.*)|*.*"    ofd.filterindex = 1    ofd.showreadonly = false    ofd.restoredirectory = true    if ofd.showdialog() = dialogresult.ok then        if ofd.filename.length > 0 then             显示文档版本信息。            displayfileinfo(ofd.filename)        end if    end ifend sub
提示:如同使用 visual basic 6.0 commondialog activex 控件相同,您能够将 filedialog 类的 filter 属性配置为一个字符串,在其中包含一对以竖线分隔的值,如下所示:“description|filespec”。

在上面的示例中,一旦您选择了一个文档名,示例窗体就会在窗体的 listview 控件中显示有关该文档的信息。下一节将讨论 fileversioninfo 类,他能够实现上述操作。
检索文档版本信息

研发人员和编译人员能够将版本信息嵌入到可执行文档、dll 文档和驱动程式文档中。您可能需要检索部分或全部版本信息以用作应用程式的一部分,在 visual basic 6.0 中执行此操作需要大量的 api 调用。您需要调用 getversioninfosize、verqueryvalue 和 getfileversioninfo win32 api 函数,在 visual basic 中使用上述任何函数都不容易。
这种情况再一次显示出 .net 框架的强大:使用 fileversioninfo 对象使得这些工作变得很简单。您只需调用 fileversioninfo 对象的共享 getversioninfo 方法,传递一个文档名,一切问题就都迎刃而解了。示例窗体使用了以下代码:
dim fvi as fileversioninfo = _ fileversioninfo.getversioninfo(strfile)

完成以上操作之后,检索 fileversioninfo 对象的属性就是一件很简单的事情了。示例窗体使用下面所示的一小段程式,将每个属性名称和值都添加到窗体的 listview 控件中:
private sub additem( _byval strproperty as string, _byval strvalue as string)    with lvwinfo.items.add(strproperty)        .subitems.add(strvalue)    end withend sub

真正起作用的是代码,而代码只需反复调用 additem,每个属性调用一次即可:
additem("comments", fvi.comments)additem("companyname", fvi.companyname)additem("language", fvi.language) 此处删除了一些行...additem("product", fvi.productname)additem("productprivatepart", _ fvi.productprivatepart.tostring())additem("productversion", fvi.productversion)additem("specialbuild", fvi.specialbuild)

图 3 所示的结果窗体显示了可通过编程使用的任何版本信息。

图 3:使用 fileversioninfo 类检索文档版本信息
检索环境信息

win32 api 提供了一系列函数,使您能够确定用户的环境配置。getsystemmetrics 和 systemparametersinfo 是其中的两个函数。您能够继续从 .net 应用程式中调用这些 api 函数,但很可能您并无需这样做。environment 类(位于 system 名称空间)和 systeminformation 类(位于 system.windows.forms 名称空间)提供了许多和 api 函数相同的信息。在本节中,我们将通过示例来演示这两个类的功能。
警告:不要浪费时间从这些类中寻找配置用户环境配置的方法。此处显示的任何信息均为只读。假如您仍然希望修改环境配置,则需要寻找其他方法。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值