前些日子写软件时,需要实现一个功能,就是在Tree中快速定位节点,比如注册表编辑器左边的Tree,只要给出Tree中的节点路径(以“\”分隔),就可以快速将树展开,并将当前节点定位到指定的节点。功能的实现并不难,但稍有些麻烦。原因在于,如果是本进程中的Tree,只要发消息就可以了,但如果是另外一个进程中的Tree,就要在那个进程中申请内存,将Tree节点的文字复制到这块内存,然后再把这块内存的数据复制到本进程的一块内存中,才能与指定的节点路径相比较。由于这个功能还有一些可一般化的东西,所以就写了一个DLL,只要给出Tree的句柄和节点路径,就可以展开这颗树并定位节点。
DLL源代码如下:
/********************************************************************/
/* 文件名: Tree.cpp */
/* */
/* 功能: 标准 DLL ---- 跨进程展开 SysTreeView32 中指定的节点 */
/* */
/* 作者: 卢培培 (goodname008) 时间: 2005.02.18 */
/* */
/* BLOG: http://blog.csdn.net/goodname008 */
/********************************************************************/
#include 'stdafx.h'
#include 'Tree.h'
#include 'commctrl.h'
#include <string>
using namespace std;
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
/********************************************************************/
/* 功 能: 跨进程展开 SysTreeView32 中指定的节点
/*
/* 参 数: hTreeWnd SysTreeView32 的句柄
/* lpszPath SysTreeView32 中的节点路径(忽略大小写)
/*
/* 返回值: TRUE 成功
/* FALSE 失败(节点路径不存在时会返回失败, 但仍然展开)
/*
/* 说 明: 在节点路径不存在的情况下, 本函数会尽可能展开存在的节点
/********************************************************************/
TREE_API BOOL APIENTRY ExpandTreeNode(HWND hTreeWnd, LPCSTR lpszPath)
{
string szPath = lpszPath;
if (szPath.empty())
return FALSE;
DWORD dwProcessID = NULL;
GetWindowThreadProcessId(hTreeWnd, &dwProcessID);
if (!dwProcessID)
return FALSE;
HANDLE hProcess = NULL;
hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION, FALSE, dwProcessID);
if (!hProcess)
return FALSE;
TVITEM tvItem, *pItem = NULL;
ZeroMemory(&tvItem, sizeof(TVITEM));
pItem = (TVITEM *)VirtualAllocEx(hProcess, NULL, sizeof(TVITEM), MEM_COMMIT, PAGE_READWRITE);
tvItem.mask = TVIF_TEXT;
tvItem.cchTextMax = 512;
tvItem.pszText = (LPSTR)VirtualAllocEx(hProcess, NULL, 512, MEM_COMMIT, PAGE_READWRITE);
tvItem.hItem = TreeView_GetRoot(hTreeWnd);
if (!tvItem.hItem)
return FALSE;
string szPathNode;
string::size_type nBackslashPos = -1;
char szItemText[512] = {'\0'};
do
{
szPathNode = szPath.substr(nBackslashPos + 1, szPath.find('\\', nBackslashPos + 1) - nBackslashPos - 1);
do
{
if (!WriteProcessMemory(hProcess, pItem, &tvItem, sizeof(TVITEM), NULL))
return FALSE;
if (!TreeView_GetItem(hTreeWnd, pItem))
return FALSE;
if (!ReadProcessMemory(hProcess, tvItem.pszText, szItemText, 512, NULL))
return FALSE;
if (lstrcmpi(szPathNode.c_str(), szItemText) == 0)
{
TreeView_SelectItem(hTreeWnd, tvItem.hItem);
if (TreeView_Expand(hTreeWnd, tvItem.hItem, TVE_EXPAND))
{
tvItem.hItem = TreeView_GetChild(hTreeWnd, tvItem.hItem);
if (!tvItem.hItem)
return FALSE;
}
}
else
{
tvItem.hItem = TreeView_GetNextSibling(hTreeWnd, tvItem.hItem);
if (!tvItem.hItem)
return FALSE;
}
} while(lstrcmpi(szPathNode.c_str(), szItemText) != 0);
nBackslashPos = szPath.find('\\', nBackslashPos + 1);
} while(nBackslashPos != -1);
VirtualFreeEx(hProcess, tvItem.pszText, NULL, MEM_RELEASE);
VirtualFreeEx(hProcess, pItem, NULL, MEM_RELEASE);
CloseHandle(hProcess);
return TRUE;
}
头文件源代码:
#ifdef TREE_EXPORTS
#define TREE_API __declspec(dllexport)
#else
#define TREE_API __declspec(dllimport)
#endif
TREE_API BOOL APIENTRY ExpandTreeNode(HWND hTreeWnd, LPCSTR lpszPath);
DEF文件如下:
LIBRARY Tree
EXPORTS
ExpandTreeNode @1
调用例程就不再这里给出了,DLL和VC的调用例程都是用.net环境写的。
源代码及调用例程的下载地址: http://csdngoodname008.51.net/Tree.zip
*-------------------------------------------*
* 转载请通知作者并注明出处,CSDN欢迎您! *
* 作者:卢培培(goodname008) *
* 邮箱:goodname008@163.com *
* 专栏:http://blog.csdn.net/goodname008 *
*-------------------------------------------*