2012-03-01 17 views
6

Utilizzo di Delphi XE2 update 3 o update 4 su Win7 64 bit.Delphi XE2 EnumWindows non funziona correttamente

EnumWindows di chiamata non funziona come è abituato a lavorare in Delphi 6.

In Delphi 6 EnumWindows finestre processati fino a quando la funzione di callback restituito False. Questo è ciò che la documentazione dice che dovrebbe fare:

"Per continuare l'enumerazione, la funzione di callback deve restituire TRUE; per interrompere l'enumerazione, deve restituire FALSE."

Effettuare una chiamata al EnumWindows come segue:

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    EnumWindows(@FindMyWindow,0); 
    if GLBWindowHandle <> 0 then begin 
    ShowMessage('found'); 
    end; 
end; 

Ecco la funzione di callback:

function FindMyWindow(hWnd: HWND; lParam: LPARAM): boolean; stdcall; 
var TheText : array[0..150] of char; 
str : string; 
begin 
Result := True; 
GLBWindowHandle := 0; 
if (GetWindowText(hWnd, TheText, 150) <> 0) then 
    begin 
    str := TheText; 
    if str = 'Form1' then 
     begin 
     GLBWindowHandle := hWnd; 
     Result := False; 
     end 
    else 
     result := True; 
    end; 
end; 

tanto per essere chiari la funzione di callback è definita nel codice prima che l'evento ButtonClick quindi è trovato dal compilatore senza che sia necessario definirlo nella sezione dell'interfaccia.

Se questo viene eseguito utilizzando Delphi 6 l'enumerazione delle finestre si ferma una volta che il falso risultato viene restituito e GLBWindowHandle non è zero

Se questo viene eseguito utilizzando Delphi XE2 l'enumerazione continua dopo il Falso risultato viene restituito e GLBWindowHandle è sempre zero.

WTF? Qualcuno ha qualche idea sul perché l'enumerazione non si fermi come la documentazione afferma che dovrebbe e come era usata in Delphi 6?

Cheers!

+0

Hai verificato che 'GLBWindowHandle' viene impostato e quindi resettato, o è anche possibile che non venga impostato affatto? – hvd

+0

Sì, è impostato e quindi ripristinato. –

+0

Osservate lo stesso comportamento se compilate per 32 bit e 64 bit? –

risposta

12

Questa dichiarazione non è corretto:

function FindMyWindow(hWnd: HWND; lParam: LPARAM): boolean; stdcall; 

dovrebbe essere:

function FindMyWindow(hWnd: HWND; lParam: LPARAM): BOOL; stdcall; 

bisogna essere attenti a non confondere Boolean e BOOL dal momento che non sono la stessa cosa. Il primo è un byte singolo, il secondo è di 4 byte. Questa discrepanza tra ciò che si aspetta EnumWindows e ciò che la funzione di callback offre è sufficiente a causare il comportamento osservato.


Inoltre, Rob Kennedy ha contribuito questo eccellente commento:

The compiler can help find this error if you get out of the habit of using the @ operator before the function name when you call EnumWindows . If the function signature is compatible, the compiler will let you use it without @ . Using @ turns it into a generic pointer, and that's compatible with everything, so the error is masked by unnecessary syntax. In short, using @ to create function pointers should be considered a code smell.


Discussione

Purtroppo la traduzione Windows.pas intestazione definisce EnumWindows in maniera più indisponibili, in questo modo:

function EnumWindows(lpEnumFunc: TFNWndEnumProc; lParam: LPARAM): BOOL; stdcall; 

Ora, il problema è nella definizione di TFNWndEnumProc.Essa è definita come:

TFarProc = Pointer; 
TFNWndEnumProc = TFarProc; 

Questo significa che si deve di utilizzare l'operatore @ per fare un puntatore generico, perché la funzione ha bisogno di un puntatore generico. Se TFNWndEnumProc sono stati dichiarati in questo modo:

TFNWndEnumProc = function(hWnd: HWND; lParam: LPARAM): BOOL; stdcall; 

il compilatore sarebbe stato in grado di trovare l'errore.

type 
    TFNWndEnumProc = function(hWnd: HWND; lParam: LPARAM): BOOL; stdcall; 

function EnumWindows(lpEnumFunc: TFNWndEnumProc; 
    lParam: LPARAM): BOOL; stdcall; external 'user32'; 

function FindMyWindow(hWnd: HWND; lParam: LPARAM): Boolean; stdcall; 
begin 
    Result := False; 
end; 

.... 
EnumWindows(FindMyWindow, 0); 

Il compilatore rifiuta la chiamata alla EnumWindows con il seguente errore:

[DCC Error] Unit1.pas(38): E2010 Incompatible types: 'LongBool' and 'Boolean'

Penso che Qc questo problema e tentare la fortuna a persuadere Embarcadero di smettere di usare TFarProc.

+0

DOH! Grazie, David. Strano che funzioni in Delphi 6. –

+0

Immagino che tu sia fortunato solo in D6. Non sono arrivato al punto di cercare di capire il motivo esatto per cui il comportamento cambia. –

+0

Un numero di cose sembra essere accaduto nel corso degli anni agli interni del compilatore che hanno effetti apparentemente strani. vedo la mia risposta alla mia stessa domanda (che mi ha costretto a rimanere per quasi un ANNO) (http://stackoverflow.com/questions/1482699/zeroconf-bonjour-code-that-works-in-delphi-7-not- working-in-2009) – Deltics

Problemi correlati