DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: szliyu112358
今日帖子: 52
在线用户: 11
导航: 论坛 -> DELPHI技术 斑竹:liumazi,sephil  
作者:
男 namejm (namejm) ▲▲▲▲▲ -
普通会员
2017/9/12 17:57:53
标题:
如何获取已选文件完整路径 浏览:2114
加入我的收藏
楼主: 在开发的程序A中,需要识别在资源管理器中点选了哪些文件(注意:不能调用文件选择窗口去获取,而是已经在资源管理器中点了文件之后,要在程序A中识别出当前点选了哪些文件
目前已经拿到了被点选资源管理器窗口的句柄
有没有什么办法识别出当前点选了哪些文件?(需要每一个文件的完整路径)
网上搜了几天了,没有找到可行的代码,直接的讨论也少得可怜
比较接近需求的是王集鹄(Zswang)大虾在2009年写的一段“跨进程访问VCL”的代码,可惜那个只能针对VCL控件,似乎处理不了资源管理器(也许我不太会改代码)
不知道哪位大虾能给个演示代码
----------------------------------------------
-
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2017/9/12 19:04:51
1楼: 估计是你方向弄错了。

二种解决方法:

  1、拖拽;将选中的文件拖放到你的程序窗口上,处理拖放消息就可以了;比较简单;

  2、编写Shell扩展;有点复杂;
----------------------------------------------
武汉天气不好
作者:
男 bahamut8348 (leonna) ★☆☆☆☆ -
普通会员
2017/9/12 21:05:28
2楼: 你要做啥?如果你是要获取拖拽到程序窗口的文件列表的话,去看wm_dropfiles消息。
如果你只想获取用户资源管理器里已选择的的文件列表的话,那你用一般的方式是没卵用的,windows的资源管理器是directui,和一般窗口不一样的,要用进程注入才能达到目标。但是注入的话你先考虑考虑怎么搞定安全软件。
----------------------------------------------
--
作者:
男 namejm (namejm) ▲▲▲▲▲ -
普通会员
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工程师联合开发网
作者:
男 namejm (namejm) ▲▲▲▲▲ -
普通会员
2017/9/12 22:26:38
5楼: 考虑到大多数人习惯于在自带的资源管理器中操作文件,我这个小工具侧重于自动识别自带资源管理器中已选的文件,要不然我只需要识别 TotalCommander 中已选的文件就够我自用了
所以,暂时不考虑自己做个替代自带资源管理器的方案,还是希望能够直接识别出自带资源管理器中已选的文件为上。
----------------------------------------------
-
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2017/9/13 1:34:58
6楼: 微软自带工具,可供你研究。
此帖子包含附件:
PNG 图像
大小:265.6K
----------------------------------------------
武汉天气不好
作者:
女 blbz (冰力不足) ★☆☆☆☆ -
禁用账号
2017/9/13 4:50:25
7楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
SPAM
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2017/9/13 9:58:42
8楼: IShellWindows--->IWebBrowser2-->IShellBrowser--->IShellView-->SVGIO_SELECTION
测试通过。
----------------------------------------------
武汉天气不好
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
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.
----------------------------------------------
武汉天气不好
作者:
男 namejm (namejm) ▲▲▲▲▲ -
普通会员
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.

----------------------------------------------
-
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2017/9/13 19:35:31
11楼: 你把问题弄的太复杂了。

无需使用钩子和dll。

获取窗口句柄,用 WindowFromPoint 可以了。
在定时器中,时时获取鼠标指向的窗口句柄。

注释掉代码是不正确的。打开的窗口可能有多个。

窗口的类是:CabinetWClass,句柄应该是这个窗口类的句柄。
----------------------------------------------
武汉天气不好
作者:
男 namejm (namejm) ▲▲▲▲▲ -
普通会员
2017/9/13 20:06:21
12楼: 感觉用定时器有点耗资源,所以我就用了鼠标钩子,没比较过定时器和鼠标钩子哪个更好一些,可能我的直觉错了。

注释代码是调试过程中查看问题出在那一步时才做的,正式代码中会恢复过去。

如果用dll的方案,该如何修改呢——纯讨论下。
----------------------------------------------
-
作者:
男 luckyso999 (luckyso) ★☆☆☆☆ -
盒子活跃会员
2017/9/13 22:59:33
13楼: 用DLL会被360报病毒。。。
----------------------------------------------
-
作者:
男 namejm (namejm) ▲▲▲▲▲ -
普通会员
2017/9/13 23:50:28
14楼: 梳理了下我那个小工具的处理流程,觉得还是应当使用dll方案,而定时器方案的弊端是比较明显的
因为我只是希望在鼠标点中文件的那一刻获取文件相关信息,其它时间无需重复获取
而定时器会隔一段时间就获取一次,如果定时间隔设置得稍小,获取信息的过程略微耗时,可能会导致CPU占用明显升高,如果通过比较前后两次选中的文件是否不同来决定是否获取,也只是稍微减轻了一点而已;如果时间间隔设置得稍大,又会导致响应略有延迟,不够流畅
考虑到以后其它地方也会有类似的需求,所以还是想弄清楚如何通过dll来完美实现
DLL会被报毒的问题,通过白名单应该好解决。
----------------------------------------------
-
作者:
男 scarlette (Scarlette) ★☆☆☆☆ -
普通会员
2017/9/14 1:01:36
15楼:  blbz (冰力不足):
“一般老菜鸟才知道spy++有强大的消息拦截功能。”
嗯…老菜鸟…╮( ̄▽ ̄"")╭
----------------------------------------------
-
作者:
男 namejm (namejm) ▲▲▲▲▲ -
普通会员
2017/9/14 10:29:02
16楼: 我获取了窗口类名为 CabinetWClass 的句柄后,用 GetPathByExplorerHandle 获取到的路径名一般是 "c\Users\当前用户名\Desktop\已选文件名",总是获取到桌面路径,而不是当前的真正路径,哪里出问题了呢?
----------------------------------------------
-
作者:
男 bahamut8348 (leonna) ★☆☆☆☆ -
普通会员
2017/9/15 8:55:16
17楼: 鼠标钩子哦。用低级钩子可以不用带dll的。直接全局钩子就可以了。

至于为什么列举出来的全部都是桌面目录下,因为序号1开始是文件名。序号0是路径。

自己处理一下就可以了。


最后,钩子和计时器,都不如远线程节约资源。通过远线程注入,然后通过readprocessmemory来获取已选项才最节约资源。
----------------------------------------------
--
作者:
男 namejm (namejm) ▲▲▲▲▲ -
普通会员
2017/9/16 0:23:56
18楼: 谢谢 bahamut8348 的指点,已经能够正确显示在普通目录下已选文件的信息了
不过如果在桌面上选择文件时,若仍然捕获窗口类 CabinetWClass ,那么,显示的将是资源管理器中其它路径下的文件,而不是桌面上的文件
GetPathByExplorerHandle 需要怎么修改呢?

远程线程注入我再找找资料琢磨下。
----------------------------------------------
-
作者:
男 olo (奧哩奧) ▲▲▲△△ -
普通会员
2017/9/16 20:21:44
19楼: 哇,厉害..现在我只能拖拉才能出路径;

请问 楼主可以共享下如何做 "已经能够正确显示在普通目录下已选文件的信息了"  吗?
----------------------------------------------
-
作者:
男 bahamut8348 (leonna) ★☆☆☆☆ -
普通会员
2017/9/20 10:06:26
20楼: 桌面有点特殊,你可以用spy看一下,桌面和进入目录后的资源管理器的窗口结构不太一样。
如果你一定要在9楼的基础上改的话,你可以用findwindowssw(不知道有没有打错)来查找桌面窗口,不过这个方法只支持vista以后的系统。xp什么的就别想了。
----------------------------------------------
--
作者:
男 namejm (namejm) ▲▲▲▲▲ -
普通会员
2023/1/10 12:31:18
21楼: 多年后,我还在坚守 Win7,但不知道什么原因(也可能是系统打了补丁后改动了什么设置),以上代码居然捕获不到资源管理器中已选的文件了
问题出在这一句:SHGetPathFromIDList(PItemIDList(PInteger(pPIDA.aoffset[JJJ] + Cardinal(pPIDA))), strName);
不知道怎么修改
哪位大虾能完善一下吗?
----------------------------------------------
-
作者:
男 aknightchen (.) ★☆☆☆☆ -
盒子活跃会员
2023/1/10 12:41:31
22楼: 楼主, 如果你已解决或部分解决此问题, 也应当分享出代码.
----------------------------------------------
...
作者:
男 teclick (nelson) ★☆☆☆☆ -
普通会员
2023/1/12 19:06:36
23楼: 不知这个能否满足你的要求,这是win7的,我看了win10也有相关的设置
此帖子包含附件:
PNG 图像
大小:91.4K
----------------------------------------------
-
作者:
男 namejm (namejm) ▲▲▲▲▲ -
普通会员
2023/1/15 23:07:15
24楼: @teclick:
您抓的图是 SynEdit 的文件,貌似 SynEdit 并没有捕获资源管理器中当前已选文件列表的功能
也许它在某个模块中有这个功能而我并没有发现
还望您详细指点
----------------------------------------------
-
作者:
男 namejm (namejm) ▲▲▲▲▲ -
普通会员
2023/1/15 23:08:37
25楼: @aknightchen 
我后来使用的代码就是9楼的那段代码
当时是成功的
只是不知道为什么,近期重新使用的时候发现失败了
----------------------------------------------
-
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行117.1875毫秒 RSS