///////////////////////////////////////////////////////////////////////////// // SimpleBrowser.cpp: Web browser control ///////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "comdef.h" #include "mshtml.h" #include "mshtmcid.h" #include "mshtmhst.h" #include "exdispid.h" #include "SimpleBrowser.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define Unused(parameter) parameter // avoid compile warnings // about unused parameters ///////////////////////////////////////////////////////////////////////////// // Construction and creation ///////////////////////////////////////////////////////////////////////////// SimpleBrowser::SimpleBrowser() : _Browser(NULL), _BrowserDispatch(NULL), _Ready(false), _Content(_T("")) { } SimpleBrowser::~SimpleBrowser() { // release browser interfaces if (_Browser != NULL) { _Browser->Release(); _Browser = NULL; } if (_BrowserDispatch != NULL) { _BrowserDispatch->Release(); _BrowserDispatch = NULL; } } // Standard create BOOL SimpleBrowser::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID) { BOOL results = TRUE; _Ready = false; _Browser = NULL; // create this window CWnd *window = this; results = window->Create(AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW), NULL, dwStyle, rect, pParentWnd, nID); if (!results) return FALSE; // create browser control window as child of this window; // this window sinks events from control CRect browser_window_rect(0,0,(rect.right - rect.left),(rect.bottom - rect.top)); results = _BrowserWindow.CreateControl(CLSID_WebBrowser, NULL, (WS_VISIBLE | WS_TABSTOP), browser_window_rect, this, AFX_IDW_PANE_FIRST); if (!results) { DestroyWindow(); return FALSE; } // get control interfaces LPUNKNOWN unknown = _BrowserWindow.GetControlUnknown(); HRESULT hr = unknown->QueryInterface(IID_IWebBrowser2,(void **)&_Browser); if (SUCCEEDED(hr)) { hr = unknown->QueryInterface(IID_IDispatch,(void **)&_BrowserDispatch); } if (!SUCCEEDED(hr)) { _BrowserWindow.DestroyWindow(); DestroyWindow(); return FALSE; } // navigate to initial blank page if (_Browser != NULL) { Navigate(_T("about:blank")); } return TRUE; } // Create in place of dialog control BOOL SimpleBrowser::CreateFromControl(CWnd *pParentWnd,UINT nID,DWORD dwStyle) { BOOL result = FALSE; ASSERT(pParentWnd != NULL); CWnd *control = pParentWnd->GetDlgItem(nID); if (control != NULL) { // get control location CRect rect; control->GetWindowRect(&rect); pParentWnd->ScreenToClient(&rect); // destroy control, since the browser will take its place control->DestroyWindow(); // create browser result = Create(dwStyle, rect, pParentWnd, nID); } return result; } // Destruction void SimpleBrowser::PostNcDestroy() { // release browser interfaces if (_Browser != NULL) { _Browser->Release(); _Browser = NULL; } if (_BrowserDispatch != NULL) { _BrowserDispatch->Release(); _BrowserDispatch = NULL; } _Ready = false; _Content = _T(""); CWnd::PostNcDestroy(); } ///////////////////////////////////////////////////////////////////////////// // Controls ///////////////////////////////////////////////////////////////////////////// // Navigate to URL void SimpleBrowser::Copy() { if (_Browser != NULL) { _Browser->ExecWB(OLECMDID_COPY, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL); } } void SimpleBrowser::Navigate(LPCTSTR URL) { _Ready = false; _Content = _T(""); if (_Browser != NULL) { CString url(URL); _variant_t flags(0L,VT_I4); _variant_t target_frame_name(""); _variant_t post_data(""); _variant_t headers(""); _Browser->Navigate(url.AllocSysString(), &flags, &target_frame_name, &post_data, &headers); } } // Navigate to HTML document in resource void SimpleBrowser::NavigateResource(int resource_ID) { if (_Browser != NULL) { CString resource_string; // load HTML document from resource HRSRC resource_handle = FindResource(AfxGetResourceHandle(), MAKEINTRESOURCE(resource_ID), RT_HTML); if (resource_handle != NULL) { HGLOBAL resource = LoadResource(AfxGetResourceHandle(), resource_handle); if (resource != NULL) { LPVOID resource_memory = LockResource(resource); if (resource_memory != NULL) { DWORD resource_size = SizeofResource(AfxGetResourceHandle(), resource_handle); // identify the resource document as MBCS (e.g. ANSI) // or UNICODE bool UNICODE_document = false; wchar_t *UNICODE_memory = (wchar_t *)resource_memory; int UNICODE_size = resource_size / sizeof(wchar_t); if (UNICODE_size >= 1) { // check for UNICODE byte order mark if (*UNICODE_memory == L'\xFEFF') { UNICODE_document = true; UNICODE_memory += 1; UNICODE_size -= 1; } // otherwise, check for UNICODE leading tag else if (UNICODE_size >= 5) { if ((UNICODE_memory[0] == L'<') && (towupper(UNICODE_memory[1]) == L'H') && (towupper(UNICODE_memory[2]) == L'T') && (towupper(UNICODE_memory[3]) == L'M') && (towupper(UNICODE_memory[4]) == L'L')) { UNICODE_document = true; } } // Note: This logic assumes that the UNICODE resource document is // in little-endian byte order, which would be typical for // any HTML document used as a resource in a Windows application. } // convert resource document if required #if !defined(UNICODE) if (UNICODE_document) { char *MBCS_buffer = resource_string.GetBufferSetLength(resource_size + 1); int MBCS_length = ::WideCharToMultiByte(CP_ACP, 0, UNICODE_memory, UNICODE_size, MBCS_buffer, resource_size + 1, NULL, NULL); resource_string.ReleaseBuffer(MBCS_length); } else { resource_string = CString((char *)resource_memory,resource_size); } #else if (UNICODE_document) { resource_string = CString(UNICODE_memory,UNICODE_size); } else { wchar_t *UNICODE_buffer = resource_string.GetBufferSetLength(resource_size + 1); int UNICODE_length = ::MultiByteToWideChar(CP_ACP, 0, (const char *)resource_memory, resource_size, UNICODE_buffer, (resource_size + 1)); resource_string.ReleaseBuffer(UNICODE_length); } #endif } } } Clear(); Write(resource_string); } } // Append string to current document void SimpleBrowser::Write(LPCTSTR string) { if (_Browser != NULL) { _Content.Append(string); _ContentWrite(); } } void SimpleBrowser::Clear() { if (_Browser != NULL) { _Content = _T(""); // get document interface IHTMLDocument2 *document = GetDocument(); HRESULT hr = S_OK; if (document != NULL) { // close and re-open document to empty contents document->close(); VARIANT open_name; VARIANT open_features; VARIANT open_replace; IDispatch *open_window = NULL; ::VariantInit(&open_name); open_name.vt = VT_BSTR; open_name.bstrVal = ::SysAllocString(L"_self"); ::VariantInit(&open_features); ::VariantInit(&open_replace); hr = document->open(::SysAllocString(L"text/html"), open_name, open_features, open_replace, &open_window); if (hr == S_OK) { Refresh(); } if (open_window != NULL) { open_window->Release(); } ::VariantClear(&open_name); document->Release(); document = NULL; } else { Navigate(_T("about:blank")); } } } // Navigation operations void SimpleBrowser::GoBack() { if (_Browser != NULL) { _Browser->GoBack(); } } void SimpleBrowser::GoForward() { if (_Browser != NULL) { _Browser->GoForward(); } } void SimpleBrowser::GoHome() { if (_Browser != NULL) { _Browser->GoHome(); } } void SimpleBrowser::Refresh() { if (_Browser != NULL) { _Browser->Refresh(); } } void SimpleBrowser::Stop() { if (_Browser != NULL) { _Browser->Stop(); } } // Print contents void SimpleBrowser::Print(LPCTSTR header,LPCTSTR footer) { if (_Browser != NULL) { // construct two element SAFEARRAY; // first element is header string, second element is footer string HRESULT hr; VARIANT header_variant; VariantInit(&header_variant); V_VT(&header_variant) = VT_BSTR; V_BSTR(&header_variant) = CString(header).AllocSysString(); VARIANT footer_variant; VariantInit(&footer_variant); V_VT(&footer_variant) = VT_BSTR; V_BSTR(&footer_variant) = CString(footer).AllocSysString(); long index; SAFEARRAYBOUND parameter_array_bound[1]; SAFEARRAY *parameter_array = NULL; parameter_array_bound[0].cElements = 2; parameter_array_bound[0].lLbound = 0; parameter_array = SafeArrayCreate(VT_VARIANT,1,parameter_array_bound); index = 0; hr = SafeArrayPutElement(parameter_array,&index,&header_variant); index = 1; hr = SafeArrayPutElement(parameter_array,&index,&footer_variant); VARIANT parameter; VariantInit(¶meter); V_VT(¶meter) = VT_ARRAY | VT_BYREF; V_ARRAY(¶meter) = parameter_array; // start printing browser contents hr = _Browser->ExecWB(OLECMDID_PRINT,OLECMDEXECOPT_DODEFAULT,¶meter,NULL); // release SAFEARRAY if (!SUCCEEDED(hr)) { VariantClear(&header_variant); VariantClear(&footer_variant); if (parameter_array != NULL) { SafeArrayDestroy(parameter_array); } } } } void SimpleBrowser::PrintPreview() { if (_Browser != NULL) { _Browser->ExecWB(OLECMDID_PRINTPREVIEW,OLECMDEXECOPT_DODEFAULT,NULL,NULL); } } // Miscellaneous bool SimpleBrowser::GetBusy() { bool busy = false; if (_Browser != NULL) { VARIANT_BOOL variant_bool; HRESULT hr = _Browser->get_Busy(&variant_bool); if (SUCCEEDED(hr)) { busy = (variant_bool == VARIANT_TRUE); } } return busy; } CString SimpleBrowser::GetLocationName() { CString location_name = _T(""); if (_Browser != NULL) { BSTR location_name_BSTR = NULL; HRESULT hr = _Browser->get_LocationName(&location_name_BSTR); if (SUCCEEDED(hr)) { location_name = location_name_BSTR; } ::SysFreeString(location_name_BSTR); } return location_name; } CString SimpleBrowser::GetLocationURL() { CString location_URL = _T(""); if (_Browser != NULL) { BSTR location_URL_BSTR = NULL; HRESULT hr = _Browser->get_LocationURL(&location_URL_BSTR); if (SUCCEEDED(hr)) { location_URL = location_URL_BSTR; } ::SysFreeString(location_URL_BSTR); } return location_URL; } READYSTATE SimpleBrowser::GetReadyState() { READYSTATE readystate = READYSTATE_UNINITIALIZED; if (_Browser != NULL) { _Browser->get_ReadyState(&readystate); } return readystate; } bool SimpleBrowser::GetSilent() { bool silent = false; if (_Browser != NULL) { VARIANT_BOOL silent_variant; HRESULT hr = _Browser->get_Silent(&silent_variant); if (SUCCEEDED(hr)) { silent = (silent_variant == VARIANT_TRUE); } } return silent; } void SimpleBrowser::PutSilent(bool silent) { if (_Browser != NULL) { VARIANT_BOOL silent_variant; if (silent) silent_variant = VARIANT_TRUE; else silent_variant = VARIANT_FALSE; _Browser->put_Silent(silent_variant); } } IHTMLDocument2 *SimpleBrowser::GetDocument() { IHTMLDocument2 *document = NULL; if (_Browser != NULL) { // get browser document's dispatch interface IDispatch *document_dispatch = NULL; HRESULT hr = _Browser->get_Document(&document_dispatch); if (SUCCEEDED(hr) && (document_dispatch != NULL)) { // get the actual document interface hr = document_dispatch->QueryInterface(IID_IHTMLDocument2, (void **)&document); // release dispatch interface document_dispatch->Release(); } } return document; } ///////////////////////////////////////////////////////////////////////////// // Message handlers ///////////////////////////////////////////////////////////////////////////// BEGIN_MESSAGE_MAP(SimpleBrowser,CWnd) //{{AFX_MSG_MAP(SimpleBrowser) ON_WM_SIZE() //}}AFX_MSG_MAP END_MESSAGE_MAP() BOOL SimpleBrowser::PreTranslateMessage(MSG *pMsg) { BOOL result = FALSE; // translate keys correctly, especially Tab, Del, (Enter?) if (_Browser != NULL) { IOleInPlaceActiveObject* OleInPlaceActiveObject = NULL; HRESULT hr = _Browser->QueryInterface(IID_IOleInPlaceActiveObject, (void**)&OleInPlaceActiveObject); if (SUCCEEDED(hr) && (OleInPlaceActiveObject != NULL)) { hr = OleInPlaceActiveObject->TranslateAccelerator(pMsg); result = (hr == S_OK ? TRUE : FALSE); OleInPlaceActiveObject->Release(); } } else { result = CWnd::PreTranslateMessage(pMsg); } return result; } // Resize control window as this window is resized void SimpleBrowser::OnSize(UINT nType, int cx, int cy) { CWnd::OnSize(nType, cx, cy); if (_Browser != NULL) { CRect rect(0,0,cx,cy); _BrowserWindow.MoveWindow(&rect); } } ///////////////////////////////////////////////////////////////////////////// // Event handlers ///////////////////////////////////////////////////////////////////////////// #ifndef DISPID_PRINTTEMPLATEINSTANTIATION #define DISPID_PRINTTEMPLATEINSTANTIATION 225 #endif #ifndef DISPID_PRINTTEMPLATETEARDOWN #define DISPID_PRINTTEMPLATETEARDOWN 226 #endif BEGIN_EVENTSINK_MAP(SimpleBrowser,CWnd) ON_EVENT(SimpleBrowser,AFX_IDW_PANE_FIRST, DISPID_BEFORENAVIGATE2, _OnBeforeNavigate2, VTS_DISPATCH VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PBOOL) ON_EVENT(SimpleBrowser,AFX_IDW_PANE_FIRST, DISPID_DOCUMENTCOMPLETE, _OnDocumentComplete, VTS_DISPATCH VTS_PVARIANT) ON_EVENT(SimpleBrowser,AFX_IDW_PANE_FIRST, DISPID_DOWNLOADBEGIN, _OnDownloadBegin, VTS_NONE) ON_EVENT(SimpleBrowser,AFX_IDW_PANE_FIRST, DISPID_PROGRESSCHANGE, _OnProgressChange, VTS_I4 VTS_I4) ON_EVENT(SimpleBrowser,AFX_IDW_PANE_FIRST, DISPID_DOWNLOADCOMPLETE, _OnDownloadComplete, VTS_NONE) ON_EVENT(SimpleBrowser,AFX_IDW_PANE_FIRST, DISPID_NAVIGATECOMPLETE2, _OnNavigateComplete2, VTS_DISPATCH VTS_PVARIANT) ON_EVENT(SimpleBrowser,AFX_IDW_PANE_FIRST, DISPID_STATUSTEXTCHANGE, _OnStatusTextChange, VTS_BSTR) ON_EVENT(SimpleBrowser,AFX_IDW_PANE_FIRST, DISPID_TITLECHANGE, _OnTitleChange, VTS_BSTR) ON_EVENT(SimpleBrowser,AFX_IDW_PANE_FIRST, DISPID_PRINTTEMPLATEINSTANTIATION, _OnPrintTemplateInstantiation, VTS_DISPATCH) ON_EVENT(SimpleBrowser,AFX_IDW_PANE_FIRST, DISPID_PRINTTEMPLATETEARDOWN, _OnPrintTemplateTeardown, VTS_DISPATCH) END_EVENTSINK_MAP() SimpleBrowser::Notification::Notification(HWND hwnd,UINT ID,NotificationType type) { hdr.hwndFrom = hwnd; hdr.idFrom = ID; hdr.code = type; URL = _T(""); frame = _T(""); post_data = NULL; post_data_size = 0; headers = _T(""); progress = 0; progress_max = 0; text = _T(""); } SimpleBrowser::Notification::~Notification() { } // Called before navigation begins; application may cancel if required void SimpleBrowser::_OnBeforeNavigate2(LPDISPATCH lpDisp, VARIANT FAR *URL, VARIANT FAR *Flags, VARIANT FAR *TargetFrameName, VARIANT FAR *PostData, VARIANT FAR *Headers, VARIANT_BOOL *Cancel) { Unused(Flags); // Note: flags value is reserved if (lpDisp == _BrowserDispatch) { CString URL_string; CString frame; unsigned char *post_data = NULL; int post_data_size = 0; CString headers; if ((URL != NULL) && (V_VT(URL) == VT_BSTR)) { URL_string = V_BSTR(URL); } if ((TargetFrameName != NULL) && (V_VT(TargetFrameName) == VT_BSTR)) { frame = V_BSTR(TargetFrameName); } if ((PostData != NULL) && (V_VT(PostData) == (VT_VARIANT | VT_BYREF))) { VARIANT *PostData_variant = V_VARIANTREF(PostData); if ((PostData_variant != NULL) && (V_VT(PostData_variant) != VT_EMPTY)) { SAFEARRAY *PostData_safearray = V_ARRAY(PostData_variant); if (PostData_safearray != NULL) { char *post_data_array = NULL; SafeArrayAccessData(PostData_safearray,(void HUGEP **)&post_data_array); long lower_bound = 1; long upper_bound = 1; SafeArrayGetLBound(PostData_safearray,1,&lower_bound); SafeArrayGetUBound(PostData_safearray,1,&upper_bound); post_data_size = (int)(upper_bound - lower_bound + 1); post_data = new unsigned char[post_data_size]; memcpy(post_data,post_data_array,post_data_size); SafeArrayUnaccessData(PostData_safearray); } } } if ((Headers != NULL) && (V_VT(Headers) == VT_BSTR)) { headers = V_BSTR(Headers); } bool cancel = OnBeforeNavigate2(URL_string, frame, post_data,post_data_size, headers); if (Cancel != NULL) { if (cancel) *Cancel = VARIANT_TRUE; else *Cancel = VARIANT_FALSE; } delete []post_data; } } bool SimpleBrowser::OnBeforeNavigate2(CString URL, CString frame, void *post_data,int post_data_size, CString headers) { bool cancel = false; CWnd *parent = GetParent(); if (parent != NULL) { Notification notification(m_hWnd,GetDlgCtrlID(),BeforeNavigate2); notification.URL = URL; notification.frame = frame; notification.post_data = post_data; notification.post_data_size = post_data_size; notification.headers = headers; LRESULT result = parent->SendMessage(WM_NOTIFY, notification.hdr.idFrom, (LPARAM)¬ification); if (result) { cancel = true; } } return cancel; } bool SimpleBrowser::ParsePostData(CString post_data, CStringArray &names, CStringArray &values) { bool result = true; int size = 1; names.SetSize(size); values.SetSize(size); int offset = 0; bool parsing_name = true; CString hex(_T("0123456789ABCDEF")); while ((offset < post_data.GetLength()) && result) { if (post_data[offset] == _T('%')) { if ((offset + 2) < post_data.GetLength()) { int digit1 = hex.Find(_totupper(post_data[offset + 1])); int digit2 = hex.Find(_totupper(post_data[offset + 2])); if ((digit1 >= 0) && (digit2 >= 0)) { _TCHAR character = (_TCHAR)((digit1 << 4) + digit2); if (parsing_name) names[size - 1].AppendChar(character); else values[size - 1].AppendChar(character); } else { result = false; } offset += 2; } else { result = false; } } else if (post_data[offset] == _T('+')) { if (parsing_name) names[size - 1].AppendChar(_T(' ')); else values[size - 1].AppendChar(_T(' ')); } else if (post_data[offset] == _T('=')) { if (parsing_name) { parsing_name = false; } else { values[size - 1].AppendChar(post_data[offset]); } } else if (post_data[offset] == _T('&')) { if (!parsing_name) { parsing_name = true; size += 1; names.SetSize(size); values.SetSize(size); } else { values[size - 1].AppendChar(post_data[offset]); } } else { if (parsing_name) names[size - 1].AppendChar(post_data[offset]); else values[size - 1].AppendChar(post_data[offset]); } offset++; } if ((names[size - 1] == _T("")) && (values[size - 1] == _T(""))) { names.SetSize(size - 1); values.SetSize(size - 1); } return result; } // Document loaded and initialized void SimpleBrowser::_OnDocumentComplete(LPDISPATCH lpDisp,VARIANT *URL) { if (lpDisp == _BrowserDispatch) { CString URL_string; if ((URL != NULL) && (V_VT(URL) == VT_BSTR)) { URL_string = CString(V_BSTR(URL)); } OnDocumentComplete(URL_string); } } void SimpleBrowser::OnDocumentComplete(CString URL) { CWnd *parent = GetParent(); if (parent != NULL) { Notification notification(m_hWnd,GetDlgCtrlID(),DocumentComplete); notification.URL = URL; LRESULT result = parent->SendMessage(WM_NOTIFY, notification.hdr.idFrom, (LPARAM)¬ification); } } // Navigation/download progress void SimpleBrowser::_OnDownloadBegin() { OnDownloadBegin(); } void SimpleBrowser::OnDownloadBegin() { CWnd *parent = GetParent(); if (parent != NULL) { Notification notification(m_hWnd,GetDlgCtrlID(),DownloadBegin); LRESULT result = parent->SendMessage(WM_NOTIFY, notification.hdr.idFrom, (LPARAM)¬ification); } } void SimpleBrowser::_OnProgressChange(long progress,long progress_max) { OnProgressChange((int)progress,(int)progress_max); } void SimpleBrowser::OnProgressChange(int progress,int progress_max) { CWnd *parent = GetParent(); if (parent != NULL) { Notification notification(m_hWnd,GetDlgCtrlID(),ProgressChange); notification.progress = progress; notification.progress_max = progress_max; LRESULT result = parent->SendMessage(WM_NOTIFY, notification.hdr.idFrom, (LPARAM)¬ification); } } void SimpleBrowser::_OnDownloadComplete() { OnDownloadComplete(); } void SimpleBrowser::OnDownloadComplete() { CWnd *parent = GetParent(); if (parent != NULL) { Notification notification(m_hWnd,GetDlgCtrlID(),DownloadComplete); LRESULT result = parent->SendMessage(WM_NOTIFY, notification.hdr.idFrom, (LPARAM)¬ification); } } // Navigation to a link has completed void SimpleBrowser::_OnNavigateComplete2(LPDISPATCH lpDisp,VARIANT *URL) { if (lpDisp == _BrowserDispatch) { // signal document ready _Ready = true; // write current content _ContentWrite(); // inform user navigation complete CString URL_string; if ((URL != NULL) && (V_VT(URL) == VT_BSTR)) { URL_string = V_BSTR(URL); } OnNavigateComplete2(URL_string); } } void SimpleBrowser::OnNavigateComplete2(CString URL) { CWnd *parent = GetParent(); if (parent != NULL) { Notification notification(m_hWnd,GetDlgCtrlID(),NavigateComplete2); notification.URL = URL; LRESULT result = parent->SendMessage(WM_NOTIFY, notification.hdr.idFrom, (LPARAM)¬ification); } } // Status text has changed void SimpleBrowser::_OnStatusTextChange(BSTR bstrText) { CString text; if (bstrText != NULL) { text = (LPCTSTR)bstrText; } OnStatusTextChange(text); } void SimpleBrowser::OnStatusTextChange(CString text) { CWnd *parent = GetParent(); if (parent != NULL) { Notification notification(m_hWnd,GetDlgCtrlID(),StatusTextChange); notification.text = text; LRESULT result = parent->SendMessage(WM_NOTIFY, notification.hdr.idFrom, (LPARAM)¬ification); } } // Title text has changed void SimpleBrowser::_OnTitleChange(BSTR bstrText) { CString text; if (bstrText != NULL) { text = (LPCTSTR)bstrText; } OnTitleChange(text); } void SimpleBrowser::OnTitleChange(CString text) { CWnd *parent = GetParent(); if (parent != NULL) { Notification notification(m_hWnd,GetDlgCtrlID(),TitleChange); notification.text = text; LRESULT result = parent->SendMessage(WM_NOTIFY, notification.hdr.idFrom, (LPARAM)¬ification); } } // Print template instantiation and teardown void SimpleBrowser::_OnPrintTemplateInstantiation(LPDISPATCH lpDisp) { OnPrintTemplateInstantiation(); }; void SimpleBrowser::OnPrintTemplateInstantiation() { CWnd *parent = GetParent(); if (parent != NULL) { Notification notification(m_hWnd,GetDlgCtrlID(),PrintTemplateInstantiation); LRESULT result = parent->SendMessage(WM_NOTIFY, notification.hdr.idFrom, (LPARAM)¬ification); } } void SimpleBrowser::_OnPrintTemplateTeardown(LPDISPATCH lpDisp) { OnPrintTemplateTeardown(); }; void SimpleBrowser::OnPrintTemplateTeardown() { CWnd *parent = GetParent(); if (parent != NULL) { Notification notification(m_hWnd,GetDlgCtrlID(),PrintTemplateTeardown); LRESULT result = parent->SendMessage(WM_NOTIFY, notification.hdr.idFrom, (LPARAM)¬ification); } } // Write deferred content void SimpleBrowser::_ContentWrite() { if (_Ready && (!_Content.IsEmpty())) { // get document interface IHTMLDocument2 *document = GetDocument(); if (document != NULL) { // construct text to be written to browser as SAFEARRAY SAFEARRAY *safe_array = SafeArrayCreateVector(VT_VARIANT,0,1); VARIANT *variant; SafeArrayAccessData(safe_array,(LPVOID *)&variant); variant->vt = VT_BSTR; variant->bstrVal = _Content.AllocSysString(); SafeArrayUnaccessData(safe_array); // write SAFEARRAY to browser document document->write(safe_array); // cleanup document->Release(); document = NULL; ::SysFreeString(variant->bstrVal); variant->bstrVal = NULL; SafeArrayDestroy(safe_array); } } }