2010-07-27 14 views
11

Voglio P/Invoke a GetWindowLongPtr e SetWindowLongPtr e visualizzo informazioni contrastanti su di essi.Come posso eseguire il pinvoke su GetWindowLongPtr e SetWindowLongPtr su piattaforme a 32 bit?

Alcune fonti dicono che, su piattaforme a 32 bit, GetWindowLongPtr è solo una macro di preprocessore che chiama GetWindowLong e GetWindowLongPtr non esiste come punto di ingresso in user32.dll. Per esempio:

  • Il pinvoke.net entry for SetWindowLongPtr ha un metodo statico che controlla IntPtr.Size e quindi chiama o SetWindowLong o SetWindowLongPtr, con un commento che dice che "sistemi operativi legacy non supportano SetWindowLongPtr". Non c'è spiegazione di cosa si intende per "sistemi operativi legacy".
  • Uno stato answer on StackOverflow "Su sistemi a 32 bit GetWindowLongPtr è solo una macro C che punta a GetWindowLong".

Quindi queste fonti sembrano indicare che i punti di ingresso * Ptr semplicemente non ci sono nella versione di user32.dll fornito con, diciamo, a 32 bit di Windows 7.

ma non vedo indicazione di ciò nella documentazione MSDN. Secondo MSDN, SetWindowLongPtr sostituisce SetWindowLong, semplice e semplice. E in base alla sezione dei requisiti dello SetWindowLongPtr page, sembra che SetWindowLongPtr sia stato in user32.dll da Windows 2000 (sia client che server). Di nuovo, nessuna menzione dei punti di ingresso mancanti nei sistemi operativi a 32 bit.

ho sospetto che la verità sta nel mezzo: che quando si dice al compilatore di indirizzare i sistemi operativi meno recenti (ad esempio, per compilare qualcosa che verrà eseguito su Windows 9x e NT4) C++, quindi i file di intestazione dichiaro SetWindowLongPtr come macro che chiama SetWindowLong, ma il punto di ingresso probabilmente esiste in Windows 2000 e versioni successive e lo si otterrà direttamente (invece della macro) se si dice al compilatore di indirizzare tali piattaforme. Ma questa è solo una supposizione; Non ho davvero le risorse o il know-how per scavare e verificarlo.

È anche possibile che la piattaforma di destinazione abbia un ruolo: se si compila l'app per la piattaforma x86, non si dovrebbe chiamare SetWindowLongPtr su un sistema operativo a 64 bit. Di nuovo, so abbastanza per pensare alla domanda, ma non so come trovare la risposta. MSDN sembra suggerire che SetWindowLongPtr è sempre corretto.

Qualcuno può dirmi se è sicuro semplicemente P/Invoke su SetWindowLongPtr e si può fare con esso? (Si supponga di Windows 2000 e versioni successive.) Sarebbe P/Invocare a SetWindowLongPtr dammi la corretta punto di ingresso:

  • se corro un app mira la piattaforma x86 su un sistema operativo a 32 bit?
  • se eseguo un'applicazione che ha come target la piattaforma x86 su un sistema operativo a 64 bit?
  • se eseguo un'applicazione che utilizza la piattaforma x64 su un sistema operativo a 64 bit?

risposta

15

vi consiglio di fare con questo il modo in cui Windows Form fa internamente:

public static IntPtr GetWindowLong(HandleRef hWnd, int nIndex) 
{ 
    if (IntPtr.Size == 4) 
    { 
     return GetWindowLong32(hWnd, nIndex); 
    } 
    return GetWindowLongPtr64(hWnd, nIndex); 
} 


[DllImport("user32.dll", EntryPoint="GetWindowLong", CharSet=CharSet.Auto)] 
private static extern IntPtr GetWindowLong32(HandleRef hWnd, int nIndex); 

[DllImport("user32.dll", EntryPoint="GetWindowLongPtr", CharSet=CharSet.Auto)] 
private static extern IntPtr GetWindowLongPtr64(HandleRef hWnd, int nIndex); 
+3

Non hai detto dove hai trovato questo codice, ma l'ho rintracciato su System.Windows.Forms.UnsafeNativeMethods. –

+0

@ hans-passant: grazie per questo bit di codice. È stato utile implementare una soluzione per avere una finestra di dialogo modale in un'altra finestra di dialogo: http://stackoverflow.com/a/16088711/654244 – KyleK

+1

L'attributo non dovrebbe includere 'SetLastError = true' per recuperare in seguito un possibile errore? –

3
  1. Aprire il file di intestazione (nella pagina MSDN, questo è elencato come Winuser.h). Le intestazioni Win32 si trovano solitamente a C:\Program Files\Microsoft SDKs\Windows\v7.0A\Include
  2. Cerca tutte le istanze di SetWindowLongPtr/GetWindowLongPtr.
  3. Si noti che quando è definito _WIN64, sono funzioni; quando non lo sono, sono #define 'a SetWindowLong/GetWindowLong.

Ciò implica che i sistemi operativi a 32 bit non possono avere SetWindowLongPtr/GetWindowLongPtr come una funzione reale, in modo sembrerebbe che il commento sul pinvoke.net è corretto.

Update (maggiori chiarimenti sulla _WIN64):

_WIN64 è definita dal C/C++ quando si compila il codice a 64 bit (che verrà eseguito solo su un sistema operativo a 64-bit). Questo significa che qualsiasi codice a 64 bit che utilizza SetWindowLongPtr/GetWindowLongPtr utilizzerà le funzioni effettive, ma qualsiasi codice a 32 bit che li utilizza utilizzerà invece SetWindowLong/GetWindowLong. Questo include il codice a 32 bit in esecuzione su un sistema operativo a 64 bit.

Per emulare lo stesso comportamento in C#, consiglio di controllare IntPtr.Size come fatto da pinvoke.net; che ti dice se stai usando il codice a 32 o 64 bit. (Tenendo presente che il codice a 32 bit può essere eseguito su un sistema operativo a 64 bit). L'utilizzo di IntPtr.Size nel codice gestito emula lo stesso comportamento di _WIN64 per codice nativo.

+0

mia directory 'v7.0A' non ha un' Include' sottodirectory - solo 'Bin' e' Bootstrapper'. Ho trovato un 'Include' sotto' v5.0', però. –

+0

Stessa offerta. Sono solo versioni diverse dell'SDK Win32. –

Problemi correlati