鱼C论坛

 找回密码
 立即注册
查看: 4139|回复: 0

[学习笔记] win32编程(001)——初识窗口程序的创建

[复制链接]
发表于 2017-6-14 18:44:56 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
这两天出去浪了 ,就没更新,本来想了半天开头怎么写,算了,直接进入正题吧

窗口程序的创建步骤:
1 定义WinMain入口函数
2 定义并赋值窗口类的数据
3 注册窗口类  RegisterClass
4 创建窗口  CreateWindow
5 显示窗口
    ShowWindow/UpdateWindow
6 消息循环
    GetMessage
    TranslateMessage
    DisptachMessage
7 定义窗口处理函数 WindowProc


创建窗口的基本步骤就是上面7条,这七条基本要讲好几期,下面我会先发一个窗口创建的完整源代码,并附上相关注释,之后再一条条详细解释
#include "stdafx.h"

//自定义(窗口处理函数)处理消息
LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
        switch (msgID)
        {
        case WM_DESTROY:
                PostQuitMessage(0);
                break;
        default:
                return DefWindowProc(hWnd, msgID, wParam, lParam);
        }
        return 0;
}

//WinMain入口函数
int WINAPI WinMain(HINSTANCE hInstance, //当前程序实例句柄
                                HINSTANCE hPrevInstance, //当前程序前一个实例句柄
                                PSTR szCmdLince, ,//命令行参数字符串
                                int iCmdShow)//窗口的显示方式
{
        //注册窗口类
        WNDCLASS wc = { 0 };//定义并初始化窗口类的结构体数据
        wc.cbClsExtra = 0;//窗口类附加数据buff的大小
        wc.cbWndExtra = 0;//窗口附加数据buff的大小
        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);//绘制窗口背景的画刷句柄
        wc.hCursor = NULL;//鼠标的句柄
        wc.hIcon = NULL;//窗口图标句柄
        wc.hInstance = hInstance;//当前模块的实例句柄
        wc.lpfnWndProc = WndProc;//窗口处理函数的名称
        wc.lpszClassName = _T("fishc");//窗口类的名称
        wc.lpszMenuName = NULL;//窗口菜单的资源ID字符串
        wc.style = CS_HREDRAW | CS_VREDRAW;//窗口类的风格
        RegisterClass(&wc);//将以上所有赋值全部写入操作系统
        HWND hWnd = CreateWindow(_T("fishc"), _T("fishc"),WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hInstance,NULL);

        //显示窗口
        ShowWindow(hWnd,SW_SHOW);
        UpdateWindow(hWnd);//刷新窗口

        //消息循环
        MSG nMsg= { 0 };
        while (GetMessage(&nMsg, NULL, 0, 0))
        {
                TranslateMessage(&nMsg);
                DispatchMessage(&nMsg);
        }
        return 0;
}

我们看到上面有很多我们不认识的英文,实际上都是给基本数据类型起的别名,下面附上常见的一些
大部分包含在basetsd.h,minwindef.h这两个头文件中

typedef unsigned long ULONG;
typedef unsigned short USHORT;
typedef unsigned char UCHAR;

#define CALLBACK    __stdcall
#define WINAPI      __stdcall
#define WINAPIV     __cdecl
#define APIENTRY    WINAPI
#define APIPRIVATE  __stdcall
#define PASCAL      __stdcall

typedef unsigned long       DWORD;
typedef int                 BOOL;
typedef unsigned char       BYTE;
typedef unsigned short      WORD;
typedef float               FLOAT;
typedef int                 INT;
typedef unsigned int        UINT;

typedef UINT_PTR            WPARAM;
typedef LONG_PTR            LPARAM;
typedef LONG_PTR            LRESULT;

1.窗口的注册

1.1窗口类
窗口类包含了窗口的各种参数信息的数据结构。每个窗口都具有窗口类,基于窗口类创建窗口。每个窗口类都具有一个名称,使用前必须注册到系统。

1.2窗口类的分类
1.2.1-系统窗口类
系统已经定义好的窗口类,不需要注册,直接使用窗口类即可,所有应用程序都可以直接使用。
例如按钮   - BUTTON窗口和编辑框 - EDIT窗口
#include "stdafx.h"

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
        //不需要注册类
        HWND hButton = CreateWindow( "EDIT", "OK", 
                                        WS_OVERLAPPEDWINDOW,
                                        100, 100, 500, 500, NULL, NULL, 
                                        hInstance, NULL );
        ShowWindow( hButton, SW_SHOW );
        UpdateWindow( hButton );
        MSG nMsg = { 0 };
        while( GetMessage( &nMsg, NULL, 0, 0 ) )
        {
                TranslateMessage( &nMsg );
                DispatchMessage( &nMsg );//将消息交给窗口处理函数
        }
        return 0;
}
没有消息处理函数的窗口关闭后,进程并不会结束,需要自行到任务管理器中结束

1.2.2-应用程序全局窗口类
由用户自己定义,当前应用程序所有模块都可以使用。
1.2.3-应用程序局部窗口类
由用户自己定义,当前应用程序中本模块可以使用

既然说到了win32,还有以后可能会说的mfc,就不能不提最好的老师,msdn帮助手册,关于msdn手册哪里找,怎么下,我就不在赘述,但是我会提供官方的在线版,具体msdn有什么用,就先从一个实例讲起
#include<windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLince, int iCmdShow)
{
       MessageBox(NULL,TEXT("这是我在鱼C学习的第一个程序"),TEXT("打招呼"),MB_OK);
       return 0;
}
这是小甲鱼课程中的代码,其中最关键的就是messagebox函数,这个函数有几个参数,参数具体是什么,有什么返回值,msdn中说的是非常详细了,在线地址

介绍完msdn,那么继续说窗口创建
一般应用程序窗口类的注册,常用函数是RegisterClass/RegisterClassEx,分别对应WNDCLASS/WNDCLASSEX两种结构体,EX只比普通多了两个参数,其他参数相同,所以以EX介绍为主RegisterClassEx函数
ATOM WINAPI RegisterClassEx(
  _In_ const WNDCLASSEX *lpwcx//窗口类的数据
);注册成功后,返回一个数字标识typedef WORD                ATOM

WNDCLASSEX函数
typedef struct _WNDCLASSEX { 
    UINT       cbSize; //结构体的大小
    UINT       style;  //窗口类的风格
    WNDPROC    lpfnWndProc; //窗口处理函数
    int        cbClsExtra; //窗口类附加数据buff的大小
    int        cbWndExtra; //窗口附加数据buff的大小
    HINSTANCE  hInstance; //当前模块的实例句柄
    HICON      hIcon; //窗口图标句柄
    HCURSOR    hCursor; //鼠标的句柄
    HBRUSH     hbrBackground; //绘制窗口背景的画刷句柄
    LPCTSTR    lpszMenuName; //窗口菜单的资源ID字符串
    LPCTSTR    lpszClassName; //窗口类的名称
    HICON      hIconSm; //窗口的小图标句柄 
} WNDCLASSEX, *PWNDCLASSEX;

应用程序全局窗口类的注册,需要在窗口类的风格中增加 CS_GLOBALCLASS,例如:
WNDCLASSEX wce = {0};
wce.style = CS_GLOBALCLASS;

应用程序局部窗口类
在注册窗口类时,不添加CS_GLOBALCLASS风格创建,创建的就是局部窗口类。

1.3窗口类的风格
CS_GLOBALCLASS - 应用程序全局窗口类
CS_BYTEALIGNCLIENT - 窗口客户区的水平位置8倍数对齐
CS_BYTEALIGNWINDOW - 窗口的水平位置8倍数对齐
CS_HREDRAW - 当窗口水平变化时,窗口重新绘制
CS_VREDRAW - 当窗口垂直变化时,窗口重新绘制 
CS_DBLCLKS - 允许窗口接收鼠标左键双击
CS_NOCLOSE - 窗口没有关闭按钮
#include "stdafx.h"
HINSTANCE g_hInstance = 0;//全局句柄接收当前程序实例句柄
void AppReg( )
{
        WNDCLASSEX wce = { 0 };
        wce.cbSize = sizeof(wce);
        wce.cbClsExtra = 0;
        wce.cbWndExtra = 0;
        wce.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
        wce.hCursor = NULL;
        wce.hIcon = NULL;
        wce.hIconSm = NULL;
        wce.hInstance = g_hInstance;
        wce.lpfnWndProc = DefWindowProc;
        wce.lpszClassName = "Main";
        wce.lpszMenuName = NULL;
        wce.style = CS_HREDRAW | CS_VREDRAW;
        RegisterClassEx( &wce );//将以上所有赋值全部写入操作系统
        HWND hWnd = CreateWindow( "Main", "window",
                                WS_OVERLAPPEDWINDOW,
                                100, 100, 500, 500, NULL, NULL, g_hInstance,
                                NULL );
        ShowWindow( hWnd, SW_SHOW );
        UpdateWindow( hWnd );
        MSG nMsg = { 0 };
        while( GetMessage( &nMsg, NULL, 0, 0 ) )
        {
                TranslateMessage( &nMsg );
                DispatchMessage( &nMsg );
        }
}
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
        g_hInstance = hInstance;//接收当前程序实例句柄
        AppReg( );
        return 0;
}

2.窗口的创建
2.1窗口类的查找过程
2.1.1系统根据传入的窗口类名称,在应用程序局部窗口类中查找,如果找到执行2,如果未找到执行3。
2.1.2比较局部窗口类与创建窗口时传入的HINSTANCE变量。如果发现相等,创建和注册的窗口类在同一模块,创建窗口返回。如果不相等,继续执行3。
2.1.3在应用程序全局窗口类,如果找到,执行4,如果未找到执行5。
2.1.4使用找到的窗口类的信息,创建窗口返回。
2.1.5在系统窗口类中查找,如果找到创建窗口返回,否则创建窗口失败。

当窗口注册完毕并将数据写入系统后,就可以开始窗口的创建了,窗口注册函数CreateWindow/CreateWindowEx
CreateWindowEx函数
HWND CreateWindowEx(
        DWORD dwExStyle, //窗口的扩展风格
        LPCTSTR lpClassName,  //已经注册的窗口类名称
        LPCTSTR lpWindowName, //窗口标题栏的名字
        DWORD dwStyle, //窗口的基本风格,Window Styles
        int x, //窗口左上角水平坐标位置
        int y, //窗口左上角垂直坐标位置
        int nWidth, //窗口的宽度
        int nHeight,//窗口的高度
        HWND hWndParent,//窗口的父窗口句柄
        HMENU hMenu,//窗口菜单句柄
        HINSTANCE hInstance, //应用程序实例句柄
        LPVOID lpParam //窗口创建时附加参数   
); 创建成功返回窗口句柄

2.2创建子窗口
如果你上面每句话都细心琢磨的话,会发现好多参数都有前或者父这种说法,所以在一个窗口下还能创建一个子窗口,要点主要有两个
2.2.1创建时要设置父窗口句柄
2.2.2创建风格要增加 WS_CHILD|WS_VISIBLE
#include "stdafx.h"
#include "stdio.h"
HINSTANCE g_hInstance = 0;//接收当前程序实例句柄
//自定义(窗口处理函数) 处理消息
LRESULT CALLBACK WndProc( HWND hWnd, UINT msgID,
                                                WPARAM wParam, LPARAM lParam )
{
        switch( msgID )
        {
        case WM_DESTROY:
                PostQuitMessage( 0 );//使GetMessage函数返回0???
                break;
        }
        return DefWindowProc( hWnd, msgID, wParam, lParam );
}
//注册窗口类
void Register( LPCTSTR lpClassName, WNDPROC wndproc )
{
        WNDCLASSEX wce = { 0 };
        wce.cbSize = sizeof( wce );
        wce.cbClsExtra = 0;
        wce.cbWndExtra = 0;
        wce.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
        wce.hCursor = NULL;
        wce.hIcon = NULL;
        wce.hIconSm = NULL;
        wce.hInstance = g_hInstance;
        wce.lpfnWndProc = wndproc;/***************/
        wce.lpszClassName = lpClassName;
        wce.lpszMenuName = NULL;
        wce.style = CS_HREDRAW | CS_VREDRAW;
        RegisterClassEx( &wce );
}
//创建主窗口
HWND CreateMain( LPCTSTR lpClassName, LPCTSTR lpWndName )
{
        HWND hWnd = CreateWindowEx( 0, lpClassName, lpWndName,
                                        WS_OVERLAPPEDWINDOW, 100, 100, 700, 500,
                                        NULL, NULL, g_hInstance, NULL );
        return hWnd;
}
//创建子窗口
HWND CreateChild( LPCTSTR lpClassName, LPCTSTR lpWndName, 
                                        HWND hParent )
{
        HWND hChild = CreateWindowEx( 0, lpClassName, lpWndName,
                                WS_CHILD|WS_VISIBLE|WS_OVERLAPPEDWINDOW,
                                100, 100, 200, 200, hParent, NULL, 
                                g_hInstance, NULL );
        return hChild;
}
//显示窗口
void Display( HWND hWnd )
{
        ShowWindow( hWnd, SW_SHOW );
        UpdateWindow( hWnd );
}
//消息循环
void Message( )
{
        MSG nMsg = { 0 };
        while( GetMessage(&nMsg, NULL, 0, 0) )
        {
                TranslateMessage( &nMsg );
                DispatchMessage( &nMsg );//将消息交给窗口处理函数。
        }
}

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
         g_hInstance = hInstance;
        Register( "Main", WndProc );
        HWND hWnd = CreateMain( "Main", "window" );
        Register( "Child", DefWindowProc );
        HWND hChild1 = CreateChild( "Child", "c1", hWnd );
        HWND hChild2 = CreateChild( "Child", "c2", hWnd );
        Display( hWnd );
        MoveWindow( hChild1, 100, 100, 200, 200, TRUE );//移动窗口位置和大小,(窗口句柄,水平坐标,垂直坐标,宽度,高度,是否擦除原来位置上的窗口图像)
        MoveWindow( hChild2, 400, 100, 200, 200, TRUE );//MoveWindow函数
        Message( );
        return 0;
}

2.3窗口类和窗口的附加数据
注册窗口时,可以设置这两个数据内存空间的大小。
int cbClsExtra; //窗口类附加数据buff的大小
int cbWndExtra; //窗口附加数据buff的大小
可以提供窗口类和窗口存放自己的数据的空间。

2.3.1窗口类附加数据的使用
2.3.1.1定义数据空间的大小
int cbClsExtra - 一般定义为4字节倍数
2.3.1.2存入数据(SetClassLong
DWORD SetClassLong(
        HWND hWnd,//窗口句柄
        int nIndex,//字节索引号(从哪个字节开始存)
        LONG dwNewLong //存入的数据
        );返回旧数据
2.3.1.3读取数据(GetClassLong
DWORD GetClassLong(
        HWND hWnd,  //窗口句柄
        nt nIndex  //字节索引号(从哪个字节开始读)
        ); 返回获取值

2.3.2窗口附加数据的使用
2.3.2.1定义数据空间的大小
int cbWndExtra;
2.3.2.2存入数据(SetWindowLong
LONG SetWindowLong(
        HWND hWnd,       // 窗口句柄
        int nIndex,      // 字节索引号(从哪个字节开始存)
        LONG dwNewLong   // 存入的数据
        );
2.3.2.3读取数据(GetWindowLong
LONG GetWindowLong(
        HWND hWnd,  // 窗口句柄
        int nIndex  // 字节索引号(从哪个开始读)
        );//返回值获取读到的数据
#include "stdafx.h"
#include "stdio.h"
HINSTANCE g_hInstance = 0;//接收当前程序实例句柄
//自定义(窗口处理函数) 处理消息
LRESULT CALLBACK WndProc( HWND hWnd, UINT msgID,
                                                WPARAM wParam, LPARAM lParam )
{
        switch( msgID )
        {
        case WM_DESTROY:
                PostQuitMessage( 0 );//使GetMessage函数返回0???
                break;
        }
        return DefWindowProc( hWnd, msgID, wParam, lParam );
}
//注册窗口类
void Register( LPCTSTR lpClassName, WNDPROC wndproc )
{
        WNDCLASSEX wce = { 0 };
        wce.cbSize = sizeof( wce );
        wce.cbClsExtra = 200;
        wce.cbWndExtra = 200;
        wce.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
        wce.hCursor = NULL;
        wce.hIcon = NULL;
        wce.hIconSm = NULL;
        wce.hInstance = g_hInstance;
        wce.lpfnWndProc = wndproc;/***************/
        wce.lpszClassName = lpClassName;
        wce.lpszMenuName = NULL;
        wce.style = CS_HREDRAW | CS_VREDRAW;
        RegisterClassEx( &wce );
}
//创建主窗口
HWND CreateMain( LPCTSTR lpClassName, LPCTSTR lpWndName )
{
        HWND hWnd = CreateWindowEx( 0, lpClassName, lpWndName,
                                        WS_OVERLAPPEDWINDOW, 100, 100, 700, 500,
                                        NULL, NULL, g_hInstance, NULL );
        return hWnd;
}
//创建子窗口
HWND CreateChild( LPCTSTR lpClassName, LPCTSTR lpWndName, 
                                        HWND hParent )
{
        HWND hChild = CreateWindowEx( 0, lpClassName, lpWndName,
                                WS_CHILD|WS_VISIBLE|WS_OVERLAPPEDWINDOW,
                                100, 100, 200, 200, hParent, NULL, 
                                g_hInstance, NULL );
        return hChild;
}
//显示窗口
void Display( HWND hWnd )
{
        ShowWindow( hWnd, SW_SHOW );
        UpdateWindow( hWnd );
}
//消息循环
void Message( )
{
        MSG nMsg = { 0 };
        while( GetMessage(&nMsg, NULL, 0, 0) )
        {
                TranslateMessage( &nMsg );
                DispatchMessage( &nMsg );//将消息交给窗口处理函数。
        }
}
//存入数据

void SetExtra( HWND hWnd )
{
        SetClassLong( hWnd, 0, 100);
        SetWindowLong( hWnd, 0, 100 );
}
//读取数据
void GetExtra( HWND hWnd )
{
        DWORD nClass = GetClassLong( hWnd, 0 );
        DWORD nWnd = GetWindowLong( hWnd, 0 );
        char szText[256] = { 0 };
        sprintf( szText, "窗口类附加数据缓冲区:%d,窗口附加数据缓冲区:%d", nClass, nWnd );
        MessageBox( hWnd, szText, "Infor", MB_OK );
}

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
         g_hInstance = hInstance;
        Register( "Main", WndProc );
        HWND hWnd = CreateMain( "Main", "window" );
        Register( "Child", DefWindowProc );
        HWND hChild1 = CreateChild( "Child", "c1", hWnd );
        HWND hChild2 = CreateChild( "Child", "c2", hWnd );
        Display( hWnd );
        MoveWindow( hChild1, 100, 100, 200, 200, TRUE );
        MoveWindow( hChild2, 400, 100, 200, 200, TRUE );
        SetExtra( hChild1 );
        GetExtra( hChild2 );
        Message( );
        return 0;
}

2.4使用两种附加数据的不同
2.4.1窗口类附加数据缓冲区:是基于同一个窗口类创建出来的所有窗口共享的缓冲区。
2.4.2窗口附加数据缓冲区:是窗口自己私有的缓冲区,即便是基于同一个窗口类创建出来的窗口相互之间也不共享。

下期预告:windows消息机制

评分

参与人数 1鱼币 +5 收起 理由
小甲鱼 + 5 支持楼主!

查看全部评分

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-21 19:44

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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