win32编程(001)——初识窗口程序的创建
这两天出去浪了{:10_297:} ,就没更新,本来想了半天开头怎么写,算了,直接进入正题吧窗口程序的创建步骤:
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的大小
HINSTANCEhInstance; //当前模块的实例句柄
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 = { 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]