#include #include "iebrowser.h" #include "mbsvc.h" #include "main.h" #include "../nu/ns_wc.h" #include "../Winamp/buildtype.h" #include #include #include #include #include "minibrowserCOM.h" class BrowserMsgProc: public ifc_messageprocessor { public: BrowserMsgProc(BrowserWnd *pBrowser) : pTarget(pBrowser) {} ~BrowserMsgProc(void) {} public: bool ProcessMessage(MSG *pMsg) { if (WM_KEYFIRST <= pMsg->message && WM_KEYLAST >= pMsg->message) { HWND hwndHost; hwndHost = pTarget->gethWnd(); if ((hwndHost == pMsg->hwnd || IsChild(hwndHost, pMsg->hwnd)) && IsWindowVisible(pMsg->hwnd)) { if (!(GetAsyncKeyState(VK_CONTROL)&0x8000) && !(GetAsyncKeyState(VK_MENU)&0x8000)) { if (pTarget->TranslateKey(pMsg)) return true; } switch(pMsg->message) { case WM_KEYDOWN: case WM_SYSKEYDOWN: case WM_KEYUP: case WM_SYSKEYUP: switch(pMsg->wParam) { case VK_F1: if (!(GetAsyncKeyState(VK_SHIFT)&0x8000)) pMsg->hwnd = plugin.hwndParent; break; case VK_F4: if ((pMsg->message == WM_KEYDOWN || pMsg->message == WM_SYSKEYDOWN) && (GetAsyncKeyState(VK_MENU)&0x8000)) SendMessageW(plugin.hwndParent, WM_CLOSE, 0, 0); pMsg->message = WM_NULL; break; case 'P': case 'K': case 'H': case VK_TAB: if ((GetAsyncKeyState(VK_CONTROL)&0x8000) && !(GetAsyncKeyState(VK_MENU)&0x8000)) pMsg->hwnd = plugin.hwndParent; break; case '3': case VK_UP: case VK_DOWN: break; default: if ((GetAsyncKeyState(VK_MENU)&0x8000) && !(GetAsyncKeyState(VK_CONTROL)&0x8000)) pMsg->hwnd = plugin.hwndParent; break; } break; } } } return /*(IsDialogMessageW(pTarget->gethWnd(), pMsg)) ? true :*/ false; } protected: BrowserWnd *pTarget; RECVS_DISPATCH; }; extern HINSTANCE hInstance; STDAPI WriteBSTR(BSTR *pstrDest, LPCWSTR szSrc) { *pstrDest = SysAllocString( szSrc ); if ( !(*pstrDest) ) return E_OUTOFMEMORY; return NOERROR; } STDAPI FreeBSTR(BSTR* pstr) { if ( *pstr == NULL ) return S_FALSE; SysFreeString( *pstr ); return NOERROR; } HRESULT writeBString(BSTR* psz, const char *str) { WCHAR WideStr[WA_MAX_PATH] = {0}; String s = str; if (s.isempty()) s = ""; MultiByteToWideCharSZ(CP_ACP, 0, s, -1, WideStr, WA_MAX_PATH); return WriteBSTR(psz, WideStr); } BrowserWnd::BrowserWnd() : HTMLContainer2(NULL, NULL), processor(NULL) { setVirtual(0); oleOk = FALSE; homepage = L"about:blank"; timerset1 = 0; timerset2 = 0; cancelIEErrorPage = false; scrollbarsflag = BROWSER_SCROLLBARS_DEFAULT; } BrowserWnd::~BrowserWnd() { if (processor) { if (WASABI_API_APP) WASABI_API_APP->app_removeMessageProcessor(processor); free(processor); processor = NULL; } if (timerset1) { killTimer(MB_TIMERID1); timerset1 = 0; } if (timerset2) { killTimer(MB_TIMERID2); timerset2 = 0; } freeBrowserStuff(); } bool BrowserWnd::InitializeLibrary() { return (FALSE != HTMLContainer2_Initialize()); } void BrowserWnd::UninitializeLibrary() { HTMLContainer2_Uninitialize(); } int BrowserWnd::onInit() { BROWSER_PARENT::onInit(); if (isVisible()) onSetVisible(1); updateScrollbars(); return 1; } void BrowserWnd::onSetVisible(int show) { if (show) initBrowserStuff(); } int BrowserWnd::initBrowserStuff() { if (pUnk) return 1; if (SUCCEEDED(OleInitialize(NULL))) oleOk = TRUE; if (!oleOk) return 1; // {280876CF-48C0-40bc-8E86-73CE6BB462E5} const GUID options_guid = { 0x280876cf, 0x48c0, 0x40bc, { 0x8e, 0x86, 0x73, 0xce, 0x6b, 0xb4, 0x62, 0xe5 } }; hParent = gethWnd(); int usemozilla = 0; #ifdef WASABI_COMPILE_CONFIG usemozilla = _intVal(WASABI_API_CONFIG->config_getCfgItemByGuid(options_guid), L"Use Mozilla instead of IE for minibrowser"); #endif if (SUCCEEDED(Initialize())) { HRESULT hr; IWebBrowser2 *pWeb2; hr = GetIWebBrowser2(&pWeb2); if (SUCCEEDED(hr)) { pWeb2->put_RegisterAsBrowser(VARIANT_TRUE); if (deferednavigate.isempty()) { if (!homepage.isempty()) minibrowser_navigateUrl(homepage); else minibrowser_navigateUrl(L"about:blank"); } else minibrowser_navigateUrl(deferednavigate); } } if (!processor && WASABI_API_APP) { processor = new BrowserMsgProc(this); WASABI_API_APP->app_addMessageProcessor(processor); } ShowWindow(hParent, SW_SHOWNA); return 1; } void BrowserWnd::freeBrowserStuff() { if (oleOk) { Finish(); OleUninitialize(); oleOk = FALSE; #ifndef WASABINOMAINAPI api->hint_garbageCollect(); #endif } } int BrowserWnd::minibrowser_navigateUrl(const wchar_t *url) { HRESULT hr; curpage = url; hr = NavigateToName(url, 0); if (FAILED(hr)) { deferednavigate = url; return 0; } return 1; } int BrowserWnd::minibrowser_back() { HRESULT hr; IWebBrowser2 *pWeb2; hr = GetIWebBrowser2(&pWeb2); if (SUCCEEDED(hr)) { pWeb2->GoBack(); pWeb2->Release(); } return 1; } int BrowserWnd::minibrowser_forward() { HRESULT hr; IWebBrowser2 *pWeb2; hr = GetIWebBrowser2(&pWeb2); if (SUCCEEDED(hr)) { pWeb2->GoForward(); pWeb2->Release(); } return 1; } int BrowserWnd::minibrowser_refresh() { HRESULT hr; IWebBrowser2 *pWeb2; hr = GetIWebBrowser2(&pWeb2); if (SUCCEEDED(hr)) { pWeb2->Refresh(); pWeb2->Release(); } return 1; } int BrowserWnd::minibrowser_home() { minibrowser_navigateUrl(homepage); return 1; } int BrowserWnd::minibrowser_stop() { HRESULT hr; IWebBrowser2 *pWeb2; hr = GetIWebBrowser2(&pWeb2); if (SUCCEEDED(hr)) { pWeb2->Stop(); pWeb2->Release(); } return 1; } HWND BrowserWnd::getOSHandle() { return ::GetWindow(gethWnd(), GW_CHILD); // assumes setVirtual(0) in constructor } void BrowserWnd::onTargetNameTimer() { updateTargetName(); } void BrowserWnd::onScrollbarsFlagTimer() { updateScrollbars(); } void BrowserWnd::timerCallback(int id) { switch (id) { case MB_TIMERID1: onTargetNameTimer(); return ; case MB_TIMERID2: onScrollbarsFlagTimer(); return ; } BROWSER_PARENT::timerCallback(id); } void BrowserWnd::minibrowser_setTargetName(const wchar_t *name) { targetname = name; updateTargetName(); } void BrowserWnd::updateTargetName() { if (!doSetTargetName(targetname)) { if (!timerset1) { setTimer(MB_TIMERID1, 100); timerset1 = 1; } return ; } else { if (timerset1) { killTimer(MB_TIMERID1); timerset1 = 0; } } } int BrowserWnd::doSetTargetName(const wchar_t *name) { HRESULT hr; IWebBrowser2 *pWeb2; IDispatch *id; hr = GetIWebBrowser2(&pWeb2); if (FAILED(hr)) return FALSE; if (SUCCEEDED(pWeb2->get_Document(&id)) && id) { IHTMLDocument2 *doc; if (SUCCEEDED(id->QueryInterface(IID_IHTMLDocument2, (void **)&doc)) && doc) { IHTMLWindow2 *w; if (SUCCEEDED(doc->get_parentWindow(&w)) && w) { w->put_name(SysAllocString(targetname.getValue())); w->Release(); doc->Release(); id->Release(); pWeb2->Release(); return 1; } doc->Release(); } id->Release(); } pWeb2->Release(); return 0; } const wchar_t *BrowserWnd::minibrowser_getTargetName() { return targetname; } void BrowserWnd::OnBeforeNavigate(IDispatch *pDispatch, VARIANT *URL, VARIANT *Flags, VARIANT *TargetFrameName, VARIANT *PostData, VARIANT *Headers, VARIANT_BOOL *Cancel) { int i = 0; foreach(callbacks) int r = callbacks.getfor()->minibrowsercb_onBeforeNavigate(URL->bstrVal, Flags->intVal, TargetFrameName->bstrVal); if (i++ == 0) *Cancel = (r) ? VARIANT_TRUE : VARIANT_FALSE; endfor; updateScrollbars(); } void BrowserWnd::minibrowser_setScrollbarsFlag(int a) { scrollbarsflag = a; updateScrollbars(); } void BrowserWnd::updateScrollbars() { if (!doSetScrollbars()) { if (!timerset2) { setTimer(MB_TIMERID2, 100); timerset2 = 1; } return ; } else { if (timerset2) { killTimer(MB_TIMERID2); timerset2 = 0; } } } void BrowserWnd::OnDocumentComplete(IDispatch *pDispatch, VARIANT *URL) { if (!targetname.isempty()) minibrowser_setTargetName(targetname); foreach(callbacks) callbacks.getfor()->minibrowsercb_onDocumentComplete(URL->bstrVal); endfor; updateScrollbars(); } void BrowserWnd::OnDocumentReady(IDispatch *pDispatch, VARIANT *URL) { if (!targetname.isempty()) minibrowser_setTargetName(targetname); foreach(callbacks) callbacks.getfor()->minibrowsercb_onDocumentReady(URL->bstrVal); endfor; updateScrollbars(); } void BrowserWnd::OnNavigateError(IDispatch *pDispatch, VARIANT *URL, VARIANT *TargetFrameName, VARIANT *StatusCode, VARIANT_BOOL *Cancel) { if (TargetFrameName->bstrVal != NULL) return; //TODO: send targetframe via api to script foreach(callbacks) callbacks.getfor()->minibrowsercb_onNavigateError(URL->bstrVal, StatusCode->intVal); endfor; if (cancelIEErrorPage) *Cancel = -1; } const wchar_t* BrowserWnd::messageToMaki(wchar_t* str1, wchar_t* str2, int i1, int i2, int i3) { const wchar_t* ret = 0; foreach(callbacks) ret = callbacks.getfor()->minibrowsercb_messageToMaki(str1, str2, i1, i2, i3); if (ret) break; endfor; return ret; } const wchar_t* BrowserWnd::minibrowser_messageToJS(const wchar_t* str1, const wchar_t* str2, int i1, int i2, int i3) { // TODO feed JS w/ this info return 0; } void BrowserWnd::minibrowser_scrape() { IWebBrowser2 *browser=0; GetIWebBrowser2(&browser); IDispatch *docDisp=0; IHTMLDocument2 *document = 0; if (browser) { browser->get_Document(&docDisp); if (docDisp) { docDisp->QueryInterface(&document); docDisp->Release(); } browser->Release(); } if (document) { IHTMLElementCollection *links=0; document->get_all(&links); if (links) { IDispatch *anchorDisp=0; VARIANT index; VariantInit(&index); index.vt = VT_I4; index.intVal = 0; links->item(index, index, &anchorDisp); while (anchorDisp) { IHTMLAnchorElement *anchor=0; anchorDisp->QueryInterface(&anchor); if (anchor) { BSTR href=0; anchor->get_href(&href); if (href && (wa2.CanPlay(href) || wa2.IsPlaylist(href))) { foreach(callbacks) callbacks.getfor()->minibrowsercb_onMediaLink(href); endfor; } SysFreeString(href); anchor->Release(); } index.intVal++; anchorDisp->Release(); links->item(index, index, &anchorDisp); } links->Release(); } document->Release(); } } void BrowserWnd::minibrowser_getDocumentTitle(wchar_t *str, size_t len) { IWebBrowser2 *browser=0; GetIWebBrowser2(&browser); IDispatch *docDisp=0; IHTMLDocument2 *document = 0; if (browser) { browser->get_Document(&docDisp); if (docDisp) { docDisp->QueryInterface(&document); docDisp->Release(); } browser->Release(); } if (document) { BSTR title_bstr; document->get_title(&title_bstr); document->Release(); WCSCPYN(str, title_bstr, len); // the COM object SysAllocString'd this for us, so we need to free it via COM also SysFreeString(title_bstr); } else str[0]=0; } void BrowserWnd::minibrowser_setCancelIEErrorPage (bool cancel) { cancelIEErrorPage = cancel; } int BrowserWnd::doSetScrollbars() { HRESULT hr; IWebBrowser2 *pWeb2; IDispatch *id; hr = GetIWebBrowser2(&pWeb2); if (FAILED(hr)) return 0; if (scrollbarsflag == BROWSER_SCROLLBARS_DEFAULT) return 1; if (SUCCEEDED(pWeb2->get_Document(&id)) && id) { IHTMLDocument2 *doc; if (SUCCEEDED(id->QueryInterface(IID_IHTMLDocument2, (void **)&doc)) && doc) { IHTMLElement *e; if (SUCCEEDED(doc->get_body(&e))) { IHTMLStyle *s; if (SUCCEEDED(e->get_style(&s))) { BSTR a; switch (scrollbarsflag) { case BROWSER_SCROLLBARS_ALWAYS: writeBString(&a, "scroll"); break; case BROWSER_SCROLLBARS_AUTO: writeBString(&a, "auto"); break; case BROWSER_SCROLLBARS_NEVER: writeBString(&a, "hidden"); break; default: a = NULL; break; } if (a) s->put_overflow(a); FreeBSTR(&a); s->Release(); pWeb2->Release(); return 1; } e->Release(); } doc->Release(); } id->Release(); } pWeb2->Release(); return 0; } const wchar_t *BrowserWnd::minibrowser_getCurrentUrl() { return curpage; } STDMETHODIMP BrowserWnd::GetExternal(IDispatch __RPC_FAR *__RPC_FAR *ppDispatch) { *ppDispatch = (IDispatch*) new MinibrowserCOM(this); //TODO we might need to delete this as well! return S_OK; } DWORD BrowserWnd::OnGetDownlodFlags(void) { return DLCTL_DLIMAGES | DLCTL_VIDEOS | DLCTL_PRAGMA_NO_CACHE #ifdef WINAMP_FINAL_BUILD |DLCTL_SILENT #endif ; } #define CBCLASS BrowserMsgProc START_DISPATCH; CB(IFC_MESSAGEPROCESSOR_PROCESS_MESSAGE, ProcessMessage) END_DISPATCH; #undef CBCLASS