向正在运行的应用程序传递参数

16

我正在制作一个图片上传器(将图片上传到图像托管网站),但是在传递参数(图像位置到已运行的应用程序)时遇到了一些问题。

  • 首先,假设MyApp.exe始终在运行。
  • 每当我右键单击图像时,在默认的Windows上下文菜单中添加了一个项目,名为“上传图像”。
  • 点击该项目后,需要将位置传递给已经运行的应用程序。

我的program.cs:

static class Program
{
    [DllImport("user32.dll")]
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32.dll")]
    static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, UIntPtr
    wParam, IntPtr lParam);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    static extern uint RegisterWindowMessage(string lpString);

    [STAThread]
    static void Main(params string[] Arguments)
    {
        if (Arguments.Length > 0)
        {
    //This means that the the upload item in the context menu is clicked
    //Here the method "uploadImage(string location)"
    //of the running application must be ran
        }
        else
        {
    //just start the application
            Application.Run(new ControlPanel());
        }
    }
}
请注意,ControlPanel类没有可见的窗体,只有托盘图标存在,因为不需要窗体。
我能得到如何做到这一点的任何帮助吗?
5个回答

18
我已经搞定了,感谢那个发布http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/a5bcfc8a-bf69-4bbc-923d-f30f9ecf5f64链接的人,这正是我要找的东西!
下面是完整的解决方案:
static class Program
{
    [STAThread]
    static void Main(params string[] Arguments)
    {
        SingleInstanceApplication.Run(new ControlPanel(), NewInstanceHandler);
    }

    public static void NewInstanceHandler(object sender, StartupNextInstanceEventArgs e)
    {
        string imageLocation = e.CommandLine[1];
        MessageBox.Show(imageLocation);
        e.BringToForeground = false;
        ControlPanel.uploadImage(imageLocation);
    }

    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());
        }
    }  
}

非常感谢大家,特别是那位发布了我上面提到的链接的人,但我想他删除了他的答案?

祝好, Kenny


Kenny,感谢您的帖子。它对我很有帮助。在NewInstanceHandler方法中是否有任何引用表单(您的ControlPanel)的方法?我知道您正在引用ControlPanel中的“uploadImage”方法,但那是一个静态方法。但我需要引用非静态方法。请告诉我。 - Dave

5
您需要建立一个通信渠道,让其他应用程序可以向其中发布图片。这个通信渠道可以是以下之一 - 不完整列表仅为示例:
  • 一个目录,由您的应用程序监视,一旦将文件添加到该目录中,文件就会被添加。
  • 其他应用程序可以发送信息的端口。
  • 接受图像的自托管 Web 服务。
  • 接收图像的 TCP 端口。
  • 命名管道。
  • ....
正如您所看到的,有几种可能性。适合您的正确选项取决于您的情况。文件系统是一个选项,可以使用 FileSystemWatcher 轻松实现样本,请参阅此处
自托管的 Web 服务公开了一个可以接收图像的 Web 服务,请参阅此处 以获取样本。
在我看来,这两个选项是最容易的。但是...还有几个选项。
有关 TCP 端口,请参见 Tim 的帖子。

1
+1 对于 FileSystemWatcher 的建议。我在许多应用程序中使用了 watcher 并取得了很好的结果。如果需要同步通信或请求/响应关系,我不会使用它,但似乎这些不是要求。 - Tim M.
嗨,谢谢你给了我一些额外的想法,但你应该知道我无法控制图像托管网站。我只是通过进行POST提交并检索响应(其中包含上传到互联网上的图像链接)来上传图像。我尝试了TCP的想法,但出于某种原因,我认为那不是我需要的东西。我有一个完全工作的应用程序,可以上传图像等。现在我唯一需要的就是: - Kenny

3
假设您对执行环境有控制权,监听应用程序可以使用WCF或原始TCP套接字公开端点。这样,任何其他应用程序都可以以动态但结构化的方式连接到它。
即使发送方和接收方在同一台机器上,使用网络传输解决方案(如WCF或TCP)也是安全地跨进程发送数据的好方法。
以下是使用c#中的TCP的示例:http://www.switchonthecode.com/tutorials/csharp-tutorial-simple-threaded-tcp-server WCF可能会更加复杂(部分原因是由于其灵活性,以及由于序列化限制),但有很多在线文档介绍如何使用它。WCF是一种更面向对象的解决方案,因为可以生成代理类,允许您对实际对象进行强类型调用,而不仅仅是发送消息。

2
为了避免在传递命令行参数给现有实例后运行第二个实例,我添加了以下代码片段。
static class Program
{
    [STAThread]

   static void Main(params string[] Arguments)
   {
        Form1 MainForm;
        bool bInstanceFlag;

        Mutex MyApplicationMutex = new Mutex(true, "MyApp_Mutex", out bInstanceFlag);

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        if (!bInstanceFlag)
        {
           MainForm = new Form1();
        SingleInstanceApplication.Run(MainForm, NewInstanceHandler);
    }
    else
    {
        MainForm = new Form1();
        SingleInstanceApplication.Run(MainForm, NewInstanceHandler);
        MainForm.Close();
    }
}

public static void NewInstanceHandler(object sender, StartupNextInstanceEventArgs e)
{
    MainForm.AddItem = e.CommandLine[1];
    e.BringToForeground = false;
}

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());
    }
}
}

1

我在之前的解决方案中添加了一些小的修改,以引用表单上的setter来将参数传递给它。

首先,创建一个对表单(MainForm)初始实例的静态引用。

然后,在随后发送参数时,NewInstanceHandler可以使用保存的表单引用来访问其公共方法/属性(在我的情况下,称为AddItem的setter)。

测试这个的简单方法是向您的表单添加一个公共属性,其中包含一个setter来更改表单的文本属性(标题文本)。

[STAThread]
    static Form1 MainForm;

    static void Main(params string[] Arguments)
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        MainForm = new Form1();
        SingleInstanceApplication.Run(MainForm, NewInstanceHandler);
    }

    public static void NewInstanceHandler(object sender, StartupNextInstanceEventArgs e)
    {
        MainForm.AddItem = e.CommandLine[1];
        e.BringToForeground = false;
    }

    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());
        }
    } 

确切地说,我遇到了同样的错误(当前上下文中不存在 'MainForm' 的名称)。Andy你有更新吗?我知道这很老了,希望你有解决方案。 - Anand

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接