弹出一个非阻塞对话框(在程序关闭后 仍然显示对话框)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了弹出一个非阻塞对话框(在程序关闭后 仍然显示对话框)相关的知识,希望对你有一定的参考价值。

今天有个小需求, 程序要求执行一个检测操作, 如果检测失败的话则弹出信息并且关闭程序

由于检测代码是封装到一个独立进程里的, 所以直接使用TerminateProcess(GetCurrentProcess, 0);来关闭当前进程

可是在测试时却发现, 原本使用MessageBox来弹出消息却会阻塞结束进程的操作

一般我们在系统里弹出对话框都是调用Windows.MessageBox, 这个方法在一般情况下, 可以不阻塞本程序的操作(虽然在代码层面仍然是阻塞的)

 

大家可以用一个小例子试试

procedure TForm1.Button1Click(Sender: TObject);
begin
  MessageBox(0, ‘测试内容1‘, ‘测试标题‘, MB_OK);
  MessageBox(0, ‘测试内容2‘, ‘测试标题‘, MB_OK);
end;

实际情况执行以后, 点击按钮弹出第一个对话框, 这时, 虽然程序界面仍然可以移动输入等执行其他操作, 但是测试内容2却没有弹出

只有吧第一个对话框关闭以后, 第2个对话框才能弹出来

所以, 猜测MessageBox的非阻塞只是在内部处理了对当前进程的消息循环, 但是代码层面并没有返回并向后执行, 所以并不是真正意义上的非阻塞

 

那需求怎么办呢.......

 

伟大的Google, 码农们需要你的时候来了(虽然这几天Google又被伟大的GFW给墙了...不过咱们可以换IP...嘿嘿 你懂的: 啦啦啦)

终于搜到一个相关的文章, 关于在win7下如果让一个服务向用户界面推送消息的问题: 穿透Session0隔离

其中有一个关键性函数: WTSSendMessage, 可以向指定的Session发送消息

既然是想Session发送消息, 那肯定是桌面级的, 和应用程序无关了呗, 咱们再看看他的定义: WTSSendMessage function

显然, 最后一个参数是控制是否阻塞等待的, 看来这就是我要的东西了, 马上写代码试试:

补充一下, 不知道为什么 这个自从XP就出现的函数, 直到Delphi XE5都没有被定义到Windows单元中, 而其他的2个WTS相关函数却定义了(也许定义到其他单元我没找到?)

技术分享
const
  WTS_CURRENT_SERVER_HANDLE = 0;

function WTSSendMessage(Server: HWND; SessionId: DWORD; Title: PChar;
  TitleLength: DWORD; AMessage: PChar; MessageLength: DWORD; Style: DWORD;
  Timeout: DWORD; var Response: DWORD; Wait: Boolean): Boolean; stdcall;
  external ‘wtsapi32.dll‘ name ‘WTSSendMessageA‘;

function WTSGetActiveConsoleSessionId: DWORD; stdcall;
  external kernel32 name ‘WTSGetActiveConsoleSessionId‘;


procedure TForm1.Button1Click(Sender: TObject);
var
  nTitle, nMessage: string;
  nResponse: DWORD;
begin
  nTitle := ‘测试标题‘;
  nMessage := ‘测试内容1‘;
  WTSSendMessage(WTS_CURRENT_SERVER_HANDLE, WTSGetActiveConsoleSessionId,
    PChar(nTitle), Length(nTitle), PChar(nMessage), Length(nMessage),
    MB_OK, 0, nResponse, False);
  nMessage := ‘测试内容2‘;
  WTSSendMessage(WTS_CURRENT_SERVER_HANDLE, WTSGetActiveConsoleSessionId,
    PChar(nTitle), Length(nTitle), PChar(nMessage), Length(nMessage),
    MB_OK, 0, nResponse, False);
end;
技术分享

执行测试一下, 我擦....居然还是必须先吧内容1确定了以后才能弹出内容2? 难道是我理解错了不成?

单步跟踪一下...#^&%^*

不对啊, 弹出了内容1马上就执行到内容2的代码了啊, 然后就直接end结束了, 可是为什么只弹出了1个对话框呢?

再补充一下测试

技术分享
const
  WTS_CURRENT_SERVER_HANDLE = 0;

function WTSSendMessage(Server: HWND; SessionId: DWORD; Title: PChar;
  TitleLength: DWORD; AMessage: PChar; MessageLength: DWORD; Style: DWORD;
  Timeout: DWORD; var Response: DWORD; Wait: Boolean): Boolean; stdcall;
  external ‘wtsapi32.dll‘ name ‘WTSSendMessageA‘;

function WTSGetActiveConsoleSessionId: DWORD; stdcall;
  external kernel32 name ‘WTSGetActiveConsoleSessionId‘;


procedure TForm1.Button1Click(Sender: TObject);
var
  nTitle, nMessage: string;
  nResponse: DWORD;
begin
  nTitle := ‘测试标题‘;
  nMessage := ‘测试内容1‘;
  WTSSendMessage(WTS_CURRENT_SERVER_HANDLE, WTSGetActiveConsoleSessionId,
    PChar(nTitle), Length(nTitle), PChar(nMessage), Length(nMessage),
    MB_OK, 0, nResponse, False);
  nMessage := ‘测试内容2‘;
  WTSSendMessage(WTS_CURRENT_SERVER_HANDLE, WTSGetActiveConsoleSessionId,
    PChar(nTitle), Length(nTitle), PChar(nMessage), Length(nMessage),
    MB_OK, 0, nResponse, False);
  TerminateProcess(GetCurrentProcess, 0);
end;
技术分享

看看这样, 执行结果, 果然 程序关闭了, 但是只有内容1的对话框, 确定以后才弹出内容2的

个人猜测, 应该是WTSSendMessage以类似消息队列方式给Session发对话框消息, 而对于Session的处理, 则必须是阻塞的, 估计是为了能够让用户知道多条消息的先后顺序吧

 

无所谓啦, 只要程序不阻塞就行, 搞定....嘿嘿嘿嘿.......

http://www.cnblogs.com/hs-kill/p/3797103.html

以上是关于弹出一个非阻塞对话框(在程序关闭后 仍然显示对话框)的主要内容,如果未能解决你的问题,请参考以下文章

Qt的模态对话框和非模态对话框 经常使用setAttribute (Qt::WA_DeleteOnClose)

Android:为什么我的进程在应用程序崩溃后仍然存活?

在 SaveAs 对话框前面显示弹出消息

Qt 之 模态非模态半模态窗口的介绍及 实现QDialog的exec()方法

c#,如何弹出一个显示在最前面但没有焦点的窗口?谢谢!

如果蓝牙关闭 iOS,则禁用警告对话框