在IShellFolder :: EnumObjects()中使用IShellBrowser :: BrowseObject()

时间:2018-06-21 10:05:02

标签: c++ multithreading winapi shell-extensions

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

当资源管理器想要显示文件夹的内容时,它将在我的实现中调用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);
}

有时,由于无效访问异常(x0000005),对BrowseObject的方法调用失败。

我们还使用了将使用以下变体的变体:

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_site时是NULL

EnumObject是在与浏览器不同的线程中调用的,当我进行网络通话时,UI不会冻结。我假设我可能不会从枚举该文件夹的线程中调用“浏览对象”,但是如何在正确的线程上调用“浏览”?

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

1 个答案:

答案 0 :(得分:2)

似乎您没有正确地添加对所用COM接口的引用,这可能会导致它实际上被销毁。因此,要么使用CComPtr,要么至少调用AddRef / Release来持有对该对象的有效引用。

如果使用了多个线程,您是否要从所有线程中调用CoInitialize