最近公司在做一個智能化股票交易的項目,需要控制股票交易軟件樹狀圖進行翻頁,剛開始我使用普通的WM_LBUTTONDOWN和WM_LBUTTONUP消息進行發送,發現只是實現了選擇樹狀圖節點,而沒有達到實際效果,也就是控制頁面跳轉,遂懷疑是WM_NCHITTEST的問題,可是加入了WM_NCHITTEST消息,並把截獲的消息全部依次發送後,仍無法成功。
後來發現在WM_LBUTTONUP消息後,有一個關鍵的TVM_HITTEST我沒有進行處理,此時得知這個SysTreeView32的觸發事件並不是ItemSelected,而是在鼠標點擊時通過HitTest獲取點擊的節點,再觸發下一步動作。
TVM_HITTEST消息向樹狀圖發送了一個地址,這個地址指向一個TV_HITTESTINFO結構數據:
public struct TV_HITTESTINFO
{
public POINTAPI pt;
public int flags;
public UInt32 hItem;
}
實際情況下發送的數據是這樣的:
![](http://113.11.198.136:82/FileStore/1.jpg)
如果僅僅使用普通的鼠標模擬消息發送過去,pt的坐標值均為負數,顯然達不到效果。可是我用WriteProcessMemory將有效的坐標值和節點句柄寫入這個地址再發送過去發現,TVM_HITTEST消息中的pt坐標值會瞬間變為負值,仍然失敗。如果新申請一個內存進行寫入,結果相同。
![](http://113.11.198.136:82/FileStore/2.jpg)
以下是用spy++截獲的關鍵消息:
![](http://113.11.198.136:82/FileStore/3.jpg)
以下是模擬點擊的代碼,其中一些十六進制數值已根據實際數值進行替換
class Test
{
private int Handle, MainHandle, PID;
public Test(int handle, int mainHandle, int pid)
{
this.Handle = handle; this.MainHandle = mainHandle; this.PID = pid;
pHandle = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, false, PID);
}
public void SelectTreeItem()
{
int rtn;
//windows鼠標消息
rtn = SendMessage(Handle, WM_NCHITTEST, 0x0, 0xAB0068); //0xAB0068是屏幕鼠標的坐標
rtn = SendMessage(Handle, WM_MOUSEACTIVATE, MainHandle, 0x2010001);
rtn = SendMessage(Handle, WM_SETCURSOR, Handle, 0x2010001);
//左鍵按下
rtn = PostMessage(Handle, WM_LBUTTONDOWN, 0x1, 0x9001D); //0x9001D是樹狀圖內鼠標點擊的相對坐標
//刷新樹狀圖
rtn = SendMessage(Handle, WM_GETDLGCODE, 0x0, 0x0);
rtn = PostMessage(Handle, WM_PAINT, 0x0, 0x0);
//左鍵彈起
rtn = PostMessage(Handle, WM_LBUTTONUP, 0x0, 0x9001D); //0x9001D是樹狀圖內鼠標點擊的相對坐標
//改變節點
rtn = SendMessage(Handle, WM_CAPTURECHANGED, 0x0, 0x0);
//HitTest欺騙
Hittest();
rtn = SendMessage(Handle, TVM_HITTEST, 0x0, 0x18F2AC); //0x18F2AC儲存TV_HITTESTINFO結構數據
//選擇節點
rtn = SendMessage(Handle, TVM_SELECTITEM, 0x9, 0x661770); //0x661770是目標節點的句柄(根據實際情況更改)
rtn = SendMessage(Handle, WM_NCHITTEST, 0x0, 0xAB0068);
}
private void Hittest()
{
TV_HITTESTINFO NewItem = default(TV_HITTESTINFO);
NewItem.pt = new POINTAPI(29, 9);
NewItem.flags = TVHT_ONITEM | TVHT_ONITEMRIGHT | TVHT_BELOW | TVHT_TORIGHT | TVHT_TOLEFT | 0x77615080;
NewItem.hItem = 0xF4F25FD0;
WriteProcessMemory(pHandle, 0x18F2AC, NewItem, Marshal.SizeOf(typeof(TV_HITTESTINFO)), 0);
}
}
地址0x18F2AC也嘗試過自行申請內存,結果同樣。 無論怎麼控制TV_HITTESTINFO數據,它的pt坐標總會變成負數。
被這個問題困擾了很久,嘗試過各種辦法均告失敗,請各位老師幫忙看看,還有沒有成功的可能性。
打開進程
申請內存
填充結構
發送消息 sendmessage TVM_HITTEST,0,內存地址
讀取內存
這樣就可以跨進程操作了 ,我目前只做到遍歷節點信息和坐標,獲取節點狀態還不會,如果你研究出來了告訴我下