打开“已知文件类型”到正在运行的自定义应用程序实例 - .NET

8
你如何打开一个已知文件/应用程序关联的文件(在注册表中)到“正在运行的实例”中呢?例如,我打开了Excel并单击XLS文件......文件会在当前Excel实例中打开。我想为自定义应用程序做到这一点...事件/消息是如何工作的,告诉当前实例需要打开一个文件?是否有一个“文件监视器”来查找请求等?谢谢。
5个回答

14

你需要继承一个来自 WindowsFormsApplicationBase 的类,并将保护的 IsSingleInstance 属性设置为 true:

// This should all be refactored to make it less tightly-coupled, obviously.
class MyWindowsApplicationBase : WindowsFormsApplicationBase
{
  internal MyWindowsApplicationBase() : base()
  {
    // This is a single instance application.
    this.IsSingleInstance = true;

    // Set to the instance of your form to run.
    this.MainForm = new MyForm();
  }
}

你的应用程序的主方法应该像这样:

// This should all be refactored to make it less tightly-coupled, obviously.
public static void Main(string args[])
{
  // Process the args.
  <process args here>

  // Create the application base.
  MyWindowsApplicationBase appBase = new MyWindowsApplicationBase();

  // <1> Set the StartupNextInstance event handler.
  appBase.StartupNextInstance = <event handler code>;

  // Show the main form of the app.
  appBase.Run(args);
}

注意标记为<1>的部分。你需要为StartupNextInstanceEvent设置事件处理程序来完成此操作。当你有一个单实例应用程序(在MyWindowsApplicationBase的构造函数中指定)并且启动下一个应用程序实例时,该事件将被触发。事件处理程序会传递一个派生自EventArgs的类,其中包含命令行参数,然后您可以在运行实例中处理它们。

接下来,您只需正常设置文件关联,以处理您希望应用程序处理的文件类型,然后您就完成了。


在C#中引用VisualBasic dll对我来说似乎很奇怪,所以我通常会选择全局Mutex路线,但这绝对更容易。+1 - Lucas
@Lucas:一开始我也有同样的反应,但是它是框架的标准部分(随每个安装程序一起分发),这有助于缓解我的疑虑。 - casperOne

3

2
我会这样做:
  1. 在主方法中,首先检查进程列表中是否存在该应用程序的实例。
  2. 如果找到了,使用您喜欢的进程间通信方法(如发送Windows消息、远程调用、WCF等)将文件名/路径发送给已经运行的实例。
  3. 关闭Windows尝试启动的新进程(因为现有实例已经处理了文件打开操作)。

@casperOne,哎,即使有几千个进程在运行,需要多长时间呢?如果这成为一个问题,并且启动时间对他的应用程序很重要,他可以在一个单独的线程中执行它,如果发现已存在实例,则只需中断正常启动即可。 - Joel Martinez
扫描进程列表是一种浪费时间的过程。你真正应该做的是拥有一个互斥锁,当应用程序运行时它被获取。如果你无法获取它,那么另一个实例正在运行。然后,你可以使用消息工具向原始实例指示新参数。 - casperOne
@Joel:嗯,我一直在工作到一个点,那就是大部分的工作已经为你完成了,封装在WindowsFormsApplicationBase类中。像“需要多长时间”这样的评论也相当无知,因为开销并不总是与进程数量成正比。 - casperOne
@Joel:因为如果你有机会将操作时间从O(n)降至O(1),而且这是一个容易的胜利,那么没有理由不去做(如果它们具有相同的目的)。 - casperOne
除了速度和权限之外,扫描进程列表的可靠性如何?它不仅仅是可执行文件的文件名吗?如果我重命名它会怎样? - Lucas

0

使用TCP套接字的示例: http://pieterjan.pro/?a=Projecten_csharp_DrawIt.php

  1. 在窗体上启动TCPListener
  2. 在第二个实例的主函数中连接TCPClient
  3. 通过TCP连接将ActivationArguments发送到窗体

同样适用于同时处理多个文件,甚至在应用程序尚未启动时也可以处理多个文件。

最重要的代码块是:

  1. MainForm(Hoofdscherm)的构造函数,在其中启动服务器并将端口号写入文件。还会打开第一个文件。
  2. Main函数(Program.cs),第二个、第三个等实例连接到第一个实例的TcpListener,并通过套接字发送文件名

源代码可在“Broncode”按钮上找到。


-1

Windows使用DDE来实现此目的。

动态数据交换(DDE)是一种在Microsoft Windows或OS/2下多个应用程序之间进行通信的技术。

Word或Office文件的注册表关联通常除了常规文件关联外,还有DDE命令(如果应用程序已经在运行,则执行该命令)。

因此,您可以在C#应用程序中托管一个DDE服务器来实现此功能。


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