拦截MS Windows的“SendTo”菜单调用?

情景

我在白天pipe理和组织许多文件, SendTo是我在Windows上使用最多的function。

问题

默认情况下,当用户单击上下文菜单的项目/链接发送文件时, 操作系统不会显示任何提示/通知程序,指示文件正在复制到选定的目的地。

我认为这是一个非常错误的devise问题,因为大文件的确定…将显示一个进度条,但是如果文件很小,它将不会显示任何进度条/视觉指示器,因此不可能确保文件被复制(没有人工努力),因为我是人类,我可以通过错误点击发送到上下文菜单之外。

所以,我想开发一个个人迷你工具,它将帮助我优化我的时间,当我使用上下文菜单中的SendTofunction发送/复制文件,并且只发送SendTofunction时,在屏幕上显示通知窗口。

简单地说,我想从SendTo菜单中检测复制/发送操作,以确保在菜单项上(而不是在菜单外)正确地执行了点击操作,还提供了额外的基本信息,如源文件夹,目标文件夹以及文件或文件path的数量。

任何想法开始在正确的方向开发这个工具?

我将不胜感激C#VB.Net中的代码示例,最好是最后一个。

APPROACH

由于我不知道如何开始这样做,我的意思是拦截这些SendTo调用的最简单或有效的方式,首先我想挂钩CopyFileCopyFileEx API函数,但是它们不提供我需要的信息因为这个函数会在任何一种复制操作中被调用,而不仅仅是当我使用SendTo特性的时候,所以我迷路了。

我不确定是否应该调查更多的内部调用,或者调查更多关于windows contextmenu本身,而不是弄乱function钩子和丑陋的东西,我可以避免。

我的主要想法是开发一个隐藏的WinForms(或者一个windows服务),当我使用SendTo特性(当我点击SendTo菜单的一个项目)时,保持在后台等待,然后显示任何种类的视觉指示器屏幕上,以确保我正确地点击了该菜单项,并可能通知我正在移动的文件数量以及移动的位置。

研究

下面是一个代码示例,我认为它演示如何实例化SendTo com对象来创build自己的?,但它是用c ++编写的,我不确定该示例是否有用,因为我的意图不是要replaceSendTo菜单,而是我将在这里保留这个有用的信息它为其他服务:

如何在命名空间扩展中添加(启用)标准的“发送到”上下文菜单选项

KNOWNFOLDERID常量文档提供了有关SendTo文件夹的一些有用信息,我不确定这是否可以帮助读取/访问监控方法?我只是在这里保留信息:

GUID:{8983036C-27C0-404B-8F08-102D10DCFD74}

默认path:%APPDATA%\ Microsoft \ Windows \ SendTo

旧版默认path:%USERPROFILE%\ SendTo

shell扩展处理程序文档中有一个复制钩子处理程序 ,我不知道它是否与SendToCOM组件有关系,如果这可以帮助我在某种程度上,对IContextMenu :: InvokeCommand方法引用的相同的无知也许我可以拦截它来确定一个SendTo调用?

到目前为止,我觉得像盲人一样。

我最近发现这是一个托pipe的“发送到”菜单类,但又是一个用C / C ++编写的例子(我认为是之前的同一个源码),我不明白这一点,我不知道是否可以帮助我是因为我重复说,replaceSendTo并不是我所想的(仅仅因为我不知道如何正确地做到这一点,避免了所有可能的风险,我宁愿让Windows逻辑复制/发送文件,我只是想检测复制操作来检索信息)

预期的结果和用法

步骤1:

select一个随机文件,并使用SendTo菜单(用我的语言,西class牙语,命令名是' Enviar a ')

在这里输入图像说明

第2步:

.net应用程序的逻辑(在后台工作)拦截SendTo操作来检索信息。

(我只需要帮助这一步)

第3步:

在屏幕上的某个地方显示信息,以确保SendTo操作已执行,以确保正确单击SendTo项( My Link )。

在这里输入图像说明

(该popup只是一个模拟,我不知道任何方式来检索所有的信息)

一旦你了解了SendTo真正做了什么,它确实很简单,它根本不涉及COM或shell扩展。 基本上,发送到菜单填充用户配置文件的SendTo文件夹的内容(默认情况下在Windows 6.x中是C:\ Users \\ AppData \ Roaming \ Microsoft \ Windows \ SendTo)。

单击时,如果选项是文件夹的快捷方式,则会将文件复制到该文件夹​​中,但如果存在程序的快捷方式(或程序可执行文件本身),则将运行该程序,将所选文件的路径作为命令传递在线参数。

从那里,做一些简单的路径作为参数的程序,提出某种通知,然后复制文件,或者做任何你想做的事情,真是微不足道。

一个快速和肮脏的例子可以如下(在C#中,但可以用其他任何东西):

 private static void Main(string[] args) { if(MessageBox.Show("Are you sure you want to copy files?", "Copy files", MessageBoxButtons.YesNo) == DialogResult.No) return; foreach (string file in args) File.Copy(file, Path.Combine("c:\\temp", Path.GetFileName(file)); } 

这只是要求确认复制一堆文件。 请注意,这实际上不会“截取”发送到菜单,而是完全处理它,因此程序可以负责执行任何有意义的操作。 更严重的实现可以使用内置的Windows复制对话框,并显示一些进度或其他任何屏幕,这是你的需要。

它也可以在命令行上使用更多的参数。 在SendTo文件夹中放置一个快捷方式时,目标可能会添加一些参数,这些参数将作为第一个参数(在文件名之前)传递。 例如,快捷方式的目标可以读取c:\program files\copyfiles.exe c:\temp以传递目标文件夹而不是硬编码。 被调用的程序必须将第一个参数解释为目标路径,然后将其作为源文件。

我以前不得不这样做。 你甚至不需要拦截SendTo()函数,你只需要确保文件已经到达。 如果FileSystemWatcher在同一台计算机上呢?

您可以在发送之前使用观察器进行观察,然后,如果文件成功到达目的地,则可以显示成功的消息,然后杀死观察者。

代码示例

 // Create a FileSystemWatcher property. FileSystemWatcher fsw { get; set; } // So we can set the FileToWatch within WatchFilesBeforeTransfer(). private string FileToWatch { get; set; } private void WatchFilesBeforeTransfer(string FileName, string DestinationFolder) { fsw = new FileSystemWatcher(); fsw.Path = DestinationFolder; FileToWatch = FileName; // Only if you need support for multiple directories. Code example note included. fsw.InclueSubdirectories = true; // We'll be searching for the file name and directory. fsw.NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName // If it's simply moving the file to another location on the computer. fsw.Renamed += new RenamedEventHandler(FileRenamed); // If it was copied, not moved or renamed. fsw.Created += new FileSystemEventHandler(FileCreated); fsw.EnableRaisingEvents = true; } // If the file is just renamed. (Move/Rename) private void FileRenamed(Object source, RenamedEventArgs e) { // Do something. // Note that the full filename is accessed by e.FullPath. if (e.Name == FileToWatch) { DisplaySuccessfulMessage(e.Name); KillFileWatcher(); } } // If creating a new file. (Copied) private void FileCreated(Object source, FileSystemEventArgs e) { // Do something. // Note that the full filename is accessed by e.FullPath. if (e.Name == FileToWatch) { DisplaySuccessfulMessage(e.Name); KillFileWatcher(); } } private void KillFileWatcher() { fsw.Dispose(); } 

您可以通过以下方式访问所需的属性信息(如在您的弹出式GIF中):

  • 文件夹名称Path.GetDirectory(e.FullPath); (如“C:\哟”)
  • 完整的文件名e.FullPath (如“C:\ yo \ hey.exe”)
  • 文件名e.Name (如“hey.exe”)

非代码执行过程

  1. 在启动SendTo()之前,创建FileSystemWatcher属性的一个实例,并让它监视特定的文件夹/文件名组合,该组合显示在监视的文件夹中: WatchFilesBeforeTransfer(FileName, DestinationFolder)
  2. 启动SendTo()
  3. 收到的文件? DisplaySuccessfulSendToMessage()KillFileWatcher();
  4. ???
  5. 利润。

更新

我只是意识到这只是一个文件。 如果要检查多个文件,可以创建多个FileWatcher实例(不推荐),也可以使用List<string>对象,如下所示:

 private void SendTo(List<string> FileCollection) { // Clear your previous FileList. FileList.Clear(); foreach (string file in FileCollection) { FileList.Add(file); } // Rest of the code. } List<string> FileList { get; set; } private void WatchFilesBeforeTransfer(string DestinationFolder) { // Same code as before, but delete FileToWatch. } private void FileRenamed(Object source, RenamedEventArgs e) { foreach (string file in FileList) { if (e.Name == file) { // Do stuff. } } } private void FileCreated(Object source, FileSystemEventArgs e) { foreach (string file in FileList) { if (e.Name == file) { // Do stuff. } } } 

希望这可以帮助!

恐怕这不容易。 我正在玩这个FileSystemWatcher ,但只有部分成功。

一些应该可以正常工作的东西是文件系统驱动程序,但是这看起来也是如此,看看它…

最后,这可能是编写自己的shell扩展来访问SendTo文件夹的最简单的方法,并使用它来代替SentTo命令,它将给你完全的控制权。

这些可能是一些启动者:

Windows外壳扩展

Shell上下文菜单