【问题标题】:Show Form with PInvoke使用 PInvoke 显示表单
【发布时间】:2010-07-13 20:15:34
【问题描述】:

我有以下情况: WinForms 应用程序,它只允许运行此应用程序的一个实例(此处使用互斥锁进行检查)。以一些参数开始的应用程序正在运行但被隐藏。当有人再次点击应用程序时,Mutex 将检测到该应用程序已经在运行,并通过调用本地方法“取消隐藏”主窗体(参见下面的方法 BringWindowToFront)。

这里是查找和显示表单窗口的代码:

public static class NativeMethods
{
    public enum ShowWindowOptions
    {
        FORCEMINIMIZE = 11,
        HIDE = 0,
        MAXIMIZE = 3,
        MINIMIZE = 6,
        RESTORE = 9,
        SHOW = 5,
        SHOWDEFAULT = 10,
        SHOWMAXIMIZED = 3,
        SHOWMINIMIZED = 2,
        SHOWMINNOACTIVE = 7,
        SHOWNA = 8,
        SHOWNOACTIVATE = 4,
        SHOWNORMAL = 1
    }

    [DllImport("user32.dll")]
    public static extern int ShowWindow(int hwnd, int cmdShow);

    [DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
    public static extern IntPtr FindWindow(String lpClassName, String lpWindowName);

    [DllImport("USER32.DLL")]
    public static extern bool SetForegroundWindow(IntPtr hWnd);

    public static void BringWindowToFront(string windowTitle)
    {
        // Get a handle to the application.
        IntPtr handle = FindWindow(null, windowTitle);

        // Verify that app is a running process.
        if (handle == IntPtr.Zero)
        {
            return;
        }

        // With this line you have changed window status from example, minimized to normal
        ShowWindow((int)handle, (int)ShowWindowOptions.SHOWDEFAULT);

        // Make app the foreground application
        SetForegroundWindow(handle);
    }
}

一切都很好,但我还需要一个功能。 当主表单第一次取消隐藏时,我想显示另一个附加表单。通常我通过表单 _Shown 事件来完成。但是当我使用 PInvoke 方法显示窗口时,不会触发此事件。

所以基本上我想在显示主窗体时显示附加窗体(使用 ShowWindow PInvoke 方法)

这可能吗?任何其他想法如何实现它?

【问题讨论】:

  • 您是否坚持使用 P/Invoke 机制来执行此操作?还有其他方法可以完全在 C# 代码中生成单实例应用程序。
  • 我通过 Mutex 实现了单实例。现在,在我通过 public static extern int ShowWindow(int hwnd, int cmdShow); 显示 MainWindow 后,我坚持显示其他表单;

标签: c# winforms pinvoke winforms-interop


【解决方案1】:

编写单实例应用程序很棘手。您不必这样做,.NET 框架已经很好地支持它们。项目 + 添加引用,选择 Microsoft.VisualBasic。打开项目的 Program.cs 文件,使其如下所示:

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using Microsoft.VisualBasic.ApplicationServices;

namespace WindowsFormsApplication1 {
    class Program : WindowsFormsApplicationBase {
        [STAThread]
        static void Main(string[] args) {
            var prg = new Program();
            prg.EnableVisualStyles = true;
            prg.IsSingleInstance = true;
            prg.MainForm = new Form1();
            prg.Run(args);
        }

        protected override void OnStartupNextInstance(StartupNextInstanceEventArgs e) {
            var main = this.MainForm as Form1;
            main.WindowState = FormWindowState.Normal;
            main.BringToFront();
            // You could do something interesting with the command line arguments:
            //foreach (var arg in e.CommandLine) {
            //    main.OpenFile(arg);
            //}
        }
    }
}

【讨论】:

  • Scott Hanselman 有一篇很好的帖子 - hanselman.com/blog/…
  • 汉斯,谢谢你的例子。在我的特殊情况下,这种用于单实例应用程序的方法比 Mutex 好得多。所以我只是添加 frmAnother frm = new frmAnother();在 main.BringToFront() 之后;它完全按照我的意愿为我工作。谢谢!
【解决方案2】:

Form.Shown 事件仅在第一次显示表单时触发(即加载后),以后执行任何其他操作(例如,隐藏然后重新显示)都不会触发该事件。更多信息请见:http://msdn.microsoft.com/en-us/library/system.windows.forms.form.shown.aspx

还有一些其他事件可能对您的情况有用:

如果这些都不起作用,并且您必须使用 P/Invoke,那么我将使用 SetActiveWindow,它将发送 WM_ACTIVATE 消息,这将强制发送 Form.Activated

请注意,如果这不起作用(因为SetActiveWindow 发送了一个低位为 1 的 WM_ACTIVATE,表明该窗口不是由鼠标激活的,那么您可以通过发送一个使用您自己的 WM_ACTIVATE 消息直接向窗口发送消息。

【讨论】:

    猜你喜欢
    • 2016-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-04
    相关资源
    最近更新 更多