2012-03-01 14 views
6

Usando Delphi XE2 actualización 3 o actualización 4 en Win7 64 bit.Delphi XE2 EnumWindows no funciona correctamente

EnumWindows de llamada no funciona como lo que solía trabajar en Delphi 6.

En Delphi 6 EnumWindows ventanas procesados ​​hasta que la función de devolución de llamada devuelve Falso. Eso es lo que la documentación dice que debería hacer:

"Para continuar la enumeración, la función de devolución de llamada debe devolver TRUE; para detener la enumeración, debe devolver FALSE".

Realización de una llamada a EnumWindows de la siguiente manera:

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

Aquí es la función de devolución de llamada:

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; 

Para que quede claro la función de devolución de llamada se define en el código antes del evento ButtonClick por lo que es encontrado por el compilador sin necesidad de ser definido en la sección de interfaz.

Si esto se ejecuta utilizando Delphi 6 la enumeración de las ventanas se detiene una vez que el resultado se devuelve false y GLBWindowHandle no es cero

Si esto se ejecuta utilizando Delphi XE2 la enumeración continúa después de que el resultado se devuelve false y GLBWindowHandle es siempre cero.

WTF? ¿Alguien tiene alguna idea de por qué la enumeración no se detiene como la documentación dice que debería y cómo solía hacerlo en Delphi 6?

¡Salud!

+0

¿Ha verificado que 'GLBWindowHandle' se establece y luego se restablece, o también es posible que no se configure? – hvd

+0

Sí, está configurado y luego restablecido. –

+0

¿Observas el mismo comportamiento si compilas para 32 bits y 64 bits? –

Respuesta

12

Esta declaración es incorrecta:

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

que debe ser:

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

Usted tiene que tener cuidado de no mezclar y BooleanBOOL ya que no son la misma cosa. El primero es un byte único, el último tiene 4 bytes. Esta discrepancia entre lo que EnumWindows espera y lo que devuelve la función de devolución de llamada es suficiente para causar el comportamiento que observa.


Además, Rob Kennedy contribuyó este excelente comentario:

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.


Discusión

Desafortunadamente la traducción Windows.pas cabecera define EnumWindows de una manera más inútil, como este:

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

Ahora, el problema está en la definición de TFNWndEnumProc.Se define como:

TFarProc = Pointer; 
TFNWndEnumProc = TFarProc; 

Esto significa que usted tiene utilizar el operador @ hacer un puntero genérico, debido a que la función necesita un puntero genérico. Si TFNWndEnumProc fueron declarados como esto:

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

entonces el compilador habría sido capaz de detectar el error.

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); 

El compilador rechaza la llamada a EnumWindows con el siguiente error:

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

Creo que voy a este problema de control de calidad y probar suerte a persuadir Embarcadero dejar de usar TFarProc.

+0

DOH! Gracias David. Es extraño que funcione en Delphi 6. –

+0

Supongo que tienes suerte en D6. No llegué a intentar calcular la razón exacta por la que cambia el comportamiento. –

+0

Varias cosas parecen haber sucedido a lo largo de los años con los componentes internos del compilador que tienen efectos aparentemente tan extraños. fi ver mi propia respuesta a mi propia pregunta (que me dejó perplejo durante casi un AÑO) (http://stackoverflow.com/questions/1482699/zeroconf-bonjour-code-that-works-in-delphi-7-not- working-in-2009) – Deltics

Cuestiones relacionadas