Zoom Icon

Tutorial 19: Tree View Control

From UIC

Tutorial 19: Tree View Control

Contents


Tutorial 19: Tree View Control
Author: Iczelion
Email: Translate: nOtEtA
Website: Mirror
Date: 03/02/2009 (dd/mm/yyyy)
Level: Slightly hard
Language: Italian Flag Italian.gif
Comments: Formattazione Wiki: Antelox


Introduzione

In questo tutorial, impareremo come usare un tree view control. Inoltre, impareremo anche come fare il drag and drop sotto un tree view control e come usare una lista di immagini con esso.


Tools

Esempio


Essay

Un tree view control è un genere speciale di finestra che rappresenta gli oggetti nell'ordine gerarchico. Un esempio di esso è il pannello di sinistra di Windows Explorer. Potete usare questo controllo per mostrare i rapporti fra gli oggetti. Potete creare un tree view control chiamando CreateWindowEx, passando " SysTreeView32 " come nome della classe o incorporandolo in una finestra di dialogo. Non dimenticatevi di mettere la chiamata a InitCommonControls nel vostro codice. Ci sono parecchi stili specifici per il tree view control. Questi tre sono quelli principalmente usati.

TVS_HASBUTTONS: Visualizza i tasti più (+) e meno (-) vicino alle voci principali. L'utente clicca sui tasti per espandere o sprofondare la lista di voci figlie di una voce principale. Per includere i tasti con le voci alla radice di un albero, TVS_LINESATROOT deve essere specificato.

TVS_HASLINES: Usa righe per mostrare la gerarchia delle voci.

TVS_LINESATROOT: Usa righe per collegare le voci alla radice dell'albero. Questo valore è ignorato se TVS_HASLINES non è specificato.

Il tree view control, come altri common controls, comunica con la finestra generatrice tramite messaggi. La finestra generatrice può trasmettere i vari messaggi ad esso ed il tree view control può trasmettere i messaggi " di notifica " alla relativa finestra generatrice. A questo riguardo, il tree view control non è differente da qualsiasi finestra. Quando qualcosa che lo interessa avviene, trasmette un messaggio WM_NOTIFY alla finestra generatrice accompagnato da informazioni.

WM_NOTIFY

wParam: Control ID, questo valore non è garantito che sia unico così noi non lo usiamo. Invece, usiamo hwndFrom o IDFrom membro della struttura NMHDR puntata da lParam

lParam: Puntatore alla struttura NMHDR. Alcuni comandi possono passare un puntatore a una struttura più grande ma essa deve avere una struttura NMHDR come relativo primo membro. Quindi, quando avete lParam, potete essere sicuri che punta almeno a una struttura NMHDR.

(Date uno sguardo all'API Reference per maggiori informazioni :D NdT)


Esaminiamo la struttura NMHDR.

NMHDR struct    DWORD
          hwndFrom    DWORD ?
          idFrom      DWORD ?
          code        DWORD ?
      NMHDR ends


hwndFrom è l' handle del controllo che trasmette il messaggio WM_NOTIFY.

idFrom è l'ID del controllo che trasmette questo messaggio WM_NOTIFY.

code è il messaggio attuale che il controllo desidera trasmettere alla finestra generatrice.

Le notifiche di un tree view sono quelle con TVN_ all'inizio del nome. I messaggi del tree view sono quelli con TVM_, come TVM_CREATEDRAGIMAGE. Il tree view control trasmette TVN_xxxx nel membro code di NMHDR. La finestra generatrice può trasmettere TVM_xxxx per gestirlo.

Aggiunta di voci ad un tree view control

Dopo che avete creato un tree view control, potete aggiungere delle voci ad esso. Potete fare questo inviando TVM_INSERTITEM ad esso.


TVM_INSERTITEM

wParam = 0;

lParam = puntatore a una TV_INSERTSTRUCT;

Avete bisogno di conoscere una certa terminologia a questo punto circa il rapporto fra le voci nel tree view control. Una voce può essere principale, figlia, o entrambe allo stesso tempo. Una voce principale è una voce che ha un certo numero di sottovoci connesse ad essa. Allo stesso tempo, la voce principale può essere figlia di una certa altra voce. Una voce senza un genitore è chiamata voce di radice. Ci possono essere molte voci di radice in un tree view control. Ora esamineremo la struttura TV_INSERTSTRUCT

TV_INSERTSTRUCT STRUCT DWORD
        hParent       DWORD ?
        hInsertAfter  DWORD ?
                            ITEMTYPE <>
      TV_INSERTSTRUCT ENDS

hParent: Handle della voce principale. Se questo membro è il valore TVI_ROOT o NULL, la voce è inserita alla radice del tree-view control.

hInsertAfter: Handle della voce dopo che una nuova voce è stata inserita o uno dei seguenti valori:

  • TVI_FIRST ==> Inserisce la voce all'inizio della lista.
  • TVI_LAST ==> Inserisce la voce alla fine della lista.
  • TVI_SORT ==> Inserisce la voce nella lista in ordine alfabetico.


ITEMTYPE UNION
itemex TVITEMEX <>
item TVITEM <>
ITEMTYPE ENDS

Useremo soltanto TVITEM.

TV_ITEM STRUCT DWORD
        imask             DWORD      ?
        hItem             DWORD      ?
        state             DWORD      ?
        stateMask         DWORD      ?
        pszText           DWORD      ?
        cchTextMax        DWORD      ?
        iImage            DWORD      ?
        iSelectedImage    DWORD      ?
        cChildren         DWORD      ?
        lParam            DWORD      ?
      TV_ITEM ENDS

Questa struttura è usata per trasmettere o ricevere informazioni circa una voce del tree view, secondo i messaggi. Per esempio, con TVM_INSERTITEM, è usata per specificare gli attributi della voce da inserire nel tree view control. Con TVM_GETITEM, sarà riempita di informazioni sulla voce selezionata nel tree view.

imask è usato per specificare quale(i) membro(i) della struttura TV_ITEM è(sono) valido(i). Per esempio, se il valore di imask è TVIF_TEXT , significa che soltanto il membro pszText è valido. Potete unire insieme parecchi flags.

hItem è l' handle di una voce del tree view. Ogni voce ha una propria handle, come l' handle di una finestra. Se desiderate fare qualcosa con una voce, dovete selezionarla tramite la relativa handle.

pszText è il puntatore ad una stringa null-terminata che è l'etichetta di una voce del tree view.

cchTextMax è usato soltanto quando desiderate richiamare l'etichetta di una voce del tree view. Poichè fornirete il puntatore a un buffer in pszText, Window deve conoscere la dimensione del buffer fornito. Dovete specificare la dimensione in questo membro.

iImage ed iSelectedImage si riferiscono all'indice in una lista di immagini che contiene le immagini da mostrare quando la voce non è selezionata e quando è selezionata. Se ricordate il pannello di sinistra di Windows Explorer, le immagini delle cartelle sono specificate da questi due membri. Per inserire una voce nel tree view control, dovete riempire almeno hParent, hInsertAfter e dovreste riempire anche imask e pszText.

Aggiunta di immagini al tree view control

Se desiderate mettere un'immagine alla sinistra dell'etichetta di una voce del tree view, dovete creare una lista di immagine ed associarla al tree view control. Potete creare una lista di immagine chiamando ImageList_Create.

ImageList_Create PROTO
          cx:DWORD,
          cy:DWORD,
          flags:DWORD,
          cInitial:DWORD,
          cGrow:DWORD

Questa funzione se riuscita restituisce l' handle ad una lista vuota di immagini. cx: larghezza di ogni immagine in questa lista di immagini, in pixel.

cy: altezza di ogni immagine in questa lista di immagini, in pixel. Ogni immagine in una lista di immagini deve essere uguale l'un l'altra nel formato. Se specificate una bitmap più grande, Window userà cx e cy per * tagliarla * in parecchie parti. Così dovreste preparare la vostra immagine come striscie di immagini con le dimensioni identiche.

flags: specifica i tipi di immagini in questa lista ,se sono a colori o monocromatiche e la loro intensità di colore. Consultate la vostra documentazione win32 api per più particolari.

cInitial: il numero di immagini che questa lista inizialmente conterrà. Window userà questa info per allocare la memoria per le immagini.

cGrow: la quantità di immagini che la lista può incorporare quando il sistema deve ridimensionarla per inserire nuove immagini. Questo parametro rappresenta il numero di nuove immagini che la lista ridimensionata può contenere.

Una lista di immagine non è una finestra! È soltanto un deposito di immagini ad uso di altre finestre. Dopo che una lista di immagine è stata creata, potete aggiungere le immagini ad essa chiamando ImageList_Add

ImageList_Add PROTO himl:DWORD, hbmImage:DWORD, hbmMask:DWORD

Questa funzione restituisce -1 se infruttuosa.

himl: handle della lista di immagine a cui desiderate aggiungere l' immagine. È il valore restituito da una chiamata riuscita a ImageList_Create

hbmImage: handle della bitmap da aggiungere alla lista di immagini. Solitamente memorizzate la bitmap nelle risorse e la caricate con la chiamata di LoadBitmap. Si noti che non dovete specificare il numero di immagini contenute in questa bitmap perché questa informazione è determinata dai parametri cx e cy passati da ImageList_Create.

hbmMask: handle della bitmask. Se nessuna maschera è usata con la lista di immagini, questo parametro è ignorato.

Normalmente, aggiungeremo soltanto due immagini alla lista per usarle con il tree view control: una usata quando la voce del tree view non è selezionata e l'altra quando è selezionata. Quando la lista di immagini è pronta, la associate con il tree view control trasmettendo TVM_SETIMAGELIST al tree view control.

TVM_SETIMAGELIST

wParam = tipo di lista di immagini da settare. Ci sono due scelte:

  • TVSIL_NORMAL Setta la lista di immagini normali, che contiene le immagini selezionata e non selezionata per una voce del tree-view.
  • TVSIL_STATE Setta la lista di immagini condizionate, che contiene le immagini per le voci del tree-view che sono in una condizione prestabilita dall'utente.

lParam = handle della lista di immagini


Richiamare le informazioni circa una voce del tree view

Potete richiamare le informazioni di una voce del tree view trasmettendo il messaggio TVM_GETITEM.

TVM_GETITEM

wParam = 0

lParam = puntatore alla struttura TV_ITEM da riempire con le informazioni

Prima che trasmettiate questo messaggio, dovete riempire il membro imask con i flag(s) che specificano quale membro(i) di TV_ITEM desiderate che Window riempia. E più importante, dovete riempire hItem con l'handle della voce di cui desiderate ottenere le informazioni. E questo crea un problema: Come potete conoscere l'handle della voce di cui desiderate richiamare l'Info? Dovrete memorizzare tutte l'handle del tree view? La risposta è abbastanza semplice: non dovete. Potete trasmettere il messaggio TVM_GETNEXTITEM al tree view control per ottenere l'handle della voce del tree view che ha gli attributi che avete specificato. Per esempio, potete chiedere l'handle della prima voce figlia, della voce alla radice, della voce selezionata e così via.

TVM_GETNEXTITEM

wParam = flag

lParam = handle per una voce del tree view (necessaria soltanto per alcuni valori di flag)

Il valore in wParam è molto importante. Presento tutti i flags qui sotto:

  • TVGN_CARET Ritorna la voce attualmente selezionata.
  • TVGN_CHILD Ritorna la prima voce figlia della voce specificata dal parametro hItem
  • TVGN_DROPHILITE Ritorna la voce che è l'obiettivo di un'operazione di drag-and-drop.
  • TVGN_FIRSTVISIBLE Ritorna la prima voce visibile.
  • TVGN_NEXT Ritorna la successiva voce figlia.
  • TVGN_NEXTVISIBLE Ritorna la successiva voce visibile seguente a quella specificata. La voce specificata deve essere visibile. Usate il messaggio TVM_GETITEMRECT per determinare se una voce è visibile.
  • TVGN_PARENT Ritorna la voce genitore della voce specificata.
  • TVGN_PREVIOUS Ritorna la precedente voce figlia.
  • TVGN_PREVIOUSVISIBLE Ritorna la prima voce visibile che precede quella specificata. La voce specificata deve essere visibile. Usate il messaggio TVM_GETITEMRECT per determinare se una voce è visibile.
  • TVGN_ROOT Ritorna la voce radice del tree-view control.

Si può notare che, potete richiamare l'handle della voce del tree view a cui siete interessati tramite questo messaggio. SendMessage restituisce l'handle della voce del tree view se riuscita. Potete allora inserire l'handle restituita nel membro hItem di TV_ITEM da usare con il messaggio TVM_GETITEM.

Operazione di Drag and Drop nel tree view control

Questa parte è il motivo per cui ho deciso di scrivere questo tutorial. Quando ho provato a seguire l'esempio del riferimento delle api win32 ( win32.hlp di InPrise), sono stato molto frustrato perché le informazioni vitali sono difettose. Dalle prove e dagli errori, infine ho capito come effettuare il drag & drop in un tree view control e non auguro a nessuno di percorrere la stessa strada che ho fatto io. Sotto è implementato in punti il drag & drop in un tree view control.

1) Quando l'utente prova a trascinare una voce, il tree view control trasmette la notifica TVN_BEGINDRAG alla finestra generatrice. Potete usare questa occasione per creare un'immagine per il drag che è l'immagine che sarà usata per rappresentare la voce mentre è trascinata. Potete trasmettere TVM_CREATEDRAGIMAGE al tree view control per dirgli di creare un'immagine di drag per l'immagine che attualmente è usata dalla voce che sarà trascinata. Il tree view control creerà una lista di immagini con solo un' immagine per il drag e restituirà l'handle della lista di immagini a voi.

2) Dopo che l'immagine di drag è stata creata, specificate l' hotspot dell'immagine di drag chiamando ImageList_BeginDrag.

ImageList_BeginDrag PROTO
himlTrack:DWORD,
iTrack:DWORD,
dxHotspot:DWORD,
dyHotspot:DWORD

himlTrack è l'handle della lista di immagini che contiene l'immagine di drag.

iTrack è l'indice nella lista di immagine che specifica l'immagine di drag

dxHotspot specifica la distanza relativa dell' hotspot nel piano orizzontale dell'immagine di drag che sarà usata al posto del cursore del mouse, in modo da specificare quale parte dell'immagine è l' hotspot.

dyHotspot specifica la distanza relativa dell' hotspot nel piano verticale. Normalmente, iTrack deve essere 0 se specificate al tree view control di creare l'immagine di drag per voi e dxHotspot , dyHotspot possono essere 0 se desiderate che l'angolo superiore di sinistra dell'immagine di drag sia l'hotspot.

3) Quando l'immagine di drag è pronta per essere visualizzata, chiamiamo 'ImageList_DragEnter per visualizzare l'immagine di drag nella finestra.

ImageList_DragEnter PROTO hwndLock:DWORD, x:DWORD, y:DWORD

hwndLock è l'handle della finestra che possiede l'immagine di drag. L'immagine di drag non potrà spostarsi nelle parti esterne alla finestra.

x e y sono x-e y-coordinate del posto in cui l'immagine di drag dovrebbe inizialmente essere visualizzata. Si noti che questi valori sono relativi all'angolo superiore sinistro della finestra, non alla zona del client.

4) Ora che l'immagine di drag è visualizzata nella finestra, dovrete supportare il funzionamento del drag nel tree view control. Tuttavia, c'è un piccolo problema. Dobbiamo controllare il percorso di drag con WM_MOUSEMOVE e la posizione di drop con i messaggi WM_LBUTTONUP. Tuttavia, se l'immagine di drag è sopra altre finestre figlie, la finestra generatrice non riceverà mai alcun messaggio del mouse. La soluzione è di bloccare l'input del mouse con SetCapture usando la chiamata, i messaggi del mouse saranno diretti verso la finestra specificata senza riguardo a dove il cursore del mouse si trova.

5) Tramite la ricezione di WM_MOUSEMOVE , aggiornerete il percorso di drag con la chiamata di ImageList_DragMove. Questa funzione sposta l'immagine che si sta trascinando durante l'operazione di drag-and-drop. Ancora, se volete, potete evidenziare la voce sottostante l'immagine di drag trasmettendo TVM_HITTEST per controllare se l'immagine di drag è sopra qualche voce. Se è così, potete trasmettere TVM_SELECTITEM con il flag TVGN_DROPHILITE per evidenziare la voce. Si noti che prima di inviare il messaggio TVM_SELECTITEM , dovete in primo luogo nascondere l'immagine di drag altrimenti la vostra immagine di drag lascerà delle tracce indesiderate. Potete nascondere l'immagine di drag chiamando ImageList_DragShowNolock e, dopo che l'operazione di evidenziamento è finita, chiamerete ImageList_DragShowNolock ancora per mostrare l'immagine di drag.

6) Quando l'utente libera il tasto di sinistra del mouse, dovete fare parecchie cose. Se avete evidenziato una voce, dovete rilasciarla trasmettendo TVM_SELECTITEM con ancora il flag TVGN_DROPHILITE, ma questo volta, lParam DEVE essere zero. Se non rilasciate la voce, otterrete un effetto indesiderato: quando selezionerete una certa altra voce, quella voce sarà racchiusa in un rettangolo ma sarà ancora evidenziata l'ultima voce selezionata. Successivamente, dovete chiamare ImageList_DragLeave seguito da ImageList_EndDrag. Dovete liberare il mouse chiamando ReleaseCapture. Se avete creato una lista di immagini, dovete distruggerla chiamando ImageList_Destroy. Dopo questo, potete procedere con cosa il vostro programma desiderate che faccia quando l'operazione di drag & drop è completata.

.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\comctl32.inc
include \masm32\include\gdi32.inc
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\comctl32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
.const
IDB_TREE equ 4006                ; ID of the bitmap resource
.data
ClassName  db "TreeViewWinClass",0
AppName    db "Tree View Demo",0
TreeViewClass  db "SysTreeView32",0
Parent  db "Parent Item",0
Child1  db "child1",0
Child2  db "child2",0
DragMode  dd FALSE                ; a flag to determine if we are in drag mode

.data?
hInstance  HINSTANCE ?
hwndTreeView dd ?            ; handle of the tree view control
hParent  dd ?                        ; handle of the root tree view item
hImageList dd ?                    ; handle of the image list used in the tree view control
hDragImageList  dd ?        ; handle of the image list used to store the drag image

.code
start:
    invoke GetModuleHandle, NULL
    mov    hInstance,eax
    invoke WinMain, hInstance,NULL,NULL, SW_SHOWDEFAULT
    invoke ExitProcess,eax
    invoke InitCommonControls

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
    LOCAL wc:WNDCLASSEX
    LOCAL msg:MSG
    LOCAL hwnd:HWND
    mov   wc.cbSize,SIZEOF WNDCLASSEX
    mov   wc.style, CS_HREDRAW or CS_VREDRAW
    mov   wc.lpfnWndProc, OFFSET WndProc
    mov   wc.cbClsExtra,NULL
    mov   wc.cbWndExtra,NULL
    push  hInst
    pop   wc.hInstance
    mov   wc.hbrBackground,COLOR_APPWORKSPACE
    mov   wc.lpszMenuName,NULL
    mov   wc.lpszClassName,OFFSET ClassName
    invoke LoadIcon,NULL,IDI_APPLICATION
    mov   wc.hIcon,eax
    mov   wc.hIconSm,eax
    invoke LoadCursor,NULL,IDC_ARROW
    mov   wc.hCursor,eax
    invoke RegisterClassEx, addr wc
    invoke CreateWindowEx,WS_EX_CLIENTEDGE,
                          ADDR ClassName,ADDR AppName, WS_OVERLAPPED+WS_CAPTION+WS_SYSMENU+WS_MINIMIZEBOX+WS_MAXIMIZEBOX+WS_VISIBLE,CW_USEDEFAULT,
           CW_USEDEFAULT,200,400,NULL,NULL,\
           hInst,NULL
    mov   hwnd,eax
    .while TRUE
        invoke GetMessage, ADDR msg,NULL,0,0
        .BREAK .IF (!eax)
        invoke TranslateMessage, ADDR msg
        invoke DispatchMessage, ADDR msg
    .endw
    mov eax,msg.wParam
    ret
WinMain endp

WndProc proc uses edi hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    LOCAL tvinsert:TV_INSERTSTRUCT
    LOCAL hBitmap:DWORD
    LOCAL tvhit:TV_HITTESTINFO
    .if uMsg==WM_CREATE
        invoke CreateWindowEx,NULL,ADDR TreeViewClass,NULL,\
            WS_CHILD+WS_VISIBLE+TVS_HASLINES+TVS_HASBUTTONS+TVS_LINESATROOT,0,\
            0,200,400,hWnd,NULL,\
            hInstance,NULL            ; Create the tree view control
        mov hwndTreeView,eax
        invoke ImageList_Create,16,16,ILC_COLOR16,2,10    ; create the associated image list
        mov hImageList,eax
        invoke LoadBitmap,hInstance,IDB_TREE        ; load the bitmap from the resource
        mov hBitmap,eax
        invoke ImageList_Add,hImageList,hBitmap,NULL    ; Add the bitmap into the image list
        invoke DeleteObject,hBitmap    ; always delete the bitmap resource
        invoke SendMessage,hwndTreeView,TVM_SETIMAGELIST,0,hImageList
        mov tvinsert.hParent,NULL
        mov tvinsert.hInsertAfter,TVI_ROOT
        mov tvinsert.item.imask,TVIF_TEXT+TVIF_IMAGE+TVIF_SELECTEDIMAGE
        mov tvinsert.item.pszText,offset Parent
        mov tvinsert.item.iImage,0
        mov tvinsert.item.iSelectedImage,1
        invoke SendMessage,hwndTreeView,TVM_INSERTITEM,0,addr tvinsert
        mov hParent,eax
        mov tvinsert.hParent,eax
        mov tvinsert.hInsertAfter,TVI_LAST
        mov tvinsert.item.pszText,offset Child1
        invoke SendMessage,hwndTreeView,TVM_INSERTITEM,0,addr tvinsert
        mov tvinsert.item.pszText,offset Child2
        invoke SendMessage,hwndTreeView,TVM_INSERTITEM,0,addr tvinsert
    .elseif uMsg==WM_MOUSEMOVE
        .if DragMode==TRUE
            mov eax,lParam
            and eax,0ffffh
            mov ecx,lParam
            shr ecx,16
            mov tvhit.pt.x,eax
            mov tvhit.pt.y,ecx
            invoke ImageList_DragMove,eax,ecx
            invoke ImageList_DragShowNolock,FALSE
            invoke SendMessage,hwndTreeView,TVM_HITTEST,NULL,addr tvhit
            .if eax!=NULL
                invoke SendMessage,hwndTreeView,TVM_SELECTITEM,TVGN_DROPHILITE,eax
            .endif
            invoke ImageList_DragShowNolock,TRUE
        .endif
    .elseif uMsg==WM_LBUTTONUP
        .if DragMode==TRUE
            invoke ImageList_DragLeave,hwndTreeView
            invoke ImageList_EndDrag
            invoke ImageList_Destroy,hDragImageList
            invoke SendMessage,hwndTreeView,TVM_GETNEXTITEM,TVGN_DROPHILITE,0
            invoke SendMessage,hwndTreeView,TVM_SELECTITEM,TVGN_CARET,eax
            invoke SendMessage,hwndTreeView,TVM_SELECTITEM,TVGN_DROPHILITE,0
            invoke ReleaseCapture
            mov DragMode,FALSE
        .endif
    .elseif uMsg==WM_NOTIFY
        mov edi,lParam
        assume edi:ptr NM_TREEVIEW
        .if [edi].hdr.code==TVN_BEGINDRAG
            invoke SendMessage,hwndTreeView,TVM_CREATEDRAGIMAGE,0,[edi].itemNew.hItem
            mov hDragImageList,eax
            invoke ImageList_BeginDrag,hDragImageList,0,0,0
            invoke ImageList_DragEnter,hwndTreeView,[edi].ptDrag.x,[edi].ptDrag.y
            invoke SetCapture,hWnd
            mov DragMode,TRUE
        .endif
        assume edi:nothing
    .elseif uMsg==WM_DESTROY
        invoke PostQuitMessage,NULL
    .else
        invoke DefWindowProc,hWnd,uMsg,wParam,lParam
        ret
    .endif
    xor eax,eax
    ret
WndProc endp
end start


Analisi

Nella risposta a WM_CREATE , create il tree view control

invoke CreateWindowEx,NULL,ADDR TreeViewClass,NULL,\
            WS_CHILD+WS_VISIBLE+TVS_HASLINES+TVS_HASBUTTONS+TVS_LINESATROOT,0,\
            0,200,400,hWnd,NULL,\
            hInstance,NULL

Notare gli stili. TVS_xxxx sono gli stili di specifica del tree view.

invoke ImageList_Create,16,16,ILC_COLOR16,2,10
mov hImageList,eax
invoke LoadBitmap,hInstance,IDB_TREE
mov hBitmap,eax
invoke ImageList_Add,hImageList,hBitmap,NULL
invoke DeleteObject,hBitmap
invoke SendMessage,hwndTreeView,TVM_SETIMAGELIST,0,hImageList

Successivamente, create una lista vuota di immagini che accetterà immagini nel formato 16x16 pixel, colore a 16 bit ed inizialmente, conterrà 2 immagini ma potrà essere espansa a 10 se sarà necessario. Quindi caricate la bitmap dalle risorse e aggiungetela alla lista di immagini appena creata. Dopo questo , cancellate l'handle della bitmap poiché non sarà più usata. Quando la lista di immagini è pronta, associatela con il tree view control trasmettendo TVM_SETIMAGELIST al controllo.

mov tvinsert.hParent,NULL
mov tvinsert.hInsertAfter,TVI_ROOT
mov tvinsert.u.item.imask,TVIF_TEXT+TVIF_IMAGE+TVIF_SELECTEDIMAGE
mov tvinsert.u.item.pszText,offset Parent
mov tvinsert.u.item.iImage,0
mov tvinsert.u.item.iSelectedImage,1
invoke SendMessage,hwndTreeView,TVM_INSERTITEM,0,addr tvinsert

Inserite le voci nel tree view control, cominciando dalla voce alla radice. Poiché sarà la voce alla radice, il membro hParent è NULL e hInsertAfter è TVI_ROOT. Il membro imask specifica che i membri pszText, iImage e iSelectedImage della struttura TV_ITEM sono validi. Riempite questi tre membri di valori adatti. pszText contiene l'etichetta della voce alla radice, iImage è l'indice dell'immagine nella lista di immagini che sarà visualizzata alla sinistra della voce non selezionata, ed iSelectedImage è l'indice dell'immagine nella lista di immagini che sarà visualizzata quando la voce sarà selezionata. Quando tutti i membri sono riempiti, trasmettete il messaggio TVM_INSERTITEM al tree view control per aggiungere la voce alla radice.

mov hParent,eax
mov tvinsert.hParent,eax
mov tvinsert.hInsertAfter,TVI_LAST
mov tvinsert.u.item.pszText,offset Child1
invoke SendMessage,hwndTreeView,TVM_INSERTITEM,0,addr tvinsert
mov tvinsert.u.item.pszText,offset Child2
invoke SendMessage,hwndTreeView,TVM_INSERTITEM,0,addr tvinsert

Dopo che la voce alla radice è stata aggiunta, potete attaccare le voci figlie, ad essa. hParent ora è riempito con l'handle della voce del genitore. Ed useremo le stesse immagini nella lista di immagini in modo da non cambiare i membri iSelectedImage e iImage.

.elseif uMsg==WM_NOTIFY
        mov edi,lParam
        assume edi:ptr NM_TREEVIEW
        .if [edi].hdr.code==TVN_BEGINDRAG
            invoke SendMessage,hwndTreeView,TVM_CREATEDRAGIMAGE,0,[edi].itemNew.hItem
            mov hDragImageList,eax
            invoke ImageList_BeginDrag,hDragImageList,0,0,0
            invoke ImageList_DragEnter,hwndTreeView,[edi].ptDrag.x,[edi].ptDrag.y
            invoke SetCapture,hWnd
            mov DragMode,TRUE
        .endif
        assume edi:nothing

Ora quando l'utente prova a trascinare una voce, il tree view control trasmette il messaggio WM_NOTIFY con TVN_BEGINDRAG come codice. lParam è il puntatore ad una struttura NM_TREEVIEW che contiene parecchie informazioni di cui abbiamo bisogno. Mettete il relativo valore in edi ed usate edi come puntatore alla struttura NM_TREEVIEW. assume edi:ptr NM_TREEVIEW è un modo di dire a MASM di trattare edi come puntatore alla struttura NM_TREEVIEW. Quindi crate un'immagine di drag trasmettendo TVM_CREATEDRAGIMAGE al tree view control. Esso restituisce l'handle alla lista di immagini recentemente creata con l'immagine di drag all'interno. Chiamate ImageList_BeginDrag per regolare l'hotspot nell'immagine di drag. Quindi azionate l'operazione di drag chiamando ImageList_DragEnter. Questa funzione visualizza l'immagine di drag alla posizione specificata nella finestra specificata. Usiamo la struttura ptDrag che è un membro della struttura NM_TREEVIEW come il punto in cui l'immagine di drag dovrebbe essere inizialmente mostrata. Dopo ciò, bloccate l'input del mouse e regolate i flags per indicare che inizia la modalità di drag.

.elseif uMsg==WM_MOUSEMOVE
        .if DragMode==TRUE
            mov eax,lParam
            and eax,0ffffh
            mov ecx,lParam
            shr ecx,16
            mov tvhit.pt.x,eax
            mov tvhit.pt.y,ecx
            invoke ImageList_DragMove,eax,ecx
            invoke ImageList_DragShowNolock,FALSE
            invoke SendMessage,hwndTreeView,TVM_HITTEST,NULL,addr tvhit
            .if eax!=NULL
                invoke SendMessage,hwndTreeView,TVM_SELECTITEM,TVGN_DROPHILITE,eax
            .endif
            invoke ImageList_DragShowNolock,TRUE
        .endif

Ora ci concentreremo su WM_MOUSEMOVE. Quando l'utente trascina l'immagine di drag avanti, la nostra finestra generatrice riceve i messaggi WM_MOUSEMOVE. In risposta a questi messaggi, aggiornate la posizione dell'immagine di drag con ImageList_DragMove. Dopo ciò, controllate se l'immagine di drag è sopra una certa voce. Fate questo trasmettendo il messaggio TVM_HITTEST al tree view control con un punto da controllare. Se l'immagine di drag è sopra una certa voce, evidenziate quella voce trasmettendo il messaggio TVM_SELECTITEM con il flag TVGN_DROPHILITE al tree view control. Durante l'operazione di evidenziamento, nascondete l'immagine di drag in modo che non lasci delle macchie sgradevoli sul tree view control.

.elseif uMsg==WM_LBUTTONUP
        .if DragMode==TRUE
            invoke ImageList_DragLeave,hwndTreeView
            invoke ImageList_EndDrag
            invoke ImageList_Destroy,hDragImageList
            invoke SendMessage,hwndTreeView,TVM_GETNEXTITEM,TVGN_DROPHILITE,0
            invoke SendMessage,hwndTreeView,TVM_SELECTITEM,TVGN_CARET,eax
            invoke SendMessage,hwndTreeView,TVM_SELECTITEM,TVGN_DROPHILITE,0
            invoke ReleaseCapture
            mov DragMode,FALSE
        .endif

Quando l'utente libera il tasto di sinistra del mouse, l'operazione di drag è alla fine. Lasciate la modalità di drag chiamando ImageList_DragLeave, seguita da ImageList_EndDrag e da ImageList_Destroy. Ricreate le voci del tree view in modo corretto, controllate anche l'ultima voce evidenziata e la selezionate. Dovete poi deselezionarla altrimenti le altre voci non verranno evidenziate quando selezionate. Ed infine, liberate il bloccaggio del mouse.


Disclaimer

I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.

Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevole e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.