ShowWindow后面UpdateWindow的作用

#include <Windows.h>
#include <stdio.h>//sprintf

//对调函数:窗口过程函数,由操作系统调用
LRESULT	CALLBACK WinProc(HWND hwnd, UINT  uMsg,WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(
	HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPSTR lpCmdLine,
	int nCmdShow
	)
{
	//1.定义该窗口类
	WNDCLASS wndcls;
	wndcls.cbClsExtra = 0;
	wndcls.cbWndExtra = 0;
	wndcls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);//窗口背景画刷子
	wndcls.hCursor = LoadCursor(NULL,IDC_ARROW);    //加载鼠标形状 
	wndcls.hIcon  = LoadIcon(NULL,IDI_APPLICATION); //窗口的最小化图标为缺省图标   
	wndcls.hInstance  = hInstance;   //当前实例句柄
	wndcls.lpfnWndProc = WinProc; //回调函数,用于处理消息相应函数
	wndcls.lpszClassName = LPCSTR("UpdateWindow_Test");//窗口类的名字
	wndcls.lpszMenuName  = NULL;//菜单名称
	wndcls.style = CS_HREDRAW | CS_VREDRAW;
	//2.注册该窗口类
	RegisterClass(&wndcls);
    //3.实例化该窗口(创建该窗口)
	HWND hwnd;
	hwnd = CreateWindow(LPCSTR("UpdateWindow_Test"),LPCSTR("UpdateWindow的作用测试"),WS_OVERLAPPEDWINDOW,\
		   800,20,300,600,NULL,NULL,hInstance,NULL);
		
	//4.显示窗口
	//不发送消息,当消息队列为空时,Windows会自动探测窗口的内容是否需要重画、以及需要重画的区域组成,
	//并且在消息队列中放置一个WM_PAINT
	ShowWindow(hwnd,SW_SHOWNORMAL);
	//假若当前被标记为重画的区域存在(不存在的话它什么也不做),
	//UpdateWindow函数可使WM_PAINT被直接发送到目标窗口,从而导致窗口立即重绘。
	//SendMessage,发送的消息不需要进入到消息队列,直接由WINDOWS调用窗口过程。
	//窗口过程完成刷新以后立刻退出,WINDOWS将控制返回给程序中UpdateWindow调用之后的语句。
	UpdateWindow(hwnd);
	//5.消息循环
	MSG msg;
	while(GetMessage(&msg,NULL,0,0))//主要部分
	{
	    TranslateMessage(&msg);
	    DispatchMessage(&msg);
	}

    return 0;
}
LRESULT	CALLBACK WinProc(
	HWND hwnd,
    UINT  uMsg,
    WPARAM wParam,  // first message parameter
    LPARAM lParam   // second message parameter
	)
{
	static int n = 0;//用于查看进入重绘的次数
	char szChar[100] = {0};
	static int mLine = 40;//控制打印的位置
	switch(uMsg)
	{
	case WM_PAINT:
		n++;
		sprintf(szChar,"第%d次进入WM_PAINT!",n);
		mLine += 20;
		HDC hDC;
		PAINTSTRUCT ps;
		//BeginPaint的一个重要作用,就是在它返回的DC里,用原来标记的区域制作一个剪裁区域(ClipRegion),
		//从而使你的所有重画操作都被限定在这一个区域中。EndPaint之后,重画区域的标记被取消。
		//我们自己也需要更新窗口的显示内容,这时候也是通过调用InvalidateRect来做标记。
		//不过,很多人在这种情况下习惯于将整个窗口统统Inalidate做标记,方便但是不好。
		//除非你需要更新的内容波及到整个窗口,否则应该仅仅把需要改变的那部分Invalidate。
		//GetDC不能取消该标记区域,会造成无休止的重绘过程
		hDC=BeginPaint(hwnd,&ps);
		TextOut(hDC,0,mLine,LPCSTR(szChar),strlen(szChar));
	  	EndPaint(hwnd,&ps);
		break;
	case WM_LBUTTONDOWN:
		HDC hdc;
		hdc=GetDC(hwnd);
		TextOut(hdc,0,0,LPCSTR("鼠标左键被按下"),strlen("鼠标左键被按下"));
		ReleaseDC(hwnd,hdc);
		break;
	
	case WM_CLOSE:
		if(IDYES==MessageBox(hwnd,LPCSTR("退出该测试程序?"),LPCSTR("weixin"),MB_YESNO))
		{
			DestroyWindow(hwnd);//发送WM_DESTROY消息
		}
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:          //必须有的,缺省的窗口处理过程
		return DefWindowProc(hwnd,uMsg,wParam,lParam);
	}
	return 0;

}

//UpdateWindow的作用,是使得窗口立即被重绘,而不是去等待那个不确定的消息队列。

CALLBACK的调用方式:_stdcall。编译器默认的是__cdecl,所以在回掉函数前面显示说明。
1、__stdcall调用约定相当于16位动态库中经常使用的PASCAL调用约定。在32位的VC++5.0中PASCAL调用约定不再被支持(实际上它已被定义为__stdcall。除了__pascal 外,__fortran和__syscall也不被支持),取而代之的是__stdcall调用约定。两者实质上是一致的,即函数的参数自右向左通过栈传递,被调用的函数在返回前清理传送参数的内存栈,但不同的是函数名的修饰部分(关于函数名的修饰部分在后面将详细说明)。
_stdcall是Pascal程序的缺省调用方式,通常用于Win32   Api中,函数采用从右到左的 压栈方式,自己在退出时清空堆栈。VC将函数编译后会在函数名前面加上下划线前缀,在函数名后加上"@"和参数的字节数。   
2、C调用约定(即用__cdecl关键字说明)按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于传送参数的内存栈是由调用者来维护的(正因为如此,实现可变参数的函数只能使用该调用约定)。另外,在函数名修饰约定方面也有所不同。
_cdecl是C和C++程序的缺省调用方式。每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。函数采用从右到左的压栈方式。VC将函数编译后会在函数名前面加上下划线前缀。是MFC缺省调用约定。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值