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

时间:2015-04-09 18:46:51

标签: c# .net vb.net windows com

SCENARIO

我在白天管理和整理了很多文件, SendTo 是我在Windows上使用最多的功能。

问题

默认情况下,当用户单击上下文菜单的项目/链接以发送文件时,操作系统不会显示任何类型的建议/通知程序,表明文件正在复制到所选目的地

我认为这是一个非常错误的设计问题,因为对于大文件,它可以......显示进度条,但如果文件很小,它将不会显示任何进度条/可视指示器,因此无法确保文件被复制(无需人工操作),因为我是人,我可以通过错误点击 SendTo 上下文菜单之外。

所以,我想开发一个个人迷你工具,当我使用 SendTo 功能发送/复制文件时,我会在屏幕上的任何地方显示通知窗口,以帮助我优化时间contextmenu,只有 SendTo 功能。

问题

简单来说,我想从 SendTo 菜单中检测复制/发送操作,以确保点击在菜单项上正确完成(而不是在菜单外),同时提供其他基本信息,例如源文件夹,目标文件夹以及文件数量或文件路径。

是否有任何想法开始朝着正确的方向开发此工具?

我将非常感谢 C# VB.Net 中的代码示例,最好是最后一次。

APPROACH

由于我不知道如何开始这样做,我的意思是拦截那些 SendTo 电话的最简单或最有效的方法,首先我想挂钩 { {3}} CopyFile API函数,但它们不提供我需要的信息,因为该函数将在任何类型的复制操作中调用,而不仅仅是在我使用 SendTo 功能,所以我输了。

我不确定是否应该调查更多有关内部调用的内容,或者可能会调查有关windows上下文菜单本身的更多内容,而不是弄乱我可以避免的函数挂钩和丑陋的事情。

我的主要想法是开发一个隐藏的WinForms(或者是一个Windows服务),当我使用 SendTo 功能时(当我点击的项目时)等待它SendTo 菜单),然后在屏幕上显示任何类型的可视指示器,以确保我正确点击该菜单项,并可能告知我移动的文件数量以及我在哪里移动他们。

研究

这是一个代码示例,我认为它演示了如何实例化 SendTo com对象来创建自己的?,但是它是用c ++编写的,我不确定这个例子是不是很有帮助,因为我的目的不是要取代 SendTo 菜单,但我会在这里保留这个有用的信息,它可以用于其他地方:

CopyFileEx

How to add(enable) standard "Send To" context menu option in a namespace extension 常量文档提供了有关 SendTo 文件夹的一些有用信息,我再也不确定这是否有助于阅读/访问监控方法?,我只是在这里保留信息:

  

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

     

默认路径:%APPDATA%\ Microsoft \ Windows \ SendTo

     

传统默认路径:%USERPROFILE%\ SendTo

KNOWNFOLDERID 文档中有一个 Shell Extension Handlers ,我不知道它是否与有关系SendTo COM 组件,如果这可以在某种程度上帮助我, 同样无知 Copy hook handler 方法参考,也许我可以拦截它以识别 SendTo 调用?

此刻我觉得自己是盲目的。

我最近发现了这个 IContextMenu::InvokeCommand ,但它又是一个用C / C ++编写的例子(我认为之前是同一个来源),我根本不理解我不确定这是否对我有帮助,因为我重申,取代 SendTo 并不是我的想法(因为我不知道如何正确地做到这一点,避免一切可能风险,我更喜欢仍然让Windows逻辑复制/发送文件,我只想检测复制操作以检索信息)

预期结果和用途

第1步:

选择随机文件并使用 SendTo 菜单(使用我的语言,西班牙语,命令名称为' Enviar a ')

enter image description here

第2步:

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

(我只需要帮助这一步)

第3步:

在屏幕上的某处显示信息,以确保执行 SendTo 操作,以确保我正确点击 SendTo 项目( 我的链路 )。

enter image description here

(弹出窗口只是模拟,我不知道如何检索所有信息)

3 个答案:

答案 0 :(得分:7)

一旦了解了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));
}

这只是要求确认复制一堆文件。请注意,这实际上不会截获"发送到菜单,而是完全处理它,因此程序负责执行任何有意义的操作。更严肃的实施可以使用the built-in Windows copy dialog并显示一些屏幕上的进度或其他任何内容,这可以满足您的需求。

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

答案 1 :(得分:3)

我之前必须做这样的事情。你甚至不必截取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:\ yo \")
  • 完整文件名e.FullPath(例如" C:\ yo \ hey.exe")
  • 文件名e.Name(例如" hey.exe")

非代码执行过程

  1. 在您发起SendTo()之前,请创建FileSystemWatcher属性的实例,并让它监视特定的文件夹/文件名组合,显示在该组合中观看文件夹:WatchFilesBeforeTransfer(FileName, DestinationFolder)
  2. 发起SendTo()
  3. 收到档案? DisplaySuccessfulSendToMessage()KillFileWatcher();
  4. ???
  5. 利润。
  6. <强>更新

    我刚刚意识到这只是一个文件。如果要检查多个文件,可以创建多个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.
            }
        }
    }
    

    希望这有帮助!

答案 2 :(得分:1)

我担心这并不容易。 我正在玩这个FileSystemWatcher,但只取得了部分成功。

应该肯定有用的东西是File system drivers,但这看起来也是,好吧,看看它......

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

这些可能是一些先发者:

Windows shell extensions

Shell Context Menus