当前位置:C++技术网 > 精选软件 > Windows零基础入门:2.13 修改窗口类的机制和论证

Windows零基础入门:2.13 修改窗口类的机制和论证

更新时间:2015-08-27 14:08:24浏览次数:1+次

    修改窗口类的窗口过程,能够让所有用这个窗口类来创建的窗口都改变了窗口过程吗?或者换句话说,修改窗口过程,会让修改应用于后面创建的窗口上吗?更或者说,注册的窗口类信息(窗口过程)永久修改了吗?
    如果你有这些疑问,那么就继续往下看吧。
    不管是系统窗口类,还是应用程序的窗口类(局部和全局),都是遵循一套机制。这种设计理念,可以让这些保持一致,减少复杂度。这一点,我想,有点经验的人都会想到。只是系统窗口类和应用程序窗口类注册的时间、注册的主体以及制定窗口类参数的主体和窗口过程等都不一样罢了。
    对于这个思想,一定要清楚,也就是提高复用,降低重复编码。对于两种窗口类,也都是一套机制来创建和注册的。当然,对于其他的,也不会差的太多。那么对于修改窗口类来说,也是一致的。
    修改窗口类,并不会真的在写入窗口类的地方直接修改,然后永久保留。为什么?我们先说说系统公共窗口类。这个是系统中所有进程都可以使用的。我们确实可以修改系统窗口类。但是系统不会让我们的修改,导致其他进程使用的时候,变成你修改的样子。所以,系统会保证公共的系统类不能被任何其他的方式修改。
    那你是如何修改系统窗口类,还可以定制这些窗口的样式的呢?不让你直接修改系统的窗口类,是不让你直接修改让它,因为这个会影响别人。你的修改实际上是生成了一个副本,被修改的副本,会存储到一个地方。通过SetWindowLong的第一个参数窗口句柄我们得知,这个修改,只会对你这个窗口有效。你修改了窗口类之后,再用这个窗口类去创建其让窗口,其他窗口还是与原始窗口类的样子来工作的。也就是说,你对前面一个窗口的窗口类的窗口过程的修改,并不会影响到后面创建的窗口。
    那么这就说明,其实系统让你修改窗口类,是让你有一个单独定制一个窗口的机会,系统会将你的修改的部分,单独保存起来,并与你这个窗口关联,那么与这个关联的窗口相关的消息,用你指定的新的窗口类来执行,而其他的窗口类,也就是没有修改窗口过程的窗口,它们的消息还是默认的处理方式。
    系统窗口类是这么处理的,其实应用程序窗口类也是如此,他们都是一套思想做的。所以,窗口子类化(修改窗口的处理过程)就是一个单独的行为,只会影响到指定的窗口,不会影响到其他。
    下面给两个代码例子大家去验证。第一个窗口是用原始的窗口类来创建的,但是修改了这个窗口的窗口过程。那么他就会执行新的窗口过程来处理消息。如果是系统窗口类,那么你就可以定制这个窗口的行为了。而应用程序窗口类本来你就可以定义,不过你修改后,可以用另外一个窗口类来处理。而第二个窗口则是在第一个窗口修改了窗口过程后创建的,而创建出来的窗口,由原始的窗口的窗口过程处理,也就是说,不受你修改的窗口过程处理。这就证明了,你修改窗口过程的行为只对你指定的这个窗口有效。
代码1.修改系统窗口类效果图和代码

                      

第一个窗口被修改窗口过程背景成了灰色,单击可以弹出消息

                          

第二个窗口没有受到第一个窗口的窗口过程的修改,是系统默认的样子,单击没有弹出消息

代码如下:

#include <Windows.h>
#include <tchar.h>

LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK BTNProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrev, PSTR szCmdLine, int iCmdShow)
{
    MSG  msg;
    HWND hButton = CreateWindow(_T("Button"), _T("按钮"), WS_TILEDWINDOW, 0, 0, 600, 400, NULL, NULL, NULL, NULL);
    SetWindowText(hButton, _T("原始窗口标题_C++技术网"));
    ShowWindow(hButton, SW_SHOWNORMAL);
    SetWindowLong(hButton, GWL_WNDPROC, (LONG)BTNProc);

    HWND hButton2 = CreateWindow(_T("Button"), _T("按钮2"), WS_TILEDWINDOW, 0, 0, 600, 400, NULL, NULL, NULL, NULL);
    SetWindowText(hButton2, _T("新标题_C++技术网"));
    ShowWindow(hButton2, SW_SHOWNORMAL);

    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}

LRESULT CALLBACK BTNProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    RECT rect;

    switch (message)
    {
    case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);
        GetClientRect(hwnd, &rect);
        FillRect(hdc, &rect, (HBRUSH)GetStockObject(GRAY_BRUSH));
        DrawText(hdc, _T("新窗口上的文字 - C++技术网"), -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
        EndPaint(hwnd, &ps);
        return 0;
    case WM_LBUTTONDOWN:
        GetClientRect(hwnd, &rect);
        MessageBox(NULL, _T("新窗口单击"), _T("按钮"), MB_ICONINFORMATION);
        return 0;
    case WM_RBUTTONDOWN:
        GetClientRect(hwnd, &rect);
        MessageBox(NULL, _T("新窗口右击"), _T("按钮"), MB_ICONINFORMATION);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}


代码2.修改应用程序窗口类效果图和代码

                              

自己注册的窗口类创建的窗口修改窗口过程使用了新的窗口过程的效果

                   

第二个窗口创建,依然没有受到第一个窗口修改窗口过程的影响

代码如下:

#include <Windows.h>
#include <tchar.h>

LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK BTNProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrev, PSTR szCmdLine, int iCmdShow)
{
    static TCHAR szExeName[] = _T("Win32");
    HWND hwnd;
    MSG  msg;
    WNDCLASS wndclass;

    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.lpfnWndProc = WinProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = szExeName;

    if (!RegisterClass(&wndclass))
    {
        MessageBox(NULL, _T("注册窗口类失败,此程序需要运行在Windows NT平台下。"), szExeName, MB_ICONERROR);
        return 0;
    }

    HWND hButton = CreateWindow(szExeName, _T("按钮"), WS_TILEDWINDOW, 0, 0, 600, 400, NULL, NULL, NULL, NULL);
    SetWindowText(hButton, _T("原始窗口标题_C++技术网"));
    ShowWindow(hButton, SW_SHOWNORMAL);
    SetWindowLong(hButton, GWL_WNDPROC, (LONG)BTNProc);

    HWND hButton2 = CreateWindow(szExeName, _T("按钮2"), WS_TILEDWINDOW, 0, 0, 600, 400, NULL, NULL, NULL, NULL);
    SetWindowText(hButton2, _T("窗口2标题_C++技术网"));
    ShowWindow(hButton2, SW_SHOWNORMAL);

    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}

LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    RECT rect;

    switch (message)
    {
    case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);
        GetClientRect(hwnd, &rect);
        FillRect(hdc, &rect, (HBRUSH)GetStockObject(GRAY_BRUSH));
        DrawText(hdc, _T("原始窗口上的文字 - C++技术网"), -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
        EndPaint(hwnd, &ps);
        return 0;
    case WM_LBUTTONDOWN:
        GetClientRect(hwnd, &rect);
        MessageBox(NULL, _T("原始窗口按钮左击"), _T("按钮"), MB_ICONINFORMATION);
        return 0;
    case WM_RBUTTONDOWN:
        GetClientRect(hwnd, &rect);
        MessageBox(NULL, _T("原始窗口按钮右击"), _T("按钮"), MB_ICONINFORMATION);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}
LRESULT CALLBACK BTNProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    RECT rect;

    switch (message)
    {
    case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);
        GetClientRect(hwnd, &rect);
        FillRect(hdc, &rect, (HBRUSH)GetStockObject(GRAY_BRUSH));
        DrawText(hdc, _T("新窗口上的文字 - C++技术网"), -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
        EndPaint(hwnd, &ps);
        return 0;
    case WM_LBUTTONDOWN:
        GetClientRect(hwnd, &rect);
        MessageBox(NULL, _T("新窗口单击"), _T("按钮"), MB_ICONINFORMATION);
        return 0;
    case WM_RBUTTONDOWN:
        GetClientRect(hwnd, &rect);
        MessageBox(NULL, _T("新窗口右击"), _T("按钮"), MB_ICONINFORMATION);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

    到此对于窗口类的讲解,基本就清楚了,就差最后一步,使用窗口类的代码讲解了。如果你还有任何问题,请及时提出。