【发布时间】: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_site 是NULL。
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