Lire le contenu de contrôles textbox, richedit,... d'autres applis windows

Description

Il est parfois important de communiquer entre Managé (C# et CLR) et non Managé (C++ et Win32).
Si vous devez récupérer automatiquement des données qui sont renseignées dans une application Windows extérieure, voici une technique à base de PInvoke

Le StringBuilder est très important !
essayez de décommenter la ligne de #define
ce qui provoque le remplacement des "StringBuilder" par des "string" dans la déclaration et l'appel de GetControlText
Que se passe t-il ?
Nous initialisons une zone 'string' avec des 0. Dans l'exécution de la fonction GetControlText, il y modification de la valeur du string... et la runtime alloue un nouvel emplacement pour ce string. Notre ancienne variable pointe toujours sur la zone initialisée avec nos zeros. Il est donc extrèmement important d'utiliser le StringBuilder qui lui est modifiable (méthode Append)

Source / Exemple :


//Faire un projet "Console" et copier ceci

//#define STRING // ligne à décommenter pour STRING, à commenter pour STRINGBUILDER

using System;
using System.Runtime.InteropServices;
using System.Text;//pour le StringBuilder

class Test
{
	private const int WM_GETTEXTLENGTH = 14;//pour utilisation de SendMessage
	private const int WM_GETTEXT = 13;//pour utilisation de SendMessage
	
	[DllImport("user32.dll", EntryPoint="FindWindowEx")]
	public static extern int FindWindowEx ( 
		int hwndParent,	int hwndEnfant,	int lpClasse, string lpTitre);
	[DllImport("user32.dll", EntryPoint="SendMessage")]
	public static extern int SendMessage (
		int hwnd, uint wMsg, int wParam, int lParam);
	[DllImport("user32.dll", EntryPoint="SendMessage")]
	public static extern int GetControlText ( //renommée pour spécialisation du dernier param
#if STRING
		int hwnd, uint wMsg, int wParam, string lParam);//lParam : récupération du texte
#else
		int hwnd, uint wMsg, int wParam, StringBuilder lParam);//lParam : récupération du texte
#endif

	static void Main(string[] args)
	{
		Console.WriteLine("titre de la fenetre a scanner");
		string titre = Console.ReadLine();
		int hwnd = FindWindowEx(0, 0, 0, titre);
		if (hwnd==0) {Console.WriteLine("Erreur, fenêtre non trouvée"); return ;}
		Console.WriteLine("hwnd Parent = {0}",hwnd);
		Console.WriteLine("Liste des contrôles enfants:");

		int hwndEnfant=FindWindowEx(hwnd, 0, 0, null);
		while (hwndEnfant!=0)
		{
			int lgTexte = SendMessage(hwndEnfant, WM_GETTEXTLENGTH, 0, 0) + 1; 
#if STRING
			string sbTitre = new string('0',lgTexte);
#else
			StringBuilder sbTitre = new StringBuilder(lgTexte);
#endif
			GetControlText(hwndEnfant, WM_GETTEXT, lgTexte, sbTitre);
			Console.WriteLine("hwnd={0} => {1}", hwndEnfant, sbTitre);
			hwndEnfant=FindWindowEx(hwnd, hwndEnfant, 0, null);
		}
		Console.WriteLine("Tapez sur une touche...");
		Console.Read();
	}
}

Conclusion :


code fourni avec une boite de dialogue (MFC) de test comportant en particulier un richedit

modification : la première version codait en dur une taille max de 255 caractères pour le texte récupéré. Cette version s'affranchit de cette limite
Elle appelle deux fois SendMessage :
une pour déterminer la longueur
l'autre pour charger le texte

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.