Board logo

标题: [注册表类] 求助:批处理reg右键菜单实现:获取所选中的一个或多个文件路径 [打印本页]

作者: lforl    时间: 2024-10-22 21:18     标题: 求助:批处理reg右键菜单实现:获取所选中的一个或多个文件路径

本帖最后由 lforl 于 2024-11-20 20:19 编辑

写一个reg右键菜单实现:

在资源管理器中,选择一个或者多个文件的时候,获取这些文件的路径(含文件名和后缀名)。

这是Windows内置的shift右键的,提升为不用按shift的方法。遗憾是带有引号。
  1. Windows Registry Editor Version 5.00
  2. [HKEY_CLASSES_ROOT\Allfilesystemobjects\shell\windows.copyaspath]
  3. "CanonicalName"="{707C7BC6-685A-4A4D-A275-3966A5A3EFAA}"
  4. "CommandStateHandler"="{3B1599F9-E00A-4BBF-AD3E-B3F99FA87779}"
  5. "CommandStateSync"=""
  6. "Description"="@shell32.dll,-30336"
  7. "Icon"="imageres.dll,-5302"
  8. "InvokeCommandOnSelection"=dword:00000001
  9. "MUIVerb"="@shell32.dll,-30329"
  10. "VerbHandler"="{f3d06e7c-1e45-4a26-847e-f9fcdee59be0}"
  11. "VerbName"="copyaspath"
  12. ;====这个其实就是从win10的自带右键(按shift点右键)里面提取的方法
  13. ;HKEY_CLASSES_ROOT\AllFilesystemObjects\shellex\ContextMenuHandlers\CopyAsPathMenu
  14. ;====不适合win7。复制出的结果带引号
复制代码
另外,外面比较常见的是一个vbs写的注册表右键。选择一个文件还行,当选择多个文件的时候运行就报错。

期待大佬路过,指点解决一下这个经典需求(一键复制一个或者多个文件的路径)。多谢!

暂时还没没有比较完美的方案...
作者: aloha20200628    时间: 2024-10-22 22:41

本帖最后由 aloha20200628 于 2024-10-22 22:53 编辑

回复 1# lforl

参见一》https://cloud.tencent.com/developer/news/436620
参见二》https://www.xitongzhijia.net/xtjc/20170105/90289.html

作者: Five66    时间: 2024-10-22 23:24

分开来 ,单独弄一个bat
作者: lforl    时间: 2024-10-23 13:01

回复 2# aloha20200628


   shift键内置这种玩法,我玩过,复制出来的都带引号的,不太适合。谢谢哈....
作者: ppll2030    时间: 2024-10-23 18:04

注册表脚本不支持多文件,表现就是多个文件执行bat,会弹出多个cmd窗口。所以简单的脚本貌似无解,开发dll等操作不在此列
目前建议有两个,
一个利用右键发送功能,直接把多文件发送给脚本,这个可以支持多文件。
二个是采用集成有这类功能的资源管理,推荐Directory Opus,这也是我目前在用的管理器,替换系统管理器无压力。

下面是两个功能的vbs脚本,分别保存为vbs文件后,
在开始--运行--输入shell:sendto,把两个vbs文件复制进去即可,
之后选择多个文件后,点右键--发送即可实现相关功能。
  1. '复制多文件完整路径到剪切板
  2. Dim filearray()
  3. ReDim filearray(WScript.Arguments.Count - 1)
  4. For i = 0 To WScript.Arguments.Count - 1
  5. filearray(i) = WScript.Arguments(i) & ">>tem"
  6. Next
  7. filearrays=join(filearray, "&echo ")
  8. CreateObject("WScript.shell").Run "cmd /C echo " & filearrays & "&clip<tem&del tem", 0
复制代码
  1. '复制多文件名称到剪切板
  2. Dim filearray()
  3. ReDim filearray(WScript.Arguments.Count - 1)
  4. For i = 0 To WScript.Arguments.Count - 1
  5. filearray(i) = CreateObject("Scripting.FileSystemObject").GetFileName(WScript.Arguments(i)) & ">>tem"
  6. Next
  7. filearrays=join(filearray, "&echo ")
  8. CreateObject("WScript.shell").Run "cmd /C echo " & filearrays & "&clip<tem&del tem", 0
复制代码

作者: lforl    时间: 2024-10-23 21:06

本帖最后由 lforl 于 2024-10-23 21:35 编辑

谢谢楼上热心回复。
关于处理多个选中的文件,获取他们路径文件名,@77七 大佬帮过我,实现的比较完美。
比如这贴:
http://www.bathome.net/viewthread.php?tid=69150

不过我还没学会如何把for循环里得到的变量,累加起来,最后传给剪贴板。
期待大佬路过出手指点...
作者: aloha20200628    时间: 2024-10-25 17:54

本帖最后由 aloha20200628 于 2024-10-25 18:16 编辑

回复 1# lforl

一楼的注册表代码沿用了系统为资源管理器开启 ‘复制路径’ 右键菜单的通道,实测不能直接 ‘套壳’ 这段批处代码,但通过资源管理器的 ‘发送到’ 右键菜单机制确实可以挂载类似的批处代码,从而实现楼主的要求,以下是一个最简方法示例》
一。创建一个批处理脚本(代码如下)假设存为 sendTo.bat
二。复制 sendTo.bat 到 "C:\Users\本机用户名\AppData\Roaming\Microsoft\Windows\SendTo" 系统目录中(可在资源管理器地址栏输入 shell:sendto 开启该目录),其后会在资源管理器 '发送到' 右键菜单中出现名为 sendTo.bat 的选项,当单选或多选文件或目录后,点击此右键菜单选项即可完成被选结果 '无双引号包裹' 传至剪贴板的操作
  1. @echo off &(for %%i in (%*) do @echo,%%~i)|clip.exe&exit/b
复制代码
但这个用法至少有两点限制》
一。被选文件或目录的字符总量不能超过8K,即受限于系统命令行参数的字符总量限制
二。批处脚本被调用过程会导致闪屏,这是因开关cmd窗口所致

改用 vbs 或 jscript 代码替换批处脚本是一个没有闪屏和突破选择集字符量8K限制的解决方案,以下代码是一个jscript版本,假设存为 sendTo.js,直接复制到上述系统目录中,其后会在资源管理器 '发送到' 右键菜单中出现名为 sendTo.js 的选项,当单选或多选文件或目录后,点击此右键菜单选项即可完成被选结果 '无双引号包裹' 传至剪贴板的操作
  1. v=WSH.arguments, ws=WSH.createObject('WScript.shell');
  2. for (s='',n=0,l=v.length; n<l; n++) s+=v(n).replace(/\"/g,'')+'\r\n';
  3. fso=WSH.createObject('Scripting.FileSystemObject');
  4. tF=ws.expandEnvironmentStrings('%temp%')+'\\_.clipT';
  5. fp=fso.OpenTextFile(tF,2,true), fp.write(s.slice(0,-2)), fp.close();
  6. ws.run('cmd.exe /c clip.exe<'+tF+'&&del/q '+tF, 0, false), WSH.quit();
复制代码

作者: lforl    时间: 2024-10-25 20:45

回复 7# aloha20200628

谢谢大佬,.js 方案的确也是个不错的办法。发送到js之前的确没想过。

不过,我感觉原生cmd对这个问题应该有解,搜索过全网,感觉多数方案都停留在shift右键带引号那个方案。
纯粹一个reg右键解决问题,简洁。
我再研究研究...
作者: aloha20200628    时间: 2024-10-25 23:40

本帖最后由 aloha20200628 于 2024-10-26 15:14 编辑

回复 8# lforl

   注册表右键菜单定义中的批处代码可以识别 %1, %2, ..., %L 这类命令行参数,但不识别 %*,其中每个 %n 参数变量指向被选择的单个文件或目录,系统会为每个选择项自动开启一个cmd窗口进程,分别取用对应的 %n 运行右键菜单定义中的同一段代码,因此当选择项(文件或目录)较多时可能会导致系统卡死,当选择项未被双引号包裹但其中包含了&^等特殊字符时也会被系统拦截退出...
   楼主引用的 http://www.bathome.net/viewthread.php?tid=69150 其二楼代码,在具体运行时也会因应文件选择数量相应开启多个cmd窗口进程(可能因运行速度快而闪过未被察觉),可用如下代码(由二楼代码裁剪而成)予以验证...
  1. Windows Registry Editor Version 5.00
  2. [HKEY_CLASSES_ROOT\SystemFileAssociations\.pdf\Shell\rename1]
  3. @="自定义重命名"
  4. [HKEY_CLASSES_ROOT\SystemFileAssociations\.pdf\Shell\rename1\Command]
  5. @="cmd /v:on /c (for %%i in (\"%1\") do echo,%%~ni)&pause"
复制代码
系统为资源管理器内置的 ‘复制路径’ 右键功能实现了一次性传递全部选择集至剪贴板(选择项被双引号包裹), 系统内置的 ‘sendTo(发送到)’ 右键菜单机制亦可一次性传递全部选择集(命令行参数)至接收方(如挂载的批处脚本或vbs/jscript等脚本),例如7楼示例代码完成的将无双引号包裹的所有选择项传入剪贴板... 也许微软对用右键菜单一次性获取选择集也就提供了如此 ‘捷径’ 而已...

作者: buyiyang    时间: 2024-10-26 10:38

  1. @="cmd /c mshta VBScript:Execute(\"For Each win In CreateObject(\"\"Shell.Application\"\").Windows:If win.Document.SelectedItems.Count>1 Then:For Each selected In win.Document.SelectedItems:f=selected.Name&vbCrLf&f:Next:Else:f=win.Document.SelectedItems.item(0).Path:End If:CreateObject(\"\"Scripting.Filesystemobject\"\").GetStandardStream(1).Write(f):Next\")(close)|clip"
复制代码

作者: ppll2030    时间: 2024-10-26 11:08

除了注册表不支持%*,无法同时传递多个变量,
还有一个问题,就是for %%i in (%*)j语句中,文件的命名不能带英文反括号,否则语句失效。
解决的办法有,但不完美,就是文件命名不能带英文反括号,或者命名必须同时有空格和英文反括号。
作者: lforl    时间: 4 天前 22:54

本帖最后由 lforl 于 2024-11-19 22:57 编辑

感谢@aloha20200628
那个简洁的bat放入sendto的确是比较优秀的解!

对楼上诸位大佬一并致谢,@buyiyang、@ppll2030、@Five66
作者: lforl    时间: 3 天前 14:02

@aloha20200628
大大有空看下,似乎对于文件名内含半角括号和字母的,例如:xxx(ocr).pdf
bat就会失灵。
有兼容的办法吗?
作者: aloha20200628    时间: 3 天前 15:25

回复 13# lforl

从资源管理器拖入命令行的路径参数》如果有空格则会被系统自动包裹双引号因此会保全其中的 &^=() 等特殊字符,如果无空格则因未被包裹双引号而不能保全其中的 &^=() 等特殊字符,这是一个被老东家多年 '视而不见的老毛病'...

作者: lforl    时间: 3 天前 20:03

回复 14# aloha20200628

收到,我准备最终采用:win10的自带右键(按shift点右键)里面提取含引号路径的方法(支持多条,15以内,日常足矣)。
然后引号和路径另行处理替换掉,留下文件名列表。
谢谢大大!有您指点,学到了很多!




欢迎光临 批处理之家 (http://bathome.net./) Powered by Discuz! 7.2