Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1154 lines
33 KiB

  1. ;;;;;;;;;;;;;;;;;;;;;; START OF SOURCE FILE SPECIFICATION ;;;;;;;;;;;;;;;;;;;;
  2. COMMENT $ HEADER
  3. SOURCE FILE NAME: winq
  4. DESCRIPTIVE NAME: queue management module
  5. FUNCTION: This module contains routines for creating and
  6. deleting queues and reading and writing messages
  7. to queues. The circular queue data structure (struct Q
  8. defined in user.h) consists of a header followed by a
  9. sequence of messages
  10. ENTRY POINTS: InitSysQ, CreateQueue, DeleteQueue, WriteMessage, ReadMessage,
  11. FQueueNotFull, DelQEntry, UnlinkQ
  12. $
  13. ;;;;;;;;;;;;;;;;;;;;;; END OF SOURCE FILE SPECIFICATION ;;;;;;;;;;;;;;;;;;;;
  14. ;% MOVEDS - NK (no change)
  15. norasterops = 1
  16. notext = 1
  17. .xlist
  18. include user.inc
  19. .list
  20. ExternFP <LocalAlloc, LocalFree>
  21. createSeg _TEXT,CODE,WORD,PUBLIC,CODE
  22. createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
  23. defgrp DGROUP,DATA
  24. assumes cs,CODE
  25. assumes ds,DATA
  26. ;============================================================================
  27. sBegin DATA
  28. ifndef WOW
  29. ExternW idSysPeek ; id in sys queue of message being looked at.
  30. endif
  31. sEnd DATA
  32. ;============================================================================
  33. ExternFP <GetSystemMsecCount>
  34. ExternFP <GetCurrentTask>
  35. ExternFP <SetTaskQueue>
  36. ExternFP <GlobalAlloc, GlobalFree>
  37. ExternFP <PostEvent>
  38. ExternFP <PostMessage>
  39. ExternFP <GetExeVersion>
  40. sBegin CODE
  41. ; CS variables:
  42. ifndef WOW ; WOW doesn't use these
  43. ExternNP <CheckMsgFilter2>
  44. ExternNP <CheckHwndFilter2>
  45. ExternNP <SetWakeBit>
  46. ExternNP <WakeSomeone>
  47. ExternNP <SetWakeBit2>
  48. ExternNP <SkipSysMsg>
  49. ExternNP <PostMove>
  50. ExternNP <HqCur2ES, HqCur2DS>
  51. ExternFP <HqCurrent>
  52. else
  53. ExternFP <GetTaskQueueES>
  54. endif ; WOW doesn't use these
  55. ifdef WOW ; These functions stolen from winloop3.asm
  56. ;*--------------------------------------------------------------------------*
  57. ;* *
  58. ;* HqCur2ES() - *
  59. ;* *
  60. ;*--------------------------------------------------------------------------*
  61. ; Get hqCurrent in ES.
  62. LabelNP <PUBLIC, HqCur2ES>
  63. call GetTaskQueueES ; Another wonderful KERNEL routine
  64. ret
  65. ;*--------------------------------------------------------------------------*
  66. ;* *
  67. ;* HqCurrent() - *
  68. ;* *
  69. ;*--------------------------------------------------------------------------*
  70. ; Get handle of current queue and return in AX.
  71. LabelFP <PUBLIC, HqCurrent>
  72. call HqCur2ES ; Code depends on both ES and AX
  73. mov ax,es
  74. or ax,ax ; Set flags
  75. retf
  76. endif ; WOW These functions stolen from winloop3.asm
  77. ifndef WOW ; No InitSysQueue for WOW
  78. ;;;;;;;;;;;;;;;;;;;;;;;;;; START OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  79. COMMENT $ LOCAL
  80. InitSysQueue () - Create and initialize the system queue.
  81. LINKAGE: FAR PLM
  82. ENTRY: WORD cQEntries - number of entries in system queue
  83. EXIT: hSysQueue contains handle for system queue (Shared global object.)
  84. EFFECTS: all registers modified.
  85. INTERNAL: CreateQueue2
  86. EXTERNAL: none
  87. WARNINGS: none
  88. REVISION HISTORY:
  89. IMPLEMENTATION:
  90. Set up register linkage for CreateQueue2 and let it do the work.
  91. $
  92. ;;;;;;;;;;;;;;;;;;;;;;;;;; END OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  93. cProc InitSysQueue,<PUBLIC,FAR>,<DS>
  94. cBegin
  95. mov ax,_INTDS
  96. mov ds,ax
  97. assumes ds,INTDS
  98. mov ax,ds:[cQEntries] ; number of entries
  99. push ax
  100. mov ax,size INTERNALSYSMSG ; size of entry
  101. push ax
  102. call CreateQueue2 ; create system queue
  103. mov ds:[hqSysQueue],ax
  104. assumes ds,NOTHING
  105. cEnd
  106. endif ; No InitSysQueue for WOW
  107. ;;;;;;;;;;;;;;;;;;;;;;;;;; START OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  108. COMMENT $ LOCAL
  109. CreateQueue (cMsgs) - Create a queue.
  110. Create a queue for the currently executing task and stick its handle
  111. in the task header and the queue list.
  112. LINKAGE: FAR PLM
  113. ENTRY: WORD cMsgs(parm1) - count of messages that can be stored in
  114. queue
  115. EXIT: ax - handle to queue (shared global object.)
  116. Newly created queue is linked to list of queues pointed
  117. to by hqList.
  118. EXIT - ERROR: ax hqCurrent, hqCurrentShadow contain 0.
  119. EFFECTS: all registers modified.
  120. INTERNAL: CreateQueue2
  121. EXTERNAL: SetTaskQueue
  122. WARNINGS: Running out of memory when trying to CreateQueue will
  123. init current queue to 0.
  124. REVISION HISTORY:
  125. IMPLEMENTATION:
  126. Set up register linkage for CreateQueue2 and let it create the queue.
  127. Then add to linked list and then SetTaskQueue(NULL, hqCreated).
  128. $
  129. ;;;;;;;;;;;;;;;;;;;;;;;;;; END OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  130. cProc CreateQueue,<PUBLIC, FAR>,<DS>
  131. ParmW cMsgs
  132. cBegin
  133. push cMsgs
  134. mov ax,size INTERNALMSG
  135. push ax
  136. call CreateQueue2
  137. or ax,ax
  138. jz errexit ; CreateQueue2 failed
  139. EnterCrit
  140. mov es,ax
  141. push ax
  142. mov ax,_INTDS
  143. mov ds,ax
  144. pop ax
  145. assumes ds,INTDS
  146. xchg ds:[hqList],ax ; Link us in and get old head of list
  147. mov es:[qHqNext],ax ; store ptr to next queue
  148. push es ; save hq for return
  149. xor ax,ax ; SetTaskQueue(NULL, es)
  150. push ax
  151. push es ; push queue handle
  152. call SetTaskQueue ; and ram it in there
  153. pop ax ; return queue handle
  154. LeaveCrit
  155. assumes ds,DATA
  156. errexit:
  157. cEnd
  158. ;;;;;;;;;;;;;;;;;;;;;;;;;; START OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  159. COMMENT $ PRIVATE
  160. CreateQueue2 (cMsgs, cbEntry) - Create a queue.
  161. Allocate a shared global object and initialize the header for the Q
  162. Data structure.
  163. LINKAGE: NEAR PLM
  164. ENTRY: WORD cMsgs(parm1) - count of messages that can be stored in
  165. queue
  166. WORD cbEntry(parm2) - count of bytes in single message entry.
  167. EXIT: ax - handle to queue (shared global object.)
  168. EXIT - ERROR: ax contains 0
  169. EFFECTS: all registers except DI modified.
  170. wAppVersion gets current exe version.
  171. INTERNAL:
  172. EXTERNAL: GlobalAlloc
  173. WARNINGS: cbEntry better not be less than 5.
  174. REVISION HISTORY:
  175. IMPLEMENTATION:
  176. Allocate a shared global object, initialize header with following
  177. fields: Current Task, cbEntry, cMsgs,pmsgRead, pmsgWrite,
  178. pmsgRead = pmsgWrite = rgMsg,
  179. pmsgMax = queue size
  180. wVersion = GetExeVersion
  181. WakeBits = QS_SMPARAMSFREE | (SYSQ empty ? QS_INPUT : 0).
  182. lpfnMsgFilter = cs:OldMsgFilter
  183. $
  184. ;;;;;;;;;;;;;;;;;;;;;;;;;; END OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  185. cProc CreateQueue2,<PUBLIC, NEAR>,<DI>
  186. ParmW cMsgs
  187. ParmW cbEntry
  188. cBegin
  189. call GetCurrentTask ; get current task
  190. push ax ; and save it
  191. mov ax,cMsgs
  192. mov cx,cbEntry
  193. mul cx
  194. add ax,size Q - size INTERNALMSG
  195. push ax ; save size of queue
  196. ; Alloc(GPTR, cMsgs * size INTERNALMSG + size Q)
  197. push GPTR+GMEM_SHAREALL
  198. push 0 ; hi word == 0
  199. push ax
  200. call GlobalAlloc
  201. mov es,ax ; stick hq in es
  202. pop cx ; pop queue size
  203. pop bx ; and task handle
  204. or ax,ax ; error on alloc?
  205. jz cqexit ; yes, quit
  206. xchg bx,ax ; get task handle into ax
  207. cld
  208. mov di,qHTask ; point at hTask
  209. stosw ; store task handle
  210. errnz qHTask-2
  211. mov ax,cbEntry ; store size of entry
  212. stosw
  213. errnz qCbEntry-4
  214. inc di ; cMsgs = 0 (cleared by alloc)
  215. inc di
  216. errnz qCMsgs-6
  217. mov ax,qRgmsg
  218. stosw ; init read/write pointers
  219. errnz qPmsgRead-8
  220. stosw
  221. errnz qPmsgWrite-10
  222. mov ax,cx ; get size of queue (ptr to end)
  223. stosw ; and store it
  224. errnz qPmsgMax-12
  225. push es ; save hq
  226. call GetExeVersion ; returns sys version in dx, app in ax
  227. pop es
  228. mov es:[qWVersion],ax ; set up app version number
  229. mov es:[qWakeBits],QS_SMPARAMSFREE ; default ON flags.
  230. mov es:[qFlags],QF_INIT ; indicate initialization is in progress
  231. mov ax,es ; Save hq in ax.
  232. push ax
  233. mov ax,_INTDS
  234. mov es,ax
  235. pop ax
  236. assumes es,INTDS
  237. cmp es:[hqList],0 ; If we are the first queue and
  238. jnz cq100 ; there is input waiting for us,
  239. mov es:[hqCursor],ax ; Initialize this guy for WakeSomeone.
  240. cmp es:[hqSysQueue],0 ; System queue set yet???
  241. jz cq100 ; Nope, don't touch it
  242. mov bx,es:[hqSysQueue] ; set the input flag.
  243. or bx,bx
  244. jz cq100
  245. mov es,bx
  246. cmp es:[qCMsgs],0 ; Any messages in the system queue?
  247. mov es,ax
  248. jz cq100 ; No messages.
  249. or es:[qWakeBits],QS_INPUT ; Yes - tell the guy he has input.
  250. cq100:
  251. ;
  252. ; Return queue handle in ax.
  253. ;
  254. cqexit:
  255. cEnd
  256. ;============================================================================
  257. ;;;;;;;;;;;;;;;;;;;;;;;;;; START OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  258. COMMENT $ LOCAL
  259. DeleteQueue() - Remove current queue from queue list
  260. Unlink Queue from all lists, Delete the Q global object, then wake
  261. someone else.
  262. LINKAGE: NEAR PLM
  263. ENTRY:
  264. EFFECTS: current queue is removed from queue list and object is deleted.
  265. New task wakes up.
  266. hqSysLock = 0
  267. all registers modified.
  268. INTERNAL: UnlinkQ, SetWakeBit, WakeSomeone
  269. EXTERNAL: GlobalFree,
  270. WARNINGS: none
  271. REVISION HISTORY:
  272. IMPLEMENTATION:
  273. Unlink the queue from list of queues then unlink from all send lists.
  274. Then set the result bit for every queue with sendmessage waiting on
  275. this guy. Then free queue global object, and wakesomeone.
  276. $
  277. ;;;;;;;;;;;;;;;;;;;;;;;;;; END OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  278. cProc DeleteQueue,<PUBLIC, NEAR>, <SI>
  279. cBegin
  280. call HqCurrent
  281. mov si,ax ; si = hqCurrent.
  282. mov dx,_INTDS
  283. push dx ; Save for later
  284. mov ax,OFFSET hqList
  285. push dx
  286. push ax
  287. push si
  288. mov ax,qHqNext
  289. push ax
  290. call UnlinkQ ; UnlinkQ(lphqStart, hqCurrent, cbHqNext)
  291. pop es ; get INTDS
  292. jz dqexit ; if bad unlink, exit.
  293. ifndef WOW ; WOW doesn't have most USER16 structures to worry about.
  294. assumes es,INTDS
  295. EnterCrit
  296. xor bx,bx ; zero hqSysLock.
  297. mov es:[hqSysLock],bx
  298. mov es:[hqMouse],bx ; zero hqMouse.
  299. mov es:[hqKeyboard],bx ; zero hqKeyboard.
  300. mov bx,es:[hqList] ; Get the first guy in the list for
  301. mov es:[hqCursor],bx ; hqCursor.
  302. LeaveCrit
  303. ;
  304. ; Unlink this guy from everyone's hqSendList.
  305. ;
  306. mov cx,es:[hqList]
  307. assumes es,NOTHING
  308. dq100:
  309. mov es,cx
  310. jcxz dq200
  311. push es:[qHqNext]
  312. push cx ; Unlink this queue from all send
  313. mov ax,qHqSendList ; lists.
  314. push ax
  315. push si
  316. mov ax,qHqSendNext
  317. push ax ; UnlinkQ(lphqStart, hqUnlink, cbLink)
  318. call UnlinkQ
  319. pop cx ; Get the next hq.
  320. jmps dq100
  321. dq200:
  322. ;
  323. ; Now set the result bit of everyone waiting on a SendMsg response from
  324. ; this guy.
  325. ;
  326. mov es,si ; es = hqCurrent.
  327. mov cx,es:[qHqSendList]
  328. dq300:
  329. mov es,cx
  330. jcxz dq400 ; Are we at the end of the list?
  331. push es:[qHqSendNext]
  332. xor bx,bx
  333. mov word ptr es:[qResult],bx ; Zero out the result.
  334. mov word ptr es:[qResult+2],bx
  335. mov ax,QS_SMRESULT ; Tell this guy to wake up and
  336. call SetWakeBit2 ; get the result.
  337. pop cx
  338. jmps dq300
  339. endif ; WOW doesn't have most USER16 structures to worry about.
  340. dq400:
  341. xor ax,ax
  342. push ax
  343. push ax ; Set NULL queue
  344. call SetTaskQueue ; SetTaskQueue(NULL, NULL)
  345. push si
  346. call GlobalFree ; throw away the queue
  347. xor cx,cx
  348. ifndef WOW ; No need - user32 takes care of this for WOW
  349. call WakeSomeone ; wake someone up to process events
  350. endif ;WOW
  351. ; if anyone jumps here, he better do it with ints enabled!
  352. dqexit:
  353. cEnd
  354. ifndef WOW ; WOW doesn't ever put anything in the 16-bit Queue
  355. ;;;;;;;;;;;;;;;;;;;;;;;;;; START OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  356. COMMENT $ LOCAL
  357. WriteMessage (hq, lParam, wParam, message, hwnd, dwExtra) - Write a message
  358. to hq.
  359. If queue not full, Write message record at pmsgWrite, then advance pmsgWrite.
  360. SetWakeBit(hq) to tell him he has input.
  361. LINKAGE: NEAR PLM
  362. ENTRY: WORD hq handle to queue that gets message
  363. DWORD lParam lParam of message
  364. WORD wParam wParam of message
  365. WORD message message
  366. WORD hwnd associated window
  367. DWORD dwExtra dwExtraMsgInfo of the message
  368. EXIT: zero flag not set
  369. AX = pmsgWrite
  370. EXIT ERROR: zero flag set
  371. EFFECTS: Write pointer (pmsgWrite) to hq advanced to next message.
  372. QS_POSTMESSAGE set for hq.
  373. All registers changed
  374. INTERNAL: FQueueNotFull, SetWakeBit2
  375. EXTERNAL: none
  376. WARNINGS: the order of params on stack is assumed so we can do
  377. a rep movsb
  378. REVISION HISTORY:
  379. IMPLEMENTATION:
  380. Call FQueueNotFull which sets di = pmsgwrite if queue not full.
  381. Blt message bytes to queue at di, advance the write pointer,
  382. then SetWakeBit(hq, QS_POSTMESSAGE).
  383. $
  384. ;;;;;;;;;;;;;;;;;;;;;;;;;; END OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  385. cProc WriteMessage,<PUBLIC, NEAR>, <SI,DI,DS>
  386. ParmW hq
  387. ParmD lParam
  388. ParmW wParam
  389. ParmW message
  390. ParmW hwnd
  391. ParmD dwExtraInfo
  392. cBegin WriteMessage
  393. NewEnterCrit ax ; This trashes ax register
  394. push ds ; See if queue is full.
  395. mov ax,hq
  396. mov ds,ax
  397. mov es,ax
  398. assumes ds,NOTHING
  399. assumes es,NOTHING
  400. call FQueueNotFull ; Z flag set if FULL.
  401. jz pmexit
  402. push di ; Save Message pointer.
  403. pm30:
  404. mov cx,ds:[qCbEntry] ; Copy message into queue.
  405. shr cx,1
  406. push ds
  407. lea si,dwExtraInfo
  408. push ss
  409. pop ds
  410. cld
  411. errnz <size INTERNALSYSMSG - 7*2>
  412. errnz msgTime-10
  413. errnz imMsg-4
  414. movsw
  415. movsw
  416. movsw
  417. movsw
  418. movsw ; Store away the message.
  419. movsw
  420. movsw
  421. errnz <size INTERNALSYSMSG - 7*2>
  422. errnz msgTime-10
  423. errnz imMsg-4
  424. sub cx,7
  425. jcxz pm40 ; If have room, store time.
  426. push es
  427. call GetSystemMsecCount ; Tick count in dx:ax.
  428. pop es
  429. push ax
  430. mov ax,_INTDS
  431. mov ds,ax
  432. pop ax
  433. assumes ds,INTDS
  434. stosw
  435. mov ax,dx
  436. stosw
  437. sub cx,2
  438. jcxz pm40
  439. mov ax,word ptr ds:[ptCursor] ; If have room, store pt.
  440. stosw
  441. mov ax,word ptr ds:[ptCursor+2]
  442. stosw
  443. pm40:
  444. pop ds
  445. assumes ds,DATA
  446. pop bx ; reget ptr to msg
  447. push bx
  448. call rtestwrap ; advance pointer
  449. mov ds:[qPmsgWrite],bx
  450. inc ds:[qCMsgs] ; advance count
  451. mov ax,QS_POSTMESSAGE
  452. call SetWakeBit2 ; Tell this guy he has input.
  453. pm75:
  454. pop ax ; get back message ID
  455. pmexit:
  456. pop ds
  457. NewLeaveCrit dx, cx ; This trashes dx and cx registers
  458. cEnd WriteMessage
  459. ;;;;;;;;;;;;;;;;;;;;;;;;;; START OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  460. COMMENT $ LOCAL
  461. FQueueNotFull - IsQueueFull?
  462. If queue not full, get pmsgWrite and return TRUE.
  463. otherwise return FALSE.
  464. LINKAGE: register
  465. ENTRY: WORD ax - hq
  466. EXIT: ax - non zero. zero flag clear
  467. di - pmsgWrite (pointer to next write record.)
  468. EXIT ERROR: ax - 0; zero flag set
  469. EFFECTS: no other registers
  470. INTERNAL: none
  471. EXTERNAL: none
  472. WARNINGS: none
  473. REVISION HISTORY:
  474. IMPLEMENTATION:
  475. Advance write pointer. Error condition occurs only if
  476. pmsgWrite == pmsgRead && cMsg != 0.
  477. $
  478. ;;;;;;;;;;;;;;;;;;;;;;;;;; END OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  479. ;
  480. ; FQueueNotFull - zero in ax and Z flag if FULL, else cMsgLeft in ax, NZ
  481. ; flag set. Returns write pointer in di.
  482. ; AX has DS on entry.
  483. ;
  484. LabelNP <PUBLIC, FQueueNotFull>
  485. push ds
  486. assumes ds,NOTHING
  487. mov ds,ax
  488. mov di,ds:[qPmsgWrite] ; get write pointer and advance
  489. cmp di,ds:[qPmsgRead] ; if read == write, then we're either
  490. jnz qfNotFull
  491. xor ax,ax
  492. cmp ax,ds:[qCMsgs] ; cMsgs != 0 if empty
  493. jnz qfexit ; Jump if Full.
  494. qfNotFull:
  495. push es
  496. mov ax,_INTDS
  497. mov es,ax
  498. assumes es,INTDS
  499. mov ax,es:[cQEntries] ; See how many messages are left.
  500. assumes es,NOTHING
  501. pop es
  502. sub ax,ds:[qCMsgs] ; number of messages left
  503. qfexit:
  504. or ax,ax
  505. pop ds
  506. assumes ds,DATA
  507. ret
  508. ;;;;;;;;;;;;;;;;;;;;;;;;;; START OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  509. COMMENT $ LOCAL
  510. ReadMessage (hq, lpMsg, hwndFilter, msgMinFilter, msgMaxFilter, fRemoveMsg)
  511. Read a message from hq.
  512. If queue not empty, read message satisfying filter conditions from hq to *lpMsg.
  513. LINKAGE: FAR PLM
  514. ENTRY: WORD hq handle to queue to read from
  515. MSG *lpMsg far pointer to message buffer
  516. NOTE: This points to MSG struct and not INTERNALMSG.
  517. WORD hwndFilter Window filter
  518. WORD msgMinFilter min filter spec for message number
  519. WORD msgMaxFilter max filter spec for message number
  520. WORD fRemoveMsg Remove message if non-zero
  521. EXIT: zero flag not set
  522. ax = Non-Zero - we have a message.
  523. ax = 0 - we don't have a message.
  524. EXIT ERROR: zero flag set
  525. EFFECTS: All registers trashed
  526. QS_POSTMESSAGE wakebit cleared if no msgs left in app queue.
  527. INTERNAL: none
  528. EXTERNAL: none
  529. WARNINGS:
  530. REVISION HISTORY:
  531. SRL - 4/12 Fixed bug where if system queue was locked by someone else,
  532. it was being unlocked.
  533. SRL - 4/18 Fixed journalling.
  534. SRL - 5/4 Changed system queue journalling to call ScanSysQueue.
  535. (which used to be called FindMsgHq. It now does all the
  536. message enumeration).
  537. IMPLEMENTATION:
  538. If not quitting, look through the specified queue starting at pmsgRead
  539. for message that matches filters. Blt message to lpmsg, advance the read
  540. pointer. If out of queue messages, clear the input bit.
  541. Message matches hwndFilter if hwndFilter == 0 or hwndFilter == msgHwnd.
  542. Message matches msgMinFilter, msgMaxFilter if both are zero or
  543. msgMinFilter <= msg <= msgMaxFilter.
  544. $
  545. ;;;;;;;;;;;;;;;;;;;;;;;;;; END OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  546. ;
  547. ; ReadMessage(hq, lpMsg, hwndFilter, msgMinFilter, msgMaxFilter, fRemoveMsg)
  548. ;
  549. ; NOTE: lpMsg points to MSG structure and not INTERNALMSG.
  550. ;
  551. cProc ReadMessage, <PUBLIC, FAR>, <SI, DI,DS>
  552. ParmW hq
  553. ParmD lpMsg
  554. ParmW hwndFilter
  555. ParmW msgMinFilter
  556. ParmW msgMaxFilter
  557. ParmW fRemoveMsg
  558. cBegin
  559. push hq ; set ds to queue pointer
  560. pop ds
  561. assumes ds,NOTHING
  562. mov bx,fRemoveMsg ; pass this to rmquit
  563. call rmquit ; Must we quit?
  564. jnz rmexit ; Exit and be sure to leave the
  565. ; QS_POSTMESSAGE bit still set.
  566. ;
  567. ; Run through the queue and find a message that matches the filters.
  568. ;
  569. rm150:
  570. xor ax,ax
  571. cmp ds:[qCMsgs],ax
  572. jz rm500 ; nothing in queue: exit
  573. mov si,ds:[qPmsgRead] ; Get current read pointer.
  574. rm200:
  575. call rmcheckappqueue ; Check the app queue for a message
  576. jnz rm500 ; fitting the filters.
  577. rm400:
  578. call rtestwrap ; increment pointer in bx and copy to si
  579. mov si,bx
  580. jnz rm200 ; at end of queue if Z set
  581. xor ax,ax ; return FALSE
  582. rm500:
  583. EnterCrit
  584. cmp ds:[qCMsgs],0 ; If no messages left, and out the
  585. jnz rm600 ; input bit.
  586. cmp ds:[qCQuit],0 ; But only if not quitting
  587. jnz rm600
  588. and ds:[qWakeBits],NOT QS_POSTMESSAGE
  589. rm600:
  590. LeaveCrit
  591. rmexit:
  592. assumes es,NOTHING
  593. assumes ds,DATA
  594. cEnd
  595. assumes ds,NOTHING
  596. ; bx = fRemoveMsg
  597. rmquit:
  598. mov ax,ds:[qCQuit] ; Are we in the middle of quiting?
  599. or ax,ax ; if cQuit == 0, then continue
  600. jz rmq200 ; return Z.
  601. ; dec al ; if al == 2, then send quit msg
  602. ; jnz rmq100
  603. cmp ds:[qCMsgs],0 ; if queue not empty, don't send quit
  604. jnz rmq200
  605. ; inc ds:[qCQuit] ; set sticky quit & send quit msg
  606. or bx,bx
  607. jz rmq100 ; if PM_NOREMOVE, multiple WM_QUIT's
  608. mov ds:[qCQuit],0 ; give only one WM_QUIT(raor)
  609. rmq100:
  610. les bx,lpMsg
  611. mov es:[bx].msgMessage,WM_QUIT ; send a WM_QUIT
  612. mov es:[bx].msgHwnd,NULL ; null window handle
  613. mov ax,ds:[qExitCode] ; stick the exit code in wParam
  614. mov es:[bx].msgWParam,ax
  615. or al,TRUE
  616. ret
  617. rmq200:
  618. xor ax,ax
  619. ret
  620. ;
  621. ; If the hq is an app queue, we can filter immediately.
  622. ;
  623. rmcheckappqueue:
  624. mov bx,ds:[si].ismMsg.msgHwnd ; see if hwnd satisfies hwndFilter
  625. mov cx,hwndFilter
  626. call CheckHwndFilter2
  627. mov bx,si ; copy read ptr into bx
  628. jz rmc200 ; bad luck - try next one
  629. mov ax,ds:[si].ismMsg.msgMessage ; see if msgMinFilter <= msg <= msgMaxFilter
  630. mov cx,msgMinFilter ; cx = msgMinFilter
  631. mov dx,msgMaxFilter ; dx = msgMaxFilter
  632. call CheckMsgFilter2 ; Z if no message.
  633. jz rmc200
  634. ;
  635. ; We've found a message -- read it into lpMsg
  636. ;
  637. les di,lpMsg ; get pointer to event block
  638. mov cx,ds:[qCbEntry]
  639. sub cx, size INTERNALMSG - size MSG
  640. push si ; preserve ptr to ExtraMsgInfo
  641. add si, size INTERNALMSG - size MSG
  642. cld
  643. rep movsb ; copy message structure & advance rd ptr
  644. ;
  645. ; save away time, id, and position of this event in queue header
  646. ;
  647. ; NOTE: this code doesn't work for the system queue, but that's ok since we
  648. ; don't use the queue's time anyway.
  649. ;
  650. sub si,size MSG - msgTime ; point at saved time
  651. mov di,qTimeLast ;
  652. push ds ; copy into ES too
  653. pop es
  654. movsw ; copy time and position
  655. movsw
  656. errnz qPtLast-qTimeLast-4
  657. movsw
  658. movsw
  659. mov ax,bx ; store position of msg in q header
  660. stosw
  661. errnz qIdLast-qPtLast-4
  662. pop si ; Restore ptr to ExtraMsgInfo
  663. errnz qdwExtraInfoLast-qIdLast-2
  664. errnz <size INTERNALMSG - size MSG - 4>
  665. movsw
  666. movsw
  667. cmp fRemoveMsg,0 ; are we supposed to yank the message?
  668. jnz rmc100 ; yes: take it out
  669. mov ds:[qIdLast],1 ; stick something random in qidLast
  670. jmps rmc150 ; so we don't reply until it's yanked
  671. rmc100:
  672. call DelQEntry ; delete queue entry & update ptrs
  673. rmc150:
  674. mov ax,bx ; return ID value, TRUE, NZ.
  675. or ax,ax
  676. rmc200:
  677. ret
  678. assumes ds,DATA
  679. ;;;;;;;;;;;;;;;;;;;;;;;;;; START OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  680. COMMENT $ PRIVATE
  681. DelQEntry - Delete a queue message entry.
  682. Delete message entry from queue. Adjust pmsgRead, pmsgWrite
  683. and cMsgs.
  684. LINKAGE: register
  685. ENTRY: WORD bx - pointer to entry to delete
  686. WORD ds - hq
  687. EXIT: void
  688. EFFECTS: pmsgRead and pmsgWrite are adjusted, and part of rgMsg
  689. is blt'ed to fill hole left by deleted message.
  690. Trashes es, si, di
  691. INTERNAL: none
  692. EXTERNAL: none
  693. WARNINGS: none
  694. REVISION HISTORY:
  695. IMPLEMENTATION:
  696. disable interrupts, change cMsgs, pmsgRead, pmsgWrite, then
  697. rep movsb from bottom up.
  698. $
  699. ;;;;;;;;;;;;;;;;;;;;;;;;;; END OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  700. LabelNP <PUBLIC, DelQEntry>
  701. assumes DS,NOTHING
  702. EnterCrit
  703. push ds
  704. pop es
  705. dec ds:[qCMsgs] ; decrement count
  706. mov ax,ds:[qCbEntry]
  707. mov si,ds:[qPmsgRead]
  708. mov di,ds:[qPmsgWrite]
  709. cmp si,bx ; compare sptr to dptr
  710. ja de500
  711. ;
  712. ; rptr < dptr: blt stuff below up
  713. ; move(rptr, rptr+1, dptr-rptr)
  714. ; rptr++;
  715. ;
  716. std ; blt backwards
  717. mov cx,bx ; cb = dptr-rptr
  718. sub cx,si
  719. mov si,bx ; src = dptr
  720. dec si ; point at first byte to copy
  721. mov di,si ; dest = src + size(entry)
  722. add di,ax
  723. rep movsb ; copy those bytes
  724. inc di ; readjust DI
  725. cmp di,ds:[qPmsgMax] ; update read pointer
  726. jb de200 ; checking for wraparound
  727. mov di,qRgmsg
  728. de200:
  729. mov ds:[qPmsgRead],di
  730. cld
  731. LeaveCrit
  732. ret
  733. ;
  734. ; rptr > dptr: blt stuff above down
  735. ; wptr--;
  736. ; move(dptr + 1, dptr, wptr - dptr)
  737. ;
  738. de500:
  739. cld
  740. mov si,bx ; src = dptr + size(entry)
  741. add si,ax
  742. mov cx,di ; cb = (wptr - (dptr + size(entry)))
  743. sub cx,si
  744. mov di,bx ; dest = dptr
  745. rep movsb ; copy those bytes
  746. mov ds:[qPmsgWrite],di ; update write pointer
  747. LeaveCrit
  748. ret
  749. ;
  750. ; increment read ptr in bx, testing for wraparound
  751. ;
  752. LabelNP <PUBLIC, rtestwrap>
  753. add bx,ds:[qCbEntry] ; advance pointer
  754. cmp bx,ds:[qPmsgMax] ; wrap around if needed
  755. jb tw50
  756. mov bx,qRgmsg
  757. tw50:
  758. cmp bx,ds:[qPmsgWrite] ; set CC's if end of queue
  759. ret
  760. assumes ds,DATA
  761. endif ; WOW doesn't ever put anything in the 16-bit Queue
  762. ;;;;;;;;;;;;;;;;;;;;;;;;;; START OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  763. COMMENT $ LOCAL
  764. LinkQ (lphqStart, hqLink, ibLink) - Add Q to linked list.
  765. Add new queue entry to END of linked list starting at lphqStart and
  766. linked by ibLink. ibLink can be qHqNext or qHqSendNext.
  767. LINKAGE: NEAR PLM
  768. ENTRY: DWORD lphqStart (parm1) - far pointer to start of queue list
  769. WORD hqLink (parm2) - handle of queue to be linked
  770. WORD ibLink (parm3) - byte index to link to be used in
  771. Q structure.
  772. EXIT: ax contains hqLink
  773. EFFECTS: all registers modified.
  774. INTERNAL: none
  775. EXTERNAL: none
  776. WARNINGS: none
  777. REVISION HISTORY:
  778. IMPLEMENTATION:
  779. Walk the linked list starting at lphqStart till hqNext is NULL indicating
  780. end of list. Add new entry to list there.
  781. $
  782. ;;;;;;;;;;;;;;;;;;;;;;;;;; END OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  783. LabelNP <PUBLIC, LinkQ>
  784. ; ret = 0+2 (saved si)
  785. ; ibLink = 2+2
  786. ; hqLink = 4+2
  787. ; lpHqStart = 6+2
  788. ;
  789. push si
  790. mov si,sp
  791. EnterCrit
  792. les bx,ss:[si+8] ; Get lpHqStart
  793. lnk100:
  794. mov cx,word ptr es:[bx] ; Check for end of the list.
  795. jcxz lnk200
  796. mov es,cx ; Get Next Link.
  797. mov bx,ss:[si+4] ; BX = ibLink.
  798. jmps lnk100
  799. lnk200:
  800. mov ax,ss:[si+6] ; Store hqLink at end of list.
  801. mov word ptr es:[bx],ax
  802. mov es,ax ; AX = hqLink.
  803. mov bx,ss:[si+4]
  804. mov word ptr es:[bx],cx ; CX = 0. Zero out pNext.
  805. LeaveCrit
  806. pop si
  807. ret 8
  808. ;;;;;;;;;;;;;;;;;;;;;;;;;; START OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  809. COMMENT $ LOCAL
  810. UnlinkQ (lphqStart, hqLink, ibLink) - Unlink Q from list.
  811. Unlink queue specified by hqLink from linked list starting at lphqStart and
  812. linked by ibLink. ibLink can be qHqNext or qHqSendNext.
  813. LINKAGE: NEAR PLM
  814. ENTRY: DWORD lphqStart (parm1) - far pointer to start of queue list
  815. WORD hqLink (parm2) - handle of queue to be unlinked
  816. WORD ibLink (parm3) - byte index to link to be used in
  817. Q structure.
  818. EXIT: ax contains handle of unlinked queue, zero flag clear
  819. EXIT ERROR - zero flag is set
  820. EFFECTS: all registers modified.
  821. INTERNAL: none
  822. EXTERNAL: none
  823. WARNINGS: none
  824. REVISION HISTORY:
  825. IMPLEMENTATION:
  826. Walk the linked list starting at lphqStart till hqLink is found and
  827. unlink.
  828. $
  829. ;;;;;;;;;;;;;;;;;;;;;;;;;; END OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  830. LabelNP <PUBLIC, UnlinkQ>
  831. ;
  832. ;
  833. ; ret = 0+2+ (pushed si)
  834. ; cbLink = 2+2
  835. ; hq = 4+2
  836. ; lpHqStart = 6+2
  837. ;
  838. assumes ds,NOTHING
  839. push si
  840. mov si,sp
  841. push di
  842. push ds
  843. EnterCrit
  844. les di,ss:[si+8] ; Get lpHqStart.
  845. mov bx,ss:[si+6] ; Get hqUnlink.
  846. ulq100:
  847. mov cx,es:[di] ; Exit with zero if at end of list.
  848. jcxz ulqExit
  849. cmp cx,bx ; Have we found the guy that points
  850. jz ulq200 ; to hqUnlink?
  851. mov es,cx ; Point to the next guy and continue.
  852. mov di,ss:[si+4]
  853. jmps ulq100
  854. ulq200:
  855. mov ds,bx ; Get the hq that hqUnlink points to.
  856. mov bx,ss:[si+4]
  857. mov bx,ds:[bx]
  858. mov es:[di],bx ; Store in hqLinkNext of the guy
  859. ; previous to hqUnlink.
  860. ulqExit:
  861. LeaveCrit
  862. or cx,cx
  863. pop ds
  864. pop di
  865. pop si
  866. ret 8
  867. assumes DS,DATA
  868. ifndef WOW ; WOW thunks SetMessageQueue
  869. ;;;;;;;;;;;;;;;;;;;;;;;;;; START OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  870. COMMENT $ LOCAL
  871. BOOL SetMessageQueue(cMsg)
  872. This function is available to the task that desires a larger message
  873. queue than the default. This routine must be called from the
  874. applications' WinMain routine as soon as possible. It must not be
  875. called after any operation that could generate messages (such as
  876. a CreateWindow). Any messages currently in the queue will be
  877. destroyed. By default, the system creates a default queue with room
  878. for 8 messages.
  879. LINKAGE: FAR PLM
  880. ENTRY: WORD cMsg - The size of the new queue in messages.
  881. EXIT: ax contains:
  882. TRUE: If new queue is sucessfully created.
  883. FALSE: If there was an error creating the new queue. In this case,
  884. the application has no queue associated with it (since the
  885. origional queue is deleted first). The application MUST
  886. call SetMessageQueue with a smaller size until a TRUE is
  887. returned (or the application may terminate itself).
  888. EFFECTS: SI, DI preserved.
  889. INTERNAL: none
  890. EXTERNAL: none
  891. WARNINGS: none
  892. REVISION HISTORY:
  893. IMPLEMENTATION:
  894. Call DeleteQueue()
  895. Call CreateQueue(cMsg)
  896. $
  897. ;;;;;;;;;;;;;;;;;;;;;;;;;; END OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  898. cProc SetMessageQueue, <PUBLIC, FAR, EXPORTED>, <SI, DI>
  899. ParmW cMsg
  900. cBegin
  901. call DeleteQueue
  902. mov ax,cMsg
  903. push ax
  904. call CreateQueue
  905. cEnd
  906. endif ; WOW thunks SetMessageQueue
  907. sEnd CODE
  908. end