SendMessageA и SendMessageW в Win7 перенесены из WinXP

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

У меня есть диалоговое окно, написанное на C, которое отлично работает в WinXP, но не может собирать данные, вводимые пользователем из элемента управления редактированием в Юникоде в Win7. Проблема возникает при первом вызове SendMessageW, как показано ниже:

/* handles to controls */
HWND hDomainEdit;
HWND hOtherEdit;
HWND hTextOut;
HWND hButton;
/* buffers to receive input */
WCHAR wszDomain[256];
CHAR szOtherInput[512];
CHAR szBuffer[512]; //added to hold temporary value of wszDomain
/* a test string */
const CHAR szTest[] = "This is a test of SendMessageA."

BOOL dialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {

    if (message == WM_INIT) {
        /* get all the handles shown above, then... */
        SendMessageA(hTextOut, WM_SETTEXT, 0, (LPARAM) szTest);
        /* worked fine */
        /* do a few other things */
    } else if (message == WM_COMMAND) {
        /* are some other conditions are true?  they sure are */
        /* time to collect a bunch of input from controls */
        int cchResultLen = (int) SendMessageA(hOtherEdit, WM_GETTEXT, 512, (LPARAM) szOtherInput);
        /* cchResultLen is correctly the length of the user input */
        /* cchResultLen = (int) SendMessageW(hDomainEdit, WM_GETTEXT, 256, (LPARAM) wszDomain); */
        /* begin new code */
        cchResultLen = (int) SendMessageA(hDomainEdit, WM_GETTEXT, 512, (LPARAM) szBuffer);
        cchResultLen = MultiByteToWideChar(CP_UTF8, 0, szBuffer, cchResultLen, wszDomain, 256);
        wszDomain[cchResultLen] = 0; /* above doesn't terminate string */
        /* after SendMessageW(), cchResultLen was 0, no string transferred, no error
           message.  using SendMessageA, all is well. */
    }
}

Похоже, что SendMessageA работает несколько раз с message = WM_GETTEXT или WM_SETTEXT, и внезапно, когда требуется широкая строка, SendMessageW терпит неудачу. Я знаю, что все думают, что вы должны выбрать CHAR_T и придерживаться его, всегда используя SendMessage, но это не так; Win32.hlp явно отмечает, что их можно использовать в одной программе, вызывая отдельные функции вручную. Я уверен, что кто-то еще готов сказать, что сам элемент управления привязан или становится привязанным к одному конкретному CHAR_T, но это не относится к WinXP, где это сработало идеально. Этот конкретный элемент редактирования также никогда не устанавливается в строку ASCII явно.

Программа взаимодействует с WinHttp, для которого требуются все строки WCHAR, и именно здесь на помощь приходит SendMessageW. Остальные входные данные используются только для внутреннего использования и в основном представляют собой анализируемые целые числа с метками единиц измерения, которые более удобны и эффективны в ASCII, если нет по другой причине, кроме того, что программа изначально была написана именно так.

Так что же делать? Неужели они действительно изменили что-то столь же неотъемлемое, как SendMessage, на несовместимое? Если да, то это известная ошибка, которую можно обойти, или возможность переключать CHAR_T по желанию является устаревшей функцией? Есть ли другой более простой способ, чем расширение ввода в WCHAR вручную после его получения с помощью SendMessageA?


person sqykly    schedule 15.09.2011    source источник
comment
Я склонен думать, что ошибка не в SendMessageW(); по крайней мере, в качестве отправной точки. Вы уверены, что hDomainEdit действительно? Что происходит, когда вы используете на нем SendMessageA? Кроме того, почему бы не использовать GetWindowText[AW]?   -  person atzz    schedule 15.09.2011
comment
sayeth MSDN: Если целевое окно принадлежит текущему процессу, GetWindowText вызывает отправку сообщения WM_GETTEXT в указанное окно или элемент управления. так что должно быть примерно такое же действие. Я попробую проверить значение дескриптора - он никогда не использовался за пределами этого одного оператора, поэтому в противном случае другая проблема была бы молчаливой. Тем не менее, это определенно действительный указатель на правильный контроль в XP.   -  person sqykly    schedule 16.09.2011
comment
Я не говорю, что вы неправильно используете здесь WM_GETTEXT; но лично я бы предпочел функции API сообщениям, если нет другой причины. Кроме того, MSDN не сообщает, делает ли GetWindowText что-нибудь еще, кроме отправки WM_GETTEXT. Например. могут быть нюансы по поводу. Преобразование ANSI / UNICODE (правда, не помню).   -  person atzz    schedule 16.09.2011
comment
Возможно, SendMessage не работает по какой-то другой причине, которая вообще не связана с ANSI / UNICODE? Попробуйте вызвать SetLastError (0) перед этим, а затем использовать GetLastError () и посмотреть, возвращает ли он код ошибки. Находятся ли здесь HWND в вашем собственном процессе или вы пытаетесь получить текст из другого процесса?   -  person BrendanMcK    schedule 16.09.2011
comment
@BrendanMcK - это, вероятно, не сработает. По крайней мере, единственный задокументированный случай, когда SendMessage устанавливает LastError, - это сбой из-за нарушения уровня целостности. Хотя не повредит. И нам определенно нужно как можно больше неопровержимых фактов.   -  person atzz    schedule 16.09.2011
comment
ожидающие проверки для каждого из этих запросов. atzz - у вас есть смысл в том, что это может быть похоже на EnableWindow (). @BrendanMcK - это все мои собственные HWND из GetDlgItem () в сообщении WM_INITDIALOG.   -  person sqykly    schedule 19.09.2011
comment
Я не уверен, но я где-то читал, что последняя буква сообщает кодировку символов, которую использует функция, например a = ascii и w = широкий (юникод?)   -  person BlackBear    schedule 02.10.2011


Ответы (2)


Насколько я понимаю, если вы выполните свой код с помощью отладчика, вы увидите причину.

Прежде всего, два сообщения SendMessage, которые у вас есть одно за другим, используют разные дескрипторы окон, поэтому они не из тех, которые дают вам одинаковый результат. Давайте поговорим о том, в котором возникает проблема:

cchResultLen = (int) SendMessageW(hDomainEdit, WM_GETTEXT, 256, (LPARAM) wszDomain);
// cchResultLen is ZERO!  wszDomain[0] is null.  Edit control is not empty 

Стоя с отладчиком в этой строке, проверьте свою переменную hDomainEdit. Возможно, он недействителен, например, NULL или поврежден каким-то другим кодом. Это объяснило бы недействительный дескриптор и нулевой результат.

person Roman R.    schedule 30.09.2011

Все оконные ручки были в порядке. Сотрудники MSDN сообщили мне, что любое окно, созданное с помощью функции «A» - в данном случае DialogBoxParamA () - должно быть доступно через функции «A». Что касается того факта, что это работает в XP, они сказали: «То, что это работает, не значит, что это правильно». Я полагаю, что эта функциональность устарела - было бы неплохо услышать об этом, прежде чем она перестанет работать!

person sqykly    schedule 01.10.2011
comment
Вы слышали об этом, вы просто не обратили внимания. Это никогда не должно было работать так, как вы это делаете. Тебе просто повезло. MS не обязана сообщать кому-либо об изменениях в реализации своих библиотек, которые не выходят за рамки опубликованных спецификаций. - person David Heffernan; 02.10.2011
comment
@ Дэвид Хеффернан: Ссылка на документацию, в которой конкретно указана эта проблема? Я не вижу этого в разделе «Типы данных Windows для строк» ​​или «SendMessage» в MSDN - уж точно не в Win32.hlp. Взгляните на: msdn.microsoft.com /en-us/library/dd317720%28v=VS.85%29.aspx - person sqykly; 02.10.2011
comment
@DavidHeffernan: окна были созданы с помощью DialogBoxParamA, и класс был зарегистрирован системой, а не приложением - хотя я признаю, что это предполагает, что классы окон могут быть строго Unicode, очевидно, существуют обе версии общих элементов управления. Ссылка выше контрастирует: приложения, использующие функции API Unicode и набора символов, обычно используют один и тот же класс окна. Операционная система прозрачно переводит сообщения между окнами разных классов. [...] Оконная функция может отправлять сообщения или вызывать функции любого типа. - person sqykly; 02.10.2011