пятница, 17 апреля 2009 г.

В чём разница между HINSTANCE и HMODULE?

Это перевод What is the difference between HINSTANCE and HMODULE? Автор: Реймон Чен.

Сегодня это одно и то же, но когда-то они обозначали разные вещи.

Это пришло к нам из 16-ти битных Windows.

В те дни, "модуль" (module) представлял файл на диске, который был загружен в память, и этот модуль имел "описатель" (handle), который указывал на структуру данных, описывающую части файла, откуда они взялись, откуда были загружены в память (если были загружены). С другой стороны, "экземпляр" (instance) представлял собой "набор переменных".

Аналогия, которая может пролить свет на это дело (или нет?): "модуль" - это как-бы код для класса в языке программирования; он описывает, как создать объект, как реализованы его методы, он описывает, как ведут себя объекты этого класса. С другой стороны, "экземпляр" - это как-бы конкретный объект, который является объектом какого-то класса; он описывает состояние конкретного экземпляра этого класса.

(Ну разве что модули не имеют вещей типа "статические методы", но всё равно это была довольно слабая аналогия).

Вот диаграмма (вспомните, что мы уже обсуждали 16-ти битный HRSRC ранее):

USER32 HMODULEUSER32 HINSTANCE
дескриптор сегмента кодаКод USER32...Данные USER32...
дескриптор сегмента кода(не в памяти)
дескриптор сегмента кодаКод USER32...
дескриптор сегмента данных
HRSRC(не в памяти)
HRSRCРесурсы USER32...
HRSRC(не в памяти)
таблица экспорта

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

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

В терминах гиков: был только один "экземпляр" (instance) DLL в системе.

С другой стороны, если вы запускали две копии Блокнота, каждая из них получала свой собственный набор переменных - это были два разных "экземпляра":

HMODULE БлокнотаHINSTANCE
дескриптор сегмента кодаКод Блокнота...Данные Блокнота...
дескриптор сегмента кода(не в памяти)
дескриптор сегмента данныхHINSTANCE
HRSRC(не в памяти)Данные Блокнота...
HRSRCРесурсы Блокнота...

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

Дескрипторы "экземпляров" (instance) в диаграммах выше являются сегментами данных.

Запущенные программы идентифицировались по их instance handle. Вы не могли использовать module handle, потому что две копии Блокнота имели один и тот же module handle (поскольку один и тот же код выполняется в обоих копиях). Штука, которая их отличала друг от друга - это их собственный набор переменных.

Вот почему функции WinExec и ShellExecute возвращают HINSTANCE: это рудимент 16-ти битных Windows, где HINSTANCE использовались для идентификации запущенных программ.

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

Когда пришло время проектировать Win32, возник вопрос: "что нам делать с HINSTANCE и HMODULE для Win32?". Поскольку программы теперь выполняются каждая в своём адресном пространстве, вам не нужно делать instance handle видимыми между процессами. Поэтому дизайнеры сделали единственную вещь, которая у них была: базовый адрес модуля. Это аналог HMODULE, поскольку файловый заголовок описывает содержимое файла и его структуру. Но он же является аналогом HINSTANCE, потому что данные хранятся в сегменте данных, который теперь проецируется в адресное пространство процесса напрямую.

Поэтому в Win32, HINSTANCE и HMODULE являются просто базовыми адресами модуля.

Завтра, я поговорю об этом загадочном параметре hinstPrev в WinMain.

Комментариев нет:

Отправить комментарий

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

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