1、如何利⽤CC++编程打开⼀个windows窗⼝
创建⼀个windows窗⼝,再在内存中构建⼀个buffer,做⼀些我们⾃⼰定义的rendering并且在窗⼝中展⽰buffer。
现在的游戏都是让显卡做rendering,但是要我们⾃⼰做rendering,必须先做⼀些⾃⼰的东西,然后在展⽰出来,并不是显卡⾃⼰做的。但是这个话题以后再说,现在主要问题是如何打开⼀个标准的windows 窗⼝?
windows窗⼝的结构如下:
typedef struct tagWNDCLASS {
UINT style;//是⼀些⼆进制的整数flag
WNDPROC lpfnWndProc//是指向我们将定义的函数的指针,这个函数也是定义了Windows对事件的处理;
int cbClsExtra;//若想存储与windowclass的额外字节,own-personal 字节;但我们不需要
int cbWndExtra;//也是同上,可让你创建与窗⼝相联系的额外内存,也不需要
HINSTANCE hInstance;//A handle to the instance that contains the window procedure for the class,这是⼀个句柄,指向我们⾃⼰创建的窗⼝实体
HICON hIcon;//图标
HCURSOR hCursor;//光标
HBRUSH hbrBackground;//背景,但是我们可传⼊⼀个brusher来修改
LPCSTR lpszMenuName;//菜单,就像打开txt编辑器中,⽂件、编辑菜单⼀样
LPCSTR lpszClassName;//窗⼝的名称,创建后,可以把这个名字传出去,以此来⾼效的创建我们给定的窗⼝类
} WNDCLASSA,*PWNDCLASSA;
为什么叫tagWNDCLASS ?
在windows中,你总可以调⽤kernel,并访问当前运⾏程序的hInstance,这种⽅法叫做GetModuleHandle()⼤概是windows.h头⽂件为了⽀持⽼版本的编译器,实际上是为了⽀持C和C++;
创建窗⼝代码:
#include<windows.h>
LRESULT CALLBACK MainWindowCallback(
HWND Window,
UINT Message,
WPARAM wParam,
LPARAM lParam)
{
LRESULT Result =0;
switch(Message)
{
case WM_SIZE:
case WM_SIZE:
{
OutputDebugStringA("WM_SIZE\n");
}break;
case WM_DESTROY://windows系统删除我们的window
{
OutputDebugStringA("WM_DESTROY\n");
}break;
case WM_CLOSE://⽤户关闭窗⼝
{
OutputDebugStringA("WM_CLOSE\n");
}break;
case WM_ACTIVATEAPP:
{
OutputDebugStringA("WM_ACTIVATEAPP\n");
}break;
//在窗⼝⾥⾯画画,需要gdi32.dll
case WM_PAINT:
{
PAINTSTRUCT Paint;
HDC DeviceContext =BeginPaint(Window,&Paint);
LONG X = Paint.left;
LONG Y = p;
LONG Hight = Paint.bottom - p;
LONG Width = Paint.right - Paint.left;
static DWORD Operation = WHITENESS;
PatBlt(DeviceContext, X, Y, Width, Hight, Operation);
if(Operation == WHITENESS){
Operation = BLACKNESS;
}
else{
Operation = WHITENESS;
}
EndPaint(Window,&Paint);
}break;
default:
{
//OutputDebugStringA("default");
Result =DefWindowProc(Window, Message, wParam, lParam);
}
}
return Result;
}
int CALLBACK
WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
WNDCLASS WindowClass ={};//初始化
//注意,在C语⾔中,{0}才是把所有都初始化为0,
//C++中,如果什么都不放{},就会把整个这个结构的堆栈内存,全部设置为0 WindowClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
WindowClass.lpfnWndProc = MainWindowCallback;
WindowClass.hInstance = hInstance;//或GetModuleHandle(0)
//WindowClass.icon=;暂时不设置图标
WindowClass.lpszClassName =TEXT("AllsundayWindowClass");
if(RegisterClass(&WindowClass)){
HWND WindowHandle =CreateWindowEx(
0,//DWORD dwExStyle,
WindowClass.lpszClassName,//LPCTSTR lpClassName,
TEXT("Allsunday"),//LPCTSTR lpWindowName,
TEXT("Allsunday"),//LPCTSTR lpWindowName,
WS_OVERLAPPEDWINDOW | WS_VISIBLE,//DWORD dwStyle,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
0,//HWND hWndParent,
怎样写代码 自己做编程0,//HMENU hMenu,
hInstance,
0);
if(WindowHandle){
MSG Message;
for(;;){
BOOL MessageResult =GetMessage(
&Message,
0,//如果传⼊句柄,有时可能没发现任何消息,填写0会抓取所有我们创建窗⼝的消息
0,
0);
if(MessageResult>0){
TranslateMessage(&Message);//从消息队列中取出消息,让消息更加clear
DispatchMessage(&Message);
}
else{
break;
}
}
}
else{
}
}
else{
}
return0;
}
第⼀步:定义WNDCLASS结构体
1、WindowClass.style参数:
DC=device context
引⽂地址:
设备上下⽂DC是⼀个Windows数据结构,它包含了某个设备的绘制属性。通常,绘制调⽤都是借助于上下⽂对象,⽽这些设备上下⽂对象封装了⽤于画线、形状、⽂本等的Windows API。设备上下⽂是设备⽆关的,所以它既可以⽤于绘制屏幕,也可以⽤于绘制打印机甚⾄元⽂件。设备上下⽂在内存中创建,⽽内存经常受到扰动,所以它的地址是不固定的。因此,⼀个设备上下⽂句柄不是直接指向设备上下⽂对象,⽽是指向另外⼀个跟踪设备上下⽂地址的指针。
在本次的设计中,我们会使⽤classDC和ownDC,他们在⼤多数情况下做同⼀件事情, 因为我们只需要⼀个窗⼝。但是,区别是,在正常情况下,windows系统只有这些DC,当我们需要draw some stuff时,就得到⼀个DC,然后使⽤、还回去。
classDC想要⾃⼰的DC只在任何⾃⼰创建的class类型窗⼝中作⽤。
ownDC是说⾃⼰的DC可以在任何窗⼝中作⽤。
同时,还使⽤到CS_HREDRAW、CS_VREDRAW;
他们是flag,告诉windows系统从那个⽅向去重写我们创建的窗⼝,包括⽔平和垂直重写。
2、WindowClass.lpfnWndProc参数:
/
/ You must use the CallWindowProc function to call the window procedure. For more information, see WindowProc
LRESULT CALLBACK WindowProc(
_In_ HWND hwnd,//是个句柄,告诉windows我们使⽤那个窗⼝
_In_ UINT uMsg,//windows的massage处理请求,windows要我们做处理的message会传进来。
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
WindowProc是回调函数,处理送到windows系统的message,是windows系统从它的代码中调⽤“我们”回去为它做事情,这个指针就是指向那个具体的(待我们完成的)回调函数。
知道了结构和功能后,我们可以使⽤随意使⽤它,直接把函数名、传⼊的参数名——>改成⾃⼰熟悉的。
需要⾃⼰理解的是,C/C++中的函数签名只是标⽰类型⽽已,⼀个定义了的函数、函数签名,只是取决于你要传送参数的类型,参数的名字是⾃由设定的。
3、回调函数的编写
其中LRESULT(8字节) ,是⼀个返回值的code,它表⽰我们对这个Message基本做了什么。每⼀个消息,Windows系统都赋予其特定含义,并且每个消息都会有特定返回值,所以这个返回值是消息处理之后才拿到的。
⾸先,我们把LRESULT Result 定义在消息处理之前,赋初值为0(这是CLOSE处理后的返回值),之后必须做⼀个catch all,因为,调⽤windows默认窗⼝回调的结果是包罗万象的。
如果你不想去处理所有不明的消息,可以直接叫⼀个函数来处理他们,他会以默认⽅式处理这些消息,就像这些消息⾷物链中顶层的男⼈,也就是把其他的消息传给windows,让windows执⾏默认⾏为。所以在switch的default⾥⾯,设置Result参数值,让它等于DefWindowProc();
可以看到,DefWindowProc()的函数签名(参数类型)和我们的回调函数⼀样,唯⼀不同的是,我们的是callback(windows求助我们),它是WinAPI(我们求助Windows,callin)
4、⽤WindowClass打开⼀个窗⼝
先要注册,利⽤RegisterClass(),接收⼀个指向我们窗⼝class的⼀个指针参数,只要注册了⼀个WindowClass,就可以创建它的实体。ATOM 是为了存储你指向的⼀个字符串值.
然后创建⼀个句柄去接收创建好的窗⼝,具体函数如下:
HWND CreateWindowEx(
DWORD dwExStyle,
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x, a
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
);
5、在打开窗⼝前,需要做的最后⼀个事情——开始消息循环
windows系统默认情况下是不会 传送message到你的window,除⾮你把他们从队列中取出来,这个队列的⼯作原理是,每次你创建应⽤窗⼝,系统就创建⼀个消息队列,其中存储的就是windows系统发给你消息。
于是,我们就要⽤个GetMessage()去队列上抓取他们,如果没有消息,就坐在那个队列上等,
BOOL GetMessage(
LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax
);
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论