找回密码
 注册
搜索
[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
查看: 16089|回复: 2

[文件操作] 批处理怎么读取特殊快捷方式的目标?[已解决]

[复制链接]
发表于 2023-1-1 12:41:03 | 显示全部楼层 |阅读模式
本帖最后由 czjt1234 于 2026-5-19 18:38 编辑

比如控制面板,声音,右击,创建快捷方式
怎么读取这个快捷方式的目标,或者说手工创建这个快捷方式

由于微软提供的lnk二进制数据结构不全,所以有不少地方纯属猜测
 楼主| 发表于 昨天 18:33 | 显示全部楼层
本帖最后由 czjt1234 于 2026-5-19 18:35 编辑
  1. '仅用于读取控制面板项目的快捷方式
  2. Option Explicit
  3. Dim s, control

  4. Const MYCOMPUTER = "20D04FE0-3AEA-1069-A2D8-08002B30309D"    '我的电脑 win95 ~ winxp
  5. Const CONTROL1   = "21EC2020-3AEA-1069-A2DD-08002B30309D"    '控制面板 win95 ~ winvista
  6. Const CONTROL2   = "26EE0668-A00A-44D7-9371-BEB064C98683"    '控制面板 win7  ~ win11

  7. s = "设备和打印机 - 快捷方式.lnk"

  8. Call RunAsCmd()
  9. If wsh.Arguments.Count > 0 Then s = wsh.Arguments(0)
  10. wsh.Echo s & vbCrLf & vbCrLf & LinkTargetIDList(s)

  11. Function LinkTargetIDList(ByVal lnkFilePath)
  12.     Dim oStream, arrByte, m, n, s

  13.     Set oStream = CreateObject("ADODB.Stream")
  14.     oStream.Type = 1    'adTypeBinary
  15.     oStream.Mode = 3    'adModeReadWrite
  16.     oStream.Open()
  17.     oStream.LoadFromFile lnkFilePath
  18.     oStream.Position = &H004C
  19.     arrByte = oStream.Read(2)
  20.     m = bin2Hex(arrByte, 2, 1)
  21.     LinkTargetIDList = ": &H" & Right("000" & Hex(&H004C + 2 + CLng(m)), 4)
  22.     s = "LinkTargetIDList  : &H004C"        & vbCrLf & _
  23.         "  IDListSize      : &H004C = " & m & vbCrLf & _
  24.         "  IDList          : &H004E"        & vbCrLf & _
  25.         "    ItemIDList    : &H004E"        & vbCrLf
  26.     Do
  27.         n = "&H" & Right("000" & Hex(oStream.Position), 4)
  28.         arrByte = oStream.Read(2)
  29.         m = bin2Hex(arrByte, 2, 1)
  30.         If m = "&H0000" Then
  31.             s = s & "    TerminalID    : " & n & " = " & m & vbCrLf
  32.             Exit Do
  33.         End If
  34.         s = s & "      ItemIDSize  : " & n & " = " & m & vbCrLf
  35.         n = "&H" & Right("000" & Hex(oStream.Position), 4)
  36.         arrByte = oStream.Read(CLng(m) - 2)
  37.         s = s & "      Data        : " & n & vbCrLf & getData(arrByte, n)
  38.     Loop
  39.     LinkTargetIDList = s & LinkTargetIDList
  40. End Function

  41. Function getData(ByRef arrByte, ByVal p)
  42.     Dim i, m, n, s, a, b

  43.     i = LenB(arrByte)
  44.     n = bin2Hex(arrByte, 1, i)
  45.     Select Case Left(n, 4)
  46.     Case "&H1F"    '根路径
  47.         s = "        ClassType : " & p & " = &H1F" & vbCrLf
  48.         p = "&H" & Right("000" & Hex(CLng(p) + 1), 4)
  49.         n = bin2Hex(arrByte, 2, 2)
  50.         s = s & "        SortIndex : " & p & " = " & n & vbCrLf
  51.         p = "&H" & Right("000" & Hex(CLng(p) + 1), 4)
  52.         n = hex2GUID(bin2Hex(arrByte, 3, i))
  53.         control = n
  54.         s = s & "        GUID      : " & p & " = " & n & getGUID_Name(n) & vbCrLf
  55.     Case Else
  56.         If i = 10 Then    '类别 winvista ~ win11
  57.             m = "shell:::{" & control & "}\" & CInt("&H" & Mid(n, 16, 1))
  58.             m = " (" & CreateObject("Shell.Application").NameSpace(m).Title & ")"
  59.             s = "        未知结构  : " & p & " = " & n & m & vbCrLf
  60.         ElseIf i = 18 Then    '控制面板的GUID win95 ~ winxp
  61.             s = "        未知结构  : " & p & " = " & Left(n, 6) & vbCrLf
  62.             p = "&H" & Right("000" & Hex(CLng(p) + 2), 4)
  63.             n = hex2GUID(Right(n, 32))
  64.             control = n
  65.             s = s & "        GUID      : " & p & " = " & n & getGUID_Name(n) & vbCrLf
  66.         ElseIf i = 28 Then    'winxp ~ win11
  67.             s = "        未知结构  : " & p & " = " & Left(n, 26) & vbCrLf
  68.             p = "&H" & Right("000" & Hex(CLng(p) + 12), 4)
  69.             n = hex2GUID(Right(n, 32))
  70.             s = s & "        GUID      : " & p & " = " & n & getGUID_Name(n) & vbCrLf
  71.         ElseIf Right(n, 4) = "0000" Then    'Unicode winxp ~ win11
  72.             s = "        未知结构  : " & p & " = " & Left(n, 22) & "..." & vbCrLf
  73.             p = "&H" & Right("000" & Hex(CLng(p) + 18), 4)
  74.             a = "&H" & Mid(n, 41, 2) & Mid(n, 39, 2)
  75.             s = s & "        名称偏移  : " & p & " = " & a & vbCrLf
  76.             p = "&H" & Right("000" & Hex(CLng(p) + 2), 4)
  77.             b = "&H" & Mid(n, 45, 2) & Mid(n, 43, 2)
  78.             s = s & "        简介偏移  : " & p & " = " & b & vbCrLf
  79.             a = CLng(a)
  80.             b = CLng(b)
  81.             p = "&H" & Right("000" & Hex(CLng(p) + 2), 4)
  82.             m = unicode2chr(Mid(n, 47, a * 4))
  83.             s = s & "        目标文件  : " & p & " = " & m & vbCrLf
  84.             p = "&H" & Right("000" & Hex(CLng(p) + a * 2), 4)
  85.             m = unicode2chr(Mid(n, 47 + a * 4, b * 4 - a * 4))
  86.             If Mid(n, 31, 2) = "01" Then m = m & " (32 位)"
  87.             s = s & "        名称      : " & p & " = " & m & vbCrLf
  88.             p = "&H" & Right("000" & Hex(CLng(p) + b * 2 - a * 2 ), 4)
  89.             m = unicode2chr(Mid(n, 47 + b * 4))
  90.             s = s & "        简介      : " & p & " = " & m & vbCrLf
  91.         Else    'ANSI (GBK) win95 win98
  92.             s = "        未知结构  : " & p & " = " & Left(n, 14) & vbCrLf
  93.             p = "&H" & Right("000" & Hex(CLng(p) + 6), 4)
  94.             a = "&H" & Mid(n, 17, 2) & Mid(n, 15, 2)
  95.             s = s & "        名称偏移  : " & p & " = " & a & vbCrLf
  96.             p = "&H" & Right("000" & Hex(CLng(p) + 2), 4)
  97.             b = "&H" & Mid(n, 21, 2) & Mid(n, 19, 2)
  98.             s = s & "        简介偏移  : " & p & " = " & b & vbCrLf
  99.             a = CLng(a)
  100.             b = CLng(b)
  101.             p = "&H" & Right("000" & Hex(CLng(p) + 2), 4)
  102.             m = gbk2chr(Mid(n, 23, a * 2))
  103.             s = s & "        目标文件  : " & p & " = " & m & vbCrLf
  104.             p = "&H" & Right("000" & Hex(CLng(p) + a), 4)
  105.             m = gbk2chr(Mid(n, 23 + a * 2, b * 2 - a * 2))
  106.             s = s & "        名称      : " & p & " = " & m & vbCrLf
  107.             p = "&H" & Right("000" & Hex(CLng(p) + b - a), 4)
  108.             m = gbk2chr(Mid(n, 23 + b * 2))
  109.             s = s & "        简介      : " & p & " = " & m & vbCrLf
  110.         End If
  111.     End Select
  112.     getData = s
  113. End Function

  114. Function hex2GUID(ByVal s)
  115.     Dim arr, m, i
  116.     s = RePlace(s, "&H", "")
  117.     s = RePlace(s, " ", "")
  118.     arr = Array(7, 8, 5, 6, 3, 4, 1, 2, 11, 12, 9, 10, 15, 16, 13, 14)
  119.     m = ""
  120.     For i = 1 To 16
  121.         m = m & Mid(s, arr(i - 1), 1)
  122.         If i = 8 Or i = 12 Or i = 16 Then m = m & "-"
  123.     Next
  124.     For i = 17 To 32
  125.         m = m & Mid(s, i, 1)
  126.         If i = 20 Then m = m & "-"
  127.     Next
  128.     hex2GUID = m
  129. End Function

  130. Sub RunAsCmd()
  131.     Dim oFSO, oWshShell, s, i
  132.     Set oFSO = CreateObject("Scripting.FileSystemObject")
  133.     Set oWshShell = CreateObject("WScript.Shell")
  134.     s = oWshShell.ExpandEnvironmentStrings("%windir%\System32\CScript.exe")
  135.     If LCase(WScript.FullName) <> LCase(s) Then
  136.         s = s & " /nologo """ & WScript.ScriptFullName & """"
  137.         For Each i In WScript.Arguments
  138.             s = s & " """ & i & """"
  139.         Next
  140.         oWshShell.Run "cmd.exe /k " & s
  141.         WScript.Quit()
  142.     End If
  143. End Sub

  144. Function bin2Hex(ByRef arrByte, ByVal m, ByVal n)
  145.     Dim k, i, s
  146.     k = 1
  147.     If n < m Then k = -1
  148.     s = "&H"
  149.     For i = m To n Step k
  150.         s = s & Right("0" & Hex(AscB(MidB(arrByte, i, 1))), 2)
  151.     Next
  152.     bin2Hex = s
  153. End Function

  154. Function getGUID_Name(ByVal t)
  155.     Dim oWshShell, s, n
  156.     If t = MYCOMPUTER Then getGUID_Name = " (我的电脑)" : Exit Function
  157.     If t = CONTROL1 Or t = CONTROL2 Then
  158.         getGUID_Name = " (控制面板)"
  159.         Exit Function
  160.     End If
  161.     s = "HKEY_CLASSES_ROOT\CLSID\{" & t & "}\"
  162.     getGUID_Name = ""
  163.     Set oWshShell = CreateObject("WScript.Shell")
  164.     Err.Clear()
  165.     On Error Resume Next
  166.     n = oWshShell.RegRead(s)
  167.     If oWshShell.Run("cmd.exe /c set | find.exe /i ""powershell"" && exit /b 6", 0, True) <> 6 Then
  168.         getGUID_Name = " (" & n & ")"
  169.         Exit Function
  170.     End If
  171.     If Err.Number <> 0 Then Exit Function
  172.     s = s & "LocalizedString"
  173.     Err.Clear()
  174.     n = oWshShell.RegRead(s)
  175.     If Err.Number <> 0 Then Exit Function
  176.     With CreateObject("VBScript.RegExp")
  177.         .Pattern = "^(.+-\d+)(#.+)?"
  178.         n = .Execute(n)(0).SubMatches(0)
  179.     End With
  180.     getGUID_Name = getDllString(n)
  181. End Function

  182. Function getDllString(ByVal n)
  183.     Dim oWshShell, oWshScriptExec, s, i
  184.     Set oWshShell = CreateObject("WScript.Shell")
  185.     Set oWshScriptExec = oWshShell.Exec("cmd.exe")
  186.     s = """" & RePlace(wsh.ScriptFullName, wsh.ScriptName, "") & "ReadDllString.ps1"""
  187.     s = "PowerShell.exe -NoProfile -Exec Bypass -F " & s & " -ResourceString """ & n & """"
  188.     With oWshScriptExec.StdIn
  189.         .WriteLine "@echo off & " & s
  190.         .Close()
  191.     End With
  192.     With oWshScriptExec.StdOut
  193.         s = .ReadAll()
  194.         .Close()
  195.     End With
  196.     With CreateObject("VBScript.RegExp")
  197.         .Pattern = "[\s\S]+\n(.+)"
  198.         s = .Execute(s)(0).SubMatches(0)
  199.     End With
  200.     getDllString = " (" & s & ")"
  201. End Function

  202. Function unicode2chr(ByVal m)
  203.     Dim s, i, n
  204.     m = RePlace(m, "&H", "")
  205.     m = RePlace(m, " ", "")
  206.     s = ""
  207.     n = "&H"
  208.     For i = 1 To Len(m) Step 4
  209.         n = n & Mid(m, i + 2, 1) & Mid(m, i + 3, 1) & Mid(m, i, 1) & Mid(m, i + 1, 1)
  210.         If CLng(n) <> 0 Then s = s & ChrW(CLng(n))
  211.         n = "&H"
  212.     Next
  213.     unicode2chr = s
  214. End Function

  215. Function gbk2chr(ByVal m)
  216.     Dim s, i, n
  217.     m = RePlace(m, "&H", "")
  218.     m = RePlace(m, " ", "")
  219.     s = ""
  220.     n = "&H"
  221.     For i = 1 To Len(m) Step 2
  222.         n = n & Mid(m, i, 1) & Mid(m, i + 1, 1)
  223.         If CLng(n) > CLng(&H7F) Then
  224.             i = i + 2
  225.             n = n & Mid(m, i, 1) & Mid(m, i + 1, 1)
  226.         End If
  227.         If CLng(n) <> 0 Then s = s & Chr(CLng(n))
  228.         n = "&H"
  229.     Next
  230.     gbk2chr = s
  231. End Function
复制代码
仅用于读取控制面板项目的快捷方式
在 winxp_x86_sp3 winvista_x64_sp2 win7_x64_sp1 win8_x64 win8.1_x64 win10_x64_22H2 win11_x64_22H2 测试通过

winvista及更新的系统由于要读取dll文件里的中文字符串,所以要调用powershell,见3楼
不调用powershell则会显示快捷方式的英文名
winvista原版没有powershell, 需要安装补丁kb968930并重启
 楼主| 发表于 昨天 18:35 | 显示全部楼层
  1. <# : 另存为 ANSI 编码 ReadDllString.ps1
  2. @echo off
  3. cls
  4. PowerShell.exe -NoProfile -ExecutionPolicy Bypass "Invoke-Expression (${%~f0} | Out-String)"
  5. pause
  6. exit /b
  7. #>

  8. param(
  9.     [Parameter(Mandatory=$true)]
  10.     [string]$ResourceString
  11. )

  12. function Parse-ResourceString {
  13.     param([string]$inputString)
  14.    
  15.     $cleanString = $inputString.TrimStart('@')
  16.     $parts = $cleanString -split ','
  17.     if ($parts.Count -ne 2) {
  18.         throw "无效的资源字符串格式: $inputString。正确格式: 路径,-ID"
  19.     }
  20.     $dllPathRaw = $parts[0].Trim()
  21.     $idRaw = $parts[1].Trim()
  22.     if ($idRaw -match '^-?(\d+)$') {
  23.         $stringId = [uint32]$matches[1]
  24.     } else {
  25.         throw "无效的 ID 格式: $idRaw"
  26.     }
  27.     $dllPath = [System.Environment]::ExpandEnvironmentVariables($dllPathRaw)

  28.     return @{
  29.         DllPath = $dllPath
  30.         StringId = $stringId
  31.     }
  32. }

  33. Add-Type @"
  34. using System;
  35. using System.Runtime.InteropServices;
  36. using System.Text;

  37. public class winAPI {
  38.     [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
  39.     private static extern int LoadStringW(IntPtr hInstance, uint uID, StringBuilder lpBuffer, int cchBufferMax);

  40.     [DllImport("kernel32.dll", SetLastError = true)]
  41.     private static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags);

  42.     [DllImport("kernel32.dll", SetLastError = true)]
  43.     private static extern bool FreeLibrary(IntPtr hModule);

  44.     private const uint LOAD_LIBRARY_AS_DATAFILE = 0x00000002;

  45.     public static string LoadString(string dllPath, uint stringId)
  46.     {
  47.         IntPtr hModule = LoadLibraryEx(dllPath, IntPtr.Zero, LOAD_LIBRARY_AS_DATAFILE);
  48.         if (hModule == IntPtr.Zero)
  49.         {
  50.             return "无法加载 DLL: " + dllPath;
  51.         }

  52.         try
  53.         {
  54.             StringBuilder buffer = new StringBuilder(1024);
  55.             int charsCopied = LoadStringW(hModule, stringId, buffer, buffer.Capacity);
  56.             
  57.             if (charsCopied > 0)
  58.             {
  59.                 return buffer.ToString();
  60.             }
  61.             else
  62.             {
  63.                 return "未找到 ID 为 " + stringId.ToString() + " 的字符串。";
  64.             }
  65.         }
  66.         finally
  67.         {
  68.             FreeLibrary(hModule);
  69.         }
  70.     }
  71. }
  72. "@

  73. try {
  74.     # Write-Host "输入资源字符串: $ResourceString" -ForegroundColor Cyan
  75.     $parsed = Parse-ResourceString -inputString $ResourceString
  76.     # Write-Host "解析结果:" -ForegroundColor Green
  77.     # Write-Host "  DLL路径: $($parsed.DllPath)"
  78.     # Write-Host "  字符串ID: $($parsed.StringId)"
  79.     # Write-Host ""
  80.     if (-not (Test-Path $parsed.DllPath)) {
  81.         Write-Host "错误: DLL 文件不存在 - $($parsed.DllPath)" -ForegroundColor Red
  82.         exit 1
  83.     }
  84.     $result = [winAPI]::LoadString($parsed.DllPath, $parsed.StringId)
  85.     # Write-Host "读取结果:" -ForegroundColor Green
  86.     Write-Host $result
  87. } catch {
  88.     Write-Host "错误: $_" -ForegroundColor Red
  89.     exit 1
  90. }
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|批处理之家 ( 渝ICP备10000708号 )

GMT+8, 2026-5-20 12:12

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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