原本是想获取INTERNET EXPLORER_SERVER里面的文本,用了下面这个函数,获取接口正常,但一使用接口就出错。后来我直接尝试获取接口的原函数,还是不行,执行到spDoc->put_bgColor( CComVariant("red") );这一行就死掉了,麻烦高手帮我看一下,下面是我在MSDN上面找到的代码,一起贴上来,
还有说一下我用的是WIN7+VS2008,IE的窗口句柄是直接用Spy++得到的,
BOOL CALLBACK MyEnumChildProc(HWND hwnd,LPARAM lParam)
{
TCHAR buf[100];
::GetClassName( hwnd, (LPTSTR)&buf, 100 );
if ( _tcscmp( buf, _T("Internet Explorer_Server") ) == 0 )
{
*(HWND*)lParam = hwnd;
return FALSE;
}
else
return TRUE;
}
void OnGetDocInterface(HWND hWnd)
{
CoInitialize( NULL );
// Explicitly load MSAA so we know if it's installed
HINSTANCE hInst = ::LoadLibrary( _T("OLEACC.DLL") );
if ( hInst != NULL )
{
if ( hWnd != NULL )
{
HWND hWndChild=NULL;
// Get 1st document window
::EnumChildWindows( hWnd, MyEnumChildProc, (LPARAM)&hWndChild );
if ( hWndChild )
{
CComPtr<IHTMLDocument2> spDoc;
LRESULT lRes;
UINT nMsg = ::RegisterWindowMessage( _T("WM_HTML_GETOBJECT") );
::SendMessageTimeout( hWndChild, nMsg, 0L, 0L, SMTO_ABORTIFHUNG, 1000, (DWORD*)&lRes );
LPFNOBJECTFROMLRESULT pfObjectFromLresult = (LPFNOBJECTFROMLRESULT)::GetProcAddress( hInst, "ObjectFromLresult");
if ( pfObjectFromLresult != NULL )
{
HRESULT hr;
hr = (*pfObjectFromLresult)( lRes, IID_IHTMLDocument, 0, (void**)&spDoc );
if ( SUCCEEDED(hr))
{
// Change background color to red
spDoc->put_bgColor( CComVariant("red") );
}
}
} // else document not ready
} // else Internet Explorer is not running
::FreeLibrary( hInst );
} // else Active Accessibility is not installed
CoUninitialize();
}
ObjectFromLresult 仅限项目内部使用,MSDN的解释:Neither clients nor servers should call this function.
实际上这个API本来不应该公开,它只能用于当前线程中创建的组件,跨线程不能用,跨进程更不用说。
你这个说法是不是有点太离谱了,连跨线程都不能用,我以前也想过这个问题,后来改为DLL注入还是不行,难道真的不能跨线程使用,
要真的象你这样说的话,那岂不是没有办法去获取别的窗口的IHTMLDocument2接口了??
不知道还有没有其他的办法呢??
道理很简单,当客户端向窗口发送 WM_HTML_GETOBJECT 消息时,窗口把组件(注意这个组件属于窗口所在线程)的 IUnknown* 转换成 LRESULT 返回给客户端,然后 ObjectFromLresult 把 LRESULT 转换回 IUnknown* 之后调用其 QueryInterface 方法查询需要的接口。过程决定结果,一个线程中的接口指针未经列集传递给其它线程或进程,这个接口还能用吗?
事实上 WM_HTML_GETOBJECT 不是标准消息,并不被微软支持,它是开发库内部定义的消息。标准消息是跟 IAccessible 有关的 WM_GETOBJECT 消息,这个消息能被系统自动列集,所以可以跨线程调用 ObjectFromLresult 并获得正确的结果。
我都被你说糊涂了,你前面不是说不能跨线程使用么,怎么现在又改成能呢,
经过单步执行,发现ObjectFromResult这个函数可以成功执行,但是返回的接口就是不能用,这样看来这个方法真的行不能,不知道还有没有其他的办法呢,我只是想获得Internet Explorer_Server里面的html代码,请指点
我说的是这个API对 WM_GETOBJECT 消息有效,对 WM_HTML_GETOBJECT 消息无效,你没看清楚。
因为你是枚举窗口来寻找浏览器控件的,所以找到其它进程的概率很大,这就是一个巨大的问题。而如果要得到其它进程中浏览器控件的文档对象并能进行DOM操作,只有一种途径:这个进程的浏览器控件是由你的代码通过自动化方式创建出来的。
事实上,这种方法是可以用的,获取【其他进程】的doc进行操作没有任何问题!
我曾经用这种方法写过一个自动玩qq网页游戏怪物对对碰的辅助工具(使用IE打开qq怪物对对碰游戏,然后用工具选中该IE窗口,就可以自动玩)
C/C++ code
转一篇文章,希望对你有用
不要在线程之间传递原始接口指针我咨询的首批COM项目之一就涉及到一个包含100,000行代码的分布式应用程序,该程序是由美国西海岸的一个大型软件公司编写的。该应用程序在多个机器上创建了数十个COM对象,并从客户端进程启动的背景线程中调用这些对象。开发小组遇到问题了,调用要么消失得无影无踪,要么在没有明显原因的情况下失败。他们给我演示的最惊人的症状是:当一个调用无法返回时,在同一台机器上启动其他支持COM的应用程序(包括MicrosoftPaint等)会频繁导致这些应用程序被锁定。检查他们的代码后发现,他们违反了COM并发的一个基本规则,就是说,如果一个线程要与另一个线程共享一个接口指针,它应首先封送该接口指针。如果有必要,封送接口指针可使COM创建一个新的代理(以及一个新的信道对象,将代理和存根结对),以允许从另一个单元向外调用。不通过封送而将原始接口指针(内存中的一个32位地址)传递给另一个线程,会绕过COM的并发机制,并且如果发送和接收的线程位于不同的单元中,将出现各种不良行为。(在Windows2000中,由于两个对象可以共享一个单元,但又位于不同的上下文中,因此如果线程位于同一个单元中,可能会使您陷入困境。)典型的症状包括调用失败和返回RPC_E_WRONG_THREAD_ERROR。WindowsNT4.0和更高版本可以使用一对名为CoMarshalInterThreadInte**ceInStream和CoGetInte**ceAndReleaseStream的API函数,在线程之间轻松地封送接口指针。假定您应用程序中的一个线程(线程A)创建了一个COM对象,继而接收了一个IFoo接口指针,并且同一进程中的另一个线程(线程B)想调用这个对象。在准备将接口指针传递给线程B时,线程A应该封送该接口指针,如下所示:CoMarshalInterThreadInte**ceInStream(IID_IFoo,pFoo,&pStream);在CoMarshalInterThreadInte**ceInStream返回后,线程B就可以安全地取消封送该接口指针:IFoo*pFoo;CoGetInte**ceAndReleaseStream(pStream,IID_IFoo,(void**)&pFoo);在这些示例中,pFoo是一个IFoo接口指针,pStream是一个IStream接口指针。COM在调用CoMarshalInterThreadInte**ceInStream时初始化IStream接口指针,然后在CoGetInte**ceAndReleaseStream内部使用和释放该接口指针。实际上,您通常要使用一个事件或其他同步化基元来协调这两个线程的行为—例如,让线程B知道接口指针已准备好,可以取消封送。请注意,以这种方式封送接口指针不会出现任何问题,因为COM有足够的智能,在不需要进行封送时不会去封送(或重新封送)指针。如果在线程之间传递接口指针时这样做,使用COM就轻松多了。如果调用CoMarshalInterThreadInte**ceInStream和CoGetInte**ceAndReleaseStream看起来太麻烦,您还可以通过将接口指针放在全局接口表(GIT)中,并让其他线程去那里检索它们,从而实现在线程之间传递接口指针。从GIT中检索到的接口指针在被检索时会自动封送。更多信息,请参阅IGlobalInte**ceTable中的文档。
确实如你所说,再QI一次就可以了,呵呵
虽然这篇文章中所说的方法我用不上,不过还是长见识了,相信以后一定用得上的,
还有说一下我用的是WIN7+VS2008,IE的窗口句柄是直接用Spy++得到的,
BOOL CALLBACK MyEnumChildProc(HWND hwnd,LPARAM lParam)
{
TCHAR buf[100];
::GetClassName( hwnd, (LPTSTR)&buf, 100 );
if ( _tcscmp( buf, _T("Internet Explorer_Server") ) == 0 )
{
*(HWND*)lParam = hwnd;
return FALSE;
}
else
return TRUE;
}
void OnGetDocInterface(HWND hWnd)
{
CoInitialize( NULL );
// Explicitly load MSAA so we know if it's installed
HINSTANCE hInst = ::LoadLibrary( _T("OLEACC.DLL") );
if ( hInst != NULL )
{
if ( hWnd != NULL )
{
HWND hWndChild=NULL;
// Get 1st document window
::EnumChildWindows( hWnd, MyEnumChildProc, (LPARAM)&hWndChild );
if ( hWndChild )
{
CComPtr<IHTMLDocument2> spDoc;
LRESULT lRes;
UINT nMsg = ::RegisterWindowMessage( _T("WM_HTML_GETOBJECT") );
::SendMessageTimeout( hWndChild, nMsg, 0L, 0L, SMTO_ABORTIFHUNG, 1000, (DWORD*)&lRes );
LPFNOBJECTFROMLRESULT pfObjectFromLresult = (LPFNOBJECTFROMLRESULT)::GetProcAddress( hInst, "ObjectFromLresult");
if ( pfObjectFromLresult != NULL )
{
HRESULT hr;
hr = (*pfObjectFromLresult)( lRes, IID_IHTMLDocument, 0, (void**)&spDoc );
if ( SUCCEEDED(hr))
{
// Change background color to red
spDoc->put_bgColor( CComVariant("red") );
}
}
} // else document not ready
} // else Internet Explorer is not running
::FreeLibrary( hInst );
} // else Active Accessibility is not installed
CoUninitialize();
}
实际上这个API本来不应该公开,它只能用于当前线程中创建的组件,跨线程不能用,跨进程更不用说。
引用 4 楼 jameshooo 的回复:
ObjectFromLresult 仅限项目内部使用,MSDN的解释:Neither clients nor servers should call this function.
实际上这个API本来不应该公开,它只能用于当前线程中创建的组件,跨线程不能用,跨进程更不用说。
ObjectFromLresult 仅限项目内部使用,MSDN的解释:Neither clients nor servers should call this function.
实际上这个API本来不应该公开,它只能用于当前线程中创建的组件,跨线程不能用,跨进程更不用说。
你这个说法是不是有点太离谱了,连跨线程都不能用,我以前也想过这个问题,后来改为DLL注入还是不行,难道真的不能跨线程使用,
要真的象你这样说的话,那岂不是没有办法去获取别的窗口的IHTMLDocument2接口了??
不知道还有没有其他的办法呢??
事实上 WM_HTML_GETOBJECT 不是标准消息,并不被微软支持,它是开发库内部定义的消息。标准消息是跟 IAccessible 有关的 WM_GETOBJECT 消息,这个消息能被系统自动列集,所以可以跨线程调用 ObjectFromLresult 并获得正确的结果。
引用 7 楼 jameshooo 的回复:
道理很简单,当客户端向窗口发送 WM_HTML_GETOBJECT 消息时,窗口把组件(注意这个组件属于窗口所在线程)的 IUnknown* 转换成 LRESULT 返回给客户端,然后 ObjectFromLresult 把 LRESULT 转换回 IUnknown* 之后调用其 QueryInterface 方法查询需要的接口。过程决定结果,一个线程中的接口指针未经列集传递给其它线程或进程,这个接口还能用吗?
事实上 WM_HTML_GETOBJECT 不是标准消息,并不被微软支持,它是开发库内部定义的消息。标准消息是跟 IAccessible 有关的 WM_GETOBJECT 消息,这个消息能被系统自动列集,所以可以跨线程调用 ObjectFromLresult 并获得正确的结果。
道理很简单,当客户端向窗口发送 WM_HTML_GETOBJECT 消息时,窗口把组件(注意这个组件属于窗口所在线程)的 IUnknown* 转换成 LRESULT 返回给客户端,然后 ObjectFromLresult 把 LRESULT 转换回 IUnknown* 之后调用其 QueryInterface 方法查询需要的接口。过程决定结果,一个线程中的接口指针未经列集传递给其它线程或进程,这个接口还能用吗?
事实上 WM_HTML_GETOBJECT 不是标准消息,并不被微软支持,它是开发库内部定义的消息。标准消息是跟 IAccessible 有关的 WM_GETOBJECT 消息,这个消息能被系统自动列集,所以可以跨线程调用 ObjectFromLresult 并获得正确的结果。
我都被你说糊涂了,你前面不是说不能跨线程使用么,怎么现在又改成能呢,
经过单步执行,发现ObjectFromResult这个函数可以成功执行,但是返回的接口就是不能用,这样看来这个方法真的行不能,不知道还有没有其他的办法呢,我只是想获得Internet Explorer_Server里面的html代码,请指点
因为你是枚举窗口来寻找浏览器控件的,所以找到其它进程的概率很大,这就是一个巨大的问题。而如果要得到其它进程中浏览器控件的文档对象并能进行DOM操作,只有一种途径:这个进程的浏览器控件是由你的代码通过自动化方式创建出来的。
我曾经用这种方法写过一个自动玩qq网页游戏怪物对对碰的辅助工具(使用IE打开qq怪物对对碰游戏,然后用工具选中该IE窗口,就可以自动玩)
C/C++ code
HRESULT CMyQQGameToolDlg::GetIHTMLDocument2FromHWND(IHTMLDocument2 ** pDoc2) { LRESULT lRes; UINT nMsg = ::RegisterWindowMessage( _T("WM_HTML_GETOBJECT") ); ::SendMessageTimeout(m_hIE, nMsg, 0L, 0L, SMTO_ABORTIFHUNG, 1000, (DWORD*)&lRes ); LPFNOBJECTFROMLRESULT pfObjectFromLresult = (LPFNOBJECTFROMLRESULT)::GetProcAddress( m_hInstMSAA, "ObjectFromLresult"); if (NULL == pfObjectFromLresult) { ... } HRESULT hr; hr = (*pfObjectFromLresult)( lRes, IID_IHTMLDocument, 0, (void**)pDoc2 ); if (FAILED(hr)) { ... } return S_OK; } 调用处的代码 // GET IE hwnd ... CComPtr<IHTMLDocument2> spDoc2; HRESULT hr = E_FAIL; hr = GetIHTMLDocument2FromHWND(&spDoc2); ///////////////////////////////////////////////////// // 直接操作spDoc2会有异常! // 再QI一次获取另外的接口就可以操作了 // CComQIPtr<IHTMLDocument3> spDoc3 = spDoc2; hr = spDoc3->getElementById(...
不要在线程之间传递原始接口指针我咨询的首批COM项目之一就涉及到一个包含100,000行代码的分布式应用程序,该程序是由美国西海岸的一个大型软件公司编写的。该应用程序在多个机器上创建了数十个COM对象,并从客户端进程启动的背景线程中调用这些对象。开发小组遇到问题了,调用要么消失得无影无踪,要么在没有明显原因的情况下失败。他们给我演示的最惊人的症状是:当一个调用无法返回时,在同一台机器上启动其他支持COM的应用程序(包括MicrosoftPaint等)会频繁导致这些应用程序被锁定。检查他们的代码后发现,他们违反了COM并发的一个基本规则,就是说,如果一个线程要与另一个线程共享一个接口指针,它应首先封送该接口指针。如果有必要,封送接口指针可使COM创建一个新的代理(以及一个新的信道对象,将代理和存根结对),以允许从另一个单元向外调用。不通过封送而将原始接口指针(内存中的一个32位地址)传递给另一个线程,会绕过COM的并发机制,并且如果发送和接收的线程位于不同的单元中,将出现各种不良行为。(在Windows2000中,由于两个对象可以共享一个单元,但又位于不同的上下文中,因此如果线程位于同一个单元中,可能会使您陷入困境。)典型的症状包括调用失败和返回RPC_E_WRONG_THREAD_ERROR。WindowsNT4.0和更高版本可以使用一对名为CoMarshalInterThreadInte**ceInStream和CoGetInte**ceAndReleaseStream的API函数,在线程之间轻松地封送接口指针。假定您应用程序中的一个线程(线程A)创建了一个COM对象,继而接收了一个IFoo接口指针,并且同一进程中的另一个线程(线程B)想调用这个对象。在准备将接口指针传递给线程B时,线程A应该封送该接口指针,如下所示:CoMarshalInterThreadInte**ceInStream(IID_IFoo,pFoo,&pStream);在CoMarshalInterThreadInte**ceInStream返回后,线程B就可以安全地取消封送该接口指针:IFoo*pFoo;CoGetInte**ceAndReleaseStream(pStream,IID_IFoo,(void**)&pFoo);在这些示例中,pFoo是一个IFoo接口指针,pStream是一个IStream接口指针。COM在调用CoMarshalInterThreadInte**ceInStream时初始化IStream接口指针,然后在CoGetInte**ceAndReleaseStream内部使用和释放该接口指针。实际上,您通常要使用一个事件或其他同步化基元来协调这两个线程的行为—例如,让线程B知道接口指针已准备好,可以取消封送。请注意,以这种方式封送接口指针不会出现任何问题,因为COM有足够的智能,在不需要进行封送时不会去封送(或重新封送)指针。如果在线程之间传递接口指针时这样做,使用COM就轻松多了。如果调用CoMarshalInterThreadInte**ceInStream和CoGetInte**ceAndReleaseStream看起来太麻烦,您还可以通过将接口指针放在全局接口表(GIT)中,并让其他线程去那里检索它们,从而实现在线程之间传递接口指针。从GIT中检索到的接口指针在被检索时会自动封送。更多信息,请参阅IGlobalInte**ceTable中的文档。
引用 11 楼 skyxie 的回复:
事实上,这种方法是可以用的,获取【其他进程】的doc进行操作没有任何问题!
我曾经用这种方法写过一个自动玩qq网页游戏怪物对对碰的辅助工具(使用IE打开qq怪物对对碰游戏,然后用工具选中该IE窗口,就可以自动玩)
C/C++ code
HRESULT CMyQQGameToolDlg::GetIHTMLDocument2FromHWND(IHTMLDocument2 ** pDo……
事实上,这种方法是可以用的,获取【其他进程】的doc进行操作没有任何问题!
我曾经用这种方法写过一个自动玩qq网页游戏怪物对对碰的辅助工具(使用IE打开qq怪物对对碰游戏,然后用工具选中该IE窗口,就可以自动玩)
C/C++ code
HRESULT CMyQQGameToolDlg::GetIHTMLDocument2FromHWND(IHTMLDocument2 ** pDo……
确实如你所说,再QI一次就可以了,呵呵
引用 12 楼 grany 的回复:
转一篇文章,希望对你有用
不要在线程之间传递原始接口指针我咨询的首批COM项目之一就涉及到一个包含100,000行代码的分布式应用程序,该程序是由美国西海岸的一个大型软件公司编写的。该应用程序在多个机器上创建了数十个COM对象,并从客户端进程启动的背景线程中调用这些对象。开发小组遇到问题了,调用要么消失得无影无踪,要么在没有明显原因的情况下失败。他们给我演示的最惊人的症状是:当一个调用无法返回……
转一篇文章,希望对你有用
不要在线程之间传递原始接口指针我咨询的首批COM项目之一就涉及到一个包含100,000行代码的分布式应用程序,该程序是由美国西海岸的一个大型软件公司编写的。该应用程序在多个机器上创建了数十个COM对象,并从客户端进程启动的背景线程中调用这些对象。开发小组遇到问题了,调用要么消失得无影无踪,要么在没有明显原因的情况下失败。他们给我演示的最惊人的症状是:当一个调用无法返回……
虽然这篇文章中所说的方法我用不上,不过还是长见识了,相信以后一定用得上的,
北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号世纪乐知(北京)网络技术有限公司 提供技术支持Copyright © 1999-2010, CSDN.NET, All Rights Reserved