Page 2 of 4

Re: Message Box

Posted: Wed Mar 18, 2009 7:55 pm
by Albom
IgorA
1) посмотри исходники console.obj
2) http://devotes.narod.ru/Books/3/ch05_02a.htm.
то, что нужно, начинается со слов "Для удобства ссылок на параметры, переданные в стеке".
правда, там код 16-разрядный.
! обрати внимание на ret 6.

Re: Message Box

Posted: Thu Mar 19, 2009 12:58 am
by IgorA
Не получается сделать вызов параметров, как в примере. Вызов желаю так:

Code: Select all

but_3:
  push eax
    mov eax,[mb_procinfo]
    mov [eax],dword procinfo
  pop eax
  push msgbox_3 ;дал адрес сообщения +4(1)
  push thread ;дал адрес памяти для стека +4(2)
  call [mb_create] ;вызвал функцию +4(3)
  jmp still
А саму функцию так:

Code: Select all

MsgBoxCreate:
;  push ebp
;  mov ebp,esp
;    push eax ebx ecx edx
    mov eax,[ebp+12] ;беру адрес сообщения 4(3)+4(2)+4(1)=12
    m2m dword[mb_text],dword[eax] ;адрес пишу в переменную mb_text
    mov edx,[ebp+8] ;беру адрес памяти для процесса 4(3)+4(2)=8
    mov eax,51 ;создание потока функцией 51 ...
    mov ebx,1
    mov ecx,start
    int 0x40
;    pop edx ecx ebx eax
  ret 8 ;выкидаю из стека переменные 4(1) и 4(2)
В результате не работает, могу дать весь код, но думаю что и в этом можно найти ошибку

Re: Message Box

Posted: Thu Mar 19, 2009 1:29 pm
by diamond
Принцип работы со переменными, передаваемыми в стеке, следующий.
Пусть процедура вызывается как stdcall с тремя параметрами param0, param1, param2; тогда код вызова выглядит следующим образом:

Code: Select all

    push param2
    push param1
    push param0
    call func
label:
При этом в момент начала выполнения func стек выглядит следующим образом:

Code: Select all

    [esp] = label ; на вершине стека находится адрес возврата, результат инструкции call
    [esp+4] = param0 ; последнее запихнутое в стек значение, результат последнего push
    [esp+8] = param1 ; предпоследнее запихнутое в стек значение, результат предпоследнего push
    [esp+12] = param2
Так что к переданным аргументам уже можно обращаться через esp со смещением. Это один из вариантов работы.
Есть и другой вариант. Работать с esp не всегда удобно, поскольку оно меняется при всяких push/pop и нужно соответственно добавлять 4*число заpushенных dwordов; кроме того, в 16-битном режиме адресации через sp не было вообще, а в 32-битном она хотя и есть, но занимает на байт больше (mov eax,[esp+4] на байт длиннее mov eax,[ebp+4]); кроме того, если процедура работает с постоянно меняющимся esp, то нельзя автоматически из внешнего кода раскрутить стек в поисках цепочки вызовов, приведших к текущему состоянию (есть и другие аспекты). Поэтому часто используется также адресация через ebp. Для этого в начало функции добавляется код

Code: Select all

    push ebp
    mov  ebp, esp
после чего стек принимает вид

Code: Select all

    [ebp] = старое значение ebp ; верхушка стека
    [ebp+4] = адрес возврата из процедуры
    [ebp+8] = param0
    [ebp+12] = param1
    [ebp+16] = param2
В конце процедуры, естественно, нужно восстановить стек и старое значение ebp. Минусы такого стиля адресации заключаются в дополнительном коде пролога/эпилога процедуры и в потере одного регистра, который можно было бы задействовать для других целей.

В коде, приведённом ранее, отсутствует инициализация ebp, так что [ebp+N] указывает в никуда.

Re: Message Box

Posted: Thu Mar 19, 2009 7:02 pm
by IgorA
Учел то что сказали Albom и diamond, и сделал более новую версию библиотеки. Убрал ссылку на структуру mb_procinfo, потому что передаю ее в стеке.
Кроме того несколько изменений: улучшил работу с кнопками Влево и Вправо, окно размещается в центре экрана.
Описал в файле msgbox.asm все константы и переменные. Функция теперь stdcal потому думаю с ней все понятно и так.

Re: Message Box

Posted: Thu Mar 19, 2009 8:48 pm
by Albom
чувствую, что скоро библиотекой можно будет пользоваться! :)

IgorA
не понимаю зачем в вызывающей прогремме нужно передавать структуру procinfo и массив thread? они в ней не используются. может как-нибудь перенести в библиотеку? да и экспорт библиотекой mb_text и mb_reinit немного нелогичный.

Re: Message Box

Posted: Thu Mar 19, 2009 9:43 pm
by IgorA
массив thread нужен для функции 51

Code: Select all

Функция 51 - создать поток
  * edx = указатель стэка потока (начальный esp)
из структуры procinfo я определяю ширину окна (client_box.width), а исходя из ширины окна определяю отступ для рисования кнопок по центру окна.
Хотя эту структуру можно и не давать указателем, а обьявить ее внутри msgbox.lib, но тогда размер библиотеки будет на 1Кб больше. Я решил что если приложение будет использовать структуру procinfo, то зачем ее дублировать 2 раза.
Экспорт mb_text и mb_reinit сделал в расчете на то, что сообщение можно будет динамически изменять в процессе работы. Допустим программа что-то выполняет в несколько этапов ...
При запуске выдала сообщение: Выполнено 0% [Закрыть][Прервать], прошло время и изменили надпись: Выполнено 30% [Закрыть][Прервать], и т. д., а потом : Выполнено все [Закрыть].
Потому mb_text и mb_reinit выкинуты на всеобщее обозрение.
Хотя возможно функцию mb_reinit стоит изменить, что-бы она принимала параметр mb_reinit через стек.

Re: Message Box

Posted: Thu Mar 19, 2009 9:52 pm
by Albom
массив thread нужен для функции 51
а создавать поток в mb_create не пробовал?
тогда размер библиотеки будет на 1Кб больше
это единственная причина? этот килобайт сожмётся kpack'ом до пары десятков байт. :)
возможно функцию mb_reinit стоит изменить, что-бы она принимала параметр mb_reinit через стек
ну это другое дело! :)

Re: Message Box

Posted: Thu Mar 19, 2009 10:34 pm
by diamond
IgorA wrote:но тогда размер библиотеки будет на 1Кб больше.
Да ну?

Re: Message Box

Posted: Fri Mar 20, 2009 12:33 am
by DmitrySokolowsky
Наконец-то попробовал! Выглядит интересно, багов не заметил.

Re: Message Box

Posted: Fri Mar 20, 2009 12:38 am
by IgorA
Albom
а создавать поток в mb_create не пробовал?
Почему-то но не удалось :( , кроме того мне кажется, что если вдруг возникнет необходимость создать несколько сообщений, то нужно разные массивы для стеков давать. Потому оно пока из внешней программы передается.
А mb_procinfo вкинул внутрь библиотеки.
Сделал пример на функцию mb_reinit , но перерисовка окна сама не делается, нужно подвигать окно чтобы заметить изменение сообщения.

Re: Message Box

Posted: Fri Mar 20, 2009 9:58 am
by Albom
IgorA wrote: если вдруг возникнет необходимость создать несколько сообщений, то нужно разные массивы для стеков давать.
можно спокойно динамически выделять 4 кила. вопрос только в том, когда эту память освобождать - не всё так просто. :)

Re: Message Box

Posted: Wed May 27, 2009 11:09 am
by IgorA
Добавил в библиотеку msgbox функцию mb_setfunctions. Пример использования можно посмотреть в примере на 2-м сообщении на 3-й кнопке с надписью "Помощь".
Смысл данной функции в том, что окну сообщения можно назначить функции на нажатие кнопок, т. е. сразу при нажатии на кнопку сообщения выполнится вызов функции по назначенному адресу. (Если адрес равен 0 то ничего не делается). Раньше планировалось в вызывающей программе анализировать какую кнопку нажали и по ней определять что делать, а теперь можно и так и по новому.

Re: Message Box

Posted: Wed May 27, 2009 3:07 pm
by Albom
IgorA wrote:Добавил в библиотеку msgbox функцию mb_setfunctions
Очень полезная функция. :) Код пока не смотрел, но пример работает здорово.

Маленький вопросик: зачем выделять кнопки? (чёрным цветом)

Re: Message Box

Posted: Wed May 27, 2009 4:02 pm
by IgorA
зачем выделять кнопки? (чёрным цветом)
Дело в том, что можно кнопками влево и вправо на клавиатуре выбрать нужную кнопку, и нажать потом enter для выбора. Т. е. можно не только мышкой на кнопку нажать, а и на клавиатуре. Потому возникает необходимость выделить кнопку, показать что она в фокусе. А черный цвет, это цвет текста который берется из системного скина. Если взять другой скин то эта кнопка может выглядеть и не черной.

Re: Message Box

Posted: Thu May 28, 2009 6:34 am
by Albom
А нельзя просто рисовать поверх кнопки прямоугольник с толщиной линии в 1 пиксел? Или (что было бы вообще здорово) 4 прерывистых линии?