【问题标题】:Opening a "known file type" into running instance of custom app - .NET在自定义应用程序的运行实例中打开“已知文件类型” - .NET
【发布时间】:2009-01-08 14:16:19
【问题描述】:

您如何将文件(在注册表中具有已知的文件/应用程序关联)打开到应该打开的应用程序的“运行实例”中?一个例子是,我打开了 Excel,然后单击了一个 XLS 文件.....该文件在当前 Excel 实例中打开。我想为自定义应用程序执行此操作......事件/消息传递如何“告诉”当前实例它需要打开文件?是否有一个“文件观察者”来寻找这样做的请求等?谢谢。。

【问题讨论】:

    标签: c# .net winforms


    【解决方案1】:

    您要做的是从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();
      }
    }
    

    您的应用程序的 Main 方法如下所示:

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

    注意标记为 的部分。您使用StartupNextInstanceEvent 的事件处理程序进行设置。当您有一个单实例应用程序(您在 MyWindowsApplicationBase 的构造函数中指定)时,当您的应用程序的 next 实例被触发时,将触发此事件。事件处理程序将传递一个 EventArgs 派生类,该类将具有命令行参数,然后您可以在应用程序的运行实例中处理这些参数。

    然后,您所要做的就是为您希望您的应用处理的文件类型正常设置文件关联,然后您就设置好了。

    【讨论】:

    • 在 C# 中包含对 VisualBasic dll 的引用对我来说似乎很奇怪,所以我通常采用全局互斥体路线,但这绝对更容易。 +1
    • @Lucas:我最初有这种反应,但它是框架的标准部分(随每次安装分发),因此有助于缓解我对这件事的感受。
    【解决方案2】:

    看起来您正在寻找的是创建单实例应用程序。这可以通过使用位于 Microsoft.VisualBasic.dll 中的 WindowsFormsApplicationBase 在 C# 中完成

    详情请看: http://www.hanselman.com/blog/TheWeeklySourceCode31SingleInstanceWinFormsAndMicrosoftVisualBasicdll.aspx 或搜索WindowsFormsApplicationBase

    【讨论】:

      【解决方案3】:

      我的做法是这样的:

      1. 首先在 main 方法中,检查进程列表中是否存在应用程序的现有实例。
      2. 如果找到,请使用您最喜欢的进程间通信方法(sending windows messages、远程处理、wcf 等)将文件名/路径发送到已运行的实例
      3. 关闭windows试图启动的新进程(因为现有实例已经处理了文件打开操作

      【讨论】:

      • @casperOne,嗯,即使有几千个进程在运行,也需要多长时间?如果它成为问题并且启动时间对他的应用程序很重要,他可以在 sep 线程中执行此操作,如果找到现有实例,则只需中断正常启动。
      • 扫描进程列表是一个浪费的过程。您真正应该做的是拥有一个 Mutex,它在应用程序运行时被应用程序获取。如果您无法获取它,则另一个实例正在运行。然后您使用消息传递工具向原始实例指示新参数。
      • @Joel:好吧,我已经完成了大部分工作,包含在 WindowsFormsApplicationBase 类中。像“需要多长时间”这样的评论也很无知,因为开销并不总是进程数的函数。
      • @Joel:因为如果你有机会将操作从 O(n) 时间减少到 O(1),而且很容易获胜,那么没有理由不接受它(如果它们具有相同的目的)。
      • 抛开速度和权限,扫描进程列表的可靠性如何?它不只是可执行文件的文件名吗?如果我重命名它呢?
      【解决方案4】:

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

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

      同时适用于多个文件,甚至在第一次也适用于多个文件(当应用程序尚未启动时)

      最重要的代码块是:

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

      源代码在“Broncode”按钮上提供

      【讨论】:

        【解决方案5】:

        Windows 为此使用DDE

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

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-01-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多