彈出一個非阻塞對話框(在程序關閉后 仍然顯示對話框)


今天有個小需求, 程序要求執行一個檢測操作, 如果檢測失敗的話則彈出信息並且關閉程序

由於檢測代碼是封裝到一個獨立進程里的, 所以直接使用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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM