C# ed=真 .Start() 以 结束选择 端接头 ''' ''处理应用程序的StartupNextInstance事件。 ''' ''事件的源头。 ''包含事件数据的实例。 私有子Me_StartupNextInstance(ByVal sender作为对象,ByVal e作为StartupNextInstanceEventArgs)_ 处理我的问题 选择Case e.CommandLine.Count 案例0'终止计时器并运行应用程序。 我是终结者() Case Else'添加filepath参数并继续侦听下一个可能的参数。 Me.filePathsSB.AppendFormat(“{0}”,e.CommandLine.Item(0)) Me.filePathCount+=1 结束选择 端接头 ''' ''处理InactivityTimer控件的勾号事件。 ''' ''事件的源头。 ''包含事件数据的实例。 私有子InactivityTimer_勾选(ByVal发送方作为对象,ByVal e作为事件参数)_ 处理未激活的VityTimer。勾选 Dim tmr As Timer=DirectCast(发送器、计时器) 如果DirectCast(tmr.Tag,Integer)=Me.filePathCount,则 我是终结者() 其他的 tmr.Tag=Me.filePathCount 如果结束 端接头 #末端区域 #区域“方法” ''' ''终止非活动计时器并运行应用程序。 ''' 专用子终结符() Me.inactivitymer.Enabled=False Me.Inactivitymer.Stop() Me.RunApplication() 端接头 ''' ''运行默认应用程序,将所有文件路径作为单行参数传递。 ''' 私有子应用程序() #如果调试,则 Debug.WriteLine(Me.filepath) #如果结束 尝试 Process.Start(Me.AppPath、Me.filepath) 捕获ex作为FileNotFoundException “做点什么? 结束尝试 '终止申请。 MyBase.MainForm.Close() 端接头 #末端区域 末级 结束命名空间 您确实需要外壳扩展名吗

C# ed=真 .Start() 以 结束选择 端接头 ''' ''处理应用程序的StartupNextInstance事件。 ''' ''事件的源头。 ''包含事件数据的实例。 私有子Me_StartupNextInstance(ByVal sender作为对象,ByVal e作为StartupNextInstanceEventArgs)_ 处理我的问题 选择Case e.CommandLine.Count 案例0'终止计时器并运行应用程序。 我是终结者() Case Else'添加filepath参数并继续侦听下一个可能的参数。 Me.filePathsSB.AppendFormat(“{0}”,e.CommandLine.Item(0)) Me.filePathCount+=1 结束选择 端接头 ''' ''处理InactivityTimer控件的勾号事件。 ''' ''事件的源头。 ''包含事件数据的实例。 私有子InactivityTimer_勾选(ByVal发送方作为对象,ByVal e作为事件参数)_ 处理未激活的VityTimer。勾选 Dim tmr As Timer=DirectCast(发送器、计时器) 如果DirectCast(tmr.Tag,Integer)=Me.filePathCount,则 我是终结者() 其他的 tmr.Tag=Me.filePathCount 如果结束 端接头 #末端区域 #区域“方法” ''' ''终止非活动计时器并运行应用程序。 ''' 专用子终结符() Me.inactivitymer.Enabled=False Me.Inactivitymer.Stop() Me.RunApplication() 端接头 ''' ''运行默认应用程序,将所有文件路径作为单行参数传递。 ''' 私有子应用程序() #如果调试,则 Debug.WriteLine(Me.filepath) #如果结束 尝试 Process.Start(Me.AppPath、Me.filepath) 捕获ex作为FileNotFoundException “做点什么? 结束尝试 '终止申请。 MyBase.MainForm.Close() 端接头 #末端区域 末级 结束命名空间 您确实需要外壳扩展名吗,c#,.net,vb.net,windows,explorer,C#,.net,Vb.net,Windows,Explorer,你想要的并不像你想象的那么简单。多个文件选择的正常行为是在新窗口/应用程序实例中打开每个文件。实际上,它只是将选定的文件发送到已注册的应用程序,并由应用程序决定如何使用它们 不过,至少有一种快速简便的替代方案: 方法1:使用发送到 打开发送至文件夹(“C:\Users\YOURNAME\AppData\Roaming\Microsoft\Windows\SendTo”)并为应用添加条目。目标将是您希望向其提供/发送文件选择的应用程序: "C:\Program Files\That Ot

你想要的并不像你想象的那么简单。多个文件选择的正常行为是在新窗口/应用程序实例中打开每个文件。实际上,它只是将选定的文件发送到已注册的应用程序,并由应用程序决定如何使用它们

不过,至少有一种快速简便的替代方案:

方法1:使用发送到 打开
发送至
文件夹(
“C:\Users\YOURNAME\AppData\Roaming\Microsoft\Windows\SendTo”
)并为应用添加条目。目标将是您希望向其提供/发送文件选择的应用程序:

"C:\Program Files\That Other App\OtherApp.exe "
您不需要“%1”占位符或其他任何内容。您不必编写中介来执行任何操作,只需将文件直接发送到实际的应用程序。只要应用程序在命令行上接受多个文件,它就可以正常工作

唯一不重要的是,它驻留在“共享”或通用子菜单上,而不是顶级上下文菜单上。与适当的ContextMenu处理程序不同,它对于任何文件扩展名都不是“智能”的,但它是一种快速、简单、无代码的解决方案,已经存在很长时间了


方法2:更改动词限定符 您还可以更改动词限定符/模式,这听起来是最简单的方法。例如,VideoLan的VLC播放器:

如果单击多个.MP4文件而不是打开多个实例,则会打开其中一个实例,其余的将排队等待播放。这是通过修改注册表中的动词来完成的:

+ VLC.MP4
   + shell    
       + Open   
           -  MultiSelectModel = Player
           + Command    
             - (Default) "C:\Program Files.... %1"
             
MultiSelectModel
Open
动词的修饰符:

  • Single用于仅支持单个项目的动词
  • Player用于支持任意项目数的动词
  • 为每个项目创建顶级窗口的谓词编写文档
对于我的MediaProps小程序,由于它涉及相同的文件类型,我通过添加一个
ViewProps
谓词,将其设置为
MultiSelectModel.Player
,并在我的谓词不会混淆VLC的情况下,将谓词附加到VLC的文件类型上

不幸的是,我还没有发现一些问题。Windows似乎仍然没有像预期的那样将所有文件粘合在一起——即使我自己制作动词。注册表配置或应用程序中都缺少一个步骤——但有两种其他方法可以做同样的事情,我从未进一步研究过


方法3:创建ShellExtension/ContextMenu处理程序 许多建议的解决方案最终都是一个游戏,你必须在一个介入的应用程序中修复同一个1文件1实例问题,这样它才能将串联参数提供给最终参与者。由于最终的结果是有一个资源管理器上下文菜单来做一些有用的事情,所以让我们为另一个应用程序构建一个外壳扩展

这很容易,因为已经完成了一个框架,并且在CodeProject:上可用。这是一篇MS-PL文章,包含一个已完成的ShellExtension项目

经过一些修改,这将非常适用于:

  • 设置多个文件类型的关联
  • 收集单击的多个文件
  • 将它们格式化为命令行参数集
  • 将命令行传递给实际的worker应用程序
  • 提供自定义内容菜单
  • 显示时髦的菜单图标
此测试平台是一个小程序,用于显示媒体文件的MediaInfo属性(如持续时间、帧大小、编解码器、格式等)。除了接受删除的文件外,它还使用ContextMenu DLL帮助程序接受在资源管理器中选择的多个文件,并将它们提供给
Public Class Main

    Public Sub New()

        ' This call is required by the designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
        Me.Size = New Size(0, 0)
        Me.Hide()
        Me.SuspendLayout()

    End Sub

End Class
#Region " Option Statements "

Option Strict On
Option Explicit On
Option Infer Off

#End Region

#Region " Imports "

Imports Microsoft.VisualBasic.ApplicationServices
Imports System.IO
Imports System.Text

#End Region

Namespace My

    ''' <summary>
    ''' Class MyApplication.
    ''' </summary>
    Partial Friend Class MyApplication

#Region " Properties "

        ''' <summary>
        ''' Gets the application path to pass the filepaths as a single-line argument.
        ''' </summary>
        ''' <value>The application path.</value>
        Private ReadOnly Property AppPath As String
            Get
                Return Path.Combine(My.Application.Info.DirectoryPath, "MP3GainGUI.exe")
            End Get
        End Property

        ''' <summary>
        ''' Gets the inactivity timeout, in milliseconds.
        ''' </summary>
        ''' <value>The inactivity timeout, in milliseconds.</value>
        Private ReadOnly Property TimeOut As Integer
            Get
                Return 750
            End Get
        End Property

        ''' <summary>
        ''' Gets the catched filepaths.
        ''' </summary>
        ''' <value>The catched filepaths.</value>
        Private ReadOnly Property FilePaths As String
            Get
                Return Me.filePathsSB.ToString
            End Get
        End Property

#End Region

#Region " Misc. Objects "

        ''' <summary>
        ''' Stores the catched filepaths.
        ''' </summary>
        Private filePathsSB As StringBuilder

        ''' <summary>
        ''' Keeps track of the current filepath count.
        ''' </summary>
        Private filePathCount As Integer

        ''' <summary>
        ''' Timer that determines whether the app is inactive.
        ''' </summary>
        Private WithEvents inactivityTimer As New Timer With
            {
                .Enabled = False,
                .Interval = Me.TimeOut
            }

#End Region

#Region " Event Handlers "

        ''' <summary>
        ''' Handles the Startup event of the application.
        ''' </summary>
        ''' <param name="sender">The source of the event.</param>
        ''' <param name="e">The <see cref="ApplicationServices.StartupEventArgs"/> instance containing the event data.</param>
        Private Sub Me_Startup(ByVal sender As Object, ByVal e As StartupEventArgs) _
        Handles Me.Startup

            Select Case e.CommandLine.Count

                Case 0 ' Terminate the application.
                    e.Cancel = True

                Case Else ' Add the filepath argument and keep listen to next possible arguments.
                    Me.filePathsSB = New StringBuilder
                    Me.filePathsSB.AppendFormat("""{0}"" ", e.CommandLine.Item(0))
                    Me.filePathCount += 1

                    With Me.inactivityTimer
                        .Tag = Me.filePathCount
                        .Enabled = True
                        .Start()
                    End With

            End Select

        End Sub

        ''' <summary>
        ''' Handles the StartupNextInstance event of the application.
        ''' </summary>
        ''' <param name="sender">The source of the event.</param>
        ''' <param name="e">The <see cref="ApplicationServices.StartupNextInstanceEventArgs"/> instance containing the event data.</param>
        Private Sub Me_StartupNextInstance(ByVal sender As Object, ByVal e As StartupNextInstanceEventArgs) _
        Handles Me.StartupNextInstance

            Select Case e.CommandLine.Count

                Case 0 ' Terminate the timer and run the application.
                    Me.TerminateTimer()

                Case Else ' Add the filepath argument and keep listen to next possible arguments.
                    Me.filePathsSB.AppendFormat("""{0}"" ", e.CommandLine.Item(0))
                    Me.filePathCount += 1

            End Select

        End Sub

        ''' <summary>
        ''' Handles the Tick event of the InactivityTimer control.
        ''' </summary>
        ''' <param name="sender">The source of the event.</param>
        ''' <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        Private Sub InactivityTimer_Tick(ByVal sender As Object, ByVal e As EventArgs) _
        Handles inactivityTimer.Tick

            Dim tmr As Timer = DirectCast(sender, Timer)

            If DirectCast(tmr.Tag, Integer) = Me.filePathCount Then
                Me.TerminateTimer()

            Else
                tmr.Tag = Me.filePathCount

            End If

        End Sub

#End Region

#Region " Methods "

        ''' <summary>
        ''' Terminates the inactivity timer and runs the application.
        ''' </summary>
        Private Sub TerminateTimer()

            Me.inactivityTimer.Enabled = False
            Me.inactivityTimer.Stop()
            Me.RunApplication()

        End Sub

        ''' <summary>
        ''' Runs the default application passing all the filepaths as a single-line argument.
        ''' </summary>
        Private Sub RunApplication()

#If DEBUG Then
            Debug.WriteLine(Me.FilePaths)
#End If
            Try
                Process.Start(Me.AppPath, Me.FilePaths)

            Catch ex As FileNotFoundException
                ' Do Something?
            End Try

            ' Terminate the application.
            MyBase.MainForm.Close()

        End Sub

#End Region

    End Class

End Namespace
"C:\Program Files\That Other App\OtherApp.exe "
+ VLC.MP4
   + shell    
       + Open   
           -  MultiSelectModel = Player
           + Command    
             - (Default) "C:\Program Files.... %1"