Gravando drivers de áudio de 64 bits
Se você estiver escrevendo um driver de 64 bits ou escrevendo um driver que possa ser compilado para ser executado em sistemas de 32 e 64 bits, siga as diretrizes de portabilidade em Técnicas de Programação de Driver. Algumas das armadilhas que você pode encontrar ao escrever um driver de áudio de 64 bits são descritas abaixo.
Em primeiro lugar, um problema potencial a ser buscado no código do driver de 32 bits existente é a conversão entre tipos de ponteiro e tipos inteiros, como DWORD ou ULONG. Programadores com experiência para escrever código para computadores de 32 bits podem ser usados para assumir que um valor de ponteiro se encaixe em um DWORD ou ULONG. Para código de 64 bits, essa suposição é perigosa. Converter um ponteiro para digitar DWORD ou ULONG pode fazer com que um ponteiro de 64 bits seja truncado. Uma abordagem melhor é converter o ponteiro para digitar DWORD_PTR ou ULONG_PTR. Um inteiro sem sinal do tipo DWORD_PTR ou ULONG_PTR é sempre grande o suficiente para armazenar todo o ponteiro, independentemente de o código ser compilado para um computador de 32 ou 64 bits.
Por exemplo, o campo de ponteiro IRP IoStatus. As informações são do tipo ULONG_PTR. O código a seguir mostra o que não fazer ao copiar um valor de ponteiro de 64 bits para este campo:
PDEVICE_RELATIONS pDeviceRelations;
Irp->IoStatus.Information = (ULONG)pDeviceRelations; // wrong
Este exemplo de código converte erroneamente o pDeviceRelations
ponteiro para o tipo ULONG, que pode truncar o valor do ponteiro se sizeof(pDeviceRelations) > sizeof(ULONG)
. A abordagem correta é converter o ponteiro para ULONG_PTR, conforme mostrado no seguinte:
PDEVICE_RELATIONS pDeviceRelations;
Irp->IoStatus.Information = (ULONG_PTR)pDeviceRelations; // correct
Isso preserva todos os 64 bits do valor do ponteiro.
Uma lista de recursos armazena o endereço físico de um recurso em uma estrutura do tipo PHYSICAL_ADDRESS (consulte IResourceList). Para evitar truncar um endereço de 64 bits, você deve acessar o membro QuadPart da estrutura em vez de seu membro LowPart ao copiar um endereço para a estrutura ou ler um endereço da estrutura. Por exemplo, a macro FindTranslatedPort retorna um ponteiro para uma estrutura CM_PARTIAL_RESOURCE_DESCRIPTOR que contém o endereço base de uma porta de E/S. O u. Porta. O membro inicial dessa estrutura é um ponteiro PHYSICAL_ADDRESS para o endereço base. O código a seguir mostra o que não fazer:
PUSHORT pBase = (PUSHORT)FindTranslatedPort(0)->u.Port.Start.LowPart; // wrong
Novamente, isso pode truncar o ponteiro. Em vez disso, você deve acessar o QuadPart deste membro, conforme mostrado no seguinte:
PUSHORT pBase = (PUSHORT)FindTranslatedPort(0)->u.Port.Start.QuadPart; // correct
Isso copia todo o ponteiro de 64 bits.
Funções Win64 embutidas, como PtrToUlong e UlongToPtr, convertem com segurança entre tipos de ponteiro e inteiro sem depender de suposições sobre os tamanhos relativos desses tipos. Se um tipo for menor que o outro, ele deverá ser estendido ao converter para o tipo mais longo. Se o tipo mais curto é estendido preenchendo com o bit de sinal ou com zeros está bem definido para cada função Win64. Isso significa que todos os snippets de código, como
ULONG ulSlotPhysAddr[NUM_PHYS_ADDRS];
ulSlotPhysAddr[0] = ULONG(pulPhysDmaBuffer) + DMA_BUFFER_SIZE; // wrong
deve ser substituído por
ULONG_PTR ulSlotPhysAddr[NUM_PHYS_ADDRS];
ulSlotPhysAddr[0] = PtrToUlong(pulPhysDmaBuffer) + DMA_BUFFER_SIZE; // correct
Isso é preferencial, embora ulSlotPhysAddr
possa representar o valor de um registro de hardware com apenas 32, em vez de 64 bits de comprimento. Para obter uma lista de todas as novas funções auxiliares do Win64 para converter entre tipos de ponteiro e inteiro, consulte Os Novos Tipos de Dados.