Compartilhar via


Creating, Registering, and Using a Handle-based API Set

Windows Mobile Not SupportedWindows Embedded CE Supported

9/8/2008

Um servidor identificador nunca gerencia alças diretamente. O servidor identificador deve fornecer um conjunto de funções e o tipo de identificador para o kernel, e o kernel gerencia o resto.

Criando e Registering um conjunto API Handle-based

Para que qualquer processo possa se tornar um servidor identificador, ele deve criar e registrar um API handle-Based definido com o seguinte funções:

Para criar um novo identificador para um objeto, o servidor deve chamar a função CreateAPIHandle. Para transmitir o identificador para outro processo, o servidor deve chamar a função DuplicateHandle. Além disso, o servidor deve usar a função CloseHandle para fechar sua própria referência para o identificador criado pelo CreateAPIHandle ou transmitir DUPLICATE_CLOSE_SOURCE para DuplicateHandle. Para acessar de forma assíncrona deve o servidor o identificador, chamar LockAPIHandle e UnlockAPIHandle Para que o identificador não está fechada in the middle of o operação assíncrona.

Os descritores de Parâmetro API

A seguinte tabela descreve os descritores de parâmetros API.

Descritor Descrição

DW

4-escalar bit.

I_PTR

Ponteiro para uma reserva Input-only. O tamanho consta o próximo parâmetro.

I_WSTR

Ponteiro para uma Input-only seqüência de caracteres Unicode.

I_ASTR

Ponteiro para uma Input-only seqüência de caracteres ASCII.

O_PTR

Ponteiro para uma reserva Output-only. O tamanho consta o próximo parâmetro.

O_PDW

Ponteiro para uma reserva Output-only, 4 bytes em tamanho.

O_PI64

Ponteiro para uma reserva Output-only, 8 bytes em tamanho.

IO_PTR

Ponteiro para uma reserva In/Out. O tamanho consta o próximo parâmetro.

IO_PDW

Ponteiro para uma reserva in/out, 4 bytes em tamanho.

IO_PI64

Ponteiro para uma reserva in/out, 8 bytes em tamanho.

Observação

Ao implementar um usuário-modo servidor, nenhum ponteiro que pode ser acessado de forma assíncrona deve ser descrita como um escalar DW.Isso desativa a verificação automático de acesso e empacotamento que é feito no parâmetro.Em vez disso, o usuário-modo servidor deve chamar o CeOpenCallerBuffer e CeAllocAsynchronousBuffer auxiliares para executar o Access-checking e empacotamento.Isso garante que o empacotamento permanecerá válido depois de chamar API retorna.O retorno API seria caso contrário destruir a memória duplicada ou alias.

O seguinte é algumas ramificações de assinatura:

  • Porque há um limite de parâmetros 13 (FNSIG13), é possível que você terá que consolidar parâmetros escalares em uma estrutura que é passada por um ponteiro, instead of passando um grande número de argumentos escalares. Você nunca precisará exceder parâmetros 13. Apenas uma API que leva os ponteiros reserva 7 ou mais e, portanto, precisa tamanhos reserva 7 ou mais, excederia parâmetros 13.
  • O limite de parâmetros ponteiro 6 se aplica a ambos os ponteiros de tamanho fixo (O_PDW, IO_PDW, O_PI64 e IO_PI64), ponteiros de explicitamente especificado tamanho (I_PTR, IO_PTR e O_PTR) e buffers seqüência de caracteres (I_WSTR e I_ASTR).
  • Se seu API aceita parâmetros reserva com ponteiros interno, você pode localizá-la útil para mover aqueles em primário parâmetros para o API. Em seguida, o parâmetro automática empacotamento e validação feita pelo kernel irão salvar você algum trabalho.

Usando uma tabela do método mala direta

Um kernel-modo servidor também pode registrar uma segunda tabela dos ponteiros função a ser usado para chamadas internas feita por outro kernel-modo servidores. Este registro é executado com o RegisterDirectMethods função. Se nenhum direcionar tabela método está registrada, todas as chamadas internas são roteadas por meio de externo tabela fornecida para CreateAPISet. Se qualquer entrada na direcionar-chamar API conjunto é NULL, que API não é que pode ser chamado pelo dentro de kernel. Se qualquer entrada no externo é tabela NULL, que API não é que pode ser chamado por outros processos.

O externo função faz o seguinte:

  • A verificação de acesso, empacotamento e Seguro-copiar operações que devem ser feitas em ponteiros chamador.
  • Atribuindo alças, pseudo-Handles e outros recursos que são pertencentes um processo específico para o processo chamador.
  • Qualquer operação que envolva GetCallerProcess. O externo função pode chamar GetCallerProcess, enquanto que interno chama GetCurrentProcess.
  • Chamar a função interna, ou alguns outro de trabalho, para fazer o real trabalho.

A função interna faz o seguinte:

  • Tudo, incluindo qualquer privilégio verifica. As verificações devem ter como base o privilégio do atual segmento, não a nível de confiabilidade do processo chamador.

Se ele for muito complexa para executar todas as gerenciamento de empacotamento ou identificador no externo função, você pode implementar o API, fazendo com que o externo e chamar funções internas um comum função de trabalho, passando um sinalizador para dizer se originou a chamar externamente.

Usando um conjunto API Handle-based

A chamar para CreateAPIHandle associa o objeto identificador de conjunto API e retorna um identificador para o objeto. Daí em diante, o identificador identifica com exclusividade pMyObject e o conjunto API usado para manipular pMyObject. Funções na tabela de função não recebem o identificador como um parâmetro, mas receber o objeto diretamente. Em qualquer dessas funções, você pode usar o objeto identificador e ele não é destruído durante o chamada de função, a menos que você destrui-lo. As chamadas para CALLMYREAD e CALLMYWRITE são geralmente exportações de Coredll, onde um chamar API para o kernel é feita. O kernel, em seguida, decodifica o identificador, bloqueios, se necessário e chama o correspondente funções na tabela de função.

O seguinte exemplo de código mostra como um servidor identificador cria e registra um conjunto API alça-com:

// Function table of “my handle”
// Index 0 is called when the handle is to be destroyed. Index 1 is for “pre-close”. Called when the last actual reference is closed (but still in use).
const PFNVOID ppfnMethods [] ={ (PFNVOID) MyDestroyObject, (PFNVOID) MyPreCloseHandle, (PFNVOID) MyRead, (PFNVOID) MyWrite};
// The function signature here matches the parameters of the MyRead function. The first parameter of every function in a handle-based API set is the object the handle refers to.
// Signatures of the functions
const ULONGLONG pu64Sigs [] = { FNSIG1 (DW), FNSIG1 (DW), FNSIG3 (DW, O_PTR, DW), FNSIG3 (DW, I_PTR, DW) };
BOOL MyRead (PMYOBJECT pObj, LPBYTE pbuf, DWORD cbSize)
{
}
BOOL MyWrite (PMYOBJECT pObj, const BYTE *pbuf, DWORD cbSize)
{
}
BOOL MyDestroyObject (PMYOBJECT pObj)
{
   LocalFree (pObj);
}
BOOL MyPreCloseHandle (PMYOBJECT pObj)
{
// The primary purpose of the pre-close operation is to force any asynchronous operations on the handle to complete, so that the last references to the handle are cleaned up when the handle is closed. If your API set does not perform any asynchronous operations on the open handles, then you may not need to implement a pre-close operation
}
// Sample program
// ID (Note, 128 APIsets supported)
#define  ID_MYAPI 0x30
// The type cast helps check that callers pass the right arguments. The arguments listed are those that are passed to MyRead, with the exception that the PMYOBJECT is replaced by a handle since callers pass a handle while MyRead receives the object data buffer. ID_MYAPI identifies the API set, while "2" is the index of the MyRead function in the ppfnMethods table.
#define CALLMYREAD(hObject, pReadBuf, cbReadBuf) (*(BOOL (*) (HANDLE, LPBYTE, DWORD) IMPLICIT_CALL(ID_MYAPI, 2))
#define CALLMYWRITE(hObject, pWriteBuf, cbWriteBuf) (*(BOOL (*) (HANDLE, const BYTE*, DWORD) IMPLICIT_CALL(ID_MYAPI, 3))
void HandleSample (void)
{
   // Create the API set.
   HANDLE hAPISet = CreateAPISet (“MINE”, 4, ppfnMethods, ppfnMyWrite);
   // Register the API set.
   if (!hAPISet || !RegisterAPISet (hAPISet, ID_MYAPI | REGISTER_APISET_TYPE))
   {
      // Error
      return;
   }
   // Create my own handle object.
   PMYOBJECT pHandleObject = (PMYOBJECT) LocalAlloc (sizeof (MYOBJECT));
   InitializeMyObject (pHandleObject);
   // Create the handle associated with my handle object.
   HANDLE hMyHandle = CreateAPIHandle (hAPISet, pHandleObject);
   // Prepare a handle to pass to the target application, and close the server's reference to the object.
   HANDLE hAppHandle = DuplicateHandle (hMyHandle, ..., DUPLICATE_CLOSE_SOURCE);
   // Now pass hAppHandle to the application.
}

O seguinte amostra de código mostra codificar que chama in para o servidor identificador:

BYTE buf[100];
// Call the server to get a handle
HANDLE hObject = ...
// The exact method in the server that opens the handle is not demonstrated here.
// The server could be a driver which opens the handle during a particular IOCTL. It could be a driver or  a user mode process that opens the handle during some other inter-process communication method, like in response to a point-to-point message queue message or window message. It could be a handle open API that is implemented via a non handle-based API set.
// Call the read method.
CALLMYREAD (hObject, buf, 100);
// Call the write method.
CALLMYWRITE (hObject, buf, 100);
// Close the handle.
CloseHandle (hObject); 
// call the ReadMethod
CALLMYREAD (hMyHandle, buf, 100);
// Close the handle, will trigger MyPreCloseHandle and MyCloseHandle.
CloseHandle (hMyHandle);

See Also

Concepts

System Calls
Handle Tables: Windows CE 5.0 vs. Windows Embedded CE 6.0

Other Resources

DuplicateHandle
CloseHandle