Tu peux envoyer tout ce que tu veux, entre
threads ou entre processus
Voici deux exemples.
Rediriger la sortie d'une application console.
Admettons que cycliquement, tu lances en tâche de fond une application console invisible pour de la maintenance (
backup, mise à jour...). Tu aimerais cependant que l'utilisateur soit informé de l'avancement ou d'une éventuelle erreur. Tu pourrais bien sûr :
- utiliser CreateProcess et rediriger la sortie sur un Pipe. Un travail conséquent ;
- lancer ShellExecuteEx depuis un thread et attendre la fin pour contrôler le code de sortie (ExitCode), mais pas de notification d'avancement ;
- envoyer WM_COPYDATA mais SendMessage est bloquant et dû à la structure de taille fixe, le texte risque d'être tronqué (ou alors il faut surdimentionner le buffer).
Ici, rien de tout cela ! Il suffit de redéfinir
WriteLn et d'envoyer
PostTextMessage
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, Windows, Messages, MessagesEx;
procedure WriteLn(aText :string);
begin
PostTextMessage(FindWindow('ClassName', 'WindowName'), WM_USER, aText);
end;
begin
ClearTableOnExit := FALSE;
try
WriteLn('BlaBla');
WriteLn('BlaBla');
except
on E: Exception do
WriteLn(E.Message);
end;
end. |
Hook.
Tu aimerais intercepter le retour de traitement d'un message par une fenêtre quelconque. Tu vas pour cela injecter une DLL dans les processus par
SetWindowsHookEx. Mais un
hook peut être très pénalisant pour le système et le ralentir considérablement si le traitement à effectuer est long.
Jusqu'à Windows XP, on privilégiait le passage d'info par fichier mappé. Les lectures et écritures devant bien sûr être synchronisées par mutex. Depuis Vista et l'UAC, C'est fini ! La DLL injectée dans une application de niveau d'intégrité inférieur (par exemple Internet Explorer en mode protégé) n'aura pas accès au fichier mappé. Une violation est générée et c'est le
deadlock assuré de l'application cible.
On pourrait à nouveau utiliser WM_COPYDATA, mais il faudra que notre application soit très réactive. Imagine un
hook souris tellement pénalisant que le curseur avance par saccade !
Router simplement les informations par
PostMessage ? Bien sûr si peu d'informations nous intéressent et tiennent dans WParam/LParam. Mais il ne faut pas espérer en récupérer plus par la suite par
AttachThreadInput (UAC quand tu nous tiens...).
Intercepter le retour d'un message se fait en plaçant un
hook de type WH_CALLWNDPROCRET. Un pointeur est passé dans
LParam correspondant à la structure suivante :
1 2 3 4 5 6 7 8
| type
TCwpRetStruct = record
lResult :LRESULT;
lParam :LPARAM;
wParam :WPARAM;
message :UINT;
hwnd :HWND;
end; |
Nous n'aurons donc plus qu'à faire :
1 2 3 4 5 6 7
| function CWPRetProc(aCode: integer; aWParam: WPARAM; aLParam: LPARAM):LRESULT; stdcall;
begin
if (aCode = HC_ACTION) then
PostBufferMessage(FindWindow('ClassName', 'WindowName'), WM_USER, aLParam, SizeOf(TCwpRetStruct));
Result := CallNextHookEx(0, aCode, aWParam, aLParam);
end; |
Est-ce plus clair ?
4 |
0 |