Tutorial
Windows Drag und Drop Tutorial
von stephanbrunker | Seite 5 von 12 |
Der Code für IDropTarget
Nachdem wir jetzt das Interface haben, müssen wir das nur noch in unser Programm einbauen. Wenn wir jetzt für IUnknown, IDataObject und IDropTarget jeweils eigene Dateien erzeugen, sehen die Includes so aus:
#Include "windows.bi"
#Include "win\commctrl.bi"
#Include "win\shellapi.bi"
#Include "win\commdlg.bi"
#Include "vbcompat.bi"
#Include "win\ole2.bi"
#Include "win\shlobj.bi"
#Include "win\winbase.bi"
#Include "windows-fix.bi"
#Undef RegisterDragDrop
#Include "IUnknown.bas"
#Include "IDataObject.bas"
#Include "IDropTarget.bas"
Declare Function RegisterDragDrop Alias "RegisterDragDrop" (ByVal As HWND, ByVal As IDropTarget Ptr ) As HRESULT
'Include our own *.bi
#Include "Dialog.bi"
Wir müssen zuerst einmal die *.bi für OLE und ein paar andere Sachen laden. Da für die Interfaces eine vordefinierte Implementation vorhanden ist, wurden diese mit #Undef freigegeben. Weil sich die Datentypen damit ändern, definiert man RegisterDragDrop am besten auch noch mal neu, sonst meckert der Compiler, da der IDropTarget Ptr von vor der Neudefinition ein anderer ist als der danach. Ob wir das vorne bei den includes haben oder direkt vor und nach den neuen Typen in den jeweiligen Dateien, ist Geschmackssache. pDropTarget kommt als shared in unsere *.bi.
Beim Programmstart kommen dann folgende Anweisungen dazu:
OleInitialize(NULL)
...
'DragDrop: Formats to accept and create the interface for it
Dim fmtetc (0 To 0) As FORMATETC
With fmtetc(0)
.cfFormat = CF_HDROP
.tymed = TYMED_HGLOBAL
.dwAspect = DVASPECT_CONTENT
.ptd = NULL
.lindex = -1
End With
pDropTarget = New IDROPTARGET(hLSV1,fmtetc() )
'tell OLE that the Listview is a drop target and associate a interface
RegisterDragDrop(hLSV1, pDropTarget)
OLE will in dem Fall zuerst initialisiert werden, dann legen wir das Format fest, dass wir als Drop akzeptieren wollen und erzeugen das Interface mit NEW als Pointer, den wir dann mit RegisterDragDrop an OLE übergeben. Das müssen wir natürlich am Programmende alles wieder freigeben. Das Interface löscht sich selbst, wenn wir unsere eigene Referenz freigeben und es bei OLE deregistrieren:
RevokeDragDrop(hLSV1)
pDropTarget->Release()
OleUninitialize()
Bleibt dann nur noch die DataDrop-Funktion, die wir aus dem Interface heraus aufgerufen haben.
Function DataDrop (ByVal hWin As HWND, ByVal pfmtetc As FORMATETC Ptr, ByVal pstgmed As STGMEDIUM Ptr) As Integer
Select Case hWin
Case hLSV1
'drop on our Listview
Select Case pfmtetc->cfFormat
Case CF_HDROP
'get the HDROP handle:
Dim dropfiles As HDROP = GlobalLock(pstgmed->hGlobal)
Dim tempstring As ZString * MAX_PATH
Dim As String filepath,filetitle
Dim As Integer index,i,j
'get number of files dropped
index = DragQueryFile(dropfiles,-1,@tempstring,SizeOf(tempstring))
'get file and break it up into Path and Filename
For i=0 To index-1
DragQueryFile(dropfiles,i,@tempstring,SizeOf(tempstring))
filepath=Left(tempstring,InStrRev(tempstring,"\"))
filetitle=LTrim(tempstring,filepath)
AddListViewRow(hLSV1,filepath,filetitle,hLarge1,hSmall1)
Next i
'Unlock the Global Memory:
GlobalUnlock(pstgmed->hGlobal)
Case Else
'if we accept other formats ...
'implement here
End Select
End Select
Return TRUE
End Function
Die Funktion ist aber ziemlich analog dessen, was wir bei der WM_DROPFILES Message schon hatten. Wenn wir am Anfang mehrere Formate freigegeben haben, müssen wir die natürlich auch im Drop auswerten. An der ganzen Vorgehensweise ist nichts außergewöhnlich, außer dass vielleicht alles über GLOBAL Memory läuft, was bedeutet, das wir den erhaltenen Pointer mit GlobalLock reservieren müssen und nach Gebrauch wieder freigeben. Um zu zeigen, wie man mehrere verschiedene Drops akzeptieren kann und das CF_TEXT-Format vorzustellen, gibt es eine zweite Version des Codes mit einer zusätzlichen Editbox, die CF_TEXT akzeptiert. Da dieses Format einen Null-terminierten Pointer ins GlobalMemory stellt, kann man den direkt für SetWindowText verwenden.
Die zwei Varianten des Programms:
DragDrop2.zip
DragDrop2a.zip
Und wenn wir jetzt nicht nur Drops akzeptieren wollen, sondern selbst die Quelle sein wollen? Dazu müssen wir uns gleich drei zusätzliche Interfaces ansehen: IDropSource, IDataObject und IEnumFormatEtc .
Zusätzliche Informationen und Funktionen | |||||||
---|---|---|---|---|---|---|---|
|
|