ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 127989|回复: 265

上一道冷门的菜(在VBA中使用WMI,,到此结束)

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2011-6-22 08:50 | 显示全部楼层 |阅读模式
本帖已被收录到知识树中,索引项:WMI应用
第三部分地址:
http://club.excelhome.net/viewthread.php?tid=733445&extra=page%3D1%26amp%3Bfilter%3D0%26amp%3Borderby%3Dlastpost%26amp%3Bascdesc%3DDESC&page=3
第四部分地址:
http://club.excelhome.net/viewth ... cdesc%3DDESC&page=8
第五部分地址:
http://club.excelhome.net/viewth ... cdesc%3DDESC&page=9
在这里学到很多东西,总想写点什么回报excelhome,暑假来了,有了大段的时间,那就开始干吧。
VB(VBA)的优点多多,不再多说,它最为使用者诟病的是:在硬件控制和系统底层应用方面较差,动辄就要API,
这意味你必须面对以下的困难:
1、重回面向过程的编程方式,(实在让人头大)。
2、在数以百计的函数中寻找合适的函数,然后理解并设置函数中的各项参数(还全是英文的)。
好消息是你可以不用API也可以完成好多API的功能。你应该知道VBScript脚本,它是利用WMI对象来实现对系统操控的,(网上好多抓“肉鸡”的程序就是利用它做的,有点危险,跑题了哈),VBScript和VB都是一样的血统,所以我们可以在VB(VBA)中使WMI对象。
认识和使用WMI
那么WMI是什么, WMI是Windows Management Instrumentation (Windows管理工具)的缩写,是内置在操作系统中核心的管理支持技术。基于由 Distributed Management Task Force (DMTF) 所监督的业界标准,通过它可以访问、配置、管理和监视几乎所有的 Windows 资源。很枯燥吧,不过你暂时可以按以下几点去简单理解:

1、就像ADO对象是用于数据库操作的,WMI是一个用于管理Windows系统的对象。你可以把Windows系统的资源看做
   数据库,WMI就是ADO。
2、引用WMI对象就可以实现管理Windows系统中的磁盘、事件日志、文件、文件夹、文件系统、网络组件、操作系
   设置、性能数据、打印机、进程、注册表设置、安全性、服务、共享、用户、组等等。
3、WMI的类有自己的属性、方法,就像使用标准控件一样简单。(还是有区别)

要使用WMI要满足一下条件,以后不再重复:
1、添加对“Microsoft WMI Scripting V1.2 Library”的引用。
2、Windows里的WMI 服务(winmgmt)保证是运行的。
说明一下,你在网上看到的使用WMI的方法大多是这样的:
Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
这是创建对象的方式,不用在工程中先引用“Microsoft WMI Scripting V1.2 Library”。为了不混淆,我们统一使用先引用方的式。二者只是句法不同,作用一样,两者的优缺点和在VBA中使用其他类是一样的(这不多解释了)。

好了,先看一个使用WMI的例子,该例子列举本机上的所有系统服务的名字、状态、启动方式、登录身份、描述、路径。(就是用VBA做一个和控制面板里的服务组件一样的服务管理器)
例1:打开VBA编辑器,单击“工具”—“引用“ ,添加“Microsoft WMI Scripting V1.2 Library”,
在Sheet1中添加CommandButton1和如下代码:

Option Explicit

Dim WMILocator As New SWbemLocator '定义一个指向WMI的指针
Dim WMIServices As SWbemServices
Dim WMIObjectSet As SWbemObjectSet
Dim WMIObject As SWbemObject

Private Sub CommandButton1_Click()
Dim i As Long
Sheet1.Cells.Clear
Sheet1.Range("a1:e1") = Array("名称", "状态", "启动类型", "登录身份", "描述")
Set WMIServices = WMILocator.ConnectServer()  
'利用指针连接到本机的WMI,返回一个对 SWbemServices 对象的引用
Set WMIObjectSet = WMIServices.InstancesOf("Win32_Service")
'用对象WMIServices的InstancesOf方法返回Win32_Service类名标识的所有实例
i = 2
With Sheet1
    For Each WMIObject In WMIObjectSet '在WMIObjectSet(Win32_Service类集合)中遍历每个实例
        .Range("a" & i).Value = WMIObject.DisplayName '服务名称添加到a列
        If WMIObject.State = "Stopped" Then '判断对象State属性的值并转换为中文添加到B列
            .Range("b" & i).Value = "停止"
        Else
            .Range("b" & i).Value = "启动"
        End If
        If WMIObject.StartMode = "Disabled" Then '判断对象StartMode属性的值并转换为中文添加到C列
            .Range("c" & i).Value = "禁用"
        ElseIf WMIObject.StartMode = "Manual" Then
            .Range("c" & i).Value = "手动"
        Else
            .Range("c" & i).Value = "自动"
        End If
        .Range("d" & i).Value = WMIObject.StartName '将服务的登录身份添加到D列
                .Range("e" & i).Value = WMIObject.Description '将服务的描述添加到E列
        i = i + 1
    Next
End With
Set WMIObject = Nothing
Set WMIObjectSet = Nothing
End Sub
我们没有用API函数的情况实现了枚举服务这个系统底层应用。也许你要问,这只是列举并不能对列举的服务进行任何操作,别急,每个WMIObject都有属性、方法,改变它的属性或使用其方法就可以控制服务的启动类型、状态(开启或关闭),这个以后再说。
例中我们枚举"Win32_Service"类的每个服务得到了服务列表,把例中的"Win32_Service"换成Win32_Process类,就可以对本机的进程进行列举(你就做了一个VBA版的进程管理器)动手试试吧!附件里有(最好先别看,自己做一下),你会发现除了枚举的类其他都是一样的。
照葫芦画瓢,把Set WMIObjectSet = WMIServices.InstancesOf("Win32_Service")中的"Win32_Service"换成其他类你就可以利用系统的其他资源了!你又要问了,我怎么知道有哪些类,不着急,后面会给出枚举系统中所有类的例子。(全是英文,懂英语会好些,根据类的名字判断他的作用,以Win32_Service为例Service就是服务,Win32_Service里包含的就是和系统服务有关的资源。)
其实稍作修改,你还可以列举局域网中其他机器的服务和进程(前提是你要有足够的授权,比如系统管理员

总结一下使用WMI的步骤:
1、添加对“Microsoft WMI Scripting V1.1 Library”的引用。
2、创建SwbemLocator指针。创建指针的目的是为了建立对WMI对象的引用实例,然后用这个实例操作WMI。
用Dim WMILocator As New SwbemLocator定义语句直接创建就可以了。
3、连接到WMI服务
Set WMIServices = WMILocator.ConnectServer()
'利用指针连接到指定计算机的WMI服务,然后返回一个SwbemServices对象。
4、获得WMI类的实例集合
Set WMIObjectSet = WMIServices.InstancesOf(“类名”)
'利用SwbemServices对象的InstancesOf 方法返回指定类名的所有实例
5、使用WMI资源

先写到这吧,如果你感兴趣的话,顶一下,我会接着写下去。
下次通过几个有趣而实用的例子详细学习使用WMI的方法。
获取U盘物理序列号,CPU ID ,网卡物理地址等。9楼继续
为方便大家使用,所有例子整理到一起

[ 本帖最后由 wpxxsyzx 于 2011-7-4 17:56 编辑 ]

评分

11

查看全部评分

TA的精华主题

TA的得分主题

发表于 2011-6-22 08:54 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2011-6-22 09:14 | 显示全部楼层
虽然不太熟悉VBA对系统的控制,对看了该文,多有收获。
不错,辛苦了。

TA的精华主题

TA的得分主题

发表于 2011-6-22 09:18 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2011-6-22 09:23 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
厉害

TA的精华主题

TA的得分主题

发表于 2011-6-22 09:24 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2011-6-22 09:45 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2011-6-22 09:48 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册

回复 wpxxsyzx

我这里论坛短信发送功能失效,只好在这里跟贴回复:
如果文章字数过多,可以多建几个楼层发表。

TA的精华主题

TA的得分主题

 楼主| 发表于 2011-6-22 11:04 | 显示全部楼层
建立对WMI对象的引用的方法
例1中第二步Set WMIServices = WMILocator.ConnectServer()中使用ConnectServer方法建立了对WMI对象的引用实例,该方法的句法如下:
WMILocator.ConnectServer(strServer, strNamespace, strUser, strPassword, strLocale, StrAuthority, iSecurityFlags, ObjwbemNamedValueSet)
下面说一下这八个参数(前六个参数全是字符类型):
1、strServer: 计算机名字。缺省为本机,本机也可以用”.”表示,如果对局域网中的其他机器操作,在此处将”.”换成该机器名字。
2、strNamespace :需要登录的CIM命名空间,缺省值为:"root\CIMV2",代表我们工作的WIN32环境。(CIM就是一个存储库,WMI所有的类被分组存储到不同的命名空间中,命名空间是表示一个特定的管理区域的类的逻辑组,关于命名空间我们后面再说并给出枚举所有命名空间的例子)。例如:
Set WMIServices = WMILocator.ConnectServer(“.”, "root\CIMV2"),连接到本地计算机的" "root\CIMV2"命名空间,返回一个对 SWbemServices 对象的引用。
3、strUser :用户名,一般为指定计算机上管理员帐号,仅用于远程操作。
4、strPassword:密码,对应用户名的密码,和第三部分一起使用。例如:
Set WMIServices = WMILocator.ConnectServer(“pc1” , "root\CIMV2",”administrator”,”123”),以administrator用户(密码为:123)连接到PC1的计算机的"root\CIMV2"命名空间,返回一个对 SWbemServices 对象的引用。
5、strLocale :本地化代码(和语言有关),通常省略。
6、StrAuthority :权限信息,很少使用,可以省略。
7、iSecurityFlags :没有实现,如果指定必须为0。
8、ObjwbemNamedValueSet:很少使用,当为连接请求提供服务时,一些提供程序可能需要使用这个参数。

了解了这些后,回到例1,Set WMIServices = WMILocator.ConnectServer()这句的完整写法应该为:
Set WMIServices = WMILocator.ConnectServer(“.”, "root\CIMV2")。
我们的例子中()里参数为空,就是所有参数使用了默认值,因为ConnectServer方法的所有参数都是可选的。
如果连接到本机,通常情况下只需要设置strNamespace参数,其它参数都可以省略,但如果连接到远程计算机,一般需要对前4个参数进行设置。
下面讨论获得WMI类的实例集合的几种方法
1、InstancesOf方法。
该方法用于获得指定类中所有实例,语法如下:
SwbemServices.InstancesOf(strClass,[iFlags][objWbemNamedValueSet])
strClass:要查询的类名(字符串)
iFlags:操作标志,一般使用缺省值(即wbemFlagReturnImmediately),可省略。
objWbemNamedValueSet:未用。
例2:本例枚举你机器上所有U盘的物理序列号(不是卷标哦)U盘的信息存储在Win32_USBHub类中。添加一个CommandButton1到sheet1,代码如下:
Option Explicit

Dim WMILocator As New SWbemLocator '定义一个指向WMI的指针
Dim WMIServices As SWbemServices
Dim WMIObjectSet As SWbemObjectSet
Dim WMIObject As SWbemObject

Private Sub CommandButton1_Click()
Dim i As Long
Sheet1.Cells.Clear
Set WMIServices = WMILocator.ConnectServer(".", "root\CIMV2") '可以省略,写上是为了更好理解参数的使用
Set WMIObjectSet = WMIServices.InstancesOf("Win32_USBHub")
i = 1
With Sheet1
    For Each WMIObject In WMIObjectSet
        .Range("a" & i).Value = "U盘" & i
        .Range("b" & i).Value = Split(WMIObject.DeviceID, "\")(2) '物理序列号添加到B列
        i = i + 1
    Next
End With
Set WMIObject = Nothing
Set WMIObjectSet = Nothing
End Sub
因为是枚举了所有USB实例,所以除了U盘还包括机器上的USB接口,我的机器上真正的U盘只一个。(其实你可以利用后面的方法把USB接口排除只留U盘)
它的缺点显而易见:
1、类的实例较多时速度会慢(如果针对局域网中其他计算机使用WMI,网络流量较大)。
2、再者,你只需要特定的几个或一个类的实例时,显然这种方法效率不高。
针对以上情况,我们可以使用以下方法获取类的一个或符合条件的一组实例:
2、使用ExecQuery方法。
该方法配合WQL语句用于获得指定类中所有实例或符合条件的一组实例,语法参数格式如下:
SwbemServices.ExecQuery(strQuery,[strQueryLanguage],[iFlags],[objWbemNamedValueSet])
strQuery:WQL查询语句。
strQueryLanguage:表示所使用的查询语言,可以省去,如添加的话,只能用"WQL"。
iFlags和objWbemNamedValueSet的解释同InstancesOf方法。

例3:获取机器上网卡的名称和其物理地址(它的信息存储在Win32_NetworkAdapterConfiguration类)使用ExecQuery方法和WQL语句排除系统的红外、VPN WAN等端口。添加一个CommandButton1到sheet2,代码如下:
Option Explicit

Dim WMILocator As New SWbemLocator
Dim WMIServices As SWbemServices
Dim WMIObjectSet As SWbemObjectSet
Dim WMIObject As SWbemObject

Private Sub CommandButton1_Click()
Dim i As Long
Sheet2.Cells.Clear
Sheet2.Range("a1:e1") = Array("名字", "物理地址", "IP地址", "子网掩码", "网关")
Set WMIServices = WMILocator.ConnectServer() '省略参数
Set WMIObjectSet = WMIServices.ExecQuery("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE DatabasePath Is Not NULL ")
i = 2
With Sheet2
    For Each WMIObject In WMIObjectSet
        .Range("a" & i).Value = WMIObject.Description '名字添加到a列
        .Range("b" & i).Value = WMIObject.MACAddress '物理地址添加到B列
        .Range("c" & i).Value = WMIObject.IPAddress
        .Range("d" & i).Value = WMIObject.IPSubnet
        .Range("e" & i).Value = WMIObject.DefaultIPGateway
        i = i + 1
    Next
End With
Set WMIObject = Nothing
Set WMIObjectSet = Nothing
End Sub
“SELECT * FROM Win32_NetworkAdapterConfiguration WHERE DatabasePath Is Not NULL "这句是否很熟悉,这是WQL语句(SOL的子集,具体的使用方法我还没找到,估计和SQL的方法一样)。
说明:
A、如果要在例1中只返回启动方式为“自动”的服务只需改Set WMIObjectSet = WMIServices.InstancesOf("Win32_Service")为Set WMIObjectSet = WMIServices.ExecQuery("SELECT * FROM Win32_Service WHERE StartMode='auto'")就可以了。该句的意思为:从Win32_Service类中返回StartMode属性为auto的所有实例(包括实例的所有属性),“*”代表选择实例的所有属性。
B、“SELECT * FROM Win32_NetworkAdapterConfiguration WHERE DatabasePath Is Not NULL "把这句的where子句全删除,你会发现多出来许多东西。
C、语句中使用了“*” ,说明获得实例的所有属性,如果只需实例的要一个或几个属性该如何呢?例如例中我们只用到了名称和地址两个属性,把该句改为:"SELECT Description, MACAddress FROM Win32_NetworkAdapter WHERE DatabasePath Is Not NULL " 。效果是一样的。以上三点自己动手试一下。
3、使用Get方法。
该方法用于获得指定类中符合条件的一个实例,语法参数格式如下:
SwbemServices.Get([strObjectPath][.KeyProperty='Value'],[iFlags],[objWbemNamedValueSet])
strObjectPath:类的名字
KeyProperty:主键属性名,Value是指定的主键属性值。通过指定此项就可返回类中KeyProperty属性值为Value的唯一的实例。
iFlags和objWbemNamedValueSet与ExecQuery方法中的说明相同。
例4:CPU的信息存储在Win32_Processor类里。通常我们只有一个CPU,再用上面枚举全部或部分实例的方法显得多余,本例获取我们的第一个CPU的相关信息。添加一个CommandButton1到sheet3,代码如下:
Option Explicit

Dim WMILocator As New SWbemLocator
Dim WMIServices As SWbemServices
Dim WMIObject As SWbemObject

Private Sub CommandButton1_Click()
Sheet3.Cells.Clear
Sheet3.Range("a1:e1") = Array("类型", "频率", "二级缓存", "接口类型", "核心数")
Set WMIServices = WMILocator.ConnectServer() '省略参数
Set WMIObject = WMIServices.Get("Win32_Processor.DeviceID='cpu0'")
With Sheet3
        .Range("a2").Value = WMIObject.Name '添加cpu类型,cpu发展太快,wmi没跟上,可能和实际不符
        .Range("b2").Value = WMIObject.CurrentClockSpeed / 1000 & "GHz"
        .Range("c2").Value = WMIObject.L2CacheSize & "K"
        .Range("d2").Value = WMIObject.SocketDesignation
        .Range("e2").Value = WMIObject.NumberOfLogicalProcessors & "核"
.Range("f2").Value = WMIObject.ProcessorId
End With
Set WMIObject = Nothing
End Sub
好了,现在你对使用WMI应该比较熟悉了吧。如果你感觉还是比较混乱的话,我们在回顾一下:
1、用Dim WMILocator As New SwbemLocator建立对WMI对象的引用实例
2、用Set WMIServices = WMILocator.ConnectServer(机器名,命名空间)连接到指定计算机的指定名字空间的WMI服务
3、用Set WMIObjectSet = WMIServices.InstancesOf(“类名”),返回指定类名的所有实例
现在令你感到困惑的可能是:类有多少,在哪,各是什么作用,什么是命名空间等等,这关系到WMI的体系结构,下一节学习。吃饭去喽。24楼继续

[ 本帖最后由 wpxxsyzx 于 2011-6-23 09:01 编辑 ]

例2、3、4、7-U盘、网卡、cpu、硬盘.rar

20.5 KB, 下载次数: 1481

评分

2

查看全部评分

TA的精华主题

TA的得分主题

发表于 2011-6-22 11:12 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
这个膘旱了
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-12-22 00:24 , Processed in 0.047377 second(s), 11 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表