Что такое код iswindow


Содержание

mfc — ошибка управления IP-адресом C ++ ASSERT (:: IsWindow (m_hWnd))

Я пытаюсь получить IP-адрес из управления IP-адресами в MFC C ++. Но это возвращает ошибку ASSERT(::IsWindow(m_hWnd)); return (int) ::SendMessage(m_hWnd, IPM_GETADDRESS, 0, (LPARAM) &dwAddress); >

Вот код, который я сделал. Ошибка генерируется в этой строке Dlg.m_IPAdd.GetAddress(IP2);

Решение

Предполагая, что контроль IP-адреса на вашем CLogin диалог, вот где вам нужно позвонить GetAddress ,

Итак, переопределить CLogin::OnOK() и позвонить m_IPAdd.GetAddress там, чтобы получить IP-адрес в CLogin переменная-член. Затем вы можете получить доступ к этой переменной-члену из вложенного диалога.

Причиной сбоя является то, что к тому времени, когда вы пытаетесь получить доступ к элементу управления из вложенного диалога, элемент управления IP-адресом на CLogin диалог уже был уничтожен. Поместив содержимое в CLogin переменная-член, вы все равно можете получить к ней доступ.

Most accurate isWindow function

While I’m aware of various different means of checking if a variable is a Window object in JavaScript, I’m interested in writing a function that is more accurate and resilient.

For example, jQuery uses:

which will return an incorrect result for:

For purposes of this question, assume that the browser’s native functions and objects have not been modified at the time of initialization.

Currently my code is:

A few assertions:

2 Answers 2

What about taking advantage of the (stupid) fact that the context parameter inside a function invoked without call or apply will be the window?

Seems to even work when wrapped in a with . That being said, you might have legitimate reasons to want to test for this but I can’t think of any.

Edit: Added check for ‘other’ window. You could probably add some finagling to check that eval isn’t a stub that always returns true . So if it returns true for example you could generate two random numbers, add them together, and then pass them into the eval string and have it add those numbers and confirm the result is indeed accurate. Let’s be honest though, that’s stupid, if someone wants to trick you that bad, they’ll find a way.

Для чего используется папка $WINDOWS.

BT в Windows 7/8/10 и можно ли ее удалить?

Папки $WINDOWS.

BT и $WINDOWS.

WS связаны с процессом обновления до Windows 10. Так же эти папки могут появиться и в Windows 7, 8 занимая при этом до одного гигабайта дискового пространства. По умолчанию данные папки скрыты.

В Windows 7 и 8

В период бесплатного обновления с Windows 7 и 8 до Windows 10, система автоматически загружает необходимые файлы для обновления создавая при этом папку $WINDOWS.

BT на вашем системном диске. В случае когда вы согласитесь на обновление до Windows 10, то процесс обновления начнется быстро, используя уже загруженные файлы установки.

Бесплатный период обновления закончился, поэтому вы не сможете использовать эти файлы расположенные в папке $WINDOWS.

BT для обновления до Windows 10.

Microsoft в конечном счете должны удалить эти файлы, если они все еще присутствуют на системах с установленной Windows 7 и 8, но файлы обновления все еще могут находится в вашей системе.

В Windows 10

В операционной системе Windows 10, папка $WINDOWS.

BT содержит файлы предыдущей установки Windows. Эти файлы используются для того чтобы вы смогли вернутся на предыдущую версии Windows, либо на предыдущую сборку Windows 10.

Он похож на папку Windows.old, которая содержит файлы из предыдущей установки Windows. На самом деле, вы увидите обе папки Windows.old и $WINDOWS.

BT после обновления до Windows 10.

Он также содержит файлы журналов. Например, если вы загрузите и запустите утилитку Media Creation Tool, он создаст папку $WINDOWS.

BT с несколькими файлами журнала настройки. Media Creation Tool также создает папку $WINDOWS.

WS, которая содержит большинство файлов установки Windows.

Можно ли удалить папки $WINDOWS.

Внимание: Если вы решили удалить папку $WINDOWS.

BT в Windows 10, вы больше не сможете вернуться к использованию предыдущей сборки Windows 10 или предыдущей версии Windows, которая была установлена на Вашем компьютере до обновления. Настройка Настройки> Обновление и Безопасность> Восстановление также не будет доступна. Тем не менее, Windows 10 автоматически удалит эти файлы обновлений и папку $WINDOWS.

BT через десять дней.

В случае если вы все же решились удалить эти папки, вы не должны делать это обычным способом кликнув правой кнопкой мыши и поместить файл в корзину. Для удаления папок следует использовать средство очистки диска, данная утилитка по умолчанию встроена во все версии Windows.

  1. Введите в строке поиска «Очистка диска».
  2. Откроется небольшое окошко утилитки, в котором вам необходимо выбрать системный диск.
    «Предыдущие установки Windows» — данный пункт удалит папки $WINDOWS.

BT и Windows.old на Windows 10.
«Временные файлы установки Windows» — данный пункт удалит папку $WINDOWS.

BT на Windows 7 и 8, а в Windows 10 будет удалена $WINDOWS.

WS.

  • Выделив нужные пункты нажмите на кнопку «Ок», чтобы удалить выбранные файлы.
  • В итоге, вы можете смело удалять папки $WINDOWS.

    BT и $WINDOWS.

    WS с вашей системы. Удаление данных папок не приведет к поломки вашей системы.

    Открытые коды Windows: сила закона

    The monster must die

    Я не отношу себя к специалистам IT-сферы, ортодоксальным пользователям
    интернета или сумасшедшим геймерам, однако у меня есть компьютер, я работаю с
    определённым программным обеспечением и слежу за компьютерно-информационной
    ситуацией в мире. В первую очередь из-за того, что мы живём в post/информационном,
    глобализированном мире, где компьютеры управляют атомными станциями, военными
    объектами стратегического назначения, и, да простят меня закоренелые
    славянофилы, мышлением большинства населения. Влияние на высокотехнологичную
    сферу post/общества определяет влияние на человечество в целом. Особенно, если
    это влияние оказывает монополист.

    Монополия на операционные системы, а если выражаться без техномонокультурных
    вульгарностей, монополия на удачные имитации искусственного интеллекта, приводит
    к определённой политической нестабильности. Научные фантасты, прореки нашего
    времени, неоднократно предсказывали будущее, в котором крупные корпорации
    наделялись политическими полномочиями. Что ж, когда некоторая система
    взаимодействует с большинством разумных пользователей, и при этом принадлежит
    (подчиняется) узкому кругу лиц, мы можем прогнозировать различные варианты
    развития событий. У нас даже имеется возможность опираться на реальный прототип,
    если брать за основу корпорацию Microsoft. Небезызвестное детище Пола Алена и
    Билла Гейтса отбивается от обвинений в монополизме с далёкого 1990-го года.
    Тогда Федеральная комиссия по торговле США (Federal Trade Commission) устроила
    проверку на предмет возможного сговора между Microsoft и IBM. Расследование
    заглохло, однако в 1993 году маркетинговой политикой Microsoft, связанной с
    распространением DOS, заинтересовалось Министерство юстиции США. В 1994 году
    между Microsoft и Министерством юстиции заключается полюбовное соглашение, по
    условиям которого Microsoft запрещается использовать своё уже тогда доминирующее
    положение на рынке для подавления конкурентов. На следующий год Министерство
    блокирует планы по слиянию Microsoft и компании Intuit – опять-таки из
    антимонопольных соображений. В августе 1997 году Microsoft устраивает донорское
    вливание своему конкуренту – Apple Computers — на сумму $150 миллионов. Эти и
    некоторые другие действия Microsoft вызывают у Министерства юстиции самые
    нехорошие подозрения. Через два месяца Министерство юстиции подаёт иск против
    Microsoft с требованием назначить корпорации ежедневный штраф на сумму 1 миллион
    долларов за нарушение договорённости от 1994 года. И так далее и так по многу
    раз, с переменным успехом Microsoft двигалась к своей нынешней лидирующей
    позиции. Последнее антимонопольное разбирательство прошло уже за территорией
    США, в Евросоюзе. Специально сформированная комиссия пригрозила штрафом до $3,2
    млрд, если Компания не откроет для исследований программный код, а также не
    исключит Media Player из комплекта операционной системы Windows. Однако, по
    словам представителя Еврокомиссии Тилмана Людера, «Microsoft вряд ли придется
    открывать программный код Windows. Компания должна будет лишь предоставить
    «протоколы», которые позволят конкурентам создавать совместимые с Windows
    программные продукты».

    Microsoft же, несколько неоднозначно истолковав решение комиссии ЕС,
    предложила открыть исходные коды Windows Server 2003 и предоставить документации
    с описанием протоколов под определенными лицензиями, которые, естественно, надо
    будет купить. Пока неясно, удовлетворят ли европейских чиновников новые
    предложения Microsoft. Представители ЕС уже заявили, что внимательно изучат её
    заявления. Однако не исключено, что конфликт ЕС с Microsoft этим не исчерпается,
    поскольку американская корпорация и европейские структуры также спорят о цене
    лицензий на использование кода Windows. К тому же, авторы иска к Microsoft
    считают, что последняя не имеет права брать деньги за лицензии на сетевые
    протоколы, поскольку это стандартное программное обеспечение, зашифрованное для
    противодействия конкурентам. В самой корпорации, однако, утверждают, что речь
    идет об уникальных разработках.

    Горшочек с мёдом

    Чего, собственно, добиваются все эти «антимонопольные» процессы, помимо,
    конечно же, ограничения роста компании? Во-первых, принудить Microsoft выпустить
    ограниченную версию Windows, из которой поставщики могли полностью выкинуть
    любую прикладную программу, так или иначе «ущемляющую» интересы конкурентов –
    всякие мультимедийные утилиты, вроде Windows Media Player или Internet Explorer.
    Во-вторых, приказать Microsoft предоставить конкурентам всю необходимую
    техническую информацию, с тем, чтобы их софт мог безглючно работать с Windows.
    В-третьих, открыть исходники всей операционной системы для тщательного изучения.

    Теперь следует более подробно остановиться на открытии исходного кода Windows.
    Заглянуть в него очень хотелось бы и конкурентам, и разработчикам из open source
    community, и, вполне вероятно, хакерам ;). Вот последних в Microsoft, видимо,
    убоялись больше всего. Не однократно представители Microsoft заявляли, что
    открытость – это как раз не преимущество, что утверждают сторонники Linux, а
    страшная опасность: дескать, любой желающий может найти нужную ему дыру, и
    использовать её во зло – вирус написать, или взлом устроить. Поэтому лучше
    скрывать исходные коды, вместе со всеми их дырами. Напомню, что в сообществе
    открытых программ принято инспектировать коды, выявлять ошибки, заявлять о них и
    пытаться залатать. Кто во что горазд. Неоднократно высказывались мысли и о том,
    что в исходниках Windows наличествуют такие огрехи, что открывать их означает и
    впрямь поставить под теоретическую угрозу всех тех, кто пользуется продукцией
    Microsoft. Скорее всего Microsoft Windows во всех своих версиях содержит
    уязвимость, которую исправить невозможно (по мнению некоторых сторонних
    исследователей в разных версиях подобные Абсолютные Ошибки разные). Лечить её
    примерно то же самое, как заделывать дыру в середине фундамента, на котором уже
    стоит многоэтажный дом. Безусловно Microsoft прекрасно осведомлены насчёт
    наличия Абсолютной ошибки, но не считают её уязвимостью. Конечно, ведь исходные
    коды пока ещё скрыты от глаз общественности.

    Чуть-чуть сбавим обороты и отдадим Компании должное. Она уже несколько лет
    предоставляет исходный кода органам власти многих стран, в том числе и
    Российской Федерации. Факт обеспечения доступа к исходным кодам Windows очень
    важен, поскольку это программное обеспечение служит платформой, на основе
    которой построены государственные информационные системы многих стран, а так же
    и оборонные системы (а вы думали там повсюду сверхоси на базе Linux? :)).
    Соглашения подразумевают не только предоставляет доступ к исходному коду Windows
    и другой важной технической информации, но и совместные работы, а также
    консультации с целью адаптации операционной системы к требованиям, которые
    предъявляются государством к информационным системам, используемым в органах
    государственной власти. Предоставление корпорацией Microsoft исходных кодов и
    подробной технической документации в рамках инициативы GSP (Government Security
    Program) потрясающе гениальный ход по утверждению монополии Microsoft.
    Действительно, открытие кодов — исключительно сильный аргумент в споре с активно
    наступающими клонами Linux. Причем заявленный переход на Linux ряда
    правительственных учреждений в Европе не подкреплен экономическими расчетами.
    Конечно, Linux можно настроить точно под нужды конкретного пользователя,
    ограничив функциональность системы, но потребность в таком подходе пока низка,
    при том, что требует высокой квалификации специалистов, обслуживающих систему. В
    случае с Windows открытие кодов успокоит тех, кто убежден, что в операционную
    систему встраиваются какие-либо дополнительные шпионские функции, а также
    укрепит положение Microsoft на рынке. Кроме того, теоретически появляется
    возможность точно такой же тонкой настройки операционной системы под нужды
    определенной группы пользователей.

    Даже лояльные к Microsoft чиновники понимают, что закрытость исходных кодов и
    технической информации делает программы корпорации потенциально опасными для
    национальных интересов страны. Кто может гарантировать, что те дыры, которые все
    время находят хакеры, не оставлены Microsoft специально, чтобы заглядывать в
    компьютеры пользователей? Пусть это не так. Менеджмент Microsoft состоит из
    кристально честных людей. Но кто поручится, что под давлением правительственных
    структур Соединенных Штатов случайно допущенные ошибки не будут использованы без
    ведома других государств на их территории? Не стоит забывать, что идет
    масштабная антитеррористическая кампания, а Microsoft обвиняется многими
    американскими штатами и правительственными организациями в монополизме и
    нечестной конкуренции. В таком положении вряд ли Билл Гейтс будет
    последовательно отстаивать права граждан других стран.

    Исходные коды разрешено просматривать, но изменять их можно только вместе со
    специалистами Microsoft. Кроме этого компания предоставляет техническую
    информацию о платформе Windows для создания более защищенных вычислительных
    систем. Да, сразу и не поймешь где же тут защита, когда все интимные защитные
    операции делаются при участии и под присмотром сотрудников Microsoft? Но сила
    Microsoft, конечно, не в кодах, а в знании психологии.

    Несколько лет назад много шума наделал история с кражей и распространением
    через интернет исходников 2000 и NT 4.0. Часть кода, появившаяся в интернете,
    являлась, по мнению экспертов, первым сервис-паком для Windows 2000 и
    датировалась 25 июля 2000 года. Предполагалось, что источником утечки стал файл
    разгрузки оперативной памяти, сгенерированный одним из компьютеров компании
    Mainsoft, работающим под Linux. В ходе расследования утечки исходных кодов
    операционных систем Windows 2000 и Windows NT стало известно, что в свободном
    доступе оказалось порядке 15 процентов оригинального текста программ. Речь идет
    о 30915 файлах исходного кода Windows 2000, содержащих 13,5 миллиона строк
    текста, и 95103 файлах и 28 миллионах строк кода Windows NT. Исходный код был
    написан на языках программирования ассемблер, С и С++.

    Публикация исходного кода привела в восторг интернет-сообщество, но
    насторожила экспертов. «В том, что исходный код попадет в случайные руки, нет
    ничего хорошего, — говорил старший менеджер центра экстренного реагирования
    антивирусной компании Symantec Оливер Фридрихс.- Его смогут изучать
    злоумышленники, и у секьюрити-экспертов не будет возможности находить уязвимости
    заранее».

    Однако Microsoft отрицало и отрицает возможность любых проблем безопасности.
    В заявлении компании говорится, что ее больше всего беспокоит возможность кражи
    результатов ее труда, а не угроза безопасности, создаваемая этой утечкой. «Если
    небольшой фрагмент исходного кода Windows становится общедоступным, то это
    проблема защиты прав интеллектуальной собственности, а не безопасности» — заявил
    представитель Компании. Как видите, Компанию в первую очередь волнуют вопросы
    финансовых потерь. Впрочем, не удивительно: многие эксперты уверены, что
    опасения по поводу того, что утечка кодов приводит к массовому выявлению
    уязвимостей, безосновательны. Теоретически для хорошего инженера-аналитика весь
    код является открытым. К тому же, даже гениальному хакеру на изучение кода
    потребуется столько времени, что к моменту, когда он будет готов использовать
    уязвимость, выйдет обновленная версия программного продукта. Спорное
    предположение, не так ли? Но если оно вас не успокаивает, ставьте альтернативные
    программные продукты на основе открытых кодов и радуйтесь жизни.

    Quality on conscience of the buyer

    А как же обстоят дела с открытием кода Windows 2003, спросит внимательный
    читатель. Ну его нах, отвечают представители IT-сферы. Microsoft никто и не
    просил открывать коды этой системы. Это вообще нужно только самой Microsoft.
    Клонировать код можно и без Microsoft, а вот получить внятную документацию –
    нет. Microsoft стремится лицензировать собственное ПО, чтобы иметь ещё больше
    возможностей контроля доступа. Ещё в 2004 году решение Еврокомиссии говорило о
    том, что Компании следует в 120-дневный срок предоставить точную документацию
    интерфейса. Раскрытая информация должна была обновляться каждый раз после
    выпуска новых версий. Речь об исходных кодах вообще не шла. Представители
    Microsoft с умным видом заявили, что «исходный код – это и есть окончательная
    документация, ДНК системы». Действительно, не отмажешься. От таких определений в
    пору сходить с ума юристам и устраивать бесконечные судебные процессы. На чём,
    собственно, и строится Компания вот уже столько лет.

    В 2004 году Microsoft по решению ЕС предоставила 12.000 страничный (ага, это
    не опечатка – 12 тысяч страниц) трактат с описанием исходного кода. Тогда
    разобраться в нём евроспециалисты не смогли. В нынешнем году майкрасофтовцы
    сжалились и пообещали всего 500 часов техподдержки с попыткой объяснения, чего
    же они там на 12.000 страниц написали. Складывается впечатление, что Microsoft
    как может, в рамках доступного законодательства, тормозит процесс, известный по
    аксиоме «всё тайное рано или поздно становится явным» и при этом ещё пытается
    проводить выгодную для себя политику запатентованных продуктов. Программа по
    «разоблачению» Windows у Microsoft предполагает предоставление только справочных
    лицензий на исходный код. Поэтому Microsoft позволит просматривать код,
    обнаруживать в нем ошибки, но не разрешит вносить изменения. Так что если вы
    создаете собственные приложения для Windows, то можете отлаживать код этих
    приложений и код Windows с соответствующими API. По идеи это означает, что при
    анализе функций защиты никто не станет проводить полную проверку защиты Windows,
    но компоненты, связанные с вашим приложением, проверить будет возможно. Если же
    вы обнаружите ошибку в Windows, то обязаны будете сообщить о ней в офис
    Microsoft. И даже если вы предложите способ устранения ошибки, Компания
    оставляет за собой правой выбирать, включать или нет его в следующий сервис-пак.

    Даже при оптимальном варианте исследования кода Компания предоставит около
    95% Windows. Еще три процента кода Microsoft вроде как не принадлежит, а
    некоторые места – такие, как код активации продукта – имеют слишком большую
    ценность, чтобы их открывать. К тому же распространение некоторых
    криптографических элементов ограничено правительством США и не может быть
    экспортированы в другие страны.

    Пора уже понять, что исходные коды Windows — это миф. По информации
    Microsoft, ОС Windows содержит несколько десятков (если не сотен) миллионов
    строк кода, который постоянно дорабатывается и модернизируется. Даже в самой
    Компании не совсем точно понимают, что же они разработали. Разбираться в коде
    очень и очень сложно. Шумиха, время от время поднимаемая вокруг исходников,
    выгодна в первую очередь самой Microsoft. Не откроют коды – сохранят
    коммерческую тайну и скроют многочисленные ошибки. Откроют – ещё лучше.
    Обеспечат более жёсткий контроль по лицензиям, ударят по Linux и практически
    ничего не потеряют. В 2006 году обещан выпуск новой операционной системы Windows
    Vista, исходники которой никто открывать не собирается. Хочется спросить у
    Microsoft – какие конкретно выгоды получит пользователь от решения Комиссии ЕС?
    Что именно поимеем мы вообще от решений Компании по собственному исходному коду?

    Win32 API. Функции окна
    Страница 44. Функция IsWindow

    Функция IsWindow

    Функция IsWindow определяет, идентифицирует ли дескриптор определяемого окна существующее окно.

    hWnd
    Устанавливает дескриптор окна.

    Возвращаемые значения
    Если дескриптор окна идентифицирует существующее окно, возвращаемое значение отлично от нуля. Если дескриптор окна не идентифицирует существующее окно, возвращаемое значение нулевое.

    Смотри также
    IsWindowEnabled, IsWindowVisible

    Размещение и совместимость IsWindow

    Что такое код iswindow

    Установили Windows XP вместе с Windows 7 и потеряли возможность загружать Windows 7?

    Восстановление Windows 7 и двойная загрузка

    Ввиду невозможности использования загрузчика NTLDR (Windows XP), необходимо восстановить ссылку на загрузчик Windows 7 (winload) в главной загрузочной записи (MBR) и сконфигурировать его для дальнейшего управления обеими операционными системами.

    Подготовка и восстановление возможности загрузки Windows 7 достаточно просты.

      Автоматически загрузитесь с Windows 7 DVD. На экране, где вам предлагают „Install now” (установить сейчас), выберите „Repair your computer” (починить компьютер).

    Следующий экран ищет установленные локальные версии Windows 7 – должна быть только одна, поэтому нажимайте Next.

    Далее загрузится экран с опциями системы восстановления (System Recovery Options). Выберите первую опцию – „Startup Repair” (начало ремонта). Она будет искать проблемы, которые могут повлиять на загрузку Windows 7 (например, потерянный автозагрузчик), и автоматически их исправит.

    Если вы нажмете на „Click here for diagnostic and repair details” (нажмите здесь для подробностей относительно диагностики и ремонта) и пролистаете до конца странички, то увидите, что выявленная и исправленная проблема – неисправный загрузочный сектор (что нам и требовалось).

    Нажмите Close (закрыть), а затем Finish (завершить), и после перезагрузки системы загрузится Windows 7.

    Теперь нам надо сделать двойную загрузку, и EasyBCD является наилучшим приложением для данного действия. Скачаем EasyBCD (заполнять поля «Name» и «Email» необязательно, достаточно нажать «Download!»), зеркало.

    Запустите приложение и нажмите «Add New Entry» (Добавить запись).

    На вкладке «Windows» выберите в списке версий „Windows NT/2k/XP/2k3”.

    Смените диск на тот, на котором была установлена Windows XP или, если доступно, выберете «Automatically detect correct drive» (Автопоиск диска с исправной ОС) и измените имя на желаемое (например, „Windows XP”), затем нажмите „Add Entry” (добавить значение).

  • Перезагрузите систему, и у вас появятся два значения в загрузчике Windows 7, что позволит загружать любую операционную систему.
  • Сообщение отредактировал Shoore — 27.11.14, 19:13

      Практическая часть:
      В 32-битных версиях Windows XP, Vista и 7 объем доступной оперативной памяти ограничен 4Гб.
      Причем в свойствах системы пользователь видит значения от 2,75 до 3,5 Гб. Это связано с архитектурными особенностями ОС. Обозначается такая версия 32-bit или х-86.

    В 64-битных версиях Windows XP, Vista и 7 объем доступной оперативной памяти логически ограничен 16Тб. Обозначается такая версия 64-bit или х-64. Фактически Microsoft из маркетинговых соображений ограничивает объем памяти в 4Гб, 8Гб, 16Гб и т.д. в зависимости от типа лицензии ОС.

    Важное замечание: для 64-битной версии Windows необходимы и 64-битные версии драйверов для всех устройств ПК (мат.плата, видеокарта и т.д.), включая периферию (принтер, сканер, блютуз и т.д.).
    Если этих драйверов нет, то устройство работать не будет.
    Я на своем опыте столкнулся с этим, когда не оказалось драйверов на принтер, сканер, звуковую карту и блютуз (производители обычно не выпускают новые драйвера на старые модели, т.к. им надо продавать новые продукты). Пришлось от использования 64-битной версии отказаться.

    Для обычного пользователя ПК все это сводится к следующему:
    Если в ПК установлено 4Гб или меньше оперативной памяти, то достаточно будет обычной, 32-битной версии ОС.

    Если в ПК установлено больше 4Гб оперативной памяти, то надо ставить 64-битную версию ОС.

    Если пользователь хочет увеличить оперативную память в ПК для увеличения быстродействия, то увеличивать стоит только до 4Гб, не более.

    При увеличении памяти, например, с 1Гб до 4Гб или с 2Гб до 4Гб производительность ПК не вырастет пропорционально – в 4 или 2 раза.

    Визуально скорость работы ОС вырастет — скорость загрузки системы, запуска программ, загрузки/сохранения в играх. Также будет быстрее происходить переключение между задачами.

    Источник: pc-user.ru

    Сообщение отредактировал svm — 06.05.13, 20:30

    Как переразбить HDD без потери данных не используя сторонние программы?

    1. Идём в «Управление дисками» (Самый простой способ: Win+R >diskmgmt.msc >Enter. Либо: Меню пуск —> вызываем контекстное меню (правая кнопка мыши) на иконке «Компьютер» —> «Управление» —> «Управление дисками»).
    2. Вызываем контекстное меню (правая кнопка мыши) на области диска С и выбираем «Сжать том».
    3. Вводим размер остающегося дискового пространства (или соглашаемся с предложением разбить диск пополам) и после недолгого ожидания имеем диск С и нераспределенное пространство после него. При этом никакая переустановка системы не требуется. Затем — всё просто. Оставшееся пространство разбиваем на логические диски, форматируем и имеем обихоженный винт, размеченный уже под наши потребности и привычки.

    Если нет желания возиться потом с переименованием дисков, то перед созданием логических дисков переименовываем DVD-привод, присвоив ему букву Z. Тогда, остальные логические диски сразу встанут на свои места. Потом приводу можно будет вернуть букву, следующую за последним логическим.

    P.S. Аналогичным функционалом обладает и Vista.

    Сообщение отредактировал Shoore — 26.06.13, 01:53

    В Windows 7, как и в Windows Vista, существует возможность трехкомпонентной OEM OFF-LINE активации. Сочетание именно ВСЕХ трех составляющих процедуры OEM активации, а именно (OEM SLP Key + OEM Certificate + Full SLIC Table = Windows 7 Activated Offline), дает возможность активировать Windows 7 без интернета!
    Вот основные составляющие OEM OFF-LINE активации:

    OEM SLP (System-Locked Pre-installation) — специальный двадцатипятизначный OEM SLP ключ-лицензия, доступный только крупным производителям железа.
    OEM Certificate — специальный OEMный файл-сертификат. Каждому крупному производителю ПК корпорация Microsoft выдает свой персональный файл-сертификат!
    BIOS ACPI_SLIC TABLE — специальная SLIC (Software Licensing Description Table) — таблица, вшиваемая производителем ПК в BIOS системы.

    Сообщение отредактировал svm — 07.05.13, 13:31

    Почему установка Windows 7 идет очень долго?

    Подрабатываю по настройке компов, и тут встретился с одной проблемой: установка семёрки тянется мучительно долго. До запуска окна с выбором языка и т.п. проходит почти 10 минут и далее установка затягивается на часы. Я до конца установки так и не стал ждать. Приходилось ставить ХР.
    Оказалось, физически флопа нет, а в биос он включен. Решение такое: надо в биосе отключить «ссылки» на флопик.
    PS может, уже такой совет был, но ещё раз продублировать не помешает, и я думаю в шапку закрепить тоже следует.

    Сообщение отредактировал Catg — 31.12.10, 17:37

    Автоматический вход в систему

    В диалоговом окне «Выполнить» (Пуск —> Выполнить / [Win+R]) вводим control userpasswords2 и нажимаем «ОК»

    В окне «Учетные записи пользователей» снимаем галочку с чекбокса «Требовать ввод имени пользователя и пароля». Затем нажимаем «ОК».


    Сообщение отредактировал DJ_Diman — 30.12.10, 11:10

    Активация Windows 7 через Интернет.

    Для активации Windows 7 ноутбук или компьютер должен быть подключен к Интернету. Для начала активации нажимаем на кнопку Пуск, щелкаем на Компьютер правой кнопкой мышки и выбираем пункт Свойства:
    Так же можно воспользоваться сочетанием клавиш Win+PAUSE

    Щелкаем на Осталось 3 дн. . (в Вашем случае кол-во дней может быть другим):

    Щелкаем на кнопке Активировать Windows по сети:

    Через некоторое время должно появится такое окошко:

    Сообщение отредактировал Shoore — 06.05.13, 17:48

    Как продлить срок работы Windows 7 без Ключа продукта (Product Key)?

    Без ключа Windows 7 будет работать только 30 дней, но можно выполнять реактивацию системы каждые 29 дней, правда не более трех раз:
    1. Запустите Командную строку (Command promt) от имени Администратора
    2. Введите одну из следующих команд:

    Это оффициально подтвержденный способ реактивации системы. Более того, система в таком состоянии определяется как genuine, и доступны все обновления, которые требуют наличия лицензионной ОС (WGA-geniune)

    Сообщение отредактировал DJ_Diman — 30.12.10, 11:19

    Запуск командной строки (cmd.exe) с правами администратора.

    Для запуска командной строки (cmd.exe) с правами администратора сделайте следующее:
    Нажмите Пуск и в поле поиска введите cmd
    На найденном файле нажмите правую клавишу мыши и выберите в контекстном меню пункт «Запуск от имени администратора»

    Сообщение отредактировал DJ_Diman — 30.12.10, 11:19

    Как посмотреть ошибки в Журнале событий?

    Открываем Журнал событий (Пуск —> Выполнить —> eventvwr) —> справа Журнал Windows —> Приложение.
    Смотрим ошибки, по времени совпадающие с возникновением проблемы.

    IP Address Control C ++ ASSERT (:: IsWindow (m_hWnd)) ошибка

    Я пытаюсь получить IP-адрес из элемента управления IP-адреса в MFC C ++. Но она возвращается сообщение об ошибке ASSERT(::IsWindow(m_hWnd)); return (int) ::SendMessage(m_hWnd, IPM_GETADDRESS, 0, (LPARAM) &dwAddress); >

    Вот код, который я сделал. Ошибка генерируется в этой строке Dlg.m_IPAdd.GetAddress(IP2);

    Предполагая , что управление IP — адрес на вашем CLogin диалоге, это где вам нужно позвонить GetAddress .

    Таким образом, переопределять CLogin::OnOK() и позвонить m_IPAdd.GetAddress туда , чтобы получить IP — адрес в CLogin переменной — члена. Тогда вы можете получить доступ к этой переменной — члена из вашего ограждающих диалога.

    Причина это недостаток в том , что к тому времени , вы пытаетесь получить доступ управления из вмещающего диалога, управление IP — адреса в CLogin диалоговом окне уже уничтожено. Поставив содержимое в CLogin переменную — член, вы можете получить доступ к нему.

    Использование WTL

    Часть 1


    Автор: Александр Шаргин

    Опубликовано: 21.04.2001
    Исправлено: 15.09.2005
    Версия текста: 0.9

    Введение


    Что такое WTL?

    WTL (Windows Template Library) — это ещё одна библиотека классов от Микрософт, которую вы можете использовать при создании ваших программ. «Ещё одна», потому что на сегодняшний день существуют различные библиотеки классов (MFC и ATL фирмы Microsoft, OWL и VCL фирмы Borland и т. д.). WTL изначально создавалась как пример расширения ATL, и предназначалась для упрощения процесса создания графического интерфейса в программах, использующих эту библиотеку. Как и ATL, WTL базируется на шаблонах языка C++ и позволяет создавать очень быстрые компактные программы.

    WTL стала чем-то вроде «побочного продукта» деятельности Микрософт, и до сих пор для неё не нашлось места в официальных планах компании. Поддержка этого продукта и официальная документация на него отсутствуют. Тем не менее, WTL продолжает развиваться, и сейчас разработчикам доступна уже версия 3.1 этой библиотеки. Всё больше программистов использует её в своих приложениях. Давайте рассмотрим, как WTL соотносится с другими технологиями фирмы Микрософт и какие преимущества может дать её использование.

    WTL и Win32

    WTL является «надстройкой» над оконной подсистемой Win32 API и существенно упрощает работу с функциями этой подсистемы, а также облегчает задачу написания повторно используемого кода. В WTL поддерживает работу с окнами и диалогами, окнами-рамками, полным набором стандартных элементов управления, стандартными диалогами, GDI и другими неотъемлемыми элементами пользовательского интерфейса. Изучить WTL можно сравнительно быстро, после чего она позволит вам существенно ускорить разработку приложений, которые раньше писались на «чистом» API.

    WTL и ATL

    ATL и WTL очень тесно интегрированы между собой. WTL использует базовый механизм поддержки работы с окнами, предоставляемый ATL, для реализации более «продвинутых» возможностей. Фактически, многие файлы WTL (такие как atlbase.h и atlwin.h) даже не входят в комплект поставки, так как распространяются вместе с Visual C++ в составе библиотеки ATL. Если вы уже программируете на ATL, WTL несомненно придётся вам по вкусу.

    WTL и MFC

    Самую интересную и животрепещущую тему я приберёг под конец. Вопрос, что же лучше, WTL или MFC, занимает умы программистов уже некоторое время. За 8 лет своего существования MFC прошла долгий путь развития и успела обзавестись «тяжёлой наследственностью». В ней сосуществуют (не всегда мирно) как старые классы (типа CToolBar ), так и более новые (такие, как CToolBarCtrl ). Для поддержки совместимости с уже существующим кодом Микрософт была вынуждена вносить в MFC всё новые и новые неоптимальные решения и «заплатки», которые сделали внутреннее устройство MFC запутанным и ненадёжным. Сейчас уже практически невозможно что-то изменить в архитектуре MFC, не получив при этом неприятных побочных эффектов. Косность и монолитность MFC порой приводит программистов в бешенство. Наконец, MFC создавалась в то время, когда Windows не поддерживала многопоточное программирование, и с тех пор остаётся недостаточно потокобезопасной. Другими словами, в своём развитии MFC зашла в тупик, и теперь её отмирание — это вопрос времени.

    Однако, использование MFC имеет не только недостатки, но и определённые преимущества. Во-первых, на данный момент накоплен поистине громадный опыт использования этой библиотеки. Её используют многие программисты, по ней написаны горы документации, книг и статей. Проблемы, возникающие при её использовании, хорошо изучены. Не следует забывать и про мощные библиотеки классов, расширяющие MFC, как коммерческие (продукты Stingray, Dundas), так и свободно доступные в Интернете. Во-вторых, MFC остаётся самым быстрым средством разработки крупномасштабных приложений на Visual C++, а скорость разработки — немаловажный фактор, который следует учитывать при выборе той или иной библиотеки. В-третьих, MFC предоставляет гораздо более полный набор классов, чем WTL. В неё встроена поддержка файлов, сокетов, классов WinInet, технологий ODBC и DAO, OLE-серверов, ISAPI и многое другое, чего нет в других библиотеках. Более того, в WTL эти средства никогда не будут встроены, так как она создавалась исключительно для поддержки GUI.

    Резюмируя сказанное выше, можно утверждать, что вопрос о том, что лучше, невозможно решить однозначно. В зависимости от ситуации следует предпочесть или мощь MFC, или эффективность и гибкость WTL.

    В этой статье я буду часто вставлять в текст примечания, сопоставляющие решения, реализованные в WTL, с аналогичными решениями в MFC. Если вы знакомы с MFC, это позволит вам лучше понять сходства и различия двух библиотек.

    Будущее WTL

    Будущее WTL предсказать достаточно сложно. Вероятно, эта библиотека появилась слишком поздно. Сейчас всё более актуальной становится проблема интеграции самых различных платформ, операционных систем, языков программирования и т. д. Поэтому всё внимание Микрософт сосредоточено на разработке .NET, «платформы будущего», которая, по мнению её создателей, должна дать ответ на многие вопросы. В этих планах фирмы Микрософт для библиотеки WTL скорее всего не найдётся места. Она будет и дальше развиваться усилиями энтузиастов, создавших её; программисты будут использовать её там, где использование MFC менее удобно. Но она не станет официальным средством разработки, которое придёт на смену MFC. Что будет с ней дальше, покажет время.

    Для кого предназначена эта статья

    Эту статью могут читать все, кого интересует библиотека WTL. При её написании я предполагал, что вы уже достаточно хорошо знаете язык C++ и платформу Win32. Если эти темы вам не знакомы, вам скорее всего не следует браться за WTL, так как изучение этой библиотеки часто сводится к чтению её исходных текстов.

    Если это предостережение вас не очень напугало, давайте закончим разговоры и приступим непосредственно к изучению WTL.

    Установка WTL

    Итак, вы решили использовать WTL. Прежде всего, нужно установить эту библиотеку, так как она не входит в состав Visual C++ 6.0 и или более ранних версий. Файлы, входящие в состав, WTL можно загрузить с сервера Microsoft. Самораспаковывающийся архив лежит по адресу:

    После того, как вы загрузили и распаковали архив с файлами WTL, дальнейший процесс установки распадается на два этапа.

    Копирование файлов

    В архиве, который вы получили от Микрософт, находится три каталога: Include, AppWiz и Samples. Каталог Include содержит файлы, составляющие собственно библиотеку WTL. Поскольку она широко использует шаблоны языка C++, вся её реализация содержится в заголовочных файлах. Скопируйте этот каталог, куда вам нравится. Мне представляется логичным поместить его в том же каталоге, где уже находятся библиотеки MFC и ATL, — в %Visual Studio%\Vc98\ (%Visual Studio% обозначает базовый каталог, в который установлен пакет Visual Studio).

    В каталоге AppWiz содержится WTL App Wizard, предназначенный для создания заготовок приложений на базе WTL. Местонахождение файла визарда более критично: чтобы он был успешно обнаружен интегрированной средой Visual C++, его необходимо разместить в каталоге %Visual Studio%\Common\MSDev98\Template.

    Что касается примеров из каталога Samples, вы можете разместить их где угодно, например, в папке, где хранятся ваши проекты.

    Настройка путей

    Чтобы компилятор языка C++ мог найти заголовочные файлы библиотеки WTL, нужно указать ему каталог, в котором они лежат. Можно, конечно, указывать в директиве #include полный путь к каждому файлу, но это менее удобно и ухудшит переносимость вашей программы (на другом компьютере файлы WTL могут оказаться в совсем другом каталоге, и ваше приложение откажется компилироваться).

    Чтобы указать путь к файлам WTL, запустите Visual C++, откройте диалог Tools->Options и перейдите на вкладку Directories . Затем выберите из выпадающего списка «Show directories for:» пункт Include files и добавьте в конец списка каталог, в который вы скопировали файлы WTL. После выполнения этой операции на моём компьютере окно выглядело так.

    Рисунок 1. Окно Tools->Options после добаления пути к файлам библиотеки WTL

    Вот и всё! WTL установлена, и теперь вы можете использовать её при разработке собственных программ.

    Обзор WTL

    Давайте посмотрим, что же содержится в файлах, которые мы только что установили. Их полный список приведён в таблице 1.

    Файл Что содержит
    atlapp.h Классы модуля и цикла сообщений, интерфейсы фоновых обработчиков и фильтров сообщений.
    atlcrack.h Набор дополнительных макросов для карты сообщений.
    atlctrls.h Классы для всех основных контролов Windows.
    atlctrlw.h Класс командной панели (command bar).
    atlctrlx.h Набор «самодельных» контролов, не входящих в стандартный комплект Windows.
    atlddx.h Поддержка механизма обмена данными с диалогом.
    atldlgs.h Классы для стандартных диалогов и страниц свойств.
    atlframe.h Класс окна-рамки, классы окон интерфейса MDI, поддержка механизма обновления объектов пользовательского интерфейса.
    atlgdi.h Классы контекста устройства и объектов GDI (перья, кисти).
    atlmisc.h Набор вспомогательных классов: CPoint и CRect, CString и т. д.
    atlprint.h Поддержка печати и предварительного просмотра.
    atlres.h Набор описаний идентификаторов ресурсов, используемых WTL.
    atlscrl.h Классы окон с поддержкой прокрутки.
    atlsplit.h Класс окна-разделителя (splitter window).
    atluser.h Класс меню.
    Таблица 1. Заголовочные файлы WTL

    Ещё раз подчеркну, что некоторые важные файлы, без которых WTL не может работать в принципе, распространяются в составе библиотеки ATL и находятся в каталоге %Visual Studio%\Vc98\Atl. В первую очередь к таким файлам относятся atlbase.h и atlwin.h.

    Hello, WTL!

    В книгах по программированию для Windows можно найти множество вариаций на тему приложения «Hello, World!», с которого принято изучать программирование на любом новом языке или в любой новой среде. Вот один из возможных вариантов такого приложения.

    Хотя это приложение не назовёшь многофункциональным, оно содержит все основные элементы, присущие программе для Windows: регистрацию оконного класса, создание главного окна, цикл обработки сообщений и оконную процедуру с обработчиками сообщений WM_PAINT и WM_DESTROY .

    Теперь посмотрим, как выглядит та же самая программа, написанная с использованием WTL. Для её создания мы не будем пользоваться визардом. Безусловно, он ускоряет разработку приложений «в реальной жизни», но нам с вами торопиться некуда. Наша задача — как можно глубже понять, как работает WTL.

    Как видим, функция WinMain никуда не исчезла (как известно, в MFC эта функция спрятана от программиста). Вместо оконной процедуры появился класс CMainWindow , содержащий обработчики интересующих нас сообщений, а также карту сообщений , сопоставляющую сообщения соответствующим обработчикам. Что касается цикла обработки сообщений, он реализован как объект класса CMessageLoop .

    В последующих разделах мы подробно рассмотрим, что происходит внутри WTL и каким образом она выполняет базовые операции, которые мы видели в программе «Hello, Win32!».

    Классы WTL для работы с окнами

    Как видно из нашего примера, для работы с окнами в WTL предназначен класс CWindowImpl<> . Однако, под этим классом лежит целая иерархия классов, каждый из которых добавляет в CWindowImpl<> определённую часть функциональности. Классы, входящие в эту иерархию, показаны на рисунке 2. Рассмотрим их по порядку.

    Рисунок 2. Иерархия оконных классов библиотеки WTL

    Класс CWindow

    Класс CWindow представляет собой тонкую обёртку вокруг хэндла HWND , который используется для работы с окнами в Windows API, и упрощает вызов функций, требующих указания этого хэндла, например:

    Как видим, класс CWindow хранит хэндл связанного с ним окна в переменной-члене m_hWnd и передаёт его функциям Win32. Использование класса CWindow избавляет нас от необходимости помнить, какие сообщения нужно посылать окну для выполнения с ним определённых действий и как упаковывать параметры этих сообщений в WPARAM и LPARAM . Кроме того, каждая функция содержит строчку ATLASSERT(::IsWindow(m_hWnd)) . Попытавшись выполнить какую-либо операцию с несуществующим окном, мы тут же получим предупреждение в отладочной версии программы. В финальной версии проверки исчезнут, избавляя программу от лишней нагрузки.

    Класс CWindow никак не зависит от остальных классов WTL. Это означает, что вы легко можете использовать только его в программе на «чистом» API. Для этого достаточно включить в программу строчки:

    Замечу, что описывать переменную _Module в этом случае не нужно. Достаточно декларации, чтобы умиротворить компилятор языка C++.

    Если вы когда-нибудь пытались использовать в программе на «чистом» API класс CWnd из библиотеки MFC, вы знаете, что сделать это практически невозможно. Сказывается «монолитность» MFC, в которой все классы зависят друг от друга.

    Обратите внимание на ещё один важный момент: функции типа SetFocus и GetDlgItem возвращают HWND , а не объект класса CWindow . Тем не менее, класс CWindow имеет полный набор конструкторов, операторов присваивания и приведения типа, что позволяет вам использовать HWND и CWindow как один и тот же тип. Например, вы можете «на лету» преобразовать возвращаемый вам HWND в CWindow:

    Функции MFC-класса CWnd никогда не возвращают HWND . Вместо этого возвращается указатель на объект CWnd . Если в программе не существует объекта класса CWnd , соответствующего нужному окну, MFC создаёт временный объект. При этом происходит динамическое распределение памяти, поиск объекта в постоянной и временной карте окон и множество других подобный операций. Кроме того, MFC уничтожает временные объекты класса CWnd в цикле фоновой обработки. При этом возвращённые нам указатели становятся недействительными, что вносит дополнительную путаницу и может стать причиной ошибки.

    Класс CMessageMap

    Класс CMessageMap является абстракцией карты сообщений. Посмотрим, как этот класс описан в atlwin.h.

    Картой сообщений в WTL является любой класс, который может обрабатывать сообщения Windows. Для этого он порождается от CMessageMap и предоставляет свою реализацию виртуальной функции ProcessWindowMessage . В разделе «Маршрутизация сообщений» мы подробно рассмотрим, как эта функция создаётся с помощью макросов карты сообщений, предоставляемых нам библиотекой WTL.

    А сейчас ещё раз внимательно посмотрите на описание класса CMessageMap . Он очень похож на интерфейсы, которые используются в COM и Java. И это сходство не случайно. Любой объект в вашей программе (не обязательно оконный!) может реализовать интерфейс, задаваемый классом CMessageMap , и обрабатывать сообщения. Благодаря этому вы без труда сможете распределить обработку сообщений по объектам, в которых осуществлять её наиболее удобно. Этот простой и элегантный подход нам ещё не раз встретится при изучении WTL.

    Знатоки MFC несомненно заметят здесь сходство с классом CCmdTarget . Однако, есть и два важных различия. Во-первых, неоконные классы, порождённые от CCmdTarget , могут обрабатывать только команды ( WM_COMMAND ) и уведомления ( WM_NOTIFY ), а все остальные сообщения — нет. Во вторых, MFC накладывает существенные ограничения на множественное наследование: вы не можете произвести класс от двух классов, в свою очередь порождённых от CObject . Это означает, что класс, порождённый от CFile , CDC или CRecordset , уже не может наследоваться ещё и от CCmdTarget . С другой стороны, WTL не накладывает ограничений на множественное наследование, и вы можете без труда «прикрутить» класс CMessageMap к любому производному классу.

    Класс CWinTraits<>

    CWinTraits — это очень маленький и лёгкий класс, предназначенный для работы с обычными и расширенными стилями окна. Он описан следующим образом.

    Обратите внимание, что этот класс вообще не содержит переменных-членов. Стили, которые возвращают функции GetWndStyle и GetWndExStyle , статически задаются на этапе компиляции. Классы, порождаемые от CWinTraits , используют эти стили при создании окна.

    Чтобы сделать нашу работу более комфортной, разработчики WTL предоставили нам несколько специализаций шаблона CWinTraits<> , задав в них наиболее часто используемые комбинации стилей:

    Класс CControlWinTraits удобнее всего применять для элементов управления, CFrameWinTraits — для главного окна приложения (именно его я использовал в программе «Hello, Wtl!»), а CMDIChildWinTraits — для дочерних окон главного окна в приложении с интерфейсом MDI. CNullTraits вообще не определяет никаких стилей.

    Класс CWindowImplRoot<>

    CWindowImplRoot — очень важный класс. Именно с него начинается «ветвление» иерархии оконных классов WTL. Одна ветвь, отходящая от него — это обычные окна, вторая ветвь — диалоги. Соответственно, класс CWindowImplRoot как бы «резюмирует» все свойства, необходимые и тем, и другим.

    Описание класса CWindowImplRoot выглядит так.

    Как видим, класс CWindowImplRoot , произведён от двух других классов, TBase и CMessageMap. В связи с этим возникает интересный вопрос: а почему нельзя было сразу подставить вместо TBase класс CWindow? Дело в том, что CWindow далеко не всегда отвечает всем нашим нуждам. Если, к примеру, мы работаем с полем ввода (edit box), нам будет удобно породить от CWindow новый класс (например, CEdit) и добавить в него обёртки сообщений типа EM_SETSEL и EM_SETLIMITTEXT . Как мы узнаем позже, WTL предлагает нам целый набор подобных классов, описанных в файле atlctrls.h. Благодаря предусмотрительности WTL мы сможем подставить любой из них в шаблон CWindowImplRoot , наделив результирующий класс необходимыми свойствами.

    Кроме поддержки работы с HWND в объектно-ориентированном стиле и карт сообщений класс CWindowImplRoot обеспечивает поддержку ещё двух важных механизмов: переходников оконной процедуры (window proc thunks) и отражения уведомлений (notification reflection). Переходники используются для эффективного отображения хэндла окна на адрес соответствующего ему объекта в нашей программе. Отражение сообщений позволяет контролам обрабатывать собственные уведомления. Мы увидим, как работают эти механизмы, в разделе «Маршрутизация сообщений».

    Класс CWindowImplBaseT<>

    Класс CWindowImplBaseT реализует практически все функции, необходимые для работы с окном. Именно здесь появляются оконные процедуры StartWindowProc и WindowProc , которые обеспечивают обработку сообщений через карты сообщений. Кроме того, класс CWindowImplBaseT содержит функции SubclassWindow и UnsubclassWindow , позволяющие классу «подключиться» к уже существующему окну и обработать часть поступающих в него сообщений через карту сообщений (остальные будут по-прежнему поступать в оконную процедуру окна).

    Обратите внимание на переменную-член m_pfnSuperWindowProc . Именно в ней сохраняется указатель на оконную процедуру, которую окно имело до сабклассинга с помощью функции SubclassWindow . Если карта сообщений не содержит записи для некоторого сообщения, оно будет передано в изначальную оконную процедуру (как мы видим, это происходит в функции DefWindowProc ).

    Для работы со стилями окна класс CWindowImplBaseT использует уже рассмотренный нами шаблон CWinTraits.

    Класс CWindowImpl

    Ну, вот мы и добрались до класса CWindowImpl . Это совсем маленький класс, который наследует большую часть функциональности от CWindowImplBaseT . Единственное, что в нём добавляется — это поддержка работы с классами окна. Как мы знаем, в Windows каждое окно имеет свой класс. Классы регистрируются с помощью функции RegisterClass(Ex) и передаются в функцию, создающую окно ( CreateWindow(Ex) ).

    Класс CWindowImpl скрывает от нас работу по регистрации класса окна. Посмотрим, как он описан в atlwin.h.

    В WTL информация о классе окна содержится в объекте класса CWndClassInfo, который в зависимости от значения макроса _UNICODE разворачивается либо в структуру _ATL_WNDCLASSINFOA , либо в структуру _ATL_WNDCLASSINFOW . Для примера рассмотрим структуру _ATL_WNDCLASSINFOA .

    Как видим, самое первое поле этой структуры имеет тип WNDCLASSEX — это структура, которая используется при регистрации класса в Win32 API. Функция Register выполняет регистрацию оконного класса, информация о котором хранится в объекте класса CWndClassInfo .

    Макрос DECLARE_WND_CLASS добавляет в класс окна (языка C++) статический экземпляр объекта класса CWndClassInfo , а также функцию для доступа к нему:

    При создании окна функция CWindowImpl::Create использует информацию, добавленную с помощью макроса DECLARE_WND_CLASS , для автоматической регистрации оконного класса (с помощью функции CWndClassInfo::Register ). Замечу, что в классе CWindowImpl класс окна объявлен с именем NULL. Для таких «безымянных» классов WTL выбирает имя сама. Это имя имеет вид «ATL:XXXXXXXX», где XXXXXXXX — адрес структуры m_wc в объекте CWndClassInfo . Вы можете изменить это имя на любое другое, добавив в секцию public произведённого от CWindowImpl класса строчку:

    Вы можете также изменить любые параметры, которые выбрал за вас макрос DECLARE_WND_CLASS . Для этого измените соответствующие поля структуры m_wc , содержащейся в классе CWndClassInfo . Например, сменить иконку приложения можно так:

    Модули и циклы сообщений

    Иерархию оконных классов, которую мы только что рассмотрели, WTL унаследовала от библиотеки ATL. Зато классы CAppModule и CMessageLoop в WTL появились впервые. Они описаны в файле atlapp.h. Давайте посмотрим, как они вписываются в общую картину.

    Класс CMessageLoop

    Класс CMessageLoop реализует цикл обработки сообщений Windows. Концептуально он ничем не отличается от простейшего цикла сообщений, который мы видели в программе «Hello, Win32», но предоставляет несколько новых возможностей — фильтрацию сообщений и фоновую обработку. Вот как цикл сообщений описан в функции CMessageLoop::Run .

    Работа цикла сообщений распадается на нескольких этапов. Сначала он проверяет, нет ли в очереди необработанных сообщений. Если сообщений нет, вызывается виртуальная функция OnIdle , в которой выполняется фоновая обработка. После того как фоновая обработка закончена, вызывается функция GetMessage . Эта функция извлекает следующее сообщение из очереди. Если сообщений нет, Windows немедленно заберёт у нашей программы управление и вернёт его только тогда, когда сообщения появятся. Рано или поздно это произойдёт, и GetMessage вернёт управление. Если к нам пришло сообщение WM_QUIT, цикл сообщений немедленно завершается. В противном случае вызывается виртуальная функция PreTranslateMessage , поддерживающая механизм фильтров сообщений. В процессе работы фильтров сообщение может быть преобразовано, а то и вовсе отброшено (в этом случае PreTranslateMessage вернёт TRUE, и цикл сообщений перейдёт к следующей итерации). Если этого не произошло, сообщение направляется в целевую оконную процедуру вызовом DispatchMessage .

    Фоновые обработчики

    Посмотрим, каким образом выполняется фоновая обработка.

    Каждый объект класса CMessageMap поддерживает список фоновых обработчиков . Добавить объект в этот список можно, используя функцию CMessageLoop::AddIdleHandler . Функция CMessageLoop::RemoveIdleHandler выполняет обратную операцию — удаляет обработчик из списка. Когда в цикле сообщений вызывается функция OnIdle , она просматривает список фоновых обработчиков и вызывает их по очереди, пока список не будет исчерпан:

    Обратите внимание, что существующая реализация функции OnIdle никак не использует счётчик nIdleCount и всегда возвращает FALSE . Поэтому фоновая обработка всегда выполняется за одну итерацию. Вы можете изменить это поведение, переопределив виртуальную функцию OnIdle в классе, производном от CMessageLoop .

    ПРИМЕЧАНИЕ
    Как видим, WTL, в отличие от MFC, сама по себе не выполняет никакой фоновой обработки. Если вам требуется обновлять объекты пользовательского интерфейса или выполнять ещё какие-либо операции «в фоне», вы должны явно добавить в цикл сообщений один или несколько фоновых обработчиков.

    Осталось выяснить, что представляет собой объект, который может стать фоновым обработчиком. Такой объект обязан наследовать от класса CIdleHandler и предоставлять собственную реализацию чисто виртуальной функции OnIdle , объявленной в этом классе.

    Класс CIdleHandler определяет интерфейс, единый для всех фоновых обработчиков. Его описание, как и в случае с CMessageMap , совсем простое.

    Таким образом, в WTL объект совершенно любого класса может стать фоновым обработчиком. Всё, что для этого нужно, — произвести этот класс от CIdleHandler и добавить в него функцию OnIdle .

    Фильтры сообщений

    Мы не будем долго задерживаться на фильтрах сообщений, поскольку они реализованы полностью аналогично фоновым обработчикам. Класс CMessageLoop поддерживает список фильтров сообщений, работа с которым ведётся через функции CMessageLoop::AddMessageFilter и CMessageLoop::RemoveMessageFilter . Когда из цикла сообщений вызывается функция CMessageLoop::PreTranslateMessage , эта функция просматривает список фильтров и вызывает их по очереди. Фильтр получает указатель на структуру MSG, содержащую текущее сообщение, и может делать с ней всё, что угодно (например, подменять параметры сообщения или окно-адресата). Как только один из фильтров вернул TRUE, функция немедленно завершается, также возвращая TRUE. Оставшиеся фильтры при этом не вызываются. Если ни один фильтр не отбросил сообщение, PreTranslateMessage возвращает FALSE, и сообщение, как мы уже видели, попадает в оконную процедуру.

    Из сказанного следует, что порядок добавления фильтров, в отличие от порядка добавления фоновых обработчиков, может иметь значение. Чем раньше фильтр был добавлен, тем раньше он будет вызываться в процессе работы CMessageLoop::PreTranslateMessage .

    Интерфейс, общий для всех фильтров сообщений, определяет класс CMessageFilter . В этом классе содержится чисто виртуальная функция PreTranslateMessage , которая должна быть реализована в производном классе. Если эта функция возвращает TRUE, дальнейшая обработка сообщения не производится. Класс CMessageFilter выглядит так.

    Если вы программировали с использованием библиотеки MFC, вам должно быть известно, что MFC реализует похожий механизм фильтрации сообщений: перед вызовом TranslateMessage и DispatchMessage MFC вызывает функцию PreTranslateMessage , которая может преобразовывать или отбрасывать сообщения. Однако есть и существенное различие: MFC сама решает, для каких объектов вызывать PreTranslateMessage , а для каких нет. Это избавляет вас от дополнительной работы, но зато лишает вас «свободы действий» и может приводить к весьма странным ошибкам. У меня был случай, когда сообщения WM_KEYDOWN , адресованные окну верхнего уровня, попадали в диалог (который являлся главным окном приложения), после чего программа входила в бесконечный цикл. Искать такие ошибки довольно сложно. Если же попытаться изменить стандартный механизм фильтров в MFC (перегрузив CWinThread::PreTranslateMessage ), это может привести к непредсказуемым последствиям.

    Класс CAppModule

    Класс CAppModule является чем-то вроде центрального репозитория данных о приложении. Так, в нём хранится hInstance , который ОС передаёт в функцию WinMain . Объект класса CAppModule должен иметь имя _Module , так как некоторые заголовочные файлы WTL рассчитывают именно на это название (обратите внимание, что декларация объекта _Module в нашем примере предшествует включению файла atlwin.h, — функции, описанные в этом файле, активно используют _Module ).

    На самом деле, класс CAppModule порождён от ATL-класса CComModule и наследует от него не только функции для поддержки работы с окнами, но и функции, отвечающие за манипулирование COM-объектами (добавление информации об объектах в реестр Windows, создание объектов через фабрики классов и т. д.).

    Объект _Module является глобальным и доступен в любой точке приложения. Целостность его внутренних структур обеспечивается с помощью применения критических секций, поэтому вы можете спокойно обращаться к нему из разных потоков. Инициализация объекта _Module выполняется с помощью функции Init . Советую вызывать эту функцию как можно раньше, так как иначе могут возникнуть ошибки. Например, именно в ней инициализируются все критические секции объекта, а попытка использовать хотя бы одну из них без предварительной инициализации приведёт к аварийному завершению программы.

    В примерах, поставляемых вместе с WTL, можно увидеть примерно следующий код.

    Как видим, в объекте _Module можно регистрировать циклы сообщений. Благодаря этому доступ к ним можно получить из любого места в вашей программе. Хотя я не стал регистрировать цикл сообщений в примере «Hello, Wtl!», это может быть очень удобно для последующей регистрации фоновых обработчиков и фильтров сообщений. Получить цикл сообщений, соответствующий текущему потоку, можно с помощью вызова:

    Получить цикл любого другого потока можно, передав идентификатор этого потока функции GetMessageLoop .

    ПРЕДУПРЕЖДЕНИЕ
    Попытка добавить два цикла сообщений, принадлежащих одному и тому же потоку, приведёт к ошибке.

    В следующем разделе мы увидим, как объект _Module используется в процессе создания окна.

    Маршрутизация сообщений в WTL

    Маршрутизация сообщений — важная тема. Без понимания механизмов обработки сообщений можно легко зайти в тупик, когда программа начинает вести себя не так, как предполагалось. Давайте попытаемся проследить путь сообщений, которые операционная система передаёт нашему приложению.

    Предварительная обработка

    Для обработки сообщений в Windows используются оконные процедуры. Но прежде чем туда попасть, сообщение добавляется в очередь сообщений потока. Каждый поток имеет свою очередь. Сообщение поступает в поток, создавший окно, которому это сообщение адресовано.

    Кроме того, есть сообщения, адресованные потоку, а не окну; в этом случае поле hwnd структуры MSG устанавливается в NULL .

    Мы уже видели, как сообщения выбираются из очереди с помощью функции GetMessage . Это происходит в цикле сообщений. Полученное сообщение направляется в фильтры, которые мы зарегистрировали. Любой фильтр может изменить сообщение или запретить его дальнейшую обработку. Если ни один фильтр не отбросил сообщение, оно передаётся функции DispatchMessage , которая направляет его в соответствующую оконную процедуру.

    Используя фильтры сообщений, необходимо всегда помнить важный момент: не все сообщения ставятся в очередь. Многие сообщения направляются прямиком в оконную процедуру. К их числу относятся такие сообщения, как WM_CREATE , WM_SIZE , WM_COPY , любые сообщения, отправленные с помощью SendMessage и т. д. Попытка перехватить любое из этих сообщений в фильтре закончится неудачей, так как оно туда просто не попадёт.

    Карты сообщений

    Итак, сообщение попадает в оконную процедуру. Если окно имеет связанный с ним класс CWindowImpl , то эта процедура — CWindowImplBaseT<>::WindowProc . Посмотрим, как она реализована.

    Для нас здесь важно то, что функция WindowProc определяет по хэндлу окна адрес связанного с ним объекта класса, а затем вызывает функцию ProcessWindowMessage . Реализация этой функции целиком лежит на совести программиста. Можно, как в старые добрые времена, написать её в стиле огромного switch’а. Но проще воспользоваться специальными макросами карты сообщений, которые предоставляет нам WTL.


    Заготовка функции ProcessWindowMessage создаётся макросами BEGIN_MSG_MAP и END_MSG_MAP :

    После обработки препроцессором этот фрагмент примет следующий вид.

    Возможно, вы подумали, что оператор switch , который для нас приготовила WTL, предназначен для выбора сообщения. Но это не так. Этот оператор предназначен для выбора карты сообщений . По умолчанию используется карта с номером 0. Функция ProcessWindowMessage узнаёт, какую карту использовать, по параметру dwMsgMapID . Как видим, объект может иметь несколько карт сообщений и использовать разные карты в различных обстоятельствах. Гибкость WTL впечатляет, не так ли?

    ПРИМЕЧАНИЕ
    В MFC карты сообщений реализованы совершенно иначе, чем в WTL. Там карта сообщений представляет собой не функцию, а массив структур, каждая из которых сопоставляет сообщению нужный обработчик. Каждый раз, когда сообщение нужно обработать, карта сообщений сканируется в поисках нужного обработчика. Если обработчик не найден, процедура повторяется для базового класса и так далее до самого верхнего уровня иерархии наследования.

    Другие макросы карты сообщений делают именно то, что можно было предположить. Например, макрос MESSAGE_HANDLER связывает сообщение Windows с соответствующим обработчиком:

    Макрос ATL_MSG_MAP служит для начала новой карты сообщений; для этого он просто вставляет ещё одну ветку оператора switch :

    Макрос CHAIN_MSG_MAP позволяет направить сообщение в карту сообщений базового класса.

    ПРИМЕЧАНИЕ
    В отличие от MFC, в WTL карты сообщений не наследуются автоматически. Направлять сообщение в базовый класс вам придётся самостоятельно.

    Макрос CHAIN_MSG_MAP_MEMBER позволяет передать сообщение на обработку другому объекту.

    Из описания макроса видно, что он может передавать сообщение не только объекту-члену нашего класса, но и глобальному объекту.

    Полный список макросов можно найти в MSDN. Однако я призываю вас не доверять документации, а обратиться к описаниям этих макросов в файле atlwin.h. В этом случае вы будете уверенными, что не упустили что-то важное. Кроме того, вы можете перемежать макросы карты сообщений с обычным кодом на C++. Допустим, вы хотите направить сообщения WM_LBUTTONUP и WM_RBUTTONUP в один и тот же обработчик. Можно добавить в карту сообщений два макроса MESSAGE_HANDLER , а можно написать просто:

    Если вы долго писали на MFC и чувствуете себя неуютно без макросов типа ON_WM_CREATE и ON_WM_PAINT , вам будет приятно узнать, что WTL предоставляет вам набор похожих макросов. Они описаны в файле atlcrack.h. Так как они не входят в библиотеку ATL, документацию на них вы не найдёте. Тем не менее, вы сможете без труда разобраться в работе этих макросов, посмотрев на их описания.

    Все макросы из atlcrack.h имеют вид:

    Если вы решите использовать их в вашей программе, помните, что в этом случае вам следует использовать вместо BEGIN_MSG_MAP макрос BEGIN_MSG_MAP_EX . Этот макрос тоже вставляет пролог функции ProcessWindowMessage , но предваряет его описаниями нескольких вспомогательных функций.

    Вот небольшой пример использования макросов из atlcrack.h:

    Отражение уведомлений

    Важный случай обработки сообщений в WTL — отражение уведомлений. Контролы посылают уведомления родительскому окну, когда происходит что-то важное. Но очень часто уведомления удобнее обрабатывать в классе самого контрола, а не родительского окна. Механизм отражения позволяет окну переправлять уведомления обратно дочерним контролам, которые их послали. Чтобы это происходило, следует добавить в карту сообщений этого окна макрос REFLECT_NOTIFICATIONS .

    ПРИМЕЧАНИЕ
    В MFC механизм отражения реализован иначе: для перенаправления уведомлений обратно в контрол там не требуется модифицировать карту сообщений родительского окна, так как библиотека сама заботится о корректной маршрутизации.

    Как видим, макрос REFLECT_NOTIFICATIONS просто передаёт сообщение в функцию ReflectNotifications , которая описана в классе CWindowImplRoot . Эта функция определяет, является ли сообщение уведомлением, и если является, направляет его обратно отправителю.

    Мы уже знаем, что в WTL любой класс может иметь карту сообщений. Однако, включение макроса REFLECT_NOTIFICATIONS в карту объекта, у которого нет функции ReflectNotifications , приведёт к ошибке. Используя макросы карты сообщений, следует всегда помнить, какой код за ними стоит.

    Отражённые сообщения обрабатываются точно так же, как и все остальные. Чтобы их можно было отличить от нормальных сообщений, функция ReflectNotifications добавляет к их коду константу OCM__BASE . Коды сообщений с прибавленной константой описаны в файле olectrl.h и имеют префикс OCM_. WM_COMMAND превращается в OCM_COMMAND , WM_DRAWITEM — в OCM_DRAWITEM и т. д. Таким образом, для обработки отражённого сообщения WM_COMMAND нужно вставить в карту сообщений контрола макрос вида:

    Чтобы перенаправить все необработанные отражённые сообщения в обработчик по умолчанию, добавьте в конец карты сообщений контрола макрос DEFAULT_REFLECTION_HANDLER , который вызовет функцию CWindowImplRoot::DefaultReflectionHandler . Функция DefaultReflectionHandler реализована более чем прямолинейно:

    Переходники и процесс создания окна

    В этом разделе мы рассмотрим два тонких момента, связанных с оконными процедурами в WTL. Вы вполне можете пропустить его, удовлетворившись тем, что «это всё работает». Но самых любопытных я приглашаю читать дальше.

    В предыдущим разделе мы познакомились с оконной функцией WindowProc . Однако в ней есть строчка, заслуживающая более пристального внимания. Посмотрим на неё ещё раз.

    Как видим, переход от хэндла окна к указателю на объект класса, связанный с ним, осуществляется прямым приведением типа. Как же так? Ведь мы не можем заказать Windows нужный нам хэндл, и просмотр в Spy++ действительно показывает, что он не совпадает с адресом объекта. Функция WindowProc вызывается непосредственно операционной системой, и никакие другие функции WTL в этот процесс не вмешиваются. Если вы подумали о перегрузке операторов, то опять не угадали. WTL не перегружает оператор приведения типа, и преобразование осуществляется по обычным правилам языка C++.

    Так в чём же дело? Оказывается, при вызове оконной процедуры управление попадает в неё не сразу. Вместо этого операционная система вызывает переходник , который имеет следующий вид.

    Этот код подменяет хэндл, лежащий в стеке, на адрес объекта, а затем делает безусловный переход по адресу оконной процедуры. Вот как получается, что она получает адрес вместо хэндла.

    Каждый объект класса, производного от CWindowImplRoot , имеет свой собственный переходник. Он находится в переменной класса m_thunk :

    Посмотрим, как описан класс CWndProcThunk для процессора Intel x86.

    Сейчас для нас не важно, что такое _AtlCreateWndData . Важно, что после записи в поля m_mov и m_jmp предопределённых значений, а в поля m_this и m_relproc соответствующих адресов в классе CWndProcThunk образуется код переходника, который мы рассмотрели выше. Обратите внимание на директиву #pragma pack , которая отключает выравнивание полей структуры по границам, отличным от байта. Без неё компилятор мог бы добавить в структуру _WndProcThunk незаполненные пространства, нарушая содержащийся в ней код.

    Надо признать, что механизм переходников оконных процедур весьма элегантен. Сколько бы окон не создала наша программа, определение указателя на объект класса по хэндлу окна будет происходить практически моментально.

    В MFC для определения указателя на объект класса по хэндлу окна используются карта хэндлов — класс, похожий на map из STL. Такой подход существенно проигрывает по скорости способу, применяемому в WTL.

    Теперь мы знаем, как работают переходники, и нам осталось выяснить, когда WTL подменяет адрес настоящей оконной процедуры на адрес переходника. Если мы подключаемся к уже существующему окну, ответ на этот вопрос достаточно прост — это происходит в функции CWindowImplBaseT::SubclassWindow . Но в случае создания окна «с нуля» функцией CWindowImpl::Create процесс усложняется. Класс окна, который регистрирует эта функция, имеет в качестве оконной процедуры функцию CWindowImplBaseT::StartWindowProc :

    Функция StartWindowProc назначается окну «временно». Её задача — создать для окна переходник к функции WindowProc и задать его адрес в качестве новой оконной процедуры. Когда окно создаётся (внутри функции CreateWindowEx из Win32 API), ему посылается одно или несколько сообщений ( WM_CREATE , WM_NCCREATE и т. д.). Как только первое из них достигает StartWindowProc , она выполняет необходимые операции и передаёт все полномочия функции WindowProc . Кроме того, она записывает в поле m_hWnd реальное значение хэндла окна, чтобы ваши обработчики сообщений WM_CREATE , WM_NCCREATE и т. д. могли использовать это поле до фактического возврата из функции ::CreateWindowEx .

    Но откуда StartWindowProc узнаёт адрес объекта, связанного с окном? Эта информация записывается в объект _Module непосредственно перед вызовом CreateWindowEx :

    Для каждого потока создаётся отдельная запись, поэтому неприятностей с многопоточной программой не возникает. Получив управление от операционной системы, StartWindowProc извлекает нужную информацию из объекта _Module :

    Кстати, только что рассмотренные фрагменты кода отвечают на вопрос, зачем нужно объявлять объект CAppModule _Module до включения файла atlwin.h: как мы только что видели, описанные в нём функции активно используют этот объект в процессе своей работы.

    В MFC механизм подмены оригинальной оконной процедуры на AfxWndProc происходит похожим образом. Перед вызовом функции ::CreateWindowEx информация об объекте класса CWnd записывается в структуру состояния потока. Разница в том, что в MFC эту информацию извлекает и использует локальный хук типа WH_CBT, а не временная оконная процедура.

    Продолжение следует

    В первой части статьи мы изучили основные механизмы, лежащие в основе поддержки оконного интерфейса библиотекой WTL. Тем самым мы заложили прочный фундамент для дальнейших исследований, и теперь сможем двигаться вперёд гораздо быстрее. В следующей части мы изучим использование диалогов и окон-рамок, меню, панелей инструментов и строк состояния в программах, написанных с использованием библиотеки WTL.

    ASSERT (:: IsWindow (m_hWnd)) вопрос, не уверен, что это неправильно

    У меня ошибка в моем коде, который пинать мою задницу, поэтому после долгих попытки отладки я, наконец, решил посмотреть, если кто-то знал, что мой вопрос был.

    Я пытаюсь добавить объект сетки к диалогу , который у меня есть, но я продолжаю заганяю assert упоминаются в названии , и я не знаю , почему.

    Любая идея , что происходит? Я имею в виду, я только создать диалоговое окно , как только все инициализирован, так что не должно быть проблема. m_Grid.Create() возвращается true , поэтому создание успешно. Почему SetRedraw() заганяют assert что m_hWnd не дескриптор окна? Где m_hWnd получить набор в любом случае?

    Спасибо за любую помощь вы можете предложить.

    Вы уверены , что диалог создается , когда вы звоните
    CDerivedDocument::SetMyDoc(myDialog * pDlg) ?

    То, что я вижу, что вы загружаете сетки (& диалог) из документа, вы должны достаточно загрузить диалоговое окно и сетки из представления, используя документ.

    Это не может быть прямой причиной вашей проблемы утверждать, но все-таки улучшение. Это может быть просто положить вещи в правильном порядке, и решить эту проблему.

    Базовые сервисы windows и функции api. Что такое Windows API. Наследование объектов для вывода и арифм. операций

    Казалось бы, что WinAPI уходит в прошлое. Давно уже существует огромное количество кросс-платформенных фреймфорков, Windows не только на десктопах, да и сами Microsoft в свой магазин не жалуют приложения, которые используют этого монстра. Помимо этого статей о том, как создать окошки на WinAPI, не только здесь, но и по всему интернету, исчисляется тысячами по уровню от дошколят и выше. Весь этот процесс разобран уже даже не по атомам, а по субатомным частицам. Что может быть проще и понятнее? А тут я еще…

    Но не все так просто, как кажется.

    Почему о WinAPI сейчас?

    О чем это я? А вот кусочке кода:

    Case WM_KEYDOWN: MessageBox(hwndDlg,»Die!»,»I»m dead!»,MB_YESNO|MB_ICONINFORMATION); break;
    Таким образом, авторы хотели добавить поддержку клавиатуры, но суровая реальность недр архитектуры диалоговых окон в Windows жестко пресекла такую самодеятельность. Те, кто пользовался эмулятором и отладчиком в нем, хоть раз видели это сообщение?
    В чем же проблема?

    Ответ такой: так делать нельзя!

    И, возвращаясь, к изначальному вопросу о WinAPI: очень много популярных, и не очень, проектов продолжают его использовать и в настоящее время, т.к. лучше, чем на чистом API многие вещи не сделать (тут можно бесконечно приводить аналогии вроде сравнения высокоуровневых языков и ассемблера, но сейчас не об этом). Да и мало ли почему? Просто используют и все тут.

    О проблеме

    Обойти такие мелкие неприятности просто. Есть, как минимум, два вполне легальных способа:

    1. Создать свой собственный класс через RegisterClassEx и в процедуре обработки класса схватывать WM_KEYDOWN, перенаправлять в процедуру обработки самого диалога. Да-да! Можно создавать диалоги со своим собственным классом, и встроенный в VS редактор даже позволяет задавать имя класса для диалога. Вот только кто об этом знает и этим пользуется?
      Минус очевиден: Нужно регистрировать еще один класс, иметь на 1 CALLBACK процедуру больше, суть которой будет всего-навсего в трансляции пары сообщений. Кроме того, мы не будем знать куда их транслировать, и придется городить костыли.
    2. Использовать встроенный механизм акселераторов. И нам даже не придется менять код диалоговой процедуры! Ну, разве что, добавить одну строчку в switch/case, но об этом ниже.

    Tutorials?

    While (GetMessage(&msg, nullptr, 0, 0)) < TranslateMessage(&msg); DispatchMessage(&msg); >
    Здесь действительно все просто:

    1. GetMessage() выхватывает очередное сообщение из очереди, и ключевой момент : блокирует поток, если в очереди пусто.
    2. TranslateMessage() из WM_KEYDOWN/WM_KEYUP формирует сообщения WM_CHAR/WM_SYSCHAR (они нужны, если кто-то хочет сделать свой редактор текста).
    3. DispatchMessage() отправляет сообщение в оконную процедуру (если таковая существует).

    Начнем с того, что этот код использовать опасно, и вот почему . Обратите внимание на сноску:

    Because the return value can be nonzero, zero, or -1, avoid code like this:
    while (GetMessage(lpMsg, hWnd, 0, 0)) .

    Стоит сказать, что в шаблонах VS для Win32 приложений, написан именно такой неправильный цикл. И это очень печально. Ведь мало кто будет вникать в то, что сделали сами авторы, ведь это априори правильно. И неправильный код множится вместе с багами, которые очень сложно отловить.

    После этого фрагмента кода, как правило, следует рассказ про акселераторы, и добавляется пара новых строчек (учитывая замечание в MSDN, предлагаю сразу писать правильный цикл):

    HACCEL hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE( > Этот вариант я видел чаще всего. И он (та-дам ) снова неправильный!

    Сперва о том, что изменилось (потом о проблемах этого кода):

    В первой строчке из ресурсов загружается таблица клавиш, при нажатии на которые, будет формироваться сообщение WM_COMMAND с соответствующим id команды.

    Собственно TranslateAccelerator этим и занимается: если видит WM_KEYDOWN и код клавиши, которые есть в этом списке, то (опять же ключевой момент) будет формировать сообщение WM_COMMAND (MAKEWPARAM(id, 1)) и отправлять в соответствующую для дескриптора окна, указанного в первом аргументе, процедуру обработки.

    Из последней фразы, думаю, стало понятно, в чем проблема предыдущего кода.
    Поясню: GetMessage выхватывает сообщения для ВСЕХ объектов типа «окно» (в число которых входят и дочерние: кнопки, списки и прочее), а TranslateAccelerator будет отправлять сформированную WM_COMMAND куда? Правильно: обратно в кнопку/список и т.д. Но мы обрабатываем WM_COMMAND в своей процедуре, а значит нам интересно ее получать в ней же.

    Ясно, что TranslateAccelerator надо вызывать для нашего созданного окна:

    HWND hMainWnd = CreateWindow(. ); HACCEL hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE( > И вроде все хорошо и замечательно теперь: мы разобрали все детально и все должно работать идеально.

    И снова нет. :-) Это будет работать правильно, пока у нас ровно одно окно — наше. Как только появится немодальное новое окно (диалог), все клавиши, которые будут в нем нажаты оттранслируются в WM_COMMAND и отправляться куда? И опять же правильно: в наше главное окно.

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

    IsDialogMessage

    На самом деле, делает она чуть больше, чем следует из названия. А именно:

    • Осуществляет навигацию по дочерним контролам кнопками Tab/Shift+Tab/вверх/вниз/вправо/влево. Плюс еще кое-что, но этого нам достаточно
    • По нажатии на ESC формирует WM_COMMAND(IDCANCEL)
    • По нажатии на Enter формирует WM_COMMAND(IDOK) или нажатие на текущую кнопку по умолчанию
    • Переключает кнопки по умолчанию (рамочка у таких кнопок чуть ярче остальных)
    • Ну и еще разные штуки, которые облегчают пользователю работу с диалогом

    Что она нам дает? Во-первых, нам не надо думать о навигации внутри окна. Нам и так все сделают. Кстати, навигацию по Tab можно сделать, добавив стиль WS_EX_CONTROLPARENT нашему основному окну, но это топорно и не так функционально .

    Во-вторых, она нам облегчит жизнь по всем остальным пунктам, перечисленным в списке (и даже немного больше).

    Вообще, она используется где-то в недрах Windows для обеспечения работы модальных диалоговых окон , а программистам дана, чтобы вызывать ее для немодальных диалогов. Однако мы ее можем использовать где угодно :

    Although the IsDialogMessage function is intended for modeless dialog boxes, you can use it with any window that contains controls, enabling the windows to provide the same keyboard selection as is used in a dialog box.

    HWND hMainWnd = CreateWindow(. ); HACCEL hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE( > То наше окошко будет иметь навигацию, как в родном диалоге Windows. Но теперь мы получили два недостатка:

    1. Этот код также будет хорошо работать только с одним (немодальным) окном ;
    2. Получив все достоинства диалоговой навигации, мы лишаемся прелестей в виде сообщений WM_KEYDOWN/WM_KEYUP (только для самого окна, а не для дочерних контролов);

    И вот на этом этапе вообще все туториалы заканчиваются и начинаются вопросы: How to handle keyboard events in a winapi standard dialog?
    Это первая ссылка в гугле, но поверьте: тысячи их. Про предлагаемые решений (лучшее из которых — это создать свой класс диалогов, о чем я писал выше, до subclassing и RegisterHotKey. Где-то я даже видел «лучший» из способов: использовать Windows Hooks).

    Пора поговорить о том, чего нет в туториалах и ответах.

    Как правило (как правило! Если кому-то захочется большего, то можно регистрировать свой класс для диалогов и работать так. И, если же, кому-то это интересно, я могу дополнить этим статью) WM_KEYDOWN хотят тогда, когда хотят обработать нажатие на клавишу, которая выполнит функцию в независимости от выбранного контрола в окне — т.е. некая общая функция для всего данного конкретного диалога. А раз так, то почему бы не воспользоваться богатыми возможностями, которые нам сама WinAPI и предлагает: TranslateAccelerator .

    Везде используют ровно одну таблицу акселераторов, и только для главного окна. Ну действительно: цикл GetMessage-loop один, значит и таблица одна. Куда еще их девать?

    На самом деле, циклы GetMessage-loop могут быть вложенными . Давайте еще раз посмотрим описание PostQuitMessage :

    The PostQuitMessage function posts a WM_QUIT message to the thread»s message queue and returns immediately; the function simply indicates to the system that the thread is requesting to quit at some time in the future.

    If the function retrieves the WM_QUIT message, the return value is zero.

    Мы можем для каждого немодального окна в нашей программе создавать свой собственный подобный цикл. В данном случае DialogBoxParam нам не подходит, т.к. оно крутит свой собственный цикл и повлиять мы на него не можем. Однако если создадим диалог через CreateDialogBoxParam или окно через CreateWindow, то можно закрутить еще один цикл. При этом в каждом таком окне и диалоге мы должны вызывать PostQuitMessage:

    HWND hMainWnd = CreateWindow(. ); HACCEL hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE( > Обратите внимание: теперь для каждого нового окна в нашей программе мы можем добавить в обработку собственную таблицу акселераторов. WM_QUIT будет выхватывать GetMessage из цикла для диалога, а внешний цикл его даже не увидит. Почему так происходит?

    Дело в том, что внешний цикл «встал» на вызове DispatchMessage, который вызвал нашу процедуру, которая крутит свой собственный внутренний цикл GetMessage с таким же DispatchMessage. Классический вложенный вызов (в данном случае DispatchMessage). Посему внешний цикл не получит WM_QUIT и не завершится на этом этапе. Все будет работать стройно.

    Но и тут есть свои недостатки:
    Каждый такой цикл будет обрабатывать сообщения только для «своего» окна . Про другие-то мы здесь не знаем. А значит, если где-то объявится еще один цикл, то все остальные окна не будут получать нужной обработки своих сообщений парой TranslateAccelerator/IsDialogMessage.

    Что ж, пора учесть все эти замечание и написать наконец правильную обработку всех сообщений от всех окон нашей программы. Хочу заметить, что ниже рассматривается случай для одного потока. Т.к. каждый поток имеет свою очередь сообщений, то для каждого потока придется создавать свои структуры. Делается это весьма тривиальными изменениями в коде.

    Делаем красиво

    Во-первых, было бы логично, что только активное окно принимает сообщения. Т.е. для неактивного окна мы не будем транслировать акселераторы и передавать сообщения в IsDialogMessage.

    Во-вторых, если для окна не задана таблица акселераторов, то транслировать нечего, будем просто отдавать сообщение в IsDialogMessage.

    Создадим простой std::map, который будет мапить дескриптор окна в дескриптор таблицы акселераторов. Вот так:

    Std::map l_mAccelTable;
    И по мере создания окон будем в него добавлять новые окна с дескриптором на свою любимую таблицу (или нуль, если такая обработка не требуется).

    Void DelAccel(HWND hWnd) < std::map ::iterator me = l_mAccelTable.find(hWnd); if (me != l_mAccelTable.end()) < if (me->second) < DestroyAcceleratorTable(me->second); > l_mAccelTable.erase(me); > >
    Теперь, как создаем новый диалог/окно, вызываем AddAccelerators(hNewDialog, IDR_MY_ACCEL_TABLE). Как закрываем: DelAccel(hNewDialog).

    Список окон с нужными дескрипторами у нас есть. Немного модифицируем наш основной цикл обработки сообщений:

    // . HWND hMainWnd = CreateWindow(. ); AddAccelerators(hMainWnd, > Значительно лучше! Что же там в HandleAccelArray и зачем там GetActiveWindow()?

    Есть две функции, возвращающих дескриптор активного окна GetForegroundWindow и GetActiveWindow . Отличие первой от второй вполне доходчиво описано в описании второй:

    The return value is the handle to the active window attached to the calling thread»s message queue. Otherwise, the return value is NULL.

    Так вот HandleAccelArray, руководствуясь переданным ей дескриптором на активное окно, ищет это самое окно в нашей мапе, и если оно там есть, отдает это сообщение на трансляцию в TranslateAccelerator, а затем (если первый не увидел нужного) в IsDialogMessage. Если и последняя не обработала сообщение, то возвращаем FALSE, чтобы пройти по стандартной процедуре TranslateMessage/DispatchMessage.

    А что там еще об одной строчке в коде обработчика WM_COMMAND?

    To differentiate the message that this function sends from messages sent by menus or controls, the high-order word of the wParam parameter of the WM_COMMAND or WM_SYSCOMMAND message contains the value 1.

    Switch(HIWORD(wParam)) < case 1: // accelerator case BN_CLICKED: // command from buttons/menus < switch(LOWORD(wParam)) < case IDC_BUTTON1: DoButton1Stuff(); break; case IDC_BUTTON2: DoButton2Stuff(); break; // . >break; > >
    И теперь, возвращаясь к тому же fceux, добавив всего одну строчку в код обработки команд от кнопок, мы получим желаемое: управлять дебагером с клавиатуры. Достаточно добавить небольшую обертку вокруг главного цикла сообщений и новую таблицу акселераторов с нужными соответствиями VK_KEY => IDC_DEBUGGER_BUTTON.

    P.S.: Мало кто знает, но можно создавать свою собственную таблицу акселераторов , а теперь и применять ее прямо налету.

    P.P.S.: Т.к. DialogBox/DialogBoxParam крутит собственный цикл, то от при вызове диалога через них акселераторы работать не будут и наш цикл (или циклы) будет «простаивать».

    P.P.P.S.: После вызова HandleAccelWindow мап l_mAccelTable может измениться, т.к. TranslateAccelerator или IsDialogMessage вызывают DispatchMessage, а там может встретиться AddAccelerators или DelAccel в наших обработчиках! Поэтому лучше его после этой функции не трогать.

    Пощупать код можно . За основу был взят код, генерируемый из стандартного шаблона MS VS 2020.

    Теги: Добавить метки

    FindWindow
    GetWindow
    GetWindowText
    SetWindowText
    IsWindow
    MoveWindow
    IsWindowVisible
    EnableWindow
    IsWindowEnabled
    WindowFromPoint
    ShowWindow
    CloseWindow
    SetWindowPos
    GetClassLong
    SetClassLong
    GetWindowLong
    SetWindowLong
    GetDesktopWindow
    GetParent

    Функция FindWindow

    function FindWindow(className,WindowName: PChar) : HWND;
    Функция возвращает описатель окна, удовлетворяющий запросу (0 -если такого окна не найдено).

    ClassName Имя класса, по которому призводится поиск среди ВСЕХ окон системы. WindowName Заголовок окна

    Один из параметров может быть равен nil, тогда поиск ведется по другому параметру.
    Пример:

    Функция GetWindow

    function GetWindow(Wnd: HWND; Param) : HWND
    Функция возвращает описатель окна удовлетворяющий запросу.

    Wnd Описатель какого-либо начального окна Param Принимает одно из следующих значений-констант: gw_Owner Возвращается описатель окна-предка (0 — если нет предка). gwHWNDFirst Возвращает описатель первого окна (относительно Wnd). gw_HWNDNext Возвращает описатель следующего окна (окна перебираются без повторений, т.е. если вы не меняли параметр Wnd функции, повторно описатели не возвращаются) gw_Child Возвращает описатель первого дочернего окна.

    Функция GetWindowText

    function GetWindowText(hWnd: HWND; lpString: PChar; nMaxCount: Integer): Integer;
    Функция возвращает текст окна. Для формы это будет заголовок, для кнопки — надпись на кнопке.

    hWnd Описатель того окна, текст которого нужно получить. lpString Переменная, в которую будет помещен результат nMaxCount

    Максимальная длина текста, если текст длиннее, то он обрезается.

    Функция IsWindow

    function IsWindow(hWnd: HWND): BOOL; Возвращает True, если окно с заданным описателем существует и False в противном случае.

    Hwnd Описатель нужного окна

    Функция MoveWindow

    MoveWindow(hWnd: HWND; X, Y, nWidth, nHeight: Integer; bRepaint: BOOL): BOOL; Перемещает окно в новую позицию.

    hWnd Описатель перемещаемого окна. X, Y, nWidth, nHeight Соответственно: новые координаты X,Y; новая ширина, высота. bRepaint Булево значение, показывающее будет ли окно перерисовано заново.

    Функция IsWindowVisible

    function IsWindowVisible(hWnd: HWND): BOOL;
    Возвращает True если данное окно видимо.

    hWnd Описатель окна.

    Функция EnableWindow

    function EnableWindow(hWnd: HWND; bEnable: BOOL): BOOL;
    Устанавливает доступность окна(окно недоступно, если оно не отвечает на события мыши, клавиатуры и т.д.). Аналог в Delphi свойство Enabled компонентов. EnableWindow возвращает True, если всё прошло успешно и False в противром случае.

    hWnd Описатель окна. bEnable Булево значение, определяющее доступность окна.


    Функция IsWindowEnabled

    function IsWindowEnabled(hWnd: HWND): BOOL;
    Возвращает для заданного окна: True, если окно доступно и False в противном случае.

    hWnd Описатель окна.

    Функция WindowFromPoint

    WindowFromPoint(Point: TPoint): HWND;
    Возвращает описатель окна, находящегося в данной точке экрана.

    Point Координата точки экрана типа TPoint (определение типа смотри ниже)

    Функция

    type TPoint = Record x: Longint; y: Longint; end ;

    Функция ShowWindow

    function ShowWindow(hWnd: HWND; nCmdShow: Integer): BOOL; Показывает или прячет окно.

    hWnd Описатель нужного окна nCmdShow Константа, определяющая, что будет сделано с окном: SW_HIDE SW_SHOWNORMAL SW_NORMAL SW_SHOWMINIMIZED SW_SHOWMAXIMIZED SW_MAXIMIZE SW_SHOWNOACTIVATE SW_SHOW SW_MINIMIZE SW_SHOWMINNOACTIVE SW_SHOWNA SW_RESTORE SW_SHOWDEFAULT SW_MAX

    Функция CloseWindow

    function CloseWindow(hWnd: HWND): BOOL; stdcall;
    Закрывает окно.

    hWnd Описатель закрываемого окна.

    SetWindowPos

    function SetWindowPos(hWnd: HWND; hWndInsertAfter: HWND; X, Y, cx, cy: Integer; uFlags: UINT): BOOL; stdcall;
    Устанавливает окно в новую позицию

    hWnd Оптсатель окна hWndInsertAfter Описатель окна, перед которым в списке Z-Order будет вставлено окно hWnd , или одна из следующих констант: HWND_BOTTOM Поместить окно на дно списка Z-Order HWND_TOP Поместить окно на верх списка Z-Order X, Y, cx, cy

    Соответственно — новые горизонт. , верт. позиции окна (X, Y ), а также новая ширина
    и высота (cx, cy )

    uFlags Одна или несколько (разделенных OR ) следующих констант: SWP_NOSIZE Не изменять размер окна после перемещения (cx, cy игнорируются) SWP_NOZORDER Не изменять положение окна в списке Z-Order SWP_SHOWWINDOW Сделать окно видимым после перемещения SWP_HIDEWINDOW Спрятать окно после перемещения SWP_NOACTIVATE Не передавать фокус окну после перемещения SWP_NOMOVE Не перемещать окно (игнорируется X, Y )

    Функция GetClassLong

    function GetClassLong(hWnd: HWND; nIndex: Integer): Integer;
    Эта функция возвращает 32-разрядное целое, взятое из определенного поля записи TWndClassEx указанного окна.

    hWnd Описатель окна nIndex Константа, определяющая что будет возвращено. Должна быть одна из следующих: GCL_MENUNAME Возвращает указатель на строку, содержащую имя меню класса, определенного в файле ресурсов связанного с некоторой программой. GCL_HBRBACKGROUND Возвращает описатель (HBRUSH) кисти фона, ассоциированной с классом GCL_HCURSOR Возвращает описатель (HCURSOR) курсора, фссоциированного с классом GCL_HICON Возвращает описатель (HICON) пиктограммы, ассоциированной с классом GCL_HMODULE Возвращает описатель процесса (HMODULE), зарегистртровавшего класс. GCL_CBWNDEXTRA Возвращает размер памяти (в байтах), выделенной под хранение дополнительных данных ДАННОГО ОКНА. Описание как использвать эту память, смотри в описании функции GCL_CBCLSEXTRA Возвращает размер памяти (в байтах), выделенной под хранение дополнительных ДАННОГ КЛАССА GCL_WNDPROC Возвращает адрес оконной процедуры, связанной с классом. GCL_STYLE Возвращает стиль класса (наличие того или иного стиля проверяется побитовой операцией And с помощью констант типа cs_XXX ) GCL_HICONSM

    Обратите внимание : в случае, когда функция возвращает указатель, необходимо приведение типов (Integer ->

    Функция SetClassLong

    function SetClassLong(hWnd: HWND; nIndex: Integer; dwNewLong: Longint): Integer; Парная функция функции . Устанавливает в нужное поле соответствующее значение.
    Функция возвращает старое значение поля, чтобы его потом можно было исправить или же возврашается ноль, если что-то пошло не так как надо.

    hWnd Описатель окна nIndex Одна из констант GCL_XXX из функции . В зависимости от значения этого поля будет изменнено нужное поле.

    Обратите внимание Pointer к типу Integer .

    Функция GetWindowLong

    function GetWindowLong(hWnd: HWND; nIndex: Integer): Longint; Возвращает информацию о некотором окне в виде 32-битного целого.

    hWnd Описатель окна nIndex Константа,определяющая, что будет возвращено. Должна быть одна их следующих:
    GWL_WNDPROC Возвращает адрес оконной процедуры, связанной с данным окном. Полученный адрес (после соответсвующих приведений типов) может использоваться в функции CallWindowProc . Данное значение обычно используют, если хотят заменить существующую оконную процедуру на свою собственную, при этом, чтобы не потерять работоспособности окна, обычно и используют CallWindowProc . GWL_HINSTANCE Возвращает описатель приложения, заданный при создании окна функцией CreateWindowEx . GWL_HWNDPARENT Возвращает описатель (HWND) родительского окна GWL_STYLE Возвращает стиль окна. Конкркетные значения стилей узнаются при помощи побитовой операции And и констант WS_XXX GWL_EXSTYLE Возвращает расширенный стиль окна. Конкркетные значения стилей узнаются при помощи побитовой операции And и констант WS_EX_XXX GWL_USERDATA Возвращает 32-битное целое, ассоциированное с окном (это последний параметр в вызове CreateWindow или CreateWindowEx) GWL_ID Возвращает идентификатор окна (он не имеет ничего общего с описателем окна!), задаваемый параметром hMenu для дочерних окон при вызове CreateWindow или CreateWindowEx

    Обратите внимание : в случае, когда функция возвращает указатель, необходимо приведение типов (Integer -> Pointer). Делать это можно так:

    Функция SetWindowLong

    function SetWindowLong(hWnd: HWND; nIndex: Integer; dwNewLong: Longint): Longint;
    Парная к функции . Изменяет аттрибуты определенного окна.
    Функция возвращает старое значение свойства, если вызов прошел удачно или нуль в противном случае.

    hWnd Описатель окна nIndex Константа, определяющая, какое свойство будет изменено. Должна быть одной из констант GWL_XXX из описания функции dwNewLong Новое значение свойства, определяемого константой nIndex

    Обратите внимание :при установке полей-указателей необходимо приведение типа Pointer к типу Integer .

    Функция GetDesktopWindow

    function GetDesktopWindow: HWND
    Функция возвращает описатель окна Рабочего Стола (Desktop). Без параметров.

    GetParent

    function GetParent(hWnd: HWND): HWND;
    Возвращает описатель родительского окна для окна hWnd .

    hWnd Описатель окна

    Аббревиатура API, Application Programming Interface (API) — это просто некоторый готовый набор функций, который могут использовать разработчики приложений. В общем случае данное понятие эквивалентно тому, что раньше чаще называли библиотекой подпрограмм. Однако чаще всего под API подразумевается некоторая особая категория таких библиотек.

    В ходе разработки практически любого достаточно сложного приложения (MyAppication) для конечного пользователя формируется набор специфических внутренних функций, используемых для реализации данной конкретной программы, который называется MyApplication API. Часто оказывается, что эти функции могут эффективно использоваться также для создания других приложений, в том числе другими программистами. В этом случае авторы исходя из стратегии продвижения своего продукта должны решить вопрос — открывают ли они доступ к этому набору для внешних пользователей или нет? При положительном ответе на него в описании программного пакета, как его достоинство, появляется фраза о том, что «комплект включает открытый набор API-функций».

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

    Соответственно, Windows API — это набор функций, являющийся частью самой операционной системы и в то же время — доступной для любого другого приложения. И в этом плане вполне оправдана аналогия с набором системных прерываний BIOS/DOS, который фактически представляет собой DOS API.

    Отличие заключается в том, что состав функций Windows API, с одной стороны значительно шире, по сравнению с DOS, с другой — не включает многие средства прямого управления ресурсами компьютера, которые были доступны программистам в предыдущей ОС. Кроме того, обращение к Windows API выполняется с помощью обыкновенных процедурных обращений, а вызов функций DOS — через специальную машинную команду процессора, которая называется Interrupt («прерывание»).

    Win16 API и Win32 API

    Как известно смена Windows 3.x на Windows 95 ознаменовала собой переход от 16-разрядной архитектуры операционной системы к 32-разрядной. Одновременно произошла замена 16-разрядного Windows API (Win16 API) на новый 32-разрядный вариант (Win32 API) . В данном случае нужно просто иметь в виду, что за небольшим исключением набор Win32 API является единым для семейств Windows 9x и Windows NT.

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

    API-функции, которые полностью реализованы в виде встроенных функций. Тем не менее, иногда и в этом случае бывает полезным перейти к применению API, так как это позволяет порой существенно повысить производительность (в частности, за счет отсутствия ненужных преобразований передаваемых параметров).

    Встроенные функции реализуют лишь частный случай соответствующей API-функции. Это довольно обычный вариант.

    Огромное число API-функций вообще не имеют аналогов в существующем сегодня варианте компиляторов. Например, удалить каталог нельзя средствами VB — для этого нужно использовать функцию DeleteDirectory.

    Следует также подчеркнуть, что некоторые API-функции (их доля в Win API весьма незначительна) не могут вызываться из программ из-за ряда ограничений языка, например отсутствие возможности работы с адресами памяти. Но в ряде случаев могут помочь нетривиальные приемы программирования (в частности, в случае с теми же адресами).

    Win API и Dynamic Link Library (DLL)

    Набор Win API реализован в виде динамических DLL-библиотек.

    В данном случае под DLL мы подразумеваем традиционный вариант двоичных динамических библиотек, которые обеспечивают прямое обращение приложений к нужным процедурам — подпрограммам или функциям (примерно также как это происходит при вызове процедур внутри проекта). Такие библиотеки могут создаваться с помощью разных инструментов — VC++, Delphi, Fortran, Assembler.

    Обычно файлы динамических библиотек имеют расширение.DLL, но это совсем не обязательно. Для Win16 часто применялось расширение.EXE, драйверы внешних устройств обозначаются с помощью.DRV.

    Определить точное число API-функций Windows и файлов, их содержащих, достаточно сложно (но все они находятся в системном каталоге). В этом плане лучше выделить состав библиотек, составляющих ядро операционной системы, и основных библиотек с ключевыми дополнительными функциями.

    Библиотеки Win32 API ядра операционной системы Windows 95/98:

    KERNEL32.DLL: низкоуровневые функции управления памятью, задачами и другими ресурсами системы;

    USER32.DLL: здесь в основном находятся функции управления пользовательским интерфейсом;

    GDI32.DLL: библиотека Graphics Device Interface — разнообразные функции вывода на внешние устройства;

    COMDLG32.DLL: функции, связанные с использованием диалоговых окон общего назначения.

    Основные библиотеки с функциями расширения:

    COMCTL32.DLL: набор дополнительных элементов управления Windows, в том числе Tree List и Rich Text;

    MAPI32.DLL: функции работы с электронной почтой;

    NETAPI32.DLL: элементы управления и функции работы с сетью;

    ODBC32.DLL: функции этой библиотеки нужны для работы с различными базами данных через протокол ODBC;

    WINMM.DLL: операции доступа к системным средствам мультимедиа.

    Windows API — набор функций операционной системы

    Аббревиатура API многим начинающим программистам кажется весьма таинственной и даже пугающей. На самом же деле Application Programming Interface (API) — это просто некоторый готовый набор функций, который могут использовать разработчики приложений. В общем случае данное понятие эквивалентно тому, что раньше чаще называли библиотекой подпрограмм. Однако обычно под API подразумевается особая категория таких библиотек.

    В ходе разработки практически любого достаточно сложного приложения (MyAppication) для конечного пользователя формируется набор специфических внутренних функций, используемых для реализации данной конкретной программы, который называется MyApplication API. Однако часто оказывается, что эти функции могут эффективно использоваться и для создания других приложений, в том числе другими программистами. В этом случае авторы, исходя из стратегии продвижения своего продукта, должны решить вопрос: открывают они доступ к этому набору для внешних пользователей или нет? При утвердительном ответе в описании программного пакета в качестве положительной характеристики появляется фраза: «Комплект включает открытый набор API-функций» (но иногда за дополнительные деньги).

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

    Соответственно Windows API — это набор функций, являющийся частью самой операционной системы и в то же время — доступный для любого другого приложения, в том числе написанного с помощью VB. В этом плане вполне оправданна аналогия с набором системных прерываний BIOS/DOS, который фактически представляет собой DOS API.

    Отличие заключается в том, что состав функций Windows API, с одной стороны, значительно шире по сравнению с DOS, с другой — не включает многие средства прямого управления ресурсами компьютера, которые были доступны программистам в предыдущей ОС. Кроме того, обращение к Windows API выполняется с помощью обыкновенных процедурных обращений, а вызов функций DOS — через специальную машинную команду процессора, которая называется Interrupt («прерывание»).

    Зачем нужен Win API для VB-программистов

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

    При знакомстве с Win API обнаруживается, что многие встроенные VB-функции — не что иное, как обращение к соответствующим системным процедурам, но только реализованное в виде синтаксиса данного языка. С учетом этого необходимость использования API определяется следующим вариантами:

    1. API-функции, которые полностью реализованы в виде встроенных VB-функций. Тем не менее иногда и в этом случае бывает полезным перейти к применению API, так как это позволяет порой существенно повысить производительность (в частности, за счет отсутствия ненужных преобразований передаваемых параметров).
    2. Встроенные VB-функции реализуют лишь частный случай соответствующей API-функции. Это довольно обычный вариант. Например, API-функция CreateDirectory обладает более широкими возможностями по сравнению со встроенным VB-оператором MkDir.
    3. Огромное число API-функций вообще не имеет аналогов в существующем сегодня варианте языка VB. Например, удалить каталог средствами VB нельзя — для этого нужно использовать функцию DeleteDirectory.

    Следует также подчеркнуть, что некоторые API-функции (их доля в Win API весьма незначительна) не могут вызываться из VB-программ из-за ряда ограничений языка, например из-за отсутствия возможности работы с адресами памяти. Но в ряде случаев могут помочь нетривиальные приемы программирования (в частности, в случае с теми же адресами).

    Личная точка зрения автора такова — вместо расширения от версии к версии встроенных функций VВ следовало бы давать хорошее описание наиболее ходовых API-функций. В то же время хочется посоветовать разработчикам не ждать появления новой версии средства с расширенными функциями, а внимательнее изучить состав существующего Win API — вполне вероятно, что нужные вам возможности можно было реализовать уже в версии VB 1.0 выпуска 1991 года.

    Как изучать Win API

    Это не такой простой вопрос, если учесть, что число функций Win32 API оценивается величиной порядка 10 тысяч (точной цифры не знает никто, даже Microsoft).

    В состав VB (версий 4-6) входит файл с описанием объявлений Win API — WIN32API.TXT (подробнее о его применении мы расскажем позднее). Но, во-первых, с его помощью можно получить сведения о назначении той или иной функции и ее параметрах только по используемым мнемоническим именам, а во-вторых — перечень функций в этом файле далеко не полный. В свое время (семь лет назад) в VB 3.0 имелись специальные справочные файлы с описанием функций Win16 API. Однако уже в v.4.0 эта полезная информация с удобным интерфейсом исчезла.

    Исчерпывающую информацию о Win32 API можно найти в справочной системе Platform Software Development Kit, которая, в частности, находится на компакт-дисках MSDN Library, включенных в состав VB 5.0 и 6.0 Enterprise Edition и Office 2000 Developer Edition. Однако разыскать там нужную информацию и разобраться в ней совсем не просто. Не говоря уж о том, что все описания там приводятся применительно к языку C.

    Общепризнанным в мире пособием для изучения API-программирования в среде VB являются книги известного американского эксперта Даниэля Эпплмана (Daniel Appleman). Его серия Dan Appleman’s Visual Basic Programmer’s Guide to the Windows API (для Win16, Win32, применительно к разным версиям VB) с 1993 года неизменно входит в число бестселлеров для VB-программистов. Книгу Dan Appleman’s VB 5.0 Programmer’s Guide to the Win32 API, выпущенную в 1997 году, автору привез из США приятель, который нашел ее в первом же книжном магазине небольшого провинциального городка.

    Эта книга объемом свыше 1500 страниц включает описание общей методики API-программирования в среде VB, а также более 900 функций. Прилагаемый компакт-диск содержит полный текст книги и всех программных примеров, а кроме того, несколько дополнительных глав, не вошедших в печатный вариант. В 1999 году Дэн Эпплман выпустил новую книгу Dan Appleman’s Win32 API Puzzle Book and Tutorial for Visual Basic Programmers, которая включает сведения о еще 7600 функциях (хотя и не столь обстоятельные).

    Набор Win API реализован в виде динамических DLL-библиотек. Далее речь фактически пойдет о технологии использования DLL в среде VB на примере библиотек, входящих в состав Win API. Однако, говоря о DLL, необходимо сделать несколько важных замечаний.

    В данном случае под DLL мы подразумеваем традиционный вариант двоичных динамических библиотек, которые обеспечивают прямое обращение приложений к нужным процедурам — подпрограммам или функциям (примерно так же, как это происходит при вызове процедур внутри VB-проекта). Такие библиотеки могут создаваться с помощью разных инструментов: VC++, Delphi, Fortran, кроме VB (посмотрим, что появится в версии 7.0) — последний может делать только ActiveX DLL, доступ к которым выполняется через интерфейс OLE Automation.

    Обычно файлы динамических библиотек имеют расширение.DLL, но это совсем не обязательно (для Win16 часто применялось расширение.EXE); драйверы внешних устройств обозначаются с помощью.DRV.

    Как мы уже отмечали, определить точное число API-функций Windows и содержащих их файлов достаточно сложно, однако все они находятся в системном каталоге. В этом плане лучше выделить состав библиотек, входящих в ядро операционной системы, и основных библиотек с ключевыми дополнительными функциями.

    А теперь несколько советов.

    Совет 1. Следите за правильным оформлением объявления DL L-процедур

    Само обращение к DLL-процедурам в программе выглядит точно так же, как к «обычным» процедурам Visual Basic, например:

    Call DllName ([список аргументов])

    Однако для использования внешних DLL-функций (в том числе и Win API) их нужно обязательно объявить в программе с помощью оператора Declare, который имеет следующий вид:

    Declare Sub ИмяПроцедуры Lib _ “ИмяБиблиотеки” _ [([СписокАргументов])]

    Declare Function ИмяФункции _ Lib “ИмяБиблиотеки” _ [([СписокАргументов])]

    Здесь в квадратных скобках приведены необязательные элементы оператора, курсивом выделены переменные выражения, остальные слова — ключевые. В справочной системе приведено достаточно хорошее описание синтаксиса оператора, поэтому сейчас мы только отметим некоторые моменты.

    Объявления внешних функций должны размещаться в секции General Declarations модуля. Если вы размещаете его в модуле формы, то обязательно нужно указать ключевое слово Private (это объявление будет доступно только внутри данного модуля) — таково ограничение для всех процедур модуля формы.

    Набор Win32 API реализован только в виде функций (в Win16 API было много подпрограмм Sub). В большинстве своем — это функции типа Long, которые чаще всего возвращают код завершения операции.

    Оператор Declare появился в MS Basic еще во времена DOS, причем он использовался и для объявления внутренних процедур проекта. В Visual Basic этого не требуется, так как объявлением внутренних процедур автоматически является их описание Sub или Function. По сравнению с Basic/DOS в новом описании обязательно указывать имя файла-библиотеки, где находится искомая процедура. Библиотеки Wip API размещаются в системном каталоге Windows, поэтому достаточно привести только название файла. Если же вы обращаетесь к DLL, которая находится в произвольном месте, нужно записать полный путь к данному файлу.

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

    Declare Function GetTempPath _ Lib “kernel32” Alias “GetTempPathA” _ (ByVal nBufferLength As Long, _ ByVal lpBuffer As String) As Long

    В этом случае все основные элементы описания разнесены на разные строчки и поэтому хорошо читаются.

    Совет 2. Будьте особенно внимательны при работе с DLL-функциями

    Использование Win API и разнообразных DLL-функций существенно расширяет функциональные возможности VB и зачастую позволяет повысить производительность программ. Однако расплата за это — риск снижения надежности работы приложения, особенно в процессе его отладки.

    Одним из самых важных достоинств среды VB является надежность процесса разработки программ: функционируя под управлением интерпретатора, программный код теоретически не может нарушить работу Windows и самого VB. Программист может не очень внимательно следить за правильностью передачи параметров в вызываемые функции — подобные ошибки будут легко обнаружены самим интерпретатором либо в процессе трансляции кода, либо во время его выполнения. В самом неприятном случае просто произойдет прерывание режима обработки, причем с указанием, где и почему произошла ошибка.

    Использование напрямую функций Windows API или других DLL-библиотек снимает такой контроль за передачей данных и процессом выполнения кода вне среды VB. Поэтому ошибка в обращении к внешним функциям может привести к неработоспособности и VB и операционной системы. Это особенно актуально на этапе разработки программы, когда наличие ошибок — дело вполне естественное. Таким образом, применяя более широкие возможности функций базового слоя системы, программист берет на себя ответственность за правильность их применения.

    Проблема усугубляется еще и тем, что разные языки программирования используют различные способы передачи параметров между процедурами. (Точнее, разные способы передачи используются по умолчанию, так как многие языки могут поддерживать несколько способов.) Win API реализованы на C/C++ и применяют соглашения о передаче параметров, принятые в этой системе, которые отличаются от привычного для VB варианта.

    В связи с этим следует отметить, что появление встроенных в VB аналогов API-функций оправданно именно адаптацией последних к синтаксису VB и реализацией соответствующего механизма контроля обмена данными. Обратим также внимание, что на этапе опытной отладки приложения при создании исполняемого модуля лучше использовать вариант компиляции P-code вместо Native Code (машинный код). В первом случае программа будет работать под управлением интерпретатора — медленнее по сравнению с машинным кодом, но более надежно с точки зрения возможного ошибочного воздействия на операционную систему и обеспечивая более удобный режим выявления возможных ошибок.

    Совет 3. Десять рекомендаций Дэна Эпплмана по надежному API-программированию в среде VB

    Использование функции API требует более внимательного программирования с использованием некоторых не очень привычных методов обращения к процедурам (по сравнению с VB). Далее мы будем постоянно обращаться к этим вопросам. А сейчас приведем изложение сформулированных Дэном Эпплманом советов на эту тему (их первый вариант появился еще в 1993 году) с некоторыми нашими дополнениями и комментариями.

    1. Помните о ByVal. Наиболее частая ошибка, совершаемая при обращении к функциям API и DLL, заключается в некорректном использовании ключевого слова ByVal: его или забывают ставить, или, наоборот, ставят, когда в нем нет необходимости.

    На этих примерах показано влияние оператора ByVal на передачу параметров

    Тип параметра С ByVal Без ByVal
    Integer В стек помещается 16-разрядное целое В стек помещается 32-разрядный адрес 16-разрядного целого
    Long В стек помещается 32-разрядное целое В стек помещается 32-разрядный адрес 32-разрядного целого
    String Строка преобразуется в формат, используемый в С (данные и завершающий нулевой байт). 32-разрядный адрес новой строки помещается в стек В стек помещается VB-дескриптор строки. (Такие дескрипторы никогда не используются самим Windows API и распознаются только в DLL, реализованных специально для VB.)

    Здесь следует напомнить, что передача параметров в любой системе программирования, в том числе и VB, выполняется двумя основными путями: по ссылке (ByRef) или по значению (ByVal). В первом случае передается адрес переменной (этот вариант используется в VB по умолчанию), во втором — ее величина. Принципиальное отличие заключается в том, что с помощью ссылки обеспечивается возврат в вызывающую программу измененного значения передаваемого параметра.

    Чтобы разобраться в этом, проведите эксперимент с помощью таких программ:

    Dim v As Integer v = 2 Call MyProc(v) MsgBox “v = “ & v Sub MyProc (v As Integer) v = v + 1 End Sub

    Запустив на выполнение этот пример, вы получите сообщение со значением переменной, равным 3. Дело в том, что в данном случае в подпрограмму MyProc передается адрес переменной v, физически созданной в вызывающей программе. Теперь измените описание процедуры на

    Sub MyProc (ByVal v As Integer)

    В результате при выполнении теста вы получите v = 2, потому что в процедуру передается лишь исходное значение переменной — результат выполненных с ним операций не возвращается в вызывающую программу. Режим передачи по значению можно поменять также с помощью оператора Call следующим образом:

    Sub MyProc (v As Integer) . Call MyProc((v)) ‘ (v) — скобки указывают режим _ передачи по значению.

    Однако при обращении к внутренним VB-процедурам использование в операторе Call ключевого слова ByVal запрещено — вместо него применяются круглые скобки. Этому есть свое объяснение.

    В классическом случае (С, Fortran, Pascal) различие режимов ByRef и ByVal зависит от того, что именно помещается в стек обмена данными — адрес переменной или ее значение. В Basic исторически используется вариант программной эмуляции ByVal — в стеке всегда находится адрес, но только при передаче по значению для этого создается временная переменная. Чтобы отличить два этих варианта (классический и Basic), используются разные способы описания режима ByVal. Отметим, что эмуляция режима ByVal в VB обеспечивает более высокую надежность программы: перепутав форму обращения, программист рискует лишь тем, что в вызывающую программу вернется (или не вернется) исправленное значение переменной. В «классическом» же варианте такая путаница может привести к фатальной ошибке при выполнении процедуры (например, когда вместо адреса памяти будет использоваться значение переменной, равное, скажем, нулю).

    DLL-функции реализованы по «классическим» принципам и поэтому требуют обязательного описания того, каким образом происходит обмен данными с каждым из аргументов. Именно этой цели служат объявления функций через описание Declare (точнее, списка передаваемых аргументов). Чаще всего передача параметров в функцию Windows API или DLL выполняется с помощью ключевого слова ByVal. Причем оно может быть задано как в операторе Declare, так и непосредственно при вызове функции.

    Последствия неправильной передачи параметров легко предугадать. В случае получения явно недопустимого адреса вам будет выдано сообщение GPF (General Protection Fault — ошибка защиты памяти). Если же функция получит значение, совпадающее с допустимым адресом, то функция API залезет в чужую область (например, в ядро Windows) со всеми вытекающими отсюда катастрофическими последствиями.

    2. Проверяйте тип передаваемых параметров. Не менее важны верное число и тип передаваемых параметров. Необходимо, чтобы объявленные в Declare аргументы соответствовали ожидаемым параметрам в функции API. Наиболее часто встречающийся случай ошибки в передаче параметров связан с различием между NULL и строкой нулевой длины — следует помнить, что это не одно и то же.

    3. Проверяйте тип возвращаемого значения.

    VB довольно терпимо относится к несовпадению типов возвращаемых функцией значений, поскольку числовые значения обычно возвращаются через регистры, а не через стек. Следующие правила помогут определить корректное значение, возвращаемое функцией API:

    • DLL-функция, не возвращающая значения (аналог void в ‘C’), должна быть объявлена как VB Sub.
    • функция API, возвращающая целое значение (Integer или Long), может быть определена или как Sub, или как Function, возвращающая значение соответствующего типа.
    • ни одна из функций API не возвращает числа с плавающей точкой, но некоторые DLL вполне могут возвращать такой тип данных.

    4. С большой осторожностью используйте конструкцию «As Any». Множество функций Windows API имеют возможность принимать параметры различных типов и используют при этом обращение с применением конструкции As Any (интерпретация типа выполняется в зависимости от значения других передаваемых параметров).

    Хорошим решением в этом случае может быть использование нескольких псевдонимов (Alias) функции с созданием двух и более объявлений для одной и той же функции, причем в каждом из описаний указываются параметры определенного типа.

    5. Не забывайте инициализировать строки. В Win API существует множество функций, возвращающих информацию путем загрузки данных в передаваемые как параметр строковые буферы. В своей программе вы можете вроде бы все сделать правильно: не забыть о ByVal, верно передать параметры в функцию. Но Windows не может проверить, насколько велик размер выделенного под строку участка памяти. Размер строки должен быть достаточным для размещения всех данных, которые могут быть в него помещены. Ответственность за резервирование буфера нужного размера лежит на VB-программисте.

    Следует отметить, что в 32-разрядных Windows при использовании строк производится преобразование из Unicode (двухбайтовая кодировка) в ANSI (однобайтовая) и обратно, причем с учетом национальных установок системы. Поэтому для резервирования буферов порой удобнее использовать байтовые массивы вместо строковых переменных. (Подробнее об этом будет рассказано ниже.)

    Чаще всего функции Win API позволяют вам самим определить максимальный размер блока. В частности, иногда для этого нужно вызвать другую функцию API, которая «подскажет» размер блока. Например, GetWindowTextLength позволяет определить размер строки, необходимый для размещения заголовка окна, получаемого функцией GetWindowText. В этом случае Windows гарантирует, что вы не выйдете за границу.

    6. Обязательно используйте Option Explicit.

    7. Внимательно проверяйте значения параметров и возвращаемых величин. VB обладает хорошими возможностями по проверке типов. Это означает, что, когда вы пытаетесь передать неверный параметр в функцию VB, самое плохое, что может случиться, — вы получите сообщение об ошибке от VB. Но данный механизм, к сожалению, не работает при обращении к функциям Windows API.

    Windows 9x обладает усовершенствованной системой проверки параметров для большинства функций API. Поэтому наличие ошибки в данных обычно не вызывает фатальной ошибки, однако определить, что же явилось ее причиной — не так-то просто.


    Здесь можно посоветовать использовать несколько способов отладки ошибки данного типа:

    • используйте пошаговый режим отладки или команду Debug.Print для проверки каждого подозрительного вызова функции API. Проверьте результаты этих вызовов, чтобы удостовериться, что все в пределах нормы и функция корректно завершилась;
    • используйте Windows-отладчик типа CodeView и отладочную версию Windows (имеется в Windows SDK). Эти средства могут обнаружить ошибку параметров и по меньшей мере определить, какая функция API приводит к ошибке;
    • используйте дополнительные средства третьих фирм для проверки типов параметров и допустимости их значений. Такие средства могут не только находить ошибки параметров, но даже указать на строку кода VB, где произошла ошибка.

    Кроме того, нужно обязательно проверять результат выполнения API-функции.

    8. Помните, что целые числа в VB и в Windows — не одно и то же. В первую очередь следует иметь в виду, что под термином «Integer» в VB понимается 16-разрядное число, в документации Win 32 — 32-разрядное. Во-вторых, целые числа (Integer и Long) в VB — это величины со знаком (то есть один разряд используется как знак, остальные — как мантисса числа), в Windows — используются только неотрицательные числа. Это обстоятельство нужно иметь в виду, когда вы формируете передаваемый параметр с помощью арифметических операций (например, вычисляете адрес с помощью суммирования некоторой базы и смещения). Для этого стандартные арифметические функции VB не годятся. Как быть в этом случае, мы поговорим отдельно.

    9. Внимательно следите за именами функций. В отличие от Win16 имена всех функций Win32 API являются чувствительными к точному использованию строчных и прописных букв (в Win16 такого не было). Если вы где-то применяете строчную букву вместо прописной или наоборот, то нужная функция не будет найдена. Следите также за правильным использованием суффикса A или W в функциях, применяющих строковые параметры. (Подробнее об этом – см. ниже.)

    10. Чаще сохраняйте результаты работы. Ошибки, связанные с неверным использованием DLL и Win API, могут приводить к аварийному завершению работы VB-среды, а возможно — и всей операционной системы. Вы должны позаботиться о том, чтобы написанный вами код перед тестовым запуском был сохранен. Самое простое — это установить режим автоматической записи модулей проекта перед запуском проекта в среде VB.

    После прочтения предыдущего совета может возникнуть мысль, что использование функций Win API — дело рискованное. В какой-то степени это так, но только в сравнении с безопасным программированием, предоставляемым самим VB. Но при умелом их применении и знании возможных подводных камней этот риск минимален. К тому же полностью отказаться от применения Win API зачастую просто невозможно — они все равно потребуются при сколь-нибудь серьезной разработке.

    К тому же ранее мы упоминали о «подводных» камнях для широкого класса DLL. В случае с Win API все обстоит гораздо проще, так как здесь четко унифицирована форма обращения к этим функциям. При этом следует иметь в виду следующие основные моменты:

      Функции Win32 API являются именно функциями, то есть процедурами типа Function (в Win16 API было много подпрограмм Sub). Все это функции типа Long, поэтому их описания записываются в следующем виде: Declare Function name . As Long ‘ тип функции _ определяется в явном виде

    Declare Function name& ‘ тип функции _ определяется с помощью суффикса

    Обращение к API-функции выглядит так:

    1. Чаще всего возвращаемое значение функции является кодом завершения операции. Причем ненулевое значение означает в данном случае нормальное завершение, нулевое — ошибку. Обычно (но не всегда) уточнить характер ошибки можно с помощью обращения к функции GetLastError. Описание этой функции имеет такой вид: Declare Function GetLastError& Lib “kernel32” ()

    ВНИМАНИЕ! При работе в среде VB для получения значения уточненного кода ошибки лучше использовать свойство LastDLLError объекта Err, так как иногда VB обнуляет функцию GetLastError в промежутке между обращением к API и продолжением выполнения программы.

    Интерпретировать код, возвращаемый GelLastError, можно с помощью констант, записанных в файле API32.TXT, с именами, начинающимися с суффикса ERROR_.

    Наиболее типичные ошибки имеют следующие коды:

      ERROR_INVAL >Однако многие функции возвращают значение некоторого запрашиваемого параметра (например, OpenFile возвращает значение описателя файла). В таких случаях ошибка определяется каким-либо другим специальным значением Return&, чаще всего 0 или –1.

    Win32 API используют строго фиксированные способы передачи самых простых типов данных. а) ByVal . As Long

    С помощью переменных типа Long выполняется не менее 80% передачи аргументов. Обратите внимание, что аргумент всегда сопровождается ключевым словом ByVal, а это, кроме всего прочего, означает, что выполняется односторонняя передача данных — от VB-программы к API-функции.

    Б) ByVal . As String

    Этот тип передачи данных также встречается достаточно часто, причем с аргументом также всегда применяется ByVal. При вызове API-функции в стек записывается адрес строки, поэтому в данном случае возможен двусторонний обмен данными. При работе со строками нужно учитывать несколько опасностей.

    Первая — резервирование памяти под строку производится в вызывающей программе, поэтому если API-функция будет заполнять строки, то нужно перед ее вызовом создать строку необходимого размера. Например, функция GetWindowsDirectory возвращает путь к каталогу Windows, который по определению не должен занимать более 144 символов. Соответственно обращение к этой функции должно выглядеть примерно так:

    WinPath$ = Space$(144) ‘ резервируем строку в _ 144 символа Result& = GetWindowsDirectory& (WinTath$, 144) _ ‘заполнение буфера ‘ Result& — фактическое число символов в имени _ каталога WinPath$ = Left$(WinPath, Result&)

    Вторая проблема заключается в том, что при обращении к API-функции производится преобразование исходной строки в ее некоторое внутреннее представление, а при выходе из функции — наоборот. Если во времена Win16 эта операция заключалась лишь в добавлении нулевого байта в конце строки, то с появлением Win32 к этому добавилась трансформация двухбайтной кодировки Unicode в ANSI и наоборот. (Об этом подробно говорилось в статье «Особенности работы со строковыми переменными в VB», КомпьютерПресс 10’99 и 01’2000). Сейчас же только отметим, что с помощью конструкции ByVal . As String можно обмениваться строками только с символьными данными.

    Это означает, что в стек будет помещен некоторый адрес буфера памяти, интерпретация содержимого которого будет выполняться API-функцией, например, в зависимости от значения других аргументов. Однако As Any может использоваться только в операторе Declare — при конкретном обращении к функции в качестве аргумента должна быть определена конкретная переменная.

    Г) . As UserDefinedType

    Такая конструкция также часто применяется, когда необходимо обменяться данными (в общем случае в обе стороны) с помощью некоторой структуры. На самом деле эта конструкция — некий вид конкретной реализации формы передачи As Any, просто в данном случае функция настроена на фиксированную структуру.

    Форма структуры данных определяется конкретной API-функцией, и на программисте лежит ответственность правильным образом описать и зарезервировать ее в вызывающей программе. Такая конструкция всегда используется без слова ByVal, то есть в данном случае выполняется передача по ссылке — в стек записывается адрес переменной.

    Пример обращения к API-функции

    Проиллюстрируем сказанное выше на примере использования двух полезных функций работы с файлами — lopen и lread, которые описываются следующим образом:

    Declare Function lopen Lib “kernel32” _ Alias “_lopen” (_ ByVal lpFileName As String, _ ByVal wReadWrite As Long) As Long Declare Function lread Lib “kernel32” _ Alias “_lread” (_ ByVal hFile As Long, lpBuffer As Any, _ ByVal wBytes As Long) As Long

    В VB их аналогами — в данном случае точными — являются операторы Open и Get (для режима Binary). Обратим сразу внимание на использование ключевого слова Alias в объявлении функции — это как раз тот случай, когда без него не обойтись. Настоящие названия функции в библиотеке начинаются с символа подчеркивания (типичный стиль для языка C), что не разрешается в VB.

    Операция открытия файла может выглядеть следующим образом:

    Здесь нужно обратить внимание на два момента:

    • в качестве значения функции мы получаем значение описателя файла. Ошибке соответствует значение –1;
    • как раз в данном случае не срабатывает обращение к функции GetLastError — для получения уточненного значения ошибки мы обратились к объекту Err (о возможности такой ситуации мы говорили выше).

    Далее можно читать содержимое файла, но это предполагает, что программист должен иметь некоторое представление о его структуре (так же как это происходит при работе с произвольными двоичными файлами). В этом случае обращение к функции lread может выглядеть следующим образом:

    Dim MyVar As Single wBytes = lread (hFile&, MyVar, Len(MyVar) ‘ чтение вещественного числа, 4 байта ‘ wBytes — число фактически прочитанных данных, ‘ -1 — ошибка. Type MyStruct x As Single i As Integer End Type Dim MyVar As MyStruct wBytes = lread (hFile&, MyVar, Len(MyVar)) ‘ чтение структуры данных, 6 байтов

    Еще раз обратите внимание: второй аргумент функции передается по ссылке, остальные — по значению.

    Dim MyVar As String MyVar = Space$(10) ‘резервируем переменную для 10 символов wBytes = lread (hFile&, ByVal MyVar, Len(MyVar)) ‘ чтение символьной строки, 10 символов

    Здесь видно важное отличие от приведенного ранее примера — строковая переменная обязательно сопровождается ключевым словом ByVal.

    Чтение содержимого файла в массиве (для простоты будем использовать одномерный байтовый массив) выполняется следующим образом:

    Dim MyArray(1 To 10) As Byte wBytes = lread (hFile&, MyArray(1), _ Len(MyArray(1))* 10) ‘ чтение 10 элементов массива

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

    WBytes = lread (hFile&, MyArray(4), _ Len(MyArray(1))* 5) ‘ чтение элементов массива с 4-го по 8-й

    Совет 5. Используйте Alias для передач и параметров As Any

    Здесь на основе предыдущего примера мы раскроем суть четвертого совета Дэна Эпплмана.

    Работая с функцией lread, следует помнить, что при обращении к ней с использованием строковой переменной необходимо использовать ключевое слово ByVal (иначе сообщения о нелегальной операции не избежать). Чтобы обезопасить себя, можно сделать дополнительное специальное описание этой же функции для работы только со строковыми переменными:

    Declare Function lreadString Lib “kernel32” _ Alias “_lread” (_ ByVal hFile As Long, ByVal lpBuffer As String, _ ByVal wBytes As Long) As Long

    При работе с этим описанием указывать ByVal при обращении уже не нужно:

    WBytes = lreadString (hFile&, MyVarString, _ Len(MyVarString)) ‘

    Казалось бы, синтаксис оператора Declare позволяет сделать подобное специальное описание для массива:

    Declare Function lreadString Lib “kernel32” Alias “_lread” (_ ByVal hFile As Long, lpBuffer() As Byte, _ ByVal wBytes As Long) As Long

    WBytes = lreadArray (hFile&, MyArray(), 10)

    неизбежно приводит к фатальной ошибке программы.

    Это продолжение разговора об особенностях обработки строковых переменных в Visual Basic: VB использует двухбайтную кодировку Unicode, Win API — однобайтную ANSI (причем с форматом, принятым в С, — с нулевым байтом в конце). Соответственно при использовании строковых переменных в качестве аргумента всегда автоматически производится преобразование из Unicode в ANSI при вызове API-функции (точнее, DLL-функции) и обратное преобразование при возврате.

    Вывод из этого простой: с помощью переменных String можно обмениваться символьными данными, но нельзя использовать их для обмена произвольной двоичной информацией (как это было при работе с 16-разрядными версиями VB). В последнем случае лучше использовать одномерный байтовый массив.

    Как известно, тип String можно использовать для описания пользовательской структуры. В связи с этим нужно помнить следующее:

      Категорически нельзя использовать для обращения к Win API конструкцию следующего вида: Type MyStruct x As Single s As String ‘ строка переменной длины End Type

    В случае строки переменной длины в составе структуры передается дескриптор строки со всеми вытекающими отсюда последствиями в виде ошибки выполнения программы.

  • Можно использовать в качестве элемента структуры строку фиксированной длины: Type MyStruct x As Single s As String*8 ‘ строка фиксированной длины End Type
  • При этом производится соответствующее преобразование кодировок.

    И последнее замечание: применять массив строковых переменных (как фиксированной, так и переменной длины) при обращении к API-функции нельзя ни в коем случае. Иначе появление «нелегальной операции» будет гарантировано.

    Вполне вероятно, что у вас возникнет ситуация, когда вам потребуется написать собственную библиотеку DLL-функций. Потребность в этом неизбежно появится, если вы будете использовать технологию смешанного программирования — использования двух или более языков программирования для реализации одного приложения.

    Отметим в связи с этим, что смешанное программирование — это вполне обычное явление для реализации достаточно сложного приложения. Действительно, каждый язык (точнее, система программирования на базе языка) имеет свои сильные и слабые стороны, поэтому вполне логично использовать преимущества различных инструментов для решения разных задач. Например, VB — для создания пользовательского интерфейса, С — для эффективного доступа к системным ресурсам, Fortran — для реализации численных алгоритмов.

    Мнение автора таково: сколь-нибудь серьезное занятие программированием требует от разработчика владения по крайней мере двумя инструментами. Разумеется, в современных условиях четкого разделения труда очень сложно быть отличным экспертом даже по двум системам, поэтому более логичной является схема «основной и вспомогательный языки». Идея здесь заключается в том, что даже поверхностное знание «вспомогательного» языка (написание довольно простых процедур) может очень заметно повысить эффективность применения «основного». Отметим, что знание VB хотя бы в качестве вспомогательного является сегодня практически обязательным требованием для профессионального программиста. Кстати, во времена DOS для любого программиста, в том числе Basic, было крайне желательным знание основ Ассемблера.

    Так или иначе, но даже в условиях групповой работы, когда каждый программист занимается своим конкретным делом, представление об особенностях процедурного интерфейса в разных языках должны иметь все участники проекта. И знать, что многие системы программирования (в том числе и VB), кроме интерфейса, используемого по умолчанию, позволяют применять иные, расширенные методы обращения к процедурам, которые дают возможность адаптировать интерфейс к другому языку.

    При изучении межпроцедурного интерфейса следует обратить внимание на следующие возможные «подводные камни»:

    • Разные языки могут использовать различные соглашения о правилах написания идентификаторов. Например, часто используется знак подчеркивания в начале имени процедуры, что запрещено в VB. Эта проблема легко решается с помощью ключевого слова Alias в операторе Declare (см. пример совета 2.3).
    • Может быть использована разная последовательность записи передаваемых аргументов в стек. Например, во времена DOS (честно признаюсь — не знаю, как это выглядит сейчас в среде Windows), C записывал аргументы с конца списка, другие языки (Fortran, Pascal, Basic) — с начала.
    • По умолчанию используются разные принципы передачи параметров — по ссылке или по значению.
    • Различные принципы хранения строковых переменных. Например, в C (так же как в Fortran и Pascal) длина строки определяется нулевым байтом в ее конце, а в Basic длина записывается в явном виде в дескрипторе строки. Разумеется, нужно иметь в виду возможность использования разных кодировок символов.
    • При передаче многомерных массивов следует помнить, что возможны различные варианты преобразования многомерных структур в одномерные (начиная с первого индекса или с последнего, применительно к двухмерным массивам — «по строчкам» или «по столбцам»).

    С учетом всего этого можно сформулировать следующие рекомендации:

    • Используйте самые простые, проверенные способы передачи аргументов в DLL-функции. Стандарты, принятые для Win API, вполне годятся в качестве образца.
    • Ни в коем случае не передавайте массивы строковых переменных.
    • Очень внимательно используйте передачу простых строковых переменных и многомерных массивов.
    • Обязательно специальным образом проверяйте работоспособность механизма передачи аргументов в вызываемую процедуру и обратно. Напишите специальный тест для проверки передачи данных. Отдельно проверьте правильность передачи каждого аргумента. Например, если у вас есть процедура с несколькими аргументами, проверьте сначала корректность передачи каждого параметра для варианта с одним аргументом, а уж потом — для всего списка.

    А что делать, если DLL-функция уже написана, например, на Фортране, но ее входной интерфейс не очень хорошо вписывается в приведенные выше стандарты VB? Здесь можно дать два совета. Первый: напишите тестовую DLL-функцию и с ее помощью постарайтесь методом проб и ошибок подобрать нужное обращение из VB-программы. Второй: напишите процедуру-переходник на том же Фортране, который бы обеспечивал простой интерфейс между VB и DLL-функцией с преобразованием простых структур данных в сложные (например, преобразовывал многомерный байтовый массив в строковый массив).

    Итак: используйте DLL-функции. Но сохраняйте бдительность.

    Наконец-то! Наконец-то! Сегодня мы начнём создавать полноценное окно Windows. Прощай убогая консоль.

    К этому моменту вы уже должны неплохо знать синтаксис C++, уметь работать с ветвлениями и циклами, хорошо понимать работу функций. Если вы справились с морским боем, можете считать, что всё это вы усвоили.

    Венгерская форма записи

    Весь код, который мы встретим в WinAPI написан в венгерской форме. Это такое соглашение по написанию кода.

    При этом перед именем переменной ставится начальная буква типа. Все слова в именах переменных и функций начинаются с заглавной буквы.

    Вот несколько префиксов:

    b — переменная типа bool.
    l — переменная типа long integer.
    w — от word (слово) — 16 бит. Переменная типа unsigned short.
    dw — от double word (двойное слово) — 32 бита. Переменная типа unsigned long.
    sz — строка заканчивающаяся нулём (string terminated zero). Просто обычная строка, которую мы постоянно использовали.
    p или lp — указатель (от pointer). lp (от long pointer) — данные указатели перешли из прошлого. Сейчас lp и p означают одно и то же.
    h — описатель (от handle).

    Например, указатель будет называться вот так:

    Данная форма записи используется Microsoft. Многие критикуют этот способ именования переменных. Но подобные вещи (соглашения о кодировании) в больших компаниях жизненно необходимы.

    Напомню, что идентификаторы констант обычно состоят только из заглавных букв: WM_DESTROY. WM_DESTOY — это 2, константа определена через define.

    Кроме того, в winAPI используется очень много переопределённых типов. Вот на этой страничке — http://msdn.microsoft.com/en-us/library/aa383751(VS.85).aspx , можете найти описания всех типов Windows (на английском).

    И ещё одна вещь, которую мы не разбирали. Указателям часто присваивается значение NULL. Считайте, что это просто 0 и указатели которым присвоено значение NULL (ноль), не указывают ни на какой участок памяти.

    Windows API (WinAPI)

    Все программы под Windows используют специальный интерфейс программирования WinAPI. Это набор функций и структур на языке C, благодаря которым ваша программа становится совместимой с Windows.

    Windows API обладает огромными возможностями по работе с операционной системой. Можно даже сказать — безграничными.

    Мы не рассмотрим даже один процент всех возможностей WinAPI. Первоначально я хотел взять больше материала, но это заняло бы слишком много времени, и увязнув в болоте WinAPI, до DirectX»а мы добрались бы через пару лет. Описание WinAPI займёт два урока (включая этот). В них мы рассмотрим только каркас приложения под Windows.

    Программа под Windows точно так же как и программа под DOS, имеет главную функцию. Здесь эта функция называется WinMain.

    Программа под Windows состоит из следующих частей (всё это происходит внутри WinMain):

    Создание и регистрация класса окна. Не путайте с классами C++. WinAPI написана на C, здесь нет классов в привычном для нас понимании этого слова.
    Создание окна программы.
    Основной цикл, в котором обрабатываются сообщения.
    Обработка сообщений программы в оконной процедуре. Оконная процедура представляет собой обычную функцию.
    Вот эти четыре пункта — основа программы Windows. В течение этого и следующего урока мы разберём всё это подробно. Если вы запутаетесь в описании программы, то вернитесь к этим пунктам.

    Теперь разберём всё это подробно:

    WinAPI: Структура WNDCLASS

    Прежде всего нужно создать и заполнить структурную переменную WNDCLASS, а затем на её основе зарегистрировать оконный класс.

    Вот как выглядит эта структура:

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

    После того как вы заполните эту структуру, на её основе можно зарегистрировать оконный класс. Речь идёт не о таких классах как в C++. Скорее можно считать, что оконный класс это такой шаблон, вы его зарегистрировали в системе, и теперь на основе этого шаблона можно создать несколько окон. И все эти окна будут обладать свойствами, которые вы определили в структурной переменной WNDCLASS.

    WinAPI: Функция CreateWindow

    После регистрации оконного класса, на его основе создаётся главное окно приложения (мы сейчас приступили ко второму пункту). Делается это с помощью функции CreateWindow. Она имеет следующий прототип:

    код на языке c++ HWND CreateWindow(LPCTSTR lpClassName, // имя класса LPCTSTR lpWindowName, // имя окна (отображается в заголовке) DWORD dwStyle, // стиль окна int x, // координата по горизонтали от левого края экрана int y, // координата по вертикали от верхнего края экрана int nWidth, // ширина окна int nHeight, // высота окна HWND hWndParent, // родительское окно HMENU hMenu, // описатель меню HINSTANCE hInstance, // экземпляр приложения LPVOID lpParam // параметр; всегда ставьте NULL);

    Если в оконном классе (структуре WNDCLASS) задаются базовые свойства окна, то здесь — более специфические для каждого окна: размер окна, координаты.

    Данная функция возвращает описатель окна. С помощью описателя можно обращаться к окну, это примерно как идентификатор.

    Обратите внимание, что здесь очень много новых типов. На самом деле они все старые, просто переопределены. Например: HWND — это переопределение типа HANDLE, который в свою очередь является переопределением PVOID, который в свою очередь является переопределением void*. Как глубоко закопана правда! Но всё же тип HWND — это указатель на void.

    Окно состоит из нескольких частей. Практически в каждой программе вы увидите: заголовок окна, системное меню (если нажать на иконку приложения в левой верхней части окна), три системные кнопки для работы с окном: свернуть, развернуть на весь экран и закрыть. Также, практически всегда в приложении присутствует меню. Вот как раз последнего у нас точно не будет. И, конечно же, большую часть окна занимает т.н. клиентская область, в которой обычно и работает пользователь.

    Это что касается оконного режима. Довольно долго мы будем практиковаться с DiectX именно в окне — не будем пользоваться полноэкранным режимом.

    Обработка сообщений (Message handling)

    Основным отличием всех наших предыдущих программ от программ под Windows является обработка сообщений.

    Например, когда пользователь нажимает какую-нибудь клавишу на клавиатуре, генерируется сообщение, что была нажата клавиша. Затем это сообщение поступает в приложение, которое было активным, когда пользователь нажал клавишу.

    Здесь у нас произошло событие (event) — была нажата клавиша.

    Событием может быть: перемещение курсора мыши, смена фокуса приложения, нажатие клавиши клавиатуры, закрытие окна. Событий очень много. Очень! За секунду в операционной системе может происходить десятки событий.

    Так вот, когда происходит какое-либо событие, операционная система создаёт сообщение: была нажата такая-то клавиша, координаты курсора мыши изменились, открылось новое окно.

    Сообщения может создавать как операционная система, так и различные приложения.

    Сообщение представляет собой структуру, и выглядят следующим образом:

    Обратите внимание, как с помощью typedef переопределяются структуры.

    Чтобы создать данную структуру можно воспользоваться следующим кодом:

    код на языке c++ msg.messgae == 2; // эти две строки эквивалентны так как msg.message == WM_DESTROY; // константа WM_DESTROY равна двум

    Здесь, поле, в котором содержится код сообщения (имя сообщения, сравнивается с константой WM_DESTROY. WM — от Windows Message (сообщение Windows). WM_DESTROY — это сообщение, которое генерируется при закрытии окна (destroy — уничтожить).

    Коды сообщений определены с помощью констант и имеют префикс WM_: WM_CLOSE, WM_CREATE и др.

    В структуре MSG встречается тип HWND — от Window Handle (дескриптор окна или описатель окна). Это такая штука, которая «описывает» окно. Это что-то вроде идентификатора (имени окна).

    Запомните это слово — handle (описатель, дескриптор). В Windows это понятие используется очень часто. Почти все типы Windows, которые начинаются с H — описатели: описатель иконки, описатель шрифта, описатель экземпляра приложения. Их штук тридцать насколько я помню.

    Все взаимодействия между приложениями в Windows осуществляются с помощью этих самых описателей окон (HWND).

    Существует ещё один важный описатель — описатель приложения (HINSTANCE — первый параметр WinMain) — это уникальный идентификатор приложения, благодаря которому операционная система не сможет перепутать две разных программы. Это примерно как штрих-код. Мы рассмотрим его позже.

    Каждый раз, когда пользователь совершает какое-то действие, создаётся и заполняется сообщение: задаётся описатель окна, которое должно получить данное сообщение, задаётся идентификатор сообщения, заполняются параметры, заполняется время (текущее) и указываются координаты курсора мыши (смотрите структуру).

    После этого данное сообщение помещается в очередь сообщений операционной системы. Когда доходит очередь до нашего сообщения, оно отправляется нужному окну (windows знает какому окну отправлять каждое сообщение благодаря описателям). Когда сообщение приходит в приложение, оно помещается в очередь сообщений приложения. Как только до него доходит очередь, оно обрабатывается.

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

    Оконная процедура (Window procedure — WndProc)

    Продолжаем с того момента, как сообщение попало в очередь сообщений приложения. Как только до него дошла очередь, оно обрабатывается. Для обработки сообщений в каждой программе должна существовать специальная функция — оконная процедура. Обычно она называется WndProc (от Window Procedure). Вызов оконной процедуры расположен в основном цикле программы и выполняется при каждой итерации цикла.

    Сообщения (в виде структурных переменных MSG) попадают в данную функцию в виде параметров: описатель окна, идентификатор сообщения и два параметра. Обратите внимание, что в оконную процедуру не передаются поля time и pt. То есть сообщение уже «разобрано».

    Внутри оконной процедуры расположено ветвление switch, в котором идёт проверка идентификатора сообщения. Вот пример простой оконной процедуры (она полностью рабочая):

    код на языке c++ // не обращайте пока внимания на HRESULT и __stdcall. Мы рассмотрим их позже HRESULT __stdcall WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) < switch (message) < case WM_PAINT: // код обработки сообщения WM_PAINT return 0; case WM_DESTROY: // код обработки сообщения WM_DESTROY return 0; >// обработчик всех остальных сообщений >

    И последнее — основной цикл. Он очень прост. Каждую итерацию цикла проверяется очередь сообщений приложения. Если в очереди сообщений есть сообщение, оно вытаскивается из очереди. Затем в теле цикла происходит вызов оконной процедуры, чтобы обработать взятое из очереди сообщение.

    Вот, в общем-то, и всё на сегодня. Уже видно, что программа под WinAPI намного сложнее программы под DOS. Как я уже писал выше, в следующем уроке мы разберём код работающей программы.

    В качестве упражнения создайте новый проект. В окне New Project (Новый проект) выберите шаблон (template) — Win32Project (до сих пор мы выбирали Win32 Console Application). В одном из следующих окон не ставьте флажок Empty Project (пустой проект) и IDE сгенерирует заготовку программы.

    Если вы внимательно посмотрите на код файла имя_проекта.cpp, то вы обнаружите все вещи, которые мы обсуждали: структурную переменную MSG, заполнение структуры WNDCLASS, создание окна функцией CreateWindow, основной цикл программы. Кроме того, в файле определена функция WndProc. В ней происходит обработка нескольких сообщений в ветвях switch: WM_COMMAND, WM_PAINT, WM_DESTROY. Найдите всё это в файле.

    Кроме того что мы рассмотрели, в программе содержится много дополнительного кода. В следующем выпуске мы рассмотрим код программы, в котором будет вырезано всё лишнее. Он будет намного проще и понятнее того, что генерирует IDE.

    Илон Маск рекомендует:  Что такое код asp logodbctablename
    Понравилась статья? Поделиться с друзьями:
    Кодинг, CSS и SQL