Дескриптор активного окна c ++ не совпадает с m_hwnd моего приложения, основанного на диалоге MFC - PullRequest
0 голосов
/ 06 мая 2018

Может кто-то знает, какой дескриптор использовать (вместо m_hWnd) для сопоставления с дескриптором активного окна, сообщаемым обратным вызовом ловушки?

Я думал, что m_hWnd моего приложения, основанного на диалоге MFC, будет соответствовать окну активного дескриптора, сообщаемому обратным вызовом ловушки.

Ниже приведен небольшой пример (приложение на основе диалогового окна 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 голосов
/ 06 мая 2018

Просто, если кому-то интересно, под решением, которое я буду использовать, мой сервер сможет отправить сообщение экземпляру указанного приложения, которое находится вверху. Он состоит в изменении обратного вызова для извлечения дескриптора главного окна из полученного 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);
}
0 голосов
/ 06 мая 2018

Элемент управления для редактирования, по-видимому, предназначен только для чтения. Этот элемент управления получает фокус по умолчанию, и указывается дескриптор окна для этого элемента управления. Вы можете изменить стиль элемента управления редактирования на «Отключено», чтобы он не крал фокус из родительского диалога.

Если вас не интересует окно фокуса, вы можете поискать окно переднего плана EVENT_SYSTEM_FOREGROUND, пример

SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, 
        NULL, &window_change_hook, 0, 0, WINEVENT_OUTOFCONTEXT);
...

void CALLBACK window_change_hook(HWINEVENTHOOK, DWORD, HWND hwnd, LONG, LONG, DWORD, DWORD)
{
    CString str;
    GetWindowText(GetAncestor(hwnd, GA_ROOT), str.GetBuffer(100), 100);
    str.ReleaseBuffer();
    ::SetDlgItemText(h_this_app_wnd, IDC_EDIT1, str);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...