前一篇介绍了 Thread,这里再演示一下 OwnerPolicy 的妙用。以下是我的 HtmlCtrl 类(VS2005 及以上版本)。
对话框的头文件
对话框的 cpp 文件
#ifndef HtmlCtrl_H
#define HtmlCtrl_H
//
#include <AfxOle.h>
#include <AfxHtml.h>
#include <AtlBase.h>
//
#include "OwnerPolicy.h"
//
template <typename OwnerT>
class HtmlCtrlT : public CHtmlView,
public OwnerPolicy<OwnerT>
{
public:
virtual HRESULT OnShowContextMenu(DWORD dwID, LPPOINT ppt, LPUNKNOWN pcmdtReserved, LPDISPATCH pdispReserved)
{
return S_OK;
}
virtual HRESULT OnGetExternal(LPDISPATCH *lppDispatch)
{
OwnerT *pOwner = owner();
*lppDispatch = (pOwner == NULL) ? NULL : (owner()->GetIDispatch(TRUE));
return S_OK;
}
HRESULT SetHTMLText(LPCTSTR lpszHTML)
{
HRESULT hr = E_FAIL;
COleStreamFile fileOleStream;
fileOleStream.CreateMemoryStream();
CString strHTML(lpszHTML);
fileOleStream.Write(strHTML.GetBuffer(0), strHTML.GetLength() * sizeof(TCHAR));
strHTML.ReleaseBuffer();
fileOleStream.SeekToBegin();
CComQIPtr<IPersistStreamInit> pPersistStreamInit(GetHtmlDocument());
if (pPersistStreamInit == NULL) {
Navigate(TEXT("about:blank"));
}
pPersistStreamInit = GetHtmlDocument();
if (pPersistStreamInit) {
hr = pPersistStreamInit->Load(static_cast<IStream *>(fileOleStream.GetStream()));
}
return hr;
}
virtual void PostNcDestroy()
{
// disable CView::PostNcDestroy(), he will call (delete this);
}
};
//
#endif
对话框的头文件
#pragma once
#include <AfxWin.h>
#include "Resource.h"
#include "HtmlCtrl.h"
//
class CMainDialog : public CDialog
{
typedef HtmlCtrlT<CMainDialog> CHtmlCtrl;
public:
CMainDialog(CWnd *pParent = NULL);
enum { IDD = IDD_DEMOHTMLCTRL_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange *pDX);
protected:
HICON m_hIcon;
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
DECLARE_DISPATCH_MAP()
private:
void MessageBox(BSTR bstrMessage);
private:
CHtmlCtrl m_htmlCtrl;
};
对话框的 cpp 文件
#include "MainDialog.h"
//
BEGIN_DISPATCH_MAP(CMainDialog, CDialog)
DISP_FUNCTION(CMainDialog, "MessageBox", MessageBox, VT_EMPTY, VTS_BSTR)
END_DISPATCH_MAP()
//
CMainDialog::CMainDialog(CWnd *pParent)
: CDialog(CMainDialog::IDD, pParent)
{
EnableAutomation();
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CMainDialog::DoDataExchange(CDataExchange *pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CMainDialog, CDialog)
//{{AFX_MSG_MAP
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
BOOL CMainDialog::OnInitDialog()
{
CDialog::OnInitDialog();
SetIcon(m_hIcon, TRUE);
SetIcon(m_hIcon, FALSE);
//
CStatic wndStatic;
if (!wndStatic.SubclassDlgItem(IDC_HTML_CTRL, this)) {
return FALSE;
}
CRect rect;
wndStatic.GetWindowRect(&rect);
ScreenToClient(&rect);
wndStatic.DestroyWindow();
m_htmlCtrl.owner(this);
m_htmlCtrl.Create(NULL, NULL, WS_CHILD|WS_VISIBLE, rect, this, IDC_HTML_CTRL, NULL);
m_htmlCtrl.SetHTMLText(TEXT("<HTML><BODY><Button OnClick=\"external.MessageBox('Hello, JavaScript!');\">Message</Button></BODY></HTML>"));
return TRUE;
}
void CMainDialog::OnPaint()
{
if (IsIconic()) {
CPaintDC dc(this);
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
dc.DrawIcon(x, y, m_hIcon);
}
else {
CDialog::OnPaint();
}
}
HCURSOR CMainDialog::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CMainDialog::MessageBox(BSTR bstrMessage)
{
::MessageBoxW(GetSafeHwnd(), bstrMessage, L"Title", MB_ICONINFORMATION);
}