include common.asm
BMP_TREEVIEW = 1
CTRL_TREEVIEW = 3
CTRL_STATUS = 4
MENU_MAIN = 1
MITEM_OPEN = 3
MITEM_EXIT = 4
MITEM_HELP = 5
X_TREEVIEW = 20
Y_TREEVIEW = 20
WM_NEWTVROOT = WM_USER + 100h
.data
hInstance dd ?
fnTreeViewProc dd ?
hWndMain dd ?
.code
_newTreeViewProc proc uses ebx esi edi hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
local @szFileName[MAX_PATH*2]:byte ;
local @tvinsert:TV_INSERTSTRUCT
local @wfd:WIN32_FIND_DATA
.if uMsg==WM_DROPFILES
invoke DragQueryFile, wParam, 0, addr @szFileName, sizeof @szFileName
; 可接受目录(视作文件),得到的文件名不带两头的引号
; 缓冲区不够大没有关系,API会截断过长的文件名,且保证会以0结尾
invoke DragFinish, wParam ; 释放系统用来传递文件名的内存
invoke GetFileAttributes, addr @szFileName
.if eax & FILE_ATTRIBUTE_DIRECTORY
invoke SendMessage, hWndMain, WM_NEWTVROOT, 0, addr @szFileName ;
.endif
.else
invoke CallWindowProc, fnTreeViewProc, hWnd, uMsg, wParam, lParam
ret ;
.endif
return 0
_newTreeViewProc endp
WndProc proc uses ebx esi edi hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
local @tvinsert:TV_INSERTSTRUCT
local @hBitmap, @hStatusBar, @hTreeView, @hItemDragTarget
local @tvhit:TV_HITTESTINFO
local @rectWindow:RECT
local @szBuf[256]:byte
static _szBuf, byte, 256 dup (?)
static _DragMode, dword, FALSE
static _hItemParent, dword, ?
static _hImageList, dword, ?
static _hDragImageList, dword, ?
static _hItemDragged, dword, ?
static _hCursorNormal, dword, ?
static _hCursorForbidden, dword, ?
.if uMsg==WM_COMMAND
.if lParam==0
mov eax, wParam
and eax, 0ffffh
.if eax==MITEM_OPEN
.elseif eax==MITEM_EXIT
invoke DestroyWindow, hWnd
.elseif eax==MITEM_HELP
invoke MessageBox, hWnd, \
CTXT("Just a treeview control demo."), \
CTXT("about me"), MB_OK
.endif
.endif
.elseif uMsg==WM_NEWTVROOT
invoke SendDlgItemMessage, hWnd, CTRL_TREEVIEW, TVM_DELETEITEM, 0, TVI_ROOT
invoke _AddDirToTreeView, hWnd, CTRL_TREEVIEW, NULL, lParam
.elseif uMsg==WM_MOUSEMOVE
.if _DragMode
invoke lstrcpy, addr @szBuf, addr _szBuf
invoke lstrlen, addr @szBuf
lea ebx, @szBuf[eax]
mov eax, lParam
mov edx, eax
and eax, 0ffffh
shr edx, 16
pushs eax, edx
invoke wsprintf, ebx, CTXT(" | mouse move @ (%d, %d)"), eax, edx
invoke SendDlgItemMessage, hWnd, CTRL_STATUS, SB_SETTEXT, 0, addr @szBuf
pops eax, edx
sub eax, X_TREEVIEW ; 注意这些坐标是相对于treeview窗口的左上角
sub edx, Y_TREEVIEW
mov @tvhit.pt.x, eax
mov @tvhit.pt.y, edx
invoke ImageList_DragMove, eax, edx ; update the drag path
invoke ImageList_DragShowNolock,FALSE
; Shows or hides the image being dragged
invoke SendDlgItemMessage, hWnd, CTRL_TREEVIEW, \
TVM_HITTEST, 0, addr @tvhit ; check if an item is hit
; TVM_HITTEST: returns the handle to the tree view item
; that occupies the specified point, or NULL if no item occupies the point.
.if eax
mov @hItemDragTarget, eax
;.if eax==_hItemDragged
;源条目与目标条目为同一个:实际测试验证可以用句柄代替ID来标识条目
; 取消高亮或是使用表示禁止的指针都会产生难看的拖动痕迹
;.else
invoke SendDlgItemMessage, hWnd, CTRL_TREEVIEW, \
TVM_EXPAND, TVE_EXPAND, @hItemDragTarget
invoke SendDlgItemMessage, hWnd, CTRL_TREEVIEW, \
TVM_SELECTITEM, TVGN_DROPHILITE, @hItemDragTarget
;.endif
.else
invoke SendDlgItemMessage, hWnd, CTRL_TREEVIEW, \
TVM_SELECTITEM, TVGN_DROPHILITE, NULL
; 出界的话,则不显示高亮的效果。不加本句,出界了也会在最后
; 拖到的那个条目处显示高亮效果
.endif
invoke ImageList_DragShowNolock, TRUE ;
.endif
.elseif uMsg==WM_LBUTTONUP
.if _DragMode
invoke GetDlgItem, hWnd, CTRL_TREEVIEW
invoke ImageList_DragLeave, eax
invoke ImageList_EndDrag
invoke ImageList_Destroy, _hDragImageList
invoke SendDlgItemMessage, hWnd, CTRL_TREEVIEW, \
TVM_GETNEXTITEM, TVGN_DROPHILITE, NULL
; Get the currently hilited item, i.e. the item that
; is the target of a drag-and-drop operation
; 其实是有高亮效果的那个条目的句柄
.if eax
; 处理拖动
mov @hItemDragTarget, eax
; un-hilite the item
invoke SendDlgItemMessage, hWnd, CTRL_TREEVIEW, \
TVM_SELECTITEM, TVGN_DROPHILITE, NULL
; If you don't un-hilite the item, you will get a strange effect:
; 在拖动之后when you select some other item, that item will be enclosed by
; a rectangle but the hilite will still be on the last hilited item.
invoke SendDlgItemMessage, hWnd, CTRL_TREEVIEW, \
TVM_SELECTITEM, TVGN_CARET, @hItemDragTarget
; Sets the selection to the target of a drag-and-drop operation
.endif
invoke ReleaseCapture
mov _DragMode, FALSE ;
.endif
.elseif uMsg==WM_NOTIFY
mov ebx, lParam
assume ebx:ptr NM_TREEVIEW
.if [ebx].hdr.code==TVN_BEGINDRAG
invoke SendDlgItemMessage, hWnd, CTRL_TREEVIEW, \
TVM_CREATEDRAGIMAGE, 0, [ebx].itemNew.hItem
mov _hDragImageList, eax
invoke ImageList_BeginDrag, _hDragImageList, 0, 8,8 ;鼠标指针显示在图片的正中
; 新建的图片列表中其实只有一张图片,若指定1,会显示暗影。
comment /*
msdn Community对msdn上关于ptDrag的文档的反馈:
ptDrag (TVN_BEGINDRAG notification code (Windows))
Documentation says that the ptDrag member has the current cursor position in screen coordinates. This is wrong. The ptDrag has the cursor position relative to the upper left corner of the TreeView window.
History
6-22-2010
Alessandro Antonello
*/
; msdn 2001有误,ptDrag实为鼠标指针相对树型视图控件左上角的坐标,而非屏幕坐标
; ptDrag为POINT结构体(2个long:X,Y)
invoke wsprintf, addr _szBuf, CTXT("begin drag @ (%d, %d)"), \
[ebx].ptDrag.x, [ebx].ptDrag.y
invoke SendDlgItemMessage, hWnd, CTRL_TREEVIEW, \
TVM_GETNEXTITEM, TVGN_DROPHILITE, NULL
invoke GetDlgItem, hWnd, CTRL_TREEVIEW
invoke ImageList_DragEnter, eax, [ebx].ptDrag.x, [ebx].ptDrag.y
m2m _hItemDragged, [ebx].itemNew.hItem
invoke SetCapture, hWnd ;
mov _DragMode, TRUE ;
.endif
assume ebx:nothing
.elseif uMsg==WM_SIZE
.if wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED
;最大化、非最大化且非最小化造成的窗口大小改变
invoke GetDlgItem, hWnd, CTRL_STATUS
mov @hStatusBar, eax
invoke GetWindowRect, @hStatusBar, addr @rectWindow
mov eax, lParam ;新窗口客户区的宽,即状态栏的宽
and eax, 0ffffh
mov edx, @rectWindow.bottom ; 这些坐标是屏幕坐标
sub edx, @rectWindow.top ;状态栏的高
mov ebx, edx ;
mov ecx, lParam
shr ecx, 16 ;新窗口客户区的高
sub ecx, edx ;状态栏的y
invoke MoveWindow, @hStatusBar, 0, ecx, eax, edx, TRUE
invoke GetDlgItem, hWnd, CTRL_TREEVIEW
mov @hTreeView, eax
mov eax, lParam
mov edx, eax
and eax, 0ffffh
sub eax, X_TREEVIEW*2 ; 主窗口客户区的宽度减去两端对齐的宽度
shr edx, 16
sub edx, ebx ; 主窗口客户区的高度减去状态栏的高度,再减去两端对齐的高度
sub edx, Y_TREEVIEW*2
invoke MoveWindow, @hTreeView, X_TREEVIEW, Y_TREEVIEW, eax, edx, TRUE
.endif
.elseif uMsg==WM_CREATE
invoke InitCommonControls
invoke CreateStatusWindow, WS_CHILD or WS_VISIBLE, CTXT("Hi!"), hWnd, CTRL_STATUS
invoke CreateWindowEx, NULL, CTXT("SysTreeView32"), NULL, \
WS_CHILD or WS_VISIBLE or TVS_HASLINES or TVS_HASBUTTONS or TVS_LINESATROOT, \
X_TREEVIEW, Y_TREEVIEW, 150, 300, hWnd, CTRL_TREEVIEW, hInstance,NULL
mov ebx, eax
invoke DragAcceptFiles, eax, TRUE ;
invoke SetWindowLong, ebx, GWL_WNDPROC, offset _newTreeViewProc
mov fnTreeViewProc, eax
invoke ImageList_Create, 16, 16, ILC_COLOR4, 2, 10 ; ILC_COLOR4: 4-bit (16-color)
mov _hImageList, eax
invoke LoadBitmap, hInstance, BMP_TREEVIEW
mov @hBitmap, eax
invoke ImageList_Add, _hImageList, eax, NULL
invoke DeleteObject, @hBitmap ; always delete the bitmap resource
; since it will not be used anymore
invoke SendDlgItemMessage, hWnd, CTRL_TREEVIEW, \
TVM_SETIMAGELIST, TVSIL_NORMAL, _hImageList
; 用于拖动的时候
;invoke LoadCursor, 0, IDC_NO ;Slashed(斜线) circle
;mov _hCursorForbidden, eax
.elseif uMsg==WM_DESTROY
invoke PostQuitMessage, 0
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
xor eax,eax
ret
WndProc endp
start proc
local @wc:WNDCLASSEX
local @msg:MSG
invoke GetModuleHandle, NULL
mov hInstance, eax
mov @wc.cbSize, sizeof @wc
mov @wc.style, CS_HREDRAW or CS_VREDRAW
mov @wc.lpfnWndProc, offset WndProc
mov @wc.cbClsExtra, 0
mov @wc.cbWndExtra, 0
push hInstance
pop @wc.hInstance
mov @wc.hbrBackground, COLOR_APPWORKSPACE+1
mov @wc.lpszMenuName, MENU_MAIN
mov @wc.lpszClassName, CTXT("SimpleWindow")
invoke LoadIcon, 0, IDI_APPLICATION
mov @wc.hIcon, eax
mov @wc.hIconSm, eax
invoke LoadCursor, 0, IDC_ARROW
mov @wc.hCursor, eax
invoke RegisterClassEx, addr @wc
invoke CreateWindowEx, WS_EX_CLIENTEDGE, CTXT("SimpleWindow"), CTXT("Tree View Demo"),\
WS_OVERLAPPEDWINDOW or WS_VISIBLE, \
CW_USEDEFAULT, CW_USEDEFAULT,200,400, \
NULL, NULL, hInstance, NULL
mov hWndMain, eax
.while 1
invoke GetMessage, addr @msg, NULL, 0, 0
.break .if !eax
invoke TranslateMessage, addr @msg
invoke DispatchMessage, addr @msg
.endw
invoke ExitProcess, @msg.wParam
start endp
end start
------------------------------------------------------------------------
; 把一个目录及其其下的子目录加到树型视图控件hItem指定的条目下
_AddDirToTreeView proc uses ebx esi hDlg, idTreeView, hItem, pszPathName
local @szFileName[MAX_PATH*8]:byte ;有溢出的风险
local @tvinsert:TV_INSERTSTRUCT
local @wfd:WIN32_FIND_DATA
m2m @tvinsert.hParent, hItem
mov @tvinsert.hInsertAfter, TVI_SORT ;按字母序排列
mov @tvinsert.item.imask,TVIF_TEXT or TVIF_IMAGE or TVIF_SELECTEDIMAGE
invoke _GetFileName, pszPathName
mov @tvinsert.item.pszText, eax
mov @tvinsert.item.iImage, 0
mov @tvinsert.item.iSelectedImage, 1
invoke SendDlgItemMessage, hDlg, idTreeView, TVM_INSERTITEM,0,addr @tvinsert
mov ebx, eax
invoke lstrcpy, addr @szFileName, pszPathName
invoke lstrcat, addr @szFileName, CTXT("\*")
invoke FindFirstFile, addr @szFileName, addr @wfd ;用来查找指定名字的文件或目录
mov esi, eax
.while 1
.if @wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
invoke lstrcmp, addr @wfd.cFileName, CTXT(".") ; 表示本目录的条目
.if !eax
jmp @next
.endif
invoke lstrcmp, addr @wfd.cFileName, CTXT("..") ; 表示父目录的条目
.if !eax
jmp @next
.endif
invoke lstrcpy, addr @szFileName, pszPathName
invoke lstrcat, addr @szFileName, CTXT("\")
invoke lstrcat, addr @szFileName, addr @wfd.cFileName
invoke _AddDirToTreeView, hDlg, idTreeView, ebx, addr @szFileName
.endif
@next:
invoke FindNextFile, esi, addr @wfd
.if !eax
;invoke GetLastError
;.if eax==ERROR_NO_MORE_FILES
;.endif
.break
.endif
.endw
invoke FindClose, esi
ret
_AddDirToTreeView endp