OVH Cloud OVH Cloud

EnumWindow API insuffisant sous Terminal Server (panique!)

12 réponses
Avatar
Philippe
Bonjour,

je viens d'écrire une application en VB6, dont un programme est chargé
d'envoyer un message windows à toutes les fenetres d'un certain type de
la machine.

Cela marche très bien avec EnumWindow, mais seulement aussi longtemps
qu'on est sans Terminal.

Sous Terminal server, on ne trouve que les fenetres de la session
courante, pas celles des autres sessions.

Comment faire ?
Merci de toute aide....

Philippe (desepéré!)

10 réponses

1 2
Avatar
Arnaud Debaene
Philippe wrote:
Bonjour,

je viens d'écrire une application en VB6, dont un programme est chargé
d'envoyer un message windows à toutes les fenetres d'un certain type
de la machine.

Cela marche très bien avec EnumWindow, mais seulement aussi longtemps
qu'on est sans Terminal.

Sous Terminal server, on ne trouve que les fenetres de la session
courante, pas celles des autres sessions.


C'est normal! Le principe de Terminal Server, c'est de fournir des espaces
de travail (Windows station / desktop) *séparés* pour les différents
utilisateurs, et qu'ils ne puissent pas interagir les uns avec les autres!

Comment faire ?


A priori, la seule solution c'est d'avoir un "agent" qui a la possibilité
d'ouvrir les desktops de chaque session et qui fasse l'EnumWindow dans
chaque desktop. Ce devrait très probablement être un service (pour avoir les
droits nécessaires).
Ceci dit, c'est un peu usine à gaz et c'est surtout complètement contraire à
l'esprit même de Terminal Server (sans parler des implications de sécurité).

Arnaud
Avatar
Philippe Michel
Arnaud Debaene wrote:
Philippe wrote:

Bonjour,

je viens d'écrire une application en VB6, dont un programme est chargé
d'envoyer un message windows à toutes les fenetres d'un certain type
de la machine.

Cela marche très bien avec EnumWindow, mais seulement aussi longtemps
qu'on est sans Terminal.

Sous Terminal server, on ne trouve que les fenetres de la session
courante, pas celles des autres sessions.



C'est normal! Le principe de Terminal Server, c'est de fournir des espaces
de travail (Windows station / desktop) *séparés* pour les différents
utilisateurs, et qu'ils ne puissent pas interagir les uns avec les autres!


Comment faire ?



A priori, la seule solution c'est d'avoir un "agent" qui a la possibilité
d'ouvrir les desktops de chaque session et qui fasse l'EnumWindow dans
chaque desktop. Ce devrait très probablement être un service (pour avoir les
droits nécessaires).
Ceci dit, c'est un peu usine à gaz et c'est surtout complètement contraire à
l'esprit même de Terminal Server (sans parler des implications de sécurité).



L'esprit Terminal Server ? vaste debat je crois...;o)

Disons que l'objectif, est que plusieurs utlisateurs visualisent un
écran de controle. Chaque fois qu'un nouvel enregistrement arrive dans
la base (alerte), il faut que le prog qui l'inscript avertisse tous les
programmes de controls. Comment faire ? Des messages au processus ou
thread en VB, ca n'a jamais été envisagé par les concepteurs de vb. J'ai
essayé plusieurs API, mais ca ne mene à rien.

Pour l'instant c'est la deche complete. J'envisage effectivement
d'écrire un service (en C cette fois!) auquel les prog de controle se
connecte par IP (tcp ou udp), et qui avertira ceux-ci dès qu'il se passe
quelque chose. Il faudra bien sur que ce quelque chose se manifeste
auprès du service.... mais le temps presse comme d'hab.

Philippe
Avatar
Remi Thomas
>
Disons que l'objectif, est que plusieurs utlisateurs visualisent un écran
de controle. Chaque fois qu'un nouvel enregistrement arrive dans la base
(alerte), il faut que le prog qui l'inscript avertisse tous les programmes
de controls. Comment faire ? Des messages au processus ou thread en VB, ca
n'a jamais été envisagé par les concepteurs de vb. J'ai essayé plusieurs
API, mais ca ne mene à rien.

Pour l'instant c'est la deche complete. J'envisage effectivement d'écrire
un service (en C cette fois!) auquel les prog de controle se connecte par
IP (tcp ou udp), et qui avertira ceux-ci dès qu'il se passe quelque chose.
Il faudra bien sur que ce quelque chose se manifeste auprès du service....
mais le temps presse comme d'hab.

Philippe



Salut,

Tu peux partager un event entre plusieurs process.
Comme l'indique la doc de CreateEvent tu peux même préciser si ce mutex est
visible entre les sessions Terminal Server ou non.
Tu peux aussi partager un memory mapped file dans l'espace système, le
mécanisme le plus simple pour partager de l'information 1 vers n.

Voir le code plus bas ou tu peux récupérer le projet ici:
http://www.xtware.com/client-server.zip

Rémi

--
Rémi Thomas - MVP Visual Studio .NET
Développeur Windows indépendant
http://www.xtware.com/cv


----SERVEUR
struct Message1
{
char messageId;
int valeur1;
char message[256];
};

void main(int argc, char* argv[])
{
// Creation de l'event partagé avec les autres process
HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, "GlobalBDD_EVENT");

// Creation de l'espace d'echange partagé
HANDLE hExchange = CreateFileMapping(INVALID_HANDLE_VALUE, // Le créer
dans l'espace système
NULL,
PAGE_READWRITE, // Lecture - écriture
0,
4096, // 4ko
"GlobalBDD_EXCHANGE");

char *exchangeSpace = (char *)MapViewOfFile(hExchange, FILE_MAP_WRITE, 0,
0, 4096);

// Ici attendre
int index=5;
while (_getch()!='Q')
{
// Un message
Message1 mes;
mes.messageId = 1;
mes.valeur1 = index++; // pour que le message change pour tester :-)
lstrcpy(mes.message, "Mon beau message");

// L'écrire dans l'espace d'exchange
memcpy(exchangeSpace, &mes, sizeof(Message1));

// Prévenir les abonnées
SetEvent(hEvent);
}

UnmapViewOfFile(exchangeSpace);
CloseHandle(hExchange);
CloseHandle(hEvent);
}

----CLIENT
struct Message1
{
char messageId;
int valeur1;
char message[256];
};

void main(int argc, char* argv[])
{
// Essayer de trouver l'event
HANDLE hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, "GlobalBDD_EVENT");
if (hEvent!=INVALID_HANDLE_VALUE)
{
// Essayer de trouver l'espace d'échange
HANDLE hExchange = CreateFileMapping(INVALID_HANDLE_VALUE, // Le créer
dans l'espace système
NULL,
PAGE_READONLY, // Lecture
0,
4096, // 4ko
"GlobalBDD_EXCHANGE");

if (hExchange!=INVALID_HANDLE_VALUE)
{
char *exchangeSpace = (char *)MapViewOfFile(hExchange, FILE_MAP_READ, 0,
0, 4096);
// Attendre un message
DWORD dwVal;
while((dwVal=WaitForSingleObject(hEvent, INFINITE))==WAIT_OBJECT_0)
{
ResetEvent(hEvent);
// Retouver le type de message
switch (exchangeSpace[0])
{
case 1:
{
Message1 *mes = (Message1 *)exchangeSpace;
printf("Message %drnvaleur1=%drnmessage=%srn",
(int)mes->messageId, mes->valeur1, mes->message);
}
break;
}
}
DWORD error = GetLastError();
UnmapViewOfFile(exchangeSpace);
CloseHandle(hExchange);
}
else
printf ("Impossible de trouver l'espace d'echange");
CloseHandle(hEvent);
}
else
printf ("Impossible de trouver l'event partage");
}

----
Avatar
Patrick D.
On Wed, 05 Jan 2005 23:50:40 +0100, Philippe Michel wrote:

Disons que l'objectif, est que plusieurs utlisateurs visualisent un
écran de controle. Chaque fois qu'un nouvel enregistrement arrive dans
la base (alerte), il faut que le prog qui l'inscript avertisse tous les
programmes de controls. Comment faire ? Des messages au processus ou
thread en VB, ca n'a jamais été envisagé par les concepteurs de vb. J'ai
essayé plusieurs API, mais ca ne mene à rien.




ce ne serait pas plutôt à la base de prévenir les clients qu'un
enregistrement est arrivé, par une procédure stockée et un
evenement-machin ( dont j'ai oublié le nom, mais vous allez le retrouver).
évidemment, il doit falloir utiliser autre chose qu'access ...

--
* enlevez '.don't.spam' et '.invalid' de mon adresse eMail si vous voulez
m'écrire *
* Donne un poisson à un homme, il aura à manger pour un jour
* Apprends-lui à pêcher, il aura à manger pour tous les jours de sa vie *
Avatar
Philippe
Patrick D. wrote:
On Wed, 05 Jan 2005 23:50:40 +0100, Philippe Michel wrote:

Disons que l'objectif, est que plusieurs utlisateurs visualisent un
écran de controle. Chaque fois qu'un nouvel enregistrement arrive
dans la base (alerte), il faut que le prog qui l'inscript avertisse
tous les programmes de controls. Comment faire ? Des messages au
processus ou thread en VB, ca n'a jamais été envisagé par les
concepteurs de vb. J'ai essayé plusieurs API, mais ca ne mene à rien.




ce ne serait pas plutôt à la base de prévenir les clients qu'un
enregistrement est arrivé, par une procédure stockée et un
evenement-machin ( dont j'ai oublié le nom, mais vous allez le retrouver).
évidemment, il doit falloir utiliser autre chose qu'access ...




click click, 1 heure de dev, et ca roule ... dirait mon chef. :o)

Ca a l'air simple comme ca. Je travail avec MS-Sql server, mais je ne
suis pas du tout spécialisé dans cette base. Procedure stocké ?
d'accord, mais comment réactiver une appli VB6 avec ca, autrement qu'en
appelant une appli qui communique avec les applis clientes ?

merci,
Philippe
Avatar
Philippe
Remi Thomas wrote:

Disons que l'objectif, est que plusieurs utlisateurs visualisent un écran
de controle. Chaque fois qu'un nouvel enregistrement arrive dans la base
(alerte), il faut que le prog qui l'inscript avertisse tous les programmes
de controls. Comment faire ? Des messages au processus ou thread en VB, ca
n'a jamais été envisagé par les concepteurs de vb. J'ai essayé plusieurs
API, mais ca ne mene à rien.

Pour l'instant c'est la deche complete. J'envisage effectivement d'écrire
un service (en C cette fois!) auquel les prog de controle se connecte par
IP (tcp ou udp), et qui avertira ceux-ci dès qu'il se passe quelque chose.
Il faudra bien sur que ce quelque chose se manifeste auprès du service....
mais le temps presse comme d'hab.

Philippe




Salut,

Tu peux partager un event entre plusieurs process.
Comme l'indique la doc de CreateEvent tu peux même préciser si ce mutex est
visible entre les sessions Terminal Server ou non.
Tu peux aussi partager un memory mapped file dans l'espace système, le
mécanisme le plus simple pour partager de l'information 1 vers n.

Voir le code plus bas ou tu peux récupérer le projet ici:
http://www.xtware.com/client-server.zip

Rémi



Merci pour ta réponse, je suis entrain de réetudier l'option Event. Mais
je pense qu'il y a 3 inconvénients:

1- est-ce praticable en vb6, ou vais-je bloquer l'appli jusqu'à ce qu'un
evenement survienne ?

2- Lorsqu'un server declanche un évenement, est-ce que les X clients
derrières seront informés de l'évenement, ou seulement le premier ?

3- S'il faut un evenement par client, je ne sais jamais combien de
client sont courament executés....

je teste.. je teste...
merci encore,
Philippe
Avatar
Remi Thomas
Salut,

Merci pour ta réponse, je suis entrain de réetudier l'option Event. Mais
je pense qu'il y a 3 inconvénients:

1- est-ce praticable en vb6, ou vais-je bloquer l'appli jusqu'à ce qu'un
evenement survienne ?



C'est le problème, il faut créer un thread qui attend.
Facile en C, plus délicat en VB6


2- Lorsqu'un server declanche un évenement, est-ce que les X clients
derrières seront informés de l'évenement, ou seulement le premier ?



Tous les clients sont abonnées

3- S'il faut un evenement par client, je ne sais jamais combien de client
sont courament executés....


Pas besoin, l'exemple fonctionne avec autant de client que tu veux, dans la
limite des ressources de la machine.


Rémi
Avatar
Philippe
Remi Thomas wrote:

Pas besoin, l'exemple fonctionne avec autant de client que tu veux, dans la
limite des ressources de la machine.



chuis entrain de tester, mais ton server plante sur la ligne

memcpy(exchangeSpace, &mes, sizeof(Message1));

dès que je tape une touche

Je compile en visual studio 6.0 sp ... ca ne vient pas de là tout de meme.

Merci pour ton aide.
Philippe
Avatar
Philippe
Philippe wrote:

Remi Thomas wrote:

Pas besoin, l'exemple fonctionne avec autant de client que tu veux,
dans la limite des ressources de la machine.




chuis entrain de tester, mais ton server plante sur la ligne

memcpy(exchangeSpace, &mes, sizeof(Message1));

dès que je tape une touche

Je compile en visual studio 6.0 sp ... ca ne vient pas de là tout de meme.



j'ai trouvé je viens d'enlever le douche BS pour un BS simple dans les
noms de share et d'event. Maintenant ca marche....

Je teste ca de suite sur TerminalServer, et ensuite je vais voir si je
peux m'en servir en VB6.

je te tiens au courant.
Merci beaucoup en tout ca.

Philippe
Avatar
Philippe
Philippe wrote:

Philippe wrote:

j'ai trouvé je viens d'enlever le douche BS pour un BS simple dans les
noms de share et d'event. Maintenant ca marche....



RE RE correction. Sur NT4 il faut simple backslash sinon plante, sur TS
(et probablement W2000) il en faut 2 sinon ca plante, je t'assure. :o))

ben reste plus vb6, et le monde est beau.
a+
Philippe
1 2