Расширение объектной модели DHTML
Компания Microsoft предоставила возможность расширения объектной модели через механизм window.external. Приложение, использующее web-browser control может реализовывать собственную логику через переопределение объекта external. Естественно, чтобы иметь возможноть работать со своим приложением из скрипта, программа должна реализовывать dispatch-интерфейсы. При помощи ClassWizard, добавить поддержку автоматизации к своим объектам не составляет труда. Единственным замечанием здесь может служить лишь то, что объекты должны наследоваться от CCmdTarget. Чтобы передать указатель на свой объект самому объекту webbrowser, а заодно установить целую кучу дополнительных параметров, необходимо реализовать cлужебный интерфейс IDocHostUIHandler, который описан в mshtmhst.h. Этот интерфейс представляет собой некий call-back, или интерфейс обратной связи, к которому обращается webbrowser в следующих случаях:
• Необходимо показать контекстное меню. Как раз здесь можно заменить стандартное меню Internet-explorer на свое собственное. Либо вообще сделать так, чтобы меню не показывалось.
• Есть возможность подменить элементы пользовательского интерфейса браузера.
• Нужно обработать нажатие горячей клавиши.
• Нужно обработать URL, по которому совершается переход.
• Нужно обработать события drag-and-drop.
• Необходимо получить указатель на объект window.external.
После реализации этого call-back объекта, его можно "инсталлировать", используя метод интерфейса ICustomDoc SetUIHandler. Интерфейс IСustomDoc экспортируется обычно реализуется тем же объектом, что реализует IHTMLDocument2.
// код из OnNavigateComplete
CComQIPtr m_pBrowserCustomDoc;
CComQIPtr pADocument;
CDocHostUIHandler m_DocHostImpl;
m_DocHostImpl.AddRef();
m_DocHostImpl.m_pAppDisp = m_pApp->GetIDispatch(FALSE);
m_pBrowserCustomDoc = pADocument;
m_pBrowserCustomDoc->SetUIHandler((IDocHostUIHandler*)&m_DocHostImpl);
В данном коде фигурирует класс CDocHostUIHandler, который реализует все методы интерфейса IDocHostUIHandler (и конечно же AddRef, QueryInterface и Release от IUnknown). В базовом варианте, реализация этого объекта сводится лишь к созданию процедур-заглушек для каждого метода IDocHostUIHandler, возвращающих E_NOTIMPL. А если хочется, чтобы Internet Explorer не показывал своего конекстного меню, нужно возвращать из метода ShowContextMenu S_OK.
Если наш объект CDocHostUIHandler возвращает указатель в методе get_External, то этот указатель и используется как объект расширения и тогда где-нибудь внутри самой html странички можно будет написать такие строки:
function ShowSettingsDialog() {
if (window.external.ShowSettings() == true) {
document.body.bgcolor = window.external.BackColor;
}
}
Settings
В приведенном примере, функция ShowSettings и свойство BackColor запрашиваются из недр нашего собственного приложения.
Где хранить свои HTML
В ресурсах! К счастью, Internet explorer умеет грузить из ресурсов, нужно только в качестве префикса URL написать res://<���путь к модулю>/<���название ресурса>. Я привожу реализацию этого метода, выдранную из исходного текста CHTMLView.
HINSTANCE hInstance = AfxGetResourceHandle();
CString strResourceURL;
BOOL bRetVal = TRUE;
LPTSTR lpszModule = new TCHAR[_MAX_PATH];
if (GetModuleFileName(hInstance, lpszModule, _MAX_PATH)) {
// lpszResource - строкое название ресурса
strResourceURL.Format(_T("res://%s/%s"), lpszModule, lpszResource);
m_pBrowserApp->Navigate(strResourceURL, NULL, NULL, NULL, NULL);
} else bRetVal = FALSE;
delete [] lpszModule;
return bRetVal;
HTML ресурсы можно вынести в отдельный подкаталог, например html. Тогда в файле описания ресурсов (например, myapp.rc) необходимо добавить строки следующего вида:
IDR_MAIN HTML DISCARDABLE "html\\main.html"
DEL.GIF HTML DISCARDABLE "html\\del.gif"
LEFTARR.GIF HTML DISCARDABLE "html\\leftarr.gif"
RIGHTARR.GIF HTML DISCARDABLE "html\\rightarr.gif"
TITLE.GIF HTML DISCARDABLE "html\\title.gif"
NEWMSG.GIF HTML DISCARDABLE "html\\newmsg.gif"
Реализация доступа к ресурсам в IE достаточно умна, чтобы автоматически найти все необходимые объекты в ресурсах, на которые ссылается страничка, поэтому достаточно знать лишь ресурс-имя основной странички.
ВОПРОС-ОТВЕТ
Q. Насколько корректно будут работать методы контроля утечек памяти (в частности объект CMemoryState) в многопоточных приложениях?
У меня сложилось впечатление, что объект CMemoryState не делает различия в каком потоке вызывались операторы new с момента обращения к memState.Checkpoint() до обращения к memState.DumpAllObjectsSince().
Видимо "моментальные снимки" распределённой памяти в данном случае не информативны, ведь несколько потоков работают в одном адресном пространстве?
Николай Турпитко
A. Действительно, вне зависимости от потока, все распределения памяти попадают в один большой двусвязный список блоков памяти, который поддерживает отладочная версия CRT (если задан макрос _DEBUG). Что касается MFC-класса CMemoryState, он является просто тонкой обёрткой вокруг структуры _CrtMemState и функций для диагностики утечек памяти CRT. Поэтому он также не делает различий между потоками.
Читать дальше