GetActiveWindow 這個函數是幹嘛的

來源:互聯網
上載者:User

標籤:getactivewindow   setforegroundwindow   

問題引出:

    今天看了一下 深入解析MFC,第40頁到第50頁之間,有一句


  650) this.width=650;" src="http://s3.51cto.com/wyfs02/M02/2F/47/wKioL1OexYmisi79AAG7Pp4DiLM527.jpg" title="1.jpg" alt="wKioL1OexYmisi79AAG7Pp4DiLM527.jpg" />


這裡面說到了一個函數,,, GetActiveWindow,,根據直觀意思很容易理解 就是擷取  使用中視窗的控制代碼,但是什麼才是使用中視窗。


Retrieves a pointer to the active window.

//擷取一個指向使用中視窗的CWnd指標。
static CWnd* PASCAL GetActiveWindow( );
Return Value //傳回值

The active window or NULL if no window was active at the time of the call. The pointer may be temporary and should not be stored for later use.

//返回使用中視窗的控制代碼,如果在調用這個函數時沒有使用中視窗,則返回NULL。這個指標可能是指向臨時對象 因此不要 將它儲存起來以備後來之用。

Remarks//說明

The active window is either the window that has the current input focus or the window explicitly made active by the SetActiveWindow member function.

//使用中視窗是 擁有輸入焦點的視窗。顯示使用 SetActiveWindow 這個函數來指定的視窗也是使用中視窗。


上面是MSDN中給出的解釋 ,我做了簡單的翻譯。其實軟體技術本身並不複雜,複雜的是我們弄不清楚概念。但是上面 說明處 也給出了概念。那麼我們就來測試一下吧。


用VS2008 建立一個MFC 對話方塊程式。

然後再上面 對話方塊上放 2 個 編輯框(這樣就可以有輸入焦點了)。


然後 在 OnPaint 中添加如下代碼

void CTestDlg::OnPaint(){    if (IsIconic())    {        CPaintDC dc(this); // device context for painting        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);        // Center icon in client rectangle        int cxIcon = GetSystemMetrics(SM_CXICON);        int cyIcon = GetSystemMetrics(SM_CYICON);        CRect rect;        GetClientRect(&rect);        int x = (rect.Width() - cxIcon + 1) / 2;        int y = (rect.Height() - cyIcon + 1) / 2;        // Draw the icon        dc.DrawIcon(x, y, m_hIcon);    }    else    {        //新添加        HWND    hwndEdit1 = ((CEdit *)GetDlgItem(IDC_EDIT1))->m_hWnd;        HWND    hwndEdit2 = ((CEdit *)GetDlgItem(IDC_EDIT2))->m_hWnd;        CString    str;        str.Format("edit1:%x  edit2:%x  dlg:%x",hwndEdit1,hwndEdit2,m_hWnd);        CPaintDC  dc(this);        dc.TextOut(0,0,str);        CDialog::OnPaint();    }}

其實功能就是在  對話方塊的客戶區上輸出  兩個編輯框和主對話方塊的控制代碼值。

運行效果如下:

650) this.width=650;" src="http://s3.51cto.com/wyfs02/M02/2F/4A/wKiom1Oe0ByxAzZIAABfNXFrqU4895.jpg" title="1.jpg" alt="wKiom1Oe0ByxAzZIAABfNXFrqU4895.jpg" />


下面我們應該如何擷取一下 使用中視窗的控制代碼呢,就要用那個函數了,,我們來試試,問題是在哪裡使用這個函數呢?

因為要輸入焦點,而我們還想要切換焦點,所以,我想到了計時器,我們啟動一個計時器,比如10秒一次,在這裡面來調用函數。

在   BOOL CTestDlg::OnInitDialog()  裡面加上 SetTimer(1,10000,NULL);

為對話方塊添加 WM_TIMER 訊息響應函數

void CTestDlg::OnTimer(UINT_PTR nIDEvent){    // TODO: Add your message handler code here and/or call default    switch (nIDEvent)    {    case 1:        {            CWnd    * pWnd = CWnd::GetActiveWindow();            ASSERT(pWnd != NULL);            CString  str;            str.Format("%x",pWnd->m_hWnd);            AfxMessageBox(str);        }        break;    default:         break;    }    CDialog::OnTimer(nIDEvent);}

這樣子,我們的程式會每隔10秒鐘就彈出一個值,我們來測試一下,在測試過程中,我們可以對比彈出的值與對話方塊中輸出的三個值的關係,我們還可以點擊兩個編輯框,以讓它們擷取輸入焦點。


如果不出意外,那麼這個彈出的值會是 對話方塊的控制代碼,那麼什麼時候會出意外呢,就是你把其它視窗點開了,比如你切換到了瀏覽器視窗或者其它應用程式。這個時候 程式會出現 斷言錯誤,就是

 ASSERT(pWnd != NULL);

這時候,pWnd擷取的值是 NULL。

這裡很奇怪。

1、為什麼總是 對話方塊的控制代碼呢

2、為什麼一切換到其它視窗就命中斷言了呢


我們去看一下這個函數的實現吧。

_AFXWIN_INLINE CWnd* PASCAL CWnd::GetActiveWindow()
    { return CWnd::FromHandle(::GetActiveWindow()); }

這是先調用API 函數  GetActiveWindow  ,以擷取 控制代碼值,然後通過控制代碼值檢索對象或者構造臨時對象。

那麼我們就去看一下 這個API 的說明吧。


The GetActiveWindow function retrieves the window handle to the active window attached to the calling thread‘s message queue.

// 函數 GetActiveWindow 擷取 關聯到 調用線程的訊息佇列 的 使用中視窗的控制代碼值。


Syntax

HWND GetActiveWindow(VOID);

Return Value

The return value is the handle to the active window attached to the calling thread‘s message queue. Otherwise, the return value is NULL.

//意思跟上面差不多,但這裡我要說明一點知識,那就是一個線程只有一個訊息佇列,一個線程可以建立多個視窗,一個線程最多有一個使用中視窗,也可能沒有,明白這一點後你再看這點就可以理解了。


Remarks

To get the handle to the foreground window, you can use GetForegroundWindow.

Windows 98/Me and Windows NT 4.0 SP3 and later: To get the window handle to the active window in the message queue for another thread, use GetGUIThreadInfo.

//如果要擷取前台視窗的控制代碼,你應該使用  GetForegroundWindow 。

//如果要擷取其它線程中的使用中視窗,你應該使用  GetGUIThreadInfo。


好了,說了這麼多,我們終於有點眉目了。

雖然編輯框也是視窗,但這個函數中說明的視窗是指

  • Overlapped Windows   重疊的視窗

  • Pop-up Windows       快顯視窗

,而不是

  • Child Windows        子視窗

  其實視窗還有另外兩種類型

  • Layered Windows      帶透明效果的視窗

  • Message-Only Windows 僅訊息視窗(不可見,沒次序,僅允許收發訊息)


好了,這樣我們就明白了,編輯框是視窗不假,但是它是子視窗,而且在MFC對這個函數的說明不是太明確。


現在也就是 如果 我們再開一個背景工作執行緒,在這裡來 用 GetActiveWindow  ,這是肯定不行的,因為我們的這個背景工作執行緒 自身 並沒有建立視窗。當我們啟用一個視窗時,就是在工作列點擊一個視窗程序,這個時候這個程式就擁有了輸入焦點,它就是使用中視窗。


還是之前的例子,我們在 程式的 標題列上右擊,選擇關於 ,此時會再彈出一個模態對話方塊,如

650) this.width=650;" src="http://s3.51cto.com/wyfs02/M01/2F/4A/wKioL1Oe10rwMACyAADXu9lpi1M613.jpg" title="1.jpg" alt="wKioL1Oe10rwMACyAADXu9lpi1M613.jpg" />


可以看出不再是主對框了,因為在沒有彈出Test 那個對話方塊之前,About Test 才是 這個線程 中的 使用中視窗。如果再等 幾十秒(不要點確定),會發現 他還會彈出 提示框,而且每次的結果都不一樣,

650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/2F/4A/wKioL1Oe2BKiMbNWAADtWYmvatI093.jpg" title="1.jpg" alt="wKioL1Oe2BKiMbNWAADtWYmvatI093.jpg" />


這是因為當第一個提示框彈出後,它就變成了使用中視窗了,第2個彈出的就是第一個的控制代碼了,第3個彈出的就是第二個的控制代碼了。


當我們一切到其它視窗的時候,程式會因為斷言宏 的問題 而中斷。


還有一個問題 就是,我們可以開一個線程,來擷取 其它線程中的 使用中視窗。


定義一個線程


UINT __cdecl Worker( LPVOID pParam )
{
    CTestDlg  * pDlg = (CTestDlg *)pParam;
    ASSERT(pDlg != NULL);
    DWORD  tid = GetWindowThreadProcessId(pDlg->m_hWnd,NULL);
    GUITHREADINFO   guiTI = {0};
    guiTI.cbSize = sizeof(GUITHREADINFO);
    GetGUIThreadInfo(tid,&guiTI);
    CString  str;
    str.Format("%x\n",guiTI.hwndActive);
    AfxMessageBox(str);
    return 0;
}


然後將 計時器  中 換成

    switch (nIDEvent)
    {
    case 1:
        {
            AfxBeginThread(Worker,(LPVOID)this);
        }
        break;


650) this.width=650;" src="http://s3.51cto.com/wyfs02/M02/2F/4A/wKioL1Oe2n2TFqduAAHVx9oPFX4044.jpg" title="1.jpg" alt="wKioL1Oe2n2TFqduAAHVx9oPFX4044.jpg" />

這樣子依舊可以擷取 其 使用中視窗,當然可以利用這種方式 來擷取  其它 軟體 的 使用中視窗哦。


如果還有不明白的地方,那就是前台視窗 與 使用中視窗 這兩個概念的 區別了。


不妨來做個測試。

我們隨便寫個小按鈕響應事件


//點擊開始菜單,點擊運行,,輸入  notepad 斷行符號即可

    HWND     hwndNotepad = ::FindWindow(NULL,"無標題 - 記事本");
    ASSERT(hwndNotepad != NULL);
    ::SetForegroundWindow(hwndNotepad);


功能就是將記事本  置成前台,我們發現 記事本  果然就 跑前面來了,而且也被啟用了。


那麼它們到底有什麼區別嗎?


1、設定都沒有什麼好說的

2、擷取,一個是針對某一線程進行擷取,一個是針對整個系統中的所有視窗進行擷取

3、反上去,其它設定也是範圍不同,一個針對線程,另一個針對系統。


什麼時候應該哪個,要取決於你具體的目的是什麼,然後再做一個判斷。


其實說到這裡應該結束了,但是其實還有一點,就是如何 在一個線程中,啟用另一個線程中的 視窗,說白了就是 線程A 沒有視窗,線程B有3個視窗,我想用A 啟用B中的 2號視窗,怎麼辦。 擷取是 使用的GetGUIThreadInfo ,設定 可沒有  SetGUIThreadInfo 這個函數的,


這個時候 ,我們應該行看看MSDN中有沒有辦法


By using the AttachThreadInput function, a thread can attach its input processing to another thread. This allows a thread to call SetActiveWindow to activate a window attached to another thread‘s message queue.


可以看到 可以使用 AttachThreadInput 這個函數可以將 一個線程 的輸入處理 關聯到 另一個線程,進而 完成 設定 其它線程中的 使用中視窗的 目的。


可能有的人還不清楚 一個程式到底有多少個視窗,哈哈,這個是初學者最不容易理解的地方,一個程式可以有多個視窗的,舉一個例子吧,VS2008 等類似的軟體有吧,,知道怎麼設定行號嗎,知道怎麼改變字型大小嗎,知道怎麼建立工程嗎,知道怎麼添加檔案嗎,好吧,這些功能,每一個都是一個對話方塊哦,再比如,一個記事本程式,裡面有搜尋功能吧,這也是一個對話方塊,還有 最後一個例子,


直接

650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/2F/4A/wKiom1Oe4C3jiNAyAANCwasOPU0730.jpg" title="1.jpg" alt="wKiom1Oe4C3jiNAyAANCwasOPU0730.jpg" />


好了,我想大家對使用中視窗應該理解了吧。。。。

本文出自 “千千闕歌” 部落格,請務必保留此出處http://qianqianquege.blog.51cto.com/8004200/1427059

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.