Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Utiliser une API asynchrone dans un exe sans GUI

9 réponses
Avatar
Olivier Randria
Bonjour,

J'ai developpé une classe qui se base sur L'API C# Notification Request
Broker, qui permet d'avoir du feedback sur des infos style niveau de
batterie, nouveaux réseaux disponibles ... Les API sont par nature
asynchrones et déclenchent un évènement dès qu'il y a un changement,
classique quoi ;). J'ai pu tester sans problème dans une appli Windows.Form
(ça marche).

J'ai ensuite voulu tester tout cela dans un exe de type console (pour faire
une sorte de démon/service), et là ça s'est gaté. Dans la mesure où c'est
asynchrone, j'ai mis une boucle d'attente avec un Sleep() à la fin de mon
Main(), mais rien, pas de feedback, du tout (quand bien même l'appli GUI qui
fonctionne en même temps loggue effectivement les feedbacks).

Comme mon composant fonctionne en GUI, je me suis donc dit que mon contexte
d'utilisation en "mode console" n'était pas adapté (je pense au sleep()). Du
coup, je me demande comment faire en sorte que mon programme attende, quel
type d'attente utiliser ? Est-ce possible d'utiliser une API asynchrone dans
ce mode console ?

Merci pour votre aide,

Olivier

9 réponses

Avatar
adebaene
Olivier Randria a écrit :

Bonjour,

J'ai developpé une classe qui se base sur L'API C# Notification Request
Broker, qui permet d'avoir du feedback sur des infos style niveau de
batterie, nouveaux réseaux disponibles ... Les API sont par nature
asynchrones et déclenchent un évènement dès qu'il y a un changeme nt,
classique quoi ;). J'ai pu tester sans problème dans une appli Windows. Form
(ça marche).

J'ai ensuite voulu tester tout cela dans un exe de type console (pour fai re
une sorte de démon/service), et là ça s'est gaté. Dans la mesure où c'est
asynchrone, j'ai mis une boucle d'attente avec un Sleep() à la fin de m on
Main(), mais rien, pas de feedback, du tout (quand bien même l'appli GU I qui
fonctionne en même temps loggue effectivement les feedbacks).

Comme mon composant fonctionne en GUI, je me suis donc dit que mon contex te
d'utilisation en "mode console" n'était pas adapté (je pense au sleep ()). Du
coup, je me demande comment faire en sorte que mon programme attende, quel
type d'attente utiliser ? Est-ce possible d'utiliser une API asynchrone d ans
ce mode console ?



Je ne connais pas cette API (une page de référence peut être??),
mais très certainement les notifications sont faites de manière
asynchrone sur un thread du pool, et non pas sur le thread principal de
ton application.
Ce qui veut dire que :
- il faut synchroniser les accès aux variables manipulées dans ton
handler de notification.

- dans une appli WinForm, il faut utiliser BeginInvoke pour notifier
l'IHM de se raffraichir, et pas manipuler directement les controles ou
l'IHM. Si tu l'as fait et que ca marche, c'est un coup de bol.

- Dans une appli console, il suffit de bloquer ton thread principal
(par exemple sur une attente de saisie au clavier - Pas de boucle de
pooling!!!), puisque le boulot sera fait sur un autre thread.

Arnaud
MVP - VC
Avatar
Olivier Randria
Bonjour M. Arnaud,

L'API sous-visée est dans Microsoft.WindowsMobile.Status, c'est un peu
spécifique WM 5.0 en fait, et si je ne m'abuse , tout est là:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/mobilesdk5/html/wce50constatstorpropertiesnotificationtypes.asp

Comme tu le verras, il suffit en fait de créer une isntance d'une class
SystemState à qui l'on donne un nom définissant la variable à surveiller, un
delegate et hop, c'est parti, dès que la variable change, le delegate se
fait invoquer... De fait (et sous réserve que j'ai bien compris tout), je du
mal à voir pourquoi il faudrait synchroniser l'accès aux données manipulées
dans mon delegate, vu qu'un seul thread y accèdera (celui de chargé de
déclencher la notification) dans la mesure on j'ai pas de thread de GUI...
Je suis d'accord pour l'attente clavier, ceci dit, je me demandais, l'état
de mon thread bloqué change de façon subtile suivant que je fais une attente
clavier et un while(true) {Sleep()} ??

Merci pour tes lumières,

Olivier



a écrit dans le message de news:


Olivier Randria a écrit :

Bonjour,

J'ai developpé une classe qui se base sur L'API C# Notification Request
Broker, qui permet d'avoir du feedback sur des infos style niveau de
batterie, nouveaux réseaux disponibles ... Les API sont par nature
asynchrones et déclenchent un évènement dès qu'il y a un changement,
classique quoi ;). J'ai pu tester sans problème dans une appli
Windows.Form
(ça marche).

J'ai ensuite voulu tester tout cela dans un exe de type console (pour
faire
une sorte de démon/service), et là ça s'est gaté. Dans la mesure où c'est
asynchrone, j'ai mis une boucle d'attente avec un Sleep() à la fin de mon
Main(), mais rien, pas de feedback, du tout (quand bien même l'appli GUI
qui
fonctionne en même temps loggue effectivement les feedbacks).

Comme mon composant fonctionne en GUI, je me suis donc dit que mon
contexte
d'utilisation en "mode console" n'était pas adapté (je pense au sleep()).
Du
coup, je me demande comment faire en sorte que mon programme attende, quel
type d'attente utiliser ? Est-ce possible d'utiliser une API asynchrone
dans
ce mode console ?



Je ne connais pas cette API (une page de référence peut être??),
mais très certainement les notifications sont faites de manière
asynchrone sur un thread du pool, et non pas sur le thread principal de
ton application.
Ce qui veut dire que :
- il faut synchroniser les accès aux variables manipulées dans ton
handler de notification.

- dans une appli WinForm, il faut utiliser BeginInvoke pour notifier
l'IHM de se raffraichir, et pas manipuler directement les controles ou
l'IHM. Si tu l'as fait et que ca marche, c'est un coup de bol.

- Dans une appli console, il suffit de bloquer ton thread principal
(par exemple sur une attente de saisie au clavier - Pas de boucle de
pooling!!!), puisque le boulot sera fait sur un autre thread.

Arnaud
MVP - VC
Avatar
Arnaud Debaene
Olivier Randria wrote:
Bonjour M. Arnaud,

L'API sous-visée est dans Microsoft.WindowsMobile.Status, c'est un peu
spécifique WM 5.0 en fait, et si je ne m'abuse , tout est là:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/mobilesdk5/html/wce50constatstorpropertiesnotificationtypes.asp



Tu m'a indiqué la doc de l'API native. Ce qui nous intéresse, c'est plutôt
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/mobilesdk5/html/T_Microsoft_WindowsMobile_Status_SystemState.asp?frame=true

Comme tu le verras, il suffit en fait de créer une isntance d'une
class SystemState à qui l'on donne un nom définissant la variable à
surveiller, un delegate et hop, c'est parti, dès que la variable
change, le delegate se fait invoquer... De fait (et sous réserve que
j'ai bien compris tout), je du mal à voir pourquoi il faudrait
synchroniser l'accès aux données manipulées dans mon delegate, vu
qu'un seul thread y accèdera (celui de chargé de déclencher la
notification) dans la mesure on j'ai pas de thread de GUI...



Effectivement, si tu fais tout ton traitement directement dans le handler de
notification (donc sur le thread de callback), tu n'as pas besoin de
synchroniser quoi que ce soit. Ceci-dit, il y a un certain nombre de choses
que tu n'as pas le droit de faire depuis ce thread de callback, notamment
manipuler le GUI si en as un (ce qui n'est pas le cas).

Je suis
d'accord pour l'attente clavier, ceci dit, je me demandais, l'état de
mon thread bloqué change de façon subtile suivant que je fais une
attente clavier et un while(true) {Sleep()} ??


Dans le 2ème cas (attente active ou polling), tu manges de la ressource
processeur pour rien. Sur Pocket PC, c'est d'autant plus embêtant que ca va
vider sa batterie. Poses-toi aussi la question : comment tu fais pour sortir
de ton application?
Le plus probable, c'est que dans ton appli finale, le thread principal (dans
le main) sera en attente sur un mutex ou un event qui lui indiquera qu'il
doit sortir, et ce mutex ou event sera signalé dans un des callbacks de
notification de changement d'état, quand tu auras déterminé que tu devras
sortir de l'application.

Arnaud
MVP - VC

PS : Merci de ne pas top-poster, ca rend la lecture pénible...
Avatar
Olivier Randria
"Arnaud Debaene" a écrit dans le message de
news:
Olivier Randria wrote:
Bonjour M. Arnaud,

L'API sous-visée est dans Microsoft.WindowsMobile.Status, c'est un peu
spécifique WM 5.0 en fait, et si je ne m'abuse , tout est là:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/mobilesdk5/html/wce50constatstorpropertiesnotificationtypes.asp



Tu m'a indiqué la doc de l'API native. Ce qui nous intéresse, c'est plutôt
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/mobilesdk5/html/T_Microsoft_WindowsMobile_Status_SystemState.asp?frame=true

Comme tu le verras, il suffit en fait de créer une isntance d'une
class SystemState à qui l'on donne un nom définissant la variable à
surveiller, un delegate et hop, c'est parti, dès que la variable
change, le delegate se fait invoquer... De fait (et sous réserve que
j'ai bien compris tout), je du mal à voir pourquoi il faudrait
synchroniser l'accès aux données manipulées dans mon delegate, vu
qu'un seul thread y accèdera (celui de chargé de déclencher la
notification) dans la mesure on j'ai pas de thread de GUI...



Effectivement, si tu fais tout ton traitement directement dans le handler
de notification (donc sur le thread de callback), tu n'as pas besoin de
synchroniser quoi que ce soit. Ceci-dit, il y a un certain nombre de
choses que tu n'as pas le droit de faire depuis ce thread de callback,
notamment manipuler le GUI si en as un (ce qui n'est pas le cas).

Je suis
d'accord pour l'attente clavier, ceci dit, je me demandais, l'état de
mon thread bloqué change de façon subtile suivant que je fais une
attente clavier et un while(true) {Sleep()} ??


Dans le 2ème cas (attente active ou polling), tu manges de la ressource
processeur pour rien. Sur Pocket PC, c'est d'autant plus embêtant que ca
va vider sa batterie. Poses-toi aussi la question : comment tu fais pour
sortir de ton application?
Le plus probable, c'est que dans ton appli finale, le thread principal
(dans le main) sera en attente sur un mutex ou un event qui lui indiquera
qu'il doit sortir, et ce mutex ou event sera signalé dans un des callbacks
de notification de changement d'état, quand tu auras déterminé que tu
devras sortir de l'application.

Arnaud
MVP - VC

PS : Merci de ne pas top-poster, ca rend la lecture pénible...




Bonjour,

Désolé pour le top posting... Et merci pour ses réponses... J'ai modifié mon
programme pour qu'il se syncrhonise un peu plus élégamment. Et je l'ai rendu
minimal, pour le poster et le soumettre à votre sagacité. Mon problème est
donc que le delegate OnSystemEventChange, n'est jamais appelé, quand bien
même, je fais une manip sur le device qui le produit un changement (activer
Wifi sur le device dans une environn. qui fourmille de réseaux Wifi pas
discrets) qui devrait causer l'appel (d'après la doc).:

static void OnSystemStateChange(object sender, ChangeEventArgs args)
{
Utilities.Debug.Append("OnSystemStateChange: new value
'"+args.NewValue+"'");
}

static void Main(string[] args)
{
SystemState aState = new
SystemState(SystemProperty.ConnectionsNetworkDescriptions,false);
aState.Changed += new ChangeEventHandler(OnSystemStateChange);

AutoResetEvent aSynchroEvent = null;
aSynchroEvent = new AutoResetEvent(false);

Utilities.Debug.Append("Main: waiting");
aSynchroEvent.WaitOne();
//Should not go here since there is no matching aSynchroEvent.Set();
Utilities.Debug.Append("Main: Done");
}


En relisant la doc de SystemState, je suis tombé sur un constructeur qui
permet de spécifier s'il faut où non spécifier l'utilisation du thread de
Form pour traiter les évènements (pour référence:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/mobilesdk5/html/C_Microsoft_WindowsMobile_Status_SystemState_ctor_1_931bf76b.asp).
Que je mette ce bool à faux ou vrai ne résout pas mon problème. Du coup, je
suis hmmm, dans le doute le plus complet... Qu'en pensez-vous ???

Merci du temps que vous me consacrez,

Olivier
Avatar
Cyrille Szymanski
"Olivier Randria" wrote in
news:du244n$7q0$:

static void Main(string[] args)
{
SystemState aState = new
SystemState(SystemProperty.ConnectionsNetworkDescriptions,false);
aState.Changed += new ChangeEventHandler(OnSystemStateChange);

AutoResetEvent aSynchroEvent = null;
aSynchroEvent = new AutoResetEvent(false);

Utilities.Debug.Append("Main: waiting");
aSynchroEvent.WaitOne();
//Should not go here since there is no matching
aSynchroEvent.Set(); Utilities.Debug.Append("Main: Done");
}



Ne faut-il pas une vraie boucle de messages plutôt (GetMessage() +
DispatchMessage()) pour que l'événement (qui est un message après tout)
puisse être traité ?

--
Cyrille Szymanski
Avatar
Arnaud Debaene
Olivier Randria wrote:
Mon problème est donc que le delegate
OnSystemEventChange, n'est jamais appelé, quand bien même, je fais
une manip sur le device qui le produit un changement (activer Wifi
sur le device dans une environn. qui fourmille de réseaux Wifi pas
discrets) qui devrait causer l'appel (d'après la doc).:
static void OnSystemStateChange(object sender, ChangeEventArgs args)
{
Utilities.Debug.Append("OnSystemStateChange: new value
'"+args.NewValue+"'");
}

static void Main(string[] args)
{
SystemState aState = new
SystemState(SystemProperty.ConnectionsNetworkDescriptions,false);
aState.Changed += new ChangeEventHandler(OnSystemStateChange);

AutoResetEvent aSynchroEvent = null;
aSynchroEvent = new AutoResetEvent(false);

Utilities.Debug.Append("Main: waiting");
aSynchroEvent.WaitOne();
//Should not go here since there is no matching aSynchroEvent.Set();
Utilities.Debug.Append("Main: Done");
}



Je ne vois rien qui cloche là-dedans, et maheureusement je n'ai pas de CE
5.0 sous la main pour tester.... Tu as essayé avec un autre type d'événement
qu'il est plus facile de déclencher de manière "sure" ? (OwnerName ou Time
par exemple) ???

Arnaud
MVP - VC
Avatar
Olivier Randria
"Cyrille Szymanski" a écrit dans le message de news:

"Olivier Randria" wrote in
news:du244n$7q0$:

static void Main(string[] args)
{
SystemState aState = new
SystemState(SystemProperty.ConnectionsNetworkDescriptions,false);
aState.Changed += new ChangeEventHandler(OnSystemStateChange);

AutoResetEvent aSynchroEvent = null;
aSynchroEvent = new AutoResetEvent(false);

Utilities.Debug.Append("Main: waiting");
aSynchroEvent.WaitOne();
//Should not go here since there is no matching
aSynchroEvent.Set(); Utilities.Debug.Append("Main: Done");
}



Ne faut-il pas une vraie boucle de messages plutôt (GetMessage() +
DispatchMessage()) pour que l'événement (qui est un message après tout)
puisse être traité ?

--
Cyrille Szymanski



Bonjour,

J'ai crossposté sur smartphone.developer et une personne m'a également
répondu qu'on ne pouvait pas "s'assoir et s'attendre à être rappelé comme ça
dans le même thread". Apparement il faut un utiliser une message loop... Je
crois que je ne vais pas échapper aux arcanes de l'évènementiel Windows...
Le temps de comprendre tout ça et hop...

Olivier
Avatar
adebaene
Cyrille Szymanski wrote:

Ne faut-il pas une vraie boucle de messages plutôt (GetMessage() +
DispatchMessage()) pour que l'événement (qui est un message après t out)
puisse être traité ?



En fait, le problème est que l'API native permet d'être notifié de
différentes façons:
- RegistryNotifyApp
- RegistryNotifyMsgQueue
- RegistryNotifyWindow
- RegistryNotifyCallback

Selon le mécanisme utilisé, le modèle de threading nécessaire
n'aura bien sûr rien à voir.

Mais la doc de la version managée est particulièrement mal foutue
(comme une bonne partie de la doc dédiée à l'embarqué - je suppose
que c'est une question de culture chez les développeurs "embedded"
d'aimer jouer aux devinettes ;-) et n'indique pas quel est le mécanime
natif utilisé en sous-main....

Arnaud
MVP - VC
Avatar
Olivier Randria
a écrit dans le message de news:


Cyrille Szymanski wrote:

Ne faut-il pas une vraie boucle de messages plutôt (GetMessage() +
DispatchMessage()) pour que l'événement (qui est un message après tout)
puisse être traité ?



En fait, le problème est que l'API native permet d'être notifié de
différentes façons:
- RegistryNotifyApp
- RegistryNotifyMsgQueue
- RegistryNotifyWindow
- RegistryNotifyCallback

Selon le mécanisme utilisé, le modèle de threading nécessaire
n'aura bien sûr rien à voir.

Mais la doc de la version managée est particulièrement mal foutue
(comme une bonne partie de la doc dédiée à l'embarqué - je suppose
que c'est une question de culture chez les développeurs "embedded"
d'aimer jouer aux devinettes ;-) et n'indique pas quel est le mécanime
natif utilisé en sous-main....

Arnaud
MVP - VC

Bonjour,

Aaaah, on est D'ACCORD! J'ai essayé d'autre truc et pas mieux, donc je vais
revenir à un peu de C pas pointu.

Olivier