多线程电梯调度仿真程序

 
程序名称:多线程电梯调度仿真程序

程序说明:利用多线程同步技术模拟电梯调度算法。主要用到了事件内核对象、临界区来让电梯服务线程、楼层请求正确地对请求队列进行访问、以及修改。

作者:Seed-L

完成日期:2012-3-4

特别鸣谢:ICE-Light!s 童鞋(阿池)


 

 

主要文件:

 

/*	-------------------------------------------------------------------------------------
	*	Copyright(c) 2012-3-6	Seed-L
	
	*	All rights reserved.

	*	文件名称:	LiftDemo.h

	*	简要描述:	定义各类数据结构、常量

	*	作者:Seed-L

	*	完成日期:2012-3-4
	-------------------------------------------------------------------------------------	*/



#ifndef LIFTDEMO_H_
#define LIFTDEMO_H_

#include"help.h"
#include<windows.h>
#include<bitset>
#include<string>


using std::bitset ; 
using std::string ;


//楼层请求的类型:电梯外、电梯内、没有请求
//本来定义的名称是OUT、IN的简单名称,结果编译不通过,找了也挺久的错误
//后来发现原来OUT 和 IN 是库里面已经定义好的。但是错误提示又没有提示说重定义
enum eReqStatus { LIFTOUT = 0 ,LIFTIN = 1 , NOTREQ = 2} ;   


//电梯方向:
//貌似发现LIFTSTOP 没有用上
enum eLiftDir	{  LIFTUP , LIFTDOWN ,LIFTSTOP} ; 

const int DEFAULT_FLOOR_NUM = 5 ;				//楼层总楼
const int TOPFLOOR = 5 ;						//顶层
const int BOTTOMFLOOR = 1 ;						//底层


//动画电梯结构
typedef struct LiftStruct
{
	HWND hwnd ;			//电梯轨道
	int speed ;
	RECT rect ;			//相对自己的窗口区
	RECT realrect ;		//相对窗口客户区
	int pos ;			//电梯的位置

}	LiftStruct  , *PLiftStruct ;

//动画楼层结构
typedef struct FloorStruct
{
	HWND hwndDisplay ;		//上下楼请求绘制窗口句柄
	HWND hwndLog ;			//显示请求的窗口,文字描述
	RECT rect ;				
	RECT realrect ;			//相对窗口窗户区的坐标
	POINT  pt[3] ;			//绘制三角形的三个点的坐标
	eLiftDir direction ;
}   FlooStruct ,PFloorStruct;



class LiftDemoS
{

public	:

	//本来是私有函数
	inline void EnterLiftCs() { EnterCriticalSection(&m_Cs)  ; } 

	inline void LeaveLiftCs() { LeaveCriticalSection(&m_Cs)  ; } 		

	inline eLiftDir GetLiftDirection() { return m_eLiftCurDir ; } 
	
	inline int GetLiftCurFloor() {	return m_iLiftCurFloor ;}

	inline int GetLiftCurDesNum() { return m_bsReqQueue.count() ; }

	inline int GetLiftNextDes() { return m_iLiftNextDes ;}

	inline bitset<DEFAULT_FLOOR_NUM+1> GetLiftDesFloor() { return m_bsReqQueue ;}

	inline bitset<DEFAULT_FLOOR_NUM+1> GetUpDirQueue() { return m_bsUpDirQueue ;}

	inline bitset<DEFAULT_FLOOR_NUM+1> GetDownDirQueue() { return m_bsDownDirQueue ;}

	void LiftReachAndWait(int iNum) ;

	int LiftChangeDirection( int* iOldDir)  ;

	LiftDemoS() ;

	virtual ~LiftDemoS() ;

private :

	HANDLE  m_hReqHappenEvents[DEFAULT_FLOOR_NUM] ;		//某楼层发出请求事件对象

	HANDLE	m_hLiftReachEvents[DEFAULT_FLOOR_NUM] ;		//电梯到达楼层时,通知楼层事件

	HANDLE  m_LiftGoEvent ;								//用来告知电梯可以起动

	CRITICAL_SECTION	m_Cs ;							//互斥段,用来修改队列时使用	

	CRITICAL_SECTION    m_ResAllEventCs ;

	CRITICAL_SECTION	m_InsertReqCs ;

private	:
	
	inline void InitLiftCs() 
	{ 
		InitializeCriticalSection(&m_Cs) ; 
		InitializeCriticalSection(&m_ResAllEventCs) ;
		InitializeCriticalSection(&m_InsertReqCs) ;
	}

	inline void DeleteLiftCs() 
	{ 
		DeleteCriticalSection(&m_Cs) ; 
		DeleteCriticalSection(&m_ResAllEventCs) ;
		DeleteCriticalSection(&m_InsertReqCs) ;
	}

	void CreateLiftEvent()  ;

public :

	//分两种
	//第一种是电梯外请求,第一个参数代表请求的状态,第二个请求代表发生请求的楼层
	//第二个是电梯内请求,第一个参数代表请求的状态是电梯内的,第二个请求代表里面发生的楼层

	bool SetFloorReq(eReqStatus eStatus , bitset<DEFAULT_FLOOR_NUM+1> &bsFloor, int iFloorNum , eLiftDir eWantDir) ;  

	bool ReSetFloorReq(eReqStatus &eStatus , int &biFloor) ; 

	void LiftSetGoOnEvent() ;
	
	void LiftResetGoOnEvent() ;

	void ResetAllEvents() ;

	inline void EnterInsertReqCs() { EnterCriticalSection(&m_InsertReqCs)  ; } 

	inline void LeaveInsertReqCs() { LeaveCriticalSection(&m_InsertReqCs)  ; } 

private	:

	eLiftDir m_eLiftCurDir ;				//电梯此时的方向,转向有用

	int m_iLiftCurFloor ;			//电梯此时所在楼层,请求发生时,用来和这一个比较,
									//以便决定放入到上升队列,还是下降队列
	int m_iLiftNextDes ;			//下一站

	bitset<DEFAULT_FLOOR_NUM+1> m_bsReqQueue ;

	bitset<DEFAULT_FLOOR_NUM+1> m_bsUpDirQueue ;   //1为向上,0为向下
												   //将这一个原来的方向队列,变为上升队列
												   //某位的1,表示某楼层要向上,0表示没有请求,或者向下

	bitset<DEFAULT_FLOOR_NUM+1> m_bsDownDirQueue ; //新增的一个向下请求队列
												  //某位的1,表示某楼层要向下,0表示没有请求,或者向上

	bool m_fTurnToFindFloor ;

	bool m_fAcceptOppReq ;


} ;
#endif


 

 

/*	-------------------------------------------------------------------------------------
	*	Copyright(c)	2012-3-6	Seed-L
	
	*	All rights reserved.

	*	文件名称:	Lift.cpp

	*	简要描述:	程序主要框架

	*	作者:		Seed-L

	*	完成日期:	2012-3-4
	-------------------------------------------------------------------------------------	*/

#include"help.h"
#include"LiftDemo.h"
#include<tchar.h>
#include<windowsx.h>
#include<windows.h>
#include<process.h>
#include<Commctrl.h>
#include<time.h>
#include"resource.h"




/*核心对象区*/
LiftDemoS Lift ;

HINSTANCE g_hInst ;			//实例句柄


/*线程相关区*/
HANDLE g_hThreads[DEFAULT_FLOOR_NUM + 1] ;

int g_nNumThreads = 0 ;

/*测试统计转向次数*/
int iTurnDirCount = 0 ;

/*一些全局变量*/
int iFinishCount = 0 ;		//用于统计完成请求数窗口
int iLiftSize = 0 ;			//用于保存电梯的大小,画图时所用
int iListViewIndex = 0 ;	//将日志记录插入到列表视图控件的索引
int iLiftSpeed = 25 ;		//设置电梯的速度,默认值为25
int iReqSpeed = 7000 ;		//楼层产生请求的速度,默认值为7000


/*布尔变量区*/
volatile long  g_fShutDown = FALSE ;	//volatile用于防止编译器优化这,产生未知错误
bool g_fInsertReq = false ;				//用于判断电梯在上升途中是否产生了优先级更高的请求
bool g_fSuspend = false ;				//用于判断暂停按钮是否按下

bitset<DEFAULT_FLOOR_NUM+1> g_bsDrawDir ;  //用于判断决定是否重绘三角形(上升或者下降请求)

/*全局句柄变量区*/
HWND g_HwndMain ;				//程序主窗口
HWND g_HwndListView ;			//列表视图控件窗口
HWND g_HwndDesFloor ;			//电梯内控件窗口
HWND g_HwndDir ;				//电梯方向窗口
HWND g_HwndNextDesFloor ;		//下一站窗口
HWND g_HwndFinishCount ;		//统计完成请求窗口
HWND g_HwndLiftSpeed ;			//电梯速度窗口
HWND g_HwndReqSpeed ;			//楼层请求窗口
HWND g_HwndMainStop ;			//停止按钮



//RECT g_DlgClientRect ;
//RECT g_rcDlgRealRect ;

/*电梯动画显示区*/
FloorStruct g_fsFloor[DEFAULT_FLOOR_NUM] ;		//楼层显示结构
RECT g_rcFloor ;								//某楼层的坐标,用来计算电梯的大小,画图所用
LiftStruct g_lsLift ;							//电梯显示结构
int g_FloorPos[DEFAULT_FLOOR_NUM] ;				//每一层楼的坐标



/*主要函数声明区*/
DWORD LiftSeverThread(PVOID pvParam) ;										//电梯服务函数
DWORD LiftClientThread(PVOID pvParam) ;										//楼层请求函数
INT WINAPI Dlg_Proc(HWND hwnd ,UINT uMsg, WPARAM wParam , LPARAM lParam) ;	//主窗口消息处理函数
BOOL CALLBACK AboutDlgProc(HWND,UINT,WPARAM,LPARAM) ;				

/*消息处理宏对应消息处理函数区*/
BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus,LPARAM lParam) ;
void Dlg_OnPaint(HWND hwnd) ;
void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtl , UINT codeNotify) ;


/*有关按钮消息处理函数*/
void OnStart() ; 
void OnStop() ;

/*画三角形的函数,也就是上下楼请求*/
void Triangle(HDC hdc,POINT pt[]) ;





/*	-------------------------------------------------------------------------------------
	*	函数名称:	_tWinMain

	*	功能描述:	作为程序的入口点函数,生成主窗口,让各线程安全退出,以及关闭内核对象
					程序的主框架取自《Windows核心编程 5th》一书

	*	参数列表:	这一个略

	*	返回结果:	这一个略,呵呵
	-------------------------------------------------------------------------------------	*/

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstanec , 
					 LPTSTR lpCmdLind,int nCmdShow) 
{	
	g_hInst = hInstance ;			//方便后面使用

	DialogBox(hInstance,MAKEINTRESOURCE(IDD_LIFTDEMO),NULL, Dlg_Proc) ;

	InterlockedExchange(&g_fShutDown,TRUE) ;   //VC6下要转型(long *)

	WaitForMultipleObjects(g_nNumThreads,g_hThreads,TRUE,INFINITE) ;

	while(g_nNumThreads--)						//关闭句柄
	{
		CloseHandle(g_hThreads[g_nNumThreads]) ;
	}

	MessageBox(NULL,"程序结束","测试程序是否死锁",MB_OK) ;			//测试死锁

	return (0) ;
}



/*	-------------------------------------------------------------------------------------
	*	函数名称:	LiftSeverThread

	*	功能描述:	作为电梯线程的入口函数,处理楼层的请求,更新相应窗口的信息

	*	参数列表:	这一个略,呵呵

	*	返回结果:	0
	-------------------------------------------------------------------------------------	*/

DWORD LiftSeverThread(PVOID pvParam)
{

	Sleep(2000) ;

	eLiftDir LiftCurDir = Lift.GetLiftDirection() ;  

	TCHAR szDesFloor[MAX_PATH] ;
	TCHAR szDir[10] ;
	TCHAR szCount[10] ;

	bitset<DEFAULT_FLOOR_NUM+1> btLiftInReq ;
	bitset<DEFAULT_FLOOR_NUM+1> btUpDirQueuue ;
	bitset<DEFAULT_FLOOR_NUM+1>	btDownDirQueue ;

	string strLiftInReq ;		//保存电梯内所有的请求

	int i = 0 ;

	int iLiftCurFloor = 1 ;

	int iLiftDesFloor = 0 ; 

	int iSleepTime = 0 ; 

	eReqStatus eStatus = LIFTOUT ;

	int bsFloor ;

	eLiftDir iWantDir = LIFTDOWN ;

	eLiftDir eLiftCurDir = LIFTUP ;

	while((PVOID)1 != InterlockedCompareExchangePointer((PVOID *)&g_fShutDown,(PVOID)0,(PVOID)0))
	{	

		if(!Lift.ReSetFloorReq(eStatus,bsFloor))
		{
			continue ;   //显示错误
		}
		else
		{
			iLiftCurFloor = Lift.GetLiftCurFloor() ;
			iLiftDesFloor = Lift.GetLiftNextDes() ;

			eLiftCurDir = Lift.GetLiftDirection() ;

			iSleepTime = ( iLiftDesFloor > iLiftCurFloor ) ? (iLiftDesFloor - iLiftCurFloor ) :(iLiftCurFloor - iLiftDesFloor) ;

			//Sleep( iSleepTime * 2000) ;  //这里挂了,因为下楼的时候,传了一个负数,卡死了
			//必须停止两秒以上,不然的话,就会出现系统BUG

			wsprintf(szDesFloor,"%d",iLiftDesFloor) ;

			SetWindowText(g_HwndNextDesFloor, szDesFloor) ;

			btLiftInReq = Lift.GetLiftDesFloor() ;

			Lift.EnterLiftCs() ;  //本来是私有的

			btUpDirQueuue = Lift.GetUpDirQueue() ;
			btDownDirQueue = Lift.GetDownDirQueue() ;

			for(i = 1 ; i < DEFAULT_FLOOR_NUM + 1 ; i++)
			{
				if(btUpDirQueuue.test(i) && eLiftCurDir == LIFTUP && (iLiftCurFloor <=  i))
				{
					wsprintf(szDesFloor," %d 楼",i) ;
					strLiftInReq += szDesFloor ;
				}
				else if(btDownDirQueue.test(i) && eLiftCurDir == LIFTDOWN && (iLiftCurFloor >= i))
				{
					wsprintf(szDesFloor," %d 楼",i) ;
					strLiftInReq += szDesFloor ;
				}
			}

			SetWindowText(g_HwndDesFloor,strLiftInReq.c_str()) ;
			

			Lift.LeaveLiftCs() ;

			strLiftInReq.clear() ;

			//插入事件日志
			LVITEM lvitem;  
            lvitem.mask=LVIF_TEXT;  
            lvitem.cchTextMax=MAX_PATH;  
            lvitem.iSubItem=0;  
			lvitem.pszText = TEXT("电梯");  
			lvitem.iItem = iListViewIndex ;//插入第几行,从0开始   
              
            ListView_InsertItem(g_HwndListView,&lvitem); 
			
			wsprintf(szDesFloor,"下一站目的地为 %d 楼",iLiftDesFloor) ;

			ListView_SetItemText(g_HwndListView,lvitem.iItem,1,szDesFloor);  


			iListViewIndex++ ;

			if(LIFTUP == Lift.GetLiftDirection())
			{
				wsprintf(szDir,"%s","上升") ;

				SetWindowText(g_HwndDir,szDir) ;

				while(g_lsLift.pos >= g_FloorPos[iLiftDesFloor-1] && !g_fInsertReq)//while(!g_fInsertReq)上升过程如果有中途插入的请求,则跳到下一次循环
				{
					Lift.EnterInsertReqCs() ;   //互斥
					g_lsLift.pos -= 1 ;
					Lift.LeaveInsertReqCs() ;

					InvalidateRect(g_HwndMain,&g_lsLift.realrect,TRUE);  //少了这一句,电梯则不会上升

					Sleep(g_lsLift.speed) ;
				}

				if(g_fInsertReq)		//有插入请求,跳到下一次循环
				{
					g_fInsertReq = false ;
					continue ;
				}

			}
			else if(LIFTDOWN == Lift.GetLiftDirection() )
			{
				wsprintf(szDir,"%s","下降") ;

				SetWindowText(g_HwndDir,szDir) ;

				while(g_lsLift.pos <= g_FloorPos[iLiftDesFloor-1] && !g_fInsertReq )
				{
					Lift.EnterInsertReqCs() ; //互斥
					g_lsLift.pos += 1 ;
					Lift.LeaveInsertReqCs() ;
		
					InvalidateRect(g_HwndMain,&g_lsLift.realrect,TRUE);

					Sleep(g_lsLift.speed) ;
				}

				if(g_fInsertReq)
				{
					g_fInsertReq = false ;
					continue ;
				}
			}

			//这里用iLiftCurFloor代替
			Lift.LiftReachAndWait(iLiftDesFloor) ;  //电梯到达目标楼层,触发电梯到达事件

			/*统计一下电梯运行了多少次*/
			iFinishCount++ ;

			wsprintf(szCount,"%d",iFinishCount) ;

			SetWindowText(g_HwndFinishCount,szCount) ;

			continue ;
		}
	}


	Lift.ResetAllEvents() ;

	return (0) ;
}



/*	------------------------------------------------------------------------------------
	*	函数名称:	LiftClientThread

	*	功能描述:	产生请求,请求有两种,一种是电梯外的请求,也就是上楼,下楼请求。另外
					一种是电梯内的请求,也就是电梯应该前行的目的地。对于楼层的这两种请求,
					我都做简化,呵呵,有点懒。对于电梯外的请求,我做的简化就是,每一层产
					生请求时,有且只有一种请求,也就是要么上楼,要么下楼。不过,如果要实
					现两个方向的请求也不难。对于电梯内的请求,我做的简化就是,电梯内产生
					的目的地一定是电梯此时方向可以到达的,比如电梯在2楼,方向向上2楼的人
					只能产生到3、4、5楼的请求,而不会产生去1楼的请求,因为这不符合逻辑,
					呵呵,虽然现实生活中真的有人这样做。

	*	参数列表:	略

	*	返回结果:	0				
	------------------------------------------------------------------------------------	*/

DWORD LiftClientThread(PVOID pvParam)   //添加一个对g_fInsertReq处理
{

	int iFloorNum = PtrToUlong(pvParam) ;

	TCHAR *szpUpDirReq = TEXT("上楼请求");
	TCHAR *szpDownDirReq = TEXT("下楼请求");

	Sleep(1000  * (5 - iFloorNum + 1 )) ;

	int iWantFloorNum = 0 ; ;

	HWND hwndLV = GetDlgItem(g_HwndMain,IDC_LIST_LIFTLOG) ;   //列表控件的句柄

	eReqStatus eStatus = LIFTOUT ;

	bool IsTopOrBottom = false ;

	eLiftDir iWantDir = LIFTDOWN ;   //

	bitset<DEFAULT_FLOOR_NUM+1> bsFloor ;

	srand(time(0)) ;  //产生随机数

	if(TOPFLOOR == iFloorNum)
	{
		iWantDir = LIFTDOWN ;
		IsTopOrBottom = true ;
	}
	else if(BOTTOMFLOOR == iFloorNum)
	{
		iWantDir = LIFTUP ;
		IsTopOrBottom = true ;
	}

	while((PVOID)1 != InterlockedCompareExchangePointer((PVOID *)&g_fShutDown,(PVOID)0,(PVOID)0))
	{
		if(!IsTopOrBottom)
		{
			iWantDir = (eLiftDir)(rand() % 3 );   //产生3个状态,0 1 2 分别代表停上下
		}

		if(NOTREQ == iWantDir)  //这里应该是判断是否等于LIFTSTOP,而不是NOTREQ
		{
			Sleep(5000) ;
			continue ;
		}
		else if(LIFTOUT == eStatus)
		{
			bsFloor.set(iFloorNum) ; 

			if(iWantDir == LIFTUP)
			{
				SetWindowText(g_fsFloor[iFloorNum-1].hwndLog,szpUpDirReq) ;

				g_fsFloor[iFloorNum-1].direction = LIFTUP ;

				g_bsDrawDir.set(iFloorNum) ;

//				InvalidateRect(g_HwndMain,&g_fsFloor[iFloorNum-1].realrect,TRUE);
			}
			else
			{
				SetWindowText(g_fsFloor[iFloorNum-1].hwndLog,szpDownDirReq) ;

				g_fsFloor[iFloorNum-1].direction = LIFTDOWN ;

				g_bsDrawDir.set(iFloorNum) ;

	//			InvalidateRect(g_HwndMain,&g_fsFloor[iFloorNum-1].realrect,TRUE);

			}


			InvalidateRect(g_HwndMain,&g_fsFloor[iFloorNum-1].realrect,TRUE);

			Lift.SetFloorReq(eStatus,bsFloor,iFloorNum,iWantDir) ;  //这里会阻塞//

			g_bsDrawDir.reset(iFloorNum) ;  //进入电梯之后,不用画

			eStatus = LIFTIN ;  //表明已经进入电梯

			bsFloor.reset() ;

			if(LIFTUP == iWantDir)
			{
				int iDesNum = (rand()% (DEFAULT_FLOOR_NUM - iFloorNum)) + 1 ;   //如果是上升,总共可以产生这么多个请求

				for(int i = 0 ; i < iDesNum ; i++)
				{
					iWantFloorNum = (rand() % (TOPFLOOR- iFloorNum) )+ iFloorNum ;

					if(iFloorNum == iWantFloorNum && iFloorNum < 5)
					{
						iWantFloorNum++ ;
					}

					bsFloor.set(iWantFloorNum) ;   //原来里面这个(rand() % (TOPFLOOR- iFloorNum) )+ 1
				}//for

				
				g_bsDrawDir.reset(iFloorNum) ;  //进入电梯之后,不用画

	

	//			InvalidateRect(g_HwndMain,&g_fsFloor[iFloorNum-1].realrect,TRUE);

				InvalidateRect(g_HwndMain,NULL,TRUE) ;   //重画整个窗口

				Lift.SetFloorReq(eStatus,bsFloor,iFloorNum,iWantDir) ; //触发电梯继续事件	

				SetWindowText(g_fsFloor[iFloorNum-1].hwndLog,TEXT("")) ;		

				eStatus = LIFTOUT ;    //重置人的状态,表明请求是电梯外的

			}//if
			else if(LIFTDOWN == iWantDir)  //下楼
			{
				int iDesNum = rand()% (iFloorNum - BOTTOMFLOOR) + 1 ;	

				for(int i = 0 ; i < iDesNum ; i++)
				{
					iWantFloorNum = (rand() % (iFloorNum - BOTTOMFLOOR) ) + 1 ;

					if(iFloorNum == iWantFloorNum && iFloorNum > 1)
					{		
						iWantFloorNum-- ;
					}//if

					bsFloor.set(iWantFloorNum) ;   //原来里面这个(rand() % (iFloorNum - BOTTOMFLOOR) )+ 1 
				}//for

				Lift.SetFloorReq(eStatus,bsFloor,iFloorNum,iWantDir) ;

				g_bsDrawDir.reset(iFloorNum) ;  //进入电梯之后,不用画

				InvalidateRect(g_HwndMain,&g_fsFloor[iFloorNum-1].realrect,TRUE);

		//		InvalidateRect(g_HwndMain,NULL,TRUE) ; 

				SetWindowText(g_fsFloor[iFloorNum-1].hwndLog,TEXT("")) ;

				eStatus = LIFTOUT ;

			}//else if

		}//else if			


		bsFloor.reset() ;

		Sleep(iReqSpeed * ( ( rand() % iFloorNum) + 1)) ;	

	}  //while


	Lift.ResetAllEvents() ;

	return 0 ;
}


/*	-------------------------------------------------------------------------------------
	*	函数名称:	Dlg_Proc

	*	功能描述:	主窗口的消息处理处理,分发消息,实现对各消息的处理。这一消息处理函数框
					架取自《Windows核心编程 5th》一书
					这一部分使用了消息处理宏,简化工作量。其中的chHANDLE_DLGMSG是取自核心
					编程一书,源码可以在那本书看到。定义相关消息的处理函数时,只需对那个消
					息点击右击,转到其定义,便可以看到其函数的原型。
					例如 void Cls_OnPaint(HWND hwnd) 对应HANDLE_WM_PAINT

	*	参数列表:	这一个略,呵呵

	*	返回结果:	略
	-------------------------------------------------------------------------------------	*/

INT WINAPI Dlg_Proc(HWND hwnd ,UINT uMsg, WPARAM wParam , LPARAM lParam)
{
	switch(uMsg)
	{			
		chHANDLE_DLGMSG(hwnd,WM_INITDIALOG,Dlg_OnInitDialog) ;
		chHANDLE_DLGMSG(hwnd,WM_COMMAND,	Dlg_OnCommand ) ;
		chHANDLE_DLGMSG(hwnd,WM_PAINT , Dlg_OnPaint) ;      //不要乱用,会占用过多的CPU
	}

	return (FALSE)  ;
}



/*	-------------------------------------------------------------------------------------
	*	函数名称:	Dlg_OnInitDialog

	*	功能描述:	初始化各窗口句柄、电梯速度、电梯大小、电梯轨道、楼层相对窗口客户区的坐
					标,设置窗口属性等。

	*	参数列表:	略

	*	返回结果:	略
	-------------------------------------------------------------------------------------	*/

BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus,LPARAM lParam)
{
	/*初始化对话框,得到对话框窗口句柄*/
	HMENU  hMenu ;

	g_HwndMain = hwnd ;

//	GetClientRect(g_HwndMain,&g_DlgClientRect) ;

	g_HwndMainStop = GetDlgItem(g_HwndMain,IDC_BUTTON_STOP) ;

	EnableWindow(g_HwndMainStop,false) ;

	chSETDLGICONS(g_HwndMain,IDI_ICONLIFT) ;		//图标

	hMenu = LoadMenu(g_hInst,MAKEINTRESOURCE(IDR_MENULEFT)) ;

	SetMenu(hwnd,hMenu) ;

	SetWindowLong(g_HwndMain,GWL_STYLE,WS_OVERLAPPEDWINDOW &~ WS_MAXIMIZEBOX ) ;  //除去窗口最大化效果


	/*视图控件*/
	LVCOLUMN LvC ; 

	TCHAR szTextLift[] = "电梯"  ;

	TCHAR szTextEvent[] = "事件" ;


	/*全局电梯状态窗口初始化*/
	g_HwndListView = GetDlgItem(hwnd,IDC_LIST_LIFTLOG) ;

	g_HwndDesFloor = GetDlgItem(hwnd,IDC_EDIT_DES) ;

	g_HwndDir = GetDlgItem(hwnd,IDC_EDIT_DIR) ;

	g_HwndNextDesFloor = GetDlgItem(hwnd,IDC_EDIT_NEXTDES) ;

	g_HwndFinishCount = GetDlgItem(hwnd	,IDC_FINISHCOUNT) ;

	
	g_HwndLiftSpeed = GetDlgItem(hwnd,IDC_EDIT_LIFTSPEED) ;

	g_HwndReqSpeed = GetDlgItem(hwnd,IDC_EDIT_REQSPEED) ;;


	/*每一层的窗口初始化*/

	g_fsFloor[0].hwndDisplay = GetDlgItem(hwnd,IDC_PICTURE_FRISTFLOOR) ;
	g_fsFloor[0].hwndLog = GetDlgItem(hwnd,IDC_EDIT_FIRST) ;

	g_fsFloor[1].hwndDisplay = GetDlgItem(hwnd,IDC_PICTURE_SECONDFLOOR) ;
	g_fsFloor[1].hwndLog = GetDlgItem(hwnd,IDC_EDIT_SECOND) ;

	g_fsFloor[2].hwndDisplay = GetDlgItem(hwnd,IDC_PICTURE_THRIDFLOOR) ;
	g_fsFloor[2].hwndLog = GetDlgItem(hwnd,IDC_EDIT_THRID) ;

	g_fsFloor[3].hwndDisplay = GetDlgItem(hwnd,IDC_PICTURE_FORTHFLOOR) ;
	g_fsFloor[3].hwndLog = GetDlgItem(hwnd,IDC_EDIT_FORTH) ;	  

	g_fsFloor[4].hwndDisplay = GetDlgItem(hwnd,IDC_PICTURE_FIFTHFLOOR) ;
	g_fsFloor[4].hwndLog = GetDlgItem(hwnd,IDC_EDIT_FIFTH) ;


	/*初始化电梯动画显示窗口*/
	g_lsLift.hwnd = GetDlgItem(hwnd,IDC_PICTURE_LIFT) ;


	/*初始化视图控件*/
	ZeroMemory( &LvC, sizeof(LVCOLUMN)) ;

	LvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM ;
	LvC.iSubItem = 0 ;
	LvC.cx = 200 ;
	LvC.fmt = LVCFMT_LEFT ;
	LvC.pszText = szTextLift ;

	if(-1 == ListView_InsertColumn(g_HwndListView,0,&LvC) )
	{
		MessageBox(hwnd,"测试","多测试",MB_OK) ;
	}

	LvC.pszText = szTextEvent ;
	LvC.cx = 250 ;

	if(-1 == ListView_InsertColumn(g_HwndListView,1,&LvC))
	{
		MessageBox(hwnd,"测试","多测试",MB_OK) ;
	}

	/*初始化动画,坐标转换*/	
	POINT pt ; 
	RECT rcDlgRect ;
	RECT rcDlgRealRect ;

	GetClientRect(g_HwndMain,&rcDlgRect) ;  //获取对话框的大小
	pt.x = rcDlgRect.left ;
	pt.y = rcDlgRect.top ;

	ClientToScreen(g_HwndMain,&pt) ;
	rcDlgRealRect.top = pt.y ;
	rcDlgRealRect.left = pt.x ;

	pt.x = rcDlgRect.right ;
	pt.y = rcDlgRect.bottom ;
	ClientToScreen(g_HwndMain,&pt) ;

	rcDlgRealRect.bottom = pt.y ;  //客户区相对于屏幕的绝对坐标
	rcDlgRealRect.right = pt.x ;

	/////电梯客户区转换成屏幕坐标
	RECT rect ;
	RECT rcRealRect ;
	RECT tmpRect ;

	GetClientRect(g_lsLift.hwnd ,&rect) ;
	GetClientRect(g_lsLift.hwnd ,&tmpRect) ;

	pt.x = tmpRect.left ;
	pt.y = tmpRect.top ;

	ClientToScreen(g_lsLift.hwnd ,&pt) ;
	rcRealRect.top = pt.y ;
	rcRealRect.left = pt.x ;

	pt.x = tmpRect.right ;
	pt.y = tmpRect.bottom ;
	ClientToScreen(g_lsLift.hwnd ,&pt) ;

	rcRealRect.bottom = pt.y ;  //客户区相对于屏幕的绝对坐标
	rcRealRect.right = pt.x ;

	rcRealRect.top -= rcDlgRealRect.top ;  //电梯轨道相对于客户区的坐标  22
	rcRealRect.left -= rcDlgRealRect.left ;	//3 
	rcRealRect.bottom -= rcDlgRealRect.top ;
	rcRealRect.right -= rcDlgRealRect.left ;

	g_lsLift.rect = rect ; 
	g_lsLift.pos = rcRealRect.bottom ;
	g_lsLift.realrect = rcRealRect ;
	g_lsLift.speed = 25 ;						//电梯速度



//	GetWindowRect(g_lsLift.hwnd ,&tmpRect) ; //测试是否成功转换绝对坐标


	/*初始化楼层*/
	int i = 0 ;
	int j = 0 ;

	for( i = 0 ; i < DEFAULT_FLOOR_NUM ; i++)
	{
		GetClientRect(g_fsFloor[i].hwndDisplay,&g_fsFloor[i].rect) ;
		GetWindowRect(g_fsFloor[i].hwndDisplay,&g_fsFloor[i].realrect) ;
		g_FloorPos[i] = g_fsFloor[i].realrect.bottom - rcDlgRealRect.top ;  //电梯的相对位置
		g_fsFloor[i].realrect.top -= rcDlgRealRect.top ;		//得到每一层相对于窗口客户区的位置
		g_fsFloor[i].realrect.left -= rcDlgRealRect.left ;	
		g_fsFloor[i].realrect.right -= rcDlgRealRect.left ;
		g_fsFloor[i].realrect.bottom -= rcDlgRealRect.top ;

	}

	g_rcFloor = g_fsFloor[0].rect ;  //电梯大小,也就是那个矩形的大小

	iLiftSize = g_rcFloor.bottom - g_rcFloor.top ;   //固定电梯的size

	return TRUE ;

}


/*	-------------------------------------------------------------------------------------
	*	函数名称:	Dlg_OnCommand

	*	功能描述:	处理WM_COMMAND消息,响应各按钮,响应菜单

	*	参数列表:	略

	*	返回结果:	无
	-------------------------------------------------------------------------------------	*/

void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtl , UINT codeNotify)
{
	switch(id)
	{
	case IDC_BUTTON_START :

		OnStart() ;
		break ;

	case IDC_BUTTON_STOP :

		OnStop() ;
		break ;

	case ID_MENUITEM_ABOUT :
		
		DialogBox(g_hInst,MAKEINTRESOURCE(IDD_ABOUT),g_HwndMain, AboutDlgProc) ;

		break ;

	case IDCANCEL :

		EndDialog(hwnd,id) ;
		break ;

	}
}


/*	-------------------------------------------------------------------------------------
	*	函数名称:	AboutDlgProc

	*	功能描述:	“关于”对话框的消息处理函数,什么也没有用,只是简单的显示一下。

	*	参数列表:	略

	*	返回结果:	略
	-------------------------------------------------------------------------------------	*/

BOOL CALLBACK AboutDlgProc(HWND hDlg,UINT message ,WPARAM wParam,LPARAM lParam)
{
	switch(message)
	{
	case WM_INITDIALOG :
		return TRUE ;

	case WM_COMMAND :
		switch(LOWORD(wParam))
		{
		case IDOK:
		case IDCANCEL :

			EndDialog(hDlg,0) ;
			return TRUE ;
		}
		break ;
	}

	return FALSE ;
}



/*	-------------------------------------------------------------------------------------
	*	函数名称:	OnStart

	*	功能描述:	响应开始按钮,设置电梯、楼层速度,生成电梯服务线程以及楼层请求线程

	*	参数列表:	略

	*	返回结果:	无
	-------------------------------------------------------------------------------------	*/

void OnStart()
{
	//生成线程

	HWND ButtonStartHwnd = GetDlgItem(g_HwndMain ,IDC_BUTTON_START) ; 

	DWORD dwThreadID ;

	int i = 0 ;

	/*初始化速度*/

	int iLiftSpeedValue = 0 ;
	int iReqSpeedValue = 0 ;

	TCHAR szLiftSpeed[10] ;
	TCHAR szReqSpeed[10] ;

	iLiftSpeedValue = GetWindowText(GetDlgItem(g_HwndMain,IDC_EDIT_LIFTSPEED),szLiftSpeed,10) ;
	iReqSpeedValue = GetWindowText(GetDlgItem(g_HwndMain,IDC_EDIT_REQSPEED),szReqSpeed,10) ;
	if(iLiftSpeedValue != 0 && iReqSpeedValue != 0) 
	{
		iLiftSpeedValue = atoi(szLiftSpeed) ;
		iReqSpeedValue = atoi(szReqSpeed) ;
	
		if(iLiftSpeed != 0 && iReqSpeed != 0 &&
				iLiftSpeed >= 10 && iLiftSpeed <= 35 && iReqSpeed >= 3000 && iReqSpeed <= 9000)
		{
			iLiftSpeed = iLiftSpeedValue ;
			iReqSpeed = iReqSpeedValue ;
			g_lsLift.speed = iLiftSpeedValue ;						//电梯速度
		}

	}
		
	EnableWindow(GetDlgItem(g_HwndMain,IDC_EDIT_LIFTSPEED),false) ;
	EnableWindow(GetDlgItem(g_HwndMain,IDC_EDIT_REQSPEED),false) ;

	EnableWindow(ButtonStartHwnd,false) ;
	EnableWindow(g_HwndMainStop,true) ;

	for(i = 0 ; i < DEFAULT_FLOOR_NUM ; i++)
	{
		g_hThreads[g_nNumThreads++] = chBEGINTHREADEX(NULL,0,LiftClientThread,(PVOID)(i+1),
			0,&dwThreadID) ;
	}

	g_hThreads[g_nNumThreads++] = chBEGINTHREADEX(NULL,0,LiftSeverThread,(PVOID)(i+1),
		0,&dwThreadID) ;


}


/*	-------------------------------------------------------------------------------------
	*	函数名称:	OnStop

	*	功能描述:	响应停止按钮,挂起各线程

	*	参数列表:	略

	*	返回结果:	无
	-------------------------------------------------------------------------------------	*/

void OnStop()
{
	int i = 0 ;

	HWND Canclehwnd = GetDlgItem(g_HwndMain,IDCANCEL) ;

	if(!g_fSuspend)
	{
		g_fSuspend = true ;

		//这里改变停止按钮的文字
		SetWindowText(g_HwndMainStop,"继续动画显示") ;

		EnableWindow(Canclehwnd,false) ;

		for(i = 0 ; i < g_nNumThreads ; i++)
		{
			SuspendThread(g_hThreads[i]) ;
		}
	}
	else
	{
		g_fSuspend = false ;

		//改变停止按钮的文件
		SetWindowText(g_HwndMainStop,"暂停") ;

		EnableWindow(Canclehwnd,true) ;

		for(i = 0 ; i < g_nNumThreads ; i++)
		{
			ResumeThread(g_hThreads[i]) ;
		}
	}

}


/*	-------------------------------------------------------------------------------------
	*	函数名称:	Dlg_OnPaint

	*	功能描述:	处理WM_PAINT消息,绘制电梯位置、绘制各楼层的上下楼请求

	*	参数列表:	略

	*	返回结果:	无
	-------------------------------------------------------------------------------------	*/

void Dlg_OnPaint(HWND hwnd)
{
	PAINTSTRUCT ps ;

	HDC hdc ;	

	hdc = BeginPaint(hwnd,&ps) ;

	/******************************开始画图********************************/

	HBRUSH hBrush = (HBRUSH)GetStockObject(BLACK_BRUSH) ;

	HGDIOBJ  hOldBrush  ;

	hOldBrush = SelectObject(hdc,hBrush) ;

	Rectangle(hdc,g_lsLift.realrect.left ,g_lsLift.pos - iLiftSize ,
		g_lsLift.realrect.right,g_lsLift.pos) ;  //全部填满

	SelectObject(hdc,hOldBrush) ;

	/*画三角形*/
	for(int i = 0 ; i < DEFAULT_FLOOR_NUM  ; i++)
	{
		if(g_bsDrawDir.test(i+1))
		{

			if(g_fsFloor[i].direction == LIFTUP)
			{			
				g_fsFloor[i].pt[0].x = g_fsFloor[i].realrect.left + g_fsFloor[i].rect.right / 2 ;
				g_fsFloor[i].pt[1].x = g_fsFloor[i].realrect.left + g_fsFloor[i].rect.right / 3 ;
				g_fsFloor[i].pt[2].x = g_fsFloor[i].realrect.right - g_fsFloor[i].rect.right / 3 ;
				g_fsFloor[i].pt[0].y = g_fsFloor[i].realrect.top ;
				g_fsFloor[i].pt[1].y = g_fsFloor[i].realrect.bottom ;
				g_fsFloor[i].pt[2].y = g_fsFloor[i].realrect.bottom  ;

				Triangle(hdc,g_fsFloor[i].pt) ;
			}
			else if(g_fsFloor[i].direction == LIFTDOWN)
			{			
				g_fsFloor[i].pt[0].x = g_fsFloor[i].realrect.left + g_fsFloor[i].rect.right / 2  ;
				g_fsFloor[i].pt[1].x = g_fsFloor[i].realrect.left  + g_fsFloor[i].rect.right / 3   ;
				g_fsFloor[i].pt[2].x = g_fsFloor[i].realrect.right  - g_fsFloor[i].rect.right / 3   ;
				g_fsFloor[i].pt[0].y = g_fsFloor[i].realrect.bottom ;
				g_fsFloor[i].pt[1].y = g_fsFloor[i].realrect.top ; 
				g_fsFloor[i].pt[2].y =	g_fsFloor[i].realrect.top  ;

				Triangle(hdc,g_fsFloor[i].pt) ;
			}			
		}
	}

	EndPaint(hwnd,&ps) ;
}



/*	-------------------------------------------------------------------------------------
	*	函数名称:	Triangle

	*	功能描述:	此函数取自《Windows程序设计 5th》。此函数用来绘制上下楼的三角形

	*	参数列表:	略

	*	返回结果:	无
	-------------------------------------------------------------------------------------	*/

void Triangle(HDC hdc,POINT pt[])
{
	HBRUSH hBrush = CreateSolidBrush(RGB(255,216,0)) ;

	HGDIOBJ hOldBrush = SelectObject(hdc,hBrush) ;

	Polygon(hdc,pt,3) ;

	SelectObject(hdc,hOldBrush) ;

	DeleteObject((HGDIOBJ)hBrush) ;	   //不用的话,记得要删除,否则内存泄漏,造成界面问题严重
}


 

 

/*	-------------------------------------------------------------------------------------
	*	Copyright(c) 2012-3-6	Seed-L
	
	*	All rights reserved.

	*	文件名称:	LiftDemo.h

	*	简要描述:	定义各类数据结构、常量

	*	作者:Seed-L

	*	完成日期:2012-3-4
	-------------------------------------------------------------------------------------	*/



#ifndef LIFTDEMO_H_
#define LIFTDEMO_H_

#include"help.h"
#include<windows.h>
#include<bitset>
#include<string>


using std::bitset ; 
using std::string ;


//楼层请求的类型:电梯外、电梯内、没有请求
//本来定义的名称是OUT、IN的简单名称,结果编译不通过,找了也挺久的错误
//后来发现原来OUT 和 IN 是库里面已经定义好的。但是错误提示又没有提示说重定义
enum eReqStatus { LIFTOUT = 0 ,LIFTIN = 1 , NOTREQ = 2} ;   


//电梯方向:
//貌似发现LIFTSTOP 没有用上
enum eLiftDir	{  LIFTUP , LIFTDOWN ,LIFTSTOP} ; 

const int DEFAULT_FLOOR_NUM = 5 ;				//楼层总楼
const int TOPFLOOR = 5 ;						//顶层
const int BOTTOMFLOOR = 1 ;						//底层


//动画电梯结构
typedef struct LiftStruct
{
	HWND hwnd ;			//电梯轨道
	int speed ;
	RECT rect ;			//相对自己的窗口区
	RECT realrect ;		//相对窗口客户区
	int pos ;			//电梯的位置

}	LiftStruct  , *PLiftStruct ;

//动画楼层结构
typedef struct FloorStruct
{
	HWND hwndDisplay ;		//上下楼请求绘制窗口句柄
	HWND hwndLog ;			//显示请求的窗口,文字描述
	RECT rect ;				
	RECT realrect ;			//相对窗口窗户区的坐标
	POINT  pt[3] ;			//绘制三角形的三个点的坐标
	eLiftDir direction ;
}   FlooStruct ,PFloorStruct;



class LiftDemoS
{

public	:

	//本来是私有函数
	inline void EnterLiftCs() { EnterCriticalSection(&m_Cs)  ; } 

	inline void LeaveLiftCs() { LeaveCriticalSection(&m_Cs)  ; } 		

	inline eLiftDir GetLiftDirection() { return m_eLiftCurDir ; } 
	
	inline int GetLiftCurFloor() {	return m_iLiftCurFloor ;}

	inline int GetLiftCurDesNum() { return m_bsReqQueue.count() ; }

	inline int GetLiftNextDes() { return m_iLiftNextDes ;}

	inline bitset<DEFAULT_FLOOR_NUM+1> GetLiftDesFloor() { return m_bsReqQueue ;}

	inline bitset<DEFAULT_FLOOR_NUM+1> GetUpDirQueue() { return m_bsUpDirQueue ;}

	inline bitset<DEFAULT_FLOOR_NUM+1> GetDownDirQueue() { return m_bsDownDirQueue ;}

	void LiftReachAndWait(int iNum) ;

	int LiftChangeDirection( int* iOldDir)  ;

	LiftDemoS() ;

	virtual ~LiftDemoS() ;

private :

	HANDLE  m_hReqHappenEvents[DEFAULT_FLOOR_NUM] ;		//某楼层发出请求事件对象

	HANDLE	m_hLiftReachEvents[DEFAULT_FLOOR_NUM] ;		//电梯到达楼层时,通知楼层事件

	HANDLE  m_LiftGoEvent ;								//用来告知电梯可以起动

	CRITICAL_SECTION	m_Cs ;							//互斥段,用来修改队列时使用	

	CRITICAL_SECTION    m_ResAllEventCs ;

	CRITICAL_SECTION	m_InsertReqCs ;

private	:
	
	inline void InitLiftCs() 
	{ 
		InitializeCriticalSection(&m_Cs) ; 
		InitializeCriticalSection(&m_ResAllEventCs) ;
		InitializeCriticalSection(&m_InsertReqCs) ;
	}

	inline void DeleteLiftCs() 
	{ 
		DeleteCriticalSection(&m_Cs) ; 
		DeleteCriticalSection(&m_ResAllEventCs) ;
		DeleteCriticalSection(&m_InsertReqCs) ;
	}

	void CreateLiftEvent()  ;

public :

	//分两种
	//第一种是电梯外请求,第一个参数代表请求的状态,第二个请求代表发生请求的楼层
	//第二个是电梯内请求,第一个参数代表请求的状态是电梯内的,第二个请求代表里面发生的楼层

	bool SetFloorReq(eReqStatus eStatus , bitset<DEFAULT_FLOOR_NUM+1> &bsFloor, int iFloorNum , eLiftDir eWantDir) ;  

	bool ReSetFloorReq(eReqStatus &eStatus , int &biFloor) ; 

	void LiftSetGoOnEvent() ;
	
	void LiftResetGoOnEvent() ;

	void ResetAllEvents() ;

	inline void EnterInsertReqCs() { EnterCriticalSection(&m_InsertReqCs)  ; } 

	inline void LeaveInsertReqCs() { LeaveCriticalSection(&m_InsertReqCs)  ; } 

private	:

	eLiftDir m_eLiftCurDir ;				//电梯此时的方向,转向有用

	int m_iLiftCurFloor ;			//电梯此时所在楼层,请求发生时,用来和这一个比较,
									//以便决定放入到上升队列,还是下降队列
	int m_iLiftNextDes ;			//下一站

	bitset<DEFAULT_FLOOR_NUM+1> m_bsReqQueue ;

	bitset<DEFAULT_FLOOR_NUM+1> m_bsUpDirQueue ;   //1为向上,0为向下
												   //将这一个原来的方向队列,变为上升队列
												   //某位的1,表示某楼层要向上,0表示没有请求,或者向下

	bitset<DEFAULT_FLOOR_NUM+1> m_bsDownDirQueue ; //新增的一个向下请求队列
												  //某位的1,表示某楼层要向下,0表示没有请求,或者向上

	bool m_fTurnToFindFloor ;

	bool m_fAcceptOppReq ;


} ;
#endif


 

/*	-------------------------------------------------------------------------
	*	Copyright(c)  来自《Windows核心编程》

	*	All rights reserved.

	*	文件名称:	help.h

	*	简要描述:	此文件的内容来自核心编程一书,主要是一些辅助宏,用来
					简化自己的工作量

	*	作者	:	《Windows核心编程》一书的作者
	--------------------------------------------------------------------------*/



#ifndef HELP_H_
#define HELP_H_



#define _WIN32_WINNT 0x0500
//#define WINVER       0x0500

#include<tchar.h>
#include<windowsx.h>
#include<windows.h>



///////////////////////////// chBEGINTHREADEX Macro ///////////////////////////


// This macro function calls the C runtime's _beginthreadex function. 
// The C runtime library doesn't want to have any reliance on Windows' data 
// types such as HANDLE. This means that a Windows programmer needs to cast
// values when using _beginthreadex. Since this is terribly inconvenient, 
// I created this macro to perform the casting.
typedef unsigned (__stdcall *PTHREAD_START) (void *);

#define chBEGINTHREADEX(psa, cbStack, pfnStartAddr, \
   pvParam, fdwCreate, pdwThreadId)                 \
      ((HANDLE)_beginthreadex(                      \
         (void *)        (psa),                     \
         (unsigned)      (cbStack),                 \
         (PTHREAD_START) (pfnStartAddr),            \
         (void *)        (pvParam),                 \
         (unsigned)      (fdwCreate),               \
         (unsigned *)    (pdwThreadId)))


//////////////////////////////// chDIMOF Macro ////////////////////////////////


// This macro evaluates to the number of elements in an array. 
#define chDIMOF(Array) (sizeof(Array) / sizeof(Array[0]))

/////////////////////////// Quick MessageBox Macro ////////////////////////////


inline void chMB(PCSTR s) {
   char szTMP[128];
   GetModuleFileNameA(NULL, szTMP, chDIMOF(szTMP));
   MessageBoxA(GetActiveWindow(), s, szTMP, MB_OK);
}


////////////////////////// chHANDLE_DLGMSG Macro /////////////////////////////


// The normal HANDLE_MSG macro in WindowsX.h does not work properly for dialog
// boxes because DlgProc return a BOOL instead of an LRESULT (like
// WndProcs). This chHANDLE_DLGMSG macro corrects the problem:
#define chHANDLE_DLGMSG(hwnd, message, fn)                 \
   case (message): return (SetDlgMsgResult(hwnd, uMsg,     \
      HANDLE_##message((hwnd), (wParam), (lParam), (fn))))


// Sets the dialog box icons
inline void chSETDLGICONS(HWND hwnd, int idi) {
   SendMessage(hwnd, WM_SETICON, TRUE,  (LPARAM) 
      LoadIcon((HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE), 
         MAKEINTRESOURCE(idi)));
   SendMessage(hwnd, WM_SETICON, FALSE, (LPARAM) 
      LoadIcon((HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE), 
      MAKEINTRESOURCE(idi)));
}


#endif

//////////////////////////////////////以上的来自核心编程///////////////////////////////////////




 

 

本来注释已经写好的,但是VS出了点Bug关闭后发现刚才的保存完全没有作用。。。


 

 

你可能感兴趣的:(多线程,windows,ListView,button,winapi)