P/Invoke with Shell32, bypass Interop.Shell32.dll

2020-07-23 04:09发布

So I'm using the following code to dump every extended file attribute to the debug console...

ShellClass shellClass = new ShellClass();
Folder dir = shellClass.NameSpace(Path.GetDirectoryName(sFilePath));
FolderItem item = dir.ParseName(Path.GetFileName(sFilePath));
for (int i = 0; i < 267; i++)
{
   System.Debug.WriteLine(dir.GetDetailsOf(item, i));
}

As Shell32 is a non-managed library, I can't embed the DLL resource in the program directly, and it has to generate an interop helper DLL.

Anyone know of the DLLImport command lines for these functions in Shell32 to get around the whole generation of the interop DLL? I've checked pinvoke.net and under the Shell32 entry they either don't have what I'm looking for, or it's not named what I'm expecting.

If it's not possible to use a DLLImport to accomplish this, does anyone know of a way to pull all of the extended attributes about a file using a managed DLL, or at least a way to do it where I don't have to generate a helper DLL and require an installer with an application I'm developing?

Thanks a bunch!

2条回答
家丑人穷心不美
2楼-- · 2020-07-23 05:03

Most of the Windows Shell API features have P/Invoke entry points that return COM interfaces, so you should rarely need to explicitly create a ShellClass CoClass instance. (The objects you are using, Folder and FolderItem, are mostly meant for use by late-bound clients such as script languages; with C# you can do much better.)

To avoid having to generate the interop assembly, you just need to declare the appropriate types in your C# code that match the P/Invoke functions and COM interfaces that the shell already implements. In your case, what you're looking for is the IShellFolder2 interface (which is essentially identical to the Folder object).

Typically, to do what you're asking, you would:

  1. Call SHGetDesktopFolder to return an IShellFolder interface pointing to the desktop folder.
  2. Call IShellFolder::ParseDisplayName on the folder you want, which gives you a "pointer to an Identifier list" (a PIDL) representing that folder's internal shell identifier.
  3. Cast your IShellFolder to an IShellFolder2 (using as, like any other interfaces).
  4. Call IShellFolder2::GetDetailsOf(), passing the PIDL from step 2 and the column you want.

You will need to translate the two COM interfaces, plus one structure and one P/Invoke function, and put the C# code in your project. You can get away with IntPtr for a lot of this (like the PIDL) since you only need to pass them around between COM methods. (The MSDN articles will tell you that you are responsible for freeing memory after you are done; the CLR's interop code will take care of that stuff for you in almost all cases.)

pinvoke.net will help you out here, as will this fascinatingly well written series of blog posts on doing COM interop translations from the MSDN articles.

查看更多
Ridiculous、
3楼-- · 2020-07-23 05:12

In my experience, the most effective way to use the shell API from managed code is to use the Windows API Code Pack. This wraps up all the useful parts of the shell API and makes it trivially accessible from managed code. The download includes lots of examples to get you on the way.

查看更多
登录 后发表回答