|
<P>马哥做了几个小例子大多都关于子类处理的 ,很有用,我从网上找了点关于子类化的东东,和俺一样很菜的来看看把!</P>
<B>1.</B><B> </B><B>何谓子类化(</B><B>subclassing</B><B>)</B><B><p></p></B></P>
众所周知,Windows是一个基于消息的系统,消息在Windows的对象之间进行着传递。子类化和Windows的钩子机制存在于消息系统之中,我们可以利用这些机制来操纵、修改甚至丢弃那些在操作系统或是进程中传递的消息,以求改变系统的一些行为。<p></p></P>
子类化技术用来截取窗口或控件之间的消息,当然是消息在到达目的窗口之前完成的操作。这些被截获的消息既可以保留也可以修改它们的状态,之后就继续发送到目的地。子类化技术实现了一些正常情况下无法实现的功能,试想鼠标右键单击TextBox,系统默认弹出Undo、Cut、Copy、Paste等菜单,我们就可以利用子类化技术来改变这个系统菜单。<p></p></P>
简单的说,子类化就是创建一个新的窗口消息处理过程,并将其插入到原先的默认窗口消息处理过程之前。<p></p></P>
子类化分为三类:实例子类化(instance subclassing)—从窗口或控件的单一实例截获消息,这种子类化技术最普遍;全局子类化(global subclassing)—能够截获从相同的窗口类创建出来的多个窗口或控件的消息;超类化(superclassing)—和全局子类化很类似,区别在于可以应用在新的窗口类上面。<p></p></P>
<p></p></P>
<B>2. Visual Basic 6</B><B>子类化的实现</B><p></p></P>
在Visual Basic 6子类化的实现中我将通过一段代码的实例来介绍这一技术在VB6中的应用。下面的例子将演示如何将About加入窗口的系统菜单。</P>
<B>①创建工程</B><B><p></p></B></P>
启动Visual Basic 6同时创建一个标准EXE工程。<p></p></P>
<p></p></P>
<B>②在窗体中录入代码</B><B><p></p></B></P>
Private Declare Function GetSystemMenu Lib "user32" (ByVal hWnd As Long, ByVal bRevert As Long) As Long<p></p></P>
Private Declare Function InsertMenu Lib "user32" Alias "InsertMenuA" (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long, ByVal wIDNewItem As Long, ByVal lpNewItem As String) As Long<p></p></P>
<p></p></P>
Private Const MF_BYCOMMAND = &H0&<p></p></P>
Private Const MF_BYPOSITION = &H400&<p></p></P>
Private Const MF_STRING = &H0&<p></p></P>
Private Const MF_SEPARATOR = &H800&<p></p></P>
<p></p></P>
<p></p></P>
Private Sub Form_Load()<p></p></P>
InsertMenu GetSystemMenu(Me.hWnd, False), 0, MF_BYPOSITION Or MF_SEPARATOR, 2001, ""<p></p></P>
InsertMenu GetSystemMenu(Me.hWnd, False), 0, MF_BYPOSITION Or MF_STRING, 2002, "About Me(&A)"<p></p></P>
'安装子类化入口<p></p></P>
Call Init(Me.hWnd)<p></p></P>
End Sub<p></p></P>
<p></p></P>
Private Sub Form_Unload(Cancel As Integer)<p></p></P>
‘卸载子类化<p></p></P>
Call Terminate(Me.hWnd)<p></p></P>
End Sub<p></p></P>
<p></p></P>
<B>③加入一个模块并录入代码</B><B><p></p></B></P>
Option Explicit<p></p></P>
<p></p></P>
Private Declare Function SetWindowLong Lib "user32" Alias _<p></p></P>
"SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex _<p></p></P>
As Long, ByVal dwNewLong As Long) As Long<p></p></P>
<p></p></P>
Private Declare Function CallWindowProc Lib "user32" Alias _<p></p></P>
"CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal _<p></p></P>
hWnd As Long, ByVal Msg As Long, ByVal wParam As _<p></p></P>
Long, ByVal lParam As Long) As Long<p></p></P>
<p></p></P>
Const GWL_WNDPROC = (-4&)<p></p></P>
<p></p></P>
Dim PrevWndProc&<p></p></P>
<p></p></P>
Private Const WM_SYSCOMMAND = &H112<p></p></P>
Const WM_DESTROY = &H2<p></p></P>
‘子类化入口<p></p></P>
Public Sub Init(hWnd As Long)<p></p></P>
PrevWndProc = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf SubWndProc)<p></p></P>
End Sub<p></p></P>
‘子类化出口<p></p></P>
Public Sub Terminate(hWnd As Long)<p></p></P>
Call SetWindowLong(hWnd, GWL_WNDPROC, PrevWndProc)<p></p></P>
End Sub<p></p></P>
‘新的窗口消息处理过程,将被插入到默认处理过程之前<p></p></P>
Private Function SubWndProc(ByVal hWnd As Long, ByVal Msg As Long, _<p></p></P>
ByVal wParam As Long, ByVal lParam As Long) _<p></p></P>
As Long<p></p></P>
If Msg = WM_DESTROY Then Terminate (Form1.hWnd)<p></p></P>
<p></p></P>
If wParam = 2002 Then<p></p></P>
MsgBox "我是40Star", vbInformation, "hia..hia..."<p></p></P>
End If<p></p></P>
‘调用默认的窗口处理过程<p></p></P>
SubWndProc = CallWindowProc(PrevWndProc, hWnd, Msg, wParam, lParam)<p></p></P>
End Function <p></p></P>
' -- 模块结束 -- '<p></p></P>
<p></p></P>
但是,需要指出的是不正确的子类化是非常危险的,将导致一个General Protection Fault(GPF)错误,致使VB应用立即崩溃。<p></p></P>
<p></p></P>
<B>3. Visual Basic .NET</B><B>子类化的实现</B><B><p></p></B></P>
在.NET中使用子类化技术要比VB6中简单,因为微软在.NET中已经提供了接口,不需要我们再自己SetWindowLong了,我们做的是Overrides(覆盖) WndProc过程即可。<p></p></P>
Overrides Protected Sub WndProc( ByRef m As Message )<p></p></P>
参数m实现了Windows的消息类型。<p></p></P>
下面的例子将同样演示如何将About加入窗口的系统菜单。<p></p></P>
<B>①创建工程</B><B><p></p></B></P>
创建一个VB.NET的Windows Application工程。<p></p></P>
<p></p></P>
<B>②录入代码</B><B><p></p></B></P>
Public Class Form1<p></p></P>
Inherits System.Windows.Forms.Form<p></p></P>
<p></p></P>
‘中间隐去了.NET自动生成的代码<p></p></P>
‘ – 引用Win32Api – ‘<p></p></P>
Private Declare Function GetSystemMenu Lib "user32" (ByVal hWnd As IntPtr, ByVal bRevert As Int32) As Int32<p></p></P>
Private Declare Function InsertMenu Lib "user32" Alias "InsertMenuA" (ByVal hMenu As Int32, ByVal nPosition As Int32, ByVal wFlags As Int32, ByVal wIDNewItem As Int32, ByVal lpNewItem As String) As Int32<p></p></P>
<p></p></P>
Private Const MF_BYCOMMAND = &H0&<p></p></P>
Private Const MF_BYPOSITION = &H400&<p></p></P>
Private Const MF_STRING = &H0&<p></p></P>
Private Const MF_SEPARATOR = &H800&<p></p></P>
Private Const WM_SYSCOMMAND = &H112<p></p></P>
<p></p></P>
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load<p></p></P>
InsertMenu(GetSystemMenu(Me.Handle, False), 0, MF_BYPOSITION Or MF_SEPARATOR, 2001, "") '加入一条分割线<p></p></P>
‘GetSystemMenu(Me.Handle, False)是得到系统菜单的句柄,第二个参数为True的话不能改变系统菜单,所以要设为False<p></p></P>
InsertMenu(GetSystemMenu(Me.Handle, False), 0, MF_BYPOSITION Or MF_STRING, 2002, "About Me(&A)") '加入About me菜单在系统菜单中<p></p></P>
End Sub<p></p></P>
‘子类化窗口--覆盖WndProc过程<p></p></P>
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)<p></p></P>
If m.Msg = WM_SYSCOMMAND Then<p></p></P>
If m.WParam.ToInt32 = 2002 Then<p></p></P>
MsgBox("我是40Star", vbInformation, "hia..hia...")<p></p></P>
End If<p></p></P>
End If<p></p></P>
‘调用窗口默认的处理过程<p></p></P>
MyBase.WndProc(m)<p></p></P>
End Sub<p></p></P>
End Class<p></p></P>
<p></p></P>
<B>4. </B><B>小结</B><p></p></P>
子类化技术可以让我们实现一些使用VB在正常条件下无法完成的任务,而且通过这些技术可以更为深入的学习Windows编程,成为VB开发人员中的高手。</P>
</P>
好了希望大家在本论坛愉快!</P> |
|