понедельник, 1 декабря 2008 г.

Что это за странные значения, возвращаемые GWLP_WNDPROC?

Это перевод What are these strange values returned from GWLP_WNDPROC? Автор: Реймонд Чен.

GetWindowLongPtr(hwnd, GWLP_WNDPROC) (или GetWindowLong(hwnd, GWL_WNDPROC), если вы ещё не сделали свой код совместимым с 64-х разрядной ОС) должна возвращать текущую оконную процедуру. Почему же я иногда получаю при этом какие-то совершенно левые значения?

Потому что иногда "вы не можете справиться с истиной".

Если текущая оконная процедура несовместима с вызывающей стороной, тогда нельзя вернуть вам настоящий указатель на функцию, потому что вы не сможете его вызвать. Вместо этого возвращается "волшебное число". Единственный смысл этого значения - быть узнанным функцией CallWindowProc, чтобы она смогла перевести парамеры сообщения в формат, который ожидает настоящая оконная процедура, и корректно её вызвать.

Например, предположим, что вы работаете на Windows XP и что окно является окном UNICODE, но компонент, скомпилированный как ANSI, вызывает GetWindowLong(hwnd, GWL_WNDPROC) (в действительности это будет вызов GetWindowLongA, т.к. компонент скомпилирован как ANSI - прим. пер.). При этом нельзя вернуть прямой указатель на оконную процедуру, потому что она ожидает параметры сообщений в формате UNICODE, а ваш компонент оперирует с сообщениями в формате ANSI. Поэтому вместо этого возвращается волшебное значение. Когда вы передаёте это волшебное значение в CallWindowProc, она распознаёт это значение как: "ох, мне нужно перевести параметры для сообщения из ANSI в UNICODE и передать UNICODE-сообщение в вон ту оконную процедуру".

В качестве другого примера, предположим, что вы работаете в Windows 95 и окно было создано 32-х битным приложением, но 16-ти битный компонент вызывает GetWindowLong(hwnd, GWLP_WNDPROC). И снова, вы не можете вернуть указатель на 32-х битную оконную процедуру, потому что сообщения нужно конвертировать между 16-ю и 32-мя битами (и кроме того, 16-ти битная программа просто не может перейти по 32-х битному плоскому адресу). Поэтому снова, вместо настоящего указателя, возвращается полшебное значение, по которому CallWindowProc понимает, что: "ох, мне нужно перевести сообщение из 16-ти битного в 32-х битное и передать его вон той оконной процедуре".

(Эти превращения известны как "thunks".)

Поэтому помните: единственная вещь, которую можно сделать со значением, полученным от GetWindowLongPtr(hwnd, GWLP_WNDPROC), это: (1) передать это значение в CallWindowProc, или (2) передать его обратно через SetWindowLongPtr(hwnd, GWLP_WNDPROC).

Комментариев нет:

Отправить комментарий

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.