找回密码
 注册
搜索
系统gho:最纯净好用系统下载站投放广告、加入VIP会员,请联系 微信:wuyouceo
查看: 2180|回复: 19

[讨论] 一些 PECMD 封装函数和调用 WinApi 示例代码

  [复制链接]
发表于 2026-1-17 19:19:25 | 显示全部楼层 |阅读模式
本帖最后由 Bluebells 于 2026-5-3 19:47 编辑

一些实用的(?) PECMD 示例代码分享给大家参考参考
代码质量可能不太好, 一些术语描述可能有误, 因为本人没啥编程基础, 希望大家谅解

EFI 变量设置封装函数
简单的 Ini 文本文件读写封装函数 (2楼)
获取目标驱动器的磁盘号和分区号 (3楼)
判断当前安全启动状态 或使用 18 楼示例代码
获取系统版本号 (8楼)
获取计算机名和当前登录用户名 (10楼)
脱机注册表封装函数
获取系统(启动)分区 (15楼)
获取系统当前启动方式 (16楼)
获取 Windows, System 和 Temp 目录 (17楼)
调用libwim-15.dll函数获取WIM/ESD映像文件信息

 楼主| 发表于 2026-1-17 19:20:19 | 显示全部楼层
本帖最后由 Bluebells 于 2026-5-3 13:57 编辑
  1. ;IniRead 有五个参数, 第一个参数为目标 .ini 完整文件名, 第二个参数为节名, 第三个参数为键名, 第四个参数为默认值, 第五个参数为存放读取的值的变量
  2. ;当无法读取目标键的值时, 其返回值(第五个参数变量值)将为默认值(第四个参数定义的值)
  3. _SUB IniRead
  4.     TEAM ENVI &FileName=%~1| ENVI &SectionName=%~2| ENVI &KeyName=%~3| ENVI &DefValue=%~4
  5.     FIND %&FileName%=,EXIT _SUB
  6.     FIND %&SectionName%=,EXIT _SUB
  7.     FIND %&KeyName%=,EXIT _SUB
  8.     FIND %&DefValue%=,EXIT _SUB
  9.     ENVI$# &ValueName=*65535 0
  10.     CALL $--qd --ret:&ret Kernel32.dll,GetPrivateProfileStringW,$%&SectionName%,$%&KeyName%,$%&DefValue%,*&ValueName,#65535,$%&FileName%
  11.     ENVI-ret %~5=%&ValueName%
  12. _END

  13. ;IniWrite 有四个参数, 第一个参数为目标 .ini 完整文件名, 第二个参数为节名, 第三个参数为键名, 第四个参数为值名, 第五个参数为返回值(若返回零则写入失败)
  14. ;其中第四个和第五个参数为可选, 当第四个参数留空时, 将移除目标键的值
  15. _SUB IniWrite
  16.     TEAM ENVI &FileName=%~1| ENVI &SectionName=%~2| ENVI &KeyName=%~3| ENVI &ValueName=%~4
  17.     FIND %&FileName%=,EXIT _SUB
  18.     FIND %&SectionName%=,EXIT _SUB
  19.     FIND %&KeyName%=,EXIT _SUB
  20.     CALL $--qd --ret:&ret Kernel32.dll,WritePrivateProfileStringW,$%&SectionName%,$%&KeyName%,$%&ValueName%,$%&FileName%
  21.     ENVI-ret %~5=%&ret%
  22. _END

  23. ;示例
  24. IniRead "D:\Example\Config.ini" "Settings" "Simple" "" &Value
  25. MESS %&Value%
  26. IniWrite "D:\Example\Config.ini" "Settings" "Simple" "Value" &RetVal
  27. MESS %&RetVal%
复制代码
PS: mdyblog 老大的 PECMD 的示例代码(readini.wcs)中有读取 Ini 文本文件的封装代码段, 不过挺复杂的; 将 IniWrite 封装函数内置到 PECMD 可执行文件里时好像需要将代码文件的文本编码转换为 ANSI 编码, 否则可能会导致 PECMD 在执行该封装函数时卡死


回复

使用道具 举报

 楼主| 发表于 2026-1-17 19:23:43 | 显示全部楼层
本帖最后由 Bluebells 于 2026-5-3 13:49 编辑
  1. ;只有一个输入参数和两个输出参数
  2. ;输入参数为路径, 支持驱动器号(盘符), 路径命名空间(\\?\HarddiskVolumeX, \\?\HarddiskX\PartitionX 等)
  3. ;第一个输出参数为设备号, 第二个输出参数为分区号
  4. _SUB GetDevicePartNum
  5.     TEAM ENVI &drv=%~1| ENVI-ret %~2=| ENVI-ret %~3=
  6.     TEAM ENVI &prefix=\\?\| ENVI &gr=
  7.     TEAM LSTR aStr1=4,%&drv%| LSTR aStr2=7,%&drv%
  8.     FIND $%aStr1%=\\?\,ENVI &prefix=
  9.     FIND $%aStr2%=\Device,ENVI &gr=GLOBALROOT
  10.    
  11.     TEAM ENVI &FILE_ANY_ACCESS=0x00000000| ENVI &OPEN_EXISTING=3
  12.     TEAM ENVI &IOCTL_STORAGE_GET_DEVICE_NUMBER=0x2D1080| ENVI$# &udtQuery=*4 0 *4 0 *4 0| ENVI$# &cbBytesReturned=*8 0
  13.     CALL $--qd --ret:&h Kernel32.dll,CreateFileW,$%&prefix%%&gr%%&drv%,#0,#%&FILE_ANY_ACCESS%,#0,#%&OPEN_EXISTING%,#0,#0
  14.     IFEX #%h%=-1, EXIT
  15.     CALL $--qd --ret:&ret Kernel32.dll,DeviceIoControl,#%&h%,#%&IOCTL_STORAGE_GET_DEVICE_NUMBER%,#0,#0,*&udtQuery,#12,*&cbBytesReturned,#0 //待处理
  16.     CALL $--qd --ret:&ret Kernel32.dll,CloseHandle,#%&h%
  17.     TEAM ENVI?int &udtQuery=&DeviceNum:4| ENVI?int &udtQuery=&PartNum:8
  18.     ENVI-ret %~2=%&DeviceNum%
  19.     ENVI-ret %~3=%&PartNum%
  20. _END

  21. ;示例
  22. GetDevicePartNum C: &1 &2
  23. GetDevicePartNum \\?\HarddiskVolume4 &3 &4
  24. MESS 设备(磁盘)号: %1%\n分区号: %2%\n\n设备(磁盘)号: %3%\n分区号: %4%
复制代码



回复

使用道具 举报

发表于 2026-1-17 19:30:51 | 显示全部楼层
回复

使用道具 举报

发表于 2026-1-17 19:32:19 | 显示全部楼层
学习一下
回复

使用道具 举报

发表于 2026-1-17 19:47:52 来自手机 | 显示全部楼层
强贴留名
回复

使用道具 举报

发表于 2026-1-17 19:54:47 | 显示全部楼层
了解一下。
回复

使用道具 举报

 楼主| 发表于 2026-1-17 20:09:23 | 显示全部楼层
本帖最后由 Bluebells 于 2026-5-3 14:01 编辑
  1. ;此封装函数有三个参数, 第一个参数用于存放返回的操作系统主要版本号, 第二个参数用于存放返回的操作系统次要版本号, 第三个参数用于存放返回的操作系统内部版本号
  2. _SUB RtlGetVersion
  3.     ENVI$# &VersionInformation=*4 0 *4 0 *4 0 *4 0 *4 0 *256 0
  4.     ENVI-long &VersionInformation=276
  5.     CALL $--qd --ret:&ret ntdll.dll,RtlGetVersion,*&VersionInformation
  6.     IFEX #%&ret%<>0,EXIT
  7.     TEAM ENVI?int &VersionInformation=&MajorVersion:4| ENVI?int &VersionInformation=&MinorVersion:8| ENVI?int &VersionInformation=&BuildNumber:12
  8.     ENVI-ret %~1=%MajorVersion%
  9.     ENVI-ret %~2=%MinorVersion%
  10.     ENVI-ret %~3=%BuildNumber%
  11. _END

  12. ;参数同上
  13. _SUB GetNTVersion
  14.     TEAM ENVI-long &pMajorVersion=| ENVI-long &pMinorVersion=| ENVI-long &pBuildNumber=
  15.     CALL $--qd --ret:&ret ntdll.dll,RtlGetNtVersionNumbers,*&pMajorVersion,*&pMinorVersion,*&pBuildNumber
  16.     IFEX #%&ret%=0,EXIT
  17.     TEAM ENVI?int &pMajorVersion=&MajorVersion| ENVI?int &pMinorVersion=&MinorVersion| ENVI?int &pBuildNumber=&BuildNumber
  18.     CALC #&BuildNumber = %&BuildNumber% & 0xFFFF
  19.     ENVI-ret %~1=%MajorVersion%
  20.     ENVI-ret %~2=%MinorVersion%
  21.     ENVI-ret %~3=%BuildNumber%
  22. _END

  23. ;示例
  24. RtlGetVersion &MajorVersion &MinorVersion &BuildNumber
  25. MESS %&MajorVersion%\n%&MinorVersion%\n%&BuildNumber%
  26. GetNTVersion &MajorVersion &MinorVersion &BuildNumber
  27. MESS %&MajorVersion%\n%&MinorVersion%\n%&BuildNumber%
复制代码
PS: RtlGetNtVersionNumbers 为非公开函数, 且支持系统版本范围为 NT5.1+; 感谢 wintoflash 老大帮忙处理获取正确的 BuildNumber 值


回复

使用道具 举报

发表于 2026-1-17 20:19:24 | 显示全部楼层
技术贴 支持
回复

使用道具 举报

 楼主| 发表于 2026-1-17 20:27:20 | 显示全部楼层
本帖最后由 Bluebells 于 2026-5-3 14:13 编辑
  1. ;获取计算机名称, 仅一个参数, 用于存放返回的计算机名称
  2. _SUB GetComputerName
  3.     ENVI$# &nSize=*4 0
  4.     CALL $--qd --ret:&ret Kernel32.dll,GetComputerNameW,*,*&nSize
  5.     ENVI?int &nSize=&BufferSize
  6.     IFEX $%&BufferSize%=0,EXIT _SUB
  7.     ENVI$ &lpBuffer=*%&BufferSize% 0
  8.     CALL $--qd --ret:&&ret Kernel32.dll,GetComputerNameW,*&lpBuffer,*&nSize
  9.     IFEX $%&ret%=0,EXIT _SUB
  10.     ENVI-ret %~1=%&lpBuffer%
  11. _END

  12. ;获取系统当前登录用户名, 仅一个参数, 用于存放返回的当前登录用户名
  13. _SUB GetUserName
  14.     ENVI-ret %~1=
  15.     ENVI$# &pcbBuffer=*4 0
  16.     CALL $--qd --ret:&ret Advapi32.dll,GetUserNameW,*,*&pcbBuffer
  17.     ENVI?int &pcbBuffer=&BufferSize
  18.     IFEX $%&BufferSize%=0,EXIT _SUB
  19.     ENVI$ &lpBuffer=*%&BufferSize% 0
  20.     CALL $--qd --ret:&ret Advapi32.dll,GetUserNameW,*&lpBuffer,*&pcbBuffer
  21.     IFEX $%&ret%=0,EXIT _SUB
  22.     ENVI-ret %~1=%&lpBuffer%
  23. _END

  24. ;调用示例
  25. GetComputerName &ComputerName
  26. GetUserName &UserName
  27. MESS 计算机名称: %&ComputerName%\n\n用户名: %&UserName%
复制代码

回复

使用道具 举报

发表于 2026-1-17 21:05:17 | 显示全部楼层
感谢分享!
回复

使用道具 举报

发表于 2026-1-17 21:22:06 | 显示全部楼层
谢谢分享
回复

使用道具 举报

发表于 2026-1-18 00:26:16 | 显示全部楼层
学习一下。
回复

使用道具 举报

 楼主| 发表于 2026-1-18 19:51:44 | 显示全部楼层
本帖最后由 Bluebells 于 2026-5-3 14:13 编辑

获取系统(启动)分区
  1. _SUB GetBootDevice
  2.     IFEX #%&bX64%=3, ENVI &PtrSz=8! ENVI &PtrSz=4
  3.     CALC #&Sz=%&PtrSz% * 2
  4.     CALC #&SzA=%&Sz% + 8192
  5.     ENVI$# &retName=*%&SzA% 0 *32 0
  6.     ENVI-mkdummy &Nm=&retName@%&Sz%;8192
  7.     CALL $--qd --ret:&ret Ntdll.dll,NtQuerySystemInformation,#98,*&retName,#%&SzA%,#0
  8.     IFEX #%&ret%=0,ENVI-ret %~1=%&Nm%
  9. _END

  10. ;示例
  11. GetBootDevice &BootDevice
  12. MESS %&BootDevice%
复制代码
PS: 此代码摘自 mdyblog 老大的 PECMD 的示例代码, 且返回信息为 dos 设备路径


回复

使用道具 举报

 楼主| 发表于 2026-1-18 19:56:01 | 显示全部楼层
本帖最后由 Bluebells 于 2026-5-3 14:13 编辑

获取系统当前启动方式
  1. _SUB GetSystemBootEnvironmentInformation
  2.     ENVI &SystemBootEnvironmentInformation=90
  3.     ENVI$# &pBuffer=*16 0 *4 0 *8 0
  4.     CALL $--qd --ret:&ret Ntdll.dll,NtQuerySystemInformation,#%&SystemBootEnvironmentInformation%,*&pBuffer,#32,#0
  5.     IFEX #%&ret%=0,
  6.     {*
  7.         ENVI?int pBuffer=&&FirmwareType:16
  8.         IFEX #%&FirmwareType%=0,ENVI-ret %~1=Unknown
  9.         IFEX #%&FirmwareType%=1,ENVI-ret %~1=BIOS
  10.         IFEX #%&FirmwareType%=2,ENVI-ret %~1=UEFI
  11.         IFEX #%&FirmwareType%=3,ENVI-ret %~1=Unknown
  12.     }! ENVI-ret %~1=Unknown
  13. _END

  14. ;示例
  15. GetSystemBootEnvironmentInformation &BootEnvironment
  16. MESS %&BootEnvironment%
复制代码
PS: 一些人根据磁盘的分区样式去判断启动方式是非常不正确的
回复

使用道具 举报

 楼主| 发表于 2026-1-18 20:09:55 | 显示全部楼层
本帖最后由 Bluebells 于 2026-5-3 14:15 编辑

获取 Windows, System 和 Temp 目录
  1. _SUB GetWindowsDirectory
  2.     CALL $--qd --ret:&ret Kernel32.dll,GetWindowsDirectoryW,*&lpBuffer,#0
  3.     ENVI$ &lpBuffer=*%&ret% 0
  4.     CALL $--qd --ret:&ret Kernel32.dll,GetWindowsDirectoryW,*&lpBuffer,#%&ret%
  5.     IFEX #%&ret%=0,EXIT
  6.     ENVI-ret %~1=%&lpBuffer%
  7. _END

  8. _SUB GetSystemDirectory
  9.     CALL $--qd --ret:&ret Kernel32.dll,GetSystemDirectoryW,*&lpBuffer,#0
  10.     ENVI$ &lpBuffer=*%&ret% 0
  11.     CALL $--qd --ret:&&ret Kernel32.dll,GetSystemDirectoryW,*&lpBuffer,#%&ret%
  12.     IFEX #%&ret%=0,EXIT
  13.     ENVI-ret %~1=%&lpBuffer%
  14. _END

  15. _SUB GetTempPath
  16.     CALL $--qd --ret:&ret Kernel32.dll,GetTempPathW,#0,*&lpBuffer
  17.     ENVI$ &lpBuffer=*%&ret% 0
  18.     CALL $--qd --ret:&ret Kernel32.dll,GetTempPathW,#%&ret%,*&lpBuffer
  19.     IFEX #%&ret%=0,EXIT
  20.     ENVI-ret %~1=%&lpBuffer%
  21. _END

  22. GetWindowsDirectory &WinPath
  23. GetSystemDirectory &SystemPath
  24. GetTempPath &TempPath
  25. MESS %&WinPath%\n%&SystemPath%\n%&TempPath%
复制代码
PS: 也许有人说, 为啥不直接用环境变量, 正所谓萝卜青菜,各有所爱



回复

使用道具 举报

 楼主| 发表于 2026-1-18 20:43:01 | 显示全部楼层
本帖最后由 Bluebells 于 2026-5-3 14:16 编辑

获取当前安全启动状态
  1. ;此方法仅支持NT6.2及以上版本, 此函数还能查询目标机器是否支持安全启动功能
  2. _SUB GetSystemSecureBootInformation
  3.     ENVI$ &SSBI=*1 0 *1 0
  4.     CALL $--qd --ret:&ret ntdll.dll,NtQuerySystemInformation,#145,*&SSBI,#2,#0
  5.     IFEX #%&ret%<>0,TEAM ENVI-ret %~1=Unknown| EXIT _SUB
  6.     ENVI?char &SSBI=&SecureBootEnabled
  7.     ;ENVI?char &SSBI=&SecureBootCapable:1
  8.     IFEX #%&SecureBootEnabled%=0,ENVI-ret %~1=Disabled! ENVI-ret %~1=Enabled
  9. _END

  10. ;示例
  11. GetSystemSecureBootInformation &SecureBoot
  12. MESS %&SecureBoot%
复制代码
PS: 在 64 位操作系统下必须使用 64 位版本的 PECMD 才能正确调用此函数



回复

使用道具 举报

发表于 2026-1-19 08:21:53 | 显示全部楼层
等热心人来
回复

使用道具 举报

发表于 2026-1-19 13:17:36 来自手机 | 显示全部楼层
感谢分享
回复

使用道具 举报

发表于 2026-1-21 13:30:07 | 显示全部楼层
学习一下
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|捐助支持|无忧启动 ( 闽ICP备05002490号-1|闽公网安备35020302032614号 )

GMT+8, 2026-5-3 20:36

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

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