(не придумал куда лучше постить: сюда или в раздел по Ц. не серчайте, если что) делаю очень маленькое приложение на Ц с WINAPI и обязательно с окном (кнопки там всякие то-сё). Как делать маленькие приложения в 2кб я знаю ) но я их всю жизнь делал без окон. драйверы, сервисы всякие. А сейчас хочу сделать такое же маленькое, но с окном. Необходимое условие для создание минимального экзешника это параметр /ENTRY:WinMain . А всё остальное я как бы делаю руками что бы минимизировать размер. Но обнаружил досадный баг (или это не баг): с этим ключём прога, в которой окно создаётся по всем API правилам компилируется без проблем и даже запускается и работает, НО функции ShowWindow() и UpdateWindow() не дают никакого эффекта. Т.е. класс окна я настроил, зарегестрировал его, окно создал с помощью CreateWindowEx (и крейт виндоу и регистркласс отрабатывают нормально) а дальше пытаюсь его нарисовать, однако ничего у меня не выходит. Функции как "в холостую" отрабатывают. Окно так и не появляется. Хотя и обработчик сообщений окна и всё остальное - работает, но самого окна невидно. Стоит ключь /ENTRY:WinMain из батника убрать, как окно магическим образом начинает рисоваться, но за это я плачу аж 16 килобаетами. Может есть какой-то тайный способ?
rmn да прибудет с тобой сила! я передавал параметр с винмэйн, при этом был уверен что там то, что нужно. всё заработало
Arisu Явно тут не изза ENTRY баг, т.к. я писал и baseindependent-shellcodes с изображением окна. Работало. В вашем случае если рассуждать технологически могут возникать лишь проблемы с инициализацией стандартной библиотеки с, других потенциальных проблем трудно придумать изза использования ключа ENTRY. Если хотите сделать мааленький EXE, то лучше конечно использовать не С, а ASM. Для решения проблемы в вашем случае лишь могу посоветовать покопать в отладчике значение GetLastError()/@err,hr (если использовать VC) после вызова каждой из функции, холостых вызовов быть не доллжно, если вы все делаете правильно. Правильное использование инструментов может освободить ваш моск от сложных технических размышлений о классах окон. И конечно выкладывайте код, мы очень любим читать код, если он хорошо и красиво написан.
Mental_Mirror Да нет, все проще Функция в точке входа получает только один параметр - адрес PEB. Именно он будет в hInstance WinMain, в остальных параметрах будет какой-нибудь мусор со стека.
Ага, наступал на такие же грабли, только проблема была с командной строкой. Решил вызовом GetCommandLine(). http://ru.wikipedia.org/wiki/WinMain
Интересно. Ты уверен что у функции один параметр? Я погуглил немножко, peb берут из fs:xxxx, а у функции нет никаких параметров.
crt0.c: Код (Text): /*** *BaseProcessStartup(PVOID Peb) * *Purpose: * This routine does the C runtime initialization, calls main(), and * then exits. It never returns. * *Entry: * PVOID Peb - pointer to Win32 Process Environment Block (not used) * *Exit: * This function never returns. * *******************************************************************************/ это комментарий к функциям mainCRTStartup и WinMainCRTStartup, которые, собственно, и являются точкой входа.
rmn Вот виндовая функция в winxp, которая запускает xxxCRTStartup(): Код (Text): 7C816FB4 6A 0C push 0Ch 7C816FB6 68 E0 6F 81 7C push 7C816FE0h 7C816FBB E8 06 B5 FE FF call 7C8024C6 7C816FC0 83 65 FC 00 and dword ptr [ebp-4],0 7C816FC4 6A 04 push 4 7C816FC6 8D 45 08 lea eax,[ebp+8] 7C816FC9 50 push eax 7C816FCA 6A 09 push 9 7C816FCC 6A FE push 0FFFFFFFEh 7C816FCE FF 15 A0 13 80 7C call dword ptr ds:[7C8013A0h] 7C816FD4 FF 55 08 call dword ptr [ebp+8] 7C816FD7 50 push eax 7C816FD8 E8 7B 50 FF FF call 7C80C058 7C816FDD 90 nop 7C816FDE 90 nop 7C816FDF 90 nop 7C816FE0 ?? db ffh 7C816FE1 ?? db ffh 7C816FE2 ?? db ffh call 7C8024C6 - это вроде как настройка SEH call dword ptr ds:[7C8013A0h] - не знаю что, но она свои 4 параметра из стека достает call dword ptr [ebp+8] - собсно вызов xxxCRTStartup() Как видишь, никакими peb и не пахнет. Из какого компилятора ты привел комментарий? В VC++ нет такого, по крайней мере начиная с шестой версии. И здесь у тебя ошибочка. Это call 7C80C058 никогда не возвращается.
Вобщем листинг почти в яблочко, только точка входа начинается еще чуть раньше. Вот точная точка входа на XP SP2: Код (Text): .text:7C810665 xor ebp, ebp .text:7C810667 push eax .text:7C810668 push 0 .text:7C81066A jmp loc_7C816FB4 После этого кода выполняется как раз то, о чем говорил CoolCmd. Ну видите сами смещения совпадают. Что такое точка входа? Есть параметр EntryPoint в опциональном заголовке PE-модуля. При создании процесса процесс родитель создает первичный поток. Вот именно адрес 0x7C810665 и есть стартовый адрес для нового потока. Этот адрес тоже можно считать точкой входа. Далее, это так-сказать первичная точка входа вызывает точку входа, которая указана в опциональном заголовке PE-модуля. Вызывает и действительно не передает никаких параметров. Есть тонкость, она может пронзить ваш спинной мозг холодом на несколько секунд. Итак, пойду убью сибя ап стену.
rmn Упс ошибся, дано шестерку забросил. IceStudent Там формат вызова __cdecl, могут все что угодно в параметрах написать и прога будет работать... если эти параметры не использовать. Mental_Mirror У тебя IDA? Может этот код вызывается для запуска всех новых потоков? Тогда call 7C80C058 скорее всего ExitThread(). Давай выкладывай тонкость, я хочу умереть.
CoolCmd Тонкость в том, что есть точка входа еще до той которая указана в контексте нового создаваемого потока. Что она активизировалась, надо поставить в PEB флаг BeingDebugged и обработать int3, тогда мы попадаем на на начальный этап загрузки процесса, когда еще TLS Callbacks не вызваны. IDA. Не, только для стартового. В Context.EAX записывается EntryPoint из опционального заголовка. Потом он кладется в стек. И вызов идет call dword ptr [ebp+8]. Про ExitThread верно. Ну в общем возьми IDA и посмотри, там все видно и без моих коментариев. Полезно.