【问题标题】:How to write simple background thread in CWorkerThread如何在 CWorkerThread 中编写简单的后台线程
【发布时间】:2011-05-16 17:30:16
【问题描述】:

我正在尝试在我的 Internet Explorer 插件中异步运行函数(我正在用 VC++ 编写 BHO)。正如 here 建议的那样,我正在尝试使用 CWorkerThread。

我已经尝试了好几个小时,但仍然不知道该怎么做。我在 ATL 方面没有太多经验。互联网上缺乏好的文档或教程正在扼杀我。

我正在通过 Add->Class 创建类并选择 ATL Simple Object(这就是您将类添加到 ATL 项目的方式对吗?)。但是如何实现这个 IWorkerThreadClient 呢?我认为在 Class View 中选择 Add->Implement Interface 会很好,但是列表中没有 IWorkerThreadClient。

我想我不太了解 ATL 或 COM,但找不到学习这个的好资源(esspessialy 最新 ATL7)。

我什至尝试过 winapi CreateThread 方法,但它不起作用。我正在传递this 类指针来运行静态方法,但是稍后会出现内存损坏。尽管如此,如果它成功了,我仍然宁愿使用 CreateThread 以外的其他东西。

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

编辑:我对@9​​87654332@做了什么:

我尝试异步运行 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。”这里的粗线:

无效 CHelloWorldBHO::DontDisplayElement(CComPtr htmlElement) { CComPtr 风格; HRESULT hr = htmlElement->get_style(&style); 如果(hr == S_OK && 风格!= NULL) { 静态常量 CComBSTR strNone(L"none"); style->put_display(strNone); } }

【问题讨论】:

  • 你看过像this one这样的例子吗?
  • 是的,我做到了。我认为这个和this 只是关于这个类的“好”来源。但我有这个问题。我什至无法创建实现IWorkerThreadClient 的简单类,因为我收到“错误 C2504:'IWorkerThreadClient':未定义的基类”并且我正在添加#include <atlutil.h>。我只能在 add->class->Atl Simple Object 创建的对象中实现它。我以后不能使用它,因为为什么我无法获得指向IWorkerThreadClient 接口的指针以将其传递给AddHandle。

标签: c++ multithreading com atl bho


【解决方案1】:

您试图在另一个线程中使用分配在 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() );
  }
}

【讨论】:

    【解决方案2】:

    和 sptmlDoc - 它是 IHTMLDocumet* 吗?

    IWorkerThreadClient - 没听说过

    “我什至尝试过 winapi CreateThread 方法,但它不起作用。我正在传递这个类指针以运行静态方法,但稍后内存会损坏”

    保持简单是最好的设计模式。因此,除非您有充分的理由不这样做,否则请坚持使用 CreateThread。现在,我的猜测是发生崩溃是因为 sptmlDoc 被传递给线程以供以后处理。事情是这样的指针仅在 BeforeNavigate 事件到 DocumentComplete 事件中才有效。尝试在现场(在您的事件处理程序中)进行该处理,看看它是否仍然崩溃。一些代码发布也会有所帮助

    【讨论】:

    • 保持简单是最好的,但在工作线程上调用CoInitialize 更好。
    • IWorkerThreadClient - 这是 CWorkerThread 的东西。我更新了我的问题,准确描述了什么是粉碎女巫CreateThread。你能看一下吗?
    • 再一次,我不希望 m_tmpHtmlDocument2 = htmlDoc2 稍后在某些工作线程中使用时有效。检查您是否可以首先在同一线程上完成您的目标。如果可以的话,我看不到如何从另一个线程做同样的事情。并且还要听从 wqw 上面的建议
    猜你喜欢
    • 1970-01-01
    • 2020-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多