Вопрос

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

Это было полезно?

Решение

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

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

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

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

Другие советы

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

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

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

HANDLEs — это намеренно непрозрачные представления, обеспечивающие инкапсуляцию и абстракцию от внутренних ресурсов Win32.Таким образом, API-интерфейсы Win32 потенциально могут изменить базовый тип, лежащий в основе 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.

HANDLE в программировании Win32 — это токен, представляющий ресурс, управляемый ядром Windows.Дескриптор может относиться к окну, файлу и т. д.

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

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

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

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

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

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

Видеть Дескрипторы и типы данных Чтобы получить больше информации.

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

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

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

Таким образом, на самом базовом уровне любой тип HANDLE является указателем на указатель или

#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 и т. д.) зависят от домена и указывают на определенный тип структуры для защиты от повреждения памяти.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top