Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception when using Shell32 to get File extended properties

Tags:

c#

.net

asp.net

I am trying to use Shell32 to get extended 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 am getting exception as follows. enter image description here

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)).

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)

How to fix this?

Thanks.

like image 984
Nikhil Chavan Avatar asked Jul 14 '15 10:07

Nikhil Chavan


People also ask

Is it possible to retrieve extended file properties using getdetailsof?

Not open for further replies. Recently, this thread 'Windows 10 Retrieving Extended File Properties' raised issues about using the GetDetailsOf method to retrieve extended file properties (attributes). GetDetailsOf is a member of the VBA library ' Microsoft Shell Controls and Automation ' based on Shell32.dll.

Why can't I edit extended file properties?

Every file type has specific extended file properties and not all of them are writable. If you right-click a file on desktop and cannot edit a property, you wont be able to edit it in code too. Example: Create txt file on desktop, rename its extension to docx. You can't edit its Author or Title property.

How to get the value of a DLL file's extended properties?

If you open properties of an exe (or dll) file in Windows Explorer, you get a Version tab, and a view of Extended Properties of that file. I wanted to access one of those values. The solution to this is the property indexer FolderItem.ExtendedProperty and if you drop all spaces in the property's name, you'll get the value.

What is the use of shell application property?

Shell.Application property - Contains the object's Application object. Represents an item in a Shell folder. This object contains properties and methods that allow you to retrieve information about the item. Retrieves details about an item in a folder. For example, its size, type, or the time of its last modification.


2 Answers

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);          }     } 
like image 124
Rory Avatar answered Oct 17 '22 02:10

Rory


I had simliar issue and the answer from jeronevw on this forum fixed it 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 credits for jeronevw

like image 23
Maarten Kieft Avatar answered Oct 17 '22 03:10

Maarten Kieft