【发布时间】:2012-04-11 12:03:37
【问题描述】:
在 .NET 4.0 应用程序 (WPF) 中,我们使用 SHGetFileInfo 获取目录树的外壳图标。由于在某些情况下这需要相当长的时间(即对于无法访问的网络驱动器或软盘驱动器),我们希望在线程中执行此操作,然后在读入图标时更新它。
调用基本相同,现在只是在一个线程中执行。因为有人说线程必须是STA才能工作,所以我们使用Thread而不是ThreadPool进行测试,结果相同。使用ThreadPool 也不起作用。
SHGetFileInfo 成功(返回 1),但结构中的 hIcon 成员为零。
IntPtr GetIcon(string name)
{
Shell32.SHFILEINFO shfi = new Shell32.SHFILEINFO();
uint flags = Shell32.SHGFI_ICON | Shell32.SHGFI_USEFILEATTRIBUTES | Shell32.SHGFI_SMALLICON;
Shell32.SHGetFileInfo(
name, System.IO.Directory.Exists(name) ? Shell32.FILE_ATTRIBUTE_DIRECTORY : Shell32.FILE_ATTRIBUTE_NORMAL,
ref shfi,
(uint) System.Runtime.InteropServices.Marshal.SizeOf(shfi),
flags );
return shfi.hIcon;
}
同样的代码在 GUI 线程中运行良好。必须做些什么才能使函数在单独的线程中工作,或者在不阻塞 GUI 线程的情况下使其工作?
更新:围绕这个的代码基本上是这样的:
var thread = new System.Threading.Thread(() => {
var result = GetIcon("C:\\");
// ... do something with the result
});
thread.SetApartmentState(System.Threading.ApartmentState.STA);
thread.Start();
如果只保留线程委托中的行,它可以正常工作(当然是在 GUI 线程上)。
更新:目前,我们只需调用SHGetFileInfo 即可使其工作。这样做的好处是解决了最初的问题(在加载所有图标之前,不会显示带有文件视图的页面),尽管这意味着页面对于每个图标都挂起。但至少用户现在可以看到正在发生的事情。我们仍在寻找该问题的实际解决方案。
【问题讨论】:
-
没有足够的代码。你真的调用过 Thread.SetApartmentState 吗?
-
是的。我刚刚发布了对 SHGetFileInfo 的实际调用。代码作为其委托从线程调用,然后设置单元状态(或不设置,没有任何区别),然后启动线程。
-
@OregonGhost 你最后有没有找到更好的解决方案?
标签: windows multithreading .net-4.0 shell32