Blog. Just Blog

Использование системного окна прогресса на Ассемблере

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Системное окно прогресса - удобный инструмент в тех случаях, когда нет возможности возиться с кастомизацией или созданием нестандартных элементов, или хочется сделать все максимально приближенным к системному интерфейсу, независимо от платформы, где будет запускаться ваше приложение. И очень странно, что нет никакой информации о реализации этого диалогового окна на Ассемблере, хотя все делается достаточно просто. Начинаем с описания интерфейса, GUID'ов и констант.
  1. ; GUID {F8383852-FCD3-11D1-A6B9-006097DF5BD4}
  2. CLSID_ProgressDialog \
  3.     dd 0F8383852h
  4.     dw 0FCD3h
  5.     dw 011D1h
  6.     db 0A6h, 0B9h, 000h, 060h, 097h, 0DFh, 05Bh, 0D4h
  7.  
  8. ; GUID {EBBC7C04-315E-11D2-B62F-006097DF5BD4}
  9. IID_IProgressDialog \
  10.     dd 0EBBC7C04h
  11.     dw 0315Eh
  12.     dw 011D2h
  13.     db 0B6h, 02Fh, 000h, 060h, 097h, 0DFh, 05Bh, 0D4h
  14.  
  15. ; IID_IProgressDialog Interface
  16. struct IProgressDialog
  17.     ; IUnknown
  18.     QueryInterface      dd ?
  19.     AddRef              dd ?
  20.     Release             dd ?
  21.     ; IProgressDialog
  22.     StartProgressDialog dd ?
  23.     StopProgressDialog  dd ?
  24.     SetTitle            dd ?
  25.     SetAnimation        dd ?
  26.     HasUserCancelled    dd ?
  27.     SetProgress         dd ?
  28.     SetProgress64       dd ?
  29.     SetLine             dd ?
  30.     SetCancelMsg        dd ?
  31.     Timer               dd ?
  32. ends
  33.  
  34. PDTIMER_RESET  = 0x00000001
  35. PDTIMER_PAUSE  = 0x00000002
  36. PDTIMER_RESUME = 0x00000003
  37.  
  38. PROGDLG_NORMAL          = 0x00000000
  39. PROGDLG_MODAL           = 0x00000001
  40. PROGDLG_AUTOTIME        = 0x00000002
  41. PROGDLG_NOTIME          = 0x00000004
  42. PROGDLG_NOMINIMIZE      = 0x00000008
  43. PROGDLG_NOPROGRESSBAR   = 0x00000010
  44. PROGDLG_MARQUEEPROGRESS = 0x00000020
  45. PROGDLG_NOCANCEL        = 0x00000040
Окно прогресса создается, настраивается и управляется при помощи методов интерфейса IProgressDialog.

Начинается все с инициализации COM-системы и создания объекта окна прогресса. Затем настраивается его внешний вид: заголовок, текст в главной (первой) строчке, текст в двух дополнительных строчках, а также текст, который появится, если пользователь нажмет кнопку отмены. Инициализировать индикатор прогресса начальным и максимальным значением не обязательно, но вроде как рекомендуется, последуем совету. Владельцем окна прогресса может быть как ваше приложение, так и, например, окно рабочего стола.
  1.         ; Создать объект
  2.         invoke  CoCreateInstance,CLSID_ProgressDialog,NULL,\
  3.                 CLSCTX_ALL,IID_IProgressDialog,pProgress
  4.  
  5.         ; Установить заголовок
  6.         mov     eax,[pProgress]
  7.         mov     eax,[eax]
  8.         stdcall dword [eax+IProgressDialog.SetTitle],[pProgress],\
  9.                 szTitle
  10.  
  11.         ; Установить текстовые строки
  12.         mov     eax,[pProgress]
  13.         mov     eax,[eax]
  14.         stdcall dword [eax+IProgressDialog.SetLine],[pProgress],\
  15.                 1,szLine1,FALSE,NULL
  16.  
  17.         mov     eax,[pProgress]
  18.         mov     eax,[eax]
  19.         stdcall dword [eax+IProgressDialog.SetLine],[pProgress],\
  20.                 2,szLine2,FALSE,NULL
  21.  
  22.         ; Установить сообщение об остановке процесса
  23.         mov     eax,[pProgress]
  24.         mov     eax,[eax]
  25.         stdcall dword [eax+IProgressDialog.SetCancelMsg],[pProgress],\
  26.                 szCancel
  27.  
  28.         ; Инициализировать индикатор прогресса
  29.         mov     eax,[pProgress]
  30.         mov     eax,[eax]
  31.         stdcall dword [eax+IProgressDialog.SetProgress],[pProgress],\
  32.                 0,100
В окне прогресса третьей строкой может отображаться оставшееся время до окончания операции. Это значение рассчитывается автоматически на основании уже выполненного объема действий и затраченного на это времени. Для правильного расчета оставшегося времени надо инициализировать внутренний таймер прогресса непосредственно перед запуском окна. Дальше он будет обновляться самостоятельно, но при необходимости его можно приостановить и снова запустить из вашего приложения.
  1.         ; Сбросить таймер для автоподсчета времени
  2.         mov     eax,[pProgress]
  3.         mov     eax,[eax]
  4.         stdcall dword [eax+IProgressDialog.Timer],[pProgress],\
  5.                 PDTIMER_RESET,NULL
  6.  
  7.         ; Запустить прогресс
  8.         mov     eax,[pProgress]
  9.         mov     eax,[eax]
  10.         stdcall dword [eax+IProgressDialog.StartProgressDialog],[pProgress],\
  11.                 [hwnddlg],NULL,\
  12.                 PROGDLG_MODAL+PROGDLG_AUTOTIME,\
  13.                 NULL
Управление окном прогресса выполняется по таймеру или в отдельном потоке в цикле с периодической задержкой. Каждый раз сперва проверяется, была ли нажата пользователем кнопка отмены, так как это действие никаким образом не уведомляет родительское приложение:
  1.         ; Кнопка отмены нажата?
  2.         mov     eax,[pProgress]
  3.         mov     eax,[eax]
  4.         stdcall dword [eax+IProgressDialog.HasUserCancelled],[pProgress]
  5.         cmp     eax,TRUE
  6.         je      .loc_cancel
Затем выполняются запланированные действия, самостоятельно считается процент их выполнения, после чего устанавливается новый уровень заполнения полоски прогресса. Границы совершенно не обязательно должны быть от 0 до 100, это могут быть произвольные значения, все зависит от задачи.
  1.         ; Обновить прогресс выполнения
  2.         mov     eax,[pProgress]
  3.         mov     eax,[eax]
  4.         stdcall dword [eax+IProgressDialog.SetProgress],[pProgress],\
  5.                 [percent],100
Когда прогресс достигнет финального значения или будет нажата и соответствующим образом обработана кнопка отмены, надо остановить окно прогресса и освободить выделенные под него ресурсы.
  1.         ; Остановить диалог
  2.         mov     eax,[pProgress]
  3.         mov     eax,[eax]
  4.         stdcall dword [eax+IProgressDialog.StopProgressDialog],[pProgress]
  5.  
  6.         ; Прибраться за собой
  7.         mov     eax,[pProgress]
  8.         mov     eax,[eax]
  9.         stdcall dword [eax+IProgressDialog.Release],[pProgress]
Как видите, ничего сложного в работе с системным окном прогресса нет. Осваивайте COM, это открывает практически безграничные возможности работы с системой.

В приложении пример программы с исходным текстом, которая выводит окно прогресса и обрабатывает связанные с ним события.

Пример программы с исходным текстом (FASM)Пример программы с исходным текстом (FASM)

System.ProgressBar.Demo.zip (3,661 bytes)


Поделиться ссылкой ВКонтакте
Просмотров: 583 | Комментариев: 2

Метки: Assembler, COM
Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
ManHunter (02.02.2023 в 19:50):
Обнови
Nemo (02.02.2023 в 19:49):
То же в x84 https://www.justbeamit.com/gwr6f

Кстати, GUID Helper 1.5 -> в интерфейсе IProgressDialog ошибка
Нет функции HasUserCancelled

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.06 сек. / MySQL: 2 (0.0037 сек.) / Память: 4.5 Mb
Наверх