Pregunta

¿Qué es un "identificador" cuando se habla de recursos en Windows?¿Cómo trabajan?

¿Fue útil?

Solución

Es un valor de referencia abstracto a un recurso, a menudo memoria, un archivo abierto o una tubería.

Adecuadamente, en Windows (y en general en informática), un identificador es una abstracción que oculta una dirección de memoria real al usuario de API, lo que permite al sistema reorganizar la memoria física de forma transparente para el programa.Resolver un identificador en un puntero bloquea la memoria y soltar el identificador invalida el puntero.En este caso, considérelo como un índice de una tabla de punteros...utiliza el índice para las llamadas a la API del sistema y el sistema puede cambiar el puntero en la tabla a voluntad.

Alternativamente, se puede proporcionar un puntero real como identificador cuando el autor de la API pretende que el usuario de la API esté aislado de los detalles específicos a los que apunta la dirección devuelta;en este caso se debe considerar que lo que apunta el identificador puede cambiar en cualquier momento (de una versión de API a otra o incluso de una llamada a otra de la API que devuelve el identificador); por lo tanto, el identificador debe tratarse simplemente como un valor opaco. significativo solo a la API.

Debo agregar que en cualquier sistema operativo moderno, incluso los llamados "punteros reales" siguen siendo identificadores opacos en el espacio de memoria virtual del proceso, lo que permite al sistema operativo administrar y reorganizar la memoria sin invalidar los punteros dentro del proceso. .

Otros consejos

A HANDLE es un identificador único específico del contexto. Por el contexto específico, quiero decir que un mango obtenido a partir de un contexto no necesariamente puede ser utilizado en cualquier otro contexto aribtrary que también trabaja en HANDLEs.

Por ejemplo, GetModuleHandle devuelve un identificador único para un módulo cargado actualmente. El manejador devuelto se puede utilizar en otras funciones que aceptan manijas de módulos. No se puede dar a las funciones que requieren otros tipos de mangos. Por ejemplo, no se podía dar un mango de regresar de GetModuleHandle a HeapDestroy y esperar que se hace algo razonable.

El HANDLE sí es sólo un tipo entero. Por lo general, pero no necesariamente, es un puntero a algún tipo de base o posición de memoria. Por ejemplo, el HANDLE devuelto por GetModuleHandle es en realidad un puntero a la dirección de memoria virtual de base del módulo. Pero no hay ninguna regla que indica que los mangos deben ser punteros. Un asa también podría ser simplemente un entero simple (que posiblemente podría ser utilizado por algunos API Win32 como un índice en una matriz).

HANDLEs son intencionalmente representaciones opacos que proporcionan la encapsulación y abstracción de los recursos de Win32 internos. De esta manera, las API de Win32 podría potencialmente cambiar el tipo subyacente detrás de un mango, sin que el código de usuario que impacta de ninguna manera (al menos esa es la idea).

Tenga en cuenta estas tres implementaciones internas diferentes de una API de Win32 que acabo de componer, y se supone que es un 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);
}

El primer ejemplo expone los detalles internos sobre el API: permite que el código de usuario sepa que GetWidget devuelve un puntero a una struct Widget. Esto tiene un par de consecuencias:

  • el código de usuario debe tener acceso al archivo de encabezado que define la estructura Widget
  • el código de usuario potencialmente podría modificar partes internas de la struct Widget devuelto

Tanto de estas consecuencias puede ser indeseable.

El segundo ejemplo se esconde este detalle interno del código de usuario, devolviendo simplemente void *. El código de usuario no necesita acceso a la cabecera que define la estructura Widget.

El tercer ejemplo es exactamente el mismo que el segundo, pero acabamos de llamar a la void * un HANDLE lugar. Tal vez esto desalienta código de usuario en tratar de averiguar exactamente cuáles son los puntos a void *.

¿Por qué pasar por este problema? Considere este cuarto ejemplo de una nueva versión de este mismo API:

typedef void * HANDLE;

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

    w = findImprovedWidget(name);

    return reinterpret_cast<HANDLE>(w);
}

Observe que la interfaz de la función es idéntica a la tercera ejemplo anterior. Esto significa que el código de usuario puede seguir utilizando esta nueva versión de la API, sin ningún cambio, a pesar de la implementación "entre bastidores" ha cambiado a utilizar la estructura NewImprovedWidget lugar.

Las asas en estos ejemplos son en realidad un nuevo, presumiblemente, más amigable, nombre para void *, que es exactamente lo que un HANDLE está en la API Win32 (mirar hacia arriba en MSDN ). Proporciona una pared opaca entre el código de usuario y representaciones internas de la biblioteca Win32 que aumenta la portabilidad, entre las versiones de Windows, de código que utiliza el API Win32.

Un MANGO en la programación Win32 es un símbolo que representa un recurso que es administrado por el núcleo de Windows. Un mango puede ser de una ventana, un archivo, etc.

Los mangos son simplemente una forma de identificar un recurso de partículas que se desea trabajar con el uso de la API de Win32.

Así por ejemplo, si desea crear una ventana, y mostrarlo en la pantalla que podría hacer lo siguiente:

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

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

En el ejemplo anterior HWND significa "un identificador a una ventana".

Si estás acostumbrado a un lenguaje orientado a objetos se puede pensar en un mango como una instancia de una clase sin métodos que el estado sólo es modificable por otras funciones. En este caso, el ShowWindow función modifica el estado del identificador de ventana.

y tipos de datos para obtener más información.

Un identificador es un identificador único para un objeto gestionado por Windows. Es como un puntero , pero no un puntero en el SENCE que no es una dirección que ha podido obtener mediante código de usuario para acceder a algunos datos. En lugar de un mango se va a pasar a un conjunto de funciones que pueden realizar acciones sobre el objeto identifica el mango.

Un mango es como un valor de clave principal de un registro en una base de datos.

editar 1: así, por qué el downvote, una clave principal identifica de forma única un registro de base de datos, y un mango en el sistema de Windows identifica de manera única una ventana, un archivo abierto, etc, eso es lo que estoy diciendo

.

Así que en el nivel más básico de un mango de cualquier tipo es un puntero a un puntero o

#define HANDLE void **

Ahora en cuanto a por qué usted quiere usarlo

Vamos a tomar una configuración:

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);
}

Así pues obj se pasan por valor (hacer una copia y que dará a la función) a foo, el printf imprimirá el valor original de 1.

Ahora bien, si actualizamos a foo:

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

Hay una posibilidad de que el printf se imprimirá el valor actualizado de 2. Pero también existe la posibilidad de que fu causará algún tipo de corrupción de memoria o una excepción.

La razón es la siguiente, mientras que ahora está usando un puntero para pasar obj a la función que también se están asignando 2 megas de memoria, esto podría hacer que el sistema operativo para mover la memoria en torno a la actualización de la ubicación de obj. Puesto que usted ha pasado el puntero por valor, si obj consigue movida entonces el sistema operativo actualiza el puntero, pero no la copia en la función y los problemas que podían causar.

Una última actualización de foo de:

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

Esto imprimirá siempre el valor actualizado.

Vea, cuando el compilador asigna memoria para los punteros que los marca como inmuebles, por lo que cualquier re-barajar de la memoria causado por el gran objeto que se asigna el valor pasado a la función apuntará a la dirección correcta para averiguar la ubicación final en la memoria para actualizar.

Cualquier tipos particulares de asas (hWnd, archivo, etc.) son de dominio específico y apuntan a un cierto tipo de estructura para proteger contra la corrupción de la memoria.

Piense en la ventana en Windows como una estructura que lo describe. Esta estructura es una parte interna de Windows y no necesita conocer los detalles de la misma. En su lugar, Windows proporciona un typedef para el puntero a struct para esa estructura. Esa es la "manija" por el cual se puede conseguir en la ventana.,

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top