身兼兩個熱門 QQ 群的管理員,日常既要維持秩序,又要應對突發狀況。兩大痛點最讓人頭疼:
@%#%&^*),藉此篩選長期潛水者並踢出騰位置。踢人聽起來簡單,實操卻是噩夢:
@天使 改成 天@使,肉眼辨識易漏判、誤判,看得眼花撩亂。最初嘗試抓取騰訊伺服器踢人封包分析協議,卻發現全是加密亂碼,無從下手。轉念一想:何不直接操控 QQ 客戶端介面? 只要能在「群設定」的成員列表自動定位目標 QQ 號,再模擬點擊「刪除」按鈕,豈不兩全其美?
用 Spy++ 觀察發現,「群設定」視窗層層巢狀,成員列表是一個 SysListView32 控件,寄宿於 #32770 對話框中。要跨進程讀取/操作該列表,必須解決記憶體隔離問題。
EnumWindows / EnumChildWindows:層層遞歸尋找目視窗句柄VirtualAllocEx / WriteProcessMemory / ReadProcessMemory:在目標進程 (TM2006) 記憶體空間分配緩衝區,實現跨進程資料交換LVM_GETITEMCOUNT / LVM_GETITEMTEXT / LVM_SETITEMSTATE:枚舉列表項、讀取 QQ 號、選中目標行BM_CLICK:向「刪除成員」按鈕發送點擊訊息完成踢人// 在目標進程分配 LVITEM 結構與字串緩衝區
plvitem = (LVITEM*)VirtualAllocEx(hProcess, NULL, sizeof(LVITEM), MEM_COMMIT, PAGE_READWRITE);
pItem = (char*)VirtualAllocEx(hProcess, NULL, 5120, MEM_COMMIT, PAGE_READWRITE);
// 遍歷列表項
for (iItem = 0; iItem < nItemCount; iItem++) {
SendMessage(hwnd, LVM_GETITEMTEXT, iItem, (LPARAM)plvitem);
ReadProcessMemory(hProcess, pItem, ItemBuf, 512, NULL);
if (strQQNum == ItemBuf) { // 找到目標 QQ 號
SendMessage(hwnd, LVM_SETITEMSTATE, iItem, (LPARAM)&lvitemSelected);
break;
}
}
// 最後發送 BM_CLICK 給刪除按鈕
避坑指南:直接在自身進程 ListView_GetItem 會導致存取違規,因為 LVITEM 結構必須位於目標進程記憶體空間。VirtualAllocEx + ReadProcessMemory 是跨進程讀取 ListView 文字的標準範式。
工具上線後,輸入 QQ 號即可秒踢,解決了開頭兩大痛點。後來同事提新需求:「能否一次掃描所有我管理的群,把同一 QQ 號全踢了?」
思路是模擬人工:展開聯繫人面板 → 雙擊群項 → 打開群設定 → 復用現有邏輯。但面板類別 Tencent_UserBar_Class_Ver1.0 非標準控件,消息機制不明,仍在探索中。
從抓包挫敗到 UI 自動化突圍,這段經歷印證了「條條大路通羅馬」。代碼雖簡陋,卻實打實解決了實際問題。若有高人指點面板自動化,或有更優雅的跨進程方案,不吝賜教。