Windows程序内部运行原理

时间:2022-12-23 21:44:35

Windows程序内部运行原理

一、基本原理

1Windows应用程序,操作系统,计算机硬件之间的相互关系 

Windows程序内部运行原理

一个例子:

汽车厂家生产汽车好比应用程序创建窗口,用户使用汽车好比操作系统管理窗口,某种汽车在销售前就指定好了修理站(类似回调函数),当用户的汽车出现故障后(类似窗口收到消息),汽车用户(类似操作系统)自己直接找到修理站去修理,不用厂家(类似应用程序)亲自将车送到修理站去修理,但修理站还得由厂家事先建造好。 

2API

应用程序是以函数调用的方式来通知操作系统执行相应的功能的。操作系统所能够完成的每一个特殊功能通常都有一个函数与其对应。操作系统把它所能够完成的功能以函数的形式提供给应用程序使用,应用程序对这些函数的调用就叫做系统调用,这些函数的集合就是Windows操作系统提供给应用程序编程的接口(Application Programming Interface),简称Windows API。如CreateWindow就是一个API函数,应用程序中调用这个函数,操作系统就会按照该函数提供的参数信息产生一个相应的窗口。 

3Windows程序的入口函数

int WINAPI WinMain(

  HINSTANCE hInstance,      // handle to current instance

//在这里,句柄是一个标识符,用来标识资源,类似指针,一般以H**开头//的标识符都是句柄

  HINSTANCE hPrevInstance,  // handle to previous instance

  LPSTR lpCmdLine, // command line//传递给程序的命令行//参数

  int nCmdShow       // show state

);

4、创建一个完整的窗口需要经过下面四个操作步骤:

1)设计一个窗口类;//WNDCLASS wndcls;

typedef struct _WNDCLASS { 

    UINT       style; 

    WNDPROC    lpfnWndProc;//函数指针,指向本窗口的处理函数,//也称为窗口过程函数

    int        cbClsExtra; 

    int        cbWndExtra; 

    HINSTANCE  hInstance; 

    HICON      hIcon; 

    HCURSOR    hCursor; 

    HBRUSH     hbrBackground; 

    LPCTSTR    lpszMenuName; 

    LPCTSTR    lpszClassName; 

} WNDCLASS, *PWNDCLASS; 

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

3)创建窗口;//hwnd=CreateWindow(//...);

    4)显示及更新窗口。

//ShowWindow(hwnd,SW_SHOWNORMAL);

//UpdateWindow(hwnd);

    基于一个窗口类创建的窗口使用同一个窗口过程。

5、消息和消息队列

Windos程序是一种事件驱动方式和程序设计模式,主要是基本消息的。

操作系统将每个感知的事件都包装成一个称为消息的结构体MSG来传递给应用程序。MSG结构如下示:

typedef struct tagMSG {       

    HWND   hwnd;  //一个消息总是与某个窗体相关联的    

    UINT   message; //消息标识符,数值,对应WM_XXX的宏

    WPARAM wParam; //附加消息

    LPARAM lParam; //附加消息

    DWORD  time; //投递时间

    POINT  pt; //鼠标当前位置

} MSG; 

而应用程序则循环不断地从消息队列中取出消息,并进行响应,这就是消息机制。注意到,操作系统为不同类型的应用程序维护不同的消息队列。消息也分进队和不进队消息,进队的消息由系统放入到应用程序的消息队列中,不进队的消息在系统调用窗口过程时直接发送给窗口。不管是进队还是不进队消息,最终都由系统调用窗口过程函数对消息进行处理。

发送消息可以用SendMessagePosMessage,前者为不进队消息,将消息直接发送到窗口,并调用窗口过程函数处理,处理完后,返回。后者是将消息放入与创建窗口相关联的消息队列后立即返回。

6、完整的Win32程序

1WinMain函数的定义

int WINAPI WinMain(

  HINSTANCE hInstance,      // handle to current instance

  HINSTANCE hPrevInstance,  // handle to previous instance

  LPSTR lpCmdLine,          // command line

  int nCmdShow              // show state

);

2)创建一个窗口

HWND CreateWindow(

  LPCTSTR lpClassName,  // registered class name

  LPCTSTR lpWindowName, // window name

  DWORD dwStyle,        // window style

  int x,                // horizontal position of window

  int y,                // vertical position of window

  int nWidth,           // window width

  int nHeight,          // window height

  HWND hWndParent,      // handle to parent or owner window

  HMENU hMenu,          // menu handle or child identifier

  HINSTANCE hInstance,  // handle to application instance

  LPVOID lpParam        // window-creation data

);

3)进行消息循环

通常如下表示:

MSG msg;

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

{

TranslateMessage(&msg);//将虚拟键转换成字符消息,并投放到调用
     //线程的消息队列中,不改变原来的消息

DispatchMessage(&msg);//分派一个消息到窗口函数,实际上就是//将消息回传给操作系统,由操作系统调用窗口过程函数对消息进行处理//响应

}

Windows程序内部运行原理

其中GetMessage原型为:

BOOL GetMessage(

  LPMSG lpMsg,       // message information,是个指针,指向消息结构体

  HWND hWnd,    // handle to window,与该消息相对应的窗口句柄,//NULL,则为所有窗口

  UINT wMsgFilterMin,  // first message

  UINT wMsgFilterMax   // last message

);

If the function retrieves a message other than WM_QUIT, the return value is nonzero.

If the function retrieves the WM_QUIT message, the return value is zero. If there is

an error(比如无效的窗口句柄或lpMsg是无效的指针时), the return value is -1. 

4)窗口过程函数

LRESULT CALLBACK WindowProc(

  HWND hwnd,      // handle to window,要处理的窗口类

  UINT uMsg,      // message identifier,要处理的消息类型

  WPARAM wParam,  // first message parameter

  LPARAM lParam   // second message parameter

);

6、其它

1)用HGDIOBJ GetStockObject(int fnObject   // stock object type);

   来得到系统的标准画涮。

2Win32 Application win32 console application的区别

win32 console application基于命令行,一般用于教学,类dos界面

win32 application基于窗口,常用win32 sdkmfc等开发,实际应用的都是win32 application

3__stdcall__cdecl

    __cdeclC/C++MFC程序默认使用的调用约定,也可以在函数声明时加上__cdecl关键字来手工指定。采用__cdecl约定时,函数参数按照从右到左的顺序入栈,并且由调用函数者把参数弹出栈以清理堆栈。因此,实现可变参数的函数只能使用该调用约定。由于每一个使用__cdecl约定的函数都要包含清理堆栈的代码,所以产生的可执行文件大小会比较大。__cdecl可以写成_cdecl

    __stdcall调用约定用于调用Win32 API函数。采用__stdcal约定时,函数参数按照从右到左的顺序入栈,被调用的函数在返回前清理传送参数的栈,函数参数个数固定。由于函数体本身知道传进来的参数个数,因此被调用的函数可以在返回前用一条ret n指令直接清理传递参数的堆栈。__stdcall可以写成 _stdcall

    __fastcall约定用于对性能要求非常高的场合。__fastcall约定将函数的从左边开始的两个大小不大于4个字节(DWORD)的参数分别放在ECXEDX寄存器,其余的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的堆栈。 __fastcall可以写成_fastcall。 

       特别说明

1)在默认情况下,采用__cdecl方式,因此可以省略.

2WINAPI一般用于修饰动态链接库中导出函数

3CALLBACK仅用于修饰回调函数

4)用WM_PAINT消息来刷新窗口,UpdateWindowWM_PAINT消息直接发送给了窗口过程函数进行处理。

参考:

1VC++深入详解

2http://big5.china.com/gate/big5/ghostdepth.blog.china.com/200807/2929745.html