Exception lors de l’utilisation de Shell32 pour obtenir les propriétés étendues du fichier

J’essaie d’utiliser Shell32 pour obtenir des propriétés de fichier étendues en c #.

Mon code pour cela est comme suit.

var file = FileUpload1.PostedFile; List arrHeaders = new List(); 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); } 

Je reçois une exception comme suit. entrez la description de l'image ici

Message – Impossible de convertir l’object COM du type “Shell32.ShellClass” en type d’interface “Shell32.IShellDispatch6”. Cette opération a échoué car l’appel QueryInterface sur le composant COM de l’interface avec l’IID ‘{286E6F1B-7113-4355-9562-96B7E9D64C54}’ a échoué en raison de l’erreur suivante: Aucune interface de ce type n’a été prise en charge (exception de HRESULT: 0x80004002 (E_NOIN)). .

Stack Trace – at System.StubHelpers.StubHelpers.GetCOMIPFromRCW (Objet objSr, IntPtr pCPCMD, IntPtr & Boolean & pfNeedsRelease) \ Projects \ PBSWebApplication \ PBSWebApplication \ PBSWebApplication \ Test.aspx.cs: ligne 33 à System.Web.UI.WebControls.Button.OnClick (EventArgs e) à System.Web.UI.WebControls.Button.RoutePostBackEvent (Ssortingng eventArgument) à System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent (Ssortingng eventArgument) sur System.Web.UI.Page.RaisePostBackEvent (IPostBackEventHandler sourceControl, à la suite) (NameValueCollection postData) sur System.Web.UI.Page.ProcessRequestMain (Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

Comment régler ceci?

Merci.

Comme vous l’avez identifié, c’est parce que Shell32 requirejs un thread STA. Si vous ne pouvez pas simplement configurer votre application pour qu’elle s’exécute avec un thread STA comme dans votre solution, vous pouvez également créer un thread STA distinct, utilisez-le pour exécuter le code Shell32, puis poursuivez l’exécution. Par exemple, c’est ce à quoi j’ai abouti lors de l’écriture d’une tâche de script SSIS qui, si j’ai bien compris, est toujours exécutée sur le thread MTA. Dans mon cas, j’appelle une méthode différente de Shell32 (CopyHere), mais la même logique s’appliquerait à la méthode que vous souhaitez appeler:

  ///  /// 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. ///  /// File to unzip /// Folder to put the unzipped files public static void UnZipFromMTAThread(ssortingng zipFile, ssortingng 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(); } } ///  /// From http://www.streambytes.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(). ///  /// object array containing: [ssortingng zipFile, ssortingng destinationFolderPath] private static void UnZip(object param) { object[] args = (object[]) param; ssortingng zipFile = (ssortingng)args[0]; ssortingng folderPath = (ssortingng)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); } } 

J’ai eu un problème similaire et la réponse de jeronevw sur ce forum l’a corrigé pour moi: 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 }); } 

Tous les crédits pour jeronevw

Il s’est avéré être une solution simple d’append l’atsortingbut STAThread à ma classe et le problème a disparu comme par magie.

Voici mon code complet après la mise à jour.

Note: C’est une application console simple.

 class Program { [STAThread] static void Main(ssortingng[] args) { Console.Title = "Extended file properties."; List arrHeaders = new List(); 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)); } } }