コード例 #1
0
/*-----------------------------------------------------------------------------
	Locate the first HTML element on the DOM of any of the browsers that
	matches the attribute we're looking for
	The attrVal contains a concatenated attribute and value in attribute=value form
-----------------------------------------------------------------------------*/
CComPtr<IHTMLElement> CPagetestBase::FindDomElementByAttribute(CString attrVal)
{
	CComPtr<IHTMLElement> result;

	CString attribute = _T("id");
	CString value = attrVal;
	value.Trim();
	
	// = or ' are delimiters for a direct full comparison
	int index = attrVal.Find('=');
	if( index == -1 )
		index = attrVal.Find('\'');
	
	// < is the delimiter to compare the left of the string
	int index2 = attrVal.Find('<');
	attrOperator op = equal;
	if( index2 != -1 && (index2 < index || index == -1) )
	{
		index = index2;
		op = left;
	}

	// ^ is the delimiter to do a substring match
	int index3 = attrVal.Find('^');
	if( index3 != -1 && (index3 < index || index == -1) && (index3 < index2 || index2 == -1) )
	{
		index = index3;
		op = mid;
	}
	
	if( index != -1 )
	{
		attribute = attrVal.Left(index);
		value = attrVal.Right(attrVal.GetLength() - index - 1);
		value.Trim();
		value.Trim(_T("\""));	// allow for the value to be in quotes
	}
	
	// see if there is a specific tag we're looking for - i.e. div:xxx=yy or A:xxx=yy
	index = attribute.Find(':');
	CString tag;
	if( index != -1 )
	{
		tag = attribute.Left(index);
		attribute = attribute.Right(attribute.GetLength() - index - 1);
	}
	
	attribute.Trim();
	
	result = FindDomElementByAttribute(tag, attribute, value, op);
	
	return result;
}
コード例 #2
0
/*-----------------------------------------------------------------------------
	Locate the first HTML element on the DOM of any of the browsers that
	matches the attribute we're looking for
-----------------------------------------------------------------------------*/
CComPtr<IHTMLElement> CPagetestBase::FindDomElementByAttribute(CString &tag, CString &attribute, CString &value, attrOperator &op)
{
	CComPtr<IHTMLElement> result;
	
	POSITION pos = browsers.GetHeadPosition();
	while(pos && !result)
	{
		CBrowserTracker tracker = browsers.GetNext(pos);
		if( tracker.threadId == GetCurrentThreadId() && tracker.browser )
		{
			CComPtr<IDispatch> spDoc;
			if( SUCCEEDED(tracker.browser->get_Document(&spDoc)) && spDoc )
			{
				CComQIPtr<IHTMLDocument2> doc = spDoc;
        if( doc )
				  result = FindDomElementByAttribute(tag, attribute, value, op, doc);
			}
		}
	}
	
	return result;
}
コード例 #3
0
/*-----------------------------------------------------------------------------
	Locate the first HTML element on the DOM in the given document that
	matches the attribute we're looking for
	
	This will recursively search any frames within the document
-----------------------------------------------------------------------------*/
CComPtr<IHTMLElement> CPagetestBase::FindDomElementByAttribute(CString &tag, CString &attribute, CString &value, attrOperator &op, CComPtr<IHTMLDocument2> doc)
{
	CComPtr<IHTMLElement> result;
	CComBSTR attrib(attribute);
	
	bool innerText = false;
	bool innerHtml = false;
	bool sourceIndex = false;
	if( !attribute.CompareNoCase(_T("innerText")) )
		innerText = true;
	else if( !attribute.CompareNoCase(_T("innerHtml")) )
		innerHtml = true;
	else if( !attribute.CompareNoCase(_T("sourceIndex")) )
		sourceIndex = true;

	// force class to className (it's a special case where the attribute is different on the DOM)
	if( !attribute.CompareNoCase(_T("class")) )
		attribute = _T("className");

	if( doc )
	{
		// get all of the elements
		if( !result )
		{
			bool ok = false;
			if( !sourceIndex && !innerText && !innerHtml && op == equal && tag.IsEmpty() && (!attribute.CompareNoCase(_T("id"))) )
			{
				CComQIPtr<IHTMLDocument3> doc3 = doc;
				if( doc3 )
				{
					ok = true;
					_bstr_t val = value;
					
					doc3->getElementById(val, &result);
				}
			}

			if( !ok )
			{
				// have to manually walk all of the elements
				CComPtr<IHTMLElementCollection> coll;
				ok = false;
				
				// if we're looking for name, short-cut and do a direct search
				if( !tag.IsEmpty() || (!attribute.CompareNoCase(_T("name")) && op == equal) )
				{
					CComQIPtr<IHTMLDocument3> doc3 = doc;
					if( doc3 )
					{
						ok = true;
						if( !attribute.CompareNoCase(_T("name")) && op == equal )
						{
							_bstr_t name = value;
							doc3->getElementsByName(name, &coll);
						}
						else if( !tag.IsEmpty() )
						{
							_bstr_t tagName = tag;
							doc3->getElementsByTagName(tagName, &coll);
						}
					}
				}
				
				if( !ok )
					if( SUCCEEDED(doc->get_all(&coll)) )
						ok = true;
				
				if( ok && coll )
				{
					long count = 0;
					if( SUCCEEDED(coll->get_length(&count)) )
					{
						for( long i = 0; i < count && !result; i++ )
						{
							_variant_t index = i;
							CComPtr<IDispatch> item;
							if( SUCCEEDED(coll->item(index, index, &item)) && item )
							{
								CComQIPtr<IHTMLElement> element = item;
								if( element )
								{
									ok = false;
									
									// see if we're looking for a particular element type
									if( tag.IsEmpty() )
										ok = true;
									else
									{
										_bstr_t elementTag;
										if( SUCCEEDED(element->get_tagName(elementTag.GetAddress())) )
										{
											CString elTag = elementTag;
											if( !tag.CompareNoCase(elTag) )
												ok = true;
										}
									}
									
									if( ok )
									{								
										_variant_t varVal;
										_bstr_t text;
										
										if( sourceIndex )
										{
											long index;
											if( SUCCEEDED(element->get_sourceIndex(&index)) )
											{
												long lValue = _ttol(value);
												if( index == lValue )
													result = element;
											}
										}
										else
										{
											if( innerText )
												element->get_innerText(text.GetAddress());
											else if (innerHtml)
												element->get_innerHTML(text.GetAddress());
											else if( SUCCEEDED(element->getAttribute(attrib, 0, &varVal)) )
											{
												if( varVal.vt != VT_EMPTY && varVal.vt != VT_NULL && varVal.vt != VT_ERROR )
													text = (_bstr_t)varVal;
											}

											CString val = text;
											val.Trim();
											if( val.GetLength() )
											{
												switch( op )
												{
													case equal:
														{
															if( val == value )
																result = element;
														}break;
													
													case left:
														{
															if( val.Left(value.GetLength()) == value )
																result = element;
														}break;

													case mid:
														{
															if( val.Find(value) > -1 )
																result = element;
														}break;
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}

		// recursively check in any iFrames
		if( !result )
		{
			// walk all of the frames on the document
			CComPtr<IHTMLFramesCollection2> frames;
			if( SUCCEEDED(doc->get_frames(&frames)) && frames )
			{
				// for each frame, walk all of the elements in the frame
				long count = 0;
				if( SUCCEEDED(frames->get_length(&count)) )
				{
					for( long i = 0; i < count && !result; i++ )
					{
						_variant_t index = i;
						_variant_t varFrame;
						
						if( SUCCEEDED(frames->item(&index, &varFrame)) )
						{
							CComQIPtr<IHTMLWindow2> window(varFrame);
							if( window )
							{
								CComQIPtr<IHTMLDocument2> frameDoc;
								frameDoc = HtmlWindowToHtmlDocument(window);
								if( frameDoc )
									result = FindDomElementByAttribute(tag, attribute, value, op, frameDoc);
							}
						}
					}
				}
			}
		}
	}
	
	return result;
}
コード例 #4
0
ファイル: PagetestBase.cpp プロジェクト: Trott/webpagetest
/*-----------------------------------------------------------------------------
	Locate the first HTML element on the DOM in the given document that
	matches the attribute we're looking for
	
	This will recursively search any frames within the document
-----------------------------------------------------------------------------*/
CComPtr<IHTMLElement> CPagetestBase::FindDomElementByAttribute(CString &tag, CString &attribute, CString &value, attrOperator &op, CComPtr<IHTMLDocument2> doc)
{
	CComPtr<IHTMLElement> result;
	CComBSTR attrib(attribute);
	
	bool innerText = false;
	bool innerHtml = false;
	bool sourceIndex = false;
	if( !attribute.CompareNoCase(_T("innerText")) )
		innerText = true;
	else if( !attribute.CompareNoCase(_T("innerHtml")) )
		innerHtml = true;
	else if( !attribute.CompareNoCase(_T("sourceIndex")) )
		sourceIndex = true;

	// force class to className (it's a special case where the attribute is different on the DOM)
	if( !attribute.CompareNoCase(_T("class")) )
		attribute = _T("className");

	if( doc )
	{
		// get all of the elements
		if( !result )
		{
			bool ok = false;
			if( !sourceIndex && !innerText && !innerHtml && op == equal && tag.IsEmpty() && (!attribute.CompareNoCase(_T("id"))) )
			{
				CComQIPtr<IHTMLDocument3> doc3 = doc;
				if( doc3 )
				{
					ok = true;
					_bstr_t val = value;
					
					doc3->getElementById(val, &result);
				}
			}

			if( !ok )
			{
				// have to manually walk all of the elements
				CComPtr<IHTMLElementCollection> coll;
				ok = false;
				
				// if we're looking for name, short-cut and do a direct search
				if( !tag.IsEmpty() || (!attribute.CompareNoCase(_T("name")) && op == equal) )
				{
					CComQIPtr<IHTMLDocument3> doc3 = doc;
					if( doc3 )
					{
						ok = true;
						if( !attribute.CompareNoCase(_T("name")) && op == equal )
						{
							_bstr_t name = value;
							doc3->getElementsByName(name, &coll);
						}
						else if( !tag.IsEmpty() )
						{
							_bstr_t tagName = tag;
							doc3->getElementsByTagName(tagName, &coll);
						}
					}
				}
				
				if( !ok )
					if( SUCCEEDED(doc->get_all(&coll)) )
						ok = true;
				
				if( ok && coll )
				{
					long count = 0;
					if( SUCCEEDED(coll->get_length(&count)) )
					{
						for( long i = 0; i < count && !result; i++ )
						{
							_variant_t index = i;
							CComPtr<IDispatch> item;
							if( SUCCEEDED(coll->item(index, index, &item)) && item )
							{
								CComQIPtr<IHTMLElement> element = item;
								if( element )
								{
									ok = false;
									
									// see if we're looking for a particular element type
									if( tag.IsEmpty() )
										ok = true;
									else
									{
										_bstr_t elementTag;
										if( SUCCEEDED(element->get_tagName(elementTag.GetAddress())) )
										{
											CString elTag = elementTag;
											if( !tag.CompareNoCase(elTag) )
												ok = true;
										}
									}
									
									if( ok )
									{								
										_variant_t varVal;
										_bstr_t text;
										
										if( sourceIndex )
										{
											long index;
											if( SUCCEEDED(element->get_sourceIndex(&index)) )
											{
												long lValue = _ttol(value);
												if( index == lValue )
													result = element;
											}
										}
										else
										{
											if( innerText )
												element->get_innerText(text.GetAddress());
											else if (innerHtml)
												element->get_innerHTML(text.GetAddress());
											else if( SUCCEEDED(element->getAttribute(attrib, 0, &varVal)) )
											{
												if( varVal.vt != VT_EMPTY && varVal.vt != VT_NULL && varVal.vt != VT_ERROR )
													text = (_bstr_t)varVal;
											}

											CString val = text;
											val.Trim();
											if( val.GetLength() )
											{
												switch( op )
												{
													case equal:
														{
															if( val == value )
																result = element;
														}break;
													
													case left:
														{
															if( val.Left(value.GetLength()) == value )
																result = element;
														}break;

													case mid:
														{
															if( val.Find(value) > -1 )
																result = element;
														}break;
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}

		// walk the IFrames using OLE (to bypass security blocks)
		if( !result )
		{
			// walk all of the frames on the document
			// this is a little complicated because we need to bypass cross site scripting security
			CComQIPtr<IOleContainer> ole(doc);
			if(ole)
			{
				CComPtr<IEnumUnknown> objects;

				// Get an enumerator for the frames
				if( SUCCEEDED(ole->EnumObjects(OLECONTF_EMBEDDINGS, &objects)) && objects )
				{
					IUnknown* pUnk;
					ULONG uFetched;

					// Enumerate all the frames
					while( !result && S_OK == objects->Next(1, &pUnk, &uFetched) )
					{
						// QI for IWebBrowser here to see if we have an embedded browser
						CComQIPtr<IWebBrowser2> browser(pUnk);
						pUnk->Release();

						if (browser)
						{
							CComPtr<IDispatch> disp;
							if( SUCCEEDED(browser->get_Document(&disp)) && disp )
							{
								CComQIPtr<IHTMLDocument2> frameDoc(disp);
								if (frameDoc)
									result = FindDomElementByAttribute(tag, attribute, value, op, frameDoc);
							}
						}
					}
				}
			}			
		}

		// walk the IFrames diriectly (the OLE way doesn't appear to always work)
		if( !result )
		{
			// walk all of the frames on the document
			CComPtr<IHTMLFramesCollection2> frames;
			if( SUCCEEDED(doc->get_frames(&frames)) && frames )
			{
				// for each frame, walk all of the elements in the frame
				long count = 0;
				if( SUCCEEDED(frames->get_length(&count)) )
				{
					for( long i = 0; i < count && !result; i++ )
					{
						_variant_t index = i;
						_variant_t varFrame;
						
						if( SUCCEEDED(frames->item(&index, &varFrame)) )
						{
							CComQIPtr<IHTMLWindow2> window(varFrame);
							if( window )
							{
								CComQIPtr<IHTMLDocument2> frameDoc;
								if( SUCCEEDED(window->get_document(&frameDoc)) && frameDoc )
									result = FindDomElementByAttribute(tag, attribute, value, op, frameDoc);
							}
						}
					}
				}
			}
		}
	}
	
	return result;
}