枚举设备的 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) {
有两种实用的方法可以从 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) {