#vb.net #menu #command #line #sendto
#.net #vb.net
Вопрос:
Я уже реализовал контекстное меню, которое появляется, когда пользователь щелкает правой кнопкой мыши файл в проводнике Windows с помощью реестра. Адрес файла будет передан приложению в виде командной строки. Синтаксический анализ не проблема.
Как я могу реализовать это аналогично «Добавить в список воспроизведения проигрывателя Windows Media»? Он не открывает другой экземпляр приложения, но работает в том же открытом окне и добавляет его в список?
Ответ №1:
Есть 2 способа сделать это в зависимости от того, как запускается ваше приложение.
Метод 1: использование VB App Framework и MainForm
Это самый простой способ, потому что в основном вам просто нужно добавить некоторый код для события приложения. Сначала добавьте метод в свою основную форму, чтобы получать новые аргументы от последующих экземпляров вашего приложения:
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
в правом.
Здесь мы находим основную форму и отправляем аргументы командной строки в созданный нами метод:
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
также проще.
Вот и все — при запуске нового экземпляра его аргументы командной строки должны быть переданы в форму и отображены в списке (или обработаны, как ваш метод считает нужным).
Способ 2: начиная с Sub Main
Это сложнее, потому что запуск вашего приложения из подосновы означает, что платформа приложений VB не используется, что обеспечивает StartupNextInstance
событие. Решение заключается в создании подкласса WindowsFormsApplicationBase
для обеспечения необходимой функциональности.
Сначала дайте вашей основной форме значимое имя и добавьте NewArgumentsReceived(args As String())
что-то вроде приведенного выше.
Для тех, кто не в курсе, вот как запустить ваше приложение с Sub Main()
:
- Добавьте модуль с именем «Program» в свое приложение
- Добавьте
Public Sub Main()
к нему a . - Перейдите в Проект -> Свойства -> Приложение
- Снимите флажок
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
Обратите внимание, что все три основные вещи, которые платформа приложений может сделать для нас («Включить стили 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
приложением любого стиля, и код в этом методе в основном является шаблонным для копирования-вставки, за исключением, возможно, ссылки на форму и фактического имени NewArgumentsReceived
метода.
Тестирование
Скомпилируйте приложение, затем, используя командное окно, отправьте в приложение некоторые аргументы командной строки. Я использовал:
C:Temp > одиночный экземпляр «First Inst» яблочные летучие мыши кошки
При этом приложение запускается как обычно, с показанными аргументами. Затем:
C:Temp >сингл-экземпляр «Next Inst» зигги зои Заки
C:Temp >одиночный экземпляр «Последний Inst» 111 222 3333
Не имеет значения, какой подход вы используете — они оба работают одинаково. Результат:
Обратите внимание, что в зависимости от настроек безопасности ваш брандмауэр может запрашивать разрешение для приложений, использующих любой метод для подключения к другим компьютерам. Это результат того, как экземпляр отправляет или прослушивает аргументы от других. По крайней мере, с моим я могу запретить разрешение на подключение, и все по-прежнему работает нормально.
Ответ №2:
решение @Plutonix довольно эффективное и элегантное.
Однако, если ваша программа проходит через несколько форм, т.Е. Если Основная форма может измениться во время выполнения программы, например, если у вас есть форма входа, а затем основная форма или последовательность немодальных форм, Application.Основная форма не всегда будет одинаковой и может быть неизвестна заранее (жестко запрограммирована).
Код Plutonix предполагает, что он известен, и жестко кодирует его. В этом случае вы можете захотеть иметь возможность получать новые аргументы в любое время, в любой форме, которая активна в данный момент в вашем приложении.
Существует 2 решения для расширения решения Plutonix:
1) Повторно принудительно применить.MainForm в определенную форму в коде (я не тестировал это, но приложение.MainForm читается / записывается, поэтому он может работать).
2) Наиболее элегантным является реализация интерфейса для всех форм, которые могут стать основной формой:
Создайте базовый интерфейс:
Public Interface INewArgumentsReceived
Sub NewArgumentsReceived(args As String())
End Interface
Измените код @Plutonix для MyApplication_StartupNextInstance на:
Private Sub MyApplication_StartupNextInstance(sender As Object, e As ApplicationServices.StartupNextInstanceEventArgs) Handles Me.StartupNextInstance
Dim f = Application.MainForm
If f.GetType.GetInterfaces.Contains(GetType(INewArgumentsReceived)) Then
CType(f, INewArgumentsReceived).NewArgumentsReceived(e.CommandLine.ToArray)
Else
MsgBox("The current program state can't receive new requests.",, vbExclamation)
End If
Теперь для всех возможных форм, которые могут стать основной формой, реализуйте интерфейс INewArgumentsReceived:
Public Class FormA: Implements INewArgumentsReceived
Public Sub NewArgumentsReceived(args As String()) Implements INewArgumentsReceived.NewArgumentsReceived
MsgBox("Got new arguments")
End Sub
Другим преимуществом использования интерфейсов является то, что мы можем проверить, работает ли текущее приложение.MainForm реализует его и может его получать.
Если текущее приложение.MainForm не реализует интерфейс, он корректно завершается с информационным сообщением.