none
如何让其他线程隐藏的主窗口显示出来? RRS feed

  • 问题

  • 我要实现的功能如下:
    打开程序的时候先检查,如果这个程序已经在运行了,就直接将以前打开的程序窗口正常显示出来就行了。

    我的代码如下,但隐藏的窗口不能显示出来,请问怎么改?

    Program.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    using System.Reflection;
    
    namespace 例子01
    {
        static class Program
        {
    
            [DllImport("User32.dll")]
            private static extern bool ShowWindow(IntPtr hWnd, int cmdShow);
    
            [DllImport("User32.dll")]
            private static extern bool SetForegroundWindow(IntPtr hWnd);
            private const int WS_SHOWNORMAL = 1;
    
            /// <summary>
            /// 应用程序的主入口点。
            /// </summary>
            [STAThread]
            static void Main(string[] args)
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Process instance = RunningInstance();
                if (instance == null)
                {
                    Application.Run(new Form1());
                }
                else
                {
                    MessageBox.Show("程序已在运行中", "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    HandleRunningInstance(instance);
                }
            }
    
            /// <summary> 
            /// 获取正在运行的实例,没有运行的实例返回null; 
            /// </summary> 
            public static Process RunningInstance()
            {
                Process current = Process.GetCurrentProcess();
                Process[] processes = Process.GetProcessesByName(current.ProcessName);
                foreach (Process process in processes)
                {
                    if (process.Id != current.Id)
                    {
                        if (Assembly.GetExecutingAssembly().Location.Replace("/", "\\") == current.MainModule.FileName)
                        {
                            return process;
                        }
                    }
                }
                return null;
            }
    
            /// <summary> 
            /// 显示已运行的程序。 
            /// </summary> 
            public static void HandleRunningInstance(Process instance)
            {
                ShowWindow(instance.MainWindowHandle, WS_SHOWNORMAL); //显示,可以注释掉 
                SetForegroundWindow(instance.MainWindowHandle);            //放到前端 
            }
    
        }
    }
    

    Form1.cs

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace 例子01
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                this.Hide();
                this.ShowInTaskbar = false;
            }
    
            private void notifyIcon1_MouseClick(object sender, MouseEventArgs e)
            {
                    this.Show();
                    this.ShowInTaskbar = true;
            }
        }
    }
    

    2013年6月6日 5:53

答案

  • 你这个代码我在博客园看到了,文章中已经明确指出 “只有窗口最小化的时候可以达到此效果,如果隐藏到托盘则无法将打开的程序显示到桌面”,所以你上面的代码根本无法达到你的目的的,要实现你说的需求你需要用到FindWindow 函数,具体实现代码如下:

     static class Program
        {
            [DllImport("user32.dll")]
            public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
            [DllImport("user32.dll ", SetLastError = true)]
            static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
    
            [DllImport("user32.dll", EntryPoint = "ShowWindow", CharSet = CharSet.Auto)]
            public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
            public const int SW_RESTORE=9;
            public static IntPtr formhwnd;
            static Form1 form = null;
            ///<summary>
            /// 应用程序的主入口点。
            ///</summary>
            [STAThread]
            static void Main()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
    
                string proc = Process.GetCurrentProcess().ProcessName;
                Process[] processes = Process.GetProcessesByName(proc);
                if (processes.Length <= 1)
                {
                    form = new Form1();
                    Application.Run(form);
                }
                else
                {
                    for (int i = 0; i < processes.Length; i++)
                    {
                        if (processes[i].Id != Process.GetCurrentProcess().Id)
                        {
                            if (processes[i].MainWindowHandle.ToInt32() == 0)
                            {
                                formhwnd = FindWindow(null, "Form1");
                                ShowWindow(formhwnd,SW_RESTORE);
                                SwitchToThisWindow(formhwnd, true);
                            }
                            else
                            {
                                SwitchToThisWindow(processes[i].MainWindowHandle, true);
                            }
                        }
    
                    }
                }
    
            }
        }
    Form1.cs中代码和你原来代码一样的,我在本地测试是完全可以的,你可以自己试试


    If my post is helpful,please help to vote as helpful, if my post solve your question, please help to make it as answer. My sample

    2013年6月14日 7:25

全部回复

  • 因为你在Form_Load事件中调用了this.Hide方法把窗体隐藏了,其实此时已经创建了窗体的实例且已经初始化了窗体中所有控件,只是你没看到而已,你可以把在Form_Load中this.Hide方法去掉就可以达到你想要的效果了。

    If my post is helpful,please help to vote as helpful, if my post solve your question, please help to make it as answer. my sample

    2013年6月9日 10:39
  • 因为你在Form_Load事件中调用了this.Hide方法把窗体隐藏了,其实此时已经创建了窗体的实例且已经初始化了窗体中所有控件,只是你没看到而已,你可以把在Form_Load中this.Hide方法去掉就可以达到你想要的效果了。

    If my post is helpful,please help to vote as helpful, if my post solve your question, please help to make it as answer. my sample


    我需要窗体在启动时隐藏并在托盘显示图标,那个this.Hide不能去掉。
    2013年6月14日 3:05
  • 你的程序代码是没有错误的,刚才我在我这边测试过了,点击托盘上的图标是可以显示窗体的,你应该没有为NotifyIcon控件指定一个图片了。具体实现你也可以参考这个文章:

    http://www.cnblogs.com/BrightMoon/archive/2013/02/23/2923338.html


    If my post is helpful,please help to vote as helpful, if my post solve your question, please help to make it as answer. My sample

    2013年6月14日 5:18
  • 你的程序代码是没有错误的,刚才我在我这边测试过了,点击托盘上的图标是可以显示窗体的,你应该没有为NotifyIcon控件指定一个图片了。具体实现你也可以参考这个文章:

    http://www.cnblogs.com/BrightMoon/archive/2013/02/23/2923338.html


    If my post is helpful,please help to vote as helpful, if my post solve your question, please help to make it as answer. My sample

    可能我没说清楚,我现在的问题是:在该程序正在运行的情况下,再次打开这个程序的时候,阻止第2次运行该程序,并将第1次运行的程序窗口“正常化”显示在屏幕上。
    2013年6月14日 6:04
  • 你这个代码我在博客园看到了,文章中已经明确指出 “只有窗口最小化的时候可以达到此效果,如果隐藏到托盘则无法将打开的程序显示到桌面”,所以你上面的代码根本无法达到你的目的的,要实现你说的需求你需要用到FindWindow 函数,具体实现代码如下:

     static class Program
        {
            [DllImport("user32.dll")]
            public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
            [DllImport("user32.dll ", SetLastError = true)]
            static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
    
            [DllImport("user32.dll", EntryPoint = "ShowWindow", CharSet = CharSet.Auto)]
            public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
            public const int SW_RESTORE=9;
            public static IntPtr formhwnd;
            static Form1 form = null;
            ///<summary>
            /// 应用程序的主入口点。
            ///</summary>
            [STAThread]
            static void Main()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
    
                string proc = Process.GetCurrentProcess().ProcessName;
                Process[] processes = Process.GetProcessesByName(proc);
                if (processes.Length <= 1)
                {
                    form = new Form1();
                    Application.Run(form);
                }
                else
                {
                    for (int i = 0; i < processes.Length; i++)
                    {
                        if (processes[i].Id != Process.GetCurrentProcess().Id)
                        {
                            if (processes[i].MainWindowHandle.ToInt32() == 0)
                            {
                                formhwnd = FindWindow(null, "Form1");
                                ShowWindow(formhwnd,SW_RESTORE);
                                SwitchToThisWindow(formhwnd, true);
                            }
                            else
                            {
                                SwitchToThisWindow(processes[i].MainWindowHandle, true);
                            }
                        }
    
                    }
                }
    
            }
        }
    Form1.cs中代码和你原来代码一样的,我在本地测试是完全可以的,你可以自己试试


    If my post is helpful,please help to vote as helpful, if my post solve your question, please help to make it as answer. My sample

    2013年6月14日 7:25
  • 不行啊,没反应
    2014年3月14日 15:28
  • 不行啊,没反应

    是可以的,不过要注意一点就是下面这句代码中的"Form1",放到自己的程序中要注意替换。这里要替换为 “目标窗体”的标题,即目标窗体的 Text 属性中的字符串。

    formhwnd = FindWindow(null, "Form1");

    2015年2月19日 9:06
  • 不错,好文要顶。

    注意一点就是下面这句代码中的"Form1",放到自己的程序中要注意替换。这里要替换为 “目标窗体”的标题,即目标窗体的 Text 属性中的字符串。

    2016年1月13日 8:26
  • 可以显示到前端,这段代码没问题。

    但产生了一个新问题:

    被显示出来的页面中的动态加载的button都不显示了,重新刷新程序页面,button能够显示出来。

    有破解办法吗?

    2018年11月15日 7:02