【问题标题】:Enumerating the shell for devices枚举设备的外壳
【发布时间】:2017-12-08 00:10:48
【问题描述】:

有两种实用的方法可以从 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 Code Pack 是开源的事实并修改了 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,隐藏的东西,所有我能想到的组合,但完全没有区别。某些过滤器组合会删除已枚举的项目,但不会将其增加到设备。

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

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

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 包来编译它。当我运行它时,这两个列表几乎是相同的。就像在资源管理器窗口中一样,首先是文件夹,然后是驱动器。但在第二个列表中,中间会有一个额外的条目:一个设备。就像在资源管理器中一样。第一个列表中缺少该项目。

【问题讨论】:

  • 您是否尝试过使用相同的位数(32 对 64)?另外你为什么要通过 ShellNativeMethods.ShellFolderEnumerationOptions.Storage?这会过滤带有 SFGAO_STORAGE 标志 (msdn.microsoft.com/en-us/library/windows/desktop/bb762589.aspx) 的项目。所有项目都没有那个标志。文件夹和非文件夹确实是默认过滤器。
  • 我使用了 AnyCPU。因为,正如我所提到的,我尝试了所有组合。 MS 源最初只指定了 Folders 和 NonFolders,因为它一开始没有枚举手机,所以我也开始尝试其他标志。没有任何组合可以提供我可以从 Shell32 调用中看到的结果。
  • 这是非常出乎意料的。 IShellFolder::EnumObjects 方法是所有枚举之母。没有别的办法。如果我写一个 shell 文件夹命名空间扩展,它将在这个界面上被 exclusively 调用。你能提供一些代码或步骤来帮助重现吗?我无法复制。
  • 我可以复制整个程序,但实际上并没有比上面的多多少。一个简单的控制台应用程序,使用这两个枚举,foreach 都简单地打印每个项目的名称和解析名称。两个打印输出会有所不同:第一个不会报告设备,而第二个会。尝试了几台不同的机器,W10 Creator,64 位,各种手机。实际上,我从来没有见过我生活中列举的设备(除了 Win 本身在它的资源管理器中,当然,我是指以编程方式)。使用 Shell32 是我第一次看到它们出现。
  • 好消息是:我可以重现,而且只有 APIPack 可以做到这一点。如果我使用 C++ IEnumShellItems 或 IShellFolder::EnumObjects,它会返回正常的电话。坏消息是:到目前为止我还不明白 APIPack 为什么会这样做。一切似乎都声明正确,实际上与我在 C++ 中所做的完全一样......我会尝试进一步挖掘......

标签: c# shell com


【解决方案1】:

哦,亲爱的,天哪,这是古老的 STAThread 失踪了。有点误导,因为它的大部分都在工作,所以它可能是在 cmets 末尾附近提到的IDelegateFolder 导致单个界面错过了节奏。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-01
    • 2020-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-30
    相关资源
    最近更新 更多