导航:
论坛 -> DELPHI技术
斑竹:liumazi,sephil
作者:
2017/9/12 17:57:53
标题:
加入我的收藏
楼主:
在开发的程序A中,需要识别在资源管理器中点选了哪些文件(注意:不能调用文件选择窗口去获取,而是已经在资源管理器中点了文件之后,要在程序A中识别出当前点选了哪些文件 ) 目前已经拿到了被点选资源管理器窗口的句柄 有没有什么办法识别出当前点选了哪些文件?(需要每一个文件的完整路径) 网上搜了几天了,没有找到可行的代码,直接的讨论也少得可怜 比较接近需求的是王集鹄(Zswang)大虾在2009年写的一段“跨进程访问VCL”的代码,可惜那个只能针对VCL控件,似乎处理不了资源管理器(也许我不太会改代码) 不知道哪位大虾能给个演示代码
----------------------------------------------
-
作者:
2017/9/12 19:04:51
1楼:
估计是你方向弄错了。 二种解决方法: 1、拖拽;将选中的文件拖放到你的程序窗口上,处理拖放消息就可以了;比较简单; 2、编写Shell扩展;有点复杂;
----------------------------------------------
武汉天气不好
作者:
2017/9/12 21:05:28
2楼:
你要做啥?如果你是要获取拖拽到程序窗口的文件列表的话,去看wm_dropfiles消息。 如果你只想获取用户资源管理器里已选择的的文件列表的话,那你用一般的方式是没卵用的,windows的资源管理器是directui,和一般窗口不一样的,要用进程注入才能达到目标。但是注入的话你先考虑考虑怎么搞定安全软件。
----------------------------------------------
--
作者:
2017/9/12 21:35:18
3楼:
我在捣鼓一个小工具,希望在鼠标点中文件的时候直接显示文件的相关信息 因为查看文件信息的操作很频繁,我希望用最少的操作环节来实现,不能用拖拽文件到程序界面上的方式,要不然非得把人累死不可 当然,也可以直接把所有文件先在程序中列出来,然后点击程序中的文件列表,但是这样操作仍显得有点繁琐,在切换文件夹的时候不够灵活,和这个工具的定位不符合 目前,我写了个dll,用钩子函数捕获了鼠标的点击操作,能够获取到资源管理器的句柄,但是不知道如何识别选中了哪些文件,不知道Shell扩展需要用到哪些方法,谁能指点下?不甚感激。
----------------------------------------------
-
作者:
go_on (go_on)
★☆☆☆☆
-
盒子活跃会员
2017/9/12 21:43:33
4楼:
方法1:自己做一个替代资源管理器,例如用Raize的,想怎么都可以 方法2:写扩展,像TortoiseSVN 改图标都可以,这个没做过,应该类似做 工具条 Band Extension
----------------------------------------------
www.eudn.cn工程师联合开发网
作者:
2017/9/12 22:26:38
5楼:
考虑到大多数人习惯于在自带的资源管理器中操作文件,我这个小工具侧重于自动识别自带资源管理器中已选的文件,要不然我只需要识别 TotalCommander 中已选的文件就够我自用了 所以,暂时不考虑自己做个替代自带资源管理器的方案,还是希望能够直接识别出自带资源管理器中已选的文件为上。
----------------------------------------------
-
作者:
2017/9/13 1:34:58
6楼:
微软自带工具,可供你研究。
此帖子包含附件: 大小: 265.6K
----------------------------------------------
武汉天气不好
作者:
blbz (冰力不足)
★☆☆☆☆
-
禁用账号
2017/9/13 4:50:25
7楼:
…… 被禁用帐号,帖子内容自动屏蔽! ……
----------------------------------------------
SPAM
作者:
2017/9/13 9:58:42
8楼:
IShellWindows--->IWebBrowser2-->IShellBrowser--->IShellView-->SVGIO_SELECTION 测试通过。
----------------------------------------------
武汉天气不好
作者:
2017/9/13 10:20:34
9楼:
unit Unit1; interface uses Windows, SysUtils, Variants, Classes, Controls, Forms, ShlObj, SHDocVw, ActiveX, ComObj, Dialogs; type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} const IID_IDataObject: TGUID = (D1: $0000010E; D2: $0000; D3: $0000; D4: ($C0, $00, $00, $00, $00, $00, $00, $46)); procedure GetPathByExplorerHandle(AHandle: Integer); var ShellWindows : IShellWindows; III, JJJ : Integer; Dispatch : System.IDispatch; WebBrowser2 : IWebBrowser2; ServiceProvider: IServiceProvider; ShellBrowser : IShellBrowser; ShellView : IShellView; plDataObject : Pointer; fmte : TFormatEtc; stgmedium : TStgMedium; pPIDA : PIDA; intSelected : Integer; strName : PChar; begin OleCheck(CoCreateInstance(CLASS_ShellWindows, nil, CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER, IShellWindows, ShellWindows)); try for III := ShellWindows.Count - 1 downto 0 do begin Dispatch := ShellWindows.Item(III); try OleCheck(Dispatch.QueryInterface(IWebBrowser2, WebBrowser2)); try if WebBrowser2.HWND = AHandle then begin OleCheck(Dispatch.QueryInterface(IServiceProvider, ServiceProvider)); try OleCheck(ServiceProvider.QueryService(SID_STopLevelBrowser, IShellBrowser, ShellBrowser)); try OleCheck(ShellBrowser.QueryActiveShellView(ShellView)); try ShellView.GetItemObject(SVGIO_SELECTION, IID_IDataObject, plDataObject); fmte.tymed := TYMED_HGLOBAL; fmte.lindex := -1; fmte.dwAspect := DVASPECT_CONTENT; fmte.cfFormat := RegisterClipboardFormatA(CFSTR_SHELLIDLIST); IDataObject(plDataObject).GetData(fmte, stgmedium); pPIDA := GlobalLock(stgmedium.hGlobal); if pPIDA <> nil then begin { 选中文件的个数 } intSelected := pPIDA.cidl; ShowMessage(IntToStr(intSelected)); { 获取文件名称 } for JJJ := 1 to intSelected do begin strName := AllocMem(255); SHGetPathFromIDList(PItemIDList(PInteger(pPIDA.aoffset[JJJ] + Cardinal(pPIDA))), strName); ShowMessage(strName); end; end; finally ShellView := nil; end; finally ShellBrowser := nil; end; finally ServiceProvider := nil; end; end; finally WebBrowser2 := nil; end; finally Dispatch := nil; end; end; finally ShellWindows := nil; end; end; procedure TForm1.FormCreate(Sender: TObject); begin GetPathByExplorerHandle($30746); end; end.
----------------------------------------------
武汉天气不好
作者:
2017/9/13 19:11:23
10楼:
实际上,我还只是个菜鸟,很多代码都是抄网上的代码,7楼大虾谬赞了。 Re dbyoung: 感谢大虾给出了完整代码 我把 GetPathByExplorerHandle 这个过程放到我的代码中后,没有捕获到结果 注释掉 if WebBrowser2.HWND = AHandle then 这一句后可以正常显示 可能我在鼠标点击时抓到的句柄是错误的 我贴一下我那段捕获资源管理器的dll代码,不知道能不能指点一下哪里错了(在主程序的 procedure TfrmMain.IMouseMessage(var msg: TMessage); 过程中,我是用 GetPathByExplorerHandle(msg.LParam) 调用的): library IMouseHook; uses System.SysUtils, Winapi.Windows, {钩子函数都来自 Windows 单元} Winapi.Messages, {消息 WM_LBUTTONDOWN 定义在 Messages 单元} System.Classes; {$R *.res} const WM_IMouseMessage = WM_USER + 1; {自定义消息} var hook: HHOOK; AppHwnd: HWND; {用作外部窗口的句柄} {获取外部窗口的句柄} function GetAppHwnd(hwnd: HWND): Boolean; stdcall; begin AppHwnd := hwnd; Result := True; end; function MouseHook(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; var curPoint: TPoint; begin case wParam of WM_LBUTTONDOWN : begin {通过消息把数据传递给指定窗口} GetCursorPos(curPoint); PostMessage(AppHwnd, WM_IMouseMessage, 0, WindowFromPoint(curPoint)); end; end; Result := CallNextHookEx(hook, nCode, wParam, lParam); end; function SetHook: Boolean; stdcall; const WH_MOUSE_LL = 14; begin hook := SetWindowsHookEx(WH_MOUSE_LL, @MouseHook, HInstance, 0); Result := hook <> 0; end; function UnHook: Boolean; stdcall; begin Result := UnhookWindowsHookEx(hook); end; exports SetHook, UnHook, MouseHook, GetAppHwnd; begin end.
----------------------------------------------
-
作者:
2017/9/13 19:35:31
11楼:
你把问题弄的太复杂了。 无需使用钩子和dll。 获取窗口句柄,用 WindowFromPoint 可以了。 在定时器中,时时获取鼠标指向的窗口句柄。 注释掉代码是不正确的。打开的窗口可能有多个。 窗口的类是:CabinetWClass,句柄应该是这个窗口类的句柄。
----------------------------------------------
武汉天气不好
作者:
2017/9/13 20:06:21
12楼:
感觉用定时器有点耗资源,所以我就用了鼠标钩子,没比较过定时器和鼠标钩子哪个更好一些,可能我的直觉错了。 注释代码是调试过程中查看问题出在那一步时才做的,正式代码中会恢复过去。 如果用dll的方案,该如何修改呢——纯讨论下。
----------------------------------------------
-
作者:
2017/9/13 22:59:33
13楼:
用DLL会被360报病毒。。。
----------------------------------------------
-
作者:
2017/9/13 23:50:28
14楼:
梳理了下我那个小工具的处理流程,觉得还是应当使用dll方案,而定时器方案的弊端是比较明显的 因为我只是希望在鼠标点中文件的那一刻获取文件相关信息,其它时间无需重复获取 而定时器会隔一段时间就获取一次,如果定时间隔设置得稍小,获取信息的过程略微耗时,可能会导致CPU占用明显升高,如果通过比较前后两次选中的文件是否不同来决定是否获取,也只是稍微减轻了一点而已;如果时间间隔设置得稍大,又会导致响应略有延迟,不够流畅 考虑到以后其它地方也会有类似的需求,所以还是想弄清楚如何通过dll来完美实现 DLL会被报毒的问题,通过白名单应该好解决。
----------------------------------------------
-
作者:
2017/9/14 1:01:36
15楼:
blbz (冰力不足): “一般老菜鸟才知道spy++有强大的消息拦截功能。” 嗯…老菜鸟…╮( ̄▽ ̄"")╭
----------------------------------------------
-
作者:
2017/9/14 10:29:02
16楼:
我获取了窗口类名为 CabinetWClass 的句柄后,用 GetPathByExplorerHandle 获取到的路径名一般是 "c\Users\当前用户名\Desktop\已选文件名",总是获取到桌面路径,而不是当前的真正路径,哪里出问题了呢?
----------------------------------------------
-
作者:
2017/9/15 8:55:16
17楼:
鼠标钩子哦。用低级钩子可以不用带dll的。直接全局钩子就可以了。 至于为什么列举出来的全部都是桌面目录下,因为序号1开始是文件名。序号0是路径。 自己处理一下就可以了。 最后,钩子和计时器,都不如远线程节约资源。通过远线程注入,然后通过readprocessmemory来获取已选项才最节约资源。
----------------------------------------------
--
作者:
2017/9/16 0:23:56
18楼:
谢谢 bahamut8348 的指点,已经能够正确显示在普通目录下已选文件的信息了 不过如果在桌面上选择文件时,若仍然捕获窗口类 CabinetWClass ,那么,显示的将是资源管理器中其它路径下的文件,而不是桌面上的文件 GetPathByExplorerHandle 需要怎么修改呢? 远程线程注入我再找找资料琢磨下。
----------------------------------------------
-
作者:
olo (奧哩奧)
▲▲▲△△
-
普通会员
2017/9/16 20:21:44
19楼:
哇,厉害..现在我只能拖拉才能出路径; 请问 楼主可以共享下如何做 "已经能够正确显示在普通目录下已选文件的信息了" 吗?
----------------------------------------------
-
作者:
2017/9/20 10:06:26
20楼:
桌面有点特殊,你可以用spy看一下,桌面和进入目录后的资源管理器的窗口结构不太一样。 如果你一定要在9楼的基础上改的话,你可以用findwindowssw(不知道有没有打错)来查找桌面窗口,不过这个方法只支持vista以后的系统。xp什么的就别想了。
----------------------------------------------
--
作者:
2023/1/10 12:31:18
21楼:
多年后,我还在坚守 Win7,但不知道什么原因(也可能是系统打了补丁后改动了什么设置),以上代码居然捕获不到资源管理器中已选的文件了 问题出在这一句:SHGetPathFromIDList(PItemIDList(PInteger(pPIDA.aoffset[JJJ] + Cardinal(pPIDA))), strName); 不知道怎么修改 哪位大虾能完善一下吗?
----------------------------------------------
-
作者:
2023/1/10 12:41:31
22楼:
楼主, 如果你已解决或部分解决此问题, 也应当分享出代码.
----------------------------------------------
...
作者:
2023/1/12 19:06:36
23楼:
不知这个能否满足你的要求,这是win7的,我看了win10也有相关的设置
此帖子包含附件: 大小: 91.4K
----------------------------------------------
-
作者:
2023/1/15 23:07:15
24楼:
@teclick: 您抓的图是 SynEdit 的文件,貌似 SynEdit 并没有捕获资源管理器中当前已选文件列表的功能 也许它在某个模块中有这个功能而我并没有发现 还望您详细指点
----------------------------------------------
-
作者:
2023/1/15 23:08:37
25楼:
@aknightchen 我后来使用的代码就是9楼的那段代码 当时是成功的 只是不知道为什么,近期重新使用的时候发现失败了
----------------------------------------------
-