Касты в случае WinAPI
От: FrozenHeart  
Дата: 10.12.13 14:58
Оценка: :))
Приветствую.

Имеется WinAPI-функция (если быть более точным, то в данном случае это SendMessageTimeoutA), которая в качестве одного из параметров принимает аргумент типа PDWORD_PTR, который определён (по крайней мере, в моём случае — мало ли, это от каких-то макросов зависит) в заголовочном файле "basetsd.h" следующим образом:

typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;


ULONG_PTR определён как

typedef _W64 unsigned long ULONG_PTR, *PULONG_PTR;


Требуется вызвать данную функцию из кода, написанного на C++. Разумеется, все примеры в интернете пестрят вариантами с C-style кастами:

if (!SendMessageTimeoutA(
    window_handle
    , msg_id
    , NULL
    , NULL
    , SMTO_ABORTIFHUNG
    , 1000
    , (PDWORD)&lRes
    ))
{
    // ...
}


C-style касты, на мой взгляд, не должны быть в коде, написанном на C++, ведь специально для этих целей там были заведены операторы приведения типов. Впрочем, использовать reinterpret_cast тоже не очень-то и хочется, ведь существует прекрасный инструмент под названием boost::reinterpret_pointer_cast (boost в проекте итак используется, так что специально ради одного лишь каста подключать его не придётся). В таком случае каст примет вид

boost::reinterpret_pointer_cast<DWORD>(&lRes)


Обратите внимание, что в качестве шаблонного аргумента здесь используется уже не PDWORD, как это было в случае C-style каста, а DWORD. PDWORD определён как

typedef DWORD near          *PDWORD;


near, по идее, это "пустой" макрос:

#define near


К чему я веду? К тому, что от изначального PDWORD_PTR мы пришли аж к DWORD*, который, казалось бы, абсолютно то же самое, но гадать, будет ли при каких-то обстоятельствах он отличаться или нет — мне не очень хочется (мало ли, какие-то макросы на это влияют или ещё что-то).

Что Вы делаете в подобных случаях? Используете C-style каст и не паритесь? Делает reinterpret_cast? Используете boost::reinterpret_pointer_cast? В общем, подскажите, пожалуйста, best practices по этому поводу.
avalon/1.0.433
Re: Касты в случае WinAPI
От: Abyx Россия  
Дата: 10.12.13 15:16
Оценка:
Здравствуйте, FrozenHeart, Вы писали:

а зачем вам вообще каст? чтобы сконвертировать LRESULT* в PDWORD_PTR? так просто используйте временную переменную с типом DWORD_PTR и потом копируйте ее куда надо.
In Zen We Trust
Re: Касты в случае WinAPI
От: Pavel Dvorkin Россия  
Дата: 10.12.13 15:34
Оценка: 1 (1) +1
Здравствуйте, FrozenHeart, Вы писали:


FH>Что Вы делаете в подобных случаях? Используете C-style каст и не паритесь?


В Win API свои нравы, потому что основной интерфейс Win API (про OLE не говорю)- это С, а не С++. А поэтому там принят C-style каст. Лучше его и оставить, иначе тебя не поймут. Да и не все ли равно — там же только статические касты, то есть ничего реально не делающие, за ними не стоит код

SendMessage(hWndListbox,LB_ADDSTRING, 0, (LPARAM)szString);

Да, тут char* преобразуется к long, но кода тут нет — просто берется численное значение указателя szString и подается под видом long.
With best regards
Pavel Dvorkin
Re: Касты в случае WinAPI
От: uzhas Ниоткуда  
Дата: 10.12.13 15:39
Оценка: +2
Здравствуйте, FrozenHeart, Вы писали:

FH>Что Вы делаете в подобных случаях? Используете C-style каст и не паритесь? Делает reinterpret_cast? Используете boost::reinterpret_pointer_cast? В общем, подскажите, пожалуйста, best practices по этому поводу.


просто не смешивайте WINAPI и плюсовый код. пишите обвязки, которые уже удобно будет использовать в плюсовом коде. это стандартный подход, применяемый во взаимодействии C и C++.
внутри обвязок я использую C-style

использование boost::reinterpret_pointer_cast<DWORD> считаю неразумным, ибо усложняется восприятие кода из-за синтаксического расхождения типов аргументов (в сигнатуре функции и передаваемого аргумента). лучше в данном случае reinterpret_cast<PDWORD>, т.к. тип в сигнатуре функции и тип в касте совпадают. погружаться в обилие типов и макросов реально лениво. погрузился и забыл — вот мой подход. и коллег стараюсь не напрягать этим =)

обвязки полезны для внедрения проверок на ошибки, которые можно превращать в исключения
Re[2]: Касты в случае WinAPI
От: Abyx Россия  
Дата: 10.12.13 15:59
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>В Win API свои нравы, потому что основной интерфейс Win API (про OLE не говорю)- это С, а не С++. А поэтому там принят C-style каст. Лучше его и оставить, иначе тебя не поймут. Да и не все ли равно — там же только статические касты, то есть ничего реально не делающие, за ними не стоит код


разница есть, нельзя случайно убрать const и нарваться на #AV, или нельзя подсунуть параметр не того типа который реально ожидает функция.
type-safety вобщем.

конечно в случае каста к LPARAM и т.п. достаточно использовать c-style каст, но в других случаях лучше использовать static_cast/reinterpret_cast/numeric_cast/etc, если их использование делает код безопаснее.
In Zen We Trust
Re[3]: Касты в случае WinAPI
От: Pavel Dvorkin Россия  
Дата: 10.12.13 16:31
Оценка:
Здравствуйте, Abyx, Вы писали:

A>разница есть, нельзя случайно убрать const и нарваться на #AV, или нельзя подсунуть параметр не того типа который реально ожидает функция.

A>type-safety вобщем.

A>конечно в случае каста к LPARAM и т.п. достаточно использовать c-style каст, но в других случаях лучше использовать static_cast/reinterpret_cast/numeric_cast/etc, если их использование делает код безопаснее.


Можно реальный пример, где делает , для Win API, конечно ? Просто я не помню, чтобы хоть где-то в WinAPI программах использовались эти *_cast.
With best regards
Pavel Dvorkin
Re: Касты в случае WinAPI
От: visual_wind  
Дата: 10.12.13 17:00
Оценка: -1
Здравствуйте, FrozenHeart, Вы писали:

FH>Что Вы делаете в подобных случаях? Используете C-style каст и не паритесь? Делает reinterpret_cast? Используете boost::reinterpret_pointer_cast? В общем, подскажите, пожалуйста, best practices по этому поводу.


Вот здесь
Автор: _nn_
Дата: 18.01.07
и static_cast не спас, а только закамуфлировал проблему. ИМХО, малообоснованно надеяться, что плюсовые касты радикально изменят ситуацию лучшему при использовании WinAPI.
Re[4]: Касты в случае WinAPI
От: Abyx Россия  
Дата: 10.12.13 18:12
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, Abyx, Вы писали:


A>>разница есть, нельзя случайно убрать const и нарваться на #AV, или нельзя подсунуть параметр не того типа который реально ожидает функция.

A>>type-safety вобщем.

A>>конечно в случае каста к LPARAM и т.п. достаточно использовать c-style каст, но в других случаях лучше использовать static_cast/reinterpret_cast/numeric_cast/etc, если их использование делает код безопаснее.


PD>Можно реальный пример, где делает , для Win API, конечно ? Просто я не помню, чтобы хоть где-то в WinAPI программах использовались эти *_cast.


хм... кажется я несколько поторопился осудить неиспользование *_кастов.
я тоже не могу вспомнить где имело бы смысл их использовать. это могли бы быть касты указателей LPCVOID -> T*, но я не помню API где мы получаем LPCVOID, или другой LPCXXX и должны скастовать его в какой-то другой тип
In Zen We Trust
Re: Касты в случае WinAPI
От: Mr.Delphist  
Дата: 10.12.13 20:22
Оценка:
Здравствуйте, FrozenHeart, Вы писали:

FH>Что Вы делаете в подобных случаях? Используете C-style каст и не паритесь? Делает reinterpret_cast? Используете boost::reinterpret_pointer_cast? В общем, подскажите, пожалуйста, best practices по этому поводу.


Вообще это принято прятать за врапперами. Да, это излишество, но неизбежное зло на стыке двух миров. Интеграционный glue-код всегда место повышенного риска, поэтому надеяться на помощь компилятора и прочих автоматических сил — бесперспективно.
Re[2]: Касты в случае WinAPI
От: FrozenHeart  
Дата: 11.12.13 05:55
Оценка:
u> просто не смешивайте WINAPI и плюсовый код. пишите обвязки, которые уже удобно будет использовать в плюсовом коде. это стандартный подход, применяемый во взаимодействии C и C++.
u> внутри обвязок я использую C-style

А как Вы обычно поступаете — делаете обёртки для каждой из используемых WinAPI-функций? Не слишком ли это много?
avalon/1.0.433
Re[2]: Касты в случае WinAPI
От: FrozenHeart  
Дата: 11.12.13 05:55
Оценка:
MD> Вообще это принято прятать за врапперами. Да, это излишество, но неизбежное зло на стыке двух миров. Интеграционный glue-код всегда место повышенного риска, поэтому надеяться на помощь компилятора и прочих автоматических сил — бесперспективно.

А как Вы обычно поступаете — делаете обёртки для каждой из используемых WinAPI-функций?
avalon/1.0.433
Re[2]: Касты в случае WinAPI
От: FrozenHeart  
Дата: 11.12.13 06:02
Оценка:
A> а зачем вам вообще каст? чтобы сконвертировать LRESULT* в PDWORD_PTR? так просто используйте временную переменную с типом DWORD_PTR и потом копируйте ее куда надо.

Да, здесь действительно непонятно, зачем было использовать LRESULT (код брал из примера в интернете), но это не отменяет вопроса, т.к. похожих мест при работе с WinAPI довольно много.
avalon/1.0.433
Re[5]: Касты в случае WinAPI
От: John1979  
Дата: 11.12.13 06:22
Оценка:
Здравствуйте, Abyx, Вы писали:

A>хм... кажется я несколько поторопился осудить неиспользование *_кастов.

A>я тоже не могу вспомнить где имело бы смысл их использовать. это могли бы быть касты указателей LPCVOID -> T*, но я не помню API где мы получаем LPCVOID, или другой LPCXXX и должны скастовать его в какой-то другой тип
GetWindowLongPtr ?
Re[3]: Касты в случае WinAPI
От: uzhas Ниоткуда  
Дата: 11.12.13 07:04
Оценка: -1
Здравствуйте, FrozenHeart, Вы писали:

FH>А как Вы обычно поступаете — делаете обёртки для каждой из используемых WinAPI-функций?


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

к примеру, пишется класс Thread, который внутри использует несколько WINAPI функций, для управления потоками: запуск потока, передача аргументов в функцию потока, пауза, ожидание на потоке или нескольких хендлах, освобождение ресурсов (хендлов)
класс Thread наружу выдает удобный для приложения C++ интерфейс, внутри использует несколько WINAPI функций
Re[3]: Касты в случае WinAPI
От: Mr.Delphist  
Дата: 11.12.13 10:45
Оценка:
Здравствуйте, FrozenHeart, Вы писали:

MD>> Вообще это принято прятать за врапперами. Да, это излишество, но неизбежное зло на стыке двух миров. Интеграционный glue-код всегда место повышенного риска, поэтому надеяться на помощь компилятора и прочих автоматических сил — бесперспективно.


FH>А как Вы обычно поступаете — делаете обёртки для каждой из используемых WinAPI-функций?


Обычно это собирается в какой-то враппер-классец, который в числе прочего стимулирует клиентский код к определённому workflow. Просто оборачивать функцию другой функцией с одним лишь приведением типов — тоже можно.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.