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

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

Ответ 1

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

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

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

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

Ответ 2

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

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

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

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

Рассмотрим эти три различные внутренние реализации API Win32, которые я только что составил, и предположим, что 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 struct
  • код пользователя может потенциально изменять внутренние части возвращенной структуры Widget

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

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

Третий пример точно такой же, как второй, но мы просто вызываем void * a 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.

Ответ 3

A 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 означает "дескриптор окна".

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

Подробнее см. "Ручки и типы данных" .

Ответ 4

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

Ответ 5

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

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

Ответ 6

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

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

Ответ 7

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

Ответ 8

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