153Fermer155
ZerosquareLe 08/08/2015 à 21:00
Mais non ! Je disais juste que tu aimes te lancer des défis pas triviaux, c'est tout cheeky

(et puis c'est très bien de se lancer dans des trucs qui ont l'air de te dépasser à priori. C'est comme ça qu'on progresse !)

Le subclassing, c'est grosso-modo comme détourner une interruption. Tu as une fonction, qui s'appelle la "window procedure", qui est appelée lorsqu'un objet reçoit un message à traiter (note : dans ce contexte, "window" est un terme générique pour un objet GUI, ça peut être une fenêtre mais aussi un bouton, une zone de texte, etc.). L'adresse de cette fonction est stockée dans un champ de la structure associée à l'objet. Subclasser, c'est simplement changer ce champ pour mettre à la place l'adresse d'une autre fonction, qui sera du coup appelée à chaque message. Libre à elle ensuite de traiter le message elle-même, d'appeler la window procedure d'origine, de le modifier ou de l'ignorer complètement. L'avantage, c'est que c'est normalement transparent pour le code existant, donc c'est censé marcher sans avoir besoin de décortiquer ce que fait ce code.

Là où c'est différent d'une interruption, et un peu plus subtil, c'est que l'appel à la window procedure ne se fait pas automatiquement en interrompant le thread en cours (tout ce fonctionnement date de l'époque où Windows ne faisait que du multitâche coopératif, donc c'était techniquement impossible). C'est le thread principal qui doit le faire, en exécutant une boucle qui ne s'arrête que quand tu quittes l'appli :
- attente et récupération des messages avec GetMessage
- exécution de la window procedure kivabien avec DispatchMessage

Ça, c'est le fonctionnement "normal" prévu par le système : la boucle de messages ne gère rien elle-même, elle se contente de déléguer. Mais en pratique, un programme peut très bien gérer certains messages directement dans la boucle d'événements elle-même, sans jamais appeler DispatchMessage (donc la window procedure, en fin de compte). Si c'est le cas de Qt, le subclassing ne marchera pas, parce que les messages n'atteindront jamais ta fonction.

Sinon, je vois une autre solution : créer un thread avec sa propre boucle de messages, qui ne fait que gérer la hotkey (en envoyant un signal au thread principal quand il reçoit le message correspondant). À moins que Qt pousse le vice jusqu'à intercepter tous les messages de tous les threads de l'appli, ça devrait fonctionner.

Points à prendre en compte :

- est-ce que ça ne pose pas de problème d'envoyer un signal depuis un autre thread que celui de la GUI ? (à voir dans la doc de Qt)

- il faut un moyen de dire au thread de se terminer (quand on quitte l'appli). Le plus simple est probablement de gérer, en plus de WM_HOTKEY, un autre message (par exemple WM_QUIT) dont la réception va déclencher l'arrêt du thread. Quand on quitte l'appli, le thread principal envoie le message au thread de traitement de la hotkey avec PostThreadMessage, et attend que le thread soit effectivement arrêté avec WaitForSingleObject.

- si tu utilises les fonctions de threading de Qt au lieu des fonctions natives, il faudra récupérer le handle et l'ID natifs du thread, parce que tu en auras besoin pour appeler les fonctions Windows (là aussi, voir dans la doc de Qt).