最近公司在做一个智能化股票交易的项目,需要控制股票交易软件树状图进行翻页,刚开始我使用普通的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;
}
实际情况下发送的数据是这样的:

如果仅仅使用普通的鼠标模拟消息发送过去,pt的坐标值均为负数,显然达不到效果。可是我用WriteProcessMemory将有效的坐标值和节点句柄写入这个地址再发送过去发现,TVM_HITTEST消息中的pt坐标值会瞬间变为负值,仍然失败。如果新申请一个内存进行写入,结果相同。

以下是用spy++截获的关键消息:

以下是模拟点击的代码,其中一些十六进制数值已根据实际数值进行替换
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坐标总会变成负数。
被这个问题困扰了很久,尝试过各种办法均告失败,请各位老师帮忙看看,还有没有成功的可能性。

跨进程控制SysTreeView32树状图控件的难题
- 写回答
- 好问题 0 提建议
- 关注问题
- 邀请回答
-
1条回答 默认 最新
- 红牛工作室 2015-10-01 02:02关注
打开进程
申请内存
填充结构
发送消息 sendmessage TVM_HITTEST,0,内存地址
读取内存
这样就可以跨进程操作了 ,我目前只做到遍历节点信息和坐标,获取节点状态还不会,如果你研究出来了告诉我下本回答被题主选为最佳回答 , 对您是否有帮助呢?解决 无用评论 打赏 举报