枚举设备的 shell

Enumerating the shell for devices

有两种实用的方法可以从 C# 访问 Shell 命名空间,MS WindowsApiCodePack 桥接 IShellFolder 和相关内容(在 NuGet 上可用),或引用 Shell32(Microsoft Shell 控制和自动化)直接。这两种方法基本相似,尽管第一种方法具有更多功能(我最感兴趣的是支持图像缩略图和更好的文件复制功能)。

枚举 This PC 文件夹的方法如下:

string ThisPC = "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}";
var folder = ShellFolder.FromParsingName(ThisPC) as ShellFolder;
foreach (var child in folder)

var shellAppType = Type.GetTypeFromProgID("Shell.Application");
object shell = Activator.CreateInstance(shellAppType);
var ThisPC = (Folder)shellAppType.InvokeMember("NameSpace", BindingFlags.InvokeMethod, null, shell, new object[] { 0x11 });
foreach (FolderItem child in ThisPC.Items())

但两者之间有一个非常重要的区别:第二个枚举设备,如连接的电话,而第一个不枚举。我利用 Api 代码包是开源的这一事实,并修改了 ShellFolderItems 构造函数(这是 ShellFolder 迭代的内容)以尝试

HResult hr = nativeShellFolder.NativeShellFolder.EnumObjects(
  IntPtr.Zero,
  //ShellNativeMethods.ShellFolderEnumerationOptions.IncludeHidden | ShellNativeMethods.ShellFolderEnumerationOptions.IncludeSuperHidden |
  //ShellNativeMethods.ShellFolderEnumerationOptions.Shareable |
  ShellNativeMethods.ShellFolderEnumerationOptions.Folders | ShellNativeMethods.ShellFolderEnumerationOptions.NonFolders | ShellNativeMethods.ShellFolderEnumerationOptions.Storage,
  out nativeEnumIdList);

代码最初针对文件夹和非文件夹过滤,但这首先排除了电话。所以我加了Storage,隐藏的东西,所有我能想到的组合,但一点区别都没有。某些过滤器组合会删除已枚举的项目,但 none 会将其增加到设备。

我该怎么做才能使第一种方法像第二种方法一样枚举?

更新:为了更容易重现,这里是整个程序,真的没有比上面描述的多多少:

using System;
using System.Reflection;
using Microsoft.WindowsAPICodePack.Shell;
using Shell32;

namespace ConsoleApp1 {
  class Program {

    private static void ShellObjects1() {
      string ThisPC = "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}";
      var folder = ShellFolder.FromParsingName(ThisPC) as ShellFolder;
      foreach (var child in folder)
        Console.WriteLine($"{child.Name} = {child.ParsingName}");
    }

    private static void ShellObjects2() {
      var shellAppType = Type.GetTypeFromProgID("Shell.Application");
      object shell = Activator.CreateInstance(shellAppType);
      var ThisPC = (Folder)shellAppType.InvokeMember("NameSpace", BindingFlags.InvokeMethod, null, shell, new object[] { 0x11 });
      foreach (FolderItem child in ThisPC.Items())
        Console.WriteLine($"{child.Name} = {child.Path}");
    }

    static void Main(string[] args) {
      Console.WriteLine("WindowsAPICodePack");
      ShellObjects1();
      Console.WriteLine();

      Console.WriteLine("Shell32");
      ShellObjects2();
      Console.WriteLine();
    }

  }
}

您应该从 COM 项目中添加对 Microsoft Shell 的引用,并安装 Microsoft.WindowsAPICodePack-Shell NuGet 包来编译它。正如我 运行 这个,这两个列表将几乎相同。就像在资源管理器 window 中一样,首先是文件夹,然后是驱动器。但是在第二个列表中会有一个额外的条目:一个设备。就像在资源管理器中一样。第一个列表中缺少该项目。

哦,天哪,天哪,老旧的 STAThread 不见了。有点误导,因为它的大部分都在工作,所以它可能是评论末尾提到的 IDelegateFolder 使单个界面错过了节拍。

[STAThread]
static void Main(string[] args) {