VB中用API实现文件拖放

       借助API函数CallWindowProc、DragAcceptFiles、DragQueryFile、DragFinish同样可以实现文件从资源管理器EXPLORE到应用程序的拖放,另一种方法是采用OLE拖放,可以参照趣味编程栏目的相关内容。下面我们一起来看看程序编写的过程。
  借助API函数CallWindowProc、DragAcceptFiles、DragQueryFile、DragFinish同样可以实现文件从资源管理器EXPLORE到应用程序的拖放,另一种方法是采用OLE拖放,可以参照趣味编程栏目的相关内容。下面我们一起来看看程序编写的过程。

  对于每个需要引用的API函数,我们需要先在程序中说明,如果只在某一窗体内声明并使用它,则把它声明为Private,而如果在模块中声明,且需要在整个工程内使用它,则需要把它声明为Public。

     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&)

  SetWindowLong函数的作用是在窗口结构中为指定的窗口设置属性,利用它我们来改变窗口的属性参数,其中各个参数的意义如下表所示:

参数 意义 hwnd Long,欲为其取得信息的窗口的句柄 nIndex Long,这里取GWL_WNDPROC,表示设置该窗口的窗口函数的地址 dwNewLong Long,由nIndex指定的窗口信息的新值
  返回值 Long,指定数据的前一个值

  在默认状态下WINDOWS操作系统会指定一个窗口函数来接受和处理WINDOWS消息,而通过使用SetWindowLong函数改变窗口函数的地址使它指向我们自己写的一个函数WindowProc,这样WINDOWS消息就会转由WindowProc函数接收和处理。于是我们就能判断文件拖放的消息并进行处理。改变窗口属性的语句如下:

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

 

  附:子类派生技术

  WINDOWS运行的基础是“消息机制”,所谓的“消息”是一个唯一的值,这个值会被一个窗体或操作系统收到,它能告诉什么事件发生了以及需要采用什么样的动作来响应。这与我们人类的神经系统将感知的信息传递给大脑,而大脑发出指令给我们的身体非常相似。于是每一个窗体都具有一个消息句柄,这个机制使得所有发自于WINDOWS操作系统的消息能被接收到需要强调的是每个窗体以及每个控件,包括按钮、文本框、图片框等都具有这样的消息句柄。WINDOWS操作系统会跟踪这些消息句柄,这称为类结构中的一个WindowProc,所谓的类结构是于窗体句柄相关联的。

  当我们加入一个新的WindowProc函数而这个WindowProc与原始的窗体函数相符合的话,我们称这个窗被子类化了。换言之,如果WINDOWS操作系统发给你所在的WindowProc一个消息,而你所在的WindowProc正在响应其它的动作,这时你必须将剩余的消息传递给一个默认的WindoProc。

  如下所示: 操作系统消息-->你所在WindoProc-->默认的WindoProc而一个窗体是可以被子类化多次的,这样就产生了如下的情况:

  Windows Message Sender --> Your WindowProc --> Another WindowProc _--> Yet Another WindowProc --> Default WindowProc

  What is subclassing anyway?

  通过窗体子类化,你可以改变响应消息的顺序,也就是说,你可以把消息传递到默认的WindowProc上而不立即响应。举个例子:

  如果我们要在接收到WM_PAINT 消息后,在窗体上画出一些东西,可以用下面的语句实现:

Public Function WindowProc(Byval hWnd, Byval etc....)
    Select Case iMsg      '筛选出WM_PAINT消息
        Case SOME_MESSAGE    '如果是其他消息
        DoSomeStuff
        Case WM_PAINT    '如果是WM_PAINT 消息
        '首先把消息传递给一个默认的WindowProc
        WindowProc = CallWindowProc(procOld, hWnd, iMsg, wParam, lParam)
        DoDrawingStuff      '进行画图操作
        Exit Function
        '因为我们已经把消息传递给默认的WindowProc,我们可以退出这个WindowProc
        '
    End Select
    '
 End Function
摘自:网络整理
 
   

VB

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值