IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

comment obtenir en C# l'adresse de la WndProc d'une fenêtre dans un autre processus ?


Sujet :

C#

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 18
    Points : 9
    Points
    9
    Par défaut comment obtenir en C# l'adresse de la WndProc d'une fenêtre dans un autre processus ?
    Bonjour,
    Je prends comme cible la fenêtre Shell_SystrayWnd. Je suis sous windows10 en 64bits. Lors de mes recherches, certains sites mettent en garde contre le mélange 32/64 ou unicode/Ascii. Rien de cela ici.
    Mon but n'est pas d'appeler cette WndProc qui se situe dans un autre processus, donc inaccessible.
    (Note : je suppose que l'appel avec CallWndProc doit fonctionner mais je ne saurais pas passer les paramètres. Et SendMessage/PostMessage sont là pour cela je suppose)

    Spy++ affiche l'offset de la WndProc, mais non le segment. Idem pour le hInst.
    Extrait de cet affichage de Spy++:
    Windows Handle: 000201D8
    Windows Proc: 00000000 C02C4100 ( unicode )
    Instance Handle: 00000000 C0280000
    Windows Bytes: +4 00007FF7

    J'utilise le bout de code C# suivant et je le dépose dans un script Powershell pour aller plus vite :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
     
    $code=@'
    using System; 
    using System.Runtime.InteropServices;  
    namespace Win32_API 
    { 
    public enum GWL
    {
         GWL_WNDPROC =    (-4),
         GWL_HINSTANCE =  (-6),
         GWL_HWNDPARENT = (-8),
         GWL_STYLE =      (-16),
         GWL_EXSTYLE =    (-20),
         GWL_USERDATA =   (-21),
         GWL_ID =     (-12)
    }
    public class Win32_API_Class
    {
    [DllImport("user32.dll", EntryPoint="GetWindowLongPtr", SetLastError = true )]
    public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
     
    [DllImport("kernel32.dll")]
    public static extern uint GetLastError();
    //https://blogs.msdn.microsoft.com/adam_nathan/2003/04/25/getlasterror-and-managed-code/
    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className,  string windowTitle);
    public static IntPtr GetWindowLongPtr_(IntPtr hWnd, int nIndex) 
            {
     		 IntPtr ret = GetWindowLongPtr( hWnd, nIndex);
     		 if (ret == IntPtr.Zero){
     		 	Console.Write("GetLastError : {0}", GetLastError());
     		 }
     		 return ret;
    	}
    }
    }
    '@
    add-type -TypeDefinition $code
    $handle = [Win32_API.Win32_API_Class]::FindWindow("Shell_TrayWnd", "");
    "Handle  : {0:x}" -f [int]$handle
    $hinst=[Win32_API.Win32_API_Class]::GetWindowLongPtr( $handle, [int][Win32_API.GWL]::GWL_HINSTANCE)
    "hinst : {0:x}" -f [int64]$hinst
     
    [Win32_API.Win32_API_Class]::GetWindowLongPtr( $handle, [int][Win32_API.GWL]::GWL_WNDPROC)
     
    [Win32_API.Win32_API_Class]::GetWindowLongPtr_( $handle, [int][Win32_API.GWL]::GWL_WNDPROC)
    Ce qui affiche :
    Handle : 201d8
    hinst : 7ff7c0280000
    0
    GetLastError : 50

    L'erreur 50(d) : The request is not supported.

    Je ne comprends pas pourquoi l'appel de GetWindowLongPtr retourne une erreur et non la WndProc.
    Spy++ arrive bien à lire cette WndProc. Comment procède t-il ?
    Bizarre aussi que le hinst contienne le segment.

    Si vous pouvez m'expliquer ou me montrer des pistes de solution, je vous en remercie d'avance.

  2. #2
    Expert confirmé
    Avatar de wallace1
    Homme Profil pro
    Administrateur systèmes
    Inscrit en
    Octobre 2008
    Messages
    1 966
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Administrateur systèmes
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 966
    Points : 4 005
    Points
    4 005
    Billets dans le blog
    7
    Par défaut
    Bonjour,

    Pourquoi ne pas utiliser l'API FindWindow et FindWindowEx ainsi :

    http://www.pinvoke.net/default.aspx/user32.findwindow

    Car je ne suis pas convaincu que Shell_SystrayWnd existe (à voir j'ai pas vérifié) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    int hdn = NativeMethods.FindWindow("Shell_TrayWnd", string.Empty);
    int hdn1 = NativeMethods.FindWindowEx(hdn, 0, "TrayNotifyWnd", string.Empty);
    Accessoirement as-tu regarder l’implémentation de GetWindowLongPtr ici :

    http://www.pinvoke.net/default.aspx/...tWindowLongPtr

    ++

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 18
    Points : 9
    Points
    9
    Par défaut
    merci pour la réponse.
    En effet, j'ai fait une erreur en écrivant le nom de la fenêtre dans le texte.
    Mais à la ligne 40 ($handle = [Win32_API.Win32_API_Class]::FindWindow("Shell_TrayWnd", "") j'utilise bien le bon nom de fenêtre.
    C'est la ligne 42 [Win32_API.Win32_API_Class]::GetWindowLongPtr( $handle, [int][Win32_API.GWL]::GWL_WNDPROC) qui ne me retourne pas l'adresse de la WndProc alors que Spy++ la retourne.
    Je retire "l'emballage" du code Powershell pour vérifier qu'en compilant avec CSC.exe j'obtiens le même résultat.
    A+

  4. #4
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 18
    Points : 9
    Points
    9
    Par défaut
    Avec le code entièrement c#, j'obtiens la même "anomalie" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
     
    // c:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe  /target:exe   /out:.\Desktop\get-Shell_Systray.exe   .\Desktop\get-Shell_Systray.txt
     
    using System; 
    using System.Runtime.InteropServices;  
    namespace Win32_API 
    { 
    	public enum GWL
    	{
    		GWL_WNDPROC =    (-4),
    		GWL_HINSTANCE =  (-6),
    		GWL_HWNDPARENT = (-8),
    		GWL_STYLE =      (-16),
    		GWL_EXSTYLE =    (-20),
    		GWL_USERDATA =   (-21),
    		GWL_ID =     (-12)
    	}
    	public class Win32_API_Class
    	{
    		[DllImport("user32.dll", EntryPoint="GetWindowLongPtr", SetLastError = true )]
    		public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
     
    		[DllImport("kernel32.dll")]
    		public static extern uint GetLastError();
    		[DllImport("user32.dll", SetLastError = true)]
    		public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    		[DllImport("user32.dll", SetLastError = true)]
    		public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className,  string windowTitle);
            	static public IntPtr GetWindowLongPtr_(IntPtr hWnd, int nIndex) 
            	{
     			IntPtr ret = GetWindowLongPtr( hWnd, nIndex);
     			if (ret == IntPtr.Zero){
     		 		Console.Write("GetLastError : {0}", GetLastError());
     		 	}
     		 	return ret;
    		}
    		static int Main()
    		{
    			IntPtr handle  = FindWindow("Shell_TrayWnd", "");
    			Console.WriteLine("handle Shell_TrayWnd: 0x{0:x}", (int)handle);
    			IntPtr hInst   = GetWindowLongPtr( handle, (int)GWL.GWL_HINSTANCE);
    			Console.WriteLine("hInst : 0x{0:x}", (Int64)hInst);
    			IntPtr wndProc = GetWindowLongPtr( handle, (int)GWL.GWL_WNDPROC);
    			Console.WriteLine("wndProc : 0x{0:x}", (Int64)wndProc);
    			Console.WriteLine("GetLastError : {0}", GetLastError());
    			return 0;
    		}
    	}
    }
    C:\Users\noel>.\Desktop\get-Shell_Systray.exe
    handle Shell_TrayWnd: 0x201d8
    hInst : 0x7ff7c0280000
    wndProc : 0x0
    GetLastError : 5 --->>> access denied
    (note : On voit que le hInst contient aussi le segment, en plus de l'offset.)
    Des idées pour cette anomalie dans le retour de l'adresse de la WndProc ?
    Merci d'avance.

  5. #5
    Expert confirmé
    Avatar de wallace1
    Homme Profil pro
    Administrateur systèmes
    Inscrit en
    Octobre 2008
    Messages
    1 966
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Administrateur systèmes
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 966
    Points : 4 005
    Points
    4 005
    Billets dans le blog
    7
    Par défaut
    Comme évoqué plus haut as-tu regardés l'implémentation x32/x64 ici :

    http://www.pinvoke.net/default.aspx/...tWindowLongPtr

  6. #6
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 18
    Points : 9
    Points
    9
    Par défaut
    Mon script powershell contient une coquille. Avec la ligne suivante :
    Console.WriteLine("GetLastError : {0}", GetLastError());
    et non
    Console.Write("GetLastError : {0}", GetLastError());

    j'obtiens bien la même erreur, soit l'erreur 5 = access denied
    (note: le 5 provient du code C#, sans retour de ligne à cause du write, et le powershell ajoutait un zéro à cause du retour de la fonction. Bref, une erreur de jeunesse).

    Mais alors comment fait Spy++ pour afficher la wndProc ?
    J'ai essayé en lançant ce bout de code avec les droits "administrateur" mais j'ai encore l'erreur 5.

    Si quelqu'un peut me dire comment faire pour lire l'adresse de la wndProc d'un autre process, ce serait super.
    Merci d'avance.

  7. #7
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 18
    Points : 9
    Points
    9
    Par défaut
    @wallace1
    Oui bien sûr j'ai fouillé tant que j'ai pu dans pinvoke et dans msdn aussi.

Discussions similaires

  1. Réponses: 4
    Dernier message: 06/04/2014, 12h32
  2. Réponses: 1
    Dernier message: 22/02/2007, 14h36
  3. Réponses: 7
    Dernier message: 27/04/2006, 16h58
  4. Réponses: 12
    Dernier message: 27/06/2005, 19h06

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo