SHGetFileInfo没有返回图标

时间:2017-06-29 11:30:57

标签: multithreading winforms winapi

我正在使用SHGetFileInfo函数来获取文件夹和不同文件类型的图标。根据{{​​3}}调用此函数应该从后台线程完成,并且在调用组件对象模型(COM)之前必须使用CoInitialize或OleInitialize初始化。 我的代码如下所示:

    public void SetHlinkImage(string path)
    {
        Shell32.OleInitialize(IntPtr.Zero);
        Task task = Task.Factory.StartNew(() => { LoadIcons(path); });
    }

    private void LoadIcons(string path)
    {
        image = GetHlinkImage(path);

        if (OwnerControl.InvokeRequired)
            layout.ModuleControl.BeginInvoke((MethodInvoker)delegate ()
            {
                Shell32.OleUninitialize();
            });
    }

    public Icon GetHlinkImage(string path)
    {
        uint flags = Shell32.SHGFI_ICON | Shell32.SHGFI_ATTRIBUTES | Shell32.SHGFI_SMALLICON;

        Shell32.SHFILEINFO shfi = new Shell32.SHFILEINFO();

        IntPtr result = Shell32.SHGetFileInfo(path,
                            Shell32.FILE_ATTRIBUTE_DIRECTORY,
                            ref shfi,
                            (uint)Marshal.SizeOf(shfi),
                            flags);

        Icon icon = (Icon)Icon.FromHandle(shfi.hIcon).Clone();
        WinApi.DestroyIcon(shfi.hIcon);     // cleanup

        return icon;
    }

大多数问题出现在第一次调用代码之后,因此当我尝试从图标句柄创建Icon时出现异常:

  

System.ArgumentException:传递给Icon的Win32句柄不是   有效或类型错误

进一步调用代码工作没有问题。 实际上行为也在某种程度上取决于测试系统。几乎不可能在Windows10系统上重现这个问题,但在Windows 7上它经常发生。

有没有人遇到过这个问题?

1 个答案:

答案 0 :(得分:1)

来自Hans Passant的评论:

调用OleInitialize()是没有意义的,CLR在启动线程之前已经初始化了COM。它失败了,你无法看到的东西,因为你没有检查它的返回值。不知道这一点,它只是从那里陷入无法估量的苦难。是的,在Win7上更多。您必须提供STA线程,如果需要在后台运行,请考虑this solution