PUBLIC oForm oForm = NEWOBJECT( "MyForm" ) oForm.Show() READ EVENTS
DEFINE CLASS MyForm AS Form Height = 142 Width = 312 ShowWindow = 2 DoCreate = .T. AutoCenter = .T. Caption = "Form1" MaxButton = .F. MinButton = .F. AllowOutput = .F. Name = "Form1"
ADD OBJECT lblClsName AS label WITH ; AutoSize = .T., ; BackStyle = 0, ; Caption = "当前控件类名", ; Height = 17, ; Left = 20, ; Top = 15, ; Width = 74, ; Name = "lblClsName"
ADD OBJECT txtClsName AS textbox WITH ; Height = 23, ; Left = 100, ; ReadOnly = .T., ; Top = 12, ; Width = 200, ; DisabledBackColor = RGB(255,255,255), ; Name = "txtClsName"
ADD OBJECT lblTvHwnd AS label WITH ; AutoSize = .T., ; BackStyle = 0, ; Caption = "树控件 hWnd", ; Height = 17, ; Left = 20, ; Top = 45, ; Width = 73, ; Name = "lblTvHwnd"
ADD OBJECT txtTvHwnd AS textbox WITH ; Alignment = 3, ; Height = 23, ; Left = 100, ; Top = 41, ; Width = 108, ; Name = "txtTvHwnd"
ADD OBJECT cmdView AS commandbutton WITH ; Top = 39, ; Left = 212, ; Height = 27, ; Width = 90, ; Caption = "查看节点信息", ; Name = "cmdView"
ADD OBJECT chkDetect AS checkbox WITH ; Top = 78, ; Left = 12, ; Height = 48, ; Width = 288, ; WordWrap = .T., ; Alignment = 0, ; Caption = (" 按下后将鼠标指针移到要获取 hWnd 的树控件上" ; + CHR(13) + " 获取成功后 hWnd 会显示在上面的文本框中"), ; Value = .F., ; Style = 1, ; Name = "chkDetect"
ADD OBJECT timer1 AS timer WITH ; Top = 104, ; Left = 0, ; Height = 23, ; Width = 23, ; Name = "Timer1" PROCEDURE Init DECLARE Long GetLastError IN WIN32API DECLARE Long GetCursorPos IN WIN32API String @ cPoint DECLARE Long WindowFromPoint IN WIN32API Long x, Long y DECLARE Long GetClassName IN WIN32API ; Long hWnd, String @ lpClassName, Long nMaxCount
DECLARE Long GetWindowThreadProcessId IN WIN32API ; Long hWnd, Long @ lpdwProcessId DECLARE Long OpenProcess IN WIN32API ; Long dwDesiredAccess, Long bInheritHandle, Long dwProcessId DECLARE Long CloseHandle IN WIN32API Long hObject
DECLARE Long VirtualAllocEx IN WIN32API ; Long hProcess, Long @ lpAddress, Long dwSize, ; Long flAllocationType, Long flProtect DECLARE Long VirtualFreeEx IN WIN32API ; Long hProcess, Long lpAddress, Long dwSize, Long dwFreeType DECLARE Long WriteProcessMemory IN WIN32API ; Long hProcess, Long lpBaseAddress, Long lpBuffer, ; Long nSize, Long @ lpNumberOfBytesWritten DECLARE Long ReadProcessMemory IN WIN32API ; Long hProcess, Long lpBaseAddress, Long lpBuffer, ; Long nSize, Long @ lpNumberOfBytesWritten DECLARE Long GlobalAlloc IN WIN32API Long uFlags, Long dwBytes DECLARE Long GlobalFree IN WIN32API Long hMem
DECLARE Long SendMessage IN WIN32API AS sendmsg_nn ; Long, Long, Long, Long DECLARE Long SendMessage IN WIN32API AS sendmsg_nc ; Long, Long, Long, String @ ENDPROC
PROCEDURE Unload CLEAR EVENTS ENDPROC
PROCEDURE cmdView.Click Thisform.GetNodeInfo() ENDPROC
PROCEDURE Timer1.Timer LOCAL hWnd, cPoint, x, y, iLen, cBuff
m.cPoint = REPLICATE( CHR(0), 8 ) GetCursorPos( @ m.cPoint ) m.x = CTOBIN( SUBSTR( m.cPoint, 1, 4 ), "rs" ) m.y = CTOBIN( SUBSTR( m.cPoint, 5, 4 ), "rs" ) m.hWnd = WindowFromPoint( m.x, m.y )
m.iLen = 260 m.cBuff = REPLICATE( CHR(0), m.iLen ) m.iLen = GetClassName( m.hWnd, @ m.cBuff, m.iLen ) m.cBuff = LEFT( m.cBuff, m.iLen )
Thisform.txtClsName.Value = m.cBuff IF ( "TreeView" $ m.cBuff ) STORE TRANSFORM( m.hWnd ) TO _ClipText, Thisform.txtTvHwnd.Value ENDIF ENDPROC
PROCEDURE chkDetect.ProgrammaticChange Thisform.Timer1.Interval = IIF( This.Value, 100, 0 ) ENDPROC
PROCEDURE chkDetect.InteractiveChange This.ProgrammaticChange() ENDPROC
PROCEDURE GetNodeInfo #define TVGN_ROOT 0x0000 #define TVGN_NEXT 0x0001 #define TVGN_PREVIOUS 0x0002 #define TVGN_PARENT 0x0003 #define TVGN_CHILD 0x0004
#define TV_FIRST 0x1100 #define TVM_GETNEXTITEM TV_FIRST + 10
#define PROCESS_VM_OPERATION 0x0008 #define PROCESS_VM_READ 0x0010 #define PROCESS_VM_WRITE 0x0020 #define PROCESS_QUERY_INFORMATION 0x0400
LOCAL hWnd, iPid, hProc, cText, cMsg, hItem
This.chkDetect.Value = .F. && 关闭取树控件句柄的计时器
m.hWnd = INT( VAL( Thisform.txtTvHwnd.Value )) && 树控件句柄 m.iPid = 0 GetWindowThreadProcessId( m.hWnd, @ m.iPid ) && 取树控件所在进程 id IF ( 0 == m.iPid ) MESSAGEBOX( "获取进程 id 失败" ) RETURN .F. ENDIF
m.hProc = OpenProcess( ; && 打开该进程 BITOR( PROCESS_VM_OPERATION, PROCESS_VM_READ, ; PROCESS_VM_WRITE, PROCESS_QUERY_INFORMATION ), ; 0, m.iPid ) IF ( 0 == m.hProc ) MESSAGEBOX( "打开进程失败" ) RETURN .F. ENDIF
*!* 先找到根节点的 hItem m.hItem = sendmsg_nn( m.hWnd, TVM_GETNEXTITEM, TVGN_ROOT, 0 ) *!* 取它的文字 m.cText = This.GetNodeText( m.hWnd, m.hProc, m.hItem ) IF !ISNULL( m.cText ) m.cMsg = "根节点文字: " + m.cText *!* 再找根节点的第一个子结点 m.hItem = sendmsg_nn( m.hWnd, TVM_GETNEXTITEM, TVGN_CHILD, m.hItem ) *!* 取它的文字 m.cText = This.GetNodeText( m.hWnd, m.hProc, m.hItem ) IF !ISNULL( m.cText ) m.cMsg = m.cMsg + 0h0d0a + "第一个子结点文字: " + m.cText ENDIF MESSAGEBOX( m.cMsg ) ENDIF
CloseHandle( m.hProc ) && 关闭打开的进程 ENDPROC PROCEDURE GetNodeText LPARAMETERS thWnd, thProc, thItem
#define TV_FIRST 0x1100 #define TVM_GETITEM TV_FIRST + 12
#define TVIF_TEXT 0x0001 #define TVIF_IMAGE 0x0002 #define TVIF_PARAM 0x0004 #define TVIF_STATE 0x0008 #define TVIF_HANDLE 0x0010 #define TVIF_SELECTEDIMAGE 0x0020 #define TVIF_CHILDREN 0x0040
#define GMEM_FIXED 0x0000
#define PAGE_READWRITE 0x04 #define MEM_COMMIT 0x1000 #define MEM_RELEASE 0x8000
LOCAL cStru, pText, pStru, pTransit, iSize, cText
*!* typedef struct _TVITEM { // 节点信息结构 *!* UINT mask; *!* HTREEITEM hItem; *!* UINT state; *!* UINT stateMask; *!* LPTSTR pszText; *!* int cchTextMax; *!* int iImage; *!* int iSelectedImage; *!* int cChildren; *!* LPARAM lParam; *!* int iIntegral; *!* #if (_WIN32_IE >= 0x0600) *!* UINT uStateEx; *!* HWND hwnd; *!* int iExpandedImage; *!* #endif *!* } TVITEM
*!* ------------------------------------------------------------------------------- *!* 由于进程只能存取属于自己的地址空间, 我们需要将结构复制到树控件所在的进程空间内, *!* 又因为我们无法得到 cStru 的地址, 所以要先申请一块用于中转的存储块并复制过去 *!* 我们不得不绕一个大弯来完成这项工作!!! *!* ------------------------------------------------------------------------------- *!* 下面注释中, A 代表 vfp 程序所在进程, B 代表树控件所在进程 *!* -------------------------------------------------------------------------------
*!* 先在 B 中分配一块存储器用于存放结构和节点文字信息(属于 B) m.pStru = VirtualAllocEx( m.thProc, 0, 0x300, MEM_COMMIT, PAGE_READWRITE ) IF ( 0 == m.pStru ) MESSAGEBOX( "分配存储器失败 !" ) RETURN "" ENDIF
m.pText = m.pStru + 0x100 *!* 我们只获取节点的文字信息 m.cStru = BINTOC( TVIF_TEXT, "rs" ) ; && 构造节点信息结构 + BINTOC( m.thItem, "rs" ) + REPLICATE( CHR(0), 2*4 ) ; + BINTOC( m.pText, "rs" ) + BINTOC( 0x200, "rs" ) ; + REPLICATE( CHR(0), 8*4 ) m.iSize = LEN( m.cStru )
*!* 申请一块用于中转的存储块(属于 A), 先申请大一点, 以后还要用来存储节点文字 m.pTransit = GlobalAlloc( GMEM_FIXED, 0x200 ) SYS( 2600, m.pTransit, m.iSize, m.cStru ) && 将 cStru 复制过去
m.cText = "" *!* 将中转站中的结构复制到 B 中刚分配的存储块内 IF ( 0 == WriteProcessMemory( m.thProc, m.pStru, m.pTransit, m.iSize, 0 )) MESSAGEBOX( "复制结构到树控件所在进程失败 !" ) ELSE *!* 发消息给 B 中树控件获取节点信息 IF ( 0 == sendmsg_nn( m.thWnd, TVM_GETITEM, 0, m.pStru )) MESSAGEBOX( "取节点信息失败 !" ) ELSE *!* 将获取的信息从 B 中复制回我们的中转存储器 ReadProcessMemory( m.thProc, m.pText, m.pTransit, 0x200, 0 ) m.cText = SYS( 2600, m.pTransit, 0x200 ) m.cText = LEFT( m.cText, AT( CHR(0), m.cText )-1 ) ENDIF ENDIF
*!* 释放分配的存储块 GlobalFree( m.pTransit ) VirtualFreeEx( m.thProc, m.pStru, 0, MEM_RELEASE ) RETURN m.cText ENDPROC
ENDDEFINE
|