MFC编程第一节:Windows程序内部运行原理

3 篇文章 0 订阅
3 篇文章 0 订阅

第一节:Windows程序内部运行原理

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


关于API:

向下的箭头③表示应用程序可以通知操作系统执行某个具体的动作,如操作系统能够控制声卡发出声音,但它并不知道应该何时发出何种声音,需要应用程序告诉操作系统该发出什么样的声音。这个关系好比有个机器人能够完成行走的功能,但是,如果人们不告诉它往哪个方向上走,机器人是不会主动行走的。这里的机器人就是操作系统,人们就是应用程序。

 

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

 

关于消息及消息队列:

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

 

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

MSG结构定义如下:

The MSG structure contains messageinformation from a thread's message queue.

typedef struct tagMSG{     // msg

    HWND  hwnd;    

    UINT  message;

    WPARAM wParam;

    LPARAM lParam;

    DWORD time;

    POINT pt;

} MSG;

关于句柄:

n  句柄(HANDLE),资源的标识。

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

从变量的类型区分变量的用途:

int x,y;

x=30;       

y=30;                 

//x和y既可以用来表示坐标点,也可以用来表示宽度和高度,还可以用来表示身高和体重。

typedef int WIDTH

typedef int HEIGHT

WIDTH x;

HEIGHT y;

//好处:我们从变量的类型上就可以知道x和y是用来表示宽度和高度。

 

匈牙利表示法:

 

Win32asm源程序风格采用匈牙利表示法,是由Microsoft公司的程序设计人员CharlesSimonyi首创的。在匈牙利表示法中,变量名以一个或多个小写字母开始,代表变量的类型。后面附以变量的名字,变量名以意义明确的大小写混合字母序列所构成。这种方案允许每个变量都附有表征变量类型的信息。如:WORD wParam1;LONG lParam2;HANDLE hInstance。其优点:通过给每个变量名加上表示所属数据类型的前缀,从而在编译前即可防止许多常见的错误。如下面的语句看起来正确,实际不正确,但却容易漏过检查:

  Param1=Param2

  使用匈牙利表示法,就很容易查出下面的错误。

  wParam1=lParam2

  变量的前缀及含义

  前缀隐含的数据类型 说明

  b BOOL 实际为整型

  by BYTE 无符号字符

  c char 字符

  dw DWORD 无符号长型

  fn function 函数

  h HANDLE 无符号整型

  i integer 整数

  l LONG 长型

  lp Long pointer 远指针

  n Short(integer) 整型

  np Near pointer 近指针

  p pointer 指针

  s string 字符串

  sz Zero terminated string 以0结尾的字符串

  w WORD 整数或字

  x,y short X坐标和y坐标

  cx,cy short X方向长和y方向长,c代表count(量度)

  远指针

  远指针用32位值确定内存地址,它指明了内存的特定的段值和段内的偏移量。

  近指针

  近指针用16位值确定内存地址,它代表模块缺省数据段的一个偏移值。

  句柄

  句柄是窗口用来标识创建或使用应用程序的唯一的整数值。窗口要使用各种不同的句柄来标识应用程序实例、窗口、菜单、控制、分配的内存区和设备接口对象等。

  WinMain函数具有hInstance句柄参数.窗口中不仅一次能同时运行多个程序,而且能多次运行同一个应用程序,即运行多个副本,每个副本叫做一个实例。为区别实例,窗口在每次调用WinMain函数时,要提供一个不同的实例句柄,即代表句柄的不同的实际值。也就是说,一个实例是应用程序的一个单独的可执行副本,而实例句柄是唯一标识实例的整数。每当运行应用程序的新实例(一个副本)时,仅加载该应用程序的数据.这样窗口对应用程序的所有实例都使用相同代码,可以大大节省空间。

对大多数程序来说,第一个实例作用较特殊,它创建的许多资源都可以被以后所有实例使用,而不需要重新创建。

 

 

WinMain函数:

Windows程序的入口函数

WinMain

The WinMain function is called bythe system as the initial entry point for a Win32-based application.

int WINAPI WinMain(

 HINSTANCE hInstance// handle to current instance

 HINSTANCE hPrevInstance// handle to previous instance

 LPSTRlpCmdLine,     // pointer to command line

 int nCmdShow         // show state of window

);

 

Parameters

hInstance

Handle to thecurrent instance of the application.

hPrevInstance

Handle to theprevious instance of the application. For a Win32-based application, thisparameter is always NULL.

If you need todetect whether another instance already exists, create a uniquely named mutexusing theCreateMutex function.CreateMutex will succeed even if the mutex already exists, but theGetLastError function will returnERROR_ALREADY_EXISTS. This indicates that another instance of your applicationexists, because it created the mutex first.

lpCmdLine

Pointer to anull-terminated string specifying the command line for the application,excluding the program name. To retrieve the entire command line, use theGetCommandLine function.

nCmdShow

Specifies howthe window is to be shown. This parameter can be one of the following values:

Value

Meaning

SW_HIDE

Hides the window and activates another window.

SW_MINIMIZE

Minimizes the specified window and activates the top-level window in the system's list.

SW_RESTORE

Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and position (same as SW_SHOWNORMAL).

SW_SHOW

Activates a window and displays it in its current size and position.

SW_SHOWMAXIMIZED

Activates a window and displays it as a maximized window.

SW_SHOWMINIMIZED

Activates a window and displays it as an icon.

SW_SHOWMINNOACTIVE

Displays a window as an icon. The active window remains active.

SW_SHOWNA

Displays a window in its current state. The active window remains active.

SW_SHOWNOACTIVATE

Displays a window in its most recent size and position. The active window remains active.

SW_SHOWNORMAL

Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and position (same as SW_RESTORE).

 

Return Values

If the functionsucceeds, terminating when it receives a WM_QUIT message, it should return theexit value contained in that message'swParam parameter. If the functionterminates before entering the message loop, it should return zero.

Remarks

Your WinMainshould initialize the application, display its main window, and enter a messageretrieval-and-dispatch loop that is the top-level control structure for theremainder of the application's execution. Terminate the message loop when itreceives a WM_QUIT message. At that point, your WinMain should exit theapplication, returning the value passed in the WM_QUIT message'swParamparameter. If WM_QUIT was received as a result of calling PostQuitMessage,the value of wParam is the value of the PostQuitMessage function'snExitCode parameter. For more information, seeCreatinga Message Loop.

ANSIapplications can use the lpCmdLine parameter of the WinMainfunction to access the command-line string, excluding the program name. Thereason thatWinMain cannot return Unicode strings is that lpCmdLineuses theLPSTR data type, not the LPTSTR data type. The GetCommandLinefunction can be used to access Unicode strings in the command line, because ituses theLPTSTR data type.

 

窗口的创建:

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

1.设计窗口类;

2.注册窗口类; RegisterClass()

3.创建窗口; CreateWindow()

4.显示及更新窗口. ShowWindow()


(1).设计一个窗口类(给结构体WNDCLASS赋值);
typedef struct _WNDCLASS { 

    UINT   style;

    WNDPROC lpfnWndProc;

    int    cbClsExtra;

    int    cbWndExtra;

    HANDLE hInstance;

    HICON  hIcon;

    HCURSOR hCursor;

    HBRUSH hbrBackground;

    LPCTSTR lpszMenuName;

    LPCTSTR lpszClassName;

} WNDCLASS;

 

WNDCLASS wndcls;

   wndcls.cbClsExtra = 0;   //类的额外空间,设0即可

   wndcls.cbWndExtra = 0;  // 窗口的额外空间,设0

   wndcls.hbrBackground =(HBRUSH)GetStockObject(DKGRAY_BRUSH); //设置画刷颜色

   wndcls.hCursor = LoadCursor(NULL, IDC_CROSS);//鼠标类型,cross是十字型

   wndcls.hIcon = LoadIcon(NULL, IDI_ERROR);   //标题栏上图标类型

   wndcls.hInstance = hInstance;//应用程序实例句柄,已通过WinMain由OS传入

   wndcls.lpfnWndProc = WinProc;//消息处理函数(回调函数)

   wndcls.lpszClassName = "July";// 类的名字(应该是内部标识吧)

   wndcls.lpszMenuName = NULL;//菜单名,没有就写NULL

   wndcls.style = CS_VREDRAW | CS_HREDRAW; //设置窗口风格,这两个是窗口重绘

=========================tips=============================
窗口类的类型:

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

窗口过程函数:

第二个成员变量lpfnWndProc指定了这一类型窗口的过程函数,也称回调函数。回调函数的原理是这样的,当应用程序收到给某一窗口的消息时(还记得前面讲过的消息通常与窗口相关的吗?),就应该调用某一函数来处理这条消息。这一调用过程不用应用程序自己来实施,而由操作系统来完成,但是,回调函数本身的代码必须由应用程序自己完成。对于一条消息,操作系统到底调用应用程序中的哪个函数(回调函数)来处理呢?操作系统调用的就是接受消息的窗口所属的类型中的lpfnWndProc成员指定的函数。每一种不同类型的窗口都有自己专用的回调函数,该函数就是通过lpfnWndProc成员指定的。

 

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

窗口过程函数的举例:(函数头固定,函数名和变量名随意)

LRESULT CALLBACKWinProc(

  HWND hwnd,      // handle to window

  UINT uMsg,      // message identifier

  WPARAM wParam,  // first message parameter

  LPARAM lParam   // second message parameter

);

 

其中一些乱七八糟的数据类型定义参考这篇文章,或者自己查定义

http://blog.csdn.net/gneveek/article/details/7859863

 

LRESULT CALLBACKWinProc(

  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, "键%d被按下了",wParam);

            MessageBox(hwnd, szChar,"July", MB_OK);

            break;

   case WM_LBUTTONDBLCLK:

            MessageBox(hwnd, "双击!","July", MB_OK);

            break;

   case WM_LBUTTONDOWN:

            MessageBox(hwnd, "单击!","July", MB_OK);

            HDC hdc;

            hdc = GetDC(hwnd);

            TextOut(hdc,0,50,"呵呵中华人民共和国",strlen("呵呵中华人民共和国"));

            ReleaseDC(hwnd,hdc);

            break;

   case WM_PAINT:

            HDC hDc;

            PAINTSTRUCT ps;

            hDc = BeginPaint(hwnd, &ps);

            TextOut(hDc, 0,0,"周岩周岩周岩",strlen("周岩周岩周岩"));

            EndPaint(hwnd, &ps);

            break;

   case WM_CLOSE:

            if(IDYES == MessageBox(hwnd,"是否真的要结束","July", MB_YESNO))

            {

                     DestroyWindow(hwnd);

            }

            break;

   case WM_DESTROY:

            PostQuitMessage(0);

            break;

   default:

            returnDefWindowProc(hwnd,uMsg,wParam,lParam);

            break;

   }

}

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

(3). 创建窗口:

HWND hwnd =CreateWindow("July", "July's title.",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,

                  CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL);

CreateWindow

The CreateWindowfunction creates an overlapped, pop-up, or child window. It specifies thewindow class, window title, window style, and (optionally) the initial positionand size of the window. The function also specifies the window's parent orowner, if any, and the window's menu.

HWND CreateWindow(

  LPCTSTR lpClassName// pointer to registered class name

  LPCTSTR lpWindowName, // pointer towindow name

  DWORD dwStyle,        // window style

  int x,                // horizontal position ofwindow

  int y,                // vertical position ofwindow

  int nWidth,           // window width

  int nHeight,          // window height

  HWND hWndParent,      // handle to parent or ownerwindow

  HMENU hMenu,          // handle to menu orchild-window identifier

  HANDLE hInstance,     // handle to applicationinstance

  LPVOID lpParam        // pointer to window-creation data

);

 

 

(4).  显示及更新窗口。
ShowWindow(hwnd, SW_SHOWNORMAL); //第二个参数是显示窗口的方式,有最大化最小化,再常显示这些选项,这里我们写正常显示。

   UpdateWindow(hwnd);

 

以下是这节课的代码(孙鑫MFC):

#include <windows.h>
#include <stdio.h>

LRESULT CALLBACK WinProc(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
);


int WINAPI WinMain(
  HINSTANCE hInstance,
  HINSTANCE hPreInstance,
  LPSTR lpCmdLine,
  int nShowCmd)
{
	WNDCLASS wndcls;
	wndcls.cbClsExtra = 0;
	wndcls.cbWndExtra = 0;
	wndcls.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH);
	wndcls.hCursor = LoadCursor(NULL, IDC_CROSS);
	wndcls.hIcon = LoadIcon(NULL, IDI_ERROR);
	wndcls.hInstance = hInstance;
	wndcls.lpfnWndProc = WinProc;
	wndcls.lpszClassName = "July";
	wndcls.lpszMenuName = NULL;
	wndcls.style = CS_VREDRAW | CS_HREDRAW;

	RegisterClass(&wndcls);

	HWND hwnd = CreateWindow("July", "July's title.",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,
		CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL);

	ShowWindow(hwnd, SW_SHOWNORMAL);
	UpdateWindow(hwnd);

	MSG msg;
	while(GetMessage(&msg, NULL,0,0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return 0;
}
int xLocation = 0;
int yLocation = 50;

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, "键%d被按下了", wParam);
		MessageBox(hwnd, szChar, "July", MB_OK);
		break;
	case WM_LBUTTONDBLCLK:
		MessageBox(hwnd, "双击!", "July", MB_OK);
		break;
	case WM_LBUTTONDOWN:
		MessageBox(hwnd, "单击!", "July", MB_OK);
		HDC hdc;
		hdc = GetDC(hwnd);
		TextOut(hdc,0,50,"呵呵中华人民共和国",strlen("呵呵中华人民共和国"));
		ReleaseDC(hwnd,hdc);
		break;
	case WM_PAINT:
		HDC hDc;
		PAINTSTRUCT ps;
		hDc = BeginPaint(hwnd, &ps);
		TextOut(hDc, 0,0,"周岩周岩周岩", strlen("周岩周岩周岩"));
		EndPaint(hwnd, &ps);
		break;
	case WM_CLOSE:
		if(IDYES == MessageBox(hwnd,"是否真的要结束", "July", MB_YESNO))
		{
			DestroyWindow(hwnd);
		}
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hwnd,uMsg,wParam,lParam);
		break;
	}
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值