Appels récursifs à des fonctions de gestionnaire de fenêtre peuvent échouer de façon inattendue

S’applique à : Windows

Symptômes


Appels récursifs à des fonctions de gestionnaire de fenêtre exportées par USER32. DLL peut retourner sans effectuer l’opération demandée et sans définir un code d’erreur. Cela se produit généralement dans les applications avec une hiérarchie de fenêtre profondément imbriqués. Parmi les problèmes, vous pouvez rencontrer :
  • Applications avec une hiérarchie de fenêtre profondément imbriqués ne pas redimensionner les fenêtres enfants correctement lorsque la fenêtre frame est redimensionnée. Windows sont déplacés ou redimensionnés en appelant MoveWindow, SetWindowPos ou DeferWindowPos.
  • Messages de fenêtre ne sont pas propagées aux fenêtres parentes ou aux fenêtres enfants comme prévu. DefWindowProc ne peut pas propager correctement les messages vers la fenêtre parente ou les fenêtres enfants de la fenêtre de réception du message.
  • Les messages de fenêtre envoyés à une fenêtre en appelant SendMessage, SendMessageTimeout ou SendMessageCallback ne sont pas reçus par la fenêtre spécifiée.
En outre, les applications dans le cas contraire, fonctionner normalement peuvent également rencontrer les problèmes décrits ci-dessus si les crochets de fenêtre WH_CALLWNDPROC ou WH_CALLWNDPROCRET sont définis sur les threads qui possèdent les fenêtres dans l’application. Les crochets de fenêtre peuvent être définies sur un thread spécifique ou sur tous les threads d’interface utilisateur en appelant la fonction SetWindowsHookEx.

Cause


Ce problème est le résultat de Windows est impossible d’agrandir la pile du noyau du thread appelant pour effectuer l’opération demandée. En raison de la pile noyau supplémentaires les manipulations nécessaires dans les x64 l’environnement Windows, la pile du noyau peut être consommée à un rythme plus rapide que dans un environnement Windows lorsque les appels récursifs à des fonctions de gestionnaire de fenêtre exportée de x86 par USER32. DLL. bien que les symptômes décrits dans cet article sont plus susceptibles de se produire, dans x64, les plates-formes Windows, il est possible pour les appels récursifs à consommer la pile du noyau d’un thread sur x86 les plates-formes Windows.

Résolution


Les solutions suivantes peuvent être utilisées pour contourner ce problème
  1. Redimensionner les fenêtres enfants lors de la gestion des messages de fenêtre WM_WINDOWPOSCHANGED au lieu de cela passer le message à DefWindowProc.
  2. En mode asynchrone redimensionner les fenêtres enfants lorsque la fenêtre parent est redimensionnée au lieu de redimensionner les fenêtres enfants lors du traitement de la WM_WINDOWPOSCHANGED ou le message WM_SIZE.
  3. Reconcevez l’application de l’interface utilisateur afin de réduire la profondeur de la fenêtre imbriquée.

Informations supplémentaires


Certaines parties du sous-système Win32 sont implémentées dans un pilote de périphérique en mode noyau (WIN32K. (SYS). Appels aux fonctions exportées par USER32. DLL pour modifier l’état d’une fenêtre, y compris sa taille et sa position, appelle WIN32K. SYS pour effectuer l’opération demandée. Résultat des fonctions qui modifient l’état d’une fenêtre en général dans les messages de fenêtre envoyés à la fenêtre en cours de modification, où WIN32K. SYS est une légende en mode utilisateur pour appeler la procédure de fenêtre de la fenêtre en cours de modification. Par exemple, WIN32K. SYS pour envoyer une fenêtre un message de fenêtre WM_WINDOWPOSCHANGING et un message de fenêtre WM_WINDOWPOSCHANGED lorsque la taille et/ou la position de la fenêtre est modifiée en appelant la fonction SetWindowPos. DefWindowProc envoie la fenêtre spécifiée un message WM_SIZE lorsqu’elle est appelée avec un message WM_WINDOWPOSCHANGED et la taille de la fenêtre a été modifié. Applications redimensionnement généralement les fenêtres enfants lorsque la fenêtre parent reçoit un message de fenêtre WM_WINDOWPOSCHANGED ou WM_SIZE, qui conduit à des appels récursifs dans WIN32K. SYS pour les hiérarchies de fenêtre profondément imbriqués. Applications qui sinon fonctionnent normalement peuvent également rencontrer les problèmes décrits dans cet article, lorsque les crochets WH_CALLWNDPROC ou WH_CALLWNDPROCRET sont définies sur des threads dans le processus. Ceci est dû à l’espace de pile de noyau supplémentaires qui est consommée lorsque WIN32K. SYS gère les procédures de hook d’appel. Appel SendMessage pour envoyer un message de fenêtre pour une fenêtre appartienne au thread appelant appelle généralement la procédure de fenêtre de la fenêtre de réception du message sans avoir à appeler dans WIN32K. SYS. Toutefois, appelle SendMessage dans WIN32K. SYS, s’il existe des raccordements WH_CALLWNDPROC ou WH_CALLWNDPROCRET raccorde ensemble sur le thread appelant, comme WIN32K. SYS gère les raccordements et les poignées appelant des procédures de hook. Comme indiqué ci-dessus, DefWindowProc envoie la fenêtre spécifiée un message WM_SIZE lorsqu’elle est appelée avec un message WM_WINDOWPOSCHANGED et la taille de la fenêtre a été modifié. Un raccordement WH_CALLWNDPROC ou un WH_CALLWNDPROCRET entraîne l’appel SendMessage DefWindowProc facilite la transition en mode noyau pour appeler les procédures de hook. Redimensionnement de fenêtres enfants lors de la gestion des messages de fenêtre WM_WINDOWPOSCHANGED au lieu de messages de fenêtre WM_SIZE permet de réduire l’utilisation de pile de noyau en éliminant le besoin de SendMessage pour passer en mode noyau appellent les procédures de hook. Les développeurs d’applications Windows Forms qui rencontrent ce problème doivent faire référence à la base de connaissances l’article 953934pour plus d’informations.