如何双击外部程序中treeview的某个节点

coffee36 2008-04-18 09:36:07
1-我现在要操纵一个外部程序中的TreeView控件.目前已经可以对它进行遍历,而且也能找到某一个特定的节点,但我现在想实现双击这个找到的节点,该怎么做?
2-ListView控件也是一样的问题。现在已经能够找到特定的行了,但是想双击特定的行,也就是双击ListView的Caption列该怎么实现?
我目前的做法是SendMessage(TreeViewHWD,WM_LBUTTONDBLCLK,0,0),这样似乎不行。
谢谢!

我帖上我现在的一些代码:
1-查找TreeView的代码
function TFrmMain.SearchInTreeView(ABeginItem:HTREEITEM;AName:PChar):HTREEITEM;
var
MainHWD:HWND;
TreeViewHWD:HWND;
ItemRec:TTVItem;
ItemPointer:PTVItem;
ItemText:PChar;
ItemBuf:PChar;
TextBuf:array[0..512] of char;
PID,WriteCount,ReadCount:DWord;
hProcess:HWND;
begin
result:=nil;
//查找主窗体句柄
MainHWD:=FindWindowEx(0,0,'TForm1','Form1');
//查找TreeView控件句柄
if MainHWD<>0 then
begin
TreeViewHWD:=FindWindowEx(MainHWD,0,'TTreeView',nil);
end;

GetWindowThreadProcessId(MainHWD,@PID);
hProcess:=OpenProcess(PROCESS_ALL_ACCESS,false,PID);
if hProcess=0 then
begin
Application.MessageBox('获取进程句柄操作失败!','提示',mb_ok+mb_iconinformation);
exit;
end;

ItemPointer:=PTVItem(VirtualAllocEx(hProcess,nil,sizeof(TTVItem),MEM_COMMIT,PAGE_READWRITE));
ItemText:=PChar(VirtualAllocEx(hProcess,nil,512,MEM_COMMIT, PAGE_READWRITE));
if (ItemPointer=nil)or(ItemText=nil) then
begin
Application.MessageBox('无法分配内存!','提示',mb_ok+mb_iconinformation);
exit;
end;

ItemRec.mask:=TVIF_TEXT;
ItemRec.cchTextMax:=512;
ItemRec.pszText:=ItemText;
ItemBuf:=TextBuf;

if ABeginItem<>nil then
begin
//从指定节点开始查找
ItemRec.hItem:=ABeginItem;
end else
begin
//得到根句柄
ItemRec.hItem:=HTreeItem(SendMessage(TreeViewHWD,TVM_GETNEXTITEM,TVGN_ROOT,$0));
//选中状态
SendMessage(TreeViewHWD,TVM_SELECTITEM,TVGN_CARET,LongInt(ItemRec.hItem));
//将设置好的结构插入目标进程
WriteProcessMemory(hProcess,ItemPointer,@ItemRec,sizeof(TTVItem),WriteCount);
//发送TVM_GETITEM消息
SendMessage(TreeViewHWD,TVM_GETITEM,0,LPARAM(ItemPointer));
//获取pszText
ReadProcessMemory(hProcess, ItemText,ItemBuf,512,ReadCount);

if StrComp(ItemBuf,AName)=0 then
begin
Result:=ItemRec.hItem;
SendMessage(TreeViewHWD,WM_LBUTTONDBLCLK,0,0);
VirtualFreeEx(hProcess,ItemPointer,0,MEM_RELEASE);
exit;
end;
end;

while LongInt(ItemRec.hItem)<>0 do
begin
//当此项目能展开时
while Boolean(SendMessage(TreeViewHWD,TVM_EXPAND,TVE_EXPAND,LongInt(ItemRec.hItem))) do
begin
ItemRec.hItem:=HTREEITEM(SendMessage(TreeViewHWD,TVM_GETNEXTITEM,TVGN_NEXTVISIBLE,LongInt(ItemRec.hItem)));
//选中状态
SendMessage(TreeViewHWD,TVM_SELECTITEM,TVGN_CARET,LongInt(ItemRec.hItem));
//将设置好的结构插入目标进程
WriteProcessMemory(hProcess,ItemPointer,@ItemRec,sizeof(TTVItem),WriteCount);
//发送TVM_GETITEM消息
SendMessage(TreeViewHWD,TVM_GETITEM,0,LPARAM(ItemPointer));
//获取pszText
ReadProcessMemory(hProcess, ItemText,ItemBuf,512,ReadCount);

if StrComp(ItemBuf,AName)=0 then
begin
SendMessage(TreeViewHWD,WM_LBUTTONDBLCLK,0,0);//这句实现不了双击找到的节点
Result:=ItemRec.hItem;
VirtualFreeEx(hProcess,ItemPointer,0,MEM_RELEASE);
exit;
end;
end;//如果能展开节点
ItemRec.hItem:=HTREEITEM(SendMessage(TreeViewHWD,TVM_GETNEXTITEM,TVGN_NEXTVISIBLE,LongInt(ItemRec.hItem)));
//选中状态
SendMessage(TreeViewHWD,TVM_SELECTITEM,TVGN_CARET,LongInt(ItemRec.hItem));
//将设置好的结构插入目标进程
WriteProcessMemory(hProcess,ItemPointer,@ItemRec,sizeof(TTVItem),WriteCount);
//发送TVM_GETITEM消息
SendMessage(TreeViewHWD,TVM_GETITEM,0,LPARAM(ItemPointer));
//获取pszText
ReadProcessMemory(hProcess, ItemText,ItemBuf,512,WriteCount);

if StrComp(ItemBuf,AName)=0 then
begin
SendMessage(TreeViewHWD,WM_LBUTTONDBLCLK,0,0);//这句实现不了双击找到的节点
Result:=ItemRec.hItem;
VirtualFreeEx(hProcess,ItemPointer,0,MEM_RELEASE);
exit;
end;
end;//如果有下个节点

end;

2-查找ListView的代码:
procedure TFrmMain.FindItem(AItemName: PChar);
var
Count:integer;
MainHWD:HWND;
ListViewHWD:HWND;
i:integer;
ItemRec:TLVItem;
ItemPointer:PLVItem;
ItemText:PChar;
ItemBuf:PChar;
TextBuf:array[0..512] of char;
PID,WriteCount,ReadCount:DWord;
hProcess:HWND;
begin
//查找主窗体句柄
MainHWD:=FindWindowEx(0,0,'TForm1','Form1');
//查找ListView控件句柄
if MainHWD<>0 then
begin
ListViewHWD:=FindWindowEx(MainHWD,0,'TListView',nil);
end;

//获得列表框控件的数目
Count:=SendMessage(ListViewHWD,LVM_GETITEMCOUNT,0,0);
GetWindowThreadProcessId(ListViewHWD,@PID);
hProcess:=OpenProcess(PROCESS_ALL_ACCESS,false,PID);
if hProcess=0 then
begin
Application.MessageBox('获取进程句柄操作失败!','提示',mb_ok+mb_iconinformation);
exit;
end;

ItemPointer:=PLVItem(VirtualAllocEx(hProcess,nil,SizeOf(TLVITEM),MEM_COMMIT,PAGE_READWRITE));
ItemText:=PChar(VirtualAllocEx(hProcess,nil,512,MEM_COMMIT,PAGE_READWRITE));
if (ItemPointer=nil)or(ItemText=nil) then
begin
Application.MessageBox('无法分配内存!','提示',mb_ok+mb_iconinformation);
exit;
end;

ItemRec.cchTextMax:=512;
ItemRec.pszText:=ItemText;
ItemRec.iSubItem:=0;
ItemBuf:=TextBuf;

//将设置好的结构插入目标进程
WriteProcessMemory(hProcess,ItemPointer,@ItemRec,sizeof(TLVItem)+8,WriteCount);

//遍历LISTVIEW查找指定的ITEM
for i:=0 to Count-1 do
begin
//发送TVM_GETITEM消息
SendMessage(ListViewHWD,LVM_GETITEMTEXT,WPARAM(i),LPARAM(ItemPointer));
//获取pszText
ReadProcessMemory(hProcess, ItemText,ItemBuf,512,ReadCount);
if StrComp(ItemBuf,AItemName)=0 then
begin
SendMessage(ListViewHWD,WM_LBUTTONDBLCLK,0,0);//这句实现不了双击找到的节点
VirtualFreeEx(hProcess,ItemPointer,0,MEM_RELEASE);
exit;
end;//如果找到
end;//for end

end;
...全文
699 10 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
coffee36 2008-04-21
  • 打赏
  • 举报
回复
搞定了。在上边那段代码前加上ZeroMemory就可以了。谢谢老大帮忙!
coffee36 2008-04-21
  • 打赏
  • 举报
回复
RECT Rect, *_rect;
_rect = (RECT*)VirtualAllocEx(process, NULL, sizeof(RECT), MEM_COMMIT, PAGE_READWRITE);

WriteProcessMemory(process, _rect, &Rect, sizeof(RECT), NULL);
SendMessage(hListView, LVM_GETITEMRECT, (WPARAM)i, (LPARAM)_rect);
ReadProcessMemory(process, _rect, &Rect, sizeof(RECT), NULL);

我是用的上边这段代码,把上边这段代码翻译成DELPHI的了。可是取不到坐标值,全都是很大的负值
coffee36 2008-04-21
  • 打赏
  • 举报
回复
至于如果获得其他程序中TreeView选中项的区域这个不用我再详细说吧。。。
----------------------------------------
呵呵,老大,这个我还真不会。跨进程取得其他程序中TREEVIEW或者LISTVIEW选中节点的坐标不会写,在网上查好像说是要在目标进程里边申请空间,然后再读取,也没找到例子。所以就难在这了。请老大给个指点。
王集鹄 2008-04-18
  • 打赏
  • 举报
回复
先测试当前程序如何用消息模拟,参考如下代码:
procedure TForm1.ListView1DblClick(Sender: TObject);
begin
if Assigned(TListView(Sender).Selected) then
ShowMessage(TListView(Sender).Selected.Caption);
end;

procedure TForm1.TreeView1DblClick(Sender: TObject);
begin
if Assigned(TTreeView(Sender).Selected) then
ShowMessage(TTreeView(Sender).Selected.Text);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
vRect: TRect;
begin
if not Assigned(ListView1.Selected) then Exit;
vRect := ListView1.Selected.DisplayRect(drLabel);
SendMessage(ListView1.Handle, WM_LBUTTONDBLCLK, 0,
MakeLong(vRect.Left, vRect.Top));
ListView1.SetFocus;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
vRect: TRect;
begin
if not Assigned(TreeView1.Selected) then Exit;
vRect := TreeView1.Selected.DisplayRect(True);
SendMessage(TreeView1.Handle, WM_LBUTTONDBLCLK, 0,
MakeLong(vRect.Left, vRect.Top));
TreeView1.SetFocus;
end;
至于如果获得其他程序中TreeView选中项的区域这个不用我再详细说吧。。。
coffee36 2008-04-18
  • 打赏
  • 举报
回复
呵呵。不好意思。PB的demo在客户的机器上。而且环境配置很麻烦,所以我只能隔一段时间去调试一次。我这边使用DELPHI模仿了一个。我现在就是用TVM_SELECTITEM消息来选中节点,然后获得文本。但发双击消息不知道该怎么办
zhu_gx 2008-04-18
  • 打赏
  • 举报
回复
帮顶
王集鹄 2008-04-18
  • 打赏
  • 举报
回复
-_-!!! 跨进程能直接访问TreeView1.Selected吗?还不是得通过消息或者API什么的。。。

先试试“TVM_SELECTITEM”消息选中TreeView的节点

另外有pb写的Demo没?(只要响应双击显示选中的节点文本即可)
发我一个(wjhu111#21cn.com)
coffee36 2008-04-18
  • 打赏
  • 举报
回复
我要操纵的程序是用PB写的,所以我目前只能使用Windows SDK去操纵它。

另外发送WM_LBUTTONDBLCLK消息需要计算节点的坐标,获得节点的坐标还必须在目标进程中开辟空间用来接收坐标,然后再读取,这一布我没找到相关代码,所以搞不定。

第三种响应WM_NOTIFY消息中NM_DBLCLK方式
---------------------------------------
WM_NOTIFY消息中的NMHDR这个结构体不知道在Delphi里怎么填写。而且感觉里边的成员变量没有指明是哪个触发的。我按照自己的想法填写后,也没有实现双击。
王集鹄 2008-04-18
  • 打赏
  • 举报
回复
如果是在当前程序该如何处理双击事件?
procedure TForm1.ListView1DblClick(Sender: TObject);
begin
//
end;

procedure TForm1.TreeView1DblClick(Sender: TObject);
begin
//
end;


第二种可能是通过:ListView1.Selected、TreeView1.Selected判断
那么只要先选中项再模拟双击

第二种可能是通过:ListView1.GetItemAt()、TreeView1.GetNodeAt()判断
那么需要计算鼠标点击的位置

WM_LBUTTONDBLCLK
fwKeys = wParam; // key flags
xPos = LOWORD(lParam); // horizontal position of cursor
yPos = HIWORD(lParam); // vertical position of cursor

第三种响应WM_NOTIFY消息中NM_DBLCLK方式
先试试前两种,这个再议
王集鹄 2008-04-18
  • 打赏
  • 举报
回复
裤衩多了,问问题就是清楚。意思明白,先关注,有空调试看看。

1,183

社区成员

发帖
与我相关
我的任务
社区描述
Delphi Windows SDK/API
社区管理员
  • Windows SDK/API社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧