每周源代码31—单实例WinForms和Microsoft.VisualBasic.dll

[原文发表地址] The Weekly Source Code 31- Single Instance WinForms and Microsoft.VisualBasic.dll

[原文发表时间] 2008-08-02 12:25

我最近遇到个有趣的问题(重点提到了我):

我是你博客的忠实读者,希望在单实例winform方面能得到帮助。 点击一个文件(.ext)时,我必须打开应用程序(文件和应用程序相关联,正如.doc 和WINWORD相连一样)。应用程序必须是单个的实例。点击the .ext文件时,应打开该内容的应用程序。如果一个实例正在运行,应该询问用户是否要关闭此应用程序并打开新的 .ext文件。我需要有关C#的帮助。

有些问题更有趣。但我认为我们15年来总是在一次次地解决这个“单实例”问题。我曾使用过Visual Basic 3中的Dan Appleman VBX,在Mutexes系统中也看到过许多解决方案和各种及其复杂的操作来解决这个简单问题。这个技术确实很老套,但是三年过去,却鲜有人了解WindowsFormsApplicationBase 类的存在以及它包含的多种有用功能。

关于操作,有一个有趣的线程。有人问到过这个问题,有人答道:“WinForms 2.0支持内置的单实例应用程序”。还有人则这样答道:“但它仅适用于Visual Basic应用程序”。

Microsoft.VisualBasic.dll已经成为最实用的 .NET Framework标准安装部件之一。大家都迟疑是否该从C#引用它。它看上去像是错误的。

这有点像在英文句子中突然冒出几个法语单词一样,在引用Microsoft.VisualBasic.dll时,je ne sais quoi(难以描述的事情) 给C#开发人员一种mal de mer(晕船)的感觉。但是这个程序集的存在是有着特定的raison d'être(重要原因)的。注意到了吗?你感觉它是错的,但它其实仍然是有效的。Microsoft.VisualBasic还是有很多了不起的东西。不能仅因为它不是System.Something,就意味着你不能任意引用它。唉,我要疯了!

回到正题。在众多的示例中,我见过的最简单的是一个OpenWinForms.com上的示例,它用C#语言编写并引用Microsoft.VisualBasic.dll 。我对它做了些修改,以便这个单实例应用程序可以打开传递到命令行的文本文件名。如果第二次调用相同的应用程序,它会运行新的命令行参数,并在第一个实例中加载这个文本文件。

加载这个单实例程序使其从命令行运行"SuperSingleInstance foo.txt"

clip_image002

然后,从相同的命令行开始,当第一个示例运行时,在命令行启动第二个"SuperSingleInstance bar.txt"。这将重用第一个实例,将其移到前面,并得到一个事件,告知我们有人正试图攻击我们,该事件包括新的命令行。

clip_image004

该代码真的很棒,因为所有的操作都在WindowsFormsApplicationBase中完成。这似乎有点让人困惑,因为你必须调用一个控制器实例,并告知你的MainForm,,而非调用Application.Run(). 当应用程序的第二个实例开始运行的时候,第一个应用程序就会调用StartupNextInstance 事件。它在第二个新的实例和原来的实例之间跨进程通信, 传递命令行。

usingSystem;

usingSystem.Windows.Forms;

usingMicrosoft.VisualBasic.ApplicationServices;

namespaceSuperSingleInstance

{

    ``staticclassProgram

    ``{

        ``[STAThread]

        ``staticvoidMain()

        ``{

            ``Application.EnableVisualStyles();

            ``Application.SetCompatibleTextRenderingDefault(``false``);

            ``string``[] args = Environment.GetCommandLineArgs();

            `` SingleInstanceController controller = ``newSingleInstanceController();

            ``controller.Run(args);

        ``}

    ``}

    ``publicclassSingleInstanceController : WindowsFormsApplicationBase

    ``{

        ``publicSingleInstanceController()

        ``{

            `` IsSingleInstance = ``true``;

            ``StartupNextInstance += this_StartupNextInstance;

        ``}

        ``voidthis_StartupNextInstance(``objectsender, StartupNextInstanceEventArgs e)

        ``{

            `` Form1 form = MainForm ``as Form1; ``//My derived form type

            ``form.LoadFile(e.CommandLine[1]);

        ``}

        ``protectedoverridevoidOnCreateMainForm()

        ``{

            `` MainForm = ``newForm1();

        ``}

    ``}

}

该表虽然很繁琐,你可以从文件中把文本加载到TextBox.

usingSystem;

usingSystem.Windows.Forms;

usingSystem.IO;

namespaceSuperSingleInstance

{

    ``publicpartialclassForm1 : Form

    ``{

        ``publicForm1()

        ``{

            ``InitializeComponent();

        ``}

        ``protectedoverridevoidOnLoad(EventArgs e)

        ``{

            ``base``.OnLoad(e);

            ``string``[] args = Environment.GetCommandLineArgs();

            ``LoadFile(args[1]);

        ``}

        ``publicvoidLoadFile(``stringfile)

        ``{

            ``textBox1.Text = File.ReadAllText(file);

        ``}

    ``}

}

WindowsFormsApplicationBase还有其他不错的功能,例如,支持SplashScreens和网络可用性事件。 Again, check out the good stuff over at https://www.openwinforms.com/ , like the Controller I used in this post.再者,你可以在 https://www.openwinforms.com/ 上查看一些好用的东西,比如我在这个帖子里用到的控制器就很不错。