DuiLib : 模拟百度网页的填写和搜索

mgitlife@csdn 和我讨论一个问题:

"楼主我使用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);
}




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值