1. Если вы только начинаете программировать на ассемблере и не знаете с чего начать, тогда попробуйте среду разработки ASM Visual IDE
    (c) на правах рекламы
    Скрыть объявление

Сказки дядюшки Римуса

Тема в разделе "WASM.ARTICLES", создана пользователем Mikl___, 19 дек 2016.

Метки:
  1. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.993
    Скачайте пример здесь.
    Код (ASM):
    1. ; GUI #
    2. include win64a.inc
    3. .code
    4. WinMain proc
    5. local msg:MSG
    6. LEFT equ 0
    7. TOP equ 0
    8. RIGHT equ 780
    9. BOTTOM equ 800
    10. invoke InitCommonControls
    11. ;Создание родительского окна
    12. jns @f
    13. xor ebx,ebx
    14. @@: mov esi,IMAGE_BASE
    15. mov ecx,offset FileName
    16. invoke LoadCursorFromFile
    17. mov edi,offset ClassName
    18. push rax ;hIconSm
    19. push rdi ;lpszClassName
    20. push rbx ;lpszMenuName
    21. push COLOR_WINDOW+1;hbrBackground
    22. push rax ;hCursor
    23. push rax        ;hIcon
    24. push rsi ;hInstance
    25. push rbx        ;cbClsExtra & cbWndExtra
    26. pushaddr WndProc;lpfnWndProc
    27.         mov rax,((CS_HREDRAW or CS_VREDRAW)shl 32)+sizeof WNDCLASSEX
    28. push rax       ;cbSize & style
    29.     invoke RegisterClassEx,esp ;addr WNDCLASSEX
    30. push rbx
    31. push rsi ;rsi = 400000h
    32. shl esi,9 ;rsi = CW_USEDEFAULT
    33. push rbx
    34. push rbx
    35. push RIGHT
    36. push BOTTOM
    37. push rsi
    38. push rsi
    39. sub esp,20h
    40.     invoke CreateWindowEx,0,edi,edi,WS_OVERLAPPED or WS_VISIBLE or \
    41.         WS_CAPTION or WS_SYSMENU or WS_MINIMIZEBOX
    42. ;цикл сообщений
    43.     lea edi,msg
    44. @@: invoke GetMessage,edi,0,0,0
    45. invoke DispatchMessage,edi
    46. jmp @b
    47. WinMain endp
    48. ;Оконная процедура
    49. WndProc proc hWnd:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD
    50. local tci:TCITEMA
    51. local ps:PAINTSTRUCT
    52. local y:DWORD
    53. local hdc:QWORD
    54. local tm:TEXTMETRICA
    55.       mov hWnd,rcx
    56. cmp edx,WM_DESTROY
    57. je wmDESTROY
    58. cmp edx,WM_CREATE
    59. je wmCREATE
    60. cmp edx,WM_NOTIFY
    61. je wmNOTIFY
    62.       cmp edx,WM_PAINT
    63.       je wmPAINT
    64. wmDEFAULT:leave
    65.       jmp NtdllDefWindowProc_
    66. wmDESTROY:invoke RtlExitUserProcess,NULL
    67. wmCREATE:invoke GetClientRect,,&expRect
    68. ;создать закладку
    69. push rbx
    70. push IMAGE_BASE
    71. push rbx
    72. push hWnd
    73. mov eax,expRect.bottom
    74. sub eax,720
    75. push rax
    76. mov eax,expRect.right
    77. push rax
    78. push TOP
    79. push rbx
    80. sub esp,20h
    81. invoke CreateWindowEx,WS_EX_RIGHTSCROLLBAR,&aSysTabControl32,&NullString,WS_VISIBLE or \
    82. WS_TABSTOP or WS_CHILD
    83. mov hTabWnd,rax
    84. ;создания элемента STATIC
    85.         push rbx
    86. push IMAGE_BASE
    87. push rbx
    88. push hWnd
    89. push BOTTOM+100
    90. push RIGHT
    91. push TOP+25
    92. push LEFT
    93. sub esp,20h
    94. invoke CreateWindowEx,0,&aStatic,&expTxt0,SS_LEFT or WS_CHILD or WS_VISIBLE
    95. mov hStaticText1,rax
    96. ;создания элемента STATIC для вывода текста функцией SendMessage
    97.       push rbx
    98. push IMAGE_BASE
    99. push rbx
    100. push hWnd
    101. push BOTTOM
    102. push RIGHT;640
    103. push TOP+25
    104. push LEFT
    105. sub esp,20h
    106. invoke CreateWindowEx,0,&aStatic,0,SS_LEFT or WS_CHILD; or WS_VISIBLE
    107. mov hStaticText2,rax
    108. ;Заполняем структуру TCITEMA
    109. mov tci.imask,TCIF_TEXT
    110. or tci.iImage,-1
    111. @@:;создаем 10 закладок
    112. mov rax,handle1[rbx*8]
    113. mov tci.pszText,rax;название закладки
    114. mov tci.lParam,rbx;номер закладки
    115. neg rax
    116. add rax,handle1[rbx*8+8]
    117. mov tci.cchTextMax,eax
    118. invoke SendMessage,hTabWnd,TCM_INSERTITEMA,ebx,&tci
    119. inc ebx
    120. cmp ebx,10
    121. jb @b
    122. xor ebx,ebx
    123. ;---------------------------------------------------------------
    124. invoke GetDC,hWnd
    125. mov hdc,rax
    126.         invoke GetTextMetrics,eax,&tm
    127.         mov eax,tm.tmHeight
    128.         add eax,tm.tmExternalLeading
    129. mov font_height,eax
    130. ;строим растр, совместимый с окном
    131. invoke CreateCompatibleDC,hdc
    132. mov MemDC,rax
    133.         invoke CreateCompatibleBitmap,hdc,RIGHT,BOTTOM
    134. mov hbit,rax
    135. invoke SelectObject,MemDC,eax
    136.         invoke GetStockObject,WHITE_BRUSH
    137. invoke SelectObject,MemDC,eax
    138. invoke SetBkMode,MemDC,TRANSPARENT
    139. invoke PatBlt,MemDC,0,0,RIGHT,BOTTOM,PATCOPY
    140.         invoke ReleaseDC,hWnd,hdc
    141. jmp wmBYE
    142. wmNOTIFY:;изменение состояния закладки
    143. cmp [r9+NMHDR._code],TCN_SELCHANGE
    144. jne wmBYE;DEFAULT
    145. invoke SendMessage,hWnd,WM_SETTEXT,0,&ClassName
    146.         invoke ShowWindow,hStaticText2,SW_HIDE
    147. invoke ShowWindow,hStaticText1,SW_HIDE;спрятать "статический" текст
    148. invoke PatBlt,MemDC,0,0,RIGHT,BOTTOM,PATCOPY
    149.         xor ebx,ebx
    150. mov edi,font_height
    151.         mov y,ebx
    152.         invoke SendMessage,hTabWnd,TCM_GETCURSEL,0,0
    153. jmp [handle+rax*8];переходим на выбранную закладку
    154. DrawTextEx1::;вывод текста при помощи функции DrawTextEx
    155. invoke DrawTextEx,MemDC,&expTxt5,-1,&expRect,DT_LEFT or DT_WORDBREAK or DT_EXPANDTABS or \
    156. DT_END_ELLIPSIS or DT_MODIFYSTRING or DT_WORD_ELLIPSIS,0
    157.         jmp a1
    158. wmPAINT:invoke BeginPaint,,&ps
    159. invoke BitBlt,eax,0,0,RIGHT,BOTTOM,MemDC,0,-28,SRCCOPY
    160. invoke EndPaint,hWnd,&ps
    161.         jmp wmBYE
    162. ExtTextOut1::;вывод текста при помощи функции ExtTextOut
    163. @@: mov r10d,stringtable2[rbx]
    164. mov eax,stringtable2[rbx+4]
    165. or eax,eax
    166. jz a1
    167. sub eax,r10d
    168.         invoke ExtTextOut,MemDC,LEFT,y,0,&expRect,r10,rax,0
    169. add y,edi
    170. add ebx,4
    171. jmp @b
    172. STATICText::;вывод стического текста
    173. invoke ShowWindow,hStaticText1,SW_SHOW
    174. jmp wmBYE
    175. PolyTextOut1::;вывод текста при помощи функции PolyTextOut
    176. invoke PolyTextOut,MemDC,&pptxt,19
    177. jmp a1
    178. TextOut1::;вывод текста при помощи функции TextOut
    179. @@: mov r9d,stringtable3[rbx]
    180. mov eax,stringtable3[rbx+4]
    181. or eax,eax
    182. jz a1
    183. sub eax,r9d
    184. mov [rsp+20h],rax
    185. invoke TextOut,MemDC,LEFT,y
    186. add y,edi
    187. add ebx,4
    188. jmp @b
    189. DrawText1::;вывод текста при помощи функции DrawText
    190. invoke DrawText,MemDC,&expTxt1,-1,&expRect,DT_WORDBREAK
    191. jmp a1
    192. Title1::invoke SetWindowText,hWnd,&expTxt8
    193. jmp a1
    194. Title2::invoke SendMessage,hWnd,WM_SETTEXT,0,&expTxt9
    195.         jmp a1
    196. TabbedTextOut1::;вывод текста при помощи функции TabbedTextOut
    197. @@:     mov r9d,stringtable4[rbx]
    198.         or r9,r9
    199. jz a1
    200. invoke TabbedTextOut,MemDC,LEFT,y,,-1,0,0,0
    201. add y,edi
    202.         add ebx,4
    203.         jmp @b
    204. a1: xor ebx,ebx
    205. invoke InvalidateRect,hWnd,0,TRUE
    206. jmp wmBYE
    207. SendMessage1::invoke SendMessage,hStaticText2,WM_SETTEXT,0,&expTxt7
    208. invoke ShowWindow,hStaticText2,SW_SHOW
    209. wmBYE: leave    
    210. xor eax,eax
    211. ret
    212. WndProc endp
    213. ;---------------------------------------
    214. ClassName db 'Uncle Remus tales:#5a Вывод текста всеми способами'
    215. NullString db 0
    216. FileName db "br_Rabbit3.cur",0
    217. hTabWnd dq ?
    218. aSysTabControl32 db "SysTabControl32",0
    219. tab0 db "Static",0
    220. tab1 db "DrawTextEx",0
    221. tab2    db "TextOut",0
    222. tab3 db "TabbedTextOut",0
    223. tab4 db "DrawText",0
    224. tab5    db "PolyTextOut",0
    225. tab6 db "ExtTextOut",0
    226. tab7 db "SendMessage",0
    227. tab8 db "Title1",0
    228. tab9 db "Title2",0
    229. handle1 dq tab0,tab1,tab2,tab3,tab4,tab5,tab6,tab7,tab8,tab9,handle1
    230. handle  dq STATICText,DrawTextEx1,TextOut1,TabbedTextOut1,DrawText1
    231. dq PolyTextOut1,ExtTextOut1,SendMessage1,Title1,Title2
    232. ;---------------------------------------------------------------------------------------------
    233. expTxt0 db 'Было еще не так поздно, а госпожа Салли, мама семилетнего Джоэля, уже начала волноваться: "Где же он до '
    234. db 'сих пор носится, этот сорванец?" Она обыскала весь дом, обыскала весь двор, но мальчика нигде не было. '
    235. db 'Вдруг госпожа Салли услышала голоса в хижине старого негра Римуса. Она заглянула в окно и увидела, что Джоэль '
    236. db 'сидит у дядюшки Римуса на коленях и, прислонив голову к плечу старика, внимательно '
    237. db 'смотрит в его доброе морщинистое лицо. И госпожа Салли поняла, что негр рассказывает '
    238. db 'ее сыну одну из тех чудесных историй, которые он рассказывал и ей, когда она была крохотной '
    239. db 'девочкой. Госпожа Салли улыбнулась и задумчиво побрела к своему дому.',10
    240. db 'Но мы останемся и вместе с Джоулем послушаем дядюшку Римуса. Вот что он рассказал в '
    241. db 'этот вечер: -- С незапамятных пор, мальчик, Братец Лис гонялся за Братцем Кроликом. И чего '
    242. db 'только он ни придумывал, чтобы поймать его, а Братец Кролик чего только не придумывал, '
    243. db 'чтобы не угодить в лапы Братцу Лису.',10
    244. db 'Вот однажды и сказал сам себе Братец Лис: -- "Хватит, пора покончить с Братцем Кроликом раз'
    245. db 'и навсегда!" И едва он произнес эти слова, Братец Кролик тут как тут. Бежит по лужайке, взбрыкивает '
    246. db 'задом, прядет ушами, резвый, веселый, словно жеребчик, вырвавшийся на волю. Да еще и песенку напевает:',10
    247. db ' Дидель-дум-дай, дидель-дум-дай,',10
    248. db ' Я выбежал на луг.',10
    249. db ' Дидель-дум-дай, дидель-дум-дай,',10
    250. db ' Как хорошо вокруг!',10
    251. db ' Хочу -- туда, хочу -- сюда',10
    252. db ' Скачу средь бела дня',10
    253. db ' И Братцу Лису никогда',10
    254. db ' Здесь не найти меня',10
    255. db 'Тут он увидел Братца Лиса и остановился, как вкопанный.',10
    256. db '"Ну, что же ты, Братец Кролик? Иди сюда" -- сказал Братец Лис',10
    257. db '"Не могу, Братец Лис, ноги в траве запутались" -- ответил Братец Кролик.',10
    258. db '"Тогда я сам подойду к тебе. Нам надо поговорить об одном важном деле."',10
    259. db '"Не советую рисковать, Братец Лис. Приближаться ко мне опасно."',10
    260. db '"Почему. Братец Кролик?"',10
    261. db '"День для меня сегодня плох -- я нахватался где-то блох. Говори оттуда, только погромче"',10
    262. db 'Братец Лис так бы и бросился на Братца Кролика, да побоялся заразиться блохами.',10
    263. db '"Ну, хорошо, Братец Кролик, я не буду приближаться к тебе", -- говорит Братец Лис, а сам думает -- "О каком бы важном деле поговорить с братцем Кроликом, чтобы обмануть его?" '
    264. db 'И послушай, что придумал Братец Лис: "Вчера я встретил Братца Медведя, он пристыдил меня и сказал, что раз мы с тобой соседи, то, как и подобает соседям, должны жить в дружбе и согласии. Я обещал Братцу медведю потолковать с тобой об этом."',10
    265. db 'Братец Кролик почесал лапой за ухом, будто его действительно кусают блохи. Он не поверил ни одному слову, но вида не подал.',10
    266. db '"Я не против мира", -- сказал он. -- "А чтобы закрепить наши добрососедские отношения, приходи завтра к нам на обед. Мы хоть и небогаты, но, я думаю, моя жена сумеет приготовить что-нибудь, достойное такого высокого гостя, как ты".',10
    267. db '"Благодарю за приглашение, Братец Кролик. Я непременно приду", -- сказал Братец Лис, а про себя подумал -- "Это именно то, что мне и надо. Завтра же я полакомлюсь свежей крольчатиной"',10
    268. db '"Итак, мы договорились", -- Братец Кролик откланялся и поскакал прочь.',10
    269. db 'На следующий день, рано утром, пока маленькие крольчата еще нежились в своих кроватках, папа Кролик и мама Крольчиха пошли в огород, -- а это было единственное, что осторожная Крольчиха держала снаружи дома, -- нарвали там разного дурмана и '
    270. db 'конопли, вернувшись домой, приготовили такую отраву, что одной ложки было достаточно, чтобы отбросить все четыре лапы. Когда угощение было готово, Кролики сели за стол и стали ждать Братца Лиса. Ждут-пождут, а Братец Лис не появляется.',10
    271. db 'Тут один из маленьких крольчат, игравший на полу, подбежал к двери и посмотрел в дырочку от выпавшего сучка.',10
    272. db '"Папа, мама!" -- радостно закричал он -- "Там во дворе, совсем близко, лежит какая-то рыжая длинная штука. Может быть мы сбегаем и поглядим?"',10
    273. db 'Братец Кролик тоже припал к дырочке. И как ты думаешь, что он увидел? -- Из-за угла дома торчит лисий хвост. Братец Лис-то надеялся сцапать либо самого Братца Кролика, либо кого-нибудь из маленьких крольчат. '
    274. db 'Вот и затаился, а про свой длинный хвост забыл.',0
    275. expTxt1 db '-- Давным-давно это было, -- начал дядюшка Римус, надевая очки, чтобы вставить нить в иголку. У него',10
    276. db 'прохудился пиджак, и он хотел починить его. Но нить никак не попадала в игольное ушко',10
    277. db '-- Дядюшка Римус, давай я тебе помогу -- предолжил Джоэль',10
    278. db 'А ну-ка, мальчик -- старик протянул ему иголку и нитку',10
    279. db 'Джоэль мигом вставил нить, удивляясь, почему это не получилось у дядюшки Римуса.',10
    280. db '-- У тебя глаза молодые, зоркие, а мои даже с очками никуда не годятся -- Дядюшка Римус вздохнул и стал',10
    281. db 'продолжать рассказ. -- Да, очень и очень давно это случилось, когда еще не было на свете ни тебя, ни твоего отца,',10
    282. db 'ни твоей мамы, ни твоего дедушки, ни твоей бабушки.',10
    283. db '-- А ты был, дядюшка Римус?',10
    284. db '-- Нет, мальчик, и меня не было. Не было вообще никого из живущего теперь на земле человеческого рода. Вот',10
    285. db 'тогда и порешили все звери от мала до велика провести заседание.',10
    286. db '-- Какое заседание, дядюшка Римус?',10
    287. db '-- Обыкновенное, на котором обсуждают какие-нибудь выжные вопросы. В те времена, -- пояснил старик, заметив',10
    288. db 'на лице ребенка некоторое недоверие, -- у зверей разума было гораздо больше, чем теперь, во всяком случае,',10
    289. db 'не меньше, чем сейчас у людей. Как порешили, так и зделали. Прекратили все распри, уладили все дела и в',10
    290. db 'назначенный день собрались в назначенном месте. Был тут и Слон и Осел, Верблюд и Носорог и прочие звери,',10
    291. db 'вплоть до маленьких раков.',10
    292. db 'Император Лев, властелин зверей, поприветствовал своих подданых, сел на трон и заседание началось.',10
    293. db '-- Что же они обсуждали, дядюшка Римус? -- спросил Джоэль. Он хотя и был маленький, но, часто слышал',10
    294. db 'разговоры взрослых, неплохо разбирался в политических событиях.',10
    295. db '-- Я не помню, какие именно вопросы они обсуждали, но знаю точно, что речи там произносились длинные,',10
    296. db 'шума было много. Все лезли на трибуну, оттаптывали друг другу ноги. Крепкие словечки так и летали в воздухе.',10
    297. db 'Словом, это походило на предвыборный митинг в нашем штате, когда твой отец хотел стать губернатором, но у',10
    298. db 'него ничего не вышло. Заседание было в самом разгаре, но тут случилось непредвиденное: Слон протискиваясь',10
    299. db 'к трибуне, нечаянно наступил на Рака. Ну, ты, разумеется, знаешь: где ступит Слон, там трава не растет.',10
    300. db 'Раздался хруст, и когда Слон поднял ногу, бедного Рака больше не было видно, как будто его вообще не',10
    301. db 'существовало. Остальные раки пришли в негодование. Самый усатый из них закричал:',10
    302. db '"Господа раки! Прошу всех собраться у выхода!"',10
    303. db 'Раки сползлись все вместе и сочинили протест, состоящий из множества пунктов, один грозней другого. в конце',10
    304. db 'они написали:',10
    305. db '                                 Мы заявляем: если Слон',10
    306. db '                                    Не будет осужден.',10
    307. db '                                 А нанесенный нам урон',10
    308. db '                                    Не будет возмещен,',10
    309. db '                                То мы ряды свои сомкнем,',10
    310. db '                                   Шагнем вперед спиной.',10
    311. db '                                И, как один, навек уйдем',10
    312. db '                                  С поверхности земной',10
    313. db '-- Дядюшка Римус, а почему они написали: "шагнем вперед спиной"? -- спросил мальчик с недоумением.',10
    314. db '-- Мальчик, мальчик! -- старик сдвинул очки на лоб -- Разве ты никогда не видел, как ходят раки?',10
    315. db '-- Нет, дядюшка.',10
    316. db '-- Раки, мальчик, это такой народ, который всегда ходит задом наперед.',10
    317. db 'Пояснив, дядюшка Римус продолжил:',10
    318. db '-- С этим протестом раки попытались пролезть на трибуну вне очереди. Но, Боже мой, поднялся такой шум, что',10
    319. db 'никого не было слышно, особенно ящериц и черепах, которые и без того-то не разговаривали.',10
    320. db 'Император Лев, властелин зверей, пытался урезонить Носорога, который шумел больше всех, Гиена стала смеяться',10
    321. db 'в кулачки. Слон, неловко повернувшись, раздавил еще одного Рака и чуть было не наступил на Черепаху.',10
    322. db 'Раки вновь сползлись в одну кучу, сочинили новый протест, с еще большим количеством пунктов, и вторично',10
    323. db 'полезли к трибуне, требуя. чтобы им предоставили слово. Но с таким же успехом могла бы пищать мышь рядом',10
    324. db 'с грохочущим барабаном. Других зверей больше интересовало, как поставить и решить собственные вопросы. Бедные',10
    325. db 'раки не знали, как им быть. Они злились все сильнее, метались из стороны в сторону. Наконец, сговорившись с',10
    326. db 'ящерицами и черепахами, просверлили дыры в земле, заползли в них, и были таковы.',0
     

    Вложения:

    • 05.zip
      Размер файла:
      30,8 КБ
      Просмотров:
      195
    Последнее редактирование: 23 мар 2019
  2. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.993
    Код (ASM):
    1. expTxt2A db 'На другой день мальчик пришёл к дядюшке Римусу послушать, чем кончилась история с лошадью Братца'
    2. expTxt2B db 'Кролика. Но дядюшка Римус был не в духе.'
    3. expTxt2C db '-— Плохим мальчикам я не рассказываю никаких сказок, —- сказал он.'
    4. expTxt2D db '—- Но ведь я не плохой, дядюшка Римус!'
    5. expTxt2E db '—- А кто кур гонял сегодня утром? И кто стрелял из рогатки? И кто в обед науськал собаку на моего'
    6. expTxt2F db 'поросёнка? И ко мне на крышу кто бросал камни?'
    7. expTxt2G db '— Я не нарочно, дядюшка Римус, и я больше не буду. Пожалуйста, дядюшка Римус, а я коржиков тебе принесу.'
    8. expTxt2H db '— Коржики — они, конечно, лучше на вкус, чем на слух…'
    9. expTxt2I db 'Но, прежде чем старик кончил, Джоэль стрелой умчался прочь, а через минуту вернулся назад с полными '
    10. expTxt2J db 'карманами коржиков.'
    11. expTxt2K db '— Право, твоя мама подумает, что у крыс по соседству вот как животы раздуло! — усмехнулся дядюшка Римус.'
    12. expTxt2L db ' — Эти вот я сейчас съем, — продолжал он, раскладывая коржики на две одинаковые кучки, — а вот эти оставлю'
    13. expTxt2M db 'на воскресенье… Так до чего ж мы дошли? Я и забыл, что у нас делали Братец Лис и Братец Кролик.'
    14. expTxt2N db '— Кролик прискакал на Лисе верхом к Матушке Мидоус и привязал Лиса к коновязи.'
    15. expTxt2O db '— Ага! — сказал дядюшка Римус. — Так вот, привязал он свою лошадь к коновязи, а сам пошёл в дом, закурил'
    16. expTxt2P db 'сигару. Они болтали с Матушкой Мидоус и с девочками и пели, и девочки играли на пианино. Потом Братцу'
    17. expTxt2Q db 'Кролику пришло время уходить.'
    18. expTxt2R db 'Попрощался он и пошёл к коновязи такой важной походкой, вроде как барин. Сел на Лиса и поехал прочь.'
    19. expTxt2S db 'Старый Лис ничего не сказал. Он только стиснул зубы и поскакал вперёд. Но Братец Кролик знал, что Лис'
    20. expTxt2T db 'так и кипит от злости. Ох и струсил же он!'
    21. expTxt2U db 'А Лис бежал, бежал, пока не выбрался на лужайку, подальше от дома Матушки Мидоус. Тут он как с цепи'
    22. expTxt2V db 'сорвался. Уж он бесился: и фыркал, и бранился, и визжал, и прыгал, и кружился… '
    23. expTxt2W db 'Так и этак старался сбросить Братца Кролика со спины. Но Кролик держался крепко. Выгнет спину Лис, а'
    24. expTxt2X db 'Кролик его шпорами. Старый Лис и вверх и вбок, щёлк да щёлк зубами — чуть свой собственный хвост не отгрыз.'
    25. expTxt2Y db 'Потом вдруг на землю — и ну кататься. Тут Кролик и вылетел из седла. Но, прежде чем Лис вскочил на ноги,'
    26. expTxt2Z db 'Кролик в кусты — и наутёк. А Лис за ним, да так шибко — еле-еле успел Кролик нырнуть в дупло.'
    27. expTxt2a db 'Дыра была маленькая, Лису никак не пролезть. Вот лёг он, отдышался, стал думать, как быть теперь с Кроликом.'
    28. expTxt2b db 'А пока так лежал Старый Лис, пролетал мимо Братец Сарыч.'
    29. expTxt2c db 'Увидал, что Лис лежит, как дохлый, — дай, думает, закушу дохлятинкой. Сел на ветку, похлопал крыльями.'
    30. expTxt2d db 'Наклонил голову набок и говорит, будто сам себе:'
    31. expTxt2e db '— Помер Братец Лис. А мне как жалко!'
    32. expTxt2f db '— Нет, я жив, — говорит Лис. — Я загнал сюда Братца Кролика. Уж на этот раз он не уйдёт, хоть до Нового'
    33. expTxt2g db 'года буду ждать тут.'
    34. expTxt2h db 'Потолковали они ещё. Сарыч согласился постеречь Кролика, пока Братец Лис сбегает за топором. Лис убежал,'
    35. expTxt2i db 'а Сарыч стал, стоит у дупла. Вот, как стало тихо, Кролик подошёл поближе к дыре и кричит:'
    36. expTxt2j db '— Братец Лис! А Братец Лис!'
    37. expTxt2k db 'Но Лис был уже далеко, и никто не ответил. Тогда Кролик закричал:'
    38. expTxt2l db '— Ах, ты не хочешь отвечать, Братец Лис? И не надо! Всё равно я знаю, что ты тут стоишь. А мне и дела нет.'
    39. expTxt2m db 'Я просто хотел сказать тебе: вот если б тут был Братец Сарыч!'
    40. expTxt2n db 'Тогда Сарыч ответил лисьим голосом:'
    41. expTxt2o db '— А зачем тебе нужен Братец Сарыч?'
    42. expTxt2p db '— Да так, просто тут серая белка в дупле, а жирная, — сколько живу, такой не видал. Был бы тут Братец Сарыч,'
    43. expTxt2q db 'уж он бы полакомился Белочкой.'
    44. expTxt2r db 'Сарыч опять лисьим голосом:'
    45. expTxt2s db '— А как бы поймал её Братец Сарыч?'
    46. expTxt2t db '— А тут, на другой стороне дерева, маленькая дырочка, — говорит Кролик. — Был бы тут Братец Сарыч, стал бы'
    47. expTxt2u db 'он возле той дырочки, а я бы выгнал оттуда белку.'
    48. expTxt2v db '— Ну гони, гони, — сказал Сарыч, — а я постараюсь, чтоб она не ушла от Братца Сарыча.'
    49. expTxt2w db 'Тогда Кролик поднял шум, будто гонит кого-то, и Сарыч побежал на ту сторону ловить белку. А Кролик шмыг из'
    50. expTxt2x db 'дупла — и во все лопатки домой.'
    51. expTxt2y db 'Тут дядюшка Римус взял коржик, откинул назад голову, положил коржик в рот. Потом закрыл глаза и принялся жевать,'
    52. expTxt2z db 'бормоча под нос песенку.'
    53. expTxt2@ dd 0
    54. stringtable2 dd expTxt2A,expTxt2B,expTxt2C,expTxt2D,expTxt2E,expTxt2F, expTxt2G,expTxt2H, expTxt2I,expTxt2J,expTxt2K,expTxt2L
    55. dd expTxt2M,expTxt2N,expTxt2O,expTxt2P,expTxt2Q,expTxt2R,expTxt2S, expTxt2T,expTxt2U,expTxt2V,expTxt2W,expTxt2X,expTxt2Y
    56. dd expTxt2Z,expTxt2a,expTxt2b,expTxt2c,expTxt2d,expTxt2e,expTxt2f, expTxt2g,expTxt2h,expTxt2i,expTxt2j,expTxt2k,expTxt2l
    57. dd expTxt2m,expTxt2n,expTxt2o,expTxt2p,expTxt2q,expTxt2r,expTxt2s,expTxt2t, expTxt2u,expTxt2v,expTxt2w,expTxt2x,expTxt2y
    58. dd expTxt2z,expTxt2@,0
    59. expTxt3A db 'Дядюшка Римус посадил Джоэля на колени и ласково поглаживая его льняные волосы начал рассказывать.'
    60. expTxt3B db '-- Братец Опоссум и Братец Енот были такими друзьями, что их как говорится, водой не разольешь.'
    61. expTxt3C db 'Куда Братец Опоссум -- туда и Братец Енот, куда Братец Енот -- туда и Братец Опоссум. И вот как-то'
    62. expTxt3D db 'вечером Братец Опоссум гостил у Братца Енота. Они съели блюдо тушеных овощей, выкурили по сигаре'
    63. expTxt3E db 'и решили навестить знакомых, которые жили по соседству. Старик, вероятно, забыл, что накануне он'
    64. expTxt3F db 'не закончил рассказ про Братца Кролика, попавшего в беду, а маленький Джоэл решил, что это'
    65. expTxt3G db 'продолжение вчерашнего рассказа и не стал перебивать дядюшку Римуса.'
    66. expTxt3H db '-- Они добежали бы быстро, ведь оба они бегают как гнедая лошадь твоего отца, но Братец Опоссум то'
    67. expTxt3I db 'и дело останавливался, чтобы набить живот лесными сливами, а Братец Енот, поджидая его, дурачился'
    68. expTxt3J db '-- то квакал, как лягушка, то верещал, как головастик. Вдруг Братец Енот и Братец Опоссум услышали,'
    69. expTxt3K db 'что в глубине леса лает Собака'
    70. expTxt3L db '"Братец Опоссум, а что ты будешь делать, если Сестрица Собака прибежит сюда?" -- спросил Братец Енот.'
    71. expTxt3M db '"Если она прибежит сюда, Братец Енот, я не брошу тебя на произвол судьбы. Ты можешь смело положиться на'
    72. expTxt3N db 'меня", -- ответил Братец Опоссум -- "А что ты сделаешь?"'
    73. expTxt3O db '"Кто, я?" -- удивился Братец Енот -- "Пусть она только появится, я ей покажу, где раки зимуют".'
    74. expTxt3P db '-- "И Сестрица Собака появилась?" -- спросил нетерпеливо Джоэль'
    75. expTxt3Q db 'А собака увидала их и не стала тратить времени зря. Она и здороваться не стала.'
    76. expTxt3R db 'Прямо кинулась на них — и всё тут.'
    77. expTxt3S db 'Братец Опоссум в ту же минуту осклабился, рот до ушей, и кувырнулся на спину, будто мёртвый.'
    78. expTxt3T db 'А Енот — тот мастер был драться. Подмял под себя собаку и ну трепать. Правду сказать, от собаки не много'
    79. expTxt3U db 'осталось, а то, что осталось, вырвалось — и наутёк, в самую чащу, будто кто пальнул из ружья.'
    80. expTxt3V db 'Вот Братец Енот привёл свой костюм в порядок, встряхнулся, а Братец Опоссум всё лежал как мёртвый. Потом'
    81. expTxt3W db 'осторожно привстал, огляделся да как бросится бежать, только пятки засверкали.'
    82. expTxt3X db 'В другой раз, как повстречались Опоссум и Енот, говорит Опоссум:'
    83. expTxt3Y db '— Здравствуй, Братец Енот! Как поживаешь?'
    84. expTxt3Z db 'Но Енот — руки в карманы, здороваться не хочет.'
    85. expTxt3a db '— Ты что ж это нос воротишь, Братец Енот? — спрашивает Опоссум.'
    86. expTxt3b db '— Я с трусами и разговаривать не хочу, — отвечает Енот. — Ступай своей дорогой!'
    87. expTxt3c db 'Опоссум разобиделся — страх.'
    88. expTxt3d db '— Кто ж это трус, нельзя ли узнать?'
    89. expTxt3e db '— Да ты, конечно, — говорит Енот. — Очень нужны мне такие приятели, что кидаются на спину и строят из себя'
    90. expTxt3f db 'мёртвых, чуть дело дойдёт до драки!'
    91. expTxt3g db 'Опоссум, как услышал эти слова, ну смеяться, ну хохотать.'
    92. expTxt3h db '— Неужто ты думаешь, Братец Енот, что это я со страху? Не думаешь ли ты, что я испугался несчастного пса?'
    93. expTxt3i db 'И чего мне было бояться? Я ведь отлично знал, что, если я не слажу с этой собакой, ты-то задашь ей жару.'
    94. expTxt3j db 'Да я просто лежал и смотрел, как ты треплешь её, и ждал, когда придёт мой черёд позабавиться.'
    95. expTxt3k db 'Но Енот только нос наморщил:'
    96. expTxt3l db '— Рассказывай сказки, Братец Опоссум. Как дотронулась до тебя собака, ты сразу кувырнулся и прикинулся'
    97. expTxt3m db 'мёртвым.'
    98. expTxt3n db '— Так ведь я говорю тебе, Братец Енот, что это совсем не от страху. Я одной только вещи и боюсь на свете'
    99. expTxt3o db '— это щекотки. А когда эта собака ткнулась носом мне в рёбра, я рассмеялся, и так разобрал меня смех, что'
    100. expTxt3p db 'вот не шелохнуть ни рукой, ни ногой! Конечно, её счастье, что я боюсь щекотки, а то ещё минутка, и я'
    101. expTxt3q db 'разорвал бы её в клочья. Драки я не боюсь никакой, Братец Енот, но щекотка — это дело другое. С кем угодно'
    102. expTxt3r db 'согласен я драться, но только — чур — без щекотки.'
    103. expTxt3s db '— Вот с того самого дня, — продолжал дядюшка Римус, глядя, как завивается в кольца дымок из трубки, — и до'
    104. expTxt3t db 'сих пор так боится щекотки Братец Опоссум: тронь его только между рёбер — кидается на спину и хохочет до'
    105. expTxt3u db 'упаду, так что не может шевельнуть ни рукой, ни ногой.'
    106. expTxt3v db 0
    107. stringtable3 dd expTxt3A,expTxt3B,expTxt3C,expTxt3D,expTxt3E,expTxt3F,expTxt3G,expTxt3H,expTxt3I,expTxt3J,expTxt3K,expTxt3L
    108. dd expTxt3M,expTxt3N,expTxt3O,expTxt3P,expTxt3Q,expTxt3R,expTxt3S,expTxt3T,expTxt3U,expTxt3V,expTxt3W,expTxt3X,expTxt3Y,expTxt3Z
    109. dd expTxt3a,expTxt3b,expTxt3c,expTxt3d,expTxt3e,expTxt3f,expTxt3g,expTxt3h,expTxt3i,expTxt3j,expTxt3k,expTxt3l
    110. dd expTxt3m,expTxt3n,expTxt3o,expTxt3p,expTxt3q,expTxt3r,expTxt3s,expTxt3t,expTxt3u,expTxt3v,0
    111. expTxt4A db 'Заметив, что старый негр сидит на пороге хижины и ничем не занят, Джоэль присел рядышком.',0
    112. expTxt4B db 'Негр молчал, и Джоэль молчал, не решаясь нарушить ход мыслей старика. Но время шло, и',0
    113. expTxt4C db 'мальчик не выдержал.',0
    114. expTxt4D db '-- "Дядюшка Римус, а Братец Лис съел Братца Кролика?" -- спросил он осторожно.',0
    115. expTxt4E db '— Разве ж я не рассказывал тебе об этом, дружок? Ну да, я ведь сонный был, и в голове',0
    116. expTxt4F db 'у меня всё спуталось, и мама как раз позвала тебя. О чём же мы тогда толковали? Помню, помню. Ты, никак, и',0
    117. expTxt4G db 'глазки уже трёшь? Нет, плакать по Братцу Кролику погоди. Даром, что ли, он был такой шустрый? Ты послушай,',0
    118. expTxt4H db 'что дальше будет.',0
    119. expTxt4I db 'Приклеился, значит, Братец Кролик к Чучелку, а Старый Лис ну кататься по земле, ну хохотать. А потом говорит:',0
    120. expTxt4J db '— Сдаётся мне, Братец Кролик, на этот раз я тебя поймал. Может, я и ошибаюсь, но кажется мне,',0
    121. expTxt4K db 'что поймал. Ты всё тут скакал и потешался надо мной, но теперь конец твоим шуткам. И кто просил',0
    122. expTxt4L db 'тебя лезть не в своё дело? И зачем сдалось тебе это Чучелко? И кто это прилепил тебя к нему? Никто,',0
    123. expTxt4M db 'никто в целом свете! Никто не просил тебя, а просто ты сам взял и влепился в это Чучелко! И сам ты во',0
    124. expTxt4N db 'всём виноват, Братец Кролик! Так и надо тебе, так и будешь сидеть, пока я не наберу хворосту и не зажгу его,',0
    125. expTxt4O db 'потому что я, конечно, зажарю тебя сегодня, Братец Кролик.',0
    126. expTxt4P db 'Так сказал Старый Лис.',0
    127. expTxt4Q db 'А Кролик отвечает так смирно, послушно:',0
    128. expTxt4R db '— Делай со мной что хочешь, братец Лис, только, пожалуйста, не вздумай бросить меня в этот терновый куст.',0
    129. expTxt4S db 'Жарь меня, как хочешь. Братец Лис, только не бросай меня в этот терновый куст.',0
    130. expTxt4T db '— Пожалуй, слишком много возни с костром, — говорит Лис. — Пожалуй, я лучше, повешу тебя, Братец Кролик.',0
    131. expTxt4U db '— Вешай, как хочешь высоко, Братец Лис, — говорит Кролик, — только бы ты не вздумал бросить меня в этот',0
    132. expTxt4V db 'терновый куст.',0
    133. expTxt4W db '— Верёвки-то у меня нет, — говорит Лис, — так что, пожалуй, я утоплю тебя.',0
    134. expTxt4X db '— Топи меня так глубоко, как хочешь, Братец Лис, — говорит Кролик, — только не бросай меня в этот терновый куст.',0
    135. expTxt4Y db 'Но Братец Лис хотел расправиться с Кроликом покрепче; — Ну, — говорит, — раз ты боишься, как раз и брошу',0
    136. expTxt4Z db 'тебя в терновый куст.',0
    137. expTxt4a db '— Где тебе! — говорит Братец Кролик. — С Чучелком-то я слишком тяжёл, не добросишь.',0
    138. expTxt4b db 'Схватил Лис Кролика за уши да как тряхнёт! Отклеилось, упало Чучелко.',0
    139. expTxt4c db '— А вот и доброшу, — говорит Лис.',0
    140. expTxt4d db 'Как размахнётся, как бросит Кролика в серёдку тернового куста, даже треск пошёл.',0
    141. expTxt4e db 'Встал Лис на задние лапы, смотрит, что будет с Кроликом. Вдруг слышит — кличет его кто-то. Глядь — там,',0
    142. expTxt4f db 'на пригорке. Братец Кролик на брёвнышке, нога на ногу, сидит-посиживает, смолу из шерсти вычёсывает щепкой.',0
    143. expTxt4g db 'Понял тут Лис, что опять остался в дураках. А Братцу Кролику позлить его охота, он и кричит:',0
    144. expTxt4h db '— Терновый куст — мой дом родной. Братец Лис! Терновый куст — мой дом родной!',0
    145. expTxt4i db 'Вскочил и пропал, как сверчок в золе.',0
    146. expTxt4@ dd 0
    147. stringtable4 dd expTxt4A,expTxt4B,expTxt4C,expTxt4D,expTxt4E,expTxt4F, expTxt4G, expTxt4H,expTxt4I,expTxt4J,expTxt4K,expTxt4L,expTxt4M,expTxt4N,expTxt4O,expTxt4P,expTxt4Q,expTxt4R,expTxt4S,expTxt4T,expTxt4U,expTxt4V,expTxt4W
    148. dd expTxt4X,expTxt4Y,expTxt4Z,expTxt4a,expTxt4b,expTxt4c,expTxt4d,expTxt4e, expTxt4f,expTxt4g,expTxt4h,expTxt4i,expTxt4@,0
    149. expTxt5 db '-- "Дядюшка Римус, а Братец Лис и в самом деле никогда не поймал Братца Кролика?'
    150. db '-- спосил маленький Джоэль',10
    151. db 'на следующий вечер',10
    152. db '-- "Один раз Братец Лис чуть-чуть не поймал Братца Кролика. Это случилось вскоре'
    153. db 'после истории с укропом.',10
    154. db 'Братец Лис рыскал повсюду вынюхивая, где что плохо лежит, -- стянул у соседей большой кусок смолы.',10
    155. db 'Я знаю, дядюшка Римус -- смолой ты натираешь дратву, когда чинишь обувь.',10
    156. db '-- Правильно, Джоэль. Смолой натирают дратву, мажут днища лодок, крыши домов, делают '
    157. db 'асфальт... Послушай',10
    158. db 'ЧТО придумал Братец Лис. Он размягчил смолу и вылепил из нее человечка, да так ловко, что его можно было',10
    159. db 'запросто принять за живого. Выражение лица у этого смоляного человечка было свирепое, а от солнца он стал',10
    160. db 'таким липким, что до него нельзя было дотронуться. Братец Лис назвал его -- Липкий Джек, а для пущей',10
    161. db 'важности надел на него свою старую соломенную шляпу. Этого мистера Джека -- Липкого Человечка, Братец Лис',10
    162. db 'поставил на полянке, куда Братец Кролик обычно прибегал порезвиться перед обедом, а сам спрятался в кустах',10
    163. db 'неподалеку.',10
    164. db 'Прошло немного времени, скачет Братец Кролик -- прыг, прыг, прыг. Шерстка лоснится, грудь -- колесом, хвост',10
    165. db '-- торчком. Ладный, да ловкий. Скачет и поет:',10
    166. db '                               Укроп для Лиса был в тот день,',10
    167. db '                                      Как наголову снег',10
    168. db '                               Со мной тебе, трухлявый пень,',10
    169. db '                                     не справиться вовек',10
    170. db 'А Братец Лис лежит в кустах и ухмыляется -- "Посмотрим, Братец Кролик, как ты запоешь в объятиях липкого',10
    171. db 'Джека"',10
    172. db 'Выбежал Братец Кролик на полянку и остолбенел -- прямо перед ним стоит черный незнакомец в соломенной',10
    173. db 'шляпе и вид его не предвещает ничего хорошего.',10
    174. db 'Братец Лис в кустах даже дышать перестал.',10
    175. db '"Добрый день, мистер!" -- вежливо сказал Братец Кролик -- "Чудесная погода сегодня. Не правда ли?"',10
    176. db 'Смоляной человечек не ответил ничего. А Братец Лис лежал тихо-тихо.',10
    177. db '"Как поживаете, мистер?... Извините, не имею чести знать ваше имя" -- Братец Кролик замолчал ожидая ответа.',10
    178. db 'Братец Лис довольнеханек, но лежит тихо.',10
    179. db '"Как поживаете, я спрашиваю. Или вы глухой, мистер? Если так, то я могу подойти поближе и говорить громче"',10
    180. db 'Смоляное чучелко не проронило и слова. А поскольку смола на солнце начала плавиться, лицо его перекосило и',10
    181. db 'стало еще свирепее.',10
    182. db '"Однако, парень, ты невежа, как я погляжу" -- сказал Братец Кролик -- "К тебе обращается почтенный',10
    183. db 'джентельмен, а ты молчишь словно воды в рот набрал, да еще и рожи корчишь"',10
    184. db 'Братец Лис тихонько хихикнул, а смоляной человечек презрительно посмотрел на Братца Кролика и опять ничего',10
    185. db 'не ответил Братец Кролик начал терять терпение -- "Ну, хорошо, я тебя научу вежливости. Если ты сейчас же не',10
    186. db 'снимешь шляпу и не скажешь -- Добрый день, Братец Кролик! -- я тебя вздую"',10
    187. db 'Смоляное чучелко молчит, а Братец Лис лежит тихо.',10
    188. db 'Братец Кролик закипел -- "Ах, ты, такой-сякой невежа, вот я тебе сейчас как врежу!" ',10
    189. db 'Он размахнулся и со всей силы ударил смоляного человечка кулаком в ухо. Лапа, конечно же, завязла в смоле,',10
    190. db 'да так крепко, что не оторвать. Братец Лис в кустах чуть не описался от удовольствия.',10
    191. db '"Эй, черножопый, что ты делаешь?! Отпусти мою лапу!" -- закричал Братец Кролик -- "Это не честный прием.',10
    192. db 'Если ты сейчас же не отпустишь мою лапу, то получишь еще!" Но Липкий Джек и не думает отпускать его лапу.',10
    193. db 'А Братец Лис лежит тихо.',10
    194. db '"Ах, так! Ну, погоди!" -- и Братец Кролик стукнул Смоляного Человечка другой лапой. И другая лапа завязла.',10
    195. db 'Братец Лис внесебя от радости, но ждет, не показывается',10
    196. db 'А Братец Кролик не на шутку разбушевался -- "Отпусти, говорю! А не отпустишь -- я пну тебя в живот" Но',10
    197. db 'липкий Джек молчит и крепко держит Братца Кролика. Братец Кролик пнул ненавистного незнакомца одной ногой,',10
    198. db 'другой -- обе задние лапы Братца Кролика также завязли. А Братец Лис не торопится выходить. "Последний раз',10
    199. db 'тебя предупреждаю", -- разъярился Братец Кролик -- "Если не отпустишь. я ударю так, что у тебя искры из глаз',10
    200. db 'посыпятся"',0
    201. expTxt7   db '-— Если я не ошибаюсь, -— начал дядюшка Римус, -— Братец Сарыч всё стерёг дупло, куда спрятался Кролик',10,'и откуда он давно уже выскочил. На этом мы кончили, Джоэль?',10
    202. db 'Братец Сарыч совсем приуныл. Но он обещал Лису, что постережет Кролика.',10
    203. db '"Дай-ка, -— думает, — подожду Братца Лиса, обману его как-нибудь".',10
    204. db 'Глядь-поглядь —- скачет из лесу Лис с топором на плече.',10
    205. db '-— Ну, что слышно, Братец Сарыч? Всё там Братец Кролик?',10
    206. db '— Там, конечно, — отвечает Сарыч. — Притаился — видно, вздремнул.',10
    207. db '— Ну, уж я разбужу его, — говорит Лис.',10
    208. db 'Скинул он тут свой пиджак, поплевал на руки, взял топор. Размахнулся, как ударит по дереву — поу! Всякий раз, как стукнет топор, — поу! Сарыч скок да скок, а сам приговаривает:',10
    209. db '— Он там, Братец Лис! Он там, он там!',10
    210. db 'Брызнет в сторону щепка, подскочит Сарыч, голову набок, кричит:',10
    211. db '— Он там, Братец Лис! Я слышу, он там!',10
    212. db 'А Лис знай рубит и рубит. Уж совсем мало осталось рубить, опустил Лис топор, чтобы перевести дух, вдруг видит — сидит у него за спиной Сарыч, усмехается.',10
    213. db 'Смекнул Лис, что тут дело не чисто. А Сарыч знай твердит:',10
    214. db '— Он там, Братец Лис! Он там, мне видать его хвостик!',10
    215. db 'Тут Лис заглянул в дупло и кричит:',10
    216. db '— Погляди, Братец Сарыч, что там торчит? Не нога ли это братца Кролика?',10
    217. db 'Сарыч и сунул голову в дупло. А Лис его — хвать за шею.',10
    218. db 'Уж Сарыч и крыльями хлопал и бился — всё без толку. Лису ловко было держать его, он прижал его к земле, не пускает. Тут Сарыч взмолился:',10
    219. db '— Отпусти меня, Братец Лис! Отпусти, Братец Кролик — он тут, совсем близко! Ещё два разочка ударь топором, и он твой!',10
    220. db '— А не лжёшь ли ты, Братец Сарыч?',10
    221. db '— Да нет же, он тут, он тут! Отпусти меня к моей жёнушке, Братец Лис! Он тут, Братец Лис, он тут!',10
    222. db '— Почему-то клочок его шерсти тут, на кусте ежевики, — говорит Братец Лис, — а пришёл он с другой стороны!',10
    223. db 'Тогда Сарыч рассказал всё, как было.',10
    224. db '— Я такого пройдохи, сколько живу, не видывал, Братец Лис, — сказал Сарыч.',10
    225. db 'А Лис говорит:',10
    226. db '— Всё равно ты ответишь мне за него, Братец Сарыч. Я ушёл, Братец Кролик был в дупле, а ты остался стеречь его. Прихожу — ты тут, а Братца Кролика нет.',10
    227. db 'Придётся мне зажарить тебя вместо Кролика, Братец Сарыч.',10
    228. db '— Ну, если ты бросишь меня в огонь, я улечу, Братец Лис, — говорит Сарыч.',10
    229. db '— А я сперва расшибу тебя оземь, Братец Сарыч.',10
    230. db 'Так сказал Лис, ухватил Сарыча за хвост, размахнулся… А перья вырвались из хвоста, и Сарыч полетел кверху.',10
    231. db 'Летит и кричит:',10
    232. db '— Спасибо, что дал мне разгон, Братец Лис! Спасибо, что дал мне разгон!',10
    233. db 'И улетел. А Лис только зубами защёлкал с досады.',10
    234. db '— А что сталось с Кроликом, дядюшка Римус?',10
    235. db '— Да ты не заботься о Братце Кролике, дружок. Я всё тебе про него расскажу.',0
    236. expTxt8   db 'Вывод текста в заголовок окна через SetWindowText',0
    237. expTxt9   db 'Вывод текста в заголовок окна через SendMessage',0
    238. expTxt10  db 'Вывод текста при помощи PolyTextOut API',0
    239. pptxt POLYTEXT <0,TOP+16*0, expTxt6b-expTxt6a,expTxt6a,ETO_OPAQUE,{0,0,100,200},0>
    240.       POLYTEXT <0,TOP+16*1, expTxt6c-expTxt6b,expTxt6b,ETO_OPAQUE,{0,0,100,200},0>
    241.       POLYTEXT <0,TOP+16*2, expTxt6d-expTxt6c,expTxt6c,ETO_OPAQUE,{0,0,100,200},0>
    242.       POLYTEXT <0,TOP+16*3, expTxt6e-expTxt6d,expTxt6d,ETO_OPAQUE,{0,0,100,200},0>
    243.       POLYTEXT <0,TOP+16*4, expTxt6f-expTxt6e,expTxt6e,ETO_OPAQUE,{0,0,100,200},0>
    244.       POLYTEXT <0,TOP+16*5, expTxt6g-expTxt6f,expTxt6f,ETO_OPAQUE,{0,0,100,200},0>
    245.       POLYTEXT <0,TOP+16*6, expTxt6h-expTxt6g,expTxt6g,ETO_OPAQUE,{0,0,100,200},0>
    246.       POLYTEXT <0,TOP+16*7, expTxt6i-expTxt6h,expTxt6h,ETO_OPAQUE,{0,0,100,200},0>
    247.       POLYTEXT <0,TOP+16*8, expTxt6j-expTxt6i,expTxt6i,ETO_OPAQUE,{0,0,100,200},0>
    248.       POLYTEXT <0,TOP+16*9, expTxt6k-expTxt6j,expTxt6j,ETO_OPAQUE,{0,0,100,200},0>
    249.       POLYTEXT <0,TOP+16*10,expTxt6l-expTxt6k,expTxt6k,ETO_OPAQUE,{0,0,100,200},0>
    250.       POLYTEXT <0,TOP+16*11,expTxt6m-expTxt6l,expTxt6l,ETO_OPAQUE,{0,0,100,200},0>
    251.       POLYTEXT <0,TOP+16*12,expTxt6n-expTxt6m,expTxt6m,ETO_OPAQUE,{0,0,100,200},0>
    252.       POLYTEXT <0,TOP+16*13,expTxt6o-expTxt6n,expTxt6n,ETO_OPAQUE,{0,0,100,200},0>
    253.       POLYTEXT <0,TOP+16*14,expTxt6p-expTxt6o,expTxt6o,ETO_OPAQUE,{0,0,100,200},0>
    254.       POLYTEXT <0,TOP+16*15,expTxt6q-expTxt6p,expTxt6p,ETO_OPAQUE,{0,0,100,200},0>
    255.       POLYTEXT <0,TOP+16*16,expTxt6r-expTxt6q,expTxt6q,ETO_OPAQUE,{0,0,100,200},0>
    256.       POLYTEXT <0,TOP+16*17,expTxt6s-expTxt6r,expTxt6r,ETO_OPAQUE,{0,0,100,200},0>
    257.       POLYTEXT <0,TOP+16*18,aStatic -expTxt6t,expTxt6s,ETO_OPAQUE,{0,0,100,200},0>
    258. expTxt6a db 'Раз после ужина мальчик прибежал к старому негру, чтобы послушать ещё про Братца Кролика и его'
    259. expTxt6b db 'приятелей. Дядюшка Римус был очень весел в этот день. Только Джоэль сунул голову в дверь, он '
    260. expTxt6c db 'услышал песенку:'
    261. expTxt6d db '                                  Где ты, Братец Кролик?'
    262. expTxt6e db '                                    Сидишь на крылечке,'
    263. expTxt6f db '                                      Куришь сигару,'
    264. expTxt6g db '                                    Пускаешь колечки?'
    265. expTxt6h db 'И мальчик тотчас вспомнил, как гнался за Кроликом Старый Лис.'
    266. expTxt6i db '— Дядюшка Римус, — спросил Джоэль, — а Кролик совсем удрал, когда отлепился от Чучелка?'
    267. expTxt6j db '— Что ты, дружок! Зачем ему было совсем удирать? Такой человек, как Братец Кролик, да вдруг удирать! Конечно,'
    268. expTxt6k db 'он посидел дома, пока не выскреб из шерсти смолу; день, другой посидел и  опять за своё: скачет то здесь, то'
    269. expTxt6l db 'там, как ни в чём не бывало. Все соседи посмеивались над Кроликом:'
    270. expTxt6m db '— Ну-ка, ну-ка, Братец Кролик, расскажи, что случилось у тебя со Смоляным Чучелком? '
    271. expTxt6n db 'Уж так-то ему это надоело. Вот зашёл он раз навестить свою соседку, Матушку Мидоус с дочками, а девчонки ну'
    272. expTxt6o db ' потешаться над ним, ну хохотать. Братец Кролик сидел спокойно, будто оглох.'
    273. expTxt6p db '— А кто это — Матушка Мидоус? — спросил мальчик.'
    274. expTxt6q db '— Не перебивай, дружок. Ну просто так говориться в сказке: Матушка Мидоус с дочками, а больше я ничего не знаю.'
    275. expTxt6r db 'Слушал, слушал Кролик, как они потешались над ним, потом положил ногу на ногу, подмигнул девочкам и говорит:'
    276. expTxt6s db '— Милые вы мои, да ведь Братец Лис у моего папаши тридцать лет был верховой лошадью: может, и больше, но'
    277. expTxt6t db 'тридцать — это наверное. Так он сказал, и встал, и откланялся, и пошёл прочь медленным, важным шагом.'
    278. aStatic db 'STATIC'
    279. expTxt11 db 0
    280. hStaticText1 dq ?
    281. hStaticText2 dq ?
    282. expRect RECT <>
    283. MemDC dq ?
    284. hbit dq ?
    285. font_height dd ?
    286. end
    В главе показан пример окна с "закладками" (Tab Controls). Окно с закладками позволяет отображать несколько страниц связанных элементов управления внутри одного окна. Способ обращения к каждой странице подобен выбору закладки в книге: щелчок на ярлычке в строке закладок, отображаемой в верхней части окна.
    Создание закладок
    Для создания закладок используется функция CreateWindow/CreateWindowEx. В качестве имени класса используется SysTabControl32. Фрагмент программы, создающий закладку.
    Код (ASM):
    1. wmCREATE:invoke GetClientRect,,&expRect
    2. ;создать закладку
    3.     push rbx
    4.     push IMAGE_BASE
    5.     push rbx
    6.     push hWnd
    7.     mov eax,expRect.bottom
    8.     sub eax,720
    9.     push rax
    10.     mov eax,expRect.right
    11.     push rax
    12.     push TOP
    13.     push rbx
    14.     sub esp,20h
    15.     invoke CreateWindowEx,WS_EX_RIGHTSCROLLBAR,&aSysTabControl32,&NullString,WS_VISIBLE or \
    16.     WS_TABSTOP or WS_CHILD
    17.     mov hTabWnd,rax
    18.     . . . . .
    19. ;Заполняем структуру TCITEMA
    20.     mov tci.imask,TCIF_TEXT
    21.     or tci.iImage,-1
    22. @@:;создаем 10 закладок
    23.     mov rax,handle1[rbx*8]
    24.     mov tci.pszText,rax;название закладки
    25.     mov tci.lParam,rbx;номер закладки
    26.     neg rax
    27.     add rax,handle1[rbx*8+8]
    28.     mov tci.cchTextMax,eax
    29.     invoke SendMessage,hTabWnd,TCM_INSERTITEMA,ebx,&tci
    30.     inc ebx
    31.     cmp ebx,10
    32.     jb @b
    33.     xor ebx,ebx
    Перед созданием закладки вызывается GetClientRect ― для получения размеров рабочей области главного окна. При создании закладки ее размеры изменяются таким образом, чтобы полностью заполнить рабочую область родительского окна.
    После создания закладки приложение может передавать ей управляющие сообщение, а сама закладка, изменяя свое состояние, будет посылать сообщения родительскому окну.
    Элементы закладки определяются структурами типа TC_ITEM
    Код (C):
    1. typedef struct tagTCITEMA {
    2.     UINT imask;
    3.     DWORD dwState;
    4.     DWORD dwStateMask;
    5.     LPSTR pszText;
    6.     int cchTextMax;
    7.     int iImage;
    8.     LPARAM lParam;
    9. } TCITEMA, *LPTCITEMA;
    Поле imask этой структуры указывает, в каком из ее полей ― pszText, iImage или lParam ― содержится реальное значение, определяющее элемент закладки, когда в структуру записываются данные из закладки. Поле imask может содержать одно или несколько значений из таблицы.
    КонстантаЗначениеНазначение
    hexbin
    TCIF_TEXT
    1​
    00001данные содержатся в поле pszText
    TCIF_IMAGE
    2​
    00010данные содержатся в поле iImage
    TCIF_RTLREADING
    4​
    00100для отображения текста в pszText справа налево в еврейских или арабских версиях Windows
    TCIF_PARAM
    8​
    01000данные содержатся в поле lParam
    TCIF_ALL
    B​
    01011все три поля lParam, iImage и pszText содержат данные
    TCIF_STATE
    10​
    10000данные содержатся в поле dwState
    При инициализации отдельного элемента закладки поле pszText содержит текст, отражаемый в этом элементе. При получении информации из элемента закладки это поле содержит указатель на символьный массив, в который будет записан соответствующий текст. В этом случае поле cchTextMax содержит количество символов, записанных в pszText
    Если с закладкой связан список изображений (графических объектов), то поле iImage задает индекс изображения, связанного с элементом закладки. Если список изображений с закладкой не связывается, то значение в этом поле должно быть равным -1
    Поле lParam может содержать любые данные, задаваемые пользователем.
    Текущее состояние закладки dwState может принимать значения:
    • TCIS_BUTTONPRESSED ― элемент выбран
    • TCIS_HIGHLIGHTED ― элемент выделен и отображается с использованием текущего цвета выделения
     
    Последнее редактирование: 15 июл 2019
  3. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.993
    Управляющие сообщения
    КонстантаHexwParamlParamДействиеПример
    TCM_FIRST1300Значения сообщений типа TCM_ зависит от версии Windows и от значения TCM_FIRST
    TCM_GETIMAGELISTTCM_FIRST+2
    0​
    0​
    В случае успеха возвращается дескриптор списка изображений, в случае неуспеха возвращается 0invoke SendMessage, hTabWnd, TCM_GETIMAGELIST, 0, 0
    TCM_SETIMAGELISTTCM_FIRST+3
    0​
    Дескриптор списка изображений ассоциированный с вкладкойВ случае успеха возвращается дескриптор списка изображений, в случае неуспеха возвращается 0invoke SendMessage, hTabWnd, TCM_SETIMAGELIST, 0, handle
    TCM_GETITEMCOUNTTCM_FIRST+4
    0​
    0​
    Получение количества элементов на закладкеinvoke SendMessage, hTabWnd, TCM_GETITEMCOUNT, 0, 0
    TCM_GETITEMTCM_FIRST+5индекс элемента закладкиуказатель на структуру типа TC_ITEM, в которую записывается информация о заданном элементеПолучение информации о заданном элементе закладки. В случае успешного завершения возвращается ненулевое значение, в противном случае ― нульinvoke SendMessage, hTabWnd, TCM_GETITEM, index, &tci
    TCM_SETITEMTCM_FIRST+6индекс элемента закладкиуказатель на структуру типа TC_ITEM, в которой содержится информация о заданном элементеУстановка новой информации относительно заданного элемента закладки. В случае успешного завершения возвращается ненулевое значение, в противном случае ― нульinvoke SendMessage, hTabWnd, TCM_SETITEM, index, &tci
    TCM_INSERTITEMTCM_FIRST+7индекс элемента закладки, после которого вставляется новый элементуказатель на структуру типа TC_ITEM, определяющую новый элементсоздание (вставка) нового элемента закладки. В случае успешного завершения возвращается ненулевое значение, в противном случае ― нульinvoke SendMessage, hTabWnd, TCM_INSERTITEM, index, &tci
    TCM_DELETEITEMTCM_FIRST+8индекс удаляемого элемента
    0​
    Удаление из закладки заданного элемента. В случае успешного завершения возвращается ненулевое значение, в противном случае ― нульinvoke SendMessage, hTabWnd, TCM_DELETEITEM, index, &tci
    TCM_DELETEALLITEMSTCM_FIRST+9
    0​
    0​
    Удаление из закладки всех элементов. В случае успешного завершения возвращается ненулевое значение, в противном случае ― нульinvoke SendMessage, hTabWnd, TCM_DELETEALLITEMS, 0, 0
    TCM_GETITEMRECTTCM_FIRST+10индекс элемента закладкиУказатель на структуру RECT, в которую передадут координаты ограничивающего вкладку прямоугольника, в области отображенияПолучение координат ограничивающего прямоугольник для закладки. Возвращает TRUE в случае успеха или FALSE в противном случаеinvoke SendMessage, hTabWnd, TCM_GETITEMRECT, index, &Rect
    TCM_GETCURSELTCM_FIRST+11
    0​
    0​
    Возвращает индекс текущего выбранного элемента. Если никакой элемент не выбран, возвращается -1invoke SendMessage, hTabWnd, TCM_GETCURSEL, 0, 0
    TCM_SETCURSELTCM_FIRST+12индекс выбранного элемента закладки
    0​
    Возвращает индекс предыдущего выбранного элемента. Если никакой элемент не выбран, возвращается -1invoke SendMessage, hTabWnd, TCM_SETCURSEL, index, 0
    TCM_HITTESTTCM_FIRST+13
    0​
    содержит указатель на структуру TCHITTESTINFO которая определяет позицию на экранеВозвращает индекс элемента закладки или -1, если в указанной позиции нет вкладкиinvoke SendMessage, hTabWnd, TCM_HITTEST, 0, &tci
    TCM_SETITEMEXTRATCM_FIRST+14Количество дополнительных байтов
    0​
    Устанавливает количество байтов на закладку, зарезервированное для данных приложения в элементе управления вкладкой. Возвращает TRUE в случае успеха или FALSE в противном случаеinvoke SendMessage, hTabWnd, TCM_SETITEMEXTRA, number, 0
    TCM_ADJUSTRECTTCM_FIRST+40задает тип операции. Если он не равен нулю, получить размеры окна исходя из размеров рабочей области. В противном случае размеры рабочей области исходя из размеров окнасодержит указатель на структуру RECT, в которую записываются координаты исходного прямоугольника. При возвращении в эту структуру записываются координаты результирующего прямоугольникаПолучение размеров окна в соответствии с размерами рабочей областиinvoke SendMessage, hTabWnd, TCM_ADJUSTRECT, 0, &Rect
    TCM_SETITEMSIZETCM_FIRST+41
    0​
    младшие 16 бит содержат новую ширину рисунка, старшие 16 бит ― новую высоту в пикселяхВозвращает старые ширину и высоту рисунка. В младших 16 битах содержатся старая ширина рисунка, в старших 16 битах ― высотаinvoke SendMessage, hTabWnd, TCM_SETITEMSIZE, 0, int
    TCM_REMOVEIMAGETCM_FIRST+42индекс удаляемого рисунка
    0​
    удаляет рисунок из закладкиinvoke SendMessage, hTabWnd, TCM_REMOVEIMAGE, index, 0
    TCM_SETPADDINGTCM_FIRST+43
    0​
    В младших 16 битах содержится величину горизонтального заполнения в пикселях, в старших 16 битах ― количество отступов по вертикали в пикселях.Устанавливает количество места (отступ) вокруг значка и метки каждой закладкиinvoke SendMessage, hTabWnd, TCM_SETPADDING, 0, int
    TCM_GETROWCOUNTTCM_FIRST+44
    0​
    0​
    Возвращает количество строк на закладкеinvoke SendMessage, hTabWnd, TCM_GETROWCOUNT, 0, 0
    TCM_GETTOOLTIPSTCM_FIRST+45
    0​
    0​
    Извлекает дескриптор всплывающей подсказки, связанной с закладкой. Возвращает дескриптор всплывающей подсказки в случае успеха или NULL в противном случаеinvoke SendMessage, hTabWnd, TCM_GETTOOLTIPS, 0, 0
    TCM_SETTOOLTIPSTCM_FIRST+46Дескриптор к элементу управления "подсказка"
    0​
    Назначает всплывающую подсказку закладке. При использовании сообщения TCM_GETTOOLTIPS можно получить "всплывающую подсказку", связанную с закладкой,invoke SendMessage, hTabWnd, TCM_SETTOOLTIPS, handle, 0
    TCM_GETCURFOCUSTCM_FIRST+47
    0​
    0​
    Возвращает индекс элемента закладки, который имеет фокусinvoke SendMessage, hTabWnd, TCM_GETCURFOCUS, 0, 0
    TCM_SETCURFOCUSTCM_FIRST+48Индекс вкладки, которая получает фокус
    0​
    Устанавливает фокус на конкретную закладкуinvoke SendMessage, hTabWnd, TCM_SETCURFOCUS, index, 0
    Вновь созданная закладка не содержит никаких элементов. Поэтому программа должна направить закладке хотя бы одно сообщение TCM_INSERTITEM. Сообщение TCM_ADJUSTRECT необходимо для определения размеров рабочей области ("страницы") закладки. Рабочая область ― это та часть окна закладки, где не отображаются элементы закладки.
    Нотификационные сообщения

    При воздействии на закладку генерируется сообщение WM_NOTIFY, которое может содержать один из двух нотификационных кодов TCN_SELCHANGEили TCN_SELCHANGING. Код TCN_SELCHANGING используется, когда текущий выбор элемента закладки должен измениться. Код TCN_SELCHANGE передается после выбора нового элемента закладки.
    Параметр lParam сообщения WM_NOTIFY содержит указатель на структуру типа NMHDR
    Код (ASM):
    1. NMHDR STRUC
    2.   hwndFrom QWORD ?
    3.   idFrom   QWORD ?
    4.   _code       DWORD ?
    5. NMHDR ENDS
    Нотификационный код содержится в поле _code, а дескриптор закладки, пославшей сообщение, в поле hwndFrom
    Когда сообщение WM_NOTIFY в функции WndProc содержит код TCN_SELCHANGE, в рабочую область выводится текст выбранным способом
    Код (ASM):
    1. wmNOTIFY:;изменение состояния закладки
    2.     cmp [r9+NMHDR._code],TCN_SELCHANGE
    3.     jne wmBYE;DEFAULT
    4.     . . . .
    5.         invoke SendMessage,hTabWnd,TCM_GETCURSEL,0,0
    6.     jmp [handle+rax*8];переходим на выбранную закладку
    Стили элементов Tab Control
    (Tab Control Styles ― TCS_)

    Tab control
    style
    hexОписание
    TCS_TABS
    0​
    Tab Control отображаются в виде закладок с границей вокруг области отображения 00.png
    TCS_SINGLE-
    LINE
    0​
    Элементы Tab Control вытянуты в одну строку. Что бы увидеть те Tab Control'ы, которые не вошли на форму можно воспользоваться прокруткой 12.png
    TCS_RIGHT-
    JUSTIFY
    0​
    Ширина каждого Tab Control увеличивается, чтобы каждая строка Tab Control заполнила всю ширину. Используется со стилем TCS_MULTILINE
    TCS_SCROLL-
    OPPOSITE
    1​
    Неиспользуемые Tab Control перемещаются на противоположную сторону элемента управления при выборе новой вкладки 02.png
    TCS_BOTTOM
    2​
    Отображает вкладки в нижней части элемента управления 04.png
    TCS_RIGHT
    2​
    Tab Control на правой стороне элементов управления, требуется стиль TCS_VERTICAL 06.png
    TCS_MULTI-
    SELECT
    4​
    При выборе вкладки с удержанием клавиши CTRL можно выбрать несколько вкладок. Применяется к вкладкам со стилем TCS_BUTTONS 08.png
    TCS_FLAT-
    BUTTONS
    8​
    Изменяет внешний вид выбранной вкладки на "плоскую" кнопку. Применяется к элементам Tab Control со стилем TCS_BUTTONS 07.png
    TCS_FORCE-
    ICONLEFT
    10​
    Tab Control с иконкой по левому краю вкладки фиксированной ширины. Может использоваться только со стилем TCS_FIXEDWIDTH
    TCS_FORCE-
    LABELLEFT
    20​
    Выравнивает надпись по левому краю Tab Control с фиксированной шириной; надпись отображается справа от значка, а не центрируется. Может использоваться только со стилем TCS_FIXEDWIDTH и подразумевает стиль TCS_FORCEICONLEFT
    TCS_HOT-
    TRACK
    40​
    Элементы под указателем подсвечиваются автоматически. Вы можете проверить, включено ли горячее отслеживание, вызвав SystemParametersInfo
    TCS_VERTICAL
    80​
    элементы Tab Control расположены в левой части элемента управления. Чтобы Tab Control появились в правой части элемента управления, объедините этот стиль со стилем TCS_RIGHT 05.png
    TCS_BUTTONS
    100​
    Все элементы Tab Control в виде кнопок 03.png
    TCS_MULTI-
    LINE
    200​
    Все элементы Tab Control видны одновременно и могут отображаться в несколько строк 01.png
    TCS_FIXED-
    WIDTH
    400​
    Все элементы Tab Control с одинаковой шириной. Стиль нельзя комбинировать со стилем TCS_RIGHTJUSTIFY
    TCS_RAGGED-
    RIGHT
    800​
    Оставляет неровный правый край, не растягивая ряд Tab Control, чтобы заполнить всю ширину элемента управления
    TCS_FOCUS-
    ONBUTTON-
    DOWN
    1000​
    Если элемент Tab Control выбран, то он получает фокус ввода 11.png
    TCS_OWNER-
    DRAWFIXED
    2000​
    За рисование Tab Control отвечает родительское окно
    TCS_TOOLTIPS
    4000​
    У элемента Tab Control есть всплывающая подсказка
    TCS_FOCUS-
    NEVER
    8000​
    Выбранный элемент Tab Control не получает фокус ввода 10.png
    Расширенные стили
    TCS_EX_FLAT-
    SEPARATORS
    1​
    Указывает, что элемент управления вкладкой будет рисовать разделители между элементами вкладки. Этот расширенный стиль влияет только на элементы управления вкладками, которые имеют стили TCS_BUTTONS и TCS_FLATBUTTONS. По умолчанию создание элемента управления вкладками со стилем TCS_BUTTONS или со стилем TCS_FLATBUTTONS устанавливает этот расширенный стиль. Если вам не нужны разделители, вы должны удалить этот расширенный стиль после создания элемента управления
    TCS_EX_REGIS-TERDROP
    2​
    Элемент управления вкладками генерирует коды уведомлений TCN_GETOBJECT, чтобы запросить объект перетаскивания при перетаскивании объекта на элементы вкладки в элементе управления. Приложение должно вызвать CoInitialize или OleInitialize перед установкой этого стиля.
    Иконки на Tab Control
    Создаем 24-разрядный 00.bmp файл с размером 96х32 пикселей (3 картинки 32х32)
    15.png
    asm-файл
    Код (ASM):
    1. ; GUI #
    2. include win64a.inc
    3. RIGHT equ 300
    4. BOTTOM equ 120
    5. IDI_NRM_BITMAP equ 2000
    6. .code
    7. WinMain proc
    8. local msg:MSG
    9. ;Создание родительского окна
    10.          xor ebx,ebx
    11.          mov esi,IMAGE_BASE
    12.          mov ecx,offset FileName
    13.          invoke LoadCursorFromFile
    14.          mov edi,offset ClassName
    15.          push rax ;hIconSm
    16.          push rdi ;lpszClassName
    17.          push rbx ;lpszMenuName
    18.          push COLOR_WINDOW+1 ;hbrBackground
    19.          push 10003h ;hCursor
    20.          push rax        ;hIcon
    21.          push rsi ;hInstance
    22.          push rbx        ;cbClsExtra & cbWndExtra
    23.          pushaddr WndProc ;lpfnWndProc
    24.          push sizeof WNDCLASSEX ;cbSize & style
    25.          invoke RegisterClassEx,esp ;addr WNDCLASSEX
    26.          push rbx ;без дополнительных аргументов
    27.          push rsi ;rsi = 400000h дескриптор приложения
    28.          shl esi,9 ;rsi = CW_USEDEFAULT X и Y координаты окна определяет Windows
    29.          push rbx  ;нет меню
    30.          push rbx  ;нет родителя
    31.          push BOTTOM ;высота
    32.          push RIGHT ;ширина
    33.          push rsi    ;Y-координата окна
    34.          push rsi    ;X-координата окна
    35.          sub esp,20h
    36.          invoke CreateWindowEx,0,edi,edi,WS_OVERLAPPED or WS_VISIBLE \
    37.         or WS_CAPTION or WS_SYSMENU or WS_MINIMIZEBOX
    38. ;цикл сообщений
    39.          lea edi,msg
    40. @@: invoke GetMessage,edi,0,0,0
    41.          invoke DispatchMessage,edi
    42.          jmp @b
    43. WinMain endp
    44. ;Оконная процедура
    45. WndProc proc hWnd:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD
    46. local tci:TCITEMA
    47. local expRect:RECT
    48. local hTabWnd:qword
    49.          mov hWnd,rcx
    50.          cmp edx,WM_DESTROY
    51.          je wmDESTROY
    52.          cmp edx,WM_CREATE
    53.          je wmCREATE
    54. wmDEFAULT:leave
    55.          jmp NtdllDefWindowProc_
    56. wmDESTROY:invoke RtlExitUserProcess,NULL
    57. wmCREATE:lea edx,expRect
    58.          invoke GetClientRect
    59. ;создать закладку
    60.          push rbx
    61.          push IMAGE_BASE
    62.          push rbx
    63.          push hWnd
    64.          mov eax,expRect.bottom
    65.          push rax  ;высота
    66.          mov eax,expRect.right
    67.          push rax  ;ширина
    68.          push rbx  ;Y-координата
    69.          push rbx  ;X-координата
    70.          mov r8d,offset NullString
    71.          mov edx,offset aSysTabControl32
    72.          sub esp,20h
    73.          invoke CreateWindowEx,WS_EX_RIGHTSCROLLBAR,,,WS_VISIBLE \
    74.          or WS_TABSTOP or WS_CHILD or TCS_FORCEICONLEFT
    75.          mov hTabWnd,rax
    76.         invoke ImageList_Create,32,32,ILC_COLOR24 + ILC_MASK,3,0
    77.          mov hImageList, rax
    78.          invoke LoadBitmap,IMAGE_BASE,IDI_NRM_BITMAP
    79.          push rax ; for DeleteObject
    80.          invoke ImageList_Add, hImageList, rax, 0
    81.          pop rax
    82.          invoke DeleteObject,rax
    83.          invoke SendMessage, hTabWnd, TCM_SETIMAGELIST, 0, hImageList
    84.          mov tci.imask,TCIF_TEXT or TCIF_IMAGE ; Text + image
    85. @@:;создаем 3 закладки
    86.          mov rax,handle[rbx*8]
    87.          mov tci.pszText,rax;название закладки
    88.          mov tci.lParam,rbx;номер закладки
    89.          mov tci.iImage,ebx; index to tab control's image
    90.          neg rax
    91.          add rax,handle[rbx*8+8]
    92.          mov tci.cchTextMax,eax
    93.          invoke SendMessage,hTabWnd,TCM_INSERTITEMA,ebx,&tci
    94.          inc ebx
    95.          cmp ebx,3
    96.          jb @b
    97.          xor ebx,ebx
    98. wmBYE:   leave
    99.          xor eax,eax
    100.          ret
    101. WndProc endp
    102. ;---------------------------------------
    103. ClassName db 'TabControl with icons'
    104. NullString db 0
    105. FileName db "br_Rabbit3.cur",0
    106. aSysTabControl32 db "SysTabControl32",0
    107. tab0 db "one",0
    108. tab1 db "two",0
    109. tab2    db "three",0
    110. handle dq tab0,tab1,tab2,handle
    111. hImageList dq ?
    112. end
    rc-файл
    Код (C):
    1. #define IDI_NRM_BITMAP 2000
    2. IDI_NRM_BITMAP BITMAP DISCARDABLE "00.bmp"
    результат
    14.png
     

    Вложения:

    • 09.png
      09.png
      Размер файла:
      182,2 КБ
      Просмотров:
      1.263
    • tut_08.zip
      Размер файла:
      3,2 КБ
      Просмотров:
      549
    Последнее редактирование: 4 сен 2019
  4. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.993
    Глава восьмая. Как Братец Кролик осваивал мышь
    Кролик шел по лесу, игриво повиливая бедрами и мурлыча себе под нос «А я простила, я простила его опять-опять-опять»1. Внезапно на него откуда-то сбоку прыгнула огромная рыжая тень.
    ― «Привет, Братец Кролик!» ― довольно пропыхтел Братец Лис. Правда, пока он это пыхтел, довольства в его голосе поубавилось ― он унюхал, что пахнет Братец Кролик вовсе не Кроликом, а духами и пудрой, и разглядел, что ресницы у него явно темнее, длиннее и гуще, чем обычно бывают у Кроликов. Помимо остальных подозрительных моментов, Кролик и не пытался вырваться. Он томно обмяк на пыльной дороге.
    ― «Я не Кролик, я Крольчиха... противный.» ― проворковала Крольчиха, одновременно, пытаясь пощекотать длинным серым ухом могучую лисью грудь.
    К чести Братец Лиса надо отметить, что кoлeбaлcя он не более секунды.
    «Запах духов, конечно, не очень... но на вкус это ничуть не повлияло», ― сыто размышлял он во время послеобеденного отдыха.
    [​IMG]
    Мы научимся получать и отвечать на ввод с мыши. Учебная программа ожидает нажатия на левую кнопку мыши и отображает текстовую строку в том месте клиентской области, где произошел щелчок мышью.
    Скачайте пример здесь.

    Теория ― мать склероза

    Так же, как и при вводе с клавиатуры, Windows определяет и посылает уведомления об активности мыши относительно какого-либо окна. Эта активность включает в себя одинарные и двойные нажатия на правую, левую, среднюю клавишу, скролинг мышью, передвижения курсора через окно. В отличие от клавиатуры, сообщения от которой направляются окну, имеющему в данный момент фокус ввода, сведения о котором передаются окну, над которым находится мышь, независимо от того, активно оно или нет. Вдобавок, обрабатываются сообщения от мыши, связанные с неклиентской частью окна, но их, как правило, игнорируют. Сфокусируемся на сообщениях связанных с клиентской областью.
    Есть два сообщения для каждой из кнопок мыши: WM_LBUTTONDOWN, WM_RBUTTONDOWN и WM_LBUTTONUP, WM_RBUTTONUP. Если мышь трехкнопочная, то есть еще WM_MBUTTONDOWN и WM_MBUTTONUP. Когда курсор мыши двигается над клиентской областью, Windows шлет WM_MOUSEMOVE окну, над которым он находится. Окно может получать сообщения о двойных нажатиях, WM_LBUTTONDBCLK или WM_RBUTTONDBCLK, тогда и только тогда, когда окно имеет стиль CS_DBLCLKS, или же оно будет получать только серию сообщений об одинарных нажатиях.

    Полный список сообщений, поступающих от мыши


    СообщениеhexОписание
    WM_MOUSEACTIVATE
    21​
    Нажата клавиша мыши над неактивным окном
    WM_NCHITTEST
    84​
    Перемещение мыши в любом месте экрана
    WM_NCMOUSEMOVE0A0Перемещение курсора мыши во внешней области окна
    WM_NCLBUTTONDOWN0A1Нажата левая клавиша мыши во внешней области окна
    WM_NCLBUTTONUP0A2Отпущена левая клавиша мыши во внешней области окна
    WM_NCLBUTTONDBLCLK0A3Двойной щелчок левой клавишей мыши во внешней (non-client) области окна
    WM_NCRBUTTONDOWN0A4Нажата правая клавиша мыши во внешней области окна
    WM_NCRBUTTONUP0A5Отпущена правая клавиша мыши во внешней области окна
    WM_NCRBUTTONDBLCLK0A6Двойной щелчок правой клавишей мыши во внешней области окна
    WM_NCMBUTTONDOWN0A7Нажата средняя клавиша мыши во внешней области окна
    WM_NCMBUTTONUP0A8Отпущена средняя клавиша мыши во внешней области окна
    WM_NCMBUTTONDBLCLK0A9Двойной щелчок средней клавишей мыши во внешней области окна
    WM_MOUSEMOVE200Перемещение курсора мыши во внутренней области окна
    WM_LBUTTONDOWN201Нажата левая клавиша мыши во внутренней области окна
    WM_LBUTTONUP202Отпущена левая клавиша мыши во внутренней области окна
    WM_LBUTTONDBLCLK203Двойной щелчок левой клавишей мыши во внутренней (client) области окна
    WM_RBUTTONDOWN204Нажата правая клавиша мыши во внутренней области окна
    WM_RBUTTONUP205Отпущена правая клавиша мыши во внутренней области окна
    WM_RBUTTONDBLCLK206Двойной щелчок правой клавишей мыши во внутренней области окна
    WM_MBUTTONDOWN207Нажата средняя клавиша мыши во внутренней области окна
    WM_MBUTTONUP208Отпущена средняя клавиша мыши во внутренней области окна
    WM_MBUTTONDBLCLK209Двойной щелчок средней клавишей мыши во внутренней области окна
    Во всех этих сообщениях значение lParam содержит позицию мыши. Младшие 16 разрядов (с 0 по 15) содержат x-координату, старшие 16 разрядов (с 16 по 31) ― y-координату верхнего левого угла клиентской области окна. Параметр wParam содержит информацию о состоянии кнопок мыши и о кнопках клавиатуры Shift и Ctrl.

    Практика ― сестра шизофрении

    Скачайте пример здесь.
    Код (ASM):
    1. include win64a.inc
    2. .code
    3. WinMain proc
    4. local msg:MSG
    5.     xor ebx,ebx
    6.     mov esi,IMAGE_BASE
    7.     mov eax,10027h
    8.     mov edi,offset ClassName
    9.     push rax    ;hIconSm
    10.     push rdi    ;lpszClassName
    11.     push rbx    ;lpszMenuName
    12.     push COLOR_WINDOW+1;hbrBackground
    13.     push 10003h ;hCursor
    14.     push rax    ;hIcon
    15.     push rsi    ;hInstance
    16.     push rbx    ;cbClsExtra & cbWndExtra
    17.     pushaddr WndProc      ;lpfnWndProc
    18.     push sizeof WNDCLASSEX;cbSize & style
    19.     invoke RegisterClassEx,esp    ;addr WNDCLASSEX
    20.     push rbx
    21.     push rsi    ;rsi=400000h
    22.     shl esi,9   ;rsi=CW_USEDEFAULT
    23.     push rbx
    24.     push rbx
    25.     push rsi
    26.     push rsi
    27.     push rsi
    28.     push rsi
    29.     sub esp,20h
    30.     invoke CreateWindowEx,0,edi,edi,WS_OVERLAPPEDWINDOW or WS_VISIBLE
    31.     lea edi,msg
    32. @@: invoke GetMessage,edi,0,0,0
    33.     invoke DispatchMessage,edi
    34.     jmp @b
    35. WinMain endp
    36. WndProc proc hwnd:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD
    37. local ps:PAINTSTRUCT
    38.     mov edi,offset expClick
    39.     mov hwnd,rcx
    40.     cmp edx,WM_DESTROY
    41.     je wmDESTROY
    42.     cmp edx,WM_PAINT
    43.     je wmPAINT
    44.     cmp dx,WM_LBUTTONDOWN
    45.     je wmLBUTTONDOWN
    46.     leave
    47.     jmp DefWindowProc
    48. wmDESTROY:invoke ExitProcess,NULL
    49. wmLBUTTONDOWN:;low order lParam  = x  high order lParam = y
    50.     mov word ptr [rdi+sizeof expClick+POINT.x],r9w    ;mov expHPoint.x,r9w
    51.     shr r9,16
    52.     mov [rdi+sizeof expClick+POINT.y],r9d        ;mov expHPoint.y,r9d
    53.     mov r8b,TRUE
    54.     mov [rdi],r8b                    ;mov expClick,TRUE
    55.     invoke InvalidateRect,,0            ;hWnd,0,TRUE
    56.     jmp  wmBYE
    57. wmPAINT:invoke BeginPaint,,&ps
    58.     cmp byte ptr [rdi],TRUE                ;cmp expClick,TRUE
    59.     jne  wmPAINT_END
    60.     mov dword ptr [rbp-60h],lengthof expTxt
    61.     lea r9d,[rdi+sizeof expClick+sizeof POINT]    ;mov r9,offset expTxt
    62.     mov r8d,[rdi+sizeof expClick+POINT.y]        ;mov r8,expHPoint.y
    63.     mov edx,[rdi+sizeof expClick+POINT.x]        ;mov rdx,expHPoint.x
    64.     invoke TextOut,ps.hdc    ;hdc,expHPoint.x,expHPoint.y,offset expTxt,lengthof expTxt
    65. wmPAINT_END:invoke EndPaint,hwnd,&ps
    66. wmBYE:leave
    67.     retn
    68. WndProc endp
    69. ;---------------------------------------
    70. ClassName db 'Win64 Iczelion''s lesson #7:Mouse Input',0
    71. expClick  db FALSE
    72. expHPoint POINT <0>
    73. expTxt    db 'You clicked here!',0
    74. end

    Разбор полетов

    Код (ASM):
    1. wmLBUTTONDOWN:;low order lParam  = x  high order lParam = y
    2.     mov word ptr [rdi+sizeof expClick+POINT.x],r9w    ;mov expHPoint.x,r9w
    3.     shr r9,16
    4.     mov [rdi+sizeof expClick+POINT.y],r9d        ;mov expHPoint.y,r9d
    5.     mov r8b,TRUE
    6.     mov [rdi],r8b                    ;mov expClick,TRUE
    7.     invoke InvalidateRect,,0            ;hWnd,0,TRUE
    Процедура окна ждет нажатия на левую клавишу мыши. Когда WndProc получает сообщение WM_LBUTTONDOWN, регистр r9=lParam содержит координаты курсора мыши в клиентской области. Координаты выделяются из lParam и сохраняются их в переменной типа POINT, определенной следующим образом:
    Код (ASM):
    1.    POINT STRUCT
    2.     x   dd ?
    3.     y   dd ?
    4.    POINT ENDS
    Затем переменная expClick получает значение TRUE ― это означает, что в клиентской области была нажата левая клавиша мыши для того, чтобы отрисовывающий код в секции WM_PAINT, знал, что было нажатие в клиентской области, и значит поэтому он может нарисовать строку в позиции, где была мышь при нажатии. Затем мы вызываем функцию InvalidateRect, чтобы заставить окно полностью перерисовать клиентскую область.
    Код (ASM):
    1. wmPAINT:invoke BeginPaint,,&ps
    2.     cmp byte ptr [rdi],TRUE                ;cmp expClick,TRUE
    3.     jne  wmPAINT_END
    4.     mov dword ptr [rbp-60h],lengthof expTxt
    5.     lea r9d,[rdi+sizeof expClick+sizeof POINT]    ;mov r9,offset expTxt
    6.     mov r8d,[rdi+sizeof expClick+POINT.y]        ;mov r8,expHPoint.y
    7.     mov edx,[rdi+sizeof expClick+POINT.x]        ;mov rdx,expHPoint.x
    8.     invoke TextOut,ps.hdc    ;hdc,expHPoint.x,expHPoint.y,offset expTxt,lengthof expTxt
    9. wmPAINT_END:invoke EndPaint,hwnd,&ps
    Отрисовывающий код в секции wmPAINT должен проверять, равно ли содержимое переменной expClick TRUE, потому что когда окно создается, процедура окна получает сообщение WM_PAINT в то время, пока не было сделано еще ни одного нажатия, то есть строку отрисовывать нельзя. Содержимое переменной expClick при запуске программы равно FALSE и становится равным TRUE, когда происходит нажатие на левую клавишу мыши. Если, по крайней мере, одно нажатие на мышь произошло, отрисовывается строка «You clicked here!» в клиентской области в позиции, где была мышь при нажатии.
    1 Песня ВИА Гра «Попытка номер 5», текст и музыка Константина Меладзе

    Глава девятая. Братец Кролик продолжает осваивать мышь
    Братца Кролика замучила депрессия до такой степени, что он решил покончить с собой. Но не каким-нибудь там простым образом, вроде отравиться, а самым естественным для кроликов. И он пошел на поиски Братца Лиса.
    По злосчастному стечению обстоятельств, Братец Лис как раз в тот же самый день твердо решил, что он садится на особую тибетскую диету, которая, среди прочего, категорически исключала из рациона крольчатину. Он как раз направлялся на опушку, где росла невероятно полезная для фигуры и блеска шерсти травка, когда ему наперерез бросился Братец Кролик.
    Братец Лис зажмурился, чтоб не видеть сладкого мяса и попятился в чащу. Братец Кролик молча и решительно последовал за ним, след в след. Братец Лис приоткрыл один глаз, застонал и проглотил слюну. Братец Кролик, не сводя с Братца Лиса горящих безумным огнем глаз, расчетливо повернул голову, чтоб удобнее было разглядеть хрупкую шейку. Братец Лис не выдержал и пустился наутек.
    «Фаст-фуд, говорите», ― в истерике думал Братец Лис, спасаясь бегством от озверевшего завтрака, ― «Теперь понятно, какой от него вред организму. Бегом от инфаркта!»
    [​IMG]
    В отличии от восьмой главы, где обрабатывалось событие по нажатию левой клавиши мыши и выводилась единственная надпись «You clicked here!», мы будем обрабатывать нажатие на левую и правую клавиши мыши, одинарные и двойные щелчки и будем выводить надписи «right-click», «left-click», «right-click double» и «left-click double». Этих надписей будет столько, какое значение мы присвоим константе MAXRECTS. Если количество нажатий превысит число MAXRECTS ― будет раздаваться звуковой сигнал.

    Практика ― сестра шизофрении

    Скачайте пример здесь
    Код (ASM):
    1. include win64a.inc
    2. MAXRECTS = 40;the maximum number of processed mouse clicks
    3. .code
    4. WinMain proc
    5. local msg:MSG
    6.  
    7.     xor ebx,ebx
    8.     mov esi,IMAGE_BASE
    9.     mov eax,10027h
    10.     mov edi,offset ClassName
    11.     push rax    ;hIconSm
    12.     push rdi    ;lpszClassName
    13.     push rbx    ;lpszMenuName
    14.     push COLOR_WINDOW+1;hbrBackground
    15.     push 10003h ;hCursor
    16.     push rax    ;hIcon
    17.     push rsi    ;hInstance
    18.     push rbx    ;cbClsExtra & cbWndExtra
    19.     pushaddr WndProc      ;lpfnWndProc
    20.     mov rax,(CS_DBLCLKS shl 32)+sizeof WNDCLASSEX
    21.     push rax    ;cbSize & style
    22.     invoke RegisterClassEx,esp    ;addr WNDCLASSEX
    23.     push rbx
    24.     push rsi    ;rsi=400000h
    25.     shl esi,9   ;rsi=CW_USEDEFAULT
    26.     push rbx
    27.     push rbx
    28.     push rsi
    29.     push rsi
    30.     push rsi
    31.     push rsi
    32.     sub esp,20h
    33.     invoke CreateWindowEx,0,edi,edi,WS_OVERLAPPEDWINDOW or WS_VISIBLE
    34.     lea edi,msg
    35. @@: invoke GetMessage,edi,0,0,0
    36.     invoke DispatchMessage,edi
    37.     jmp @b
    38. WinMain endp
    39.  
    40. WndProc proc hwnd:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD
    41. local ps:PAINTSTRUCT
    42.  
    43.     mov lParam,r9
    44.     mov hwnd,rcx
    45.     xor eax,eax
    46.  
    47.     cmp edx,WM_DESTROY
    48.     je  wmDESTROY
    49.     cmp edx,WM_PAINT
    50.     je  wmPAINT
    51.     cmp dx,WM_LBUTTONDOWN
    52.     je wmLBUTTONDOWN
    53.     cmp dx,WM_RBUTTONDOWN
    54.     je wmRBUTTONDOWN
    55.     cmp dx,WM_LBUTTONDBLCLK
    56.     je wmLBUTTONDBCLK
    57.     cmp dx,WM_RBUTTONDBLCLK
    58.     je wmRBUTTONDBCLK
    59.     leave
    60.     jmp DefWindowProc
    61.  
    62. wmDESTROY:invoke ExitProcess,NULL
    63. wmLBUTTONDBCLK:;low order lParam  = x  high order lParam = y
    64.     mov eax,0C0000000h
    65.     jmp wmRBUTTONDOWN
    66. wmRBUTTONDBCLK:mov eax,80000000h
    67.     jmp wmRBUTTONDOWN
    68. wmLBUTTONDOWN:mov eax,40000000h
    69. wmRBUTTONDOWN:add eax,r9d;lParam
    70.     cmp nextRect,MAXRECTS-1
    71.     jge @f
    72.     inc nextRect
    73.     mov edx,nextRect
    74.     mov [rdx*4+recs],eax
    75.     mov r8b,TRUE
    76.     invoke InvalidateRect,,FALSE    ;перерисовать часть окна
    77.     jmp wmBYE
    78. @@: invoke MessageBeep,0
    79.     jmp  wmBYE
    80. wmPAINT:mov ebx,nextRect
    81.     inc ebx            ;cmp nextRect,-1
    82.     jz wmBYE
    83.     invoke BeginPaint,,&ps
    84.     invoke SetBkMode,eax,TRANSPARENT
    85. @@: mov eax,[rbx*4+recs-4]
    86.     xor ecx,ecx
    87.     shld ecx,eax,2
    88.     inc ecx
    89.     shl ecx,4
    90.     movzx edx,ax    ;edx равно младшим 16 битам lParam (координата X)
    91.     shl eax,2       ;удаляем метку "левый/правый клик" и "двойной/одинарный"
    92.     shr eax,18
    93.     mov r8d,eax    ;r8 равно старшим 16 битам lParam (координата X)
    94.     mov rax,[PS+rcx]    ;в rax длина текста
    95.     mov r9,[PS+rcx+8]    ;в r9 указатель на строку
    96.     invoke TextOut,ps.hdc,,,,eax
    97.     dec  ebx
    98.     jnz @b
    99. wmPAINT_END:invoke EndPaint,hwnd,&ps
    100. wmBYE:leave
    101.     retn
    102. WndProc endp
    103. ;---------------------------------------
    104. ClassName db "Win64 Iczelion's lesson #7a: Mouse Input",0
    105. text1     db "right-click"
    106. text2     db "left-click"
    107. text3     db "right-click double"
    108. text4     db "left-click double"
    109. PS        dq 0,0,lengthof text1, text1, lengthof text2, text2,lengthof text3, text3, lengthof text4, text4
    110. recs      dd MAXRECTS dup(?)
    111. nextRect  dd -1
    112. end

    Разбор полетов

    MAXRECTS - константа, значение которой определяет максимальное количество обрабатываемых кликов мыши, которые пользователь может разместить в окне. Если вам захочется обрабатывать больше кликов, достаточно увеличить значение MAXRECTS. В массиве recs хранятся координаты всех прямоугольников. Переменная nextRect используется и как счетчик прямоугольников, и как индекс в массиве recs.
    Когда пользователь нажимает на левую кнопку мыши при нахождении курсора над окном приложению посылается сообщение WM_LBUTTONDOWN, когда на правую - RBUTTONDOWN. При двойных щелчках WM_RBUTTONDOWN и WM_LBUTTONDBLCLK. При обработке сообщений WM_LBUTTONDOWN, RBUTTONDOWN, WM_RBUTTONDOWN и WM_LBUTTONDBLCLK параметр lParam процедуры окна WndProc содержит координаты X и Y курсора мыши в момент щелчка. Координата X хранится в 16 младших битах lParam, а координата Y ― в 16 старших битах. Параметр wParam определяет, какие виртуальные клавиши были нажаты в момент щелчка. Его значение может состоять из любого сочетания констант MK_CONTROL, MK_MBUTTON, MK_RBUTTON и MK_SHIFT, представляющих клавишу CONTROL, среднюю клавишу мыши и клавишу SHIFT соответственно.
    Когда приложение получило сообщение WM_LBUTTONDOWN, RBUTTONDOWN, WM_RBUTTONDOWN или WM_LBUTTONDBLCLK оно должно нарисовать прямоугольник с текстом «right-click», «left-click», «right-click double» или «left-click double» в месте щелчка.
    Структурный тип RECT содержит координаты левой, верхней, правой и нижней сторон прямоугольника. Если пользователь не вывел на экран предельное количество прямоугольников программа увеличит значение счетчика прямоугольников
    Код (ASM):
    1. inc nextRect
    2. mov edx,nextRect
    Затем координаты X, Y курсора мыши вместе с меткой правая или левая кнопка и двойной или одинарный щелчок клавиши мыши копируются в массив recs
    Код (ASM):
    1. wmLBUTTONDBCLK:;low order lParam  = x  high order lParam = y
    2.     mov eax,0C0000000h
    3.     jmp wmRBUTTONDOWN
    4. wmRBUTTONDBCLK:mov eax,80000000h
    5.     jmp wmRBUTTONDOWN
    6. wmLBUTTONDOWN:mov eax,40000000h
    7. wmRBUTTONDOWN:add eax,r9d;перед получением сообщения WM_RBUTTONDOWN eax равно 0
    8.     . . .
    9.     mov [rdx*4+recs],eax
    10.     mov r8b,TRUE
    11.     invoke InvalidateRect,,FALSE    ;перерисовать часть окна
    Вызов функции InvalidateRect приводит к тому, что окну посылается сообщение WM_PAINT. Функция InvalidateRect получает при вызове три аргумента: логический номер окна, адрес структуры RECT и логическое значение, которое указывает, должен ли перерисовываться фон окна.
    Затем программа использует координаты курсора мыши для определения той минимальной прямоугольной области окна, которую необходимо перерисовать для отображения происшедших изменений
    Код (ASM):
    1.     mov eax,[rbx*4+recs-4]
    2.     xor ecx,ecx
    3.     shld ecx,eax,2  ;два старших бита из eax в ecx
    4.     inc ecx         ;учитываем пустую строчку при старте программы
    5.     shl ecx,4       ;умножаем содержимое есх на 16
    6.     movzx edx,ax    ;edx равно младшим 16 битам lParam (координата X)
    7.     shl eax,2       ;удаляем метку "левый/правый клик" и "двойной/одинарный"
    8.     shr eax,18
    9.     mov r8d,eax    ;r8 равно старшим 16 битам lParam (координата X)
    10.     mov rax,[PS+rcx]    ;в rax длина текста
    11.     mov r9,[PS+rcx+8]    ;в r9 указатель на строку
    12.     invoke TextOut,ps.hdc,,,,eax
    Обработка сообщения WM_PAINT начинается с проверки того, имеются ли прямоугольники, которые необходимо нарисовать
    Код (ASM):
    1. wmPAINT: mov ebx,nextRect
    2.     inc ebx;cmp nextRect,-1
    3.     jz wmBYE;если массив координат пуст, тогда ничего не делаем
    4.     . . .
    5. wmBYE:    leave
    6.     ret
    Если массив координат recs не пуст, тогда вызывается функция BeginPaint для заполнения структуры PAINTSTRUCT и получения hDC
    Код (ASM):
    1.     lea edx,ps
    2.     invoke BeginPaint
    3.     invoke SetBkMode,eax,TRANSPARENT
    Однако на этот раз поле rcPaint структуры PAINTSTRUCT содержит прямоугольник, переданный нами при вызове InvalidateRect. Он представляет собой минимальную часть окна подлежащую перерисовке. При использовании hDC, возвращаемого функцией BeginPaint, Windows не будет ничего рисовать за пределами этого прямоугольника, который называется областью отсечения (clipping region) ― это позволяет ускорить обновление окна. После вызова BeginPaint функция SetBkMode устанавливает для надписей прозрачный фон, далее по значению в 31-ом и 30-ом бите расшифровывается какая надпись и какой длины будет выведена функцией TextOut на экран и какие координаты будут у этой надписи и далее в цикле от nextRect до 0 выводим прямоугольники на экран.
    Код (ASM):
    1. wmPAINT: mov ebx,nextRect
    2.     inc ebx         ;cmp nextRect,-1
    3.     . . .
    4. @@:    mov eax,[rbx*4+recs-4];-4 компенсирует увеличение rbx на 1
    5.     xor ecx,ecx
    6.     shld ecx,eax,2
    7.     inc ecx
    8.     shl ecx,4
    9.     movzx edx,ax    ;edx равно младшим 16 битам lParam (координата X)
    10.     shl eax,2       ;удаляем метку "левый/правый клик" и "двойной/одинарный"
    11.     shr eax,18
    12.     mov r8d,eax    ;r8 равно старшим 16 битам lParam (координата X)
    13.     mov rax,[PS+rcx]    ;в rax длина текста
    14.     mov r9,[PS+rcx+8]    ;в r9 указатель на строку
    15.     invoke TextOut,ps.hdc,,,,eax
    16.     dec  ebx
    17.     jnz @b
    © Mikl___ 2019
     

    Вложения:

    • tut_09.zip
      Размер файла:
      3,7 КБ
      Просмотров:
      302
    rococo795 нравится это.
  5. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.993

    Глава десятая. "Липкая" надпись


    [​IMG]
    Скачайте пример здесь
    Код (ASM):
    1. include win64a.inc
    2. .code
    3. WinMain proc
    4. local msg:MSG
    5.  
    6.     xor ebx,ebx
    7.     mov esi,IMAGE_BASE
    8.     mov eax,10027h
    9.     mov edi,offset ClassName
    10.  
    11.     push rax    ;hIconSm
    12.     push rdi    ;lpszClassName
    13.     push rbx    ;lpszMenuName
    14.     push COLOR_WINDOW+1;hbrBackground
    15.     push 10003h ;hCursor
    16.     push rax    ;hIcon
    17.     push rsi    ;hInstance
    18.     push rbx    ;cbClsExtra & cbWndExtra
    19.     pushaddr WndProc      ;lpfnWndProc
    20.     push sizeof WNDCLASSEX;cbSize & style
    21.     invoke RegisterClassEx,esp    ;addr WNDCLASSEX  
    22.     push rbx
    23.     push rsi    ;rsi=400000h
    24.     shl esi,9   ;rsi=CW_USEDEFAULT
    25.     push rbx
    26.     push rbx
    27.     push rsi
    28.     push rsi
    29.     push rsi
    30.     push rsi
    31.     sub esp,20h
    32.     invoke CreateWindowEx,0,edi,edi,WS_OVERLAPPEDWINDOW or WS_VISIBLE
    33.  
    34.     lea edi,msg
    35. @@: invoke GetMessage,edi,0,0,0
    36.     invoke DispatchMessage,edi
    37.     jmp @b
    38. WinMain endp
    39. WndProc proc hwnd:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD
    40. local ps:PAINTSTRUCT
    41.  
    42.     mov hwnd,rcx
    43.     mov edi,offset expHPoint
    44.  
    45.     cmp edx,WM_DESTROY
    46.     je wmDESTROY
    47.     cmp edx,WM_PAINT
    48.     je wmPAINT
    49.     cmp dx,WM_MOUSEMOVE
    50.     je wmMOUSEMOVE
    51.     leave
    52.     jmp DefWindowProc
    53.  
    54. wmDESTROY:invoke ExitProcess,NULL
    55. wmMOUSEMOVE:;low order lParam  = x    high order lParam = y
    56.     mov word ptr [rdi+POINT.x],r9w    ;mov expHPoint.x,r9w
    57.     shr r9,16
    58.     mov [rdi+POINT.y],r9d        ;mov expHPoint.y,r9d
    59.     mov r8b,TRUE
    60.     invoke InvalidateRect,,0;,TRUE
    61.     jmp  wmBYE
    62. wmPAINT:invoke BeginPaint,,&ps
    63.     mov dword ptr [rbp-60h],lengthof expTxt
    64.     lea r9d,[rdi+sizeof POINT]    ;mov r9d,offset expTxt
    65.     mov r8d,[rdi+POINT.y]        ;mov r8d,expHPoint.y
    66.     mov edx,[rdi+POINT.x]        ;mov edx,expHPoint.x            
    67.     invoke TextOut,ps.hdc
    68.     invoke EndPaint,hwnd,&ps
    69. wmBYE:leave
    70.     retn
    71. WndProc endp
    72. ;---------------------------------------
    73. ClassName db "Win64 Iczelion's lesson #7e: липкая надпись",0
    74. expHPoint POINT <0>
    75. expTxt    db "Win64 assembly is great and easy",0
    76. end
    © Mikl___ 2016
     

    Вложения:

    • tut_10.zip
      Размер файла:
      3,1 КБ
      Просмотров:
      542
    Последнее редактирование: 5 янв 2017
  6. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.993

    Глава одиннадцатая. Братец Кролик изучает иконки и курсоры


    [​IMG]

    Определение

    Курсoр
    ― элемент графического интерфейса, который указывает на объект, с которым будет производиться взаимодействие с помощью клавиатуры, мыши или другого устройства управления. Курсор может иметь любую форму. Основной его частью является «активный пиксель» («горячее пятно» ― hotspot) ― точка на экране, в которой расположен элемент, через который происходит взаимодействие пользователя и программы. Большинство курсоров имеют форму, указывающую на расположение этой точки:
    • у курсоров-«стрелок» hotspot расположен на острие стрелки ([​IMG]);
    • у курсоров-«перекрестий» ― в центре ([​IMG]);
    • если же курсор не предполагает взаимодействия с объектом на экране, например, курсор-«ожидание», тогда положение hotspot в иконке не имеет значения ([​IMG]).
    В Windows курсоры хранятся в файлах с расширениями CUR («статичные» курсоры) и ANI («анимированные» курсоры). Большинство курсоров представляют собой изображения размером 32×32 пикселя, и могут иметь несколько цветовых вариаций для различной глубины цвета, установленной в системе (True Color, High Color, 256 цветов, 16 цветов, монохромный). Начиная с Windows XP курсоры мыши поддерживают режим 32bpp (bits-per-pixel), с указанием альфа-канала для каждой точки. Графические программы для рисования используют собственные курсоры для отражения различных действий программы (курсоры в виде «кистей», «карандашей», «ластиков», «пипеток» и тому подобное).
    [​IMG]
    Иконка ― элемент графического интерфейса, небольшая картинка, представляющая приложение, файл, каталог, окно, компонент операционной системы, устройство и тому подобное. В ответ на щелчок, совершенный мышью или другим указательным устройством ввода на иконке, обычно выполняется соответствующее действие (запуск приложения, открытие файла и так далее).
    Windows выводит на экран пользовательские иконки в:
    1. левом верхнем углу строки заголовка окна приложения
    2. списках программ меню Start
    3. панели задач в нижней части экрана
    4. списке программы Windows Explorer
    В Windows используются иконки квадратного формата со стороной: 16, 24, 32, 40, 48, 60, 72, 92, 108, 128 или 256 пикселов.
    Обычно файл иконки содержит в себе несколько отдельных изображений различных размеров и с различным количеством используемых цветов. Это связано с тем, что при автоматизированном уменьшении растрового изображения оно теряет резкость, а при увеличении — детализацию.
    [​IMG]
    Многие среды и приложения задают «иконки по умолчанию». Иконка для приложения выбирается стандартной, для файла — в зависимости от типа файла (часто это иконка приложения, обрабатывающего этот файл «по-умолчанию»). Иконки для графических файлов получаются из содержимого самого файла (уменьшенная копия изображения, «thumbnail»). Не все иконки статичны. Иконка, представляющая связь с Интернетом, показывает идет ли передача данных, иконка диспетчера задач ― загрузку процессора и так далее.
    В Windows иконки хранятся в ICO-файлах. Один ICO-файл содержит одну или несколько иконок, размер и цветность каждой иконки задается отдельно.
    ICO-формат поддерживает внедрение изображений в формате JPEG и PNG, но обычно данные иконок хранятся в несжатом виде.
    Для цветопередачи пикселов иконок используют:
    1. True Color (глубина цвета равна 32 бита), для каждого пиксела изображения используется:
      • 8 бит для представления красной
      • 8 ― синей
      • 8 бит ― зеленой составляющей
      (28 = 256 возможных значения). Таким образом получаются 256 x 256 x 256 = 224 = 16777216 цветовых оттенков. Также может использоваться (а может и не использоваться :)) 8-битный альфа-канал, позволяющий реализовать 256 уровней частичной прозрачности. С помощью альфа-канала можно отображать иконки со сглаженными (размытыми) краями и тенью, сочетающимися с любым фоном; маска в этом случае игнорируется.
    2. High Color (глубина цвета 16 бит), для каждого пиксела изображения используется:
      • 5 бит для представления красной составляющей (25 = 32 возможных значения)
      • 5 ― синей
      • 6 бит (26 = 64 возможных значения) для представления зеленой, так как человеческий глаз более чувствителен к зеленой составляющей
      Таким образом получаются 32 x 64 x 32 = 216 = 65536 цветовых оттенков.
    3. цвет с фиксированной палитрой (из 256, 16, или 2 цветов), число, соответствующее каждому пикселу указывает не на цвет, а на номер цвета в палитре.
    По своей структуре изображения в файле ICO и CUR наиболее близки к BMP, но принципиально отличаются от них наличием дополнительного изображения ― маски, накладываемой на задний план при помощи операции «побитового AND», что позволяет реализовать (полную) прозрачность рисунка. Последующее наложение основного изображения с помощью операции «XOR» может дать «инверсные» пиксели в тех местах, где задний план не был замаскирован.

    Структура ICO и CUR-форматов


    Иконки и курсоры создаются с помощью графического редактора и сохраняются в файлах с расширением ICO и CUR соответственно. ICO-формат аналогичен CUR-формату, предназначенному для хранения курсоров. Отличие состоит в численном значении поля type в заголовочной структуре, и интерпретации значений полей planes и bpp.
    ICO/CUR-файл состоит из
    1. заголовка
    2. каталога информации об изображениях
    3. непосредственно изображений

    Заголовок


    Размер заголовка 6 байт:

    ПолеТипОписание
    reservedWORDЗарезервировано. Всегда 0.
    typeWORDТип файла:
    • 1 для иконок
    • 2 для курсоров
    Иные значения недопустимы
    countWORDКоличество изображений в файле, минимум 1.

    Каталог информации об изображениях


    Представляет собой последовательные записи фиксированного размера (16 байт), следующие одна за другой. Количество записей определяется полем count заголовка.
    ПолеТипОписание
    widthBYTEШирина изображения в точках. Принимает значения от 0 до 255. Если 0, тогда ширина изображения 256 точек.
    heightBYTEВысота изображения в точках. Принимает значения от 0 до 255. Если 0, тогда высота изображения 256 точек.
    colorsBYTEКоличество цветов в палитре изображения. Для полноцветных иконок должно быть 0.
    reservedBYTEЗарезервировано. Всегда должно быть 0, однако иконки, которые создаются встроенными средствами .NET (System.Drawing.Icon.Save) содержат в этом поле значение 255.
    planesWORD
    • В ICO количество плоскостей. Может быть 0 или 1.
    • В CUR горизонтальная координата «горячей точки» в пикселях относительно левого края изображения.
    bppWORD
    • В ICO количество битов на пиксель (bits-per-pixel). Может быть 0, так как вычисляется на основе других данных; например, если изображение не хранится в формате PNG, тогда количество битов на пиксель рассчитывается на основе информации о размере растра, а также его ширине и высоте. Если изображение хранится в формате PNG, то соответствующая информация хранится в самом PNG. Указывать в этом поле 0 не рекомендуется, так как логика выбора наилучшего изображения в различных версиях Windows неизвестна.
    • В CUR вертикальная координата «горячей точки» в пикселях относительно верхнего края изображения.
    sizeDWORDРазмер растра в байтах
    offsetDWORDАбсолютное смещение растра в файле.
    Иконки и курсоры ― это виды ресурсов (resources) Windows. Ресурсы являются данными, хранятся в EXE-файле, но расположены не в сегменте данных, а в сегменте ресурсов. К ресурсам нет непосредственного доступа через переменные. Они должны быть загружены из EXE-файла в память. Когда Windows загружает в память код и данные для выполнения программы, ресурсы остаются на диске. Когда Windows нужен конкретный ресурс, его загружают в память.
    Иконки и курсоры добавляются в RC-файл (файл ресурсов) с помощью операторов ICON и CURSOR
    <Имя_иконки> ICON <Имя_файла>
    <Имя_курсора> CURSOR <Имя_файла>
    Имя_курсора и Имя_иконки ― имена, индентифицирующие иконку и курсор, используются для обращения к этим ресурсам. Загрузить иконку или курсор в приложени можно либо по имени, либо по идентификатору. Если Вы используете не предопределенные системой курсоры или иконки, тогда их требуется загрузить до регистрации окна функциями LoadIcon и LoadCursor и запомнить дескриптор курсора и иконки в соответствующих полях структуры WNDCLASSEX
    Синтаксис
     
    Последнее редактирование: 24 мар 2019
  7. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.993
    Код (C):
    1. HICON WINAPI LoadIcon(
    2.   _In_opt_ HINSTANCE hInstance,/*дескриптор модуля, в ресурсы которого загружена
    3. иконка. Если этот параметр равен нулю, тогда загружается системная иконка*/
    4.   _In_     LPCTSTR   lpIconName /*строка с именем загружаемой из ресурсов иконки.
    5. Иногда, этот параметр может содержать идентификатор ресурса*/
    6. );
    Синтаксис
    Код (C):
    1. HCURSOR WINAPI LoadCursor(
    2.   _In_opt_ HINSTANCE hInstance,/*дескриптор модуля, в ресурсы которого загружен
    3. курсор. Если этот параметр равен нулю, тогда загружается системный курсор*/
    4.   _In_     LPCTSTR   lpCursorName /*строка с именем загружаемого
    5. из ресурсов курсора. Иногда, этот параметр может содержать идентификатор ресурса*/
    6. );
    Код (ASM):
    1. .data
    2. MyIcon        db "MY_ICON",0
    3. MySmIcon    db "MY_SMALL_ICON",0
    4. MyCursor    db "MY_CURSOR",0
    5.     ...
    6. local wc:WNDCLASSEX
    7.     ...
    8.     mov edx,offset MyIcon
    9.     invoke LoadIcon,400000h
    10.     mov wc.hIcon,rax    ;загрузка иконки
    11.         mov edx,offset MySmIcon
    12.     invoke LoadIcon,400000h
    13.     mov wc.hIconSm,rax  ;загрузка малой иконки
    14.     mov edx,offset MyCuror
    15.     invoke LoadCuror,400000h
    16.     mov wc.hCuror,rax   ;загрузка курсора
    где 400000h ― дескриптор нашей программы
    Можно при вызовах функции LoadIcon для загрузки стандартной и малой иконок сослаться на одну и ту же иконку стандартного размера, а Windows при выводе малой иконки приведет иконку стандартного размера к необходимому.
    Если в дальнейшем вы захотите изменить иконку, это можно сделать с помощью функции SetClassLong. Предположим, что у вас в описании ресурсов есть вторая иконка:
    Код (C):
    1.  SecondIcon ICON icon2.ico
    Следующий фрагмент программы заменяет иконку MyIcon иконкой SecondIcon:
    Код (ASM):
    1.     mov edx,offset SecondIcon
    2.     invoke LoadIcon,400000h
    3.     invoke SetClassLong, hwnd, GCL_HICON, rax
    Малую иконку можно заменить с помощью GCL_HICONSM.

    Создание пользовательских курсора и иконки из CUR-файла без использования компилятора ресурсов

    Скачайте пример здесь
    [​IMG]

    В качестве курсора и иконки используем иконку из файла Cursor.cur. Убеждаемся, что разницы между курсором и иконкой нет.
    Код (ASM):
    1. ; GUI #
    2. include win64a.inc
    3. .code
    4. WinMain proc
    5. local msg:MSG
    6.  
    7.     xor ebx,ebx
    8.     mov esi,IMAGE_BASE
    9.     mov edi,offset ClassName
    10.     mov ecx,offset FileName
    11.     invoke LoadCursorFromFile
    12.     push rax    ;hIconSm
    13.     push rdi    ;lpszClassName
    14.     push rbx    ;lpszMenuName
    15.     push COLOR_WINDOWTEXT;hbrBackground
    16.     push rax    ;hCursor
    17.     push rax        ;hIcon
    18.     push rsi    ;hInstance
    19.     push rbx        ;cbClsExtra & cbWndExtra
    20.     db 68h
    21.     dd WndProc      ;lpfnWndProc
    22.     push sizeof WNDCLASSEX;cbSize & style
    23.     invoke RegisterClassEx,esp    ;addr WNDCLASSEX
    24.     push rbx
    25.     push rsi    ;rsi=400000h
    26.     shl esi,9    ;rsi=CW_USEDEFAULT
    27.     push rbx
    28.      push rbx
    29.     push rsi
    30.     push rsi
    31.     push rsi
    32.     push rsi
    33.     sub esp,20h
    34.         invoke CreateWindowEx,0,edi,edi,WS_OVERLAPPEDWINDOW or WS_VISIBLE
    35.     lea edi,msg
    36. @@:    invoke GetMessage,edi,NULL,0,0
    37.     invoke DispatchMessage,edi
    38.     jmp @b
    39. WinMain endp
    40. WndProc:cmp edx,WM_DESTROY
    41.     je wmDESTROY
    42.       jmp DefWindowProc
    43. wmDESTROY: invoke ExitProcess,NULL
    44. ;-----------------------------------
    45. ClassName db "Win64 Iczelion's lesson #7-1:Курсор и иконка из файла *.cur",0
    46. FileName db "Images\Cursor.cur",0
    47. end

    Создание пользовательских курсора и иконки из CUR-файла
    с использованием компилятора ресурсов

    Добавляем курсор и иконку из файла Cursor.cur в секцию ресурсов. Для этого создаем файл tut_07b.rc со следующим содержанием
    Код (C):
    1. #define ID_CURSOR 18
    2. ID_CURSOR CURSOR "Images\\cursor.cur"
    в очередной раз вносим изменения в файл asm2.bat
    Код (Text):
    1. cls
    2. set masm64_path=\masm64
    3. set filename=%1
    4. if exist %1.exe del %1.exe
    5. %masm64_path%\bin\ml64 /Cp /c /I"%masm64_path%\Include" %filename%.asm || exit
    6. if exist %1.rc ( <-- если существует rc-файл с таким же именем, как и asm-файл тогда
    7. %masm64_path%\bin\RC /r  %filename%.rc || exit
    8. %masm64_path%\bin\link /SUBSYSTEM:WINDOWS /LIBPATH:"%masm64_path%\Lib" ^
    9. /entry:WinMain %filename%.obj %filename%.res /LARGEADDRESSAWARE:NO ^
    10. /ALIGN:16 /SECTION:.text,W ^
    11. /BASE:0x400000 /STUB:%masm64_path%\bin\stubby.exe || exit
    12. del %filename%.res
    13. ) else (    <-- иначе
    14. %masm64_path%\bin\link /SUBSYSTEM:WINDOWS /LIBPATH:"%masm64_path%\Lib" ^
    15. /entry:WinMain %filename%.obj /LARGEADDRESSAWARE:NO ^
    16. /ALIGN:16 /SECTION:.text,W ^
    17. /BASE:0x400000 /STUB:%masm64_path%\bin\stubby.exe || exit
    18. )
    19. if exist %1.res del %1.res
    20. del %filename%.obj
    содержимое tut_07b.asm
    Код (ASM):
    1. ; GUI #
    2. include win64a.inc
    3. ID_CURSOR     equ 18
    4. .code
    5. WinMain proc
    6. local msg:MSG
    7.  
    8.     xor ebx,ebx
    9.     mov esi,IMAGE_BASE
    10.     mov edi,offset ClassName
    11.     invoke LoadCursor,esi,ID_CURSOR
    12.     push rax    ;hIconSm
    13.     push rdi    ;lpszClassName
    14.     push rbx    ;lpszMenuName
    15.     push COLOR_WINDOWTEXT;hbrBackground
    16.     push rax    ;hCursor
    17.     push rax    ;hIcon
    18.     push rsi    ;hInstance
    19.     push rbx        ;cbClsExtra & cbWndExtra
    20.     db 68h
    21.     dd WndProc    ;lpfnWndProc
    22.     push sizeof WNDCLASSEX;cbSize & style
    23.     invoke RegisterClassEx,esp    ;addr WNDCLASSEX
    24.     push rbx
    25.     push rsi    ;rsi=400000h
    26.     shl esi,9    ;rsi=CW_USEDEFAULT
    27.     push rbx
    28.      push rbx
    29.     push rsi
    30.     push rsi
    31.     push rsi
    32.     push rsi
    33.     sub esp,20h
    34.         invoke CreateWindowEx,0,edi,edi,WS_OVERLAPPEDWINDOW or WS_VISIBLE
    35.         lea edi,msg
    36. @@:    invoke GetMessage,edi,NULL,0,0
    37.     invoke DispatchMessage,edi
    38.     jmp @b
    39. WinMain endp
    40. WndProc:cmp edx,WM_DESTROY
    41.     je wmDESTROY
    42.     jmp DefWindowProc
    43. wmDESTROY: invoke ExitProcess,NULL
    44. ;-----------------------------------
    45. ClassName db "Win64 Iczelion's lesson #7-2:Курсор и иконка из ресурсов",0
    46. end

    Создание курсора и иконки из бинарных данных

    В секцию данных добавим рисунок из файла Cursor.cur, воспользовавшись программой bintodb.exe из \masm32\tools\bin2db, которая превратит рисунок в текстовый файл, состоящий из DB-наборов. При помощи функции CreateIconFromResource получаем указатель на иконку, и, передав его DrawIcon, выводим рисунок из Cursor.cur на клиентскую область окна.
    Функция CreateIconFromResource создает иконку или курсор из байтов ресурса.
    Синтаксис
    Код (C):
    1. HICON CreateIconFromResource
    2. (
    3.     PBYTE presbits,    // указатель на буфер, содержащий ресурс иконки или курсора
    4.     QWORD dwResSize,// размер в байтах
    5.     BOOL fIcon,    /* флажок иконки или курсора. Если этот параметр TRUE,
    6. тогда должна быть создана иконка. Если FALSE, должен быть создан курсор.*/
    7.     QWORD dwVer    // версия формата Windows
    8. );
    номер версии формата иконки или курсора для байтов ресурса, может быть одним из следующих значений:
    ФорматdwVer
    Windows 2.x20000h
    Windows 3.x и старше30000h
    Функция DrawIcon рисует иконку в рабочей области окна заданным контекстом устройства.
    Синтаксис
    Код (C):
    1. BOOL DrawIcon
    2. (       HDC hDC,// дескриптор контекста устройства
    3.     int X,    // x-координата верхнего левого угла
    4.     int Y,    // y- координата верхнего левого угла
    5.     HICON hIcon// дескриптор иконы, которую надо нарисовать
    6. );
    Примеp:
     

    Вложения:

    • tut_11.zip
      Размер файла:
      6,2 КБ
      Просмотров:
      280
    Последнее редактирование: 5 янв 2017
  8. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.993
    Код (ASM):
    1. ; GUI #
    2. include win64a.inc
    3. ICON_SIZE = 744  ;общий размер файла Cursor.cur =766 байт (заголовок=22 картинка=744)
    4. .code
    5. WinMain proc
    6. local msg:MSG
    7.     xor ebx,ebx
    8.     mov ecx,offset ptIcon
    9.     invoke CreateIconFromResource,,ICON_SIZE,-1,30000h
    10.     mov hIcon,rax
    11.     push rax    ;hIconSm
    12.     mov edi,offset ClassName
    13.     push rdi    ;lpszClassName
    14.     push rbx    ;lpszMenuName
    15.     push COLOR_WINDOW;hbrBackground
    16.     push rax    ;hCursor
    17.     push rax        ;hIcon
    18.     mov esi,IMAGE_BASE
    19.     push rsi    ;hInstance
    20.     push rbx        ;cbClsExtra & cbWndExtra
    21.     db 68h
    22.     dd WndProc    ;lpfnWndProc
    23.     push sizeof WNDCLASSEX;cbSize & style
    24.     invoke RegisterClassEx,rsp    ;addr WNDCLASSEX
    25.  
    26.     push rbx
    27.     push rsi    ;rsi=400000h
    28.     shl esi,9    ;rsi=CW_USEDEFAULT
    29.     push rbx
    30.     push rbx
    31.     push rsi
    32.     push rsi
    33.     push rsi
    34.     push rsi
    35.     sub esp,20h
    36.         invoke CreateWindowEx,0,edi,edi,WS_OVERLAPPEDWINDOW or WS_VISIBLE
    37.         lea edi,msg
    38. @@:    invoke GetMessage,edi,0,0,0
    39.     invoke DispatchMessage,edi
    40.     jmp @b
    41. WinMain endp
    42. WndProc proc hWnd:HWND
    43.  
    44. local ps:PAINTSTRUCT
    45.     mov hWnd,rcx
    46.  
    47.         cmp  edx,WM_DESTROY
    48.         je   wmDESTROY
    49.     cmp  edx,WM_PAINT
    50.         je   wmPAINT
    51.     leave
    52.         jmp DefWindowProc
    53. wmDESTROY:invoke ExitProcess,NULL
    54. wmPAINT:lea edx,ps
    55.     invoke BeginPaint
    56.     invoke DrawIcon,eax,134,68,hIcon
    57.     lea edx,ps
    58.     invoke EndPaint,hWnd
    59. wmBYE:leave
    60.     retn
    61. WndProc endp
    62. ;---------------------------------------
    63. ClassName    db "Win64 Iczelion's lesson #7-3: Создание курсора и иконки из бинарных данных",0
    64. hIcon           dq ?
    65. ptIcon:;изображение из файла Cursor.cur
    66. ;пропускаем 22 байта заголовка
    67. db 40,0,0,0,32,0,0,0,64,0,0,0,1,0,4,31 dup(0)
    68. db 128,0,0,128,0,0,0,128,128,0,128,0
    69. db 0,0,128,0,128,0,128,128,0,0,192,192,192,0,128,128
    70. db 128,0,0,0,255,0,0,255,0,0,0,255,255,0,255,0
    71. db 0,0,255,0,255,0,255,255,0,0,255,255,255,0,0,10
    72. db 5 dup(170),160,10 dup(0),3 dup(170),160,12 dup(0)
    73. db 10,170,0,10,4 dup(170),0,128,8 dup(0)
    74. db 10,6 dup(170),168,6 dup(0)
    75. db 8,10,170,160,0,0,0,10,170,170,7 dup(0)
    76. db 170,170,1,16,5 dup(170),168,5 dup(0)
    77. db 10,170,160,17,10,4 dup(170),0,0,0,128,0,0,0
    78. db 74,170,160,16,8 dup(170),160,0,8,0
    79. db 0,170,160,10,9 dup(170),0,128,10
    80. db 3 dup(170),10,170,160,8,6 dup(170),168,0,170
    81. db 170,170,160,0,170,138,160,136,160,4 dup(170),160,10,170
    82. db 170,74,170,170,168,170,15,0,0,10,170,170,170,168,10,170
    83. db 164,10,170,170,10,160,255,0,15,0,10,170,170,0,10,170
    84. db 64,10,160,168,10,160,255,240,15,0,0,0,0,0,10,160
    85. db 0,170,160,8,10,160,4 dup(255),10,0,0,0,0,170
    86. db 170,170,0,128,10,160,255,255,15,255,10,0,0,0,7,10
    87. db 170,160,8,248,10,170,15,240,15,240,170,0,0,0,15,112
    88. db 0,15,255,255,0,170,160,10,168,10,160,128,0,0,15,5 dup(255)
    89. db 128,170,170,170,138,170,8,0,0,0,7,5 dup(255)
    90. db 248,10,170,160,96,0,0,0,0,0,0,6 dup(255)
    91. db 128,0,15,255,247,112,0,0,0,0,9 dup(255)
    92. db 119,119,128,0,128,0,0,6 dup(255)
    93. db 127,136,136,128,8,255,255,248,0,8,127
    94. db 5 dup(255),247,112,8,4 dup(255),240,0,0,15
    95. db 5 dup(255),248,143,5 dup(255),240,0,0,135
    96. db 12 dup(255),248,0,0,0,12 dup(255),0,0,0,0
    97. db 7,10 dup(255),240,5 dup(0),135,8 dup(255),247,7 dup(0)
    98. db 7,6 dup(255),247,8,8 dup(0)
    99. db 8,127,3 dup(255),247,8,10 dup(0)
    100. db 128,0,0,0,8,5 dup(0),192,0
    101. db 255,255,224,0,15,255,240,0,1,255,248,0,0,255,248,0
    102. db 0,127,248,0,0,63,240,0,0,7,224,0,0,3,128,0
    103. db 0,1,15 dup(0),1,0,0,0,3,4 dup(0,0,0,31)
    104. db 0,0,0,63,0,0,0,127,128,0
    105. db 0,63,128,0,0,7,128,0,0,3,128,0,0,3,192,0
    106. db 0,3,192,0,0,3,224,0,0,7,240,0,0,15,248,0
    107. db 0,31,254,0,0,63,255,128,0,255,255,240,3,255
    108. end

    Использование альтернативных курсоров

    Если вы используете дочерние окна, можно сделать так, чтобы курсор выглядел по-разному в разных окнах. Если в вашей программе определяются классы этих дочерних окон, то для каждого класса вы можете использовать свой курсор путем соответствующей установки поля hCursor в каждом классе окна. А если вы используете предопределенные дочерние элементы управления, то изменить поле hCursor класса окна можно с помощью функции:
    Код (ASM):
    1.     mov edx,offset childcursor
    2.     invoke LoadCursor,400000h
    3.     invoke SetClassLong,hwndChild,GCL_HCURSOR,rax
    Если вы разделяете рабочую область окна вашей программы на маленькие логические области без использования дочерних окон, то для изменения курсора мыши вы можете использовать функцию SetCursor:
    Код (ASM):
    1.     invoke SetCursor,hCursor
    Функцию SetCursor следует вызывать при обработке сообщения WM_MOUSEMOVE. В противном случае для перерисовки курсора при его движении Windows использует курсор, ранее заданный в классе окна.

    Загрузка стандартных иконок и курсоров

    Поскольку параметр hInstance равен NULL, Windows знает, что эта иконка или курсор являются системной. Системные иконки и курсоры являются частью файла драйвера дисплея. Заполняя структуру WNDCLASSEX дескрипторами системного курсора и иконки можно и не использовать функции LoadIcon и LoadCursor. Дело в том, что эти функции нужны, если загружаемая иконка или курсор изготовлены собственноручно или позаимствованы из какой-либо понравившейся программы. Для стандартных (системных) иконок, битмапов и курсоров конкретной версии Windows идентификаторы неизменны и их можно посмотреть при помощи «связки» из функций wsprintf +LoadIcon/Cursor/Bitmap + MessageBox
    Код (ASM):
    1. ; GUI #
    2. include win64a.inc
    3. .code
    4. WinMain proc
    5. local hCursor:QWORD
    6. local buffer[100]:BYTE
    7.  
    8.         invoke LoadCursor,NULL,IDC_ARROW
    9.     mov hCursor,rax
    10.     invoke LoadIcon,NULL,IDI_APPLICATION
    11.     invoke wsprintf,&buffer,&fmt,hCursor,rax
    12.         invoke MessageBox,NULL,&buffer,&MsgCaption,MB_OK
    13.     invoke ExitProcess,NULL
    14. WinMain endp
    15. ;-----------------------------------
    16. MsgCaption      db "Iczelion's tutorial #2b",0
    17. fmt db "hCursor = %08Xh",0Ah,"hIcon = %08Xh",0
    18. end
    [​IMG]
    Полученный при помощи этой программы дескриптор курсора вставлялся в программу, выводящую окно, и проверялся результат. Начав с курсоров IDC_ARROW, IDC_IBEAM очень скоро замечаем, что дескрипторы курсоров могут быть только нечетными числами (иначе окно становится невидимым). Теперь уже без «связки» wsprintf + LoadCursor + MessageBox подставляем значения в шаблон окна и смотрим, что будет выведено в качестве курсора:
    Когда, дескриптор окажется больше 10025h (у Вас может быть другое число), в качестве курсора появляется стандартная системная иконка IDI_APPLICATION, IDI_QUESTION и так далее, то есть еще раз убеждаемся, что разница между иконкой и курсором отсутствует (на это я наткнулся случайно, когда во время заполнения WNDCLASSEX перепутал местами функции LoadIcon и LoadCursor и только потом прочитал о ICO и CUR-форматах :))
    Для части системных курсоров и иконок в файле windows.inc константы IDC_ и IDI_ отсутствуют константы IDI_APPLICATION и IDI_WINLOGO хотя и имеют разное значение (32512 и 32517 соответственно), но соответствуют одной и той же иконке.
    IDC_SIZE (=32640) и IDC_ICON (=32641), актуальны только для Windows NT, а для остальных Windows не соответствуют никакому курсору.
    Часть курсоров, принадлежащих системе, чьи идентификаторы не попали в файл windows.inc можно посмотреть на вкладке «Панель управления» «Оборудование и звук» «Устройства и принтеры» «Мышь» «Указатели»
    [​IMG]
     

    Вложения:

    • tut_07b.png
      tut_07b.png
      Размер файла:
      58,3 КБ
      Просмотров:
      1.282
    Последнее редактирование: 29 мар 2019
  9. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.993
    Результат исследования помещен в таблицу. Повторюсь еще раз ― значение дескриптора зависит от конкретной версии Window и у Вас могут быть совсем другие значения

    типзначениеописание и предназначениедескрипторкартинка
    Курсоры
    IDC_ARROW32512Курсор по умолчанию — стрелка. Предполагается, что объект под таким курсором самостоятельно сообщает пользователю своим видом, можно ли с ним взаимодействовать;10003h[​IMG]
    IDC_IBEAM32513Текстовое выделение — сигнализирует о том, что в это поле можно вводить текст, а также для него действуют выделения и контекстные меню, характерные для полей текстового ввода;10005h[​IMG]
    IDC_WAIT32514Курсор ожидания — сообщает пользователю, что в текущий момент взаимодействие с элементом невозможно по причине выполнения программой каких-то операций. По окончании выполнения курсор должен вернуться в исходное состояние;10007h[​IMG]
    IDC_CROSS32515Перекрестие — используется прежде всего для графического выделения;10009h[​IMG]
    IDC_UPARROW32516Специальное выделение1000Bh[​IMG]
    IDC_SIZE32640Только для Windows NT: Четырехнаправленная стрелка0
    IDC_ICON32641Только для Windows NT: Пустая иконка0
    IDC_SIZENWSE32642Курсор изменения размеров с левого верхнего и правого нижнего углов1000Dh[​IMG]
    IDC_SIZENESW32643Курсор изменения размеров с левого нижнего и правого верхнего углов1000Fh[​IMG]
    IDC_SIZEWE32644Курсор изменения размеров с левого и правого края10011h[​IMG]
    IDC_SIZENS32645Курсор изменения размеров с верхнего и нижнего краев10013h[​IMG]
    IDC_SIZEALL32646Курсор перемещения ― сигнализирует о том, что для выбранного объекта доступна функция перетаскивания;10015h[​IMG]
    IDC_NO32648Курсор запрета действия ― сообщает, что какое-то действие (перетаскивание, нажатие и т. д.) для данного элемента недоступно.10017h[​IMG]
    IDC_APPSTARTING32650Курсор фонового режима ― показывает, что действие запущено, но видимых результатов может не быть. Такой курсор используется для того, чтобы пользователь увидел, что команда принята и повторно нажимать на объект не требуется. В некоторых графических средах рядом с курсором отображается движущаяся иконка запущенного приложения;10019h[​IMG]
    IDC_HELP32651Курсор режима справки ― сигнализирует, что для данного объекта по нажатию кнопки мыши доступна справка, либо имеется всплывающая подсказка;1001Bh[​IMG]
    32631Рукописный ввод1001Dh[​IMG]
    IDC_HAND32649Курсор-рука ― для обозначения гиперссылок, чтобы сообщить пользователю о том, что гиперссылка работает;1001Fh[​IMG]
    10021h[​IMG]
    32663Ожидание готовности CD/DVD10023h[​IMG]
     

    Вложения:

    • cursor14.GIF
      cursor14.GIF
      Размер файла:
      927 байт
      Просмотров:
      718
    • cursor15.GIF
      cursor15.GIF
      Размер файла:
      914 байт
      Просмотров:
      717
    • cursor18.GIF
      cursor18.GIF
      Размер файла:
      909 байт
      Просмотров:
      735
    • cursor19.GIF
      cursor19.GIF
      Размер файла:
      921 байт
      Просмотров:
      716
    • cursor20.GIF
      cursor20.GIF
      Размер файла:
      946 байт
      Просмотров:
      744
    • cursor21.GIF
      cursor21.GIF
      Размер файла:
      880 байт
      Просмотров:
      726
    • cursor22.GIF
      cursor22.GIF
      Размер файла:
      880 байт
      Просмотров:
      719
    • cursor23.GIF
      cursor23.GIF
      Размер файла:
      888 байт
      Просмотров:
      729
    • cursor24.GIF
      cursor24.GIF
      Размер файла:
      888 байт
      Просмотров:
      734
    • cursor25.GIF
      cursor25.GIF
      Размер файла:
      882 байт
      Просмотров:
      694
    Последнее редактирование: 29 мар 2019
  10. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.993
    Иконки
    иконка программы малая10025h[​IMG]
    IDI_APPLICATION32512иконка программы большая10027h[​IMG]
    IDI_EXCLAMATION, IDI_WARNING32515Восклицательный знак (используется в предупреждающих сообщениях)10029h[​IMG]
    IDI_QUESTION32514Вопросительный знак (используется в подсказках)1002Bh[​IMG]
    IDI_HAND, IDI_ERROR32513серьезные предупреждающие сообщения1002Dh[​IMG]
    IDI_ASTERISK, IDI_INFORMATION32516Звездочка (используется в информационных сообщениях)1002Fh[​IMG]
    IDI_WINLOGO32517Иконка приложения по-умолчанию Windows 2000: Логотип Windows10031h[​IMG]
    IDI_SHIELD32518Приложение требует особых прав по безопасности.10033h[​IMG]
    Курсоры
    32652Курсор изменения размеров с верхнего и нижнего краев3602E7h[​IMG]
    32653Курсор изменения размеров с левого и правого края350291h[​IMG]
    32654Курсор перемещения ― сигнализирует о том, что для выбранного объекта доступна функция перетаскивания;5F02BFh[​IMG]
    3265519A0237h[​IMG]
    3265685B0241h[​IMG]
    326575A029Dh[​IMG]
    3265817A0223h[​IMG]
    326591940223h[​IMG]
    3266016D02CBh[​IMG]
    326619302ADh[​IMG]
    32662290295h[​IMG]
    © Mikl___ 2019
     

    Вложения:

    • cursor35.GIF
      cursor35.GIF
      Размер файла:
      898 байт
      Просмотров:
      728
    • cursor34.GIF
      cursor34.GIF
      Размер файла:
      973 байт
      Просмотров:
      723
    • cursor33.GIF
      cursor33.GIF
      Размер файла:
      1,2 КБ
      Просмотров:
      694
    • cursor01.GIF
      cursor01.GIF
      Размер файла:
      900 байт
      Просмотров:
      730
    • cursor02.GIF
      cursor02.GIF
      Размер файла:
      878 байт
      Просмотров:
      701
    • cursor03.GIF
      cursor03.GIF
      Размер файла:
      917 байт
      Просмотров:
      734
    • cursor04.GIF
      cursor04.GIF
      Размер файла:
      862 байт
      Просмотров:
      718
    • cursor05.GIF
      cursor05.GIF
      Размер файла:
      876 байт
      Просмотров:
      735
    • cursor06.GIF
      cursor06.GIF
      Размер файла:
      919 байт
      Просмотров:
      720
    • cursor08.GIF
      cursor08.GIF
      Размер файла:
      908 байт
      Просмотров:
      730
    Последнее редактирование: 29 мар 2019
  11. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.993

    Глава двенадцатая. Братец Кролик изучает меню


    [​IMG]

    — Что же, Братец Си никогда-никогда не поймал Братца Кролика? А, дядюшка Римус? — спросил Джоэль на другой вечер.
    — Было и так, дружок, чуть-чуть не поймал. Помнишь, как Братец Кролик надул его с укропом?

    Теория:

    Меню ― это один из важнейших компонентов вашего окна. Меню является списком всех возможностей, которые программа предлагает пользователю. Пользователь не обязан читать мануал, поставляемый с программой, чтобы использовать ее, он может досконально исследовать меню, чтобы получить представление о возможностях данной программы и начать «играть» с ней немедленно. Так как меню ― это инструмент для того, чтобы дать пользователю «быстрый старт», вы должны следовать стандарту.
    Первые два пункта меню должны быть «Файл» и «Редактирование», а последний ― «Помощь». Вы можете вставить ваши собственные пункты между «Редактированием» и «Помощью». Если пункт меню вызывает диалоговое окно, вам нужно заканчивать название пункта эллипсисом («...»).
    Меню ― это разновидность ресурсов. Есть несколько видов ресурсов, таких как диалоговые окна, строковые таблицы, иконки, битмапы, меню и так далее. Ресурсы описываются в отдельном файле, называющемся файлом ресурсов, который, как правило, имеет расширение RC. Вы можете соединять ресурсы с исходным кодом во время линковки. Окончательный продукт ― это исполняемый файл, который содержит как инструкции, так и ресурсы.
    Вы можете писать файлы ресурсов, используя любой текстовый редактор. Они состоят из набора фраз, определяющих внешний вид и другие атрибуты ресурсов, используемых в программе. Файлы ресурсов можно создовать в текстовом виде (при условии, что вы знакомы с их синтаксисом), а можно воспользоваться редактором ресурсов. Важно понимать, что файл ресурсов ― это обычный текстовый файл. После его создания его компилируют и превращают в двоичный файл с расширением RES.
    Важно! Комментарии в файлах ресурсов, как и комментарии в программах на C++, начинаются с двойного символа наклонной черты.
    Вы описываете ресурс меню примерно так:
    Код (C):
    1.        Имя_меню  MENU
    2.        {
    3.          список пунктов меню
    4.        }
    Си-программисты могут заметить, что это похоже на объявление структуры. Имя_меню ― это имя меню, за ним следует ключевое слово MENU и список пунктов меню, заключенный в фигурные скобки. Вместо { и } вы можете использовать BEGIN и END. Этот вариант больше понравится программистам на Паскале.
    Список меню включает в себя выражения MENUITEM или POPUP.
    MENUITEM определяет пункт меню, который не является подменю. Его синтаксис следующий:
    Код (C):
    1.        MENUITEM "&название_пункта_меню", ID [, опции]
    Выражение начинается ключевым словом MENUITEM, за который следует текст, который будет отображаться. Обратите внимание на амперсанд («&»). Его действие заключается в том, что следующий за ним символ будет подчеркнут. Затем идет строка в качестве ID пункта меню. ID ― это номер, который будет использоваться для обозначения пункта меню в сообщении, посылаемое процедуре окно, когда этот пункт меню будет выбран. Каждое ID должно быть уникальным.
    Доступны следующие опции:
    GRAYEDпункт меню неактивен, и он не генерирует сообщение WM_COMMAND. Текст пункта меню отображается серым цветом.
    INACTIVEпункт меню неактивен, и он не генерирует сообщение WM_COMMAND. Текст пункта меню отображается нормально.
    MENUBREAKэтот пункт меню и последующие пункты отображаются после новой линии меню.
    HELPэтот пункт меню и последующие пункты выравнены по правой стороне.
    Вы можете использовать одну из вышеописанных опций или комбинировать их оператором «or». Учтите, что INACTIVE и GRAYED не могут комбинироваться вместе. Выражение POPUP имеет следующий синтаксис:
    Код (Text):
    1.    POPUP "&название_пункта_меню" [, опции]
    2.    {
    3.      список пунктов меню
    4.    }
    Выражение POPUP определяет пункт меню, при выборе которого выпадает список пунктов в маленьком рoрuр-окне. Список меню может быть выражением MENUITEM или POPUP. Есть специальный вид выражения MENUITEM ― MENUITEM SEPARATOR, который отрисовывает горизонтальную линию в popup-окне.
    Последний шаг ― ссылка на скрипт ресурса меню в программе.
    Вы можете сделать это в двух разных местах.
    1. В поле lpszMenuName структуры WNDCLASSEX. Скажем, если у вас было меню под названием «FirstMenu», вы можете присоединить меню к вашему окну следующим образом:
      Код (ASM):
      1. .data
      2.  MenuName  db "FirstMenu",0
      3.      ...
      4.  .code
      5.          ...
      6.          mov wc.lpszMenuName, OFFSET MenuName
    2. С помощью параметра-дескриптора меню в функции CreateWindowEx:
      Код (ASM):
      1. .data
      2.  MenuName  db "FirstMenu",0
      3.  hMenu dq ?
      4.      ...
      5.  .code
      6.          ...
      7.          invoke LoadMenu, hInst, &MenuName
      8.          mov   hMenu,rax
      9.          invoke CreateWindowEx,NULL,&ClsName,\
      10.          &Caption, WS_OVERLAPPEDWINDOW+WS_VISIBLE,\
      11.          CW_USEDEFAULT,CW_USEDEFAULT,\
      12.          CW_USEDEFAULT,CW_USEDEFAULT,\
      13.          NULL,hMenu,\
      14.          hInst,NULL\
    Вы можете спросить, в чем разница между этими двумя методами? Когда вы делаете ссылку на меню в структуре WNDCLASSEX, меню становится «меню по умолчанию» для данного класса окна. Каждое окно этого класса будет иметь такое меню.
    Если вы хотите, чтобы каждое окно, созданное из одного класса, имело разное меню, вы можете выбрать второй подход. В этом случае, любое окно, которому передается дескриптор меню в функции CreateWindowEx будет иметь меню, которое замещает «меню по умолчанию», указанное в структуре WNDCLASSEX. Сейчас мы узнаем, как меню уведомляет процедуру окна о том, что пользователь выбрал пункт меню.
    Когда пользователь выберет пункт меню, процедура окна получит сообщение WM_COMMAND. Младшие 16 разрядов wParam'а содержит ID выбранного пункта меню.
    Теперь у нас достаточно информации для того, чтобы создать и использовать меню. Давайте сделаем это.

    Создание меню через файл ресурсов

    Скачайте пример здесь
    Первый пример показывает нам как создать и использовать меню, указав имя меню в классе окна.
    Код (ASM):
    1. ; GUI #
    2.  include win64a.inc
    3.  ZZZ_TEST equ 0 ;ID меню
    4.  ZZZ_OPEN equ 1
    5.  ZZZ_SAVE equ 2
    6.  ZZZ_EXIT equ 3
    7.  .code
    8.  WinMain proc
    9.  local msg:MSG
    10.  
    11.      xor ebx,ebx
    12.      mov esi,IMAGE_BASE
    13.      mov eax,10029h
    14.      mov edi,offset ClassName
    15.      push rax    ;Иконка окна по умолчанию
    16.      push rdi    ;Указатель на имя нашего класса    
    17.      pushaddr menu_name    ;Меню
    18.      push COLOR_WINDOW+1;Фон нашего окна
    19.      push 10005h    ;Курсор окна по умолчанию (здесь указан ID обычной стрелки)
    20.      push rax        ;Иконка окна по умолчанию
    21.      push rsi    ;Адрес нашей программы в памяти - Windows всегда её грузит
    22.  ;по этому адресу
    23.      push rbx        ;cbClsExtra & cbWndExtra
    24.      pushaddr  WndProc      ;Адрес процедуры обработки событий
    25.      push sizeof WNDCLASSEX;размер структуры WNDCLASSEX и cтиль нашего окна
    26.      invoke RegisterClassEx,esp;addr WNDCLASSEX
    27.      push rbx
    28.      push rsi    ;rsi=400000h
    29.      shl esi,9    ;rsi=CW_USEDEFAULT
    30.      push rbx
    31.      push rbx
    32.      push rsi
    33.      push rsi
    34.      push rsi
    35.      push rsi
    36.      sub esp,20h
    37.          invoke CreateWindowEx,0,edi,edi,WS_OVERLAPPEDWINDOW or WS_VISIBLE;создать окно
    38.          lea edi,msg
    39.  ;цикл обработки сообщений
    40.  @@:     invoke GetMessage,edi,0,0,0
    41.      invoke DispatchMessage,edi
    42.          jmp @b
    43.  WinMain endp
    44.  
    45.  WndProc proc hwnd:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD
    46.  
    47.          cmp  edx,WM_DESTROY
    48.          je   wmDESTROY
    49.          cmp  edx,WM_COMMAND
    50.          je   wmCOMMAND
    51.          leave
    52.          jmp DefWindowProc
    53.  
    54.  wmDESTROY:invoke ExitProcess,NULL;завершение программы
    55.  wmCOMMAND:cmp r8,ZZZ_EXIT
    56.          je wmDESTROY
    57.  show_msg:mov rdx,menu_handlers[r8*8]
    58.      mov r8d,offset menu_name
    59.          invoke MessageBox,,,,MB_OK
    60.  wmBYE:  leave
    61.          retn
    62.  WndProc endp
    63.  ;---------------------------------------
    64.  ClassName db 'Win64 Iczelion''s lesson #8: создание меню через файл ресурсов',0
    65.  menu_name db 'ZZZ_Menu',0 ;Имя нашего меню в файле ресурсов
    66.  test_msg  db 'You select menu item TEST',0
    67.  open_msg  db 'You select menu item OPEN',0
    68.  save_msg  db 'You select menu item SAVE',0
    69.  menu_handlers dq test_msg, open_msg, save_msg
    70.  end
    Для работы с ресурсами нам потребуется создать файл с таким же именем, но с расширением RC, ниже показано его содержимое
    Код (ASM):
    1. #define ZZZ_TEST 0
    2.  #define ZZZ_OPEN 1
    3.  #define ZZZ_SAVE 2
    4.  #define ZZZ_EXIT 3
    5.  
    6.  ZZZ_Menu MENU
    7.  {
    8.      POPUP "&File"
    9.      {       MENUITEM "&Test",ZZZ_TEST
    10.          MENUITEM "&Open",ZZZ_OPEN
    11.          MENUITEM "&Save",ZZZ_SAVE
    12.                  MENUITEM SEPARATOR
    13.          MENUITEM "&Exit",ZZZ_EXIT
    14.      }
    15.      MENUITEM "&Exit",ZZZ_EXIT
    16.  }

    Анализ:

    В следующих четырех строках определяются четыре константы
    Код (C):
    1. #define ZZZ_TEST 0 /* все равно, что ZZZ_TEST equ 0*/
    2.  #define ZZZ_OPEN 1
    3.  #define ZZZ_SAVE 2
    4.  #define ZZZ_EXIT 3
    Константы соответствуют идентификаторам ресурсов, с помощью которых программа обращается к командам меню. Точно такие же идентификаторы есть и в основном файле
    Код (ASM):
    1. ZZZ_TEST equ 0
    2. ZZZ_OPEN equ 1
    3. ZZZ_SAVE equ 2
    4. ZZZ_EXIT equ 3
    Важно чтобы в разные файлы включались одни и те же идентификаторы. Обратите внимание, что значения идентификаторов начинается с нуля и идут по порядку

    Добавление меню в класс окна

    Далее вы должны указать меню в классе окна. Если взглянуть на определение структуры WNDCLASSEX в основном приложении, можно найти соответствующую строку
     

    Вложения:

    • tut_12.zip
      Размер файла:
      2,7 КБ
      Просмотров:
      301
    Последнее редактирование: 29 мар 2019
  12. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.993
    Код (ASM):
    1.     xor ebx,ebx
    2.     mov esi,IMAGE_BASE
    3.     mov eax,10029h
    4.     mov edi,offset ClassName
    5.     push rax    ;Иконка окна по умолчанию
    6.     push rdi    ;Указатель на имя нашего класса
    7.     db 68h
    8.     dd menu_name    ;адрес имени меню
    9.     push COLOR_WINDOW+1;Фон нашего окна
    10.     push 10005h    ;Курсор окна по умолчанию (здесь указан ID обычной стрелки)
    11.     push rax        ;Иконка окна по умолчанию
    12.     push rsi    ;Адрес нашей программы в памяти - Windows всегда её грузит
    13. ;по этому адресу
    14.     push rbx        ;cbClsExtra & cbWndExtra
    15.     db 68h
    16.     dd WndProc      ;Адрес процедуры обработки событий
    17.     push sizeof WNDCLASSEX;размер структуры WNDCLASSEX и стиль нашего окна
    18.     invoke RegisterClassEx,esp;addr WNDCLASSEX
    19.     . . .
    20. menu_name db 'ZZZ_Menu',0 ;Имя нашего меню в файле ресурсов
    То же имя должно быть и в файле ресурсов
    Код (C):
    1. ZZZ_Menu MENU
    2. {
    Добавление имени меню в структуру WNDCLASSEX ― это все что требуется для установления связи между приложением и меню.

    Обработка команд меню

    Теперь, когда в главном окне нашего приложения появилось меню, вам наверняка хочется знать, как реагировать на действия пользователя при выполнении им определенной команды. При выполнении команды меню Windows посылает вашему приложению сообщение ― в данном случаеWM_COMMAND. Это означает, что вы должны включить в процедуру окна обработку сообщения WM_COMMAND. Когда приложение получает сообщение WM_COMMAND в параметре wParam хранится идентификатор выполненной команды меню.
    При выборе пунктов меню «Test», «Open» и «Save» должны быть выведены мессаджбоксы с сообщениями «You select menu item TEST», «You select menu item OPEN» и «You select menu item SAVE» соответственно, а при выборе пункта меню «Exit» мы должны закрыть приложение.
    [​IMG]
    Iczelion на нашем месте три раза повторяет одинаковые фрагменты
    Код (ASM):
    1.       .ELSEIF uMsg==WM_COMMAND
    2.            mov eax,wParam
    3.            .IF ax==IDM_TEST
    4.              invoke MessageBox,NULL,ADDR Test_string,OFFSET AppName,MB_OK
    5.            .ELSEIF ax==IDM_HELLO
    6.              invoke MessageBox, NULL,ADDR Hello_string, OFFSET AppName,MB_OK
    7.            .ELSEIF ax==IDM_GOODBYE
    8.              invoke MessageBox,NULL,ADDR Goodbye_string, OFFSET AppName, MB_OK
    9.            .ELSE
    10.              invoke DestroyWindow,hWnd
    11.            .ENDIF
    А мы будем только менять сообщение у мессаджбокса в зависимости от содержимого wParam и если wParam = IDM_EXIT перейдем на обработку сообщения WM_DESTROY. Простенько, и со вкусом! :)
    Код (ASM):
    1.         cmp  edx,WM_COMMAND
    2.         je   wmCOMMAND
    3.         leave
    4.         jmp DefWindowProc
    5.  
    6. wmDESTROY:invoke ExitProcess,NULL
    7. wmCOMMAND:cmp r8,ZZZ_EXIT
    8.         je wmDESTROY
    9. show_msg:mov rdx,menu_handlers[r8*8]
    10.     mov r8d,offset menu_name
    11.         invoke MessageBox,,,,MB_OK
    12.     . . .
    13. test_msg  db 'You select menu item TEST',0
    14. open_msg  db 'You select menu item OPEN',0
    15. save_msg  db 'You select menu item SAVE',0
    16. menu_handlers dq test_msg, open_msg, save_msg
    К моменту перехода на show_msg регистр RCX = hwnd, а регистр R8 = wParam. Так как ID пунктов меню идут по порядку от 0 до 3, а в переменной menu_handlers по порядку расположены адреса сообщений ― когда пользователь выбирает «Test», «Open» и «Save», мы отображаем соответствующую текстовую строку при помощи MessageBox.

    Глава тринадцатая. Братец Кролик создает меню через функцию LoadMenu


    [​IMG]
    Этот способ Iczelion назвал альтернативным методом для того, чтобы загружать меню в окно. Исходный код практически такой же как в главе двенадцатой. Файл ресурсов такой же. Есть небольшие изменения в исходнике.
    Для большей убедительности уберем указатель на имя меню из определения структуры WNDCLASSEX
    Код (ASM):
    1.     xor ebx,ebx
    2.     mov esi,IMAGE_BASE
    3.     mov eax,10029h
    4.     mov edi,offset ClassName
    5.     push rax    ;hIconSm
    6.     push rdi    ;Указатель на имя нашего класса
    7.     push rbx    ;lpszMenuName = 0 - меню в WNDCLASS не предусмотрено
    8.     push COLOR_WINDOW+1;Фон нашего окна
    9.     push 10005h    ;Курсор окна по умолчанию (здесь указан ID обычной стрелки)
    10.     push rax    ;Иконка окна по умолчанию
    11.     push rsi    ;Адрес нашей программы в памяти - Windows всегда грузит ее
    12. ;по этому адресу
    13.     push rbx    ;cbClsExtra & cbWndExtra
    14.     pushaddr WndProc    ;Адрес процедуры обработки событий
    15.     push sizeof WNDCLASSEX;размер структуры WNDCLASSEX и стиль нашего окна
    16.     invoke RegisterClassEx,esp;addr WNDCLASSEX
    Перед вызовом CreateWindowEx, мы вызываем LoadMenu, передавая ему дескриптор процесса и указатель на имя меню. LoadMenu возвращает дескриптор нашего меню, который мы передаем CreateWindowEx.
    Код (ASM):
    1. invoke LoadMenu,esi,ZZZ_Menu
    2.     push rbx
    3.     push rsi    ;rsi=400000h
    4.     shl esi,9    ;rsi=CW_USEDEFAULT
    5.     push rax
    6.     push rbx
    7.     push rsi
    8.     push rsi
    9.     push rsi
    10.     push rsi
    11.     sub esp,20h
    12.     invoke CreateWindowEx,0,edi,edi,WS_OVERLAPPEDWINDOW or WS_VISIBLE
    Скачайте пример здесь
    Полный текст программы
    Код (ASM):
    1. ; GUI #
    2. include win64a.inc
    3. ZZZ_TEST equ 0
    4. ZZZ_OPEN equ 1
    5. ZZZ_SAVE equ 2
    6. ZZZ_EXIT equ 3
    7. ZZZ_Menu equ 30
    8. .code
    9. WinMain proc
    10. local msg:MSG
    11.  
    12.     xor ebx,ebx
    13.     mov esi,IMAGE_BASE
    14.     mov eax,10029h
    15.     mov edi,offset ClassName
    16.     push rax    ;hIconSm
    17.     push rdi    ;lpszClassName
    18.     push rbx    ;lpszMenuName
    19.     push COLOR_WINDOW+1;hbrBackground
    20.     push 10005h    ;hCursor
    21.     push rax    ;hIcon
    22.     push rsi    ;hInstance
    23.     push rbx    ;cbClsExtra & cbWndExtra
    24.     pushaddr WndProc    ;lpfnWndProc
    25.     push sizeof WNDCLASSEX;cbSize & style
    26.     invoke RegisterClassEx,esp;addr WNDCLASSEX
    27.     invoke LoadMenu,esi,ZZZ_Menu
    28.     push rbx
    29.     push rsi    ;rsi=400000h
    30.     shl esi,9    ;rsi=CW_USEDEFAULT
    31.     push rax
    32.     push rbx
    33.     push rsi
    34.     push rsi
    35.     push rsi
    36.     push rsi
    37.     sub esp,20h
    38.         invoke CreateWindowEx,0,edi,edi,WS_OVERLAPPEDWINDOW or WS_VISIBLE
    39.         lea edi,msg
    40. @@:    invoke GetMessage,edi,0,0,0
    41.     invoke DispatchMessage,edi
    42.       jmp @b
    43. WinMain endp
    44. WndProc proc hwnd:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD
    45.  
    46.     cmp edx,WM_DESTROY
    47.     je wmDESTROY
    48.     cmp edx,WM_COMMAND
    49.     je wmCOMMAND
    50.     leave
    51.     jmp DefWindowProc
    52. wmDESTROY:invoke ExitProcess,NULL
    53. wmCOMMAND:cmp r8,ZZZ_EXIT
    54.     je wmDESTROY
    55. show_msg:mov rdx,menu_handlers[r8*8]
    56.     mov r8d,offset menu_name
    57.     invoke MessageBox,,,,MB_OK
    58. wmBYE:    leave
    59.     retn
    60. WndProc endp
    61. ;data
    62. ClassName db 'Win64 Iczelion''s lesson #8a: Menu and LoadMenu',0
    63. menu_name db 'ZZZ_Menu',0
    64. test_msg  db 'You select menu item TEST',0
    65. open_msg  db 'You select menu item OPEN',0
    66. save_msg  db 'You select menu item SAVE',0
    67. menu_handlers dq test_msg, open_msg, save_msg
    68. end
    Код (C):
    1. #define ZZZ_TEST 0
    2. #define ZZZ_OPEN 1
    3. #define ZZZ_SAVE 2
    4. #define ZZZ_EXIT 3
    5. #define ZZZ_Menu 30
    6.  
    7. ZZZ_Menu MENU
    8. {
    9.     POPUP "&File"
    10.     {       MENUITEM "&Test",ZZZ_TEST
    11.         MENUITEM "&Open",ZZZ_OPEN
    12.         MENUITEM "&Save",ZZZ_SAVE
    13.                 MENUITEM SEPARATOR
    14.         MENUITEM "&Exit",ZZZ_EXIT
    15.     }
    16.     MENUITEM "&Exit",ZZZ_EXIT
    17. }

    Глава четырнадцатая. Программное создание меню


    [​IMG]
    В этой главе Братец Кролик научился, создавать меню программно, при помощи функций CreateMenu, CreatePopupMenu, AppendMenu, SetMenu

    Теория:

    Меню чаще всего описывается в файле ресурсов, так как в этом случае облегчается задача изменения его состава или пунктов меню. Но в некоторых случаях может оказывается более удобным создавать меню программно, без помощи редактора и компилятора ресурсов. Программное создание меню включает следующие действия:
     

    Вложения:

    • 20.png
      20.png
      Размер файла:
      269,4 КБ
      Просмотров:
      1.227
    • 21.png
      21.png
      Размер файла:
      221,4 КБ
      Просмотров:
      1.255
    • tut_13.zip
      Размер файла:
      4,9 КБ
      Просмотров:
      507
    Последнее редактирование: 7 май 2019
  13. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.993
    1. создание линейки меню приложения (пока пустой) функцией CreateMenu с получением дескриптора этого меню;
    2. создание «всплывающего» меню для помещения в него требуемого набора пунктов меню (но пока тоже пустого и без названия) функцией CreatePopupMenu с получением дескриптора «всплывающего» меню;
    3. заполнение «всплывающего» меню при помощи функции AppendMenu пунктами меню. Функции AppendMenu передается четыре параметра:
      • первым параметром указывается дескриптор всплывающего меню;
      • вторым параметром указывается константа MF_STRING (или MF_SEPARATOR для разделительной линии);
      • третьим параметром ― идентификатор данного пункта меню;
      • четвертым параметром ― адрес строки текста, представляющего собой название пункта меню (для разделительной линии передается значение NULL).
    4. включение «всплывающего» меню в линейку меню при помощи функции AppendMenu и передачи этой функции:
      • первым параметром имени «всплывающего» меню;?
      • вторым параметром указывается константа MF_POPUP;
      • третьим ― дескриптор «всплывающего» меню;
      • четвертым ― адрес строки с названием «всплывающего» меню;
    5. присоединение всего меню к главному окну приложения функцией SetMenu.
    Скачайте пример здесь
    Код (ASM):
    1. ; GUI #
    2. include win64a.inc
    3. ZZZ_TEST equ 0
    4. ZZZ_OPEN equ 1
    5. ZZZ_SAVE equ 2
    6. ZZZ_EXIT equ 3
    7. ;-----------------------------------------
    8. .code
    9. WinMain proc
    10. local msg:MSG
    11.  
    12.     xor ebx,ebx
    13.     mov eax,10029h
    14.     push rax    ;hIconSm
    15.     mov edi,offset ClassName
    16.     push rdi    ;lpszClassName
    17.     push rbx    ;lpszMenuName
    18.     push COLOR_WINDOW;hbrBackground
    19.     push 10005h    ;hCursor
    20.     push rax        ;hIcon
    21.     mov esi,IMAGE_BASE
    22.     push rsi    ;hInstance
    23.     push rbx        ;cbClsExtra & cbWndExtra
    24.     db 68h
    25.     dd WndProc      ;lpfnWndProc
    26.     push sizeof WNDCLASSEX;cbSize & style
    27.         invoke RegisterClassEx,esp;addr WNDCLASSEX
    28.         push rbx
    29.     push rsi    ;rsi=400000h
    30.     shl esi,9    ;rsi=CW_USEDEFAULT
    31.     push rbx
    32.     push rbx
    33.     push rsi
    34.     push rsi
    35.     push rsi
    36.     push rsi
    37.     sub esp,20h
    38.         invoke CreateWindowEx,0,edi,edi,WS_OVERLAPPEDWINDOW or WS_VISIBLE
    39.         lea edi,msg
    40. @@:     invoke GetMessage,edi,0,0,0
    41.         invoke DispatchMessage,edi
    42.         jmp @b
    43. WinMain endp
    44. WndProc proc hWnd:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD
    45.  
    46.         mov  hWnd,rcx
    47.  
    48.     cmp  edx,WM_CREATE
    49.     je   wmCREATE
    50.         cmp  edx,WM_DESTROY
    51.         je   wmDESTROY
    52.         cmp  edx,WM_COMMAND
    53.         je   wmCOMMAND
    54.         leave
    55.         jmp DefWindowProc
    56. wmDESTROY:invoke ExitProcess,0
    57. wmCREATE: invoke CreatePopupMenu
    58.       mov edi,eax
    59.       mov r9d,offset menu_test1
    60.       invoke AppendMenu,edi,MF_STRING,ZZZ_TEST
    61.       mov r9d,offset menu_open1
    62.       invoke AppendMenu,edi,MF_STRING,ZZZ_OPEN
    63.       mov r9d,offset menu_save1
    64.       invoke AppendMenu,edi,MF_STRING,ZZZ_SAVE
    65.       invoke AppendMenu,edi,MF_SEPARATOR,0,0
    66.       mov r9d,offset menu_exit1
    67.       invoke AppendMenu,edi,MF_STRING,ZZZ_EXIT
    68.       invoke CreateMenu
    69.       mov hMenu,rax
    70.       mov r9d,offset menu_file
    71.       invoke AppendMenu,eax,MF_POPUP,edi
    72.       mov r9d,offset menu_exit1
    73.       invoke AppendMenu,hMenu,MF_STRING,ZZZ_EXIT
    74.       invoke SetMenu,hWnd,hMenu
    75.       jmp wmBYE
    76. wmCOMMAND:cmp r8,ZZZ_EXIT
    77.         je wmDESTROY
    78. show_msg:mov rdx,menu_handlers[r8*8]
    79.     mov r8d,offset menu_name
    80.         invoke MessageBox,,,,MB_OK
    81. wmBYE:  leave
    82.         retn
    83. WndProc endp
    84. ;data
    85. ClassName db 'Win64 Iczelion''s lesson #8c: Program creation menu',0
    86. menu_file    db 'File',0
    87. menu_test1    db 'Test',0
    88. menu_open1    db 'Open',0
    89. menu_save1    db 'Save',0
    90. menu_exit1    db 'Exit',0
    91. menu_name     db 'ZZZ_Menu',0
    92. test_msg        db 'You select menu item TEST',0
    93. open_msg        db 'You select menu item OPEN',0
    94. save_msg        db 'You select menu item SAVE',0
    95. menu_handlers     dq test_msg, open_msg, save_msg
    96. hMenu         dq ?
    97. end
    Функция CreatePopupMenu создает «всплывающее» меню, подменю или контекстное меню. Меню вначале пустое. Вы можете вставлять или добавлять в конец пункты меню при помощи использования функции InsertMenuItem. Вы можете также использовать функцию InsertMenu, чтобы вставить пункты меню, а функцию AppendMenu, чтобы добавлять в конец пункты меню.
    Функция CreateMenu создает меню. Меню вначале пустое, но оно может быть заполнено пунктами меню при помощи использования функцийInsertMenuItem, AppendMenu и InsertMenu.
    Функция SetMenu связывает новое меню с заданным окном.
    Код (C):
    1. BOOL SetMenu
    2. (       HWND hWnd,    // дескриптор окна, с которым должно быть связано меню
    3.     HMENU hMenu    // дескриптор меню. Если hMenu = NULL, текущее меню окна удаляется
    4. );
    Функция AppendMenu добавляет в конец определяемой строки меню, «всплывающего» меню, подменю или контекстного меню новый пункт. Вы можете использовать эту функцию, чтобы определить содержание, внешний вид и характеристики пункта меню.
    Функция AppendMenu была заменена функцией InsertMenuItem. Вы можете все еще использовать AppendMenu, в том случае, если Вы не нуждаетесь в какой-либо из расширенных функций InsertMenuItem.
    Синтаксис
    Код (C):
    1. BOOL AppendMenu(
    2.     HMENU hMenu,    // дескриптор меню, который будет изменен
    3.     UINT uFlags,    /* флажки пункта меню, которые управляют внешним видом и характеристиками нового
    4. пункта меню. Этот параметр может быть комбинация значений, перечисленных ниже */
    5.     UINT uIDNewItem,/* идентификатор пункта меню или, если параметр uFlags установлен в MF_POPUP,
    6. дескриптор "всплывающего" меню или подменю */
    7.     LPCTSTR lpNewItem//  пункт контекстного меню. Интерпретация lpNewItem зависит от того, включает ли
    8. параметр uFlags в себя флажок MF_BITMAP, MF_OWNERDRAW или MF_STRING
    9. );
    Прикладная программа должна вызывать функцию DrawMenuBar всякий раз, когда меню изменяется, независимо от того, находится оно или нет в отображаемом окне.
    Следующие флажки могут быть установлены в параметре uFlags:
    uFlagshexОписание
    MF_ENABLED
    0​
    Включает пункт меню, так что он может быть выбран и восстанавливает его из недоступного состояния.
    MF_STRING
    0​
    Определяет, что пункт меню ― текстовая строка; параметр lpNewItem указывает на строку.
    MF_UNCHECKED
    0​
    Удаляет галочку рядом с пунктом («значение по умолчанию»). Если прикладная программа предоставляет точечные рисунки (значки) «галочки», тогда этот флажок показывает на экране снятую метку «галочки» рядом с пунктом меню.
    MF_INSERT
    0​
    MF_BYCOMMAND
    0​
    MF_UNHILITE
    0​
    MF_GRAYED
    1​
    Отключает пункт меню и окрашивает его в серый цвет (делает недоступным), так что он не может быть выбран.
    MF_DISABLED
    2​
    Отключает пункт меню, так что он не может быть выбран, но флажок не окрашивает его в серый цвет.
    MF_BITMAP
    4​
    Использует точечный рисунок как пункт меню. Параметр lpNewItem содержит дескриптор точечного рисунка.
    MF_CHECKED
    8​
    Помещает галочку рядом с пунктом меню. Если прикладная программа предоставляет значки «галочки» тогда этот флажок показывает на экране точечный рисунок галочки рядом с пунктом меню.
    MF_POPUP
    10​
    Определяет, что пункт меню открывает «всплывающее» меню или подменю. Параметр uIDNewItem определяет дескриптор «всплывающего» меню или подменю. Этот флажок используется, чтобы добавить имя меню в строке меню, или пункт меню, который открывает подменю «всплывающего» меню, подменю или контекстное меню.
    MF_MENUBARBREAK
    20​
    Исполняет такую же функцию, как и флажок MF_MENUBREAK для строки меню. Для «всплывающего» меню, подменю или контекстного меню, новый столбец отделяется от старого столбца вертикальной линией.
    MF_MENUBREAK
    40​
    Помещает пункт в новую строку (для строки меню) или в новом столбце (для «всплывающего» меню, подменю, или контекстного меню) без разделения столбцов.
    MF_HILITE
    80​
    MF_END
    80​
    MF_CHANGE
    80​
    MF_OWNERDRAW
    100​
    Определяет, что пункт является «собственным» пунктом (нарисованным пользователем). Перед тем как меню отображается впервые, окно, которое владеет им, получает сообщение WM_MEASUREITEM, чтобы извлечь данные о ширине и высоте пункта меню. Сообщение WM_DRAWITEM затем отправляется в оконную процедуру окна владельца всякий раз, когда внешний вид пункта меню должен модифицироваться.
    Содержит 32-разрядное значение, предоставленное прикладной программой, которое может быть использовано, чтобы утвердить, что дополнительные данные касаются пункта меню. Значение является членом itemData структуры, указываемой параметром lParam при помощи передачи сообщения WM_MEASURE или WM_DRAWITEM, когда создается меню, или его внешний вид модифицируется.
    MF_APPEND
    100​
    MF_USECHECKBITMAPS
    200​
    MF_DELETE
    200​
    MF_BYPOSITION
    400​
    MF_SEPARATOR
    800​
    Рисует горизонтальную разделительную линию. Этот флажок используется только во «всплывающем» меню, подменю или контекстном меню. Строка не может быть недоступна, заблокирована, или выделена. Параметры lpNewItem и uIDNewItem игнорируются.
    MF_SEPARATOR
    800​
    MF_DEFAULT1000
    MF_REMOVE1000
    MF_SYSMENU2000
    MF_HELP4000
    MF_RIGHTJUSTIFY4000
    MF_MOUSESELECT8000

    Глава пятнадцатая. Создание динамического меню


    [​IMG]
    Во многих программах меню может динамически изменяться во время работы ― исчезают и добавляются пункты меню, одно меню встраивается в другое и тому подобное. Пример простейших манипуляций с меню приведен в этой главе.

    Теория:

    В приложение открывается окно с кнопкой и «пустым» меню. При нажатии на кнопку появляется одно меню (MENUC), которое сменяется следующим меню (MENUP), которое заменяет «пустое» меню и так далее по кругу. При передвижении по меню название его пунктов и заголовков «выпадающих» (popup) подменю отображается в заголовке окна
     

    Вложения:

    • 17.png
      17.png
      Размер файла:
      233 КБ
      Просмотров:
      1.259
    • tut_15.zip
      Размер файла:
      1,9 КБ
      Просмотров:
      540
    Последнее редактирование: 4 сен 2019
  14. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.993
    Скачайте пример здесь
    Код (ASM):
    1. ; GUI #
    2. include win64a.inc
    3.  
    4. STYLBTN     equ BS_DEFPUSHBUTTON+WS_VISIBLE+WS_CHILD
    5. sizeof_buffer = 128
    6.  
    7. .code
    8. WinMain proc
    9. local msg:MSG
    10.     xor ebx,ebx
    11.     mov esi,IMAGE_BASE
    12.     mov eax,10027h
    13.     mov edi,offset ClassName
    14.     push rax    ;hIconSm
    15.     push rdi    ;lpszClassName
    16.     push rbx    ;lpszMenuName
    17.     push COLOR_WINDOW+1;hbrBackground
    18.     push 10005h    ;hCursor
    19.     push rax        ;hIcon
    20.     push rsi    ;hInstance
    21.     push rbx        ;cbClsExtra & cbWndExtra
    22.     db 68h
    23.     dd WndProc      ;lpfnWndProc
    24.     push sizeof WNDCLASSEX;cbSize & style
    25.     invoke RegisterClassEx,esp    ;addr WNDCLASSEX
    26.         push rbx
    27.     push rsi    ;rsi=400000h
    28.     shl esi,9    ;rsi=CW_USEDEFAULT
    29.     push rbx
    30.     push rbx
    31.     push rsi
    32.     push rsi
    33.     push rsi
    34.     push rsi
    35.     sub esp,20h
    36.         invoke CreateWindowEx,0,edi,edi,WS_OVERLAPPEDWINDOW or WS_VISIBLE
    37.         lea edi,msg
    38. @@:   invoke GetMessage,edi,0,0,0
    39.     invoke DispatchMessage,edi
    40.       jmp @b
    41. WinMain endp
    42.  
    43. WndProc proc hWnd:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD
    44. local MENI:MENUITEMINFO
    45. local buffer[sizeof_buffer]:BYTE
    46.  
    47.       mov  hWnd,rcx
    48.       mov  lParam,r9
    49.     mov  wParam,r8
    50.  
    51.     cmp  edx,WM_CREATE
    52.     je   wmCREATE
    53.       cmp  edx,WM_DESTROY
    54.       je   wmDESTROY
    55.       cmp  edx,WM_COMMAND
    56.       je   wmCOMMAND
    57.       cmp edx,WM_MENUSELECT
    58.     je wmMENUSELECT
    59. wmDEFAULT:leave
    60.       jmp DefWindowProc
    61. wmDESTROY:invoke ExitProcess,NULL
    62. wmCOMMAND:mov rax,HWNDBTN;проверить, не нажата ли кнопка
    63.     cmp r9,rax     ;cmp lParam,rax
    64.     je YES_BUT
    65.     cmp r8w,5      ;word ptr wParam,5;проверить, не выбран ли пункт меню MENUC - выход
    66.     je wmDESTROY
    67.     cmp r8w,4      ;cmp word ptr wParam,4;проверить, не выбран ли пункт меню с идентификатором 4
    68.     jne wmBYE
    69. YES_BUT:mov r9d,offset SPACE;обработка нажатия кнопки. сначала стереть текст в заголовке
    70.     invoke SendMessage,,WM_SETTEXT,0
    71.     dec PRIZN
    72.     jns @f
    73.     add PRIZN,3;if (PRIZN < 0) PRIZN=2
    74.     jmp @f
    75. wmCREATE:push rbx
    76.     push IMAGE_BASE
    77.     push rbx
    78.     push rcx;[hWnd]
    79.     push 25
    80.     push 120
    81.     push 10
    82.     push 10
    83.     mov r8d,offset CPBUT
    84.     mov edx,offset CLSBUTN
    85.     sub esp,20h
    86.     invoke CreateWindowEx,0,,,STYLBTN
    87.     mov HWNDBTN,rax;запомнить дескриптор кнопки
    88. ;загрузить необходимое меню
    89. @@:   mov edx,PRIZN
    90.     invoke LoadMenu,IMAGE_BASE
    91.     invoke SetMenu,hWnd,eax ;установить меню
    92.     jmp wmBYE
    93. wmMENUSELECT:mov rcx,r9;lParam = 0 ?
    94.     jecxz wmBYE;пропускаем первое сообщение при обращении к меню
    95.     xor r8,r8
    96.     test word ptr wParam+2,MF_POPUP;проверяем, что активизировано - пункт меню или заголовок выпадающего меню
    97.     setne r8b
    98. ;если 0, то в lword wParam идентификатор пункта меню          
    99. ;если 1, то в lword wParam номер заголовка выпадающего меню
    100.     mov MENI.hSubMenu,rcx;MENI.hSubMenu:=lParam
    101. ;заполнение структуры для вызова функции GetMenuItemInfo
    102.     lea r9d,MENI
    103.     mov MENI.cbSize,sizeof MENUITEMINFO
    104.     mov MENI.fMask,MIIM_TYPE
    105.     lea eax,buffer
    106.     mov MENI.dwTypeData,rax;указатель на буфер, получающий необходимую строку
    107.     mov MENI.cch,sizeof_buffer;длина буфера
    108.     movzx rdx,word ptr wParam;получить информацию о выбранном пункте меню
    109.     invoke GetMenuItemInfo
    110.     or eax,eax ;cmp eax,0;проверить результат выполнения функции
    111.     jz wmBYE
    112.     invoke SendMessage,hWnd,WM_SETTEXT,0,MENI.dwTypeData;вывести название пункта меню как заголовок всего окна
    113. wmBYE:  leave
    114.         retn
    115. WndProc endp
    116. ;data
    117. ClassName db 'Win64 Iczelion''s lesson #8d: Создание динамического меню'
    118. SPACE       db 0
    119. CPBUT      db 'Change menu',0
    120. CLSBUTN   db 'BUTTON',0
    121. HWNDBTN   dq ?
    122. PRIZN      dd 0
    123. end
    [​IMG]
    В ресурсах программы находятся два меню.
    Код (C):
    1. #define MENUC 2
    2. #define MENUP 1
    3.  
    4. MENUP MENU
    5. {
    6.     POPUP "First point"
    7.      {
    8.          MENUITEM "First",1
    9.          MENUITEM "Second",2
    10.      }
    11.      POPUP "Second point"
    12.      {
    13.           MENUITEM "Third",3
    14.           MENUITEM "Fourth",4
    15.           MENUITEM SEPARATOR
    16.           POPUP "Else submenu"
    17.           {
    18.                MENUITEM "Additional point",6
    19.           }
    20.           MENUITEM "Exit",5
    21.      }
    22. }
    23. MENUC MENU
    24. {
    25.     POPUP "First set"
    26.      {
    27.          MENUITEM "White",101
    28.          MENUITEM "Grey",102
    29.          MENUITEM "Black",103
    30.      }
    31.      POPUP "Second set"
    32.      {
    33.           MENUITEM "Red",104
    34.           MENUITEM "Blue",105
    35.           MENUITEM "Green",106
    36.      }
    37. }
    В переменной PRIZN хранится состояние меню:
    • 2 ― загружено меню MENUC
    • 1 ― загружено меню MENUP
    • 0 ― меню отсутствует
    Начальное состояние обеспечивается заданием меню при регистрации класса окна
    Код (ASM):
    1.     xor ebx,ebx
    2.     mov esi,IMAGE_BASE
    3.     mov eax,10027h
    4.     mov edi,offset ClassName
    5.     push rax    ;hIconSm
    6.     push rdi    ;lpszClassName
    7.     push rbx    ;меню отсутствует
    8.     push COLOR_WINDOW+1;hbrBackground
    9.     push 10005h    ;hCursor
    10.     push rax        ;hIcon
    11.     push rsi    ;hInstance
    12.     push rbx        ;cbClsExtra & cbWndExtra
    13.     db 68h
    14.     dd WndProc      ;lpfnWndProc
    15.     push sizeof WNDCLASSEX;cbSize & style
    16.     invoke RegisterClassEx,esp;addr WNDCLASSEX
    При нажатии на кнопку «Change menu» происходит циклическое изменение значения PRIZN от 0 к 1, далее 2 и снова 0
    Код (ASM):
    1. YES_BUT:mov r9d,offset SPACE;обработка нажатия кнопки. сначала стереть текст в заголовке
    2.     invoke SendMessage,,WM_SETTEXT,0
    3.     dec PRIZN
    4.     jns @f
    5.     add PRIZN,3;if (PRIZN < 0) PRIZN=2
    6.     jmp @f
    7.     . . .
    8. ;загрузить необходимое меню
    9. @@:   mov edx,PRIZN
    10.     invoke LoadMenu,IMAGE_BASE
    11.     invoke SetMenu,hWnd,eax ;установить меню
    При определении названия выбранного пункта меню приходит сообщение WM_MENUSELECT. При активизации меню приходит сообщениеWM_MENUSELECT со значением lParam, которое определяет идентификатор меню равным нулю.
    Код (ASM):
    1. wmMENUSELECT:mov rcx,r9;lParam = 0 ?
    2.     jecxz wmBYE;пропускаем первое сообщение при обращении к меню
    При получении сообщения WM_MENUSELECT в младших 16 разрядах параметра wParam может содержаться либо идентификатор пункта меню, либо номер заголовка выпадающего меню. Определить, что выбрано, можно по старшим 16 разрядам параметра wParam
    Код (ASM):
    1.     xor r8,r8
    2.     test word ptr wParam+2,MF_POPUP;проверяем, что активизировано - пункт меню или заголовок выпадающего меню
    3.     setne r8b
    4. ;если 0, то в lword wParam идентификатор пункта меню                      
    5. ;если 1, то в lword wParam номер заголовка выпадающего меню
    6.     mov MENI.hSubMenu,rcx;MENI.hSubMenu:=lParam
    7. ;заполнение структуры для вызова функции GetMenuItemInfo
    8.     lea r9d,MENI
    9.     mov MENI.cbSize,sizeof MENUITEMINFO
    10.     mov MENI.fMask,MIIM_TYPE
    11.     lea eax,buffer
    12.     mov MENI.dwTypeData,rax;указатель на буфер, получающий необходимую строку
    13.     mov MENI.cch,sizeof_buffer;длина буфера
    14.     movzx rdx,word ptr wParam;получить информацию о выбранном пункте меню
    15.     invoke GetMenuItemInfo
    16.     or eax,eax ;cmp eax,0;проверить результат выполнения функции
    17.     jz wmBYE
    18.     invoke SendMessage,hWnd,WM_SETTEXT,0,MENI.dwTypeData;вывести название пункта меню как заголовок всего окна
    после команды setne выполняющейся после test регистр r8b установится в 1 или сбросится в 0. Далее, для получения строки-названия используется функция GetMenuItemInfo. Третьим параметром этой функции как раз и может быть либо ноль, либо единица. Если ноль, то второй параметр ― это идентификатор пункта меню, если единица, то второй параметр ― номер заголовка выпадающего меню. Четвертым параметром является указатель на структуру, которая и будет заполняться в результате выполнения функции. Некоторые поля этой структуры должны быть заполнены заранее. Поле dwTypeData, которое должно содержать указатель на буфер, получающий необходимую нам строку. Поле cchдолжно содержать длину этого буфера. Для того чтобы поля idwTypeData и cch трактовались функцией как указатель на буфер и его длину, поля fMask и fType должны быть правильно заполнены. Поле cbSize должно содержать длину всей структуры.
    После получения нужной информации, то есть строки-названия пункта меню, при помощи функции SendMessage посылается сообщение WM_SETTEXT, которое дает команду установить заголовок окна.
    Функция GetMenuItemInfo извлекает информацию о пункте меню.
    Код (C):
    1. BOOL WINAPI GetMenuItemInfo(
    2.    HMENU hMenu, // Дескриптор меню, которое содержит пункт меню
    3.     UINT uItem,  /* Идентификатор или позиция пункта меню, о котором надо получить
    4. информацию. Предназначение этого параметра зависит от значения fByPosition*/
    5.     BOOL fByPosition, /* Значение, определяющее предназначение uItem. Если этот
    6. параметр ― FALSE, uItem - идентификатор пункта меню. Иначе, это - позиция пункта
    7. меню*/
    8.     LPMENUITEMINFO lpmii /*Указатель на структуру MENUITEMINFO, которая
    9. определяет информацию, чтобы извлечь и получить информацию о пункте меню */
    10. );
     

    Вложения:

    • tut_08e.png
      tut_08e.png
      Размер файла:
      96,2 КБ
      Просмотров:
      1.268
    • tut_08f.png
      tut_08f.png
      Размер файла:
      37,3 КБ
      Просмотров:
      1.264
    • tut_08g.png
      tut_08g.png
      Размер файла:
      38,4 КБ
      Просмотров:
      1.219
    • tut_16.zip
      Размер файла:
      3,6 КБ
      Просмотров:
      240
    Последнее редактирование: 7 май 2019
  15. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.993

    Глава шестнадцатая. «Плавающее» меню

    [​IMG]

    Теория:

    В приложениях Windows широко используется «плавающее» меню (не путать с «всплывающим» меню (popup menu), являющимся элементом обычного меню), активизируеммые обычно щелчком правой клавиши мыши. «Плавающее» меню появляется в том месте экрана, где в данный момент находится курсор мыши.

    Поскольку «плавающее» меню должно активизироваться нажатием правой клавиши мыши, в оконную функцию следует включить обработку сообщения WM_RBUTTONDOWN, и все действия по созданию меню выполнить в функции обработки этого сообщения. Установка «плавающего» меню почти не отличается от программного создания обычного статического меню и включает в себя следующие действия:
    1. создание «всплывающего» меню для помещения в него требуемого набора пунктов (пока пустого) функцией CreatePopupMenu с получением дескриптора «всплывающего» меню (линейка меню в этом случае не создается);
    2. заполнение «всплывающего» меню конкретными пунктами функцией AppendMenu в точности так же, как и при создании обычного меню. Поскольку линейки меню в этом случае нет, «всплывающее» меню ни к чему не подсоединяется;
    3. объявление созданного «всплывающего» меню «плавающим» при помощи функции TrackPopupMenu. Второй параметр этой функции задается равным 0. В качестве третьего и четвертого параметров указывают текущие координаты курсора мыши, пятый параметр дескриптор окна, шестой NULL
    Для более точного позиционирования рекомендуют передавать экранные координаты мыши из структурной переменной MSG
    Скачайте пример здесь
    Код (ASM):
    1. ; GUI #
    2. include win64a.inc
    3.  
    4. ZZZ_TEST equ 0
    5. ZZZ_OPEN equ 1
    6. ZZZ_SAVE equ 2
    7. ZZZ_EXIT equ 3
    8. ;-----------------------------------------
    9. .code
    10. WinMain proc
    11.     enter 20h,0
    12.  
    13.     xor ebx,ebx
    14.     mov esi,IMAGE_BASE
    15.     mov eax,10027h
    16.     mov edi,offset ClassName
    17.     push rax    ;hIconSm
    18.     push rdi    ;lpszClassName
    19.     push rbx    ;lpszMenuName
    20.     push COLOR_WINDOW+1;hbrBackground
    21.     push 10005h    ;hCursor
    22.     push rax        ;hIcon
    23.     push rsi    ;hInstance
    24.     push rbx        ;cbClsExtra & cbWndExtra
    25.     db 68h
    26.     dd WndProc      ;lpfnWndProc
    27.     push sizeof WNDCLASSEX;cbSize & style
    28.     invoke RegisterClassEx,esp;addr WNDCLASSEX
    29.       push rbx
    30.     push rsi    ;rsi=400000h
    31.     shl esi,9    ;rsi=CW_USEDEFAULT
    32.     push rbx
    33.     push rbx
    34.     push rsi
    35.     push rsi
    36.     push rsi
    37.     push rsi
    38.     sub esp,20h
    39.         invoke CreateWindowEx,0,edi,edi,WS_OVERLAPPEDWINDOW or WS_VISIBLE
    40.         mov edi,offset msg
    41. @@:   invoke GetMessage,edi,0,0,0
    42.     invoke DispatchMessage,edi
    43.       jmp @b
    44. WinMain endp
    45. WndProc proc hWnd:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD
    46. local rect:RECT
    47. local hMenu:QWORD
    48.     mov  hWnd,rcx
    49.  
    50.     cmp  edx,WM_DESTROY
    51.       je   wmDESTROY
    52.       cmp  edx,WM_COMMAND
    53.       je   wmCOMMAND
    54.       cmp  edx,WM_RBUTTONDOWN
    55.     je   wmRBUTTONDOWN
    56. wmDEFAULT:leave
    57.       jmp DefWindowProc
    58. wmDESTROY:invoke ExitProcess,NULL
    59. wmRBUTTONDOWN: invoke CreatePopupMenu
    60.     mov edi,eax;hPopupMenu,eax
    61.     invoke CreateMenu
    62.     mov hMenu,rax;hMenu=rbp-20h
    63.     mov r9d,offset menu_test1
    64.     invoke AppendMenu,edi,MF_STRING,ZZZ_TEST
    65.     mov r9d,offset menu_open1
    66.     invoke AppendMenu,edi,MF_STRING,ZZZ_OPEN
    67.     mov r9d,offset menu_save1
    68.     invoke AppendMenu,edi,MF_STRING,ZZZ_SAVE
    69.     invoke AppendMenu,edi,MF_SEPARATOR,0,0
    70.     mov r9d,offset menu_exit1
    71.     invoke AppendMenu,edi,MF_STRING,ZZZ_EXIT
    72.     mov r9d,offset menu_file
    73.     invoke AppendMenu,hMenu,MF_POPUP,edi
    74.     mov r9d,offset menu_exit1
    75.     invoke AppendMenu,hMenu,MF_STRING,ZZZ_EXIT
    76.     ;xor edx,edx;mov edx,TPM_LEFTALIGN+TPM_LEFTBUTTON
    77.     mov r8d,msg.pt.x
    78.     mov r9d,msg.pt.y