⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 _msgqueue.asm

📁 可以防止同一用户多次登陆
💻 ASM
字号:
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Sample code for < Win32ASM Programming 2nd Edition>
; by 罗云彬, http://asm.yeah.net
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; FIFO(First in, first out)消息队列的实现
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;
;
;
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
QUEUE_SIZE	equ	100		;消息队列的长度
MSG_QUEUE_ITEM	struct			;队列中单条消息的格式定义
  dwMessageId	dd	?		;消息编号
  szSender	db	12 dup (?)	;发送者
  szContent	db	256 dup (?)	;聊天内容
MSG_QUEUE_ITEM	ends
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

		.data?

stCS		CRITICAL_SECTION <?>
stMsgQueue	MSG_QUEUE_ITEM QUEUE_SIZE dup (<?>)
dwMsgCount	dd	?		;队列中当前消息数量

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

		.data

dwSequence	dd	1	;消息序号,从1开始

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 在队列中加入一条消息
; -- 如果队列已经满了,则将整个队列前移一个位置,相当于最早的消息被覆盖
;    然后在队列尾部空出的位置加入新消息
; -- 如果队列未满,则在队列的最后加入新消息
; -- 消息编号从1开始递增,这样保证队列中各消息的编号是连续的
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 入口:_lpszSender = 指向发送者字符串的指针
;	_lpszContent = 指向聊天语句内容字符串的指针
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_InsertMsgQueue	proc	_lpszSender,_lpszContent

		pushad
		invoke	EnterCriticalSection,addr stCS
		mov	eax,dwMsgCount
;********************************************************************
; 如果队列满,则移动队列,并在队列尾部添加新消息
;********************************************************************
		.if	eax >= QUEUE_SIZE
			mov	edi,offset stMsgQueue
			mov	esi,offset stMsgQueue + sizeof MSG_QUEUE_ITEM
			mov	ecx,(QUEUE_SIZE-1) * sizeof MSG_QUEUE_ITEM
			mov	eax,ecx
			cld
			rep	movsb
;********************************************************************
; 否则直接添加到队列尾部
;********************************************************************
		.else
			inc	dwMsgCount
			mov	ecx,sizeof MSG_QUEUE_ITEM
			mul	ecx
		.endif
;********************************************************************
; 前面的语句执行完毕后,eax指向队列中空位置的偏移量
;********************************************************************
		lea	esi,[stMsgQueue+eax]
		assume	esi:ptr MSG_QUEUE_ITEM
		invoke	lstrcpy,addr [esi].szSender,_lpszSender
		invoke	lstrcpy,addr [esi].szContent,_lpszContent
		inc	dwSequence
		mov	eax,dwSequence
		mov	[esi].dwMessageId,eax
		assume	esi:nothing
		invoke	LeaveCriticalSection,addr stCS
		popad
		ret

_InsertMsgQueue	endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 从队列获取指定编号的消息
; -- 如果指定编号的消息已经被清除出消息队列,则返回编号最小的一条消息
;    当向连接速度过慢的客户端发消息的速度比不上消息被清除的速度,则中间
;    的消息等于被忽略,这样可以保证慢速链路不会影响快速链路
; -- 如果队列中的所有消息的编号都比指定编号小(意味着这些消息以前都被获取过)
;    那么不返回任何消息
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 入口:_dwMessageId = 需要获取的消息编号
;	_lpszSender = 用于返回消息中发送者字符串的缓冲区指针
;	_lpszSender = 用于返回消息中聊天内容字符串的缓冲区指针
; 返回:eax = 0(队列为空,或者队列中没有小于等于指定编号的消息)
;	eax <> 0(已经获取了一条消息,获取的消息编号返回到eax中)
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_GetMsgFromQueue	proc	_dwMessageId,_lpszSender,_lpszContent
			local	@dwReturn

		pushad
		invoke	EnterCriticalSection,addr stCS
		xor	eax,eax
		mov	@dwReturn,eax
		cmp	dwMsgCount,eax
		jz	_Ret

		mov	esi,offset stMsgQueue
		assume	esi:ptr MSG_QUEUE_ITEM
;********************************************************************
; esi 指向队列头部,所以这条消息的编号就是最小编号
; 最大编号=最小编号+队列长度-1
;********************************************************************
		mov	ecx,[esi].dwMessageId	;ecx=队列中的最小消息编号
		mov	edx,dwMsgCount
		lea	edx,[edx+ecx-1]		;edx=队列中的最大消息编号
;********************************************************************
; 如果指定编号 < 最小编号,则返回最小编号的消息
; 如果指定编号 > 最大编号,则不返回任何消息
;********************************************************************
		mov	eax,_dwMessageId
		cmp	eax,ecx
		jae	@F
		mov	eax,ecx
		@@:
		cmp	eax,edx
		ja	_Ret
		mov	@dwReturn,eax
;********************************************************************
; 要获取的消息在队列中的位置 = 指定消息编号-最小消息编号
;********************************************************************
		sub	eax,ecx
		mov	ecx,sizeof MSG_QUEUE_ITEM
		mul	ecx
		lea	esi,[esi+eax]
		invoke	lstrcpy,_lpszSender,addr [esi].szSender
		invoke	lstrcpy,_lpszContent,addr [esi].szContent
;********************************************************************
		assume	esi:nothing
_Ret:
		invoke	LeaveCriticalSection,addr stCS
		popad
		mov	eax,@dwReturn
		ret

_GetMsgFromQueue	endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -