O que é uma maçaneta do Windows?

O que é um "manípulo" ao discutir recursos no Windows? Como funcionam?

Author: akashchandrakar, 2009-05-24

7 answers

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

apropriadamente , no Windows, (e geralmente em computação) um cabo é uma abstração que esconde um endereço de memória real do usuário da API, permitindo que o sistema reorganize a memória física de forma transparente para o programa. Resolver um manípulo em um ponteiro bloqueia a memória, e liberar o manípulo invalida o ponteiro. Neste caso, considere-o como um índice numa tabela de ponteiro... você usa o índice para as chamadas da API do sistema, e o sistema pode alterar o ponteiro na tabela à vontade.

Alternativamente, pode ser dado um ponteiro real como a pega quando o autor da API pretende que o Utilizador da API seja isolado das especificidades para que o endereço devolvido aponta; neste caso, deve considerar-se que o que a pega aponta pode mudar a qualquer momento (da versão da API para a versão ou mesmo da chamada para a chamada da API que devolve a pega) - a por conseguinte, o manípulo deve ser tratado simplesmente como um valor opaco significativo apenas para a API.

Devo acrescentar que em qualquer sistema operativo moderno, mesmo os chamados "ponteiros reais" ainda são opacos no espaço de memória virtual do processo, o que permite aos O/s gerir e reorganizar a memória sem invalidar os ponteiros dentro do processo.

 176
Author: Lawrence Dol, 2016-09-29 03:08:50

A HANDLE é um identificador único específico do contexto. Por contexto específico, quero dizer que um cabo obtido de um contexto não pode necessariamente ser usado em qualquer outro contexto aribtrary que também funciona em HANDLE S.

Por exemplo, GetModuleHandle devolve um identificador único a um módulo actualmente carregado. O manípulo devolvido pode ser usado em outras funções que aceitam manípulos. Não pode ser dada a funções que requerem outros tipos de pegas. Por exemplo, você não poderia dar uma alça regressou de GetModuleHandle para HeapDestroy e espera que faça algo sensato.

O HANDLE em si é apenas um tipo integral. Normalmente,mas não necessariamente, é um ponteiro para algum tipo subjacente ou localização da memória. Por exemplo, o HANDLE devolvido por GetModuleHandle é na verdade um ponteiro para o endereço de memória virtual base do módulo. Mas não há nenhuma regra que declare que as pegas devem ser ponteiros. Um cabo também poderia ser apenas um simples inteiro (que poderia ser usado por alguma API Win32 como um índice em matriz).

HANDLEs são representações intencionalmente opacas que fornecem encapsulação e abstração de recursos internos Win32. Desta forma, a APIs Win32 poderia potencialmente mudar o tipo subjacente por trás de uma pega, sem que isso impactasse 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 acabei de inventar, e assuma que Widget é uma 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 da API: permite ao código do utilizador saber que GetWidget devolve um ponteiro a struct Widget. Isto tem algumas consequências:

  • o código do utilizador deve ter acesso ao ficheiro header que define a estrutura Widget
  • o código do utilizador pode modificar partes internas da estrutura devolvida Widget

Ambas as consequências podem ser indesejáveis.

O segundo exemplo esconde este detalhe interno do Código do utilizador, retornando apenas void *. O código do utilizador não precisa de acesso ao cabeçalho que define a estrutura Widget.

O terceiro exemplo é exatamente o mesmo que o segundo, mas nós apenas chamamos o void * a {4]} em vez disso. Talvez isto desencoraje o código do usuário de tentar descobrir exatamente o que o void * aponta para.

Porque te dás a este trabalho? Considere Este quarto exemplo de uma versão mais recente desta mesma API:
typedef void * HANDLE;

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

    w = findImprovedWidget(name);

    return reinterpret_cast<HANDLE>(w);
}

Note que a interface da função é idêntica à terceiro exemplo acima. Isto significa que o código de usuário pode continuar a usar esta nova versão da API, sem quaisquer alterações, mesmo que a implementação "por trás das cenas" tenha mudado para usar a estrutura NewImprovedWidget em vez disso.

As pegas neste exemplo são realmente apenas um nome novo, presumivelmente amigável, para void *, que é exatamente o que um HANDLE está na API Win32 (procure-o em MSDN). Ele fornece uma parede opaca entre o código do Usuário e o interno da Biblioteca Win32 representações que aumentam a portabilidade, entre versões do Windows, do código que usa a API Win32.

 102
Author: Dan Moulding, 2016-01-22 13:56:40

Uma pega na programação Win32 é um token que representa um recurso que é gerenciado pelo kernel do Windows. Um cabo pode ser para uma janela, um arquivo, etc.

As pegas são simplesmente uma forma de identificar um recurso de partículas com o qual quer trabalhar usando a APIs Win32.

Por exemplo, se quiser criar uma janela e mostrá-la no ecrã, pode fazer o seguinte:
// Create the window
HWND hwnd = CreateWindow(...); 
if (!hwnd)
   return; // hwnd not created

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

No exemplo acima HWND significa "uma pega para uma janela".

Se estiver usado para uma linguagem orientada a objetos Você pode pensar em um punho como uma instância de uma classe sem métodos que o estado só é modificável por outras funções. Neste caso, a função ShowWindow modifica o estado da Pega Da Janela.

Ver Cabos e tipos de Dados para mais informações.

 39
Author: Nick Haddad, 2009-05-24 03:07:50

Um cabo é um identificador único para um objecto gerido pelo Windows. É {[[2]} como um ponteiro , mas não um ponteiro na condição de que não é um endereço que possa ser deslocado pelo código do utilizador para ter acesso a alguns dados. Em vez disso, um manípulo deve ser passado para um conjunto de funções que podem realizar ações sobre o objeto que o manípulo identifica.

 9
Author: sharptooth, 2009-05-25 04:26:45

Então, no nível mais básico, uma pega de qualquer tipo é um ponteiro para um ponteiro ou

#define HANDLE void **

Agora quanto ao porquê de querer usá-lo

Vamos fazer 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 o obj foi passado pelo valor (faça uma cópia e dê isso à função) para o foo, o printf irá imprimir o valor original de 1.

Agora se actualizarmos o foo para:

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

Existe a possibilidade de a printf imprimir o valor actualizado de 2. Mas há também a possibilidade de que foo causará alguma forma de corrupção de memória ou exceção.

A razão é esta, enquanto você está agora usando um ponteiro para passar o obj para a função que você também está alocando 2 Megs de memória, isso pode fazer com que o SO para mover a memória em torno da atualização da localização do obj. Uma vez que você passou o ponteiro pelo valor, se obj for movido, então o SO atualiza o ponteiro, mas não a cópia na função e potencialmente causando problemas.

Uma última actualização à foo de:

void foo(Object **bar){
    LargeObj lo = LargeObj();
    Object * b = &bar;
    b->val++;
}
Isto vai ... imprime sempre o valor actualizado.

Ver, quando o compilador aloca memória para ponteiros de marca-los como imóveis, de modo que qualquer re-embaralhar de memória causada por o grande objeto que está sendo atribuído o valor passado para a função irá apontar para o endereço correto para descobrir a localização final na memória para atualizar.

Qualquer tipo particular de Pegas (hWnd, arquivo, etc) são específicos de domínio e apontam para um certo tipo de estrutura para proteger contra a corrupção de memória.

 5
Author: , 2009-05-25 04:14:43

Um cabo é como um valor chave primário de um registo numa base de dados.

Edit 1: bem, porque é que o downvote, uma chave primária identifica unicamente um registo de banco de dados, e uma pega no sistema Windows identifica unicamente uma janela, um ficheiro aberto, etc, é o que estou a dizer.

 5
Author: Edwin Yip, 2014-04-03 15:05:41

Pense na janela do Windows como sendo uma estrutura que a descreve. Esta estrutura é uma parte interna do Windows e você não precisa saber os detalhes dela. Em vez disso, Windows fornece um typedef para o pointer para estruturar para essa struct. É o "cabo" pelo qual se pode agarrar na janela.,

 4
Author: Charlie Martin, 2009-05-24 02:57:16