3

I was trying to get the metadata from a file using Shell. I am using MVC5 and Windows 8 OS. Here is the below code.

Code

public JsonResult Ind(string file)
{
    List<string> arrHeaders = new List<string>();
    string filename = Path.GetFileName(file);
    Shell shell = new ShellClass();
    Folder rFolder = shell.NameSpace(file);
    FolderItem rFiles = rFolder.ParseName(filename);
    for (int i = 0; i < short.MaxValue; i++)
    {
         string value = rFolder.GetDetailsOf(rFiles, i).Trim();
         arrHeaders.Add(value);
    }
    return Json(arrHeaders, JsonRequestBehavior.AllowGet);
 }

When I try to run the above code, I am getting error 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)).

Is there any other better solution to read metadata from different file formats?? Pls suggest me anything. I ll appreciate you.

Thanks

DonMax
  • 970
  • 3
  • 12
  • 47
  • The context of this code isn't visible in the question. But high odds that it runs on a worker thread in the MTA, given the error. There is no proxy for IShellDispatch6, an STA thread is required. – Hans Passant Nov 03 '14 at 18:32

1 Answers1

8

Seems that problem is in strict reference to specific version of Shell32 object(s) on build system which is differs from target system.

Here is how your reference looks like in project file (C# project in given case):

 <COMReference Include="Shell32">
  <Guid>{50A7E9B0-70EF-11D1-B75A-00A0C90564FE}</Guid>
  <VersionMajor>1</VersionMajor>
  <VersionMinor>0</VersionMinor>
  <Lcid>0</Lcid>
  <WrapperTool>tlbimp</WrapperTool>
  <Isolated>False</Isolated>
</COMReference>

So after referencing you're using specific version of Shell (ShellClass), which implements

[Guid("D8F015C0-C278-11CE-A49E-444553540000")]
[TypeLibType(4176)]
public interface IShellDispatch

To prevent this on different platforms it is better to create needed objects by name using reflection, rather than referencing specific types with specific versions\libraries. Instead of this code:

Shell shell = new ShellClass();
Folder rFolder = shell.NameSpace(file);

You can create Folder object this way:

    private static Folder GetShell32NameSpaceFolder(Object folder)
    {
        var shellAppType = Type.GetTypeFromProgID("Shell.Application");

        var shell = Activator.CreateInstance(shellAppType);
        return (Folder)shellAppType.InvokeMember("NameSpace",
        System.Reflection.BindingFlags.InvokeMethod, null, shell, new [] { folder });
    }

Also note that method shell.NameSpace(...) parameter is "The folder for which to create the Folder object. This can be a string that specifies the path of the folder or one of the ShellSpecialFolderConstants values." (MSDN), so you should pass not file path, but directory path of the desired file by, for example, Path.GetDirectoryName(file).

So your code should work this way:

    public JsonResult Ind(string file)
    {
        List<string> arrHeaders = new List<string>();
        string filename = Path.GetFileName(file);
        Folder rFolder = GetShell32NameSpaceFolder(Path.GetDirectoryName(file));
        FolderItem rFiles = rFolder.ParseName(filename);
        for (int i = 0; i < short.MaxValue; i++)
        {
             string value = rFolder.GetDetailsOf(rFiles, i).Trim();
             arrHeaders.Add(value);
        }
        return Json(arrHeaders, JsonRequestBehavior.AllowGet);
    }

    private static Folder GetShell32NameSpaceFolder(Object folder)
    {
        var shellAppType = Type.GetTypeFromProgID("Shell.Application");

        var shell = Activator.CreateInstance(shellAppType);
        return (Folder)shellAppType.InvokeMember("NameSpace",
        System.Reflection.BindingFlags.InvokeMethod, null, shell, new [] { folder });
    }
liferunner
  • 96
  • 3
  • @liferunner_: As I try to get metadata for .xlsx and .docx. but didnt get the metadata information for those files. Can you tell me why?? – DonMax Dec 15 '14 at 09:30
  • FYI there is another similar solution for this same problem here that might be helpful: https://stackoverflow.com/questions/12075188/reference-a-windows-shell-interface-using-net-4-0 – blitz_jones Jul 07 '16 at 16:22