近日正在更新用MASM32编写的sysInfo,通过WMI访问Win32_UserCount来获取系统用户帐号信息,访问Win32_Product来获取系统中安装的产品信息。
在进行更新过程中,有一些新的收获跟大家分享。
在MASM32中使用WMI访问这些对象及其成员,必须用Unicode DW 字符串。比如要访问Win32_Product对象:
[Provider("MSIProv"), Dynamic]
class Win32_Product : CIM_Product
{
uint16 AssignmentType;
string Caption;
string Description;
string IdentifyingNumber;
string InstallDate;
datetime InstallDate2;
string InstallLocation;
sint16 InstallState;
string HelpLink;
string HelpTelephone;
string InstallSource;
string Language;
string LocalPackage;
string Name;
string PackageCache;
string PackageCode;
string PackageName;
string ProductID;
string RegOwner;
string RegCompany;
string SKUNumber;
string Transforms;
string URLInfoAbout;
string URLUpdateInfo;
string Vendor;
uint32 WordCount;
string Version;
};
那对象名称Win32_Product要定义为:
g_wszWin32_Product dw "W","i","n","3","2","_","P","r","o","d","u","c","t",0,0
其中的成员,如AssignmentType,要定义为:
g_wszAssignmentType dw 'A','s','s','i','g','n','m','e','n','t','T','y','p','e', 0, 0
虽然MASM32 在其自带的准开发环境QEDITOR 的 Conversions菜单中里提供了Text to DW UNICODE菜单项功能,但这个菜单项还不能实现自动从类中提出成员属性名称并转换为MASM32的DW UNICODE字符串的格式,所以我们还是先得手工将AssignmentType、Caption……提取出来。当对象成员很多的时候,不仅工作量大,而且还容易出错。为此,我用HTML+Javascript写了一个转换工具来完成这些工作,详见:
HTML+JavaScript构建C++类代码一键转换MASM32代码平台
Win32_Product等对象虽然定义没有变,但其中的成员属性的有效性会因Windows版本而异。
比如Win32_Product对象中的的InstallDate就不再有效,由InstallDate2来替代。
但InstallDate2的有效性会因Windows版本而异,初步测试发现这个属性在Windows XP上有效,在Windows 7 、Windows 10上似乎无效。
要想保证程序在各个版本的Windows上正确运行,还需要逐一测试。
测试发现Win32_Product对象的成员Language
Language
Data type: string
Access type: Read-only
The language of the product.
Windows Server 2003: This property is not available.
在Windows XP、和Windows 10均有效,它返回的是产品的Locale ID(区域性标识符)字符串,最常见的就是2052对应的是简体中文Chinese (Simplified)People's Republic of China,1033对应的是英文(美国)。
比如中文就有下面这些:
Language |
Location (or type) |
Language ID(Hex) |
Language ID(Dec) | Language tag |
Supported version |
---|---|---|---|---|---|
Chinese (Simplified) |
0x0004 |
4 | zh-Hans |
Release A |
|
Chinese (Simplified) |
0x7804 |
30724 | zh |
Windows 7 |
|
Chinese (Simplified) |
People's Republic of China |
0x0804 |
2052 | zh-CN |
Release A |
Chinese (Simplified) |
Singapore |
0x1004 |
4100 | zh-SG |
Release A |
Chinese (Traditional) |
0x7C04 |
31748 | zh-Hant |
Release A |
|
Chinese (Traditional) |
Hong Kong Special Administrative Region |
0x0C04 |
3076 | zh-HK |
Release A |
Chinese (Traditional) |
Macao S.A.R. |
0x1404 |
5124 | zh-MO |
Release D |
Chinese (Traditional) |
Taiwan |
0x0404 |
1028 | zh-TW |
Release A |
更详细的信息可参考:5 Appendix A: Product Behavior
如果我们要精确将这些中文区域性标识符区分出来,直接进行字符串比较运算量就大了,我们可以把字符串转换为对应的数字,再进行比较,运算量会小一些。
要实现字符串转换为对应的数字,可以使用Windows API函数:StrToIntEx():
BOOL StrToIntExA(
[in] PCSTR pszString,
STIF_FLAGS dwFlags,
[out] int *piRet
);
详见微软网官的说明:StrToIntExA function (shlwapi.h) - Win32 apps | Microsoft Learn
我们也可以自己写一个程序来进行转换,比如下面这个网友分享的字符串转数值函数:
;======================================================
str2num proc uses ebx ecx edx esi edi
;======================================================
; In: eax, offset to str_num
; out: eax, the number converted
mov edi, eax ; offset
xor eax, eax ;mov eax, 0
mov ecx, cdMaxSize
repne scasb
jne @NoFound
sub edi, 2
sub ecx, cdMaxSize
neg ecx
mov ebx, 1 ; factor
mov esi, 0 ; Acumulative
@Next:
dec ecx
jl @Exit
xor eax, eax ; clear it
mov al, byte ptr [edi]
and al, 15 ; 2num
mul ebx
add esi, eax ; get into accumulative
mov eax, ebx ; increases factor
mov ebx, 10
mul ebx
mov ebx, eax
dec edi ; reset pointer
jmp @Next
@Exit:
mov eax, esi
@NoFound:
ret
str2num endp
需要注意的是,这个函数没有考虑字符串中掺杂其它字符的情况,比如字符串末尾有回车、换行符的情况。