/****************************************************************************** Copyright (c) 1999-2000 Microsoft Corporation Module Name: HtmlUtil.cpp Abstract: This file contains the implementation of various functions and classes designed to help the handling of HTML elements. Revision History: Davide Massarenti (Dmassare) 07/11/2000 created ******************************************************************************/ #include "stdafx.h" //////////////////////////////////////////////////////////////////////////////// void MPC::HTML::QuoteEscape( /*[out]*/ MPC::wstring& strAppendTo , /*[in]*/ LPCWSTR szToEscape , /*[in]*/ WCHAR chQuote ) { if(szToEscape) { WCHAR ch; while((ch = *szToEscape++)) { if(ch == chQuote || ch == '\\') { strAppendTo += '\\'; } strAppendTo += ch; } } } void MPC::HTML::UrlUnescape( /*[out]*/ MPC::wstring& strAppendTo , /*[in]*/ LPCWSTR szToUnescape , /*[in]*/ bool fAsQueryString ) { if(szToUnescape) { WCHAR ch; while((ch = *szToUnescape++)) { if(fAsQueryString && ch == '+') { strAppendTo += ' '; } else if(ch == '%') { int iLen = wcslen( szToUnescape ); bool fFourDigit = (szToUnescape[0] == 'u'); // // Do we have enough characters?? // if(iLen >= (fFourDigit ? 5 : 2)) { if(fFourDigit) { ch = (HexToNum( szToUnescape[1] ) << 12) | (HexToNum( szToUnescape[2] ) << 8) | (HexToNum( szToUnescape[3] ) << 4) | HexToNum( szToUnescape[4] ); szToUnescape += 5; } else { ch = (HexToNum( szToUnescape[0] ) << 4) | HexToNum( szToUnescape[1] ); szToUnescape += 2; } } if(ch) strAppendTo += ch; } else { strAppendTo += ch; } } } } void MPC::HTML::UrlEscape( /*[out]*/ MPC::wstring& strAppendTo , /*[in]*/ LPCWSTR szToEscape , /*[in]*/ bool fAsQueryString ) { // This is a bit field for the hex values: 00-29, 2C, 3A-3F, 5B-5E, 60, 7B-FF // These are the values escape encodes using the default mask (or mask >= 4) static const BYTE s_grfbitEscape[] = { 0xFF, 0xFF, // 00 - 0F 0xFF, 0xFF, // 10 - 1F 0xFF, 0x13, // 20 - 2F 0x00, 0xFC, // 30 - 3F 0x00, 0x00, // 40 - 4F 0x00, 0x78, // 50 - 5F 0x01, 0x00, // 60 - 6F 0x00, 0xF8, // 70 - 7F 0xFF, 0xFF, // 80 - 8F 0xFF, 0xFF, // 90 - 9F 0xFF, 0xFF, // A0 - AF 0xFF, 0xFF, // B0 - BF 0xFF, 0xFF, // C0 - CF 0xFF, 0xFF, // D0 - DF 0xFF, 0xFF, // E0 - EF 0xFF, 0xFF, // F0 - FF }; static const WCHAR s_rgchHex[] = L"0123456789ABCDEF"; //////////////////// if(szToEscape) { WCHAR ch; while((ch = *szToEscape++)) { if(fAsQueryString && ch == ' ') { strAppendTo += '+'; } else if(0 != (ch & 0xFF00)) { strAppendTo += L"%u"; strAppendTo += s_rgchHex[(ch >> 12) & 0x0F]; strAppendTo += s_rgchHex[(ch >> 8) & 0x0F]; strAppendTo += s_rgchHex[(ch >> 4) & 0x0F]; strAppendTo += s_rgchHex[ ch & 0x0F]; } else if((s_grfbitEscape[ch >> 3] & (1 << (ch & 7))) || (fAsQueryString && ch == '+')) { strAppendTo += L"%"; strAppendTo += s_rgchHex[(ch >> 4) & 0x0F]; strAppendTo += s_rgchHex[ ch & 0x0F]; } else { strAppendTo += ch; } } } } void MPC::HTML::HTMLEscape( /*[out]*/ MPC::wstring& strAppendTo , /*[in]*/ LPCWSTR szToEscape ) { if(szToEscape) { WCHAR ch; while((ch = *szToEscape++)) { switch(ch) { case '&': strAppendTo += L"&" ; break; case '"': strAppendTo += L"""; break; case '<': strAppendTo += L"<" ; break; case '>': strAppendTo += L">" ; break; default: strAppendTo += ch ; break; } } } } HRESULT MPC::HTML::ConstructFullTag( /*[out]*/ MPC::wstring& strHTML , /*[in] */ LPCWSTR szTag , /*[in] */ bool fCloseTag , /*[in] */ const MPC::WStringLookup* pmapAttributes , /*[in] */ LPCWSTR szExtraAttributes , /*[in] */ LPCWSTR szBody , /*[in] */ bool fEscapeBody ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::ConstructFullTag" ); HRESULT hr; size_t iLen = szBody ? wcslen( szBody ) : 0; __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_STRING_NOT_EMPTY(szTag); __MPC_PARAMCHECK_END(); // // Let's allocate enough storage for the common case, so we don't need to allocate at each append... // if(fEscapeBody) iLen *= 2; strHTML.reserve( 1024 + iLen ); // // Opening tag. // strHTML.erase(); // We use 'erase' instead of an assignment, because 'erase' just resets the end of string... strHTML += L"<"; strHTML += szTag; if(pmapAttributes) { MPC::WStringLookupIterConst it = pmapAttributes->begin(); MPC::WStringLookupIterConst itEnd = pmapAttributes->end (); for(;it != itEnd; it++) { strHTML += L" "; strHTML += it->first; strHTML += L"=\""; QuoteEscape( strHTML, it->second.c_str(), '\"' ); //" strHTML += L"\""; } } if(szExtraAttributes) { strHTML += L" "; strHTML += szExtraAttributes; } strHTML += L">"; // // Optional body. // if(szBody) { if(fEscapeBody) { HTMLEscape( strHTML, szBody ); } else { strHTML += szBody; } } // // Optional closing tag. // if(fCloseTag) { strHTML += L""; } //////////////////// hr = S_OK; __MPC_FUNC_CLEANUP; __MPC_FUNC_EXIT(hr); } void MPC::HTML::ParseHREF( /*[in] */ LPCWSTR szText , /*[out]*/ MPC::wstring& strBaseURL , /*[out]*/ MPC::WStringLookup& mapQuery ) { LPCWSTR szEnd; mapQuery.clear(); SANITIZEWSTR(szText); szEnd = wcsrchr( szText, '?' ); if(szEnd) { MPC::wstring strRest( szEnd+1 ); MPC::wstring::size_type iLen = strRest.size(); // // Cut before the question mark. // strBaseURL = MPC::wstring( szText, szEnd ); if(iLen) { MPC::wstring::size_type iStart = 0; MPC::wstring::size_type iEnd = 0; MPC::wstring::size_type iMid; MPC::wstring nameESCAPED; MPC::wstring valueESCAPED; MPC::wstring name; MPC::wstring value; while(1) { iEnd = strRest.find( '&', iStart ); if(iEnd == strRest.npos) iEnd = iLen; iMid = strRest.find( '=', iStart ); // // If we have an equality sign, split the query part into a name and value part, unescaping the value // if(iMid != strRest.npos && iMid++ < iEnd) { nameESCAPED = strRest.substr( iStart, (iMid-1) - iStart ); valueESCAPED = strRest.substr( iMid , iEnd - iMid ); } else { nameESCAPED = strRest.substr( iStart, iEnd - iStart ); valueESCAPED = L""; } // // Unescape everything. // name = L""; UrlUnescape( name , nameESCAPED .c_str(), true ); value = L""; UrlUnescape( value, valueESCAPED.c_str(), true ); mapQuery[ name ] = value; if(iEnd == iLen) break; iStart = iEnd + 1; } } } else { strBaseURL = szText; } } void MPC::HTML::BuildHREF( /*[out]*/ MPC::wstring& strURL , /*[in ]*/ LPCWSTR szBaseURL , /*[in ]*/ const MPC::WStringLookup& mapQuery ) { bool fFirst = true; strURL = SAFEWSTR(szBaseURL); for(WStringLookupIterConst it=mapQuery.begin(); it!=mapQuery.end(); it++) { strURL += fFirst ? L"?" : L"&"; UrlEscape( strURL, it->first .c_str(), true ); strURL += L"=" ; UrlEscape( strURL, it->second.c_str(), true ); fFirst = false; } } void MPC::HTML::vBuildHREF( /*[out]*/ MPC::wstring& strURL , /*[in ]*/ LPCWSTR szBaseURL , /*[in ]*/ ... ) { bool fFirst = true; va_list arglist; LPCWSTR szName; LPCWSTR szValue; strURL = SAFEWSTR(szBaseURL); va_start( arglist, szBaseURL ); while((szName = va_arg(arglist,LPCWSTR))) { szValue = va_arg(arglist,LPCWSTR); if(!szValue) szValue = L""; strURL += fFirst ? L"?" : L"&"; UrlEscape( strURL, szName , true ); strURL += L"=" ; UrlEscape( strURL, szValue, true ); fFirst = false; } } //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// HRESULT MPC::HTML::IDispatch_To_IHTMLDocument2( /*[out]*/ CComPtr& doc , /*[in] */ IDispatch* pDisp ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::IDispatch_To_IHTMLDocument2" ); HRESULT hr; doc.Release(); __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_NOTNULL(pDisp); __MPC_PARAMCHECK_END(); // // The pointer passed as input can point to any of these things: // // 1) An IHTMLDocument2 itself. // 2) An IWebBrowser2. // 3) An IHTMLWindow2. // 3) An IHTMLElement. // if(FAILED(pDisp->QueryInterface( IID_IHTMLDocument2, (LPVOID*)&doc ))) { // // Let's try IHTMLWindow2. // { CComPtr win; if(SUCCEEDED(pDisp->QueryInterface( IID_IHTMLWindow2, (LPVOID*)&win ))) { __MPC_EXIT_IF_METHOD_FAILS(hr, win->get_document( &doc )); if(doc == NULL) __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL); __MPC_EXIT_IF_METHOD_FAILS(hr, S_OK); } } // // Let's try IWebBrowser2 or IHTMLElement. // { CComPtr wb; CComPtr elem; CComPtr docDisp; if(SUCCEEDED(pDisp->QueryInterface( IID_IWebBrowser2, (LPVOID*)&wb ))) { __MPC_EXIT_IF_METHOD_FAILS(hr, wb->get_Document( &docDisp )); } else if(SUCCEEDED(pDisp->QueryInterface( IID_IHTMLElement, (LPVOID*)&elem ))) { __MPC_EXIT_IF_METHOD_FAILS(hr, elem->get_document( &docDisp )); } if(docDisp == NULL) __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL); __MPC_EXIT_IF_METHOD_FAILS(hr, docDisp->QueryInterface( IID_IHTMLDocument2, (LPVOID*)&doc )); } } hr = S_OK; __MPC_FUNC_CLEANUP; __MPC_FUNC_EXIT(hr); } ///////////////////////////////////////////////////////////////////////////// HRESULT MPC::HTML::GetFramePath( /*[out]*/ CComBSTR& bstrFrame , /*[in] */ IDispatch* pDisp ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::GetFramePath" ); HRESULT hr; CComPtr pDoc; CComPtr pWin; CComPtr pTop; // // Get to the document and construct the recursive frame name. // __MPC_EXIT_IF_METHOD_FAILS(hr, IDispatch_To_IHTMLDocument2( pDoc, pDisp )); __MPC_EXIT_IF_METHOD_FAILS(hr, pDoc->get_parentWindow( &pWin )); if(pWin == NULL) __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL); __MPC_EXIT_IF_METHOD_FAILS(hr, pWin->get_top ( &pTop )); if(pTop == NULL) __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL); while(pWin != pTop) { CComPtr pParent; CComBSTR bstrName; pWin->get_name( &bstrName ); // // Concatenate the frame names, backward. // if(bstrFrame.Length()) { bstrName += L"/"; bstrName += bstrFrame; } bstrFrame = bstrName; __MPC_EXIT_IF_METHOD_FAILS(hr, pWin->get_parent( &pParent )); if(pParent == NULL) break; pWin = pParent; } hr = S_OK; __MPC_FUNC_CLEANUP; __MPC_FUNC_EXIT(hr); } HRESULT MPC::HTML::AreAllTheFramesInTheCompleteState( /*[out]*/ bool& fDone , /*[in] */ IDispatch* pDisp ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::AreAllTheFramesInTheCompleteState" ); HRESULT hr; CComPtr pDoc; CComPtr pFrames; fDone = true; __MPC_EXIT_IF_METHOD_FAILS(hr, IDispatch_To_IHTMLDocument2( pDoc, pDisp )); __MPC_EXIT_IF_METHOD_FAILS(hr, pDoc->get_frames( &pFrames )); if(pFrames) { long len; __MPC_EXIT_IF_METHOD_FAILS(hr, pFrames->get_length( &len )); for(int i=0; iitem( &vIndex, &vValue )); if(vValue.vt == VT_DISPATCH) { CComQIPtr fb = vValue.pdispVal; if(fb) { CComPtr pDoc2; __MPC_EXIT_IF_METHOD_FAILS(hr, fb->get_document( &pDoc2 )); if(pDoc2) { CComBSTR bstrReadyState; __MPC_EXIT_IF_METHOD_FAILS(hr, pDoc2->get_readyState( &bstrReadyState )); if(MPC::StrICmp( bstrReadyState, L"complete" ) != 0) { fDone = false; break; } } } } } } hr = S_OK; __MPC_FUNC_CLEANUP; __MPC_FUNC_EXIT(hr); } //////////////////////////////////////////////////////////////////////////////// HRESULT MPC::HTML::LocateFrame( /*[out]*/ CComPtr& win , /*[in]*/ IHTMLElement* pObj , /*[in]*/ LPCWSTR szName ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::LocateFrame" ); HRESULT hr; CComPtr doc; win.Release(); __MPC_EXIT_IF_METHOD_FAILS(hr, IDispatch_To_IHTMLDocument2( doc, pObj )); if(szName && szName[0]) { if(!_wcsicmp( szName, L"_top" )) { CComPtr winCurrent; MPC_SCRIPTHELPER_GET__DIRECT__NOTNULL(winCurrent, doc , parentWindow); MPC_SCRIPTHELPER_GET__DIRECT__NOTNULL(win , winCurrent, top ); } else { CComPtr frames; CComVariant vName( szName ); CComVariant vFrame; __MPC_EXIT_IF_METHOD_FAILS(hr, doc->get_frames( &frames )); __MPC_EXIT_IF_METHOD_FAILS(hr, frames->item( &vName, &vFrame )); MPC_SCRIPTHELPER_FAIL_IF_NOT_AN_OBJECT(vFrame); __MPC_EXIT_IF_METHOD_FAILS(hr, vFrame.pdispVal->QueryInterface( __uuidof(IHTMLWindow2), (LPVOID*)&win )); } } else { MPC_SCRIPTHELPER_GET__DIRECT__NOTNULL(win, doc, parentWindow); } hr = S_OK; __MPC_FUNC_CLEANUP; __MPC_FUNC_EXIT(hr); } HRESULT MPC::HTML::GetEventObject( /*[out]*/ CComPtr& ev , /*[in] */ IHTMLElement* pObj ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::GetEventObject" ); HRESULT hr; CComPtr doc; CComPtr win; ev.Release(); __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_NOTNULL(pObj); __MPC_PARAMCHECK_END(); __MPC_EXIT_IF_METHOD_FAILS(hr, IDispatch_To_IHTMLDocument2( doc, pObj )); __MPC_EXIT_IF_METHOD_FAILS(hr, doc->get_parentWindow( &win )); if(win == NULL) __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL); MPC_SCRIPTHELPER_GET__DIRECT__NOTNULL(ev, win, event); hr = S_OK; __MPC_FUNC_CLEANUP; __MPC_FUNC_EXIT(hr); } HRESULT MPC::HTML::GetUniqueID( /*[out]*/ CComBSTR& bstrID, /*[in]*/ IHTMLElement* pObj ) { return MPC::COMUtil::GetPropertyByName( pObj, L"uniqueID", bstrID ); } HRESULT MPC::HTML::FindFirstParentWithThisTag( /*[out]*/ CComPtr& elem , /*[in] */ IHTMLElement* pObj , /*[in]*/ LPCWSTR szTag ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::FindFirstParentWithThisTag" ); HRESULT hr; elem.Release(); __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_STRING_NOT_EMPTY(szTag); __MPC_PARAMCHECK_END(); elem = pObj; while(elem) { CComBSTR bstrTag; CComPtr parent; __MPC_EXIT_IF_METHOD_FAILS(hr, elem->get_tagName( &bstrTag )); if(!MPC::StrICmp( bstrTag, szTag )) break; __MPC_EXIT_IF_METHOD_FAILS(hr, elem->get_parentElement( &parent )); elem = parent; } hr = S_OK; __MPC_FUNC_CLEANUP; __MPC_FUNC_EXIT(hr); } HRESULT MPC::HTML::FindFirstParentWithThisID( /*[out]*/ CComPtr& elem , /*[in] */ IHTMLElement* pObj , /*[in]*/ LPCWSTR szID ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::FindFirstParentWithThisTag" ); HRESULT hr; elem = pObj; while(elem) { CComBSTR bstrID; CComPtr parent; __MPC_EXIT_IF_METHOD_FAILS(hr, elem->get_id( &bstrID )); if(bstrID) { if(szID == NULL || !_wcsicmp( bstrID, szID )) { break; } } __MPC_EXIT_IF_METHOD_FAILS(hr, elem->get_parentElement( &parent )); elem = parent; } hr = S_OK; __MPC_FUNC_CLEANUP; __MPC_FUNC_EXIT(hr); } //////////////////////////////////////////////////////////////////////////////// HRESULT MPC::HTML::FindElementInCollection( /*[out]*/ CComPtr& elem , /*[in] */ IHTMLElementCollection* coll , /*[in] */ LPCWSTR szID , /*[in] */ int iPos ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::FindElementInCollection" ); HRESULT hr; CComPtr disp; CComVariant vName; CComVariant vIndex; elem.Release(); __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_NOTNULL(coll); __MPC_PARAMCHECK_END(); if(szID) { vName = szID; vIndex = iPos; } else { vName = iPos; } __MPC_EXIT_IF_METHOD_FAILS(hr, coll->item( vName, vIndex, &disp )); if(disp) { __MPC_EXIT_IF_METHOD_FAILS(hr, disp.QueryInterface( &elem )); } hr = S_OK; __MPC_FUNC_CLEANUP; __MPC_FUNC_EXIT(hr); } HRESULT MPC::HTML::FindElement( /*[out]*/ CComPtr& elem , /*[in] */ IHTMLElement* pObj , /*[in] */ LPCWSTR szID , /*[in] */ int iPos ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::FindElement" ); HRESULT hr; CComPtr coll; __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_NOTNULL(pObj); __MPC_PARAMCHECK_END(); MPC_SCRIPTHELPER_GET_OBJECT__NOTNULL(coll, pObj, all); __MPC_SET_ERROR_AND_EXIT(hr, FindElementInCollection( elem, coll, szID, iPos )); hr = S_OK; __MPC_FUNC_CLEANUP; __MPC_FUNC_EXIT(hr); } HRESULT MPC::HTML::FindChild( /*[out]*/ CComPtr& elem , /*[in] */ IHTMLElement* pObj , /*[in] */ LPCWSTR szID , /*[in] */ int iPos ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::FindChild" ); HRESULT hr; CComPtr coll; __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_NOTNULL(pObj); __MPC_PARAMCHECK_END(); MPC_SCRIPTHELPER_GET_OBJECT__NOTNULL(coll, pObj, children); __MPC_SET_ERROR_AND_EXIT(hr, FindElementInCollection( elem, coll, szID, iPos )); hr = S_OK; __MPC_FUNC_CLEANUP; __MPC_FUNC_EXIT(hr); } //////////////////////////////////////////////////////////////////////////////// HRESULT MPC::HTML::EnumerateCollection( /*[out]*/ IHTMLElementList& lst , /*[in] */ IHTMLElementCollection* pColl , /*[in] */ LPCWSTR szFilterID ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::EnumerateCollection" ); HRESULT hr; long lLen; long lPos; CComVariant vName; CComVariant vIndex; bool fFilterAsTag; MPC::ReleaseAll( lst ); __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_NOTNULL(pColl); __MPC_PARAMCHECK_END(); if(szFilterID && szFilterID[0] == '<') { fFilterAsTag = true; szFilterID++; } else { fFilterAsTag = false; } MPC_SCRIPTHELPER_GET__DIRECT(lLen, pColl, length); for(lPos=0; lPos disp; CComPtr elem; vName = lPos; __MPC_EXIT_IF_METHOD_FAILS(hr, pColl->item( vName, vIndex, &disp )); if(disp == NULL) __MPC_SET_ERROR_AND_EXIT(hr, E_NOINTERFACE); __MPC_EXIT_IF_METHOD_FAILS(hr, disp.QueryInterface( &elem )); // // If we receive a string as input, filter out all the tags not matching with the ID or TAG. // if(szFilterID) { CComBSTR bstr; if(fFilterAsTag) { __MPC_EXIT_IF_METHOD_FAILS(hr, elem->get_tagName( &bstr )); } else { __MPC_EXIT_IF_METHOD_FAILS(hr, elem->get_id( &bstr )); } if(MPC::StrICmp( bstr, szFilterID )) continue; } lst.push_back( elem.Detach() ); } hr = S_OK; __MPC_FUNC_CLEANUP; __MPC_FUNC_EXIT(hr); } HRESULT MPC::HTML::EnumerateElements( /*[out]*/ IHTMLElementList& lst , /*[in] */ IHTMLElement* pObj , /*[in] */ LPCWSTR szFilterID ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::EnumerateElements" ); HRESULT hr; CComPtr coll; __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_NOTNULL(pObj); __MPC_PARAMCHECK_END(); MPC_SCRIPTHELPER_GET_OBJECT__NOTNULL(coll, pObj, all); __MPC_EXIT_IF_METHOD_FAILS(hr, EnumerateCollection( lst, coll, szFilterID )); hr = S_OK; __MPC_FUNC_CLEANUP; __MPC_FUNC_EXIT(hr); } HRESULT MPC::HTML::EnumerateChildren( /*[out]*/ IHTMLElementList& lst , /*[in] */ IHTMLElement* pObj , /*[in] */ LPCWSTR szFilterID ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::EnumerateChildren" ); HRESULT hr; CComPtr coll; __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_NOTNULL(pObj); __MPC_PARAMCHECK_END(); MPC_SCRIPTHELPER_GET_OBJECT__NOTNULL(coll, pObj, children); __MPC_EXIT_IF_METHOD_FAILS(hr, EnumerateCollection( lst, coll, szFilterID )); hr = S_OK; __MPC_FUNC_CLEANUP; __MPC_FUNC_EXIT(hr); } //////////////////////////////////////////////////////////////////////////////// HRESULT MPC::HTML::FindStyle( /*[out]*/ CComPtr& style , /*[in ]*/ IHTMLElement* pObj , /*[in ]*/ LPCWSTR szName ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::FindStyle" ); HRESULT hr; CComPtr doc; CComPtr styles; VARIANT vIdx; long lNumStyles; __MPC_EXIT_IF_METHOD_FAILS(hr, IDispatch_To_IHTMLDocument2( doc, pObj )); MPC_SCRIPTHELPER_GET__DIRECT__NOTNULL(styles , doc , styleSheets); MPC_SCRIPTHELPER_GET__DIRECT (lNumStyles, styles, length ); vIdx.vt = VT_I4; for(vIdx.iVal=0; vIdx.iVal css; CComVariant v; __MPC_EXIT_IF_METHOD_FAILS(hr, styles->item( &vIdx, &v )); if(v.vt == VT_DISPATCH && (css = v.pdispVal)) { CComPtr rules; long lNumRules; MPC_SCRIPTHELPER_GET__DIRECT__NOTNULL(rules , css , rules ); MPC_SCRIPTHELPER_GET__DIRECT (lNumRules, rules, length); for(long l=0; l rule; __MPC_EXIT_IF_METHOD_FAILS(hr, rules->item( l, &rule )); if(rule) { CComBSTR bstrName; MPC_SCRIPTHELPER_GET__DIRECT(bstrName, rule, selectorText); if(!MPC::StrICmp( bstrName, szName )) { __MPC_SET_ERROR_AND_EXIT(hr, rule->get_style( &style )); } } } } } hr = S_OK; __MPC_FUNC_CLEANUP; __MPC_FUNC_EXIT(hr); } //////////////////////////////////////////////////////////////////////////////// HRESULT MPC::HTML::GetAttribute( /*[out]*/ CComPtr& attr , /*[in]*/ IHTMLElement* pObj , /*[in]*/ LPCWSTR szName ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::GetAttribute" ); HRESULT hr; CComPtr dom; CComPtr coll; CComPtr dispAttr; CComVariant v( szName ); __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_NOTNULL(pObj); __MPC_PARAMCHECK_END(); attr.Release(); __MPC_EXIT_IF_METHOD_FAILS(hr, pObj->QueryInterface( IID_IHTMLDOMNode, (LPVOID *)&dom )); MPC_SCRIPTHELPER_GET_OBJECT__NOTNULL(coll, dom, attributes); __MPC_EXIT_IF_METHOD_FAILS(hr, coll->item( &v, &dispAttr )); if(dispAttr) { __MPC_EXIT_IF_METHOD_FAILS(hr, dispAttr->QueryInterface( &attr )); } hr = S_OK; __MPC_FUNC_CLEANUP; __MPC_FUNC_EXIT(hr); } HRESULT MPC::HTML::GetAttribute( /*[out]*/ CComBSTR& value , /*[in]*/ IHTMLElement* pObj , /*[in]*/ LPCWSTR szName ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::GetAttribute" ); HRESULT hr; CComPtr attr; value.Empty(); __MPC_EXIT_IF_METHOD_FAILS(hr, GetAttribute( attr, pObj, szName )); if(attr) { MPC_SCRIPTHELPER_GET_STRING__VARIANT(value, attr, nodeValue); } hr = S_OK; __MPC_FUNC_CLEANUP; __MPC_FUNC_EXIT(hr); } //////////////////////////////////////////////////////////////////////////////// typedef struct { const WCHAR* szName; DWORD dwValue; } COLORVALUE_PAIR; static const COLORVALUE_PAIR c_rgColorNames[] = { { L"aliceblue" , 0xfff8f0 }, { L"antiquewhite" , 0xd7ebfa }, { L"aqua" , 0xffff00 }, { L"aquamarine" , 0xd4ff7f }, { L"azure" , 0xfffff0 }, { L"beige" , 0xdcf5f5 }, { L"bisque" , 0xc4e4ff }, { L"black" , 0x000000 }, { L"blanchedalmond" , 0xcdebff }, { L"blue" , 0xff0000 }, { L"blueviolet" , 0xe22b8a }, { L"brown" , 0x2a2aa5 }, { L"burlywood" , 0x87b8de }, { L"cadetblue" , 0xa09e5f }, { L"chartreuse" , 0x00ff7f }, { L"chocolate" , 0x1e69d2 }, { L"coral" , 0x507fff }, { L"cornflowerblue" , 0xed9564 }, { L"cornsilk" , 0xdcf8ff }, { L"crimson" , 0x3c14dc }, { L"cyan" , 0xffff00 }, { L"darkblue" , 0x8b0000 }, { L"darkcyan" , 0x8b8b00 }, { L"darkgoldenrod" , 0x0b86b8 }, { L"darkgray" , 0xa9a9a9 }, { L"darkgreen" , 0x006400 }, { L"darkkhaki" , 0x6bb7bd }, { L"darkmagenta" , 0x8b008b }, { L"darkolivegreen" , 0x2f6b55 }, { L"darkorange" , 0x008cff }, { L"darkorchid" , 0xcc3299 }, { L"darkred" , 0x00008b }, { L"darksalmon" , 0x7a96e9 }, { L"darkseagreen" , 0x8fbc8f }, { L"darkslateblue" , 0x8b3d48 }, { L"darkslategray" , 0x4f4f2f }, { L"darkturquoise" , 0xd1ce00 }, { L"darkviolet" , 0xd30094 }, { L"deeppink" , 0x9314ff }, { L"deepskyblue" , 0xffbf00 }, { L"dimgray" , 0x696969 }, { L"dodgerblue" , 0xff901e }, { L"firebrick" , 0x2222b2 }, { L"floralwhite" , 0xf0faff }, { L"forestgreen" , 0x228b22 }, { L"fuchsia" , 0xff00ff }, { L"gainsboro" , 0xdcdcdc }, { L"ghostwhite" , 0xfff8f8 }, { L"gold" , 0x00d7ff }, { L"goldenrod" , 0x20a5da }, { L"gray" , 0x808080 }, { L"green" , 0x008000 }, { L"greenyellow" , 0x2fffad }, { L"honeydew" , 0xf0fff0 }, { L"hotpink" , 0xb469ff }, { L"indianred" , 0x5c5ccd }, { L"indigo" , 0x82004b }, { L"ivory" , 0xf0ffff }, { L"khaki" , 0x8ce6f0 }, { L"lavender" , 0xfae6e6 }, { L"lavenderblush" , 0xf5f0ff }, { L"lawngreen" , 0x00fc7c }, { L"lemonchiffon" , 0xcdfaff }, { L"lightblue" , 0xe6d8ad }, { L"lightcoral" , 0x8080f0 }, { L"lightcyan" , 0xffffe0 }, { L"lightgoldenrodyellow", 0xd2fafa }, { L"lightgreen" , 0x90ee90 }, { L"lightgrey" , 0xd3d3d3 }, { L"lightpink" , 0xc1b6ff }, { L"lightsalmon" , 0x7aa0ff }, { L"lightseagreen" , 0xaab220 }, { L"lightskyblue" , 0xface87 }, { L"lightslategray" , 0x998877 }, { L"lightsteelblue" , 0xdec4b0 }, { L"lightyellow" , 0xe0ffff }, { L"lime" , 0x00ff00 }, { L"limegreen" , 0x32cd32 }, { L"linen" , 0xe6f0fa }, { L"magenta" , 0xff00ff }, { L"maroon" , 0x000080 }, { L"mediumaquamarine" , 0xaacd66 }, { L"mediumblue" , 0xcd0000 }, { L"mediumorchid" , 0xd355ba }, { L"mediumpurple" , 0xdb7093 }, { L"mediumseagreen" , 0x71b33c }, { L"mediumslateblue" , 0xee687b }, { L"mediumspringgreen" , 0x9afa00 }, { L"mediumturquoise" , 0xccd148 }, { L"mediumvioletred" , 0x8515c7 }, { L"midnightblue" , 0x701919 }, { L"mintcream" , 0xfafff5 }, { L"mistyrose" , 0xe1e4ff }, { L"moccasin" , 0xb5e4ff }, { L"navajowhite" , 0xaddeff }, { L"navy" , 0x800000 }, { L"oldlace" , 0xe6f5fd }, { L"olive" , 0x008080 }, { L"olivedrab" , 0x238e6b }, { L"orange" , 0x00a5ff }, { L"orangered" , 0x0045ff }, { L"orchid" , 0xd670da }, { L"palegoldenrod" , 0xaae8ee }, { L"palegreen" , 0x98fb98 }, { L"paleturquoise" , 0xeeeeaf }, { L"palevioletred" , 0x9370db }, { L"papayawhip" , 0xd5efff }, { L"peachpuff" , 0xb9daff }, { L"peru" , 0x3f85cd }, { L"pink" , 0xcbc0ff }, { L"plum" , 0xdda0dd }, { L"powderblue" , 0xe6e0b0 }, { L"purple" , 0x800080 }, { L"red" , 0x0000ff }, { L"rosybrown" , 0x8f8fbc }, { L"royalblue" , 0xe16941 }, { L"saddlebrown" , 0x13458b }, { L"salmon" , 0x7280fa }, { L"sandybrown" , 0x60a4f4 }, { L"seagreen" , 0x578b2e }, { L"seashell" , 0xeef5ff }, { L"sienna" , 0x2d52a0 }, { L"silver" , 0xc0c0c0 }, { L"skyblue" , 0xebce87 }, { L"slateblue" , 0xcd5a6a }, { L"slategray" , 0x908070 }, { L"snow" , 0xfafaff }, { L"springgreen" , 0x7fff00 }, { L"steelblue" , 0xb48246 }, { L"tan" , 0x8cb4d2 }, { L"teal" , 0x808000 }, { L"thistle" , 0xd8bfd8 }, { L"tomato" , 0x4763ff }, { L"turquoise" , 0xd0e040 }, { L"violet" , 0xee82ee }, { L"wheat" , 0xb3def5 }, { L"white" , 0xffffff }, { L"whitesmoke" , 0xf5f5f5 }, { L"yellow" , 0x00ffff }, { L"yellowgreen" , 0x32cd9a } }; static const COLORVALUE_PAIR c_rgSystemColors[] = { { L"activeborder" , COLOR_ACTIVEBORDER }, { L"activecaption" , COLOR_ACTIVECAPTION }, { L"appworkspace" , COLOR_APPWORKSPACE }, { L"background" , COLOR_BACKGROUND }, { L"buttonface" , COLOR_BTNFACE }, { L"buttonhighlight" , COLOR_BTNHIGHLIGHT }, { L"buttonshadow" , COLOR_BTNSHADOW }, { L"buttontext" , COLOR_BTNTEXT }, { L"captiontext" , COLOR_CAPTIONTEXT }, { L"gradientactivecaption" , COLOR_GRADIENTACTIVECAPTION }, { L"gradientinactivecaption", COLOR_GRADIENTINACTIVECAPTION }, { L"graytext" , COLOR_GRAYTEXT }, { L"highlight" , COLOR_HIGHLIGHT }, { L"highlighttext" , COLOR_HIGHLIGHTTEXT }, { L"hotlight" , COLOR_HOTLIGHT }, { L"inactiveborder" , COLOR_INACTIVEBORDER }, { L"inactivecaption" , COLOR_INACTIVECAPTION }, { L"inactivecaptiontext" , COLOR_INACTIVECAPTIONTEXT }, { L"infobackground" , COLOR_INFOBK }, { L"infotext" , COLOR_INFOTEXT }, { L"menu" , COLOR_MENU }, { L"menutext" , COLOR_MENUTEXT }, { L"scrollbar" , COLOR_SCROLLBAR }, { L"threeddarkshadow" , COLOR_3DDKSHADOW }, { L"threedface" , COLOR_3DFACE }, { L"threedhighlight" , COLOR_3DHIGHLIGHT }, { L"threedlightshadow" , COLOR_3DLIGHT }, { L"threedshadow" , COLOR_3DSHADOW }, { L"window" , COLOR_WINDOW }, { L"windowframe" , COLOR_WINDOWFRAME }, { L"windowtext" , COLOR_WINDOWTEXT }, }; static const COLORVALUE_PAIR* local_LookupName( /*[in]*/ const COLORVALUE_PAIR* tbl , /*[in]*/ int iSize , /*[in]*/ LPCWSTR szText ) { while(iSize-- > 0) { if(!_wcsicmp( tbl->szName, szText )) return tbl; tbl++; } return NULL; } bool MPC::HTML::ConvertColor( /*[in]*/ VARIANT& v, /*[out]*/ COLORREF& color, /*[out]*/ bool& fSystem ) { color = RGB(255,255,255); fSystem = false; if(v.vt == VT_I4) { color = (COLORREF)v.iVal; return true; } if(v.vt == VT_BSTR && v.bstrVal) { const COLORVALUE_PAIR* ptr; ptr = local_LookupName( c_rgColorNames, ARRAYSIZE(c_rgColorNames), v.bstrVal ); if(ptr) { color = (COLORREF)ptr->dwValue; return true; } ptr = local_LookupName( c_rgSystemColors, ARRAYSIZE(c_rgSystemColors), v.bstrVal ); if(ptr) { color = (COLORREF)::GetSysColor( ptr->dwValue ); fSystem = true; return true; } if(v.bstrVal[0] == '#') { int iRED; int iGREEN; int iBLUE; if(swscanf( &v.bstrVal[1], L"%02x%02x%02x", &iRED, &iGREEN, &iBLUE ) == 3) { color = RGB( iRED, iGREEN, iBLUE ); return true; } } } return false; }