前些日子写软件时,需要实现一个功能,就是在Tree中快速定位节点,比如注册表编辑器左边的Tree,只要给出Tree中的节点路径(以“/”分隔),就可以快速将树展开,并将当前节点定位到指定的节点。功能的实现并不难,但稍有些麻烦。原因在于,如果是本进程中的Tree,只要发消息就可以了,但如果是另外一个进程中的Tree,就要在那个进程中申请内存,将Tree节点的文字复制到这块内存,然后再把这块内存的数据复制到本进程的一块内存中,才能与指定的节点路径相比较。由于这个功能还有一些可一般化的东西,所以就写了一个DLL,只要给出Tree的句柄和节点路径,就可以展开这颗树并定位节点。
DLL源代码如下:
/********************************************************************/ /* 文件名: Tree.cpp */ /* */ /* 功能: 标准 DLL ---- 跨进程展开 SysTreeView32 中指定的节点 */ /* */ /* 作者: 卢培培 (goodname008) 时间: 2005.02.18 */ /* */ /* BLOG: http://blog.youkuaiyun.com/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
*-------------------------------------------*
* 转载请通知作者并注明出处,优快云欢迎您! *
* 作者:卢培培(goodname008) *
* 邮箱:goodname008@163.com *
* 专栏:http://blog.youkuaiyun.com/goodname008 *
*-------------------------------------------*