Вызов процедуры окна во время выполнения API функций
Столкнулся с проблемой опроса элемента Edit через оконную процедуру во время перехвата функции ExtTextOut, рисующей текст в этом элементе. Возникает ошибка 0xC0000005: нарушение прав доступа при чтении по адресу 0x0000000000000000 при отправке сообщения SendMessageW(hWnd, EM_POSFROMCHAR, 0, 0). Такое происходит только в однострочном элементе, в многострочном такого явления не замечал. Перехватываю функцию ExtTextOut для отрисовки текста другими своими функциями, перехват осуществляется с помощью библиотеки Detours. Перехват оконной процедуры Edit не делаю. Могли бы вы помочь мне прояснить, что тут происходит и как с этим справиться?
using gtl::flat_hash_map;
using WndList = flat_hash_map<HDC, HWND>;
WndList DataWndList;
BOOL WINAPI MyExtTextOutW(HDC hdc, int x, int y, UINT options, const RECT* lprect, LPCWSTR lpString, UINT c, const INT* lpDx)
{
HWND hWnd = LWnd(hdc);
WCHAR szWindowClass[MAX_PATH];
GetClassName(hWnd, szWindowClass, MAX_PATH);
if (!_wcsicmp(szWindowClass, L"Edit"))
{
UINT style = GetWindowLong(hWnd, GWL_STYLE);
int cchText = GetWindowTextLength(hWnd) + 1;
wchar_t* pszText = new wchar_t[cchText];
cchText = GetWindowTextW(hWnd, pszText, cchText);
// здесь происходит ошибка
DWORD pos = SendMessageW(hWnd, EM_POSFROMCHAR, 0, 0);
}
return g_hookDispatcher.GetOrg<HK_EXTTEXTOUT, decltype(&MyExtTextOutW)>()(hdc, x, y, options, lprect, lpString, c, lpDx);
}
// Ниже показаны функции, с помощью которых я получаю дескриптор окна, связанный с контекстом
// получение дескриптора окна, связанного с контекстом
HWND LWnd(HDC hdc) try
{
WCHAR szWindowClass[MAX_PATH];
HWND HwndFrom = WindowFromDC(hdc);
if (!HwndFrom) HwndFrom = DataWndList[hdc];
return HwndFrom;
}
catch (...)
{
return nullptr;
}
// запись в карту дескриптора окна
HDC WINAPI MyBeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint)
{
HDC hdc = actualBeginPaint(hWnd, lpPaint);
DataWndList[hdc] = hWnd;
return hdc;
}
// стирание пары из карты
BOOL WINAPI MyEndPaint(HWND hWnd, const PAINTSTRUCT* lpPaint)
{
DataWndList.erase(lpPaint->hdc);
return actualEndPaint(hWnd, lpPaint);
}
Ответы (1 шт):
Судя по этому вопросу и комментариям к нему, а также по описанию сообщения EM_POSFROMCHAR, один из параметров функции SendMessageW должен указывать на некую структуру, куда будет помещаться результат:
EM_POSFROMCHAR
wParam = (LPPOINT) lpPoint; // address of structure
// receiving character position
lParam = (LPARAM) wCharIndex; // zero-based index of character
А у вас там просто 0 в обоих параметрах. Судя по приведённой вами ошибке, именно это и происходит - попытка чтения по адресу 0, где эта функция ожидает структуру:
0xC0000005: нарушение прав доступа при чтении по адресу 0x0000000000000000
Возможно, передаваемые параметры при посылке сообщения EM_POSFROMCHAR зависят от типа контрола. Поэтому для каких-то контролов у вас всё нормально отрабатывает, а для каких-то получается вот так.