"楼主我使用CWebBrowserUI控件,什么也获取不到htm某个标签,如input。弄了几天了无果,可否...?"
我写了一个Demo给他, 希望他开心~
其实我写完这个Demo, 也很开心, 又复习了一个技术点~
这个Demo功能 :
* 一个DuiLib的UI, 显示一个浏览器控件. 加载百度的首页.
* 用程序向百度网页的搜索输入框内填写需要搜索的内容
* 用程序点击百度搜索的搜索按钮, 实现搜索.
做的过程中,我遇到一些应该注意的地方.
* 要找的HTML元素, 有的要按照ID来找, 有的要按照CLASS NAME来找. 因为如果一直按照ID来找,有的元素没有ID名称内容...
* 实际查找的关键字和用chrome"审查元素"看到的并不一致. 以实际调试的结果为准!
否则就会找不到该元素! e.g. 我们遍历了一个节点, 如果该节点是正确的, 但是下面的搜索的元素找不到, 那一定是要搜索的元素名称(id or class)填错了
这时要单步遍历这个节点, 看看遍历后的元素列表, 有那些和我们要找的节点符合. 最终才能确认正确的元素名称.
对于实际加载的不同HTML页面, 需要在查找元素那单步遍历调整一下, 才能符合实际的需要.
从DOM树从上到下,一个目标顶层节点找到后, 在此节点下,再找下一个目标节点, 直到找到要操作的HTML元素指针.
在将此HTML元素指针, 用 QueryInterface(IID_IHTML_X) 转换为能提供适当方法的最终COM指针,调用该COM指针的方法就完事了.
工程下载点 : prj_webpage_element_opt_srcbk_2015_0905_1841.rar
编译环境 : vs2010 vc++ + duilib + debug
效果图:
工程预览:
/// @file MainDlg.cpp
#include "stdafx.h"
#include "resource.h"
#include "resource.h"
#include <comutil.h>
#include <commdlg.h>
#include <mshtml.h>
#include <wininet.h>
#include <sys/stat.h>
#include "MainDlg.h"
#define CHECK_HR_BREAK(hr) \
if (FAILED(hr)) { \
break; \
}
#define CHECK_HR_POINTER_BREAK(hr,p) \
if (FAILED(hr) || NULL == (p)) { \
if (NULL == (p)) { \
hr = E_FAIL; \
} \
break; \
}
/// Hook键盘产生的数据, 动机 : 当焦点在Edit中时, DuiLib不传递 WM_KEYxx + VT_TAB
/// 下全局钩子, 不采用DLL注入方式, 只监控本程序的键盘输入
/// 当有Tab键按下时, PostMessage 到主程序中处理,
/// 当此时, 登录框出现时, 就切换用户名和密码的Edit焦点
TAG_HOOK_DATA g_KbHookData;
TAG_HOOK_DATA g_MouseHookData;
HWND g_hHwndMain = NULL;
LRESULT CALLBACK MouseProc(int nCode,WPARAM wParam,LPARAM lParam)
{
if (nCode==0)
{
MOUSEHOOKSTRUCT* pMouseHook= (MOUSEHOOKSTRUCT*)lParam;
if ( pMouseHook->hwnd == NULL )
{
}
}
return CallNextHookEx(g_MouseHookData.hHook, nCode, wParam, lParam);
}
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
static LONG_PTR lVkCodePrev_Tab = 0;
static LONG_PTR lVkCode_Tab = 0;
static LONG_PTR lVkCode_Enter = 0;
static LONG_PTR lVkCode_Cancel = 0;
LONG_PTR lTemp = 0;
/** when tab key press down and up
KeyboardProc : nCode = 0x0, wParam = 0x9, lParam = 0xF0001
KeyboardProc : nCode = 0x0, wParam = 0x9, lParam = 0xC00F0001
*/
if (0 == nCode)
{
switch (wParam)
{
case VK_TAB:
{
lVkCode_Tab = (LONG_PTR)lParam;
lTemp = lVkCode_Tab & 0xFFF00000;
if (0 == lTemp)
{
// tab key press down
lVkCodePrev_Tab = lVkCode_Tab;
}
else
{
// tab key press up
if (lVkCode_Tab != lVkCodePrev_Tab)
{
lVkCodePrev_Tab = lVkCode_Tab;
if (NULL != g_hHwndMain)
{
::PostMessageW(g_hHwndMain, WM_TAB_KEY_PRESS, 0, 0);
}
}
}
}
break;
case VK_RETURN:
{
lVkCode_Enter = (LONG_PTR)lParam;
lTemp = lVkCode_Enter & 0xFFF00000;
if (lTemp > 0)
{
// key press up
if (NULL != g_hHwndMain)
{
::PostMessageW(g_hHwndMain, WM_ENTER_KEY_PRESS, 0, 0);
}
}
}
break;
case VK_UP:
{
lVkCode_Enter = (LONG_PTR)lParam;
lTemp = lVkCode_Enter & 0xFFF00000;
if (lTemp>0)
{
POINT pt;
GetCursorPos(&pt);
::PostMessageW(g_hHwndMain,WM_UP_KEY_PRESS,pt.x,pt.y);
}
}
break;
case VK_DOWN:
{
lVkCode_Enter = (LONG_PTR)lParam;
lTemp = lVkCode_Enter & 0xFFF00000;
if (lTemp>0)
{
::PostMessageW(g_hHwndMain,WM_DOWN_KEY_PRESS,0,0);
}
}
break;
case VK_ESCAPE:
{
lVkCode_Cancel = (LONG_PTR)lParam;
lTemp = lVkCode_Cancel & 0xFFF00000;
if (0 == lTemp)
{
// key press down
if (NULL != g_hHwndMain)
{
::PostMessageW(g_hHwndMain, WM_CANCEL_KEY_PRESS, 0, 0);
}
}
}
break;
default:
break;
}
}
return CallNextHookEx(g_KbHookData.hHook, nCode, wParam, lParam);
}
CMainDlg::CMainDlg(WCHAR * pcXmlFileName, WCHAR * pcWndClassName)
: CXmlWnd(pcXmlFileName, pcWndClassName)
{
DataInit();
}
CMainDlg::~CMainDlg(void)
{
DataUnInit();
}
DUI_BEGIN_MESSAGE_MAP(CMainDlg, CXmlWnd)
DUI_ON_MSGTYPE(DUI_MSGTYPE_CLICK, OnClick)
DUI_END_MESSAGE_MAP()
void CMainDlg::UiInit()
{
do
{
m_dwMainTID = ::GetCurrentThreadId();
WriteLogEx(L"m_dwMainTID = 0x%x or %d", m_dwMainTID, m_dwMainTID);
m_pTabView = (DuiLib::CTabLayoutUI*)m_PaintManager.FindControl(L"TabLayout_setup_now");
if (NULL == m_pTabView)
break;
m_pPage_StartProg = (DuiLib::CContainerUI*)m_pTabView->FindSubControl(L"Container_page_install_over");
if (NULL == m_pPage_StartProg)
break;
m_pStatusMsg = (CLabelUI*)m_PaintManager.FindControl(L"Label_UI_MSG");
_ASSERT(NULL != m_pStatusMsg);
UiInit_WebPage();
switch_view(e_view_index_start_prog);
/// 将窗体放到桌面右下角
MoveMyWindowToDesktopRightBottom();
ThreadProcStart();
} while (0);
}
void CMainDlg::UiInit_WebPage()
{
m_pWebBrowser_url_1 = static_cast<CWebBrowserUI *>(m_pPage_StartProg->FindSubControl(L"ActiveX_url_webPage1"));
_ASSERT(NULL != m_pWebBrowser_url_1);
WebBrowserInit(m_pWebBrowser_url_1);
m_pWebBrowser_url_2 = static_cast<CWebBrowserUI *>(m_pPage_StartProg->FindSubControl(L"ActiveX_url_webPage2"));
_ASSERT(NULL != m_pWebBrowser_url_2);
WebBrowserInit(m_pWebBrowser_url_2);
}
BOOL CMainDlg::WebBrowserInit(CWebBrowserUI * pActivexUi)
{
BOOL bRc = FALSE;
if (NULL == pActivexUi)
return FALSE;
pActivexUi->SetDelayCreate(false);
return TRUE;
}
BOOL CMainDlg::WebBrowserNavigate(CWebBrowserUI * pActivexUi, const WCHAR * pcUrl, BOOL bCloseBeforeOpen /*= FALSE*/)
{
VARIANT_BOOL bBusy;
IWebBrowser2* pWebBrowser = NULL;
if ((NULL == pActivexUi) || (NULL == pcUrl))
return FALSE;
pActivexUi->GetControl(IID_IWebBrowser2, (void**)&pWebBrowser);
if (NULL == pWebBrowser)
return FALSE;
/// 传进自己的 CWebBrowserEventHandler *, 多个网页可以公用一个事件捕捉器
// pActivexUi->SetWebBrowserEventHandler(m_pWebBrowserEventHandler_MainDlg);
if (bCloseBeforeOpen)
{
pWebBrowser->Quit();
}
pWebBrowser->Navigate(_bstr_t(pcUrl), NULL, NULL, NULL, NULL);
WriteLogEx(L"CMainDlg::WebBrowserNavigate pcUrl = [%s]", (NULL != pcUrl) ? pcUrl : L"");
do
{
pWebBrowser->get_Busy(&bBusy);
if (bBusy > 0)
{
Sleep(10); ///< 从来没进过这里...
}
} while (bBusy > 0);
pWebBrowser->Release();
return TRUE;
}
void CMainDlg::SetWebPageFocusEx(CWebBrowserUI * pWebPage)
{
/// 设置网页为焦点, 使鼠标滚动时, 可以让网页元素进行滚动
/// 相当于当网页打开后,先用鼠标在网页中空白处点击一下,再用鼠标滚轮滚动网页
/// @ref invalid http://www.cnblogs.com/baoconghui/archive/2012/09/08/2676935.html
/// @ref ok http://stackoverflow.com/questions/298932/set-focus-to-embedded-mshtml
/// DuiLib的 CWebBrowserUI 稍有不同
HRESULT hr = S_FALSE;
IWebBrowser2 * pIWebBrowser2 = NULL;
IDispatch * pHtmlDocDisp = NULL;
IHTMLDocument2 * pHtmlDoc2 = NULL;
IHTMLWindow2 * pHtmlWindow2 = NULL;
if (NULL == pWebPage)
goto END_SetWebPageFocus;
// get web browser interface
pIWebBrowser2 = pWebPage->GetWebBrowser2();
if (NULL == pIWebBrowser2)
goto END_SetWebPageFocus;
// get the IDispatch interface of the document
hr = pIWebBrowser2->get_Document(&pHtmlDocDisp);
if (FAILED(hr) || (NULL == pHtmlDocDisp))
goto END_SetWebPageFocus;
// Query interface for IHTMLDocument2
hr = pHtmlDocDisp->QueryInterface (IID_IHTMLDocument2, (void**)&pHtmlDoc2);
if (FAILED(hr) || (NULL == pHtmlDoc2))
goto END_SetWebPageFocus;
hr = pHtmlDoc2->get_parentWindow(&pHtmlWindow2);
if (FAILED(hr) || (NULL == pHtmlWindow2))
goto END_SetWebPageFocus;
pHtmlWindow2->focus(); ///< !
END_SetWebPageFocus:
/// 这里不能释放得到的COM指针,否则运行21~36次的时候报错.
/// 只释放通过QueryInterface得到的COM指针
if (NULL != pHtmlDoc2)
{
pHtmlDoc2->Release();
pHtmlDoc2 = NULL;
}
return;
}
void CMainDlg::CloseWebPageToDo(CWebBrowserUI * pWebPage)
{
WebBrowserNavigate(pWebPage, L"about:blank", TRUE);
}
void CMainDlg::CloseWebPage(CWebBrowserUI * pWebPage)
{
/// 设置网页为焦点, 使鼠标滚动时, 可以让网页元素进行滚动
/// 相当于当网页打开后,先用鼠标在网页中空白处点击一下,再用鼠标滚轮滚动网页
/// @ref invalid http://www.cnblogs.com/baoconghui/archive/2012/09/08/2676935.html
/// @ref ok http://stackoverflow.com/questions/298932/set-focus-to-embedded-mshtml
/// DuiLib的 CWebBrowserUI 稍有不同
HRESULT hr = S_FALSE;
IWebBrowser2 * pIWebBrowser2 = NULL;
IDispatch * pHtmlDocDisp = NULL;
IHTMLDocument2 * pHtmlDoc2 = NULL;
IHTMLWindow2 * pHtmlWindow2 = NULL;
if (NULL == pWebPage)
goto END_CloseWebPage;
// get web browser interface
pIWebBrowser2 = pWebPage->GetWebBrowser2();
if (NULL == pIWebBrowser2)
goto END_CloseWebPage;
// get the IDispatch interface of the document
hr = pIWebBrowser2->get_Document(&pHtmlDocDisp);
if (FAILED(hr) || (NULL == pHtmlDocDisp))
goto END_CloseWebPage;
// Query interface for IHTMLDocument2
hr = pHtmlDocDisp->QueryInterface (IID_IHTMLDocument2, (void**)&pHtmlDoc2);
if (FAILED(hr) || (NULL == pHtmlDoc2))
goto END_CloseWebPage;
hr = pHtmlDoc2->get_parentWindow(&pHtmlWindow2);
if (FAILED(hr) || (NULL == pHtmlWindow2))
goto END_CloseWebPage;
VARIANT var;
::VariantInit(&var);
hr = pHtmlWindow2->execScript(L"window.close=true", L"javascript", &var);
/// hr = E_INVALIDARG, why ?
// if (FAILED(hr))
// goto END_CloseWebPage;
pHtmlWindow2->close(); ///< IE会弹出提示"您查看的网页正在试图关闭窗口.是否关闭此窗口?", 点击是, 浏览器就关闭了
/// 但是关闭之后, 该窗口就停止响应了, 无法再次载入url
/// @todo 暂时只能 WebBrowserNavigate 到别的url e.g. 导航到空白页 或 隐藏该浏览器控件
END_CloseWebPage:
/// 这里不能释放得到的COM指针,否则运行21~36次的时候报错.
/// 只释放通过QueryInterface得到的COM指针
if (NULL != pHtmlDoc2)
{
pHtmlDoc2->Release();
pHtmlDoc2 = NULL;
}
return;
}
void CMainDlg::MoveMyWindowToDesktopRightBottom()
{
ASSERT(::IsWindow(m_hWnd));
ASSERT((GetWindowStyle(m_hWnd)&WS_CHILD)==0);
RECT rcDlg = { 0 };
::GetWindowRect(m_hWnd, &rcDlg);
RECT rcArea = { 0 };
RECT rcCenter = { 0 };
HWND hWnd=*this;
HWND hWndParent = ::GetParent(m_hWnd);
HWND hWndCenter = ::GetWindowOwner(m_hWnd);
if (hWndCenter!=NULL)
hWnd=hWndCenter;
// 处理多显示器模式下屏幕居中
MONITORINFO oMonitor = {};
oMonitor.cbSize = sizeof(oMonitor);
::GetMonitorInfo(::MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST), &oMonitor);
rcArea = oMonitor.rcWork;
if( hWndCenter == NULL )
rcCenter = rcArea;
else
::GetWindowRect(hWndCenter, &rcCenter);
int DlgWidth = rcDlg.right - rcDlg.left;
int DlgHeight = rcDlg.bottom - rcDlg.top;
// Find dialog's upper left based on rcCenter
int xLeft = rcCenter.right - DlgWidth;
int yTop = rcCenter.bottom - DlgHeight;
// The dialog is outside the screen, move it inside
if( xLeft < rcArea.left )
xLeft = rcArea.left;
else if( xLeft + DlgWidth > rcArea.right )
xLeft = rcArea.right - DlgWidth;
if( yTop < rcArea.top )
yTop = rcArea.top;
else if( yTop + DlgHeight > rcArea.bottom )
yTop = rcArea.bottom - DlgHeight;
::SetWindowPos(m_hWnd, NULL, xLeft, yTop, -1, -1, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
void CMainDlg::DataInit()
{
m_strTipMsg = L"";
m_strTipMsgPerv = L"";
m_pStatusMsg = NULL;
m_bRunObjProgNow = FALSE;
m_dwMainTID = 0;
m_pTabView = NULL;
m_pPage_StartProg = NULL;
m_pWebBrowser_url_1 = NULL;
m_pWebBrowser_url_2 = NULL;
}
void CMainDlg::DataUnInit()
{
}
LONG CMainDlg::GetStyle()
{
long dwStyle = __super::GetStyle();
dwStyle &= ~WS_MAXIMIZEBOX;
return dwStyle;
}
/// CMainDlg::GetExStyle 是虚函数, 在WindowImplBase::OnCreate中被调用, 用来设置扩展窗口风格
LONG CMainDlg::GetExStyle()
{
long dwStyle = __super::GetExStyle();
/// 禁止接受文件拖拽
dwStyle &= ~WS_EX_ACCEPTFILES;
/// 禁止产生任务栏图标
dwStyle |= WS_EX_TOOLWINDOW;
dwStyle &= ~(WS_EX_APPWINDOW);
return dwStyle;
}
LRESULT CMainDlg::WndMessageProc_WM_DISP_REFRESH(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (WM_DISP_REFRESH == uMsg)
{
switch (wParam)
{
case DISP_MSG:
ShowMsg(m_strTipMsg.c_str());
break;
default:
break;
}
}
return S_OK;
}
void CMainDlg::ShowMsg(const WCHAR* pcMsg)
{
do
{
/// 防止显示重复数据时, 由于要加锁判断, 使显示效率降低
if (0 == m_strTipMsgPerv.compare((NULL != pcMsg) ? pcMsg : L""))
break;
m_Locker_MainUI.enter();
m_strTipMsg = (NULL != pcMsg) ? pcMsg : L"";
m_Locker_MainUI.leave();
if (GetCurrentThreadId() != m_dwMainTID)
{
::PostMessageW(this->GetHWND(), WM_DISP_REFRESH, DISP_MSG, 0);
}
else
{
m_Locker_MainUI.enter();
m_pStatusMsg->SetText(m_strTipMsg.c_str());
m_Locker_MainUI.leave();
}
} while (0);
}
LRESULT CMainDlg::WndMessageProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
BOOL bNeedDefaultProcess = FALSE;
do
{
switch (uMsg)
{
case WM_DISP_REFRESH:
WndMessageProc_WM_DISP_REFRESH(uMsg, wParam, lParam);
break;
/// 如果窗口的扩展风格 WS_EX_ACCEPTFILES 被禁止, 是接受不到 WM_DROPFILES 消息的
/// 同时, 拖动文件到CMainDlg时, 图标是禁止样式的图标
case WM_DROPFILES:
OutputDebugStringW(L"");
break;
case WM_CREATE:
bNeedDefaultProcess = TRUE;
break;
case WM_SWITCH_VIEW:
switch_view((e_view_index)wParam);
break;
case WM_CLOSE:
CloseWebPageToDo(m_pWebBrowser_url_1);
CloseWebPageToDo(m_pWebBrowser_url_2);
EntryUiDestory(TRUE);
bNeedDefaultProcess = ThreadProcEnd(FALSE);
break;
default:
bNeedDefaultProcess = TRUE;
break;
}
if (bNeedDefaultProcess)
return __super::WndMessageProc(uMsg, wParam, lParam);
} while (0);
return S_OK;
}
void CMainDlg::InitWindow()
{
BOOL bRc = FALSE;
DWORD dwStyle = 0;
UiInit();
}
CControlUI* CMainDlg::CreateUiControlByMySelf(LPCTSTR pstrClass)
{
if (0 == _tcscmp(pstrClass,_T("ButtonGif")))
return new CButtonGifUI;
return NULL;
}
LRESULT CMainDlg::SysMessageProc(UINT uMsg, WPARAM wParam, LPARAM lParam, bool& bHandled)
{
return __super::SysMessageProc(uMsg, wParam, lParam, bHandled);
}
void CMainDlg::OnFinalMessage(HWND hWnd)
{
m_PaintManager.FreeResourceZip(); ///< !
__super::OnFinalMessage(hWnd);
}
void CMainDlg::Notify(TNotifyUI & msg)
{
std::wstring strName = L"";
do
{
if (NULL == msg.pSender)
{
break;
}
strName = msg.pSender->GetName().GetData();
if (msg.sType == DUI_MSGTYPE_SCROLL)
{
}
} while (0);
return __super::Notify(msg);
}
void CMainDlg::OnClick(TNotifyUI& msg)
{
BOOL bNeedDefaultProcess = FALSE;
std::wstring strName = L"";
std::wstring strTmp = L"";
if (NULL != msg.pSender)
{
strName = msg.pSender->GetName().GetData();
}
if (strName == L"btn_close_ui5")
{
::PostMessageW(this->GetHWND(), WM_CLOSE, 0, 0);
}
else if (strName == L"btn_run_now")
{
m_bRunObjProgNow = TRUE;
}
else if (strName == L"Button_UI_load_web_page1")
{
// D:\prj\study\demo\prj_webpage_element_opt\srcMain\dlgNotify\test_baidu.html
WebBrowserNavigate(m_pWebBrowser_url_1, L"www.baidu.com");
// WebBrowserNavigate(m_pWebBrowser_url_1, L"D:\\prj\\study\\demo\\prj_webpage_element_opt\\srcMain\\dlgNotify\\test_baidu.html");
}
else if (strName == L"Button_UI_load_web_page2")
{
WebBrowserNavigate(m_pWebBrowser_url_2, L"www.bing.com");
}
else if (strName == L"Button_UI_set_focus_on_web_page1")
{
SetWebPageFocusEx(m_pWebBrowser_url_1);
}
else if (strName == L"Button_UI_set_focus_on_web_page2")
{
SetWebPageFocusEx(m_pWebBrowser_url_2);
}
else if (strName == L"Button_UI_close_on_web_page1")
{
CloseWebPageToDo(m_pWebBrowser_url_1);
}
else if (strName == L"Button_UI_close_on_web_page2")
{
CloseWebPageToDo(m_pWebBrowser_url_2);
}
else if (strName == L"Button_UI_fill_baidu_search_content")
{
/// 填充百度搜索内容框
strTmp = ns_base::StringFormatV(L"our_content_%d", GetTickCount()).c_str();
WebBrowserOpt_fill_baidu_search_content(m_pWebBrowser_url_1, strTmp.c_str());
}
else if (strName == L"Button_UI_click_baidu_btn_search")
{
/// 点击百度搜索按钮
WebBrowserOpt_click_baidu_btn_search(m_pWebBrowser_url_1);
}
else
{
bNeedDefaultProcess = TRUE;
}
if (bNeedDefaultProcess)
__super::OnClick(msg);
}
BOOL CMainDlg::WebBrowserOpt_fill_baidu_search_content(CWebBrowserUI * pWebPage, const WCHAR* pcMsg)
{
BOOL bRc = FALSE;
HRESULT hr = S_FALSE;
// CComPtr<IWebBrowser2> spWeb = NULL;
IWebBrowser2* spWeb = NULL;
long lElementCnt = 0;
long lElementCurIndex = 0;
CComPtr<IDispatch> dispDoc = NULL;
CComPtr<IHTMLDocument2> spDoc = NULL;
CComPtr<IHTMLElement> spBody = NULL;
CComPtr<IHTMLElement> sp_div_wrapper = NULL;
CComPtr<IHTMLElement> sp_div_head = NULL;
CComPtr<IHTMLElement> sp_div_head_wrapper = NULL;
CComPtr<IHTMLElement> sp_div_s_fm = NULL;
CComPtr<IHTMLElement> sp_div_s_form_wrapper = NULL;
CComPtr<IHTMLElement> sp_form_f = NULL;
CComPtr<IHTMLElement> sp_span_s_ipt_wr = NULL;
CComPtr<IHTMLElement> sp_input_s_ipt = NULL; ///< ! 这是我们最终要找的input控件
/// 从sp_input_s_ipt查询出来的input控件, 用于最后的实际操作
/// e.g. 对INPUT控件进行读写
CComPtr<IHTMLInputElement> sp_input_ctrl = NULL;
do
{
if (NULL == pWebPage)
break;
// hr = pWebPage->QueryInterface(IID_IWebBrowser2, (LPVOID*)&spWeb);
// hr = E_NOINTERFACE
spWeb = pWebPage->GetWebBrowser2();
CHECK_HR_POINTER_BREAK(hr, spWeb);
hr = spWeb->get_Document(&dispDoc);
CHECK_HR_POINTER_BREAK(hr, dispDoc);
hr = dispDoc->QueryInterface(IID_IHTMLDocument2, (LPVOID*)&spDoc);
CHECK_HR_POINTER_BREAK(hr, spDoc);
hr = spDoc->get_body(&spBody);
CHECK_HR_POINTER_BREAK(hr, spBody);
/// 在DOM节点下,一个一个的缩小搜索范围, 直到找到目标元素
/// 用chrome打开网页, 在需要的HTML元素上点击审查元素, 就可以看到DOM树
hr = GetElement(spBody, EID, L"wrapper", sp_div_wrapper, lElementCnt, lElementCurIndex, FALSE);
CHECK_HR_POINTER_BREAK(hr, sp_div_wrapper);
hr = GetElement(sp_div_wrapper, EID, L"head", sp_div_head, lElementCnt, lElementCurIndex, FALSE);
CHECK_HR_POINTER_BREAK(hr, sp_div_head);
/// 当html元素的class和id名称相同时, 应该去查class的名称, 才能找到元素!
/// 因为 spElem->get_id得不到内容, spElem->get_className可以得到内容
/// e.g. <div class="s_form_wrapper" id="s_form_wrapper">
hr = GetElement(sp_div_head, ECLASSNAME, L"head_wrapper", sp_div_head_wrapper, lElementCnt, lElementCurIndex, FALSE);
CHECK_HR_POINTER_BREAK(hr, sp_div_head_wrapper);
hr = GetElement(sp_div_head_wrapper, ECLASSNAME, L"s_form", sp_div_s_fm, lElementCnt, lElementCurIndex, FALSE);
CHECK_HR_POINTER_BREAK(hr, sp_div_s_fm);
hr = GetElement(sp_div_s_fm, ECLASSNAME, L"s_form_wrapper", sp_div_s_form_wrapper, lElementCnt, lElementCurIndex, FALSE);
CHECK_HR_POINTER_BREAK(hr, sp_div_s_form_wrapper);
hr = GetElement(sp_div_s_form_wrapper, ECLASSNAME, L"fm", sp_form_f, lElementCnt, lElementCurIndex, FALSE);
CHECK_HR_POINTER_BREAK(hr, sp_form_f);
hr = GetElement(sp_form_f, ECLASSNAME, L"bg s_ipt_wr quickdelete-wrap", sp_span_s_ipt_wr, lElementCnt, lElementCurIndex, FALSE);
CHECK_HR_POINTER_BREAK(hr, sp_span_s_ipt_wr);
hr = GetElement(sp_span_s_ipt_wr, ECLASSNAME, L"s_ipt", sp_input_s_ipt, lElementCnt, lElementCurIndex, FALSE);
CHECK_HR_POINTER_BREAK(hr, sp_input_s_ipt);
// ok 已经得到 INPUT控件 sp_input_s_ipt
hr = sp_input_s_ipt->QueryInterface(IID_IHTMLInputElement, (LPVOID*)&sp_input_ctrl);
CHECK_HR_POINTER_BREAK(hr, sp_input_ctrl);
hr = sp_input_ctrl->put_value(BSTR((NULL != pcMsg) ? pcMsg : L""));
CHECK_HR_BREAK(hr);
bRc = TRUE;
} while (0);
return bRc;
}
BOOL CMainDlg::WebBrowserOpt_click_baidu_btn_search(CWebBrowserUI * pWebPage)
{
BOOL bRc = FALSE;
HRESULT hr = S_FALSE;
// CComPtr<IWebBrowser2> spWeb = NULL;
IWebBrowser2* spWeb = NULL;
long lElementCnt = 0;
long lElementCurIndex = 0;
CComPtr<IDispatch> dispDoc = NULL;
CComPtr<IHTMLDocument2> spDoc = NULL;
CComPtr<IHTMLElement> spBody = NULL;
CComPtr<IHTMLElement> sp_div_wrapper = NULL;
CComPtr<IHTMLElement> sp_div_head = NULL;
CComPtr<IHTMLElement> sp_div_head_wrapper = NULL;
CComPtr<IHTMLElement> sp_div_s_fm = NULL;
CComPtr<IHTMLElement> sp_div_s_form_wrapper = NULL;
CComPtr<IHTMLElement> sp_form_f = NULL;
CComPtr<IHTMLElement> sp_span_btn_wr = NULL;
CComPtr<IHTMLElement> sp_input_self_btn = NULL; ///< 百度搜索的提交按钮
/// 从sp_input_self_btn查询出来的input控件, 用于最后的实际操作
/// e.g. 提交, 进行搜索
CComPtr<IHTMLElement> sp_input_ctrl = NULL; ///< IHTMLElement 有click方法
do
{
if (NULL == pWebPage)
break;
// hr = pWebPage->QueryInterface(IID_IWebBrowser2, (LPVOID*)&spWeb);
// hr = E_NOINTERFACE
spWeb = pWebPage->GetWebBrowser2();
CHECK_HR_POINTER_BREAK(hr, spWeb);
hr = spWeb->get_Document(&dispDoc);
CHECK_HR_POINTER_BREAK(hr, dispDoc);
hr = dispDoc->QueryInterface(IID_IHTMLDocument2, (LPVOID*)&spDoc);
CHECK_HR_POINTER_BREAK(hr, spDoc);
hr = spDoc->get_body(&spBody);
CHECK_HR_POINTER_BREAK(hr, spBody);
/// 在DOM节点下,一个一个的缩小搜索范围, 直到找到目标元素
/// 用chrome打开网页, 在需要的HTML元素上点击审查元素, 就可以看到DOM树
hr = GetElement(spBody, EID, L"wrapper", sp_div_wrapper, lElementCnt, lElementCurIndex, FALSE);
CHECK_HR_POINTER_BREAK(hr, sp_div_wrapper);
hr = GetElement(sp_div_wrapper, EID, L"head", sp_div_head, lElementCnt, lElementCurIndex, FALSE);
CHECK_HR_POINTER_BREAK(hr, sp_div_head);
/// 当html元素的class和id名称相同时, 应该去查class的名称, 才能找到元素!
/// 因为 spElem->get_id得不到内容, spElem->get_className可以得到内容
/// e.g. <div class="s_form_wrapper" id="s_form_wrapper">
hr = GetElement(sp_div_head, ECLASSNAME, L"head_wrapper", sp_div_head_wrapper, lElementCnt, lElementCurIndex, FALSE);
CHECK_HR_POINTER_BREAK(hr, sp_div_head_wrapper);
hr = GetElement(sp_div_head_wrapper, ECLASSNAME, L"s_form", sp_div_s_fm, lElementCnt, lElementCurIndex, FALSE);
CHECK_HR_POINTER_BREAK(hr, sp_div_s_fm);
hr = GetElement(sp_div_s_fm, ECLASSNAME, L"s_form_wrapper", sp_div_s_form_wrapper, lElementCnt, lElementCurIndex, FALSE);
CHECK_HR_POINTER_BREAK(hr, sp_div_s_form_wrapper);
hr = GetElement(sp_div_s_form_wrapper, ECLASSNAME, L"fm", sp_form_f, lElementCnt, lElementCurIndex, FALSE);
CHECK_HR_POINTER_BREAK(hr, sp_form_f);
hr = GetElement(sp_form_f, ECLASSNAME, L"bg s_btn_wr", sp_span_btn_wr, lElementCnt, lElementCurIndex, FALSE);
CHECK_HR_POINTER_BREAK(hr, sp_span_btn_wr);
hr = GetElement(sp_span_btn_wr, ECLASSNAME, L"bg s_btn", sp_input_self_btn, lElementCnt, lElementCurIndex, FALSE);
CHECK_HR_POINTER_BREAK(hr, sp_input_self_btn);
// ok 已经得到 INPUT控件 sp_input_self_btn(百度搜索提交按钮)
hr = sp_input_self_btn->QueryInterface(IID_IHTMLElement, (LPVOID*)&sp_input_ctrl);
CHECK_HR_POINTER_BREAK(hr, sp_input_ctrl);
sp_input_ctrl->click();
bRc = TRUE;
} while (0);
return bRc;
}
HRESULT CMainDlg::GetElement(
CComPtr<IHTMLElement>& spElem,
EQUERYTYPE eType,
const std::wstring& cstrValue,
CComPtr<IHTMLElement>& spResElem,
OUT long& lElementCnt,
OUT long& lElementCurIndex,
IN BOOL bNeedBebug)
{
HRESULT hr = E_FAIL;
HRESULT hrOut = E_FAIL;
spResElem = NULL;
do {
lElementCnt = -1;
lElementCurIndex = -1;
CComPtr<IHTMLElementCollection> spElemCollection;
hr = GetElementCollection( spElem, spElemCollection);
CHECK_HR_POINTER_BREAK(hr,spElemCollection);
hr = spElemCollection->get_length(&lElementCnt);
CHECK_HR_BREAK(hr);
if (bNeedBebug)
{
OutputDebugStringW(L"");
}
for ( long i = 0; i < lElementCnt; i++ ) {
CComVariant VarIndex = i;
CComPtr<IDispatch> spDispatchElem;
hr = spElemCollection->item( VarIndex, VarIndex, &spDispatchElem );
CHECK_HR_POINTER_BREAK(hr,spDispatchElem);
CComPtr<IHTMLElement> spElem;
hr = spDispatchElem->QueryInterface(IID_IHTMLElement, (LPVOID*)& spElem );
CHECK_HR_POINTER_BREAK(hr, spElem);
/// @todo ls for debug >>
CComBSTR bstrValue_id;
CComBSTR bstrValue_name;
CComBSTR bstrValue_class_name;
hr = spElem->get_id(&bstrValue_id);
hr = spElem->get_tagName(&bstrValue_name);
hr = spElem->get_className(&bstrValue_class_name);
if (bNeedBebug)
{
OutputDebugStringW(L"");
}
/// @todo ls for debug <<
CComBSTR bstrValue;
switch (eType)
{
case EID:
{
hr = spElem->get_id(&bstrValue);
}
break;
case ETAGNAME:
{
hr = spElem->get_tagName(&bstrValue);
}
break;
case ECLASSNAME:
{
hr = spElem->get_className(&bstrValue);
}
break;
default:
break;
}
if ((NULL != bstrValue.m_str)
&& (0 == _tcsicmp((LPWSTR)bstrValue, cstrValue.c_str())))
{
/// find object html element
spResElem = spElem;
hrOut = hr;
lElementCurIndex = i;
if (bNeedBebug)
{
OutputDebugStringW(L"");
}
break;
}
}
} while (0);
if (bNeedBebug)
{
OutputDebugStringW(L"");
}
return hrOut;
}
HRESULT CMainDlg::GetElementCollection(
CComPtr<IHTMLElement>& spElem,
CComPtr<IHTMLElementCollection> & spElemCollection)
{
HRESULT hr = S_FALSE;
CComPtr<IDispatch> spDispatch;
do
{
// hr = spElem->get_children(&spDispatch); ///< get_children 和 DOM 树对不上
hr = spElem->get_children(&spDispatch);
CHECK_HR_BREAK(hr);
hr = spDispatch->QueryInterface( IID_IHTMLElementCollection, (LPVOID*)&spElemCollection);
CHECK_HR_BREAK(hr);
} while (0);
return hr;
}
LRESULT CMainDlg::OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
return __super::OnNcHitTest(uMsg, wParam, lParam, bHandled);
}
void CMainDlg::switch_view(e_view_index PageIndex)
{
static int iWidth = 0;
static int iHeight = 0;
do
{
if (::GetCurrentThreadId() != m_dwMainTID)
{
::PostMessageW(this->GetHWND(), WM_SWITCH_VIEW, PageIndex, 0);
break;
}
if (NULL == m_pTabView)
break;
iWidth = m_pTabView->GetFixedWidth();
iHeight = m_pTabView->GetFixedHeight();
switch (PageIndex)
{
case e_view_index_start_prog:
{
if (NULL != m_pPage_StartProg)
{
m_pTabView->SelectItem(m_pPage_StartProg);
}
}
break;
default:
break;
}
} while (0);
}
void CMainDlg::ThreadProcStart()
{
if (!m_ThreadManager.IsNeedQuitThread()
&& !m_ThreadManager.IsThreadRunning())
{
m_ThreadManager.SetThreadHandle((HANDLE)_beginthreadex(NULL, 0, &CMainDlg::ThreadProc, (void*)this, 0, NULL));
}
}
BOOL CMainDlg::ThreadProcEnd(BOOL bStopNow)
{
BOOL bThreadWasStop = FALSE;
do {
m_ThreadManager.StopThread(bStopNow, L"m_ThreadManager");
bThreadWasStop = !m_ThreadManager.IsThreadRunning();
} while (0);
return bThreadWasStop;
}
UINT WINAPI CMainDlg::ThreadProc(void* pParam)
{
UINT uRc = S_FALSE;
do
{
if (NULL == pParam)
break;
uRc = ((CMainDlg*)pParam)->ThreadProc();
} while (0);
return uRc;
}
UINT WINAPI CMainDlg::ThreadProc()
{
ShowMsg(L">> CMainDlg::ThreadProc()");
do
{
::Sleep(20);
if (IsEntryUiDestory())
break;
if (m_ThreadManager.IsNeedQuitThread())
break;
if (m_bRunObjProgNow)
{
m_bRunObjProgNow = FALSE;
RunObjProg();
::PostMessageW(this->GetHWND(), WM_CLOSE, 0, 0);
break;
}
} while (1);
::PostMessageW(this->GetHWND(), WM_CLOSE, 0, 0);
ShowMsg(L"<< CMainDlg::ThreadProc()");
return S_OK;
}
void CMainDlg::RunObjProg()
{
ns_base::CreateProcessEx(L"C:\\Windows\\System32\\notepad.exe", L"", FALSE, TRUE);
}