欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
QQ截圖時(shí)窗口自動(dòng)識別的原理(WindowFromPoint, ChildWindowFromPoint, ChildWindowFromPointEx,RealChildWindowFromPoin

新版的QQ在截圖時(shí)加入了窗口自動(dòng)識別的功能,能根據鼠標的位置自動(dòng)畫(huà)出下面窗口的輪廓。今天有人在論壇上問(wèn)起這個(gè)問(wèn)題,下面我們來(lái)探討這個(gè)功能的實(shí)現原理。

首先我們要明白截圖軟件的基本原理,截圖時(shí)實(shí)際上是新建了一個(gè)全屏窗口,然后將當前桌面的截圖畫(huà)在上面,大部分截圖軟件,包括QQ都是這么做的。根據鼠標位置獲取下層窗口,有好幾個(gè)類(lèi)似的API可以用(WindowFromPoint, ChildWindowFromPoint, ChildWindowFromPointEx,RealChildWindowFromPoint)。

這里我們重點(diǎn)關(guān)注ChildWindowFromPointEx,因為我們知道截圖時(shí)有個(gè)全屏窗口覆蓋在上面,通過(guò)鼠標位置去取得窗口,肯定首先取到的是這個(gè)全屏窗口,所以我們要把這個(gè)窗口過(guò)濾掉,而只有ChildWindowFromPointEx這個(gè)API有窗口過(guò)濾功能。

HWND ChildWindowFromPointEx(      

    HWND hwndParent,     POINT pt,     UINT uFlags );

Parameters

hwndParent
[in] Handle to the parent window.
pt
[in] Specifies a POINT structure that defines the client coordinates (relative to hwndParent) of the point to be checked.
uFlags
[in] Specifies which child windows to skip. This parameter can be one or more of the following values.
CWP_ALL
Does not skip any child windows
CWP_SKIPINVISIBLE
Skips invisible child windows
CWP_SKIPDISABLED
Skips disabled child windows
CWP_SKIPTRANSPARENT
Skips transparent child windows


所以我們有理由相信QQ的全屏窗口用了WS_EX_LAYERED屬性,然后QQ通過(guò)調用ChildWindowFromPointEx(hWndDesktop,ptCursor, CWP_SKIPINVISIBLE|CWP_SKIPTRANSPARENT), 這樣就可以過(guò)濾掉不可見(jiàn)的和Layered窗口,然后通過(guò)遞歸調用該API,就可以獲取里面的子窗口了。

為了驗證我們猜想,怎么可以自己建立一個(gè)Layered Window,然后用QQ截圖,可以看到QQ是無(wú)法識別該窗口的。

另外我們可以在啟動(dòng)QQ截圖后,通過(guò)Windows鍵激活任務(wù)欄,然后改變通過(guò)任務(wù)欄最小化或是關(guān)閉某個(gè)包含在截圖內的窗口,再繼續截圖就會(huì )發(fā)現QQ沒(méi)法識別了。這也說(shuō)明了QQ截圖是實(shí)時(shí)通過(guò)ChildWindowFromPointEx來(lái)獲取下層窗口的。這也算是QQ截圖的一個(gè)Bug。

很多截圖軟件卻沒(méi)有上述問(wèn)題,我想他們應該是在開(kāi)始截圖時(shí)保存了桌面上所有窗口的層次關(guān)系和所在區域,后面用的都是當時(shí)保存的信息來(lái)識別的,這樣即使后面下面的窗口變化了,識別也不會(huì )受到影響。

另外,有些截圖軟件能夠識別到比窗口粒度更小的元素,比如Toolbar控件上的每個(gè)Item,他們用的應該是MSAA(Microsoft Active Accessibility),標準控件一般都支持該接口。

看到有些人對通過(guò)枚舉方式識別窗口的代碼感興趣 , 下面是我的代碼:

class CSCWinFilter
{
public:
    static BOOL IsFilterWindow(HWND hWnd)
    {
        _ASSERTE(hWnd != NULL);
        DWORD dwProcessID = GetCurrentProcessId();
        if(hWnd != NULL && IsWindow(hWnd))
        {
            DWORD dwWinProcessId(0);
            GetWindowThreadProcessId(hWnd, &dwWinProcessId);
            if(dwProcessID == dwWinProcessId) 
            {
                return TRUE;
            }
        }
        
        return FALSE;
    }
    
    static DWORD GetIncludeStyle()
    {
        return WS_VISIBLE;
    }
    
    static DWORD GetExcludeStyleEx()
    {
        return  WS_EX_TRANSPARENT;
    }
    
    static BOOL IsTargetPopupWindow()
    {
        return FALSE;
    }
};

class CSCWinInfo
{
public:
    HWND m_hWnd;    
    CRect m_rtWin;    //window rect
                    
    INT m_nLevel;    // 1 - pop up window  ;  2
N - child window
};

//pop up win 1 (level 1)
.. first Z order
//        child11 (level 2)
//        child12 (level 2)
//                chilld121 (level 3)
//                chilld122 (level 3)
//                

//        child3 (level 2)
//pop up win2
//        child21 (level 2)
//        child21 (level 2)
// 
.
// 
.
//pop up winN 
. last Z order


template<typename CWinFilterTraits = CSCWinFilter>
class CSCWinSpy:  public CHYSingleton<CSCWinSpy>
{
public:
    BOOL SnapshotAllWinRect()
    {
        ClearData();

        // cache current window Z order when call this function
        EnumWindows(EnumWindowsSnapshotProc, 1); 
        
        return TRUE;
    }
    
    //get from current Z order of desktop
    HWND GetHWNDByPoint(CPoint pt)
    {
        m_hWndTarget = NULL;
        
        EnumWindows(EnumWindowsRealTimeProc, MAKELPARAM(pt.x, pt.y));
        
        return m_hWndTarget;
    }
    
    CRect GetWinRectByPoint(CPoint ptHit, BOOL bGetInRealTime = FALSE)
    {
        CRect rtRect(0, 0, 0, 0);
        if(bGetInRealTime) //get from current Z order
        {
            HWND hWndTarget = GetHWNDByPoint(ptHit);
            if(hWndTarget != NULL )
            {
                GetWindowRect(hWndTarget, &rtRect);
            }
        }
        else //get from snapshot cache
        {
            GetRectByPointFromSnapshot(ptHit, rtRect);
        }
        
        return rtRect;
    }
    
protected:
    static BOOL CALLBACK EnumWindowsRealTimeProc(HWND hwnd, LPARAM lParam)
    {
        if(!PtInWinRect(hwnd, CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)))) return TRUE;
        
        if(ShouldWinBeFiltered(hwnd))  return TRUE;
        
        m_hWndTarget = hwnd;
        
        if(CWinFilterTraits::IsTargetPopupWindow()) return FALSE; //this is the target window, exit search
        
        EnumChildWindows(hwnd, EnumChildRealTimeProc, lParam);
        
        return FALSE;
    }
    
    static BOOL CALLBACK EnumChildRealTimeProc(HWND hwnd, LPARAM lParam)
    {
        if(!PtInWinRect(hwnd, CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)))) return TRUE;
        
        if(ShouldWinBeFiltered(hwnd)) return TRUE;
        
        m_hWndTarget = hwnd;
        EnumChildWindows(hwnd, EnumChildRealTimeProc, lParam);
        
        return FALSE;
    }
    
protected:
    static BOOL CALLBACK EnumWindowsSnapshotProc(HWND hwnd, LPARAM lParam)
    {
        INT nLevel = lParam;
        if(ShouldWinBeFiltered(hwnd))  return TRUE;
        
        SaveSnapshotWindow(hwnd, nLevel);
        
        if(!CWinFilterTraits::IsTargetPopupWindow())
        {
            ++nLevel;
            EnumChildWindows(hwnd, EnumChildSnapshotProc, nLevel);
        }
        
        return TRUE;
    }
    
    static BOOL CALLBACK EnumChildSnapshotProc(HWND hwnd, LPARAM lParam)
    {
        INT nLevel = lParam;
        
        if(ShouldWinBeFiltered(hwnd)) return TRUE;
        
        SaveSnapshotWindow(hwnd, nLevel);
        
        ++nLevel;
        EnumChildWindows(hwnd, EnumChildSnapshotProc, nLevel);
        
        return TRUE;
    }
    
protected:
    static BOOL PtInWinRect(HWND hWnd, CPoint pt)
    {
        CRect rtWin(0, 0, 0, 0);
        GetWindowRect(hWnd, &rtWin);
        return PtInRect(&rtWin, pt);
    }
    
    static BOOL ShouldWinBeFiltered(HWND hWnd)
    {
        if(CWinFilterTraits::IsFilterWindow(hWnd)) return TRUE;
        
        DWORD dwStyle = GetWindowLong(hWnd, GWL_STYLE);
        DWORD dwStyleMust = CWinFilterTraits::GetIncludeStyle();
        if((dwStyle & dwStyleMust) != dwStyleMust) return TRUE;
        
        DWORD dwStyleEx = GetWindowLong(hWnd, GWL_EXSTYLE);
        DWORD dwStyleMustNot = CWinFilterTraits::GetExcludeStyleEx();
        if((dwStyleMustNot & dwStyleEx) != 0) return TRUE;
        
        return FALSE;
    }
    
    //find the first window that level is biggest
    static BOOL  GetRectByPointFromSnapshot(CPoint ptHit, CRect& rtRet)
    {
        int nCount = m_arSnapshot.size();
        _ASSERTE(nCount > 0);
        CSCWinInfo* pInfo = NULL;
        CSCWinInfo* pTarget = NULL; 
        
        for(int i=0; i<nCount; ++i)
        {
            pInfo = m_arSnapshot[i];
            _ASSERTE(pInfo != NULL);
            
            //target window is found 
            //and level is not increasing, 
            //that is checking its sibling or parent window, exit search
            if(pTarget != NULL
                && pInfo->m_nLevel <= pTarget->m_nLevel)
            {
                break;
            }
            
            if(PtInRect(&pInfo->m_rtWin, ptHit))
            {
                if(pTarget == NULL)
                {
                    pTarget = pInfo;
                }
                else
                {
                    if( pInfo->m_nLevel > pTarget->m_nLevel)
                    {
                        pTarget = pInfo;
                    }
                }
            }
        }
        
        if(pTarget != NULL)
        {
#ifdef _DEBUG
            if(pTarget != NULL)
            {
                HWND hWnd = pTarget->m_hWnd;
                TCHAR szText[128] = {0};
                _sntprintf(szText, 127, _T("GetRectByPointFromSnapshot: pt(%d, %d), hWnd(%x)"),
                    ptHit.x, ptHit.y, (UINT)(pInfo->m_hWnd));
                OutputDebugString(szText);
            }
#endif

            rtRet.CopyRect(&pTarget->m_rtWin);
            return TRUE;
        }
        
        return FALSE;
    }
    
    static VOID SaveSnapshotWindow(HWND hWnd, INT nLevel)
    {
        _ASSERTE(hWnd != NULL && IsWindow(hWnd));
        CRect rtWin(0, 0, 0, 0);
        GetWindowRect(hWnd, &rtWin);
        if(rtWin.IsRectEmpty()) return;
        
        CSCWinInfo* pInfo = new CSCWinInfo;
        if(pInfo == NULL) return;
        
        pInfo->m_hWnd = hWnd;
        pInfo->m_nLevel = nLevel;
        pInfo->m_rtWin = rtWin;
        
        m_arSnapshot.push_back(pInfo);
    }
    
    static VOID ClearData()
    {
        int nCount = m_arSnapshot.size();
        for(int i=0; i<nCount; ++i)
        {
            delete m_arSnapshot[i];
        }
        
        m_arSnapshot.clear();
    }
    
protected:
    friend class CHYSingleton<CSCWinSpy>;

    CSCWinSpy() { NULL; }
    ~CSCWinSpy() {    ClearData(); }
    
    static HWND m_hWndTarget;
    static std::vector<CSCWinInfo*> m_arSnapshot;
};

template<typename T> HWND CSCWinSpy<T>::m_hWndTarget = NULL;
template<typename T> std::vector<CSCWinInfo*> CSCWinSpy<T>::m_arSnapshot;


這樣使用, 在截圖開(kāi)始時(shí)保存所有桌面窗口層次:

CSCWinSpy<CSCWinFilter>::GetInstance()->SnapshotAllWinRect();


然后就可以這樣查詢(xún)某個(gè)位置的最上層窗口了:

CRect rtSelect = CSCWinSpy<CSCWinFilter>::GetInstance()->GetWinRectByPoint(pt, FALSE);

http://www.cppblog.com/weiym/archive/2012/05/06/173845.html

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
MFC多線(xiàn)程的創(chuàng )建,包括工作線(xiàn)程和用戶(hù)界面線(xiàn)程
windows10自帶的【截圖】功能,比QQ截圖還牛,你有沒(méi)有用過(guò)?
用Windows API實(shí)現一個(gè)簡(jiǎn)單的文本輸入框
windows的消息隊列與消息循環(huán)
qq聊天信息的獲取和設置與自動(dòng)發(fā)送
孫鑫VC視頻教程筆記之第一課“Windows程序的內部運行原理”
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久