如何正确处理来自MSFTEDIT_CLASS(RichEdit)控件的Windows消息? [英] How to correctly handle Windows messages from an MSFTEDIT_CLASS (RichEdit) control?

查看:291
本文介绍了如何正确处理来自MSFTEDIT_CLASS(RichEdit)控件的Windows消息?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新:根据要求,我添加了所有用于创建窗口及其RichEdit控件的代码。

m尝试处理窗口消息的RichEdit控件用作另一个窗口的孩子。

I'm trying to handle windows messages for a RichEdit control used as a child of another window.

现在我有RichEdit控件使用我自己的 WndProc 。问题是,当我设置 wc.lpszClassName = MSFTEDIT_CLASS; ,使它匹配 lpClassName 中使用 CreateWindowEx(),RichEdit控件的内容不再显示为绘制(即文本等),但是,它的WndProc函数可以处理消息。

Now I did have the RichEdit control working with the exception of my own WndProc. The issue is that, when I set wc.lpszClassName = MSFTEDIT_CLASS; so that it matches lpClassName used in CreateWindowEx(), the content of the RichEdit control no longer appears to draw (ie text, etc), however, its WndProc function can then handle messages.

创建窗口:

首先是构造函数:

SubWindow::SubWindow(const wchar_t *szAppNameImport)
{
    szAppName = szAppNameImport;

    cfmt = CHARFORMATW();
    hwnd = HWND();
    windowRect = RECT();
    editControlHwnd = HWND();
    wc = WNDCLASSEX();

    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_CLASSDC;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = GetModuleHandle(NULL);
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = szAppName;
    wc.hIconSm = LoadIcon(wc.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
}

然后 Create()函数:

VOID SubWindow::Create(unsigned int window_startX, unsigned int window_startY, unsigned int windowWidthInput, unsigned int windowHeightInput, HWND parent)
{   
    windowRect.left = window_startX;
    windowRect.top = window_startY;

    windowRect.right = windowWidthInput;
    windowRect.bottom = windowHeightInput;

    if(!RegisterClassEx(&wc))
    {
        throw std::exception();
    }

    if((hwnd = CreateWindowEx
        (
        WS_EX_CLIENTEDGE,
        szAppName,
        TEXT("Our classy sub window!"),
        WS_OVERLAPPEDWINDOW| WS_VISIBLE,

        windowRect.left, windowRect.top,
        windowRect.right, windowRect.bottom,
        parent,
        NULL,       
        wc.hInstance,
        NULL))==NULL)
    {
        throw std::exception();
    }

    SetWindowLongPtr(hwnd, GWL_USERDATA, (LONG_PTR)this);

    ShowWindow(hwnd, SW_SHOWDEFAULT);
    UpdateWindow(hwnd);
}

WndProc:

LRESULT CALLBACK SubWindow::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    SubWindow *childWindowPointer = (SubWindow*)GetWindowLongPtr(hwnd, GWLP_USERDATA);

    if(childWindowPointer != NULL)
    {
        if(childWindowPointer->GetEditControl() == hwnd)
            OutputDebugString(L"I SHOULD NOT BE CALLED");

        return childWindowPointer->MsgProc(hwnd, uMsg, wParam, lParam);
    }
    else
    {
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
}

MsgProc:

LRESULT SubWindow::MsgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{
    PAINTSTRUCT ps;
    HDC hdc;

    switch(uMsg)
    {
    case WM_WINDOWPOSCHANGED:
        {
            GetClientRect(hwnd, &windowRect);
            SetWindowPos(editControlHwnd, NULL, windowRect.left, windowRect.top, windowRect.right, windowRect.bottom, SWP_NOZORDER | SWP_NOACTIVATE);
            return 0;
        }
    case WM_DESTROY:
        {
            OutputDebugString(TEXT("DESTROYING A SUB WINDOW!\n"));
            return 0;
        }

    case WM_PAINT:
        {
            InvalidateRect (hwnd, NULL, FALSE);
            hdc = BeginPaint(hwnd, &ps);
            EndPaint(hwnd, &ps);
            return 0;
        }

    case EM_EXSETSEL:
        {
            if(hwnd == editControlHwnd)
            {
                OutputDebugString(L"Text selection changed");
                return 0;
            }
        }
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
} 

RichEdit控件绘制和功能完美,显然没有问题,它不使用 WndProc 我已经定义。

The RichEdit control draws and functions perfectly, apparently without issue, with the exception of it not using the WndProc I have defined.

我不知道我在这里做错了什么我可以正确解决这个问题。

I'm not sure what I'm doing wrong here or how I can correctly resolve this.

编辑:
根据回答和评论, 窗口包含RichEdit控件的类,创建如下:

Based on the answers and comments, I have restored my code to use only a Window class which contains a RichEdit control, created thusly:

void SubWindow::CreateEditControl()
{
    std::wstring initialText = TEXT("TestWindow\r\n");

    LoadLibrary(L"Msftedit.dll");

    GetClientRect(hwnd, &windowRect);
    editControlHwnd = CreateWindowEx(0, MSFTEDIT_CLASS, initialText.data(),
        WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_READONLY | WS_VSCROLL | ES_NOHIDESEL,
        windowRect.left, windowRect.top,windowRect.right,windowRect.bottom,
        hwnd,
        NULL, NULL, NULL);

    cfmt.cbSize = sizeof(CHARFORMAT);
    cfmt.dwMask = CFM_COLOR | CFM_FACE | CFM_SIZE;
    cfmt.dwEffects = 0;
    cfmt.yHeight = 160;
    cfmt.crTextColor = RGB(0,0,0);
    wcscpy_s(cfmt.szFaceName, TEXT("Tahoma"));

    SendMessage(editControlHwnd, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cfmt);
}

如何在窗口的MsgProc中处理来自此控件的消息?当您使用默认类名( MSFTEDIT_CLASS

How do I process the messages from this control in the Window's MsgProc?

推荐答案

>),所有消息都将发送到其父窗口。由于您不是父窗口,因此您无法处理这些邮件。

When you create a rich edit control window using the default class name (MSFTEDIT_CLASS), all messages are going to be sent to its parent window. Since you are not that parent window, you are not able to handle those messages.

因此,您需要对控件进行子类化,用您自己的 >窗口过程将被直接调用,而不是允许消息传递到父级。这很简单;我之前在此答案中讨论了常规编辑控件。修改的示例代码如下所示:

So you will need to subclass the control, substituting your own window procedure that will be called directly, instead of allowing the messages to be passed on to the parent. That is simple to do; I've discussed it before in this answer for a regular edit control. The altered example code looks like this:

// Stores the old original window procedure for the rich edit control.
WNDPROC wpOldRichEditProc;

// The new custom window procedure for the rich edit control.
LRESULT CALLBACK CustomRichEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        ...
    }

    // Pass the messages you don't process on to the original window procedure.
    CallWindowProc(wpOldRichEditProc, hWnd, msg, wParam, lParam);
}

当您创建控件时:

// Create the rich edit control
HWND hWnd = CreateWindowEx(...)

// Subclass it.
wpOldRichEditProc= (WNDPROC)SetWindowLongPtr(hWnd,
                                             GWLP_WNDPROC,
                                             (WNDPROC)CustomRichEditProc);

您还需要确保取消订阅销毁。另一个例子演示了响应父窗口收到的消息,但是在你的情况下不会工作,因为你没有收到父窗口的消息。相反,您需要从控件中删除子类以响应自己的 WM_NCDESTROY 讯息:

You will also need to make sure to unsubclass the control whenever it is destroyed. The other example demonstrates doing that in response to messages received by the parent window, but that won't work in your case, since you're not getting messages for the parent window. Instead, you'll need to remove the subclass from the control in response to its own WM_NCDESTROY message:

SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)wpOldRichEditProc);

或者,版本6的常用控件库引入了一个新的,容易出错的子类化方法一组实用功能。 (关键功能实际上是在早期版本中,但它没有记录。)考虑到你不能控制实际拥有窗口的进程,这可以说是首选方法。

Or, version 6 of the common controls library introduced a new, less error-prone method of subclassing using a set of utility functions. (The critical functionality was actually there in earlier versions, but it was undocumented.) Considering that you do not have control over the process that actually owns the window, this is arguably the preferred approach.

有两种方法的演示在MSDN上

当然,你不必只子类化单独的控件。您还可以注册一个自定义窗口类,它的行为方式与内置丰富的编辑控件相同,但仍然让你第一次破解在该类的Windows接收的消息。我不能从这个问题得知是否有必要;它会发出 的声音,因为您只有一个您关心的控制。

And of course, you don't have to subclass only individual controls. You can also register a custom window class that behaves the same way as the built-in rich edit control, but still gives you first crack at the messages received by windows of that class. I can't tell from the question whether that's necessary or not; it sounds like you only have a single control you care about.

这篇关于如何正确处理来自MSFTEDIT_CLASS(RichEdit)控件的Windows消息?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆