移植程式代碼以針對 32 位和 64 位Microsoft Windows 進行編譯很簡單。 您只需要遵循一些關於轉換指標的簡單規則,並在程式代碼中使用新的數據類型。 指標操作的規則如下。
請勿將指標轉換成 int、long、ULONG或 DWORD。
如果您必須轉換指標以測試某些位元、設定或清除位元,或以其他方式操作其內容,請使用 UINT_PTR 或 INT_PTR 類型。 這些型別是會隨著 32 位和 64 位 Windows 指標大小進行調整的整數類型(例如,32 位 Windows 使用 ULONG,而 64 位 Windows 使用 _int64)。 例如,假設您正在移植下列程式代碼:
ImageBase = (PVOID)((ULONG)ImageBase | 1);在移植程式中,您會變更程序代碼,如下所示:
ImageBase = (PVOID)((ULONG_PTR)ImageBase | 1);在適當的情況下使用 UINT_PTR 和 INT_PTR。如果您不確定是否需要使用它們,還是使用它們以防萬一,這樣沒有任何壞處。 請勿將 指標轉換成 ULONG、LONG、INT、UINT或 DWORD類型。
請注意,HANDLE 定義為 void*,因此將 HANDLE 值類型轉換為 ULONG 值,以測試、設定或清除低 2 位元是在 64 位元 Windows 上的錯誤。
使用 PtrToLong 或 PtrToUlong 函式來截斷指標。
如果您必須截斷 32 位值的指標,請使用 PtrToLong 或 PtrToUlong 函式 (定義於 Basetsd.h 中)。 這些函式會在呼叫期間停用指標截斷警告。
請仔細使用這些函式。 使用下列其中一個函式轉換指標變數之後,請勿再將它當做指標使用。 這些函式會截斷位址的上層 32 位,這通常需要存取原本由指標參考的記憶體。 在不仔細考慮的情況下使用這些函式會導致程式代碼脆弱。
在可能編譯為64位程式代碼的程式代碼中使用POINTER_32值時,請小心。 編譯器在64位元程式碼中將指標指派給原生指標時,會進行符號位擴展,而不是零擴展。
在可能編譯為32位程式代碼的程式代碼中使用POINTER_64值時,請小心。 編譯器會在32位程式碼中對指標進行符號延伸,而不是零擴展指標。
請小心使用 OUT 參數。
例如,假設您有定義如下的函式:
void func( OUT PULONG *PointerToUlong );請不要像下面這樣呼叫這個函式。
ULONG ul; PULONG lp; func((PULONG *)&ul); lp = (PULONG)ul;請改用下列呼叫。
PULONG lp; func(&lp);將 &ul 型別轉換為 PULONG* 可以避免編譯器錯誤,但該函式會將 64 位指標值寫入在 &ul 的記憶體中。 此程式代碼適用於 32 位 Windows,但會導致 64 位 Windows 上的數據損毀,而且會很微妙且難以尋找損毀。 底線:不要用 C 語言耍花招,簡單明瞭更好。
請小心多型介面。
請勿建立可接受多型數據的 DWORD 參數的函式。 如果數據可以是指針或整數值,請使用UINT_PTR或 PVOID 類型。
例如,請勿建立函式,以接受類型為 DWORD 值的例外狀況參數陣列。 陣列應該是 DWORD_PTR 值的陣列。 因此,陣列元素可以保存位址或32位整數值。 (一般規則是,如果原始類型 DWORD 且必須是指針寬度,請將它轉換成 DWORD_PTR 值。這就是為什麼有對應的指標精確度類型。如果您有使用 DWORD、ULONG或其他 32 位類型的多型方式的程式代碼(也就是您真的想要參數或結構成員保留位址),請使用 UINT_PTR 取代目前的類型。
使用新的視窗類別函式。
如果您有包含指標的視窗或類別私用資料,您的程式代碼將需要使用下列新函式:
這些函式可以在 32 位和 64 位 Windows 上使用,但在 64 位 Windows 上是必要的。 立即使用這些函式來準備轉換。
此外,您必須使用 64 位 Windows 上的新函式,存取類別私用數據中的指標或句柄。 為了協助您尋找這些案例,在64位編譯期間,Winuser.h 中不會定義下列索引:
- GWL_WNDPROC
- GWL_HINSTANCE
- GWL_HWNDPARENT
- GWL_USERDATA
相反地,Winuser.h 會定義下列新索引:
- GWLP_WNDPROC
- GWLP_HINSTANCE
- GWLP_HWNDPARENT
- GWLP_USERDATA
- GWLP_ID
例如,下列程式代碼不會編譯:
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)MyWndProc);它應該變更如下:
SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)MyWndProc);設定 cbWndExtraWNDCLASS 結構的成員時,請務必為指標保留足夠的空間。 例如,如果您目前為指標值分配 sizeof(DWORD) 字節,請分配 sizeof(DWORD_PTR) 字節。
使用 FIELD_OFFSET存取所有視窗和類別數據。
使用硬編碼位移來存取視窗資料很常見。 這項技術無法移植到64位 Windows。 若要讓您的程式代碼可攜式,請使用 FIELD_OFFSET 巨集來存取視窗和類別數據。 請勿假設第二個指標的位移為 4。
LPARAM、WPARAM和 LRESULT 類型會隨著平台變更大小。
編譯 64 位程式代碼時,這些類型會擴充為 64 位,因為它們通常會保存指標或整數型別。 請勿將這些值與 DWORD、ULONG、UINT、INT、int或 long 值混合。 檢查如何使用這些類型,並確定您不會不小心截斷值。