将命令行传递给单实例应用程序的第一个实例

时间:2015-03-03 12:23:57

标签: .net vb.net

当用户使用Registry右键单击Windows资源管理器中的文件时,我已经实现了上下文菜单。文件地址将作为命令行传递给应用程序。解析它没问题。

如何实现类似于“添加到Windows Media Player播放列表”的内容?它没有打开应用程序的另一个实例,但在同一个打开的窗口上工作并将其添加到列表中?

1 个答案:

答案 0 :(得分:10)

根据应用的启动方式,有两种方法可以执行此操作。

方法1:使用VB App Framework和MainForm

这是最简单的,因为您只需要为Application事件添加一些代码。首先,在主表单中添加一个方法,以便从应用的后续实例中接收新参数:

Public Class MyMainForm       ' note the class name of the form
    ...

    Public Sub NewArgumentsReceived(args As String())
        ' e.g. add them to a list box
        If args.Length > 0 Then
            lbArgs.Items.AddRange(args)
        End If
    End Sub

下一步:

  • 打开项目属性
  • 检查"制作单一实例"选项
  • 点击底部的查看应用程序事件
  • 这将打开一个新的代码窗口,就像任何其他窗口一样;在左下角选择MyApplication Events;和StartupNextInstance在右边。{/ li>

在这里,我们找到主窗体并将命令行参数发送到我们创建的方法:

Private Sub MyApplication_StartupNextInstance(sender As Object,
                e As ApplicationServices.StartupNextInstanceEventArgs) _
                     Handles Me.StartupNextInstance

    Dim f = Application.MainForm
    '  use YOUR actual form class name:
    If f.GetType Is GetType(MyMainForm) Then
        CType(f, MyMainForm).NewArgumentsReceived(e.CommandLine.ToArray)
    End If

End Sub

注意:请勿尝试从Application.OpenForms中删除主要表单。有几次我没有在集合中找到一个开放的表格,所以我已经放弃了依赖它。 Application.MainForm也更简单。

它就是 - 当一个新实例运行时,它的命令行args应该传递给表单并显示在列表框中(或者处理,但是你的方法看起来合适)。


方法2:从Sub Main

开始

这更复杂,因为从Sub Main启动应用程序意味着不使用VB Application Framework,它提供StartupNextInstance事件。解决方案是将WindowsFormsApplicationBase子类化以提供所需的功能。

首先,为您的主表单添加一个有意义的名称,并添加如上所述的NewArgumentsReceived(args As String())

对于那些不知道的人,以下是如何从Sub Main()启动您的应用:

  • 添加一个名为' Program'的模块。到你的应用程序
  • 为其添加Public Sub Main()
  • 转到项目 - >属性 - >申请
  • 取消选中Enable Application Framework
  • 选择新的" Sub Main"作为启动对象

模块实际上可以命名为任何东西,Program是VS用于C#应用程序的约定。我们创建类后,Sub Main的代码将会更晚。以下大部分内容源自旧的MSDN文章或博客或其他内容。

Imports Microsoft.VisualBasic.ApplicationServices
Imports System.Collections.ObjectModel

Public Class SingleInstanceApp
    ' this is My.Application
    Inherits WindowsFormsApplicationBase

    Public Sub New(mode As AuthenticationMode)
        MyBase.New(mode)
        InitializeApp()
    End Sub

    Public Sub New()
        InitializeApp()
    End Sub

    ' standard startup procedures we want to implement
    Protected Overridable Sub InitializeApp()
        Me.IsSingleInstance = True
        Me.EnableVisualStyles = True
    End Sub

    ' ie Application.Run(frm):
    Public Overloads Sub Run(frm As Form)
        ' set mainform to be used as message pump
        Me.MainForm = frm
        ' pass the commandline
        Me.Run(Me.CommandLineArgs)
    End Sub

    Private Overloads Sub Run(args As ReadOnlyCollection(Of String))
        ' convert RO collection to simple array
        ' these will be handled by Sub Main for the First instance
        '    and in the StartupNextInstance handler for the others
        Me.Run(myArgs.ToArray)
    End Sub

    ' optional: save settings on exit
    Protected Overrides Sub OnShutdown()

        If My.Settings.Properties.Count > 0 Then
            My.Settings.Save()
        End If

        MyBase.OnShutdown()
    End Sub
End Class

请注意App框架可以为我们做的三件事("启用XP样式","制作单个实例""在退出时保存设置" )都是占了。现在,对Sub Main进行了一些修改:

Imports Microsoft.VisualBasic.ApplicationServices
Imports System.Collections.ObjectModel

Module Program  
    ' this app's main form
    Friend myForm As MyMainForm

    Public Sub Main(args As String())
        ' create app object hardwired to SingleInstance
        Dim app As New SingleInstanceApp()

        ' add a handler for when a second instance tries to start
        ' (magic happens there)
        AddHandler app.StartupNextInstance, AddressOf StartupNextInstance

        myForm = New MyMainForm

        ' process command line args here for the first instance
        ' calling the method you added to the form:
        myForm.NewArgumentsReceived(args)

        ' start app
        app.Run(myForm)   
    End Sub

    ' This is invoked when subsequent instances try to start.
    '    grab and process their command line 
    Private Sub StartupNextInstance(sender As Object, 
                        e As StartupNextInstanceEventArgs)

        ' ToDo: Process the command line provided in e.CommandLine.
        myForm.NewArgumentsReceived(e.CommandLine.ToArray)

    End Sub   

End Module

SingleInstanceApp类可以与任何Sub Main样式应用程序一起使用,并且该方法中的代码主要是复制粘贴样板事件,除了可能是{{的表单引用和实际名称1}}方法。


测试

编译应用程序,然后使用命令窗口,向应用程序发送一些命令行参数。我用过:

  
    

C:\ Temp> singleinstance" First Inst"苹果蝙蝠猫

  

这会正常启动应用程序,并显示参数。然后:

  
    

C:\ Temp> singleinstance" Next Inst" ziggy zoey zacky
    C:\ Temp> singleinstance" Last Inst" 111 222 3333

  

使用哪种方法并不重要 - 它们的工作原理相同。结果:

enter image description here enter image description here

请注意,根据安全设置,您的防火墙可能会使用这两种方法连接到其他计算机来请求应用程序的权限。这是实例如何发送或侦听来自其他人的参数的结果。至少和我的一样,我可以拒绝连接,一切仍然可以正常工作。