精华内容
下载资源
问答
  • Windows程序运行原理

    2011-01-16 14:07:00
    Windows程序运行原理 Windows应用程序,操作系统,计算机硬件之间的相互关系 关于消息及消息队列
  •  那Windows应用程序,操作系统,计算机硬件之间的相互关系究竟什么了,下面的图就给予很好的解释。  向下箭头①是 应用程序运行判断处理的结果,输出到输出的设备。  向上箭头②是输入设备,输入到操作系统中。 ...
  • Windows程序内部运行原理 具体讲述windows程序的开发,运行原理
  • windows程序运行原理

    2012-12-01 12:23:56
    关于应用程序怎样在windows操作系统上运行。及怎样实现的。
  • PAGE / NUMPAGES WINDOWS程序内部运行原理事件驱动 应用程序消息队列 应用程序 消息队列 操作系统 操作系统 输入输出设备 输入输出设备 掌握C++ C++中结构体和类的区别在于访问控制方面 在结构体中成员的访问属性都...
  • Windows程序内部运行原理

    千次阅读 2016-10-18 19:58:27
    本文大部分内容都是摘自孙鑫老师,在下就是一个简单的总结,归纳,希望对大家有用!!!!Windows操作系统是一种完全不同于传统的dos方式的程序设计方法,是事件驱动的...)Windows应用程序,操作系统,计算机硬件之间

    本文大部分内容都是摘自孙鑫老师,在下就是一个简单的总结,归纳,希望对大家有用!!!!

    Windows操作系统是一种完全不同于传统的dos方式的程序设计方法,是事件驱动的方式(主要是基于消息的,当用户需要完成某种功能时,会调用操作系统的某种支持,然后操作系统将用户的某种需要,包装成消息,并投递到消息队列中去,最后应用程序从消息队列中取走消息,并进行响应。)

    Windows应用程序,操作系统,计算机硬件之间的相互关系。
    这里写图片描述
    1,表示操作系统能操作输出设备,以执行特定的功能:让声卡发出声音,让显卡显示图像
    2,表示操作系统能够感知输入设备状态的变化:鼠标移动,键盘按下,并且能够清楚的明白当前移动到了那个位置,键盘按下的是什么字符

    (这就是操作系统和计算机硬件之间的交互关系)
    应用程序的开发者通常不需要知道具体的实现细节,我们所关心的仅仅是应用程序和操作系统之间的交互

    3,表示应用程序可以通知操作系统执行某个具体的动作,操作系统能够控制声卡发出声音,但它并不知道应该何时发出什么样的声音,需要应用程序告诉操作系统该发出什么声音

    那么,应用程序是如何通知操作系统执行某个功能的呢???
    有过编程经验的读者都应该知道,在应用程序中要完成某个功能,都是以函数调用的形式实现的,同样,应用程序也是以函数调用的方式来通知操作系统执行相应的功能的。操作系统所能够完成的每一个特殊功能通常都有一个函数与其对应,也就是说,操作系统把它所能够完成的功能以函数的形式提供给应用程序使用,应用程序对这些函数的调用就叫做系统调用,,,这些函数的集合就是Windows操作系统提供给应用程序编程的接口(Application Programming Interface),简称为Windows API。
    如:CreateWindow就是一个API函数,应用程序中调用这个函数。操作系统就会按照该函数提供的参数信息产生一个相应的窗口。。

    4,表示操作系统能够将输入设备的变化上传给应用程序。如:用户在某个程序活动中按下了一个按键,操作系统马上能够感知到这一事件,并且能够知道用户按下的是哪一个键,操作系统并不决定对这一事件如何做出反应,而是将这一事件转交给应用程序,由应用程序决定如何对这一事件做出反应。
    蚊子叮了我们一口,我们的神经末梢(操作系统)马上感知到这一事件,并传递给了我们的大脑(应用程序),我们的大脑最终决定如何对这一事件做出反应。将蚊子赶走,或是拍死蚊子。
    对事件做出反应的过程就是消息响应。。。。。

    操作系统是如何将感知到的事件传递给应用程序的呢???
    这是通过消息机制(Message)来实现的。操作系统将每个事件都包装成一个称为消息的结构体MSG来传递给应用进程,
    MSG结构定义如下:

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

    句柄(HANDLE),资源的标示(和指针类似)
    操作系统要管理和操作这些资源,都是通过句柄来找到对应的资源。按资源的类型,又可将句柄细分为图标句柄(HICON),光标句柄(HCURSOR),窗口句柄(HWND),应用程序实例句柄(HINSTANCE)等到各种类型的句柄。操作系统给每一个窗口指定的一个唯一的标识号即窗口句柄

    其实:WPARAM,LPARAM本质上就是int类型,之所以会出现,只是为了更加直观的明白这些参数的意义

    WORD:是一个16位的整数
    DWORD:是一个32位的整数,表示了这个消息被投递于消息队列中的时间
    POINT:是一个点的结构体(当消息被投递时,光标在屏幕上的位置)

    int WINAPI WinMain(
        HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        LPSTR     lpCmdLine,
        int       nCmdShow
    );
    
    //HINSTANCE:当同样的应用程序打开多次的时候,产生多个窗口
    //hPrevInstance:标示上一次打开的窗口
    //(for a win32-based application,this parameter is always NULL)
    //LP:long point(长指针)
    //LPSTR:是一个指向字符串首地址的指针
    //lpCmdLine:是一个命令行的参数(dos中接收两个参数:argc是参数的个数,argv是一个指针数组,用来存放命令行的参数),
    //同样的,windows中也可以接收命令行的参数
    
    //nCmdShow:窗口显示的状态。(最大化,最小化,隐藏显示)

    WinMain:是一个入口点函数,其实是由操作系统来调用的,不是由我们去调用的。
    当操作系统启动我们的程序的时候,会给我们运行中的程序分配一个实例号,通过这个参数就传递进来了,如果我们传递了一个参数的话,那么操作系统就会将这个参数放在相应的参数中(lpCmdLine)
    上面的这些参数,都是由操作系统来赋值呢,,,,

    窗口的创建:

    创建一个完整的窗口需要经过下面四个操作步骤:
    1,设计一个窗口类
    2,注册窗口类
    3,创建窗口
    4,显示及更新窗口

    设计一个窗口类???

    因为一个窗口具有很多特征,光标(形状(十字,箭头)),图标,背景
    也就是说:windows已经为我们定义了一个窗口所需要的因素,我们只需要向里面填写相应的值即可

    这里写图片描述

    style:
    可能会出现:CS_HREDRAW, CS_VREDRAW
    CS:表示的是class style
    程序中:我们可能会这么写

    wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE
    //中间用的是(|)运算符,表示两者特性兼而有之
    //水平重画,垂直重画,当我们窗口应用程序的水平,垂直坐标发生变化的时候,窗口此刻需要重画

    窗口类的类型

    在我们的程序中经常要用到一类变量,这个变量里的每一位(bit)都对应某一种特性。当该变量的某位为1时,表示有该位对应的那种特性,当该位为0时,即没有该位所对应的特性。当变量中的某几位同时为1时,就表示同时具有几种特性的组合。一个变量中的哪一位代表那种意义,不容易记忆,所以我们经常根据特征的英语拼写的大写去定义一些宏,该宏所对应的数值中仅有与该特征相对应的那一位(bit)为1,其余的bit都为0.
    CS_VREDRAW = 0X0001
    CS_HREDRAW = 0X0002
    CS_DBLCLKS = 0X0008
    CS_NOCLOSE = 0X0200
    全部都是只有一位为1,其余全是0,如果我们希望某一变量的数值既有CS_VREDRAW的特性,又有CS_HREDRAW,我们只需要使用二进制OR(|)运算符,将其进行组合,如上
    如果我们希望在某一变量原有的几个特征上去掉其中一个特征,用取反(~)之后再进行与(&)运算,就可以实现,如在刚才的style基础上去掉CS_NOCLOSE特征,可以用style & ~CS_NOCLOSE

    WNDPROC:    lpfnWndProc
    /*
    窗口过程的一个类型,(long point function,接收一个函数指针),
    
    指定了这一类型窗口的过程函数,也称为回调函数(当应用程序收到某一个
    
    窗口的消息时,就应该调用某一函数来处理这条消息(消息通常都是与窗口
    
    相关的)。这一调用不是应用程
    
    序自己来实施,而是由操作系统来完成的,但是,回调函数本身的代码必须
    
    由应用程序自己完成。对于一条消息,操作系统到底调用应用程序中的那个
    
    函数(回调函数)来处理呢???操作系统调用的就是接受消息的窗口所属
    
    的类型中的lpfnWndProc成员指定的函数。每一种不同类型的窗口都有自
    
    己专用的回调函数,该函数就是通过lpfnWndProc成员指定的)
    */
    HINSTANCE:hInstance
    //代表当前应用程序的实例号
    HICON:    hIcon
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    HICON LoadIcon(
        HINSTANCE hInstance,
        LPCTSTR   lpIconName
    );
    //hInstance:handle to application instance
    //this parameter must be NULL when a standard icon is being loaded.
    //lpIconName: name string or resource identifier
    //图标的句柄
    HCURSOR:hCursor
    //光标
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    HCURSOR LoadCursor(
        HINSTANCE hInstance,
        LPCTRSTR  lpCursorName
    );
    //解释同上
    HBRUSH:hbrBackground
    //画刷的句柄
    wndclass.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH);
    //the GetStockObject function retrieves a handle to one of the stock pens , brushes, fonts, or palettes(获取一个句柄,笔,画刷,字体,调色板)
    HGDIOBJ GetStockObject(
        int fnObject;
    );
    可以为:BLACK_BRUSH, DKGRAY_BRUSH, DC_BRUSH, WHITE_BRUSH, BLACK_PEN, DC_PEN, ANSI_FIXED_FONT
    LPCSTR:lpszMenuName
    //LPC: long point const
    //菜单的名字
    wndclass.lpszMenuName = NULL;//表面当前这个程序没有菜单
    LPCTSTR:lpszClassName
    //一个窗口类的名字

    同样的,汽车的生产必须上交国家有关部门的批准。我们才能够生产汽车;类似的,当我们设计完一款新的窗口之后,需要对这个窗口进行注册,向操作系统进行注册,那么我们只有注册成功之后,我们才能创建基于当前类型的窗口

    RegisterClass(&wndclass);
    //注册一个窗口类
    ATOM RegisterClass(
        CONST WNDCLASS * lpWndClass;
    );
    //创建一个窗口,首先需要一个句柄:
    HWND hwnd;
    //我们利用这个句柄来作为新创建窗口的标示
    

    这里写图片描述

    //窗口创建完成之后,就应该将我们的这个窗口显示出来
    ShowWindow(hwnd, SW_SHOWNORMAL);
    
    BOOL ShowWind(
        HWND hWnd,   //句柄
        int nCmdShow //窗口显示的状态(最大化,最小化)
    );
    
    //当然,我们还是需要更新的
    UpdateWindow(hwnd);
    
    //接下来,就到了我们程序当中关键的部分,消息循环
    MSG msg;
    while(GetMessage(&msg, NULL , 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    //GetMessage:从消息队列中取出一条消息
    the GetMessage function retrieves a message from the calling thread's message queue.
    
    BOOL GetMessage(
            LPMSG lpMsg,
            HWND  hWnd,
            UINT  wMsgFilterMin,
            UINT  wMsgFilterMax
    );
    //每一个应用程序,操作系统就会给其建立一个消息队列,当我们的一个窗口有消息的时候,操作系统会将这个消息放到消息队列当中。我们的程序就会通过GetMessage从消息队列中取出一条一条具体的消息
    
    lpMsg: [out](out表明,在传参的过程中,不需要对这个结构体内部的成员进行初始化,我们只需要定义一个结构体变量,将地址放在这个位置就可以了,通过这个函数调用,会帮我们自动的填充消息结构体内部的变量,这就是out的含义,当我们调用getmessage的时候,这个函数就会从消息队列中取出一条消息,然后利用消息结构体的变量返回)
    
    hWnd:是一个句柄(我们要获取的是哪一个窗口的消息),如果我们将其设置为NULL,则说明,我们需要获取属于这个调用线程的任何窗口的消息,如上,我们将其设置为NULL
    
    
    wMsgFilterMin:可以指示这个消息的最小的消息值,在我们的消息队列当中,有很多的消息。那么我们可以对这个消息进行一些选择(有的消息可能感兴趣,有的消息可能不感兴趣),那么我们还可以指定一些消息的范围。就可以利用当前的这个参数来设定消息的最小值。(use WM_KEYFIRST to specify the first keyboard message or WM_MOUSEFIRST to specify the first mouse message.)
    
    wMsgFilterMax:指示这个消息的最大值(use WM_KEYLAST to specify the last keyboard message or WM_MOUSELAST to specify the last mouse message.)
    
    如果我们将我们上面两个消息设置为NULL的话,那么getmessage可以返回所有可以利用的消息,没有范围的过滤。
    当然,我们也可以用这两个参数做一个消息的过滤,在这个范围当中的我们进行获取,不在这个范围当中的,我们过滤
    
    GetMessage(&msg, NULL , 0, 0);
    
    
    此刻GetMessage的返回值为bool类型的,当getmessage从消息队列中取出一条消息的时候,返回为真,如果我们能够保证这个消息队列当中始终都有消息的话,那么返回值应该永远为真
    //下面我们紧接着用到了TranslateMessage(&msg)
    上面提到了,while(getmessage(&msg, NULL00))
    while1)的话,那么上面就是一个死循环,这样也就能够保证程序不断的运行,那么什么时候为假呢,也就是什么时候退出呢???
    当我们取出一条消息的时候,我们才用到了translatemessage函数,转换消息,翻译消息,这个函数到底什么意思呢???
    是对取到的消息对进行转换(当我们按下键盘上的一个按键,系统将发出一个WM_KEYDOWN和WM_KEYUP这样的两个消息,并且参数当中提供了键盘上的,刚才按键中的虚拟的扫描码,但是有时候用户按下某个键,我们想要得到的是用户输入某一个字符的消息,也就是键盘上对应的某一个字母,那么在消息补充的附加参数当中提供我们按键字母的一个ascii码),这个translatemessage函数能够将WM_KEYDOWN和WM_KEYUP这样的两个消息转换为WM_CHAR消息,并且将转换后的消息投递到消息队列当中,(这个转换过程不会影响原来的消息只会产生一个新的消息,)也就是说,我们如果不用这样的消息的话,我们是不会受到WM_CHAR消息的。
    
    当我们采用translatemessage消息的话,一旦我们按键,就能够将WM_KEYDOWN和WM_KEYUP这样的两个消息转换为WM_CHAR消息,并且将转换后的消息投递到消息队列当中,也就是这样的话,就能捕获到WM_CHAR
    这样的消息了。
    dispatchmessage函数呢??
    是将我们收到的消息传到窗口的回调函数中去,也就是窗口过程函数当中去处理,也可以理解为:将消息给了操作系统,然后操作系统调用我们的窗口过程函数,
    所以,windows系统消息循环的整个机制:
    当一个应用程序建立的时候,操作系统会为这个应用程序分配一个消息队列,凡是跟这个应用程序相关的消息,都会被放入到这个消息队列当中,然后,我们的应用程序利用这个getmessage从消息队列当中取出具体的消息,利用translatemessage将WM_KEYDOWN和WM_KEYUP这样的两个消息转换为WM_CHAR消息,并且投放的消息队列当中,利用dispatchmessage将这个消息投递出去,分发出去(操作系统,操作系统利用我们设计窗口类的时候所指定的窗口回调函数(winsunproc),在这个函数里面,对不同的消息做了不同的处理 )
    
    LRESULT CALLBACK WindowProc(
        HWND hwnd,  //handle to window
        UINT uMsg,  //message identifier
        WPARAM wParam, //first message parameter
        LPARAM lParam  //second message parameter
    );
    函数名字可以改,参数的类型不能改,名字可以改。
    四个参数和消息的四个参数很像。(也就是说:利用dispatchmessage的时候,操作系统会去调用这样的windowproc窗口过程函数,将这个消息参数结构体中的前四个参数传递给我们这个函数,对于消息的参数(有两个我们暂时不需要,一个是消息投递时的时间,另一个是光标在屏幕上的位置。))一旦有一个消息产生的时候,都会调用我们的窗口过程函数。因此,我们需要判断到底是哪一个消息。
    
    MessageBox:
    如下:我们的用法:
    MessageBox(hwnd, szChar, "weixin", MB_OK);
    
    int MessageBox(
        HWND    hWnd,      //handle to owner window
        LPCTSTR lpText,    //text in message box
        LPCTSTR lpCaption, //message box title
        UINT    uType      //message box style
    );

    程序简单代码:

    #include <windows.h>
    #include <stdio.h>
    
    LRESULT CALLBACK WinSunProc(
      HWND hwnd,      // handle to window
      UINT uMsg,      // message identifier
      WPARAM wParam,  // first message parameter
      LPARAM lParam   // second message parameter
    );
    
    int WINAPI WinMain(
      HINSTANCE hInstance,      // handle to current instance
      HINSTANCE hPrevInstance,  // handle to previous instance
      LPSTR lpCmdLine,          // command line
      int nCmdShow              // show state
    )
    {
        WNDCLASS wndcls;
        wndcls.cbClsExtra=0;
        wndcls.cbWndExtra=0;
        wndcls.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
        wndcls.hCursor=LoadCursor(NULL,IDC_CROSS);
        wndcls.hIcon=LoadIcon(NULL,IDI_ERROR);
        wndcls.hInstance=hInstance;
        wndcls.lpfnWndProc=WinSunProc;
        wndcls.lpszClassName="2016 3+1";
        wndcls.lpszMenuName=NULL;
        wndcls.style=CS_HREDRAW | CS_VREDRAW;
        RegisterClass(&wndcls);
    
        HWND hwnd;
        hwnd=CreateWindow("2016 3+1","wince3+1",WS_OVERLAPPEDWINDOW,
            0,0,600,400,NULL,NULL,hInstance,NULL);
    
        ShowWindow(hwnd,SW_SHOWNORMAL);
        UpdateWindow(hwnd);
    
        MSG msg;
        while(GetMessage(&msg,NULL,0,0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return 0;
    }
    
    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);
            MessageBox(hwnd,szChar,"weixin",0);
            break;
        case WM_LBUTTONDOWN:
            MessageBox(hwnd,"mouse clicked","wince3+1",0);
            HDC hdc;
            hdc=GetDC(hwnd);
            TextOut(hdc,0,50,"hello, world",strlen("hello, world"));
            ReleaseDC(hwnd,hdc);
            break;
        case WM_PAINT:
            HDC hDC;
            PAINTSTRUCT ps;
            hDC=BeginPaint(hwnd,&ps);
            TextOut(hDC,0,0,"3+1",strlen("3+1"));
            EndPaint(hwnd,&ps);
            break;
      case WM_CLOSE:
            if(IDYES==MessageBox(hwnd,"是否真的结束?","weixin",MB_YESNO))
            {
                DestroyWindow(hwnd);
            }
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd,uMsg,wParam,lParam);
        }
        return 0;
    }
    

    运行结果:
    (点击左键)
    这里写图片描述

    展开全文
  • windows程序运行原理及程序流程2
  • Windows程序运行原理及程序编写流程,窗口产生过程,句柄原理,消息队列,回调函数,窗口关闭与应用程序退出的工作关系,使用VC++的若干小技巧,stdcall与cdecl调用规范的比较,初学者常犯错误及注意事项。
  • 窗口产生过程,句柄原理,消息队列,回调函数,窗口关闭与应用程序退出的工作关系,使用VC++的若干小技巧,stdcall...操作系统提供了各种方便开发Windows应用程序的编程接口,所的函数都在Windows.h头文件中声明。Win32

    窗口产生过程,句柄原理,消息队列,回调函数,窗口关闭与应用程序退出的工作关系,使用VC++的若干小技巧,stdcall与Lessonecl调用规范的比较,初学者常犯错误及注意事项。以下是应用程序与操作系统之间的关系。

    1.Windows API与Win32 SDK

    操作系统提供了各种方便开发Windows应用程序的编程接口,所的函数都在Windows.h头文件中声明。Win32 SDK(Software Development Kit): 即Windows 32位平台下的软件开发包,包括API函数,帮助文档,微软提供的一些辅助开发工具。

    2.窗口与句柄

    窗口是是屏幕上一块矩形区域,是Windows应用程序与用户进行交互的接口。窗口分为客户区和非客户区。在Windows应用程序中,窗口是通过窗口句柄(HWND)来标识的,要对某个窗口进行操作,首先就要得到这个窗口的句柄。其它各种资源(窗口,图标,光标等),系统在创建这些资源时会为它们分配内在,并返回标识这些资源的标识号,即句柄。-->光标句柄(HCURSOR),图标句柄(HICON)。

    3.消息与队列

    Windows程序设计是一种基于消息的事件驱动方式的程序设计模式。

    windows程序是一种完全不同于传统的DOS操作系统的程序设计方法。它是一种时间驱动方式的程序设计模式,主要是基于消息的。例如用户在窗口中画图的时候,按下鼠标左键,此时,操作系统会感知到这件事件,于是将这个小时包装成一个消息,投递到应用程序的消息队列中,然后应用程序从消息队列中取出消息并进行响应。在这个过程中,操作系统也会给应用程序“发送消息”。所谓的“发送消息”,实际上是操作系统调用程序中一个专门负责处理消息的函数,这个函数称为窗口过程。

    消息:Windows中由结构体MSG来表示,

    复制代码
    typedef struct tagMSG{
            HWND hwnd;//消息所属的窗口句柄
    UINT    message;//消息本身标识符,由一数值表示,系统对消息定//义为WM_XXX宏(WM为Windows Message缩写)
                    WPARAM    wParam;    //随消息的不同附加信息也不同
                    LPARAM    lParam;        //消息的附加参数
                    DWORD    time;        //消息投递的时间
                    POINT        pt;            //鼠标当前位置
    }
    复制代码

     

    消息队列:每当一个Windows应用程序创建后,系统都会为该程序创建一个消息队列,这个消息队列用来存放该程序一的窗口的消息,消息产生后被投递到消息队列中,应用程序通过一个消息循环不断的消息队列中取出消息进行响应。响应过程由系统向应用程序发送消息,实际就是调用应用程序的消息处理函数。

    4.创建一个完整的win32程序的主要步骤

    1. WinMain函数的定义
    2. 创建一个窗口      创建一个完整的窗口的四个步骤SDK,1设计窗口类,2注册窗口类,3创建窗口,4显示窗口
    3. 进行消息循环
    4. 编写窗口过程函数

    回调函数的实现机制:

      (1)      定义一个回调函数

      (2)      提供函数实现的一方在初始化的时候,将回调函数的函数指针注册给调用者

      (3)      当特定的事件或条件发和的时候,调用使用函数指针调用回调函数对事件进行处理

        针对Windows的消息处理机制,窗口过程函数被调用的过程如下:

      1. 在设计窗口类的时候,将窗口赛程函数的地址赋值给lpfnWndProc成员变量

      2. 调用RegisterClass(&wndclass)注册窗口类,那么系统就有了我们所编写的窗口过程函数的地址

      3. 当应用程序接收到某一窗口的消息,调用DispatchMessage(&msg)将消息加值给系统。系统则利用先前注册窗口类时得到函数指针,调用窗口过程函数对消息进行处理。
    HICON LoadIcon(HINSTANCE hInstance, LPCTSTR lpIconName);
    //加载窗图标,返回系统分配给该图标的句柄, LPCTSTR被定义为CONST CHAR *(指向常量的字符指针),图标的ID是一个常数,要使用MAKEINTRESOUCE宏把资源ID标识转换为需要的LPCTSTR类型

      (4)  sprintf格式化字符,其头文件为stdio。h,在MFC中格式化字符用CString。Forma

      (5)  GetDC()与ReleaseDC()要成对使用,否则会内存泄漏。同样,BeginPaint()与EndPaint(),这两个Parint只能在影响WM_PAINT消息中调用。

      (6)  GetStockObject()得到画笔、画刷、字体、调色板的句柄,使用时必须用类型转换。如:hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH )//创建空画刷

      (7)什么时候用NULL,什么时候用0。答,对指针赋值时用NULL,对变量赋值

    时用0。

      (8)什么是野指针?答:将指针指向的变量的内存释放后,此指针即变成野指针!

    如何避免野指针?答:将此指针指向NULL即可。p=NULL;

    备注:

    1. MFC中生成的C++源文件中都有StdAfx.h,此文件包含了常用的AFX函数的声明,其中有afxwin.h,此文件包含了CRECT,CPOING,CWnd等许多类及其方法的应用。
    2. project->setting->debug可以加入命令行参数。
    3. 在SDK中要加入“windows.h"和”stdio.h"因为LoadCursor,MessageBox等函数的声明在这个文件中。
    4. 创建一个完整的窗口的四个步骤:设计窗口类,注册窗口类,创建窗口,显示窗口。
    5. 函数名可以代表函数代码的首地址,即可以作为函数指针。
    6. atof将字符串转化成float,atoi将字符串装化成int型。
    7. 所有从CWnd类派生的类都有m_hWnd句柄。
    8. 变量的生命周期:可以认为出了包含它的大括号,这个变量的生命周期就结束了。所以全局变量的声明应该在大括号的外面,但是用new声明的变量和用static声明的变量除外。

    产生窗口的程序如下:

    复制代码
    #include <stdio.h>
    #include <windows.h>
    #include <stdexcept>
    using namespace std;
    
    //回调函数原型声明,返回长整形的结果码,CALLBACK是表示stdcall调用
    LRESULT CALLBACK WinProc( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ); //(1) WinMain函数,程序入口点函数 int WINAPI WinMain( HINSTANCE hInstance, // handle to current instance HINSTANCE hPrevInstance, // handle to previous instance LPSTR lpCmdLine, // command line int nCmdShow // show state ){ //(2) //一.设计一个窗口类,类似填空题,使用窗口结构体 WNDCLASS wnd; wnd.cbClsExtra = 0; //类的额外内存 wnd.cbWndExtra = 0; //窗口的额外内存 wnd.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);//创建一个空画刷填充背景 //加载游标,如果是加载标准游标,则第一个实例标识设置为空 wnd.hCursor = LoadCursor(NULL, IDC_CROSS); wnd.hIcon = LoadIcon(NULL, IDI_ERROR); wnd.hInstance = hInstance;//实例句柄赋值为程序启动系统分配的句柄值 wnd.lpfnWndProc = WinProc;//消息响应函数 wnd.lpszClassName = "gaojun";//窗口类的名子,在注册时会使用到 wnd.lpszMenuName = NULL;//默认为NULL没有标题栏 wnd.style = CS_HREDRAW | CS_VREDRAW;//定义为水平和垂直重画 //二.注册窗口类 RegisterClass(&wnd); //三.根据定制的窗口类创建窗口 HWND hwnd;//保存创建窗口后的生成窗口句柄用于显示 //如果是多文档程序,则最后一个参数lParam必须指向一个CLIENTCREATESTRUCT结构体 hwnd = CreateWindow("gaojun", "WIN32应用程序", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL); //四.显示窗口 ShowWindow(hwnd, SW_SHOWDEFAULT); //五.更新窗口 UpdateWindow(hwnd); //(3).消息循环 MSG msg;//消息结构体 //如果消息出错,返回值是-1,当GetMessage从消息队列中取到是WM_QUIT消息时,返回值是0 //也可以使用PeekMessage函数从消息队列中取出消息 BOOL bSet; while((bSet = GetMessage(&msg, NULL, 0, 0)) != 0){ if (-1 == bSet) { return -1; } else{ TranslateMessage(&msg); DispatchMessage(&msg); } } return 0;//程序结束,返回0 } //消息循环中对不同的消息各类进行不同的响应 LRESULT CALLBACK WinProc( 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);//格式化操作,stdio.h MessageBox(hwnd, szChar, "gaojun", 0);//输出操作windows.h中 break; case WM_LBUTTONDOWN://鼠标左键按下消息 MessageBox(hwnd, "this is click event!", "点击", 0); HDC hdc; hdc = GetDC(hwnd);//获取设备上下文句柄,用来输出文字 //在x=0,y=50(像素)的地方输出文字 TextOut(hdc, 0, 50, "响应WM_LBUTTONDONW消息!", strlen("响应WM_LBUTTONDONW消息!")); ReleaseDC(hwnd, hdc);//在使用完DC后一定要注意释放 break; case WM_PAINT://窗口重给时报消息响应 HDC hDc; PAINTSTRUCT ps; hDc = BeginPaint(hwnd, &ps); TextOut(hDc, 0, 0, "这是一个Paint事件!", strlen("这是一个Paint事件!")); EndPaint(hwnd, &ps); break; case WM_CLOSE://关闭消息 if (IDYES == MessageBox(hwnd, "确定要关闭当前窗口?", "提示", MB_YESNO)) { DestroyWindow(hwnd);//销毁窗口 } break; case WM_DESTROY: PostQuitMessage(0);//在响应消息后,投递一个退出的消息使用程序安全退出 break; default: return DefWindowProc(hwnd, uMsg, wParam, lParam);//调用缺省的消息处理过程函数 } return 0; }
    复制代码
    展开全文
  • Windows程序运行原理(总结)

    千次阅读 2016-03-30 11:34:49
    1、消息及消息队列:操作系统是将感知到的事件传递给应用程序。 操作系统给出了消息结构体MSG: 和哪一个窗口相关,消息本身是什么,消息的附加参数是什么,消息发生投递的时间是什么,消息投递时当前光标的位置 ...

    写这个博客的目的仅仅是为自己编程学习过程中作一些总结,时不时来回顾,里面也有没搞明白的,希望在今后积累够后,回来看看能够豁然开朗


    1、消息及消息队列:操作系统是将感知到的事件传递给应用程序。

    操作系统给出了消息结构体MSG:  和哪一个窗口相关,消息本身是什么,消息的附加参数是什么,消息发生投递的时间是什么,消息投递时当前光标的位置

    typedef struct tagMSG {       
        	HWND   hwnd;      
        	UINT   message; //用一个整数标示一个消息,定义了宏用来表示数字,如按键消息,鼠标左键下按 WM_LBUTTONDOWN这个宏来表示数字就比较好记忆,
        	WPARAM wParam;  //变量类型整数,指示消息的附加信息,具体的按键信息:如键盘按键的ASCIA码,获取具体字符
        	LPARAM lParam;  <span style="font-family: Arial, Helvetica, sans-serif;">//变量类型整数,指示消息的附加信息</span>
        	DWORD  time;   //32位整数,doubleWord
        	POINT  pt;     // 当信息别投递时,当前光标的位置,
    } MSG; 
    

    句柄(HANDLE),资源的标示,包括图标(HICON)、光标(HCurSOR)、窗口(HWND)、应用程序实例句柄(HINSTANCE)等

    即给各种资源一个标示号,操作系统方便管理。

    如HWND,是一个窗口句柄,操作系统通过这个句柄可以管理这个窗口的内容。操作系统是用句柄去索引的内存当中的资源。


    2、每一个应用程序,操作系统都会为其建立一个消息队列,先进先出的缓冲区

    3、Windows程序的入口函数

    int WINAPI WinMain(
      HINSTANCE hInstance,      // handle to current instance   应用程序实例句柄,代表
      HINSTANCE hPrevInstance,  // handle to previous instance
      LPSTR lpCmdLine,          // command line       LP STR 指向字符串的指针        
      int nCmdShow              // show state
    );

    4、窗口创建

          a、设计一个窗口类;

          b、注册窗口类;

          c、创建窗口;

          d、显示及更新窗口



    #include "stdafx.h"
    #include <Windows.h>
    #include <stdio.h>
    #pragma(lib, "MSVCRTD.lib");
    
    
    LRESULT CALLBACK WinSunProc(HWND hwnd,      //窗口句柄
    	UINT wMsg,       //message identifier
    	WPARAM wParam,   // first message parameter
    	LPARAM lParam);   //second message parameter
    
    
    
    int WINAPI WinMain(HINSTANCE hInstance, //应用程序实例句柄
    				   HINSTANCE hPrevInstance, //先前应用程序的句柄
    				   LPSTR lpCmdLine,        //
    				   int nCmdShow)
    {
    	//设计一个窗口类
    	WNDCLASS wndcls;
    	wndcls.cbClsExtra = 0;
    	wndcls.cbWndExtra = 0;
    	wndcls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    	wndcls.hCursor = LoadCursor(NULL, IDC_CROSS);
    	wndcls.hIcon = LoadIcon(NULL,IDI_ERROR);
    	wndcls.hInstance = hInstance;
    	wndcls.lpfnWndProc = WinSunProc;
    	
    	
    	//代码在VC6中没问题. 因为它的代码没有按可编译为UNICODE版本的方式写,而VS2005之后版本默认是UNICODE编码的.所以所有使用到字串的地方都会出错.
    	//方法:修改VS2005之后版本的设置:选择你的项目->属性->常规->设置为不使用UNICODE,发现设置为多字节字符集也可以。发现用VS2005打开VC6的源代码,转换后是使用的多字节字符集。
    	// 在VS2008,vs2010中,项目->属性->常规->字符集:改为“使用多字节字符集”即可
    	//error C2440: “=”: 无法从“const char [11]”转换为“LPCWSTR”类问题
    	
    	wndcls.lpszClassName = "tranning";   //wndClass.lpszClassName =L"DIRECTX11BookWindowClass";即在字符串的前面添加一个大写L。这样可以实现将字符串转换为宽字符集。
    	wndcls.lpszMenuName = NULL;
    	wndcls.style = CS_HREDRAW | CS_VREDRAW;
    
    	//注册窗口类
    	RegisterClass(&wndcls);
    	
    	//创建一个窗口
    
    	HWND hwnd;   //创建一个句柄,代表这窗口标识符 // DWORD dwStyle 窗口类型
    	hwnd = CreateWindow("tranning", "仿生机器人实验室",WS_OVERLAPPEDWINDOW,
    							0, 0, 600, 400, NULL, NULL, hInstance, NULL);
    	//显示窗口
    	ShowWindow(hwnd,SW_SHOWNORMAL);
    	UpdateWindow(hwnd);
    
    	//消息响应函数
    	MSG msg;
    	while (GetMessage(&msg,NULL,0,0))     //第二个参数句柄设置为空,希望获取所有函数的消息
    	{
    		TranslateMessage(&msg);    //消息转换,如将WM_KEYDOWN和WM_KEYUP转换成一个char 消息,并且投递到消息队列当中
    		DispatchMessage(&msg);     //将收到的消息传递到窗口的回调函数,在窗口过程函数当中处理,理解为将消息送给操作系统再由操作系统去调用回调函数
    	}
    	return 0;
    }
    
    //窗口过程函数
    //回调函数,
    //CALLBACK 是标准调用约定_stdcall
    
    LRESULT CALLBACK WinSunProc(HWND hwnd,      //窗口句柄
    							UINT wMsg,       //message identifier
    							WPARAM wParam,   // first message parameter
    							LPARAM lParam)   //second message parameter
    {
    	switch(wMsg)
    	{
    	case WM_CHAR:
    		char szChar[20];
    		sprintf(szChar,"char is %d", wParam);
    		break;
    	case WM_LBUTTONDOWN:
    		MessageBox(hwnd,"mouse clicked", "fangsheng",0);
    		HDC hdc;            //device contacts , 提供这个接口,可以不用理会外设驱动怎么回事
    		hdc = GetDC(hwnd);
    
    		TextOut(hdc, 0, 50, "Windows程序设计基础", strlen("Windows程序设计基础"));
    		ReleaseDC(hwnd,hdc);
    		break;
    	case WM_PAINT:    //窗口重绘函数
    		HDC hdc1;
    		PAINTSTRUCT ps;
    		hdc1 = BeginPaint(hwnd,&ps);
    		TextOut(hdc1, 0, 0, "程序设计基础", strlen("程序设计基础"));
    		EndPaint(hwnd, &ps);
    		break;
    	case WM_CLOSE:
    		if(IDYES == MessageBox(hwnd, "是否真的结束?","Windows程序设计基础",0))
    		{
    			DestroyWindow(hwnd);              //销毁窗口
    		}
    		break;
    	case WM_DESTROY:
    		PostQuitMessage(0);        // 投递一个WM_QUIT的消息到线程的消息队列当中,并且立即返回    终止消息发送,式消息循环终止,从而实现退出程序
    		break;
    	default:
    		return DefWindowProc(hwnd,wMsg,wParam,lParam);   //其它消息由操作系统默认处理
    	}
    	return 0;
    }
    
    

    运行时遇到问题:

    1、//error C2440: “=”: 无法从“const char [11]”转换为“LPCWSTR”类问题代码在VC6中没问题. 因为它的代码没有按可编译为UNICODE版本的方式写,而VS2005之后版本默认是UNICODE编码的.所以所有使用到字串的地方都会出错.

    //方法:修改VS2005之后版本的设置:选择你的项目->属性->常规->设置为不使用UNICODE,发现设置为多字节字符集也可以。发现用VS2005打开VC6的源代码,转换后是使用的多字节字符集。
    // 在VS2008,vs2010中,项目->属性->常规->字符集:改为“使用多字节字符集”即可

    2、MSVCRTD.lib(crtexe.obj) : error LNK2019: 无法解析的外部符号 _main,该符号在函数 ___tmainCRTStartup 中被引用

    在项目属性-连接器-系统- 子系统 , 将:   /subsytem:console     改为/ subsystem:windows 至于为什么这么改,我就不是太清楚,

    一开始在vs2010建立工程是默认控制台工程,我将里头main函数直接删除,并且输入以上代码,就出现这个问题。


    _stdcall 与 cdcall 的区别
    调用约定,一种是标准调用约定,一种是C语言的调用约定

    定义的参数传递的顺序,还有堆栈清除有些差异

    除了可变参数API 函数调用,其他都是_stdcall

    VC++ 默认是cdcall,,在vc++调用_stdcall  API函数时必须在声明函数时,加入_stdcall标示

    展开全文
  • 也可以是针对系统设备的,对系统的输入输出做一些处理,实现特定的功能,比如当软件要做的事用应用程序无法实现或者难以实现某种功能时,但驱动程序可以实现,则需要驱动程序。以下就是一个C++以服务的方式,加载驱动...

    驱动程序可以是针对某一特定硬件的,为系统提供管理硬件的各种功能;也可以是针对系统设备的,对系统的输入输出做一些处理,实现特定的功能,比如当软件要做的事用应用程序无法实现或者难以实现某种功能时,但驱动程序可以实现,则需要驱动程序。以下就是一个C++以服务的方式,加载驱动的实例!

     

    C++的功能强大,各种编译器也层出不穷。以前用mingw用习惯了,现在学习windows驱动程序开发,还要弄Visual Studio,感觉很麻烦。就生出“用mingw编译C++写的驱动程序”的念头,搜索了一下网上的相关资料,发现一个办法不错。

     

    代码展示:

     

    效果展示:

     

     

     

    展开全文
  • 1.API:Application Programming Interface,应用程序接口。为微软开发的,要查它的用法,可以通过msdn来找。2.Win32 SDK:SoftWare Developement Kit ,32位平台下的软件开发包,为开发所需要资源的一个...在windows应用
  • WinMain(windows程序的运行原理以及VC++的实现过程)操作系统以消息机制把输入设备的变化传递给我们的应用程序,操作系统所扮演的角色是神经末梢 APP系统调用API OS 输出 输入 HARDWARE操作系统之所以成为操作...
  • 关于的消息解释,我个人觉得在这一课,解释...入口函数:一个Windows程序是在什么情况下启动的呢,也即我们创建了一个Windows程序后,当运行该已建程序时,OS是如何启动我们的这个程序的呢?这就是Windows的WinMain函数
  •   Windows程序的内部运行原理   操作系统和应用程序之间的关系: 应用程序到操作系统表示应用程序可以通知操作系统执行某个具体的动作 操作系统到应用程序表示操作系统能够将输入...
  • windows运行原理单文档

    2009-11-13 22:31:44
    windows运行原理一书单文档MFC应用程序 开发平台visual studio 2005
  • .NET程序运行原理

    千次阅读 2007-11-27 09:32:00
    .NET程序运行原理CPU虽然是计算机的核心,但光有CPU还是不能干活的,至少还需要有地方来存放机器指令代码。这就用到了存储器,有两种存储器:外存和内存。内存(参见图1-46)通常容量较小,存取数据的速度非常快,但...
  • 如何测试Windows应用程序

    千次阅读 2019-12-19 17:58:37
    本教程主要讲解如何使用AirtestIDE进行Windows应用程序的自动化测试(以网易云音乐Windows版为案例)。 通过阅读本文,你将学会: 使用AirtestIDE对一个Windows软件窗口进行脚本录制 如何调用Windows操作的接口 ...
  • 2 应用程序的启动过程 3 CreateProcess函数 4 实例3 创建进程3.1 进程和线程进程通常被定义为一个存在运行的程序的实例。进程是一个正在运行的程序,它拥有自己的虚拟地址空间,拥有自己的代码、数据和其他系统资源...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 166,998
精华内容 66,799
关键字:

windows应用程序运行原理