日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++中嵌入ie浏览器总结 .

發布時間:2025/5/22 c/c++ 139 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++中嵌入ie浏览器总结 . 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

C++中嵌入ie瀏覽器總結(1) - ie邊框 及上下文菜單

???? 最近項目中用html 來做界面,也就折騰了一下在wxwidget中嵌入瀏覽器的若干細節工作,mfc也基本是類似的,由于wxwidget中已經做了一個封裝wxie,但是開發過程中也遇到了不少問題,在此做一下總結:?

  • ie邊框 及上下文菜單
    ?? 普通嵌入到程序里面的瀏覽器頁面都會有一個灰色的邊框,這樣放到程序里面就很難看。目前網上流行的辦法添加css:
    body{
    ??border
    :0;
    }
  • ?????? 但是這個方法的缺點是,必須要把頁面頭部的dtd申明去掉。網上的錯誤提法是類似以下鏈接的:???http://www.faceker.com/200801/webbrowser-no-border.html?? 這里面講,只要把頭部改成:
    ???

    <!DOCTYPE?HTML?PUBLIC?"-//W3C//DTD?HTML?4.01?Transitional//EN">

    ?????但是目前很多頁面用了比較新的css,改成這樣后,頁面就無法正常顯示了。讓網頁美工改樣式? 真是有點困難。
    ??? 后來繼續查閱了資料,發現比較好的辦法,那就是重載? IDocHostUIHandler 接口,其中,實現以下部分:


    HRESULT?STDMETHODCALLTYPE?FrameSite::GetHostInfo(DOCHOSTUIINFO?
    *pInfo)
    {
    ????pInfo
    ->cbSize?=?sizeof(DOCHOSTUIINFO);
    ????pInfo
    ->dwFlags?=?DOCHOSTUIFLAG_NO3DBORDER|DOCHOSTUIFLAG_SCROLL_NO;
    ????pInfo
    ->dwDoubleClick?=?DOCHOSTUIDBLCLK_DEFAULT;
    ????
    return?S_OK;

    }

    ?????? 其中? DOCHOSTUIFLAG_NO3DBORDER 就表示不要生成邊框,DOCHOSTUIFLAG_SCROLL_NO 表示不要生成滾動條
    這樣就可以比較完美的解決邊框和滾動條的問題,不用依賴頁面的調整 。讓設計師愛用什么用什么。
    ?????另外一個就是禁用右鍵菜單,網上也有不少辦法,但是用這個接口可以很簡單的實現:?
    ?

    HRESULT?STDMETHODCALLTYPE?FrameSite::ShowContextMenu(DWORD?dwID,?POINT?*ppt,?
    ?????????????????????????????????????????????????????????????IUnknown?
    *pcmdtReserved,?IDispatch?*pdispReserved)
    {
    ????HRESULT?result????
    =?S_FALSE;?//Dont?Interfere
    ????BOOL????handled????=?FALSE;

    ????
    switch?(?m_contextMenuMode?)
    ????
    {
    ????
    case?kDefaultMenuSupport:
    ????????
    break;

    ????
    case?kNoContextMenu:
    ????????result????
    =?S_OK;
    ????????handled????
    =?TRUE;
    ????????
    break;

    ????
    case?kTextSelectionOnly:
    ????????
    if?(dwID?!=?CONTEXT_MENU_TEXTSELECT)
    ????????
    {
    ????????????result????
    =?S_OK;
    ????????????handled????
    =?TRUE;
    ????????}

    ????????
    break;

    ????
    case?kAllowAllButViewSource:
    ????????
    if?(dwID?==?CONTEXT_MENU_DEFAULT)
    ????????
    {
    ????????????
    //result????=?ModifyContextMenu(dwID,?ppt,?pcmdtReserved);
    ????????????handled????=?TRUE;
    ????????}

    ????????
    break;

    ????
    case?kCustomMenuSupport:
    ????????
    if?(dwID?==?CONTEXT_MENU_DEFAULT)
    ????????
    {
    ????????????
    //result?=?CustomContextMenu(ppt,?pcmdtReserved);
    ????????????handled????=?TRUE;
    ????????}

    ????????
    break;
    ????}


    ????
    if?(!?handled)
    ????
    {
    ?????????result?
    =?S_FALSE;
    ????}


    ????
    return?result;
    }

    ??? 這里不僅可以控制右鍵菜單顯示,m_contextMenuMode? = kNoContextMenu,還可以做到自定義菜單顯示,m_contextMenuMode? =其他值。因為暫時還不需要自定義菜單,所以這里沒有實現。
    ???
    ?? 如果用wxie,就在FrameSite類增加這個接口即可,不關注的接口直接返回S_FALSE 或E_NOTIMPL;

    ? 如果用sdk或mfc,可以 調用IOleObject 的SetClientSite 方法,設置一個繼承了IOleClientSite 和 IDocHostUIHandler 的接口。

    ?

    C++中嵌入ie瀏覽器總結(2) - 雙向通訊

    ?? 第一步解決了邊框和上下文菜單問題,第二部就是要解決c++程序和html頁面交互的問題。最開始的想法是通過c++去更新頁面內容的方式來完成c++->html的通訊,通過BeforeNavigate2 接口,截獲頁面url地址的方式來完成html->c++的通訊。但是這種方式存在以下缺點:?

    ???????(1) c++->html 的問題在于導致c++代碼復雜,需要通過c++代碼來完成頁面生成,如果修改頁面,將產生很大的工作量。雖然嘗試用了模板方法解決,但是還是比較繁瑣,而且會導致經常通訊的時候,頁面會經常刷新,產生其他的一些問題。
    ????? (2) html->c++ 的問題在于 傳遞參數不方便,解析也不方便、無法獲取返回值、腳本中要調用不方便

    ???? 為了解決這些問題,經過google后找到了問題的解決辦法 :?
    ??? (1) c++->html? ,可以通過調用頁面腳本方法來實現,調用方法如下:

    wxVariant?wxIEHtmlWin::ExecScript(const?wxString?&fun,const?std::vector<wxString>?&params?)
    {
    ????wxVariant?result(
    false);
    ????
    if?(!?m_webBrowser.Ok())
    ????????
    return?result;

    ????
    //?get?document?dispatch?interface
    ????IDispatch?*iDisp?=?NULL;
    ????HRESULT?hr?
    =?m_webBrowser->get_Document(&iDisp);
    ????
    if?(hr?!=?S_OK)
    ????????
    return?result;

    ????
    //?Query?for?Document?Interface
    ????wxAutoOleInterface<IHTMLDocument2>?hd(IID_IHTMLDocument2,?iDisp);
    ????iDisp
    ->Release();

    ????
    if?(!?hd.Ok())
    ????????
    return?result;

    ????IDispatch?
    *spScript;
    ????hr?
    =?hd->get_Script(&spScript);

    ????
    if(FAILED(hr))
    ????????
    return?result;
    ????BSTR?bstrMember?
    =?wxConvertStringToOle(fun);
    ????DISPID?dispid?
    =?NULL;
    ????hr?
    =?spScript->GetIDsOfNames(IID_NULL,&bstrMember,1,
    ????????LOCALE_SYSTEM_DEFAULT,
    &dispid);
    ????
    if(FAILED(hr))
    ????
    {
    ????????
    ????????
    return?result;
    ????}

    ????
    //Putting?parameters
    ????DISPPARAMS?dispparams;
    ????memset(
    &dispparams,?0,?sizeof?dispparams);
    ????dispparams.cArgs??????
    =?params.size();
    ????dispparams.rgvarg?????
    =?new?VARIANT[dispparams.cArgs];
    ????dispparams.cNamedArgs?
    =?0;

    ????
    for(?int?i?=?0;?i?<?params.size();?i++)
    ????
    {
    ????????CComBSTR?bstr?
    =?wxConvertStringToOle(params[params.size()?-?1?-?i]);
    ????????
    //?back?reading
    ????????bstr.CopyTo(&dispparams.rgvarg[i].bstrVal);

    ????????dispparams.rgvarg[i].vt?
    =?VT_BSTR;
    ????}

    ????EXCEPINFO?excepInfo;
    ????memset(
    &excepInfo,?0,?sizeof?excepInfo);
    ????VARIANT???varRet;
    ????UINT?nArgErr?
    =?(UINT)-1;??????//?initialize?to?invalid?arg
    ????
    //Call?JavaScript?function
    ????hr?=?spScript->Invoke(dispid,IID_NULL,0,
    ????????DISPATCH_METHOD,
    &dispparams,
    ????????
    &varRet,&excepInfo,&nArgErr);
    ????delete?[]?dispparams.rgvarg;
    ????
    if(FAILED(hr))
    ????
    {
    ????????
    ????????
    return?result;
    ????}


    ????wxConvertOleToVariant(varRet,result);
    ????
    return?result;


    }


    ? 這個方法實現了C++對頁面腳本調用,而且參數個數可以任意。比如頁面腳本是?:

    function?fun(a,b,c)
    {
    }


    ??C++中的調用方法是?:

    std::vector<wxString>?params;
    params.push_back("a");
    params.push_back("b");
    params.push_back("c");
    xxx
    ->ExecScripts("fun",params);


    還可以獲得腳本返回的結果。

    ? (2) html->c++? 通過腳本的window.external 方法,首先,在前文提到過的IDocHostUIHandler 接口中,實現方法:?

    HRESULT?STDMETHODCALLTYPE?FrameSite::GetExternal(IDispatch?**ppDispatch)
    {
    ?????
    ????IDispatch?
    *?pDisp?=?m_window->getExternal();
    ????
    if(pDisp)
    ????
    {
    ????????pDisp
    ->AddRef();
    ????????
    *ppDispatch?=?pDisp;
    ????}


    ????
    return?S_OK;
    }

    其中 m_window->getExternal();
    ?返回的是自定義的一個IDispatch 接口類:?

    /*
    ?*?IDispimp.H
    ?*?IDispatch
    ?*
    ?*?Copyright?(c)1995-1999?Microsoft?Corporation,?All?Rights?Reserved
    ?
    */
    ?


    #ifndef?_IDISPIMP_H_
    #define?_IDISPIMP_H_
    #include?
    <oaidl.h>
    class?CustomFunction;
    class?CImpIDispatch?:?public?IDispatch
    {
    ????
    protected:
    ????????ULONG???????????????m_cRef;

    ????
    public:
    ????????CImpIDispatch(
    void);
    ????????
    ~CImpIDispatch(void);

    ????????STDMETHODIMP?QueryInterface(REFIID,?
    void?**);
    ????????STDMETHODIMP_(ULONG)?AddRef(
    void);
    ????????STDMETHODIMP_(ULONG)?Release(
    void);

    ????????
    //IDispatch
    ????????STDMETHODIMP?GetTypeInfoCount(UINT*?pctinfo);
    ????????STDMETHODIMP?GetTypeInfo(
    /*?[in]?*/?UINT?iTInfo,
    ????????????
    /*?[in]?*/?LCID?lcid,
    ????????????
    /*?[out]?*/?ITypeInfo**?ppTInfo);
    ????????STDMETHODIMP?GetIDsOfNames(
    ????????????
    /*?[in]?*/?REFIID?riid,
    ????????????
    /*?[size_is][in]?*/?LPOLESTR?*rgszNames,
    ????????????
    /*?[in]?*/?UINT?cNames,
    ????????????
    /*?[in]?*/?LCID?lcid,
    ????????????
    /*?[size_is][out]?*/?DISPID?*rgDispId);
    ????????STDMETHODIMP?Invoke(
    ????????????
    /*?[in]?*/?DISPID?dispIdMember,
    ????????????
    /*?[in]?*/?REFIID?riid,
    ????????????
    /*?[in]?*/?LCID?lcid,
    ????????????
    /*?[in]?*/?WORD?wFlags,
    ????????????
    /*?[out][in]?*/?DISPPARAMS??*pDispParams,
    ????????????
    /*?[out]?*/?VARIANT??*pVarResult,
    ????????????
    /*?[out]?*/?EXCEPINFO?*pExcepInfo,
    ????????????
    /*?[out]?*/?UINT?*puArgErr);

    ????????????
    void?setCustomFunction(CustomFunction?*fun)?{m_fun?=?fun;}
    private:
    ????CustomFunction?
    *m_fun;

    }
    ;
    #endif?//_IDISPIMP_H_

    主要實現以下兩個方法:?

    wxString cszCB_CustomFunction = wxT("CB_CustomFunction");
    ? #define DISPID_CB_CustomFunction 3
    STDMETHODIMP?CImpIDispatch::GetIDsOfNames(
    ????????????
    /*?[in]?*/?REFIID?riid,
    ????????????
    /*?[size_is][in]?*/?OLECHAR**?rgszNames,
    ????????????
    /*?[in]?*/?UINT?cNames,
    ????????????
    /*?[in]?*/?LCID?lcid,
    ????????????
    /*?[size_is][out]?*/?DISPID*?rgDispId)
    {
    ????HRESULT?hr;
    ????UINT????i;

    ????
    //?Assume?some?degree?of?success
    ????hr?=?NOERROR;


    ????????
    for?(?i=0;?i?<?cNames;?i++)?{
    ????????wxString?cszName??
    =?rgszNames[i];
    ?
    ????????
    if(cszName?==?cszCB_CustomFunction)
    ????????
    {
    ????????????rgDispId[i]?
    =?DISPID_CB_CustomFunction;
    ????????}
    ????
    ?????
    ????????
    else?{
    ????????????
    //?One?or?more?are?unknown?so?set?the?return?code?accordingly
    ????????????hr?=?ResultFromScode(DISP_E_UNKNOWNNAME);
    ????????????rgDispId[i]?
    =?DISPID_UNKNOWN;
    ????????}

    ????}

    ????
    return?hr;
    }


    STDMETHODIMP?CImpIDispatch::Invoke(
    ????????????
    /*?[in]?*/?DISPID?dispIdMember,
    ????????????
    /*?[in]?*/?REFIID?/*riid*/,
    ????????????
    /*?[in]?*/?LCID?/*lcid*/,
    ????????????
    /*?[in]?*/?WORD?wFlags,
    ????????????
    /*?[out][in]?*/?DISPPARAMS*?pDispParams,
    ????????????
    /*?[out]?*/?VARIANT*?pVarResult,
    ????????????
    /*?[out]?*/?EXCEPINFO*?/*pExcepInfo*/,
    ????????????
    /*?[out]?*/?UINT*?puArgErr)
    {

    ?????
    ????
    ????
    if(dispIdMember?==?DISPID_CB_CustomFunction)?
    ????
    {
    ????????
    if(wFlags?&?DISPATCH_PROPERTYGET)
    ????????
    {
    ????????????
    if(pVarResult?!=?NULL)
    ????????????
    {
    ????????????????
    ????????????????VariantInit(pVarResult);
    ????????????????V_VT(pVarResult)
    =VT_BOOL;
    ????????????????V_BOOL(pVarResult)?
    =?true;
    ????????????}

    ????????}

    ????????
    ????????
    if?(?wFlags?&?DISPATCH_METHOD?)
    ????????
    {
    ????????????
    //arguments?come?in?reverse?order
    ????????????
    //for?some?reason
    ????????????if(!m_fun)?return?S_OK;

    ????????????wxString?arg1,arg2;
    ?????????
    ????????????
    if(pDispParams->cArgs<1)?return?S_FALSE;
    ????????????wxString?cmd?
    =?pDispParams->rgvarg[pDispParams->cArgs-1].bstrVal;
    ????????????std::vector
    <wxString>?args;
    ????????????
    if(pDispParams->cArgs>1)
    ????????????
    {
    ????????????????
    for(int?i=pDispParams->cArgs-2;i>=0;i--)
    ????????????????????args.push_back(pDispParams
    ->rgvarg[i].bstrVal);
    ????????????}

    ????????????wxString?re?
    =?m_fun->execute(cmd,args);
    ????????????
    if(pVarResult?!=?NULL)
    ????????????
    {
    ????????????????VariantInit(pVarResult);
    ????????????????V_VT(pVarResult)
    =VT_BSTR;
    ????????????????wxVariant?wVar(re);
    ????????????????VariantToMSWVariant(wVar,
    *pVarResult);
    ????????????????
    ?????????????????
    ????????????}

    ?????????
    ????????}

    ????????
    ????}


    ?????

    ????
    return?S_OK;
    }


    ? 其中 CustomFunction 定義如下:

    #pragma?once
    #include?
    <wx/wx.h>
    #include?
    <vector>
    class?CustomFunction
    {
    public:

    ????CustomFunction(
    void)
    ????
    {
    ????}


    ????
    virtual?~CustomFunction(void)
    ????
    {
    ????}


    ????
    virtual?wxString?execute(const?wxString?&cmd,?const?std::vector<wxString>?&args)?=?0;
    }
    ;

    ? 然后只要在自己類里面繼承這個接口,就可以接收來之腳本的調用請求。
    腳本里面編寫函數:

    window._callFun?=?function()
    ????????????????
    {
    ?????????????????????
    ????????????????????var?fun?
    =?"window.external.CB_CustomFunction(";
    ????????????????????
    for(i=0;i<arguments.length;i++)
    ????????????????????
    {
    ????????????????????????
    if(i!=0)
    ????????????????????????????fun?
    =?fun+",";
    ????????????????????????fun?
    =?fun+"/""+arguments[i]+"/"";
    ????????????????????}
    ????
    ????????????????????fun?
    =?fun+")";
    ????????????????????
    //alert(fun);
    ????????????????????return?(eval(fun));
    ????????????????}

    ?? 然后調用的地方寫:?
    ?

    _callFun("fun","param1","param2",);

    就可以調用c++的函數,并且可以得到返回值,從而解決了html->c++的通訊問題?

    ?? 解決了雙向通訊后,頁面就不需要用刷新來解決,網頁設計師和c++編程人員只要定義好通訊接口,大家各自實現好接口方法就可以完成界面功能了。

    ?

    C++中嵌入ie瀏覽器總結(3) - wxIE 的 bug解決及最后效果展示

    ?????? 前面兩個問題的解決,心里想: 這下好了,解決了這兩個問題,下一步做界面就簡單多了,不像以前,直接用mfc或第三方庫做,要做出好看效果真是很難。編譯好,運行了,發現效果還不錯。但是實現到里面的腳本的時候,發現出了問題,不響應鍵盤消息了。而且在頁面文本框里面按tab鍵,光標不是跑到下一個文本框,而是不見了。之前有這個現象,但是忙于解決前面的問題,沒有注意到。這下可完了,不會前工盡棄吧,那可麻煩大了。
    ????? google了半天,問了朋友,還是不知道什么原因。因為wxIE及嵌入瀏覽器本身是比較偏門的問題,確實很難找到答案。
    ????? 山窮水盡疑無路,柳暗花明又一村。好不容易,在google上找到了一個類似的問題,回答的說,這是wxIE的bug,在wxPython的項目中,這個問題已經解決了。下載下來編譯后,運行試試看,搞定了。
    ????? 但是還得和之前的修改合并,合并過程中又發現了一個問題。前文中提到過,通過IOleObject 接口來設置IDocHostUIHandler方法,我開始就是用這種方法。結果合并完后,發現還是不響應鍵盤消息。
    ??? 調了半天,才發現,wxIE原來已經實現過IOleClientSite 接口,我把自己的接口設上去,把wxIE的給替換掉了,所以導致了不正常的結果。 經過一番調整后,終于正常了。
    ?? 自此,用html做c++程序界面的基礎工作算是告一段落了,下面就是完成接口工作和頁面腳本了。希望不要再遇到什么問題。
    ???? 我在這里把這些問題記錄下來,以備以后查用,也愿其他朋友不要再遇到我一樣的困擾。

    ??? 下面截一張做出來的界面圖:


    這是一個對話框,完成前面的基礎工作后,只要設計師設計好頁面,我們幾分鐘就可以繼承到c++里面,再花點寫接口和腳本的時間,比原來用mfc做界面,不知要節省多少時間。這個界面比較簡單,但是只要是能設計出的界面,我們都能讓他集成進來。
    有興趣的朋友也不妨試試這種做界面的方法。

    C++中嵌入ie瀏覽器總結(4) - 對話框拖動

    ???? 前面忘了寫這個問題,就是對話框的拖動問題。就像我前面的圖片展示的對話框,一般的windows對話框是可以拖著標題欄移動的,但是我們這里沒有任何原來的標題欄了,只有html頁面,怎么拖呢? 好像有點麻煩。
    ?????? 冥思苦想之后,想到一種辦法,通過前面的接口給c++發指令,讓c++移動窗口,頁面上計算好拖動的距離。html里面頁面的拖動還是比較簡單的,c++里面移動也就是調用 MoveWindow。由于前面的通訊方法還是比較靈活,沒用多少時間,就把這個功能實現了。但是一運行看,不太對勁,拖動過程拖尾現象太明顯。可能是c++不斷調用 MoveWindow 重繪效率比較低。這可麻煩了。這時候,突然想到普通對話框拖動的時候,是一個虛框在那里動,原來的對話框是不動的,鼠標放開后,對話框才移過去。 能不能做到這樣呢? 但是windows實現這個方法的細節不得而知,怎么做呢???
    ?????? 還是google好啊,經過一番搜索,找到了答案:?
    ??

    void?TooltipDlg::moveWin(?const?std::vector<wxString>?&args?)
    {
    ????
    if(args.size()<2)?return;
    ????
    long?x,y;
    ????args[
    0].ToLong(&x);
    ????args[
    1].ToLong(&y);
    ????
    int?ix,iy;
    ????ix?
    =?x;
    ????iy?
    =?y;
    ????ClientToScreen(
    &ix,&iy);
    ?

    ????::SendMessage((HWND)
    this->GetHWND(),WM_NCMOUSEMOVE,HTCAPTION,MAKELPARAM(ix,?iy));?

    }

    ?? 搞定了,簡單吧,真是沒想到這么簡單。運行后發現,真的和windows的對話框移動一模一樣了,太好了

    今天一鼓作氣把前面幾天的工作都總結了下來,還真是敲得手有點累。但是這些東西確實是不太常規的方法,找解決問題的方法很難,這里先把他們記錄下來,免得以后找不到了。以前確實有很多知識都是用了就丟一邊找不到了。 也希望給有類似疑問的朋友一個幫助。

    《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

    總結

    以上是生活随笔為你收集整理的C++中嵌入ie浏览器总结 .的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。