Мы использовали интерфейс сценариев IHTMLElement и IHTMLElement2 для доступа к веб-объектам и их свойствам. Сейчас мы находимся в ситуации, когда хотим знать клиентскую область, занятую элементом, за вычетом любой области, занятой границами и полосами прокрутки. Я наткнулся на класс HTMLDocument, который имеет метод ClientRectangle (). Его документация звучит очень похоже на то, на что мы смотрим. Я действительно не уверен, как мне получить доступ к этому методу, если это возможно.
Кто-нибудь может дать понять, возможно ли создать экземпляр этого класса HTMLDocument и получить доступ к его методам?
Ссылка на документацию MSDN класса о чем я говорю.
http://msdn.microsoft.com/en-us/library/system.windows.forms.htmlelement.clientrectangle.aspx?cs-save-lang=1&CS-Ланг = каст # код-сниппет-1
Поскольку ваш вопрос является довольно широким решением, я предоставляю его несколько большим, но полным и проверенным. Если у вас уже есть указатель на действительный объект IHTMLDocument или IHTMLElement, вы можете довольно легко получить местоположение и размеры элемента. Единственное требование для получения измерений состоит в том, что документ должен быть присоединен к объекту IHTMLWindow / IWebBrowser. Я включил функцию stand-by, которая создает объекты IWebBrowser и IHTMLDocument для тестирования.
Я добавил несколько комментариев, чтобы помочь вам в этом. Это было протестировано с Visual Studio 2010 в системе Windows 7 с Internet Explorer 9. Это набор результатов, который я получаю из примера:
Rect = x = 8 y = 89 ширина = 992 высота = 31
Содержание = Привет
#include <comutil.h> // _bstr_t
#include <mshtml.h> // IHTMLDocument and IHTMLElement
#include <exdisp.h> // IWebBrowser2
#include <atlbase.h> // CComPtr
#include <string>
#include <iostream>
// Make sure we link in the support library!
#pragma comment(lib, "comsuppw.lib")
static const std::wstring
exampleHtml(L"<body><html><br><br><p id=\"someid\">hello</p></body>");
HRESULT CreateBrowserDocument(
const std::wstring& html,
CComPtr<IWebBrowser2>& returnBrowser,
CComPtr<IHTMLDocument3>& returnDoc);int main()
{
///////////////////////////////////////////////////////////////////////////
// In order to get the position and dimension of an element we need to
// have a browser object that owns the document we will work on. If you
// create and use a IHTMLDocument object through CoCreateInstance it does
// not have any rendering capabilities by default.
///////////////////////////////////////////////////////////////////////////
HRESULT hr;
hr = CoInitialize(NULL);
if(SUCCEEDED(hr))
{
// Make sure these two items are scoped so CoUninitialize doesn't gump
// us up.
CComPtr<IWebBrowser2> browser;
CComPtr<IHTMLDocument3> document;
hr = CreateBrowserDocument(exampleHtml, browser, document);
if(SUCCEEDED(hr))
{
CComPtr<IHTMLElement> element;
///////////////////////////////////////////////////////////////////
// We grab the element by id to make the example easier. in some
// cases you may need to iterate through all of the elements of the
// document or parent element to find the one you want the
// dimensions for.
///////////////////////////////////////////////////////////////////
hr = document->getElementById(_bstr_t(L"someid"), &element);
if(SUCCEEDED(hr) && element != NULL)
{
///////////////////////////////////////////////////////////////
// Now that we have the browser object, document object and the
// element we want to get the dimensions for .... do it the
// easy way.
///////////////////////////////////////////////////////////////
_bstr_t contents;
long left, top, width, height;
// I skip the error checking here. Add it when you implement
// your solution.
hr = element->get_innerHTML(contents.GetAddress());
hr = element->get_offsetLeft(&left);
hr = element->get_offsetTop(&top);
hr = element->get_offsetWidth(&width);
hr = element->get_offsetHeight(&height);
std::cout
<< "Rect = "<< "x=" << left << " "<< "y=" << top << " "<< "width=" << width << " "<< "height=" << height << std::endl
<< "contents=" << contents << std::endl;
}
}
}
CoUninitialize();
return 0;
}// Here we create web browser and document objects. The additional browser
// object is required for layout management. I have taken a shortcut here and
// create an instance Internet Explorer instead. This allows the browser to
// create and initializes a HTMLDocument when we call IWebBrowser::Navigate.
HRESULT CreateBrowserDocument(
const std::wstring& html,
CComPtr<IWebBrowser2>& returnBrowser,
CComPtr<IHTMLDocument3>& returnDoc)
{
CComPtr<IHTMLDocument2> document;
CComPtr<IWebBrowser2> browser;
HRESULT hr;
hr = CoCreateInstance(
CLSID_InternetExplorer,
NULL,
CLSCTX_SERVER,
IID_IWebBrowser2,
reinterpret_cast<void**>(&browser));
if(SUCCEEDED(hr))
{
// The browser does not contain a document by default. We can force
// one though by navigating to the `about` page. This is fast and
// does not require an internet connection.
VARIANT empty;
VariantInit(&empty);
hr = browser->Navigate(
_bstr_t(L"about:"), &empty, &empty, &empty, &empty);
// Wait for the load.
if(SUCCEEDED(hr))
{
READYSTATE state;
while(SUCCEEDED(hr = browser->get_ReadyState(&state)))
{
if(state == READYSTATE_COMPLETE) break;
}
}
// The browser now has a document object. Grab it.
if(SUCCEEDED(hr))
{
CComPtr<IDispatch> dispatch;
hr = browser->get_Document(&dispatch);
if(SUCCEEDED(hr) && dispatch != NULL)
{
hr = dispatch.QueryInterface<IHTMLDocument2>(&document);
}
else
{
hr = E_FAIL;
}
}
}
if(SUCCEEDED(hr))
{
// Since the about page is empty we can just write out our test HTML
// directly to the document. Takes some effort since we need to
// use a safe array to send it to the document.
SAFEARRAY *pString = SafeArrayCreateVector(VT_VARIANT, 0, 1);
if (pString != NULL)
{
VARIANT *param;
hr = SafeArrayAccessData(pString, reinterpret_cast<void**>(¶m));
if(SUCCEEDED(hr))
{
const _bstr_t htmlString(SysAllocString(html.c_str()));
param->vt = VT_BSTR;
param->bstrVal = htmlString;
hr = SafeArrayUnaccessData(pString);
if(SUCCEEDED(hr))
{
hr = document->write(pString);
document->close();
}
}
SafeArrayDestroy(pString);
}
// Set the return values
if(SUCCEEDED(hr) && document != NULL && browser != NULL)
{
CComPtr<IHTMLDocument3> temp;
hr = document.QueryInterface<IHTMLDocument3>(&temp);
if(SUCCEEDED(hr) && temp != NULL)
{
document = temp;
}
else
{
hr = E_FAIL;
}
CComPtr<IHTMLDocument3> tempDoc;
if(SUCCEEDED(hr))
{
hr = document.QueryInterface<IHTMLDocument3>(&tempDoc);
}
if(SUCCEEDED(hr) && tempDoc != NULL)
{
returnDoc = tempDoc;
returnBrowser = browser;
}
}
else if(!FAILED(hr))
{
hr = E_FAIL;
}
}
return hr;
}
[РЕДАКТИРОВАТЬ 1: Убрал ненужный звонок IWebBrowser::put_RegisterAsBrowser
]
[РЕДАКТИРОВАТЬ 2: Упрощенное получение размеров с помощью IHTMLElement::get_OffsetXXX
вместо IHTMLElement::get_clientXXX
]
Других решений пока нет …