实现浏览器文本菜单,并通过多个文件到一个程序实例多个、实例、菜单、文本

2023-09-03 00:53:44 作者:上上谦

状况

我有一个不接受通过CLI多个文件的第三方GUI应用程序, 例如:

I have a 3rd party GUI application that accepts multiple files via CLI, for example:

MyProgram.exe "file1" "file2"

然后将所有文件都立刻加载到应用程序的同一个实例。

Then all the files are loaded at once into the same instance of the application.

要优化我的时间,我想这样做来加载多个文件,从右键点击鼠标上的一些文件的 Windows资源管理器(例如: 选择5档>做右点击>选择打开在MyProgram的命令的)

To optimize my time I would like to load multiple files by doing right-mouse-click on some files from Windows Explorer (eg: Select 5 files > do right-click > select "Open in MyProgram" command)

我知道如何创建所需的注册表键在特定的文件类型的上下文菜单中添加一个命令,这是没有问题的。

I know how to create the needed registry keys to add that command in the context menu for specific file types, that is not a problem.

问题

这个第三方程序不附带任何驱动程序,外壳扩展,或方法,它可以捕获从文本菜单多个文件,所以不是说如果我选择了从资源管理器2个文件,每个文件是程序的分离实例中打开,而我没有开发驱动程序的想法,所以司机就是我要找没有什么。

This 3rd party program does not comes with any driver, shell extension, or methodology that can catch multiple files from contextmenu, so instead of that If I select 2 files from explorer, each file is open in a separated instance of the program, and I don't have idea of developing drivers, so a driver is not what I'm looking for.

聚焦

我接受建议,也许这不是有效的方法,但似乎最简单的方法:

I'm open to suggestions, maybe this is not the efficient way but seems the easiest way:

我的想法是建立一个小型的CLI应用程序,以捕捉那些多个文件(可能基于Windows消息或SO活动,我不知道,这就是为什么我问),写在一个文本文件中的文件/参数再加入所有参数在单行打电话给我的第三方程序使用这些参数来加载所有文件一次在这个项目的一个实例。

My idea is to develop a mini CLI application to catch those multiple files (maybe based in windows messages or in SO inactivity, I don't know that's why I'm asking), write those files/arguments in a text file then join all the arguments in a single line to call my 3rd party program with those arguments to load all the files at once in a single instance of this program.

在换句话说,只是一个简单的装载程序从文本菜单中选择多个文件时,这个第三方应用程序中打开的所有文件一次使用它。

In other words, just a simple loader to use it from the contextmenu when selecting multiple files to open all the files at once in this 3rd party application.

问题

首先,我想知道,如果存在一个已知的词来命名一个应用程序,它能够装载在同一个实例中选择从资源管理器的文件,那么文本菜单多个文件的这件事情的。我想研究这个词。

First of all I would like to know if exists a known term to name this thing of an application that is capable to load multiple files in the same instance selecting the files from explorer then contextmenu. I would like to research for that term.

这可能是完成下VB.NET/C#控制台应用程序这一任务的最有效方法是什么? (不驱动)

Which could be the most efficient way to accomplish this task under a VB.NET/C# console application? (not a driver)

如何开始开发这个?

从已知的网页就像任何存在的源 - code例如 $ C $的CProject ...

Any existent source-code example from known pages like codeproject...?

推荐答案

您想要的不是像你想象的那么简单。对于选择多个文件的正常行为是在一个新的窗口/应用程序实例中打开每个。其实,它只是将选定的文件到注册应用程序,并留下它的应用程序,以决定如何与他们合作。

You Do want a ShellExtension

What you want is not quite as simple as you think. The normal behavior for multiple file selections is to open each in a new Window/App instance. Actually, it just sends the selected files to the registered app and leaves it up to the app to decide how to work with them.

至少有一个快速和简单的办法,但:

There is at least 1 quick and easy alternative though:

打开发送到文件夹(C:\ Users \用户YOURNAME \应用程序数据\漫游\微软\的Windows \的SendTo),并增加对应用程序的条目。目标是要养活/发送文件选择到应用程序:

Open the Send To folder ("C:\Users\YOURNAME\AppData\Roaming\Microsoft\Windows\SendTo") and add an entry for the app. The target would be the app you wish to feed/send file selection to:

"C:\Program Files\That Other App\OtherApp.exe "

您不需要%1占位符或其他任何东西。你不必写一个中间人做任何事情,只要直接将文件发送到实际的应用程序。它会正常工作,只要应用程序将接受命令行上的多个文件。

You don't need "%1" placeholders or anything else. You don't have to write an intermediary to do anything, just send the files directly to the actual app. It will work fine, as long as the app will accept more than one file on the command line.

唯一的小事情是,它驻留在共享或一般的子菜单,而不是一个顶层上下文菜单中。它也不是聪明,只要它是可用于任何文件扩展名不象一个适当的文本菜单的处理程序,但它是一个快速简便的已经存在了很长一段时间,NO- code解决方案。

The only minor thing is that it resides on a "shared" or general sub menu rather than a top level context menu. It is also not "smart" in so far as it is available for any file extension unlike a proper ContextMenu handler, but it is a quick and easy, no-code solution which has been around for a long time.

您也可以改变动词预选赛/模式,它的声音的像最简单的方法。就拿,VideoLAN的的VLC播放器:

You can also change the verb qualifier/mode, which sounds like the easiest way. Take for instance, VideoLan's VLC player:

如果你点击多个.MP4文件,而不是开放的多个实例,但其中一人打开,其余排队等待发挥。这是通过修改动词在注册表中完成的:

If you click on multiple .MP4 files rather than open multiple instances, it opens with one of them and the rest are queued for play. This is done by modifying the verb in the registry:

+ VLC.MP4
   + shell    
       + Open   
           -  MultiSelectModel = Player
           + Command    
             - (Default) "C:\Program Files.... %1"

MultiSelectModel 是一个修改的打开的动词的:

MultiSelectModel is a modifier for the Open verb:

单作为仅支持单个项目的动词 播放作为支持任意数量的项目动词 文件作为其中的每个项目创建一个顶层窗口的动词 Single for verbs that support only a single item Player for verbs that support any number of items Document for verbs which create a top level window for each item

有关我MediaProps的​​小程序,因为它关注的是相同的文件类型,我捎带我的动词到VLC的文件类型添加一个 ViewProps 动词,被定为 MultiSelectModel.Player 和一般的工作,只要我的动词没有混淆VLC。

For my MediaProps applet, since it is concerned with the same file types, I piggybacked my verb onto the file types of VLC by adding a ViewProps verb which was set as MultiSelectModel.Player and generally worked in so far as my verbs did not confuse VLC.

不幸的是,仍然有一些不对劲,我还没有确定。窗户好像它仍然是不胶粘的所有文件一起按预期 - 即使我做我自己的动词。有一个一步无论是在注册表中的配置或应用程序丢失 - 但与另外两种方式做同样的事情,我从来没有进一步调查

Unfortunately, there is still something amiss that I have not yet identified. Windows seems like it still is not gluing all the files together as expected - even if I make my own verbs. There is a step missing either in the registry config or with the app -- but with two other ways to do the same thing, I have never investigated further.

许多提出的解决方案最终会被游戏的捶一痣 ,你必须解决同1文件-1实例问题居间应用程序,所以它可以养活连接参数的最终演员。由于最终的结果是有一个浏览器文本菜单做一些有用的东西,让刚刚建立的 ShellExtension 的在的这种其它应用。

Many proposed solutions end up being a game of Whack-a-Mole where you have to fix the same 1 file-1 instance problem in an intervening app so it can feed concatenated arguments to the final actor. Since the end result is to have an Explorer ContextMenu to do something useful, lets just build a ShellExtension for this other application.

这是的轻松的,因为框架已经完成,并可以在$ C $的CProject:How编写的Windows外壳扩展使用.NET语言。这是一个MS-PL文章完成与成品ShellExtension项目。

This is easy because a framework is already done and available on CodeProject: How to Write Windows Shell Extension with .NET Languages. This is an MS-PL article complete with a finished ShellExtension project.

通过一些修改,这将很好地工作到:

With a few modifications, this will work perfectly to:

设置为协会的多的文件类型 在收集多个文件,点击 在这些格式转换成一个命令行参数设置 在命令行传递给实际工作者应用程序 提供自定义ContentMenu 在显示一个时髦的菜单图标 setup associations for multiple file types collect multiple files clicked format them into a command line arg set pass the commandline to the actual worker app provide a custom ContentMenu display a snazzy menu icon

试验台,这是一个小程序来显示的媒体文件MediaInfo属性(像时间,帧大小,codeC,格式等)。除了接受丢弃的文件,它使用了一个文本菜单DLL帮手接受在资源管理器中选择多个文件并将它们提供给单一实例显示应用程序。

The test bed for this is an applet to display the MediaInfo properties of media files (things like Duration, Frame Size, Codec, format etc). In addition to accepting Dropped files, it uses a ContextMenu DLL helper to accept multiple files selected in Explorer and feed them to the Single Instance display app.

注:我会很乐意制作和测试,这与实际应用程序或工具也适用于工作,但被丢弃,因为不important` 的

1。更新装配/项目价值

例如,我改变了组件名称为MediaPropsShell。我也删除了根命名空间,但是这是可选的。

For instance, I changed the assembly name to "MediaPropsShell". I also removed the root namespace but that is optional.

添加你所选择的PNG图标。

Add a PNG icon of your choosing.

选择合适的平台。由于原来有2个安装程序,则可能必须专门建立一个x86版本的32位操作系统。值为anycpu工作正常的64位操作系统,我不知道86。其中使用该模型大多数系统提供一个32位和64位的DLL的外壳扩展帮手,但基于大多数过去不能NET要么其中值为anycpu是一种选择。

Pick the appropriate platform. Since the original has 2 installers, you may have to specifically build an x86 version for a 32bit OS. AnyCPU works fine for 64bit OS, I'm not sure about x86. Most systems which use this model supply a 32 and 64 bit DLL for the shell extension helper, but most in the past could not be NET based either where AnyCPU is an option.

保持在目标平台为.NET 4。如果你没看过的$ C $的CProject的文章,或者没有研究这个previously,这是非常重要的。

Keep the target platform as NET 4. If you did not read the CodeProject article or have not researched this previously, this is important.

2。 code变化

由于发表于$ C $的CProject,处理程序也只传递一个文件,并赞同只有一个文件类型。下面的code实现处理程序多个文件类型。你也将要修复的菜单名称等等。所有的变化都记录在以下prefaces的code与 {PL}

As published on CodeProject, the handler also only passes one file and associates itself with only one file type. The code below implements the handler for multiple file types. You will also want to fix the menu names and so forth. All the changes are noted in the code below prefaces with {PL}:

' {PL} - change the GUID to one you create!
<ClassInterface(ClassInterfaceType.None),
Guid("1E25BCD5-F299-496A-911D-51FB901F7F40"), ComVisible(True)>

Public Class MediaPropsContextMenuExt    ' {PL} - change the name
    Implements IShellExtInit, IContextMenu

    ' {PL} The nameS of the selected file
    Private selectedFiles As List(Of String)

    ' {PL} The names and text used in the menu
    Private menuText As String = "&View MediaProps"
    Private menuBmp As IntPtr = IntPtr.Zero
    Private verb As String = "viewprops"
    Private verbCanonicalName As String = "ViewMediaProps"
    Private verbHelpText As String = "View Media Properties"

    Private IDM_DISPLAY As UInteger = 0

    Public Sub New()
        ' {PL} - no NREs, please
        selectedFiles = New List(Of String)

        ' Load the bitmap for the menu item.
        Dim bmp As Bitmap = My.Resources.View         ' {PL} update menu image

        ' {PL} - not needed if you use a PNG with transparency (recommended):
        'bmp.MakeTransparent(bmp.GetPixel(0, 0))
        Me.menuBmp = bmp.GetHbitmap()
    End Sub

    Protected Overrides Sub Finalize()
        If (menuBmp <> IntPtr.Zero) Then
            NativeMethods.DeleteObject(menuBmp)
            menuBmp = IntPtr.Zero
        End If
    End Sub

    ' {PL} dont change the name (see note)
    Private Sub OnVerbDisplayFileName(ByVal hWnd As IntPtr)

        '' {PL} the command line, args and a literal for formatting
        'Dim cmd As String = "C:\Projects .NET\Media Props\MediaProps.exe"
        'Dim args As String = ""
        'Dim quote As String = """"

        '' {PL} concat args
        For n As Integer = 0 To selectedFiles.Count - 1
            args &= String.Format(" {0}{1}{0} ", quote, selectedFiles(n))
        Next

        ' Debug command line visualizer
        MessageBox.Show("Cmd to execute: " & Environment.NewLine & "[" & cmd & "]", "ShellExtContextMenuHandler")

        '' {PL} start the app with the cmd line we made
        'If selectedFiles.Count > 0 Then
        '    Process.Start(cmd, args)
        'End If

    End Sub

#Region "Shell Extension Registration"

    ' {PL} list of media files to show this menu on (short version)
    Private Shared exts As String() = {".avi", ".wmv", ".mp4", ".mpg", ".mp3"}

    <ComRegisterFunction()> 
    Public Shared Sub Register(ByVal t As Type)
        ' {PL}  use a loop to create the associations
        For Each s As String In exts
            Try
                ShellExtReg.RegisterShellExtContextMenuHandler(t.GUID, s,
                    "MediaPropsShell.MediaPropsContextMenuExt Class")
            Catch ex As Exception
                Console.WriteLine(ex.Message) 
                Throw ' Re-throw the exception
            End Try
        Next

    End Sub

    <ComUnregisterFunction()> 
    Public Shared Sub Unregister(ByVal t As Type)
        ' {PL}  use a loop to UNassociate
        For Each s As String In exts
            Try
                ShellExtReg.UnregisterShellExtContextMenuHandler(t.GUID, s)
            Catch ex As Exception
                Console.WriteLine(ex.Message) ' Log the error
                Throw ' Re-throw the exception
            End Try
        Next
    End Sub

#End Region

正下方一点需要在 IShellExtInit成员区域的改变,以及:

Just below a bit needs to be changed in the IShellExtInit Members REGION as well:

Public Sub Initialize(pidlFolder As IntPtr, pDataObj As IntPtr,
      hKeyProgID As IntPtr) Implements IShellExtInit.Initialize

    If (pDataObj = IntPtr.Zero) Then
        Throw New ArgumentException
    End If

    Dim fe As New FORMATETC
    With fe
        .cfFormat = CLIPFORMAT.CF_HDROP
        .ptd = IntPtr.Zero
        .dwAspect = DVASPECT.DVASPECT_CONTENT
        .lindex = -1
        .tymed = TYMED.TYMED_HGLOBAL
    End With

    Dim stm As New STGMEDIUM

    ' The pDataObj pointer contains the objects being acted upon. In this 
    ' example, we get an HDROP handle for enumerating the selected files 
    ' and folders.
    Dim dataObject As System.Runtime.InteropServices.ComTypes.IDataObject = Marshal.GetObjectForIUnknown(pDataObj)
    dataObject.GetData(fe, stm)

    Try
        ' Get an HDROP handle.
        Dim hDrop As IntPtr = stm.unionmember
        If (hDrop = IntPtr.Zero) Then
            Throw New ArgumentException
        End If

        ' Determine how many files are involved in this operation.
        Dim nFiles As UInteger = NativeMethods.DragQueryFile(hDrop,
                         UInt32.MaxValue, Nothing, 0)

        ' ********************
        ' {PL} - change how files are collected
        Dim fileName As New StringBuilder(260)
        If (nFiles > 0) Then
            For n As Long = 0 To nFiles - 1
                If (0 = NativeMethods.DragQueryFile(hDrop, CUInt(n), fileName,
                         fileName.Capacity)) Then
                    Marshal.ThrowExceptionForHR(WinError.E_FAIL)
                End If
                selectedFiles.Add(fileName.ToString)
            Next
        Else
            Marshal.ThrowExceptionForHR(WinError.E_FAIL)
        End If

        ' {/PL} 
        ' *** no more changes beyond this point ***

        ' [-or-]
        ' Enumerates the selected files and folders.
        '...

    Finally
        NativeMethods.ReleaseStgMedium((stm))
    End Try
End Sub

原来的code实际上确实有code,对于它被注释掉了一个多文件的方法。事实上,我增加一个之前没看出来。更改后的部分是明星串之间。

The original code actually does have code for a multi file method which is commented out. I actually did not see it before adding one. The changed part is between the star strings.

另外,也真难,但选项严格,你将不得不作出10个左右的微小变化,以微软的code。刚刚接受更改智能感知提示。

Also, it is sad to say, but with Option Strict, you will have to make 10 or so small changes to Microsoft's code. Just accept the changes IntelliSense suggests.

重要提示

一个单独的DLL提供代表一个EXE引擎的文本菜单服务的模式是非常常见。这是所有的 xxxShell.DLL 文件,你经常看到的文件夹以及可执行程序。这里的区别是,的您的正在建设的DLL,而不是有问题的应用程序的作者。

The model of a separate DLL to provide ContextMenu services on behalf of an EXE "engine" is very common. This is what all the xxxShell.DLL files are which you often see in folders along with program executables. The difference here is that you are building the DLL rather than the author of the app in question.

除一人外所有的变化都在 FileContextMenuExt 类 一定要改变GUID否则你的处理器可以碰撞他人基于相同的MS模板!有一个方便的工具这对你的工具菜单。 的BMP / PNG是可选的 的原始MS版本简单地显示所选择的文件的名称。因此,有关程序被命名为 OnVerbDisplayFileName 。正如你看到的,我并没有改变。如果你改变它以符合您的实际操作中,您还需要更改的PInvoke重code一些参考它 IContextMenu 。任何人,但你永远不会看到这个名字虽然。 系统调试的MessageBox是所有在那里的调用行动。你可以看到实际的code矿区使用。 All the changes except one are in the FileContextMenuExt class Be sure to change the GUID otherwise your handler could collide with others based on the same MS Template! There is a handy utility for this on your Tools menu. The BMP/PNG is optional The original MS version simply displayed the name of the file selected. So the relevant procedure is named OnVerbDisplayFileName. As you see, I did not change that. If you change it to match your actual operation, you will also need to change some references to it in the PInvoke heavy code for IContextMenu. Nobody but you will ever see that name though. A debug MessageBox is all that is there for the invoke action. You can see the actual code mine uses.

在原来的MS项目的自述说明这一点,但你编译后,将文件复制到它驻留,并注册它:

The ReadMe in the original MS project describes this, but after you compile, copy the file to where it will reside and register it:

regasm <asmfilename>.DLL /codebase

要注销:

regasm <asmfilename>.DLL /unregister

使用了 RegAsm Microsoft.NET \ Framework64 \ v4.0.xxxx 文件夹中找到。这将需要从命令窗口具有管理员权限(或等值脚本)完成。另外一个部署的应用程序,你可以在目标应用程序寄存器/使用公共Regster /注销方法注销助手DLL。

Use the RegAsm found in your Microsoft.NET\Framework64\v4.0.xxxx folder. This will have to be done from a Command Window with Administrator privileges (or the equivalent script). Alternatively for a deployed app, you can have the target app register/unregister the helper DLL using the Public Regster/UnRegister methods.

警告:让你的code改变的精心并测试之类的东西循环和字符串格式的然后再编译;你想尽可能少的编译 - 测试迭代越好。其原因是,一旦你激活你的新的上下文菜单中,该DLL正在使用资源管理器中,并且不能被新版本替换。你必须终止的Explorer.exe 过程(不只是文件浏览器!)注册,并尝试一个新的版本。

Warning: make your code changes carefully and test things like loops and string formats before you compile; you want as few compile-test iterations as possible. The reason is that once you activate your new context menu, the DLL is in use by Explorer and cannot be replaced by a new build. You have to terminate the explorer.exe process (not just File Explorer!) to register and try a new build.

有可能是另一种方式,但我只是关闭所有资源管理器窗口,然后注销和右后卫。

There may be a another way, but I just close any Explorer Windows, then log off and right back on.

如果我用鼠标右键单击已注册的文件类型之一,我得到预期的正确的菜单文字和位图图像菜单:

If I right click on one of the registered file types, I get the menu as expected with the correct menu text and bitmap image:

点击图片放大

如果我点击时,applet出现如预期的与在一个实例多个文件:

If I click, the applet comes up as expected with multiple files in one instance:

点击图片放大

请注意在preV / Next按钮底部如何启用从文件移动到文件时1文件只加载这是不是这样的。

Note how the Prev/Next buttons at the bottom are enabled to move from file to file which is not the case when 1 file only is loaded.

作品在我的机器 TM 的

How编写的Windows外壳扩展使用.NET语言。这是一个MS-PL文章完成成品ShellExtension项目。以上是一套器官功能障碍综合征,以使其与多个扩展名和多个文件的工作,所以原来的项目需要为出发点。

How to Write Windows Shell Extension with .NET Languages. This is an MS-PL article complete with a finished ShellExtension project. The above is a set of mods to make it work with multiple extensions and multiple files, so the original project is required as a starting point.

最佳实践快捷菜单处理程序和多动词

选择静态或动态快捷菜单的方法

动词和文件关联