2015-07-14 5 views
7

Sto tentando di utilizzare Shell32 per ottenere proprietà di file estese in C#.Eccezione quando si utilizza Shell32 per ottenere proprietà estese di file

Il mio codice per questo è il seguente.

 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); 
     } 

Ottengo eccezione come segue. enter image description here

Messaggio: impossibile eseguire il cast dell'oggetto COM di tipo "Shell32.ShellClass" sul tipo di interfaccia "Shell32.IShellDispatch6". Questa operazione non è riuscita perché la chiamata QueryInterface sul componente COM per l'interfaccia con IID '{286E6F1B-7113-4355-9562-96B7E9D64C54}' non è riuscita a causa del seguente errore: Nessuna interfaccia supportata (Eccezione da HRESULT: 0x80004002 (E_NOINTERFACE)) .

Stack Trace - a System.StubHelpers.StubHelpers.GetCOMIPFromRCW (Object objSrc, IntPtr pCPCMD, IntPtr & ppTarget, booleano & pfNeedsRelease) a Shell32.ShellClass.NameSpace (Object vdir) a PBSWebApplication.Test.Button1_OnClick (Object mittente, EventArgs e) in c: \ Projects \ PBSWebApplication \ PBSWebApplication \ PBSWebApplication \ Test.aspx.cs: riga 33 su System.Web.UI.WebControls.Button.OnClick (EventArgs e) su System.Web.UI. WebControls.Button.RaisePostBackEvent (String eventArgument) su System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent (String eventArgument) su System.Web.UI.Page.RaisePostBa ckEvent (IPostBackEventHandler SourceControl, String eventArgument) a System.Web.UI.Page.RaisePostBackEvent (NameValueCollection postData) a System.Web.UI.Page.ProcessRequestMain (booleano includeStagesBeforeAsyncPoint, booleano includeStagesAfterAsyncPoint)

Come risolvere questo problema?

Grazie.

risposta

7

Come è stato identificato, perché Shell32 richiede un thread STA. Se non è possibile configurare semplicemente l'app da eseguire con un thread STA come nella soluzione, in alternativa è possibile creare un thread STA separato, utilizzarlo per eseguire il codice Shell32, quindi continuare l'esecuzione. per esempio. this è quello che ho finito con la scrittura di una Script Task SSIS che, a quanto ho capito, funziona sempre sul thread MTA. Nel mio caso sto chiamando un metodo diverso di Shell32 (CopyHere), ma stessa logica sarebbe applicabile indipendentemente dal metodo che si desidera chiamare:

/// <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); 
     } 
    } 
+0

ciò che è buono cattura e buona soluzione anche! –

1

Si è rivelata una soluzione semplice per aggiungere l'attributo STAThread alla mia classe e il problema è scomparso magicamente.

Ecco il mio codice completo dopo l'aggiornamento.

Nota: è un'applicazione console semplice.

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)); 
      } 
     } 
} 
1

ho avuto problema simliar e la risposta da jeronevw su questo forum fisso per 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 }); 
} 

Tutti i crediti per jeronevw

+0

È necessario passare il percorso della cartella come argomento a questa funzione? –

Problemi correlati