У Iczelion в 26 сплеш поверх окна всплывает - это нормально или глюк? А нельзя сплеш вообще над десктопом выполнить без всяких окон? Нафиг он как child window нужен!
Semiono Судя по переводу Aquila так и должно быть -- читай урок внимательно, можно конечно и над desktop'ом
Semiono Держи анимированный gif в аттаче сорц, длл, картинка и ехе идея одного грека: Antonis Kyprianou
Mikl___ Я согласен с товей идеей первые несколько уроков посвятить структуре программы 1 сделать универсальный bat файл 2 вычленить в коде функцию WinMain 3 подобрать хорошие асм реализации case переходов в функции окна
могу поделиься своим кирпичом при строительстве WinMain ;=======[ SUBROUTINE ]============================ ; ;------------------------------------------------- ; Return: ;------------------------------------------------- ; Parameters: ;------------------------------------------------- @Routine_private\ Process_Message push EDI ;----------------------------------------- lea EDI,MyMessage $loop: xor EAX,EAX push EAX push EAX push EAX push EDI call GetMessage or EAX,EAX jz $exit ;----------------------------------------- push EDI call TranslateMessage ;----------------------------------------- push EDI call DispatchMessage jmp $loop ;----------------------------------------- $exit: pop EDI @Routine_end
Спасибо, Rockphorr! Только несколько "мелочных" замечаний к твоему "кирпичу" -- я уже отвечал hapr в #166, что цель топика создание минимальных по размеру программ под WinXP поэтому: 1) вызов Routine_Process_Message это лишние 5 байт, чем если бы код продцедуры был подставлен напрямую 2) Хотя это и не принято но так как API-функции сохраняют значения ESP, EBP, EBX, EDI, ESI то я с чистой совестью использую эти регистры для сохранения в них параметров, т.е. в Routine_Process_Message можно обойтись без начального PUSH EDI и конечного POP EDI итого минус еще два байта 3) указатель на MyMessage передается через lea EDI,MyMessage причем для Routine_Process_Message MyMessage не является локальной переменной поэтому вместо lea EDI,MyMessage (6 байт) разумнее было выбрать mov EDI,offset MyMessage (5 байт) еще минус один байт 4) для передачи трех 0 для GetMessage вы каждый раз при входе в цикл обнуляете eax, хотя достаточно поместить один раз 0 в ebx и использовать его содержимое для засылки в стек NULL, FALSE, FILE_BEGIN, PIPE_CLIENT_END, GMEM_FIXED и т.п. 5) можно упростить цикл обработки сообщений, без проверки возвращает ли GetMessageA в eax 0 поместив в обработчик WM_DESTROY вместо PostQuitMessage функцию ExitProcess Код (Text): @@WM_DESTROY: push 0 ;завершение программы call _imp__ExitProcess@4 минус еще 4 байта (or eax,eax/jz $exit)
ИМХО лучше не минимальных а оптимальных по размеру другими словами минимальность при условии максимальности удобства повторного использования у меня есть идея что подобные стандартные функции как Process_Message можно поместить вообще в собственную dll и все собственные программы станут тем короче чем больше таких функций в dll Рост dll (добавление туда функций) будет происходить по ходу переработанного курса уроков ...передается через EDI, который грузиться lea EDI,MyMessage... ИМХО в курсе уроков такая формулировка яснее загрузку адреса в регистр лучше делать макросом в котором предусмотрено средство выбора меж lea() и mov offset()
Rockphorr Ты просто не умеешь их готовить ) Прелесть invoke заценишь когда часок другой помедитируешь над странным глюком в программе, прежде чем наконец заметишь что передал в функцию неправильное количество параметров или забыл что она C decl или наоборот не C decl. Иногда конечно call удобнее потому как гибче, но это исключения подтверждающие правила ) Код (Text): @echo off @REM Сначала ассемблирует, затем ищет %1.rc и если нет то rsrc.rc @ echo Работает только с диска на котором установлен MASM32 !!! @ echo ╨рсюЄрхЄ Єюы№ъю ё фшёър эр ъюЄюЁюь єёЄрэютыхэ MASM32 !!! @REM ----------- АССЕМБЛИРОВАНИЕ --------------- @D:\masm32\bin\ml /c /coff /nologo %1.asm @ if errorlevel 1 goto ErrAsm @ echo %1.asm файл успешно скомпилирован !!! @ echo %1.asm Їрщы єёях°эю ёъюьяшышЁютрэ !!! @ echo _ @REM ----------- КОМПИЛЯЦИЯ РЕСУРСОВ (если есть) --------------- @if not exist %1.rc goto find_rsrc_rc @ D:\masm32\bin\rc /v /forsrc.res %1.rc @ if errorlevel 1 goto ErrResCompil1 @ goto Last_Res_Compil :find_rsrc_rc @if not exist rsrc.rc goto SkipResCompil @ D:\masm32\bin\rc /v /forsrc.res rsrc.rc @ if errorlevel 1 goto ErrResCompil1 :Last_Res_Compil @ D:\masm32\bin\cvtres /machine:ix86 rsrc.res @ if errorlevel 1 goto ErrResCompil2 @ echo Ресурсы успешно скомпилированы !!! @ echo ╨хёєЁё√ єёях°эю ёъюьяшышЁютрэ√ !!! @ echo _ :SkipResCompil @REM ----------- ЛИНКОВАНИЕ --------------- @if not exist rsrc.obj goto NoRes @ D:\masm32\bin\Link /RELEASE /SUBSYSTEM:WINDOWS /NOLOGO %1.obj rsrc.obj @ if errorlevel 1 goto ErrLink @ echo %1.exe файл успешно слинкован !!! @ echo %1.exe Їрщы єёях°эю ёышэъютрэ !!! @ del %1.obj @ del rsrc.res @ del rsrc.obj @ %1.exe @ goto TheEnd :NoRes @ D:\masm32\bin\Link /RELEASE /SUBSYSTEM:WINDOWS /NOLOGO %1.obj @ if errorlevel 1 goto ErrLink @ echo %1.exe файл успешно слинкован без ресурсов!!! @ echo %1.exe Їрщы єёях°эю ёышэъютрэ схч ЁхёєЁёют!!! @ del %1.obj @ %1.exe @ goto TheEnd @REM ----------- СООБЩЕНИЯ ОБ ОШИБКАХ --------------- :ErrResCompil1 @ echo Ошибка при компиляции ресурсов @ echo ╬°шсър яЁш ъюьяшы Ўшш ЁхёєЁёют @goto TheEnd :ErrResCompil2 @ echo Ошибка при преобразовании ресурсов в *.obj файл @ echo ╬°шсър яЁш яЁхюсЁрчютрэшш ЁхёєЁёют т *.obj Їрщы @goto TheEnd :errasm @ echo Ошибка при ассемблировании @ echo ╬°шсър яЁш рёёхьсышЁютрэшш @goto TheEnd :ErrLink @ echo Ошибка при связывании @ echo ╬°шсър яЁш ёт ч√трэшш @goto TheEnd :TheEnd мой вариант универсального RunMasm.bat для masm32 - запускать: RunMasm имя_asm_файла (без расширения .asm - оно подставляется автоматически виде .asm, .obj, .exe поэтому и указывать его сразу нельзя). Сообщения выводятся в двух кодировках, чтобы можно было их прочитать и в консоли и после перенаправления в файл. Лично мне не нравится main в асм программах. Дело даже не в лишнем вызове/возврате, а в её неуместности. В кросплатформенном С она полезна тем что скрывает платформозависимый код инициализации/завершения, в С++ к этому добавляется автовызов деструкторов, да и само понятие функции в С/С++ является базовой единицей структурирования программы. А в асме где ни то ни другое ни третье не актуально она имхо выглядит просто нелепо ) А если всё-таки хочется спрятать типовой стартовый/завершающий код, то имхо для этого удобнее макросы, которые в асм и есть основная единица структурирования программы, а функции идут уже после них (в С/С++ всё наоборот - в С макросы вторичны, а в С++ почти неуместны). Мой комплект masm32 макросов для табличного case - не идеал оптимизации конечно, но как вариант имхо пойдут, во всяком случае слепил их давно и пока особой потребности переделать не испытывал: Код (Text): ;======================================================================================= ;----------------------------------------------------------------------------- ; ---------------- Табличная обработка сообщений ----------------- ;.code ; Макросы рассчитаны на применение из кодового сегмента !!! ;Begin_TCASE {Имя таблицы} ; TCASE {Сообщение} , offset {Обработчик} ; Комментарий ;End_TCASE {Имя таблицы} ; TSWITCH {Имя таблицы}, {сообщение} ;----------------------------------------------------------------------------- ; Начать таблицу сообщений Begin_TCASE MACRO TCase_Table_Name .data TCase_Table_Name = $ ENDM ;----------------------------------------------------------------------------- ; Элемент таблицы сообщений Item Message Table TCASEc MACRO Item, Adr_Proc dd Item, Adr_Proc ENDM ;-------------------------------------------------------------------------------- ; Элемент таблицы сообщений Item Message Table для пользовательского сообщения TCASEv MACRO Item, Adr_Proc Item dd 0, Adr_Proc ENDM ;----------------------------------------------------------------------------- ; Завершить таблицу сообщений End_TCASE MACRO TCase_Table_Name TCase_Table_Name&_Size = $ - TCase_Table_Name TCase_Table_Name&_N_Items = TCase_Table_Name&_Size / 8 .code ENDM ;----------------------------------------------------------------------------- ; Обработать сообщение с помощью таблицы TSWITCH MACRO Table_Name, Message LOCAL End_Find, Exit_m IFDIFI <Message>, <EAX> ; исключить повторное присвоение ЕАХ mov EAX, Message ENDIF mov EDI, offset Table_Name ; Таблица mov ECX, Table_Name&_N_Items ; Количество элементов в таблице @@: cmp EAX, [EDI] jz End_Find add EDI, 8 sub ECX, 1 jnz @B jmp Exit_m ; Список кончился совпадения не было End_Find: jmp DWORD PTR [EDI + 4] ; При совпадении перейти на метку из таблицы (следует за найденным идентификаторм) Exit_m: ; Макрос осуществляет УХОД НА МЕТКУ при совпадении !!! ; Если совпадений не найдено выполняются комманды непосредственно за TSWITCH ENDM Пример использования: Код (Text): ;============================================================================ ; Основная программа для базового окна WinProc PROC uses ebx edi esi, hwnd:DWORD, wmsg:DWORD, wparam:DWORD, lparam:DWORD LOCAL PAST:PAINTSTRUCT ; Структура для работы с экраном ; Таблица сообщений главного окна приложения Begin_TCASE BW_Message_Table TCASEc WM_TIMER , OFFSET BW_WM_TIMER ; Срабатывания таймера TCASEc WM_NOTIFY , OFFSET BW_WM_NOTIFY ; Нотификации TCASEc WM_COMMAND , OFFSET BW_WM_COMMAND ; Меню TCASEc WM_SHOWWINDOW , OFFSET BW_WM_SHOWWINDOW ; Показ окна TCASEc WM_SIZE , OFFSET BW_WM_SIZE ; Изменение размера TCASEc WM_CHAR , OFFSET BW_WM_CHAR ; Символ с клавиатруы TCASEc WM_LBUTTONDOWN , OFFSET BW_WM_LBUTTONDOWN ; Левая кнопка мыши TCASEc WM_MOUSEMOVE , OFFSET BW_WM_MOUSEMOVE ; Перемещение мыши TCASEc WM_KEYDOWN , OFFSET BW_WM_KEYDOWN ; Нажатие клавиши TCASEc WM_KEYUP , OFFSET BW_WM_KEYUP ; Отпускание клавиши TCASEc WM_SYSKEYDOWN , OFFSET BW_WM_SYSKEYDOWN ; Нажатие клавиши TCASEc WM_SYSKEYUP , OFFSET BW_WM_SYSKEYUP ; Отпускание клавиши TCASEc WM_PAINT , OFFSET BW_WM_PAINT ; Изменение фона TCASEc WM_MOUSEWHEEL , OFFSET BW_WM_MOUSEWHEEL ; Перемещение колеса мыши TCASEc WM_SETFOCUS , OFFSET BW_WM_SETFOCUS ; Базовое окно получило фокус ввода TCASEc WM_CREATE , OFFSET BW_WM_CREATE ; Создание окна TCASEc WM_CLOSE , OFFSET BW_WM_CLOSE ; Требование выхода End_TCASE BW_Message_Table TSWITCH BW_Message_Table, [wmsg] ; Табличный переход к обработчику сообщений ; Стандартная обработка оконных сообщений invoke DefWindowProc, [hwnd], [wmsg], [wparam], [lparam] ret ;=========================================================================== ; Создание окна BW_WM_CREATE: xor eax, eax ; === Главное окно готово к открытию === ret ;=========================================================================== ; Требование выхода ExitWithPodtv: ; Вежливое invoke MessageBox, [hwnd], zSTR('Вы уверены, что хотите завершить работу программы ?'), \ zSTR('Подтверждение выхода'), MB_YESNO or MB_ICONQUESTION .IF eax == IDYES BW_WM_CLOSE: ; Безоговорочное invoke PostQuitMessage, 0 ; Подтвердить готовность окна к закрытию .ENDIF xor eax, eax ret ;=========================================================================== ; Показ окна BW_WM_SHOWWINDOW: xor eax, eax ret ;=========================================================================== ; Изменение размера BW_WM_SIZE: xor eax, eax ret ;--------------------------------------------------------------------------- ;=========================================================================== ; Прорисовка окна BW_WM_PAINT: xor eax, eax ret ;=========================================================================== ; Символ с клавиатруы BW_WM_CHAR: .IF [wparam] == ' ' invoke InvalidateRect, [hwnd], 0, True .ELSEIF [wparam] == 27 jmp ExitWithPodtv .ENDIF xor eax, eax ret ;=========================================================================== ; Левая кнопка мыши BW_WM_LBUTTONDOWN: xor eax, eax ret ;=========================================================================== ; Перемещение мыши BW_WM_MOUSEMOVE: xor eax, eax ret ;=========================================================================== ; Нажатие клавиши BW_WM_KEYDOWN: xor eax, eax ret ;=========================================================================== ; Отпускание клавиши BW_WM_KEYUP: xor eax, eax ret ;=========================================================================== ; Нажатие клавиши BW_WM_SYSKEYDOWN: xor eax, eax ret ;=========================================================================== ; Отпускание клавиши BW_WM_SYSKEYUP: xor eax, eax ret ;=========================================================================== ; Нотификации BW_WM_NOTIFY: mov edi, [lparam] ret ;=========================================================================== ; Меню BW_WM_COMMAND: ; Таблица сообщений меню главного окна приложения Begin_TCASE BW_MENU_Message_Table ; ------------------------ Меню Файл ------------------------- TCASEc IDM_Open , OFFSET BW_IDM_Open ; Открыть файл TCASEc IDM_Save , OFFSET BW_IDM_Save ; Сохранить файл TCASEc IDM_EXIT , OFFSET BW_IDM_EXIT ; Выход ; ------------------------ Меню Правка ------------------------- TCASEc IDM_Undo , OFFSET BW_IDM_Undo ; Отменить TCASEc IDM_Redo , OFFSET BW_IDM_Redo ; Вернуть отменённое TCASEc IDM_Copy , OFFSET BW_IDM_Copy ; Копировать в буфер ; ------------------------ Меню Помощь ------------------------- TCASEc IDM_ABOUT , OFFSET BW_IDM_ABOUT ; О программе TCASEc IDM_KEYHELP , OFFSET BW_IDM_KEYHELP ; Справка по управлению End_TCASE BW_MENU_Message_Table and [wparam], 0FFFFh ; сбросить различие меню и акселератора TSWITCH BW_MENU_Message_Table, [wparam] ; Табличный переход к обработчику сообщений меню ; ---------- Стандартная обработка оконных сообщений --------------- invoke DefWindowProc, [hwnd], [wmsg], [wparam], [lparam] ret ; ------------------------ Меню Файл ------------------------- BW_IDM_Open: ; --- Открыть файл --- xor eax, eax ret BW_IDM_Save: ; --- Сохранить файл --- xor eax, eax ret BW_IDM_EXIT: ; --- Выход --- ; jmp BW_WM_CLOSE ; Безоговорочный выход jmp ExitWithPodtv ; Вежливая просьба о выходе ; ------------------------- Меню Правка ------------------------- BW_IDM_Undo: ; --- Отменить --- xor eax, eax ret BW_IDM_Redo: ; --- Вернуть отменённое --- xor eax, eax ret BW_IDM_Copy: ; --- Копировать в буфер --- xor eax, eax ret ; ------------------------- Меню Помощь ------------------------- BW_IDM_ABOUT: ; --- О программе --- xor eax, eax ret BW_IDM_KEYHELP: ; --- Справка по управлению --- xor eax, eax ret ;=========================================================================== ; Перемещение колеса мыши BW_WM_MOUSEWHEEL: xor eax, eax ret ;=========================================================================== ; Срабатывания таймера BW_WM_TIMER: .if !([SEH_Flags] & SF_Error_Question) .endif xor eax, eax ret ;=========================================================================== ; Базовое окно получило фокус ввода BW_WM_SETFOCUS: xor eax, eax ret ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ExitWinProc: ret WinProc ENDP
6) имхо мои предложения по стилю - имена меток начинаются с $ ($loop имена макросов и констант с @ (@My_Flag=1) причем определяются спомощью = а не equ понимаю что специфичное по вкусу предложение
Rockphorr $ и @ имеют собственное значение ($ -- указатель на текущий адрес, @@ -- временная метка к которой обращаются через @b и @f), поэтому $ и @ нежелательно употреблять в именах меток, переменных и макросов; equ и = так же при употреблении имеетют свои различия, = -- определяет константу с именем, указанным в левой части, и с числовым значением, равным значению выражения справа. В отличие от констант, определенных по директиве EQU, константы определенные через = могут менять свое значение, обозначая в разных частях текста программы разные числа. Так написать можно: k = 100 / k = k+2 а так нельзя: k1 equ 100 / k1 equ k1 + 1 (error A2005: symbol redefinition: k1) Но это всё IMHO
Rockphorr имхо "фасады" это излишество вместо них тогда уж лучше свою макрореализацию ) А прелесть invoke в том что она автоматически контролирует количество параметров и чистит стек за С функциями. Mikl__ Гляжу в #19 борешься с call через jmp "дедовским" способом, т.е. через отказ от invoke. Хотя достаточно заменить инклюды (в барахолке васма лежит старенькая версия альтернативных инклюд требующая доработки напильником). Тогда и инвокабельная автоматика сохранится и лишних jmp не будет.
Mikl___ Да ладно - "фигня" прикольная и наверняка многим пригождается ) Пущай бегиннерсы медитируют и просветляются )
Mikl___ ИМХО именно изза собственных значений я их и использую никакой другой символ имени метки по сравнению с $ не будет говорить что это именно метка в коде, аналогично @ лучший индикатор того что это макрос или числовая константа Y_Mur значит вам еще предстоит их(фасады) распробовать когда мой дос проект приблизился к 10 кб я очень сильно почувствовал удобство влияния через фасады на технологические характеристики проекта