今天有個小需求, 程序要求執行一個檢測操作, 如果檢測失敗的話則彈出信息並且關閉程序
由於檢測代碼是封裝到一個獨立進程里的, 所以直接使用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

