// Copyright (c) 2008 The Chromium Embedded Framework Authors. // Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "precompiled_libcef.h" #include "context.h" #include "browser_impl.h" #include "browser_webkit_glue.h" #include "stream_impl.h" #include "base/string_util.h" #include "base/win_util.h" #include "skia/ext/vector_canvas.h" #include "webkit/glue/webframe.h" #include "webkit/glue/webkit_glue.h" #include #include #include #include #define BUFFER_SIZE 32768 LPCTSTR CefBrowserImpl::GetWndClass() { return L"CefBrowserWindow"; } LRESULT CALLBACK CefBrowserImpl::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { CefBrowserImpl* browser = static_cast(win_util::GetWindowUserData(hwnd)); switch (message) { case WM_COMMAND: { int wmId = LOWORD(wParam); int wmEvent = HIWORD(wParam); } break; case WM_DESTROY: { // Remove the browser from the list maintained by the context _Context->RemoveBrowser(browser); } return 0; case WM_SIZE: if (browser && browser->UIT_GetWebView()) { // resize the web view window to the full size of the browser window RECT rc; GetClientRect(browser->UIT_GetMainWndHandle(), &rc); MoveWindow(browser->UIT_GetWebViewWndHandle(), 0, 0, rc.right, rc.bottom, TRUE); if(browser->UIT_IsWebViewDisabled()) { // recreate the capture bitmap at the correct size HBITMAP bitmap; SIZE size; browser->UIT_CaptureWebViewBitmap(bitmap, size); browser->UIT_SetWebViewBitmap(bitmap, size); } } return 0; case WM_PAINT: if(browser->UIT_IsWebViewDisabled()) { // when web view is disabled draw the capture bitmap PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); HBITMAP bitmap; SIZE size; browser->UIT_GetWebViewBitmap(bitmap, size); HDC hMemDC = CreateCompatibleDC(hdc); HBITMAP hOldBmp = (HBITMAP)SelectObject(hMemDC, bitmap); BitBlt(hdc, 0, 0, size.cx, size.cy, hMemDC, 0, 0, SRCCOPY); SelectObject(hMemDC, hOldBmp); DeleteDC(hMemDC); EndPaint(hwnd, &ps); return 0; } break; case WM_SETFOCUS: if (browser && browser->UIT_GetWebView()) browser->UIT_GetWebView()->SetFocus(true); return 0; case WM_KILLFOCUS: if (browser && browser->UIT_GetWebView()) browser->UIT_GetWebView()->SetFocus(false); return 0; case WM_ERASEBKGND: return 0; } return DefWindowProc(hwnd, message, wParam, lParam); } CefWindowHandle CefBrowserImpl::GetWindowHandle() { Lock(); CefWindowHandle handle = window_info_.m_hWnd; Unlock(); return handle; } std::wstring CefBrowserImpl::GetSource(TargetFrame targetFrame) { if(!_Context->RunningOnUIThread()) { // We need to send the request to the UI thread and wait for the result // Event that will be used to signal that data is available. Start // in non-signaled mode so that the event will block. HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); DCHECK(hEvent != NULL); CefRefPtr stream(new CefBytesWriter(BUFFER_SIZE)); // Request the data from the UI thread stream->AddRef(); PostTask(FROM_HERE, NewRunnableMethod(this, &CefBrowserImpl::UIT_GetDocumentStringNotify, targetFrame, stream.get(), hEvent)); // Wait for the UI thread callback to tell us that the data is available WaitForSingleObject(hEvent, INFINITE); CloseHandle(hEvent); return UTF8ToWide( static_cast(stream.get())->GetDataString()); } else { // Retrieve the frame contents directly WebFrame* frame; if(targetFrame == TF_FOCUSED) frame = UIT_GetWebView()->GetFocusedFrame(); else frame = UIT_GetWebView()->GetMainFrame(); // Retrieve the document string return UTF8ToWide(webkit_glue::GetDocumentString(frame)); } } std::wstring CefBrowserImpl::GetText(TargetFrame targetFrame) { if(!_Context->RunningOnUIThread()) { // We need to send the request to the UI thread and wait for the result // Event that will be used to signal that data is available. Start // in non-signaled mode so that the event will block. HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); DCHECK(hEvent != NULL); CefRefPtr stream(new CefBytesWriter(BUFFER_SIZE)); // Request the data from the UI thread stream->AddRef(); PostTask(FROM_HERE, NewRunnableMethod(this, &CefBrowserImpl::UIT_GetDocumentTextNotify, targetFrame, stream.get(), hEvent)); // Wait for the UI thread callback to tell us that the data is available WaitForSingleObject(hEvent, INFINITE); CloseHandle(hEvent); return UTF8ToWide( static_cast(stream.get())->GetDataString()); } else { // Retrieve the frame contents directly WebFrame* frame; if(targetFrame == TF_FOCUSED) frame = UIT_GetWebView()->GetFocusedFrame(); else frame = UIT_GetWebView()->GetMainFrame(); // Retrieve the document string return webkit_glue::DumpDocumentText(frame); } } bool CefBrowserImpl::CanGoBack() { if(!_Context->RunningOnUIThread()) { // We need to send the request to the UI thread and wait for the result // Event that will be used to signal that data is available. Start // in non-signaled mode so that the event will block. HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); DCHECK(hEvent != NULL); bool retVal = true; // Request the data from the UI thread PostTask(FROM_HERE, NewRunnableMethod(this, &CefBrowserImpl::UIT_CanGoBackNotify, &retVal, hEvent)); // Wait for the UI thread callback to tell us that the data is available WaitForSingleObject(hEvent, INFINITE); CloseHandle(hEvent); return retVal; } else { // Call the method directly return UIT_CanGoBack(); } } bool CefBrowserImpl::CanGoForward() { if(!_Context->RunningOnUIThread()) { // We need to send the request to the UI thread and wait for the result // Event that will be used to signal that data is available. Start // in non-signaled mode so that the event will block. HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); DCHECK(hEvent != NULL); bool retVal = true; // Request the data from the UI thread PostTask(FROM_HERE, NewRunnableMethod(this, &CefBrowserImpl::UIT_CanGoForwardNotify, &retVal, hEvent)); // Wait for the UI thread callback to tell us that the data is available WaitForSingleObject(hEvent, INFINITE); CloseHandle(hEvent); return retVal; } else { // Call the method directly return UIT_CanGoForward(); } } void CefBrowserImpl::UIT_CreateBrowser() { REQUIRE_UIT(); // Create the new browser window window_info_.m_hWnd = CreateWindowEx(window_info_.m_dwExStyle, GetWndClass(), window_info_.m_windowName.c_str(), window_info_.m_dwStyle, window_info_.m_x, window_info_.m_y, window_info_.m_nWidth, window_info_.m_nHeight, window_info_.m_hWndParent, window_info_.m_hMenu, _Context->GetInstanceHandle(), NULL); DCHECK(window_info_.m_hWnd != NULL); // Set window user data to this object for future reference from the window // procedure win_util::SetWindowUserData(window_info_.m_hWnd, this); // Add the new browser to the list maintained by the context _Context->AddBrowser(this); // Create the webview host object webviewhost_.reset( WebViewHost::Create(window_info_.m_hWnd, delegate_.get(), *_Context->GetWebPreferences())); UIT_GetWebView()->SetUseEditorDelegate(true); delegate_->RegisterDragDrop(); // Size the web view window to the browser window RECT cr; GetClientRect(window_info_.m_hWnd, &cr); SetWindowPos(UIT_GetWebViewWndHandle(), NULL, cr.left, cr.top, cr.right, cr.bottom, SWP_NOZORDER | SWP_SHOWWINDOW); if(handler_.get()) { // Notify the handler that we're done creating the new window handler_->HandleAfterCreated(this); } if(url_.size() > 0) UIT_LoadURL(url_.c_str()); else UIT_LoadURL(L"about:blank"); } void CefBrowserImpl::UIT_LoadURLForRequest(const std::wstring& url, const std::wstring& frame_name, const std::wstring& method, net::UploadData *upload_data, const WebRequest::HeaderMap& headers) { REQUIRE_UIT(); if (url.empty()) return; std::wstring urlString(url); if (PathFileExists(url.c_str()) || PathIsUNC(url.c_str())) { TCHAR fileURL[INTERNET_MAX_URL_LENGTH]; DWORD fileURLLength = sizeof(fileURL)/sizeof(fileURL[0]); if (SUCCEEDED(UrlCreateFromPath(url.c_str(), fileURL, &fileURLLength, 0))) urlString.assign(fileURL); } nav_controller_->LoadEntry(new BrowserNavigationEntry( -1, GURL(urlString), std::wstring(), frame_name, method, upload_data, headers)); } void CefBrowserImpl::UIT_LoadHTML(const std::wstring& html, const std::wstring& url) { REQUIRE_UIT(); std::wstring urlString(url); if (PathFileExists(url.c_str()) || PathIsUNC(url.c_str())) { TCHAR fileURL[INTERNET_MAX_URL_LENGTH]; DWORD fileURLLength = sizeof(fileURL)/sizeof(fileURL[0]); if (SUCCEEDED(UrlCreateFromPath(url.c_str(), fileURL, &fileURLLength, 0))) urlString.assign(fileURL); } UIT_GetWebView()->GetMainFrame()->LoadHTMLString( WideToUTF8(html), GURL(urlString)); } void CefBrowserImpl::UIT_LoadHTMLForStreamRef(CefStreamReader* stream, const std::wstring& url) { REQUIRE_UIT(); std::wstring urlString(url); if (PathFileExists(url.c_str()) || PathIsUNC(url.c_str())) { TCHAR fileURL[INTERNET_MAX_URL_LENGTH]; DWORD fileURLLength = sizeof(fileURL)/sizeof(fileURL[0]); if (SUCCEEDED(UrlCreateFromPath(url.c_str(), fileURL, &fileURLLength, 0))) urlString.assign(fileURL); } // read all of the stream data into a std::string. std::stringstream ss; char buff[BUFFER_SIZE]; size_t read; do { read = stream->Read(buff, sizeof(char), BUFFER_SIZE-1); if(read > 0) { buff[read] = 0; ss << buff; } } while(read > 0); UIT_GetWebView()->GetMainFrame()->LoadHTMLString(ss.str(), GURL(urlString)); stream->Release(); } void CefBrowserImpl::UIT_SetFocus(WebWidgetHost* host, bool enable) { REQUIRE_UIT(); if (enable) ::SetFocus(host->window_handle()); else if (::GetFocus() == host->window_handle()) ::SetFocus(NULL); } WebWidget* CefBrowserImpl::UIT_CreatePopupWidget(WebView* webview) { REQUIRE_UIT(); DCHECK(!popuphost_); popuphost_ = WebWidgetHost::Create(NULL, delegate_.get()); ShowWindow(UIT_GetPopupWndHandle(), SW_SHOW); return popuphost_->webwidget(); } void CefBrowserImpl::UIT_ClosePopupWidget() { REQUIRE_UIT(); PostMessage(UIT_GetPopupWndHandle(), WM_CLOSE, 0, 0); popuphost_ = NULL; } static void WriteTextToFile(const std::string& data, const std::wstring& file_path) { FILE* fp; errno_t err = _wfopen_s(&fp, file_path.c_str(), L"wt"); if (err) return; fwrite(data.c_str(), 1, data.size(), fp); fclose(fp); } bool CefBrowserImpl::UIT_ViewDocumentString(WebFrame *frame) { REQUIRE_UIT(); DWORD dwRetVal; DWORD dwBufSize = 512; TCHAR lpPathBuffer[512]; UINT uRetVal; TCHAR szTempName[512]; dwRetVal = GetTempPath(dwBufSize, // length of the buffer lpPathBuffer); // buffer for path if (dwRetVal > dwBufSize || (dwRetVal == 0)) return false; // Create a temporary file. uRetVal = GetTempFileName(lpPathBuffer, // directory for tmp files TEXT("src"), // temp file name prefix 0, // create unique name szTempName); // buffer for name if (uRetVal == 0) return false; size_t len = wcslen(szTempName); wcscpy(szTempName + len - 3, L"txt"); WriteTextToFile(webkit_glue::GetDocumentString(frame), szTempName); int errorCode = (int)ShellExecute(UIT_GetMainWndHandle(), L"open", szTempName, NULL, NULL, SW_SHOWNORMAL); if(errorCode <= 32) return false; return true; } void CefBrowserImpl::UIT_GetDocumentStringNotify(TargetFrame targetFrame, CefStreamWriter* writer, HANDLE hEvent) { REQUIRE_UIT(); WebFrame* frame; if(targetFrame == TF_FOCUSED) frame = UIT_GetWebView()->GetFocusedFrame(); else frame = UIT_GetWebView()->GetMainFrame(); // Retrieve the document string std::string str = webkit_glue::GetDocumentString(frame); // Write the document string to the stream writer->Write(str.c_str(), str.size(), 1); // Notify the calling thread that the data is now available SetEvent(hEvent); writer->Release(); } void CefBrowserImpl::UIT_GetDocumentTextNotify(TargetFrame targetFrame, CefStreamWriter* writer, HANDLE hEvent) { REQUIRE_UIT(); WebFrame* frame; if(targetFrame == TF_FOCUSED) frame = UIT_GetWebView()->GetFocusedFrame(); else frame = UIT_GetWebView()->GetMainFrame(); // Retrieve the document string std::wstring str = webkit_glue::DumpDocumentText(frame); std::string cstr = WideToUTF8(str); // Write the document string to the stream writer->Write(cstr.c_str(), cstr.size(), 1); // Notify the calling thread that the data is now available SetEvent(hEvent); writer->Release(); } void CefBrowserImpl::UIT_CanGoBackNotify(bool *retVal, HANDLE hEvent) { REQUIRE_UIT(); *retVal = UIT_CanGoBack(); // Notify the calling thread that the data is now available SetEvent(hEvent); } void CefBrowserImpl::UIT_CanGoForwardNotify(bool *retVal, HANDLE hEvent) { REQUIRE_UIT(); *retVal = UIT_CanGoForward(); // Notify the calling thread that the data is now available SetEvent(hEvent); } int CefBrowserImpl::UIT_SwitchFrameToPrintMediaType(WebFrame* frame) { REQUIRE_UIT(); printing::PrintParams params; print_context_.settings().RenderParams(¶ms); float ratio = static_cast(params.desired_dpi / params.dpi); float paper_width = params.printable_size.width() * ratio; float paper_height = params.printable_size.height() * ratio; float minLayoutWidth = static_cast(paper_width * params.min_shrink); float maxLayoutWidth = static_cast(paper_width * params.max_shrink); // Safari uses: 765 & 1224. Margins aren't exactly the same either. // Scale = 2.222 for MDI printer. int pages; int width; if (!frame->SetPrintingMode(true, minLayoutWidth, maxLayoutWidth, &width)) { NOTREACHED(); pages = 0; } else { // Force to recalculate the height, otherwise it reuse the current window // height as the default. float effective_shrink = static_cast(width) / paper_width; gfx::Size page_size(width, static_cast(paper_height * effective_shrink) - 1); WebView* view = frame->GetView(); if (view) { // Hack around an issue where if the current view height is higher than // the page height, empty pages will be printed even if the bottom of the // web page is empty. printing_view_size_ = view->GetSize(); view->Resize(page_size); view->Layout(); } pages = frame->ComputePageRects(params.printable_size); DCHECK(pages); } return pages; } void CefBrowserImpl::UIT_SwitchFrameToDisplayMediaType(WebFrame* frame) { REQUIRE_UIT(); // TODO(cef): Figure out how to make the frame redraw properly after printing // to PDF file (currently leaves a white rectangle behind the save as dialog). // Set the layout back to "normal" document; i.e. CSS media type = "screen". frame->SetPrintingMode(false, 0, 0, NULL); WebView* view = frame->GetView(); if (view) { // Restore from the hack described at SwitchFrameToPrintMediaType(). view->Resize(printing_view_size_); view->Layout(); printing_view_size_.SetSize(0, 0); } } void CefBrowserImpl::UIT_PrintPage(int page_number, WebFrame* frame, int total_pages) { REQUIRE_UIT(); if (printing_view_size_.width() < 0) { NOTREACHED(); return; } printing::PrintParams params; const printing::PrintSettings &settings = print_context_.settings(); settings.RenderParams(¶ms); gfx::Size src_size = frame->GetView()->GetSize(); double src_size_x = src_size.width(); double src_size_y = src_size.height(); double src_margin = .1 * src_size_x; double dest_size_x = settings.page_setup_pixels().physical_size().width(); double dest_size_y = settings.page_setup_pixels().physical_size().height(); double dest_margin = .1 * dest_size_x; print_context_.NewPage(); HDC hDC = print_context_.context(); BOOL res; // Save the state to make sure the context this function call does not modify // the device context. int saved_state = SaveDC(hDC); DCHECK_NE(saved_state, 0); // 100% GDI based. gfx::VectorCanvas canvas(hDC, (int)ceil(dest_size_x), (int)ceil(dest_size_y)); canvas.translate(SkDoubleToScalar(dest_margin), SkDoubleToScalar(dest_margin)); canvas.scale(SkDoubleToScalar((dest_size_x - dest_margin * 2) / src_size_x), SkDoubleToScalar((dest_size_y - dest_margin * 2) / src_size_y)); // Set the clipping region to be sure to not overflow. SkRect clip_rect; clip_rect.set(0, 0, SkDoubleToScalar(src_size_x), SkDoubleToScalar(src_size_y)); canvas.clipRect(clip_rect); if (!frame->SpoolPage(page_number-1, &canvas)) { NOTREACHED() << "Printing page " << page_number << " failed."; return; } res = RestoreDC(hDC, saved_state); DCHECK_NE(res, 0); if(handler_.get()) { saved_state = SaveDC(hDC); DCHECK_NE(saved_state, 0); // Gather print header state information RECT rect; rect.left = (int)floor(dest_margin / 2); rect.top = rect.left; rect.right = (int)ceil(dest_size_x - dest_margin / 2); rect.bottom = (int)ceil(dest_size_y - dest_margin / 2); double scale = (double)settings.dpi() / (double)settings.desired_dpi; CefPrintInfo printInfo; printInfo.m_hDC = hDC; printInfo.m_Rect = rect; printInfo.m_Scale = scale; std::wstring url = UTF8ToWide(frame->GetURL().spec()); std::wstring title = title_; std::wstring topLeft, topCenter, topRight; std::wstring bottomLeft, bottomCenter, bottomRight; // allow the handler to format print header and/or footer CefHandler::RetVal rv = handler_->HandlePrintHeaderFooter(this, printInfo, url, title, page_number, total_pages, topLeft, topCenter, topRight, bottomLeft, bottomCenter, bottomRight); if(rv != CefHandler::RV_HANDLED) { // Draw handler-defined headers and/or footers. LOGFONT lf; memset(&lf, 0, sizeof(lf)); lf.lfHeight = (int)ceil(10. * scale); lf.lfPitchAndFamily = FF_SWISS; HFONT hFont = CreateFontIndirect(&lf); HFONT hOldFont = (HFONT)SelectObject(hDC, hFont); COLORREF hOldColor = SetTextColor(hDC, RGB(0,0,0)); int hOldBkMode = SetBkMode(hDC, TRANSPARENT); // TODO(cef): Keep the header strings inside a reasonable bounding box // so that they don't overlap each other. if(topLeft.size() > 0) { DrawText(hDC, topLeft.c_str(), topLeft.size(), &rect, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_END_ELLIPSIS | DT_EXPANDTABS | DT_NOPREFIX); } if(topCenter.size() > 0) { DrawText(hDC, topCenter.c_str(), topCenter.size(), &rect, DT_CENTER | DT_TOP | DT_SINGLELINE | DT_END_ELLIPSIS | DT_EXPANDTABS | DT_NOPREFIX); } if(topRight.size() > 0) { DrawText(hDC, topRight.c_str(), topRight.size(), &rect, DT_RIGHT | DT_TOP | DT_SINGLELINE | DT_END_ELLIPSIS | DT_EXPANDTABS | DT_NOPREFIX); } if(bottomLeft.size() > 0) { DrawText(hDC, bottomLeft.c_str(), bottomLeft.size(), &rect, DT_LEFT | DT_BOTTOM | DT_SINGLELINE | DT_END_ELLIPSIS | DT_EXPANDTABS | DT_NOPREFIX); } if(bottomCenter.size() > 0) { DrawText(hDC, bottomCenter.c_str(), bottomCenter.size(), &rect, DT_CENTER | DT_BOTTOM | DT_SINGLELINE | DT_END_ELLIPSIS | DT_EXPANDTABS | DT_NOPREFIX); } if(bottomRight.size() > 0) { DrawText(hDC, bottomRight.c_str(), bottomRight.size(), &rect, DT_RIGHT | DT_BOTTOM | DT_SINGLELINE | DT_END_ELLIPSIS | DT_EXPANDTABS | DT_NOPREFIX); } SetTextColor(hDC, hOldColor); SelectObject(hDC, hOldFont); DeleteObject(hFont); SetBkMode(hDC, hOldBkMode); } res = RestoreDC(hDC, saved_state); DCHECK_NE(res, 0); } print_context_.PageDone(); } void CefBrowserImpl::UIT_PrintPages(WebFrame* frame) { REQUIRE_UIT(); TCHAR printername[512]; DWORD size = sizeof(printername)-1; if(GetDefaultPrinter(printername, &size)) { printing::PrintSettings settings; settings.set_device_name(printername); // Initialize it. print_context_.InitWithSettings(settings); } if(print_context_.AskUserForSettings( UIT_GetMainWndHandle(), UIT_GetPagesCount(frame)) != printing::PrintingContext::OK) return; printing::PrintParams params; const printing::PrintSettings &settings = print_context_.settings(); settings.RenderParams(¶ms); // disable the web view so we don't see printing related layout changes on // the screen UIT_DisableWebView(true); int pages = UIT_SwitchFrameToPrintMediaType(frame); if (pages) { bool old_state = MessageLoop::current()->NestableTasksAllowed(); MessageLoop::current()->SetNestableTasksAllowed(false); // TODO(cef): Use the page title as the document name print_context_.NewDocument(L"New Document"); if(settings.ranges.size() > 0) { for (unsigned i = 0; i < settings.ranges.size(); ++i) { const printing::PageRange& range = settings.ranges[i]; for(int i = range.from; i <= range.to; ++i) UIT_PrintPage(i, frame, pages); } } else { for(int i = 1; i <= pages; ++i) UIT_PrintPage(i, frame, pages); } print_context_.DocumentDone(); MessageLoop::current()->SetNestableTasksAllowed(old_state); } UIT_SwitchFrameToDisplayMediaType(frame); // re-enable web view UIT_DisableWebView(false); } int CefBrowserImpl::UIT_GetPagesCount(WebFrame* frame) { REQUIRE_UIT(); int pages = UIT_SwitchFrameToPrintMediaType(frame); UIT_SwitchFrameToDisplayMediaType(frame); return pages; } void CefBrowserImpl::UIT_CaptureWebViewBitmap(HBITMAP &bitmap, SIZE &size) { REQUIRE_UIT(); webkit_glue::CaptureWebViewBitmap(UIT_GetMainWndHandle(), UIT_GetWebView(), bitmap, size); } void CefBrowserImpl::UIT_SetWebViewBitmap(HBITMAP bitmap, SIZE size) { REQUIRE_UIT(); if(webview_bitmap_) DeleteObject(webview_bitmap_); webview_bitmap_ = bitmap; webview_bitmap_size_ = size; } void CefBrowserImpl::UIT_DisableWebView(bool val) { REQUIRE_UIT(); if(val) { // disable the web view window if(webview_bitmap_ != NULL) return; HBITMAP bitmap; SIZE size; UIT_CaptureWebViewBitmap(bitmap, size); UIT_SetWebViewBitmap(bitmap, size); DWORD dwStyle = GetWindowLong(UIT_GetWebViewWndHandle(), GWL_STYLE); SetWindowLong(UIT_GetWebViewWndHandle(), GWL_STYLE, dwStyle & ~WS_VISIBLE); RedrawWindow(UIT_GetMainWndHandle(), NULL, NULL, RDW_INVALIDATE); } else if(webview_bitmap_) { // enable the web view window SIZE size = {0,0}; UIT_SetWebViewBitmap(NULL, size); DWORD dwStyle = GetWindowLong(UIT_GetWebViewWndHandle(), GWL_STYLE); SetWindowLong(UIT_GetWebViewWndHandle(), GWL_STYLE, dwStyle | WS_VISIBLE); RedrawWindow(UIT_GetMainWndHandle(), NULL, NULL, RDW_INVALIDATE); } }