Помогите новичку

Applications development, KoOS API questions
  • Gluk wrote:если коротко, следует заменить

    Code: Select all

    cmp   eax,3
    на

    Code: Select all

    dec   eax
    Спасибо!
    Я хотел закрывать экран по нажатию на кнопку, сейчас закрытие происходит и по кнопке и по крестику. Как определять что событие пришло от конкретного компонента (кнопки на экране), а не от системной кнопки закрытия? Нужно её идентификатор указывать?
    С помощью какой инструкции можно поменять текст на надписи?
  • gc986 wrote: Спасибо!
    Я хотел закрывать экран по нажатию на кнопку, сейчас закрытие происходит и по кнопке и по крестику. Как определять что событие пришло от конкретного компонента (кнопки на экране), а не от системной кнопки закрытия? Нужно её идентификатор указывать?
    С помощью какой инструкции можно поменять текст на надписи?
    Всегда пожалуйста!
    думаю, в данном случае следует применить системную функцию 17, о которой можно прочитать например вот на этой странице http://wiki.kolibrios.org/wiki/SysFn17/ru . Вызывать её наверное следует в участке кода, который выполняется когда нажата кнопка, то есть, скорее всего, в процедуре button_event. Если непонятно как применить, спрашивайте свободно
    И мы уже давно не пешки,
    Мы пули, мы орлы, и решки!
    Война ютит бинарный код,
    Умри, или иди вперед!
  • Gluk wrote: Всегда пожалуйста!
    думаю, в данном случае следует применить системную функцию 17, о которой можно прочитать например вот на этой странице http://wiki.kolibrios.org/wiki/SysFn17/ru . Вызывать её наверное следует в участке кода, который выполняется когда нажата кнопка, то есть, скорее всего, в процедуре button_event. Если непонятно как применить, спрашивайте свободно
    Т.е. необходимо произвести сравнение содержимого регистра eax с 17, если равны, то ничего не делать, иначе производить выход из приложения.

    Code: Select all

    cmp eax, 17
    jne close_program
    jmp wait_program
    
    Видимо делаю что-то не то, так как выходит и при нажатии на кнопку и при нажатии на кнопку закрытия окна. Как должно быть правильно?
  • не совсем. Сначала нужно вызвать системную функцию:

    Code: Select all

    mcall   17
    сразу после этого в регистре ah очутится идентификатор кнопки, которая нажата.
    идентификатор (упрощённо говоря) это то, что у вас в коде:

    Code: Select all

    mcall   8, <30,50>, <30,20>, 1, 0xf0f0f0
    равно 1. Я не писал под Колибри уже годы, так что не помню какой идентификатор по умолчанию у кнопки-крестика приложения, и быстро найти не удалось, поэтому (для быстрого старта и чтобы точно работало) порекомендую использовать вместо 1 более уникальный идентификатор, например 0xBE. То есть заменить ту строку на:

    Code: Select all

    mcall   8, <30,50>, <30,20>, 0xBE, 0xf0f0f0
    Возвращаясь к нашей button_event: надо будет после вызова 17й функции сравнить ah с 0xBE:

    Code: Select all

    cmp ah, 0xBE
    вместо

    Code: Select all

    cmp eax, 17
    .

    Далее, если вы хотите по этой кнопке как раз закрывать окно, то следует применить

    Code: Select all

    je close_program
    вместо

    Code: Select all

    jne close_program
    .

    Если я ничего не путаю, у нас получается (не забываем ещё 1 на 0xBE сменить):

    Code: Select all

    button_event:
       mcall 17
       cmp  ah, 0xBE
       je   close_program
       jmp   wait_event
    
    и программа не будет завершаться по крестику, а только по вашей кнопке
    И мы уже давно не пешки,
    Мы пули, мы орлы, и решки!
    Война ютит бинарный код,
    Умри, или иди вперед!
  • gc986 wrote:С помощью какой инструкции можно поменять текст на надписи?
    если поменять произвольным образом, то весьма просто, в области где хранится строка нужно изменить обыкновенной записью саму строку. Например, вот так (для вашей программы):

    Code: Select all

    mov byte [string],'Ф'
    
    тогда при следующей перерисовке Тестовая строка станет Фестовой (перерисовку можно и самому вызвать в таком случае).
    Однако, нехорошо так делать потому что у вас написано что эти строки -

    Code: Select all

    ; Константы
    так что менять их не стоит.

    Вместо этого следует добавить ещё одну строку, ту, на которую вы хотите изменить старую:

    Code: Select all

    string2   db   'Фестовая строка',0
    а также переменную, которая будет служить указателем на правильную строку, например, так (после строк, пожалуйста):

    Code: Select all

    ; Переменные
    
    strpointer dd string
    
    тут мы его сразу же и инициализируем, чтобы он сразу на корректную строку указывал. Тогда, в случае если нам потребуется изменить строку с тестовой на фестовую, мы просто сделаем это:

    Code: Select all

    mov dword [strpointer], string2
    Только работать это не будет, если мы по прежнему будем использовать:

    Code: Select all

    mcall   4, <30,10>, 0x80000000, string
    вместо этого нужно применить что-то вроде:

    Code: Select all

    mcall   4, <30,10>, 0x80000000, [strpointer]
    Признаться, я не очень хорошо поню как устроен макрос mcall, но вроде так сойдёт.
    Last edited by Gluk on Wed Mar 11, 2015 3:15 pm, edited 1 time in total.
    И мы уже давно не пешки,
    Мы пули, мы орлы, и решки!
    Война ютит бинарный код,
    Умри, или иди вперед!
  • Gluk wrote: Если я ничего не путаю, у нас получается (не забываем ещё 1 на 0xBE сменить):

    Code: Select all

    button_event:
       mcall 17
       cmp  ah, 0xBE
       je   close_program
       jmp   wait_event
    
    и программа не будет завершаться по крестику, а только по вашей кнопке
    Заработало :D
  • Gluk wrote: mov dword [strpointer], string2
    Что означают квадратные скобки?

    Как перевести число в строку? Хочу попробовать время выводить на экран ))
  • В какое-то время в macros.inc был добавлен макрос "header" и все программы/примеры использовавшие метку "header" перестали компилироваться как задумывалось.
    Добавьте "purge header" после строки 'include "macros.inc"', чтобы данный макрос не влиял, или переименуйте "header" в паре мест самой программы во что-нибудь другое.
  • gc986 wrote:Что означают квадратные скобки?
    Значат просто записать по адресу, написанному в квадратных скобках :) сделано так для того, чтобы если в адресе участвует регистр - не путать, куда записывать, в регистр или по адресу, куда он указывает. Так что адрес всегда в квадроскобках, когда работаем со значением.
    gc986 wrote:Как перевести число в строку? Хочу попробовать время выводить на экран ))
    отличные стремление и вопрос!

    время мы скорее всего будем получать посредством системной функции 3 http://wiki.kolibrios.org/wiki/SysFn03/ru

    Code: Select all

    mcall 3
    Не буду сюда копировать оттуда информацию, там формат хорошо описан. У нас стоит задача из этого формата получить строку, содержащую время. Сначала заготовим шаблон для того чтобы его заполнить в дальнейшем, в области данных (где переменные) пишем:

    Code: Select all

    timeline db '00:00:00',0
    на самом деле тут главное двоеточия, остальное мы планируем перезаписать всё равно. Эту же строку можно выводить куда-нибудь как обычно, разумеется, а сейчас посмотрим как её обновлять.

    Результат функции 3 сохраняется в регистре eax, с ним и будем работать.
    сперва заполним поле единиц часов (потому что почему бы и нет), часы у нас хранятся как написано в ссылке в первом байте регистра eax, а значит в регистре al, единицы часов - в его младшем полубайте. Но да, там хранится только цифра. Чтобы превратить её в символ цифры, вспомним что в кодовых таблицах цифры идут подряд, начиная с нуля. Значит, если мы прибавим число к символу нуля, мы получим символ цифры. Однако! У нас в al ещё и десятки часов мешаются. Похоже нам понадобится ещё и буферный регистр для всяких махинаций. Пусть это будет bl, потому что он прикольный, похож на ы.

    Code: Select all

    ; копируем в bl часы
    mov bl, al
    ; удаляем десятки часов
    and bl, 0x0F
    ; число->цифра
    add bl, '0'
    ; сохраняем в строку
    mov byte [timeline+1], bl
    
    Дальше прикольно, не будем отказываться от предыдущей схемы, чтобы можно было её в цикл свернуть при желании. Для этого сместим весь eax вправо на 4 бита, вот так:

    Code: Select all

    shr eax, 4
    Теперь в младшем полубайте al у нас десятки часов, круто, да? Ну тогда, очевидно:

    Code: Select all

    ; копируем в bl десятки часов
    mov bl, al
    ; удаляем единицы минут
    and bl, 0x0F
    ; число->цифра
    add bl, '0'
    ; сохраняем в строку
    mov byte [timeline+0], bl
    
    Ну и так далее:

    Code: Select all

    shr eax, 4
    mov bl, al
    and bl, 0x0F
    add bl, '0'
    mov byte [timeline+4], bl
    

    Code: Select all

    shr eax, 4
    mov bl, al
    and bl, 0x0F
    add bl, '0'
    mov byte [timeline+3], bl
    

    Code: Select all

    shr eax, 4
    mov bl, al
    and bl, 0x0F
    add bl, '0'
    mov byte [timeline+7], bl
    

    Code: Select all

    shr eax, 4
    mov bl, al
    and bl, 0x0F
    add bl, '0'
    mov byte [timeline+6], bl
    
    и готово. В цикл мне лень сворачивать, а формальная отговорка - возможная потеря прозрачности объяснения =)
    И мы уже давно не пешки,
    Мы пули, мы орлы, и решки!
    Война ютит бинарный код,
    Умри, или иди вперед!
  • Gluk wrote: и готово. В цикл мне лень сворачивать, а формальная отговорка - возможная потеря прозрачности объяснения =)
    Большое спасибо! Теперь у меня вечер занят полезным делом :)
  • Gluk wrote: и готово. В цикл мне лень сворачивать, а формальная отговорка - возможная потеря прозрачности объяснения =)
    Уф.... всё получилось просто идюально ))) Приложения написанные на асме постепенно перестают быть для меня абсолютной магией :D
    Назрели вопросы:
    1) Я повесил обновление времени на обработчик нажатия на кнопку, чтобы сделать время постоянно обновляющимся необходимо создать вечный цикл?
    2) В учебнике написано что and - оператор логического умножения. Не могли бы вы по подробнее написать зачем и как используется эта команда?
    3) Зачем складывать с '0', ведь число +0 это то же самое число или здесь другая логика?
    4) Каждый символ в строке занимает 1 байт? (никогда не обращал на это внимание при программировании на языках высокого уровня)
    5) Пользуюсь этим учебником (там промелькнуло TASM), для FASM он подойдёт? - http://www.kolasc.net.ru/cdo/programmes ... er/tc.html
    6) Не совсем понимаю как работает главный цикл программы

    Code: Select all

    wait_event:
       mcall   10
       dec   eax
       jz   redraw
       dec   eax
       jz   key
       cmp   eax,3
       jz   button_event
    
    Постоянно происходит вызов системной функции 10, и дальше перебор вариантов действий. Как система узнаёт что произошло событие обновления экрана, а не нажатия на кнопку например?
  • gc986 wrote: 1) Я повесил обновление времени на обработчик нажатия на кнопку, чтобы сделать время постоянно обновляющимся необходимо создать вечный цикл?
    совершенно верно что нужен вечный цикл - но его не нужно создавать, он уже есть! Этот вопрос я рассмотрю разом с этим:
    gc986 wrote: 6) Не совсем понимаю как работает главный цикл программы

    Code: Select all

    wait_event:
       mcall   10
       dec   eax
       jz   redraw
       dec   eax
       jz   key
       cmp   eax,3
       jz   button_event
    
    Постоянно происходит вызов системной функции 10, и дальше перебор вариантов действий. Как система узнаёт что произошло событие обновления экрана, а не нажатия на кнопку например?
    Давайте посмотрим как он работает. Из описания системной функции 10 http://wiki.kolibrios.org/wiki/SysFn10/ru мы знаем как она работает: при вызове выполнение программы приостанавливается, покуда не произойдёт событие, связанное с программой. Как только событие происходит, система "отпускает" программу и она продолжает выполнение, с одним изменением - в регистр eax записывается код произошедшего события. То есть, например, если нажата кнопка, в eax будет число 3. Вот мы и сравниваем значение eax с разными константами, если в eax единица например - перерисовываем окно, и после возвращаемся обратно к ожиданию события. Как система узнаёт что за событие - нам не важно, нам важно только как об этом узнаёт программа, ну вот я и описал вроде) надеюсь правильно понял вопрос.
    Теперь что касается первого вопроса, про бесконечный цикл. Главный цикл программы уже является бесконечным циклом, в который мы можем как раз добавить вызов процедуры обновления времени. Посмотрим что нам нужно сделать для обновления: во-первых, пересчитать строку времени, во-вторых - перерисовать окно (на самом деле как-то возможно частичное обновление окна, но я так ни разу не делал, боюсь обмануть). И это надо делать периодически (или чаще). Один из вариантов как этого можно добиться (далеко не самый правильный вариант - но должно по крайней мере работать) следующий:

    Code: Select all

    wait_event:
       ; вместо сисфункции 10 применим http://wiki.kolibrios.org/wiki/SysFn23/ru
       ;работает как 10я за одним исключением, после 0.5 секунд (в данном случае)
       ;отпускает программу, записывая в eax значение 0.
       mcall   23, 50
       ; dec для сравнения с нулём не годится, используем cmp
       cmp  eax, 0
       ; тут я предполагаю что процедура обновления времени называется update_time
       ;и заканчивается командой jmp redraw
       jz   update_time
       dec   eax
       jz   redraw
       dec   eax
       jz   key
       cmp   eax,3
       jz   button_event
    
    Ну вроде как-то так, теперь если программу не "вешать" постоянным вызовом событий (например, зажиманием кнопки клавиатуры) - время должно обновляться
    gc986 wrote:2) В учебнике написано что and - оператор логического умножения. Не могли бы вы по подробнее написать зачем и как используется эта команда?
    конечно могу. Тем более что для этого мне нужно всего лишь скопировать практически готовый ответ из этого самого учебника:
    Применение:
    Команда and используется для логического умножения двух операндов. Результат операции помещается по адресу первого операнда. Эту команду удобно использовать для принудительной установки или сброса определенных битов операнда.
    Например, преобразуем двузначное упакованное BCD-число в его символьный эквивалент.
    дальше идёт кстати код, который (примерно) я изобретал в предыдущем ответе :) там чуть меньше комментариев правда, может мне учебник написать :D
    В общем, у нас тут как раз применение для принудительного сброса определённых битов. Вот есть bl, в нём допустим значение 0x23 (это значит 23 часа пускай). Нам нужно получить символ '3' (оставим пока в покое десятки). Для этого нужно удалить 0x20 из 0x23. Как же это сделать? Можно вычесть 0x20 из 0x23. Но программа ведь не знает что там именно два десятка часов! Поэтому воспользуемся логическими операциями, например and. Что она делает? Для каждого бита операндов выполняет следующее: если у обоих операндов текущий бит равен 1, то вернуть 1, иначе вернуть 0. Возвращает в первый операнд. Как это можно использовать? Посмотрим на наше число 0x23 в бинарном виде: 0b00100011. Что будет если мы съandим его с, например, 0b00001111 (0x0f)? Совершенно верно, там где у второго операнда 0 - у результата будет 0, а где 1 - там результат будет такой же, как в первом операнде! Значит получим 0b00000011, а это число 0x03 или просто 3! Как удачно подвернулся следующий вопрос:
    gc986 wrote:3) Зачем складывать с '0', ведь число +0 это то же самое число или здесь другая логика?
    Давайте продолжим мучать наш bl, который содержит уже 0x03, или 3. Если вы запишете это значение в какую-нибудь строку, выводящуюся потом на экран (попробуйте!), вы увидите вместо символа '3' что-то другое. Что именно - давайте посмотрим вместе вот тут https://ru.wikipedia.org/wiki/ASCII - упс, похоже это вообще какой-то служебный символ, и я полагаю на выводе будет пробел или кракозябра какая. Что же делать, как же быть, как нам тройку выводить... А посмотрим на таблицу снова, и найдём там символ тройки - вот же он, с кодом 0x33. То есть чтобы вывести символ '3' надо к числу 0x03 добавить число 0x30. Но я не очень люблю магические числа, где гарантия что через лет пять вы вспомните что это за число такое? Потому то я и прибавляю к нашему bl код символа '0' (видите, он в кавычках - значит это именно код символа, равный 0x30, а не число 0!), очевидно для 0x03 мы получим тогда 0x33, то есть '3'.
    gc986 wrote: 4) Каждый символ в строке занимает 1 байт? (никогда не обращал на это внимание при программировании на языках высокого уровня)
    ага, 1 байт в кодировке которая используется в Колибри. Бывают и другие кодировки - двубайтовые, четырёхбайтовые, и даже с переменным количеством байт. Но для вывода в Колибри именно однобайтовая кодировка обычно применяется. Первая половина кодовой таблицы - уже знакомая нам ASCII, вторая - национальные и дополнительные символы. Кстати, поделитесь - с какими языками высокого уровня вы знакомы? Зная это, мне проще будет показывать на конкретных примерах всякое.
    gc986 wrote:5) Пользуюсь этим учебником (там промелькнуло TASM), для FASM он подойдёт? - http://www.kolasc.net.ru/cdo/programmes ... er/tc.html
    ну я вот на него сослался, значит на что-то он годится :D А если серьёзно, можно использовать любой учебник, только смотрите чтобы там был описан ассемблер для x86. Отличаться у разных ассемблеров будет синтаксис, например насколько я помню квадратные скобочки чуть ли не только в FASM применяются, в других ассемблерах иначе задаётся то что работа идёт со значением а не с адресом. То есть команды такие же, только несколько иначе записываются и всё.
    И мы уже давно не пешки,
    Мы пули, мы орлы, и решки!
    Война ютит бинарный код,
    Умри, или иди вперед!
  • Gluk wrote:
    gc986 wrote:5) Пользуюсь этим учебником (там промелькнуло TASM), для FASM он подойдёт? - http://www.kolasc.net.ru/cdo/programmes ... er/tc.html
    ну я вот на него сослался, значит на что-то он годится :D А если серьёзно, можно использовать любой учебник, только смотрите чтобы там был описан ассемблер для x86. Отличаться у разных ассемблеров будет синтаксис, например насколько я помню квадратные скобочки чуть ли не только в FASM применяются, в других ассемблерах иначе задаётся то что работа идёт со значением а не с адресом. То есть команды такие же, только несколько иначе записываются и всё.
    Большое спасибо! Честное слово, когда учился в техникуме ассемблер мне казался языком очень тяжёлым, а теперь интересным :D В повседневной жизни пишу приложения на Java (Android), а раньше Pascal (Delphi).
    И всё таки я пока не совсем понимаю главный цикл... Происходит вызов системной функции 10, далее происходит уменьшение регистра на 1

    Code: Select all

    dec eax
    Дальше идёт перемещение на нужную функцию, например обработка кнопок, перерисовка окна и т.д. А как именно это происходит не понимаю ))
    По моей логике должно происходить следующим образом:
    Attachments
    main_asm.png
    main_asm.png (21.76 KiB)
    Viewed 5524 times
  • gc986 wrote: И всё таки я пока не совсем понимаю главный цикл... Происходит вызов системной функции 10, далее происходит уменьшение регистра на 1

    Code: Select all

    dec eax
    Дальше идёт перемещение на нужную функцию, например обработка кнопок, перерисовка окна и т.д. А как именно это происходит не понимаю ))
    о, да это просто читерство. Легко можно было бы использовать:

    Code: Select all

       cmp   eax, 0
       je   update_time
       cmp   eax, 1
       je   redraw
       cmp   eax, 2
       je   key
       cmp   eax, 3
       je   button_event
    
    Теперь посмотрим как работает тот вариант:

    Code: Select all

       cmp   eax, 0 ; вычитаем из eax 0 (не меняя значение eax), если результат= 0, устанавливаем флаг Z, а ещё флаг E
       jz   update_time ; если флаг Z установлен, переходим к update_time
     ; je   update_time ; <или так] если флаг E установлен, переходим к update_time
       dec   eax ; уменьшаем eax на 1, если результат= 0, устанавляваем флаг Z 
       jz   redraw ; если флаг Z установлен, переходим к redraw
       dec   eax ; уменьшаем eax на 1, если результат= 0, устанавляваем флаг Z 
       jz   key ; если флаг Z установлен, переходим к key
       dec   eax ; уменьшаем eax на 1, если результат= 0, устанавляваем флаг Z 
       jz   button_event ; если флаг Z установлен, переходим к button_event 
    
    тоже работает, при этом меньше констант упомянуто в коде (нету 1, 2, 3 и т.д.).

    Хотя раз уж мы добавили,

    Code: Select all

    cmp   eax, 0
    то для однообразия может лучше и сменить всё на cmp
    И мы уже давно не пешки,
    Мы пули, мы орлы, и решки!
    Война ютит бинарный код,
    Умри, или иди вперед!
  • Who is online

    Users browsing this forum: No registered users and 15 guests