使 Windows 资源管理器的现有实例导航到特定文件夹

问题描述 投票:0回答:1

详细背景

我的项目是在 Windows 资源管理器中创建一个图标来访问远程位置,并使 Windows 上的导航与本地文件系统的导航相同。

这工作正常,包括当该位置不再可用时在 Windows 资源管理器中添加和删除图标。但是,如果在删除图标之前在此位置打开 Windows 资源管理器,它会继续显示该图标,并且那里的任何交互都会导致错误。

我的目标是确保不会发生这种情况:如果该位置被删除,使任何 Windows 资源管理器实例打开到即将删除的位置导航到默认位置(示例)。

已经完成的事情

访问打开的 Windows 资源管理器实例正常,因为获取它们打开位置的路径。我按照这些说明操作,效果很好。

供参考,这是迄今为止我的代码:

std::vector<IWebBrowserApp*> getOpenWindowsExplorers()
{
    std::vector<IWebBrowserApp*> openExplorers;
    IShellWindows *psw;
    if (SUCCEEDED(CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_ALL,
                                   IID_IShellWindows, (void**)&psw))) {
        VARIANT v;
        V_VT(&v) = VT_I4;
        IDispatch  *pdisp;
        BOOL fFound = FALSE;
        for (V_I4(&v) = 0; !fFound && psw->Item(v, &pdisp) == S_OK;V_I4(&v)++)
        {
            IWebBrowserApp *pwba;
            if (SUCCEEDED(pdisp->QueryInterface(IID_IWebBrowserApp, (void**)&pwba)))
            {
                openExplorers.push_back(pwba);
            }
            pdisp->Release();
        }
        psw->Release();
    }
    return openExplorers;
}

QString getCurrentOpenFolder(IWebBrowserApp* explorer)
{
    QString folderPath;

    IServiceProvider *psp;
    if (SUCCEEDED(explorer->QueryInterface(IID_IServiceProvider, (void**)&psp)))
    {
        IShellBrowser *psb;
        if (SUCCEEDED(psp->QueryService(SID_STopLevelBrowser, IID_IShellBrowser, (void**)&psb)))
        {
            IShellView *psv;
            if (SUCCEEDED(psb->QueryActiveShellView(&psv)))
            {
                IFolderView *pfv;
                if (SUCCEEDED(psv->QueryInterface(IID_IFolderView, (void**)&pfv)))
                {
                    IPersistFolder2 *ppf2;
                    if (SUCCEEDED(pfv->GetFolder(IID_IPersistFolder2, (void**)&ppf2)))
                    {
                        LPITEMIDLIST pidlFolder;
                        if (SUCCEEDED(ppf2->GetCurFolder(&pidlFolder)))
                        {
                            TCHAR g_szPath[MAX_PATH];
                            if (SHGetPathFromIDList(pidlFolder, g_szPath))
                            {
                                folderPath = QString::fromWCharArray(g_szPath);
                            }
                            CoTaskMemFree(pidlFolder);
                        }
                        ppf2->Release();
                    }
                    pfv->Release();
                }
                psv->Release();
            }
            psb->Release();
        }
        psp->Release();
    }
    return folderPath;
}

但是我找不到任何关于如何设置Windows资源管理器路径的文档,无论是官方的还是非官方的。

到目前为止我发现了什么

  • IPersistFolder 有一个 Initialize() 方法似乎可以做到这一点。然而,它需要一个 PCIDLIST 参数,我不知道如何获取与用户配置文件路径或任何其他硬编码路径相对应的 PCIDLIST。另外,官方文档没有说明如何使用它。
  • 围绕 IWebBrowser::Navigate() 方法有 a 文档,它似乎也可以实现我想要的功能。然而该文档不是官方的,也没有解释参数是什么。该方法虽然存在,但官方文档似乎没有引用它。

实现我想要的最好方法是什么?

c++ windows winapi windows-explorer
1个回答
0
投票

您可以使用 IWebBrowser2::Navigate2 方法,如下所示:

int main()
{
  CoInitialize(nullptr);
  {
    // build the optional VARIANT 
    // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-oaut/e93f90dc-8afb-434f-afa9-94f8564fe19b
    VARIANT optional;
    VariantInit(&optional);
    V_VT(&optional) = VT_ERROR;
    V_I4(&optional) = DISP_E_PARAMNOTFOUND;

    IShellWindows* windows;
    if (SUCCEEDED(CoCreateInstance(CLSID_ShellWindows, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&windows))))
    {
      long count;
      windows->get_Count(&count);
      for (auto i = 0; i < count; i++)
      {
        VARIANT index;
        VariantInit(&index);
        V_VT(&index) = VT_I4;
        V_I4(&index) = i;

        IDispatch* obj;
        if (SUCCEEDED(windows->Item(index, &obj)))
        {
          IWebBrowser2* app;
          if (SUCCEEDED(obj->QueryInterface(IID_PPV_ARGS(&app))))
          {
            // get a PIDL from a path
            // note pidl could represent a virtual folder too
            auto pidl = ILCreateFromPath(L"c:\\temp");
            if (pidl)
            {
              // build a VARIANT from the PIDL
              VARIANT url;
              VariantInit(&url);
              if (SUCCEEDED(InitVariantFromBuffer(pidl, ILGetSize(pidl), &url))) // propvarutil.h
              {
                app->Navigate2(&url, &optional, &optional, &optional, &optional);
              }
              VariantClear(&url);
              ILFree(pidl);
            }
            app->Release();
          }
          obj->Release();
        }
        VariantClear(&index);
      }
      windows->Release();
    }
  }
  CoUninitialize();
  return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.