程序获取webbrowser IHTMLDocument2 获取页面信息。但是只要放在多线程中执行就出出错 程序直接内存出错退出。
调试 发现错误在 spInputElement.GetPropertyByName( L"name", &vName ); 这句 进入里面单步执行 出现(MSHTML.DLL):0xC0000005:Access Violation。而在主线程中执行就没错。请问什么原因呢代码如下:
void MyFunc(LPVOID pDlg)
{
CTestDlg* pDlg2=(CTestDlg*)pDlg;
IHTMLDocument2*pHTMLDocument2=(IHTMLDocument2*)(pDlg2->m_brow.GetDocument());
HRESULT hr;
USES_CONVERSION;
CComQIPtr< IHTMLElementCollection > spElementCollection;
hr = pHTMLDocument2->get_forms( &spElementCollection ); //取得表单集合
if ( FAILED( hr ) )
{

return;
}
long nFormCount=0; //取得表单数目
hr = spElementCollection->get_length( &nFormCount );
if ( FAILED( hr ) )
{
return;
}
CComQIPtr< IHTMLFormElement > spFormElement;
for(long i=0; i<nFormCount; i++)
{
IDispatch *pDisp = NULL; //取得第 i 项表单
hr = spElementCollection->item( CComVariant( i ), CComVariant(), &pDisp );
if ( FAILED( hr ) ) continue;
spFormElement = pDisp;
pDisp->Release();
long nElemCount=0; //取得表单中 域 的数目
hr = spFormElement->get_length( &nElemCount );
if ( FAILED( hr ) ) continue;
for(long j=0; j<nElemCount; j++)
{
CComDispatchDriver spInputElement; //取得第 j 项表单域
hr = spFormElement->item( CComVariant( j ), CComVariant(), &spInputElement );
if ( FAILED( hr ) ) continue;

CComVariant vName,vVal,vType; //取得表单域的 名,值,类型
hr = spInputElement.GetPropertyByName( L"name", &vName ); /***执行此举程序内存错误***/
if( FAILED( hr ) ) continue;
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////
void CTestDlg::OnButtonStart() 
{
    CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)MyFunc,this,0,&ThreadID); //内存泄露
MyFunc(this); //没问题
}

解决方案 »

  1.   

    spFormElement->item( CComVariant( j ), CComVariant(), &spInputElement );
    可能有错,你虽然SUCCESS(hr)了,还需检查spInputElement是否为空
    而且你的调用和手册上好像有误差,param2才是index
      

  2.   

    spInputElement不为空。代码应该没问题。
    是不是多线程和主线程 调用函数上有什么不同呢。
      

  3.   

    发现你的线程居然没有OleInitialize()语句,而且跨线程复用COM指针是不允许的,必需要CComGITPtr来帮忙。
      

  4.   

    原因是COM的对象都生活在套间里,拥有线程相关性。就是你的gui主线程如果要共享一个COM接口,比如说是IHTMLDocument2*,不可以直接就把指针copy或者共享给子线程,需要向系统一个服务注册一个cookie,DWORD格式,然后子线程询问系统把这个cookie还原成接口指针。//比如你的主线程:
    IHTMLDocument2*pHTMLDocument2=(IHTMLDocument2*)(pDlg2->m_brow.GetDocument());
    CComGITPtr<IHTMLDocument2*> pgit(pHTMLDocument2);
    DWORD dwCookie=pgit.Detach();
    CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)MyFunc,dwCookie,0,&ThreadID); //内存泄露
    //MyFunc(this); //没问题 //你的子线程:
    void MyFunc(DWORD cookie){
     OleInitialize(NULL);
     CComGITPtr<IHTMLDocument2> pgit(cookie);
     CComPtr<IHTMLDocument2> pHTMLDocument2;
     if(FAILED(pgit.CopyTo(&pHTMLDocument2))){
      AtlTrace(_T("Failed in GIT to PTR"));
      CoUninitialize();
      return;
     }
     pgit.Revoke();
     //你的代码
     ...
     CoUninitialize();
    }
      

  5.   


    请问CComGITPtr在哪里定义的 我用的VC6没有CComGITPtr 
      

  6.   

    麻烦了,vc6没有CComGITPtr,atl7开始的功能,你只有使用原生态了:
    参考书上(Inside ATL),把IMyInterface改成你要的接口即可,g_pGIT可以线程共享://注册并且获得cookie
    HRESULT RegisterMyInterface(IMyInterface* pmi, DWORD* pdwCookie) {
      // this is usually a global
      IGlobalInterfaceTable* g_pGIT = NULL;
      HRESULT hr = ::CoCreateInstance(CLSID_StdGlobalInterfaceTable,
                                      NULL,
                                      CLSCTX_INPROC_SERVER,
                                      IID_IGlobalInterfaceTable,
                                      (void**)&g_pGIT);
    ATLASSERT(SUCCEEDED(hr));
    hr = g_pGIT->RegisterInterfaceInGlobal(pmi,
      __uuidof(pmi), pdwCookie);
    return hr;
    }
    //通过cookie取得接口
    HRESULT ReadMyInterface(DWORD dwCookie) {
        // ... GIT pointer obtained elsewhere
        IMyInterface* pmi = NULL;
        hr = g_pGIT->GetInterfaceFromGlobal(dwCookie,
        __uuidof(pmi), (void**)&pmi);
        // use pmi as usual
        return hr;
    }
    //注销cookie
    g_pGIT->RevokeInterfaceFromGlobal(m_dwCookie);
      

  7.   


    刚才在别人机器上用 vs2010编译一下 出现
    error C2664: “ATL::CComGITPtr<T>::CComGITPtr(T *)”: 不能将参数 1 从“IHTMLDocument2 *”转换为“IHTMLDocument2 **”
    1>          with
    1>          [
    1>              T=IHTMLDocument2 *
    1>          ]
    1>          与指向的类型无关;转换要求 reinterpret_cast、C 样式转换或函数样式转换
      

  8.   

    CComGITPtr<IHTMLDocument2*> pgit改成CComGITPtr<IHTMLDocument2> pgit