本文介绍了使用Shell32获取文件扩展属性时发生异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Shell32在c#中获取扩展文件属性。

I am trying to use Shell32 to get extended file properties in c#.

我的代码如下。

        var file = FileUpload1.PostedFile;

        List<string> arrHeaders = new List<string>();

        Shell shell = new ShellClass();

        //Exception is thrown at next line
        Folder rFolder = shell.NameSpace(Path.GetDirectoryName(file.FileName));
        FolderItem rFiles = rFolder.ParseName(Path.GetFileName(file.FileName));

        for (int i = 0; i < short.MaxValue; i++)
        {
            string value = rFolder.GetDetailsOf(rFiles, i).Trim();
            arrHeaders.Add(value);
        }

我遇到了如下异常。

I am getting exception as follows.

消息-无法将类型为 Shell32.ShellClass的COM对象转换为接口类型为 Shell32.IShellDispatch6。该操作失败,因为具有以下错误的IID为'{286E6F1B-7113-4355-9562-96B7E9D64C54}'的COM组件上的QueryInterface调用由于以下错误而失败:不支持此类接口(HRESULT的异常:0x80004002(E_NOINTERFACE))

Message - Unable to cast COM object of type 'Shell32.ShellClass' to interface type 'Shell32.IShellDispatch6'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{286E6F1B-7113-4355-9562-96B7E9D64C54}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).

堆栈跟踪-位于System.StubHelpers.StubHelpers.GetCOMIPFromRCW(Object objSrc,IntPtr pCPCMD,IntPtr& ppTarget,Boolean& pfNeedsRelease)
在Shell32.ShellClass .c:\ProjectsDPBSWebApplication\PBSWebApplication\PBSWebApplication\Test.aspx.cs:line 33 $ b上PBSWebApplication.Test.Button1_OnClick(Object sender,EventArgs e)的.NameSpace(Object vDir)
$ b在System.Web.UI.WebControls.Button.OnClick(EventArgs e)
在System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument)
在System.Web.UI.WebControls .Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument)
位于System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler源控件,字符串eventArgument)System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData)的
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint,Boolean includeStagesAfterAsyncPoint)的

Stack Trace - at System.StubHelpers.StubHelpers.GetCOMIPFromRCW(Object objSrc, IntPtr pCPCMD, IntPtr& ppTarget, Boolean& pfNeedsRelease) at Shell32.ShellClass.NameSpace(Object vDir) at PBSWebApplication.Test.Button1_OnClick(Object sender, EventArgs e) in c:\Projects\PBSWebApplication\PBSWebApplication\PBSWebApplication\Test.aspx.cs:line 33 at System.Web.UI.WebControls.Button.OnClick(EventArgs e) at System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) at System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) at System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) at System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

如何解决此问题?

谢谢。

推荐答案

您已确定这是因为Shell32需要STA线程。如果您不能像解决方案中那样简单地将应用程序配置为与STA线程一起运行,那么作为替代方案,您可以创建一个单独的STA线程,使用它来运行Shell32代码,然后继续执行。例如是我编写SSIS脚本任务时最终得到的结果,据我了解,该任务始终在MTA线程上运行。就我而言,我正在调用Shell32(CopyHere)的另一种方法,但是无论您要调用哪种方法,都将应用相同的逻辑:

As you identified this is because Shell32 requires an STA thread. If you can't simply configure your app to run with an STA Thread as in your solution then as an alternative you can create a separate STA Thread, use it to run the Shell32 code, then continue execution. e.g. this is what I ended up with when writing an SSIS Script Task which as I understand it always runs on MTA thread. In my case I'm calling a different method of Shell32 (CopyHere) but same logic would apply whichever method you want to call:

    /// <summary>
    /// Ugh! SSIS runs script tasks on MTA threads but Shell32 only wants to 
    /// run on STA thread. So start a new STA thread to call UnZip, block 
    /// till it's done, then return. 
    /// We use Shell32 since .net 2 doesn't have ZipFile and we prefer not to 
    /// ship other dlls as they normally need to be deployed to the GAC. So this 
    /// is easiest, although not very pretty.
    /// </summary>
    /// <param name="zipFile">File to unzip</param>
    /// <param name="folderPath">Folder to put the unzipped files</param>
    public static void UnZipFromMTAThread(string zipFile, string folderPath)
    {
        object[] args = new object[] { zipFile, folderPath };
        if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
        {
            UnZip(args);
        }
        else
        {
            Thread staThread = new Thread(new ParameterizedThreadStart(UnZip));
            staThread.SetApartmentState(ApartmentState.STA);
            staThread.Start(args);
            staThread.Join();
        }
    }

    /// <summary>
    /// From http://www.fluxbytes.com/csharp/unzipping-files-using-shell32-in-c/ but with 
    /// args packed in object array so can be called from new STA Thread in UnZipFromMTAThread().
    /// </summary>
    /// <param name="param">object array containing: [string zipFile, string destinationFolderPath]</param>
    private static void UnZip(object param)
    {
        object[] args = (object[]) param;
        string zipFile = (string)args[0];
        string folderPath = (string)args[1];


        if (!File.Exists(zipFile))
            throw new FileNotFoundException();

        if (!Directory.Exists(folderPath))
            Directory.CreateDirectory(folderPath);

        Shell32.Shell objShell = new Shell32.Shell();
        Shell32.Folder destinationFolder = objShell.NameSpace(folderPath);
        Shell32.Folder sourceFile = objShell.NameSpace(zipFile);

        foreach (var file in sourceFile.Items())
        {
            // Flags are: No progress displayed, Respond with 'Yes to All' for any dialog, no UI on error
            // I added 1024 although not sure it's relevant with Zip files. 
            // See https://msdn.microsoft.com/en-us/library/windows/desktop/bb787866%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
            destinationFolder.CopyHere(file, 4 | 16 | 1024); 
        }
    }

这篇关于使用Shell32获取文件扩展属性时发生异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-27 09:08