| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413 | #include "main.h"#include "./browserThread.h"#include "../nu/threadname.h"#include <exdisp.h>typedef struct __BROWSERTHREADCRAEATEPARAM{	BTCREATEWNDPROC fnCreateWnd;	BTKEYFILTERPROC fnKeyFilter;	ULONG_PTR		user;	HANDLE			readyEvent;	HWND				hHost;	HWND				hWinamp;} BROWSERTHREADCREATEPARAM;typedef struct __BROWSERTHREAD{	HHOOK	messageHook;	HANDLE	wakeupEvent;	UINT	flags;} BROWSERTHREAD;#define NAVIGATE_WAITTIMEOUT		30static size_t tlsIndex = TLS_OUT_OF_INDEXES;static UINT BHTM_DESTROY = 0xFEFE;static DWORD CALLBACK BrowserThread_MainLoop(LPVOID param);#define GetThreadInstance() ((TLS_OUT_OF_INDEXES != tlsIndex) ? (BROWSERTHREAD*)Plugin_TlsGetValue(tlsIndex) : NULL)BOOL BrowserThread_IsQuiting(){	BROWSERTHREAD *thread = GetThreadInstance();	return (NULL == thread || 0 != ((BHTF_BEGINDESTROY | BHTF_QUITLOOP) & thread->flags));}BOOL BrowserThread_SetFlags(UINT flags, UINT flagsMask, BOOL fAlarm){	BROWSERTHREAD *thread = GetThreadInstance();	if (NULL == thread) return FALSE;		thread->flags = ((thread->flags & flagsMask) | flags);	if (FALSE == fAlarm)		return TRUE;	return (NULL != thread->wakeupEvent && SetEvent(thread->wakeupEvent));}HANDLE BrowserThread_Create(HWND hWinamp, BTCREATEWNDPROC fnCreateWnd, ULONG_PTR user, BTKEYFILTERPROC fnKeyFilter, HWND *pWnd, DWORD *pThreadId){	if (NULL == fnCreateWnd)		return NULL;	if (TLS_OUT_OF_INDEXES == tlsIndex)	{		tlsIndex = Plugin_TlsAlloc();		if (TLS_OUT_OF_INDEXES == tlsIndex)			return NULL;	}	DWORD threadId;		BROWSERTHREADCREATEPARAM param;	ZeroMemory(¶m, sizeof(BROWSERTHREADCREATEPARAM));	param.fnCreateWnd = fnCreateWnd;	param.fnKeyFilter = fnKeyFilter;	param.user = user;	param.readyEvent = CreateEvent(0, TRUE, FALSE, 0); 	param.hWinamp = hWinamp;	HANDLE hThread = CreateThread(NULL, 0, BrowserThread_MainLoop, (LPVOID)¶m, 0, &threadId);		if (NULL != hThread)	{		if (NULL != param.readyEvent)			WaitForSingleObject(param.readyEvent, INFINITE);	}	else	{		if (NULL != param.hHost)		{			DestroyWindow(param.hHost);			param.hHost = NULL;		}		threadId = 0;	}	if (NULL != param.readyEvent)		CloseHandle(param.readyEvent);	if (NULL != pThreadId)		*pThreadId = threadId;	if (NULL != pWnd)		*pWnd = param.hHost;	return hThread;}BOOL BrowserThread_PostDestroyEx(DWORD threadId, HWND hHost){	if (0 == BHTM_DESTROY)		BHTM_DESTROY = RegisterWindowMessage(L"omBrowserDestroyMsg");	if (0 == BHTM_DESTROY || 		FALSE == PostThreadMessage(threadId, BHTM_DESTROY, 0, (LPARAM)hHost))	{		return FALSE;	}	BrowserThread_SetFlags(BHTF_BEGINDESTROY, BHTF_BEGINDESTROY, FALSE);	return TRUE;}BOOL BrowserThread_PostDestroy(HWND hHost){	return BrowserThread_PostDestroyEx(GetCurrentThreadId(), hHost);}BOOL BrowserThread_WaitNavigateComplete(IWebBrowser2 *pWeb2, UINT waitMax){	MSG msg;	READYSTATE state;	if (NULL == pWeb2)		return FALSE;	BOOL resultOk = FALSE;	DWORD tickStart = GetTickCount();	for(;;)	{		if (FAILED(pWeb2->get_ReadyState(&state)))			break;		if (READYSTATE_INTERACTIVE <= state)		{			resultOk = TRUE;			break;		}		else		{			DWORD tickNow = GetTickCount();			if (tickNow < tickStart || (tickNow - tickStart) >= waitMax)			{				break; // time out			}		}		DWORD status = MsgWaitForMultipleObjectsEx(0, NULL, NAVIGATE_WAITTIMEOUT, QS_POSTMESSAGE | QS_TIMER | QS_SENDMESSAGE, MWMO_ALERTABLE);		switch(status)		{			case (WAIT_OBJECT_0 + 0):				while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 				{					if (!CallMsgFilter(&msg, MSGF_BROWSERLOOP))					{						DispatchMessageW(&msg);					}				}				break;		}	}	return resultOk;}static BOOL BrowserThread_HandleMessage(MSG *pMsg){	switch(pMsg->message)	{		case WM_QUIT:			BrowserThread_SetFlags(BHTF_QUITLOOP, BHTF_QUITLOOP, TRUE);			return TRUE;	}	if (0 != BHTM_DESTROY && BHTM_DESTROY == pMsg->message)	{		HWND hHost = (HWND)pMsg->lParam;		if (NULL != hHost)		{			BrowserThread_SetFlags(BHTF_BEGINDESTROY, BHTF_BEGINDESTROY, FALSE);			SendMessage(hHost, BTM_RELEASECONTAINER, 0, 0L);			DestroyWindow(hHost);		}        return TRUE;	}	return FALSE;}static LRESULT CALLBACK BrowserThread_MessageFilterProc(INT code, WPARAM wParam, LPARAM lParam){	BROWSERTHREAD *thread = GetThreadInstance();	if (code >= 0)	{		if (BrowserThread_HandleMessage((MSG*)lParam)) 		{			return TRUE;		}	}	return (NULL != thread && NULL != thread->messageHook) ? 				CallNextHookEx(thread->messageHook, code, wParam, lParam) : 				FALSE;}static BOOL CALLBACK BrowserThread_DefaultKeyFilter(HWND hwnd, MSG *pMsg){	return FALSE;}inline static BOOL BrowserThread_ProcessMessage(HWND hHost, HWND hWinamp, MSG *pMsg, BTKEYFILTERPROC IsHostMessage){	if (hHost != pMsg->hwnd && FALSE == IsChild(hHost, pMsg->hwnd))		return FALSE;	if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)	{		if (FALSE != IsHostMessage(hHost, pMsg))			return TRUE;		switch(pMsg->wParam)		{			case VK_TAB:				{					HWND hOwner = (HWND)(LONG_PTR)GetWindowLongPtr(hHost, GWLP_HWNDPARENT);					if (NULL == hOwner || hWinamp == hOwner) 						hOwner = hHost;					return IsDialogMessageW(hOwner, pMsg);				}				break;		}	}	if (pMsg->message == WM_MOUSEWHEEL)	{		POINT cursor;		HWND targetWindow;		POINTSTOPOINT(cursor, pMsg->lParam);		targetWindow = WindowFromPoint(cursor);		if (NULL != targetWindow && 			FALSE == IsChild(hHost, targetWindow ) &&			GetWindowThreadProcessId(targetWindow, NULL) != GetWindowThreadProcessId(hHost, NULL))		{			PostMessage(hWinamp, pMsg->message, pMsg->wParam, pMsg->lParam);			return TRUE;		}	}	return FALSE;}static void BrowserThread_FinishThread(BROWSERTHREAD *thread){	if (NULL != thread)	{		if (NULL != thread->messageHook)		{			UnhookWindowsHookEx(thread->messageHook);			thread->messageHook = NULL;		}		if (NULL != thread->wakeupEvent)		{			CloseHandle(thread->wakeupEvent);			thread->wakeupEvent = NULL;		}	}	if (TLS_OUT_OF_INDEXES != tlsIndex)		Plugin_TlsSetValue(tlsIndex, NULL);	OleUninitialize();  #ifdef _DEBUG	aTRACE_FMT("[%d] %S: thread exit\r\n", GetCurrentThreadId(), OMBROWSER_NAME);  #endif // _DEBUG}static DWORD CALLBACK BrowserThread_MainLoop(LPVOID param){#ifdef _DEBUG	SetThreadName(GetCurrentThreadId(), "omBrowserThread");	aTRACE_FMT("[%d] %S: thread created\r\n", GetCurrentThreadId(), OMBROWSER_NAME);#endif //_DEBUG	BROWSERTHREADCREATEPARAM *createParam = (BROWSERTHREADCREATEPARAM*)param;	HWND hWinamp = createParam->hWinamp;	BROWSERTHREAD thread;	ZeroMemory(&thread, sizeof(BROWSERTHREAD));	if (TLS_OUT_OF_INDEXES != tlsIndex)		Plugin_TlsSetValue(tlsIndex, &thread);	MSG msg;	PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);	BTKEYFILTERPROC IsHostMessage = (NULL != createParam->fnKeyFilter) ? createParam->fnKeyFilter : BrowserThread_DefaultKeyFilter;	thread.messageHook = SetWindowsHookEx(WH_MSGFILTER, BrowserThread_MessageFilterProc, NULL, GetCurrentThreadId()); 	thread.wakeupEvent = CreateEvent(NULL, FALSE, FALSE, NULL);	HWND hHost = createParam->fnCreateWnd(createParam->user);	createParam->hHost = hHost;#ifdef _DEBUG	if (NULL != hHost)		aTRACE_FMT("[%d] %S: host created\r\n", GetCurrentThreadId(), OMBROWSER_NAME);	else		aTRACE_FMT("[%d] %S: host creation fialed\r\n", GetCurrentThreadId(), OMBROWSER_NAME);#endif //_DEBUG	if (NULL != createParam->readyEvent)		SetEvent(createParam->readyEvent);	if (NULL != hHost && FAILED(OleInitialize(0)))	{		DestroyWindow(hHost);		hHost = NULL;	}	if (NULL == hHost)	{		BrowserThread_FinishThread(&thread);		return -1;	}	SendMessage(hHost, BTM_INITCONTAINER, (WPARAM)hWinamp, 0L);	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);	while (0 == (BHTF_QUITLOOP & thread.flags))	{		DWORD status = MsgWaitForMultipleObjectsEx(1, &thread.wakeupEvent, INFINITE, 							QS_ALLPOSTMESSAGE | QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);		switch(status)		{			case (WAIT_OBJECT_0 + 0):				// wake up!!!				break;			case (WAIT_OBJECT_0 + 1):				while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 				{					if (!CallMsgFilter(&msg, MSGF_BROWSERLOOP) && NULL != msg.hwnd)					{						if (0 == (BHTF_BEGINDESTROY & thread.flags))						{							if (FALSE == BrowserThread_ProcessMessage(hHost, hWinamp, &msg, IsHostMessage))							{								TranslateMessage(&msg);									DispatchMessageW(&msg);							}						}						else						{							DispatchMessageW(&msg);						}					}				}				break;		}	}	BrowserThread_FinishThread(&thread);	return 0;}INT BrowserThread_ModalLoop(HWND hwnd, HANDLE hCancel, DWORD timeout){	MSG msg;	for (;;)	{		DWORD status = MsgWaitForMultipleObjectsEx(1, &hCancel, timeout, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);		if (WAIT_OBJECT_0 == status)		{			return 0;		}		else if ((WAIT_OBJECT_0  + 1) == status)		{			while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))			{				if (msg.message == WM_QUIT)				{					PostQuitMessage((INT)msg.wParam);					return (INT)msg.wParam;				}				if (!IsDialogMessageW(hwnd, &msg))				{					TranslateMessage(&msg);					DispatchMessageW(&msg);				}			}		}	}	return 0;}
 |