Windows Shell, передача параметров в Запуск экземпляра приложения

1

Интересно, может ли кто-нибудь предоставить ссылку или объяснение о том, как проходит оболочка 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]);

Он работает с новым экземпляром, но не с существующим экземпляром.

Теги:
arguments

2 ответа

1
Лучший ответ

Наконец, решение. Решение исходит из проб и ошибок. Проблема, которую я использовал для настройки одного экземпляра приложения, была проблемой, или я должен сказать свое понимание того, как этот код был написан и работал. Это код, который был написан на ссылке выше.

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 

На самом деле находится в другом Процессе с другим идентификатором процесса. Как-то все еще можно получить доступ? Или, может быть, процесс каким-то образом создается на этом этапе?

1

Чтобы это сработало, путь выполнения должен совпадать. Если вы создаете экземпляр 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, оно должно передать аргумент и работать правильно.

  • 0
    да, у меня есть код для выполнения этой работы автоматически, я убедился, что это не проблема. Смотрите РЕДАКТИРОВАТЬ выше.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню