Win11新资源管理器UI下 获取选中的文件/文件夹 问题

功能建议 · 1791 次浏览
FaniX 创建于 2022-10-29 11:34

关于#12232(已归档)

在ahk论坛中发现了一个获取资源管理器当前标签页的解决方案:

大致方法是根据Tab控件的hwnd来判断哪个Shell.Application窗口是当前标签页

不知道在Quicker中能不能实现

FaniX 最后更新于 2022/10/29

回复内容
CL 2022-10-29 13:16
#1

感谢!我研究下。

FaniX 回复 CL 2022-10-31 22:05 :

仔细研究了一下,大致明白了具体的实现方法。由于没有C#的调试环境就用了powershell。

Shell.Application层面,不同tab的hwnd是相同的

但tab各个控件的hwnd是不同的,可以通过IShellBrowserShell.Application对象中提取出对应tab控件的hwnd:

#powershell
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;

[ComImport]
[Guid("6d5140c1-7436-11ce-8034-00aa006009fa")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ComServiceProvider {
    [return: MarshalAs(UnmanagedType.IUnknown)]
    Object QueryService(ref Guid guidService, ref Guid riid);
}

[ComImport]
[Guid("000214e2-0000-0000-c000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IShellBrowser {
    IntPtr GetWindow();
}
"@
$w=(New-Object -ComObject Shell.Application).Windows()[0] #<-使用其他下标获取其他窗口
$shellBrowser = [ComServiceProvider].GetMethod('QueryService').Invoke($w, @([guid]'4c96be40-915c-11cf-99d3-00aa004ae837', [guid]'000214e2-0000-0000-c000-000000000046'))
$tabHwnd=[IShellBrowser].GetMethod('GetWindow').Invoke($shellBrowser, @())

同时,可以通过user32EnumChildWindows()来列出某个explore窗口各个控件的hwnd

Add-Type  @"
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;
public class APIFuncs {
    [DllImport("user32")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr i);
    public static List<IntPtr> GetChildWindows(IntPtr parent)
    {
        List<IntPtr> result = new List<IntPtr>();
        GCHandle listHandle = GCHandle.Alloc(result);
        try
        {
            EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
            EnumChildWindows(parent, childProc,GCHandle.ToIntPtr(listHandle));
        }
        finally
        {
            if (listHandle.IsAllocated)
                listHandle.Free();
        }
        return result;
    }
    private static bool EnumWindow(IntPtr handle, IntPtr pointer)
    {
        GCHandle gch = GCHandle.FromIntPtr(pointer);
        List<IntPtr> list = gch.Target as List<IntPtr>;
        if (list == null)
        {
            throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
        }
        list.Add(handle);
        //  You can modify this to check to see if you want to cancel the operation, then return a null here
        return true;
    }
    public delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);
    }
"@


[apifuncs]::GetChildWindows($w.HWND)

这里会列出所有的控件,可以根据控件的名称ShellTabWindowClass1来筛选Tab控件

控件的顺序会随着当前Tab而改变,排在最前面的ShellTabWindowClass1控件hwnd就是当前激活tab的hwnd

这样就可以得到当前窗口的活动tab了

FaniX 最后更新于 2022-10-31 22:12
FaniX 回复 CL 2022-10-31 22:05 :


FaniX 最后更新于 2022-10-31 22:07
CL 回复 FaniX 2022-10-31 22:32 :

👍 今天整了一天,基本弄好了,等下发个版本。

CL 回复 FaniX 2022-10-31 22:37 :

https://getquicker.net/Help/Versions 发了一个版本,试下看看

FaniX 回复 CL 2022-10-31 23:59 :

谢谢C大,资源管理器标签页终于能正常使用了😂

不过想问一下从Shell.Application Window获取Tab控件hwnd的操作怎么能移植到表达式内?我有个利用Shell操作选中文件的子程序需要获取到当前Tab的Shell.Application Window。后半部分获取活动Tab控件hwnd的话可以直接从Quicker的 获取窗口信息/查找窗口 查找子窗口/控件 动作来获得,不知道前半部分能不能直接在表达式里实现?

FaniX 最后更新于 2022-11-01 00:00
CL 回复 FaniX 2022-11-01 08:03 :

内部代码有点乱,目前也没法在子程序里访问这个功能。 我等试试看看能不能直接封装到模块里。

CL 回复 FaniX 2022-11-02 07:41 :

1.36.2 增加了设置选中文件的操作,可以试下看看。 https://getquicker.net/Help/Versions 

FaniX 回复 CL 2022-11-02 10:50 :

设置选中的时候可以指定窗口吗?现在只能设置前台资源管理器窗口,在实时搜索的情况下需要恢复活动窗口并等待一段时间,但实时搜索窗口的销毁时间是不确定的所以有时候会出问题

CL 回复 FaniX 2022-11-02 10:54 :

不能指定。 在多标签页的情况下,创建句柄也不能指定标签。 这个大概是什么样的需求场景呢?

FaniX 回复 CL 2022-11-02 11:13 :

我想要利用实时搜索筛选当前资源管理器下的文件并选中,动作:筛选文件

FaniX 最后更新于 2022-11-02 11:13
FaniX 回复 CL 2022-11-02 11:44 :

我想的是指定窗口hwnd,在对应窗口的活动标签页进行文件选中

FaniX 2022-11-04 23:27
#2

用C#脚本实现了一个:设置选中文件,可以指定窗口句柄(对活动标签页有效),可以不需要获取焦点

CL 回复 FaniX 2022-11-05 09:35 :

👍

回复主贴