【问题标题】:Using IShellBrowser::BrowseObject() in IShellFolder::EnumObjects()在 IShellFolder::EnumObjects() 中使用 IShellBrowser::BrowseObject()
【发布时间】:2018-06-21 10:05:01
【问题描述】:

我有一个命名空间扩展,可以通过网络调用来显示其内容。

当资源管理器想要显示文件夹的内容时,它在我的实现中调用EnumObjects。当网络通话出错时,我想将用户返回到我的 NSE 的根目录。目前我调用以下代码:

LPITEMIDLIST pidl = /*The piddle to navigate to, in my case root*/;

IShellBrowser* browser = (IShellBrowser*)SendMessage(m_hWnd, (WM_USER + 7), 0, 0);
if (browser != NULL) {

    hr = browser->BrowseObject(pidl, SBSP_SAMEBROWSER | SBSP_ABSOLUTE);
}

有时对BrowseObject 的方法调用会失败,并出现无效访问异常 (x0000005)。

我们还使用了一个变体,该变体将使用以下变体:

hr = GetSite(IID_IServiceProvider, (void**)&serviceProvider);
if (FAILED(hr))
    return false;

IShellBrowser *browser;
hr = serviceProvider->QueryService(SID_SShellBrowser, &browser);
if(FAILED(hr))
    return false;

通过接口IObjectWithSite获取站点。这也随机失败。我注意到当网络通话失败时m_siteNULL

EnumObject 在资源管理器的单独线程中调用,当我进行网络通话时 UI 不会冻结。我假设我可能不会从枚举文件夹的线程中调用 Browse 对象,但是如何在正确的线程上调用 browse?

在新线程中调用BrowseObject 并等待1 秒不会导致崩溃。但我不会认为这种 hack 是一个有效的解决方案。

【问题讨论】:

  • 枚举完成后,您将在“主”线程中收到 SFVM_BACKGROUNDENUM。所以我的提议:当您创建 IEmumIDList 对象时,将指针传递给 bool var。如果枚举失败,则在 IEmumIDList 内部设置 bool 值。当您收到 SFVM_BACKGROUNDENUM 时,请检查此布尔值,如果为真 - 调用 BrowseObject。但理论上,您的 IShellFolder 对象可以在 IEmumIDList 对象尝试设置值之前被释放。所以最好传递接口对象而不是指向 bool 的指针。
  • 请不要使用sendmessage,它会让你与其他NSE主机不兼容。
  • @Anders 没人在谈论 SendMessage
  • @DenisAnisimov 除了 OPs 第一个代码块。
  • @Anders 哦,我的错,你是对的。我以为你写了我的建议。

标签: c++ multithreading winapi shell-extensions


【解决方案1】:

您似乎没有正确添加对您正在使用的 COM 接口的引用,这可能会导致它实际上被破坏。所以要么使用CComPtr,要么至少调用AddRef/Release 来保存对该对象的有效引用。

另外,如果使用多个线程,你是从所有线程中调用CoInitialize 吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多