通过spy++我们可以发现类ATL:30A57F50为treeview控件
我们需实现如下对treeview的操作
1),遍历获取信息 2),单选 3),多选
操作其他进程的步骤这个不区分语言的,一般实现过程如下
1),打开远程进程,这个调用API 函数 OpenProcess来实现
2),分配远程内存,调用API VirtualAllocEx 来实现,当然不是绝对的,当操作是不需要对象,而是通过SendMessage直接返回时就不需要分配
3),内存复制,由本地进程内存复制到远程进程内存,使用WriteProcessMemory来实现,同上不是绝对,只有调用需要读取对象信息时,才有需要
4),发送消息,发送消息就不用说了SendMessage
5),上面发送的消息结果,如果是写入对象的话,那么我们需要读取远程内存到本地和3相反,ReadProcessMemory
6),完了?,没有的.资源没释放,OK,释放资源,一般意义上就完成了
上面所有的步骤在vc里一般都这样实现的
我来讲解一下在C#如何实现操作其他进程的TreeView
1),获取Treeview控件句柄使用API FindWindowEx来实现,下面这个函数是找出所有控件,可以调用之后判断className来获取到控件指针
public static List<IntPtr> FindControl(IntPtr hwnd, string className, string title = null)
{
List<IntPtr> controls = new List<IntPtr>();
IntPtr handle = IntPtr.Zero;
while (true)
{
IntPtr tmp = handle;
handle = WinAPIHelper.FindWindowEx(hwnd, tmp, className, title);
if (handle != IntPtr.Zero)
{
controls.Add(handle);
}
else
break;
}
return controls;
}
2),读取item
a),获取根节点
int retval = WinAPIHelper.SendMessage(hwnd, (int)WinAPIHelper.TV_Messages.TVM_GETNEXTITEM, (int)WinAPIHelper.TVM_GETNEXTITEM.TVGN_ROOT, IntPtr.Zero);
,返回值为节点指针
b),选择获取到的项
int r1 = WinAPIHelper.SendMessage(hwnd, (int)WinAPIHelper.TV_Messages.TVM_SELECTITEM, (int)WinAPIHelper.TVM_GETNEXTITEM.TVGN_CARET, new IntPtr(retval));
,返回值为操作结果
c),展开选中项
int r2 = WinAPIHelper.SendMessage(hwnd, (int)WinAPIHelper.TV_Messages.TVM_EXPAND, (int)WinAPIHelper.TVM_EXPAND.TVE_EXPAND, new IntPtr(retval));
,返回操作结果
d),声明ITEM并写入远程内存
WinAPIHelper.TVITEM tvItem = new WinAPIHelper.TVITEM();
int size = Marshal.SizeOf(tvItem);
tvItem.mask = WinAPIHelper.TVIF_TEXT;
tvItem.hItem = (IntPtr)retval;
tvItem.pszText = (IntPtr)(remoteBuffer.ToInt32() + size + 1);
tvItem.cchTextMax = 255;
localBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(tvItem));
Marshal.StructureToPtr(tvItem, localBuffer, false);
bSuccess = WinAPIHelper.WriteProcessMemory(hProcess, remoteBuffer, ref tvItem, size, IntPtr.Zero);
关于item定义,大家可查询MSDN
e),发送获取Item消息
WinAPIHelper.SendMessage(hwnd, (int)WinAPIHelper.TV_Messages.TVM_GETITEM, 0, remoteBuffer);
f),读取远程内存
bSuccess = WinAPIHelper.ReadProcessMemory(hProcess, remoteBuffer, localBuffer, buff_size, IntPtr.Zero);
g),将指针转为结构
WinAPIHelper.TVITEM retItem = (WinAPIHelper.TVITEM)
Marshal.PtrToStructure(localBuffer, (Type)typeof(WinAPIHelper.TVITEM))
经过上面的操作我们就获取到了选定的某一项的信息,接下来我们使用
retval = WinAPIHelper.SendMessage(hwnd, (int)WinAPIHelper.TV_Messages.TVM_GETNEXTITEM, (int)WinAPIHelper.TVM_GETNEXTITEM.TVGN_NEXTVISIBLE, new IntPtr(retval));来选择下一个项在进行上面的操作,直到返回值为空位置
3),多选实现,多选我们需要通过修改ITEM的状态来实现
a),声明ITEM(操作为更改状态)
WinAPIHelper.TVITEM tvItem = new WinAPIHelper.TVITEM();
tvItem.hItem = items[i].Handle;
tvItem.mask = WinAPIHelper.TVIF_STATE;
tvItem.state = WinAPIHelper.TVIS_SELECTED;
tvItem.stateMask = WinAPIHelper.TVIS_SELECTED;
b),分配远程内存
IntPtr remoteBuffer = WinAPIHelper.VirtualAllocEx(hPro, IntPtr.Zero, buff_size, WinAPIHelper.AllocationType.Commit, WinAPIHelper.MemoryProtection.ExecuteReadWrite);
c),写入远程内存
bool result = WinAPIHelper.WriteProcessMemory(hPro, remoteBuffer, ref tvItem, size, IntPtr.Zero);
d),设置状态
int retval = WinAPIHelper.SendMessage(hTv, (int)WinAPIHelper.TV_Messages.TVM_SETITEM, 0, remoteBuffer);
经过上面就实现了为某一项设置选中状态,实际操作中,我们为提高内存使用效率,是先分配缓冲区,在设置(写入)对象,然后发送指令
下面是完整代码
public class WinTreeViewItem
{
public int Index { get; set; }
public int lpAddress { get; set; }
public string Text { get; set; }
public bool OwnChild { get; set; }
public IntPtr Handle { get; set; }
}
public class TreeViewHelper
{
const int buff_size = 1024;
const int MAX_TVMSTRING = 255;
static public List<WinTreeViewItem> GetAllItem(IntPtr hTv)
{
return GetItems(hTv, null, null, int.MaxValue);
}
static public WinTreeViewItem GetItemByText(IntPtr hTv, params string[] text)
{
List<string> containsList = new List<string>();
foreach (var item in text)
{
if (item != null && item != "")
containsList.Add(item);
}
List<WinTreeViewItem> items = GetItems(hTv, containsList, null, 1, false);
if (items.Count > 0)
return items[0];
else
return null;
}
static public bool SelectItem(IntPtr hTv, WinTreeViewItem item)
{
List<WinTreeViewItem> items = new List<WinTreeViewItem>();
items.Add(item);
return SelectItems(hTv, items);
}
static public List<WinTreeViewItem> GetItems(IntPtr hTv, List<string> containsList, List<string> withOutList, int takeCount)
{
return GetItems(hTv, containsList, withOutList, takeCount, false);
}
static public List<WinTreeViewItem> GetItems(IntPtr hTv, List<string> containsList, List<string> withOutList, int takeCount, bool isAddParent, int containsPreferenceCount = 0, int withOutPreferenceCount = 0)
{
if (withOutPreferenceCount < 1 && containsPreferenceCount < 1)
{
throw new Exception("两个数量级不能同时为空");
}
int tryCount = 0;
IntPtr hPro = WinAPIHelper.OpenProcess(WinAPIHelper.PROCESS_ALL_ACCESS, false, WndHelper.GetProcessId(hTv));
List<WinTreeViewItem> withOutResultItems = new List<WinTreeViewItem>();
List<WinTreeViewItem> containsResultItems = new List<WinTreeViewItem>();
int index = 0;
int retval = 0;
GETROOT:
if (retval == 0)
{
tryCount++;
if (tryCount > SysConfig.TreeViewItemFindTryCount)
{
return null;
}
retval = WinAPIHelper.SendMessage(hTv, (int)WinAPIHelper.TV_Messages.TVM_GETNEXTITEM, (int)WinAPIHelper.TVM_GETNEXTITEM.TVGN_ROOT, IntPtr.Zero);
Console.WriteLine("根节点" + retval);
Thread.Sleep(500);
goto GETROOT;
}
tryCount = 0;
int itemCount = 0;
FINDCOUNT:
if (itemCount == 0)
{
tryCount++;
if (tryCount > SysConfig.TreeViewItemFindTryCount)
{
return null;
}
itemCount = WinAPIHelper.SendMessage(hTv, (int)WinAPIHelper.TV_Messages.TVM_GETCOUNT, 0, IntPtr.Zero);
Console.WriteLine("可用创建数量" + itemCount);
Thread.Sleep(500);
goto FINDCOUNT;
}
IntPtr pStrBufferMemory = WinAPIHelper.VirtualAllocEx(hPro, IntPtr.Zero, MAX_TVMSTRING, WinAPIHelper.AllocationType.Commit, WinAPIHelper.MemoryProtection.ReadWrite);
IntPtr remoteBuffer = WinAPIHelper.VirtualAllocEx(hPro, IntPtr.Zero, Marshal.SizeOf(typeof(WinAPIHelper.TVITEM)), WinAPIHelper.AllocationType.Commit, WinAPIHelper.MemoryProtection.ExecuteReadWrite);
if (remoteBuffer == IntPtr.Zero)
{
Console.WriteLine("远程地址分配失败");
return null;
}
if (pStrBufferMemory == IntPtr.Zero)
{
Console.WriteLine("远程地址分配失败");
return null;
}
WinAPIHelper.TVITEM tvItem = new WinAPIHelper.TVITEM();
// int size = Marshal.SizeOf(tvItem);
tvItem.mask = WinAPIHelper.TVIF_TEXT;
tvItem.pszText = pStrBufferMemory;
tvItem.cchTextMax = MAX_TVMSTRING;
IntPtr localBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(tvItem));
Marshal.StructureToPtr(tvItem, localBuffer, false);
int addCount = 0;
string tmpcontxt = "";
while (retval != 0)
{
if (index + 1 > itemCount) break;
tvItem.hItem = (IntPtr)retval;
var item = new WinTreeViewItem()
{
Index = index,
lpAddress = retval
};
int r1 = WinAPIHelper.SendMessage(hTv, (int)WinAPIHelper.TV_Messages.TVM_SELECTITEM, (int)WinAPIHelper.TVM_GETNEXTITEM.TVGN_CARET, new IntPtr(retval));
if (r1 == 0)
{
Console.WriteLine("选择项失败");
continue;
}
//Thread.Sleep(100);
int r2 = WinAPIHelper.SendMessage(hTv, (int)WinAPIHelper.TV_Messages.TVM_EXPAND, (int)WinAPIHelper.TVM_EXPAND.TVE_EXPAND, new IntPtr(retval));
if (r2 == 1)
{
//Console.WriteLine("可以展开");
itemCount = WinAPIHelper.SendMessage(hTv, (int)WinAPIHelper.TV_Messages.TVM_GETCOUNT, 0, IntPtr.Zero);
item.OwnChild = true;
}
else
{
//Console.WriteLine("不可以展开");
}
bool bSuccess = WinAPIHelper.WriteProcessMemory(hPro, remoteBuffer, ref tvItem, Marshal.SizeOf(tvItem), IntPtr.Zero);
if (bSuccess == false)
{
Console.WriteLine("写入远程地址失败");
continue;
}
int r3 = WinAPIHelper.SendMessage(hTv, (int)WinAPIHelper.TV_Messages.TVM_GETITEM, 0, remoteBuffer);
if (r3 == 0)
{
Console.WriteLine("选择项操作失败");
continue;
}
bSuccess = WinAPIHelper.ReadProcessMemory(hPro, remoteBuffer, localBuffer, Marshal.SizeOf(tvItem), IntPtr.Zero);
if (bSuccess == false)
{
Console.WriteLine("读取远程地址失败");
continue;
}
WinAPIHelper.TVITEM retItem = (WinAPIHelper.TVITEM)Marshal.PtrToStructure(localBuffer, (Type)typeof(WinAPIHelper.TVITEM));
int readLen = 0;
IntPtr pStrLocaAddress = Marshal.AllocHGlobal(MAX_TVMSTRING);
bSuccess = WinAPIHelper.ReadProcessMemory(hPro, pStrBufferMemory, pStrLocaAddress, MAX_TVMSTRING, out readLen);
string pszItemText = Marshal.PtrToStringUni(pStrLocaAddress);
// Console.WriteLine(pszItemText);
item.Handle = tvItem.hItem;
item.Text = pszItemText;
bool withOutAdd = false;
bool containsAdd = false;
if (item.OwnChild)
{
goto NEXTITEM;
}
if (containsList != null)
{
foreach (var conItem in containsList)
{
if (pszItemText.Trim().Contains(conItem.Trim()))
{
containsAdd = true; goto ADDITEM;
}
}
}
if (withOutList != null)
{
bool isContains = false;
foreach (var outItem in withOutList)
{
if (pszItemText.Trim().Contains(outItem.Trim()))
{
isContains = true;
goto NEXTITEM;
}
}
if (!isContains)
{
withOutAdd = true;
goto ADDITEM;
}
}
ADDITEM:
if ((withOutList == null && containsList == null) || (withOutAdd || containsAdd))
{
if (withOutAdd)
{
if (withOutResultItems.Count < withOutPreferenceCount && takeCount - containsPreferenceCount > withOutResultItems.Count)
{
withOutResultItems.Add(item);
addCount++;
}
}
if (containsAdd)
{
if (containsResultItems.Count < containsPreferenceCount && takeCount - withOutPreferenceCount > containsResultItems.Count)
{
containsResultItems.Add(item);
addCount++;
}
}
containsAdd = false;
withOutAdd = false;
if (addCount == takeCount)
break;
}
NEXTITEM:
retval = WinAPIHelper.SendMessage(hTv, (int)WinAPIHelper.TV_Messages.TVM_GETNEXTITEM, (int)WinAPIHelper.TVM_GETNEXTITEM.TVGN_NEXTVISIBLE, new IntPtr(retval));
index++;
}
if (localBuffer != IntPtr.Zero)
{
try { Marshal.FreeHGlobal(localBuffer); }
catch { }
}
if (remoteBuffer != IntPtr.Zero)
{
try { WinAPIHelper.VirtualFreeEx(hPro, remoteBuffer, 0, WinAPIHelper.MEM_RELEASE); }
catch { }
}
if (pStrBufferMemory != IntPtr.Zero)
{
try { WinAPIHelper.VirtualFreeEx(hPro, pStrBufferMemory, 0, WinAPIHelper.MEM_RELEASE); }
catch { }
}
if (hPro != IntPtr.Zero)
{
try { WinAPIHelper.CloseHandle(hPro); }
catch { }
}
withOutResultItems.AddRange(containsResultItems);
return withOutResultItems;
}
static public bool SelectItems(IntPtr hTv, List<WinTreeViewItem> items)
{
if (items.Count < 1) return false;
int r1 = WinAPIHelper.SendMessage(hTv, (int)WinAPIHelper.TV_Messages.TVM_SELECTITEM, (int)WinAPIHelper.TVM_GETNEXTITEM.TVGN_CARET, items[0].Handle);
if (items.Count == 1) return r1 == 1 ? true : false;
IntPtr hPro = WinAPIHelper.OpenProcess(WinAPIHelper.PROCESS_ALL_ACCESS, false, WndHelper.GetProcessId(hTv));
IntPtr remoteBuffer = WinAPIHelper.VirtualAllocEx(hPro, IntPtr.Zero, buff_size, WinAPIHelper.AllocationType.Commit, WinAPIHelper.MemoryProtection.ExecuteReadWrite);
for (int i = 1; i < items.Count; i++)
{
WinAPIHelper.TVITEM tvItem = new WinAPIHelper.TVITEM();
tvItem.hItem = items[i].Handle;
tvItem.mask = WinAPIHelper.TVIF_STATE;
tvItem.state = WinAPIHelper.TVIS_SELECTED;
tvItem.stateMask = WinAPIHelper.TVIS_SELECTED;
int size = Marshal.SizeOf(tvItem);
bool result = WinAPIHelper.WriteProcessMemory(hPro, remoteBuffer, ref tvItem, size, IntPtr.Zero);
int retval = WinAPIHelper.SendMessage(hTv, (int)WinAPIHelper.TV_Messages.TVM_SETITEM, 0, remoteBuffer);
Thread.Sleep(100);
}
if (remoteBuffer != IntPtr.Zero)
{
try { WinAPIHelper.VirtualFreeEx(hPro, remoteBuffer, 0, WinAPIHelper.MEM_RELEASE); }
catch { }
}
if (hPro != IntPtr.Zero)
{
try { WinAPIHelper.CloseHandle(hPro); }
catch { }
}
return true;
}
}
HAPPY EVERY DAY ! !