学习内嵌ie

来源:互联网 发布:php继承的几种方式 编辑:程序博客网 时间:2024/04/30 14:34


#include <Windows.h>
#include <tchar.h>
 
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
 
    return 0;
}
 
int APIENTRY _tWinMain(_In_ HINSTANCE     hInstance,
                       _In_opt_ HINSTANCE hPrevInstance,
                       _In_ LPTSTR        lpCmdLine,
                       _In_ int           nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);
 
    const LPCTSTR CLASS_NAME = _T("WebBrowserContainer");
 
    WNDCLASSEX wcex    = { sizeof(WNDCLASSEX) };
    wcex.style         = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc   = WndProc;
    wcex.cbClsExtra    = 0;
    wcex.cbWndExtra    = 0;
    wcex.hInstance     = hInstance;
    wcex.hCursor       = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszClassName = CLASS_NAME;
 
    RegisterClassEx(&wcex);
 
    HWND hWnd = CreateWindow(CLASS_NAME,
                             _T("WebBrowser Sample"),
                             WS_OVERLAPPEDWINDOW,
                             CW_USEDEFAULT,
                             0,
                             CW_USEDEFAULT,
                             0,
                             nullptr,
                             nullptr,
                             hInstance,
                             nullptr);
 
    if (hWnd == nullptr)
    {
        return 0;
    }
 
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
 
    MyWebBrowser wb(hWnd);
 
    MSG msg = {};
 
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, nullptr, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
 
    return (int)msg.wParam;
}
 


加入WebBrowser


这一部分主要参考了《使用C++实现SDK之WebBrowser容器》(http://blog.csdn.net/norsd/article/details/2921389)。但是这篇文章里没有给出真正可运行的代码,有几处小笔误,然后呢,其实我也不是很喜欢原作者的封装方式。本篇的目的是尽可能简单、原始,让后来者容易上手。


 


实现OLE容器类


实现一个WebBrowser,先要实现一个OLE容器类。我不知道OLE容器类的精确定义是什么,但现在我们需要实现三个接口:IOleClientSite、IOleInPlaceSite、IOleInPlaceFrame(<OleIdl.h>)。它们的定义在MSDN上都可以查到。


 


代码清单如下:


 


#pragma once
 
#include <Windows.h>
#include <OleIdl.h>
 
class OleContainer : public IOleClientSite,
                     public IOleInPlaceSite,
                     public IOleInPlaceFrame
{
public:
    OleContainer() : m_nRefCount(0),
                     m_pStorage(nullptr),
                     m_pOleObj(nullptr),
                     m_pInPlaceObj(nullptr),
                     m_hWindow(nullptr)
    {
        AddRef();
        OleInitialize(nullptr);
    }
 
    ~OleContainer()
    {
        if (m_pInPlaceObj != nullptr)
        {
            m_pInPlaceObj->Release();
            m_pInPlaceObj = nullptr;
        }
 
        if (m_pOleObj != nullptr)
        {
            m_pOleObj->Release();
            m_pOleObj = nullptr;
        }
 
        if (m_pStorage != nullptr)
        {
            m_pStorage->Release();
            m_pStorage = nullptr;
        }
 
        OleUninitialize();
    }
 
public:
    bool CreateOleObject(const IID &clsid)
    {
        HRESULT hr = StgCreateDocfile(nullptr,
                                        STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_CREATE,
                                        0,
                                        &m_pStorage);
        if (FAILED(hr))
        {
            return false;
        }
 
        hr = OleCreate(clsid, IID_IOleObject, OLERENDER_DRAW, 0, this, m_pStorage, (LPVOID *)&m_pOleObj);
 
        if (FAILED(hr))
        {
            return false;
        }
 
        hr = m_pOleObj->QueryInterface(IID_IOleInPlaceObject, (LPVOID *)&m_pInPlaceObj);
 
        if (FAILED(hr))
        {
            return false;
        }
 
        return true;
    }
 
    bool InPlaceActive(HWND hWnd, LPCRECT lpRect)
    {
        if (hWnd == nullptr)
        {
            return false;
        }
 
        RECT rect = {};
 
        if (lpRect == nullptr)
        {
            GetClientRect(hWnd, &rect);
            lpRect = &rect;
        }
 
        HRESULT hr = m_pOleObj->DoVerb(OLEIVERB_INPLACEACTIVATE, nullptr, this, 0, hWnd, lpRect);
 
        if (FAILED(hr))
        {
            return false;
        }
 
        m_hWindow = hWnd;
 
        return true;
    }
 
public: // IUnknown Methods
    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID *ppvObject)
    {
        *ppvObject = nullptr;
 
        if (riid == IID_IUnknown)
        {
            *ppvObject = (IOleClientSite *)this;
        }
        else if (riid == IID_IOleInPlaceSite)
        {
            *ppvObject = (IOleInPlaceSite *)this;
        }
        else if (riid == IID_IOleInPlaceUIWindow)
        {
            *ppvObject = (IOleInPlaceUIWindow *)this;
        }
        else if (riid == IID_IOleInPlaceFrame)
        {  
            *ppvObject = (IOleInPlaceFrame *)this;
        }
 
        if (*ppvObject == nullptr)
        {
            return E_NOINTERFACE;
        }
 
        AddRef();
        return S_OK;
    }
 
    ULONG STDMETHODCALLTYPE AddRef()
    {
        return (ULONG)InterlockedIncrement(&m_nRefCount);
    }
 
    ULONG STDMETHODCALLTYPE Release()
    {
        LONG nRefCount = InterlockedDecrement(&m_nRefCount);
 
        if (nRefCount <= 0)
        {
            delete this;
        }
 
        return (ULONG)nRefCount;
    }
 
public: // IOleClientSite Methods
    STDMETHOD(SaveObject)()
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(GetMoniker)(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker **ppmk)
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(GetContainer)(IOleContainer **ppContainer)
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(ShowObject)()
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(OnShowWindow)(BOOL fShow)
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(RequestNewObjectLayout)()
    {
        return E_NOTIMPL;
    }
 
public: // IOleWindow Methods
    STDMETHOD(GetWindow)(HWND *phwnd)
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(ContextSensitiveHelp)(BOOL fEnterMode)
    {
        return E_NOTIMPL;
    }
 
public: // IOleInPlaceSite Methods
    STDMETHOD(CanInPlaceActivate)()
    {
        return m_hWindow == nullptr ? S_OK : S_FALSE;
    }
 
    STDMETHOD(OnInPlaceActivate)()
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(OnUIActivate)()
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(GetWindowContext)(IOleInPlaceFrame **ppFrame,
                                IOleInPlaceUIWindow **ppDoc,
                                LPRECT lprcPosRect,
                                LPRECT lprcClipRect,
                                LPOLEINPLACEFRAMEINFO lpFrameInfo)
    {
        if (m_hWindow == nullptr)
        {
            return E_NOTIMPL;
        }
 
        *ppFrame = (IOleInPlaceFrame*)this;
        *ppDoc = NULL;
        AddRef();
 
        GetClientRect(m_hWindow, lprcPosRect);
        GetClientRect(m_hWindow, lprcClipRect);
 
        lpFrameInfo->cb = sizeof(OLEINPLACEFRAMEINFO);
        lpFrameInfo->fMDIApp = false;
        lpFrameInfo->hwndFrame = GetParent(m_hWindow);
        lpFrameInfo->haccel = nullptr;
        lpFrameInfo->cAccelEntries = 0;
 
        return S_OK;
    }
 
    STDMETHOD(Scroll)(SIZE scrollExtant)
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(OnUIDeactivate)(BOOL fUndoable)
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(OnInPlaceDeactivate)()
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(DiscardUndoState)()
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(DeactivateAndUndo)()
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(OnPosRectChange)(LPCRECT lprcPosRect)
    {
        return E_NOTIMPL;
    }
 
public: // IOleInPlaceUIWindow Methods
    STDMETHOD(GetBorder)(LPRECT lprectBorder)
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(RequestBorderSpace)(LPCBORDERWIDTHS pborderwidths)
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(SetBorderSpace)(LPCBORDERWIDTHS pborderwidths)
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(SetActiveObject)(IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName)
    {
        return E_NOTIMPL;
    }
 
public: // IOleInPlaceFrame Methods
    STDMETHOD(InsertMenus)(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths)
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(SetMenu)(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject)
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(RemoveMenus)(HMENU hmenuShared)
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(SetStatusText)(LPCOLESTR pszStatusText)
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(EnableModeless)(BOOL fEnable)
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(TranslateAccelerator)(LPMSG lpmsg, WORD wID)
    {
        return E_NOTIMPL;
    }
 
private:
    LONG m_nRefCount;
 
protected:
    IStorage          *m_pStorage;
    IOleObject        *m_pOleObj;
    IOleInPlaceObject *m_pInPlaceObj;
    HWND               m_hWindow;
};
 


这三个接口,连带他们的父类,总共需要实现31个方法!不过还好,除了篇幅稍微长一点,基本上都是E_NOTIMPL。


 


其中CreateOleObject和InPlaceActive是我自己加的,将来要调用的。


 


OleCreate期间,除了若干次QueryInterface之外,GetContainer会被调到一次。OLEIVERB_INPLACEACTIVATE期间,除了若干次QueryInterface之外,CanInPlaceActivate、OnInPlaceActivate、ShowObject会被调到。


 


那些不返回E_NOTIMPL的接口,我也没有一一查询是干嘛的,都是抄的~


 


实现WebBrowser容器类


上一节可视为(通用的)OLE容器类(只是没有使用除WebBrowser之外的其他玩意儿测试过,共性不是很明确,不敢保证通用性),这一节来实现WebBrowser。作为最简单的WebBrowser,不用再额外实现别的借口了,直接使用上面的OleContainer,创建WebBrowser对象即可。


 


代码清单:


 


#pragma once
 
#include "OleContainer.h"
#include <ExDisp.h>
 
class WebBrowser : public OleContainer
{
public:
    WebBrowser(HWND hParent) : m_pWebBrowser(nullptr), m_hWnd(hParent)
    {
 
    }
 
    ~WebBrowser()
    {
        if (m_pWebBrowser != nullptr)
        {
            m_pWebBrowser->Release();
            m_pWebBrowser = nullptr;
        }
    }
 
public:
    bool CreateWebBrowser()
    {
        if (!CreateOleObject(CLSID_WebBrowser))
        {
            return false;
        }
 
        RECT rect = {};
        GetClientRect(m_hWnd, &rect);
 
        if (!InPlaceActive(m_hWnd, &rect))
        {
            return false;
        }
 
        HRESULT hr = m_pOleObj->QueryInterface(IID_IWebBrowser2, (LPVOID *)&m_pWebBrowser);
 
        if (FAILED(hr))
        {
            return false;
        }
 
        return true;
    }
   
public:
    void Navigate(LPCTSTR lpUrl)
    {
        BSTR bstrUrl = SysAllocString(lpUrl);
        m_pWebBrowser->Navigate(bstrUrl, nullptr, nullptr, nullptr, nullptr);
        SysFreeString(bstrUrl);
    }
 
public:
    STDMETHOD(GetWindow)(HWND *phwnd)
    {
        *phwnd = m_hWnd;
        return S_OK;
 
    }
 
    STDMETHOD(GetWindowContext)(IOleInPlaceFrame **ppFrame,
                                IOleInPlaceUIWindow **ppDoc,
                                LPRECT lprcPosRect,
                                LPRECT lprcClipRect,
                                LPOLEINPLACEFRAMEINFO lpFrameInfo)
    {
        *ppFrame = (IOleInPlaceFrame*)this;
        *ppDoc = NULL;
        AddRef();
 
        GetClientRect(m_hWnd, lprcPosRect);
        GetClientRect(m_hWnd, lprcClipRect);
 
        lpFrameInfo->cb = sizeof(OLEINPLACEFRAMEINFO);
        lpFrameInfo->fMDIApp = false;
        lpFrameInfo->hwndFrame = GetParent(m_hWnd);
        lpFrameInfo->haccel = nullptr;
        lpFrameInfo->cAccelEntries = 0;
 
        return S_OK;
    }
 
protected:
    IWebBrowser2 *m_pWebBrowser;
    HWND m_hWnd;
};
 


其中CreateWebBrowser 只是简单的调用了一下CreateOleObject,传入CLSID_WebBrowser。然后InPlaceActive就可以了。最后拿的m_pWebBrowser指针是备用的,用于实现一个示例功能:Navigate。


 


后面的GetWindow和GetWindowContext在OleContainer中已经有了,之所以再写一遍,是因为WebBrowser的创建过程中,就会调用GetWindow,需要给出一个窗口句柄;InPlaceActive过程中会调用GetWindowContext,也要做事情,不能return E_NOTIMPL了事。而OleContainer中,暂时我是在InPlaceActive的时候传入窗口句柄的。可能是OleContianer根本应该更早的知道窗口的存在,但这一点我还没弄清楚,所以暂时写成那样。但到WebBrowser层面,创建一个WebBrowser之前就需要先创建好窗口。


 


使用WebBrowser容器类


我们回到Main,创建好主窗口后插入几行代码:


 


int APIENTRY _tWinMain(_In_ HINSTANCE     hInstance,
                       _In_opt_ HINSTANCE hPrevInstance,
                       _In_ LPTSTR        lpCmdLine,
                       _In_ int           nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);
 
    const LPCTSTR CLASS_NAME = _T("WebBrowserContainer");
 
    WNDCLASSEX wcex    = { sizeof(WNDCLASSEX) };
    wcex.style         = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc   = WndProc;
    wcex.cbClsExtra    = 0;
    wcex.cbWndExtra    = 0;
    wcex.hInstance     = hInstance;
    wcex.hCursor       = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszClassName = CLASS_NAME;
 
    RegisterClassEx(&wcex);
 
    HWND hWnd = CreateWindow(CLASS_NAME,
                             _T("WebBrowser Sample"),
                             WS_OVERLAPPEDWINDOW,
                             CW_USEDEFAULT,
                             0,
                             CW_USEDEFAULT,
                             0,
                             nullptr,
                             nullptr,
                             hInstance,
                             nullptr);
 
    if (hWnd == nullptr)
    {
        return 0;
    }
 
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
 
    WebBrowser wb(hWnd);
 
    if (!wb.CreateWebBrowser())
    {
        return 0;
    }
 
    wb.Navigate(_T("http://www.baidu.com/"));
 
    MSG msg = {};
 
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, nullptr, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
 
    return (int)msg.wParam;
0 0
原创粉丝点击