一、windows程序部分概念的解释
①句柄(HANDLE),资源的标识
操作系统要管理和操作这些资源,都是通过句柄来找到对应的资源。按资源的类型,又可将句柄细分成图标句柄(HICON)
、光标句柄(HCURSOR)
、窗口句柄(HWND)
、应用程序实例句柄(HINSTANCE)
等。操作系统给每一个窗口置顶的一个唯一的标识号即窗口句柄。
② 关于消息及消息队列
操作系统将每个消息事件都包装成一个成为消息的结构体(MSG)
通过消息机制Message
来传递给应用程序。
结构体MSG定义如下:
typedef struct tagMSG{
HWND hwnd; //指向窗口的句柄,指定哪个窗口接收这个消息
UINT message; //一个无符号整形类型的消息类型,比如按键,点击
WPARAM wParam; //消息的附加信息,比如按下的键是某个字母以ASCII表示
LPARAM lParam; //消息的附加信息,其他信息
DWORD time; //DWORD 双16及32位整形,指示消息投递的时间
POINT pt; //一个点的结构体POINT,指示当消息被投递的时候光标的位置
}MSG,*PMSG;
③ WinMain函数
WinMain函数是windows程序的入口函数其定义如下:
int WINAPI WinMain(
HINSTANCE hInstance, //应用程序的实例句柄,及本程序运行的句柄由操作系统传入
HINSTANCE hPrevInstance,//与其相关的兄弟实例,加入已经存在一个相同的程序,本程序为第二个,那么该参数则为先前程序的实例句柄
LPWSTR lpCmdLine, //命令行参数,类型为字符串指针类型
int nShowCmd //窗口显示的状态参数
);
④ 过程函数(回调函数)
当应用程序收到给某一窗口的消息时,就应该调用某一函数来处理这条消息。这一调用过程不用应用程序自己来实施,而由操作系统来完成。对于一条消息,操作系统调用的就是接收消息的窗口所属的类型中的lpfnWndProc
成员指定的函数。每一种不同类型的窗口都有自己专用的回调函数。
二、窗口的创建
创建一个完整的窗口需要经过下面四个操作步骤:
①设计一个窗口类
窗口类WNDCLASS定义如下
typedef struct _WNDCLASS {
UINT style; //窗口类的特征类型,可以用或运算赋予多个属性值,其变量对应的位为1 例如CS_HREDRAW | CS_VREDRAW当改变窗口宽度和高度时重画窗口
WNDPROC lpfnWndProc; //指定该窗口的一个回调函数
int cbClsExtra; //窗口类的额外空间数据,通常为0
int cbWndExtra; //为窗口附加内存空间,通常为0单位同上都为字节
HANDLE hInstance; //当前应用程序实例句柄,可为WinMain传入的实例句柄
HICON hIcon; //图标句柄,使用HICON LoadIcon(HINSTANCE hInstance, LPCTSTR lpIconName); 来加载详细可查MSDN
HCURSOR hCursor; //光标句柄,用法与HICON非常相类似可MSDN查找LoadCursor()的用法
HBRUSH hbrBackground; //背景画刷句柄可使用GetStockObject(int fnObject)来返回一个画刷需强制转换一下
LPCTSTR lpszMenuName; //指定菜单的名字没有则为NULL
LPCTSTR lpszClassName;//类的名字,也就是本注册窗口的一个名字
} WNDCLASS;
②注册窗口类
创建了一个窗口类后要为这个窗口类进行注册使用如下定义:
ATOM RegisterClass(
const WNDCLASS* lpWndClass //窗口类的地址
);
创建成功则返回一个唯一的标识id,0则表示创建失败。
③创建窗口
前期工作,创建窗口类,注册窗口类,接下来就是创建窗口了,创建窗口的api定义如下:
HWND CreateWindow(
LPCTSTR lpClassName, //窗口类的名字,要与定义的窗口类的名字保持一致,否则将无法创建窗口
LPCTSTR lpWindowName, //窗口标题的名字
DWORD dwStyle, //窗口的类型,与窗口类的类型不同
int x, //窗口的水平x坐标
int y, //窗口的垂直y坐标
int nWidth, //窗口的宽度
int nHeight, //窗口的高度
HWND hWndParent, //该窗口的父窗口实例句柄,没有则为NULL
HMENU hMenu, //菜单的实例句柄,没有则为NULL
HANDLE hInstance, //本应用程序的实例句柄
PVOID lpParam //指向传递给窗口的附加消息数据指针
);
④显示及更新窗口
创建完毕后使用ShowWindow()将窗口展示出来
BOOL ShowWindow(
HWND hWnd, //要显示的窗口
int nCmdShow //显示窗口的类型
);
BOOL UpdateWindow(
HWND hWnd //刷新窗口显示
);
三、消息循环
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
GetMessage定义如下:
BOOL GetMessage(
LPMSG lpMsg, //MSG结构体的指针
HWND hWnd, //要获取那个窗口的消息,如果为NULL则获取任何窗口的消息
UINT wMsgFilterMin, //获取最小消息值同下设置为0则获取所有消息
UINT wMsgFilterMax //获取最大消息值
);
转换,翻译消息
BOOL TranslateMessage(//将WM_KEYDOWN等类型消息转换为WM_CHAR等类型消息
const MSG* lpMsg
);
传递消息给回调函数
LONG DispatchMessage(//将消息传递给窗口的回调函数进行处理
const MSG* lpmsg
);
四、 窗口回调函数介绍
LRESULT CALLBACK WindowProc(//函数名字任意
HWND hwnd, //窗口句柄
UINT uMsg, //消息类型
WPARAM wParam,//第一个消息参数
LPARAM lParam //第二个消息参数
);
处理消息
switch(uMsg)
{
case WM_PAINT:break; //当窗口重绘时,简单说下有两组绘画句柄,BeginPaint()/EndPaint() 和 GetDC()/ReleaseDC() 两个不能相互混用
case WM_CHAR:break; //此时wParam则为按键的ascii值
case WM_LBUTTONDOWN:break; //鼠标左键按下
case WM_CLOSE:break; //关闭请求可用DestroyWindow销毁窗口
case WM_DESTROY:break; //当窗口销毁时(进程不会销毁),此时用PostQuitMessage(0);来处理这样就可以关闭整个程序了。
}
五、 简单的一个窗口程序
#include <windows.h>
#include <stdio.h>
LRESULT CALLBACK WinSunProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch(uMsg)
{
case WM_CHAR:
{
char szChar[20];
sprintf(szChar,"char is %d",wParam);
MessageBox(hwnd,szChar,"demo",0);
break;
}
case WM_LBUTTONDOWN:
{
MessageBox(hwnd,"鼠标左键点击","demo",0);
HDC hdc = GetDC(hwnd);
TextOut(hdc,0,50,"计算机编程语言练习",strlen("计算机编程语言练习"));
ReleaseDC(hwnd,hdc);
break;
}
case WM_PAINT:
{
HDC hdc;
PAINTSTRUCT paint;
hdc = BeginPaint(hwnd,&paint);
TextOut(hdc,0,0,"项目练习",strlen("项目练习"));
EndPaint(hwnd,&paint);
break;
}
case WM_CLOSE:
{
if(IDYES == MessageBox(hwnd,"是否确定退出","demo",MB_YESNO))
{
DestroyWindow(hwnd);
}
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
default:return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
return 0;
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )
{
::WNDCLASS wndcls;
wndcls.cbClsExtra = 0;
wndcls.cbWndExtra = 0;
wndcls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wndcls.hIcon = LoadIcon(NULL,IDI_ERROR);
wndcls.hCursor = LoadCursor(NULL,IDC_ARROW);
wndcls.hInstance = hInstance;
wndcls.lpfnWndProc = WinSunProc;
wndcls.lpszClassName = "Demo";
wndcls.lpszMenuName = NULL;
wndcls.style = CS_HREDRAW | CS_VREDRAW;
::RegisterClass(&wndcls);
HWND hwnd;
hwnd = CreateWindow("Demo","简单的窗口练习",WS_OVERLAPPEDWINDOW,0,0,600,400,NULL,NULL,hInstance,NULL);
::ShowWindow(hwnd,SW_SHOW);
::UpdateWindow(hwnd);
MSG msg;
while(::GetMessage(&msg,NULL,0,0))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
return 0;
}
内事不懂问百度,外事不懂问谷歌~