PC SOFT

FORUMS PROFESSIONNELS
WINDEVWEBDEV et WINDEV Mobile

Accueil → WINDEV 2024 → [WD15] Erreur systématique utilisation objet automation dans un thread
[WD15] Erreur systématique utilisation objet automation dans un thread
Débuté par Seb, 23 juil. 2010 09:49 - 11 réponses
Posté le 23 juillet 2010 - 09:49
Bonjour à tous,

Je développe depuis peu un client OPC. J'utilise par conséquent des objets "automation" pour dialoguer avec le serveur OPC.
A partir du moment où les objets "automation" sont dans le thread principal : pas de problème.
Par contre dans un thread secondaire : j'ai une erreur systématique.
(La procédure Test() est un thread secondaire)
Voici le code : "

Procedure Test()
ServeurOPC est un objet automation "OPC.Automation"
...


L'erreur renvoyée par Windev est la suivante :
"L'objet automation 'OPC.Automation' n'est pas installé sur votre système."
...Alors que cela est faux.

Au départ je pensais que le problème venait de "OPC.Automation". (Problème de DLL etc...)
Alors pour en être sûr, j'ai crée une autre procédure de test :
(La procédure Test2() est un thread secondaire)

Procedure Test2()
Excel est un objet automation "Excel.Application"
...


Et là à ma grande surprise :
L'erreur renvoyée par Windev est la suivante :
"L'objet automation 'Excel.Application' n'est pas installé sur votre système."
...Alors que cela est évidemment faux.

Question :
- Y'à t-il un moyen d'utiliser un objet automation quel qu'il soit dans un thread secondaire ?

A savoir :
J'ai fait un certain nombre de test pour essayer de résoudre le problème mais sans succès :
- Utiliser "ThreadExecute(...)" au lieu du paramétrage de la procédure avec Windev ne change rien
- Mettre des sémaphores ou section critique ne change rien
- Mettre la variable automation global ou local ne change rien
- et j'en oublie ...

Je ne sais plus quoi essayer !?!

Merci d'avance pour vos remarques ou vos solutions
Posté le 23 juillet 2010 - 11:04
l'objet automation doit être créé et utilisé dans le même thread.
impossible d'utiliser depuis le thread principal un objet créé dans un thread secondaire...
Posté le 23 juillet 2010 - 12:37
loic a écrit dans le message de news <1a21e6ecf8a82ca0260a07bea177ec1d@news.pcsoft> :
l'objet automation doit être créé et utilisé dans le même thread.
impossible d'utiliser depuis le thread principal un objet créé dans un thread secondaire...


Bonjour Loïc,
Tu as raison !
Seulement, je n'ai jamais dit que j'utilisais l'objet automation (crée dans le thread secondaire) dans le thread principal.
L'objet automation est seulement utilisé dans le thread secondaire.
Je pense avoir trouvé la solution mais j'ai encore besoin de la tester.
Aussi lorsque je serais sûr de la fiabilité de la solution, j'en ferais part à tout le
monde car je crois (d'après les forums d'ici et d'ailleurs) que ce problème se pose à beaucoup de monde.

Vos remarques sont toujours les bienvenues et je vous en remercie :)
Posté le 06 août 2010 - 16:56
Est-ce qu'une solution a été trouvée ?

J'ai le même genre de problème lié aux traitements d'objets automation dans un thread secondaire.
Posté le 06 août 2010 - 18:34
Il semblerait d'après une source officielle que les threads secondaires ne partagent pas tout le contexte du thread principal qui les appelle, et notamment une partie du contexte automation.

Quel dommage.

Si quelqu'un a trouvé un moyen propre de contourner le problème je veux bien écouter sa méthode
Posté le 06 août 2010 - 19:51
Je me demande si ce n'est pas le même problème que pour l'utilisation d'un OLE dans un service ( voir qq post plus bas )

Dans Service et composant, application COM+ il faut chercher l'entrée correspondante à "Excel application" et dans identité forcer l'utilisateur ( utilise le même que celui de développement) je pense que utilisateur interactif fonctionne aussi

Si ca marche il faut faire la même chose avec ton programme

j'espère que cela pourra t'aider à solutionner ton problème

Bon Dev
Posté le 18 août 2010 - 02:38
Bonjour à tous,

Quelqu'un a pu avancer sur ce soucis ?

merci !
eric l.

> Le 06/08/2010 18:51, Marc a écrit :
Je me demande si ce n'est pas le même problème que pour l'utilisation d'un OLE dans un service ( voir qq post plus bas )

Dans Service et composant, application COM+ il faut chercher l'entrée correspondante à "Excel application" et dans identité forcer l'utilisateur ( utilise le même que celui de développement) je pense que utilisateur interactif fonctionne aussi

Si ca marche il faut faire la même chose avec ton programme

j'espère que cela pourra t'aider à solutionner ton problème

Bon Dev
Posté le 06 décembre 2010 - 07:38
bonjour,

je suis tombé aussi sur ce problème.

Ce que j'ai constaté (à confirmer) : Dans windev, quand vous initialisez un objet automation dans un thread vous ne pourrait
l'utiliser que dans ce thread. C'est pour cela que :
=================================================================================================
A partir du moment où les objets "automation" sont dans le thread principal : pas de problème.

Par contre dans un thread secondaire : j'ai une erreur systématique.
L'erreur renvoyée par Windev est la suivante :
"L'objet automation xxxxxxxxxxxxx n'est pas installé sur votre système."
===================================================================================================


Pourquoi me direz-vous ne pas utiliser les objets automation toujours dans le thread principal et comme cela pas de problème.
Eh bien, il y a des opérations ole automation parfois longues et cela peut faire "geler" l'ihm.

L'idée : initialiser l'objet automation dans un thread secondaire et ne l'utiliser que dans ce thread.
Pour réaliser cela il faut que le thread ne soit lancé qu'une seule fois sinon à la deuxieme exécution on aura un magnifique :
"L'objet automation xxxxxxxxxxxxx n'est pas installé sur votre système."

Donc dans le thread lancé par exemple à l'initialisation on fait une boucle infinie bloquée par l'attente d'un signal (Thread).
On lance la procédure qui utilise l'objet automation en envoyant un signal "débloqueur" au thread.


Illustration par l'exemple : je veux commander deux objets automations de types différents dans deux threads secondaires
Dans l'initialisation (de fenêtre principale par exemple):
SignalCrée("DébloqueurThread1",signalManuel,signalFermé,partageAucun)
SignalCrée("DébloqueurThread2",signalManuel,signalFermé,partageAucun)
ThreadExecute("Thread1",threadNormal,ProcThread1)
ThreadExecute("Thread2",threadNormal,ProcThread2)


ProcThread1 :
BOUCLE
SI SignalAttend("DébloqueurThread1") ALORS
SignalModifie("DébloqueurThread1",signalFermé)
// mettre son code ou appel à une procédure ici
ProcédureAutomation1()
FIN
FIN


ProcThread2 :
BOUCLE
SI SignalAttend("DébloqueurThread2") ALORS
SignalModifie("DébloqueurThread2",signalFermé)
// mettre son code ou appel à une procédure ici
ProcédureAutomation2()
FIN
FIN



Et pour lancer les procédures à partir du thread principal :
SignalModifie("DébloqueurThread1",signalOuvert)
SignalModifie("DébloqueurThread2",signalOuvert)


Les procédures ProcédureAutomation1 et ProcédureAutomation2 s'exécutent une fois et les threads dans lesquels elles s'exécutent, se rebloquent, en attente de nouveaux signaux.

Remarques :
Les Threads en attente de signaux ne "consomment" pas de temps CPU.
Ils "tournent" tout le temps de l'exécution du programme.
Cela ne convient pas si vous avez à utiliser plusieurs procédures avec le même type d'objet automation dans votre programme. Dans
ce cas il faut positionner une variable globale qui dans le thread va permettre "d'aiguiller" la procédure à exécuter.

Ami calmant, J.P ;-)
Posté le 06 décembre 2010 - 16:25
Bonjour à tous,

Je suis content de voir que le sujet lancé en Juillet a suscité des réponses de certains et je les en remercie. Aussi comme promis, je dévoile la solution que j'ai utilisé (peut-être une parmi d'autres ?) permettant dans un thread secondaire d'accéder à un objet Automation quelqu'il soit. Cette solution fonctionne car je l'utilise sur une de mes applications laquelle tourne depuis plus de 3 mois.
Peut-être que je n'ai le vocabulaire ou je fais des abus de langage (je m'en excuse) ; mais voici néamoins ma solution :

En fait , je me suis concentré (et pris la tête) sur la gestion du multi-threading avec Windows ainsi que sur l'erreur qui m'était renvoyée par Windev. J'ai découvert qu'en utilisant un objet "automation" on faisait appel à une bibliothèque dite "COM".
Pour faire appel à une des fonctions de cette bibliothèque , il est nécessaire de l'initialiser. En recoupant le type d'erreur automation et la doc. fourni par Windows, j'ai trouvé qu'il fallait appeler une fonction appellée "CoInitializeEx" contenue dans la dll "Ole32.dll".

Voici un exemple concret :

Supposons que nous voulons utiliser un objet Automation "Excel.Application" dans un thread nommé "Essai" appartenant à une collection de procédures globales nommées "ProcéduresGlobales" pour afficher par exemple la version "Office" de Excel :

Créer un nouveau projet puis suivez les étapes ci-dessous :

1/ Créer une collection de procédures globales nommées "ProcéduresGlobales" puis

...Dans la partie "Déclaration" de la collection de procédure globales "ProcéduresGlobales" ecrire :

NumInstanceDLL est un entier système = ChargeDLL("Ole32.DLL") // Chargement de la dll

API("Ole32.DLL","CoInitializeEx",Null,0) // Appel à la fonction : initialisation de la bibliothèque COM

Excel est un objet Automation "Excel.Application" // Création de l'objet automation

...Dans la partie "Terminaison" de la collection de procédure globales "ProcéduresGlobales" ecrire :

API("Ole32.DLL","CoUninitialize") // Toujours accompagné un "CoInitializeEx" par "CoUninitialize" !

DéchargeDLL(NumInstanceDLL) // Libération explicite de la dll

2/ Créer la procédure "Essai" dans la collection de procédure globales "ProcéduresGlobales" :

PROCEDURE Essai()
trace(Excel>>Version)

4/ Paramètrer la procédure "Essai" (Dans la partie "Automatisme de la procédure") :
- Exécution de la procédure : Ne pas cocher "Exécuter après le code d'initialisation du projet"
- Combien de fois ? : 1 fois
- Quand ? : Immédiatement
- Comment ? : Cocher "Exécution en tâche de fond" (Exécuter en comme un Thread)


5/ Pour tester le tout :
Créer une fenêtre puis mettre un bouton.
Dans le code du clic du bouton, écrire le code suivant pour appeler la procédure "Essai" :

Essai

6/ Compiler,Exécuter puis appuyer sur le bouton et normalement vous devriez voir s'afficher la version de votre Excel :)


Quelques lignes de codes suffisent à résoudre le problème...
Voilà, j'espère que j'aurais aidé le plus grand nombre. :)
Malheuresement, je ne connais pas les raisons exactes pour lesquels cet artifice est nécessaire.:(

Si vous avez des remarques à ce sujet je suis toujours preneur,

A+
Posté le 07 décembre 2010 - 10:15
bonjour seb,

merci pour ta réponse. J'ai essayé ta méthode. Cela marche pour moi avec l'objet automation "MSScriptControl.ScriptControl" . Cette méthode par rapport à la mienne a l'avantage de ne lancer le thread que lorsqu'on en a besoin, de faire moins "bidouille", et d'être moins restrictive.
Si tu veux plus de renseignement sur le coInitializeex va voir ici :
http://windows.developpez.com/faq/dcom/…
mais gare au mal de tête :-)

Ami calmant, J.P ;-)
Posté le 02 mars 2011 - 16:45
Je vais tester ta méthode avec un opc serveur, en utilisant opc.automation

J'ai eu le même soucie que toi.

En espérant que cela marche
Posté le 13 juin 2012 - 19:18
Seb, total respect.

Ta méthode fonctionne parfaitement, même en WD16. Elle m'a permis de résoudre en 5 minutes un problème sur lequel je butais depuis plusieurs jours !
(Dans mon cas : lecture d'une carte d'identité électronique Belge dans un thread)



Didier