вторник, 18 мая 2010 г.

как подружить STL-строки с WinAPI?

std::string и std::wstring - очень удобные объекты для работы со строками, но при взаимодействии их с WinAPI могут возникать некоторые проблемы.

Если для char и wchar_t существует переходящий тип TCHAR, то в STL такого типа нет, но ведь у нас и самих есть своя голова на плечах, что нам стоит его создать?

Пожалуй, именно такую задачу решать ну совсем не интересно, давайте решим более сложную, решим ее заодно с задачей "о переходящих типах".

Существует огромный набор функций и типов WinAPI, часть из которых так или иначе требует участия строкового типа данных. И существует аналогичный набор макросов, которы
81; отвечает за совместимость всех этих функций и типов.

Но зачем нам запоминать "кривые" названия макросов, типа _stprintf и _sntscanf_s, когда мы можем просто сформулировать некоторый набор правил, по которым формируются различия между этими типами и функциями в API:
#define W( name )
#define WCAT( l, r )
#define _W( name )
#define AW( name )
#define WCSTR( name )
#define _WCSTR( name )
макрос WCAT( l, r ) нужен для подстановки литеры w между левой ( l ) и правой ( r ) частями имени типов и функций:
ANSI: _isspace_l, __argv, _vscprintf,  ...
UNICODE: _iswspace_l, __wargv, _vscwprintf, ...

макрос W( name ) нужен для подстановки литеры w к имени типов и функций:
ANSI: main, std::string, ...
UNICODE: wmain, std::wstring, ...

макрос _W( name ) нужен для подстановки литер _w к имени типов и функций:
ANSI: fopen_s, remove, ...
UNICODE: _wfopen_s, _wremove, ...

макрос AW( name ) нужен для подстановки литеры A или W в конец имени типов и функций:
ANSI: CreateWindowA, SendMessageA, CREATESTRUCTA, ...
UNICODE: CreateWindowW, SendMessageW, CREATESTRUCTW, ...

макрос WCSTR( name ) нужен для подстановки префикса str или wcs к имени типов и функций:
ANSI: strlen, strncpy_s, strchr, ...
UNICODE: wcslen, wcsncpy_s, wcschr, ...

макрос _WCSTR( name ) нужен для подстановки префикса _str или _wcs к имени типов и функций:
ANSI: _strtod_l, _strtoi64, _strdup, ...
UNICODE: _wcstod_l, _wcstoi64, _wcsdup, ...

Реализация этих макросов может быть разной, вот только один из вариантов:
#ifndef UNICODE
 #define WCAT( l, r ) l ## r
 #define W( name ) name
 #define AW( name ) name ## A
 #define WCSTR( name ) str ## name
 #define _WCSTR( name ) _str ## name
#else
 #define WCAT( l, r ) l ## w ## r
 #define W( name ) w ## name
 #define AW( name ) name ## W
 #define WCSTR( name ) wcs ## name
 #define _WCSTR( name ) _wcs ## name
#endif
#define _W( name )  WCAT( _, name )
А теперь заменим все эти макросы одним, универсальным:
#ifndef UNICODE
 #define ucat( left, right, ansi, unicode ) left ## ansi ## right
#else
 #define ucat( left, right, ansi, unicode ) left ## unicode ## right
#endif
и построим на его основе, для наглядности, все остальные:
#define WCAT( l, r ) ucat( l, r, , w )
#define W( name ) ucat( , name, , w )
#define AW( name ) ucat( name, , A, W )
#define WCSTR( name ) ucat( , name, str, wcs )
#define _WCSTR( name ) ucat( _, name, str, wcs )
#define _W( name ) ucat( _, name, , w )
да, можно заметить, макросы адекватно востпринимают отсутствие каких-либо идентификаторов между запятыми, такое поведение препроцессора и позволяет использовать всего лишь один макрос, лично я дополнительно пользуюсь только такими:
#define w( left, right ) ucat( left, right, , w )
#define W( left, right ) ucat( left, right, , W )
примеры:
w( , main )( ... );  //  main/wmain
w( __, argv )[...];  //  __argv/__wargv
W( _CrtDbgReport, )( ... );  //  _CrtDbgReport/_CrtDbgReportW
ucat( SendMessage, , A, W )( ... );  //  SendMessageA/SendMessageW
ucat( ,len , str, wcs )( ... );  //  strlen/wcslen
ucat( _, icmp, str, wcs )( ... );  //  _stricmp/_wcsicmp

в следующей статье производится унификация таких правил

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

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