Шаблон оконного приложения
Каждый сайт, хоть немного причастный к программированию для Windows, считает своим долгом поместить на своих страницах шаблон оконного приложения. Assembler.ru в этом отношении ничем не хуже остальных. Почему бы и нет? Это настоящее, живое, работающее приложение, чего ж его стыдиться? Многим из нас его хватит, чтобы сказать себе с удовлетворением: "Достаточно, я в себя поверил", и вернуться к любимому третьему видеорежиму. Остальным же, возможно, оно понадобится еще много-много раз для того, чтобы начать с него новый проект, и, потратив полмесяца на его развитие, выяснить, что нужно было начинать с чего-то другого. Итак:
.386 .Model flat,stdcall
include windows.inc ;заголовочный файл API;///////////////////////////////////////////////////////////// windows.inc GetModuleHandleA PROTO :DWORD ;прототипы функций API LoadIconA PROTO :DWORD,:DWORD LoadCursorA PROTO :DWORD,:DWORD RegisterClassExA PROTO :DWORD CreateWindowExA PROTO :DWORD,:DWORD,:DWORD,:DWORD,\ :DWORD,:DWORD,:DWORD,:DWORD,\ :DWORD,:DWORD,:DWORD,:DWORD ShowWindow PROTO :DWORD,:DWORD GetMessageA PROTO :DWORD,:DWORD,:DWORD,:DWORD TranslateMessage PROTO :DWORD DispatchMessageA PROTO :DWORD ExitProcess PROTO :DWORD PostQuitMessage PROTO :DWORD DefWindowProcA PROTO :DWORD,:DWORD,:DWORD,:DWORD
WNDCLASSEXA STRUCT 8 ;структура класса окна cbSize dd ? style dd ? lpfnWndProc dd ? cbClsExtra dd ? cbWndExtra dd ? hInstance dd ? hIcon dd ? hCursor dd ? hbrBackground dd ? lpszMenuName dd ? lpszClassName dd ? hIconSm dd ? WNDCLASSEXA ENDS
POINT STRUCT 8 x dd ? y dd ? POINT ENDS
MSG STRUCT 8 ;структура сообщения hwnd dd ? message dd ? wParam dd ? lParam dd ? time dd ?
pt POINT{} MSG ENDS
NULL =0 ;разные константы IDI_APPLICATION =32512 IDC_ARROW =32512 COLOR_WINDOWFRAME =6 SW_SHOW =5 EXIT_ERROR =0ffffffffh WM_DESTROY =2
CS_VREDRAW =0001h CS_HREDRAW =0002h
WS_OVERLAPPED =00000000h ;константы стилей окна WS_CAPTION =00C00000h WS_SYSMENU =00080000h WS_THICKFRAME =00040000h WS_MINIMIZEBOX =00020000h WS_MAXIMIZEBOX =00010000h
WS_OVERLAPPEDWINDOW= WS_OVERLAPPED OR\ WS_CAPTION OR\ WS_SYSMENU OR\ WS_THICKFRAME OR\ WS_MINIMIZEBOX OR\ WS_MAXIMIZEBOX if(dhtml){document.all["include"].style.display="block";document.all["windows"].style.display="none";}
;///////////////////////////////////////////////////////////// WinMain .const app_name db "WinApp Template",0 ;имя приложения class_name db "WinApp Template Class",0 ;имя класса окна .data? win_class WNDCLASSEXA{} win_handle dd ? loop_message MSG{} .code ;::::::::::::::::::::::::::::::::::::::::::::::::::::::::: WinMain PROC PUBLIC hinst,prev_hinst,command_line,cmd_show ;......................................................... регистрация класса окна mov win_class.cbSize,sizeof(WNDCLASSEXA) mov win_class.style,CS_HREDRAW OR CS_VREDRAW mov win_class.lpfnWndProc,offset win_procedure mov win_class.cbClsExtra,0 mov win_class.cbWndExtra,0 invoke GetModuleHandleA,NULL mov win_class.hInstance,eax invoke LoadIconA,NULL,IDI_APPLICATION mov win_class.hIcon,eax mov win_class.hIconSm,eax invoke LoadCursorA,NULL,IDC_ARROW mov win_class.hCursor,NULL mov win_class.hbrBackground,COLOR_WINDOWFRAME mov win_class.lpszMenuName,NULL mov win_class.lpszClassName,offset class_name invoke RegisterClassExA,offset win_class .if(!eax) jmp abort .endif ;......................................................... создание окна invoke CreateWindowExA,NULL,\ offset class_name,\ offset app_name,\ WS_OVERLAPPEDWINDOW,\ 100,100,300,200,\ NULL,\ NULL,\ win_class.hInstance,\ NULL .if(!eax) jmp abort .endif mov win_handle,eax ;он еще пригодится, только не сегодня ;......................................................... вывод окна на экран invoke ShowWindow,eax,SW_SHOW ;......................................................... инициализация ;здесь можно вставить все необходимые действия для первичной инициализации ;приложения (например, загрузку и разбор файла настроек) ;......................................................... цикл опроса очереди сообщений msg_loop: invoke GetMessageA,offset loop_message,NULL,0,0 .if(!eax) invoke ExitProcess,loop_message.wParam ;успешное завершение приложения .endif invoke TranslateMessage,offset loop_message invoke DispatchMessageA,offset loop_message jmp msg_loop ;......................................................... аварийное завершение abort: invoke ExitProcess,EXIT_ERROR WinMain ENDP
;///////////////////////////////////////////////////////////// Оконная процедура win_procedure PROC window_from,message,w_param,l_param .if(message==WM_DESTROY) invoke PostQuitMessage,0 ; .elseif(message==...) ;обработка остальных необходимых сообщений ; ... ; .elseif(message==...) ; ... ; .elseif(message==...) ; ... .else ;сообщение не обработано invoke DefWindowProcA,window_from,message,w_param,l_param ret .endif xor eax,eax ;сообщение обработано ret win_procedure ENDP
;############################################################# end
Вот, собственно, и все приложение. В нем реализованы фундаментальные концепции общего прикладного програмирования для Windows:
- работа начинается с вынужденного объектно-ориентированного действия - громоздкой регистрации класса окна с помощью функции RegisterClassExA. Вы должны сделать это, даже если собираетесь создать всего одно окно с такими свойствами, потому что так повелел когда-то Уильям Гейтс Второй, известный в народе как просто Билл. Впрочем, вы можете избежать этой неприятной процедуры, если воспользуетесь при создании окна одним из предопределенных классов - BUTTON, COMBOBOX , EDIT , LISTBOX , MDICLIENT , SCROLLBAR , STATIC. С помощью, например, класса BUTTON вы можете сделать большую-пребольшую кнопку и нажимать ее день и ночь до умопомрачения, ожидая, пока из floppy-дисковода выскочит банан. А класс STATIC очень удобен для эмуляции забора: написанное на таком окне емкое трехбуквенное слово всегда напомнит вам о необходимости вернуться к повседневным заботам.
- если регистрация класса окна прошла успешно, можно создать само окно с помощью функции CreateWindowExA. Полученный при ее возврате в регистре eax дескриптор окна следует сохранить до лучших времен. Он потребуется очень часто для выполнения манипуляций с окном.
- созданное окно полностью функционально за исключением одной мелочи: его не видно. Может, и в самом деле его не стоит показывать, чтобы не позориться. А иногда это действительно не нужно, например, если использовать главное окно для общей диспетчеризации приложения, а для общения с пользователем создавать другие окна. Но если вам действительно нужно показать окно, то это делает функция ShowWindow
- следующий этап - ваш. Делайте что хотите. Можете пойти попить кофейку, а можете чего-нибудь попрограммировать. Но помните: пока еще в приложении обработка сообщений не идет, поэтому оно мертво. Свежесозданное окно торчит недвижимо на экране как символ стабильности внутриполитических процессов, и ничто не оставляет на нем следов, как на зубах Кристины Пугачевой/Орбакайте/Пресняковой/Орбакайте.
- и только цикл опроса очереди сообщений оживит ваше окно, и кнопочки в его заголовке начнут нажиматься, вызывая разные полезные эффекты, и границы его станут послушны движениям придавленной слева мыши, и много еще чего разного можно будет сделать с этим окном.
- потому что в вашем распоряжении теперь - оконная процедура win_procedure. Она принимает все и всяческие сообщения, адресуемые вашему окну всеми, кому не лень, и делает в ответ на них все, что вы пожелаете. В данном случае вы пожелали отправлять все эти сообщения обратно в систему, чтобы она сама делала с окном то, что повелел когда-то Билл. Единственное сообщение, на которое реагирует ваша оконная процедура - это WM_DESTROY, которое означает, что вам надоело любоваться окном, и вы нажали Alt+F4, или щелкнули по кнопочке с крестиком, или выбрали Close в системном меню. Да и поделом ему.
Если вы соберетесь откомпилировать приложение, вы можете сделать это с помощью MS Developer Studio, воспользовавшись нашими рекомендациями.
Только не забудьте удалить из исходного текста либо строку include windows.inc, либо содержимое файла windows.inc, если он у вас имеется в готовом виде.