2010-11-28 33 views
2

J'essaie d'exécuter de manière asynchrone la fonction dans mon add-on pour Internet Explorer (j'écris BHO dans VC++). Comme suggéré here J'essaie d'utiliser CWorkerThread.Comment écrire un thread d'arrière-plan simple dans CWorkerThread

J'ai essayé de le comprendre pendant des heures mais je n'ai toujours aucune idée de comment le faire. Je n'ai pas beaucoup d'expérience en ATL. Le manque de bonnes documentations ou de tutoriels sur Internet me tue.

Je crée classe par Add-> Class et en choisissant ATL Simple Object (c'est ainsi que vous ajoutez correctement le projet ATL classifié?). Mais comment implémenter ce IWorkerThreadClient? Je pensais que le choix de Ajouter -> Implémenter l'interface dans la vue de classe serait bon mais il n'y a aucun IWorkerThreadClient sur la liste.

Je pense que je ne sais pas ATL ou COM enaugh, mais ne peut pas trouver une bonne ressource pour apprendre cela (ESSPESSIALY plus récent ATL7).

J'ai même essayé l'approche winapi CreateThread mais ça ne fonctionne pas. Je passe le pointeur de classe this pour exécuter la méthode statique mais quelque chose est corrompu avec la mémoire plus tard. Néanmoins, si cela avait fonctionné, je préfère encore utiliser autre chose que CreateThread.

En ce moment j'ai quelque chose comme this. Dans OnDocumentComplete il y a RemoveImages(sptmlDoc) et je veux juste l'exécuter de manière asynchrone.

EDIT: Ce que je l'ai fait avec CreateThread:

J'ai essayé en cours d'exécution fonction RemoveImages (de here) de manière asynchrone. J'ai créé la fonction statique dans ma classe avec la signature comme here. RemoveImages a paramètre si je l'ai copié à un membre d'une classe:

if (htmlDoc2 != NULL) 
{ 
    m_tmpHtmlDocument2 = htmlDoc2; 
    m_hThread = CreateThread(NULL, 0, MyThreadFunction, this, 0, &m_threadId); 
} 

et MyThreadFunction:

static DWORD WINAPI MyThreadFunction(LPVOID lpParam) 
{ 
    CHelloWorldBHO* myClass = (CHelloWorldBHO*)lpParam; 
    myClass->RemoveImages(myClass->m_tmpHtmlDocument2); 

    return 0; 
} 

je reçois « exception non gérée à 0x60c0da05 en iexplore.exe: 0xC0000005: violation d'accès lecture emplacement 0x000001b8 " ici dans la ligne en gras:

 
void CHelloWorldBHO::DontDisplayElement(CComPtr htmlElement) 
{ 
    CComPtr style; 
    HRESULT hr = htmlElement->get_style(&style); 

    if (hr == S_OK && style != NULL) 
    {  
     static const CComBSTR strNone(L"none"); 
     style->put_display(strNone); 
    } 
} 
+0

Avez-vous jetez un oeil à des exemples comme [celui-ci] (http://www.codeproject.com/KB/threads/CWorkerThread .aspx)? –

+0

Oui, je l'ai fait. Je pense que ceci et [ceci] (http://msdn.microsoft.com/en-us/library/w849dybf.aspx) sont seulement de "bonnes" sources à propos de cette classe. Mais j'ai des problèmes avec ça. Je ne peux même pas créer une classe simple qui implémente 'IWorkerThreadClient' car j'obtiens l'erreur C2504: 'IWorkerThreadClient': classe de base indéfinie" et j'ajoute '#include '. Je ne peux l'implémenter que dans des objets créés par add-> class-> Atl Simple Object. Par Je ne peux pas l'utiliser plus tard parce que je ne peux pas obtenir un pointeur sur l'interface 'IWorkerThreadClient' pour le passer à' AddHandle'. –

Répondre

0

et sptmlDoc - est-ce un IHTMLDocumet *?

IWorkerThreadClient - jamais entendu parler

«J'ai même essayé winapi approche CreateThread mais il ne fonctionne pas je passe ce pointeur de classe pour exécuter une méthode statique mais quelque chose corrompt avec memomory plus tard. »

Garder la simplicité est le meilleur modèle de conception de tous. Alors restez avec CreateThread, sauf si vous avez de bonnes raisons de ne pas le faire. Maintenant, je suppose que l'accident se produit à cause de sptmlDoc étant passé au thread pour un traitement ultérieur. Le problème est que ces pointeurs ne sont valides que depuis l'événement BeforeNavigate jusqu'à l'événement DocumentComplete. Essayez de faire ce traitement sur place (à l'intérieur de votre gestionnaire d'événements) et voyez si cela bloque les plantages. Une partie de l'écriture de code aiderait aussi

+0

Garder les choses simples est ce qu'il y a de mieux, mais il vaut mieux appeler CoInitialize sur le thread de travail. – wqw

+0

IWorkerThreadClient - c'est l'affaire de CWorkerThread. J'ai mis à jour ma question décrivant exactement ce qui écrase witch 'CreateThread'. Pourriez-vous y jeter un coup d'œil? –

+0

Encore une fois, je ne m'attendrais pas à ce que m_tmpHtmlDocument2 = htmlDoc2 soit valide lorsqu'il sera utilisé plus tard dans un thread de travail. Vérifiez que vous pouvez atteindre votre objectif sur le même fil d'abord. Si vous le pouvez, que je ne vois pas comment faire la même chose à partir d'un autre fil. Et suivez également les conseils de wqw ci-dessus – kellogs

2

Vous effectuez un vilain en essayant d'utiliser un handle COM alloué dans 1 thread dans un autre. L'environnement BHO est STA (Single Threaded Apartment). Vous devez donc rassembler l'objet m_tmpHtmlDocument2 pour l'utiliser dans votre thread.L'expérience a montré que, dans certains cas, IE peut vous permettre de passer l'objet Browser com d'un thread à un autre et ensuite obtenir le document et les éléments peuvent ensuite fonctionner. Ceci est entièrement non fiable. Selon IE 6/7/8, vous aurez différents threads cibles pour exécuter vos actions, en pensant aux niveaux de sécurité par niveau/image/onglet/fenêtre. En outre, chaque fois que IE crée un nouveau site

Aussi pour empêcher votre application de maintenir les pages actives même après la navigation loin de la page, dans FireFox vous utiliseriez un nsWeakPointer<>, je n'ai jamais trouvé l'équivélant dans IE. Suggestion: Au lieu de placer com dans un autre thread, car votre interaction avec la page est lente, essayez d'améliorer la façon dont vous interagissez avec la page et améliorez les performances du processus.

Voici un aperçu utilisant CThreadPool qui va mettre en file d'attente des demandes, puis les exécuter lorsque le pool a de l'espace. J'utilise pvWorkerParam pour attacher les fils au site.
J'ai différents types de ActionRequests, vous pouvez bien sûr simplifier et simplement passer null pour la demande.
Note: Cela ne résout pas les problèmes ont marshalling vous déjà

class ActionRequest{ 
    DontDisplayElement();// define your do stuff in here 
}; 

class ScriptWorker 
{ 
public: 
ScriptWorker(void); 
virtual ~ScriptWorker(void); 

public: 
BOOL Initialize(void* pvWorkerParam); 
void Execute(ActionRequest *request, void* pvWorkerParam, OVERLAPPED* pOverlapped){ 
try{ 
     std::auto_ptr<ActionRequest> cleanupRequest(request); 
     request.DontDisplayElement(); 
    } catch(...) {} 
    } 
void Terminate(void* pvWorkerParam); 

private: 
boolean m_bCoUninit; 
}; 

Site{ 
    CThreadPool<ScriptWorker> m_scriptWorkerThread; 
    Site() { 
    void *pvWorkerParam = this;// or whatever you want to have passed to every script worker and execute in the pool. 
    m_scriptWorkerThread.Initialize(pvWorkerParam, 1); 
    } 
    OnDocumentComplete() { 
    m_scriptWorkerThread.QueueRequest(new ActionRequest()); 
    } 
}