Что такое дескриптор Windows?

Что такое "дескриптор" при обсуждении ресурсов в Windows? Как они работают?

7 ответов

Решение

Это абстрактная ссылка на ресурс, часто в память, открытый файл или канал.

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

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

Я должен добавить, что в любой современной операционной системе даже так называемые "настоящие указатели" по-прежнему являются непрозрачными дескрипторами в пространстве виртуальной памяти процесса, что позволяет операционным системам управлять и переставлять память без аннулирования указателей в процессе.,

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

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

HANDLE Сам по себе просто интегральный тип. Обычно, но не обязательно, это указатель на некоторый базовый тип или область памяти. Например, HANDLE вернулся GetModuleHandle фактически является указателем на базовый адрес виртуальной памяти модуля. Но нет правила, утверждающего, что дескрипторы должны быть указателями. Дескриптор также может быть простым целым числом (которое может быть использовано некоторыми Win32 API в качестве индекса в массиве).

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

Рассмотрим эти три различные внутренние реализации Win32 API, которые я только что составил, и предположим, что Widget это struct,

Widget * GetWidget (std::string name)
{
    Widget *w;

    w = findWidget(name);

    return w;
}
void * GetWidget (std::string name)
{
    Widget *w;

    w = findWidget(name);

    return reinterpret_cast<void *>(w);
}
typedef void * HANDLE;

HANDLE GetWidget (std::string name)
{
    Widget *w;

    w = findWidget(name);

    return reinterpret_cast<HANDLE>(w);
}

В первом примере раскрываются внутренние подробности об API: он позволяет пользовательскому коду знать, что GetWidget возвращает указатель на struct Widget, Это имеет несколько последствий:

  • код пользователя должен иметь доступ к заголовочному файлу, который определяет Widget структура
  • пользовательский код может потенциально изменить внутренние части возвращаемого Widget структура

Оба эти последствия могут быть нежелательными.

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

Третий пример точно такой же, как и второй, но мы просто называем void * HANDLE вместо. Возможно, это препятствует тому, чтобы пользовательский код пытался выяснить, что именно void * указывает на.

Зачем переживать эту проблему? Рассмотрим этот четвертый пример более новой версии этого же API:

typedef void * HANDLE;

HANDLE GetWidget (std::string name)
{
    NewImprovedWidget *w;

    w = findImprovedWidget(name);

    return reinterpret_cast<HANDLE>(w);
}

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

Дескрипторы в этом примере на самом деле просто новое, по-видимому, более дружелюбное название void *что именно то, что HANDLE находится в Win32 API (посмотрите на MSDN). Он обеспечивает непрозрачную стену между пользовательским кодом и внутренними представлениями библиотеки Win32, что увеличивает переносимость между версиями Windows кода, использующего Win32 API.

РУЧКА в программировании Win32 - это токен, представляющий ресурс, которым управляет ядро ​​Windows. Дескриптор может быть окном, файлом и т. Д.

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

Например, если вы хотите создать окно и показать его на экране, вы можете сделать следующее:

// Create the window
HWND hwnd = CreateWindow(...); 
if (!hwnd)
   return; // hwnd not created

// Show the window.
ShowWindow(hwnd, SW_SHOW);

В приведенном выше примере HWND означает "дескриптор окна".

Если вы привыкли к объектно-ориентированному языку, вы можете думать о HANDLE как об экземпляре класса без методов, чье состояние может быть изменено только другими функциями. В этом случае функция ShowWindow изменяет состояние окна HANDLE.

Посмотрите Ручки и Типы данных для получения дополнительной информации.

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

Таким образом, на самом базовом уровне РУЧКА любого рода - это указатель на указатель или

#define HANDLE void **

Теперь о том, почему вы хотели бы использовать его

Давайте сделаем настройку:

class Object{
   int Value;
}

class LargeObj{

   char * val;
   LargeObj()
   {
      val = malloc(2048 * 1000);
   }

}

void foo(Object bar){
    LargeObj lo = new LargeObj();
    bar.Value++;
}

void main()
{
   Object obj = new Object();
   obj.val = 1;
   foo(obj);
   printf("%d", obj.val);
}

Так как obj был передан по значению (сделайте копию и передайте это функции) в foo, printf напечатает исходное значение 1.

Теперь, если мы обновим foo до:

void foo(Object * bar)
{
    LargeObj lo = new LargeObj();
    bar->val++;
}

Есть вероятность, что printf напечатает обновленное значение 2. Но также существует вероятность того, что foo вызовет некоторую форму повреждения памяти или исключения.

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

Последнее обновление для foo:

void foo(Object **bar){
    LargeObj lo = LargeObj();
    Object * b = &bar;
    b->val++;
}

Это всегда будет печатать обновленное значение.

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

Любые конкретные типы HANDLE (hWnd, FILE и т. Д.) Зависят от домена и указывают на определенный тип структуры для защиты от повреждения памяти.

Дескриптор подобен значению первичного ключа записи в базе данных.

edit 1: хорошо, почему downvote, первичный ключ однозначно идентифицирует запись в базе данных, а дескриптор в системе Windows однозначно идентифицирует окно, открытый файл и т. д. Это то, что я говорю.

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

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

Другие вопросы по тегам