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

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

Метки:
  1. Mikl___

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

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.748
    Глава пятая. Братец Кролик разбирается с потрохами MessageBox

    MessageBox относится к диалоговому окну, специальному виду окон, позволяющих вести диалог с программой. Обмен информацией с программой и задание режимов ее работы осуществляется с помощью кнопок разного вида и с разными свойствами. Все кнопки, так же как сама диалоговая панель, являются окнами и их можно создавать в программе при помощи соответствующих функций Windows. В отличии от оконных приложений, при вызове диалогового окна значительную часть работы по созданию и поддержке таких окон берет на себя операционная система, что упрощает логику программы.
    Диалог, представляет собой окно со специальными свойствами, может существовать и без главного окна, образуя специфический тип "безоконного" приложения. Такие приложения, состоящие из одного диалогового окна, оказываются значительно проще программ с "главным окном".
    функция MessageBox создает на экране диалоговую панель с текстом, заданным параметром lpszText и заголовком, заданным параметром lpszTitle.
    Код (C):
    1. int WINAPI MessageBox(HWND hwndParent, LPCSTR lpszText, LPCSTR lpszTitle, UINT fuStyle);
    Параметры
    hwndParent
    указывает идентификатор родительского окна, создающего диалоговую панель. Если равен NULL, в этом случае у диалоговой панели не будет родительского окна. Можно вызвать функцию MessageBox из функции диалога, в этом случае первый параметр должен содержать идентификатор окна диалоговой панели.
    lpszText
    текст на диалоговой панели
    lpszTitle
    заголовок. Если заголовок равен NULL ― заголовка нет.
    fuStyle
    определяет стиль и внешний вид диалоговой панели, а также количество кнопок, расположение на диалоговой панели, надписи на этих кнопках и так далее Битовые флаги могут быть указаны по отдельности или вместе ― через OR.
    fuStyleHexbitsfree
    1MB_OK0
    2MB_OKCANCEL10
    3MB_ABORTRETRYIGNORE21
    4MB_YESNOCANCEL31-0
    5MB_YESNO42
    6MB_RETRYCANCEL52,0
    7MB_CANCELTRYCONTINUE62,1
    8MB_TYPEMASKF3-03
    9MB_NOICON0
    10MB_ICONHAND,
    MB_ICONERROR,
    MB_ICONSTOP
    104
    11MB_ICONQUESTION205
    12MB_ICONEXCLAMATION,
    MB_ICONWARNING
    305,4
    13MB_ICONASTERISK,
    MB_ICONINFORMATION
    406
    14MB_USERICON807
    15MB_ICONMASKF07-4
    16MB_DEFBUTTON10
    17MB_DEFBUTTON21008
    18MB_DEFBUTTON32009
    19MB_DEFBUTTON43009,8
    20MB_DEFMASKF0011-811,10
    21MB_APPLMODAL0
    22MB_SYSTEMMODAL100012
    23MB_TASKMODAL200013
    24MB_MODEMASK300013,12
    26MB_HELP400014
    27MB_NOFOCUS800015
    28MB_MISCMASKC00015,14
    29MB_SETFOREGROUND1000016
    30MB_DEFAULT_DESKTOP_ONLY2000017
    31MB_TOPMOST4000018
    31MB_NOTIFICATION_NT3X4000018
    32MB_RIGHT8000019
    33MB_RTLREADING10000020
    34MB_SERVICE_NOTIFICATION2000002131-22
    88.png
    Внимательно посмотрев на диапазон значений (от 0 до 200000h), мы увидим, что используется только 19 флагов (битов) из 32 возможных ― что оставляет 13 флагов, которые ещё не определены.
    А теперь более подробно.
    MessageBox не самостоятельная функция, а может быть вызвана только, чтобы передать сообщение от программы-владельца. Владелец MessageBox'а у нас идентифицируется по параметру hwndParent. Если, как в данном примере, "программы-владельца" нет, тогда hwndParent = 0, что означает "программой-владельцем" данного MessageBox является "заданный по умолчанию рабочий стол" ― первая запущенная прикладная программа, после того, как пользователь вошел в систему.
    Сообщение через MessageBox пользователю, который еще не ввел логин/пароль может послать служба операционной системы (например, CSRSS.EXE), но как быть, ведь пользователь еще не вошел в систему и у него нет активного рабочего стола? Для этого нужно в функцию MessageBox помимо прочих флагов передать MB_SERVICE_NOTIFICATION Во время запуска, используйте функцию GetVersionEx, чтобы проверить системную версию. Тогда при продолжении запуска Windows NT 3.x, используйте MB_SERVICE_NOTIFICATION_NT3X = 40000h, а для Windows NT 4.0, используйте MB_SERVICE_NOTIFICATION = 200000h
    Код (C):
    1. #ifdef _WIN32_WINNT
    2. #if (_WIN32_WINNT >= 0x0400)
    3. #define MB_SERVICE_NOTIFICATION 0x00200000L
    4. #else
    5. #define MB_SERVICE_NOTIFICATION 0x00040000L
    6. #endif
    7. #define MB_SERVICE_NOTIFICATION_NT3X 0x00040000L
    8. #endif
    Код (ASM):
    1. OSVERSIONINFO struct
    2.  dwOSVersionInfoSize DWORD ?
    3.  dwMajorVersion DWORD ?
    4.  dwMinorVersion DWORD ?
    5.  dwBuildNumber DWORD ?
    6.  dwPlatformId DWORD ?
    7.  szCSDVersion BYTE 128 dup(?)
    8. OSVERSIONINFO ends
    9.  
    10. local VersionInfo:OSVERSIONINFO
    11.  ....
    12.  lea ecx,VersionInfo
    13.  mov [rcx].OSVERSIONINFO.dwOSVersionInfoSize,sizeof OSVERSIONINFO
    14.  invoke GetVersionEx
    15.  mov eax,VersionInfo.dwMajorVersion;6
    16.  mov eax,VersionInfo.dwMinorVersion;1
    Количество и тип кнопок

    Первые два бита (2-0) и 14-ый бит определяют количество кнопок и надписи на них
    fuStylehexbin
    MB_OK0000000000000000000000000[​IMG]
    MB_OKCANCEL1000000000000000000000001[​IMG]
    MB_ABORTRETRYIGNORE2000000000000000000000010[​IMG]
    MB_YESNOCANCEL3000000000000000000000011[​IMG]
    MB_YESNO4000000000000000000000100[​IMG]
    MB_RETRYCANCEL5000000000000000000000101[​IMG]
    MB_CANCELTRYCONTINUE6000000000000000000000110[​IMG]
    MB_TYPEMASK0Fh000000000000000000001111используется для программного определения типа MessageBox. По количеству битов можно предположить, что сочетаний кнопок может быть и больше (от 0 до 0Eh)
    Код (C):
    1. int _CustomMessageBoxShowButtons ( HWND hwndDlg, UINT uType)
    2.  { int nVisibleButtons = 0;
    3.  switch(MB_TYPEMASK & uType)
    4.  {case MB_OKCANCEL:
    5.  ::ShowWindow(::GetDlgItem(hwndDlg, IDCANCEL), SW_SHOW);
    6.  ++nVisibleButtons; // Fallsthrough
    7.  case MB_OK:
    8.  ::ShowWindow(::GetDlgItem(hwndDlg, IDOK), SW_SHOW);
    9.  ++nVisibleButtons;
    10.  break;
    11.  case MB_YESNOCANCEL:
    12.  ::ShowWindow(::GetDlgItem(hwndDlg, IDCANCEL), SW_SHOW);
    13.  ++nVisibleButtons; // Fallsthrough
    14.  case MB_YESNO:
    15.  ::ShowWindow(::GetDlgItem(hwndDlg, IDYES), SW_SHOW);
    16.  ::ShowWindow(::GetDlgItem(hwndDlg, IDNO), SW_SHOW);
    17.  nVisibleButtons += 2;
    18.  break;
    19.  case MB_ABORTRETRYIGNORE:
    20.  ::ShowWindow(::GetDlgItem(hwndDlg, IDABORT), SW_SHOW);
    21.  ::ShowWindow(::GetDlgItem(hwndDlg, IDRETRY), SW_SHOW);
    22.  ::ShowWindow(::GetDlgItem(hwndDlg, IDIGNORE), SW_SHOW);
    23.  nVisibleButtons = 3;
    24.  break;
    25.  case MB_RETRYCANCEL:
    26.  ::ShowWindow(::GetDlgItem(hwndDlg, IDRETRY), SW_SHOW);
    27.  ::ShowWindow(::GetDlgItem(hwndDlg, IDCANCEL), SW_SHOW);
    28.  nVisibleButtons = 2;
    29.  break; #if(WINVER >= 0x0500)
    30.  case MB_CANCELTRYCONTINUE:
    31.  ::ShowWindow(::GetDlgItem(hwndDlg, IDCANCEL), SW_SHOW);
    32.  ::ShowWindow(::GetDlgItem(hwndDlg, IDTRYAGAIN), SW_SHOW);
    33.  ::ShowWindow(::GetDlgItem(hwndDlg, IDCONTINUE), SW_SHOW);
    34.  nVisibleButtons = 3;
    35.  break;
    36.  #endif
    37.  default: // Not implemented yet
    38.  _ASSERTE(!"Not implemented");
    39.  break;
    40.  }
    41.  if (MB_HELP & uType)
    42.  {
    43.  ::ShowWindow(::GetDlgItem(hwndDlg, IDHELP), SW_SHOW);
    44.  ++nVisibleButtons; }
    45.  return nVisibleButtons; }
    MB_HELP4000h00000000010000000000XXXдополнительную кнопку "Помощь" можно добавить к любому сочетанию клавиш
    [​IMG]
    • Нажатие на кнопку [​IMG], или нажатие клавиши ESC, или выбор кнопки [​IMG] возвращает значение IDCANCEL=2.
    • Если у MessageBox стиль MB_OK, то нажатие клавиши ESC, или выбор кнопки [​IMG]возвращает значение IDOK=1.
    • Если у окна сообщений нет кнопки [​IMG], (стили MB_YESNO, MB_ABORTRETRYIGNORE), тогда кнопка [​IMG] не активизирована и нажатие на ESC не имеет никакого эффекта.
    • Выбор кнопки [​IMG] или нажатие F1 генерирует событие "появления Справки".
    • Остальные кнопки реагируют на mouse-click или на нажатие Enter если кнопка имеет фокус.
    Иконки
    4 следующих бита (8-4) определяют иконку
    fuStylehexbin
    MB_NOICON00h000000000000000000000000[​IMG]
    MB_ICONHAND,
    MB_ICONERROR,
    MB_ICONSTOP
    10h000000000000000000010000[​IMG]
    MB_ICONQUESTION20h000000000000000000100000[​IMG]
    MB_ICONEXCLAMATION,
    MB_ICONWARNING
    30h000000000000000000110000[​IMG]
    MB_ICONASTERISK,
    MB_ICONINFORMATION
    40h000000000000000001000000[​IMG]
    По количеству битов можно предположить, что иконок может быть и больше (от 0 до 7), но реально значениям с 50h по 70h не соответствуют никакие иконки.
    MB_USERICON80h000000000000000010000000иконка, выбранная пользователем
    [​IMG]
    MB_ICONMASKF0h000000000000000011110000для программного определения иконки
    Пример программного определения типа кнопки
    Код (C):
    1. void _CustomMessageBoxSetIcon( HWND hwndDlg, UINT uType)
    2. {       switch(MB_ICONMASK & uType)
    3.        {case MB_ICONEXCLAMATION:
    4.         ::SendDlgItemMessage(hwndDlg, ID_MSGBOXICON,
    5. STM_SETICON, (WPARAM)::LoadIcon(NULL, IDI_EXCLAMATION), 0);
    6.         break;
    7.     case MB_ICONQUESTION:
    8.         ::SendDlgItemMessage(hwndDlg, ID_MSGBOXICON,
    9. STM_SETICON, (WPARAM)::LoadIcon(NULL, IDI_QUESTION), 0);
    10.         break;
    11.     case MB_ICONASTERISK:
    12.         ::SendDlgItemMessage(hwndDlg, ID_MSGBOXICON,
    13. STM_SETICON, (WPARAM)::LoadIcon(NULL, IDI_ASTERISK), 0);
    14.         break;
    15.     case MB_ICONHAND:
    16.         ::SendDlgItemMessage(hwndDlg, ID_MSGBOXICON,
    17. STM_SETICON, (WPARAM)::LoadIcon(NULL, IDI_HAND), 0);
    18.         break;
    19.     default: // Turn off the icon
    20.         ::ShowWindow(::GetDlgItem(hwndDlg, ID_MSGBOXICON), SW_HIDE);
    21.         break;    }
    22. }
     
    Последнее редактирование: 19 мар 2019
    rasstriga нравится это.
  2. Mikl___

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

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.748
    Фокус ввода
    По умолчанию, после инициализации диалоговой панели фокус ввода имеет первая кнопка. Вы можете определить в качестве кнопки, используемой "по умолчанию" любую из четырех кнопок с помощью следующих констант:
    hexbin
    MB_DEFBUTTON1000000000000000000000000000 MB_08.png
    MB_DEFBUTTON2100000000000000000100000000 MB_09.png
    MB_DEFBUTTON3200000000000000001000000000 MB_10.png
    MB_DEFBUTTON4300000000000000001100000000 MB_11.png
    MB_DEFMASKF00000000000000111100000000для программного определения
    Модальность окна сообщения
    Немодальный диалог (MessageBox со стилем MB_APPLMODAL) пользователь должен ответить MessageBox'у, прежде чем продолжать работу в текущем окне. Пользователь может перейти на окна других приложений и работать в этих окнах. Немодальный диалог не задерживает выполнение программы, для продолжения работы программы не требуется завершение диалога MessageBox. Разрешается переключаться между диалогом MessageBox и другими приложениями.
    Модальный диалог. (MessageBox со стилем MB_SYSTEMMODAL) все приложения приостанавливаются, пока пользователь не ответит в окне MessageBox. Система модальных диалогов используется для уведомления пользователя о серьезных или потенциально опасных ошибках, которые требуют немедленного внимания и следует использовать этот стиль с осторожностью. Модальный диалог не позволит переключить ввод на другие окна, порожденные приложением.
    MessageBox со стилем MB_TASKMODAL аналогичен MessageBox со стилем MB_APPLMODAL. Эта константа зарезервирован для вызывающего приложения или библиотеки, которые не имеет доступа к дескриптору окна MessageBox.
    Чтобы понять что такое модальный или немодальный диалог, просто запустите какую-нибудь программу а затем выведите на экран MessageBox со стилем MB_SYSTEMMODAL, а теперь попробуйте переключиться на основное меню другой программы. Вы обнаружите, что не можете это сделать, потому что MessageBox блокирует фокус окна. MessageBox как бы говорит пользователю: "Сперва разберись со мной, а потом уже и все остальные программы" вы будете должны закрыть MessageBox, прежде чем сможете продолжить работу с остальными программами.
    Противополжоностью ему является MessageBox со стилем MB_APPLMODAL, когда он появится на экране, вы имеете доступ и к ней, и к главному окну другой программы.
    Диалоги бывают двух видов:
    • модальные
    • немодальные
    Модальный диалог характерен тем, что после открытия MessageBox MB_SYSTEMMODALпользователь может работать только с его элементами управления, а все остальные окна приложения блокируются до тех пор, пока модальный диалог не будет закрыт. Модальные диалоги рекомендуется использовать в тех случаях, когда без информации, вводимой через окно диалога, программа не может больше рботать. Если, например, программа на некотором этапе должна ввести данные из того или иного файла, то выбор конкретного файла естественно выполнить с помощью модального диалогового окна. Нормальное состояние модального диалога ― закрытое.
    Немодальный диалог не препятствует пользователю работать с любыми элементами главного окна приложеия или его внутренних окон. С помощью немодальных диалогов задают масштаб, цвет и другие свойства приложения. Нормальное состояние немодального диалога ― открытое.
    Другой вид диалоговых панелей ― это немодальные диалоговые панели. В отличие от модальных диалоговых панелей блокирующих при своем появлении родительское окно и все дочерние окна родительского окна, немодальные диалоговые панели работают параллельно с другими окнами приложения без взаимных блокировок. Вы можете работать как с главным окном приложения, так и окном немодальной диалоговой панели. Немодальные диалоговые панели очень удобны для объединения различных инструментальных средств, предназначенных для работы с объектом, расположенным в главном окне или в дочернем окне, созданным главным окном приложения.(Фроловы)
    С помощью бит 12 и 13 вы можете влиять на модальность MessageBox

    Прочее
    Кроме перечисленных выше флагов, объединенных в группы, пользователь может использовать следующие флаги

    hexbinОписание
    MB_HELP4000h000000000100000000000000
    MB_NOFOCUS8000h000000001000000000000000 FOCUS.png NOFOCUS.png
    MB_MISCMASK0C000h000000001100000000000000используется для программного определения типа MessageBox
    Z-последовательность

    Z-последовательность (Z order) окна обозначает позицию окна в стеке перекрывающихся окон. Этот оконный стек ориентируется по воображаемой оси, z-оси (оси аппликат), уходящей за пределы экрана. Окно наверху Z-последовательности перекрывает все другие окна. Окно внизу Z-последовательности перекрыто всеми другими окнами.
    Windows Z-последовательность сохраняет в обычном списке. Добавляя окна в Z-последовательность, она основывается на том, что в любом случае они самые верхние окна, окна верхнего уровня или дочерние окна. Самое верхнее окно (topmost window) накладывается на все другие не самые верхние окна, независимо от того, является ли они активными или приоритетными окнами. Самое верхнее окно имеет стиль WS_EX_TOPMOST. Все самые верхние окна появляются в Z-последовательности перед любыми не самыми верхними окнами. Дочернее окно сгруппировано со своим родителем в Z-последовательности.
    Когда прикладная программа создает окно, Windows помещает его наверху Z-последовательности для окон того же самого типа. Вы можете использовать функцию BringWindowToTop, чтобы перенести окно в верхнюю часть Z-последовательности для окон того же самого типа. Вы можете перестраивать Z-последовательность, используя функции SetWindowPos и DeferWindowPos.
    Пользователь изменяет порядок Z-последовательности, активизируя различные окна. Windows устанавливает активное окно наверху Z-последовательности для окон того же самого типа. Когда окно переходит в верхнюю часть Z-последовательности, его дочерние окна делают это также. Вы можете использовать функцию GetTopWindow, чтобы отыскать все дочерние окна родительского окна и возвратить дескриптор дочернего окна, которое является самым высоким в Z-последовательности. Функция GetNextWindow извлекает данные о дескрипторе следующего или предыдущего окна в Z-последовательности.
    В Windows используется z порядок окон. Окна распологаются одно над другим по вертикали. Окно на верху лежит поверх всех. Нижнее окно в самом низу, остальные в промежутке. Для этого в Windows существует специальный список, в котором эти окна расположены. Важность окна зависит от стиля окна. Самую высокую важность имеет стиль WS_EX_TOPMOST.
    Когда система создает окно она помещает это окно на самом верху относительно окон того же самого типа. Вы можете использовать функцию BringWindowToTop, чтобы вывести окно наверх относительно окон того же самого типа. Вы можете реорганизовать порядок, используя функции DeferWindowPos и SetWindowPos.
    Функция GetNextWindow возвращает указатель к следующему или предыдущему окну в Z-порядке. Для поиска подчиненных окон используется функция GetTopWindow.
    Окно поверх всех остальных
    Вы наверно сталкивались с программами, которые всегда поверх остальных окон.
    MB_TOPMOST.png
    Если Вы запустите диалоговое приложение и нажмете на его кнопки, ваше диалоговое окно будет поверх всех остальных.
    Определите один из следующих флажков, чтобы указать модальность диалогового окна:
    Замечания
    Приоритетное окно ― окно наверху Z-последовательности. Это ― окно, с которым пользователь работает. В среде приоритетной многозадачности, Вы должны вообще дать возможность управления пользователю, окно которого является приоритетным окном. Однако прикладная программа может вызывать функцию SetForegroundWindow, если требуется перевести себя в активный режим, чтобы отобразить критическую ошибку или информацию, которая требует непосредственного внимания пользователя. Хороший пример ― это отладчик, когда он обнаруживает контрольную точку останова программы. Система назначает немного более высокий приоритет потоку, который создал приоритетное окно, чем она делает это по отношению к другим потокам.
    Если закрыть окно-хозяин (Parent window), то все MessageBox исчезают. После закрытия окна MessageBox со стилем MB_SERVICE_NOTIFICATION и MessageBox со стилем MB_DEFAULT_DESKTOP_ONLY остаются на экране
    Отобразить сообщение MessageBox может любая служба, для этого нужно в функцию MessageBoxпомимо прочих флагов передать MB_SERVICE_NOTIFICATION или MB_DEFAULT_DESKTOP_ONLY. Флаг MB_SERVICE_NOTIFICATION заставит функцию вывести сообщение на экран, даже если пользователь ещё не вошёл в систему.
    Если установлен флаг MB_DEFAULT_DESKTOP_ONLY, сообщение появится только на "нормальном" рабочем столе. MB_SERVICE_NOTIFICATION заставляет сообщение появиться на текущем активном desktop-е, а MB_DEFAULT_DESKTOP_ONLY только на "нормальном".
    MB_SERVICE_NOTIFICATION.png
    ПриоритетСтильbin
    1MB_SERVICE_NOTIFICATION001000000000000000000000
    1MB_DEFAULT_DESKTOP_ONLY000000100000000000000000
    2MB_TOPMOST000001000000000000000000
    2MB_SYSTEMMODAL000000000001000000000000
    3MB_SETFOREGROUND000000010000000000000000
    3MB_TASKMODAL000000000010000000000000
    3MB_OK/MB_APPLMODAL000000000000000000000000
    • если первым запущен MessageBox со стилем MB_SERVICE_NOTIFICATION, то запущенный после него MessageBox со стилем MB_DEFAULT_DESKTOP_ONLY окажется под MessageBoxсо стилем MB_SERVICE_NOTIFICATION
    • если первым запущен MessageBox со стилем MB_DEFAULT_DESKTOP_ONLY, то запущенный после него MessageBox со стилем MB_SERVICE_NOTIFICATION окажется под MessageBox со стилем MB_DEFAULT_DESKTOP_ONLY
    • несколько запущенных MessageBox со стилем MB_DEFAULT_DESKTOP_ONLY окажутся друг под другом
    • несколько запущенных MessageBox со стилем MB_SERVICE_NOTIFICATION окажутся друг под другом
    hexbinОписание
    MB_SETFOREGROUND10000h000000010000000000000000Панель MessageBox становится окном переднего плана. При появлении окна со стилем MB_SETFOREGROUND операционная система вызывает функцию SetForegroundWindow для MessageBox'а. Информацию о мерах безопасности при использовании этого флага смотрите в разделе "Интерактивные службы". Этот флаг может создавать интерактивный контент на заблокированном рабочем столе и должен использоваться только для очень ограниченного набора сценариев, таких как исчерпание ресурсов.
    Функция SetForegroundWindow переводит поток, который создало определяемое окно в приоритетный режим и активизирует окно. Ввод с клавиатуры направлен в окно, а различные визуальные ориентиры изменяются для пользователя.]
    Код (C):
    1. BOOL SetForegroundWindow
    2. ( HWND hWnd /* дескриптор окна, которое переводится в приоритетный режим */);
    hWnd идентифицирует окно, которое должно быть активизировано и переведено в приоритетный режим. Если функция завершилась успешно, возвращается значение отличное от нуля
    MB_DEFAULT_DESKTOP_ONLY20000h000000100000000000000000Если текущий рабочий стол ввода не является рабочим столом по умолчанию, MessageBox не возвращается, пока пользователь не переключится на рабочий стол по умолчанию. "Заданный по умолчанию" рабочий стол ― первая запущенная прикладная программа, после того, как пользователь вошел в систему.
    MB_TOPMOST40000h000001000000000000000000MessageBox создается со стилем окна WS_EX_TOPMOST Рабочий стол, получивший фокус ввода должен быть рабочим столом, выбираемым по умолчанию. В противном случае функция завершается с ошибкой. Под рабочим столом, выбираемым по умолчанию, понимается рабочий стол, появляющийся после загрузки системы;
    MB_SERVICE_NOTIFICATION_NT3X40000h000001000000000000000000Вызывающая программа является обслуживающей по уведомлению пользователя о событии. Функция отображает MessageBox на текущем активном рабочем столе, даже если никто из пользователей не вошел в систему компьютера. Если этот флажок установлен, параметр hwndParent должен быть равным NULL. MessageBox с флагом MB_SERVICE_NOTIFICATION_NT3X может появляться на другом рабочем столе, а не только на том, которое соответствует hwndParent.
    MB_RIGHT80000h000010000000000000000000Обычный текст
    MB_18.png
    MessageBox с выравниванием текста в правую сторону
    MB_19.png
    MB_RTLREADING100000h000100000000000000000000Предназначен для работы с текстом на иврите или арабском. "Зеркалит" текст сообщения и расположение кнопок и иконки. Довольно интересный эффект ― обратное расположение слов в тексте сообщения
    MB_20.png
    MB_SERVICE_NOTIFICATION200000h001000000000000000000000Для Windows NT версии 4.0, значение MB_SERVICE_NOTIFICATION изменилось. Смотрите winuser.hдля старых и новых значений. Windows NT 4.0 обеспечивает совместимость вниз для существующих ранее услуг, при помощи преобразования данных старых значений в новых значениях при реализации MessageBox и MessageBoxEx. Это преобразование данных делается только для исполнимых программ (.exe), которые имеют номер версии, как установлено компоновщиком, меньше чем 4.0.
    Чтобы сформировать обслуживание, которое использует MB_SERVICE_NOTIFICATION и возможность запускать, и Windows NT 3.x и Windows NT 4.0, у вас два варианта:
    1. Во время компоновки, определите номер версии меньше чем 4.0; или
    2. Во время компоновки, определите версию 4.0.
    Во время запуска, используйте функцию GetVersionEx, чтобы проверить системную версию. Тогда при продолжении запуска Windows NT 3.x, используйте MB_SERVICE_NOTIFICATION_NT3X; а для Windows NT 4.0, используйте MB_SERVICE_NOTIFICATION.
    Возвращаемые значения
    Функция MessageBox возвращает нулевое значение при ошибке или одну из следующих констант, в зависимости от того, какую кнопку нажал пользователь.
    КонстантаЗначениеНазвание
    кнопки
    Примечание
    IDOK
    1​
    [​IMG]
    IDCANCEL
    2​
    [​IMG]
    IDABORT
    3​
    [​IMG]
    IDRETRY
    4​
    [​IMG]
    IDIGNORE
    5​
    [​IMG]
    IDYES
    6​
    [​IMG]
    IDNO
    7​
    [​IMG]
    IDCANCEL
    2​
    [​IMG]
    Если у MessageBox стиль MB_OK, тогда будет возвращено IDOK, хотя есть стиль IDCLOSE=8
    IDHELP
    9​
    [​IMG]Если у MessageBox MB_HELP
    IDTRYAGAIN
    10​
    [​IMG]
    IDCONTINUE
    11​
    [​IMG]


    © Mikl___ 2019
     

    Вложения:

    • MB_29.png
      MB_29.png
      Размер файла:
      717 байт
      Просмотров:
      128
    • MB_28.png
      MB_28.png
      Размер файла:
      432 байт
      Просмотров:
      131
    • 89.png
      89.png
      Размер файла:
      7,8 КБ
      Просмотров:
      115
    Последнее редактирование: 26 мар 2019
    rasstriga нравится это.
  3. Mikl___

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

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.748
    Глава шестая. Братец Кролик выводит MessageBox всеми возможными способами

    Казалось бы, что может быть проще функции MessageBox? Но Братецу Кролику, в погоне за минимальным размером, захотелось узнать, а что находится внутри MessageBox? Может быть это поможет ему сделать программы еще меньше? Братец Кролик запустил программу, выводящую MessageBox на экран, в дебаггере Ollydbg и в тот момент, когда курсор дошел до строки call MessageBoxA нажал не на F8 (Step over), а на клавишу F7 (Step into) и оказался внутри функции MessageBoxA ― оказывается здесь происходит перекодировка ASCII-строк заголовка и текста сообщений в UNICODE и вызов функции MessageBoxW. Братец Кролик снова нажал на F7 ― оказывается внутри MessageBoxWфункция MessageBoxExA которая имеет на один параметр больше, чем MessageBoxA и MessageBoxW и этот параметр (dwLanguageId) равен 0 (LANG_NEUTRAL), остальные же параметры совпадают полностью. Внутри MessageBoxExA находится функция MessageBoxExW. Внутри MessageBoxExW ― функция MessageBoxTimeoutA у которой на один параметр больше, чем у MessageBoxExW и этот параметр (Timeout) равен -1 (INFINITE). Внутри MessageBoxTimeoutA, (как можно было догадаться :) ) MessageBoxTimeoutW. Внутри MessageBoxTimeoutWMessageBoxIndirectA эта функция позволяет поменять иконку у MessageBox и может вызвать Справку, но мы оставляем эти параметры с нулевым значением. Внутри MessageBoxIndirectA находится точно такая же, но с UNICODE-строками функция MessageBoxIndirectW внутри которой SoftModalMessageBox внутри которой NtRaiseHardError ― вызов MessageBox на уровне ядра
    Традиционный способ определения Unicode-строки:
    Код (ASM):
    1. usz dw 'U', 'n', 'i', 'c', 'o', 'd', 'e', ' ', 's', 't', 'r', 'i', 'n', 'g', 0
    Братца Кролика этот способ не устраивал, поэтому, он написал для этой цели макрос du (define unicode string), чтобы без проблем переводить ASCII-строки в UNICODE-строки
    Код (ASM):
    1. du    macro string
    2. local bslash
    3. bslash = 0
    4. irpc c,<string>
    5. if bslash eq 0
    6.     if '&c' eq '\' ;управляющая последовательность символов
    7.     bslash = 1
    8.     elseif '&c' eq "ё"
    9.     db 51h,4
    10.     elseif '&c' eq "Ё"
    11.     db 1,4
    12.     elseif '&c' gt 127
    13.     db ('&c'- 0B0h),4;;кириллица
    14.     else
    15.     dw '&c'          ;;латиница
    16.     endif
    17. else
    18. bslash = 0
    19.     if '&c' eq "n"    ;;  \n = новая строка
    20.         DW 0Dh,0Ah
    21.         elseif '&c' eq "\";;  \\ = обратная косая черта (\)
    22.         dw '\'
    23.         elseif '&c' eq "r";;  \r = возврат каретки
    24.         dw 0Dh
    25.         elseif '&c' eq "l";;  \l = LF
    26.         dw 0Ah
    27.         elseif '&c' eq "s"
    28.         dw 20h
    29.         elseif '&c' eq "c"
    30.         dw 3Bh
    31.         elseif '&c' eq "t";;  \t = табуляция
    32.         dw 9
    33.     endif
    34. endif
    35. endm
    36. dw 0
    37. endm
    этот макрос превращает ASCII-символы латиницы в UNICODE-символы добавлением после кода символа нуля, а для кириллицы заменяет 0 на 4 и сдвигает код символа на 176, в конце UNICODE-строки ставится ноль, терминирующий строку. Всё, что требуется от пользователя ― после du написать строку в угловых скобках. То есть представить Unicode-строку так:
    Код (ASM):
    1. usz: du <Unicode string>
    обратите внимание, что после названия строки стоит двоеточие.
    MessageBoxEx

    Функция MessageBoxEx создает, отображает на экране и оперирует окном сообщений. Окно сообщений содержит определяемое программой сообщение и заголовок, плюс любую комбинацию предопределенных пиктограмм и командных кнопок. Параметр wLanguageId определяет, какой устанавливается ресурс языка, который используется для предопределенных командных кнопок.
    Синтаксис
    Код (C):
    1. int MessageBoxEx
    2. (
    3.     HWND hWnd,        // дескриптор окна владельца
    4.     LPCTSTR lpText,        // адрес текста в окне сообщений
    5.     LPCTSTR lpCaption,    // адрес заголовка в окне сообщений
    6.     UINT uType,         // стиль окна сообщений
    7.     DWORD dwLanguageId    // идентификатор языка
    8. );
    Параметры

    hWnd
    Идентифицирует окно владельца блока сообщений, которым оно было создано. Если этот параметр имеет значение NULL, у блока сообщения нет окна владельца.
    lpText
    Указывает на строку с символом нуля в конце, содержащую сообщение, которое должно быть отражено на экране.
    lpCaption
    Указывает на строку с символом нуля в конце, используемую для заголовка диалогового окна. Если этот параметр значение NULL, то по умолчанию используется заголовок "Ошибка" ("Error").
    uType
    Определяет установку битов флажков, которые обуславливают содержание и поведение диалогового окна. Этот параметр может быть комбинацией флажков.
    dwLanguageId
    Определяет язык, на котором будет отображаться текст, содержащийся в предопределенных командных кнопках. Это значение должно быть в форме, возвращающей макрокомандойMAKELANGID.
    Каждый привязанный к конкретной стране выпуск Windows обычно содержит ресурсы только для ограниченного набора языков. Таким образом американская версия предлагает LANG_ENGLISH, французская ― LANG_FRENCH, немецкая ― LANG_GERMAN и японская (а Вы как ожидали?), соответственно, ― LANG_JAPANESE. Каждая версия предлагает LANG_NEUTRAL. Это ограничивает установку значений, которые могут использоваться с параметром dwLanguageId. Перед определением идентификатора языка, Вы должны перечислить территории, которые установлены на системе.
    Замечания

    Когда Вы используете системно-модальное окно сообщений, чтобы указать, что система имеет мало памяти, строки, переданные как параметры lpText и lpCaption не должны быть приняты из файла ресурса, так как попытка загрузить ресурс может потерпеть неудачу.
    Когда прикладная программа вызывает MessageBoxEx и устанавливает флажки MB_ICONHAND и MB_SYSTEMMODAL в параметре uType, Win32 API отображает на экране законченное окно сообщений независимо от доступной памяти. Когда эти флажки установлены, Windows ограничивает длину текста окна сообщений до одной строки.
    Если Вы создаете окно сообщений, в то время когда присутствует диалоговое окно, дескриптор блока диалога используется как параметр hWnd. Параметр hWnd не должен идентифицировать дочернее окно, типа диалогового окна.
    MessageBoxTimeout
    Функция MessageBoxTimeout ...
    Синтаксис
    Код (C):
    1. int MessageBoxTimeout
    2. (
    3.     HWND hWnd,        // дескриптор окна владельца
    4.     LPCTSTR lpText,        // адрес текста в окне сообщений
    5.     LPCTSTR lpCaption,    // адрес заголовка в окне сообщений
    6.     UINT uType,         // стиль окна сообщений
    7.     DWORD dwLanguageId,    // идентификатор языка
    8.     DWORD Timeout        // время
    9. );
    MessageBoxIndirect
    Функция MessageBoxIndirect создает, отображает и оперирует окном сообщений. Окно сообщений содержит определяемый программой текст сообщения и заголовок, любую пиктограмму, и любую комбинацию предопределенных командных кнопок.
    Синтаксис
    Код (C):
    1. int MessageBoxIndirect
    2. (
    3.     LPMSGBOXPARAMS lpMsgBoxParams    // адрес структуры для параметров
    4.             // окна сообщений
    5. );
    Параметры

    lpMsgBoxParams
    Указатель на структуру MSGBOXPARAMS, которая содержит информацию, используемую для показа на экране окна сообщений.
    Замечания

    Когда Вы используете системно-модальное окно сообщений, чтобы указать, что у системы мало памяти, строки, указанные элементами lpszText и lpszCaption структуры MSGBOXPARAMS не должны быть приняты из файла ресурса, потому что попытка загрузить ресурс может потерпеть неудачу.
    Когда прикладная программа вызывает MessageBoxIndirect и устанавливает флажки MB_ICONHAND и MB_SYSTEMMODAL в элементе dwStyle структуры MSGBOXPARAMS, Windows показывает на экране законченное окно сообщений независимо от доступной памяти. Когда эти флажки установлены, Windows ограничивает длину текста в окне сообщений до трех строк. Windows автоматически не разрывает строки, чтобы подстроить их под окно сообщений, такая строка сообщения должна содержать символы перевода каретки, чтобы разрывать строки в соответствующих местах.
    Если Вы создаете окно сообщений, в то время, когда присутствует диалоговое окно, используйте дескриптор блока диалога как параметр hWnd. Параметр hWnd не должен идентифицировать дочернее окно, типа органа управления в диалоговом окне.
    SoftModalMessageBox
    Функция SoftModalMessageBox создает, отображает и оперирует окном сообщений. Окно сообщений содержит определяемый программой текст сообщения и заголовок, любую пиктограмму, и любую комбинацию предопределенных командных кнопок, любое количество кнопок и любые надписи на кнопках.
    [​IMG]
    Синтаксис
    Код (C):
    1. int SoftModalMessageBox
    2. (
    3.     LPMSGBOXDATA lpMsgBoxData    // адрес структуры для параметров
    4.             // окна сообщений
    5. );
    Параметры
    lpMsgBoxData

    Указатель на структуру MSGBOXDATA, которая содержит информацию, используемую для показа на экране окна сообщений.
    Код (ASM):
    1. MSGBOXPARAMS STRUCT
    2.   cbSize                DWORD      ?,?;размер структуры
    3.   hwndOwner             QWORD      ?;
    4.   hInstance             QWORD      ?;
    5.   lpszText              QWORD      ?;адрес текста в окне сообщений
    6.   lpszCaption           QWORD      ?;адрес заголовка в окне сообщений
    7.   dwStyle               DWORD      ?,?;
    8.   lpszIcon              QWORD      ?;
    9.   dwContextHelpId       DWORD      ?,?;
    10.   lpfnMsgBoxCallback    QWORD      ?;
    11.   dwLanguageId          DWORD      ?,?;идентификатор языка
    12. MSGBOXPARAMS ENDS
    13.  
    14. MSGBOXDATA struct  
    15.      params              MSGBOXPARAMSA <>
    16.      pwndOwner           QWORD ?
    17.      wLanguageId         DWORD ?,?
    18.      pidButton           QWORD ?         ; // Array of button IDs
    19.      ppszButtonText      QWORD ?         ; // Array of button text strings
    20.      cButtons            DWORD ?
    21.      DefButton           DWORD ?
    22.      CancelId            DWORD ?
    23.      Timeout             DWORD ?
    24. MSGBOXDATA ends
    NtRaiseHardError

    статус ошибки
    маска, единичные биты которой соответствуют тем параметрам, которые имеют тип PUNICODE_STRING, а нули ― остальным параметрам
    общее число параметров
    указатель на массив параметров
    варианты ответов
    двойное слово, куда функция запишет выбранный пользователем ответ (если тип, переданный в следующем параметре, предполагает выбор ответа пользователем)
    Код (ASM):
    1. ; GUI #
    2. include win64a.inc
    3. MSGBOXDATA struct  
    4.      params              MSGBOXPARAMS <>
    5.     pwndOwner           QWORD ?
    6.     wLanguageId         DWORD ?,?
    7.      pidButton           QWORD ?         ; // Array of button IDs
    8.      ppszButtonText      QWORD ?         ; // Array of button text strings
    9.      cButtons            DWORD ?
    10.      DefButton           DWORD ?
    11.      CancelId            DWORD ?
    12.      Timeout             DWORD ?
    13. MSGBOXDATA ends
    14. .code
    15. MsgBoxText      db "Win64 Assembly is Great!",0
    16. MsgBoxText1     dw 'W','i','n','6','4',' ','A','s','s','e','m','b','l','y',' ','i','s',' ','G','r','e','a','t','!',10
    17. dw 'W','i','n','6','4',27719,32534,31243,24207,24456,26834,'!',0;du <Win64 Assembly is Great>
    18. MsgCaption0     db "MessageBoxA",0
    19. MsgCaption1:    du <MessageBoxW>
    20. MsgCaption2     db "MessageBoxExA",0
    21. MsgCaption3:    du <MessageBoxExW>
    22. MsgCaption4     db "MessageBoxTimeoutA",0
    23. MsgCaption5:    du <MessageBoxTimeoutW>
    24. MsgCaption6     db "MessageBoxIndirectA",0
    25. MsgCaption7:    du <MessageBoxIndirectW>
    26. MsgCaption8:    du <SoftModalMessageBox>
    27.  
    28. sBTN1: du <OK>
    29.  
    30. dwBtnIds  dd 1
    31. dwTxtTbl  dq sBTN1
    32. x    dq ?
    33. align 16
    34. WinMain proc
    35. local mbxData:MSGBOXDATA
    36. Local MessageBuffer[50h]:WCHAR;в Num+Num1 в вордах
    37. Local Message[2]:UNICODE_STRING
    38. Local HardErrorPointer[3]:PVOID
    39.  
    40. ;MessageBoxA----------------------------------------
    41.     mov edx,offset MsgBoxText
    42.     lea r8,[rdx+MsgCaption0-MsgBoxText]
    43.     invoke MessageBox,0,,,MB_OK+10h
    44.     mov edx,offset MsgBoxText
    45.     lea r8,[rdx+MsgCaption0-MsgBoxText]
    46.     invoke MessageBox,0,,,MB_OK+20h
    47.     mov edx,offset MsgBoxText
    48.     lea r8,[rdx+MsgCaption0-MsgBoxText]
    49.     invoke MessageBox,0,,,MB_OK+30h
    50.     mov edx,offset MsgBoxText
    51.     lea r8,[rdx+MsgCaption0-MsgBoxText]
    52.     invoke MessageBox,0,,,MB_OK+40h
    53.     mov edx,offset MsgBoxText
    54.     lea r8,[rdx+MsgCaption0-MsgBoxText]
    55.     invoke MessageBox,0,,,MB_OK+90h
    56.     mov edx,offset MsgBoxText
    57.     lea r8,[rdx+MsgCaption0-MsgBoxText]
    58.     invoke MessageBox,0,,,MB_OK+0A0h
    59.     mov edx,offset MsgBoxText
    60.     lea r8,[rdx+MsgCaption0-MsgBoxText]
    61.     invoke MessageBox,0,,,MB_OK+0B0h
    62. ;MessageBoxW----------------------------------------
    63.     mov edx,offset MsgBoxText1
    64.     lea r8,[rdx+MsgCaption1-MsgBoxText1]
    65.     invoke MessageBoxW,0,,,MB_OK; or MB_ICONASTERISK
    66. ;MessageBoxExA--------------------------------------
    67.     xor ecx,ecx
    68.     mov [rsp+20h],rcx    ;wLanguageId
    69.     mov edx,offset MsgBoxText
    70.     lea r8,[rdx+MsgCaption2-MsgBoxText]
    71.         invoke MessageBoxEx,,,,MB_OK; or MB_ICONASTERISK
    72. ;MessageBoxExW--------------------------------------
    73.     xor ecx,ecx    
    74.     mov [rsp+20h],rcx    ;wLanguageId=LANG_NEUTRAL=0
    75.     mov edx,offset MsgBoxText1
    76.     lea r8,[rdx+MsgCaption3-MsgBoxText1]
    77.         invoke MessageBoxExW,,,,MB_OK; or MB_ICONASTERISK
    78. ;MessageBoxTimeoutA---------------------------------
    79.     xor ecx,ecx
    80.     mov [rsp+20h],rcx       ;wLanguageId=LANG_NEUTRAL
    81.     or dword ptr [rsp+28h],INFINITE;-1 или время в миллисекундах
    82.     mov edx,offset MsgBoxText
    83.     lea r8,[rdx+MsgCaption4-MsgBoxText]
    84.     invoke MessageBoxTimeout,,,,MB_OK; or MB_ICONASTERISK
    85. ;MessageBoxTimeoutW---------------------------------
    86.     xor ecx,ecx
    87.     mov [rsp+20h],rcx       ;wLanguageId=LANG_NEUTRAL
    88.     or dword ptr [rsp+28h],INFINITE;-1
    89.     mov edx,offset MsgBoxText1
    90.     lea r8,[rdx+MsgCaption5-MsgBoxText1]
    91.     invoke MessageBoxTimeoutW,,,,MB_OK; or MB_ICONASTERISK
    92. ;MessageBoxIndirectA-------------------------------
    93.     xor eax,eax
    94.     mov mbxData.params.cbSize,sizeof MSGBOXPARAMS
    95.     mov mbxData.params.hwndOwner,rax;0
    96.     mov mbxData.params.hInstance,400000h
    97.     mov mbxData.params.dwStyle,MB_OK or MB_USERICON
    98.  
    99.          mov mbxData.params.lpszIcon,1000
    100.          mov mbxData.params.dwContextHelpId,eax;0
    101.       mov mbxData.params.lpfnMsgBoxCallback,rax;0
    102.       mov mbxData.params.dwLanguageId,eax;LANG_NEUTRAL;0
    103.     lea ecx,mbxData.params
    104.         movr mbxData.params.lpszText,MsgBoxText
    105.     movr mbxData.params.lpszCaption,MsgCaption6
    106.     invoke MessageBoxIndirect
    107. ;MessageBoxIndirectW--------------------------------
    108.         movr mbxData.params.lpszText,MsgBoxText1
    109.     movr mbxData.params.lpszCaption,MsgCaption7
    110.     lea ecx,mbxData.params
    111.     invoke MessageBoxIndirectW
    112. ;SoftModalMessageBox--------------------------------
    113.       movr mbxData.params.lpszCaption,MsgCaption8;адрес заголовка в окне сообщений   8
    114.     movr mbxData.pidButton,dwBtnIds
    115.         movr mbxData.ppszButtonText,dwTxtTbl
    116.         mov mbxData.cButtons,1;4
    117.         and qword ptr mbxData.DefButton,0;        and mbxData.DefButton,0
    118.                      ;        and mbxData.CancelId,0;2
    119.         or mbxData.Timeout,-1
    120.     lea ecx,mbxData
    121.           invoke SoftModalMessageBox
    122. ;NtRaiseHardError-----------------------------------
    123.     ;первый параметр
    124.         lea edi,MessageBuffer
    125.         mov Message.Buffer+(sizeof UNICODE_STRING)*0,rdi
    126.         mov dword ptr Message.woLength+(sizeof UNICODE_STRING)*0,30002Eh
    127.         lea edx,Message+(sizeof UNICODE_STRING)*0
    128.         mov HardErrorPointer+(sizeof PVOID)*0,rdx;pwText
    129.         mov esi,offset MessageText
    130.         mov ecx,(Num+Num1+2)/4
    131.         rep movsd
    132. ;второй параметр
    133.         lea edi,MessageBuffer+Num
    134.         mov Message.Buffer+(sizeof UNICODE_STRING)*1,rdi
    135.         mov dword ptr Message.woLength+(sizeof UNICODE_STRING)*1,220020h
    136.         lea edx,Message+(sizeof UNICODE_STRING)*1
    137.         mov HardErrorPointer+(sizeof PVOID)*1,rdx;pwCaption
    138. ;третий параметр
    139.         mov HardErrorPointer+(sizeof PVOID)*2,MB_OK or MB_ICONASTERISK;uType
    140.         lea r9d,HardErrorPointer;указатель на массив параметров
    141.     movr qword ptr [rsp+28h],x;куда функция запишет выбранный юзером ответ (если тип,
    142. ;переданный в следующем параметре, предполагает выбор ответа пользователем)
    143.         mov qword ptr [rsp+20h],1
    144.     mov edx,4
    145.     mov r8d,3
    146.         mov ecx,50000018h;STATUS_SERVICE_NOTIFICATION;статус ошибки
    147.         call NtRaiseHardError
    148. ;syscall-------------------------------------------
    149. ;первый параметр
    150.     lea edi,MessageBuffer
    151.     mov Message.Buffer+(sizeof UNICODE_STRING)*0,rdi
    152.     mov dword ptr Message.woLength+(sizeof UNICODE_STRING)*0,30002Eh
    153.     lea edx,Message+(sizeof UNICODE_STRING)*0
    154.     mov HardErrorPointer+(sizeof PVOID)*0,rdx;pwText
    155.     mov esi,offset MessageText
    156.     mov ecx,(Num1+Num3)/4
    157.     rep movsd
    158. ;второй параметр
    159.     lea edi,MessageBuffer+Num
    160.     mov Message.Buffer+(sizeof UNICODE_STRING)*1,rdi
    161.     mov dword ptr Message.woLength+(sizeof UNICODE_STRING)*1,10000Eh
    162.     lea edx,Message+(sizeof UNICODE_STRING)*1
    163.     mov HardErrorPointer+(sizeof PVOID)*1,rdx;pwCaption
    164. ;третий параметр
    165.         mov HardErrorPointer+(sizeof PVOID)*2,MB_ICONASTERISK+MB_OK;uType
    166.         lea r9d,HardErrorPointer;указатель на массив параметров
    167. ;переданный в следующем параметре, предполагает выбор ответа пользователем);
    168.     movr qword ptr [rsp+28h],x;куда функция запишет выбранный юзером ответ (если тип,
    169.         mov qword ptr [rsp+20h],1
    170.     mov edx,4
    171.     mov r8d,3
    172. ;параметрам, которые имеют тип PUNICODE_STRING, а нули -- остальным параметрам
    173.     mov ecx,50000018h;STATUS_SERVICE_NOTIFICATION;статус ошибки
    174.     mov r10,rcx
    175.     mov eax,130h
    176.     push rbx
    177.     syscall
    178.     pop rbx
    179.     invoke RtlExitUserProcess,NULL
    180. WinMain endp
    181. MessageText dw 'W','i','n','6','4',27719,32534,31243,24207,24456,26834,'!',0
    182. Num = $-MessageText
    183. TitleText: du <NtRaiseHardError>
    184. Num1 = $-TitleText
    185. dw 0
    186. TitleText1: du <syscall>
    187. Num3 = $-TitleText1
    188. end
    Здесь rc-/asm-/exe-файлы и иконка


    © Mikl___ 2019
     

    Вложения:

    • 33.png
      33.png
      Размер файла:
      358,5 КБ
      Просмотров:
      130
    • 22.zip
      Размер файла:
      6,2 КБ
      Просмотров:
      13
    Последнее редактирование: 19 мар 2019
    kero, rasstriga, Коцит и ещё 1-му нравится это.
  4. Mikl___

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

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.748
    Глава восьмая. Как Братец Кролик

    Когда вы начнете осваивать хитрости программирования под Windows, то вам поможет учебная программа для экспериментов с многочисленными параметрами используемых функций ― чтобы не надо было каждый раз редактировать и компилировать заново исходный код проекта, а можно было бы выбрать необходимые опции прямо в диалоговом окне и тут же увидеть результат
    При запуске программы появится новое окно с текстом минимальной программы под х64 в рабочей области главного окна приложения. После компиляции будет получено полноценное окно с заголовком, имеющее в левом верхнем углу свой значок, при щелчке по которому появляется системное меню; в правом верхнем углу кнопки «свертнуть», «восстановить» и «развернуть»; размеры самого окна можно изменять, перетаскивая его рамку. Параметры окна заданы программой «Simple Windows Creator» по умолчанию. Для компиляции нужно выбрать «Файл» →«Создать окно»
    83.png
    приложение появится в той же папке, в которой находится программа «Simple Windows Creator». Вам остается только запустить программу, код которой вы получили в рабочей области главного окна приложения.
    84.png
    С текстом программы можно работать используя пункты «Копировать», «Вставить», «Удалить», «Сохранить», «Выделить все»
    85.png
    Основной пункт меню для наших экспериментов ― «Параметры». Содержит следующие пункты:
    1. «Windows Class Styles...»
    2. «Иконки...»
    3. «Курсоры...»
    4. «Стили Окна...»
    5. «Расширенные Стили Окна...»
    6. «Фон Окна...»
    7. «Дополнительно...»
    Каждый из них вызывает диалоговое окно, позволяющее настроить значения полей структуры WNDCLASSEX, параметров функций CreateWindowEx. Далее приводятся описания используемых структур, функций и возможностей по настройке.
    77.png
    В winuser.h описаны пятнадцать стилей окна. Для стиля окна из 32 битов отведено 18 и только один из этих битов установлен в единицу
    Стиль классаЗначениеОписание
    binhex
    1CS_VREDRAW00000000000000000000000000000001
    1​
    Перерисовывать окно при изменении вертикальных размеров
    2CS_HREDRAW00000000000000000000000000000010
    2​
    Перерисовывать все окно при изменении ширины
    3CS_KEYCVTWINDOW00000000000000000000000000000100
    4​
    Будет выполняться преобразование виртуальных клавиш
    4CS_DBLCLKS00000000000000000000000000001000
    8​
    Посылать сообщение от мыши при двойном щелчке в пределах окна
    500000000000000000000000000010000
    10​
    6CS_OWNDC00000000000000000000000000100000
    20​
    У каждого окна уникальный контекст устройства
    7CS_CLASSDC00000000000000000000000001000000
    40​
    Один и тот же контекст устройства разделяться всеми окнами этого класса. При нескольких потоках операционная система разрешит доступ только одному потоку
    8CS_PARENTDC00000000000000000000000010000000
    80​
    Дочерние окна наследуют контекст родительского окна. У дочернего окна будет область отсечки от родительского. Повышает производительность
    9CS_NOKEYCVT00000000000000000000000100000000
    100​
    Отключается преобразование виртуальных клавиш
    10CS_NOCLOSE00000000000000000000001000000000
    200​
    Убрать команду "Close" из системного меню. Отключить команду закрыть
    1100000000000000000000010000000000
    400​
    12CS_SAVEBITS00000000000000000000100000000000
    800​
    Позволяет сохранять область экрана в виде битовой матрицы закрытую в данный момент другим окном, используется для восстановления экрана
    13CS_BYTEALIGNCLIENT00000000000000000001000000000000
    1000​
    (по горизонтали) выравнивание рабочей области окна по границе байта. Влияет на ширину окна и его горизонтальное положение на экране
    14CS_BYTEALIGNWINDOW00000000000000000010000000000000
    2000​
    (по вертикали) выравнивает окна по границе байта
    15CS_GLOBALCLASS,
    CS_PUBLICCLASS
    00000000000000000100000000000000
    4000​
    Разрешается создавать глобальный класс, не зависящего от текущего hInstance, который можно поместить в динамическую библиотеку dll.
    1600000000000000001000000000000000
    8000​
    17CS_IME0000000000000001000000000000000010000Редактор метода ввода (IME ― Input Method Editor) ― программа или компонент операционной системы, позволяющий пользователям вводить символы, которых нет на клавиатуре. Используется для ввода текста на восточно-азиатских языках (китайский, японский или корейский) требующих поддержки многобайтовых кодировок и специальных методов ввода. Окно, созданное на основе этого класса, всегда можно найти с именем класса "IME", независимо от фактического имени класса
    18CS_DROPSHADOW0000000000000010000000000000000020000Включает эффект тени в окне. Эффект включается и выключается через SPI_SETDROPSHADOW. Как правило, это разрешено для небольших короткоживущих окон, таких как меню, чтобы подчеркнуть их отношение Z-порядка к другим окнам. Windows, созданная из класса с таким стилем, должна быть окон верхнего уровня; Они не могут быть дочерними окнами.
    78.png
    1. можно выбрать стандартные иконки. В качестве первого параметра функции LoadIcon можно передать NULL; в этом случае система использует один из стандартных встроенных значков. Описание соответствующего значка отображается в диалоговом окне в виде всплывающей подсказки.
    2. можно выбрать иконку из файла ― в этом случае нужно выбрать имя файла с иконкой из каталога и указать "Иконка из файла", если в файле несколько иконок, то придется указать еще и индекс иконки.
    79.png
    1. Если параметр hInstance функции LoadCursor равен NULL, в зависимости от значения второго параметра загружается один из системных курсоров. Описание соответствующего курсора отображается во всплывающей подсказке диалогового окна.
    2. можно выбрать курсор из файла ― в этом случае нужно выбрать имя файла с курсором из каталога и указать "Курсор из файла"
    80.png
    Основной стиль окна задается в диалоге «Стили окна»
    Этот параметр может быть комбинацией стилей, приведенных в диалоге «Стили окна», и дополнительных стилей элементов управления, которые здесь не рассматриваются.
    СтильЗначениеОписание
    binhex
    WS_OVERLAPPED,
    WS_TILED
    00000000000000000000000000000000
    0​
    Перекрывающееся окно, имеющее заголовок и обрамление
    WS_ACTIVECAPTION00000000000000000000000000000001
    1​
    The window is active
    WS_TABSTOP00000000000000010000000000000000
    10000​
    Определяет элемент управления, на который можно переместиться нажатием клавиши . Нажатие данной клавиши перемещает фокус ввода на следующий элемент управления, имеющий стиль WS_TABSTOP
    WS_MAXIMIZEBOX00000000000000010000000000000000
    10000​
    Создает окно с кнопкой максимизации. Должен быть указан также стиль WS_SYSMENU. Не может быть использован со стилем WS_EX_CONTEXTHELP
    WS_MINIMIZEBOX00000000000000100000000000000000
    20000​
    Создает окно с кнопкой минимизации. Должен быть указан также стиль WS_SYSMENU. Не может быть использован со стилем WS_EX_CONTEXTHELP
    WS_GROUP00000000000000100000000000000000
    20000​
    Определяет первый управляющий элемент в группе, причем в группу входит данный элемент и все последующие до следующего управляющего элемента со стилем WS_GROUP. Обычно первый элемент в группе имеет также стиль WS_TABSTOP, чтобы пользователь мог перемещаться от одной группы к другой. Внутри группы пользователь может перемещаться от одного элемента управления к другому с использованием клавиш перемещения курсора
    WS_THICKFRAME,
    WS_SIZEBOX
    00000000000001000000000000000000
    40000​
    Создает окно, имеющее a sizing border
    WS_SYSMENU00000000000010000000000000000000
    80000​
    Создает окно, имеющее системное меню в заголовке. Должен быть также указан стиль WS_CAPTION
    WS_HSCROLL00000000000100000000000000000000
    100000​
    Создает окно, имеющее a horizontal scroll bar
    WS_VSCROLL00000000001000000000000000000000
    200000​
    Создает окно, имеющее a vertical scroll bar
    WS_DLGFRAME00000000010000000000000000000000
    400000​
    Создает окно, имеющее a border of a style typically used with dialog boxes. A window with this style cannot have a title bar
    WS_BORDER00000000100000000000000000000000
    800000​
    Создает окно, имеющее a thin-line border
    WS_CAPTION00000000110000000000000000000000
    0C00000​
    Окно с заголовком (включает в себя также стиль WS_BORDER)
    WS_OVERLAPPEDWINDOW,
    WS_TILEDWINDOW
    00000000110011110000000000000000
    0CF0000​
    Создает перекрывающееся окно с заголовком, системным меню, перемещаемым обрамлением и кнопками минимизации и максимизации (комбинация стилей WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX и WS_MAXIMIZEBOX)
    WS_MAXIMIZE00000001000000000000000000000000
    1000000​
    Creates a window that is initially maximized
    WS_CLIPCHILDREN00000010000000000000000000000000
    2000000​
    Исключает область дочернего окна при рисовании в родительском окне. Этот стиль используется при создании родительского окна.
    WS_CLIPSIBLINGS00000100000000000000000000000000
    4000000​
    Исключение областей дочерних окон друг относительно друга, т.е. при получении дочерним окном сообщения WM_PAINT стиль WS_CLIPSIBLINGS исключает области всех других дочерних окон из зоны рисования. Если стиль WS_CLIPSIBLINGS не указан, а дочерние окна перекрываются, при рисовании в области пользователя дочернего окна возможен заход в область пользователя соседнего дочернего окна.
    WS_DISABLED00001000000000000000000000000000
    8000000​
    Создает окно, доступ к которому запрещен (окно, которое не может получать ввод от пользователя).
    WS_VISIBLE0001000000000000000000000000000010000000Creates a window that is initially visible
    WS_MINIMIZE,
    WS_ICONIC
    0010000000000000000000000000000020000000Creates a window that is initially minimized
    WS_CHILD,
    WS_CHILDWINDOW
    0100000000000000000000000000000040000000Creates a child window. This style cannot be used with the WS_POPUP style.Excludes the area occupied by child windows when drawing occurs within the parent window. This style is used when creating the parent window.
    WS_POPUP1000000000000000000000000000000080000000Creates a pop-up window. This style cannot be used with the WS_CHILD style
    WS_POPUPWINDOW1000000010001000000000000000000080880000Создает всплывающее окно с обрамлением и системным меню (комбинация стилей WS_BORDER, WS_POPUP и WS_SYSMENU). Чтобы меню окна было видимым, необходимо комбинировать данный стиль со стилем WS_CAPTION
    81.png
    Расширенные стили окна можно задать на одноименной вкладке диалогового окна «Параметры функции CreateWindowEx»
    Этот параметр может принимать значения, указанные на вкладке «Расширенные стили». Дополнительные сведения для некоторых из них приведены в таблице 3.
    СтильЗначениеОписание
    binhex
    WS_EX_LEFT00000000000000000000000000000000
    0​
    Окно имеет общий стиль «левостороннего» (по умолчанию) выравнивания
    WS_EX_LTRREADING00000000000000000000000000000000
    0​
    Текст окна отображается слева направо (по умолчанию)
    WS_EX_RIGHTSCROLLBAR00000000000000000000000000000000
    0​
    Вертикальная полоса прокрутки (при ее наличии) размещается в правой (по умолчанию) части рабочей области окна соответственно
    WS_EX_DLGMODALFRAME00000000000000000000000000000001
    1​
    Создает окно, которое имеет двойную рамку; окно может быть создано (необязательно) со строкой заголовка, которую определяет стиль WS_CAPTION в параметре dwStyle
    00000000000000000000000000000010
    2​
    WS_EX_NOPARENTNOTIFY00000000000000000000000000000100
    4​
    Определяет, что дочернее окно, созданное с этим стилем не посылает сообщение WM_PARENTNOTIFY родительскому окну, когда оно создается или разрушается
    WS_EX_TOPMOST00000000000000000000000000001000
    8​
    Окно, созданное с этим стилем, остается поверх всех других окон без данного стиля, даже если фокус ввода принадлежит другому окну
    Определяет, что окно, созданное с этим стилем должно быть размещено выше всех, не самых верхних окон и должно стоять выше их, даже тогда, когда окно дезактивировано. Чтобы добавить или удалить этот стиль, используйте функцию SetWindowPos
    The window should be placed above all non-topmost windows and should stay above them, even when the window is deactivated. To add or remove this style, use the SetWindowPos function
    WS_EX_ACCEPTFILES00000000000000000000000000010000
    10​
    Определяет, что окно, созданное с этим стилем принимает файлы при помощи информационной технологии "перетащи и вставь"
    WS_EX_TRANSPARENT00000000000000000000000000100000
    20​
    Specifies that a window created with this style is to be transparent. That is, any windows that are beneath the window are not obscured by the window. A window created with this style receives WM_PAINT messages only after all sibling windows beneath it have been update
    Определяет, что окно, созданное с этим стилем должно быть прозрачным. То есть любые окна, которые появляются из-под окна, не затеняются им. Окно, созданное с этим стилем принимает WM_PAINT сообщения только после того, как все сестринские окна под ним модифицировались
    The window should not be painted until siblings beneath the window (that were created by the same thread) have been painted. The window appears transparent because the bits of underlying sibling windows have already been painted. To achieve transparency without these restrictions, use the SetWindowRgn function
    WS_EX_MDICHILD00000000000000000000000001000000
    40​
    Создает дочернее MDI-окно
    WS_EX_TOOLWINDOW00000000000000000000000010000000
    80​
    Creates a tool window; that is, a window intended to be used as a floating toolbar. A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font. A tool window does not appear in the task bar or in the window that appears when the user presses ALT+TAB
    Создает окно инструментальных средств; то есть окно предполагается использовать как плавающую инструментальную панель. Окно инструментальных средств имеет строку заголовка, которая является короче, чем нормальная строка заголовка, а заголовок окна выводится, с использованием меньшего шрифта. Окно инструментальных средств не появляется в панели задач или в диалоговом окне, которое появляется, когда пользователь нажимает ALT+TAB
    The window is intended to be used as a floating toolbar. A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font. A tool window does not appear in the taskbar or in the dialog that appears when the user presses ALT+TAB. If a tool window has a system menu, its icon is not displayed on the title bar. However, you can display the system menu by right-clicking or by typing ALT+SPACE
    WS_EX_WINDOWEDGE00000000000000000000000100000000
    100​
    Определяет, что окно имеет рамку с выпуклым краем
    WS_EX_PALETTEWINDOW00000000000000000000000110001000
    188​
    Объединяет стили WS_EX_WINDOWEDGE, WS_EX_TOOLWINDOW и WS_EX_TOPMOST The window is palette window, which is a modeless dialog box that presents an array of commands
    WS_EX_CLIENTEDGE00000000000000000000001000000000
    200​
    Определяет, что окно имеет рамку с углубленным краем
    WS_EX_OVERLAPPEDWINDOW00000000000000000000001100000000
    300​
    Объединяет стили WS_EX_WINDOWEDGE и WS_EX_CLIENTEDGE The window is an overlapped window
    WS_EX_CONTEXTHELP00000000000000000000010000000000
    400​
    Включает вопросительный знак в строку заголовка окна. Когда пользователь щелкает мышью по вопросительному знаку, курсор меняется на вопросительный знак с указателем. Если пользователь затем щелкает мышью по дочернему окну, потомок принимает сообщение WM_HELP. Дочернее окно должно передать сообщение родительской оконной процедуре, которая должна вызваться функцией WinHelp, использующей команду HELP_WM_HELP. Прикладная программа Справки показывает выскакивающее окно, которое обычно содержит справку для дочернего окна. WS_EX_CONTEXTHELP не может использоваться со стилями WS_MAXIMIZEBOX или WS_MINIMIZEBOX
    00000000000000000000100000000000
    800​
    WS_EX_RIGHT00000000000000000001000000000000
    1000​
    Окно имеет общий стиль «правостороннего» выравнивания. «Правосторонний» стиль действует лишь, когда установлен язык с обратным порядком чтения (справа налево)
    Using the WS_EX_RIGHT style for static or edit controls has the same effect as using the SS_RIGHT or ES_RIGHT style, respectively. Using this style with button controls has the same effect as using BS_RIGHT and BS_RIGHTBUTTON styles
    WS_EX_RTLREADING00000000000000000010000000000000
    2000​
    Текст окна отображается справа налево. Стиль действует лишь в случае, если установлен язык с порядком чтения справа налево.
    WS_EX_LEFTSCROLLBAR00000000000000000100000000000000
    4000​
    Вертикальная полоса прокрутки (при ее наличии) размещается в левой части рабочей области окна. Слева полоса прокрутки может размещаться, если установлен язык с порядком чтения справа налево
    00000000000000001000000000000000
    8000​
    WS_EX_CONTROLPARENT00000000000000010000000000000000
    10000​
    Позволяет пользователю передвигаться среди дочерних окон основного окна, используя клавишу табуляции (TAB)
    The window itself contains child windows that should take part in dialog box navigation. If this style is specified, the dialog manager recurses into children of this window when performing navigation operations such as handling the TAB key, an arrow key, or a keyboard mnemonic
    WS_EX_STATICEDGE00000000000000100000000000000000
    20000​
    Создает окно с трехмерным стилем рамки, предполагается использовать для элементов, которые не принимают вводимую информацию от пользователя
    WS_EX_APPWINDOW00000000000001000000000000000000
    40000​
    Активизирует окно верхнего уровня на панель задач, когда окно свернуто
    WS_EX_LAYERED00000000000010000000000000000000
    80000​
    The window is a layered window. This style cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC. Windows 8: The WS_EX_LAYERED style is supported for top-level windows and child windows. Previous Windows versions support WS_EX_LAYERED only for top-level windows
    WS_EX_NOINHERITLAYOUT00000000000100000000000000000000
    100000​
    The window does not pass its window layout to its child windows
    WS_EX_NOREDIRECTIONBITMAP00000000001000000000000000000000
    200000​
    The window does not render to a redirection surface. This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual
    WS_EX_LAYOUTRTL00000000010000000000000000000000
    400000​
    If the shell language is Hebrew, Arabic, or another language that supports reading order alignment, the horizontal origin of the window is on the right edge. Increasing horizontal values advance to the left
    00000000100000000000000000000000
    800000​
    000000010000000000000000000000001000000
    WS_EX_COMPOSITED000000100000000000000000000000002000000Paints all descendants of a window in bottom-to-top painting order using double-buffering. For more information, see Remarks. This cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC. Windows 2000: This style is not supported
    000001000000000000000000000000004000000
    WS_EX_NOACTIVATE000010000000000000000000000000008000000A top-level window created with this style does not become the foreground window when the user clicks it. The system does not bring this window to the foreground when the user minimizes or closes the foreground window. The window should not be activated through programmatic access or via keyboard navigation by accessible technology, such as Narrator. To activate the window, use the SetActiveWindow or SetForegroundWindow function. The window does not appear on the taskbar by default. To force the window to appear on the taskbar, use the WS_EX_APPWINDOW style
    Фон окна можно выбрать на одноименном диалоге через
    1. Системные цвета
    2. GetStockObject
    3. CreateSolidBrush
    82.png
    Здесь asm- и rc-файлы, иконки и ехе-файл


    © Mikl___ 2019
     

    Вложения:

    • 31.png
      31.png
      Размер файла:
      393,5 КБ
      Просмотров:
      122
    • 07.zip
      Размер файла:
      81 КБ
      Просмотров:
      14
    Последнее редактирование: 19 мар 2019
    kero, rasstriga и Коцит нравится это.
  5. Mikl___

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

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.748
    Глава девятая. Братец Кролик и немного MSDN'a

    Типы окон

    Overlapped окна

    Overlapped окно ("перекрывающее окно") - это окно верхнего уровня (top-level window), у которого есть заголовок (title bar), рамка (border) и клиентская область (client area); предполагается, что окно этого типа будет использоваться в качестве главного окна приложения. У него также могут быть системное меню, кнопки максимизации и минимизации и полосы прокрутки. Overlapped окно обычно включает в себя все эти компоненты, когда используется в качестве главного окна приложения.
    Приложение может создать overlapped окно, указывая стиль WS_OVERLAPPED или WS_OVERLAPPEDWINDOW в функции CreateWindowEx. Если вы использовали стиль WS_OVERLAPPED, то окно будет также иметь заголовок и рамку. Если вы использовали стиль WS_OVERLAPPEDWINDOW, то окно будет иметь заголовок, изменяющую размеры рамку, системное меню и кнопки минимизации и максимизации.
    флаг WS_OVERLAPPED равен нулю, поэтому если вы не укажете иной стиль, то окно по умолчанию будет иметь стиль WS_OVERLAPPED. Стиль WS_OVERLAPPEDWINDOW - это не самостоятельный стиль, он является простой комбинацией стилей WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX и WS_MAXIMIZEBOX.
    Pop-up окна

    Pop-up окно ("всплывающее окно") - это разновидность overlapped окна, используемая для диалоговых окон, окон-сообщений и других аналогичных временных окон, которые появляются вне главного окна приложения. Для них заголовок не обязателен; в противном случае pop-up окна не отличаются от overlapped окон со стилем WS_OVERLAPPED.
    Вы можете создать pop-up окно, указывая стиль WS_POPUP в функции CreateWindowEx. Чтобы окно имело заголовок, вам нужно отдельно указать стиль WS_CAPTION. Для создания pop-up окна с рамкой и системным меню используйте стиль WS_POPUPWINDOW. Чтобы системное меню можно было увидеть, вам также нужно включить стиль WS_CAPTION вместе со стилем WS_POPUPWINDOW.
    стиль WS_POPUPWINDOW - это не самостоятельный стиль, он является простой комбинацией стилей WS_POPUP, WS_BORDER и WS_SYSMENU.
    Child окна

    Child окно ("дочернее окно") - имеет установленный стиль WS_CHILD и ограничивается клиентской областью его родительского окна (parent window). Как правило, child окна используются приложением, чтобы разделить клиентскую область окна по функциональным зонам. Вы можете создать child окно, указывая стиль WS_CHILD в функции CreateWindowEx.
    У child окна обязательно должно быть родительское окно. Родительское окно может быть overlapped окном, pop-up окном или даже другим child окном. Вы указываете его во время вызова функции CreateWindowEx в параметре hWndParent. Если же вы укажете стиль WS_CHILD в CreateWindowEx, но не укажете родительское окно, то система откажется создавать окно.
    Child окно имеет клиентскую область, но больше никаких других дополнительных возможностей, если только вы их явно не запросите. Вы можете добавить заголовок, системное меню, кнопки минимизации и максимизации, рамку и полосы прокрутки, но child окно не может иметь меню. Если вы укажете меню при создании child окна - оно будет проигнорировано. Если вы не укажете тип рамки, то система создаст окно вообще без рамки (borderless window). Приложение может использовать такие окна для разделения клиентской области родительского окна на части без видимого указания разделения пользователю.
    Примером child окон могут служить фреймы (TFrame), панели (TPanel) и вообще практически любые другие оконные компоненты - например, кнопка (TButton). Тут нужно помнить, что "окно" в смысле пользователя - это "форма" в Delphi. Но термин "окно" в смысле системы - это вовсе не обязательно "окно" в смысле пользователя, это вообще некоторый элемент управления. Все элементы управления в Windows являются окнами в смысле системы. Кнопки, списки, строки ввода, полосы прокрутки, панели и тулбары - всё это "окна".
    Позиционирование

    Система всегда размещает child окно, используя относительные координаты - относительно левого-верхнего угла клиентской области родительского окна. Child окно не может выступать за границы своего родительского окна. Если приложение создаёт child окно больше размеров своего родительского окна, либо же размещает его так, что какая-то его часть выходит за границы родителя, то система обрезает child окно так, что часть child окна вне его родительского окна будет просто невидима.
    Кроме того, действия с родительским окном также будут иметь эффект на все его child окна, как указано в следующей таблице:
    Parent окноChild окно
    УничтожаетсяУничтожается непосредственно перед удалением своего родительского окна.
    СкрываетсяСкрывается непосредственно перед скрытием своего родительского окна. Всякое child окно видимо только если его родительское окно тоже видимо.
    ПеремещаетсяПеремещается вместе с клиентской областью своего родителя так, что его относительное положение сохраняется. Child окно ответственно за перерисовку своей клиентской области после перемещения.
    ПоказываетсяПоказывается сразу после показа своего родителя
    Обрезание

    По умолчанию система не обрезает child окно, если оно размещено вне клиентской области своего родителя (если клиентская область родителя меньше размеров самого родительского окна, поскольку система всегда обрезает child окно, вылезающее за размеры своего родителя, как указано выше). Это означает, что родительское окно будет рисовать поверх child окна, если оно производит любую операцию рисования в той же области, что и child окно. Однако систему можно попросить обрезать child окно по клиентской области своего родителя, указав стиль WS_CLIPCHILDREN родительскому окну (не дочернему). Если child окно обрезается, то родительское окно не будет рисовать поверх его.
    Child окно может пересекать другие child окна в той же клиентской области. Child окна, которые разделяют одного родителя, называются sibling окнами ("братские окна"). Пересекающиеся sibling окна могут рисовать в клиентской области друг друга, если только одно из child окон не имеет стиль WS_CLIPSIBLINGS. Если child окно указывает этот стиль, то любая часть любого другого sibling окна, лежащая в рамках этого child окна, будет обрезаться.
    Установка стилей WS_CLIPCHILDREN или WS_CLIPSIBLINGS приводит к небольшому падению производительности. Каждое окно занимает системные ресурсы, так что приложение не должно использовать дочерние окна без разбора. Для достижения оптимальной производительности приложения, которые должны логически разделять своё главное окно, должны делать это в оконной процедуре главного окна, а не с помощью дочерних окон.
    Отношение с родительским окном

    Приложение может изменить родительское окно уже созданного child окна вызовом функции SetParent. В этом случае система удаляет child окно из клиентской области старого родительского окна и размещает его в клиентской области нового родительского окна. Если в SetParent указать 0 в качестве родителя, то новым родительским окном станет рабочий стол (desktop window). В этом случае child окно рисуется на рабочем столе, вне границ любого другого окна. Функция GetParent возвращает описатель родительского окна child окна.
    Родительское окно уступает часть своей клиентской области child окну, и child окно получает весь ввод (input) с этой области. Родительское и child окно не обязаны иметь один и тот же оконный класс (window class). Это означает, что приложение может заполнить родительское окна child окнами, которые выглядят по-разному и выполняют разные задачи. Например, диалоговое окно может содержать несколько типов элементов управления, каждый из которых является child окном, которое принимает различные типы данных от пользователя.
    Child окно имеет одно и только одно родительское окно, но родительское окно может иметь сколько угодно child окон. Каждое child окно, в свою очередь, тоже может иметь сколько угодно child окон. В такой цепочке окон каждое child окно называется descendant окном (окном-потомком) исходного родительского окна. Приложение может использовать функцию IsChild, чтобы определить, является ли заданное окно child окном или descendant окном другого окна.
    Функция EnumChildWindows перечисляет все дочерние окна родительского окна. Функция EnumChildWindows передаёт описатель каждого найденного child окна в функцию обратного вызова приложения. Функция работает рекурсивно, поэтому она также перечисляет все descendant окна заданного родительского окна.
    Сообщения

    Система передаёт все сообщения ввода для child окна самому child окну напрямую, минуя окно родителя. Исключением для этого правила является случай, если дочернее окно было отключено вызовом функции EnableWindow. В этом случае система передаёт сообщения, предназначенные child окну, его родителю. Это позволяет родительскому окну проверить сообщения ввода и при необходимости включить child окно.
    Child окно также может иметь уникальный числовой идентификатор. Идентификаторы child окон важны, если вы работаете с сообщениями. Приложение управляет элементами управления, отправляя им сообщения. Приложение может использовать идентификатор child окна для отправки в него сообщений. Кроме того, если элемент управления шлёт сообщения-уведомления своему родителю, то эти сообщения будут включать в себя идентификатор child-окна, что позволит родителю идентифицировать отправителя сообщения. Приложение указывает идентификатор child окна установкой параметра hMenu функции CreateWindowEx в число - значение идентификатора (а не описатель меню).
    Layered окна

    Использование layered окна ("окна со слоями") может здорово улучшить производительность и визуальные эффекты для окон, которые имеют сложную форму, анимацию или применяют альфа-каналы. Система автоматически производит композицию и перерисовку layered окон и окон под ним. В результате layered окна рисуются гладко, без эффектов мерцания на сложных регионах. Кроме того, layered окна могут быть сделаны частично прозрачными.
    Чтобы создать layered окно, вам нужно указать флаг WS_EX_LAYERED расширенного стиля окна при вызове функции CreateWindowEx или вызвать функцию SetWindowLong уже после создания окна. После вызова CreateWindowEx layered окно не будет видимо до тех пор, пока вы не вызовите для него функцию SetLayeredWindowAttributes или функцию UpdateLayeredWindow.
    Начиная с Windows 8 WS_EX_LAYERED может использоваться как для окон верхнего уровня, так и для дочерних окон (child окон). Предыдущие версии Windows поддерживают стиль WS_EX_LAYERED только для окон верхнего уровня.
    Чтобы установить степень непрозрачности (opacity level) или цвет-маску (transparency color key) для заданного layered окна - вызовите функцию SetLayeredWindowAttributes. После этого вызова система всё ещё может запросить окно нарисовать себя при показе или перемещении. Однако, поскольку система запоминает растровое содержимое layered окна, то она не будет просить окно перерисовать себя при частичном перекрытии окна другими окнами или при его перемещении по рабочему столу. При этом устаревшим приложениям не нужно переделывать их код рисования, если они хотят добавить прозрачность или эффекты - потому что система перенаправляет рисование на окнах, которые вызвали SetLayeredWindowAttributes, на внеэкранный растр.
    Чтобы реализовать более эффективную анимацию или если вам нужно попиксельное альфа-смешение цветов - вы можете вызвать UpdateLayeredWindow. UpdateLayeredWindow следует использовать, когда приложение хочет работать напрямую с формой и содержимым layered окна, минуя внеэкранный буфер, который система предоставляет через вызов SetLayeredWindowAttributes. Кроме того, использование UpdateLayeredWindow более эффективно, потому что системе не нужно выделять дополнительную память для хранения изображения перенаправленного окна. Обратите внимание, что если вы вызвали SetLayeredWindowAttributes, то все последующие вызовы UpdateLayeredWindow завершатся с ошибкой - до тех пор, пока вы не переустановите (сбросите и заново установите) флаг WS_EX_LAYERED.
    Тестирование на попадание мышью (hit testing) для layered окна основывается на форме и прозрачности окна. Это означает, что зоны окна, которые раскрашены цветовым ключом или же их альфа-канал равен нулю, пропустят щелчки мыши мимо себя. Однако если в окне дополнительно установлен флаг WS_EX_TRANSPARENT, то всё окно целиком будет пропускать щелчки мыши сквозь себя.
    Message-Only окна

    Message-only окно ("окно для сообщений") позволяет вам принимать и отправлять оконные сообщения. Оно не видимо, не имеет Z-порядка, не появляется в перечислениях (enum) и не принимает широковещательные сообщения. Это окно просто диспетчеризирует сообщения.
    Чтобы создать message-only окно, укажите константу HWND_MESSAGE или описатель на другое message-only окно в параметре hWndParent функции CreateWindowEx. Вы также можете сконвертировать любое существующее окно в message-only окно, указав HWND_MESSAGE в качестве параметра hWndNewParent функции SetParent.
    Чтобы найти message-only окна - укажите HWND_MESSAGE в параметре hwndParent функции FindWindowEx. Кроме того, функция FindWindowEx будет искать message-only окна наравне с окнами верхнего уровня, если оба параметра hwndParent и hwndChildAfter будут равны нулю.
    Отношения между окнами

    Существует много способов, которыми одно окно может относится к пользователю или другому окну. Окно может быть владеемым, окном переднего или заднего плана, а также у него может быть задан Z-порядок по отношению к другим окнам:
    Окна первого и заднего плана

    Каждый процесс может иметь несколько потоков для выполнения, и каждый поток может создавать окна. Поток, который создал окно, с которым сейчас работает пользователь, называется потоком первого плана (foreground thread), а окно называется foreground окном (окном первого плана). Все прочие потоки называются потоками заднего плана (background thread), а все прочие окна - окнами заднего плана (background окнами).
    Каждый поток имеет уровень приоритета, который определяет количество времени процессора, получаемое этим потоком. Хотя приложение может менять уровень приоритета своих потоков, обычно поток первого плана получает небольшую прибавку приоритета по отношению к потокам заднего плана. Поэтому поток первого плана будет получать больше процессорного времени, чем потоки заднего плана. Обычно поток первого плана имеет приоритет 9, в то время как обычное значение приоритета потока заднего плана - 7.
    Пользователь задаёт окно переднего плана, щёлкая по окну, либо используя комбинации клавиш ALT+TAB или ALT+ESC. Чтобы получить описатель окна переднего плана - используйте функцию GetForegroundWindow.
    Приложение может установить окно переднего плана, используя функцию SetForegroundWindow.
    Система ограничивает процессы, которым разрешено менять окно переднего плана. Процесс сможет сделать это только если верны условия ниже:
    • процесс является процессом первого плана (т.е. окно первого плана принадлежит ему).
    • процесс был запущен процессом переднего плана.
    • процесс получил последнее сообщение ввода.
    • в системе нет процесса переднего плана.
    • процесс первого плана сейчас отлаживается.
    • смена окна первого плана не заблокирована (функцией LockSetForegroundWindow).
    • истёк таймаут блокировки окна (параметр SPI_GETFOREGROUNDLOCKTIMEOUT в SystemParametersInfo).
    • нет активных меню.
    Процесс, которому разрешено менять окно первого плана, может передать это право другому процессу вызовом функции AllowSetForegroundWindow или функции BroadcastSystemMessage с флагом BSF_ALLOWSFW. Процесс первого плана также может отключить вызовы SetForegroundWindow, вызвав функцию LockSetForegroundWindow .
    Owned окна

    Overlapped или pop-up окно может владеть другим overlapped или pop-up окном. Отношение "владелец - owned окно" накладывают ограничения на последнее:
    • Owned окно всегда находится поверх своего владельца в Z-порядке.
    • Система автоматически уничтожает owned окна при уничтожении их владельца.
    • Owned окно скрывается при минимизации своего владельца.
    Владельцем может быть только overlapped или pop-up окно; child окна владельцами быть не могут. Приложение может создать owned окно указанием описателя окна-владельца в параметре hwndParent функции CreateWindowEx, когда она создаёт окно со стилями WS_OVERLAPPED или WS_POPUP. Параметр hwndParent должен идентифицировать overlapped или pop-up окно. После создания owned окна приложение не может передать отношение владения другому окну.
    Диалоговые окна и окна-сообщения (message box) являются owned окнами. Приложение указывает окно-владельца при вызове функции, создающей диалог или окно-сообщение.
    Приложение может использовать функцию GetWindow с флагом GW_OWNER, чтобы получить описатель окна-владельца.
    Z-порядок

    Z-order (Z-порядок) окна указывает положение окна в стопке overlapped окон. Эта стопка окон ориентируется вдоль воображаемой оси (оси Z), идущей от экрана. Окно на вершине Z оси (Z-порядка) перекрывает все прочие окна. Окно на дне Z-порядка может быть перекрыто любым другим окном.
    Система хранит Z-порядок в едином списке. Она добавляет окна в список в зависимости от их типа: topmost окна, top-level окна и child окна. Окно "поверх всех" (topmost окно) перекрывает все прочие окна (не topmost окна), вне зависимости от того, является ли topmost окно активным. У topmost окон устанавливается стиль WS_EX_TOPMOST. Все topmost окна всегда располагаются в списке Z-порядка перед любыми другими не topmost окнами. Child окна группируются вместе с их родителями.
    Когда приложение создаёт окно, система помещает окно в список Z-order - на вершину цепочки окон того же типа. Вы можете использовать функцию BringWindowToTop, чтобы переместить окно на вершину списка Z-order (но только в рамках окон того же типа). Вы можете переупорядочивать окна, используя функции SetWindowPos или DeferWindowPos.
    Пользователь может изменить Z-порядок активируя различные окна. Система перемещает активное окно на вершину Z-порядка для окон того же типа. Child окна перемещаются на вершину вместе со своим родителем. Вы можете использовать функцию GetTopWindow для поиска всех child окон родительского окна и получения описателя child окна на вершине Z-порядка. Функция GetNextWindow возвращает описатель следующего или предыдущего окна в Z-порядке.
    Состояния отображения окон

    В любой момент времени произвольное окно может быть активным или не активным; скрытым или видимым; и либо минимизированным, либо максимизированным, либо развёрнутым. Все эти характеристики называются window show state (состояния отображения окон). Они обсуждаются ниже:
    • Активное окно
    • Отключенные окна
    • Видимость окон
    • Минимизированные, максимизированные и развёрнутые окна
    Активное окно

    Активное окно (active window) - это окно верхнего уровня (top-level) приложения, с которым сейчас работает пользователь. Чтобы пользователь мог опознать активное окно, система размещает активное окно на вершине Z-порядка, а также изменяет вид заголовка (выделяя его) и рамки окна. Активным окном может быть только окно верхнего уровня. Если пользователь работает с child окном, то система активирует окно верхнего уровня, ассоциированное с текущим child окном.
    В любой момент времени в системе может быть только одно активное окно. Пользователь может активировать окно (верхнего уровня) просто щёлкая по нему (или по одному из его child окон), либо используя комбинации клавиш для переключения окон (например, ALT+ESC или ALT+TAB). Приложение может сделать окно (верхнего уровня) активным, вызывая функцию SetActiveWindow. Активация окна также может происходить при использовании других функций, включая SetWindowPos, DeferWindowPos, SetWindowPlacement и DestroyWindow. Хотя приложение может менять активное окно в любое время, но чтобы не смущать пользователя, лучше всего это делать в ответ на действия пользователя. Приложение может узнать текущее активное окно вызовом функции GetActiveWindow.
    Когда активное окно изменяется с окна одного приложения на окно другого приложения, система посылает сообщение WM_ACTIVATEAPP обоим приложениям, уведомляя их об изменении активного окна. Если же активное окно изменяется с одного окна приложения на другое окно этого же приложения, то система посылает сообщение WM_ACTIVATE обоим окнам этого приложения.
    Отключенные окна

    Окно может быть отключено. Отключенное окно (disabled window) не может получать ввод пользователя (сообщения клавиатуры и мыши), но может получать сообщения от других окон, приложений и системы. Обычно приложение отключает окно для предотвращения взаимодействия с ним пользователя. К примеру, приложение может отключить кнопку в диалоге, чтобы не дать пользователю на неё нажать. Приложение может включить (enable) отключенное окно в любое время; включение окна восстановит возможность ввода.
    По умолчанию окно создаётся в доступном состоянии. Но приложение может указать стиль WS_DISABLED для создания окна в отключенном состоянии. Приложение может включить или отключить окно вызовом функции EnableWindow. Непосредственно перед изменением состояния окна система отправляет ему сообщение WM_ENABLE. Приложение может узнать статус окна вызовом функции IsWindowEnabled.
    Когда child окно отключается, система передаёт сообщения мыши от child окна его родителю. Родительское окно может использовать эти сообщения для определения того, не нужно ли включить child окно.
    В каждый момент времени только одно окно в системе может принимать клавиатурный ввод; говорят, что такое окно имеет фокус (keyboard focus). Если приложение использует функцию EnableWindow для отключения окна, которое имеет фокус ввода, то, кроме собственно отключения, окно также потеряет фокус ввода. Функция EnableWindow установит клавиатурный фокус в 0, что означает, что в системе нет окна с фокусом ввода. Аналогично, если фокус имеет child окно или descendant окно, а родитель отключается, то descendant окно теряет фокус ввода.
    Видимость окон

    Окно может быть либо видимым, либо невидимым (скрытым). Система показывает на экране только видимые окна (visible window). Все скрытые окна (hidden window) не отображаются (не рисуются). Если окно видимо, то пользователь может взаимодействовать с окном (ввод и чтение содержимого). Если окно скрыто, то оно отключается. Скрытое окно может получать сообщения от других окон, приложений или системы, но оно не может получать ввод от пользователя или отображать себя на экране (рисовать). Приложение указывает видимость окон на экране при их создании. Приложение также может менять видимость окон после создания.
    Окно видимо, если у него установлен стиль WS_VISIBLE. По умолчанию функция CreateWindowEx создаёт скрытое окно, если только приложение явно не укажет стиль WS_VISIBLE. Обычно приложение создаёт окна скрытыми, а затем показывает их - после настройки окна, чтобы пользователь не видел процесс создания окна. Если при вызове функции CreateWindowEx указан стиль WS_VISIBLE, то система отправляет окну сообщение WM_SHOWWINDOW после его создания, но до отображения на экране.
    Приложение может определить, видимо ли окно, используя функцию IsWindowVisible. Приложение может изменить видимость окон вызовом функций ShowWindow, SetWindowPos, DeferWindowPos, SetWindowPlacement или SetWindowLong. Любая из этих функций может скрыть или показать окно - удалением или добавлением стиля WS_VISIBLE. Они также отправят окну сообщение WM_SHOWWINDOW непосредственно перед его показом или скрытием.
    Когда окно-владелец (owner) минимизируется, система автоматически скрывает ассоциированные с ним owned окна. Аналогично, когда owner окно восстанавливается, система автоматически показывает ассоциированные owned окна. В обоих случаях система посылает owned окнам сообщения WM_SHOWWINDOW. Иногда приложению может понадобится скрыть owned окна не минимизируя владельца. В этом случае приложение может использовать функцию ShowOwnedPopups. Эта функция устанавливает или удаляет стиль WS_VISIBLE для всех owned окон, а также рассылает им сообщения WM_SHOWWINDOW. Учтите, что скрытие окна-владельца не влияет на видимость ассоциированных с ним owned окон.
    Когда родительское окно видимо, то его child окна также видимы. Если родительское окно скрывается, то дочерние окна также скрываются. Минимизация родительского окна не влияет на видимость дочерних окон; то есть child окна исчезают с экрана вместе с родителем, но стиль WS_VISIBLE для них не удаляется.
    Даже если у окна есть стиль WS_VISIBLE, пользователь может не видеть окна на экране; окно может быть перекрыто другими окнами или быть расположено за границами экрана. Кроме того, видимое child окно может обрезаться, как того диктуют отношения с родительским окном. И если родительское окно не видимо, то child окно также не будет видимо. Если родительское окно будет расположено за границами экрана, то его child окна также будут расположены за границами экрана, потому что child окно перемещается вместе с родительским окном, ограничен им и располагается в относительных координатах.
    Минимизированные, максимизированные и развёрнутые окна

    Максимизированное окно (maximized window) - это окно, у которого установлен стиль WS_MAXIMIZE. По умолчанию система увеличивает максимизированное окно так, чтобы оно заполняло экран или, в случае child окна, клиентскую область родительского окна. Хотя вы также можете установить размеры и положение окна так, чтобы они совпали с положением максимизированного окна, эти состояния отличаются. Система отключает возможность перемещения окна и изменения его размера для максимизированных окон. Кроме того, кнопка максимизации изменяется на кнопку восстановления размера.
    Минимизированное окно (minimized window) - это окно, у которого установлен стиль WS_MINIMIZE. По умолчанию система уменьшает окно до размеров его кнопки на панели задач и перемещает окно на панель задач.
    Развёрнутое окно (restored window) - это окно, которое было восстановлено в исходные размер и положение после минимизации или максимизации.
    Если приложение укажет стили WS_MAXIMIZE или WS_MINIMIZE в функции CreateWindowEx, окно создастся изначально максимизированным или минимизированным. После создания окна приложение может использовать функцию CloseWindow для минимизации окна. Функция ArrangeIconicWindows упорядочивает свёрнутые окна на рабочем столе или в родительском окне. Функция OpenIcon восстанавливает минимизированное окно.
    Функция ShowWindow может минимизировать, максимизировать и восстанавливать окна. Она также может менять видимость окон и задавать активное окно. Функция SetWindowPlacement содержит ту же функциональность, что и ShowWindow, но она также может менять размещение окна по умолчанию в положениях минимизации, максимизации и восстановления.
     

    Вложения:

    • 30.png
      30.png
      Размер файла:
      495,6 КБ
      Просмотров:
      101
    Последнее редактирование: 23 мар 2019
    kero нравится это.
  6. Mikl___

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

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.748
    Функции IsZoomed и IsIconic определяют, является ли заданное окно максимизированным или минимизированным соответственно. Функция GetWindowPlacement может получить положения минимизации, максимизации и восстановления для окна, а также определить состояние отображения окна.
    Когда система получает команду на максимизацию или восстановление минимизированного окна, она отправляет окну сообщение WM_QUERYOPEN. Если оконная процедура вернёт 0, то система проигнориует команду максимизации или восстановления.
    Система автоматически устанавливает размеры и положение максимизированного окна. Чтобы изменить системные умолчания, приложение может либо использовать функцию SetWindowPlacement, либо обрабатывать сообщение WM_GETMINMAXINFO, которое отправляется окну непосредственно перед максимизацией. Сообщение WM_GETMINMAXINFO содержит указатель на запись MINMAXINFO, содержащую значения размера и положения окна, присвоенные системой. Приложение может изменить эти значения.
    Размер и положение окна

    Размер и положение окна выражаются как ограничивающий прямоугольник (bounding rectangle), задавая его координаты относительно экрана (для окон верхнего уровня) или родительского окна (для child окон). Приложение указывает размер и положение окна при его создании, но может изменить их в любое время.
    В этой секции также рассматриваются:
    • Размеры и положение по умолчанию
    • Отслеживание размера
    • Системные команды
    • Функции для размера и положения
    • Сообщения для размера и положения
    Размеры и положение по умолчанию

    Приложение может разрешить системе задать начальные положение и размер окна верхнего уровня, указав CW_USEDEFAULT в функции CreateWindowEx. Если приложение установит координаты окна в значение CW_USEDEFAULT, то если приложение не создало других окон верхнего уровня, то система будет размещать окно относительно экрана; в противном случае система будет размещать окно относительно последнего созданного окна верхнего уровня. Если приложение также укажет CW_USEDEFAULT для ширины и высоты окна, то размеры окна будут определяться системой. Если приложение до этого создавало окна верхнего уровня, то система будет определять размер окна по последнему созданному окну верхнего уровня. Указание CW_USEDEFAULT для child или pop-up окна создаст окно с минимальным размером.
    Отслеживание размера

    Система хранит максимальный и минимальный размеры окон со стилем WS_THICKFRAME; окно с этим стилем имеет рамку с возможностью изменения размера. Минимальный размер (minimum tracking size) - это наименьший размер окна, который пользователь сможет задать, перетаскивая рамку окна. Аналогично максимальный размер (maximum tracking size) - это наибольший размер окна, который сможет получить пользователь при изменении размеров окна.
    Минимальные и максимальные размеры окна устанавливаются в системные значения по умолчанию при создании окна. Приложение может узнать эти значения и заместить их на свои при обработке сообщения WM_GETMINMAXINFO.
    Системные команды

    Приложение, которое имеет оконное меню ("системное меню"), может изменить размеры окна отправкой системный команд. Системные команды отправляются, когда пользователь выбирает команды из оконного меню. Приложение может эмулировать действия пользователя отправкой сообщения WM_SYSCOMMAND окну. Следующие системные команды влияют на размер и положение окна:
    КомандаОписание
    SC_CLOSEЗакрывает окно. Эта команда отправляет сообщение WM_CLOSE окну. Дальнейшие действия зависят от окна (обработчика сообщения WM_CLOSE).
    SC_MAXIMIZEМаксимизирует окно.
    SC_MINIMIZEМинимизирует окно.
    SC_MOVEПеремещает окно.
    SC_RESTOREВосстанавливает минимизированное или максимизированное окно на его исходные положение и размер.
    SC_SIZEНачинает процедуру изменения размера. Для изменения размера окна можно использовать мышь или стрелки на клавиатуре.
    Функции для размера и положения

    После создания окна приложение может установить размер или положение окна вызовом одной из следующих функций: SetWindowPlacement, MoveWindow, SetWindowPos и DeferWindowPos. SetWindowPlacement может установить минимизированный размер, максимизированный размер, обычный размер и положение окна, а также состояние видимости. Функции MoveWindow и SetWindowPos похожи; они обе устанавливают размер или положение одного окна в приложении. Но функция SetWindowPos допускает изменение видимости окна; а MoveWindow - нет. Используя функции BeginDeferWindowPos, DeferWindowPos и EndDeferWindowPos, приложение может одновременно изменить атрибуты нескольких окон сразу - включая положение, размеры, Z-порядок и видимость.
    Приложение может получить ограничивающий прямоугольник вызовом функции GetWindowRect. GetWindowRect заполняет запись TRect координатами левого-верхнего и правого-нижнего углов окна. Координаты вычисляются относительно левого-верхнего угла экрана - даже для child окон (позиционирование которых осуществляется относительно родительского окна). Функции ScreenToClient или MapWindowPoints могут быть использованы для перевода экранных координат в относительные координаты для child окон.
    Функция GetClientRect возвращает координаты клиентской области окна. GetClientRect заполняет TRect координатами левого-верхнего и правого-нижнего углов клиентской области окна, но координаты считаются относительно самой клиентской области окна. То есть левый-верхний угол всегда имеет координаты (0, 0), а координаты правого-нижнего угла - это ширина и высота клиентской области окна.
    Функция CascadeWindows раскладывает каскадом (cascade) окна на рабочем столе или child окна в родительском окне. Функция TileWindows раскладывает окна черепицей (tiles).
    Сообщения для размера и положения

    Окну, чьё положение должно измениться, система отправляет сообщение WM_GETMINMAXINFO. К примеру, это сообщение будет отправлено, если пользователь щёлкнул по командам Переместить или Изменить размер из оконного меню или щёлкает по рамке окна или заголовку; также это сообщение будет отправлено, если приложение вызовет функцию SetWindowPos для перемещения или изменения размера окна. Сообщение WM_GETMINMAXINFO передаёт указатель на запись TMinMaxInfo, которая содержит размер и положение максимизированного окна по умолчанию, равно как и минимальные и максимальные размеры окна. Приложение может изменить эти значения, обрабатывая сообщение WM_GETMINMAXINFO. Чтобы получать сообщения WM_GETMINMAXINFO, окно должно иметь стиль WS_THICKFRAME или WS_CAPTION. Окно со стилем WS_THICKFRAME получит это сообщение во время создания окна, а также при изменениях размера и положения.
    Окну, чьи размеры, положение, Z-порядок или видимость должны измениться, система отправит сообщение WM_WINDOWPOSCHANGING. Это сообщение содержит указатель на запись TWindowsPos, которая указывает новые положения, размер, Z-порядок и видимость окна. Изменяя поля записи TWindowsPos, приложение может изменить способ отображения окна.
    После того, как изменились размер, положение, Z-порядок или видимость окна, система отправляет окну сообщение WM_WINDOWPOSCHANGED. Это сообщение содержит указатель на запись TWindowPos, которая информирует окно о его новых атрибутах. Изменение этой записи не приведёт к изменению атрибутов окна. Окно, которому нужно обрабатывать сообщения WM_SIZE и WM_MOVE, должно передавать сообщение WM_WINDOWPOSCHANGED в функцию DefWindowProc; иначе система не будет рассылать сообщения WM_SIZE и WM_MOVE.
    Когда окно создаётся или изменяет размер, система также отправляет окну сообщение WM_NCCALCSIZE. Это сообщение используется системой для вычисления размера и относительного положения клиентской области окна (относительно левого-верхнего угла самого окна). Как правило, окно просто передаёт это сообщение обработчику по умолчанию; однако это сообщение может быть использовано приложениями, которые хотят изменить размеры клиентской области окна.
    Анимация окон

    Вы можете создавать специальные эффекты при показе или скрытии окон, используя функцию AnimateWindow. При использовании этой функции вы можете указать эффекты roll, slide, collapse, expand или fade.
    По умолчанию система использует анимацию roll. При этой анимации окно "раскатывается" от одного края до противоположного. Вы можете указать в флагах направление анимации: горизонтально, вертикально или по диагонали.
    С флагом AW_SLIDE система использует анимацию slide. При этом окно "выезжает". Анимация похожа на roll анимацию. roll анимация использует сглаженный край окна, имитируя рулон, а slide использует чёткие края, имитируя плоское окно. Аналогично, вы можете указать в флагах направление анимации: горизонтально, вертикально или по диагонали.
    Флаг AW_BLEND задаёт анимацию alpha-blended fade. При этом окно постепенно "проявляется" или исчезает. У этой анимации нет направления.
    Вы также можете использовать флаг AW_CENTER для анимации разворота окна из центра окна. Анимация похожа на roll анимацию, но roll анимация показывает окно от границы к границе окна, а center анимация - от центра окна до его границ. У этой анимации нет направления.
    Компоновка и отражение

    Компоновка окна (window layout) определяет способ размещения в окне или контексте устройства (DC - Device Context) текста и объектов GDI. Некоторые языки (вроде английского, французского, русского и немецкого) требуют компоновку left-to-right (LTR) - "слева направо". Другие языки (арабский, иврит) требуют компоновки right-to-left (RTL) - "справа налево". Компоновка окна применяется к тексту, но она также влияет и на другие элементы окна, включая растры, значки, расположение кнопок, многоуровневых деревьев, то, будет ли увеличиваться или уменьшаться горизонтальная координата при сдвиге вправо и т.п. К примеру, после того, как приложение установит компоновку RTL, начало координатной сетки в окне будет расположено в правом-верхнем углу окна (или контекста устройства) - в то время как обычно точка отсчёта располагается в левом-верхнем угле; а горизонтальная координата будет увеличиваться при движении влево, а не вправо, как это было с LTR. Однако не все объекты подчиняются компоновке окна. К примеру, компоновки диалоговых окон, окон-сообщений (message box) и контекстов устройств, не ассоциированных с окном (метафайлы, принтеры и другие) - обрабатываются отдельно. Некоторые такие особенности также упомянуты ниже.
    Оконные функции позволяют вам указать или изменить компоновку окна. Заметьте, что изменение компоновки на RTL (этот процесс также называется зеркалированием или отражением окна - mirroring) не поддерживается окнами, которые установили стиль CS_OWNDC, а также контекстами устройств в режиме GM_ADVANCED.
    По умолчанию окно и контексты устройств имеют компоновку left-to-right (LTR). Чтобы изменить компоновку окна на RTL - вызовите функцию CreateWindowEx с флагом WS_EX_LAYOUTRTL. Также, по умолчанию, child окна (т.е. окна, создаваемые со стилем WS_CHILD) будут иметь ту же компоновку, что и их родитель. Чтобы отключить наследование зеркалирования для child окон и задавать компоновку явно - добавьте стиль WS_EX_NOINHERITLAYOUT в вызове CreateWindowEx. Заметьте, что компоновка не наследуется owned окнами (создаваемыми без стиля WS_CHILD) или окнами, чей параметр hWnd в функции CreateWindowEx был установлен в 0. Чтобы отключить наследование зеркалирования в отдельном окне, обработайте сообщение WM_NCCREATE, где используйте функции GetWindowLong и SetWindowLong для замены флага WS_EX_LAYOUTRTL.
    Вы также можете изменить умолчание для всего процесса вызовом функции SetProcessDefaultLayout. Все окна, создаваемые после вызова SetProcessDefaultLayout (LAYOUT_RTL), будут создаваться зеркалированными (без указания флага), но уже существующие окна не изменятся. Чтобы отключить зеркалирование по умолчанию - используйте SetProcessDefaultLayout(0).
    Заметьте, что функция SetProcessDefaultLayout отразит контексты устройств только в отзеркалированных окнах. Чтобы отразить произвольный DC - вызовите функцию SetLayout.
    Растры (bitmap) и значки (icon) в отражённом окне также по умолчанию зеркалируются. Однако это не всегда бывает необходимо. Чтобы отключить зеркалирование растра, вызовите функцию SetLayout с установленным флагом LAYOUT_BITMAPORIENTATIONPRESERVED в dwLayout. Чтобы отключить зеркалирование в DC, вызовите SetLayout(DC, 0).
    Чтобы узнать текущую компоновку по умолчанию, вызовите функцию GetProcessDefaultLayout. При успешном вызове pdwDefaultLayout будет содержать LAYOUT_RTL или 0. Чтобы узнать компоновку контекста устройства, вызовите функцию GetLayout. При успешном вызове она вернёт набор флагов, управляющих компоновкой, которые вы можете проверить на LAYOUT_RTL и LAYOUT_BITMAPORIENTATIONPRESERVED.
    Изменить компоновку после создания окна можно функцией SetWindowLong. К примеру, это может понадобится при смене языка UI в run-time. Однако при этом вы также должны обновить (перерисовать) содержимое окна.
    При отражении окна вы должны думать в терминах "ближе" и "дальше", а не "левее" и "правее". Иначе у вас могут быть проблемы. Частой ошибкой является сценарий конвертирования координат между экранными и клиентскими. К примеру, приложение может использовать такой код для расположения элемента управления в окне:
    Код (Pascal):
    1. // КОД НИЖЕ - ОШИБОЧЕН
    2.  
    3. // Получаем координаты окна в экранных координатах
    4. GetWindowRect(hControl, rControlRect);
    5.  
    6. // Проецируем координаты экрана в клиентские координаты диалога
    7. ScreenToClient(hDialog, rControlRect.left);
    8. ScreenToClient(hDialog, rControlRect.right);
    Этот код вызовет проблемы в отзеркалированных окнах, потому что в них "лево" становится "право" и наоборот. Чтобы избежать этой проблемы, замените вызовы функции ScreenToClient на вызовы MapWindowPoints:
    Код (Pascal):
    1. // Корректный код
    2. GetWindowRect(hControl, ControlRect);
    3. MapWindowPoints(0, hDialog, rControlRect, 2);
    Этот код будет работать корректно, потому что функция MapWindowPoints умеет работать с прямоугольниками (ScreenToClient и ClientToScreen работают только с точками), поэтому она может учесть зеркалированность окон и поменять местами левые и правые грани прямоугольника при необходимости.
    Ещё одна практика, которая может вызвать проблемы в отзеркалированных окнах - позиционирование элементов управления, используя экранные координаты вместо клиентских. К примеру, код ниже использует разницу в экранных коодинатах для размещения элемента управления в диалоговом окне:
    Код (Pascal):
    1. // КОД НИЖЕ - ОШИБОЧЕН
    2. var
    3.   rdDialog: TRect;
    4.   rcControl: TRect;
    5.   hControl: HWND;
    6. begin
    7.   GetWindowRect(hDlg, rcDialog);              // Получение прямоугольника в экранных координатах
    8.   GetWindowRect(hControl, rcControl);
    9.   MoveWindow(hControl,
    10.              rcControl.left - rcDialog.left,  // Получение позиции x в клиентских координатах
    11.              rcControl.top - rcDialog.top,
    12.              nWidth,
    13.              nHeight,
    14.              False);
    Этот код будет работать для диалогового окна с компоновкой left-to-right (LTR) и режимом проецирования (mapping mode) элемента управления MM_TEXT, потому что новая позиция по X в клиентских координатах соответствует разнице в левых краях элемента управления и диалога в экранных координатах. Но для отзеркалированного диалога вам нужно использовать MapWindowPoints, как показано ниже:
    Код (Pascal):
    1. // Корректный код
    2. var
    3.   rcDialog: TRect;
    4.   rcControl: TRect;
    5.   hControl: HWND;
    6. begin
    7.   ..
    8.   GetWindowRect(hControl, rcControl);
    9.  
    10.   // MapWindowPoints работает корректно в обоих режимах (прямом и зеркальном)
    11.   MapWindowPoints(0, hDlg, rcControl, 2);
    12.  
    13.   // Теперь rcControl - в клиентских координатах
    14.   MoveWindow(hControl, rcControl.left, rcControl.top, nWidth, nHeight, False);
    Отражение диалоговых окон и окон-сообщений

    Диалоговые окна и окна-сообщения (message box) не наследуют компоновку окна, поэтому вам нужно устанавливать компоновку явно. Чтобы отразить окно-сообщени, используйте флаг MB_RTLREADING при вызове функций MessageBox или MessageBoxEx. Чтобы изменить компоновку диалога - укажите стиль WS_EX_LAYOUTRTL в шаблоне диалога. Вкладки свойств (property sheets) являются частным случаем диалогов. Каждая вкладка трактуется как отдельный диалог, поэтому вам нужно включать стиль WS_EX_LAYOUTRTL для каждой вкладки отдельно.
    Отражение контекстов устройств, не ассоциированных с окном

    Контексты устройств (DC), которые не ассоциированы с окном, не наследуют компоновку, поэтому вам нужно указывать её явно. Для изменения компоновки контекста устройства используйте функцию SetLayout.
    Функция SetLayout редко используется с окнами. Как правило, окна получают ассоциированный DC только при обработке сообщения WM_PAINT. Иногда приложение может создавать DC для окна вызовом GetDC. В любом случае, компоновка этих DC устанавливается в соответствии с компоновкой целевого окна.
    Вызов функции SetLayout не влияет на значения, возвращаемые функциями GetWindowOrgEx, GetWindowExtEx, GetViewportOrgEx и GetViewportExtEx.
    При RTL компоновке функция GetMapMode вернёт MM_ANISOTROPIC вместо MM_TEXT. Вызов SetMapMode с MM_TEXT будет работать корректно; будет изменено только возвращаемое значение GetMapMode. Аналогично, вызов SetLayout(hdc, LAYOUT_RTL) при режиме MM_TEXT приведёт к смене режима на MM_ANISOTROPIC.
    Уничтожение окна

    В целом, приложение должно уничтожать все окна, которые оно создало. Оно может сделать это вызывая функцию DestroyWindow. Когда окно уничтожается, система скрывает окно (если оно было видимо), а затем удаляет все внутренние данные, ассоциированные с окном. Описатель окна (handle) становится недопустимым и не должен более использоваться приложением.
    Обычно приложения удаляет окна вскоре после их создания. К примеру, приложение удаляет диалоговое окно со всеми дочерними окнами как только оно получит достаточно информации от пользователя. В конечном итоге приложение уничтожит и главное окно (непосредственно перед выходом).
    Перед уничтожением окна приложение должно удалить любые данные, ассоциированные с окном (если они есть), а также освободить системные ресурсы, выделенные для окна. Если приложение не освободит ресурсы, то они будут освобождены системой при завершении приложения.
    Уничтожение окна не влияет на оконный класс этого окна. Приложение может создавать окна данного оконного класса и после удаления окна этого класса, равно как и продолжить использование других окон этого класса. Уничтожение окна также уничтожит все его descendant окна (т.е. все child окна, child окна child окон и так далее). Функция DestroyWindow отправляет сообщение WM_DESTROY сначала самому окну, затем всем его child окнам, а затем, аналогично, и descendant окнам.
    Окно с оконным меню также получит сообщение WM_CLOSE, когда пользователь щёлкнет по Закрыть. Приложение может запросить у пользователя подтверждение закрытия окна в обработчике этого сообщения. Если пользователь согласен с закрытием окна, то приложение может вызвать функцию DestroyWindow для уничтожения окна.
    Если уничтожаемое окно является активным, то активным окном становится другое окно. Оно же получает фокус ввода. Окно, которое станет активным, определяется по порядку окон в списке ALT+ESC.
     
    Последнее редактирование: 23 мар 2019
    kero нравится это.
  7. Mikl___

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

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.748
    Глава тринадцатая. Память Братца Кролика

    Сегментированная память

    Windows 1.0 была разработана для 16-разрядных микропроцессоров способных адресовать 1024 Кб = 1 Мб памяти. Верхние 384 Кб памяти резервировались для видеоадаптера и системного BIOS. Для программ и данных оставалось 1024 Кб - 384 Кб = 640 Кб.
    Чтобы адресовать 1 Мб требуется 20-разрядный адрес (220= 1.048.576), который формировался из двух 16-разрядных значений: сегмента и смещения внутри сегмента. Микропроцессор имел четыре сегментных регистра: кода (CS), данных (DS), стека (SS) и дополнительный (ES) сегментный регистр. 20-разрядный физический адрес получался сдвигом содержимого сегментного регистра влево на 4 разряда и добавлением к полученной величине смещения внутри сегмента:
    00.png
    Прикладные программы становились более сложными и большими по объему, появлялась необходимость во множестве сегментов для кода и данных. Были определены близкие (near) указатели, имевшие величину 16 бит, и используемые для доступа к сегментам кода и данных по умолчанию, и дальние (far) указатели, которые имели ширину 32 бита, и состоявшие из смещения и сегмента. С помощью этого 32-разрядного адреса нельзя было адресовать память непосредственно. Нельзя было увеличить адрес на 1 без учета логики, обрабатывающей переполнение смещения и установку сегментного адреса. Были определены различные модели программирования:
    • model tiny (один сегмент совмещающий данные и код),
    • model small (один сегмент для кода, один сегмент для данных),
    • model medium (один сегмент данных, много сегментов кода),
    • model compact (один сегмент кода, много сегментов данных),
    • model large (много сегментов кода и данных),
    • model huge (аналогично large, но со встроенной логикой обработки увеличения адреса).
    MS DOS не имела достаточно большой поддержки управления памятью. Программы определяли, какое количество памяти имеется в их распоряжении, и использовали ее всю целиком.
    Windows 1.0 была многозадачной средой, появилась необходимость расширить возможности управления памятью. Множество программ загружаются в память, позднее освобождают ее, память становится фрагментированной. Операционная система должна перемещать блоки памяти, чтобы объединить свободное пространство. Многозадачность без управления памятью существовать не может.
    Нельзя перемещать блоки кода и данных в памяти безотносительно прикладной программы. Так она будет содержать неправильный адрес. Но если программа использует только смещения, то сегменты могут быть изменены операционной системой.
    Программы для Windows были ограничены использованием только small и medium моделями памяти с одним 64-килобайтным сегментом для данных. Программы использовали близкие указатели для ссылок на свой сегмент данных; адрес сегмента данных для конкретного процесса устанавливался операционной системой при передаче управления программе. Это позволяло Windows перемещать сегмент данных программы и переустанавливать адрес сегмента. Все дальние вызовы функций, выполняемые программой (включая вызовы функций операционной системы), выполнялись когда сегменты кода, используемые программой, были перемещены в память.
    Программа, выполнявшаяся в 16-разрядной версии Windows, могла либо выделять память из собственного сегмента данных (локальная память, адресуемой с помощью 16-разрядного указателя смещения), либо за пределами своего сегмента данных (глобальная память адресуемая с помощью 32-разрядных адресов). В обоих случаях функции выделения памяти возвращали описатель блока памяти. Программы должны были фиксировать блок в памяти. Функции фиксации возвращали дальний указатель. После использования памяти следовало снять фиксацию с блока памяти. Это давало Windows возможность перемещать блоки памяти при необходимости. Процесс фиксации и снятия фиксации часто выполнялся в процессе обработки одного сообщения, и часто приводил к многочисленным ошибкам.
    Описатели памяти ― указатели на таблицу в ядре Windows. Ранние версии Windows содержали сегмент памяти, который содержал главную таблицу описателей памяти.
    В современной Windows содержатся некоторые части схемы адресации Windows 1.0. Архитектура Windows скрывает это, но это проявляется в структуре и синтаксисе вызовов функций.
    Проблемы с ближними и дальними адресами в 16-разрядных версиях Windows переносились и на файловый ввод/вывод. Во многих случаях программа получала от диалогового окна имя файла, которое являлось дальним указателем. Но в model small и modal medium моделях памяти WinAPI-функции файлового ввода/вывода ожидали ближнего указателя. Аналогично, программа, которая хранила данные в блоках глобальной памяти, должна была адресовать их с помощью дальних указателей и, как следствие, файловый ввод/вывод в эти блоки был затруднен. Возникала необходимость, чтобы Windows дублировала вызовы всех функций файлового ввода/вывода, написанных для MS DOS.
    Промежуточные решения

    версия Windows 3.0 получила широкое распространение, у Microsoft появилась возможность поддерживать защищенный режим (protected mode) процессора Intel 286 (вместо реального режима), причем без существенных проблем для уже существовавших программ. В защищенном режиме сегментный адрес называется селектором (selector). Он также имеет ширину 16 бит, но внутри 286 процессора он ссылается на 24-разрядный базовый адрес (base address), который складывается затем с 16-разрядным смещением, и таким образом, формируется 24-разрядный физический адрес, с помощью которого можно адресовать до 224 = 16.777.216 байт = 16 Мб памяти:
    91.png
    01.png
    trans-lin.png
    Чтобы обеспечить переход от более ранних версий Windows, описатель, возвращаемый функцией выделения глобальной памяти, был просто селектором. Такое использование защищенного режима отчасти облегчало управление памятью, но истинная цель еще не была достигнута.
    32/64-разрядные Windows

    32-разрядные Windows используют 32-разрядную адресацию памяти и могут реализовать доступ к 232 = 4.294.967.296 байтам (или 4 Гб) физической памяти.
    64-разрядные Windows могут реализовать доступ к 264 = 18.446.744.073.709.551.616 байтам или 16 экзабайтам
    Несмотря на то, что стало возможным на аппаратном уровне использовать сегментную адресацию памяти, Windows сохраняет неизменными сегментные регистры и использует 32-разрядную плоскую (model flat) адресацию. Это означает, что адреса в приложении Windows хранятся как простые 32-разрядные величины, обеспечивая доступ к 4 Гб памяти.
    Используемые прикладными программами Windows 32-разрядные адреса для доступа к коду и данным, не являются 32-разрядными физическими адресами, которые микропроцессор использует для адресации физической памяти. Адрес, который используется приложением, называется виртуальным адресом (virtual address). Он преобразуется в физический адрес посредством таблицы страниц (page table). Этот процесс обычно прозрачен для прикладных программ. Программе кажется, что она расположена в 32-разрядном адресном пространстве, и для доступа к ней не требуется никаких особых усилий. Однако, в технической документации по Windows существуют ссылки на виртуальные адреса и таблицы страниц.
    Физическая память делится на страницы (pages) размером 4096 байт (4 Кб). Каждая страница начинается с адреса, в котором младшие 12 бит нулевые. 8 Мб памяти, содержат 2048 страниц. Операционная система Windows хранит набор таблиц страниц (каждая таблица сама представляет собой страницу) для преобразования виртуального адреса в физический.
    Каждый процесс, выполняемый в Windows, имеет свою собственную страницу каталога (directory page) таблиц страниц, которая содержит до 1024 32-разрядных дескриптора таблиц страниц. Физический адрес страницы каталога таблиц страниц хранится в регистре CR3. Содержимое этого регистра изменяется при переключении Windows между процессами. Старшие 10 бит виртуального адреса определяют один из 1024 возможных дескрипторов в каталоге таблиц страниц. В свою очередь, старшие 20 бит дескриптора таблицы страниц определяют физический адрес таблицы страниц (младшие 12 бит физического адреса равны нулю). Каждая таблица страниц содержит, в свою очередь, до 1024 32-разрядных дескриптора страниц. Выбор одного из этих дескрипторов определяется содержимым средних 10 битов исходного виртуального адреса. Старшие 20 бит дескриптора страницы определяют физический адрес начала страницы, а младшие 12 бит виртуального адреса определяют физическое смещение в пределах этой страницы.
    32-разрядный виртуальный адрес с которым оперирует программа представлен в виде 10-разрядного индекса в таблице каталога таблиц страниц (Directory), 10-разрядного индекса в таблице страниц (Table), 12-разрядного смещения (Offset):
    LT4k.png
    Для каждого процесса в регистре CR3 хранятся (r) старшие 20 бит физического адреса таблицы каталога таблиц страниц:rrrr-rrrr-rrrr-rrrr-rrrr
    Начальный физический адрес каталога таблиц страниц определяется так:rrrr-rrrr-rrrr-rrrr-rrrr-0000-0000-0000
    каждая страница имеет размер 4 Кб и начинается с адреса, у которого 12 младших бит нулевые.
    Сначала микропроцессор получает физический адрес:
    rrrr-rrrr-rrrr-rrrr-rrrr-dddd-dddd-dd00
    По этому адресу содержится другое 20-разрядное значение (t-table):tttt-tttt-tttt-tttt-tttt
    соответствующее начальному физическому адресу таблицы страниц:tttt-tttt-tttt-tttt-tttt-0000-0000-0000
    Затем, микропроцессор осуществляет доступ по физическому адресу:tttt-tttt-tttt-tttt-tttt-pppp-pppp-pp00
    Здесь хранится 20-битная величина,
    являющаяся основой для физического адреса начала страницы памяти (f-page frame):
    ffff-ffff-ffff-ffff-ffff
    Результирующий 32-разрядный физический адрес получается в результате
    комбинирования основы физического адреса страницы и 12-разрядного смещения виртуального адреса:
    ffff-ffff-ffff-ffff-ffff-oooo-oooo-oooo
    Это и есть результирующий физический адрес.
    Микропроцессоры имеют внутреннюю кэш-память, в которой могут храниться таблицы страниц. Фактически, преобразование адреса осуществляется очень быстро без каких-либо существенных потерь производительности. Такое двухступенчатое разделение памяти на страницы дает каждому приложению теоретическое ограничение по памяти в 1 миллион страниц по четыре килобайта каждая. Преимущества разделения памяти на страницы.
    1. приложения изолированы друг от друга. Никакой процесс не может случайно или преднамеренно использовать адресное пространство другого процесса, так как он не имеет возможности его адресовать без указания соответствующего значения регистра CR3 этого процесса, которое устанавливается только внутри ядра Windows.
    2. такой механизм разделения на страницы решает одну из основных проблем в многозадачной среде ― объединение свободной памяти. При более простых схемах адресации в то время, как множество программ выполняются и завершаются, память может стать фрагментированной. В случае, если память сильно фрагментирована, программы не могут выполняться из-за недостатка непрерывной памяти, даже если общего количества свободной памяти вполне достаточно. При использовании разделения на страницы нет необходимости объединять свободную физическую память, поскольку страницы необязательно должны быть расположены последовательно. Все управление памятью производится с помощью манипуляций с таблицами страниц. Потери связаны с самими таблицами страниц и с их 4 Кб размером.
    3. в 32-битных дескрипторах страниц существует еще 12 бит, кроме тех, которые используются для адреса страницы.
    PTE.png

    1. "Бит доступа" (accessed bit) показывает возможность доступа к конкретной странице;
    2. "Бит мусора" (dirty bit) показывает, была ли произведена запись в эту страницу.
      Windows может использовать эти биты для того чтобы определить, можно ли сохранить эту страницу в файле подкачки для освобождения памяти.
    3. "Бит присутствия" (present bit) показывает, была ли страница сброшена на диск и должна ли быть подкачена обратно в память.
    4. "Бит чтения/записи" показывает, разрешена ли запись в данную страницу памяти. Этот бит обеспечивает защиту кода от "блуждающих" указателей. Например, если включить следующий оператор в программу для Windows:
    Код (C):
    1. *(int*) WinMain = 0;
    то на экран будет выведено следующее окно сообщения:
    This program has performed an illegal operation and will be shutdown.
    ("программа выполнила недопустимую операцию и будет завершена").
    Этот бит не препятствует компилированной и загруженной в память программе быть запущенной на выполнение.
    • Управление памятью в 32-разрядных Windows
      • Виртуальные адреса имеют разрядность 32 бита.
      • Для выявления нулевых указателей 0 - 0FFFFh
      • Программа и данные имеют адреса в диапазоне от 0 до 7FFFFFFFh.
      • Сама Windows использует адреса от 80000000h до 0FFFFFFFFh. В этой области располагаются точки входа в динамически подключаемые библиотеки Windows.
    • Управление памятью в 64-разрядных Windows
      • Для выявления нулевых указателей 0 - 0FFFFh
      • Для кода и данных пользовательского режима 10000h- 3FFFFFEFFFFh
      • Закрытый раздел размером 64 Кб 3FFFFFF0000h - 3FFFFFFFFFFh
      • Для кода и данных режима ядра 40000000000h-0FFFFFFFFFFFFFFFFh
    Общее количество свободной памяти, доступной программе, определяется как количество свободной физической памяти плюс количество свободного места на жестком диске, доступного для свопинга страниц. Как правило, при управлении виртуальной памятью Windows использует алгоритм LRU (least recently used) для определения того, какие страницы будут сброшены на диск. Бит доступа и бит мусора помогают осуществить эту операцию. Страницы кода не должны сбрасываться на диск: поскольку запись в его страницы запрещена, они могут быть просто загружены из файла с расширением .EXE или из динамически подключаемой библиотеки. Иногда вы можете заметить, что происходит обращение к диску во время перемещения мыши из рабочей области одной программы в рабочую область другой программы. Почему это происходит? Windows должна посылать сообщения о передвижении мыши второму приложению. Если программа, выполняющая обработку этого сообщения, не находится в данный момент в памяти, то Windows загружает ее с диска. Если запущено несколько больших приложений одновременно, а в компьютере немного памяти, то вы можете стать свидетелем чрезмерного количества обращений к диску в моменты перехода от одной программы к другой, так как Windows вновь загружает с диска ранее удаленные страницы. Время от времени отдельные программы будут замедляться (или приостанавливаться на какое-то время), пока Windows осуществляет свопинг.
    Страницы кода могут разделяться между приложениями. Это особенно полезно для динамически подключаемых библиотек. Несколько программ, выполняемых одновременно, могут использовать одни и те же функции Windows, не требуя, чтобы один и тот же код загружался в память несколько раз. Достаточно одной копии. При динамическом выделении памяти каждый выделяемый блок необязательно получает свою собственную страницу. Последовательное выделение небольших объемов памяти производится в одной и той же физической странице с ближайшего 4-разрядного стартового адреса (то есть для выделения одного байта используется 16 бит). Если какой-либо блок расширяется, то он может быть физически перемещен в памяти, если следующий за ним блок памяти занят.
    Кроме разделения памяти на страницы по 4 Кб физическая память не может стать безнадежно фрагментированной, поскольку дефрагментация заключается только в манипуляциях с таблицами страниц. Однако виртуальная память конкретного приложения может стать фрагментированной, если приложение осуществляет выделение, освобождение, повторное выделение и освобождение слишком большого числа блоков памяти. Ограничения в 2 ГБ обычно достаточно для приложения и его данных. Но возможно, что программа столкнется с нехваткой физической памяти до того, как будет достигнут предел виртуальной памяти. Если вы считаете, что это может случиться с вашей программой, то вам стоит подумать об использовании перемещаемой (moveable) памяти.
    Выделение памяти

    WinAPI-функции

    Вы можете определить в программе указатель (например, на массив целых чисел) следующим образом:
    Код (ASM):
    1. pMem dq ?
    Указатель pMem ― 64-разрядное неинициализированое число. Вы можете выделить блок памяти, на который будет указывать pMem, следующим образом:
    Код (ASM):
    1. invoke    malloc,1024
    2.     mov    pMem,rax
    При этом выделяется блок памяти размером 1024 байта, который может хранить 256 32-разрядных целых. Указатель, равный NULL, показывает, что выделение памяти не было успешным. Можно также выделить такой блок памяти, используя следующий вызов:
    Код (ASM):
    1. invoke    calloc,256, sizeof DWORD
    2.     mov    pMem,rax
    Два параметра функции calloc перемножаются и в результате получается 1024 байта. Кроме того, функция calloc производит обнуление блока памяти.
    Если вам необходимо увеличить размер блока памяти (например, удвоить его), то вы можете вызвать функцию:
    Код (ASM):
    1. invoke    realloc,pMem, 2048
    2.     mov    pMem,rax
    Указатель является параметром функции, и указатель (возможно, отличающийся по значению от первого, особенно, если блок увеличивается) является возвращаемым значением функции. Этот пример показывает, что Windows может перемещать блок в рамках виртуальной памяти. Например, если вы выделили блок размером 1024 байта, то его виртуальный адрес может быть равен 750100h. Вы можете выделить второй блок памяти и получить виртуальный адрес 750504h. Расширив первый блок памяти до 2048 байт, использовать тот же виртуальный адрес невозможно. В этом случае Windows должна переместить блок в физической памяти на новую страницу.
    При окончании работы с памятью, вызовите функцию:
    Код (ASM):
    1. invoke    free,pMem
    Фундаментальное выделение памяти в Windows

    Всё, что вы можете делать с помощью WinAPI-функций, вы можете делать самостоятельно, или используя вызовы функций ядра Windows. Функция Windows для выделения блока памяти для указателя на целые:
    Код (ASM):
    1. invoke GlobalAlloc,uiFlags, dwSize
    2. mov pMem,rax
    Функция имеет два параметра:
    • набор флагов
    • размер выделяемого блока в байтах
    Функция возвращает виртуальный адрес, который может использоваться в программе для доступа к выделенной памяти. Значение NULL говорит о том, что имеющейся в распоряжении памяти для выделения недостаточно.
    Для каждой функции, начинающейся со слова Global, существует функция, начинающаяся со слова Local. Два набора функций в Windows идентичны. Два различных слова сохранены для совместимости с предыдущими версиями Windows, где функции Global возвращали дальние указатели, а функции Local ― ближние.
    Хотя определения параметров немного отличаются, они оба являются 64-разрядными беззнаковыми целыми. Если первый параметр задать нулевым, то это эквивалентно использованию флага GMEM_FIXED (=0).
    Такой вызов функции GlobalAlloc эквивалентен вызову функции malloc. В ранних версиях Windows присутствие флага GMEM_FIXED приводило к проблемам управления памятью, поскольку Windows не могла перемещать такие блоки в физической памяти. Сейчас флаг GMEM_FIXED вполне допустим, поскольку функция возвращает виртуальный адрес, и операционная система может перемещать блок в физической памяти, внося изменения в таблицу страниц.
    Можно использовать флаг GMEM_ZEROINIT для обнуления всех байтов выделяемого блока памяти. Флаг GPTR включает в себя флаги GMEM_FIXED и GMEM_ZEROINIT:
    Код (ASM):
    1. GPTR equ GMEM_FIXED or GMEM_ZEROINIT
    Функция изменения размера блока памяти:
    Код (ASM):
    1. invoke GlobalReAlloc,pMem, dwSize, uiFlags
    2. mov pMem,rax
    Можно использовать флаг GMEM_ZEROINIT для обнуления добавляющихся в блок памяти байтов, если блок расширяется.
    Функция, возвращающая размер блока памяти:
    Код (ASM):
    1. invoke GlobalSize,pMem
    2. mov dwSize,rax
    Функция освобождения памяти:
    Код (ASM):
    1. invoke GlobalFree,pMem
    Перемещаемая память

    В предыдущих версиях Windows наличие флага GMEM_FIXED приводило к проблемам при управлении памятью, поскольку Windows должна была сохранять блок памяти в фиксированном месте физической памяти. Сейчас блок памяти может быть перемещен в физической памяти при сохранении виртуального адреса неизменным. Функция GlobalAlloc, тем не менее, поддерживает флаг GMEM_MOVEABLE
    и комбинированный флаг для дополнительного обнуления блока памяти:
    Код (ASM):
    1. GHND equ GMEM_MOVEABLE or GMEM_ZEROINIT
    Флаг GMEM_MOVEABLE позволяет перемещать блок памяти в виртуальной памяти. Это не означает, что блок памяти будет перемещен в физической памяти, но адрес, которым пользуется программа для чтения и записи, может измениться.
    Если ваша программа выделяет, расширяет, освобождает память, то виртуальная память может сделаться фрагментированной. Может ли ваша программа дойти до предела в 2 ГБ виртуальной памяти до того, как будет достигнут предел 4, 8 или 16 Мб физической памяти? Проблема встает острее при непрерывном использовании компьютера. Программы, выполнение которых происходит в течение нескольких дней, в конце концов могут столкнуться с большей фрагментацией памяти, чем программы, разработанные для выполнения в течение одного-двух часов. Вы можете захотеть использовать перемещаемую память. Как это делается?
    1. определим указатель и переменную типа GLOBALHANDLE:
      Код (ASM):
      1. pMem dq ?
      2. hGlobal GLOBALHANDLE ?
    2. выделим память:
      Код (ASM):
      1. invoke GlobalAlloc,GHND, 1024
      2. mov hGlobal,rax
    3. Когда вам необходимо обратиться к памяти, для фиксации блока используйте вызов:
      Код (ASM):
      1. invoke GlobalLock,hGlobal
      2. mov pMem,rax
      Эта функция преобразует описатель памяти в указатель. Пока блок зафиксирован, Windows не изменяет его виртуальный адрес.
    4. Когда вы заканчиваете работу с блоком, для снятия фиксации вызовите функцию:
      Код (ASM):
      1. invoke GlobalUnlock,hGlobal
      Этот вызов дает Windows свободу перемещать блок в виртуальной памяти. Для того чтобы правильно осуществлять этот процесс, вы должны фиксировать и снимать фиксацию блока памяти в ходе обработки одного сообщения.
    5. Когда вы хотите освободить память, вызовите функцию GlobalFree с параметром-описателем, а не указателем. Если в данный момент вы не имеете доступа к описателю, то вам необходимо использовать функцию:
      Код (ASM):
      1. invoke GlobalHandle,pMem
      2. mov hGlobal,rax
      Вы можете фиксировать блок памяти несколько раз до того, как снять с него фиксацию. Windows запоминает количество фиксаций, и каждое фиксирование требует снятия для того чтобы дать возможность блоку перемещаться. Перемещение блока в виртуальной памяти не есть перемещение байтов с одного места в другое ― производятся только манипуляции с таблицами страниц. Единственной причиной для выделения перемещаемой памяти служит предотвращение фрагментации виртуальной памяти.
    Удаляемая память

    Если вы используете опцию GMEM_MOVEABLE, то попробуйте использовать опцию GMEM_DISCARDABLE. Эта опция может быть использована только совместно с GMEM_MOVEABLE. Блок памяти, выделенный с этим флагом, может быть удален из физической памяти ядром Windows, когда необходима свободная память. Блоки памяти, содержащие код, являются удаляемыми. Они защищены от записи. Следовательно, быстрее загрузить код из исходного EXE-файла, чем записывать его на диск, а затем вновь загружать с диска. Если вы выделяете память для неизменяемых данных, которые могут быть легко регенерированы (обычно загрузкой из файла), то можно сделать этот блок удаляемым. О том, что данные были сброшены, вы узнаете, когда вызовите функцию GlobalLock и получите в ответ NULL. Теперь, вы восстанавливаете данные.
    Блок памяти не может быть удален до тех пор, пока счетчик фиксаций больше нуля. Для преднамеренного удаления блока памяти, вызовите:
    Код (ASM):
    1. invoke GlobalDiscard,hGlobal
    Другие функции и флаги

    Другим доступным для использования в функции GlobalAlloc является флаг GMEM_SHARE или GMEM_DDESHARE. Этот флаг предназначен для динамического обмена данными.
    Функции GlobalAlloc и GlobalReAlloc могут включать флаги GMEM_NODISCARD и GMEM_NOCOMPACT. Эти флаги указывают Windows не удалять и не перемещать блоки памяти для удовлетворения запросов памяти. Только излишне альтруистичные программисты используют эти флаги.
    Функция GlobalReAlloc может изменять флаги (например, преобразовывать фиксированный блок памяти в перемещаемый, и наоборот), если новый размер блока задан равным нулю, и указан флаг GMEM_MODIFY.
    Функция GlobalFlags возвращает комбинацию флагов GMEM_DISCARDABLE, GMEM_DISCARDED и GMEM_SHARE.
    Функция GlobalMemoryStatus с указателем на структуру типа MEMORYSTATUS для определения количества физической и виртуальной памяти, доступной приложению.
    Windows поддерживает функции:
    • FreeMemory заполнение конкретным байтом,
    • ZeroMemory обнуление памяти,
    • CopyMemory и MoveMemory ― обе копируют данные из одной области памяти в другую. Если эти области перекрываются, то функция CopyMemory может работать некорректно. Вместо нее используйте функцию MoveMemory.
    Перед тем как осуществить доступ к памяти, вам придется проверить, возможен доступ или нет. Если указатель является недействительным, включается общая защита программы. Предварительная проверка указателя гарантирует, что этого не произойдет. Эту проверку выполняют функции IsBadCodePtr, IsBadReadPtr, IsBadWritePtr,IsBadStringPtr.
    • IsBadCodePtr принимает указатель в качестве параметра и возвращает ненулевое значение (TRUE), если указатель действителен.
    • IsBadReadPtr, IsBadWritePtr, IsBadStringPtr получают указатель в качестве первого параметра и длину блока памяти в качестве второго параметра.
    • Функция IsBadStringPtr осуществляет проверку до тех пор, пока не встретит нулевой ограничитель строки.
     

    Вложения:

    • help1.zip
      Размер файла:
      55,9 КБ
      Просмотров:
      12
    • help2.zip
      Размер файла:
      57,4 КБ
      Просмотров:
      12
    • help3.zip
      Размер файла:
      58,6 КБ
      Просмотров:
      15
    • 00.png
      00.png
      Размер файла:
      2,9 КБ
      Просмотров:
      6
    Последнее редактирование: 1 апр 2019
    kero и Aiks нравится это.
  8. Mikl___

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

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.748
    Функции управления виртуальной памятью

    Windows поддерживает ряд функций, начинающихся с Virtual. Эти функции предоставляют значительно больше возможностей управления памятью. Однако, только очень необычные приложения требуют использования эти функции.
    Например, ваша программа читает исходный код и компилирует его, а результат компиляции заносится в память. Затем, вы хотите пометить этот блок памяти как "только для выполнения", то есть так, чтобы было невозможно случайно или преднамеренно прочитать (или того хуже, записать) в него что-либо из программы, которая была только что скомпилирована и готова к выполнению. Это одно из действий, которое должна осуществлять ваша программа для обработки ошибок при работе с указателями в пользовательской программе. Вы можете также пометить часть блоков памяти "только для чтения". Оба указанных действия выполняются только с помощью функций управления виртуальной памятью.
    Более часто возникает необходимость зарезервировать большой блок виртуальной памяти для данных, который может быть сильно увеличен в процессе выполнения программы. Действуя обычным путем ― то есть используя функции realloc или функцию GlobalReAlloc для динамического изменения размера выделенного блока памяти ― можно снизить производительность программы. Функции управления виртуальной памятью могут помочь избежать этого.
    В Windows любой блок виртуальной памяти может находиться в одном из трех состояний:
    • "committed" (блок спроецирован в физическую память),
    • "free" (свободен, доступен для будущего выделения),
    • "reserved" (зарезервирован). Зарезервированный блок виртуальной памяти не отображается в физическую память. Адреса в пределах этого блока будут недоступны до тех пор, пока всему блоку или его какой-либо части не будет передан блок физической памяти. Таким образом, вы можете зарезервировать достаточно большой блок виртуальной памяти, не передавая ему физической памяти. Когда будет необходимо обратиться по какому-либо виртуальному адресу в пределах этого блока, вы передаете по этому адресу ровно столько физической памяти, сколько необходимо, то есть в зарезервированном блоке виртуальной памяти могут быть участки, как связанные, так и несвязанные с блоками физической памяти. Спроецировав физическую память на нужный участок зарезервированной области виртуальной памяти, программа может обращаться к нему, не вызывая при этом исключения нарушения доступа.
    Для того чтобы использовать функции работы с виртуальной памятью, вашей программе необходимо знать размер страницы памяти. Размер страницы всегда равен 4096 байт. Используйте функцию GetSystemInfo для получения размера страницы. Функция имеет один параметр ― указатель на структуру SYSTEM_INFO.
    Код (C):
    1. typedef struct _SYSTEM_INFO {
    2.   union {
    3.     DWORD  dwOemId;
    4.     struct {
    5.       WORD wProcessorArchitecture;
    6.       WORD wReserved;
    7.     };
    8.   };
    9.   DWORD  dwPageSize;
    10.   LPVOID  lpMinimumApplicationAddress;
    11.   LPVOID  lpMaximumApplicationAddress;
    12.   DWORD_PTR dwActiveProcessorMask;
    13.   DWORD  dwNumberOfProcessors;
    14.   DWORD  dwProcessorType;
    15.   DWORD  dwAllocationGranularity;
    16.   WORD  wProcessorLevel;
    17.   WORD  wProcessorRevision;
    18. } SYSTEM_INFO;
    Поле dwPageSize этой структуры содержит размер страницы. Поля lpMinimumApplicationAddress и lpMaximumApplicationAddress содержат минимальный и максимальный адреса, имеющиеся в распоряжении приложения. Для Windows эти значения равны соответственно 400000h и 7FFFFFFFh.
    Функция VirtualAlloc выглядит следующим образом:
    Код (ASM):
    1. invoke VirtualAlloc,pAddr, dwSize, iAllocType, iProtect
    2. mov pMem,rax
    Первый параметр ― желаемый стартовый базовый адрес виртуальной памяти, его можно установить в NULL при первом вызове этой функции. Второй параметр ― размер. Третий параметр может быть MEM_RESERVE (для резервирования блока виртуальной памяти) или MEM_COMMIT (для резервирования и передачи физической памяти). Четвертый параметр ― константа, начинающаяся с префикса PAGE_ (PAGE_READONLY или PAGE_EXECUTE) для задания защиты блока памяти. Последовательные вызовы функции VirtualAlloc могут передавать или резервировать секции этого блока. Функция VirtualFree используется для освобождения виртуальной памяти.
    Функции работы с "кучей"

    Функции, имена которых начинаются со слова Heap (куча). Эти функции создают и поддерживают непрерывный блок виртуальной памяти, из которого можно выделять память более мелкими блоками. Работа начинается с вызова функции HeapCreate. Затем, используются функции HeapAllocate, HeapReAllocate и HeapFree для выделения и освобождения блоков памяти в рамках "кучи". "Куча" может быть уплотнена для объединения свободного пространства.
    Файловый ввод/вывод

    для файлового ввода/вывода используются WinAPI-функции fopen, fseek, fread, fwrite и fclose.
    Отличия Windows

    Можно читать и записывать файл большими блоками информации за один прием, используя однократный вызов функций fread и fwrite (или их эквивалентами). Отпадает необходимость в использовании циклов при работе с файлами большого размера.
    Windows поддерживает длинные имена файлов. Можно использовать данные, возвращаемые функцией GetVolumeInformation, для динамического выделения буферов для хранения имен файлов. Рекомендуется использовать константы MAX_PATH = 260 и MAX_FNAME = 256 для статического выделения памяти.
    Функции файлового ввода/вывода, поддерживаемые Windows

    Функция CreateFile
    Код (ASM):
    1. invoke CreateFile,szName, dwAccess, dwShare, NULL, dwCreate, dwFlags, 0
    2. mov hFile,rax
    Функция используется для открытия существующего файла, для открытия каналов, используемых при обмене между процессами, а также коммуникационных устройств.
    первый параметр является именем файла.
    Второй имеет значение либо GENERIC_READ, либо GENERIC_WRITE, либо GENERIC_READ | GENERIC_WRITE. Использование нулевого значения позволяет получить информацию о файле без доступа к его содержимому.
    Параметр dwShare открывает файл с общими атрибутами, позволяя другим процессам читать из него (FILE_SHARE_READ), или записывать в него (FILE_SHARE_WRITE), или и то и другое вместе.
    Флаг dwCreate ― константа, показывающая, каким образом файл должен быть открыт.
    • Флаг CREATE_NEWвызывает ошибку, если файл уже существует
    • флаг CREATE_ALWAYS приводит к удалению содержимого существующего файла,
    • флаг OPEN_EXISTING вызывает ошибку, если файл не существует,
    • флаг OPEN_ALWAYS создает файл, если он не существует.
    • Флаг TRUNCATE_EXISTING приводит к ошибке, если файл не существует, и удаляет все содержимое, если файл существует.
    Параметр dwFlags может быть комбинацией констант, начинающихся со слов FILE_ATTRIBUTE и FILE_FLAG, для установки атрибутов файла и других особенностей.
    Функция CreateFile возвращает переменную типа HANDLE. При завершении работы с файлом его необходимо закрыть, используя функцию CloseHandle с описателем файла в качестве параметра. Функции ReadFile и WriteFile похожи:
    Код (ASM):
    1. invoke ReadFile,hFile, pBuffer, dwToRead, &dwHaveRead, NULL
    2. invoke WriteFile,hFile, pBuffer, dwToWrite, &dwHaveWritten, NULL
    • первый параметр ― описатель файла
    • Второй параметр ― указатель на буфер, содержащий данные;
    • третий параметр ― количество байтов для чтения или записи;
    • четвертый параметр ― указатель на переменную, в которую при возврате из функции будет занесено количество байтов, которые были реально считаны или записаны. (Последний параметр используется только для файла, открываемого с флагом FILE_FLAG_OVERLAPPED
    Ввод/вывод с использованием файлов, проецируемых в память

    При работе в Windows существует возможность читать и записывать данные в файл так, как будто это блок памяти. Этот прием рекомендуется использовать также при разделении памяти между двумя и более процессами.
    Вот простейший подход к вводу/выводу с использованием файлов, проецируемых в память (memory mapped files):
    Сначала создается обычный файл с использованием функции CreateFile.
    Затем вызывается функция:
    Код (ASM):
    1. invoke CreateFileMapping,hFile, NULL, dwProtect, 0, 0, szName
    2. mov hMap,rax
    Параметр dwProtect принимает одно из следующих значений, и должен быть совместим с режимом разделения файла: PAGE_READONLY, PAGE_WRITECOPY, PAGE_READWRITE. Последний параметр функции ― необязательное имя, обычно используемое для разделения данных между процессами. В этом случае, функцияOpenFileMapping открывает тот же файл с указанным именем. Обе функции возвращают значение типа HANDLE. Если вам необходимо осуществить доступ к части файла, вызовите функцию MapViewOfFile:
    Код (ASM):
    1. invoke MapViewOfFile,hMap, dwAccess, dwHigh, dwLow, dwNumber
    2. mov pMem,rax
    Весь файл или его часть могут быть спроецированы в память, начиная с заданного 64-разрядного смещения, которое задается параметрами dwHigh и dwLow. (dwHigh = 0, если файл менее 4 ГБ.) Параметр dwNumber задает количество байтов, которое вы хотите спроецировать в память. Параметр dwAccess может быть равен FILE_MAP_WRITE (данные можно записывать и считывать) или FILE_MAP_READ (данные можно только считывать), и должен соответствовать параметру dwProtect функции CreateFileMapping.
    После этого вы можете использовать указатель, возвращаемый функцией, для доступа или модификации данных в файле. Функция FlushViewOfFile записывает на диск все измененные страницы файла, спроецированного в память. Функция UnmapViewOfFile делает недействительным указатель, возвращаемый функцией MapViewOfFile. Затем необходимо закрыть файл, используя функцию CloseHandle.


    Комментарий leo к 12 уроку Iczelion'а "Память и файлы"

    Забудьте раз и навсегда о GlobalAlloc с флагом GMEM_MOVEABLE!!! То, что было "традиционно" во времена перехода с Win16 на Win32, в наше время стало просто глупым и абсурдным. Никакого перемещения блоков памяти внутри кучи Win32 реально не поддерживают, так как им это не нужно ― все "перемещения" осуществляются на уровне подкачки и трансляции страниц. Но использовать флаг GMEM_MOVEABLE не только бессмысленно, но и накладно с точки зрения расхода памяти и быстродействия.
    Поясняю. Основными функциями для работы с кучей в Win32 являются kernel32.HeapAlloc\HeapFree, которые в NT+ просто мапятся в соответствующие функции ntdll.RtlAllocateHeap\RtlFreeHeap. Некоторым "неудобством" этих функций является то, что им нужно передавать хэндл кучи. Для основной кучи процесса этот хэндл возвращается функцией GetProcessHeap. Разумеется при многократных вызовах HeapAlloc имеет смысл один раз получить этот хэндл и сохранить его в переменной hHeap. Но если кому и один раз "в лом" вызвать GetProcessHeap, то можно использовать GlobalAlloc с флагом GMEM_FIXED. GlobalAlloc первым делом устанавливает SEH-обработчик и проверяет флаги. Если флаг GMEM_MOVEABLE не установлен, то просто берется хэндл основной кучи, вызывается HeapAlloc и затем удаляется SEH. Разумеется имеем дополнительные затраты времени на лишние call'ы, jmp'ы и mov'ы, но чего не сделаешь ради "простоты" :)
    С бестолковым флагом GMEM_MOVEABLE дела обстоят гораздо хуже. В итоге память точно также выделяется HeapAlloc, но дополнительно создается дескриптор HGLOBAL, хранящий ссылку на выделенный блок памяти. В Win 9x и NT дескрипторы создаются и хранятся по разному. В Win 9х память под дескриптор выделяется в той же основной куче процесса, то есть вместо одного HeapAlloc имеем два, плюс различные навороты типа блокировки кучи HeapLock\Unlock и т.п. В Win NT под дескрипторы HGLOBAL вообще выделяется отдельный регион памяти, который отъедает у процесса 512К(!) виртуальных адресов и как минимум 4К физической памяти у системы. Выделение памяти под дескрипторы производится при первом вызове GlobalAlloc с флагом GMEM_MOVEABLE и естественно сопровождается огромными потерями времени на обработку отказа страницы ― не менее 4-5 тысяч тактов процессора. Вот и спрашивается: насколько нужно любить и уважать "традиции", чтобы
    1. использовать совершенно бессмысленный флаг GMEM_MOVEABLE, зная, что в реальной ситуации блоки памяти в куче никуда не перемещаются
    2. бессмысленно вызывать GlobalLock\GlobalUnlock, которые только и делают, что увеличивают или уменьшают счетчик ссылок в HGLOBAL, а блок памяти как сидел на своем месте в куче так и сидит
    3. занимать 512К виртуальных адресов и 4К дополнительной физической памяти и напрягать процессор и систему, заставляя их выделять новую страницу только для того, что нам пришло в голову обращаться к выделенному блоку кучи не напрямую, а через через одно хорошо известное место :)
    PS: Еще пара замечаний до кучи:
    1. В GlobalUnlock положено передавать хэндл hMemory, а не указатель на блок pMemory. Хотя с pMemory тоже работает благодаря внутренним взаимным ссылкам hMemory - pMemory
    2. задавать флаги GMEM_ZEROINIT или HEAP_ZERO_MEMORY во многих случаях не имеет смысла, как в рассматриваемом примере с ReadFile\WriteFile. При SendMessage+WriteFile вообще незачем занулять блок памяти, а при чтении файла достаточно занулить последний байт считанной строки и не тратить впустую время на обнуление всего блока размером MEMSIZE = 64K


    В чём разница между LocalAlloc и GlobalAlloc?

    Перевод фрагмента статьи "What was the difference between LocalAlloc and GlobalAlloc?" Реймонда Ченя.

    Когда-то во времена 16-ти битных Windows разница была огромной.
    В ранних версиях Windows доступ к памяти получали через значения, называемые селекторами (selectors), каждый из которых позволял адресовать память до 64 Кб. Существовал селектор по-умолчанию, который назывался селектором данных (data selector); операции с так называемыми ближними указателями (near pointers) осуществлялись относительно селектора данных. Например, если у вас был ближний указатель p со значением 1234h и ваш селектор данных был 012Fh, то тогда, когда вы писали p^, вы получали доступ к памяти по адресу 012F:1234 (когда вы объявляли указатель, он по-умолчанию считался ближним. Вам нужно было явно приписывать far, чтобы указать, что вам нужен дальний указатель).
    Важный момент: ближние указатели всегда относительны к селектору, обычно: к селектору данных.
    Функция GlobalAlloc выделяет селектор, который может быть использован для доступа к запрошенному вами количеству памяти (а если вы попросите выделить вам больше 64 Кб памяти, то произойдёт нечто волнующее, что, впрочем, сейчас не важно). Вы можете получить доступ к памяти по этому селектору через дальний указатель (far pointer). Дальний указатель ― это селектор, соединённый с ближним указателем (не забывайте: ближний указатель относителен к селектору; когда вы соединяете ближний указатель с соответствующим ему селектором, вы получаете дальний указатель).
    Каждый экземпляр (instance) программы и DLL имеет свой собственный селектор данных, известный как HINSTANCE. Селектор данных по-умолчанию для кода в программе был HINSTANCE этого экземпляра программы; селектор данных по-умолчанию для DLL был HINSTANCE этой DLL. Поэтому, если у вас был ближний указатель p, то разыменовывая его как p^ из кода программы, вы получали доступ к памяти относительно HINSTANCE экземпляра программы. Если вы разыменовывали его в DLL, то вы получали память, относительно HINSTANCE вашей DLL.
    Память, на которую ссылается селектор по-умолчанию, может быть превращена в локальную кучу (local heap) вызовом функции LocalInit. Инициализация локальной кучи обычно была одной из первых вещей, которые делала программа или DLL при запуске (для DLL это было обычно единственной вещью, которую она делала при загрузке!). Когда у вас есть локальная куча, вы можете вызывать LocalAlloc для выделения из неё памяти. Функция LocalAlloc возвращала ближний указатель, относительный к селектору по-умолчанию, так что если вы вызывали её из программного модуля, она выделяла память для HINSTANCE программы; если вы вызывали её из DLL, она выделяла память из HINSTANCE DLL.
    Если вы были сообразительны, вы могли понять, что вы можете использовать LocalAlloc для выделения памяти из других блоков, не только из HINSTANCE. Всё, что вам нужно было для этого сделать, так это изменить ваш селектор по-умолчанию на селектор для памяти, выделенной через GlobalAlloc, вызвать функцию LocalAlloc, а затем восстановить селектор по-умолчанию. Это давало вам ближний указатель, относительный к чему-то, отличному от селектора по-умолчанию, что было очень страшной вещью. Но если вы были умны и аккуратно всё делали, то вы могли избежать неприятностей.
    Заметьте, что в 16-ти битных Windows, функции LocalAlloc и GlobalAlloc были совершенно различными! LocalAlloc возвращала ближний указатель, в то время как GlobalAlloc вообще возвращала селектор.
    Указатели, которые вы хотели передавать между модулями, должны были иметь вид "дальних указателей", потому что у каждого модуля был свой селектор по-умолчанию. Если вы хотели передать владение памятью в другой модуль, вам нужно было использовать GlobalAlloc, потому что это позволяло вызывающему использовать потом вызов GlobalFree для его освобождения (вызывающий не мог использовать LocalFree, потому что LocalFree работает в локальной куче, которая будет кучей вызывающего - это не то же самое, что ваша куча).
    Эта историческая разница между локальной и глобальной памятью до сих пор остаётся в Win32. Если у вас есть функция, которая пришла из 16-ти битных Windows, и она передаёт право на память, то она будет работать со значениями типа HGLOBAL. Классическим примером таких функций являются функции буфера обмена (clipboard). Если вы размещаете блок памяти в буфере обмена, он должен быть выделен через HGLOBAL, потому что вы передаёте память буферу обмена, и он вызовет GlobalFree, когда эта память станет ему не нужна. Память, передаваемая через STGMEDIUM, принимает форму HGLOBAL по той же причине.
    Даже в Win32, вам нужно быть осторожными и не перепутать локальную кучу и глобальную. Память, выделенная в одной, не может быть освобождена в другой. Хотя функциональные различия в основном исчезли; и семантика к этому моменту практически идентична. Все странности по ближним и дальним указателям тоже исчезли при переходе к Win32. Но функции локальной и глобальной куч, тем не менее, остаются двумя различными и не связанными интерфейсами куч.
     
    Последнее редактирование: 26 мар 2019
    kero, Коцит и Aiks нравится это.
  9. Mikl___

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

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    2.748
    Глава шестая. Братец Кролик подключает к MessageBox кнопку Help

    Для добавления кнопки "Help" в стиль MessageBox достаточно установить в единицу 14-ый бит
    Код (ASM):
    1. MB_HELP        equ 4000h
    Кнопка "Help" добавится к MessageBox с любым сочетанием клавиш, но на этом дело и остановится. Если вы нажимаете на любую клавишу кроме клавиши "Help" MessageBox всегда закрывается и программа переходит к обработке той клавиши которая только-что была нажата, но к кнопке "Help" это не относится.
    Вариант первый
    Проще всего обработку нажатия "Help" можно добавить в MessageBoxIndirect. Эта функция получает в качестве единственного параметра ссылку на структуру MSGBOXPARAMS где в поле lpfnMsgBoxCallback содержится адрес функции MsgBoxCallback.
    Код (ASM):
    1. MSGBOXPARAMS struc
    2.   cbSize         dd ?,?;UINT
    3.   hwndOwner         dq ?  ;HWND
    4.   hInstance         dq ?  ;HINSTANCE
    5.   lpszText         dq ?  ;LPCTSTR
    6.   lpszCaption         dq ?  ;LPCTSTR
    7.   dwStyle         dd ?,?;DWORD
    8.   lpszIcon         dq ?  ;LPCTSTR
    9.   dwContextHelpId    dd ?,?;DWORD_PTR
    10.   lpfnMsgBoxCallback dq ?  ;MSGBOXCALLBACK
    11.   dwLanguageId         dd ?,?;DWORD
    12. MSGBOXPARAMS ends
    Для вывода на экран справки используется функция WinHelp или ShellExecute которая обработает расширение .hlp, .chm программой "по-умолчанию"
    tut_01.asm вывод справочной информации из MessageBoxIndirect
    Код (ASM):
    1. ; GUI #
    2. include win64a.inc
    3. .code
    4. capt        db "Hello!",0
    5. msg         db "Customized message box",0
    6. ButtonText  db "Click here",0
    7. hlpfile     db "tut_01.hlp",0
    8.  
    9. WinMain proc
    10. local mbp:MSGBOXPARAMS
    11.  
    12.         mov mbp.cbSize,sizeof MSGBOXPARAMS
    13.         mov mbp.hwndOwner,0;
    14.         mov mbp.hInstance,IMAGE_BASE
    15.         mov eax,offset msg
    16.         mov mbp.lpszText,rax
    17.         mov eax,offset capt
    18.         mov mbp.lpszCaption,rax
    19.         mov mbp.dwStyle,MB_HELP or MB_USERICON
    20.         mov mbp.lpszIcon,1000
    21.         mov mbp.dwContextHelpId,1    ;help topic ID
    22.         mov eax,offset MsgBoxCallback
    23.         mov mbp.lpfnMsgBoxCallback,rax;
    24.          mov mbp.dwLanguageId,0
    25.          invoke MessageBoxIndirect,&mbp
    26.          invoke RtlExitUserProcess,NULL
    27. WinMain endp
    28. MsgBoxCallback proc x:qword
    29.  
    30.     invoke ShellExecute,0,0,&hlpfile,0,0,1
    31.     leave
    32.     retn
    33. MsgBoxCallback endp
    34. end
    tut_01.rc
    Код (C):
    1. 1000 ICON DISCARDABLE "br_Bear4.ico"
    Здесь asm/rc/exe-файлы, файл с иконкой и hlp-файл
    Вариант второй
    tut_02.asm через создание нового потока
    Код (ASM):
    1. ; GUI #
    2. include win64a.inc
    3. .code
    4. capt             db "Hello!",0
    5. msg              db "Customized message box",0
    6. ButtonText  db "OK",0
    7. bclass           db "Button",0
    8. hlpfile          db "imagedit.hlp",0
    9. pOldProc     dq ?
    10. HelpBtnID   dq ?
    11. message        dq ?
    12. caption         dq ?
    13. button           dq ?
    14. WinMain proc
    15. LOCAL ThreadID:QWORD
    16. LOCAL hWnd:QWORD
    17. LOCAL hThread:QWORD
    18. LOCAL hClick:QWORD
    19.  
    20.         mov edx,offset msg
    21.         mov message,rdx
    22.         mov r8d,offset capt
    23.         mov caption,r8
    24.         mov r9d,offset ButtonText
    25.         mov button,r9
    26.         invoke CreateThread,0,\      ;атрибуты безопасности по умолчанию
    27.                             0,\      ;размер стека используется по умолчанию
    28.                             &ThreadProc1,\;функция потока
    29.                             &caption,\    ;аргумент функции потока
    30.                             0,\           ;флажки создания используются по умолчанию
    31.                             &ThreadID     ;возвращает идентификатор потока
    32.         mov hThread,rax
    33.         invoke GetCurrentProcess
    34.         invoke WaitForInputIdle,rax,INFINITE
    35.         invoke EnumWindows,&EnumWndProc,&ThreadID
    36.         invoke FindWindowEx,hWnd,0,&bclass,0
    37.         mov hClick,rax
    38.         invoke FindWindowEx,hWnd,eax,&bclass,0
    39.         invoke GetDlgCtrlID,rax
    40.         mov HelpBtnID,rax
    41.         invoke SetWindowText,hClick,&ButtonText
    42.         invoke SetWindowLongPtr,hWnd,GWL_WNDPROC,&MsgboxProc
    43.         mov pOldProc,rax
    44.         invoke WaitForSingleObject,hThread,INFINITE
    45.         invoke CloseHandle,hThread
    46.          invoke RtlExitUserProcess,NULL
    47. WinMain endp
    48. ThreadProc1 PROC pParams:QWORD
    49.  
    50.         mov eax,ecx;ecx=pParams
    51.         invoke MessageBox,QWORD PTR [rax-16],QWORD PTR [rax-8],QWORD PTR [rax],MB_HELP
    52.          leave
    53.         retn
    54. ThreadProc1 ENDP
    55. EnumWndProc PROC hWnd:QWORD,lParam:QWORD
    56. LOCAL pid:QWORD
    57.       mov hWnd,rcx
    58.       mov lParam,rdx
    59.  
    60.         invoke GetWindowThreadProcessId,,&pid
    61.         mov rdx,lParam
    62.         cmp eax,[rdx]
    63.         mov eax,TRUE
    64.         jne @f
    65.         mov rax,hWnd
    66.         mov [rdx-8],rax  ; get the handle of the window
    67.         xor eax,eax      ; displaying the message box
    68. @@:     leave
    69.         retn
    70. EnumWndProc ENDP
    71. MsgboxProc PROC hWnd:HWND,uMsg:QWORD,wParam:WPARAM,lParam:LPARAM
    72. mov hWnd,rcx
    73. mov uMsg,rdx
    74. mov wParam,r8
    75. mov lParam,r9
    76.  
    77.         cmp edx,WM_COMMAND
    78.         jne @f
    79.         mov rax,r8;wParam
    80.         mov edx,eax
    81.         shr edx,16
    82.         ;cmp dx,BN_CLICKED=0
    83.         jne @f
    84.         mov rcx,HelpBtnID
    85.         cmp ax,cx
    86.          jne @f
    87.          invoke ShellExecute,0,0,&hlpfile,0,0,1
    88. @@: invoke CallWindowProc,pOldProc,hWnd,uMsg,wParam,lParam
    89.          leave
    90.           retn
    91. MsgboxProc    ENDP
    92. end
    Здесь asm/exe-файлы и hlp-файл
    Вариант третий
    tut_03.asm создаем окошко и обрабатываем сообщение WM_HELP
    Код (ASM):
    1. ; GUI #
    2. include win64a.inc
    3. HELPINFO struct
    4.     cbSize dq ?      ;размер структуры в байтах
    5.     iContextType dq ?;тип справки
    6.     iCtrlId dq ?     ;идентификатор окна либо меню
    7.     hItemHandle dq ? ;идентификатор дочернего окна либо связанного меню
    8.     dwContextId dq ? ;контекстный идентификатор либо окна либо элемента управления
    9.     MousePos POINT <>
    10. HELPINFO ends
    11. .code
    12. WinMain proc
    13. local msg:MSG
    14.  
    15.     xor ebx,ebx
    16.     mov esi,IMAGE_BASE
    17.     mov edi,offset ClassName
    18.     mov ecx,offset FileName
    19.     invoke LoadCursorFromFile
    20.     push rax    ;hIconSm
    21.     push rdi    ;lpszClassName
    22.     push rbx    ;lpszMenuName
    23.     push COLOR_WINDOW+1;hbrBackground
    24.     push 10003h    ;hCursor
    25.     push rax        ;hIcon
    26.     push rsi    ;hInstance
    27.     push rbx        ;cbClsExtra & cbWndExtra
    28.     pushaddr WndProc;lpfnWndProc
    29.     push sizeof WNDCLASSEX;cbSize & style
    30.     invoke RegisterClassEx,esp    ;addr WNDCLASSEX
    31.     push rbx
    32.     push rsi    ;rsi=400000h
    33.     shl esi,9    ;rsi=CW_USEDEFAULT
    34.     push rbx
    35.      push rbx
    36.     push rsi
    37.     push rsi
    38.     push rsi
    39.     push rsi
    40.     sub esp,20h
    41.     mov r9d,WS_OVERLAPPEDWINDOW or WS_VISIBLE
    42.         invoke CreateWindowEx,0,edi,edi
    43.     mov hwnd,rax
    44.     lea edi,msg
    45. @@:    invoke GetMessage,edi,NULL,0,0
    46.         invoke TranslateMessage,edi
    47.     invoke DispatchMessage,edi
    48.     jmp @b
    49. WinMain endp
    50. WndProc proc hWnd:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD
    51. local ps:PAINTSTRUCT
    52. local expRect:RECT
    53.  
    54.     mov hWnd,rcx
    55.     mov wParam,r8
    56.     mov lParam,r9
    57.  
    58.       cmp edx,WM_DESTROY
    59.       je wmDESTROY
    60.         cmp edx,WM_PAINT
    61.         je wmPAINT
    62.         cmp edx,WM_HELP
    63.         je wmHELP
    64.         cmp edx,WM_KEYDOWN
    65.         je wmF1
    66.         leave
    67.          jmp NtdllDefWindowProc_
    68.  
    69. wmDESTROY: invoke RtlExitUserProcess,NULL
    70. wmPAINT:invoke BeginPaint,,addr ps
    71.         invoke GetClientRect,hWnd,addr expRect
    72.         invoke DrawText,ps.hdc,&message,-1,addr expRect,DT_SINGLELINE or DT_CENTER or DT_VCENTER
    73.         invoke EndPaint,hWnd,addr ps
    74.        jmp wmBYE
    75. wmHELP:    mov rax,[r9+HELPINFO.iCtrlId]
    76.        cmp rax,hwnd
    77.        je wmBYE
    78.         invoke ShellExecute,0,0,&hlpfile,0,0,1
    79.         jmp wmBYE
    80. wmF1:    cmp r8,VK_F1
    81.         jne wmBYE
    82.        invoke MessageBox,hwnd,&message2,&ClassName,MB_HELP
    83. wmBYE:  leave
    84.         ret
    85. WndProc endp
    86. ;-----------------------------------
    87. ClassName db "Uncle Remus tales:#3 Simple window",0
    88. FileName db "..\Images\br_Rabbit3.cur",0
    89. message db "Press on F1 button",0
    90. message2 db "Press on 'Help'",0
    91. hlpfile db "tut_01.hlp",0
    92. hwnd dq ?
    93. end
    Здесь asm/exe-файлы и hlp-файл
    Вариант четвертый
    tut_04.asm обработка нажатия "Help" в SoftModalMessageBox.
    Код (ASM):
    1. ; GUI #
    2. include win64a.inc
    3. MSGBOXDATA struct      
    4.      params              MSGBOXPARAMS <>
    5.      pwndOwner           QWORD ?
    6.      wLanguageId         DWORD ?,?
    7.      pidButton           QWORD ?         ; // Array of button IDs
    8.      ppszButtonText      QWORD ?         ; // Array of button text strings
    9.      cButtons            DWORD ?
    10.      DefButton           DWORD ?
    11.      CancelId            DWORD ?
    12.      Timeout             DWORD ?
    13. MSGBOXDATA ends
    14. .code
    15. hlpfile     db 'ImagEdit.hlp',0
    16. MsgBoxText1:    du <Win64 Assembly is Great>
    17. MsgCaption8: du <SoftModalMessageBox>
    18. sBTN1: du <OK>
    19. sBTN2: du <Help>
    20. dwBtnIds  dd 1,9
    21. dwTxtTbl  dq sBTN1,sBTN2
    22. align 16
    23. WinMain proc
    24. local mb:MSGBOXPARAMS
    25. local mbxData:MSGBOXDATA
    26.  
    27.      mov mbxData.params.cbSize,sizeof MSGBOXPARAMS
    28.      mov mbxData.params.hwndOwner,0
    29.      mov mbxData.params.hInstance,IMAGE_BASE
    30.      movr mbxData.params.lpszText,MsgBoxText1;адрес текста в окне сообщений      8
    31.      movr mbxData.params.lpszCaption,MsgCaption8;адрес заголовка в окне сообщений   8
    32.      mov mbxData.params.dwStyle,MB_OK or MB_USERICON or MB_HELP;MB_YESNOCANCEL OR MB_ICONWARNING or MB_USERICON
    33.      movr mbxData.params.lpszIcon,1000
    34.      mov mbxData.params.dwContextHelpId,1
    35.      mov eax,offset MsgBoxCallback
    36.      mov mbxData.params.lpfnMsgBoxCallback,rax
    37.       mov mbxData.params.dwLanguageId,0
    38.       and mbxData.pwndOwner,0
    39.       and mbxData.wLanguageId,0
    40.       movr mbxData.pidButton,dwBtnIds
    41.       movr mbxData.ppszButtonText,dwTxtTbl
    42.       mov mbxData.cButtons,2;16
    43.       mov mbxData.DefButton,0
    44.        mov mbxData.CancelId,1
    45.        or mbxData.Timeout,-1
    46.       invoke SoftModalMessageBox,&mbxData
    47.       invoke RtlExitUserProcess,NULL
    48. WinMain endp
    49. align 16
    50. MsgBoxCallback proc lpHelpInfo:qword;(LPHELPINFO lpHelpInfo)
    51.  
    52.      invoke ShellExecute,0,0,&hlpfile,0,0,1
    53.      leave
    54.      retn
    55. MsgBoxCallback endp
    56. end
    tut_04.rc
    Код (C):
    1. 1000 ICON DISCARDABLE "br_Bear4.ico"
    Здесь asm/rc/exe-файлы, иконка и hlp-файл


    © Mikl___ 2019
     

    Вложения:

    • 05.jpg
      05.jpg
      Размер файла:
      36 КБ
      Просмотров:
      89
    • help0.zip
      Размер файла:
      58,2 КБ
      Просмотров:
      10
    Последнее редактирование: 23 мар 2019
    kero, q2e74 и Aiks нравится это.