文档章节

C#:从外部强制关闭用ShowDialog方法打开的模态窗口

北风其凉
 北风其凉
发布于 2017/01/03 15:05
字数 1454
阅读 998
收藏 9

在写C#程序时,一般我们不需要从外部强行关闭用ShowDialog方法打开的模态窗口。但在实际工作中,我遇到了一个非常坑爹的场景,需要在控制一个客户端程序锁屏前强制关闭由客户端程序打开的“打开”、“另存为”等窗口。因为这几个窗口是三方库打开的,我只能自己找方法手动关闭这几个窗口。

后来在网上找了一些资料,发现如下方法可以从外部关闭其他方法使用ShowDialog打开的模态窗口:

1、使用DllImport加载函数FindWindow和PostMessage

[DllImport("user32.dll")]
private static extern IntPtr FindWindow(string a, string b);

[DllImport("user32.dll")]
private static extern IntPtr PostMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);

2、使用下面方法关闭标题为指定文字窗口(需要将“窗体标题”替换为要关闭的窗体的标题)

IntPtr ptr1 = FindWindow(null, "窗体标题");
if (ptr1 != IntPtr.Zero)
{
    PostMessage(ptr1, 0x0010, IntPtr.Zero, IntPtr.Zero);
}

需要注意的是:

1、PostMessage函数执行后,指定要关闭的窗口并不会被立即关闭,而是有一个极短时间的延迟,所以若想在PostMessage函数调用后进行其他操作(如锁屏操作),建议先让程序Sleep约0.5秒的时间。

2、我做的用于输入密码的解锁窗体,在使用此方法关闭了指定模态窗口后虽然可以弹出,但并没有弹出到界面的最前面。此时需要在程序的其他部位点一下鼠标,解锁窗体才会蹦到前面来。于是我想了一个办法,使用SwitchToThisWindow方法将解锁窗体在Load函数执行完毕0.2秒后强制放到界面最前。

函数声明:

/// <summary>
/// 将窗体调整至界面最前
/// </summary>
/// <param name="hWnd"></param>
/// <param name="fAltTab"></param>
/// <returns></returns>
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool SwitchToThisWindow(IntPtr hWnd, bool fAltTab);

/// <summary>
/// 定时器,本窗口打开后,如未到界面最前,则在指定时间后强制调到界面最前 liwh - 20161215
/// </summary>
System.Windows.Forms.Timer timerSwitchToThisWindow = new System.Windows.Forms.Timer();

Load函数的末尾添加下面这句话:

//2秒后将窗体调整至界面最前 liwh - 20161215
timerSwitchToThisWindow.Tick += (obj, arg) =>
{
	SwitchToThisWindow(this.Handle, true);
	timerSwitchToThisWindow.Stop();
};
timerSwitchToThisWindow.Interval = 2000;
timerSwitchToThisWindow.Start();

下面放一个例子,我写了一个DEMO程序,测试此函数

界面上含有8个Button和1个TextBox用于输出文字

本DEMO程序针对ColorDialog、FolderBrowserDialog、FontDialog、OpenFileDialog、SaveFileDialog、MessageBox、使用Show方法打开的自定义窗体、使用ShowDialog方法打开的自定义窗体八种情况分别做了测试。点击8个按钮分别打开这八类窗体,有一个Timer每5秒检查一下这些窗口,如检测到这些窗口被打开了就关闭它们。

代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

namespace CloseDialogTest
{
    public partial class FormMain : Form
    {
        [DllImport("user32.dll")]
        private static extern IntPtr FindWindow(string a, string b);

        [DllImport("user32.dll")]
        private static extern IntPtr PostMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);

        public FormMain()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Load函数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FormMain_Load(object sender, EventArgs e)
        {
            Timer timer = new Timer();
            timer.Tick += (obj, arg) =>
                {
                    //1、尝试关闭ColorDialog
                    IntPtr ptr1 = FindWindow(null, "颜色");
                    if (ptr1 != IntPtr.Zero)
                    {
                        PostMessage(ptr1, 0x0010, IntPtr.Zero, IntPtr.Zero);
                        SetInfoBar("ColorDialog已关闭");
                    }
                    //2、尝试关闭FolderBrowserDialog
                    IntPtr ptr2 = FindWindow(null, "浏览文件夹");
                    if (ptr2 != IntPtr.Zero)
                    {
                        PostMessage(ptr2, 0x0010, IntPtr.Zero, IntPtr.Zero);
                        SetInfoBar("FolderBrowserDialog已关闭");
                    }
                    //3、尝试关闭FontDialog
                    IntPtr ptr3 = FindWindow(null, "字体");
                    if (ptr3 != IntPtr.Zero)
                    {
                        PostMessage(ptr3, 0x0010, IntPtr.Zero, IntPtr.Zero);
                        SetInfoBar("FontDialog已关闭");
                    }
                    //4、尝试关闭OpenFileDialog
                    IntPtr ptr4 = FindWindow(null, "打开");
                    if (ptr4 != IntPtr.Zero)
                    {
                        PostMessage(ptr4, 0x0010, IntPtr.Zero, IntPtr.Zero);
                        SetInfoBar("OpenFileDialog已关闭");
                    }
                    //5、尝试关闭SaveFileDialog
                    IntPtr ptr5 = FindWindow(null, "另存为");
                    if (ptr5 != IntPtr.Zero)
                    {
                        PostMessage(ptr5, 0x0010, IntPtr.Zero, IntPtr.Zero);
                        SetInfoBar("SaveFileDialog已关闭");
                    }
                    //6、尝试关闭MessageBox
                    IntPtr ptr6 = FindWindow(null, "测试消息");
                    if (ptr6 != IntPtr.Zero)
                    {
                        PostMessage(ptr6, 0x0010, IntPtr.Zero, IntPtr.Zero);
                        SetInfoBar("MessageBox已关闭");
                    }
                    //7、尝试关闭自定义窗口(Show)
                    IntPtr ptr7 = FindWindow(null, "自定义窗口(Show)");
                    if (ptr7 != IntPtr.Zero)
                    {
                        PostMessage(ptr7, 0x0010, IntPtr.Zero, IntPtr.Zero);
                        SetInfoBar("自定义窗口(Show)已关闭");
                    }
                    //8、尝试关闭自定义窗口(ShowDialog)
                    IntPtr ptr8 = FindWindow(null, "自定义窗口(ShowDialog)");
                    if (ptr8 != IntPtr.Zero)
                    {
                        PostMessage(ptr8, 0x0010, IntPtr.Zero, IntPtr.Zero);
                        SetInfoBar("自定义窗口(ShowDialog)已关闭");
                    }
                };
            timer.Interval = 5000;
            timer.Enabled = true;
            timer.Start();
        }

        /// <summary>
        /// 1、打开ColorDialog
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOpenColorDialg_Click(object sender, EventArgs e)
        {
            ColorDialog colorDialog = new ColorDialog();
            if (colorDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                Color selectedColor = colorDialog.Color;
                SetInfoBar("你选择了颜色:" + selectedColor.ToString());
            }
        }

        /// <summary>
        /// 2、打开FolderBrowserDialog
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOpenFolderBrowserDialog_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
            if (folderBrowserDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                string selectedPath = folderBrowserDialog.SelectedPath;
                SetInfoBar("你选择了目录:" + selectedPath);
            }
        }

        /// <summary>
        /// 3、打开FontDialog
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOpenFontDialog_Click(object sender, EventArgs e)
        {
            FontDialog fontDialog = new FontDialog();
            if (fontDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                Font selectedFont = fontDialog.Font;
                SetInfoBar("你选择了字体:" + selectedFont);
            }
        }

        /// <summary>
        /// 4、打开OpenFileDialog
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOpenOpenFileDialog_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                string selectedFile = openFileDialog.FileName;
                SetInfoBar("你选择了文件:" + selectedFile);
            }
        }

        /// <summary>
        /// 5、打开SaveFileDialog
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOpenSaveFileDialog_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            if (saveFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                string selectedPath = saveFileDialog.FileName;
                SetInfoBar("你选择了路径:" + selectedPath);
            }
        }

        /// <summary>
        /// 6、打开MessageBox
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOpenMessageBox_Click(object sender, EventArgs e)
        {
            MessageBox.Show("测试消息内容", "测试消息");
        }

        /// <summary>
        /// 7、通过Show打开自定义窗口
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOpenCustomWindowByShow_Click(object sender, EventArgs e)
        {
            //CustomForm构造函数接收的参数决定了该窗体的标题
            CustomForm costumForm = new CustomForm("自定义窗口(Show)");
            costumForm.Show();
        }

        /// <summary>
        /// 8、通过ShowDialog打开自定义窗口
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOpenCustomWindowByShowDialog_Click(object sender, EventArgs e)
        {
            //CustomForm构造函数接收的参数决定了该窗体的标题
            CustomForm costumForm = new CustomForm("自定义窗口(ShowDialog)");
            costumForm.ShowDialog();
        }

        /// <summary>
        /// 在文本框内显示指定文字
        /// </summary>
        /// <param name="info"></param>
        private void SetInfoBar(string info)
        {
            this.txtInfoBar.Text = info;
        }
    }
}

这个DEMO程序需要使用VS2012以上版本打开,可在此位置下载到:

https://pan.baidu.com/s/1gfhx0P1

END

© 著作权归作者所有

北风其凉

北风其凉

粉丝 121
博文 497
码字总数 462305
作品 4
朝阳
程序员
私信 提问
加载中

评论(1)

sikele
sikele
因为PostMessage是异步的,延时用Timer也太累了。。。
笔记4-从毕业生到程序员:使用c#开发商业软件

窗体的两种显示模式 模式窗体和非模式窗体。 模式窗体就是对话框,在一个应用程序中,一个对话框窗体霸占着用户的输入,用户在关闭对话框之前对应用程序的其他窗口不能进行任何操作。 在c#中...

zray4u
2016/03/31
64
0
监听浏览器返回按钮(popstate)

1.在模态框中控制返回的按钮,点击返回应该关闭模态框 2.在基本信息页面中不断的切换tab,点击返回按钮,返回到列表页 总结:1).在关闭页面之后需要销毁返回按钮的监听事件。2).如果是打开模...

Pcat
02/15
81
0
IE的模态对话框里的问题还真是不少

模态对话框(Modal Dialog),是一种会block顺序执行程序的窗口,比如C#里的MessageBox.Show(this,...),JavaScript里的alert(...)、confirm(...)等,是我们最常见的模态对话框。不关闭这种对话...

唐玄奘
2017/12/18
0
0
asp.net中窗口相关操作总结(javascript)

1.打开新窗口 这个简单:Response.Write(@" "); 2.关闭窗口 //关闭当前窗口,并提示用户时候关闭,yes关闭,no退出 Response.Write(@" "); //延迟关闭窗口(下面代码表示2秒后关闭,无需确认) Res...

晨曦之光
2012/03/09
94
0
JavaScript(Iframe、window.open、window.showModalD...

一、Iframe 篇 //父对象得到子窗口的值 //ObjectID是窗口标识,ContentID是元素ID function GetValue(ObjectID,ContentID) { var IsIE = (navigator.appName == 'Microsoft Internet Explore......

Cherish_you
2012/03/16
389
0

没有更多内容

加载失败,请刷新页面

加载更多

5 分钟快速学习,缓存一致性优化方案!

缓存操作 读缓存 读缓存可以分为两种情况命中(cache hit)和未命中(cache miss): 缓存命中 首先从缓存中获取数据 将缓存中的数据返回 缓存未命中 首先从缓存中获取数据 此时缓存未命中,...

架构文摘
9分钟前
3
0
【从入门到放弃-ZooKeeper】ZooKeeper实战-分布式锁-升级版

设计 我们依然实现java.util.concurrent.locks.Lock接口。 和上一文中实现方式不同的是,我们使用ZooKeeper的EPHEMERAL_SEQUENTIAL临时顺序节点。 当首次获取锁时,会创建一个临时节点,如果...

阿里云官方博客
11分钟前
3
0
inner join 和 union all 做的汇总区别

inner join CREATE OR REPLACE VIEW M_INVENT_BARCODE_DIFF ASSELECT "INV_PART_NO","INV_ONHAND","INV_LOCATION","PART_NO","BAR_ONHAND","BAR_LOCATION"FROM (SELECT m.part_no AS......

donald121
17分钟前
3
0
EMC 设计经验总结

整体布局 1、高速、中速、低速电路要分开; 2、强电流、高电压、强辐射元器件远离弱电流、低电压、敏感元器件; 3、模拟、数字、电源、保护电路要分开; 4 、多层板设计,有单独的电源和地平...

demyar
20分钟前
2
0
支付宝高级Java现场面试35题:页锁+死锁+集群+雪崩+负载等

年底是冲刺大厂的良机,这个时间点大部分人都在观望年终奖与加薪幅度,看情况再伺机而动,人才市场的竞争反而没那么激烈。 获悉到支付宝近期有HC放出,我通过内推渠道,得到了支付宝的面试机...

mikechen优知
23分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部