我是靠谱客的博主 感动糖豆,最近开发中收集的这篇文章主要介绍子类化和超类化(win32 SDK),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

                                                            子类化和超类化(win32 SDK)

本文所提到的子类化和超类化中的“类”并不是C++中的“类”,而是windows32 SDK编程中的RegisterClass函数用到的类,比如一个窗口类,它是WNDCLASS或者是WNDCLASSEX这样的一个结构。虽然它和C++中的“类”并不是一个概念,但是却有许多相似之处,即它们都有“模板”这样的一个概念或者功能。这里的子类化是对窗口功能的调整与扩展,而超类化是对类功能的调整与扩展。下面我们就用2个实例分别说明这两个概念。

文本输入框,我们可能都很熟悉,一般的文本输入框可以输入任何的字符,而当我们指定了ES_NUMBER风格之后,则该文本框只能输入数字,假设我们现在要求文本框只能输入16进制数,那么该怎么处理呢?如果我们重写文本框控件的所有功能,显然是吃力不讨好的事情,可是现有的文本框又不能满足我们的要求,它的所有功能都被windows封装起来了,没法直接修改,这样,一个好的方法就是我们继承原来的文本框,但是在此基础上进行小小的修改, 我们拦截windows发给文本框的WM_CHAR消息,然后判断输入的字符是不是'0'-'9','a'-'f'('A'-'F'),如果是,则我们将消息转发给文本框的默认窗口处理过程,否则,我们将消息丢弃,这样文本框就不能接收到除了16进制字符以外的字符消息了,即其它的字符被屏蔽了,但是其它的非WM_CHAR消息仍然丢给默认的窗口过程。

下面的程序,在16进制和10进制数之间进行相互的转换。16进制文本编辑框是我们子类化的控件。代码如下:

// resource.h
// 资源的ID值定义
#define IDD_MAIN                        101
#define IDC_HEX                         1001
#define IDC_DEC                         1002
#define IDC_STATIC                      -1

// SubClass.rc
// 资源文件
#include "resource.h"
#include "afxres.h"


// 对话框定义
// Dialog
//

IDD_MAIN DIALOG DISCARDABLE  0, 0, 130, 47
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Hex <> Dec"
FONT 10, "System"
BEGIN
    LTEXT           "Hex",IDC_STATIC,7,7,22,8
    LTEXT           "Dec",IDC_STATIC,7,29,22,8
    EDITTEXT        IDC_HEX,39,7,79,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_DEC,39,26,79,14,ES_AUTOHSCROLL | ES_NUMBER
END

//SubClass.c
// 实现文件
#include <windows.h>
#include "resource.h"

HWND        hWinMain = NULL; // 主对话框句柄
DWORD        dwOption = 0;    // 标志位,用于控制WM_COMMAND消息的处理
WNDPROC        lpOldProcEdit = NULL; // 16进制编辑框的默认窗口过程地址

char        szFmtDec2Hex[] = "%08X";
char        szFmtHex2Dec[] = "%u";
// 16进制编辑框允许输入的字符,/x08表示的退格键,用于删除一个字符
char        szAllowedChar[] = "0123456789ABCDEFabcdef/x08";


// 新的16进制编辑框窗口处理过程,这里根据需要只拦截了WM_CHAR消息
// 其它的消息,仍然由原来的窗口处理过程来处理
LRESULT CALLBACK ProcEdit(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    int i;
    if ( uMsg == WM_CHAR )
    {
        for (i = 0; i < sizeof(szAllowedChar); i++ )
        {
            if ( szAllowedChar[i] == (char)wParam )
            { // 将小写的'a'-'f'转换为大写
                if ( wParam > '9' )
                {
                    wParam &= ~0x20;
                }
                return CallWindowProc(lpOldProcEdit, hWnd, uMsg, wParam, lParam);
            }
        }
        return TRUE;
    }
    return CallWindowProc(lpOldProcEdit, hWnd, uMsg, wParam, lParam);
}

// 将16进制数值转换为10进制
void Hex2Dec()
{
    char szBuffer[512];
    unsigned long res = 0;
    unsigned int nbase = 1;
    int nLen;
    int i;
    unsigned int tmp;
    GetDlgItemText(hWinMain, IDC_HEX, szBuffer, sizeof(szBuffer));
    nLen = strlen(szBuffer);
    nLen--;
    for ( i = nLen; i >=0; i-- )
    {
        if ( szBuffer[i] >'9' )
            tmp = szBuffer[i] - 'A' + 10;
        else
            tmp = szBuffer[i] - '0';
    
        tmp *= nbase;
        nbase <<= 4;
        res += tmp;           
    }
    wsprintf(szBuffer, szFmtHex2Dec, res);
    SetDlgItemText(hWinMain, IDC_DEC, szBuffer);
}

// 将10进制数值转换为16进制
void Dec2Hex()
{
    char szBuffer[512];
   
    unsigned int n = GetDlgItemInt(hWinMain, IDC_DEC, NULL, FALSE);
    wsprintf(szBuffer, szFmtDec2Hex, n);
    SetDlgItemText(hWinMain, IDC_HEX, szBuffer);
}

// 主对话框过程
LRESULT CALLBACK ProcDlgMain(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    HWND hWndHex;
    switch ( uMsg )
    {
    case WM_CLOSE:
        EndDialog(hWnd, 0);
        break;
    case WM_INITDIALOG:
        {
            hWinMain = hWnd;
            SendDlgItemMessage(hWnd, IDC_HEX, EM_LIMITTEXT, 8, 0);
            SendDlgItemMessage(hWnd, IDC_DEC, EM_LIMITTEXT, 10, 0);
            hWndHex = GetDlgItem(hWnd, IDC_HEX);
            lpOldProcEdit = (WNDPROC)SetWindowLong(hWndHex, GWL_WNDPROC, (LONG)ProcEdit);
        }
        break;
    case WM_COMMAND:
        /* 由于在调用Hex2Dec的时候使用了SetDlgItemText, 而此函数会发送WM_COMMAND消息
           当收到WM_COMMAND消息的时候又进行转换计算,然后又调用WM_COMMAND, 这样,程序就
           陷入了WM_COMMAND消息的死循环, 为了避免此种情况,于是设置了一个标志dwOption,
           当dwOption为1的时候,表示正在计算和转换,转换完毕之后重新置为0,这样就能防止
           正在计算的时候又处理新的WM_COMMAND消息,避免了死循环
        */
        if ( !dwOption )
        {
            dwOption = 1;
            if ( LOWORD(wParam) == IDC_HEX )
                Hex2Dec();
            else if ( LOWORD(wParam) == IDC_DEC )
                Dec2Hex();
            dwOption = 0;
        }
        break;
    default:
        return FALSE;
    }
    return TRUE;
}

int WINAPI WinMain(IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN LPSTR lpCmdLine, IN int nShowCmd )
{
    DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, (DLGPROC)ProcDlgMain, (LPARAM)0);
    return 0;
}

上面的程序在VC6++下调试通过。编译方法是,在VC6++下,新建一个win32 application , 然后将上面3个文件加入到工程,F7编译即可。

上面的子类化只是针对一个控件,可是当我们需要多个16进制输入框的时候,该怎么办呢?如果一个一个的子类化,显然是不合适的,那么好的方法就是将该文本框这个“类”进行改写, 让它符合我们的需要,然后,所有的16进制输入框都从这个“类”“继承”而来。

下面的例子,用了5个16进制输入框,每个输入框都从我们的“类”“继承”而来,拥有相同的功能,即只能输入16进制字符和退格键,不能输入其它的字符。具体实现代码如下:

// resource.h
// 资源ID定义文件
#define IDD_MAIN                        101

// SuperClass.rc
// 资源定义文件
#include "resource.h"
#include "afxres.h"

/
//
// Dialog
//
// 可以看出下面的对话框有5个自定义控件,而这个控件的“类”就是"HexEdit"
// "HexEdit"是我们自定义的一个"类"名,它继承自“Edit”,它只能输入16进制
// 字符和退格键,其它的功能跟一般的Edit文本输入框没有两样。

IDD_MAIN DIALOG DISCARDABLE  0, 0, 126, 113
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Hex Edit Box (Super Cls)"
FONT 10, "System"
BEGIN
    CONTROL "", -1, "HexEdit",ES_LEFT | WS_BORDER | WS_TABSTOP,7,9,104,14
    CONTROL "", -1, "HexEdit",ES_LEFT | WS_BORDER | WS_TABSTOP,7,49,104,14
    CONTROL "", -1, "HexEdit",ES_LEFT | WS_BORDER | WS_TABSTOP,7,29,104,14
    CONTROL "", -1, "HexEdit",ES_LEFT | WS_BORDER | WS_TABSTOP,7,69,104,14
    CONTROL "", -1, "HexEdit",ES_LEFT | WS_BORDER | WS_TABSTOP,7,89,104,14
END

// SuperClass.c
// 实现文件
#include <windows.h>
#include "resource.h"

HINSTANCE    hInst = NULL;
HWND        hWinMain = NULL;
WNDPROC        lpOldProcEdit = NULL;

char        szAllowedChar[] = "0123456789abcdefgABCDEFG/x08";
char        szEditClass[] = "Edit";
char        szClass[] = "HexEdit";

//16进制文本框的新的窗口过程,只处理WM_CHAR消息,其它的丢给默认的处理过程
LRESULT CALLBACK ProcEdit(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    int i;
    int nLen = strlen(szAllowedChar);
    if ( uMsg == WM_CHAR )
    {
        for ( i = 0; i < nLen; i++ )
        {
            if ( szAllowedChar[i] == (char)wParam ) // wParam是字符的ASCII码
            {
                // 如果字符大于‘9’,表示是'a'-'f' 或者是'A' - 'F'
                // 无论大小写,一律转换为大写
                if ( wParam > '9' )
                    wParam &= ~0x20;
                return CallWindowProc(lpOldProcEdit, hWnd, uMsg, wParam, lParam);
            }
        }
        return TRUE;
    }
    return CallWindowProc(lpOldProcEdit, hWnd, uMsg, wParam, lParam);
}

// 超类化, 用GetClassInfoEx获取原有的类“Edit”的所有信息
// 然后用我们自定义的窗口处理过程取代原有的窗口过程
// 用我们自定义的类名“HexEdit”取代原有的类名“Edit”
// 然后用RegisterClassEx向windows注册我们的新类
void SuperClass()
{
    WNDCLASSEX stWC;
    stWC.cbSize = sizeof(stWC);
    GetClassInfoEx(NULL, szEditClass, &stWC);
    lpOldProcEdit = stWC.lpfnWndProc;
    stWC.lpfnWndProc = ProcEdit;
    stWC.hInstance = hInst;
    stWC.lpszClassName = szClass;
    RegisterClassEx(&stWC);
}

LRESULT CALLBACK ProcDlgMain(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    if ( uMsg == WM_CLOSE )
    {
        EndDialog(hWnd, 0);
        return TRUE;
    }
    return FALSE;
}

int WINAPI WinMain(IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN LPSTR lpCmdLine, IN int nShowCmd )
{
    hInst = hInstance;
    SuperClass();
    DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, (DLGPROC)ProcDlgMain, (LPARAM)0);
    return 0;
}

以上的编译过程同上面的子类化程序。

最后

以上就是感动糖豆为你收集整理的子类化和超类化(win32 SDK)的全部内容,希望文章能够帮你解决子类化和超类化(win32 SDK)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(39)

评论列表共有 0 条评论

立即
投稿
返回
顶部