Windows — это тупо.
Использование Windows API (WINAPI, исторически назывшегося WIN32API, чтобы отличать от устаревшего WIN16API) содержит кучу странных вещей. Например, если ты хочешь создать файл через Windows API, ты вызываешь CreateFile.
Но если зайти в документацию MSDN (Microsoft Developer Network) и посмотреть на CreateFile, то обнаружишь, что их там два:
- CreateFileA
- CreateFileW
Когда ты пишешь в коде на C/C++ просто «CreateFile», в зависимости от настроек компилятора/проекта оно автоматически подменяется либо на CreateFileA, либо на CreateFileW.
Почему, блин, у Windows вообще есть CreateFileA и CreateFileW?!
Потому что всё ОЧЕНЬ тупо.
CreateFileA — это ANSI-версия.
CreateFileW — это WIDE-версия (широкие символы, то бишь поддержка Unicode).
Давным-давно, ещё во времена 16-битного Windows, Microsoft захотела поддерживать символы не из английского алфавита (японские, китайские, русские и т.д.). Они решили сделать все такие символы фиксированного размера — 2 байта на символ (это и есть WIDE, он же UTF-16).
Но просто взять и перевести ВСЁ на Unicode было нельзя — это сломало бы миллионы существующих программ. Поэтому они пошли по пути наименьшего сопротивления: для каждой функции, которая работает со строками, сделали две версии — с суффиксами A (ANSI) и W (Wide).
Самое смешное: если ты вызываешь CreateFileA, то внутри Windows всё равно преобразует твою ANSI-строку в Unicode, вызовет настоящую CreateFileW, а потом ещё и обратно превратит результат в ANSI и отдаст тебе. То есть:
- Ты вызываешь CreateFileA(путь_в_ANSI)
→ Windows делает MultiByteToWideChar (ANSI → Unicode)
→ вызывает CreateFileW(путь_в_Unicode) (вся настоящая работа происходит тут)
→ делает WideCharToMultiByte (Unicode → ANSI обратно)
- Ты получаешь результат от CreateFileA
Ещё тупее становится, когда начинаешь разбираться с типами строк в Windows:
- CHAR — обычный char, ANSI (1 байт на символ)
- WCHAR — широкий символ, wchar_t, Unicode (2 байта)
- TCHAR — «транзитный» тип, который сам не знает, кем ему быть
Когда программируешь под Windows и не уверен, в каком режиме соберётся проект (ANSI или Unicode), разработчики используют TCHAR. Компилятор сам подставит нужный тип в зависимости от настроек.
Классический пример этой шизы — официальная документация Microsoft. У функции CreateProcess тоже есть CreateProcessA и CreateProcessW. И в примерах кода от Microsoft они используют LPTSTR (Long Pointer to TCHAR String, т.е. «длинный указатель на транзитную строку»).
В зависимости от настроек проекта LPTSTR превратится либо в:
- CHAR* FilePath = 0;
либо в:
- WCHAR* FilePath = 0;
Вот такая вот историческая красота и боль Windows-программирования 😅
_
src