638 lines
12 KiB
C++
638 lines
12 KiB
C++
#include <precomp.h>
|
|
#include "iebrowser.h"
|
|
#include "mbsvc.h"
|
|
#include "main.h"
|
|
#include "../nu/ns_wc.h"
|
|
#include "../Winamp/buildtype.h"
|
|
#include <api/config/items/cfgitem.h>
|
|
#include <wa2frontend.h>
|
|
#include <windows.h>
|
|
#include <Mshtml.h>
|
|
#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
|