Pergunta

O que é um "punho" quando se discute recursos no Windows? Como eles funcionam?

Foi útil?

Solução

É um valor de referência abstrata para um recurso, muitas vezes de memória ou um arquivo aberto, ou um cachimbo.

corretamente , no Windows, (e geralmente em computação) uma alça é uma abstração que esconde um endereço de memória real do usuário API, permitindo que o sistema para reorganizar a memória física de forma transparente para o programa. Resolvendo uma pega para um ponteiro bloqueia a memória, e soltar a pega invalida o ponteiro. Neste caso, pense nisso como um índice em uma tabela de ponteiros ... você usa o índice para as chamadas de API do sistema, e o sistema pode alterar o ponteiro na tabela à vontade.

Como alternativa um ponteiro real pode ser dado como a alça quando o escritor API pretende que o usuário da API ser isolados a partir das especificidades do que o endereço retornado pontos para; neste caso, deve-se considerar que o que pontos a alça para pode mudar a qualquer momento (a partir da versão API para a versão ou mesmo de chamada para chamada da API que retorna o identificador) - a alça deve, portanto, ser tratado simplesmente como um valor opaco significativa única para o API.

Devo acrescentar que em qualquer sistema operacional moderno, mesmo os chamados "ponteiros reais" ainda são pegas opacos para o espaço de memória virtual do processo, o que permite que o O / S para gerenciar e memória reorganizar sem invalidar os ponteiros dentro do processo.

Outras dicas

A HANDLE é um identificador exclusivo de contexto específico. Pelo contexto específico, quero dizer que uma alça obtida a partir de um contexto não pode necessariamente ser usado em qualquer outro contexto aribtrary que também funciona em HANDLEs.

Por exemplo, GetModuleHandle retorna um identificador único para um módulo carregado no momento. O identificador retornado pode ser usado em outras funções que aceitam manípulos do módulo. Não pode ser dada para funções que exigem outros tipos de pegas. Por exemplo, você não poderia dar um identificador retornado de GetModuleHandle para HeapDestroy e espera que ele faça algo sensato.

O HANDLE em si é apenas um tipo integral. Normalmente, mas não necessariamente, é um ponteiro para alguns subjacente tipo ou posição de memória. Por exemplo, o HANDLE retornado por GetModuleHandle é realmente um ponteiro para o endereço de memória virtual base do módulo. Mas não há nenhuma regra afirmando que trata deve ser ponteiros. Um identificador pode também ser apenas um número inteiro simples (que poderia ser utilizada por alguns API Win32 como um índice para uma matriz).

HANDLEs são intencionalmente representações opacos que proporcionam encapsulamento e abstração de recursos internos Win32. Desta forma, o APIs Win32 poderia potencialmente alterar o tipo subjacente a uma alça, sem ele impactando o código do usuário de qualquer forma (pelo menos essa é a idéia).

Considere estas três implementações internas diferentes de uma API Win32 que eu acabei de inventar, e assumir que Widget é um 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);
}

O primeiro exemplo expõe os detalhes internos sobre a API: permite o código de utilizador saber que GetWidget retorna um ponteiro para um struct Widget. Isto tem um par de conseqüências:

  • o código de usuário deve ter acesso ao arquivo de cabeçalho que define a Widget struct
  • o código de utilizador poderia modificar partes internas do Widget struct
  • retornou

Ambas as conseqüências podem ser indesejáveis.

O segundo exemplo esconde esse detalhe interno do código do usuário, retornando apenas void *. O código de utilizador não necessita de acesso ao cabeçalho que define a estrutura Widget.

O terceiro exemplo é exatamente o mesmo que o segundo, mas apenas chamar a void * um HANDLE vez. Talvez este código de usuário desencoraja a tentar descobrir exatamente o que os pontos void * a.

Por que passar por este problema? Considere este quarto exemplo de uma nova versão deste mesmo API:

typedef void * HANDLE;

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

    w = findImprovedWidget(name);

    return reinterpret_cast<HANDLE>(w);
}

Observe que a interface de função é idêntica à do terceiro exemplo acima. Isto significa que o código do usuário pode continuar a usar esta nova versão da API, sem quaisquer alterações, embora a implementação "nos bastidores" mudou para usar o struct NewImprovedWidget vez.

As alças nestes exemplo são realmente apenas uma presumivelmente mais amigável, nome novo, para void *, que é exatamente o que um HANDLE está na API Win32 (procurá-lo no MSDN ). Ele fornece uma parede opaca entre o código de utilizador e representações internas da biblioteca Win32 que a portabilidade aumenta, entre versões do Windows, de código que usa a API Win32.

A PUNHO na programação Win32 é um símbolo que representa um recurso que é gerenciado pelo kernel do Windows. Um identificador pode ser uma janela, um arquivo, etc.

alças são simplesmente uma maneira de identificar um recurso particulado que você quer trabalhar com a utilização das APIs do Win32.

Assim, por exemplo, se você quer criar uma janela, e mostrá-lo na tela, você pode fazer o seguinte:

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

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

Nos meios exemplo HWND acima "um identificador para uma janela".

Se você está acostumado a uma linguagem orientada a objetos que você pode pensar de uma alça como uma instância de uma classe sem métodos que seu estado só é modificável por outras funções. Neste caso, o ShowWindow modifica função do estado do identificador de janela.

e tipos de dados para mais informações.

Um identificador é um identificador exclusivo para um objeto gerenciado pelo Windows. É de como um ponteiro , mas não um ponteiro no sence que não é um endereço que poderia ser dereferenced pelo código do usuário para ter acesso a alguns dados. Em vez de uma alça é para ser passado para um conjunto de funções que podem executar ações no objeto os identifica punho.

A alça é como um valor de chave primária de um registro em um banco de dados.

Editar 1:. Bem, por que o downvote, uma chave primária identifica exclusivamente um registro de banco de dados, e uma alça no sistema Windows exclusivamente identifica uma janela, um arquivo aberto, etc, É o que eu estou dizendo

Assim, no nível mais básico uma alça de qualquer tipo é um ponteiro para um ponteiro ou

#define HANDLE void **

Agora, por que motivo você iria querer usá-lo

Vamos dar uma configuração:

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

Então porque obj foi passada por valor (fazer uma cópia e dar isso para a função) para foo, o printf irá imprimir o valor original do 1.

Agora, se nós atualizamos foo para:

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

Há uma chance de que o printf irá imprimir o valor atualizado de 2. Mas também existe a possibilidade de que foo irá causar alguma forma de corrupção de memória ou exceção.

A razão é esta, enquanto você está usando agora um ponteiro para passar obj para a função que também estão alocando 2 megas de memória, isso poderia fazer com que o OS para mover a memória em torno de atualizar a localização do obj. Desde que você passou o ponteiro por valor, se obj é movido, em seguida, o sistema operacional atualiza o ponteiro, mas não a cópia na função e problemas potencialmente causando.

A atualização final para foo de:

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

Esta será sempre imprimir o valor atualizado.

Veja, quando o Aloca memória compilador para ponteiros ele marca como imóveis, de modo que qualquer re-baralhar de memória causada pelo grande objeto que está sendo alocado o valor passado para a função irá apontar para o endereço correto para descobrir a localização final na memória para atualização.

Qualquer tipos particulares de alças (hWnd, o FILE, etc.) são específicos de domínio e apontar para um certo tipo de estrutura para proteger contra a corrupção de memória.

Pense na janela no Windows como sendo um struct que o descreve. Esta estrutura é uma parte interna do Windows e você não precisa conhecer os detalhes do mesmo. Em vez disso, o Windows fornece um typedef para ponteiro para struct para esse struct. Essa é a "alça", pelo qual você pode se apossar na janela.,

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top