Exception when using Shell32 to get advanced file properties

I am trying to use Shell32 to get advanced file properties in C #.

My code for this is as follows.

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 get the exception as follows. enter image description here

Message. Unable to pass a COM object of type "Shell32.ShellClass" to the interface type "Shell32.IShellDispatch6". This operation failed because the call to QueryInterface for the COM component for the IID interface '{286E6F1B-7113-4355-9562-96B7E9D64C54} failed due to the following error: this interface is not supported (exception from HRESULT: 0x80004002 (E_NOINTERFACE) )

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

How to fix it?

Thanks.

+14
source share
3 answers

As you have determined, this is because Shell32 requires an STA stream. If you cannot just configure the application to run using STA Thread, as in your solution, then as an alternative, you can create a separate STA thread, use it to run Shell32 code, and then continue execution. for example, this is what I encountered when writing the SSIS Script task, which, as I understand it, always works in the MTA stream. In my case, I call another Shell32 method (CopyHere), but the same logic applies to any 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 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 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); } } 
+17
source share

It turned out to be a simple solution to add the STAThread attribute to my class, and the problem magically disappeared.

Here is my full code after update.

Note. This is a simple console application.

 class Program { [STAThread] static void Main(string[] args) { Console.Title = "Extended file properties."; List<string> arrHeaders = new List<string>(); Shell32.Shell shell = new Shell32.Shell(); Shell32.Folder objFolder; objFolder = shell.NameSpace(@"C:\Users\Admin\Pictures\PBS Docs"); for (int i = 0; i < short.MaxValue; i++) { string header = objFolder.GetDetailsOf(null, i); if (String.IsNullOrEmpty(header)) break; arrHeaders.Add(header); } foreach (Shell32.FolderItem2 item in objFolder.Items()) { for (int i = 0; i < arrHeaders.Count; i++) { Console.WriteLine("{0}\t{1}: {2}", i, arrHeaders[i], objFolder.GetDetailsOf(item, i)); } } } } 
+5
source share

I had a simliar problem and the answer from jeronevw on this forum fixed this for me: https://social.msdn.microsoft.com/Forums/vstudio/en-US/b25e2b8f-141a-4a1c-a73c-1cb92f953b2b/instantiate- shell32shell-object-in-windows-8? forum = clr

 public Shell32.Folder GetShell32NameSpaceFolder(Object folder) { Type shellAppType = Type.GetTypeFromProgID("Shell.Application"); Object shell = Activator.CreateInstance(shellAppType); return (Shell32.Folder)shellAppType.InvokeMember("NameSpace", System.Reflection.BindingFlags.InvokeMethod, null, shell, new object[] { folder }); } 

All loans for jeronevw

+5
source share

All Articles