Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1342 lines
40 KiB

  1. /******************************************************************************
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. HtmlUtil.cpp
  5. Abstract:
  6. This file contains the implementation of various functions and classes
  7. designed to help the handling of HTML elements.
  8. Revision History:
  9. Davide Massarenti (Dmassare) 07/11/2000
  10. created
  11. ******************************************************************************/
  12. #include "stdafx.h"
  13. ////////////////////////////////////////////////////////////////////////////////
  14. void MPC::HTML::QuoteEscape( /*[out]*/ MPC::wstring& strAppendTo ,
  15. /*[in]*/ LPCWSTR szToEscape ,
  16. /*[in]*/ WCHAR chQuote )
  17. {
  18. if(szToEscape)
  19. {
  20. WCHAR ch;
  21. while((ch = *szToEscape++))
  22. {
  23. if(ch == chQuote || ch == '\\')
  24. {
  25. strAppendTo += '\\';
  26. }
  27. strAppendTo += ch;
  28. }
  29. }
  30. }
  31. void MPC::HTML::UrlUnescape( /*[out]*/ MPC::wstring& strAppendTo ,
  32. /*[in]*/ LPCWSTR szToUnescape ,
  33. /*[in]*/ bool fAsQueryString )
  34. {
  35. if(szToUnescape)
  36. {
  37. WCHAR ch;
  38. while((ch = *szToUnescape++))
  39. {
  40. if(fAsQueryString && ch == '+')
  41. {
  42. strAppendTo += ' ';
  43. }
  44. else if(ch == '%')
  45. {
  46. int iLen = wcslen( szToUnescape );
  47. bool fFourDigit = (szToUnescape[0] == 'u');
  48. //
  49. // Do we have enough characters??
  50. //
  51. if(iLen >= (fFourDigit ? 5 : 2))
  52. {
  53. if(fFourDigit)
  54. {
  55. ch = (HexToNum( szToUnescape[1] ) << 12) |
  56. (HexToNum( szToUnescape[2] ) << 8) |
  57. (HexToNum( szToUnescape[3] ) << 4) |
  58. HexToNum( szToUnescape[4] );
  59. szToUnescape += 5;
  60. }
  61. else
  62. {
  63. ch = (HexToNum( szToUnescape[0] ) << 4) |
  64. HexToNum( szToUnescape[1] );
  65. szToUnescape += 2;
  66. }
  67. }
  68. if(ch) strAppendTo += ch;
  69. }
  70. else
  71. {
  72. strAppendTo += ch;
  73. }
  74. }
  75. }
  76. }
  77. void MPC::HTML::UrlEscape( /*[out]*/ MPC::wstring& strAppendTo ,
  78. /*[in]*/ LPCWSTR szToEscape ,
  79. /*[in]*/ bool fAsQueryString )
  80. {
  81. // This is a bit field for the hex values: 00-29, 2C, 3A-3F, 5B-5E, 60, 7B-FF
  82. // These are the values escape encodes using the default mask (or mask >= 4)
  83. static const BYTE s_grfbitEscape[] =
  84. {
  85. 0xFF, 0xFF, // 00 - 0F
  86. 0xFF, 0xFF, // 10 - 1F
  87. 0xFF, 0x13, // 20 - 2F
  88. 0x00, 0xFC, // 30 - 3F
  89. 0x00, 0x00, // 40 - 4F
  90. 0x00, 0x78, // 50 - 5F
  91. 0x01, 0x00, // 60 - 6F
  92. 0x00, 0xF8, // 70 - 7F
  93. 0xFF, 0xFF, // 80 - 8F
  94. 0xFF, 0xFF, // 90 - 9F
  95. 0xFF, 0xFF, // A0 - AF
  96. 0xFF, 0xFF, // B0 - BF
  97. 0xFF, 0xFF, // C0 - CF
  98. 0xFF, 0xFF, // D0 - DF
  99. 0xFF, 0xFF, // E0 - EF
  100. 0xFF, 0xFF, // F0 - FF
  101. };
  102. static const WCHAR s_rgchHex[] = L"0123456789ABCDEF";
  103. ////////////////////
  104. if(szToEscape)
  105. {
  106. WCHAR ch;
  107. while((ch = *szToEscape++))
  108. {
  109. if(fAsQueryString && ch == ' ')
  110. {
  111. strAppendTo += '+';
  112. }
  113. else if(0 != (ch & 0xFF00))
  114. {
  115. strAppendTo += L"%u";
  116. strAppendTo += s_rgchHex[(ch >> 12) & 0x0F];
  117. strAppendTo += s_rgchHex[(ch >> 8) & 0x0F];
  118. strAppendTo += s_rgchHex[(ch >> 4) & 0x0F];
  119. strAppendTo += s_rgchHex[ ch & 0x0F];
  120. }
  121. else if((s_grfbitEscape[ch >> 3] & (1 << (ch & 7))) || (fAsQueryString && ch == '+'))
  122. {
  123. strAppendTo += L"%";
  124. strAppendTo += s_rgchHex[(ch >> 4) & 0x0F];
  125. strAppendTo += s_rgchHex[ ch & 0x0F];
  126. }
  127. else
  128. {
  129. strAppendTo += ch;
  130. }
  131. }
  132. }
  133. }
  134. void MPC::HTML::HTMLEscape( /*[out]*/ MPC::wstring& strAppendTo ,
  135. /*[in]*/ LPCWSTR szToEscape )
  136. {
  137. if(szToEscape)
  138. {
  139. WCHAR ch;
  140. while((ch = *szToEscape++))
  141. {
  142. switch(ch)
  143. {
  144. case '&': strAppendTo += L"&amp;" ; break;
  145. case '"': strAppendTo += L"&quot;"; break;
  146. case '<': strAppendTo += L"&lt;" ; break;
  147. case '>': strAppendTo += L"&gt;" ; break;
  148. default: strAppendTo += ch ; break;
  149. }
  150. }
  151. }
  152. }
  153. HRESULT MPC::HTML::ConstructFullTag( /*[out]*/ MPC::wstring& strHTML ,
  154. /*[in] */ LPCWSTR szTag ,
  155. /*[in] */ bool fCloseTag ,
  156. /*[in] */ const MPC::WStringLookup* pmapAttributes ,
  157. /*[in] */ LPCWSTR szExtraAttributes ,
  158. /*[in] */ LPCWSTR szBody ,
  159. /*[in] */ bool fEscapeBody )
  160. {
  161. __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::ConstructFullTag" );
  162. HRESULT hr;
  163. size_t iLen = szBody ? wcslen( szBody ) : 0;
  164. __MPC_PARAMCHECK_BEGIN(hr)
  165. __MPC_PARAMCHECK_STRING_NOT_EMPTY(szTag);
  166. __MPC_PARAMCHECK_END();
  167. //
  168. // Let's allocate enough storage for the common case, so we don't need to allocate at each append...
  169. //
  170. if(fEscapeBody) iLen *= 2;
  171. strHTML.reserve( 1024 + iLen );
  172. //
  173. // Opening tag.
  174. //
  175. strHTML.erase(); // We use 'erase' instead of an assignment, because 'erase' just resets the end of string...
  176. strHTML += L"<";
  177. strHTML += szTag;
  178. if(pmapAttributes)
  179. {
  180. MPC::WStringLookupIterConst it = pmapAttributes->begin();
  181. MPC::WStringLookupIterConst itEnd = pmapAttributes->end ();
  182. for(;it != itEnd; it++)
  183. {
  184. strHTML += L" ";
  185. strHTML += it->first;
  186. strHTML += L"=\"";
  187. QuoteEscape( strHTML, it->second.c_str(), '\"' ); //"
  188. strHTML += L"\"";
  189. }
  190. }
  191. if(szExtraAttributes)
  192. {
  193. strHTML += L" ";
  194. strHTML += szExtraAttributes;
  195. }
  196. strHTML += L">";
  197. //
  198. // Optional body.
  199. //
  200. if(szBody)
  201. {
  202. if(fEscapeBody)
  203. {
  204. HTMLEscape( strHTML, szBody );
  205. }
  206. else
  207. {
  208. strHTML += szBody;
  209. }
  210. }
  211. //
  212. // Optional closing tag.
  213. //
  214. if(fCloseTag)
  215. {
  216. strHTML += L"</";
  217. strHTML += szTag;
  218. strHTML += L">";
  219. }
  220. ////////////////////
  221. hr = S_OK;
  222. __MPC_FUNC_CLEANUP;
  223. __MPC_FUNC_EXIT(hr);
  224. }
  225. void MPC::HTML::ParseHREF( /*[in] */ LPCWSTR szText ,
  226. /*[out]*/ MPC::wstring& strBaseURL ,
  227. /*[out]*/ MPC::WStringLookup& mapQuery )
  228. {
  229. LPCWSTR szEnd;
  230. mapQuery.clear();
  231. SANITIZEWSTR(szText);
  232. szEnd = wcsrchr( szText, '?' );
  233. if(szEnd)
  234. {
  235. MPC::wstring strRest( szEnd+1 );
  236. MPC::wstring::size_type iLen = strRest.size();
  237. //
  238. // Cut before the question mark.
  239. //
  240. strBaseURL = MPC::wstring( szText, szEnd );
  241. if(iLen)
  242. {
  243. MPC::wstring::size_type iStart = 0;
  244. MPC::wstring::size_type iEnd = 0;
  245. MPC::wstring::size_type iMid;
  246. MPC::wstring nameESCAPED;
  247. MPC::wstring valueESCAPED;
  248. MPC::wstring name;
  249. MPC::wstring value;
  250. while(1)
  251. {
  252. iEnd = strRest.find( '&', iStart ); if(iEnd == strRest.npos) iEnd = iLen;
  253. iMid = strRest.find( '=', iStart );
  254. //
  255. // If we have an equality sign, split the query part into a name and value part, unescaping the value
  256. //
  257. if(iMid != strRest.npos && iMid++ < iEnd)
  258. {
  259. nameESCAPED = strRest.substr( iStart, (iMid-1) - iStart );
  260. valueESCAPED = strRest.substr( iMid , iEnd - iMid );
  261. }
  262. else
  263. {
  264. nameESCAPED = strRest.substr( iStart, iEnd - iStart );
  265. valueESCAPED = L"";
  266. }
  267. //
  268. // Unescape everything.
  269. //
  270. name = L""; UrlUnescape( name , nameESCAPED .c_str(), true );
  271. value = L""; UrlUnescape( value, valueESCAPED.c_str(), true );
  272. mapQuery[ name ] = value;
  273. if(iEnd == iLen) break;
  274. iStart = iEnd + 1;
  275. }
  276. }
  277. }
  278. else
  279. {
  280. strBaseURL = szText;
  281. }
  282. }
  283. void MPC::HTML::BuildHREF( /*[out]*/ MPC::wstring& strURL ,
  284. /*[in ]*/ LPCWSTR szBaseURL ,
  285. /*[in ]*/ const MPC::WStringLookup& mapQuery )
  286. {
  287. bool fFirst = true;
  288. strURL = SAFEWSTR(szBaseURL);
  289. for(WStringLookupIterConst it=mapQuery.begin(); it!=mapQuery.end(); it++)
  290. {
  291. strURL += fFirst ? L"?" : L"&"; UrlEscape( strURL, it->first .c_str(), true );
  292. strURL += L"=" ; UrlEscape( strURL, it->second.c_str(), true );
  293. fFirst = false;
  294. }
  295. }
  296. void MPC::HTML::vBuildHREF( /*[out]*/ MPC::wstring& strURL ,
  297. /*[in ]*/ LPCWSTR szBaseURL ,
  298. /*[in ]*/ ... )
  299. {
  300. bool fFirst = true;
  301. va_list arglist;
  302. LPCWSTR szName;
  303. LPCWSTR szValue;
  304. strURL = SAFEWSTR(szBaseURL);
  305. va_start( arglist, szBaseURL );
  306. while((szName = va_arg(arglist,LPCWSTR)))
  307. {
  308. szValue = va_arg(arglist,LPCWSTR); if(!szValue) szValue = L"";
  309. strURL += fFirst ? L"?" : L"&"; UrlEscape( strURL, szName , true );
  310. strURL += L"=" ; UrlEscape( strURL, szValue, true );
  311. fFirst = false;
  312. }
  313. }
  314. ////////////////////////////////////////////////////////////////////////////////
  315. ////////////////////////////////////////////////////////////////////////////////
  316. HRESULT MPC::HTML::IDispatch_To_IHTMLDocument2( /*[out]*/ CComPtr<IHTMLDocument2>& doc ,
  317. /*[in] */ IDispatch* pDisp )
  318. {
  319. __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::IDispatch_To_IHTMLDocument2" );
  320. HRESULT hr;
  321. doc.Release();
  322. __MPC_PARAMCHECK_BEGIN(hr)
  323. __MPC_PARAMCHECK_NOTNULL(pDisp);
  324. __MPC_PARAMCHECK_END();
  325. //
  326. // The pointer passed as input can point to any of these things:
  327. //
  328. // 1) An IHTMLDocument2 itself.
  329. // 2) An IWebBrowser2.
  330. // 3) An IHTMLWindow2.
  331. // 3) An IHTMLElement.
  332. //
  333. if(FAILED(pDisp->QueryInterface( IID_IHTMLDocument2, (LPVOID*)&doc )))
  334. {
  335. //
  336. // Let's try IHTMLWindow2.
  337. //
  338. {
  339. CComPtr<IHTMLWindow2> win;
  340. if(SUCCEEDED(pDisp->QueryInterface( IID_IHTMLWindow2, (LPVOID*)&win )))
  341. {
  342. __MPC_EXIT_IF_METHOD_FAILS(hr, win->get_document( &doc ));
  343. if(doc == NULL) __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  344. __MPC_EXIT_IF_METHOD_FAILS(hr, S_OK);
  345. }
  346. }
  347. //
  348. // Let's try IWebBrowser2 or IHTMLElement.
  349. //
  350. {
  351. CComPtr<IWebBrowser2> wb;
  352. CComPtr<IHTMLElement> elem;
  353. CComPtr<IDispatch> docDisp;
  354. if(SUCCEEDED(pDisp->QueryInterface( IID_IWebBrowser2, (LPVOID*)&wb )))
  355. {
  356. __MPC_EXIT_IF_METHOD_FAILS(hr, wb->get_Document( &docDisp ));
  357. }
  358. else if(SUCCEEDED(pDisp->QueryInterface( IID_IHTMLElement, (LPVOID*)&elem )))
  359. {
  360. __MPC_EXIT_IF_METHOD_FAILS(hr, elem->get_document( &docDisp ));
  361. }
  362. if(docDisp == NULL) __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  363. __MPC_EXIT_IF_METHOD_FAILS(hr, docDisp->QueryInterface( IID_IHTMLDocument2, (LPVOID*)&doc ));
  364. }
  365. }
  366. hr = S_OK;
  367. __MPC_FUNC_CLEANUP;
  368. __MPC_FUNC_EXIT(hr);
  369. }
  370. /////////////////////////////////////////////////////////////////////////////
  371. HRESULT MPC::HTML::GetFramePath( /*[out]*/ CComBSTR& bstrFrame ,
  372. /*[in] */ IDispatch* pDisp )
  373. {
  374. __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::GetFramePath" );
  375. HRESULT hr;
  376. CComPtr<IHTMLDocument2> pDoc;
  377. CComPtr<IHTMLWindow2> pWin;
  378. CComPtr<IHTMLWindow2> pTop;
  379. //
  380. // Get to the document and construct the recursive frame name.
  381. //
  382. __MPC_EXIT_IF_METHOD_FAILS(hr, IDispatch_To_IHTMLDocument2( pDoc, pDisp ));
  383. __MPC_EXIT_IF_METHOD_FAILS(hr, pDoc->get_parentWindow( &pWin )); if(pWin == NULL) __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  384. __MPC_EXIT_IF_METHOD_FAILS(hr, pWin->get_top ( &pTop )); if(pTop == NULL) __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  385. while(pWin != pTop)
  386. {
  387. CComPtr<IHTMLWindow2> pParent;
  388. CComBSTR bstrName;
  389. pWin->get_name( &bstrName );
  390. //
  391. // Concatenate the frame names, backward.
  392. //
  393. if(bstrFrame.Length())
  394. {
  395. bstrName += L"/";
  396. bstrName += bstrFrame;
  397. }
  398. bstrFrame = bstrName;
  399. __MPC_EXIT_IF_METHOD_FAILS(hr, pWin->get_parent( &pParent ));
  400. if(pParent == NULL) break;
  401. pWin = pParent;
  402. }
  403. hr = S_OK;
  404. __MPC_FUNC_CLEANUP;
  405. __MPC_FUNC_EXIT(hr);
  406. }
  407. HRESULT MPC::HTML::AreAllTheFramesInTheCompleteState( /*[out]*/ bool& fDone ,
  408. /*[in] */ IDispatch* pDisp )
  409. {
  410. __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::AreAllTheFramesInTheCompleteState" );
  411. HRESULT hr;
  412. CComPtr<IHTMLDocument2> pDoc;
  413. CComPtr<IHTMLFramesCollection2> pFrames;
  414. fDone = true;
  415. __MPC_EXIT_IF_METHOD_FAILS(hr, IDispatch_To_IHTMLDocument2( pDoc, pDisp ));
  416. __MPC_EXIT_IF_METHOD_FAILS(hr, pDoc->get_frames( &pFrames ));
  417. if(pFrames)
  418. {
  419. long len;
  420. __MPC_EXIT_IF_METHOD_FAILS(hr, pFrames->get_length( &len ));
  421. for(int i=0; i<len; i++)
  422. {
  423. CComVariant vIndex = i;
  424. CComVariant vValue;
  425. __MPC_EXIT_IF_METHOD_FAILS(hr, pFrames->item( &vIndex, &vValue ));
  426. if(vValue.vt == VT_DISPATCH)
  427. {
  428. CComQIPtr<IHTMLWindow2> fb = vValue.pdispVal;
  429. if(fb)
  430. {
  431. CComPtr<IHTMLDocument2> pDoc2;
  432. __MPC_EXIT_IF_METHOD_FAILS(hr, fb->get_document( &pDoc2 ));
  433. if(pDoc2)
  434. {
  435. CComBSTR bstrReadyState;
  436. __MPC_EXIT_IF_METHOD_FAILS(hr, pDoc2->get_readyState( &bstrReadyState ));
  437. if(MPC::StrICmp( bstrReadyState, L"complete" ) != 0)
  438. {
  439. fDone = false;
  440. break;
  441. }
  442. }
  443. }
  444. }
  445. }
  446. }
  447. hr = S_OK;
  448. __MPC_FUNC_CLEANUP;
  449. __MPC_FUNC_EXIT(hr);
  450. }
  451. ////////////////////////////////////////////////////////////////////////////////
  452. HRESULT MPC::HTML::LocateFrame( /*[out]*/ CComPtr<IHTMLWindow2>& win ,
  453. /*[in]*/ IHTMLElement* pObj ,
  454. /*[in]*/ LPCWSTR szName )
  455. {
  456. __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::LocateFrame" );
  457. HRESULT hr;
  458. CComPtr<IHTMLDocument2> doc;
  459. win.Release();
  460. __MPC_EXIT_IF_METHOD_FAILS(hr, IDispatch_To_IHTMLDocument2( doc, pObj ));
  461. if(szName && szName[0])
  462. {
  463. if(!_wcsicmp( szName, L"_top" ))
  464. {
  465. CComPtr<IHTMLWindow2> winCurrent;
  466. MPC_SCRIPTHELPER_GET__DIRECT__NOTNULL(winCurrent, doc , parentWindow);
  467. MPC_SCRIPTHELPER_GET__DIRECT__NOTNULL(win , winCurrent, top );
  468. }
  469. else
  470. {
  471. CComPtr<IHTMLFramesCollection2> frames;
  472. CComVariant vName( szName );
  473. CComVariant vFrame;
  474. __MPC_EXIT_IF_METHOD_FAILS(hr, doc->get_frames( &frames ));
  475. __MPC_EXIT_IF_METHOD_FAILS(hr, frames->item( &vName, &vFrame ));
  476. MPC_SCRIPTHELPER_FAIL_IF_NOT_AN_OBJECT(vFrame);
  477. __MPC_EXIT_IF_METHOD_FAILS(hr, vFrame.pdispVal->QueryInterface( __uuidof(IHTMLWindow2), (LPVOID*)&win ));
  478. }
  479. }
  480. else
  481. {
  482. MPC_SCRIPTHELPER_GET__DIRECT__NOTNULL(win, doc, parentWindow);
  483. }
  484. hr = S_OK;
  485. __MPC_FUNC_CLEANUP;
  486. __MPC_FUNC_EXIT(hr);
  487. }
  488. HRESULT MPC::HTML::GetEventObject( /*[out]*/ CComPtr<IHTMLEventObj>& ev ,
  489. /*[in] */ IHTMLElement* pObj )
  490. {
  491. __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::GetEventObject" );
  492. HRESULT hr;
  493. CComPtr<IHTMLDocument2> doc;
  494. CComPtr<IHTMLWindow2> win;
  495. ev.Release();
  496. __MPC_PARAMCHECK_BEGIN(hr)
  497. __MPC_PARAMCHECK_NOTNULL(pObj);
  498. __MPC_PARAMCHECK_END();
  499. __MPC_EXIT_IF_METHOD_FAILS(hr, IDispatch_To_IHTMLDocument2( doc, pObj ));
  500. __MPC_EXIT_IF_METHOD_FAILS(hr, doc->get_parentWindow( &win )); if(win == NULL) __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  501. MPC_SCRIPTHELPER_GET__DIRECT__NOTNULL(ev, win, event);
  502. hr = S_OK;
  503. __MPC_FUNC_CLEANUP;
  504. __MPC_FUNC_EXIT(hr);
  505. }
  506. HRESULT MPC::HTML::GetUniqueID( /*[out]*/ CComBSTR& bstrID, /*[in]*/ IHTMLElement* pObj )
  507. {
  508. return MPC::COMUtil::GetPropertyByName( pObj, L"uniqueID", bstrID );
  509. }
  510. HRESULT MPC::HTML::FindFirstParentWithThisTag( /*[out]*/ CComPtr<IHTMLElement>& elem ,
  511. /*[in] */ IHTMLElement* pObj ,
  512. /*[in]*/ LPCWSTR szTag )
  513. {
  514. __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::FindFirstParentWithThisTag" );
  515. HRESULT hr;
  516. elem.Release();
  517. __MPC_PARAMCHECK_BEGIN(hr)
  518. __MPC_PARAMCHECK_STRING_NOT_EMPTY(szTag);
  519. __MPC_PARAMCHECK_END();
  520. elem = pObj;
  521. while(elem)
  522. {
  523. CComBSTR bstrTag;
  524. CComPtr<IHTMLElement> parent;
  525. __MPC_EXIT_IF_METHOD_FAILS(hr, elem->get_tagName( &bstrTag ));
  526. if(!MPC::StrICmp( bstrTag, szTag )) break;
  527. __MPC_EXIT_IF_METHOD_FAILS(hr, elem->get_parentElement( &parent ));
  528. elem = parent;
  529. }
  530. hr = S_OK;
  531. __MPC_FUNC_CLEANUP;
  532. __MPC_FUNC_EXIT(hr);
  533. }
  534. HRESULT MPC::HTML::FindFirstParentWithThisID( /*[out]*/ CComPtr<IHTMLElement>& elem ,
  535. /*[in] */ IHTMLElement* pObj ,
  536. /*[in]*/ LPCWSTR szID )
  537. {
  538. __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::FindFirstParentWithThisTag" );
  539. HRESULT hr;
  540. elem = pObj;
  541. while(elem)
  542. {
  543. CComBSTR bstrID;
  544. CComPtr<IHTMLElement> parent;
  545. __MPC_EXIT_IF_METHOD_FAILS(hr, elem->get_id( &bstrID ));
  546. if(bstrID)
  547. {
  548. if(szID == NULL || !_wcsicmp( bstrID, szID ))
  549. {
  550. break;
  551. }
  552. }
  553. __MPC_EXIT_IF_METHOD_FAILS(hr, elem->get_parentElement( &parent ));
  554. elem = parent;
  555. }
  556. hr = S_OK;
  557. __MPC_FUNC_CLEANUP;
  558. __MPC_FUNC_EXIT(hr);
  559. }
  560. ////////////////////////////////////////////////////////////////////////////////
  561. HRESULT MPC::HTML::FindElementInCollection( /*[out]*/ CComPtr<IHTMLElement>& elem ,
  562. /*[in] */ IHTMLElementCollection* coll ,
  563. /*[in] */ LPCWSTR szID ,
  564. /*[in] */ int iPos )
  565. {
  566. __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::FindElementInCollection" );
  567. HRESULT hr;
  568. CComPtr<IDispatch> disp;
  569. CComVariant vName;
  570. CComVariant vIndex;
  571. elem.Release();
  572. __MPC_PARAMCHECK_BEGIN(hr)
  573. __MPC_PARAMCHECK_NOTNULL(coll);
  574. __MPC_PARAMCHECK_END();
  575. if(szID)
  576. {
  577. vName = szID;
  578. vIndex = iPos;
  579. }
  580. else
  581. {
  582. vName = iPos;
  583. }
  584. __MPC_EXIT_IF_METHOD_FAILS(hr, coll->item( vName, vIndex, &disp ));
  585. if(disp)
  586. {
  587. __MPC_EXIT_IF_METHOD_FAILS(hr, disp.QueryInterface( &elem ));
  588. }
  589. hr = S_OK;
  590. __MPC_FUNC_CLEANUP;
  591. __MPC_FUNC_EXIT(hr);
  592. }
  593. HRESULT MPC::HTML::FindElement( /*[out]*/ CComPtr<IHTMLElement>& elem ,
  594. /*[in] */ IHTMLElement* pObj ,
  595. /*[in] */ LPCWSTR szID ,
  596. /*[in] */ int iPos )
  597. {
  598. __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::FindElement" );
  599. HRESULT hr;
  600. CComPtr<IHTMLElementCollection> coll;
  601. __MPC_PARAMCHECK_BEGIN(hr)
  602. __MPC_PARAMCHECK_NOTNULL(pObj);
  603. __MPC_PARAMCHECK_END();
  604. MPC_SCRIPTHELPER_GET_OBJECT__NOTNULL(coll, pObj, all);
  605. __MPC_SET_ERROR_AND_EXIT(hr, FindElementInCollection( elem, coll, szID, iPos ));
  606. hr = S_OK;
  607. __MPC_FUNC_CLEANUP;
  608. __MPC_FUNC_EXIT(hr);
  609. }
  610. HRESULT MPC::HTML::FindChild( /*[out]*/ CComPtr<IHTMLElement>& elem ,
  611. /*[in] */ IHTMLElement* pObj ,
  612. /*[in] */ LPCWSTR szID ,
  613. /*[in] */ int iPos )
  614. {
  615. __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::FindChild" );
  616. HRESULT hr;
  617. CComPtr<IHTMLElementCollection> coll;
  618. __MPC_PARAMCHECK_BEGIN(hr)
  619. __MPC_PARAMCHECK_NOTNULL(pObj);
  620. __MPC_PARAMCHECK_END();
  621. MPC_SCRIPTHELPER_GET_OBJECT__NOTNULL(coll, pObj, children);
  622. __MPC_SET_ERROR_AND_EXIT(hr, FindElementInCollection( elem, coll, szID, iPos ));
  623. hr = S_OK;
  624. __MPC_FUNC_CLEANUP;
  625. __MPC_FUNC_EXIT(hr);
  626. }
  627. ////////////////////////////////////////////////////////////////////////////////
  628. HRESULT MPC::HTML::EnumerateCollection( /*[out]*/ IHTMLElementList& lst ,
  629. /*[in] */ IHTMLElementCollection* pColl ,
  630. /*[in] */ LPCWSTR szFilterID )
  631. {
  632. __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::EnumerateCollection" );
  633. HRESULT hr;
  634. long lLen;
  635. long lPos;
  636. CComVariant vName;
  637. CComVariant vIndex;
  638. bool fFilterAsTag;
  639. MPC::ReleaseAll( lst );
  640. __MPC_PARAMCHECK_BEGIN(hr)
  641. __MPC_PARAMCHECK_NOTNULL(pColl);
  642. __MPC_PARAMCHECK_END();
  643. if(szFilterID && szFilterID[0] == '<')
  644. {
  645. fFilterAsTag = true;
  646. szFilterID++;
  647. }
  648. else
  649. {
  650. fFilterAsTag = false;
  651. }
  652. MPC_SCRIPTHELPER_GET__DIRECT(lLen, pColl, length);
  653. for(lPos=0; lPos<lLen; lPos++)
  654. {
  655. CComPtr<IDispatch > disp;
  656. CComPtr<IHTMLElement> elem;
  657. vName = lPos;
  658. __MPC_EXIT_IF_METHOD_FAILS(hr, pColl->item( vName, vIndex, &disp ));
  659. if(disp == NULL) __MPC_SET_ERROR_AND_EXIT(hr, E_NOINTERFACE);
  660. __MPC_EXIT_IF_METHOD_FAILS(hr, disp.QueryInterface( &elem ));
  661. //
  662. // If we receive a string as input, filter out all the tags not matching with the ID or TAG.
  663. //
  664. if(szFilterID)
  665. {
  666. CComBSTR bstr;
  667. if(fFilterAsTag)
  668. {
  669. __MPC_EXIT_IF_METHOD_FAILS(hr, elem->get_tagName( &bstr ));
  670. }
  671. else
  672. {
  673. __MPC_EXIT_IF_METHOD_FAILS(hr, elem->get_id( &bstr ));
  674. }
  675. if(MPC::StrICmp( bstr, szFilterID )) continue;
  676. }
  677. lst.push_back( elem.Detach() );
  678. }
  679. hr = S_OK;
  680. __MPC_FUNC_CLEANUP;
  681. __MPC_FUNC_EXIT(hr);
  682. }
  683. HRESULT MPC::HTML::EnumerateElements( /*[out]*/ IHTMLElementList& lst ,
  684. /*[in] */ IHTMLElement* pObj ,
  685. /*[in] */ LPCWSTR szFilterID )
  686. {
  687. __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::EnumerateElements" );
  688. HRESULT hr;
  689. CComPtr<IHTMLElementCollection> coll;
  690. __MPC_PARAMCHECK_BEGIN(hr)
  691. __MPC_PARAMCHECK_NOTNULL(pObj);
  692. __MPC_PARAMCHECK_END();
  693. MPC_SCRIPTHELPER_GET_OBJECT__NOTNULL(coll, pObj, all);
  694. __MPC_EXIT_IF_METHOD_FAILS(hr, EnumerateCollection( lst, coll, szFilterID ));
  695. hr = S_OK;
  696. __MPC_FUNC_CLEANUP;
  697. __MPC_FUNC_EXIT(hr);
  698. }
  699. HRESULT MPC::HTML::EnumerateChildren( /*[out]*/ IHTMLElementList& lst ,
  700. /*[in] */ IHTMLElement* pObj ,
  701. /*[in] */ LPCWSTR szFilterID )
  702. {
  703. __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::EnumerateChildren" );
  704. HRESULT hr;
  705. CComPtr<IHTMLElementCollection> coll;
  706. __MPC_PARAMCHECK_BEGIN(hr)
  707. __MPC_PARAMCHECK_NOTNULL(pObj);
  708. __MPC_PARAMCHECK_END();
  709. MPC_SCRIPTHELPER_GET_OBJECT__NOTNULL(coll, pObj, children);
  710. __MPC_EXIT_IF_METHOD_FAILS(hr, EnumerateCollection( lst, coll, szFilterID ));
  711. hr = S_OK;
  712. __MPC_FUNC_CLEANUP;
  713. __MPC_FUNC_EXIT(hr);
  714. }
  715. ////////////////////////////////////////////////////////////////////////////////
  716. HRESULT MPC::HTML::FindStyle( /*[out]*/ CComPtr<IHTMLRuleStyle>& style ,
  717. /*[in ]*/ IHTMLElement* pObj ,
  718. /*[in ]*/ LPCWSTR szName )
  719. {
  720. __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::FindStyle" );
  721. HRESULT hr;
  722. CComPtr<IHTMLDocument2> doc;
  723. CComPtr<IHTMLStyleSheetsCollection> styles;
  724. VARIANT vIdx;
  725. long lNumStyles;
  726. __MPC_EXIT_IF_METHOD_FAILS(hr, IDispatch_To_IHTMLDocument2( doc, pObj ));
  727. MPC_SCRIPTHELPER_GET__DIRECT__NOTNULL(styles , doc , styleSheets);
  728. MPC_SCRIPTHELPER_GET__DIRECT (lNumStyles, styles, length );
  729. vIdx.vt = VT_I4;
  730. for(vIdx.iVal=0; vIdx.iVal<lNumStyles; vIdx.iVal++)
  731. {
  732. CComQIPtr<IHTMLStyleSheet> css;
  733. CComVariant v;
  734. __MPC_EXIT_IF_METHOD_FAILS(hr, styles->item( &vIdx, &v ));
  735. if(v.vt == VT_DISPATCH && (css = v.pdispVal))
  736. {
  737. CComPtr<IHTMLStyleSheetRulesCollection> rules;
  738. long lNumRules;
  739. MPC_SCRIPTHELPER_GET__DIRECT__NOTNULL(rules , css , rules );
  740. MPC_SCRIPTHELPER_GET__DIRECT (lNumRules, rules, length);
  741. for(long l=0; l<lNumRules; l++)
  742. {
  743. CComPtr<IHTMLStyleSheetRule> rule;
  744. __MPC_EXIT_IF_METHOD_FAILS(hr, rules->item( l, &rule ));
  745. if(rule)
  746. {
  747. CComBSTR bstrName;
  748. MPC_SCRIPTHELPER_GET__DIRECT(bstrName, rule, selectorText);
  749. if(!MPC::StrICmp( bstrName, szName ))
  750. {
  751. __MPC_SET_ERROR_AND_EXIT(hr, rule->get_style( &style ));
  752. }
  753. }
  754. }
  755. }
  756. }
  757. hr = S_OK;
  758. __MPC_FUNC_CLEANUP;
  759. __MPC_FUNC_EXIT(hr);
  760. }
  761. ////////////////////////////////////////////////////////////////////////////////
  762. HRESULT MPC::HTML::GetAttribute( /*[out]*/ CComPtr<IHTMLDOMAttribute>& attr ,
  763. /*[in]*/ IHTMLElement* pObj ,
  764. /*[in]*/ LPCWSTR szName )
  765. {
  766. __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::GetAttribute" );
  767. HRESULT hr;
  768. CComPtr<IHTMLDOMNode> dom;
  769. CComPtr<IHTMLAttributeCollection> coll;
  770. CComPtr<IDispatch> dispAttr;
  771. CComVariant v( szName );
  772. __MPC_PARAMCHECK_BEGIN(hr)
  773. __MPC_PARAMCHECK_NOTNULL(pObj);
  774. __MPC_PARAMCHECK_END();
  775. attr.Release();
  776. __MPC_EXIT_IF_METHOD_FAILS(hr, pObj->QueryInterface( IID_IHTMLDOMNode, (LPVOID *)&dom ));
  777. MPC_SCRIPTHELPER_GET_OBJECT__NOTNULL(coll, dom, attributes);
  778. __MPC_EXIT_IF_METHOD_FAILS(hr, coll->item( &v, &dispAttr ));
  779. if(dispAttr)
  780. {
  781. __MPC_EXIT_IF_METHOD_FAILS(hr, dispAttr->QueryInterface( &attr ));
  782. }
  783. hr = S_OK;
  784. __MPC_FUNC_CLEANUP;
  785. __MPC_FUNC_EXIT(hr);
  786. }
  787. HRESULT MPC::HTML::GetAttribute( /*[out]*/ CComBSTR& value ,
  788. /*[in]*/ IHTMLElement* pObj ,
  789. /*[in]*/ LPCWSTR szName )
  790. {
  791. __MPC_FUNC_ENTRY( COMMONID, "MPC::HTML::GetAttribute" );
  792. HRESULT hr;
  793. CComPtr<IHTMLDOMAttribute> attr;
  794. value.Empty();
  795. __MPC_EXIT_IF_METHOD_FAILS(hr, GetAttribute( attr, pObj, szName ));
  796. if(attr)
  797. {
  798. MPC_SCRIPTHELPER_GET_STRING__VARIANT(value, attr, nodeValue);
  799. }
  800. hr = S_OK;
  801. __MPC_FUNC_CLEANUP;
  802. __MPC_FUNC_EXIT(hr);
  803. }
  804. ////////////////////////////////////////////////////////////////////////////////
  805. typedef struct
  806. {
  807. const WCHAR* szName;
  808. DWORD dwValue;
  809. } COLORVALUE_PAIR;
  810. static const COLORVALUE_PAIR c_rgColorNames[] =
  811. {
  812. { L"aliceblue" , 0xfff8f0 },
  813. { L"antiquewhite" , 0xd7ebfa },
  814. { L"aqua" , 0xffff00 },
  815. { L"aquamarine" , 0xd4ff7f },
  816. { L"azure" , 0xfffff0 },
  817. { L"beige" , 0xdcf5f5 },
  818. { L"bisque" , 0xc4e4ff },
  819. { L"black" , 0x000000 },
  820. { L"blanchedalmond" , 0xcdebff },
  821. { L"blue" , 0xff0000 },
  822. { L"blueviolet" , 0xe22b8a },
  823. { L"brown" , 0x2a2aa5 },
  824. { L"burlywood" , 0x87b8de },
  825. { L"cadetblue" , 0xa09e5f },
  826. { L"chartreuse" , 0x00ff7f },
  827. { L"chocolate" , 0x1e69d2 },
  828. { L"coral" , 0x507fff },
  829. { L"cornflowerblue" , 0xed9564 },
  830. { L"cornsilk" , 0xdcf8ff },
  831. { L"crimson" , 0x3c14dc },
  832. { L"cyan" , 0xffff00 },
  833. { L"darkblue" , 0x8b0000 },
  834. { L"darkcyan" , 0x8b8b00 },
  835. { L"darkgoldenrod" , 0x0b86b8 },
  836. { L"darkgray" , 0xa9a9a9 },
  837. { L"darkgreen" , 0x006400 },
  838. { L"darkkhaki" , 0x6bb7bd },
  839. { L"darkmagenta" , 0x8b008b },
  840. { L"darkolivegreen" , 0x2f6b55 },
  841. { L"darkorange" , 0x008cff },
  842. { L"darkorchid" , 0xcc3299 },
  843. { L"darkred" , 0x00008b },
  844. { L"darksalmon" , 0x7a96e9 },
  845. { L"darkseagreen" , 0x8fbc8f },
  846. { L"darkslateblue" , 0x8b3d48 },
  847. { L"darkslategray" , 0x4f4f2f },
  848. { L"darkturquoise" , 0xd1ce00 },
  849. { L"darkviolet" , 0xd30094 },
  850. { L"deeppink" , 0x9314ff },
  851. { L"deepskyblue" , 0xffbf00 },
  852. { L"dimgray" , 0x696969 },
  853. { L"dodgerblue" , 0xff901e },
  854. { L"firebrick" , 0x2222b2 },
  855. { L"floralwhite" , 0xf0faff },
  856. { L"forestgreen" , 0x228b22 },
  857. { L"fuchsia" , 0xff00ff },
  858. { L"gainsboro" , 0xdcdcdc },
  859. { L"ghostwhite" , 0xfff8f8 },
  860. { L"gold" , 0x00d7ff },
  861. { L"goldenrod" , 0x20a5da },
  862. { L"gray" , 0x808080 },
  863. { L"green" , 0x008000 },
  864. { L"greenyellow" , 0x2fffad },
  865. { L"honeydew" , 0xf0fff0 },
  866. { L"hotpink" , 0xb469ff },
  867. { L"indianred" , 0x5c5ccd },
  868. { L"indigo" , 0x82004b },
  869. { L"ivory" , 0xf0ffff },
  870. { L"khaki" , 0x8ce6f0 },
  871. { L"lavender" , 0xfae6e6 },
  872. { L"lavenderblush" , 0xf5f0ff },
  873. { L"lawngreen" , 0x00fc7c },
  874. { L"lemonchiffon" , 0xcdfaff },
  875. { L"lightblue" , 0xe6d8ad },
  876. { L"lightcoral" , 0x8080f0 },
  877. { L"lightcyan" , 0xffffe0 },
  878. { L"lightgoldenrodyellow", 0xd2fafa },
  879. { L"lightgreen" , 0x90ee90 },
  880. { L"lightgrey" , 0xd3d3d3 },
  881. { L"lightpink" , 0xc1b6ff },
  882. { L"lightsalmon" , 0x7aa0ff },
  883. { L"lightseagreen" , 0xaab220 },
  884. { L"lightskyblue" , 0xface87 },
  885. { L"lightslategray" , 0x998877 },
  886. { L"lightsteelblue" , 0xdec4b0 },
  887. { L"lightyellow" , 0xe0ffff },
  888. { L"lime" , 0x00ff00 },
  889. { L"limegreen" , 0x32cd32 },
  890. { L"linen" , 0xe6f0fa },
  891. { L"magenta" , 0xff00ff },
  892. { L"maroon" , 0x000080 },
  893. { L"mediumaquamarine" , 0xaacd66 },
  894. { L"mediumblue" , 0xcd0000 },
  895. { L"mediumorchid" , 0xd355ba },
  896. { L"mediumpurple" , 0xdb7093 },
  897. { L"mediumseagreen" , 0x71b33c },
  898. { L"mediumslateblue" , 0xee687b },
  899. { L"mediumspringgreen" , 0x9afa00 },
  900. { L"mediumturquoise" , 0xccd148 },
  901. { L"mediumvioletred" , 0x8515c7 },
  902. { L"midnightblue" , 0x701919 },
  903. { L"mintcream" , 0xfafff5 },
  904. { L"mistyrose" , 0xe1e4ff },
  905. { L"moccasin" , 0xb5e4ff },
  906. { L"navajowhite" , 0xaddeff },
  907. { L"navy" , 0x800000 },
  908. { L"oldlace" , 0xe6f5fd },
  909. { L"olive" , 0x008080 },
  910. { L"olivedrab" , 0x238e6b },
  911. { L"orange" , 0x00a5ff },
  912. { L"orangered" , 0x0045ff },
  913. { L"orchid" , 0xd670da },
  914. { L"palegoldenrod" , 0xaae8ee },
  915. { L"palegreen" , 0x98fb98 },
  916. { L"paleturquoise" , 0xeeeeaf },
  917. { L"palevioletred" , 0x9370db },
  918. { L"papayawhip" , 0xd5efff },
  919. { L"peachpuff" , 0xb9daff },
  920. { L"peru" , 0x3f85cd },
  921. { L"pink" , 0xcbc0ff },
  922. { L"plum" , 0xdda0dd },
  923. { L"powderblue" , 0xe6e0b0 },
  924. { L"purple" , 0x800080 },
  925. { L"red" , 0x0000ff },
  926. { L"rosybrown" , 0x8f8fbc },
  927. { L"royalblue" , 0xe16941 },
  928. { L"saddlebrown" , 0x13458b },
  929. { L"salmon" , 0x7280fa },
  930. { L"sandybrown" , 0x60a4f4 },
  931. { L"seagreen" , 0x578b2e },
  932. { L"seashell" , 0xeef5ff },
  933. { L"sienna" , 0x2d52a0 },
  934. { L"silver" , 0xc0c0c0 },
  935. { L"skyblue" , 0xebce87 },
  936. { L"slateblue" , 0xcd5a6a },
  937. { L"slategray" , 0x908070 },
  938. { L"snow" , 0xfafaff },
  939. { L"springgreen" , 0x7fff00 },
  940. { L"steelblue" , 0xb48246 },
  941. { L"tan" , 0x8cb4d2 },
  942. { L"teal" , 0x808000 },
  943. { L"thistle" , 0xd8bfd8 },
  944. { L"tomato" , 0x4763ff },
  945. { L"turquoise" , 0xd0e040 },
  946. { L"violet" , 0xee82ee },
  947. { L"wheat" , 0xb3def5 },
  948. { L"white" , 0xffffff },
  949. { L"whitesmoke" , 0xf5f5f5 },
  950. { L"yellow" , 0x00ffff },
  951. { L"yellowgreen" , 0x32cd9a }
  952. };
  953. static const COLORVALUE_PAIR c_rgSystemColors[] =
  954. {
  955. { L"activeborder" , COLOR_ACTIVEBORDER },
  956. { L"activecaption" , COLOR_ACTIVECAPTION },
  957. { L"appworkspace" , COLOR_APPWORKSPACE },
  958. { L"background" , COLOR_BACKGROUND },
  959. { L"buttonface" , COLOR_BTNFACE },
  960. { L"buttonhighlight" , COLOR_BTNHIGHLIGHT },
  961. { L"buttonshadow" , COLOR_BTNSHADOW },
  962. { L"buttontext" , COLOR_BTNTEXT },
  963. { L"captiontext" , COLOR_CAPTIONTEXT },
  964. { L"gradientactivecaption" , COLOR_GRADIENTACTIVECAPTION },
  965. { L"gradientinactivecaption", COLOR_GRADIENTINACTIVECAPTION },
  966. { L"graytext" , COLOR_GRAYTEXT },
  967. { L"highlight" , COLOR_HIGHLIGHT },
  968. { L"highlighttext" , COLOR_HIGHLIGHTTEXT },
  969. { L"hotlight" , COLOR_HOTLIGHT },
  970. { L"inactiveborder" , COLOR_INACTIVEBORDER },
  971. { L"inactivecaption" , COLOR_INACTIVECAPTION },
  972. { L"inactivecaptiontext" , COLOR_INACTIVECAPTIONTEXT },
  973. { L"infobackground" , COLOR_INFOBK },
  974. { L"infotext" , COLOR_INFOTEXT },
  975. { L"menu" , COLOR_MENU },
  976. { L"menutext" , COLOR_MENUTEXT },
  977. { L"scrollbar" , COLOR_SCROLLBAR },
  978. { L"threeddarkshadow" , COLOR_3DDKSHADOW },
  979. { L"threedface" , COLOR_3DFACE },
  980. { L"threedhighlight" , COLOR_3DHIGHLIGHT },
  981. { L"threedlightshadow" , COLOR_3DLIGHT },
  982. { L"threedshadow" , COLOR_3DSHADOW },
  983. { L"window" , COLOR_WINDOW },
  984. { L"windowframe" , COLOR_WINDOWFRAME },
  985. { L"windowtext" , COLOR_WINDOWTEXT },
  986. };
  987. static const COLORVALUE_PAIR* local_LookupName( /*[in]*/ const COLORVALUE_PAIR* tbl ,
  988. /*[in]*/ int iSize ,
  989. /*[in]*/ LPCWSTR szText )
  990. {
  991. while(iSize-- > 0)
  992. {
  993. if(!_wcsicmp( tbl->szName, szText )) return tbl;
  994. tbl++;
  995. }
  996. return NULL;
  997. }
  998. bool MPC::HTML::ConvertColor( /*[in]*/ VARIANT& v, /*[out]*/ COLORREF& color, /*[out]*/ bool& fSystem )
  999. {
  1000. color = RGB(255,255,255);
  1001. fSystem = false;
  1002. if(v.vt == VT_I4)
  1003. {
  1004. color = (COLORREF)v.iVal;
  1005. return true;
  1006. }
  1007. if(v.vt == VT_BSTR && v.bstrVal)
  1008. {
  1009. const COLORVALUE_PAIR* ptr;
  1010. ptr = local_LookupName( c_rgColorNames, ARRAYSIZE(c_rgColorNames), v.bstrVal );
  1011. if(ptr)
  1012. {
  1013. color = (COLORREF)ptr->dwValue;
  1014. return true;
  1015. }
  1016. ptr = local_LookupName( c_rgSystemColors, ARRAYSIZE(c_rgSystemColors), v.bstrVal );
  1017. if(ptr)
  1018. {
  1019. color = (COLORREF)::GetSysColor( ptr->dwValue );
  1020. fSystem = true;
  1021. return true;
  1022. }
  1023. if(v.bstrVal[0] == '#')
  1024. {
  1025. int iRED;
  1026. int iGREEN;
  1027. int iBLUE;
  1028. if(swscanf( &v.bstrVal[1], L"%02x%02x%02x", &iRED, &iGREEN, &iBLUE ) == 3)
  1029. {
  1030. color = RGB( iRED, iGREEN, iBLUE );
  1031. return true;
  1032. }
  1033. }
  1034. }
  1035. return false;
  1036. }