跨进程实现在Tree中快速定位节点 -------------------------------------------------------------------------------- 前些日子写软件时,需要实现一个功能,就是在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 
|