【问题标题】:Windows Shell, passing parameters to Running Instance of an ApplicationWindows Shell,将参数传递给应用程序的运行实例
【发布时间】:2014-09-28 19:17:05
【问题描述】:

我想知道是否有人可以提供有关 Windows Shell 如何传递的链接或解释,例如,默认应用程序、Internet Explorer、Google Chrome 的 URL 或自定义构建应用程序的参数。

我看过类似的例子:Run shell commands using c# and get the info into string

上述链接和其他类似链接的问题是它们没有按预期工作还是没有真正回答实际问题。比如……

此代码按预期工作:

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-instance-application

像这样处理参数:

/// <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 中像这样处理参数:

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...
}
}
}
}

我正在使用单击一次。我在上面的链接中设置了带有 VB 单实例代码的应用程序。此代码有效,并且只有一个应用程序实例运行。

我的问题:

如果我将参数传递给我的应用程序,测试会显示进程 ID 与正在运行的实例的进程 ID 不同。从而表明已经运行的 Application 的实例不是 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();

因此,即使代码已将应用程序设置为单实例应用程序,此代码也会启动一个新实例。正在运行的现有应用程序实例不会处理传递的参数。

新实例将显示一个编码消息框(“我已经运行...”),但之后退出。

编辑 @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();

我可以验证完全相同的路径对于正在运行的实例以及对 EXE 路径的 Shell 调用有效。

编辑 - 11.08.14

我想稍微扩展一下这个问题。

当传递参数时,我一直到处理新进程 ID 中的参数,然后将实例切换到单实例应用程序回到现有实例的代码启动。在这个阶段,参数是未传递给现有实例。

如果我使用:

MessageBox.Show("Program ID: " + (Process.GetCurrentProcess().Id) + " Arg Passed: " + this.Args[0]);

它在新实例上运行,但不在现有实例上。

【问题讨论】:

    标签: c# shell arguments


    【解决方案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 字符串数组。

    所以一切都应该像我预期的那样工作,向我的项目添加第三方代码会在等式中抛出一个曲线球,并且需要进行一些测试才能找出将正确数据传递到正确部分所涉及的实际过程在正确的时间申请。

    所以流程是:EXE 是带参数执行的 --> 参数通过 string[] args 在具有新进程 ID 的新进程中传递到“Main”方法中 --> args 设置在类变量中具有新进程 ID 的新进程 --> 具有新进程 ID 的新进程启动并检查已存在的应用程序实例 --> 如果存在现有实例,则将其“提出”(这是我丢失并且我已将我的参数传递给现有实例)并且具有新进程 ID 的新进程退出。

    但是,我仍然不明白如何在没有任何进程特定代码的情况下将参数从一个实例传递到另一个实例?如代码:

    MainForm.AppArgs 
    

    实际上是在具有不同进程 ID 的另一个进程中。不知何故,它仍然可以访问?或者也许此时进程以某种方式被实例化了?

    【讨论】:

      【解决方案2】:

      为此,可执行路径必须匹配。如果您正在实例化 ClickOnce,那么您的可执行路径与示例中的一样无效:

      private string EXEPath = @"C:\Program Files (x86)\My App\My App.exe"; // Or actual path to EXE.
      

      ClickOnce 应用程序被下载到用户的个人资料应用程序数据位置。那就是执行exe的地方。根据 Windows 版本,可能是 (see this post):

      Win7

      "c:\users\username\AppData\Local\Apps\2.0\obfuscatedfoldername\obfuscatedfoldername"
      

      或 XP:

      "C:\Documents and Settings\username\LocalSettings\Apps\2.0\obfuscatedfoldername\obfuscatedfoldername"
      

      文件夹名称(如“混淆文件夹名称”)通常基于应用程序清单签名密钥。如果您在 EXEPath 中检索到正确的文件夹名称,它应该会传递 arg 并正常工作。

      【讨论】:

      • 是的,我有代码可以自动完成这项工作,我已经验证这不是问题。请参阅上面的编辑。
      猜你喜欢
      • 2017-05-30
      • 1970-01-01
      • 2011-04-17
      • 2015-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多