Public Declare Function CallWindowProc& Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc&, ByVal hWnd&, ByVal Msg&, ByVal wParam&, ByVal lParam&) Public Declare Sub DragAcceptFiles Lib "shell32.dll" (ByVal hWnd&, ByVal fAccept&) Public Declare Function DragQueryFile& Lib "shell32.dll" Alias "DragQueryFileA" (ByVal hDrop&, ByVal iFile&,ByVal lpszFile$, ByVal cch&) Public Declare Sub DragFinish Lib "shell32.dll" (ByVal hDrop&) Private Declare Function SetWindowLong& Lib "user32" Alias "SetWindowLongA" (ByVal hWnd&,ByVal nIndex&, ByVal dwNewLong&) |
参数 | 意义 |
hwnd | Long,欲为其取得信息的窗口的句柄 |
nIndex | Long,这里取GWL_WNDPROC,表示设置该窗口的窗口函数的地址 |
dwNewLong | Long,由nIndex指定的窗口信息的新值 |
返回值 | Long,指定数据的前一个值 |
procOld = SetWindowLong(Me.hwnd, GWL_WNDPROC, AddressOf WindowProc) |
DragAcceptFiles、DragQueryFile、DragFinish三个函数的作用分别是:把某个窗口设置为接收拖放的容器、返回拖放的文件的数量和信息、终止拖放。
为了学习方便,以下提供了源代码:
''------------------------------------------- '' 采用API实现的文件拖放 ''------------------------------------------- ''程序说明: ''本例是采用子类派生技术实现的文件从EXPLORE到vb程序的拖放 '' 通过三个API函数DragAcceptFiles、DragQueryFiles和 ''DragFinish,并通过回调函数WindowProc,窗口属性函数 ''SetWindowLong、CallWindowProc的使用实现,而另一种同样 ''效果的实现方法:OLE拖放,你可以参照文件拖放的另外一个实 ''例。 ''------------------------------------------- Option Explicit Private Const GWL_WNDPROC As Long = (-4&) '' API call to alter the class data for this window Private Declare Function SetWindowLong& Lib "user32" Alias "SetWindowLongA" (ByVal hWnd&, _ ByVal nIndex&, ByVal dwNewLong&) Private Sub Form_Load() ''定义 Picture1作为接收文件拖放的容器 DragAcceptFiles Me.hWnd, 1& ''整个procOld变量用来存储窗口的原始参数,以便恢复 '' 调用了 SetWindowLong 函数,它使用了 GWL_WNDPROC 索引来创建窗口类的子类,通过这样设置 ''操作系统发给窗体的消息将由回调函数 (WindowProc) 来截取, AddressOf是关键字取得函数地址 procOld = SetWindowLong(Me.hWnd, GWL_WNDPROC, AddressOf WindowProc) ''AddressOf是一元运算符,它在过程地址传送到 API 过程之前,先得到该过程的地址 End Sub Private Sub Form_Unload(Cancel As Integer) ''此句关键,把窗口(不是窗体,而是具有句柄的任一控件,这里指Picture1)的属性复原 Call SetWindowLong(Me.hWnd, GWL_WNDPROC, procOld) End Sub Public Sub DropFiles(ByVal hDrop&) Dim sFileName$, IReturn& Dim nCount&, I As Integer ''为sFileName分配存储空间 sFileName = String$(MAX_PATH, vbNullChar) ''通过文件指针hDrop, DragQueryFile返回是否有文件拖放,nCount返回拖放文件的个数 nCount = DragQueryFile(hDrop, -1, sFileName, MAX_PATH) ''循环读取每一个拖放的文件,把它在列表框中显示出来 For I = 0 To nCount - 1 sFileName = String$(MAX_PATH, vbNullChar) ''如果有文件拖放,接收文件名,并试图把它在图片框中打开 ''IReturn& IReturn& = DragQueryFile(hDrop, I, sFileName, MAX_PATH) List1.AddItem Left$(sFileName, IReturn) Next I ''完成拖放操作 DragFinish hDrop End Sub ''以下代码放在moudle中 Option Explicit Public Const MAX_PATH As Long = 260& ''标示我们要截获的消息 Public Const WM_DROPFILES As Long = &H233& ''保存原 窗体属性的变量,其实是默认的 窗体函数 的地址 Public procOld As Long '' Public Declare Function CallWindowProc& Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc&, _ ByVal hWnd&, ByVal Msg&, ByVal wParam&, ByVal lParam&) ''拖放操作相关的API函数 Public Declare Sub DragAcceptFiles Lib "shell32.dll" (ByVal hWnd&, ByVal fAccept&) Public Declare Function DragQueryFile& Lib "shell32.dll" Alias "DragQueryFileA" (ByVal hDrop&, ByVal iFile&, _ ByVal lpszFile$, ByVal cch&) Public Declare Sub DragFinish Lib "shell32.dll" (ByVal hDrop&) ''WARNING!!!!----------------------------------------------------------- ''注意这段代码是不能用DEBUG一步步调试的,否则会造成错误(崩溃) ''对消息截获的机制可以按下述理解: '' 这里要仔细理解一下,我们为窗体新指定了窗体函数地址,也就是说操作系统发送给窗体的 ''消息将被 WindowProc函数 所截获(而改变前消息是被默认的 窗体函数 所获得并作相应处理的) '' 这样我们在 WindowProc函数 中对所截获的消息进行判断,会有三种情况: ''<1>如果是需要通过程序来处理的消息就通过 WindowProc函数 中的相应语句处理; ''<2>如果是要原来的 窗体函数 来处理则把这个消息传递给原窗体函数(其实是指针指向的改变); ''<3>如果不是我们需要的消息,也传递给原 窗体函数 来处理。 ''可以参见 改变系统菜单 中的源码注释 ''WARNING!!!!----------------------------------------------------------- ''回调函数,用来截取消息 Public Function WindowProc(ByVal hWnd As Long, ByVal iMsg As Long, _ ByVal wParam As Long, ByVal lParam As Long) As Long ''确定接收到的是什么消息 Select Case iMsg ''如果是 通知文件放下 的消息,就拦截消息 Case WM_DROPFILES ''通知在FORM模块中定义的DropFiles函数来接收 指向 放下的文件 的句柄 frmDragDropFiles.DropFiles wParam ''返回0并退出这个WindowProc WindowProc = False Exit Function End Select ''如果不是我们需要的消息,则传递给原来的窗体函数处理 WindowProc = CallWindowProc(procOld, hWnd, iMsg, wParam, lParam) End Function |