Reglas para usar punteros
Migrar el código para compilar para Microsoft Windows de 32 y 64 bits es sencillo. Solo necesita seguir algunas reglas sencillas sobre la conversión de punteros y usar los nuevos tipos de datos en el código. Las reglas para la manipulación de punteros son las siguientes.
No convierta punteros a int, long, ULONG o DWORD.
Si debe convertir un puntero para probar algunos bits, establecer o borrar bits o manipular su contenido, use el tipo UINT_PTR o INT_PTR . Estos tipos son tipos enteros que se escalan al tamaño de un puntero para Windows de 32 y 64 bits (por ejemplo, ULONG para Windows de 32 bits y _int64 para Windows de 64 bits). Por ejemplo, supongamos que va a migrar el código siguiente:
ImageBase = (PVOID)((ULONG)ImageBase | 1);
Como parte del proceso de portabilidad, cambiaría el código de la siguiente manera:
ImageBase = (PVOID)((ULONG_PTR)ImageBase | 1);
Use UINT_PTR y INT_PTR cuando sea necesario (y si no está seguro de si son necesarios, no hay ningún daño en su uso solo en caso de que sea necesario). No convierta los punteros a los tipos ULONG, LONG, INT, UINT o DWORD.
Tenga en cuenta que HANDLE se define como void*, por lo que la difusión de un valor HANDLE a un valor ULONG para probar, establecer o borrar los 2 bits de orden bajo es un error en Windows de 64 bits.
Use la función PtrToLong o PtrToUlong para truncar punteros.
Si debe truncar un puntero a un valor de 32 bits, use la función PtrToLong o PtrToUlong (definida en Basetsd.h). Estas funciones deshabilitan la advertencia de truncamiento del puntero durante la llamada.
Use estas funciones con cuidado. Después de convertir una variable de puntero mediante una de estas funciones, no vuelva a usarla como puntero. Estas funciones truncan los 32 bits superiores de una dirección, que normalmente son necesarios para acceder a la memoria a la que hace referencia originalmente el puntero. El uso de estas funciones sin tener en cuenta cuidadosamente dará lugar a código frágil.
Tenga cuidado al usar POINTER_32 valores en el código que se pueden compilar como código de 64 bits. El compilador ampliará el puntero cuando se asigne a un puntero nativo en código de 64 bits, no extenderá cero el puntero.
Tenga cuidado al usar POINTER_64 valores en el código que se pueden compilar como código de 32 bits. El compilador iniciará sesión para extender el puntero en código de 32 bits, no extenderá cero el puntero.
Tenga cuidado con el uso de parámetros OUT.
Por ejemplo, supongamos que tiene una función definida de la siguiente manera:
void func( OUT PULONG *PointerToUlong );
No llame a esta función como se indica a continuación.
ULONG ul; PULONG lp; func((PULONG *)&ul); lp = (PULONG)ul;
En su lugar, use la siguiente llamada.
PULONG lp; func(&lp);
La difusión de &tipos ul a PULONG* impide un error del compilador, pero la función escribirá un valor de puntero de 64 bits en la memoria en &ul. Este código funciona en Windows de 32 bits, pero provocará daños en los datos en Windows de 64 bits y será sutil y difícil de encontrar daños. La línea de fondo: No jugar trucos con el código C, sencillo y sencillo es mejor.
Tenga cuidado con las interfaces polimórficas.
No cree funciones que acepten parámetros DWORD para datos polimórficos. Si los datos pueden ser un puntero o un valor entero, use el tipo UINT_PTR o PVOID .
Por ejemplo, no cree una función que acepte una matriz de parámetros de excepción con tipo DWORD . La matriz debe ser una matriz de valores de DWORD_PTR . Por lo tanto, los elementos de matriz pueden contener direcciones o valores enteros de 32 bits. (La regla general es que si el tipo original es DWORD y debe ser ancho de puntero, conviértelo en un valor de DWORD_PTR . Por eso hay tipos de precisión de puntero correspondientes). Si tiene código que usa DWORD, ULONG u otros tipos de 32 bits de forma polimórfica (es decir, realmente desea que el parámetro o el miembro de estructura contenga una dirección), use UINT_PTR en lugar del tipo actual.
Use las nuevas funciones de clase de ventana.
Si tiene datos privados de ventana o clase que contienen punteros, el código deberá usar las siguientes funciones nuevas:
Estas funciones se pueden usar en Windows de 32 y 64 bits, pero son necesarias en Windows de 64 bits. Prepárese para la transición con estas funciones ahora.
Además, debe tener acceso a punteros o identificadores de datos privados de clase mediante las nuevas funciones en Windows de 64 bits. Para ayudarle a encontrar estos casos, los índices siguientes no se definen en Winuser.h durante una compilación de 64 bits:
- GWL_WNDPROC
- GWL_HINSTANCE
- GWL_HWNDPARENT
- GWL_USERDATA
En su lugar, Winuser.h define los siguientes índices nuevos:
- GWLP_WNDPROC
- GWLP_HINSTANCE
- GWLP_HWNDPARENT
- GWLP_USERDATA
- GWLP_ID
Por ejemplo, el código siguiente no se compila:
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)MyWndProc);
Debe cambiarse de la siguiente manera:
SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)MyWndProc);
Al establecer el miembro cbWndExtra de la estructura WNDCLASS , asegúrese de reservar espacio suficiente para punteros. Por ejemplo, si actualmente reserva bytes sizeof(DWORD) para un valor de puntero, reserve sizeof(DWORD_PTR) bytes.
Acceda a todos los datos de ventana y clase mediante FIELD_OFFSET.
Es habitual acceder a los datos de ventana mediante desplazamientos codificados de forma rígida. Esta técnica no es portátil a Windows de 64 bits. Para que el código sea portátil, acceda a los datos de la ventana y la clase mediante la macro FIELD_OFFSET . No suponga que el segundo puntero tiene un desplazamiento de 4.
Los tipos LPARAM, WPARAM y LRESULT cambian el tamaño con la plataforma.
Al compilar código de 64 bits, estos tipos se expanden a 64 bits, ya que normalmente contienen punteros o tipos enteros. No mezcle estos valores con valores DWORD, ULONG, UINT, INT, int o long . Examine cómo se usan estos tipos y asegúrese de que no trunca accidentalmente los valores.