码迷,mamicode.com
首页 > Windows程序 > 详细

Windows程序运行原理

时间:2016-04-22 20:21:14      阅读:423      评论:0      收藏:0      [点我收藏+]

标签:

Windows程序运行原理

1.应用程序,操作系统,硬件之间的关系
技术分享
这里涉及到消息及消息队列, 操作系统是通过消息机制(Message)来将感知到的事件传递给应用程序的。
操作系统将每个事件都包装成一个称为消息的结构体MSG来传递给应用程序。
操作系统对事件做出反应的过程就叫做消息响应

typedef struct tagMSG {     // msg   
   HWND hwnd; 
   UINT message; 
   WPARAM wParam; 
   LPARAM lParam; 
   DWORD time; 
   POINT pt; 
} MSG;

2.Windows API
Windows操作系统提供给应用程序编程的接口(Application Programming Interface),简称Windows API

3.窗口句柄
说白了,窗口句柄就是资源的一个标识,也可以看成是一个指针,操作系统要管理和操作这些资源,都是通过句柄来找到对应的资源。按资源的类型,又可将句柄细分成图标句柄(HICON),光标句柄(HCURSOR),窗口句柄(HWND),应用程序实例句柄(HINSTANCE)等等各种类型的句柄。
操作系统给每一个窗口指定的一个唯一的标识号即窗口句柄,在程序中窗口句柄HWND是经常使用的

4.WinMain函数
操作系统调用WinMain函数来启动我们的应用程序,所以了解这个函数是很有必要的。
我们在MSDN中查看这个函数的定义:

int WINAPI WinMain(         //windows入口函数
  HINSTANCE hInstance,      // handle to current instance
  HINSTANCE hPrevInstance,  // handle to previous instance
  LPSTR lpCmdLine,          // command line
  int nCmdShow              // show state
)

5.Windows窗口的创建过程
具体可以分为下面的几个步骤:
1.设计窗口类

    //设计窗口类
    WNDCLASS wndcls;//窗口类的结构体变量
    wndcls.cbClsExtra = 0;//类加载的额外的空间,一般为0
    wndcls.cbWndExtra = 0;//窗口的额外分配空间,一般为0
    wndcls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);//画刷句柄
    wndcls.hCursor = LoadCursor(NULL,IDC_CROSS);//光标句柄,NULL表示使用标准的一套,后面的参数表示具体的某种
    wndcls.hIcon = LoadIcon(NULL,IDI_ERROR);//图标句柄,NULL表示使用默认的一套,后面的参数表示具体的某种
    wndcls.hInstance = hInstance;//窗口句柄
    wndcls.lpfnWndProc = WinSunProc;//回调函数
    wndcls.lpszClassName = "HelloWorld";//窗口名称
    wndcls.lpszMenuName = NULL;//菜单的名字
    wndcls.style = CS_HREDRAW | CS_VREDRAW;//窗口的风格,采用位相或的方式增加功能

2.注册窗口类

RegisterClass(&wndcls);//注册窗口

3.创建窗口类

//创建窗口之前必须定义窗口的句柄-标识窗口
    HWND hwnd;
    //创建窗口
    hwnd = CreateWindow(
        "HelloWorld",//类的名称,与之前创建的WNDCLASS名称相同
        "MyFirstMFCApp",//窗口名称
        WS_OVERLAPPEDWINDOW & ~ WS_MAXIMIZEBOX/*去掉最大化按钮*/,//窗口的默认属性,层叠菜单,系统菜单,最小最大化按钮,使用二进制位相或的技术
        0,//窗口左上角x坐标(指定缺省值CW_USEDEFAULT,则设置y坐标的值被忽略)
        0,//窗口左上角y坐标
        600,//窗口宽度(指定缺省值CW_USEDEFAULT,则设置高度的值被忽略)
        400,//窗口高度
        NULL,//父窗口句柄,没有父窗口设置为NULL
        NULL,//菜单句柄,没有菜单设置为NULL
        hInstance,//当前程序实例的句柄
        NULL);//暂时不要求这个参数

4.显示窗口类

ShowWindow(hwnd,SW_SHOWNORMAL);//窗口句柄,显示状态(最大化,最小化,正常显示)

5.更新窗口类

UpdateWindow(hwnd);//更新窗口

6.开启消息循环

    MSG msg;
    //操作系统为每一个程序分配一个消息队列
    /*
    当GetMessage函数从线程的消息队列中得到WM_QUIT消息后,返回0,程序即刻退出
    当GetMessage函数从线程的消息队列中得到的不是WM_QUIT,返回非0,继续循环接收消息
    */
    //从消息队列中取出消息:消息变量,所有消息,消息的开始(0接收所有消息),消息的结束(0接收所有消息)
    while(GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);//转换相应的消息(WM_CHAR消息)
        DispatchMessage(&msg);//派发消息给操作系统,操作系统再调用用户编写窗口时自定义的窗口回调函数-WinSunProc
    }

7.Windows窗口的回调函数
下面是一张Windows消息循环的运行原理图,能够帮助我们更好的理解消息的处理过程:
技术分享
可以看出,最后调用的窗口回调函数是我们自己定义的,这就为我们如何处理消息提供了我们想要的方式。
下面是窗口回调函数(过程函数)的定义

LRESULT CALLBACK WinSunProc(//窗口过程函数--又称为窗口回调函数
  HWND hwnd,      // handle to window 窗口句柄
  UINT uMsg,      // message identifier 消息句柄
  WPARAM wParam,  // first message parameter 第一个消息附加参数
  LPARAM lParam   // second message parameter 第二个消息附加参数
)
{
    switch(uMsg)//判断消息类型
    {
    //键盘按下消息
    case WM_CHAR:
        char szChar[20];
        sprintf(szChar,"char is %d",wParam);
        //窗口句柄, 消息文本, 对话框标题, 对话框类型(0代表MB_OK只有一个确定按钮,MB_YESNO有确定和取消按钮)
        MessageBox(hwnd,szChar,"Hello",0);
        break;
    //鼠标左键按下消息
    case WM_LBUTTONDOWN:
        MessageBox(hwnd,"mouse clicked","Hello",0);
        HDC hdc;//自动确定平台驱动设备类型
        hdc = GetDC(hwnd);//参数是窗口句柄(相当于把窗口当画布),获取DC句柄,负责显示
        //输出文本函数:dc句柄,文本的开始x,y坐标,文本,字符串长度
        TextOut(hdc,0,50,"Hello",strlen("Hello"));
        //释放DC,DC是系统内部维护的数据结构,不释放会导致内存泄露
        ReleaseDC(hwnd,hdc);
        break;
    //屏幕重绘消息
    case WM_PAINT:
        HDC hDC;
        PAINTSTRUCT ps;
        //为指定的窗口绘画
        hDC=BeginPaint(hwnd,&ps);//**只能在WM_PAINT中使用**
        //将文字一直保存在窗口上
        TextOut(hDC,0,0,"Hello",strlen("Hello"));
        //结束绘画,释放DC
        EndPaint(hwnd,&ps);//**只能在WM_PAINT中使用**
        break;
    //窗口关闭消息
    case WM_CLOSE:
        //MessageBox执行成功返回点击的按钮类型信息
        //一定要在这里执行判断
        if(IDYES==MessageBox(hwnd,"是否真的结束?","Hello",MB_YESNO))
        {
            //销毁窗口 发送WM_DESTROY消息
            //这个函数执行完后,窗口就会被销毁
            DestroyWindow(hwnd);
        }
        break;
    case WM_DESTROY:
        //0代表退出码 
        /*
        该函数:post一个WM_QUIT消息到线程的消息队列中然后立刻返回
        当GetMessage函数从线程的消息队列中得到WM_QUIT消息后,返回0,程序即刻退出
        当GetMessage函数从线程的消息队列中得到的不是WM_QUIT,返回非0,继续循环接收消息
        */
        PostQuitMessage(0);

        /*
        在DestroyWindow(hwnd);中判断是否结束
        不要在这里执行判断,因为DestroyWindow(hwnd);函数执行
        完毕后,窗口已经被销毁,再判断就没有意义了
        if(IDYES==MessageBox(hwnd,"是否真的结束?","Hello",MB_YESNO))
        {
            PostQuitMessage(0);
        }*/
        break;
    default:
        //对不感兴趣的消息,让系统进行消息的缺省处理,必不可少的处理
        return DefWindowProc(hwnd,uMsg,wParam,lParam);
    }
    return 0;
}

窗口回调函数的指定:

wndcls.lpfnWndProc = WinSunProc;//指定这个窗口类的回调函数为WinSunProc

6.Windows函数调用约定
函数调用约定:规定函数参数传递顺序,栈的清除的规则

VC中的函数调用约定:
__cdecl约定:标准C语言调用约定, VC++编译选项默认使用这种方式

__stdcall约定
标准调用约定,也称为Pascal调用约定,Delphi使用这种约定
除了可变参数的API以外,都是使用__stdcall约定,
在VC中使用这种调用约定,必须加上CALLBACK宏定义 #define CALLBACK __stdcall
回调函数必须使用__stdcall方式,更加直观的表示该函数是回调函数

7.Windows命名约定
技术分享

8.变量的位特性
在我们的程序中经常要用到一类变量,这个变量里的每一位(bit)都对应某一种特性。当该变量的某位为1时,表示有该位对应的那种特性,当该位为0时,即没有该位所对应的特性。该变量的多个位为1时,就是多种特性的组合。
例如:

指定窗口的风格为三种类型的组合

style = CS_VREDRAW | CS_HREDRAW | CS_NOCLOSE;

如果去掉其中的某个特性的方式,用取反(~)之后再进行与(&)运算,就能够实现

style & ~CS_NOCLOSE;//去掉最后一个特性

9.Visual C++程序编译过程图解
技术分享
只要我们编译过程序,那么这个过程就应该不会陌生吧,生成的中间文件时*.obj,生成的目标文件是.exe文件。

总结
我们在编写Windows程序的时候,一定要学会查找MSDN的文档,MSDN是最好的学习资料。

Windows程序运行原理

标签:

原文地址:http://blog.csdn.net/qq_22075977/article/details/51204591

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!