在 Windows 资源管理器中以编程方式选择多个文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9355/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Programmatically select multiple files in windows explorer
提问by Orion Edwards
I can display and select a single file in windows explorer like this:
我可以像这样在 Windows 资源管理器中显示和选择单个文件:
explorer.exe /select, "c:\path\to\file.txt"
However, I can't work out how to select more than one file. None of the permutations of select I've tried work.
但是,我不知道如何选择多个文件。我尝试过的所有 select 排列都不起作用。
Note: I looked at these pages for docs, neither helped.
注意:我查看了这些页面的文档,但都没有帮助。
https://support.microsoft.com/kb/314853
http://www.infocellar.com/Win98/explorer-switches.htm
https://support.microsoft.com/kb/314853
http://www.infocellar.com/Win98/explorer-switches.htm
采纳答案by flashk
This should be possible with the shell function SHOpenFolderAndSelectItems
这应该可以通过 shell 函数实现 SHOpenFolderAndSelectItems
EDIT
编辑
Here is some sample code showing how to use the function in C/C++, without error checking:
下面是一些示例代码,展示了如何在 C/C++ 中使用该函数,而不进行错误检查:
//Directory to open
ITEMIDLIST *dir = ILCreateFromPath(_T("C:\"));
//Items in directory to select
ITEMIDLIST *item1 = ILCreateFromPath(_T("C:\Program Files\"));
ITEMIDLIST *item2 = ILCreateFromPath(_T("C:\Windows\"));
const ITEMIDLIST* selection[] = {item1,item2};
UINT count = sizeof(selection) / sizeof(ITEMIDLIST);
//Perform selection
SHOpenFolderAndSelectItems(dir, count, selection, 0);
//Free resources
ILFree(dir);
ILFree(item1);
ILFree(item2);
回答by Siarhei Kuchuk
The true way of selecting multiple files in Explorer is the next
在资源管理器中选择多个文件的真正方法是下一个
Unmanaged code looks like this (compiled from China code posts with fixing its bugs)
非托管代码看起来像这样(从 CN 代码帖子编译并修复了它的错误)
static class NativeMethods
{
[DllImport("shell32.dll", ExactSpelling = true)]
public static extern int SHOpenFolderAndSelectItems(
IntPtr pidlFolder,
uint cidl,
[In, MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl,
uint dwFlags);
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr ILCreateFromPath([MarshalAs(UnmanagedType.LPTStr)] string pszPath);
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214F9-0000-0000-C000-000000000046")]
public interface IShellLinkW
{
[PreserveSig]
int GetPath(StringBuilder pszFile, int cch, [In, Out] ref WIN32_FIND_DATAW pfd, uint fFlags);
[PreserveSig]
int GetIDList([Out] out IntPtr ppidl);
[PreserveSig]
int SetIDList([In] ref IntPtr pidl);
[PreserveSig]
int GetDescription(StringBuilder pszName, int cch);
[PreserveSig]
int SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
[PreserveSig]
int GetWorkingDirectory(StringBuilder pszDir, int cch);
[PreserveSig]
int SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
[PreserveSig]
int GetArguments(StringBuilder pszArgs, int cch);
[PreserveSig]
int SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
[PreserveSig]
int GetHotkey([Out] out ushort pwHotkey);
[PreserveSig]
int SetHotkey(ushort wHotkey);
[PreserveSig]
int GetShowCmd([Out] out int piShowCmd);
[PreserveSig]
int SetShowCmd(int iShowCmd);
[PreserveSig]
int GetIconLocation(StringBuilder pszIconPath, int cch, [Out] out int piIcon);
[PreserveSig]
int SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
[PreserveSig]
int SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, uint dwReserved);
[PreserveSig]
int Resolve(IntPtr hwnd, uint fFlags);
[PreserveSig]
int SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
}
[Serializable, StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode), BestFitMapping(false)]
public struct WIN32_FIND_DATAW
{
public uint dwFileAttributes;
public FILETIME ftCreationTime;
public FILETIME ftLastAccessTime;
public FILETIME ftLastWriteTime;
public uint nFileSizeHigh;
public uint nFileSizeLow;
public uint dwReserved0;
public uint dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string cAlternateFileName;
}
public static void OpenFolderAndSelectFiles(string folder, params string[] filesToSelect)
{
IntPtr dir = ILCreateFromPath(folder);
var filesToSelectIntPtrs = new IntPtr[filesToSelect.Length];
for (int i = 0; i < filesToSelect.Length; i++)
{
filesToSelectIntPtrs[i] = ILCreateFromPath(filesToSelect[i]);
}
SHOpenFolderAndSelectItems(dir, (uint) filesToSelect.Length, filesToSelectIntPtrs, 0);
ReleaseComObject(dir);
ReleaseComObject(filesToSelectIntPtrs);
}
private static void ReleaseComObject(params object[] comObjs)
{
foreach (object obj in comObjs)
{
if (obj != null && Marshal.IsComObject(obj))
Marshal.ReleaseComObject(obj);
}
}
}
回答by Nick Berardi
it cannot be done through explorer.exe
不能通过 explorer.exe 完成
回答by bruceatk
Depending on what you actually want to accomplish you may be able to do it with AutoHotKey. It is an amazing free tool for automating things you normally can't do. It should come with Windows. This script will select your file and highlight the next two files below it when you hit F12.
根据您实际想要完成的工作,您可以使用AutoHotKey来完成。这是一个了不起的免费工具,用于自动化您通常无法做到的事情。它应该随 Windows 一起提供。当您按 F12 时,此脚本将选择您的文件并突出显示其下方的下两个文件。
F12::
run explorer.exe /select`, "c:\path\to\file.txt"
SendInput {Shift Down}{Down}{Down}{Shift Up}
return
It is also possible to just put those two middle lines in a text file and then pass it is a parm to autohotkey.exe. They have an option to compile the script also, which would make it a standalone exe that you could call. Works great with a great help file.
也可以将中间的两行放在一个文本文件中,然后将它作为参数传递给 autohotkey.exe。他们还可以选择编译脚本,这将使其成为您可以调用的独立 exe。使用很棒的帮助文件效果很好。
@Orion, It is possible to use autohotkey from C#. You can make an autohotkey script into a standalone executable (about 400k) that can be launched by your C# app (just the way you are launching explorer). You can also pass it command line parameters. It does not have any runtime requirements.
@Orion,可以使用 C# 中的自动热键。您可以将自动热键脚本制作成一个独立的可执行文件(大约 400k),可以由您的 C# 应用程序启动(就像您启动资源管理器的方式)。您还可以向它传递命令行参数。它没有任何运行时要求。
回答by Orion Edwards
This is one of those questions where it may be good to consider what you're trying to achieve, and whether there's a better method.
这是考虑您要实现的目标以及是否有更好的方法可能会很好的问题之一。
To add some more context - Our company develops a C# client application, which allows users to load files and do stuff with them, kind of like how iTunes manages your MP3 files without showing you the actual file on disk.
添加更多上下文 - 我们公司开发了一个 C# 客户端应用程序,它允许用户加载文件并使用它们做一些事情,有点像 iTunes 如何管理您的 MP3 文件而不向您显示磁盘上的实际文件。
It's useful to select a file in the application, and do a 'Show me this file in Windows Explorer` command - this is what I'm trying to achieve, and have done so for single files.
在应用程序中选择一个文件并执行“在 Windows 资源管理器中向我显示此文件”命令很有用 - 这就是我想要实现的目标,并且已经为单个文件执行了此操作。
We have a ListView which allows users to select multiple files within the application, and move/delete/etc them. It would be nice to have this 'show me this file in windows' command work for multiple selected files - at least if all the source files are in the same directory, but if it's not possible then it's not a major feature.
我们有一个 ListView,它允许用户在应用程序中选择多个文件,并移动/删除/等等。让这个“在 Windows 中向我显示这个文件”命令适用于多个选定的文件会很好 - 至少如果所有源文件都在同一目录中,但如果不可能,那么它不是主要功能。
回答by PhiLho
I suppose you can use FindWindowEx
to get the SysListView32 of Windows Explorer, then use SendMessage
with LVM_SETITEMSTATE
to select the items. The difficulty being to know the position of the items... Perhaps LVM_FINDITEM
can be used for this.
我想您可以使用FindWindowEx
来获取 Windows 资源管理器的 SysListView32,然后使用SendMessage
withLVM_SETITEMSTATE
来选择项目。困难在于知道项目的位置......也许LVM_FINDITEM
可以用于此。
回答by PhiLho
Grr i would like to do this as well. Media Player does it when you select 2+ files and right click and do "open file location" but not exactly sure how (nor do i really feel like spending the time w/ procmon to figure it out).
Grr 我也想这样做。当您选择 2 个以上的文件并右键单击并执行“打开文件位置”时,媒体播放器会执行此操作,但不完全确定如何(我也真的不想花时间使用 procmon 来弄清楚)。
回答by stax76
There are COM Automation LateBinding IDispatch interfaces, these are easy to use from PowerShell, Visual Basic.NET and C#, some sample code:
有 COM 自动化 LateBinding IDispatch 接口,这些很容易从 PowerShell、Visual Basic.NET 和 C# 中使用,一些示例代码:
$shell = New-Object -ComObject Shell.Application
function SelectFiles($filesToSelect)
{
foreach ($fileToSelect in $filesToSelect)
{
foreach ($window in $shell.Windows())
{
foreach ($folderItem in $window.Document.Folder.Items())
{
if ($folderItem.Path -eq $fileToSelect)
{
$window.Document.SelectItem($folderItem, 1 + 8)
}
}
}
}
}
-
——
Option Strict Off
Imports Microsoft.VisualBasic
Public Class ExplorerHelp
Shared ShellApp As Object = CreateObject("Shell.Application")
Shared Sub SelectFile(filepath As String)
For Each i In ShellApp.Windows
For Each i2 In i.Document.Folder.Items()
If i2.Path = filepath Then
i.Document.SelectItem(i2, 1 + 8)
Exit Sub
End If
Next
Next
End Sub
End Class
https://docs.microsoft.com/en-us/windows/win32/shell/shellfolderview-selectitem
https://docs.microsoft.com/en-us/windows/win32/shell/shellfolderview-selectitem