Windows应用程序基础

关于Windows应用程序的基础,基本内容就是那几项,以前学MFC的时候看孙鑫的视频讲过一遍,学习DirectX的时候学过一遍。现在回来想做MFC的程序,发现又忘了,这种学了忘忘了学的感觉真烦恼,每次都要从头学起,每次都是新手。所以我决定一定要自己写个总结,可能还是会忘记,但是查看自己的总结感觉踏实一些。

一. WinMain函数

Windows程序的入口函数:

int WINAPI WinMain(

    HINSTANCE hInstance, // handle to current instance
    // 应用程序实例的句柄。同一程序代码也有可能有多个实例,因为应用程序实例也是一种资源,所以需要对应用程序实例进行标识。

    HINSTANCE hPrevInstance, // handle to previous instance
    // 先前实例的标识,之前没有则为空。Win32下总是为空。

    LPSTR lpCmdLine, // command line
    //LP表示长指针,STR表示字符串,所以LPSTR表示指向字符串的指针。lpCmdLine接受命令行参数。

    int nCmdShow // show state
    // 显示状态,指定程序运行的时候应该如何显示
);

 

WinMain函数由操作系统调用,因此WinMain函数的参数都是由操作系统进行赋值。

二.窗口

窗口一般需要进行以下几个步骤:

1.设计窗口

2.注册窗口

3.创建窗口

4.显示及更新窗口

窗口类是一个结构体

typedef struct WNDCLASSEX
 { 
    UINT style; 
    WNDPROC lpfnWndProc; 
    int cbClsExtra; 
    int cbWndExtra; 
    HANDLE hInstance; 
    HICON hIcon; 
    HCURSOR hCursor; 
    HBRUSH hbrBackground; 
    LPCTSTR lpszMenuName; 
    LPCTSTR lpszClassName;
 } WNDCLASS;

1.设计窗口

设计窗口类。

WNDCLASSEX wc;

//窗口类的类型
wc.style = CS_HREDRAW | CS_VREDRAW; //水平或垂直位置变化的时候要求窗口重画

//窗口过程函数,一个指针,指向一个窗口过程,用来接收一个函数指针,用来指定窗口对应的过程函数/回调函数
wc.lpfnWndProc = (WNDPROC) WndProc; //函数名可以代表代码的首地址

//类的附加内存
wc.cbClsExtra = 0; //通常情况下设置为0

//窗口的附加内存空间
wc.cbWndExtra = 0;

wc.cbSize = sizeof(WNDCLASSEX);

//应用程序实例号,来自WinMain函数参数
wc.hInstance = hInstance;

//图标句柄
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
//标准图标被加载的时候第一个参数必须为NULL

//如果要自定义的图标的话
//wc.hIcon = LoadIcon(hInstance, //(LPCTSTR)IDI_DIRECTX_ICON);

//光标句柄
wc.hCursor = LoadCursor(NULL, IDC_ARROW);

//画刷的句柄
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);

//菜单的名字
wc.lpszMenuName = 0;

//窗口类的名字
wc.lpszClassName = "Class Name";

2.注册窗口

窗口设计完之后,需要向操作系统进行注册,之后才可以创建基于这种窗口类型的窗口。

//函数原型:
//ATOM RegisterClass (CONST WNDCLASS* lpWndClass) ;

//向操作系统注册窗口
RegisterClassEx(&wc) ) //传入窗口类结构体的地址
//函数的返回值为布尔值,注册成功则返回真

3.创建窗口

注册完成之后,就可以创建窗口类实例了。首先需要定义一个句柄,作为一个标识,保存下来。

HWND CreateWindow(

    LPCTSTR lpszClassName,    //窗口类名

    LPCTSTR lpszTitle,    //窗口标题名

    DWORD dwStyle,    //创建窗口的样式

    int x,y,    //窗口左上角坐标

    int nWidth,nHeight,    //窗口宽度和高度

    HWND hwndParent,//该窗口的父窗口句柄

    HWENU hMenu,    //窗口主菜单句柄

    HINSTANCE hInstance,    //创建窗口的应用程序当前句柄

    LPVOID lpParam    //指向一个传递给窗口的参数值的指针
);

//创建窗口

HWND hwnd = 0; //句柄,用以保存新创建的窗口的标识

hwnd = CreateWindow(
    " Class Name ", //注册的类名,设计窗口的时候指定的名字
    "窗口标题", 
    WS_OVERLAPPEDWINDOW,//层叠的窗口,具有标题栏和边框
    0, 0, width, height,
    0 /*parent hwnd*/, 
    0 /* menu */, 
    hInstance, 
    0 /*extra*/); 

//第一个参数是注册的类名,一定要用注册之后的窗口类名

//第二个参数是窗口的名字,即窗口标题名

//第三个参数是窗口的类型

//之后的四个参数表示窗口的左上角水平坐标、垂直坐标、宽度、高度

//之后是一个窗口的句柄HWND,父窗口句柄,没有父窗口可设置为NULL

//之后是菜单句柄

//之后是当前应用程序实例的句柄,WinMain形参之一

//之后是一个数据指针,多文档时用,主要作为WM_CREATE消息的附加参数

4.显示及更新窗口

//显示窗口
ShowWindow(hwnd, SW_SHOW);//窗口句柄及显示状态

//更新窗口,刷新一次窗口,可有可无
UpdateWindow(hwnd);

三.消息及消息循环

1.消息

操作系统将每个事件(输入设备上的变化)都包装成一个称为消息的结构体MSG来传递给应用程序,然后由应用程序来决定对此事件做出何种响应,应用程序通过调用函数的形式来通知操作系统执行相应的功能。应用程序对这些函数的调用就叫做系统调用,这些函数的集合就是Windows操作系统提供给应用程序编程的接口(Application Programming Interface),简称Windows API。

消息结构体:

typedef struct tagMSG
{ 
    HWND hwnd;     //接受消息的窗口的句柄;
            //句柄是资源的标识,窗口句柄的类型是HWND
    UINT message;     //消息标识符,表示具体的消息信息;
    WPARAM wParam; //32位的附加消息参数。根据消息的不同而不同。
    LPARAM lParam;     //32位的附加消息参数,其值与消息有关;
    DWORD time;     //双16位,即32位的整数,消息放入消息队列的时间
    POINT pt;     //消息放入消息队列时鼠标的坐标

} MSG, *PMSG;

UINT是一个无符号整数,因为数值一般不好记忆,所以微软定义了一些宏来帮助记忆,宏以WM作为开头(Window Message),如WM_LBUTTONDOWN,WM_CHAR等。

当按下键盘之后,无论按下哪个键,收到的都是WM_CHAR消息,并不知道按下的是哪个字母,可以通过wParam获取到相对应的字母的ASCII码。

2.消息循环

消息队列是一个先进先出的缓冲区,操作系统为每一个应用程序都会建立一个消息队列,应用程序从消息队列中取出消息,进行相应的相应。

消息循环的常见写法如下:

MSG msg;

while(GetMessage(&msg,NULL,0,0))

{
    TranslateMessage (&msg);

    DispatchMessage (&msg);
}

GetMessage从消息队列中获取消息。检索到WM_QUIT消息时返回零值。

GetMessage(

    lpMSG,//指向MSGMSG结构的指针

    hwnd, //窗口句柄

    nMsgFilteMin, //用于消息过滤的最小消息号值

    nMsgFilterMax//用于消息过滤的最大消息号值

);

TranslateMessage转换消息。比如将键盘的WM_KEYDOWN和WM_KEYUP消息转换成WM_CHAR消息,放在消息队列当中。

DispatchMessage将收到的消息传到窗口的回调函数(窗口过程函数)中。

3.窗口过程函数(回调函数)

窗口过程函数用来处理和响应消息。

LRESULT CALLBACK WindowProc(
    HWND hwnd,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam
);

函数名可以更改,但是参数的类型不能变,参数名可以随便取。

接收一个消息,DispatchMessage调用的时候,操作系统调用这个窗口过程函数,并且将相关的参数传递给这个函数。直到窗口过程函数将控制返回给Windows操作系统,DispatchMessage才能返回。

函数内部一般用Switch case语句判断具体是什么消息,然后采取相应的措施。

一个回调函数的例子如下:

//
// WndProc
//
//窗口过程函数,回调函数
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 //窗口句柄、消息标识、消息的附加参数
{
    //LRESULT是个Long型,返回的结果码

    switch( msg )
    {

        case WM_DESTROY: 
    //在消息处理程序段中一般都有对//WM_DESTROY的处理,该消息是关闭窗口时发出的
            PostQuitMessage(0);
            break;

        case WM_KEYDOWN:
            if( wParam == VK_ESCAPE )
            DestroyWindow(hwnd);
            break;
        default:
        //提供缺省处理,让系统对不感兴趣的消息进行一些缺省处理 
            return DefWindowProc(hwnd, msg, wParam, lParam);

    //按键: WM_CHAR 
    //鼠标左键: WM_LBUTTONDOWN
    //窗口重绘: WM_PAINT
    //关闭: WM_CLOSE
    //DestroyWindow函数销毁窗口,并发送以下消息
    //WM_DESTROY 然后PostQuitMessage(0) 退出程序,发送WM_QUIT消息,消息循环返回值,结束消息循环,退出WinMain函数
    }
  return 0; 
}

你可能感兴趣的:(windows)