2012-04-19 12 views
9

Tengo un proyecto Delphi 2007 que ha funcionado bien en Windos XP, Vista y "7" durante años. Fue una actualización de Delphi 5 por lo que "MainFormOnTaskBar" era "falso" por defecto (nunca lo cambié en DPR). En este escenario, la tecla de acceso directo del sistema funcionó "en todo el sistema" con el siguiente código en el controlador de eventos OnCreate de la forma principal.Delphi 2007 - La tecla de acceso directo del sistema NO es "todo el sistema" si establece "MainFormOnTaskBar: = True"

HotKey_xyz := GlobalAddAtom('Hotkey_xyz'); 
if NOT RegisterHotKey(Self.Handle, HotKey_xyz, MOD_CONTROL, VK_F12) then 
    ShowMessage('Unable to register Control-F12 as system-wide hot key') ; 

(I have GlobalDeleteAtom() and UnregisterHotKey() in Form.OnDestroy as expected.) 

Ahora, necesito un formulario para mostrar su propio botón en la barra de tareas, así que me puse "Application.MainFormOnTaskBar: = True" en la RPD. Esto funciona como se esperaba Sin embargo, esto tiene el efecto secundario de que Control-F12 NO funciona en todo el sistema, funciona SÓLO SI mi aplicación tiene foco (por lo tanto, NO es "todo el sistema")

He buscado mucho en 'Net ha encontrado muchos artículos sobre cómo/por qué' MainFormOnTaskBar 'afecta a ciertos comportamientos de formularios subformulares/modales. Sin embargo, no he encontrado nada con respecto a su efecto en una cuestión de "Acceso directo a todo el sistema" que describo más arriba. He probado y vuelto a probar mi aplicación con MainFormOnTaskBar establecido en verdadero y falso, mientras que todo lo demás permanece exactamente igual. Puedo verificar positivamente que el problema descrito anteriormente con la tecla de acceso directo en todo el sistema se relaciona con el indicador MainFormOnTaskBar.

Agradeceré cualquier orientación con respecto a una solución temporal. Necesito TANTO: una tecla de acceso directo del sistema Y un formulario con su propio botón en la barra de tareas.

Muchas gracias.

+0

¿Se puede duplicar con un * nuevo * proyecto? No pude ... –

+0

No puedo reproducir esto tampoco. ¿Puedes publicar más código? (Y posiblemente intente cambiar 'Self.Handle' por' Application.Handle' en la llamada 'RegisterHotkey' mientras tanto} El mensaje' WM_HOTKEY' seguirá llegando a su formulario, porque el manejador de mensajes de la aplicación no hace nada con eso ; se enviará a su formulario como siempre). –

+0

@KenWhite: si se utiliza 'Application.Handle' para registrar la tecla de acceso rápido, los mensajes' WM_HOTKEY' NO se enviarán directamente o indirectamente al TForm. Serán dirigidos a 'TApplication' en su lugar, por lo que para capturar esos mensajes debe usar el evento' TApplication.OnMessage' y/o el método 'TApplication.HookMainWindow()'. –

Respuesta

14

TApplication.MainFormOnTaskbar no tiene ningún efecto en las teclas de acceso directo del sistema en absoluto. Puedo confirmarlo positivamente. Puedo recibir WM_HOTKEY mensajes independientemente de en qué se configure MainFormOnTaskbar, independientemente de si la aplicación está enfocada o no, etc. Así que lo que sea que esté viendo no es lo que cree que está sucediendo.

Lo más probable, simplemente se vuelve a crear el formulario de Handle detrás de la espalda después de haber llamado RegisterHotKey(), por lo que se pierde la HWND que recibiría los mensajes WM_HOTKEY. En lugar de utilizar el evento OnCreate, debe reemplazar los métodos CreateWindowHandle() y DestroyWindowHandle() del formulario en su lugar para asegurarse de que la clave activa esté siempre registrada para el HWND actual del Formulario sin importar qué le ocurra (siempre debe hacerlo cuando vincula cualquier tipo de datos a la Handle de Forma), por ejemplo:

type 
    TForm1 = class(TForm) 
    private 
    HotKey_xyz: WORD; 
    procedure WMHotKey(var Message: TMessage); message WM_HOTKEY; 
    protected 
    procedure CreateWindowHandle(const Params: TCreateParams); override; 
    procedure DestroyWindowHandle; override; 
    end; 

procedure TForm1.CreateWindowHandle(const Params: TCreateParams); 
begin 
    inherited; 
    HotKey_xyz := GlobalAddAtom('Hotkey_xyz'); 
    if HotKey_xyz <> 0 then 
    RegisterHotKey(Self.Handle, HotKey_xyz, MOD_CONTROL, VK_F12); 
end; 

procedure TForm1.DestroyWindowHandle(const Params: TCreateParams); 
begin 
    if HotKey_xyz <> 0 then 
    begin 
    UnregisterHotKey(Self.Handle, HotKey_xyz); 
    GlobalDeleteAtom(HotKey_xyz); 
    HotKey_xyz := 0; 
    end; 
    inherited; 
end; 

procedure TForm1.WMHotKey(var Message: TMessage); 
begin 
    ... 
end; 

una mejor opción es utilizar AllocateHWnd() asignar un dedicado separado HWND sólo para el manejo de los mensajes clave calientes (a continuación, puede utilizar los eventos OnCreate y OnDestroy de nuevo), por ejemplo:

type 
    TForm1 = class(TForm) 
    procedure FormCreate(Sender: TObject); 
    procedure FormDestroy(Sender: TObject); 
    private 
    HotKey_xyz: WORD; 
    HotKeyWnd: HWND; 
    procedure HotKeyWndProc(var Message: TMessage); 
    end; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    HotKeyWnd := AllocateHwnd(HotKeyWndProc); 
    HotKey_xyz := GlobalAddAtom('Hotkey_xyz'); 
    if HotKey_xyz <> 0 then 
    RegisterHotKey(HotKeyWnd, HotKey_xyz, MOD_CONTROL, VK_F12); 
end; 

procedure TForm1.FormDestroy(Sender: TObject); 
begin 
    if HotKey_xyz <> 0 then 
    begin 
    UnregisterHotKey(HotKeyWnd, HotKey_xyz); 
    GlobalDeleteAtom(HotKey_xyz); 
    HotKey_xyz := 0; 
    end; 
    if HotKeyWnd <> 0 then 
    begin 
    DeallocateHWnd(HotKeyWnd); 
    HotKeyWnd := 0; 
    end; 
end; 

procedure TForm1.HotKeyWndProc(var Message: TMessage); 
begin 
    if Message.Msg = WM_HOTKEY then 
    begin 
    ... 
    end else 
    Message.Result := DefWindowProc(HotKeyWnd, Message.Msg, Message.WParam, Message.LParam); 
end; 
+1

+1 para el ejemplo de código 'AllocHWnd' solo. Bien, nunca antes lo había visto así. Estaré marcando esto para referencia futura. –

+0

@ Remy: muchas gracias por los métodos: CreateWindowHandle() y DestroyWindowHandle(): eso fue suficiente. Entonces, no puedo agradecerte lo suficiente. Voy a explorar "AllocateWnd()" - ¡Necesito más educación sobre eso! Quería UP-Vote su respuesta, pero Stack Overflow dice que no tengo suficientes "reputaciones" para hacerlo. – JayM

+0

@All: Gracias a todos los que comentaron y se tomaron su tiempo para probar mi afirmación de que la bandera de MainFormOnTaskBar era la culpable, estoy educada de que no es así. Una vez más, agradezco mucho el apoyo y la disposición de las comunidades para ayudar. – JayM

Cuestiones relacionadas