无忧启动论坛
标题:
一些 PECMD 封装函数和调用 WinApi 示例代码
[打印本页]
作者:
Bluebells
时间:
2026-1-17 19:19
标题:
一些 PECMD 封装函数和调用 WinApi 示例代码
本帖最后由 Bluebells 于 2026-1-18 20:43 编辑
一些实用的(?) PECMD 示例代码分享给大家参考参考
代码质量可能不太好, 一些术语描述可能有误, 因为本人没啥编程基础, 希望大家谅解
EFI 变量设置封装函数
简单的 Ini 文本文件读写封装函数 (2楼)
获取目标驱动器的磁盘号和分区号 (3楼)
判断当前安全启动状态
或使用 18 楼示例代码
获取系统版本号 (8楼)
获取计算机名和当前登录用户名 (10楼)
脱机注册表封装函数
获取系统(启动)分区 (15楼)
获取系统当前启动方式 (16楼)
获取 Windows, System 和 Temp 目录 (17楼)
作者:
Bluebells
时间:
2026-1-17 19:20
;IniRead 有五个参数, 第一个参数为目标 .ini 完整文件名, 第二个参数为节名, 第三个参数为键名, 第四个参数为默认值, 第五个参数为存放读取的值的变量
;当无法读取目标键的值时, 其返回值(第五个参数变量值)将为默认值(第四个参数定义的值)
_SUB IniRead
TEAM ENVI &FileName=%~1| ENVI &SectionName=%~2| ENVI &KeyName=%~3| ENVI &DefValue=%~4
FIND %&FileName%=,EXIT _SUB
FIND %&SectionName%=,EXIT _SUB
FIND %&KeyName%=,EXIT _SUB
FIND %&DefValue%=,EXIT _SUB
CALL $--qd --ret:&ret Kernel32.dll,GetPrivateProfileStringW,$%&SectionName%,$%&KeyName%,$%&DefValue%,0,0,$%&FileName%
TEAM CALC #&CC = %&ret% + 1| CALC #&nSize = %&CC% * 2
SET$ &ValueName=*%&nSize% 0
CALL $--qd --ret:&ret Kernel32.dll,GetPrivateProfileStringW,$%&SectionName%,$%&KeyName%,$%&DefValue%,*&ValueName,#%&CC%,$%&FileName%
ENVI-ret %~5=%&ValueName%
_END
;IniWrite 有四个参数, 第一个参数为目标 .ini 完整文件名, 第二个参数为节名, 第三个参数为键名, 第四个参数为值名, 第五个参数为返回值(若返回零则写入失败)
;其中第四个和第五个参数为可选, 当第四个参数留空时, 将移除目标键的值
_SUB IniWrite
TEAM ENVI &FileName=%~1| ENVI &SectionName=%~2| ENVI &KeyName=%~3| ENVI &ValueName=%~4
FIND %&FileName%=,EXIT _SUB
FIND %&SectionName%=,EXIT _SUB
FIND %&KeyName%=,EXIT _SUB
CALL $--qd --ret:&ret Kernel32.dll,WritePrivateProfileStringW,$%&SectionName%,$%&KeyName%,$%&ValueName%,$%&FileName%
ENVI-ret %~5=%&ret%
_END
复制代码
PS:
mdyblog
老大的 PECMD 的示例代码(readini.wcs)中有读取 Ini 文本文件的封装代码段, 不过挺复杂的
作者:
Bluebells
时间:
2026-1-17 19:23
;只有一个输入参数和两个输出参数
;输入参数为路径, 支持驱动器号(盘符), 路径命名空间(\\?\HarddiskVolumeX, \\?\HarddiskX\PartitionX 等)
;第一个输出参数为设备号, 第二个输出参数为分区号
_SUB GetDevicePartNum
SET &drv=%~1
ENVI-ret %~2=
ENVI-ret %~3=
SET &prefix=\\?\
SET &gr=
LSTR aStr1=4,%drv%
LSTR aStr2=7,%drv%
FIND $%aStr1%=\\?\,SET &prefix=
FIND $%aStr2%=\Device,SET &gr=GLOBALROOT
SET &FILE_ANY_ACCESS=0x00000000
SET &OPEN_EXISTING=3
SET &IOCTL_STORAGE_GET_DEVICE_NUMBER=0x2D1080
SET$# &udtQuery=*4 0 *4 0 *4 0
ENVI$# &&cbBytesReturned=*8 0
CALL $--qd --ret:&&h Kernel32.dll,CreateFileW,$%prefix%%gr%%drv%,#0,#%FILE_ANY_ACCESS%,#0,#%OPEN_EXISTING%,#0,#0
IFEX #%h%=-1, EXIT
CALL $--qd --ret:&&ret Kernel32.dll,DeviceIoControl,#%h%,#%IOCTL_STORAGE_GET_DEVICE_NUMBER%,#0,#0,*&udtQuery,#12,*&cbBytesReturned,#0 //待处理
CALL $--qd --ret:&&ret Kernel32.dll,CloseHandle,#%h%
ENVI?int &udtQuery=&&DeviceNum:4
ENVI?int &udtQuery=&&PartNum:8
ENVI-ret %~2=%&DeviceNum%
ENVI-ret %~3=%&PartNum%
_END
GetDevicePartNum C: &1 &2
GetDevicePartNum \\?\HarddiskVolume2 &3 &4
MESS 设备(磁盘)号: %1%\n分区号: %2%\n\n设备(磁盘)号: %3%\n分区号: %4%
复制代码
作者:
a66
时间:
2026-1-17 19:30
了解
作者:
smile_z
时间:
2026-1-17 19:32
学习一下
作者:
红毛樱木
时间:
2026-1-17 19:47
强贴留名
作者:
it323
时间:
2026-1-17 19:54
了解一下。
作者:
Bluebells
时间:
2026-1-17 20:09
;此封装函数有三个参数, 第一个参数用于存放返回的操作系统主要版本号, 第二个参数用于存放返回的操作系统次要版本号, 第三个参数用于存放返回的操作系统内部版本号
_SUB RtlGetVersion
SET$# &VersionInformation=*4 0 *4 0 *4 0 *4 0 *4 0 *256 0
SET-long &VersionInformation=276
CALL $--qd --ret:&ret ntdll.dll,RtlGetVersion,*&VersionInformation
IFEX #%&ret%<>0,EXIT
TEAM ENVI?int &VersionInformation=&MajorVersion:4| ENVI?int &VersionInformation=&MinorVersion:8| ENVI?int &VersionInformation=&BuildNumber:12
ENVI-ret %~1=%MajorVersion%
ENVI-ret %~2=%MinorVersion%
ENVI-ret %~3=%BuildNumber%
_END
;参数同上
_SUB GetNTVersion
TEAM SET-long &pMajorVersion=| SET-long &pMinorVersion=| SET-long &pBuildNumber=
CALL $--qd --ret:&ret ntdll.dll,RtlGetNtVersionNumbers,*&pMajorVersion,*&pMinorVersion,*&pBuildNumber
IFEX #%&ret%=0,EXIT
TEAM ENVI?int &pMajorVersion=&MajorVersion| ENVI?int &pMinorVersion=&MinorVersion| ENVI?int &pBuildNumber=&BuildNumber
CALC #&BuildNumber = %&BuildNumber% & 0xFFFF
ENVI-ret %~1=%MajorVersion%
ENVI-ret %~2=%MinorVersion%
ENVI-ret %~3=%BuildNumber%
_END
复制代码
PS: RtlGetNtVersionNumbers 为非公开函数, 且支持系统版本范围为 NT5.1+; 感谢
wintoflash
老大帮忙处理获取正确的 BuildNumber 值
作者:
yyz2191958
时间:
2026-1-17 20:19
技术贴 支持
作者:
Bluebells
时间:
2026-1-17 20:27
;获取计算机名称, 仅一个参数, 用于存放返回的计算机名称
_SUB GetComputerName
SET$# &nSize=*4 0
CALL $--qd --ret:&ret Kernel32.dll,GetComputerNameW,*,*&nSize
ENVI?int &nSize=&BufferSize
IFEX $%&BufferSize%=0,EXIT _SUB
SET$ &lpBuffer=*%&BufferSize% 0
CALL $--qd --ret:&&ret Kernel32.dll,GetComputerNameW,*&lpBuffer,*&nSize
IFEX $%&ret%=0,EXIT _SUB
ENVI-ret %~1=%&lpBuffer%
_END
;获取系统当前登录用户名, 仅一个参数, 用于存放返回的当前登录用户名
_SUB GetUserName
ENVI-ret %~1=
SET$# &pcbBuffer=*4 0
CALL $--qd --ret:&ret Advapi32.dll,GetUserNameW,*,*&pcbBuffer
ENVI?int &pcbBuffer=&BufferSize
IFEX $%&BufferSize%=0,EXIT _SUB
SET$ &lpBuffer=*%&BufferSize% 0
CALL $--qd --ret:&ret Advapi32.dll,GetUserNameW,*&lpBuffer,*&pcbBuffer
IFEX $%&ret%=0,EXIT _SUB
ENVI-ret %~1=%&lpBuffer%
_END
;调用示例
CALL GetComputerName &ComputerName
CALL GetUserName &UserName
MESS 计算机名称: %&ComputerName%\n\n用户名: %&UserName%
复制代码
作者:
handsome_xiang
时间:
2026-1-17 21:05
感谢分享!
作者:
没想到
时间:
2026-1-17 21:22
谢谢分享
作者:
wn168cn@163.com
时间:
2026-1-17 22:48
支持原创
作者:
张小仙
时间:
7 天前
学习一下。
作者:
Bluebells
时间:
7 天前
获取系统(启动)分区
_SUB GetBootDevice
IFEX #%&bX64%=3, Set &PtrSz=8! SET &PtrSz=4
CALC #&&Sz=%PtrSz% * 2
CALC #&&SzA=%Sz% + 8192
SET$# &retName=*%SzA% 0 *32 0
ENVI-mkdummy &&Nm=&retName@%Sz%;8192
CALL $--qd --ret:&&ret Ntdll.dll,NtQuerySystemInformation,#98,*&retName,#%SzA%,#0
IFEX #%&ret%=0,ENVI-ret %~1=%&Nm%
_END
;示例
CALL GetBootDevice &BootDevice
MESS %&BootDevice%
复制代码
PS: 此代码摘自
mdyblog
老大的 PECMD 的示例代码, 且返回信息为 dos 设备路径
作者:
Bluebells
时间:
7 天前
本帖最后由 Bluebells 于 2026-1-18 19:58 编辑
获取系统当前启动方式
_SUB GetSystemBootEnvironmentInformation
SET &SystemBootEnvironmentInformation=90
SET$# &pBuffer=*16 0 *4 0 *8 0
CALL $--qd --ret:&&ret Ntdll.dll,NtQuerySystemInformation,#%SystemBootEnvironmentInformation%,*&pBuffer,#32,#0
IFEX #%&ret%=0,
{*
SET?int pBuffer=&&FirmwareType:16
IFEX #%&FirmwareType%=0,ENVI-ret %~1=Unknown
IFEX #%&FirmwareType%=1,ENVI-ret %~1=BIOS
IFEX #%&FirmwareType%=2,ENVI-ret %~1=UEFI
IFEX #%&FirmwareType%=3,ENVI-ret %~1=Unknown
}! ENVI-ret %~1=Unknown
_END
;示例
CALL GetSystemBootEnvironmentInformation &BootEnvironment
MESS %&BootEnvironment%
复制代码
PS: 一些人根据磁盘的分区样式去判断启动方式是非常不正确的
作者:
Bluebells
时间:
7 天前
获取 Windows, System 和 Temp 目录
_SUB GetWindowsDirectory
CALL $--qd --ret:&ret Kernel32.dll,GetWindowsDirectoryW,*&lpBuffer,#0
SET$ &&lpBuffer=*%&ret% 0
CALL $--qd --ret:&ret Kernel32.dll,GetWindowsDirectoryW,*&lpBuffer,#%&ret%
IFEX #%&ret%=0,EXIT
ENVI-ret %~1=%&lpBuffer%
_END
_SUB GetSystemDirectory
CALL $--qd --ret:&ret Kernel32.dll,GetSystemDirectoryW,*&lpBuffer,#0
SET$ &&lpBuffer=*%&ret% 0
CALL $--qd --ret:&&ret Kernel32.dll,GetSystemDirectoryW,*&lpBuffer,#%&ret%
IFEX #%&ret%=0,EXIT
ENVI-ret %~1=%&lpBuffer%
_END
_SUB GetTempPath
CALL $--qd --ret:&ret Kernel32.dll,GetTempPathW,#0,*&lpBuffer
SET$ &&lpBuffer=*%&ret% 0
CALL $--qd --ret:&ret Kernel32.dll,GetTempPathW,#%&ret%,*&lpBuffer
IFEX #%&ret%=0,EXIT
ENVI-ret %~1=%&lpBuffer%
_END
CALL GetWindowsDirectory &WinPath
CALL GetSystemDirectory &SystemPath
CALL GetTempPath &TempPath
MESS %&WinPath%\n%&SystemPath%\n%&TempPath%
复制代码
PS: 也许有人说, 为啥不直接用环境变量, 正所谓萝卜青菜,各有所爱
作者:
Bluebells
时间:
7 天前
获取当前安全启动状态
;此方法仅支持NT6.2及以上版本, 此函数还能查询目标机器是否支持安全启动功能
_SUB GetSystemSecureBootInformation
SET$ &SSBI=*1 0 *1 0
CALL $--qd --ret:&ret ntdll.dll,NtQuerySystemInformation,#145,*&SSBI,#2,0
IFEX #%&ret%<>0,TEAM ENVI-ret %~1=Unknown| EXIT _SUB
SET?char &SSBI=&SecureBootEnabled
;SET?char &SSBI=&SecureBootCapable:1
IFEX #%&SecureBootEnabled%=0,ENVI-ret %~1=Disabled! ENVI-ret %~1=Enabled
_END
;示例
GetSystemSecureBootInformation &SecureBoot
MESS %&SecureBoot%
复制代码
PS: 在 64 位操作系统下必须使用 64 位版本的 PECMD 才能正确调用此函数
作者:
ebaqiang
时间:
6 天前
等热心人来
作者:
fegr
时间:
6 天前
感谢分享
作者:
win82
时间:
4 天前
学习一下
欢迎光临 无忧启动论坛 (http://bbs.c3.wuyou.net/)
Powered by Discuz! X3.3