Программа, демонстрирующая иерархию окон Windows
Министерство образования РФ
ИНСТИТУТ ПЕРЕПОДГОТОВКИ КАДРОВ
Уральского государственного технического университета
Кафедра микропроцессорной техники
Курсовая работа
Программа демонстрирующая иерархию окон Windows
руководитель: Кулюкин В.П.
слушатель гр.СП-923:
2001г.
Содержание
Введение
1. Оконные приложения Windows.
2. Каркасное Windows-приложение на ассемблере
3. Иерархия окон
4. «Программа демонстрирующая иерархию окон Windows»
5.Библиографический список
Введение
В подавляющем большинстве книг о программировании для Windows изложение, как правило, ведется на базе языка C/C++, реже — на базе Pascal. А что же ассемблер — в стороне? Конечно, нет! Мы не раз обращали ваше внимание на правильное понимание места ассемблера в архитектуре компьютера. Любая программа на языке самого высокого уровня в своем внутреннем виде представляет собой последовательность машинных кодов. А раз так, то всегда остается теоретическая возможность написать ту же программу, но уже на языке ассемблера: Непонимание или недооценка такой возможности приводит к тому, что достаточно часто приходится слышать фразу, подобную следующей: «Ах, опять этот ассемблер, но ведь это что-то несерьезное!» Также трудно согласиться с тезисом, который чаще всего следует вслед за этой фразой. Суть его сводится к утверждению того, что мощность современных компьютеров позволяет не рассматривать проблему эффективности функционирования программы в качестве первоочередной. Гораздо легче решить ее за счет увеличения объема памяти, быстродействия центрального процессора и качества компьютерной периферии. Чем обосновать необходимость разработки Windows-приложений на языке ассемблера? Приведем следующие аргументы:
языке ассемблера позволяет программисту полностью контролировать создаваемый им программный код и оптимизировать его по своему усмотрению;
компиляторы языков высокого уровня помещают в загрузочный модуль программы избыточную информацию. Эквивалентные исполняемые модули, исходный текст которых написан на языке ассемблера, имеют в несколько раз меньший размер;
при программировании на ассемблере сохраняется полный доступ к аппаратным ресурсам компьютера;
приложение, написанное на языке ассемблера, как правило, быстрее загружается в оперативную память компьютера;
приложение, написанное на языке ассемблера, обладает, как правило, более высокой скоростью работы и реактивностью ответа на действия пользователя. Разумеется, эти аргументы не следует воспринимать, как некоторую рекламную кампанию в поддержку языка ассемблера. Но нельзя забывать и о том, что существует бесконечное множество прикладных задач, ждущих своей очереди на компьютерную реализацию. Далеко не все из этих задач требуют применения тяжеловесных средств разработки, результатом работы которых являются столь же тяжеловесные исполняемые файлы. Многие прикладные задачи могут быть изящно исполнены на языке ассемблера, не теряя привлекательности.
1. Оконные приложения Windows.
Windows поддерживает два типа приложений:
оконное приложение — строится на базе специального набора функций (API), составляющих графический интерфейс пользователя (GUI, Graphic User Interface). Оконное приложение представляет собой программу, которая весь вывод на экран производит в графическом виде. Первым результатом работы оконного приложения является отображение на экране специального объекта — окна. После того как окно отображено на экране, вся работа приложения направлена на то, чтобы поддерживать его в актуальном состоянии;
Основной тип приложений в Windows — оконные, поэтому с них мы и начнем знакомство с процессом разработки программ для этой операционной системы.
Любое оконное Windows-приложение имеет типовую структуру, основу которой составляет так называемое каркасное приложение. Это приложение содержит минимально необходимый программный код для обеспечения функционирования полноценного Windows-приложения. Не случайно во всех источниках в качестве первого Windows-приложения рекомендуется изучать и исследовать работу некоторого каркасного приложения, так как именно оно отражает основные особенности взаимодействия программы с операционной системой Windows. Более того, написав и отладив один раз каркасное приложение, вы будете использовать его в необходимую терминологию и сможем больше внимания уделить логике работы Windows-приложения, а не деталям его реализации.
Минимальное приложение Windows состоит из трех частей:
главной функции;
цикла обработки сообщений;
оконной функции.
Выполнение любого оконного Windows-приложения начинается с главной функции. Она содержит код, осуществляющий настройку (инициализацию) приложения в среде операционной системы Windows. Видимым для пользователя результатом работы главной функции является появление на экране графического объекта в виде окна. Последним действием кода главной функции является создание цикла обработки сообщений. После его создания приложение становится пассивным и начинает взаимодействовать с внешним миром посредством специальным образом оформленных данных — сообщений. Обработка поступающих приложению сообщений осуществляется специальной функцией, называемой оконной. Оконная функция уникальна тем, что может быть вызвана только из операционной системы, а не из приложения, которое ее содержит. Таким образом, Windows-приложение, как минимум, должно состоять из трех перечисленных элементов.
Каркасное Windows-приложение на ассемблере содержит один сегмент данных .data и один сегмент кода . code. Сегмент стека в исходных текстах Windows-приложений непосредственно описывать не нужно. Windows выделяет для стега объем памяти, размер которого задан программистом в файле с расширением . def. Текст листинга 2 достаточно большой. Поэтому для обсуждения разобьем erо комментариями на характерные фрагменты, каждый из которых затем поясним необходимой степенью детализации.
2. Каркасное Windows-приложение на ассемблере
<1> ;Пример каркасного приложения для Win32
<2> .386
<3> locals ;разрешает применение локальных меток в программе
<4> .model flat, STDCALL ;модель памяти flat Я
<5> ;STDCALL - передача параметров в стиле С (справа налево),
<6> ; вызываемая процедура чистит за собой стек Ш
<7> include windowA.inc ;включаемый файл с описаниями базовых структур
;и констант Win32 т
<8> ;Объявление внешними используемых в данной программе функций Win32 (ASCII):
<9> extrn GetModuleHandleA:PROC
<10> extrn GetVersionExA:PROC В
<11> extrn GetCommandLineA:PROC
<12> extrn GetEnvironmentStringsA:PROC
<13> extrn GetEnvironmentStringsA:PROC
<14> extrn GetStartupInfoA:PROC
<15> extrn LoadIconA:PROC
<16> extrn LoadCursorA:PROC
<17> extrn GetStockObject:PROC
<18> extrn RegisterClassExA:PROC
<19> extrn CreateWindowExA:PROC
<20> extrn ShowWindow:PROC
<21> extrn UpdateWindow:PROC
<22> extrn GetMessageA:PROC
<23> extrn TranslateMessage:PROC
<24> extrn DispatchMessageA:PROC
<25> extrn ExitProcess:PROC
<26> extrn PostQuitMessage:PROC
<27> extrn DefWindowProcA:PROC
<28> extrn PlaySoundA:PROC
<29> extrn ReleaseDC:PROC
<30> extrn TextOutA:PROC
<31> extrn GetDC:PROC
<32> extrn BeginPaint:PROC
<33> extrn EndPaint:PROC
<34> ;объявление оконной функции объектом, видимым за пределами данного кода
<35> public WindowProc
<36> .data
<37> hwnd dd 0
<38> hInst dd 0
<39> hdc dd 0
<40> ;lpVersionInformation OSVERSIONINFO <?>
<41> wcl WNDCLASSEX <?>
<42> message MSG <?>
<43> ps PAINTSTRUCT <?>
<44> szClassName db 'Приложение Win32 ',0
<45> szTitleName db 'Каркасное приложение Win32 на ассемблере'.0
<46> MesWindow db 'Это процесс разработки приложения
на ассемблере?'
<47> MesWindowLen= $-MesWindow
<48> playFileCreate db 'create.wav',0
<49> playFilePaint db 'paint.wav',0
<50> playFileDestroy db 'destroy.wav',0
<51> . code
<52> start proc near
<53> ;точка входа в программу:
<54> ;начало стартового кода
<55> ;вызовы расположенных ниже функций можно при необходимости раскомментировать,
<56> :но они не являются обязательными в данной программе
<57> ;вызов BOOL GetVersionEx(LPOSVERSIONINFO lpVersionInformation)
<58> ; push offset lpVersionInformation
<59> ; call GetVersionExA
<60> ;далее можно вставить код для анализа информации о версии Windows
<61> ;вызов LPTSTR GetCommandLine(VOID) - получить указатель на командную строку
<62> ; call GetCommandLineA :врегистре еах адрес
<63> ;вызов LPVOID GetEnvironmentStrings (VOID) - получить указатель
;на блок с переменными окружения
<64> ; call GetEnvironmentStringsA ;врегистре еах адрес
<65> ;вызов VOIDGetStartupInfo(LPSTARTUPINFO lpStartupInfo) ;указатель
;на структуру STARTUPINFO
<66> ; push offset lpStartupInfo
<67> ; call GetStartupInfoA
<68> ;вызов HMODULE GetModuleHandleA (LPCTSTR lpModuleName)
<69> push NULL ;0->GetModuleHandle
<70> call GetModuleHandleA ;получить значение базового адреса,
<71> mov hInst, eax ;no которому загружен модуль.
<72> ;далее hInst будет использоваться в качестве дескриптора данного приложения
<73> ;конец стартового кода
<74> WinMain:
<75>;определить класс окна ATOM RegisterClassEx(CONST WNDCLASSEX *lpWndClassEx),
<76> ; где *lpWndClassEx - адрес структуры WndClassEx
<77> ;для начала инициализируем поля структуры WndClassEx
<78> mov wcl.cbSize,typeWNDCLASSEX -.размер структуры
:в wcl.cbCIZE
<79> mov wcl.style,CS_HREDRAW+CS_VREDRAW
<80> mov wcl.pfnWndProg,offsetWindowProg ;адрес оконной процедуры
<81> mov wcl.cbCisExtra,0
<82> mov wcl.cbWndExtra,0
<83> mov eax,hInst
<84> mov ;дискриптор приложения в поле hInstance структуры wcl
<85> mov wcl.hInstance, eax
<86> ;готовим вызов HICON LoadIcon (HINSTANCE hInstance, LPCTSTR lpIconName)
<87> push IDI_APPLICATION ,-стандартный значок
<88> push 0 ;NULL
<89> саП LoadIconA
<90> mov wcl.hIcon, eax ,-дескриптор значка в поле hIcon I
;структуры wcl
<91> ;готовим вызов HCURSOR LoadCursorA (HINSTANCE hInstance, LPCTSTR M ;lpCursorName)
<92> push IDC_ARROW ,-стандартный курсор - стрелка
<93> push 0
<94> саll LoadCursorA
<95> mov wcl.hCursor,eax ;дескриптор курсора в поле hCursor
;структуры wc1
<96> ;определим цвет фона окна - белый
<97> ;готовим вызов HGDIOBJ GetStockObject(int fnObject)
<98> push WHITE_BRUSH
<99> саП GetStockObject
<100> mov wcl.hbrBackground, eax
<101> mov dword ptrwcl.lpszMenuName, 0 ;без главного меню
<102> mov dwordptrwcl.lpszClassName,offsetszC1assName; имя
;класса окна
<103> mov wcl.hIconSm, 0
<104> ;регистрируем класс окна - готовим вызов RegisterClassExA (&wndclass)
<105> push offset wcl
<106> саП RegisterClassExA
<107> test ax, ах;проверить на успех регистрации класса окна
<108> jz end_cyc1_msg ;неудача
<109> ;создаем окно:
<110> ;готовим вызовHWND CreateWindowExA(DWORDdwExStyle,
LPCTSTR1pClassName,
<111> ; LPCTSTR 1pW1ndowName, DWORD dwStyle, int x, int у, int nWidth,
|;int nHeight,
<112> ; HWND hWndParent, HMENU hMenu, HANDLE hInstance, LPVOID
;lpParam)
<113> push 0 ;lpParam
<114> push hInst ;hInstance
<115> push NULL ;menu
<116> push NULL ;parent hwnd
<117> push CW_USEDEFAULT ;высота окна
<118> push CW_USEDEFAULT ;ширина окна
<119> push CW_USEDEFAULT ;координата у левого верхнего угла
;окна
<120> push CW_USEDEFAULT ;координата х левого верхнего угла
<121> push WS_OVERLAPPEDWINDOW ;стиль окна
<122> push offset szTitleName ;строка заголовка окна
<123> push offset szClassName ;имя класса окна
<124> push NULL
<125> саll CreateWindowExA
<126> mov hwnd,eax ;-дескриптор окна
<127> ;показать окно:
<128> ;готовим вызов BOOL ShowWindow( HWND hWnd, int nCmdShow )
<129> push SW_SHOWNORMAL
<130> push hwnd
<131> call ShowWindow
<132> ;перерисовываем содержимое окна
<133> ;готовим вызов BOOL UpdateWindow( HWND hWnd )
<134> push hwnd
<135> call UpdateWindow
<136> ;запускаем цикл сообщений:
<137> ;готовим вызов BOOL GetMessageA( LPMSG lpMsg, HWND hWnd,
<138> ; UINTwMsgFilterMin,UINTwMsgFilterMax)
<139> cycl_msg:
<140> push 0
<141> push 0
<142> push NULL
<143> push offset message
<144> cal 1 GetMessageA
<145> cmp ах, 0
<146> je end_cycl_msg
<147> ;трансляция ввода с клавиатуры
<148> ;готовим вызов BOOL Trans1ateMessage( CONST MSG *lpMsg )
<149> push offset message
<150> call TranslateMessage
<151> ;отправим сообщение оконной процедуре
<152> ;готовим вызов LONG D1spatchMessage( CONST MSG *lpmsg )
<153> push offset message
<154> call DispatchMessageA
<155> jmp cycl_msg
<156> end_cycl_msg:
<157>
<158> ;выход из приложения
<159> ;готовим вызов VOID ExitProcess( UINT uExitCode )
<160> push NULL
<161> call ExitProcess
<162> start endp
<163> ; - - - - - - - - - - - - --WindowProc-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
<164> WindowProc proc
<165> argP0nwnd:DWORD, PPmes:DWORD, @@wparam:DWORD, @@lparam:DWORD
<166> uses ebx, edi, es1 ;эти регистры обязательно должны сохраняться
<167> local @@hdc:DWORD
<168> cmp @@mes, WM_DESTROY
<169> je wmdestroy
<170> cmp @@mes, WM_CREATE
<171> je wmcreate
<172> cmp @@mes, WM_PAINT
<173> je wmpaint
<174> jmp default
<175> wmcreate:
<176> ;обозначим создание окна звуковым эффектом
<177> ;готовим вызов функции BOOL PlaySound(LPCSTR pszSound, HMODULE hmod, DWORD
;fdwSound )
<178> push SND_SYNC+SND_FILENAME
<179> push NULL
<180> push offset playFileCreate
<181> call PlaySoundA
<182> mov eax, О;возвращаемое значение - 0
<183> jmp exit_wndproc
<184> wmpaint:
<185> push SND_SYNC+SND_FILENAME
<186> push NULL
<187> push offset playFIilePaint
<188> call P1aySoundA
<189>;получим контекст устройства HDC BeginPaint(HWND nwnd,LPPAINTSTRUCT;LPpAINT)
<190> push offset ps
<191> push @@hwnd
<192> call BeginPaint
<193> mov @@hdc,eax
<194> ;выведем строку текста в окно BOOL TextOut( HDC hdc. int nXStart, int
:nYStart.
<195> ; LPCTSTR lpString, int cbString )
<196> push MesWindowLen
<197> push offset MesWindow
<198> push 100
<199> push 10
<200> push @@hdc
<201> call TextOutA
<202> :ocвoбoдитькoнтeкcтBOOLEndPaint( HWNDhWnd, CONSTPAINTSTRUCT*lpPai <203> push offset ps
<204> push @@hdc
<205> call EndPaint
<206> mov еах,0;возвращаемое значение-0
<207> jmp exit_wndproc
<208> wmdestroy:
<209> push SND_SYNC+SND_FILENAME
<210> push NULL
<211> push offset playFileDestroy
<212> call PlaySoundA
<213> ;послать сообщение WМ_QUIТ
<214> ;готовим вызов VOID PostQuitMessage( int nExitCode )
<215> push 0
<216> call PostQuitMessage
<217> mov eax, О;возвращаемое значение - 0
<218> jmp exit_wndproc
<219> default:
<220> ; обработка по умолчанию
<221>;готовим вызов LRESULTDefWindowProc( HWND hWnd, UINTMsg,
<222> ; WPARAMwParam,LPARAMlParam)
<223> push @@lparam
<224> push @@wparam
<225> push @@mes
<226> push @@nwnd
<227> call DefWindowProcA
<228> jmp exit_wndproc
<229> ;... ... ...
<230> exit_wndproc:
<231> ret
<232> WindowProc endp
<233> end start
3.Иерархия окон
Изучив по дисциплине «Системное программное обеспечение» написание окон Windows на языке Assembler и рассматривая графическую оконную систему нельзя обойтись без подробного рассмотрения того, какие окна можно отображать на экране.
Тип окна задается 32-битовым без знаковым целым числом, которое указывается третьим параметром вызова функции Create Window.
Существует всего лишь три основных типа окон Window.
1 тип. Перекрывающиеся окна. Флаг WS_OVERLAPPED.
2 тип. Вспомогательные окна. Флаг WS_POPUP.
3 тип. Дочерние окна. . Флаг WS_CHILD.
Для написания курсового проекта, который имеет тему «Программа демонстрирующая иерархию окон Windows» были использованы именно эти типы окон.
Нужно о них помнить следующее что:
Перекрывающееся окно никогда не имеет родителя
Дочернее окно всегда имеет родителя.
Вспомогательное окно может иметь и не иметь родителя; если оно имеет родителя, то все равно это не дочернее, а вспомогательное окно.
Из всех концепций системы управления окнами наиболее фундаментальной является отношение предок/ потомок/ сосед. Как мы видели при описании структуры данных WND, каждое окно содержит логический номер окна своего предка, логический номер своего первого дочернего окна и логический номер следующего соседнего окна. Соседними являются окна, имеющие одинаковое родительское окно. В действительности значения HWND являются просто ближними указателями в локальной "куче" модуля USER, поэтому вы можете рассматривать их как указатели связного списка, которые позволяют обходить пути в иерархии окон. Иерархия окон, создаваемая модулем USER, показана на рис.1.
Иерархия окон обходится во всех трех направлениях - от предка к потомку, от потомка к предку и от соседа к соседу. Примеры обхода иерархии включают следующее:
• При уничтожении окна модуль USER должен уничтожить всех его потомков, а также их потомков. USER обходит всю иерархию, используя поля hWndChild и hWndNext- Напомним, логические номера окон являются просто ближними указателями в локальной "куче" модуля USER.
• Когда происходит передача фокуса ввода при нажатии клавиши Tab между элементами управления в окне диалога (которые являются потомками окна диалога), указатели на соседнее окна (или поле hWndNext) соединяют друг с другом элементы управления. Кроме того, упорядочение окон в списке hWndChild и hWndNext отражает Z-порядок окон на экране. Z-порядок представляет собой относительную позицию окон в третьем измерении (в направлении от экрана к вам). Если вы щелчком кнопки мыши выбираете различные основные окна;
чтобы поместить их в вершину Z-порядка, их относительные позиции в списке hWndNext сдвигаются.