Как написать простой фоновый поток в CWorkerThread - PullRequest
2 голосов
/ 28 ноября 2010

Я пытаюсь асинхронно запустить функцию в моем дополнении для Internet Explorer (я пишу BHO в VC ++).Как и предполагалось здесь Я пытаюсь использовать CWorkerThread.

Я пытался разобраться с этим часами, но до сих пор не знаю, как это сделать.У меня нет большого опыта в ATL.Отсутствие хорошей документации или учебных пособий в Интернете убивает меня.

Я создаю класс с помощью Add-> Class и выбираю простой объект ATL (именно так вы добавляете класс в ATL-проект, верно?).Но как реализовать этот IWorkerThreadClient?Я подумал, что было бы неплохо выбрать Add-> Implement Interface в Class View, но в списке нет IWorkerThreadClient.

Я думаю, что не знаю ATL или COM, но не могу найти хороший ресурс для обученияэто (особенно новейший ATL7).

Я даже попробовал подход winapi CreateThread, но он не работает.Я передаю указатель класса this для запуска статического метода, но что-то портится с памятью позже.Тем не менее, если бы это сработало, я все равно предпочел бы использовать что-то еще, чем CreateThread.

Прямо сейчас у меня есть что-то вроде this OnDocumentComplete есть RemoveImages(sptmlDoc), и я просто хочу запустить его асинхронно.

РЕДАКТИРОВАТЬ: Что я сделал с CreateThread:

Я попытался запустить функцию RemoveImages(с здесь ) асинхронно.Я создал статическую функцию в своем классе с подписью как здесь .У параметра RemoveImages есть параметр, поэтому я скопировал его в член класса:

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

и MyThreadFunction:

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

    return 0; 
}

Я получаю необработанное исключение в 0x60c0da05 в iexplore.exe: 0xC0000005: Место чтения нарушения доступа 0x000001b8. "здесь жирной линией:

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");
        <b>style->put_display(strNone);</b>
    }
}

Ответы [ 2 ]

2 голосов
/ 29 января 2011

Вы выполняете непослушную попытку, пытаясь использовать дескриптор COM, размещенный в 1 потоке в другом. Среда BHO - это STA (квартира с одной резьбой), поэтому вы должны упорядочить объект m_tmpHtmlDocument2 для использования в вашем потоке.

Опыт показывает, что в некоторых случаях IE может позволить вам избежать передачи объекта Browser com из одного потока в другой, а затем получить документ и элементы после этого. Это совершенно ненадежно.

В зависимости от IE 6/7/8 у вас будут разные целевые потоки для выполнения ваших действий, думая об уровнях, соответствующих уровню безопасности / фрейму / вкладке / окну. практически каждый раз, когда IE создает новый «Сайт»

Кроме того, чтобы ваше приложение не удерживало страницы активными даже после перехода от страницы к странице, в FireFox вы должны использовать nsWeakPointer<>, я никогда не находил равные в IE.

Предложение. Возможно, вместо того, чтобы направлять com в другой поток, поскольку ваше взаимодействие со страницей медленное, лучше попытаться улучшить взаимодействие со страницей и повысить производительность в процессе.

Вот схема с использованием CThreadPool, который будет ставить запросы в очередь, а затем выполнять их, когда в пуле есть место.
Я использую pvWorkerParam, чтобы связать темы с сайтом.
У меня есть различные типы ActionRequests, вы, конечно, можете упростить и просто передать null для запроса.
Примечание: Это не решает проблемы с сортировкой, которые у вас уже есть

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() );
  }
}
0 голосов
/ 28 ноября 2010

и sptmlDoc - это IHTMLDocumet *?

IWorkerThreadClient - никогда не слышал об этом

"Я даже попробовал подход CreateThread в winapi, но он не работает. Я передаю этот указатель класса для запуска статического метода, но позже что-то портится с памятью"

Простота - лучший образец дизайна из всех. Так что придерживайтесь CreateThread, если у вас нет веских причин не делать этого. Теперь я предполагаю, что сбой происходит из-за передачи sptmlDoc потоку для последующей обработки. Дело в том, что такие указатели действительны только от события BeforeNavigate до события DocumentComplete. Попробуйте выполнить эту обработку на месте (внутри вашего обработчика событий) и посмотрите, не остановится ли она. Некоторая публикация кода тоже помогла бы

...