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

Problème avec Thread

5 réponses
Avatar
Ulf Bietz
J'ai besoin d'un peu d'aide pour comprendre un problème lié aux Threads:
J'ai écrit une fonction "BrowserObjects()" pour tester des contenus de pages
html.

...
IHTMLDocument3 currentDoc = (IHTMLDocument3)ObjectFromLResult(lRes, ref
IID_IHTMLDocument,0);
IHTMLElementCollection frameCol = currentDoc.getElementsByTagName("FRAME");
foreach (IHTMLElement element in frameCol)
{
if (element is IHTMLElement)
{
DispHTMLFrameElement frameElement = (DispHTMLFrameElement)element;
IHTMLWindow2 newWindow = frameElement.contentWindow;
//InvalidCastException, si appelé dans un thread différent ?
....
}
}
...

cela fonctionne sans problèmes, sauf si j'appelle la fonction à partir d'un
autre thread :

Thread secThread = new Thread(new ThreadStart(RunWebTest);
secThread.Start();

public void RunWebTest()
{
...
BrowserObjects();
...
}

chaque fois que je fais appel à la fonction, je récupère une
"InvalidCastException : Schnittstelle wird nicht unterstützt." (VS .NET
allemand, sans doute
Interface non disponible ou qqchose comme ça)
Est-ce que qqun pourrait m'expliquer pourquoi cette exception n'apparait que
lorsque je fais appel à la fonction dans un autre thread? Est-ce que c'est
un problème général avec les interfaces/threads? Et si oui, pourquoi est-ce
que cela n'arrive pas déjà avec IHTMLDocument3, et seulement avec
IHTMLWindow2 ?

merci d'avance :)

Ulf

5 réponses

Avatar
Frederic Melantois
Bonjour,

Tout d'abord, la ligne "if (element is IHTMLElement)" ne sert à rien.

Il faudrait la remplacer par

if (element is DispHTMLFrameElement)

Ensuite, dans les opérations asynchronnes, il est souvent nécessaire de
locker une référence d'objet.
<code>
lock(mareference)
{
// mon traitement
}
</code>

Dans votre cas, quelle référence faut-il locker ? Est-il nécessaire d'en
locker une ? je ne peux vous répondre ne connaissant pas les objets que vous
employez.

Frédéric Mélantois



"Ulf Bietz" a écrit dans le message de
news:cbdpia$eu$
J'ai besoin d'un peu d'aide pour comprendre un problème lié aux Threads:
J'ai écrit une fonction "BrowserObjects()" pour tester des contenus de


pages
html.

...
IHTMLDocument3 currentDoc = (IHTMLDocument3)ObjectFromLResult(lRes, ref
IID_IHTMLDocument,0);
IHTMLElementCollection frameCol currentDoc.getElementsByTagName("FRAME");
foreach (IHTMLElement element in frameCol)
{
if (element is IHTMLElement)
{
DispHTMLFrameElement frameElement = (DispHTMLFrameElement)element;
IHTMLWindow2 newWindow = frameElement.contentWindow;
//InvalidCastException, si appelé dans un thread différent ?
....
}
}
...

cela fonctionne sans problèmes, sauf si j'appelle la fonction à partir


d'un
autre thread :

Thread secThread = new Thread(new ThreadStart(RunWebTest);
secThread.Start();

public void RunWebTest()
{
...
BrowserObjects();
...
}

chaque fois que je fais appel à la fonction, je récupère une
"InvalidCastException : Schnittstelle wird nicht unterstützt." (VS .NET
allemand, sans doute
Interface non disponible ou qqchose comme ça)
Est-ce que qqun pourrait m'expliquer pourquoi cette exception n'apparait


que
lorsque je fais appel à la fonction dans un autre thread? Est-ce que c'est
un problème général avec les interfaces/threads? Et si oui, pourquoi


est-ce
que cela n'arrive pas déjà avec IHTMLDocument3, et seulement avec
IHTMLWindow2 ?

merci d'avance :)

Ulf





Avatar
Ulf Bietz
Bonjour Frédéric, et merci pour la réponse.

voici un extrait de code un peu plus complet :

private void Form1_Load(object sender, System.EventArgs e)
{
Thread secThread = new Thread(new ThreadStart(StartTest));
secThread.Priority = ThreadPriority.Lowest;
secThread.CurrentCulture = new CultureInfo("en-GB",false);
secThread.Start();

//si par contre j'utilise directement
// StartTest() ;
// tout fonctionne parfaitement
}

public void StartTest()
{
const int SMTO_ABORTIFHUNG = 0x00000002;

WarObj w = new WarObj(); //library for automated tests

Process proc = new Process();
proc.StartInfo.FileName = "iexplore";
proc.StartInfo.Arguments = "any website";
proc.Start();

int lMsg, lRes = 0, hWnd;

Guid IID_IHTMLDocument = new Guid("626FC520-A41E-11CF-A731-00A0C9082637");

hWnd = w.GetHandle(1,"Internet Explorer_Server");
if (hWnd == 0)
{
MessageBox.Show("Could not find Internet Explorer_Server");
return;
}

lMsg = Win32.RegisterWindowMessage("WM_HTML_GETOBJECT");
Win32.SendMessageTimeout(hWnd,lMsg,0,0,SMTO_ABORTIFHUNG,1000, ref lRes);
if(lRes == 0)
{
MessageBox.Show("Could not send WM_HTML_GETOBJECT message");
return;
}


IHTMLDocument3 myInstance (IHTMLDocument3)Win32.ObjectFromLresult(lRes,ref IID_IHTMLDocument,0);
IHTMLElementCollection elements = myInstance.getElementsByTagName("FRAME");

foreach(IHTMLElement element in elements )
{
if(element is IHTMLFrameElement)
{
DispHTMLFrameElement frameElement = (DispHTMLFrameElement)element;
IHTMLWindow2 window = frameElement.contentWindow;
IHTMLDocument2 frameDoc = window.document;
IHTMLElementCollection allTag = frameDoc.all;
foreach(IHTMLElement myTag in allTag)
{
if ((myTag.tagName.Equals("INPUT") || myTag.tagName.Equals("A"))&&
myTag.outerHTML.IndexOf("login")>=0)
{
MessageBox.Show("Login found");
}
}
}
}
proc.Kill();
}

le procédé de locker une référence me semble une piste prometteuse, mais je
dois avouer que je nage un peu .....

merci :)

Ulf


"Frederic Melantois" schrieb im Newsbeitrag
news:cbe2sc$1o2$
Bonjour,

Tout d'abord, la ligne "if (element is IHTMLElement)" ne sert à rien.

Il faudrait la remplacer par

if (element is DispHTMLFrameElement)

Ensuite, dans les opérations asynchronnes, il est souvent nécessaire de
locker une référence d'objet.
<code>
lock(mareference)
{
// mon traitement
}
</code>

Dans votre cas, quelle référence faut-il locker ? Est-il nécessaire d'en
locker une ? je ne peux vous répondre ne connaissant pas les objets que


vous
employez.

Frédéric Mélantois


Avatar
Ulf Bietz
Re Bonjour,


J'ai simplement ajouté ApartmentState :

private void Form1_Load(object sender, System.EventArgs e)
{
Thread secThread = new Thread(new ThreadStart(StartTest));
secThread.Priority = ThreadPriority.Lowest;
secThread.CurrentCulture = new CultureInfo("en-GB",false);
secThread.ApartmentState = ApartmentState.STA;
secThread.Start();
}

et le tout fonctionne parfaitement. Je passerai néanmoins encore qq heures
avec MSDN pour en comprendre la raison :)

Ulf
Avatar
YJLAMOTTE
Rechercher le sample de Chat (en VB) sur le MSDN, il montre un exemple avec SyncLock (lock en C#)

Sinon il existe 2 autres façons de procéder : (je l'ai lu mais je ne saurai pas le faire facilement)

System.Monitor

et le Mutex..

Courage, c'est pas la partie la plus facile..

YJLAMOTTE


"Ulf Bietz" wrote:

Bonjour Frédéric, et merci pour la réponse.

voici un extrait de code un peu plus complet :

private void Form1_Load(object sender, System.EventArgs e)
{
Thread secThread = new Thread(new ThreadStart(StartTest));
secThread.Priority = ThreadPriority.Lowest;
secThread.CurrentCulture = new CultureInfo("en-GB",false);
secThread.Start();

//si par contre j'utilise directement
// StartTest() ;
// tout fonctionne parfaitement
}

public void StartTest()
{
const int SMTO_ABORTIFHUNG = 0x00000002;

WarObj w = new WarObj(); //library for automated tests

Process proc = new Process();
proc.StartInfo.FileName = "iexplore";
proc.StartInfo.Arguments = "any website";
proc.Start();

int lMsg, lRes = 0, hWnd;

Guid IID_IHTMLDocument = new Guid("626FC520-A41E-11CF-A731-00A0C9082637");

hWnd = w.GetHandle(1,"Internet Explorer_Server");
if (hWnd == 0)
{
MessageBox.Show("Could not find Internet Explorer_Server");
return;
}

lMsg = Win32.RegisterWindowMessage("WM_HTML_GETOBJECT");
Win32.SendMessageTimeout(hWnd,lMsg,0,0,SMTO_ABORTIFHUNG,1000, ref lRes);
if(lRes == 0)
{
MessageBox.Show("Could not send WM_HTML_GETOBJECT message");
return;
}


IHTMLDocument3 myInstance > (IHTMLDocument3)Win32.ObjectFromLresult(lRes,ref IID_IHTMLDocument,0);
IHTMLElementCollection elements = myInstance.getElementsByTagName("FRAME");

foreach(IHTMLElement element in elements )
{
if(element is IHTMLFrameElement)
{
DispHTMLFrameElement frameElement = (DispHTMLFrameElement)element;
IHTMLWindow2 window = frameElement.contentWindow;
IHTMLDocument2 frameDoc = window.document;
IHTMLElementCollection allTag = frameDoc.all;
foreach(IHTMLElement myTag in allTag)
{
if ((myTag.tagName.Equals("INPUT") || myTag.tagName.Equals("A"))&&
myTag.outerHTML.IndexOf("login")>=0)
{
MessageBox.Show("Login found");
}
}
}
}
proc.Kill();
}

le procédé de locker une référence me semble une piste prometteuse, mais je
dois avouer que je nage un peu .....

merci :)

Ulf


"Frederic Melantois" schrieb im Newsbeitrag
news:cbe2sc$1o2$
> Bonjour,
>
> Tout d'abord, la ligne "if (element is IHTMLElement)" ne sert à rien.
>
> Il faudrait la remplacer par
>
> if (element is DispHTMLFrameElement)
>
> Ensuite, dans les opérations asynchronnes, il est souvent nécessaire de
> locker une référence d'objet.
> <code>
> lock(mareference)
> {
> // mon traitement
> }
> </code>
>
> Dans votre cas, quelle référence faut-il locker ? Est-il nécessaire d'en
> locker une ? je ne peux vous répondre ne connaissant pas les objets que
vous
> employez.
>
> Frédéric Mélantois





Avatar
Frederic Melantois
Merci de votre réponse.
(je n'avais pas pu essayer votre code car il me manquait des références
outre le mshtml).

Comme ça m'intéresse, et que je ne connais pas le modèle MTA (je fais pas de
c++), j'ai un peu cherché.

Voici donc quelques liens qui permettent de comprendre :

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenetchapt07.asp
(chapitre du bouquin de référence "Improving .NET Application Performance
and Scalability")

http://www.developer.com/net/asp/article.php/2202491

Frédéric


"Ulf Bietz" a écrit dans le message de
news:cbebo0$5jp$
Re Bonjour,


J'ai simplement ajouté ApartmentState :

private void Form1_Load(object sender, System.EventArgs e)
{
Thread secThread = new Thread(new ThreadStart(StartTest));
secThread.Priority = ThreadPriority.Lowest;
secThread.CurrentCulture = new CultureInfo("en-GB",false);
secThread.ApartmentState = ApartmentState.STA;
secThread.Start();
}

et le tout fonctionne parfaitement. Je passerai néanmoins encore qq heures
avec MSDN pour en comprendre la raison :)

Ulf