Вызов процедуры окна во время выполнения 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 шт):

Автор решения: CrazyElf

Судя по этому вопросу и комментариям к нему, а также по описанию сообщения 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 зависят от типа контрола. Поэтому для каких-то контролов у вас всё нормально отрабатывает, а для каких-то получается вот так.

→ Ссылка