Интересно, может ли кто-нибудь предоставить ссылку или объяснение о том, как проходит оболочка Windows, например, URL-адрес приложения по умолчанию, Internet Explorer, Google Chrome или параметр через приложение, созданное пользователем.
Я рассмотрел такие примеры, как: Запустить команды оболочки с помощью С# и получить информацию в строку
Проблема с вышеупомянутой ссылкой и другими подобными ссылками заключается в том, что они не работают так, как ожидалось, или на самом деле не отвечают на фактический вопрос. Например...
Этот код работает, как ожидалось:
private string EXEPath = @"C:\Program Files (x86)\Internet Explorer\iexplore.exe";
Process process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = EXEPath,
Arguments = "http://www.google.com.au",
UseShellExecute = true,
RedirectStandardOutput = false,
CreateNoWindow = true
}
};
process.Start();
Эта ссылка дает хороший пример того, как установить приложение в одно приложение-экземпляр: http://social.msdn.microsoft.com/Forums/vstudio/en-US/a5bcfc8a-bf69-4bbc-923d-f30f9ecf5f64/single- экземпляра приложения
Обработка аргументов следующим образом:
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1(args));
}
и в Form1, затем обрабатывая args следующим образом:
private string[] Args;
public MINION(string[] args)
{
InitializeComponent();
// Assign the incoming Arguments...
this.AppArgs = args;
}
public string[] AppArgs
{
set
{
this.Args = value;
if (this.Args.Length > 0)
{
foreach (string arg in this.Args)
{
// Do the processing here of each arg...
}
}
}
}
Я использую Click Once. У меня есть приложение с кодом VB Single Instance в приведенной выше ссылке. Этот код работает и работает только один экземпляр приложения.
Моя проблема:
Если я передам аргумент в свое приложение, тесты показывают, что идентификатор процесса не совпадает с идентификатором процесса работающего экземпляра. Таким образом, показывая, что экземпляр приложения, которое уже выполняется, не является экземпляром, с которым Args передается с кодом:
private string EXEPath = @"C:\Program Files (x86)\My App\My App.exe"; // Or actual path to EXE.
Process process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = EXEPath,
Arguments = "http://www.google.com.au",
UseShellExecute = true,
RedirectStandardOutput = false,
CreateNoWindow = true
}
};
process.Start();
Таким образом, этот код запускает новый экземпляр, даже если код установлен для установки приложения в одно экземплярное приложение. Существующий запущенный экземпляр приложения не обрабатывает переданные Args.
Новый экземпляр отобразит кодированный Messagebox ("Я запустил..."), но затем выйдет после этого.
EDIT @loopedcode - первый ответ. Это код, который я использую для обеспечения того, чтобы я постоянно разговаривал с одним и тем же EXE. Это тоже помогает. К сожалению, я уже рассмотрел ваше предложение.
Process[] runningProcess = Process.GetProcessesByName("MyEXEName.exe");
Process proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = runningProcess[0].MainModule.FileName,
Arguments = "http://www.google.com.au",
UseShellExecute = true,
RedirectStandardOutput = false,
CreateNoWindow = true
}
};
proc.Start();
Я могу проверить, что точно такой же путь действителен для Running Instance, а также для вызова Shell на EXE-путь.
EDIT - 11.08.14
Я хотел бы немного расширить вопрос.
При передаче параметра я получаю весь путь к обработке аргумента в новом Идентификаторе Процесса, тогда код, который переключает экземпляр в приложение с одним экземпляром, возвращается к существующему экземпляру. На этом этапе Args не передаются существующий экземпляр.
Если я использую:
MessageBox.Show("Program ID: " + (Process.GetCurrentProcess().Id) + " Arg Passed: " + this.Args[0]);
Он работает с новым экземпляром, но не с существующим экземпляром.
Наконец, решение. Решение исходит из проб и ошибок. Проблема, которую я использовал для настройки одного экземпляра приложения, была проблемой, или я должен сказать свое понимание того, как этот код был написан и работал. Это код, который был написан на ссылке выше.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Microsoft.VisualBasic.ApplicationServices;
namespace WindowsFormsApplication10
{
static class Program
{
static Form1 MainForm;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MainForm = new Form1();
SingleInstanceApplication.Run(MainForm, NewInstanceHandler);
}
public static void NewInstanceHandler(object sender, StartupNextInstanceEventArgs e)
{
//You can add a method on your Form1 class to notify it has been started again
//and perhaps pass parameters to it. That is if you need to know for instance
//the startup parameters.
//MainForm.NewInstance(e);
e.BringToForeground = true;
}
public class SingleInstanceApplication : WindowsFormsApplicationBase
{
private SingleInstanceApplication()
{
base.IsSingleInstance = true;
}
public static void Run(Form f, StartupNextInstanceEventHandler startupHandler)
{
SingleInstanceApplication app = new SingleInstanceApplication();
app.MainForm = f;
app.StartupNextInstance += startupHandler;
app.Run(Environment.GetCommandLineArgs());
}
}
}
}
Передача команд Аргументы строки в этом коде не так прямолинейны, как показано в коде. Конечно, это не так, как я ожидал. Логический поток просто не так, как ожидается. Не логично.
app.Run(Environment.GetCommandLineArgs());
Вышеприведенный код запускает новый экземпляр приложения, это очевидно. Ожидается, что это будет точка входа, но это не так.
public static void NewInstanceHandler(object sender, StartupNextInstanceEventArgs e)
{
//You can add a method on your Form1 class to notify it has been started again
//and perhaps pass parameters to it. That is if you need to know for instance
//the startup parameters.
//MainForm.NewInstance(e);
e.BringToForeground = true;
}
Вышеприведенный код обрабатывается как обработчик событий (НЕ НОВОГО экземпляра, но существующего экземпляра приложения). Мертвый отдать - это строка:
e.BringToForeground = true;
Поэтому, чтобы исправить проблему, я добавил в этот обработчик событий некоторый код для обработки переданных аргументов:
MainForm.AppArgs = new string[] { "Arg 1", "Arg 2" };
Этот тест работал, и я скорректировал этот код, чтобы принять аргументы:
static void Main(string[] args)
Строка args Array.
Таким образом, все должно было работать так, как я ожидал, добавив код третьей стороны к моему проекту, бросив в уравнение кривый шар, и потребовалось некоторое тестирование, чтобы выяснить, какие фактические процессы задействованы для получения правильных данных в нужную часть Приложения по адресу в нужное время.
Таким образом, процесс: EXE выполняется с аргументами → Аргументы передаются в "Основной" метод через строку [] args в новом Процессе с новым идентификатором Process ID → args устанавливаются в классе Variable в новом Process с новым идентификатором процесса → запускается новый процесс с новым идентификатором процесса и проверяет уже существующий экземпляр приложения → если есть существующий экземпляр, который он "перенесен" (это где я был потерян и Я передал свои аргументы существующему экземпляру), и новый процесс с новым идентификатором процесса.
Я все же, однако, не понимаю, как Аргументы передаются из одного экземпляра в другой без какого-либо Процессного кода? В качестве кода:
MainForm.AppArgs
На самом деле находится в другом Процессе с другим идентификатором процесса. Как-то все еще можно получить доступ? Или, может быть, процесс каким-то образом создается на этом этапе?
Чтобы это сработало, путь выполнения должен совпадать. Если вы создаете экземпляр ClickOnce, то ваш исполняемый путь недействителен, как в вашем примере:
private string EXEPath = @"C:\Program Files (x86)\My App\My App.exe"; // Or actual path to EXE.
Приложения ClickOnce загружаются в местоположение данных приложения пользователя. Вот где будет исполняться exe. В зависимости от версии Windows это может быть (см. Этот пост):
Win7
"c:\users\username\AppData\Local\Apps\2.0\obfuscatedfoldername\obfuscatedfoldername"
Или XP:
"C:\Documents and Settings\username\LocalSettings\Apps\2.0\obfuscatedfoldername\obfuscatedfoldername"
Имя папки (как в "obfuscatedfoldername") обычно основано на подписанном манифесте приложения. Если вы получите правильное имя папки в EXEPath, оно должно передать аргумент и работать правильно.