windows编程——窗口与消息2

来源:互联网 发布:散爆网络 编辑:程序博客网 时间:2024/06/07 02:07

消息处理函数

消息处理函数又叫窗口过程,在这个函数中,不同的消息将被switch语句分配到不同的处理程序中去。Windows的消息处理函数的原型是这样定义的:

LRESULT CALLBACK WindowProc(

HWND hwnd, //接收消息窗口的句柄

UINT uMsg, //主消息值

WPARAM wParam, //副消息值1

LPARAM lParam //副消息值2

);

消息处理函数必须按照上面的这个样式来定义,当然函数名称可以随便取。

第一次代码中的WinProc( )函数就是一个典型的消息处理函数。在这个函数中明确地处理了几个消息,分别是WM_KEYDOWN(击键)、WM_LBUTTONDOWN(鼠标左键按下)、WM_RBUTTONDOWN(鼠标右键按下)、WM_CLOSE(关闭窗口)、WM_DESTROY(销毁窗口)。值得注意的是,应用程序发送到窗口的消息远远不止以上这几条,像WM_SIZE、WM_MINIMIZE、WM_CREATE、WM_MOVE等频繁使用的消息就有几十条。在附录中可以查到Windows常见消息列表。

为了减轻编程的负担,Windows提供了DefWindowProc( )函数来处理这些最常用的消息,调用了这个函数后,这些消息将按照系统默认的方式得到处理。因此,在消息处理函数中,只须处理那些有必要进行特别响应的消息,其余的消息都可交给DefWindowProc( )函数来处理。

常用Windows函数

显示对话框

MessageBox函数可以用来显示对话框,它的原型是:

    int MessageBox(HWND hwndParent, LPCSTRlpszText, LPCSTR lpszTitle, UINT fuStyle);

       其中的四个参数依次为:窗口句柄,文字内容,标题,风格。常用风格有:MB_OKMB_OKCANCELMB_RETRYCANCELMB_YESNOMB_YESNOCANCEL,代表对话框有哪些按钮。常用返回值有IDCANCELIDNOIDOKIDRETRYIDYES,代表哪个按钮被按下。

定时器

       定时器可以使程序每隔一段时间执行一个函数。用法如下:

       SetTimer(HWND hwnd, UINT ID, UINT Elapse, TIMERPROC TimerFunc);

       四个参数依次为窗口句柄、定时器标识(同一程序内各个定时器的标识应不相同,一般从123...一直排下去)、每隔多少毫秒(千分之一秒)执行一次程序,要执行的过程。

       这个要执行的过程应这样定义:
    
void CALLBACK MyTimer(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime);

       这几个规定的参数用法在实例中会了解到,一般很少用到。

注意:定时器的优先级不高,当处理器很忙时我们需要定时执行的程序常常不能按时执行;无论你把定时器的Elapse(时间间隔)设得多小,它实际上最小只能是55ms。

得到时间

我们的程序经常需要得到当前的准确时间来完成测试速度等工作。这时我们可以使用GetTickCount(),因为该函数可以返回Windows已经运行了多少毫秒。

等待操作

很多时候,我们在程序的一些位置需要一段延时。虽然可以用for( )等循环语句实现,但不精确,而且都白白地占用了CPU时间。那么我们该调用什么语句呢?Sleep( )。括号内填入你想等待的微秒数即可。

播放声音

我们可以使用MCI来简易地实现在程序中播放MP3等声音。使用它需要预先声明,我们需要在文件头包含头文件#include<mmsystem.h>,链接函数库#pragma comment(lib, "winmm.lib")

       下面先让我们看看播放MP3的过程。首先我们要打开设备:

mciSendString("open + MP3路径 alias 音乐在程序里的代名词", NULL, 0, NULL);

       接着就可以播放MP3了:

mciSendString("play + 打开时定下的音乐在程序里的代名词", NULL, 0, NULL);

       停止播放:

              mciSendString("stop + 打开时定下的音乐在程序里的代名词", NULL, 0, NULL);

       最后要关闭设备:

             mciSendString("close + 打开时定下的音乐在程序里的代名词", NULL, 0, NULL);

  多线程编程

基础知识

       多线程编程技术在编程中是有不少应用的。举个例子,如果我们要在我们编写的游戏中使用一个超大的场景,那么我们要一边显示图形一边预读数据才能使游戏进行得平滑和流畅。那么如何实行在显示图形得同时预读数据呢?这就可以使用多线程技术。

       什么是线程?我们知道,一个程序的运行又被称为一个进程(Process),而一个进程可以拥有多个线程(Thread),它们共享进程的各种资源,帮助进程同时做几件事。每个线程都拥有一个优先级别,它决定了此线程执行的优先程度。注意在线程间切换是需要一些时间的,所以同时使用多个优先度很高的线程不是一个好主意。

       使用多线程的基本方法并不复杂,有点像使用定时器的方法。我们来看一个实例吧:

首先,给出线程函数的定义:

       void f( ) { i++; }

然后在主程序里创建一个线程:

       DWORD ThreadID;

       HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)f, NULL, 0, &ThreadID);

       CreateThread( )的原形如下:

HANDLE CreateThread(

  LPSECURITY_ATTRIBUTES lpThreadAttributes, //设定安全属性,一般NULL

  SIZE_T dwStackSize,//堆栈大小,一般给它0,即使用默认值

  LPTHREAD_START_ROUTINE lpStartAddress, //指向线程函数的指针

  LPVOID lpParameter, //线程函数使用的参数(最多一个)的指针

  DWORD dwCreationFlags, //如为CREATE_SUSPENDED则暂时挂起线程

  LPDWORD lpThreadId //返回线程的标识

);

       由于我们把dwCreationFlags设为0,现在f线程就会开始执行;如果把它设为CREATE_SUSPENDED或在此后执行了SuspendThread( hThread );(挂起进程),执行ResumeThread ( hThread );(继续挂起的进程) 可以让它继续执行。

我们可以执行SetThreadPriority(hThread, nPriority )设定线程的优先级,nPriority的可能取值有:

nPriority取值

含义

THREAD_PRIORITY_IDLE

线程为最低优先级

THREAD_PRIORITY_LOWEST

线程为很低优先级

THREAD_PRIORITY_BELOW_NORMAL

线程为较低优先级

THREAD_PRIORITY_NORMAL

线程为一般优先级

THREAD_PRIORITY_ABOVE_NORMAL

线程为较高优先级

THREAD_PRIORITY_HIGHEST

线程为很高优先级

THREAD_PRIORITY_TIME_CRITICAL

线程为最高优先级

其实线程的实际优先级还取决于进程的优先级,进程的优先级可以通过这种方法设定:

       得到进程:HANDLE hProcess = GetCurrentProcess( );

       设定进程优先级:SetPriorityClass(hProcess, dwPriorityClass );

       dwPriorityClass的各种取值意义如下表:

dwPriorityClass取值

含义

IDLE_PRIORITY_CLASS

进程为最低优先级

BELOW_NORMAL_PRIORITY_CLASS

进程为较低优先级(系统须为Win2000XP

NORMAL_PRIORITY_CLASS

进程为一般优先级

ABOVE_NORMAL_PRIORITY_CLASS

进程为较高优先级(系统须为Win2000XP

HIGH_PRIORITY_CLASS

进程为很高优先级

REALTIME_PRIORITY_CLASS

进程为最高优先级(慎用)

       一般来说,要停止一个线程应该在线程函数中执行ExitThread(返回值 );。如果在线程外需要强行停止线程,只能调用TerminateThread( hThread, 返回值 );,该函数会造成诸多不良后果,不宜使用。

协调线程

       多线程技术的真正难点在于如何协调多个线程。关键问题是如何控制各个线程对进程数据的访问。多个线程操作相同的数据时,一般是需要按顺序访问的,否则会多个线程重复控制一个变量,数据错乱。为解决这个问题,就需要引入互斥变量,让每个线程都按顺序地访问变量。

       CRITICAL_SECTION CriticalSection1; //我们假想此全局变量代表了i的使用权

       InitializeCriticalSection(&CriticalSection1);//使i成为临界资源,也就是说一次只能有一个线程访问的资源

       设置完以后,假如有第二个线程访问临界资源,就会先挂起,等待第一个线程用完临界资源、"离开"

       EnterCriticalSection(&CriticalSection1);//此语句会自动等待

       i--; //可以放心地使用i;

       使用完数据后记得离开

       LeaveCriticalSection(&CriticalSection1);

       最后要解除临界资源:

       DeleteCriticalSection(&CriticalSection1);

      还有一个就是等待另一个线程结束,这可以通过调用下面的语句实现:

WaitForSingleObject(hThread, dwMilliseconds );

其中dwMilliseconds为最多等待多少毫秒,若为INFINITE,则永远等下去。

如果等待多个线程,可以这样做:

WaitForMultipleObjects( 线程数,线程数组的指针, bWaitAll, dwMilliseconds );

       bWaitAll如果为true,此语句等待至全部线程完成;若为false,此语句等待至线程数组中任一线程完成。
 

这一章第一次看有一点印象就好,以后在实践中才能完全掌握,以后用到可以回来再看

————2014年1月23日17:44:07


0 0
原创粉丝点击