如何在CWorkerThread中编写简单的后台线程

时间:2010-11-28 00:09:27

标签: c++ multithreading com atl bho

我正在尝试在Internet Explorer的附加组件中异步运行函数(我在VC ++中编写BHO)。正如所建议here我正在尝试使用CWorkerThread。

我一直想弄清楚几个小时,但仍然不知道该怎么做。我在ATL没有太多经验。互联网上缺乏一个好的文档或教程正在扼杀我。

我正在通过Add-> Class创建类并选择ATL简单对象(这就是你如何添加归类到ATL项目的权利?)。但是如何实现这个IWorkerThreadClient?我认为在类视图中选择Add->实现接口会很好,但列表中没有IWorkerThreadClient。

我想我不知道ATL或COM enaugh但是找不到很好的资源来学习这个(esspessialy 最新的 ATL7)。

我甚至尝试过winapi CreateThread方法,但它无效。我正在通过this类指针来运行静态方法,但是后来有些东西会破坏内存。然而,如果它有效,我仍然宁愿使用除CreateThread以外的其他东西。

现在我有this之类的东西。在OnDocumentComplete中有RemoveImages(sptmlDoc),我只想异步运行它。

编辑:我使用CreateThread做了什么:

我尝试异步运行RemoveImages函数(来自here)。我在班上创建了静态函数,其签名如here。 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; 
}

我在iexplore.exe中的0x60c0da05处获得“未处理的异常: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");
        style->put_display(strNone);
    }
}

2 个答案:

答案 0 :(得分:2)

你通过尝试使用在另一个线程中的1个线程中分配的COM句柄来执行调皮。 BHO环境是STA(单线程单元),所以你应该编组m_tmpHtmlDocument2对象以便在你的线程中使用。

实验表明,在某些情况下,IE可能会让您将浏览器com对象从1个线程传递到另一个线程,然后获取文档和元素可能会起作用。这完全不可靠。

根据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() );
  }
}

答案 1 :(得分:0)

和sptmlDoc - 是IHTMLDocumet *吗?

IWorkerThreadClient - 从未听说过它

“我甚至尝试过winapi CreateThread方法,但它无法正常工作。我正在将此类指针传递给运行静态方法,但后来有些内容会因memomory而损坏”

保持简单是他们所有人的最佳设计模式。所以坚持使用CreateThread,除非你有充分的理由不这样做。现在,我的猜测是崩溃发生是因为sptmlDoc被传递给线程供以后处理。事情是这样的指针只有从BeforeNavigate事件有效,直到DocumentComplete事件。尝试在现场(在事件处理程序内)进行处理,看看它是否崩溃。一些代码发布也有帮助

相关问题