根据窗口句柄显示窗体

1、服务类型的应用程序一般都是单例模式,常规是要持续运行的,平常最小化到托盘,需要查看时可以点击托盘图标最大化,但是往往操作人员会误操作,程序已经打开又去重新运行程序,以前的做法是监测是否可以创建互斥进程,如果不能则说明程序已经运行,并提示客户软件已经运行,代码如下:

//单例模式

bool bCreatedNew;

System.Threading.Mutex mutex = new System.Threading.Mutex(false, Application.ProductName, out bCreatedNew);

if (!bCreatedNew)

{

MessageBox.Show("打开失败,已有消息中心服务正在运行!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);

return;

}

2、对这种方式进行改进,如果软件已经打开但是最小化到了托盘,用户再次运行软件,将隐藏在托盘里面的软件显示出来,而不是提示软件已经运行

方法一、使用FindWindow根据窗体类名或者标题获取窗体句柄(因为类名不会变化,所以优先使用类名获取),然后根据句柄显示窗体ShowWindow,让窗体获取焦点SwitchToThisWindow,然后获取窗体矩形框GetWindowRect,设置窗体显示位置SetWindowPos。

IntPtr hwnd = SingleProcess.FindWindow("WindowsForms10.Window.8.app.0.2bf8098_r11_ad1",null);

SingleProcess.ShowWin(hwnd);

获取窗体类名的方法:打开Spy++,找到“消息中心服务器”,右键属性-类 可以看到类名

方法二、开始没发现方法一,用的这种方法,获取已经运行的软件的进程,获取进程的MainWindowHandle,如果MainWindowHandle不为0(说明没有最小化)则直接根据窗口句柄显示窗体,同方法一步骤2,如果MainWindowHandle为0(由于在窗体最小化时,获取进程MainWindowHandle总是0),则枚举窗体窗体,当窗体标题与进程号满足设定值时,根据窗体句柄显示窗体。

SingleProcess.Singling("消息中心服务器");

3、完整代码:

 public class SingleProcess
    {
        //根据主窗体句柄显示窗体
        public static void ShowWin(IntPtr hwnd)
        {
            ShowWindow(hwnd, SW_RESTORE);
            SwitchToThisWindow(hwnd, true);

            Rect windowRec;
            GetWindowRect(hwnd, out windowRec);
            System.Drawing.Rectangle rect = System.Windows.Forms.SystemInformation.VirtualScreen;
            SetWindowPos(hwnd, HWND_TOP, (rect.Width - (windowRec.Right - windowRec.Left)) / 2,
                (rect.Height - (windowRec.Bottom - windowRec.Top)) / 2, 0, 0, SWP_NOSIZE);
        }

        private static string _formText;// = string.Empty;
        private static Process _process = null;
        /// <summary>
        ///
        /// </summary>
        /// <param name="str"></param>
        public static void Singling(string formtext)
        {
            _formText = formtext;
            Process instance = GetInstance();
            if (instance != null)   //首先确定有无进程
            {
                _process = instance;
                if (_process.MainWindowHandle.ToInt32() != 0) //是否托盘化
                {
                    //HandleRunningInstance(pro);
                    ShowWin(_process.MainWindowHandle);
                }
                else
                {
                    CallBack myCallBack = new CallBack(Report);
                    EnumWindows(myCallBack, 0);
                }
                //System.Environment.Exit(System.Environment.ExitCode);
            }

        }

        public static Process GetInstance()
        {
            Process current = Process.GetCurrentProcess();
            Process[] processes = Process.GetProcessesByName(Application.ProductName);//current.ProcessName);
            //遍历正在有相同名字运行的例程
            foreach (Process process in processes)
            {
                //忽略现有的例程
                if (process.Id != current.Id)
                {
                    //if (process.MainModule.FileName == current.MainModule.FileName)
                    {
                        //返回另一个例程实例
                        return process;
                    }
                }
            }
            //没有其它的例程,返回Null
            return null;
        }

        private static bool Report(IntPtr hwnd, int lParam)
        {
            //获得窗体标题
            StringBuilder sb = new StringBuilder(100);
            GetWindowText(hwnd, sb, sb.Capacity);

            int calcID;
            //获取进程ID
            GetWindowThreadProcessId(hwnd, out calcID);
            if ((sb.ToString() == _formText) && (_process != null) && (calcID == _process.Id)) //标题栏、进程id符合
            //if (pro != null && calcID == pro.Id) //进程id符合
            {
                ShowWin(hwnd);
                return true;
            }
            return true;

        }

        #region  win32 API
        /// <summary>
        /// 获取窗体句柄
        /// </summary>,两个参数至少要知道一个
        /// <param name="lpClassName">窗体类名,可以通过Spy++获取,为null表示忽略</param>
        /// <param name="lpWindowName">窗体标题,Text属性,为null时表示忽略</param>
        /// <returns></returns>
        [DllImport("user32.dll", EntryPoint = "FindWindow")]
        public extern static IntPtr FindWindow(string lpClassName, string lpWindowName);

        /// <summary>
        /// 根据窗体句柄获得窗体标题
        /// </summary>
        /// <param name="hWnd"></param>
        /// <param name="lpText"></param>
        /// <param name="nCount"></param>
        /// <returns></returns>
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpText, int nCount);

        /// <summary>
        /// 枚举窗体
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        [DllImport("user32")]
        private static extern int EnumWindows(CallBack x, int y);
        private delegate bool CallBack(IntPtr hwnd, int lParam);

        /// <summary>
        /// 根据窗体句柄获得其进程ID
        /// </summary>
        /// <param name="hwnd"></param>
        /// <param name="ID"></param>
        /// <returns></returns>
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        private static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID);

        /// <summary>
        /// 修改位置、大小
        /// </summary>
        /// <param name="hWnd"></param>
        /// <param name="hWndInsertAfter"></param>
        /// <param name="X"></param>
        /// <param name="Y"></param>
        /// <param name="cx"></param>
        /// <param name="cy"></param>
        /// <param name="uFlags"></param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        private static extern bool SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
        /// <summary>
        ///     Retains the current size (ignores the cx and cy parameters).
        /// </summary>
        static uint SWP_NOSIZE = 0x0001;
        static int HWND_TOP = 0;
        public struct Rect
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }

        [DllImport("user32.dll")]
        private static extern int GetWindowRect(IntPtr hwnd, out  Rect lpRect);

        /// <summary>
        /// 显示窗体,同  ShowWindowAsync 差不多
        /// </summary>
        /// <param name="hwnd"></param>
        /// <param name="nCmdShow"></param>
        /// <returns></returns>
        [DllImport("user32.dll", EntryPoint = "ShowWindow", CharSet = CharSet.Auto)]
        private static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
        private const int SW_RESTORE = 9;

        /// <summary>
        /// 该函数设置由不同线程产生的窗口的显示状态。 (没用)
        /// </summary>
        /// <param name="hWnd">窗口句柄</param>
        /// <param name="cmdShow">指定窗口如何显示。查看允许值列表,请查阅ShowWlndow函数的说明部分。</param>
        /// <returns>如果函数原来可见,返回值为非零;如果函数原来被隐藏,返回值为零。</returns>
        [DllImport("User32.dll")]
        private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);

        /// <summary>
        /// 该函数将创建指定窗口的线程设置到前台,并且激活该窗口。
        /// 键盘输入转向该窗口,并为用户改各种可视的记号。系统给创建前台窗口的线程分配的权限稍高于其他线程。
        /// (没用)
        /// </summary>
        /// <param name="hWnd">将被激活并被调入前台的窗口句柄。</param>
        /// <returns>如果窗口设入了前台,返回值为非零;如果窗口未被设入前台,返回值为零。</returns>
        [DllImport("User32.dll")]
        private static extern bool SetForegroundWindow(IntPtr hWnd);
        private const int WS_SHOWNORMAL = 1;

        /// <summary>
        /// 窗体焦点
        /// </summary>
        /// <param name="hWnd"></param>
        /// <param name="fAltTab"></param>
        [DllImport("user32.dll ", SetLastError = true)]
        private static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);

        #endregion

    }

4、调用

 //单例模式
            bool bCreatedNew;
            System.Threading.Mutex mutex = new System.Threading.Mutex(false, Application.ProductName, out bCreatedNew);
            if (!bCreatedNew)
            {
                tempForm.Close();
                IntPtr hwnd = SingleProcess.FindWindow("WindowsForms10.Window.8.app.0.2bf8098_r11_ad1",null);
                SingleProcess.ShowWin(hwnd);
                //SingleProcess.Singling("消息中心服务器");
                //MessageBox.Show("打开失败,已有消息中心服务正在运行!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

.参考

http://www.cnblogs.com/qingse/archive/2013/02/16/2913430.html

时间: 2024-08-29 14:04:38

根据窗口句柄显示窗体的相关文章

设计动画显示窗体

一.实例介绍 本文实现的动画是指,窗体显示的时候慢慢显示到用户面前,窗体关闭时,有一个动态效果! 二.设计思路 需要使用Windows提供的API函数AnimateWindow(),该函数存放在user.dll文件中,该函数的声明方法如下: [DllImport("user32.dll")]        private static extern bool AnimateWindow(IntPtr hwnd,int dwTime,int dwFlags); 其中参数意义如下: hwn

【笔记】动画显示窗体

实例说明 当用户启动程序后,普通的程序窗口都是瞬间显示到屏幕上,这样未免有些生硬.如果窗口能够慢慢的展现在用户面前,将会是什么样的效果?本例设计的是一个动画显示的窗体,该程序运行后,窗体是慢慢的以拉伸的效果显示到用户的面前.当关闭时也是一样慢慢的消失. 技术要点 Windows提供了一个API函数Animate Window,该函数可以实现窗体的动画效果,AnimateWindow函数在C#中的声明如下 1 [DllImportAttribute("user32.dll")] 2 pr

listview——显示窗体

listview——是用来显示的控件 一,属性 view:(显示的视图)LargeIcon——大图标:SmallIcon——小图标:Details——详细:List——列表:TItle——平铺 SmallImageList||LargeImageList:为项指定使用图片的集合 FullRowSelect:选择整行 GridLines:是否显示网格线 注意:1,要使用Details视图时一定要先添加列 2,在进行修改或删除时,一般需要把主键放在每个ListViewItem的Tag里面,使用窗体的

隐藏显示窗体

有时候我们在一个窗体编辑好了东西,但因为某些原因需要暂时关闭它(后面还需要使用),那我们就要在改改产生这个窗体的事件了. 1 //检测窗体是否已经存在,若不存在则新建窗体:若存在则将其Visible属性改为"true"即可. 2 if (frmOptionsDialog == null || frmOptionsDialog.IsDisposed) 3 { 4 frmOptionsDialog = new OptionForm(); 5 frmOptionsDialog.ShowDia

全屏显示窗体

实现效果: 知识运用: 窗体的WindowState属性 和FormBorderStyle属性 实现代码: private void Form1_MouseDoubleClick(object sender, MouseEventArgs e) { bool Validate=(this.WindowState==FormWindowState.Maximized); if(Validate){ this.FormBorderStyle = FormBorderStyle.Sizable; th

//显示窗体中所有控件的函数

function GetCtrls(MyForm: TForm): TStringList; var i: Integer; begin Result:=TStringList.Create; for i:=0 to MyForm.ComponentCount-1 do Result.Add(MyForm.Components[i].Name); end; procedure TForm1.Button1Click(Sender: TObject); begin Memo1.Lines.AddS

设置CAD显示窗体

AcDbViewTableRecord view; AcGePoint3d max = acdbHostApplicationServices()->workingDatabase()->extmax(), min = acdbHostApplicationServices()->workingDatabase()->extmin(); view.setCenterPoint(AcGePoint2d(ptInsert.x, ptInsert.y)); view.setHeight(

WinForm开发,窗体显示和窗体传值相关知识总结

以前对WinForm窗体显示和窗体间传值了解不是很清楚最近做了一些WinForm开发,把用到的相关知识整理如下 A.WinForm中窗体显示显示窗体可以有以下2种方法:Form.ShowDialog方法 (窗体显示为模式窗体)Form.Show方法 (窗体显示为无模式窗体) 2者具体区别如下:1.在调用Form.Show方法后,Show方法后面的代码会立即执行2.在调用Form.ShowDialog方法后,直到关闭对话框后,才执行此方法后面的代码3.当窗体显示为模式窗体时,单击"关闭"

WinForm窗体显示和窗体间传值[转载]

以前对WinForm窗体显示和窗体间传值了解不是很清楚 最近做了一些WinForm项目,把用到的相关知识整理如下 A.WinForm中窗体显示 显示窗体可以有以下2种方法: Form.ShowDialog方法 (窗体显示为模式窗体) Form.Show方法 (窗体显示为无模式窗体) 两者具体区别如下: 1.在调用Form.Show方法后,Show方法后面的代码会立即执行 2.在调用Form.ShowDialog方法后,直到关闭对话框后,才执行此方法后面的代码 3.当窗体显示为模式窗体时,单击“关