c ++活动窗口句柄不匹配我的基于MFC对话框的应用程序的m_hwnd

时间:2018-05-06 15:56:39

标签: c++ mfc

有人知道使用哪个句柄(而不是m_hWnd)来匹配钩子回调报告的活动窗口句柄吗?

我认为我的基于MFC对话框的应用程序的m_hWnd将与钩子回调报告的活动句柄窗口匹配。

在一个小例子(基于MFC对话框的应用程序)下面,在标题栏(m_hWnd)中显示主窗口句柄,在CEdit控件中显示活动窗口句柄。

enter image description here

我设置一个钩子来检测活动窗口何时改变

h_event_hook = SetWinEventHook(EVENT_OBJECT_FOCUS, EVENT_OBJECT_FOCUS, NULL, 
                               &window_change_hook, 0, 0, WINEVENT_OUTOFCONTEXT);
void CALLBACK window_change_hook(HWINEVENTHOOK hWinEventHook, DWORD event, 
                                 HWND hwnd, LONG idObject, LONG idChild, 
                                 DWORD dwEventThread, DWORD dwmsEventTime)
{
    ::PostMessage(h_this_app_wnd, WM_UPDATE_ACTIVE_WINDOW_CEDIT, (WPARAM)0, (LPARAM)hwnd);
}

对话框标题显示其句柄如下:

CString hwnd_text;
hwnd_text.Format("MonitorActiveWindow (%p)", m_hWnd);
SetWindowText(hwnd_text);

重现问题的MWE(最小工作示例)下方:

#include "stdafx.h"
#include "MonitorActiveWindow.h"
#include "MonitorActiveWindowDlg.h"
#include "afxdialogex.h"
#include <string>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define WM_UPDATE_ACTIVE_WINDOW_CEDIT           WM_APP + 0x1001

static HWND h_this_app_wnd;
static HWINEVENTHOOK h_event_hook;

void CALLBACK window_change_hook(HWINEVENTHOOK hWinEventHook, DWORD event, 
                                 HWND hwnd, LONG idObject, LONG idChild, 
                                 DWORD dwEventThread, DWORD dwmsEventTime)
{
    ::PostMessage(h_this_app_wnd, WM_UPDATE_ACTIVE_WINDOW_CEDIT, (WPARAM)0, (LPARAM)hwnd);
}

LRESULT CMonitorActiveWindowDlg::OnUpdateActiveWindowCedit(WPARAM w_param, LPARAM l_param)
{
    const auto h_wnd = reinterpret_cast<HWND>(l_param);
    CString text;
    text.Format("%p", h_wnd);
    GetDlgItem(IDC_EDIT1)->SetWindowText(text);
    return 0;
}

BOOL CMonitorActiveWindowDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // Set the icon for this dialog.  The framework does this automatically
    //  when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE);         // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon

    // TODO: Add extra initialization here

    // Display the main window handle
    CString hwnd_text;
    hwnd_text.Format("MonitorActiveWindow (%p)", m_hWnd);
    SetWindowText(hwnd_text);

    // Keep a copy of m_hWnd just so the callback can call PostMessage
    h_this_app_wnd = m_hWnd;

    // Set a hook to detect when the active window changes
    h_event_hook = SetWinEventHook(EVENT_OBJECT_FOCUS, EVENT_OBJECT_FOCUS, NULL, 
                                   &window_change_hook, 0, 0, WINEVENT_OUTOFCONTEXT);

    return TRUE;  // return TRUE  unless you set the focus to a control
}

void CMonitorActiveWindowDlg::OnDestroy()
{
    CDialogEx::OnDestroy();
    UnhookWinEvent(h_event_hook);
}

CMonitorActiveWindowDlg::CMonitorActiveWindowDlg(CWnd* pParent /*=NULL*/)
    : CDialogEx(IDD_MONITORACTIVEWINDOW_DIALOG, pParent)
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMonitorActiveWindowDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_EDIT1, m_output_cedit);
}

BEGIN_MESSAGE_MAP(CMonitorActiveWindowDlg, CDialogEx)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_WM_DESTROY()
    ON_MESSAGE(WM_UPDATE_ACTIVE_WINDOW_CEDIT, OnUpdateActiveWindowCedit)
END_MESSAGE_MAP()

void CMonitorActiveWindowDlg::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
    {
        CDialogEx::OnPaint();
    }
}

HCURSOR CMonitorActiveWindowDlg::OnQueryDragIcon()
{
    return static_cast<HCURSOR>(m_hIcon);
}

2 个答案:

答案 0 :(得分:2)

The edit control appears to be read-only edit control. This control get default focus, and the window handle for this edit control is reported. You can change the edit control style to "Disabled" so that it doesn't steal focus from parent dialog.

If you are not interested in focus window, you can look for foreground window Submit(), example

new WebDriverWait(driver, TimeSpan.FromSeconds(3)).Until(ExpectedConditions.ElementToBeClickable(By.XPath("//input[@id='username' and @name='username']"))).SendKeys("refactorcoding");
driver.FindElement(By.XPath("//input[@id='password' and @name='password']")).SendKeys("refactorcoding");
driver.FindElement(By.XPath("//input[@id='password' and @name='password']")).Submit();

答案 1 :(得分:1)

如果有人感兴趣,我将使用我的服务器解决方案,以便能够将消息发送到顶部指定应用程序的实例。它包括修改回调以从收到的hwnd中检索主窗口句柄。

HWND get_real_parent(HWND h_wnd)
{
    const auto h_parent = GetAncestor(h_wnd, GA_PARENT);
    if (!h_parent || h_parent == GetDesktopWindow())
        return nullptr;

    return h_parent;
}

HWND get_main_window_handle(HWND h_wnd)
{
    auto h_main_window = h_wnd;
    auto h_parent_window = h_wnd;
    while (h_parent_window != nullptr)
    {
        h_parent_window = get_real_parent(h_parent_window);
        if (h_parent_window != nullptr)
        {
            h_main_window = h_parent_window;
        }
    }
    return h_main_window;
}

void CALLBACK window_change_hook(HWINEVENTHOOK hWinEventHook, DWORD event, 
                                 HWND hwnd, LONG idObject, LONG idChild, 
                                 DWORD dwEventThread, DWORD dwmsEventTime)
{  
    hwnd = get_main_window_handle(hwnd);
    ::PostMessage(h_this_app_wnd, WM_UPDATE_ACTIVE_WINDOW_CEDIT, (WPARAM)0, (LPARAM)hwnd);
}