Как правильно обрабатывать сообщения Windows из элемента управления MSFTEDIT_CLASS (RichEdit)?

ОБНОВЛЕНИЕ: По запросу я добавил весь код, который я использую для создания окна и его элемента управления RichEdit.

Я пытаюсь обработать сообщения Windows для элемента управления RichEdit, используемого как дочерний элемент другого окна.

Теперь у меня есть элемент управления RichEdit, за исключением моего собственного WndProc, Проблема в том, что, когда я установил wc.lpszClassName = MSFTEDIT_CLASS; так что это соответствует lpClassName используется в CreateWindowEx()содержимое элемента управления RichEdit больше не отображается (т. е. текст и т. д.), однако его функция WndProc может обрабатывать сообщения.

Создание окна:

Сначала конструктор:

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 Я определил.

Я не уверен, что я делаю здесь неправильно или как я могу правильно решить эту проблему.

РЕДАКТИРОВАТЬ:
Основываясь на ответах и ​​комментариях, я восстановил свой код, чтобы использовать только Window класс, который содержит элемент управления RichEdit, созданный таким образом:

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 окна?

0

Решение

Когда вы создаете окно управления расширенным редактированием, используя имя класса по умолчанию (MSFTEDIT_CLASS), все сообщения будут отправлены в родительское окно. Поскольку вы не родительское окно, вы не можете обрабатывать эти сообщения.

Таким образом, вам нужно будет подкласс управления, заменив своя оконная процедура, которая будет вызываться напрямую, вместо того, чтобы передавать сообщения родителю. Это просто сделать; Я обсуждал это раньше в этот ответ для обычного контроля редактирования. Измененный пример кода выглядит так:

// 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);

Вам также необходимо убедиться, что unsubclass контроль всякий раз, когда он уничтожен. Другой пример демонстрирует это в ответ на сообщения, полученные родительским окном, но в вашем случае это не сработает, поскольку вы не получаете сообщения для родительского окна. Вместо этого вам нужно удалить подкласс из элемента управления в ответ на его собственный WM_NCDESTROY сообщение:

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

Или, версия 6 библиотеки общих элементов управления представила новый, менее подверженный ошибкам метод подклассов с использованием набор служебных функций. (Критическая функциональность была на самом деле в более ранних версиях, но она была недокументирована.) Учитывая, что у вас нет контроля над процессом, который фактически владеет окном, это, возможно, предпочтительный подход.

Существует демонстрация обоих подходов здесь на MSDN.

И, конечно, вам не нужно создавать подклассы только отдельных элементов управления. Вы также можете зарегистрировать пользовательский класс окна, который ведет себя так же, как встроенный элемент управления rich edit, но все же дает вам первый взлом на сообщения, полученные окнами этого класса. Я не могу сказать по вопросу, нужно ли это или нет; Это звуки как будто у вас есть только один элемент управления, который вам небезразличен.

1

Другие решения

Вы говорите, что исходная проблема заключалась в том, что ваше родительское окно не получало уведомления от элемента управления RichEdit. Вы отправили сообщение EM_SETEVENTMASK в элемент управления RichEdit? Если вы этого не сделаете, элемент управления RichEdit не будет отправлять определенные уведомления в родительское окно. Увидеть Сообщение EM_SETEVENTMASK.

1

Можете ли вы показать свой код с участием wc структура и создание окна? Я вполне уверен, что вы не хотите, чтобы главное окно имело тот же класс, что и элемент управления rich edit — и это то, что я читаю до сих пор.

Я даже не знаю, почему у вас есть WNDCLASSEX применить к элементу управления редактирования.

Мое предложение состоит в том, чтобы вы упростили вещи и «создали подкласс» элемента управления rich edit после его создания, используя SetWindowLong() с GWL_WNDPROC на ваш EditControl::WndProc,

0
По вопросам рекламы [email protected]