Windows程序运行原理

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是最好的学习资料。

时间: 2024-10-25 05:17:09

Windows程序运行原理的相关文章

Windows程序设计笔记1:第2章:win32程序运行原理

第2章:win32程序运行原理 内核对象:对象句柄,标示符,进程相关的,只能被1个进程里面的其他线程访问,不透明的,封装过的. 创建进程:返回STARTUPINFO类型的变量对象,包含了父进程传递给子进程的显示信息,   STARTUPINFO是一种类类型,和内含的类型是一样的, STARTUPINFO si={sizeof(&si)}; //初始化startupinfo的大小 ::GetStartupinfo(&si); //调用startupinfo对象 创建进程:CreateProc

.NET 程序运行原理

“Overview of the Common Language Infrastructure”,作者Jarkko Piiroinen - 自己的作品.采用Public domain授权,来自维基共享资源. 右图即为运行图. 最上层即为各种语言,然后经过对应的编译器编译成程序集,也就是 CIL 通用中间语言 最后,再由 CLR 公共语言运行时 编译成机器码 CLI 一个规范 .NET 程序运行原理

Windows程序运行过程

Windows应用程序: WinMain函数(入口函数): 1.设计窗口类,注册窗口类:WNDCLASS 2.创建窗口,显示及更新窗口: 3.消息循环: 窗口过程函数(回调函数):WindowProc PS:Dos程序入口函数为main,Windows程序入口为WinMain,都是由系统直接调用. windows程序运行过程 #include<windows.h> #include<stdio.h> LRESULT CALLBACK WinSunProc( //窗口过程函数(回调函

java程序运行原理

一.JRE.JDK.JVM 要了解java程序运行原理,首先需要了解知道jre.jdk.jvm这三者是什么,他们之间又有什么联系. JRE(JavaRuntimeEnvironment,Java运行环境),也就是Java平台.所有的Java 程序都要在JRE下才能运行. JDK(Java Development Kit,java开发工具包)是程序开发者用来来编译.调试java程序用的开发工具包.JDK的工具也是Java程序,也需要JRE才能运行.为了保持JDK的独立性和完整性,在JDK的安装过程

第二章--Win32程序运行原理 (部分概念及代码讲解)

学习<Windows程序设计>记录 概念贴士: 1. 每个进程都有赋予它自己的私有地址空间.当进程内的线程运行时,该线程仅仅能够访问属于它的进程的内存,而属于其他进程的内存被屏蔽了起来,不能被该线程访问. PS:进程A在其地址空间的0x12345678地址处能够有一个数据结构,而进程B能够在其地址空间的0x12345678处存储一个完全不同的数据.彼此不能访问. 2. 在大多数系统中,Windows将地址空间的一半(4GB的前一半,0x00000000-0x7FFFFFFF)留给进程作为私有存

QF——iOS程序运行原理

iOS程序的运行原理: 1> main.m 主函数是所有程序的入口函数. 2> 在main函数里是UIApplicationMain函数,开启了一个无限循环,以监听该应用. 该UIApplicationMain函数有4个参数,前两个分别是main函数的参数,第3个参数UIApplication的类名,第4个是应用的代理类名. 2.1> 创建一个UIApplication实例,单例的,一个应用对应一个该对象,代表整个应用程序. 2.2> 再创建一个UIApplication的dele

逆向第三课(深入.NET程序运行原理)

注:本文适用读者范围,对Windows下的PE文件有一定认识的朋友 一. 名词解释 a)        CLR: 公共语言运行时(Common LanguageRuntime),CLR时.NET框架的核心内容之一,可以把它看为一套标准资源,可以被任何.NET程序使用.它包括:面向对象的编程模型.安全模型.类型系统(CTS).所有.NET基类.程序执行以及代码管理等. b)        JIT: 即时编译(Just In-Time compile),这是.NET运行可执行程序的基本方式,也就是在

Windows内部程序运行原理

1.相互关系图 操作系统把它能够完成的功能以函数的形式提供给应用程序使用,应用程序对这些函数的调用就是系统调用.这些函数的集合就是windows操作系统提供给应用程序的编程接口Application Programming Interface(即windwos API) 2.消息机制 typedefstruct tagMSG( HWND hwnd,//handle to window,窗口标识的类型 UINT uMsg,//unsigned int 表示一个具体的消息(WM开头WM_KEYDOW

Java程序运行原理分析

class文件内容 class文件包含Java程序执行的字节码 数据严格按照格式紧凑排列在class文件的二进制流,中间无分割符 文件开头有一个0xcafebabe(16进制)特殊的标志 JVM运行时数据区 线程独占: 每个线程都会有它独立的空间,随线程的生命周而创建和销毁 线程共享: 所有线程都能访问这块内存数据,随虚拟机或GC而创建和销毁 方法区 方法区是各个线程共享的内存区域 用于存储已被虚拟机加载的类信息, 常量,静态变量, 即时编译后的代码等数据 虽然Java虚拟机规范把方法区描述为堆