找回密码
 加入我们

QQ登录

只需一步,快速开始

搜索
查看: 4664|回复: 5

[建议]关于子类化处理!

[复制链接]

54

主题

345

回帖

0

精华

铂金会员

天马行空

积分
2205
发表于 2005-5-8 19:49:47 | 显示全部楼层 |阅读模式
<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 = &amp;H0&amp;<p></p></P>
Private Const MF_BYPOSITION = &amp;H400&amp;<p></p></P>
Private Const MF_STRING = &amp;H0&amp;<p></p></P>
Private Const MF_SEPARATOR = &amp;H800&amp;<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(&amp;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&amp;)<p></p></P>
<p></p></P>
Dim PrevWndProc&amp;<p></p></P>
<p></p></P>
Private Const WM_SYSCOMMAND = &amp;H112<p></p></P>
Const WM_DESTROY = &amp;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 = &amp;H0&amp;<p></p></P>
Private Const MF_BYPOSITION = &amp;H400&amp;<p></p></P>
Private Const MF_STRING = &amp;H0&amp;<p></p></P>
Private Const MF_SEPARATOR = &amp;H800&amp;<p></p></P>
Private Const WM_SYSCOMMAND = &amp;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(&amp;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>
爱情是狗屁,不如好好去努力, 享受生活才是快乐的真谛! 本人比较菜,多多指教!

54

主题

345

回帖

0

精华

铂金会员

天马行空

积分
2205
 楼主| 发表于 2005-5-10 11:32:29 | 显示全部楼层
<P>哈哈!</P><P>小部长没事也来看看哦! </P>
爱情是狗屁,不如好好去努力, 享受生活才是快乐的真谛! 本人比较菜,多多指教!

275

主题

3017

回帖

1

精华

管理员

嗷嗷叫的老马

积分
17064

论坛牛人贡献奖关注奖最佳版主进步奖人气王疯狂作品奖精英奖赞助论坛勋章乐于助人勋章

QQ
发表于 2005-5-10 21:52:25 | 显示全部楼层
主要问题是,先要了解WINDOWS的工作机制-------消息.
我就是嗷嗷叫的老马了......

54

主题

345

回帖

0

精华

铂金会员

天马行空

积分
2205
 楼主| 发表于 2005-5-10 23:05:42 | 显示全部楼层
<P>马哥说的没错,要了解windows的机制 原理就好!!</P>
爱情是狗屁,不如好好去努力, 享受生活才是快乐的真谛! 本人比较菜,多多指教!

275

主题

3017

回帖

1

精华

管理员

嗷嗷叫的老马

积分
17064

论坛牛人贡献奖关注奖最佳版主进步奖人气王疯狂作品奖精英奖赞助论坛勋章乐于助人勋章

QQ
发表于 2005-5-19 22:46:17 | 显示全部楼层
了解了这种机制,对编程极有好处.
我就是嗷嗷叫的老马了......

275

主题

3017

回帖

1

精华

管理员

嗷嗷叫的老马

积分
17064

论坛牛人贡献奖关注奖最佳版主进步奖人气王疯狂作品奖精英奖赞助论坛勋章乐于助人勋章

QQ
发表于 2005-5-25 21:50:33 | 显示全部楼层
我来整理一个吧。
我就是嗷嗷叫的老马了......

您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

快速回复 返回顶部 返回列表