Здравствуйте. Не понимаю как сделать по смыслу #ifdef UNICODE уже на этапе исполнения кода в runtime? Проблема такая. В коде используется тип TCHAR, который принимает CHAR или WCHAR на этапе компиляции программы. Как узнать какой тип в конечном итоге установлен?
Код (C++): if (sizeof(TCHAR) == sizeof(CHAR)) { cout << "CHAR" << endl; // 1 байт на символ (но это может быть и UTF-8) } else if (sizeof(TCHAR) == sizeof(CHARW)) { cout << "CHARW" << endl; // 2 байта на символ } else { cout << sizeof(TCHAR) << endl; // 3 или 4 байта на символ }
Спасибо, глубоким вечером эта очевидная мысль мне как-то не пришла. Но вот что будет, если вместо TCHAR использовать LPTSTR? Sizeof(LPCTSTR) будет один и тот же и для LPСSTR и для LPCWSTR. Хотя конечно, эти типы все равно ссылаются на CHAR, WCHAR и можно смело применять sizeof(TCHAR) и в этом случае чтобы определить в какой тип разрешается LPTSTR. Но хотелось бы чего-нибудь более прямолинейного, неужели нет никакой глобальной константы в контексте готовой сборки (файл dll) где был бы зафиксирован результат #ifdef UNICODE? --- Сообщение объединено, 9 янв 2025 --- Спасибо за наводку, не знал об этом. Первые три буквы намекают на то что существует набор функций имеющих отношение к библиотеке времени выполнения RTL (это я уже немного погуглил). Но с какого уровня эти функции разрешено вызывать? Скажем из контекста консольного приложения Windows такой вызов разрешен? В описании фигурирует ntdll.dll - о ней мало что знаю.
Код (C++): LPCTSTR a; if (sizeof(a[0]) == sizeof(CHAR)) { cout << "CHAR" << endl; // 1 байт на символ (но это может быть и UTF-8) } else if (sizeof(*a) == sizeof(CHARW)) { cout << "CHARW" << endl; // 2 байта на символ } else { cout << sizeof(*a) << " " << sizeof(a[0]) << endl; // 3 или 4 байта на символ } Но надо сначала проверять на a == null, чтобы не было проблем с адресацией в никуда.
Разрешен. У Microsoft даже есть хидер для таких функций https://learn.microsoft.com/en-us/windows/win32/api/winternl/ (правда там и 5% от всего NativeAPI нет, так что лучше используйте https://github.com/hfiref0x/NtCall64/blob/master/Source/NtCall64/ntos.h и ему подобные). Смысл в том, что используя функции ntdll.dll из юзермода, вы просто минуете WinAPI.
malex Rtl* это нэйтив, обычному приложению это не желательно использовать. Имеются аналоги(обертки) в виде winapi, eg IsTextUnicode. В данном случае это врядле нужно(эвристика), да и сборка своя(можно константу задать и проверить значение/размер).
Помимо прочего, в ней реализован загрузчик образов РЕ из диска в память (функции с префиксом Ldr_xx), поэтому эта библиотека грузится самой первой во все пользовательские процессы. Именно она загружает ваш файл в память, и передаёт управление на точку-входа.
Мои пять копеек ОберткаОригинал в ntdllkernel32ExitProcessRtlExitUserProcessExitThreadRtlExitUserThreadHeapAllocRtlAllocateHeapHeapReAllocRtlReAllocateHeapHeapSizeRtlSizeHeapuser32DefWindowProcANtdllDefWindowProc_ADefDlgProcANtdllDialogWndProc_A
Есть конечно. Самый наглядный пример KernelBase.CreateProcessInternalW Внутри этой функции много чего происходит (особенно в последних версиях 26100)
Всегда считал, что WinAPI самый низкий уровень и ниже не лазил, а оно вон как! Под ним целый неизведанный (для меня) континент! Сие открытие надо переварить.
malex, WinAPI это можно сказать верхушка айсберга. Даже NativeAPI далеко не самый низкий уровень. За нативом идёт ядро. Условно некоторые называют эти функции KernelAPI - то что выполняется в самом ядре (ntoskrnl.exe). И самым низким уровнем можно считать слой аппаратных абстракций (HAL). Где-то между ядром и hal может спрятаться гипервизор.
... в каждой луже среди водных гадов есть свой гад, других гадов иройством превосходящий... © Салтыков-Щедрин
Кстати в Ntdll.dll (как оказалось) имеется огромное кол-во неэкпортируемых наружу "Internals" функций, в частности с префиксом Ldrp_xx() примерно 300 штук, и Rtlp_xx() овер 700 единиц. При этом экспортируемых "Externals" ~2000, а если учесть одинаковые Nt/Zw, и того меньше. Проверить это можно в WinDbg командой x ntdll!Ldrp* - у тех-что прописаны в экспорте нет символа "p" в хвосте.
А цель то какая такого выбора? А то очень похоже, что ищется поиск решения проблемы которой нет на самом деле.
..встречаются весьма интересные экземпляры, типа LdrpInitializeProcess(), LdrpLoadImportModule(), LdrpRunInitializeRoutines() и масса других - думаю ими можно будет, например, запускать экзешники в своей памяти по типу LoadPE. Надо будет покопаться..
Разные кодировки при передаче параметров из кода клиента в код библиотеки. Пытаюсь это унифицировать на манер TCHAR. Хотелось бы знать как WinAPI выполняет переход от вызова A версии к W и обратно. Где-то же оно конвертируется? Как это сделано?