Fenetre modale inaccessible

Le
Olivier Miakinen
[ diapublication dans fcom et fcom.programmation, suivi vers ce dernier ]

Bonjour,

J'ai un problème avec un CDialog dans *un* cas particulier, et je
voudrais solliciter votre aide pour le résoudre.

-

Le programme (C++) définit une classe de la manière suivante (je
remplace tout ce qui est peu important par des « ») :

class MyDlg : public CDialog
{
public:
MyDlg(, CWnd* pParent);


}

MyDlg::MyDlg(, CWnd *pParent) : CDialog(MyDlg::IDD, pParent)
{

}

Elle est appelée par :


MyDlg dlg(, CWnd::FromHandle(hParentWnd));

int ret = dlg.DoModal();


-

Pour simplifier, nommons P la fenêtre correspondant au hParentWnd, et D
la fenêtre de type MyDlg.

Dans l'immense majorité des cas, la fenêtre D prend le focus, avec une
barre de titre en bleu, tandis que la fenêtre P le perd et voit sa barre
de titre passer en gris. On peut saisir des trucs dans la fenêtre D,
mais on ne peut pas redonner le focus à P tant qu'on n'a pas fermé D.

Dans *un* cas, pourtant, les fenêtres P et D ont toutes les deux leur
titre en bleu mais il est impossible de saisir quoi que ce soit dans D,
quoiqu'il soit tout aussi impossible de rendre P active. La seule
solution consiste à cliquer n'importe où pourvu que ce soit ailleurs
que dans P ou dans D, ce qui a pour effet de mettre la barre de titre
de P en gris, et à ce moment-là on peut cliquer sur D pour commencer la
saisie.

-

Comment ce comportement est-il possible ? Et surtout, comment le
contourner ? Je précise que je n'ai pas accès au code de la fenêtre P,
qui fait partie d'un programme du commerce (je donnerai son nom au
besoin), mais seulement au code gérant la fenêtre D. Au cas où ça
pourrait être utile, je suis sur Windows XP Professionnel, mais ce
programme est censé fonctionner sur d'autres types de Windows aussi.

Cordialement,
--
Olivier Miakinen
Vos réponses
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
nico
Le #18841601
"Olivier Miakinen" news:49b156ed$
-------------------------------------------------------------------

Comment ce comportement est-il possible ? Et surtout, comment le
contourner ? Je précise que je n'ai pas accès au code de la fenêtre P,
qui fait partie d'un programme du commerce (je donnerai son nom au
besoin), mais seulement au code gérant la fenêtre D. Au cas où ça
pourrait être utile, je suis sur Windows XP Professionnel, mais ce
programme est censé fonctionner sur d'autres types de Windows aussi.



Ca parait difficile à comprendre... Peut-être qu'aucun controle n'a le focus
.
A tout hasard, on pourrait peut-être toujours forcer le focus sur un
controle sur le WM_INITDIALOG de D
Olivier Miakinen
Le #18842341
Le 06/03/2009 21:58, nico a écrit :

Comment ce comportement est-il possible ? Et surtout, comment le
contourner ? Je précise que je n'ai pas accès au code de la fenêtre P,
qui fait partie d'un programme du commerce (je donnerai son nom au
besoin), mais seulement au code gérant la fenêtre D. Au cas où ça
pourrait être utile, je suis sur Windows XP Professionnel, mais ce
programme est censé fonctionner sur d'autres types de Windows aussi.



Ca parait difficile à comprendre...



Merci de ton soutien ! ;-)

Peut-être qu'aucun controle n'a le focus



Ce qui est curieux, c'est qu'on dirait au contraire d'après la couleur
des titres que les deux fenêtres ont le focus. D'ailleurs habituellement
on peut donner le focus à une fenêtre en cliquant dessus, ce qui n'est
pas le cas de la fenêtre D. Qui plus est, c'est vraiment en *retirant*
le focus à la fenêtre P (en cliquant sur une fenêtre autre que P ou D)
que je parviens ensuite à redonner ce focus à la fenêtre D en cliquant
dessus.

A tout hasard, on pourrait peut-être toujours forcer le focus sur un
controle sur le WM_INITDIALOG de D



Si tu connais un truc pour retirer le focus par programme à la fenêtre
P, je suis preneur. Je pense que c'est vraiment ça qui résoudrait le bug
(ou du moins qui le contournerait).
Sylvain SF
Le #18842701
Olivier Miakinen a écrit :

J'ai un problème avec un CDialog dans *un* cas particulier, et je
voudrais solliciter votre aide pour le résoudre.

class MyDlg : public CDialog {
public:
MyDlg(..., CWnd* pParent) : CDialog(MyDlg::IDD, pParent)
{
...
}

Elle est appelée par :

MyDlg dlg(..., CWnd::FromHandle(hParentWnd));



qui définit ce 'hParentWnd' ?
la création du dial. devrait être faite par le frame
principal, je m'attends à cela.

or ici la fenêtre gérant l'event en cours passe par son
parent pour créer le dial. pourquoi pas en terme de
relation fenêtre principal / child (dont modal) mais
cela peu tavoir un effet sur la ... désélection si
le DoModal qui suit ne peut pas retrouver ce parent.

par ailleurs FromHandle est réputé retourné un pointeur
volatile, même si le sus-évoqué parent existe et est
correct dans la hiérarchie, il se peut que le CWnd*
obtenu ne soit plus valide lors de l'entrée dans DoModal.
pourquoi utilises-tu FromHandle et non directement un CWnd* ?

Sylvain.
Olivier Miakinen
Le #18849101
Bonjour,

Le 07/03/2009 01:12, Sylvain SF a écrit :

[...]

MyDlg dlg(..., CWnd::FromHandle(hParentWnd));



qui définit ce 'hParentWnd' ?



Tu veux dire : « qui crée la fenêtre correspondante » ou « comment
obtient-on ce handle » ?

La réponse à la première des deux questions est « un programme autre que
celui que j'ai à maintenir ». Cela peut être n'importe quel programme,
par exemple Notepad ou Wordpad, Internet Explorer, Firefox, Thunderbird,
une application propriétaire d'une obscure entreprise, ou d'un grand
groupe bancaire... n'importe qui ou n'importe quoi. En l'occurrence,
cela marche depuis des années avec tous les programmes ci-dessus, mais
il se trouve que ça ne marche plus avec la fenêtre d'authentification
de Lotus Notes, depuis qu'il est passé en version 8.0 (en tout cas en
8.0.2).

Concernant la seconde question, il faudrait que je me replonge dans le
code pour une réponse technique précise, mais en gros on fait appel à
une API Windows qui nous donne la liste de toutes les fenêtres ouvertes
avec leur HWND et leur titre.

la création du dial. devrait être faite par le frame
principal, je m'attends à cela.



Si tu veux dire que ça doit être fait par le programme qui a créé le
HWND, alors non, ce n'est pas possible. On n'a pas accès à ce code.

or ici la fenêtre gérant l'event en cours passe par son
parent pour créer le dial. pourquoi pas en terme de
relation fenêtre principal / child (dont modal) mais
cela peut avoir un effet sur la ... désélection si
le DoModal qui suit ne peut pas retrouver ce parent.



Seulement, comme je le signale ci-dessus, cela fonctionne parfaitement
et depuis des années avec des hParentWnd provenant d'applications aussi
diverses que variées. Seul Lotus Notes nous pose problème, et seulement
depuis la version 8.0.2.

par ailleurs FromHandle est réputé retourné un pointeur
volatile, même si le sus-évoqué parent existe et est
correct dans la hiérarchie, il se peut que le CWnd*
obtenu ne soit plus valide lors de l'entrée dans DoModal.



Non, il n'y a que trois ou quatre lignes de code entre la création et
le DoModal (juste quelques vérifications d'usage). Autant dire que c'est
immédiat.

pourquoi utilises-tu FromHandle et non directement un CWnd* ?



Cf. supra : on ne connaît les fenêtres ouvertes sur le système que par
leur HWND.
Sylvain SF
Le #18850501
Olivier Miakinen a écrit :

La réponse à la première des deux questions est « un programme autre que
celui que j'ai à maintenir ». [...] (Lotus Notes, 8.0.2).



OK, je comprends mieux.

pas mal d'applications (de + en +) ont tendance à se manifester
n'importe quand. des alertes systray mal codés, en passant par
l'explorateur lui-même, nombre de codes s'autorisent à prendre
le focus en se mettant au premier plan.

une explication simple à ton problème serait que, parfois, Lotus 8.0.2
veux se manifester (ou simplement peut être updater son affichage dans
un code mal écrit) et fait un bringToFront (ou équivalent), il arrive
alors à s'activer (être en bleu) sans avoir le focus utilisateur (car
il y a quand même un child modal ouvert), dans le même temps ce child
(ton dialog) a perdu le focus sans être déactivé, il en résulte le
blocage décrit (2 fenêtres sélectionnées et aucune avec un vrai focus).

j'ai déjà rencontré cela avec des codes non conformes, je crains que
tu ne puisses rien y faire car le souci vient très semblablement de
Lotus; éventuellement un thread associé au dialogue et qui scrute son
état pourrait le réactiver s'il perd incorrectement le focus.

btw, ton code est un plug-in Lotus tournant dans le process Lotus
ou une appli. distincte qui greffe des HWND child aux fenêtres /
process de Lotus (le second cas va favoriser les noeuds).

Sylvain.
Olivier Miakinen
Le #18864691
Bonjour, et merci pour le temps que tu passes sur ce problème.

Le 08/03/2009 04:12, Sylvain SF a écrit :

une explication simple à ton problème serait que, parfois, Lotus 8.0.2
veux se manifester (ou simplement peut être updater son affichage dans
un code mal écrit) et fait un bringToFront (ou équivalent), il arrive
alors à s'activer (être en bleu) sans avoir le focus utilisateur (car
il y a quand même un child modal ouvert), dans le même temps ce child
(ton dialog) a perdu le focus sans être déactivé, il en résulte le
blocage décrit (2 fenêtres sélectionnées et aucune avec un vrai focus).



L'explication est séduisante. Quoi qu'il en soit, il ne semble pas que
ce soit dû à une remise en avant « intempestive ». En effet, alors que
le phénomène apparaît immédiatement, lorsque j'ai retiré le focus à la
fenêtre Lotus Notes en cliquant ailleurs, elle ne reprend jamais le
focus d'elle-même. Par ailleurs, si je clique sur l'icone de Notes dans
la barre des applications actives (désolé, je ne connais pas son petit
nom), cela rebloque le tout en tentant de rendre active la fenêtre P,
alors que faire la même manip pour toute autre application rend active
la fenêtre D.

j'ai déjà rencontré cela avec des codes non conformes, je crains que
tu ne puisses rien y faire car le souci vient très semblablement de
Lotus; éventuellement un thread associé au dialogue et qui scrute son
état pourrait le réactiver s'il perd incorrectement le focus.



N'y a-t-il pas un événement que l'on pourrait envoyer à la fenêtre P
pour lui dire « tu n'as plus le focus » ? Le genre de truc qui se passe
quand on clique sur l'icone dans la barre des applications actives...
En fait, si je pouvais simuler ce clic par programmation, ça pourrait
peut-être marcher (je dois quand même vérifier que ça ne va pas retirer
le focus à ma fenêtre D quand la fenêtre P est autre chose que Lotus Notes).

btw, ton code est un plug-in Lotus tournant dans le process Lotus
ou une appli. distincte qui greffe des HWND child aux fenêtres /
process de Lotus (le second cas va favoriser les noeuds).



Je pense en effet être dans le second cas, quoique je ne comprenne pas
ce que signifie le premier cas (plug-in Lotus ?).
Henri
Le #18866461
"Olivier Miakinen" news:49b59f3c$

N'y a-t-il pas un événement que l'on pourrait envoyer à la fenêtre P
pour lui dire « tu n'as plus le focus » ? Le genre de truc qui se passe
quand on clique sur l'icone dans la barre des applications actives...
En fait, si je pouvais simuler ce clic par programmation, ça pourrait
peut-être marcher (je dois quand même vérifier que ça ne va pas retirer
le focus à ma fenêtre D quand la fenêtre P est autre chose que Lotus
Notes).



On peut toujours le faire avec un mouse_event(), mais ce n'est pas très
propre..
Olivier Miakinen
Le #18885501
Le 10/03/2009 09:51, Henri m'a répondu :

N'y a-t-il pas un événement que l'on pourrait envoyer à la fenêtre P
pour lui dire « tu n'as plus le focus » ? Le genre de truc qui se passe
quand on clique sur l'icone dans la barre des applications actives...
[...]



On peut toujours le faire avec un mouse_event(), mais ce n'est pas très
propre..



Oui, en effet. Qui plus est, ça risque de ne pas être simple cette
affaire ! Bon, je continue à chercher, je tiendrai le groupe au
courant si jamais je trouvais une solution miracle.

Cordialement,
--
Olivier Miakinen
Publicité
Poster une réponse
Anonyme