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

Windows Discussion :

[C#] Crash SetWindowLong


Sujet :

Windows

  1. #1
    Membre confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut [C#] Crash SetWindowLong
    Salut,

    J'essai d'intercepter les messages d'une fenêtre externe à mon application.
    J'ai fait un wrapper que voici:

    Code c# : 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
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
     
    using System;
    using System.Linq;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.InteropServices;
    using OpenNETCF.Windows.Forms;
    using System.Windows.Forms;
     
    namespace WindowHookWrapper
    {
        public struct HTCTOUCH_WPARAM
        {
            public byte Up;    //0=KeyDown,1=KeyUp
            public byte Where; //Where the click occurs (left pane, wheel, right pane)
            //Pos for the Right Pane click
            public byte xPosRP;
            public byte yPosRP;
        }
     
        class WindowHooker : IDisposable
        {
            const int GW_WNDPROC = -4;
     
            delegate int WndProcHandler(IntPtr hwnd, int message, int wParam, int lParam);
     
            [DllImport("coredll")]
            extern static IntPtr SetWindowLong(IntPtr hWnd, int dwId, IntPtr newLong);
     
            [DllImport("coredll")]
            extern static int CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, int Msg, int wParam, int lParam);
     
            [DllImport("coredll")]
            extern static bool IsWindow(IntPtr hWnd);
     
            IntPtr pOldProc;
            IntPtr pHandle;
     
            WndProcHandler WndProcH;
     
            private int WndProc(IntPtr hWnd, int uMsg, int wParam, int lParam)
            {
                return CallWindowProc(pOldProc, hWnd, uMsg, wParam, lParam);
            }
     
            public WindowHooker(IntPtr handle)
            {
                pOldProc = IntPtr.Zero;
                pHandle = IntPtr.Zero;
                WndProcH = new WndProcHandler(WndProc);
                if (handle != IntPtr.Zero)
                {
                    HookWindow(handle);
                }
            }
     
            public void UnHookWindow()
            {
                if( pOldProc != IntPtr.Zero && pHandle != IntPtr.Zero )
                {
                    if( IsWindow( pHandle ) )
                    {
                        try
                        {
                            SetWindowLong(pHandle, GW_WNDPROC, pOldProc);
                        }
                        catch
                        {
                            // Unable to setwindowlong...
                        }
                    }
                }
                pOldProc = IntPtr.Zero;
                pHandle = IntPtr.Zero;
            }
     
            public void HookWindow(IntPtr handle)
            {
                if ((pOldProc == IntPtr.Zero) && (pHandle == IntPtr.Zero))
                {
                    if (IsWindow(handle))
                    {
                        pOldProc = SetWindowLong(handle, GW_WNDPROC, Marshal.GetFunctionPointerForDelegate(WndProcH));
                        pHandle = handle;
                    }
                }
                else
                {
                    UnHookWindow();
                    HookWindow(handle);
                }
            }
     
            public void Dispose()
            {
     
            }
        }
    }

    Et je l'utilise de cette manière:

    Code C# : 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
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
     
    using System;
    using System.Linq;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
     
    namespace WindowHookWrapper
    {
        public partial class Form1 : Form
        {
            [DllImport("coredll")]
            extern static int GetClassName(IntPtr hWnd, StringBuilder sBuffer, int nChars);
     
            [DllImport("coredll")]
            extern static IntPtr GetForegroundWindow();
     
            [DllImport("coredll")]
            static extern int ShowWindow(IntPtr hWnd, int nCmdShow);
     
            WindowHooker myHooker;
            Timer tTimer;
            StringBuilder sBuff;
            short nChars = 256;
     
            public Form1()
            {
                InitializeComponent();
     
                myHooker = new WindowHooker(IntPtr.Zero);
     
                sBuff = new StringBuilder(nChars);
     
                tTimer = new Timer();
                tTimer.Interval = 1000;
                tTimer.Tick += new EventHandler(tTimer_Tick);
                tTimer.Enabled = true;
            }
     
            IntPtr handle = IntPtr.Zero;
            void tTimer_Tick(object sender, EventArgs e)
            {
                if (handle == IntPtr.Zero)
                    handle = GetForegroundWindow();
     
                if (!GetForegroundWindow().Equals(handle))
                {
                    handle = GetForegroundWindow();
                    if (GetClassName(GetForegroundWindow(), sBuff, 256) > 0)
                    {
                        if (sBuff.ToString().CompareTo("ApplicationClass") == 0)
                        {
                            myHooker.HookWindow(handle);
                        }
                    }
                }
     
     
            }
     
            private void button1_Click(object sender, EventArgs e)
            {
                ShowWindow(this.Handle, 6); // Minimize
            }
        }
    }

    Mais mon logiciel fait tout crasher quand je ferme cette dite application.

    Quelqu'un a une idée ?

    Merci d'avance

    P.S.: J'utilise ce code sur un PDA sous Windows Mobile 6

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Ça ne changera pas grand-chose si tu es en 32 bits, mais tous les paramètres de WndProc, sauf message, doivent être de type IntPtr (wParam est un UINT_PTR et lParam est un LONG_PTR). De même pour la valeur de retour.

    Et aussi, j'ignore comment (ou même si, vu que ce n'est pas du tout la même convention d'appel: __clrcall vs __stdcall) les delegates marchent avec les pointeurs de fonction, mais WndProc devrait être static.

    Mais Franchement, pour ça, je te conseillerais plutôt de bosser en C++/CLI qu'en C#.

    PS: Que signifie exactement le "p" de pHandle ?
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Ça ne changera pas grand-chose si tu es en 32 bits, mais tous les paramètres de WndProc, sauf message, doivent être de type IntPtr (wParam est un UINT_PTR et lParam est un LONG_PTR). De même pour la valeur de retour.

    Et aussi, j'ignore comment (ou même si, vu que ce n'est pas du tout la même convention d'appel: __clrcall vs __stdcall) les delegates marchent avec les pointeurs de fonction, mais WndProc devrait être static.

    Mais Franchement, pour ça, je te conseillerais plutôt de bosser en C++/CLI qu'en C#.

    PS: Que signifie exactement le "p" de pHandle ?
    Bonjour et merci pour ta réponse.

    J'avais d'abord tenté en IntPtr mais ça me faisait la même chose, pareil pour WndProc quand je le passe en static.

    le p de pHandle est un héritage que je garde de ma programmation C++. Il désigne les pointeurs (je sais qu'en C# tout passe par référence, mais c'est juste pour que je sache qu'ici, j'utilise un type "pointeur", càd IntPtr).

    Marshal.GetFunctionPtrForDelegate me demande bien un delegate pour ressortir un void(*func).

    M'enfin... Mon code complet fait plus de 3000 lignes de code et tout passer en C++, ça va être juste un peu chaud quoi :\.

    Une autre idée peut-être ? Pourquoi le code ci-dessus ne marche pas ? (même celui avec les changements indiqués)

    Je cherche je cherche je cherche mais vraiment impossible de comprendre pourquoi exactement ça ne marche pas. Si c'était pour un seul logiciel précis, j'aurais pu créer une dll en C++ pour le hook, mais malheureusement, c'est pour pouvoir capter les messages de n'importe quel fenêtre ouverte...

  4. #4
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Je pense que tu devrais créer une DLL en C++/CLI qui appelle des callbacks en C# (via une interface ou des delegates, ou même par héritage). Tu serais plus libre.

    Mon conseil: n'utilise pas "pHandle" pour un handle, car selon les conventions de Windows, ça ressemble plus à un pointeur sur handle. Appelle plutôt ta variable "hQuelqueChose", comme c'est fait dans les exemples de MSDN...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Membre confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Je pense que tu devrais créer une DLL en C++/CLI qui appelle des callbacks en C# (via une interface ou des delegates, ou même par héritage). Tu serais plus libre.
    C'est possible d'injecter une dll en plein execution du programme injecté ? Jusqu'ici j'ai toujours intercepter la création du process et injecté à ce moment. Mais dans mon cas actuel, ceci n'est pas possible.

  6. #6
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    J'ai du mal à voir ce que tu veux dire.
    Quelle différence vois-tu entre un programme C# simple et un programme C# dont une des classes dérive d'une classe d'une DLL en C++/CLI ?
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  7. #7
    Membre confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut
    Je crois que je me suis mal exprimé.

    En fait, je dois intercepter les messages de fenêtres qui n'appartiennent pas à mon logiciel, dont je n'ai pas le code source ni rien. En fait c'est pour pouvoir intercepter un message précis envoyé par la machine vers la fenêtre actuelle uniquement, mais pour que mon logiciel fonctionne j'ai aussi besoin de l'avoir, donc je dois intercepter les messages de la fenêtre actuelle pour pouvoir récupérer ce message.

    Vu que je n'ai pas le code source de ce programme, je dois hooker le WndProc de cette fenêtre. En C#, mon code ci-dessus plante comme je l'ai dit. Je peux hooker la boucle des messages via C++ mais ça ne marche que si j'injecte ma dll au moment où le programme démarre. Et dans mon cas, lorsqu'on lance mon logiciel, j'ai besoin de capter les messages de n'importe quel fenêtre. Et je me vois mal injecter ma dll dans toutes les fenêtres existantes, lol.

  8. #8
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Je sais que dans le cas d'une DLL en C++ normal non-managée, elle est injectée d'elle-même quand tu hookes une fenêtre...
    De plus, j'ai du mal à voir comment tu peux injecter une DLL managée dans n'importe quel programme...

    Donc, je conseille à présent une DLL en C++ normal, qui chargerait tes composants C# via COM...
    Ou mieux, se chargerait simplement de communiquer avec ton programme principal via sockets ou un autre mécanisme d'IPC...

    En clair, ne pas faire ton hook en .Net.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  9. #9
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Addendum: Euh... en fait, là dans ton code, tu ne hookes même pas!

    Tu subclasses... Et je ne sais même pas si faire ça d'un processus à l'autre est seulement possible...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  10. #10
    Membre confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Addendum: Euh... en fait, là dans ton code, tu ne hookes même pas!

    Tu subclasses... Et je ne sais même pas si faire ça d'un processus à l'autre est seulement possible...
    Vi, je n'hook pas dans mon code, je subclass, évidemment vu que hooker en C#, c'est pas gagné.

    Subclasser une fenêtre externe à l'application, ça fonctionne, vu que j'arrive à intercepter les messages. Seulement quand je change de fenêtre ou que je quitte l'application subclassée, ça plante. C'est ça que j'comprend pas.

  11. #11
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Peut-être que tu ne dé-subclasses pas correctement ?
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  12. #12
    Membre confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Peut-être que tu ne dé-subclasses pas correctement ?
    C'est exactement ma question. Mais je ne vois pas où dans mon code je fais une erreur

  13. #13
    Expert éminent sénior
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 361
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 361
    Points : 20 381
    Points
    20 381
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Peut-être que tu ne dé-subclasses pas correctement ?
    J'aurais dit exactement la même chose j'ai eu un problème similaire récemment.
    Quelque chose me chagrine :
    pOldProc = IntPtr.Zero;
    pHandle = IntPtr.Zero;
    Le pointeur pointant sur la WndProc initiale me semble-t-il pointe sur zéro ?Je me trompe ?

    question : c'est pas possible de faire tout en .NET ?
    Sinon je conseillerais de faire un petit projet lambda MFC avec une Dialog cela ne devrait pas être compliqué

  14. #14
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    pOldProc est initialisé dans la fonction HookWindow().
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

Discussions similaires

  1. STL::vector crash a l"execution
    Par sebA dans le forum MFC
    Réponses: 2
    Dernier message: 16/06/2004, 16h36
  2. Crash de mon dvd encrypté avec xine
    Par Slein dans le forum Applications et environnements graphiques
    Réponses: 3
    Dernier message: 06/06/2004, 16h45
  3. [IB6] mon serveur crash apres des insert en série...
    Par Rmotte dans le forum Débuter
    Réponses: 11
    Dernier message: 27/05/2004, 14h53
  4. DLL Borland chargée par Windows: crash
    Par bocher dans le forum C++Builder
    Réponses: 2
    Dernier message: 08/01/2004, 12h09
  5. Crash Base Access
    Par Ronald G. dans le forum Access
    Réponses: 4
    Dernier message: 04/08/2003, 11h55

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