Модераторы: feodorv, GremlinProg, xvr, Fixin

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Зачем проверять IsWindowUnicode перед SetWindowLon 
:(
    Опции темы
Ruzzz
Дата 9.11.2009, 08:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 20
Регистрация: 8.3.2008

Репутация: нет
Всего: 1



Часто вижу такой код (например при написании dll):
Код
    if (IsWindowUnicode(hwndParent))
        lpWndProcOld = (WNDPROC)SetWindowLongPtrW(hwndParent,GWL_WNDPROC,(LONG)WndProc);
    else
        lpWndProcOld = (WNDPROC)SetWindowLongPtrA(hwndParent,GWL_WNDPROC,(LONG)WndProc);

Есть ли в этом смысл?
Если я компилирую dll как юникод, и будет использоваться SetWindowLongPtrW, а hwndParent допустим будет указывать на не юникод окно, то к чему это может привести? В MSDN в описании SetWindowLongPtr и SetWindowLong ничего не нашел. Учитывая что оконная функция ничем не отличается, то что будет не так?
PM MAIL   Вверх
Earnest
Дата 9.11.2009, 09:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 33
Всего: 183



Скорее всего, неродная функция просто не сработает. 


--------------------
...
PM   Вверх
Ruzzz
Дата 9.11.2009, 10:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 20
Регистрация: 8.3.2008

Репутация: нет
Всего: 1



Сделал так:
Код
    if (!IsWindowUnicode(hwndParent))
        lpWndProcOld = (WNDPROC)SetWindowLongPtrW(hwndParent,GWL_WNDPROC,(LONG)WndProc);
    else
        lpWndProcOld = (WNDPROC)SetWindowLongPtrA(hwndParent,GWL_WNDPROC,(LONG)WndProc);

Все работает.

В чем же причина?
PM MAIL   Вверх
GremlinProg
Дата 9.11.2009, 12:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



можешь привести пример такой dll?

может там все же было что-то вроде такого:
Код

if ( ::IsWindowUnicode( hwndParent ) )
        lpWndProcOld = (WNDPROC)::SetWindowLongPtr( hwndParent, GWL_WNDPROC, (LONG)WndProcW );
    else
        lpWndProcOld = (WNDPROC)::SetWindowLongPtr( hwndParent, GWL_WNDPROC, (LONG)WndProcA );



--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
Ruzzz
Дата 9.11.2009, 13:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 20
Регистрация: 8.3.2008

Репутация: нет
Всего: 1



GremlinProg, мне уже подсказали что в зависимости от того какой версией SetWindowLongPtr воспользуемся, винда будет слать специфические сообщения или анси или юникодные, а ваш пример еще и показывает что иногда нужно об этом заботиться и подготавливать заранее две версии оконной процедуры. Но как я понимаю если я не «ловлю» такие сообщения, то все равно нужно предусмотреть в своей процедуре разные варианты CallWindowProc, если я вызываю ее для сообщений по умолчанию. Так ли это? Ну и какие еще могут быть ситуаци, которые требуют разных версий оконных процедкр? Мне бы примеры таких сообщений. 

То есть правильно ли я понял:
В зависимости от того оконную процедуру какого окна, юникодного или нет, мы переопределяем, я должен в своей процедуре (или одной или сделать две версии) предусмотреть:
- Вызов соответствующий CallWindowProc

В зависимости от того какую версию SetWindowLongPtr я использую, винда будет думать что я хочу принимать соотв-щие данные, а значит:
- сообщения, со строковыми данными будут «приносить» соответствующие строки (пример бы таких сообщений)
- а значит и оконная функция по умолчанию будет соот-щей версии?

Так?
PM MAIL   Вверх
Ruzzz
Дата 9.11.2009, 13:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 20
Регистрация: 8.3.2008

Репутация: нет
Всего: 1



PM MAIL   Вверх
GremlinProg
Дата 9.11.2009, 13:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(Ruzzz @  9.11.2009,  15:03 Найти цитируемый пост)
в зависимости от того какой версией SetWindowLongPtr воспользуемся, винда будет слать специфические сообщения или анси или юникодные

в данном случае, особой разницы нет, какой функцией поставить процедуру окна,
2 варианта сделаны скорее для поддержки совместимости с более ранними версиями ОС:
Цитата(GetWindowLong Function @  MSDN)

GetWindowLongA is also supported to provide more consistent behavior across all Windows operating systems

разница проявится при установке разных типов процедур окна
возьмем, к примеру сообщение WM_GETTEXT:
с этим сообщением передается буфер и число символов в нем,

если для ANSI-окон поставить UNICODE-процедуру не критично,
т.к. sizeof(char) < sizeof(wchar_t), то обратное может приветси к ошибке,
а результат в обоих случаях не будет понятен отправителю сообщения

в DLL проверка IsWindowUnicode ставится потому, что саму DLL можно подгрузить как в ANSI, так и в UNICODE-проект,
вот по большей части именно поэтому API экспортируются в двух экземплярах: с постфиксами W и A
Цитата(Ruzzz @  9.11.2009,  15:03 Найти цитируемый пост)
Но как я понимаю если я не «ловлю» такие сообщения, то все равно нужно предусмотреть в своей процедуре разные варианты CallWindowProc, если я вызываю ее для сообщений по умолчанию. Так ли это?

Цитата(Ruzzz @  9.11.2009,  15:03 Найти цитируемый пост)
То есть правильно ли я понял:В зависимости от того оконную процедуру какого окна, юникодного или нет, мы переопределяем, я должен в своей процедуре (или одной или сделать две версии) предусмотреть:- Вызов соответствующий CallWindowProc

если ловишь оконные сообщения из "чужой" программы, как в случае с длл, то да - нужно учесть все,
т.к. даже DefWindowProc аналогично - существует в двух экземплярах
Цитата(Ruzzz @  9.11.2009,  15:03 Найти цитируемый пост)
В зависимости от того какую версию SetWindowLongPtr я использую, винда будет думать что я хочу принимать соотв-щие данные, а значит

винда будет думать, опираясь исключительно на то, какой функцией создано окно:
CreateWindowA, CreateWindowW, CreateWindowExA или CreateWindowExW,
т.е. по сути, что возвращает IsWindowUnicode, то и будет приниматься во внимание, остальное на совести программиста


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
GremlinProg
Дата 9.11.2009, 14:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(Ruzzz @  9.11.2009,  15:23 Найти цитируемый пост)
Нашел вот это http://www.codeproject.com/KB/winsdk/safesubclassing.aspx

судя по отзывам, получилось,
видимо данные сообщения транслируются в этих двух точках: SetWindowLong и CallWindowProc

только вот что будешь делать, когда на разных типах окон будут посылаться разные сами сообщения или уведомления,
например то же TVN_GETDISPINFO, которое UNICODE окна отсылают как TVN_GETDISPINFOW(TVN_FIRST-52), а ANSI - как TVN_GETDISPINFOA(TVN_FIRST-3)?
разве что проверять в рантайме:
Код

if ( ::IsWindowUnicode( hwnd ) )
        if( code == TVN_GETDISPINFOW ){
                //...
        }
    else
        if( code == TVN_GETDISPINFOA ){
                //...
        }

не так уж и удобно

SetWindowLong и CallWindowProc не знают ничего о treeview,
подменить индекс сообщения они не смогут,
так что даже в случае из статьи, к IsWindowUnicode придется вернуться уже в теле процедуры окна,

надежнее всего будет просто задать соответствующий вариант процедуры окна

Это сообщение отредактировал(а) GremlinProg - 9.11.2009, 14:32


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
Ruzzz
Дата 9.11.2009, 14:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 20
Регистрация: 8.3.2008

Репутация: нет
Всего: 1



GremlinProg, С сообщениями я все понял, но вот как быть с CallWindowProc и DefWindowProc. Решил что понял, но тут мне ответили на одном форуме:

На мои слова:
«in gen_tray\TRAYCTL.C line
int ret = CallWindowProc(lpOldWinampWndProc,hwnd,message,wParam,lParam);
better to replace:
if (IsWindowUnicode(hwnd))
CallWindowProcW(lpOldWinampWndProc,hwnd,message,wParam,lParam);
else
CallWindowProcA(lpOldWinampWndProc,hwnd,message,wParam,lParam);»

«Ruzzz: that's not required as the OS will do the relevant mapping based on how you subclassed to begin with. so in this case as long as a SetWindowLongPtrW(GWLP_WNNPROC) is correctly applied then it'll map things through CallWindowProcW(..) as long as nothing else has done a CallWindowProcA(..) or a SetWindowLongPtrA(GWLP_WNNPROC).»

при этом они используют:
Код

    if (!IsWindowUnicode(hwndParent))
        lpWndProcOld = (WNDPROC)SetWindowLongPtrW(hwndParent,GWL_WNDPROC,(LONG)WndProc);
    else
        lpWndProcOld = (WNDPROC)SetWindowLongPtrA(hwndParent,GWL_WNDPROC,(LONG)WndProc);

может они предполагают что компилироваться будет только Юникод-версия? или я не пойму.

Это сообщение отредактировал(а) Ruzzz - 9.11.2009, 14:48
PM MAIL   Вверх
GremlinProg
Дата 9.11.2009, 15:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(Ruzzz @  9.11.2009,  16:44 Найти цитируемый пост)
«Ruzzz: that's not required as the OS will do the relevant mapping based on how you subclassed to begin with. so in this case as long as a SetWindowLongPtrW(GWLP_WNNPROC) is correctly applied then it'll map things through CallWindowProcW(..) as long as nothing else has done a CallWindowProcA(..) or a SetWindowLongPtrA(GWLP_WNNPROC).»

я так понимаю, он и пишет, что мол разницы нет что вызывать: SetWindowLongPtrA или SetWindowLongPtrW,
т.к. нет необходимости транслировать строки, их там просто нет
Цитата(Ruzzz @  9.11.2009,  16:44 Найти цитируемый пост)
при этом они используют

это уже я не понял )
какой смысл для юникод-окна вызывать ANSI версию, а для ANSI-окна - юникод версию, да еще опираться при этом на родительское окно?
разве что в целях эксперимента, чтобы показать, что мол процедура окна у них "симметрична"
Цитата(Ruzzz @  9.11.2009,  16:44 Найти цитируемый пост)
может они предполагают что компилироваться будет только Юникод-версия? или я не пойму.

ну да, может быть,
винамп, по крайней мере, последних версий - в юникоде


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
Ruzzz
Дата 9.11.2009, 15:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 20
Регистрация: 8.3.2008

Репутация: нет
Всего: 1



GremlinProg, аааа ) я ошибся, без ! smile
Винамп или сам плохо поддерживает юникод или некоторые модули которые идут с ним, по крайней мере в VirtualBox в XP поменял язык для Ansi приложений и получил кое-где крякозябры в русифицированном винампе, ну да не про это smile

У них в SDK есть строки:
Код

    if (IsWindowUnicode(hwndParent))
        lpWndProcOld = (WNDPROC)SetWindowLongPtrW(hwndParent,GWL_WNDPROC,(LONG)WndProc);
    else
        lpWndProcOld = (WNDPROC)SetWindowLongPtrA(hwndParent,GWL_WNDPROC,(LONG)WndProc);


При этом говорят что нет смысла в этом:
Код

    if (IsWindowUnicode(hwnd))
        CallWindowProcW(lpOldWinampWndProc,hwnd,message,wParam,lParam);
    else
        CallWindowProcA(lpOldWinampWndProc,hwnd,message,wParam,lParam);


Не понимаю почему? Только если они предполагают что этот модуль будет компилироваться как юникод? тогда еще понимаю. То есть будет явно подставлена CallWindowProcW, ну тогда нафига они верхний IsWindowUnicode не уберут? не пойму.
PM MAIL   Вверх
GremlinProg
Дата 9.11.2009, 16:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



в принципе, если локаль фиксирована, т.е. четко выставлена при старте в какой-нибудь cp1252,
то при такого рода неявных трансляциях сообщений вполне могут проскальзывать и кракозябры,
тут же физически производится перевод из MBS в WCS и обратно,

если это не учитывать, тут даже не поймешь, где конкретно происходит преобразование,
это может быть как в штатной посылке сообщения, так и внутри какой-нибудь API,

в любом случае, даже просто из соображений быстродействия программы,
лучше выделить 2 варианта оконной процедуры, если сабклассинг применяется в DLL,
или делать трансляцию, но в препроцессоре, типа такой:
Код

#define MY_UNICODE_WNDPROC
#include "my-wndproc.h"
#undef MY_UNICODE_WNDPROC
#include "my-wndproc.h"

естественно со всеми вытекающими,
т.е. пишем один транс-код, но ориентированный на MY_UNICODE_WNDPROC, а не _UNICODE
Цитата(Ruzzz @  9.11.2009,  17:27 Найти цитируемый пост)
Не понимаю почему? Только если они предполагают что этот модуль будет компилироваться как юникод? тогда еще понимаю. То есть будет явно подставлена CallWindowProcW, ну тогда нафига они верхний IsWindowUnicode не уберут? не пойму.

тут может быть такой вариант:
у них при сабклассинге используется одна кодировка, к примеру - юникод, а в процедуре по-умолчанию - ANSI,
когда они подставляли процедуру, не учли или просто не захотели пользоваться вот этой трансляцией
(может как раз из-за проблем с интернационализацией),
в итоге и получили первый уровень процедуры - юникод, а второй - ANSI,
а вместо системного перевода WCS-сообщения в MBS, используют прямой вызов ANSI процедуры,

т.е. сделали себе проблему на ровном месте,
но это просто предположение, в их SDK я не лазил


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
Earnest
Дата 10.11.2009, 08:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 33
Всего: 183



Цитата(GremlinProg @  9.11.2009,  15:29 Найти цитируемый пост)
только вот что будешь делать, когда на разных типах окон будут посылаться разные сами сообщения или уведомления,
например то же TVN_GETDISPINFO, которое UNICODE окна отсылают как TVN_GETDISPINFOW(TVN_FIRST-52), а ANSI - как TVN_GETDISPINFOA(TVN_FIRST-3)?
разве что проверять в рантайме:

Чисто добавление: в данном случае нужно проверять в обработчике код уведомления, а не Юникод. Так обычно и делают, хотя код получается громоздкий. Например, собственный (встроенный) тултип у тривью или листвью всегда Юникодный, даже если само окно не-Юникод. Помниться, как-то помучалась, пока дошло... 



--------------------
...
PM   Вверх
Ruzzz
Дата 10.11.2009, 14:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 20
Регистрация: 8.3.2008

Репутация: нет
Всего: 1



Цитата(Earnest @ 10.11.2009,  08:18)
проверять в обработчике код уведомления, а не Юникод

не совсем понял :(
PM MAIL   Вверх
Ruzzz
Дата 10.11.2009, 15:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 20
Регистрация: 8.3.2008

Репутация: нет
Всего: 1



Вот еще интересная ссылка http://msdn.microsoft.com/en-us/library/ms997565.aspx
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.0998 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.