Regras para usar ponteiros

Portar seu código para compilar para o Microsoft Windows de 32 e 64 bits é simples. Você precisa seguir apenas algumas regras simples sobre a conversão de ponteiros e usar os novos tipos de dados em seu código. As regras para manipulação de ponteiro são as seguintes.

  1. Não converta ponteiros para int, long, ULONG ou DWORD.

    Se você precisar converter um ponteiro para testar alguns bits, definir ou limpar bits ou manipular seu conteúdo, use o tipo UINT_PTR ou INT_PTR . Esses tipos são tipos integrais que dimensionam para o tamanho de um ponteiro para Windows de 32 e 64 bits (por exemplo, ULONG para Windows de 32 bits e _int64 para Windows de 64 bits). Por exemplo, suponha que você esteja portando o seguinte código:

    ImageBase = (PVOID)((ULONG)ImageBase | 1);

    Como parte do processo de portabilidade, você alteraria o código da seguinte maneira:

    ImageBase = (PVOID)((ULONG_PTR)ImageBase | 1);

    Use UINT_PTR e INT_PTR quando apropriado (e se você não tiver certeza se eles são necessários, não haverá nenhum dano em usá-los apenas no caso). Não converta seus ponteiros para os tipos ULONG, LONG, INT, UINT ou DWORD.

    Observe que HANDLE é definido como um void*, portanto, digitar um valor HANDLE para um valor ULONG para testar, definir ou limpar os 2 bits de ordem baixa é um erro no Windows de 64 bits.

  2. Use a função PtrToLong ou PtrToUlong para truncar ponteiros.

    Se você precisar truncar um ponteiro para um valor de 32 bits, use a função PtrToLong ou PtrToUlong (definida em Basetsd.h). Essas funções desabilitam o aviso de truncamento de ponteiro durante a chamada.

    Use essas funções com cuidado. Depois de converter uma variável de ponteiro usando uma dessas funções, nunca mais use-a como um ponteiro. Essas funções truncam os 32 bits superiores de um endereço, que geralmente são necessários para acessar a memória referenciada originalmente por ponteiro. Usar essas funções sem consideração cuidadosa resultará em um código frágil.

  3. Tenha cuidado ao usar POINTER_32 valores no código que podem ser compilados como código de 64 bits. O compilador assinará e estenderá o ponteiro quando ele for atribuído a um ponteiro nativo no código de 64 bits, e não estenderá o ponteiro.

  4. Tenha cuidado ao usar POINTER_64 valores no código que podem ser compilados como código de 32 bits. O compilador assinará e estenderá o ponteiro no código de 32 bits, e não estenderá o ponteiro.

  5. Tenha cuidado ao usar parâmetros OUT.

    Por exemplo, suponha que você tenha uma função definida da seguinte maneira:

    void func( OUT PULONG *PointerToUlong );

    Não chame essa função da seguinte maneira.

    ULONG ul;
    PULONG lp;
    func((PULONG *)&ul);
    lp = (PULONG)ul;
    

    Em vez disso, use a chamada a seguir.

    PULONG lp;
    func(&lp);
    

    O typecasting &ul to PULONG* impede um erro do compilador, mas a função gravará um valor de ponteiro de 64 bits na memória em &ul. Esse código funciona no Windows de 32 bits, mas causará corrupção de dados no Windows de 64 bits e será uma corrupção sutil e difícil de encontrar. A linha de fundo: não faça truques com o código C — simples e simples é melhor.

  6. Tenha cuidado com interfaces polimórficas.

    Não crie funções que aceitem parâmetros DWORD para dados polimórficos. Se os dados puderem ser um ponteiro ou um valor integral, use o tipo UINT_PTR ou PVOID .

    Por exemplo, não crie uma função que aceite uma matriz de parâmetros de exceção digitado como valores DWORD . A matriz deve ser uma matriz de valores DWORD_PTR . Portanto, os elementos da matriz podem conter endereços ou valores integrais de 32 bits. (A regra geral é que, se o tipo original for DWORD e precisar ser largura do ponteiro, converta-o em um valor DWORD_PTR . É por isso que há tipos de precisão de ponteiro correspondentes.) Se você tiver um código que usa DWORD, ULONG ou outros tipos de 32 bits de maneira polimórfica (ou seja, você realmente deseja que o parâmetro ou membro da estrutura mantenha um endereço), use UINT_PTR no lugar do tipo atual.

  7. Use as novas funções de classe de janela.

    Se você tiver dados privados de janela ou classe que contenham ponteiros, seu código precisará usar as seguintes novas funções:

    Essas funções podem ser usadas no Windows de 32 e 64 bits, mas são necessárias no Windows de 64 bits. Prepare-se para a transição usando essas funções agora.

    Além disso, você deve acessar ponteiros ou identificadores em dados privados de classe usando as novas funções no Windows de 64 bits. Para ajudá-lo a encontrar esses casos, os seguintes índices não são definidos em Winuser.h durante uma compilação de 64 bits:

    • GWL_WNDPROC
    • GWL_HINSTANCE
    • GWL_HWNDPARENT
    • GWL_USERDATA

    Em vez disso, Winuser.h define os seguintes novos índices:

    • GWLP_WNDPROC
    • GWLP_HINSTANCE
    • GWLP_HWNDPARENT
    • GWLP_USERDATA
    • GWLP_ID

    Por exemplo, o código a seguir não compila:

    SetWindowLong(hWnd, GWL_WNDPROC, (LONG)MyWndProc);

    Ela deve ser alterada da seguinte maneira:

    SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)MyWndProc);

    Ao definir o membro cbWndExtra da estrutura WNDCLASS , reserve espaço suficiente para ponteiros. Por exemplo, se você estiver reservando bytes sizeof(DWORD) no momento para um valor de ponteiro, reserve sizeof(DWORD_PTR) bytes.

  8. Acesse todos os dados de janela e classe usando FIELD_OFFSET.

    É comum acessar dados de janela usando deslocamentos embutidos em código. Essa técnica não é portátil para o Windows de 64 bits. Para tornar seu código portátil, acesse seus dados de janela e classe usando a macro FIELD_OFFSET . Não suponha que o segundo ponteiro tenha um deslocamento de 4.

  9. Os tipos LPARAM, WPARAM e LRESULT mudam de tamanho com a plataforma.

    Ao compilar código de 64 bits, esses tipos se expandem para 64 bits, pois normalmente mantêm ponteiros ou tipos integrais. Não misture esses valores com valores DWORD, ULONG, UINT, INT, int ou long . Examine como você usa esses tipos e verifique se não trunca valores inadvertidamente.