
/*
    版权声明：
    本文件版权为易语言作者吴涛所有，仅授权给第三方用作开发易语言支持库，禁止用于其他任何场合。
*/

#include "stdafx.h"
#include <AFXPRIV.H>
#include "hhctrl.h"
#include "htmlview.h"

INT WINAPI NotifySys (INT nMsg, DWORD dwParam1, DWORD dwParam2 = 0);

#include "untshare.cpp"

extern CHtmlViewApp theApp;

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static const char THIS_FILE[] = __FILE__;
#endif

BEGIN_MESSAGE_MAP(CHHCtrl, CWnd)
    //{{AFX_MSG_MAP(CHHCtrl)
	ON_WM_SETFOCUS()
    ON_WM_SIZE()
    ON_WM_PAINT()
    ON_WM_DESTROY()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

BEGIN_EVENTSINK_MAP(CHHCtrl, CWnd)
    ON_EVENT(CHHCtrl, AFX_IDW_PANE_FIRST, 102, OnStatusTextChange, VTS_BSTR)
    ON_EVENT(CHHCtrl, AFX_IDW_PANE_FIRST, 108, OnProgressChange, VTS_I4 VTS_I4)
    ON_EVENT(CHHCtrl, AFX_IDW_PANE_FIRST, 105, OnCommandStateChange, VTS_I4 VTS_BOOL)
    ON_EVENT(CHHCtrl, AFX_IDW_PANE_FIRST, 106, OnDownloadBegin, VTS_NONE)
    ON_EVENT(CHHCtrl, AFX_IDW_PANE_FIRST, 104, OnDownloadComplete, VTS_NONE)
    ON_EVENT(CHHCtrl, AFX_IDW_PANE_FIRST, 113, OnTitleChange, VTS_BSTR)
    ON_EVENT(CHHCtrl, AFX_IDW_PANE_FIRST, 252, NavigateComplete2, VTS_DISPATCH VTS_PVARIANT)
    ON_EVENT(CHHCtrl, AFX_IDW_PANE_FIRST, 250, BeforeNavigate2, VTS_DISPATCH VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PBOOL)
    ON_EVENT(CHHCtrl, AFX_IDW_PANE_FIRST, 112, OnPropertyChange, VTS_BSTR)
    ON_EVENT(CHHCtrl, AFX_IDW_PANE_FIRST, 251, OnNewWindow2, VTS_PDISPATCH VTS_PBOOL)
    ON_EVENT(CHHCtrl, AFX_IDW_PANE_FIRST, 259, DocumentComplete, VTS_DISPATCH VTS_PVARIANT)
    ON_EVENT(CHHCtrl, AFX_IDW_PANE_FIRST, 253, OnQuit, VTS_NONE)
    ON_EVENT(CHHCtrl, AFX_IDW_PANE_FIRST, 254, OnVisible, VTS_BOOL)
END_EVENTSINK_MAP()

CHHCtrl::CHHCtrl() : CWnd()
{
    m_pBrowserApp = NULL;
	m_blHasForceURL = m_blHasTitle = FALSE;
}

CHHCtrl::~CHHCtrl()
{
    if (m_pBrowserApp != NULL)
        m_pBrowserApp->Release();
}

void CHHCtrl::OnDraw(CDC* pDC)
{
    // this class should never do its own drawing;
    // the browser control should handle everything

    ASSERT(FALSE);  // make certain we aren't called
}

/*
	OLECMDID_OPEN
	OLECMDID_SAVEAS
	OLECMDID_PRINT
	OLECMDID_PRINTPREVIEW
	OLECMDID_PAGESETUP
*/
void CHHCtrl::RunCmd (OLECMDID cmdid)
{
    if (m_pBrowserApp != NULL) {
        LPDISPATCH lpDisp;
		m_pBrowserApp->get_Document(&lpDisp);

        if (lpDisp != NULL) {
            // the control will handle all printing UI

            LPOLECOMMANDTARGET lpTarget;
            if (SUCCEEDED(lpDisp->QueryInterface(IID_IOleCommandTarget,
                    (LPVOID*) &lpTarget))) {
                lpTarget->Exec(NULL, cmdid, 0, NULL, NULL);
                lpTarget->Release();
            }
            lpDisp->Release();
        }
    }
}

void CHHCtrl::OnDestroy()
{
    if (m_pBrowserApp)
	{
        m_pBrowserApp->Release();
        m_pBrowserApp = NULL;
    }

    if (::IsWindow (m_wndBrowser.m_hWnd))
        m_wndBrowser.DestroyWindow ();

    CWnd::OnDestroy ();
}

void CHHCtrl::PostNcDestroy() 
{
	CWnd::PostNcDestroy ();
	NotifySys (NRS_UNIT_DESTROIED, m_dwWinFormID, m_dwUnitID);
	delete this;
}

void CHHCtrl::OnSize(UINT nType, int cx, int cy)
{
    CWnd::OnSize(nType, cx, cy);

	if (::IsWindow(m_wndBrowser.m_hWnd))
	{
		// need to push non-client borders out of the client area
		CRect rect;
		GetClientRect(rect);
		//::AdjustWindowRectEx(rect,
		//	m_wndBrowser.GetStyle(), FALSE, WS_EX_CLIENTEDGE);
		m_wndBrowser.SetWindowPos(NULL, rect.left, rect.top,
			rect.Width(), rect.Height(), SWP_NOACTIVATE | SWP_NOZORDER);
	}
}

void CHHCtrl::OnPaint()
{
    Default();
}

void CHHCtrl::OnSetFocus(CWnd* pOldWnd) 
{
	CWnd::OnSetFocus(pOldWnd);
	if (::IsWindow (m_wndBrowser.m_hWnd))
		m_wndBrowser.SetFocus ();
}

BOOL CHHCtrl::Create (HWND hParentWnd, DWORD dwStyle, UINT uID,
					  INT x, INT y, INT cx, INT cy)
{
	if (!CWnd::CreateEx (NULL, AfxRegisterWndClass (CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW,
			::LoadCursor (NULL, IDC_ARROW), HBRUSH (::GetStockObject (WHITE_BRUSH))),
			_T(""), dwStyle, x, y, cx, cy, hParentWnd, (HMENU)uID, NULL))
		return FALSE;

	AfxEnableControlContainer();

	RECT rectClient;
	GetClientRect(&rectClient);

	// create the control window
	// AFX_IDW_PANE_FIRST is a safe but arbitrary ID
	if (!m_wndBrowser.CreateControl(CLSID_WebBrowser, NULL,
				WS_VISIBLE | WS_CHILD, rectClient, this, AFX_IDW_PANE_FIRST))
	{
		DestroyWindow();
		return FALSE;
	}

	LPUNKNOWN lpUnk = m_wndBrowser.GetControlUnknown();
	HRESULT hr = lpUnk->QueryInterface(IID_IWebBrowser2, (void**) &m_pBrowserApp);
	if (!SUCCEEDED(hr))
	{
		m_pBrowserApp = NULL;
		m_wndBrowser.DestroyWindow();
		DestroyWindow();
		return FALSE;
	}

	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////

CString CHHCtrl::GetType() const
{
    ASSERT(m_pBrowserApp != NULL);

    BSTR bstr;
    m_pBrowserApp->get_Type(&bstr);
    CString retVal(bstr);
    return retVal;
}

long CHHCtrl::GetLeft() const
{
    ASSERT(m_pBrowserApp != NULL);

    long result;
    m_pBrowserApp->get_Left(&result);
    return result;
}

long CHHCtrl::GetTop() const
{
    ASSERT(m_pBrowserApp != NULL);
    long result;
    m_pBrowserApp->get_Top(&result);
    return result;
}

long CHHCtrl::GetHeight() const
{
    ASSERT(m_pBrowserApp != NULL);
    long result;
    m_pBrowserApp->get_Height(&result);
    return result;
}

BOOL CHHCtrl::GetVisible() const
{
    ASSERT(m_pBrowserApp != NULL);

    VARIANT_BOOL result;
    m_pBrowserApp->get_Visible(&result);
    return ((result == VARIANT_TRUE) ? TRUE: FALSE);
}

CString CHHCtrl::GetLocationName() const
{
    ASSERT(m_pBrowserApp != NULL);

    BSTR bstr;
    m_pBrowserApp->get_LocationName(&bstr);
    CString retVal(bstr);
    return retVal;
}

CString CHHCtrl::GetLocationURL() const
{
    ASSERT(m_pBrowserApp != NULL);

    BSTR bstr;
    m_pBrowserApp->get_LocationURL(&bstr);
    CString retVal(bstr);
    return retVal;
}

BOOL CHHCtrl::GetBusy() const
{
    ASSERT(m_pBrowserApp != NULL);

    VARIANT_BOOL result;
    m_pBrowserApp->get_Busy(&result);
    return ((result == VARIANT_TRUE) ? TRUE: FALSE);
}

READYSTATE CHHCtrl::GetReadyState() const
{
    ASSERT(m_pBrowserApp != NULL);

    READYSTATE result;
    m_pBrowserApp->get_ReadyState(&result);
    return result;
}

BOOL CHHCtrl::GetOffline() const
{
    ASSERT(m_pBrowserApp != NULL);

    VARIANT_BOOL result;
    m_pBrowserApp->get_Offline(&result);
    return ((result == VARIANT_TRUE) ? TRUE: FALSE);
}

BOOL CHHCtrl::GetSilent() const
{
    ASSERT(m_pBrowserApp != NULL);

    VARIANT_BOOL result;
    m_pBrowserApp->get_Silent(&result);
    return ((result == VARIANT_TRUE) ? TRUE: FALSE);
}

void CHHCtrl::ExecWB(OLECMDID cmdID, OLECMDEXECOPT cmdexecopt,
    VARIANT* pvaIn, VARIANT* pvaOut)
{
    ASSERT(m_pBrowserApp != NULL);
    m_pBrowserApp->ExecWB(cmdID, cmdexecopt, pvaIn, pvaOut);
}

HRESULT CHHCtrl::Navigate(LPCTSTR lpszURL, DWORD dwFlags /* = 0 */,
    LPCTSTR lpszTargetFrameName /* = NULL */ ,
    LPCTSTR lpszHeaders /* = NULL */, LPVOID lpvPostData /* = NULL */,
    DWORD dwPostDataLen /* = 0 */)
{
    CString strURL(lpszURL);
    BSTR bstrURL = strURL.AllocSysString();

    COleSafeArray vPostData;
    if (lpvPostData != NULL)
    {
        if (dwPostDataLen == 0)
            dwPostDataLen = lstrlen((LPCTSTR) lpvPostData);

        vPostData.CreateOneDim(VT_UI1, dwPostDataLen, lpvPostData);
    }

    HRESULT hResult = m_pBrowserApp->Navigate(bstrURL,
        COleVariant((long) dwFlags, VT_I4),
        COleVariant(lpszTargetFrameName, VT_BSTR),
        vPostData,
        COleVariant(lpszHeaders, VT_BSTR));
	::SysFreeString(bstrURL);
	return hResult;
}

HRESULT CHHCtrl::NavigateChm(LPCTSTR szChmFileName, LPCTSTR URL, LPCTSTR lpszTargetFrameName)
{
    if (szChmFileName == NULL || *szChmFileName == '\0')
        return STG_E_FILENOTFOUND;  // CHM file wasn't located

    char szURL[MAX_PATH * 2];
    wsprintf(szURL, "its:%s::%s", szChmFileName, URL);
    return Navigate(szURL, NULL, lpszTargetFrameName);
}

/////////////////////////////////////////////////////////////////////////////
// CHHCtrl event reflectors

void CHHCtrl::NavigateComplete2(LPDISPATCH /* pDisp */, VARIANT* URL)
{
    ASSERT(V_VT(URL) == VT_BSTR);

    // USES_CONVERSION;

    CString str(V_BSTR(URL));
    OnNavigateComplete2(str);
}

void CHHCtrl::BeforeNavigate2(LPDISPATCH /* pDisp */, VARIANT* URL,
        VARIANT* Flags, VARIANT* TargetFrameName,
        VARIANT* PostData, VARIANT* Headers, BOOL* pfCancel)
{
    ASSERT(V_VT(URL) == VT_BSTR);
    ASSERT(V_VT(TargetFrameName) == VT_BSTR);
    ASSERT(V_VT(PostData) == (VT_VARIANT | VT_BYREF));
    ASSERT(V_VT(Headers) == VT_BSTR);
    ASSERT(pfCancel != NULL);

    //USES_CONVERSION;

    VARIANT* vtPostedData = V_VARIANTREF(PostData);
    CByteArray array;
    if (V_VT(vtPostedData) & VT_ARRAY)
	{
        // must be a vector of bytes
        ASSERT(vtPostedData->parray->cDims == 1 && vtPostedData->parray->cbElements == 1);

        vtPostedData->vt |= VT_UI1;
        COleSafeArray safe(vtPostedData);

        DWORD dwSize = safe.GetOneDimSize();
        LPVOID pVoid;
        safe.AccessData(&pVoid);

        array.SetSize(dwSize);
        LPBYTE lpByte = array.GetData();

        memcpy(lpByte, pVoid, dwSize);
        safe.UnaccessData();
    }
    // make real parameters out of the notification

    CString strTargetFrameName(V_BSTR(TargetFrameName));
    CString strURL = V_BSTR(URL);
    CString strHeaders = V_BSTR(Headers);
    DWORD nFlags = V_I4(Flags);

    // notify the user's class
    OnBeforeNavigate2(strURL, nFlags, strTargetFrameName, array, strHeaders, pfCancel);
}

void CHHCtrl::DocumentComplete(LPDISPATCH pDisp, VARIANT* URL)
{
    UNUSED_ALWAYS(pDisp);
    ASSERT(V_VT(URL) == VT_BSTR);

    CString str(V_BSTR(URL));
    OnDocumentComplete(str);
}

/////////////////////////////////////////////////////////////////////////////
// CHHCtrl Events

void CHHCtrl::OnProgressChange(long lProgress, long lProgressMax)
{
	EVENT_NOTIFY event (m_dwWinFormID, m_dwUnitID, 3);
	event.m_nArgCount = 1;
	event.m_nArgValue [0] = lProgressMax == 0 ? 100 :
			MulDiv (lProgress, 100, lProgressMax);
	NotifySys (NRS_EVENT_NOTIFY, (DWORD)&event);
}

void CHHCtrl::OnCommandStateChange(long lCommand, BOOL bEnable)
{
	if (lCommand == CSC_NAVIGATEFORWARD || lCommand == CSC_NAVIGATEBACK)
	{
		EVENT_NOTIFY event (m_dwWinFormID, m_dwUnitID, 8);
		event.m_nArgCount = 2;
		event.m_nArgValue [0] = lCommand == CSC_NAVIGATEFORWARD ? 0 : 1;
		event.m_nArgValue [1] = bEnable ? 1 : 0;
		NotifySys (NRS_EVENT_NOTIFY, (DWORD)&event);
	}
}

void CHHCtrl::OnDownloadBegin()
{
	NotifySys (NRS_EVENT_NOTIFY, (DWORD)&EVENT_NOTIFY (m_dwWinFormID, m_dwUnitID, 2));
}

void CHHCtrl::OnQuit()
{
}

void CHHCtrl::OnDocumentComplete(LPCTSTR lpszURL)
{
	m_blHasForceURL = TRUE;
	SetStr (m_strForceURL, (LPTSTR)lpszURL);

    HWND hWnd = m_hWnd;
	NotifySys (NRS_EVENT_NOTIFY, (DWORD)&EVENT_NOTIFY (m_dwWinFormID, m_dwUnitID, 5));
    if (::IsWindow (hWnd))
    {
	    m_blHasForceURL = FALSE;
	    m_strForceURL.Empty ();
    }
}

void CHHCtrl::OnDownloadComplete()
{
	NotifySys (NRS_EVENT_NOTIFY, (DWORD)&EVENT_NOTIFY (m_dwWinFormID, m_dwUnitID, 4));
}

void CHHCtrl::OnTitleChange(LPCTSTR lpszText)
{
	m_blHasTitle = TRUE;
	SetStr (m_strTitle, (LPTSTR)lpszText);

    HWND hWnd = m_hWnd;
	NotifySys (NRS_EVENT_NOTIFY, (DWORD)&EVENT_NOTIFY (m_dwWinFormID, m_dwUnitID, 7));
	
    if (::IsWindow (hWnd))
    {
        m_blHasTitle = FALSE;
        m_strTitle.Empty ();
    }
}

void CHHCtrl::OnPropertyChange(LPCTSTR lpszProperty)
{
    UNUSED_ALWAYS(lpszProperty);
}

void CHHCtrl::OnNewWindow2(LPDISPATCH* ppDisp, BOOL* pfCancel)
{
	EVENT_NOTIFY event (m_dwWinFormID, m_dwUnitID, 9);
	if (NotifySys (NRS_EVENT_NOTIFY, (DWORD)&event) != 0 &&
			event.m_blHasRetVal == TRUE &&
			event.m_nRetVal == 0)
		*pfCancel = TRUE;
	else
		*pfCancel = FALSE;

    UNUSED_ALWAYS(ppDisp);
}

void CHHCtrl::OnVisible(BOOL fVisible)
{
    UNUSED_ALWAYS(fVisible);
}

void CHHCtrl::OnBeforeNavigate2(LPCTSTR lpszURL, DWORD nFlags,
    LPCTSTR lpszTargetFrameName, CByteArray& baPostData,
    LPCTSTR lpszHeaders, BOOL* pfCancel)
{
	m_blHasForceURL = TRUE;
	SetStr (m_strForceURL, (LPTSTR)lpszURL);

    HWND hWnd = m_hWnd;

	EVENT_NOTIFY event (m_dwWinFormID, m_dwUnitID, 0);
	if (NotifySys (NRS_EVENT_NOTIFY, (DWORD)&event) != 0 &&
			event.m_blHasRetVal == TRUE &&
			event.m_nRetVal == 0)
		*pfCancel = TRUE;
	else
		*pfCancel = FALSE;

    if (::IsWindow (hWnd))
    {
	    m_blHasForceURL = FALSE;
	    m_strForceURL.Empty ();

        UNUSED_ALWAYS(nFlags);
        UNUSED_ALWAYS(lpszTargetFrameName);
        UNUSED_ALWAYS(baPostData);
        UNUSED_ALWAYS(lpszHeaders);
    }
}

void CHHCtrl::OnStatusTextChange(LPCTSTR pszText)
{
	SetStr (m_strStatusText, (LPTSTR)pszText);
	NotifySys (NRS_EVENT_NOTIFY, (DWORD)&EVENT_NOTIFY (m_dwWinFormID, m_dwUnitID, 6));
}

void CHHCtrl::OnNavigateComplete2(LPCTSTR strURL)
{
	m_blHasForceURL = TRUE;
	SetStr (m_strForceURL, (LPTSTR)strURL);
	
    HWND hWnd = m_hWnd;
    NotifySys (NRS_EVENT_NOTIFY, (DWORD)&EVENT_NOTIFY (m_dwWinFormID, m_dwUnitID, 1));
    if (::IsWindow (hWnd))
    {
	    m_blHasForceURL = FALSE;
	    m_strForceURL.Empty ();
    }
}


#ifdef _DEBUG
void CHHCtrl::AssertValid() const
{
    CWnd::AssertValid();
}

void CHHCtrl::Dump(CDumpContext& dc) const
{
    CWnd::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////

// !!! 此处的定义顺序绝对不可改变
static EVENT_ARG_INFO s_HtmlViewerArgInfo [] =
{
//****** 载入进度改变
	{
/*name*/	_WT("进度百分比"),
/*explain*/	_WT("参数值指示当前文档已经被载入的百分比"),
/*state*/	NULL,
	},

//****** 命令状态被改变
	{
/*name*/	_WT("命令"),
/*explain*/	_WT("参数值指示允许状态被改变的命令类型，为以下常量值之一："
		"0: #前进； 1: #后退"),
/*state*/	NULL,
	}, {
/*name*/	_WT("是否被允许"),
/*explain*/	_WT("参数值指示该命令当前是否被允许"),
/*state*/	EAS_IS_BOOL_ARG,
	},

};

// !!! 此处的定义顺序绝对不可改变，主默认信息放在首位。
EVENT_INFO g_HtmlViewerEvent [] =
{
	{
	_WT("即将跳转"),
	_WT("在浏览器即将跳转到另一个页面之前产生此事件，"
		"在事件处理子程序中读取“地址”属性即可得知即将跳转到的地址，"
		"返回假不允许跳转，返回真或不返回值允许跳转"),
/*m_dwState*/			EV_RETURN_BOOL,
/*m_nArgCount*/			0,
/*m_pBeginArgInfo*/		NULL,
	}, {
	_WT("跳转完毕"),
	_WT("当浏览器已跳转到另一个页面之后产生此事件，"
		"在事件处理子程序中读取“地址”属性即可得知已跳转到的地址"),
/*m_dwState*/			NULL,
/*m_nArgCount*/			0,
/*m_pBeginArgInfo*/		NULL,
	}, {
	_WT("载入开始"),
	_WT("本事件在“即将跳转”事件之后触发，表示浏览器已开始载入将要显示的文档。注意文档可能会被分批载入。"),
/*m_dwState*/			NULL,
/*m_nArgCount*/			0,
/*m_pBeginArgInfo*/		NULL,
	}, {
	_WT("载入进度改变"),
	_WT("在浏览器载入文档的过程中，每当文档被载入一部分即触发本事件，用作通知载入进度"),
/*m_dwState*/			NULL,
/*m_nArgCount*/			1,
/*m_pBeginArgInfo*/		s_HtmlViewerArgInfo,
	}, {
	_WT("载入完毕"),
	_WT("当将要显示在浏览器内的文档被载入完毕后触发本事件。注意文档可能会被分批载入，此事件发生时并不一定意味着整个文档被已载入完毕。另请参考“已就绪”事件。"),
/*m_dwState*/			NULL,
/*m_nArgCount*/			0,
/*m_pBeginArgInfo*/		NULL,
	}, {
	_WT("已就绪"),
	_WT("当浏览器已经将所需显示的文档处理完毕后发送本事件，"
		"在事件处理子程序中读取“地址”属性即可得知已就绪文档的地址"),
/*m_dwState*/			NULL,
/*m_nArgCount*/			0,
/*m_pBeginArgInfo*/		NULL,
	}, {
	_WT("状态文本被改变"),
	_WT("当浏览器的状态条文本被改变后发送本事件，"
			"在事件处理子程序中读取“状态条文本”属性即可得知其内容"),
/*m_dwState*/			NULL,
/*m_nArgCount*/			0,
/*m_pBeginArgInfo*/		NULL,
	}, {
	_WT("标题被改变"),
	_WT("当浏览器的标题文本被改变后发送本事件，"
			"在事件处理子程序中读取“标题”属性即可得知其内容"),
/*m_dwState*/			NULL,
/*m_nArgCount*/			0,
/*m_pBeginArgInfo*/		NULL,
	}, {
	_WT("命令状态被改变"),
	_WT("当“前进”、“后退”等命令的允许状态被改变后发送此事件，"
		"用户程序应该根据状态值允许或禁止对应的按钮或菜单项。"),
/*m_dwState*/			NULL,
/*m_nArgCount*/			2,
/*m_pBeginArgInfo*/		&s_HtmlViewerArgInfo [1],
	}, {
	_WT("即将打开新窗口"),
	_WT("在浏览器即将打开新窗口浏览另一个页面之前产生此事件，"
		"事件处理子程序返回假不允许打开，返回真或不返回值允许打开"),
/*m_dwState*/			EV_RETURN_BOOL,
/*m_nArgCount*/			0,
/*m_pBeginArgInfo*/		NULL,
	},
};
INT g_HtmlViewerEventCount = sizeof (g_HtmlViewerEvent) / sizeof (g_HtmlViewerEvent [0]);

// 注意顺序不可改变!!!
UNIT_PROPERTY g_HtmlViewerProperty [] =
{
	FIXED_WIN_UNIT_PROPERTY,
	{
	/*m_szName*/			_WT("字体大小"),
	/*m_szEgName*/			_WT("FontSize"),
	/*m_szExplain*/			_WT("指定浏览页面时所使用的字体尺寸"),
	/*m_shtType*/			UD_PICK_INT,
	/*m_wState*/			NULL,
	/*m_szzPickStr*/		_WT("最小\0较小\0中等\0较大\0最大\0\0"),
	}, {
	/*m_szName*/			_WT("离线浏览"),
	/*m_szEgName*/			_WT("Offline"),
	/*m_szExplain*/			_WT("指定浏览器是否从缓存里面读取超文本页面数据"),
	/*m_shtType*/			UD_BOOL,
	/*m_wState*/			NULL,
	/*m_szzPickStr*/		NULL,
	}, {
	/*m_szName*/			_WT("静默"),
	/*m_szEgName*/			_WT("Silent"),
	/*m_szExplain*/			_WT("本属性如果为真，则浏览过程中不允许浏览器显示自己的对话框"),
	/*m_shtType*/			UD_BOOL,
	/*m_wState*/			NULL,
	/*m_szzPickStr*/		NULL,
	}, {
	/*m_szName*/			_WT("地址"),
	/*m_szEgName*/			_WT("url"),
	/*m_szExplain*/			_WT("指定欲显示的网络或本机超文本页面地址"),
	/*m_shtType*/			UD_FILE_NAME,
	/*m_wState*/			NULL,
	/*m_szzPickStr*/		_WT("请输入网页文件的名称：\0网页文件 (*.htm;*.html)|*.htm;*.html\0html\0" "0\0\0"),
	}, {
	/*m_szName*/			_WT("状态条文本"),
	/*m_szEgName*/			_WT("StatusText"),
	/*m_szExplain*/			_WT("用作在运行时提供浏览器的当前状态条文本"),
	/*m_shtType*/			UD_TEXT,
	/*m_wState*/			UW_ONLY_READ,
	/*m_szzPickStr*/		NULL,
	}, {
	/*m_szName*/			_WT("标题"),
	/*m_szEgName*/			_WT("Caption"),
	/*m_szExplain*/			_WT("用作在运行时提供浏览器的当前标题文本"),
	/*m_shtType*/			UD_TEXT,
	/*m_wState*/			UW_ONLY_READ,
	/*m_szzPickStr*/		NULL,
	},
};
INT g_HtmlViewerPropertyCount = sizeof (g_HtmlViewerProperty) / sizeof (g_HtmlViewerProperty [0]);


void CPIHtmlViewer::init ()
{
	CPropertyInfo::init ();

	m_nFontSize = 2;
    m_blOffline = FALSE;
    m_blSilent = FALSE;
	m_strURL.Empty ();
}

BOOL CPIHtmlViewer::Serialize (CArchive& ar)
{
	if (CPropertyInfo::Serialize (ar) == FALSE)
		return FALSE;

	TRY
	{
		if (ar.IsLoading () == TRUE)
		{
			DWORD dwUnitDataVer;
			ar >> dwUnitDataVer;
			if (dwUnitDataVer > CUR_UNIT_VER)
				return FALSE;
			ar >> m_nFontSize >> m_blOffline >> m_blSilent;
		}
		else
		{
			ar << (DWORD)CUR_UNIT_VER;
			ar << m_nFontSize << m_blOffline << m_blSilent;
		}

		SerializeCString (m_strURL, ar);
		return TRUE;
	}
	END_TRY

	return FALSE;
}

/////////////////////////////////////////////////////////////////////////////

HUNIT WINAPI Create_HtmlViewer (LPBYTE pAllData, INT nAllDataSize,
		DWORD dwStyle, HWND hParentWnd, UINT uID, HMENU hMenu, INT x, INT y, INT cx, INT cy,
		DWORD dwWinFormID, DWORD dwUnitID, HWND hDesignWnd, BOOL blInDesignMode)
{
	CHHCtrl* pUnit = new CHHCtrl;
	CHKV_RET_VAL (pUnit != NULL, NULL)

	if (pUnit->m_info.LoadData (pAllData, nAllDataSize) == FALSE)
	{
		delete pUnit;
		return NULL;
	}

	pUnit->m_dwWinFormID = dwWinFormID;
	pUnit->m_dwUnitID = dwUnitID;
	pUnit->m_blInDesignMode = blInDesignMode;

	if (pUnit->Create (hParentWnd, dwStyle | WS_CHILD | WS_CLIPSIBLINGS,
			uID, x, y, cx, cy))
	{
		pUnit->SetOffline (pUnit->m_info.m_blOffline);
		pUnit->SetSilent (pUnit->m_info.m_blSilent);

		COleVariant vaZoomFactor ((LONG)max (0, min (4, pUnit->m_info.m_nFontSize)));
		pUnit->ExecWB (OLECMDID_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, &vaZoomFactor, NULL);

		if (!pUnit->m_info.m_strURL.IsEmpty ())
			pUnit->Navigate (pUnit->m_info.m_strURL);
		return (HUNIT)pUnit;
	}
	else
		return NULL;
}

BOOL WINAPI NotifyPropertyChanged_HtmlViewer (HUNIT hUnit, INT nPropertyIndex,
											  PUNIT_PROPERTY_VALUE pPropertyVaule,
											  LPTSTR* ppszTipText)
{
	ASSERT (hUnit != NULL);
	if (hUnit == NULL)  return FALSE;
	CHHCtrl* pUnit = (CHHCtrl*)hUnit;
	ASSERT (pUnit->GetSafeHwnd () != NULL);

	if (ppszTipText != NULL)
		*ppszTipText = NULL;

// 注意此处的属性索引必须与属性表完全一致。
	switch (nPropertyIndex)
	{
	case 0:
		{
			pUnit->m_info.m_nFontSize = max (0, min (4, pPropertyVaule->m_int));
			COleVariant vaZoomFactor ((LONG)pUnit->m_info.m_nFontSize);
			pUnit->ExecWB (OLECMDID_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, &vaZoomFactor, NULL);
		}
		break;
	case 1:
		pUnit->SetOffline (pUnit->m_info.m_blOffline = pPropertyVaule->m_bool);
		break;
	case 2:
		pUnit->SetSilent (pUnit->m_info.m_blSilent = pPropertyVaule->m_bool);
		break;
	case 3:
		SetStr (pUnit->m_info.m_strURL, pPropertyVaule->m_szText);
		pUnit->Navigate (pUnit->m_info.m_strURL);
		break;
	case 4:
		break;
	case 5:
		break;
    default:
        ASSERT (FALSE);
        break;
	}

	return FALSE;
}

// !! 对于运行时可能被用户操作改变（不考虑直接调用API函数）的属性，在运行时必须取其现行实际值。
BOOL WINAPI GetPropertyData_HtmlViewer (HUNIT hUnit, INT nPropertyIndex,
										PUNIT_PROPERTY_VALUE pPropertyVaule)
{
	ASSERT (hUnit != NULL);
	if (hUnit == NULL)  return FALSE;
	CHHCtrl* pUnit = (CHHCtrl*)hUnit;
	ASSERT (pUnit->GetSafeHwnd () != NULL);

// 注意此处的属性索引必须与属性表完全一致。
	switch (nPropertyIndex)
	{
	case 0:
		pPropertyVaule->m_int = pUnit->m_info.m_nFontSize;
		break;
	case 1:
		pPropertyVaule->m_bool = pUnit->m_blInDesignMode ?
				pUnit->m_info.m_blOffline : pUnit->GetOffline ();
		break;
	case 2:
		pPropertyVaule->m_bool = pUnit->m_blInDesignMode ?
				pUnit->m_info.m_blSilent : pUnit->GetSilent ();
		break;
	case 3:
		if (pUnit->m_blInDesignMode == FALSE)
		{
			pUnit->m_info.m_strURL = pUnit->m_blHasForceURL ?
					pUnit->m_strForceURL : pUnit->GetLocationURL ();
		}
		pPropertyVaule->m_szText = (LPTSTR)(LPCTSTR)pUnit->m_info.m_strURL;
		break;
	case 4:
		pPropertyVaule->m_szText = (LPTSTR)(LPCTSTR)pUnit->m_strStatusText;
		break;
	case 5:
		if (pUnit->m_blHasTitle == FALSE)
			pUnit->m_strTitle = pUnit->GetLocationName ();
		pPropertyVaule->m_szText = (LPTSTR)(LPCTSTR)pUnit->m_strTitle;
		break;
	default:
		ASSERT (FALSE);
		return FALSE;
	}

	return TRUE;
}

HGLOBAL WINAPI GetAllPropertyData_HtmlViewer (HUNIT hUnit)
{
	ASSERT (hUnit != NULL);
	return ((CHHCtrl*)hUnit)->m_info.SaveData ();
}

extern "C"
PFN_INTERFACE WINAPI htmlview_GetInterface_HtmlViewer (INT nInterfaceNO)
{
	return nInterfaceNO == ITF_CREATE_UNIT ? (PFN_INTERFACE)Create_HtmlViewer :
			nInterfaceNO == ITF_NOTIFY_PROPERTY_CHANGED ? (PFN_INTERFACE)NotifyPropertyChanged_HtmlViewer :
			nInterfaceNO == ITF_GET_ALL_PROPERTY_DATA ? (PFN_INTERFACE)GetAllPropertyData_HtmlViewer :
			nInterfaceNO == ITF_GET_PROPERTY_DATA ? (PFN_INTERFACE)GetPropertyData_HtmlViewer :
			NULL;
}

