AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 78500989
Accepted
jtxkopt - Stand With Palestine
jtxkopt - Stand With Palestine
Asked: 2024-05-19 05:01:52 +0800 CST2024-05-19 05:01:52 +0800 CST 2024-05-19 05:01:52 +0800 CST

在现有 Shell 窗口的新选项卡中打开文件夹

  • 772

注意:此问题仅适用于 Windows 11。

我想在现有 shell 窗口的新选项卡中打开一个文件夹。官方好像没有API。

我尝试过两种方法:

第一个,也是最明显的一个,是ShellExecute带有动词的函数opennewtab(该动词来自注册表中文件夹 ProgID 的 Shell 键内部 - [HKEY_CLASSES_ROOT\Folder\shell\opennewtab])。但是,这没有用。该函数只是为该文件夹打开一个新窗口。

为了第二次机会,我检查了opennewtab注册表中的动词。它被实现为IExecuteCommand(through DelegateExecute)。因此,我的第二次尝试是从COM服务器检索接口,通过它们提供的方法(SetXXXfor 的函数系列IExecuteCommand、Initialize方法IInitializeCommand等)设置所需的参数,最后调用该Execute方法。

为了了解Windows Shell传递给这些方法的内容以及调用它们的顺序,我实现了自定义动词实现及其COM服务器,并替换了在我的服务器上注册的旧COMopennewtab服务器。

在这里您可以看到 DebugView 显示的输出(我的动词实现使用 输出OutputDebugString)。

在此输入图像描述

正如您所看到的,它并没有调用接口的所有方法。所以,我认为通过设置相同的参数应该很容易。但是,是的,有些事情我没有考虑到。此方法生成了Null解除引用异常,但没有成功。

注意:我知道第二个是“hacky”的。

注意:CLSID实现默认动词处理程序的 是CLSID_ExecuteFolder。

我们如何在新选项卡中打开文件夹?

windows
  • 1 1 个回答
  • 36 Views

1 个回答

  • Voted
  1. Best Answer
    Simon Mourier
    2024-05-19T22:45:37+08:002024-05-19T22:45:37+08:00

    第一个解决方案是使用官方的UI Automation API。

    Microsoft UI Automation是一个辅助功能框架,使Windows应用程序能够提供和使用有关用户界面(UI)的编程信息。它提供对桌面上大多数 UI 元素的编程访问。它使辅助技术产品(例如屏幕阅读器)能够向最终用户提供有关 UI 的信息,并通过标准输入以外的方式操作 UI。UI 自动化还允许自动化测试脚本与 UI 交互。

    此代码打开一个c:\temp文件夹(或选择一个已打开的文件夹)并向资源管理器窗口添加一个新选项卡:

    int main()
    {
      CoInitialize(nullptr);
    
      // get a pidl for a given folder
      LPITEMIDLIST pidl;
      if (SUCCEEDED(SHParseDisplayName(L"c:\\temp", nullptr, &pidl, 0, nullptr)))
      {
        // open the folder (or activate an already matching opened one)
        SHOpenFolderAndSelectItems(pidl, 1, (LPCITEMIDLIST*)&pidl, 0);
    
        // find window that displays this pidl
        IShellWindows* windows;
        if (SUCCEEDED(CoCreateInstance(CLSID_ShellWindows, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&windows))))
        {
          // build buffer from pidl
          VARIANT url;
          VariantInit(&url);
          if (SUCCEEDED(InitVariantFromBuffer(pidl, ILGetSize(pidl), &url))) // propvarutil.h
          {
            long hwnd = 0;
            IDispatch* disp;
            VARIANT empty;
            VariantInit(&empty);
            windows->FindWindowSW(&url, &empty, SWC_BROWSER, &hwnd, 0, &disp);
            VariantClear(&url);
            VariantClear(&empty); // useless but we always pair calls
    
            if (disp) // should be null but we never know...
            {
              disp->Release();
            }
    
            if (hwnd)
            {
              //needs UIAutomationCore.h & UIAutomationClient.h
              IUIAutomation* automation;
              if (SUCCEEDED(CoCreateInstance(CLSID_CUIAutomation8, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&automation)))) // or CLSID_CUIAutomation
              {
                // get UIA element from handle
                IUIAutomationElement* window;
                automation->ElementFromHandle((UIA_HWND)(INT_PTR)hwnd, &window);
                if (window)
                {
                  // window's class should be 'ShellTabWindowClass'
                  // create inconditional "true" condition
                  IUIAutomationCondition* trueCondition;
                  automation->CreateTrueCondition(&trueCondition);
                  if (trueCondition)
                  {
                    // create a tree walker to determine window's parent
                    IUIAutomationTreeWalker* walker;
                    automation->CreateTreeWalker(trueCondition, &walker);
                    if (walker)
                    {
                      IUIAutomationElement* parent;
                      walker->GetParentElement(window, &parent);
                      if (parent)
                      {
                        // create a condition to find the first button with AutomationId property set to AddButton
                        VARIANT v;
                        V_VT(&v) = VT_BSTR;
                        V_BSTR(&v) = SysAllocString(L"AddButton");
                        IUIAutomationCondition* condition;
                        automation->CreatePropertyCondition(UIA_AutomationIdPropertyId, v, &condition);
                        VariantClear(&v);
                        if (condition)
                        {
                          IUIAutomationElement* button;
                          // search button
                          parent->FindFirst(TreeScope_Subtree, condition, &button);
                          if (button)
                          {
                            // a button implements the "Invoke" pattern
                            IUnknown* unk;
                            button->GetCurrentPattern(UIA_InvokePatternId, &unk);
                            if (unk)
                            {
                              IUIAutomationInvokePattern* pattern;
                              unk->QueryInterface(&pattern);
                              if (pattern)
                              {
                                // press the button
                                pattern->Invoke();
                                pattern->Release();
                              }
                              unk->Release();
                            }
                            button->Release();
                          }
                          condition->Release();
                        }
                        parent->Release();
                      }
                      walker->Release();
                    }
                    trueCondition->Release();
                  }
                }
                automation->Release();
              }
              CoUninitialize();
            }
          }
          windows->Release();
        }
        CoTaskMemFree(pidl);
      }
      CoUninitialize();
      return 0;
    }
    

    为了能够对 UIA 进行编程,您通常首先分析窗口的结构,例如使用Windows SDK 中的Inspect 工具或较新的Accessibility Insights来了解您应该执行哪些操作。这是突出显示的资源管理器的“添加新选项卡”按钮的检查屏幕截图,它告诉我们该按钮的Automation Id属性设置为“AddButton”:

    在此输入图像描述

    PS:有时,这不太明显,因为自动化 ID并不总是设置。

    另一个解决方案是使用未记录的 Explorer 的WM_COMMAND0xA21B (41499),它直接要求 Explorer 打开一个新选项卡。因此,使用前面的示例代码,在按住窗口后,您可以简单地用此替换所有 UIA 代码ShellTabWindowClass:

    ...
    if (hwnd)
    {
      // window's class should be 'ShellTabWindowClass'
      // ask to open a new tab
      SendMessage((HWND)(INT_PTR)hwnd, WM_COMMAND, 0xA21B, 0);
    }
    ...
    

    打开新选项卡后,它会被视为一个新窗口(视图),因此您可以CLSID_ShellWindows再次(重新)开始使用并使用我在此处所做的操作将此新视图导航到任何文件夹https://stackoverflow.com /a/78272475/403671通话Navigate2。

    • 1

相关问题

  • C++ 完全读取文件,其中大小>2GB (Win64)

  • Windows Palo Alto Cortex XDR BSOD,带错误检查 0x139

  • 我无法在我的 go 项目中导入本地包

  • KERNEL32.DLL 总是加载到 Windows 进程中的第三个模块吗?

  • 这个不安全的 Rust 代码有什么问题,所以它可以在 Windows 上运行,但不能在 Ubuntu 上运行?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    Vue 3:创建时出错“预期标识符但发现‘导入’”[重复]

    • 1 个回答
  • Marko Smith

    为什么这个简单而小的 Java 代码在所有 Graal JVM 上的运行速度都快 30 倍,但在任何 Oracle JVM 上却不行?

    • 1 个回答
  • Marko Smith

    具有指定基础类型但没有枚举器的“枚举类”的用途是什么?

    • 1 个回答
  • Marko Smith

    如何修复未手动导入的模块的 MODULE_NOT_FOUND 错误?

    • 6 个回答
  • Marko Smith

    `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它?

    • 3 个回答
  • Marko Smith

    何时应使用 std::inplace_vector 而不是 std::vector?

    • 3 个回答
  • Marko Smith

    在 C++ 中,一个不执行任何操作的空程序需要 204KB 的堆,但在 C 中则不需要

    • 1 个回答
  • Marko Smith

    PowerBI 目前与 BigQuery 不兼容:Simba 驱动程序与 Windows 更新有关

    • 2 个回答
  • Marko Smith

    AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String”

    • 1 个回答
  • Marko Smith

    我正在尝试仅使用海龟随机和数学模块来制作吃豆人游戏

    • 1 个回答
  • Martin Hope
    Aleksandr Dubinsky 为什么 InetAddress 上的 switch 模式匹配会失败,并出现“未涵盖所有可能的输入值”? 2024-12-23 06:56:21 +0800 CST
  • Martin Hope
    Phillip Borge 为什么这个简单而小的 Java 代码在所有 Graal JVM 上的运行速度都快 30 倍,但在任何 Oracle JVM 上却不行? 2024-12-12 20:46:46 +0800 CST
  • Martin Hope
    Oodini 具有指定基础类型但没有枚举器的“枚举类”的用途是什么? 2024-12-12 06:27:11 +0800 CST
  • Martin Hope
    sleeptightAnsiC `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它? 2024-11-09 07:18:53 +0800 CST
  • Martin Hope
    The Mad Gamer 何时应使用 std::inplace_vector 而不是 std::vector? 2024-10-29 23:01:00 +0800 CST
  • Martin Hope
    Chad Feller 在 5.2 版中,bash 条件语句中的 [[ .. ]] 中的分号现在是可选的吗? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench 为什么双破折号 (--) 会导致此 MariaDB 子句评估为 true? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng 为什么 `dict(id=1, **{'id': 2})` 有时会引发 `KeyError: 'id'` 而不是 TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String” 2024-03-20 03:12:31 +0800 CST
  • Martin Hope
    MarkB 为什么 GCC 生成有条件执行 SIMD 实现的代码? 2024-02-17 06:17:14 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve