Leaked source code of windows server 2003
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.

790 lines
20 KiB

  1. ;++
  2. ;
  3. ; WOW v1.0
  4. ;
  5. ; Copyright (c) 1991, Microsoft Corporation
  6. ;
  7. ; WINMISC2.ASM
  8. ; Win16 misc. user services
  9. ;
  10. ; History:
  11. ;
  12. ; Created 28-May-1991 by Jeff Parsons (jeffpar)
  13. ; Copied from WIN31 and edited (as little as possible) for WOW16
  14. ;--
  15. ;****************************************************************************
  16. ;* *
  17. ;* WINMISC2.ASM - *
  18. ;* *
  19. ;* Random stuff *
  20. ;* *
  21. ;****************************************************************************
  22. ifdef WOW
  23. SEGNAME equ <TEXT>
  24. endif
  25. .xlist
  26. include user.inc
  27. include vint.inc
  28. .list
  29. ExternFP <GlobalHandleNorip>
  30. ExternFP <MessageBox>
  31. ExternFP <SysErrorBox>
  32. ifndef WOW
  33. ExternFP <DoBeep>
  34. ExternFP <XCSTODS>
  35. ExternNP <rgbKeyState>
  36. ExternW <hwndCapture>
  37. ExternW <fBeep>
  38. ExternW <fMessageBox>
  39. ExternW <hwndDragIcon>
  40. ExternA <__WinFlags>
  41. ATOMTABLE STRUC
  42. at_prime DW ?
  43. at_hashTable DW ?
  44. ATOMTABLE ENDS
  45. ATOM STRUC
  46. a_chain DW ?
  47. a_usage DW ?
  48. a_len DB ?
  49. a_name DB ?
  50. ATOM ENDS
  51. LocalArena STRUC
  52. la_prev DW ? ; previous arena entry (first entry points to self)
  53. la_next DW ? ; next arena entry (last entry points to self)
  54. la_handle DW ? ; back link to handle table entry
  55. LocalArena ENDS
  56. sBegin DATA
  57. ;
  58. ; For GetSysMetrics - don't move this stuff. DS positioning is assumed.
  59. ;
  60. SM_CMETRICS1 equ 24
  61. SM_CMETRICS2 equ 16
  62. public rgwSysMet
  63. rgwSysMet dw (SM_CMETRICS1) DUP(0)
  64. ; These are 'variable metrics', conviently located the system metrics array.
  65. GlobalW hwndFullScrn, 0
  66. GlobalW iLevelCursor, 0
  67. ; These are additions since 2.0
  68. dw SM_CMETRICS2 DUP(0)
  69. sEnd DATA
  70. endif ;WOW
  71. createSeg _%SEGNAME, %SEGNAME, WORD, PUBLIC, CODE
  72. assumes cs,%SEGNAME
  73. assumes ds,DATA
  74. sBegin %SEGNAME
  75. ifndef WOW
  76. ;*--------------------------------------------------------------------------*
  77. ;* *
  78. ;* GetSystemMetrics() - *
  79. ;* *
  80. ;*--------------------------------------------------------------------------*
  81. ; int far GetSystemMetrics(iMetric)
  82. ; int iMetric;
  83. LabelFP <PUBLIC, GetSystemMetrics>
  84. pop ax ; Pop the FAR return
  85. pop dx
  86. pop bx ; BX = iMetric
  87. push dx ; Restore the FAR return
  88. push ax
  89. xor ax,ax
  90. cmp bx,SM_CMETRICSMAX ; Bigger than max?
  91. jge gsmExit ; Yes, exit
  92. shl bx,1 ; Convert to a byte index
  93. ifndef userhimem
  94. mov es,WORD PTR cs:[cstods]
  95. else
  96. push ax
  97. push ds
  98. call XCSTODS
  99. mov es,ax
  100. pop ds
  101. pop ax
  102. endif
  103. assumes es,DATA
  104. mov ax,es:[rgwSysMet+bx] ; Return the SysMetric value
  105. assumes es,NOTHING
  106. gsmExit:
  107. retf
  108. ;*--------------------------------------------------------------------------*
  109. ;* *
  110. ;* MessageBeep() - *
  111. ;* *
  112. ;*--------------------------------------------------------------------------*
  113. cProc MessageBeep, <FAR, PUBLIC>
  114. ParmW beep
  115. cBegin
  116. cmp fBeep,0
  117. je mbout ; No beeps today....
  118. mov ax,beep
  119. cmp fMessageBox,0 ; if we are in an INT24 box, let
  120. je noint24 ; the sound driver know not to load
  121. mov ax,-1 ; anything by passing -1.
  122. noint24:
  123. push ax
  124. call DoBeep ; Just call the sound driver guy
  125. mbout:
  126. cEnd
  127. ;*--------------------------------------------------------------------------*
  128. ;* *
  129. ;* IsChild() - *
  130. ;* *
  131. ;*--------------------------------------------------------------------------*
  132. LabelFP <PUBLIC, IsChild>
  133. ;
  134. ;ParmW hwnd
  135. ;ParmW hwndChild
  136. ;
  137. pop ax ; pop return address
  138. pop dx
  139. pop bx ; bx = hwndChild
  140. pop cx ; cx = hwnd
  141. push dx ; push return address
  142. push ax
  143. push ds
  144. UserDStoDS ; es = USER's DS
  145. CheckHwnd cx ; checkhwnd will zero ax if failure
  146. jz icexit
  147. ifdef DEBUG
  148. CheckHwndNull bx ; only do check if debug since
  149. jz icexit ; we never access anything off this
  150. ; pointer
  151. endif
  152. xor ax,ax ; Assume FALSE
  153. icloop:
  154. or bx,bx ; while (hwndChild == NULL &&
  155. jz icexit
  156. mov dl,byte ptr [bx+WSTATE+WFTYPEMASK/256]
  157. and dl,LOW(WFTYPEMASK) ; TestwndChild(hwndChild))
  158. cmp dl,LOW(WFCHILD)
  159. jne icexit
  160. mov bx,[bx].wndPwndParent ; hwndChild = hwndChild->hwndParent
  161. cmp bx,cx ; if (hwnd == hwndChild)
  162. jne icloop
  163. inc al ; return(TRUE);
  164. icexit:
  165. pop ds
  166. retf
  167. ; BOOL IsDescendant(hwndParent, hwndChild);
  168. ;
  169. ; Internal version of IsChild that is a bit faster and ignores the
  170. ; WFCHILD business. MUST be called with DS == USER DS.
  171. ;
  172. ; Returns TRUE if hwndChild == hwndParent (IsChild doesn't)
  173. ;
  174. ; while (hwndChild != NULL)
  175. ; {
  176. ; if (hwndParent == hwndChild)
  177. ; return TRUE;
  178. ; hwndChild = hwndChild->hwndParent;
  179. ; }
  180. ;
  181. LabelFP <PUBLIC, IsDescendant>
  182. pop ax ; pop off return address
  183. pop dx
  184. pop bx ; bx = hwndChild
  185. pop cx ; cx = hwndParent
  186. push dx ; replace return address
  187. push ax
  188. xor ax,ax ; assume FALSE
  189. idloop:
  190. or bx,bx ; if at end, return FALSE
  191. jz idexit
  192. cmp bx,cx ; hwndChild == hwndParent?
  193. mov bx,[bx].wndPwndParent ; hwndChild = hwndChild->hwndParent
  194. jnz idloop ; keep looping if we didn't find it...
  195. inc al ; ax = TRUE
  196. idexit:
  197. retf
  198. ;--------------------------------------------------------------------------
  199. ;
  200. ; IsWindowVisible() -
  201. ;
  202. ;--------------------------------------------------------------------------
  203. ;
  204. ; BOOL FAR PASCAL IsWindowVisible(register HWND hwnd)
  205. ; {
  206. ; if (!CheckHwnd(hwnd))
  207. ; return(FALSE);
  208. ;
  209. ; if (hwnd == hwndDragIcon)
  210. ; return(TRUE);
  211. ;
  212. ; for ( ; hwnd != NULL; hwnd = hwnd->hwndParent)
  213. ; {
  214. ; if (!TestWF(hwnd, WFVISIBLE))
  215. ; return FALSE;
  216. ; }
  217. ; return TRUE;
  218. ; }
  219. ;
  220. LabelFP <PUBLIC, IsWindowVisible>
  221. ;ParmW hwnd
  222. pop ax ; pop return address
  223. pop dx
  224. pop bx ; bx = hwnd
  225. push dx ; push return address
  226. push ax
  227. push ds
  228. UserDStoDS ; es = USER's DS
  229. CheckHwnd bx ; checkhwnd will zero ax if failure
  230. jz ivwexit
  231. mov ax,TRUE ; assume TRUE
  232. ; Check if this is the iconic window being moved around with a mouse */
  233. ; If so, return a TRUE, though, strictly speaking, it is hidden. */
  234. ; This helps the Tracer guys from going crazy! */
  235. ; Fix for Bug #57 -- SANKAR -- 08-08-89 -- */
  236. ;
  237. cmp bx,hwndDragIcon ; hwnd == hwndDragIcon?
  238. jz ivwexit ; yes: return TRUE.
  239. ivwloop:
  240. or bx,bx ; while (hwndChild == NULL &&
  241. jz ivwexit
  242. TSTWF bx,WFVISIBLE
  243. mov bx,[bx].wndPwndParent ; hwndChild = hwndChild->hwndParent
  244. jnz ivwloop ; if visible bit set, keep looping
  245. xor ax,ax ; visible bit clear: return FALSE
  246. ivwexit:
  247. pop ds
  248. retf
  249. ;=======================================================================
  250. ;
  251. ; Return whether or not a given window can be drawn in or not.
  252. ;
  253. ; BOOL FAR IsVisible(HWND hwnd, BOOL fClient)
  254. ; {
  255. ; HWND hwndT;
  256. ;
  257. ; for (hwndT = hwnd; hwndT != NULL; hwndT = hwndT->hwndParent)
  258. ; {
  259. ; // Invisible windows are always invisible
  260. ; //
  261. ; if (!TestWF(hwndT, WFVISIBLE))
  262. ; return FALSE;
  263. ;
  264. ; if (TestWF(hwndT, WFICONIC))
  265. ; {
  266. ; // Children of icons are always invisible.
  267. ; //
  268. ; if (hwndT != hwnd)
  269. ; return FALSE;
  270. ;
  271. ; // Client areas with class icons are always invisible.
  272. ; //
  273. ; if (fClient && hwndT->pcls->hIcon)
  274. ; return FALSE;
  275. ; }
  276. ; }
  277. ; return TRUE;
  278. ; }
  279. ;
  280. LabelFP <PUBLIC, IsVisible>
  281. pop ax
  282. pop dx
  283. pop cx ; cx = fClient
  284. pop bx ; bx = hwnd
  285. push dx
  286. push ax
  287. mov dx,bx ; hwnd = dx, bx = hwndT
  288. xor ax,ax ; assume FALSE return
  289. jmps iv100 ; fall into loop...
  290. ivloop:
  291. mov bx,[bx].wndPwndParent ; hwndChild = hwndChild->hwndParent
  292. iv100:
  293. or bx,bx
  294. jz ivtrue ; Reached the top: return TRUE
  295. TSTWF bx,WFVISIBLE ; if not visible, get out of here.
  296. jz ivfalse
  297. TSTWF bx,WFMINIMIZED ; if not minimized, keep looping
  298. jz ivloop
  299. cmp bx,dx ; if (hwnd != hwndT)
  300. jnz ivfalse ; return FALSE
  301. jcxz ivloop ; if fClient == FALSE, keep going.
  302. mov bx,[bx].wndPcls
  303. mov bx,[bx].uclshIcon
  304. or bx,bx
  305. jnz ivfalse
  306. mov bx,dx ; resume enumeration at bx
  307. jmps ivloop ; keep looping...
  308. ivtrue:
  309. inc al ; ax = TRUE
  310. ivfalse:
  311. retf
  312. ;*--------------------------------------------------------------------------*
  313. ;* *
  314. ;* GetMenu() - *
  315. ;* *
  316. ;*--------------------------------------------------------------------------*
  317. cProc GetMenu, <FAR, PUBLIC>,<si>
  318. ParmW hwnd
  319. cBegin
  320. mov si,hwnd
  321. CheckHwnd si
  322. jz gmexit
  323. mov ax,[si].wndhMenu
  324. gmexit:
  325. cEnd
  326. endif ;WOW
  327. ;*--------------------------------------------------------------------------*
  328. ;* *
  329. ;* SwapHandle() - *
  330. ;* *
  331. ;*--------------------------------------------------------------------------*
  332. ; Takes a far pointer to a word on the stack and converts it from a handle
  333. ; into a segment address or vice-versa. Note that this function is a NO OP
  334. ; in protect mode.
  335. ifndef PMODE
  336. cProc SwapHandle, <PUBLIC, FAR, NODATA, ATOMIC>
  337. ParmD lpHandle
  338. cBegin
  339. ifndef WOW
  340. mov ax,__WinFlags
  341. test ax,1
  342. jnz sh200 ; SwapHandle is a no op in pmode.
  343. endif
  344. ; Save the parameter.
  345. mov bx,off_lpHandle
  346. push bx
  347. ; Get the handle/segment
  348. mov ax,word ptr ss:[bx]+2
  349. push ax ; Save it
  350. ; Call GlobalHandleNorip which puts the proper handle in AX
  351. ; and the corresponding segment address in DX.
  352. push ax
  353. call GlobalHandleNorip
  354. ; Restore the original word.
  355. pop bx
  356. ; If DX==CS then we know we've converted a handle into a segment.
  357. ; This prevents problems with the FFFE segment.
  358. mov cx,cs
  359. cmp dx,cx
  360. je sh50
  361. ; Was the original word a segment address?
  362. test bl,1
  363. jnz sh100 ; Yes, AX = handle, DX = segment
  364. sh50: xchg ax,dx ; Nope, AX = segment, DX = handle
  365. ; Restore the pointer to the original word.
  366. sh100: pop bx
  367. ; Skip if zero.
  368. or ax,ax
  369. jz sh200
  370. ; Move the result into the original word pointed to.
  371. mov word ptr ss:[bx]+2,ax
  372. sh200:
  373. cEnd
  374. endif ;PMODE
  375. ifndef WOW
  376. ;*--------------------------------------------------------------------------*
  377. ;* *
  378. ;* SwapMouseButton() - *
  379. ;* *
  380. ;*--------------------------------------------------------------------------*
  381. ; BOOL SwapMouseButton(fSwap)
  382. ; BOOL fSwap;
  383. LabelFP <PUBLIC, SwapMouseButton>
  384. mov ax,_INTDS
  385. mov es,ax
  386. assumes es,INTDS
  387. mov ax,es:fSwapButtons ; Return fSwapButtons' old value
  388. pop cx ; Pop off the FAR return
  389. pop dx
  390. pop es:[fSwapButtons] ; fSwapButtons = fSwap
  391. mov bx,es:[fSwapButtons]
  392. assumes es,NOTHING
  393. mov es,WORD PTR cs:[cstods] ; Get user's ds
  394. assumes es,DATA
  395. mov es:[rgwSysMet+SM_SWAPBUTTON*2],bx
  396. assumes es,NOTHING
  397. push dx ; Restore the FAR return
  398. push cx
  399. retf
  400. assumes es,NOTHING
  401. endif; Not WOW
  402. ;*--------------------------------------------------------------------------*
  403. ;* *
  404. ;* SetDivZero() - *
  405. ;* *
  406. ;*--------------------------------------------------------------------------*
  407. LabelFP <PUBLIC, SetDivZero>
  408. push ds
  409. push cs ; Set DS == CS
  410. pop ds
  411. ifndef userhimem
  412. mov dx,Offset DivideByZero
  413. else
  414. push ds
  415. mov ax, _INTDS
  416. mov ds,ax
  417. assumes ds,INTDS
  418. mov ax,fffedelta
  419. pop ds
  420. assumes ds,DATA
  421. add ax,Offset DivideByZero
  422. mov dx,ax
  423. endif
  424. sdzvector:
  425. mov ax,2500h ; Use DOS to set interrupt zero
  426. int 21h
  427. pop ds
  428. retf
  429. ;*--------------------------------------------------------------------------*
  430. ;* *
  431. ;* DivideByZero() - *
  432. ;* *
  433. ;*--------------------------------------------------------------------------*
  434. LabelFP <PUBLIC, DivideByZero>
  435. FSTI
  436. ifdef DEBUG
  437. pusha
  438. push es
  439. endif
  440. ; Put up the system modal message box.
  441. mov cx,_INTDS
  442. ifdef WOW
  443. ; Put up the SysErrorBox Directly
  444. push cx
  445. lea ax,szDivZero
  446. push ax
  447. push cx
  448. lea ax,szSysError
  449. push ax
  450. ifdef DEBUGlater
  451. push SEB_CLOSE
  452. push 0
  453. push SEB_CANCEL
  454. call SysErrorBox
  455. cmp ax,SEB_BTN1
  456. jz DBZ_Terminate
  457. pop es
  458. popa
  459. DebugErr DBF_FATAL, "Divide by zero or divide overflow error: break and trace till IRET"
  460. iret
  461. DBZ_Terminate:
  462. pop es
  463. popa
  464. else ; FREE Build
  465. push 0 ; no button 1
  466. push SEB_CLOSE ; only allow close
  467. push 0 ; no button 3
  468. call SysErrorBox
  469. endif; FREE Build
  470. mov ax,4C00h ; Abort the task with a 0
  471. int 21h
  472. else; Not WOW
  473. xor ax,ax
  474. push ax ; NULL hwnd
  475. lea ax,szDivZero
  476. push cx
  477. push ax ; Message Text
  478. lea ax,szSysError
  479. push cx
  480. push ax ; Caption Text
  481. ifdef DEBUG
  482. mov ax,MB_SYSTEMMODAL OR MB_ICONHAND OR MB_OKCANCEL
  483. else
  484. mov ax,MB_SYSTEMMODAL OR MB_ICONHAND
  485. endif
  486. push ax
  487. call MessageBox
  488. ifdef DEBUG
  489. cmp ax,1 ; If OK Button clicked, terminate app
  490. jz DBZ_Terminate
  491. pop es
  492. popa
  493. DebugErr DBF_FATAL, "Divide by zero or divide overflow error: break and trace till IRET"
  494. iret
  495. DBZ_Terminate:
  496. pop es
  497. popa
  498. endif
  499. endif; Not WOW
  500. mov ax,4C00h ; Abort the task with a 0
  501. int 21h
  502. ifndef WOW
  503. ;-------------------------------------------------------------------------
  504. ;
  505. ; word FAR PASCAL GetUserLocalObjType(pObj)
  506. ; Given a near pointer to an object in USER's local heap, this function
  507. ; determines the type of the object and returns it;
  508. ; It finds out if the given object is a non-tagged belonging to the atom
  509. ; table; If not, it looks at the tag and returns the object type.
  510. ;
  511. ; WARNING: Because this function determines the type of the object by
  512. ; the process of elimination, the results will be unpredictable if the
  513. ; input in incorrect. i.e., no validation is done on the input value;
  514. ; To validate if the input value is indeed an object in USER's heap would
  515. ; warant a walk down the heap; This will be very costly, if done for
  516. ; every call; Apps like HeapWalker are expected to walk down the USER's
  517. ; local heap and make calls to this function for every object thay come
  518. ; accross; So, a validation done here is duplication of effort and affect
  519. ; the performance unnecessarily
  520. ;
  521. ;
  522. ;-------------------------------------------------------------------------
  523. ifndef DEBUG
  524. ; The following is in the RETAIL version of USER
  525. LabelFP <PUBLIC, GetUserLocalObjType>
  526. xor ax, ax ; Return Unknown struct type
  527. retf 2 ; Compensate for the WORD parameter
  528. else
  529. ; The following is in the DEBUG version of USER
  530. cProc GetUserLocalObjType, <PUBLIC, FAR>, <si, di>
  531. ParmW pObj ; Near pointer to an OBJ in USER's heap
  532. cBegin
  533. ; Now DS register is pointing to USER's DS
  534. ;
  535. ; Check if the object is a moveable object
  536. mov bx, pObj
  537. mov ax, [bx].la_prev
  538. test ax, 01 ; is it a free object
  539. jz FoundFreeObj
  540. test ax, 02 ; Is it a moveable object
  541. jz FoundFixedObj
  542. ; Now, it is a moveable obj; So, we have the tags
  543. mov al, byte ptr [bx + SIZE LocalArena]
  544. xor ah, ah
  545. jmps FoundObjType
  546. FoundFreeObj:
  547. mov ax, ST_FREE
  548. jmps FoundObjType
  549. FoundFixedObj:
  550. ; Assume that the object belongs to atom table
  551. mov ax, ST_ATOMS
  552. ; Check if this object is the atom table itself
  553. add bx, SIZE LocalArena - 2
  554. cmp bx, ds:[8] ; pAtomTable is at this offset.
  555. je FoundObjType
  556. ; Check if this is possibly an atom string. If so, the first word
  557. ; stored in this object is a ptr to the next string or NULL;
  558. ; Check if the last two bits are zero; If they are not zero, then
  559. ; this can not be an atom; If they are zero, this may or may not be
  560. ; an atom;
  561. mov cx, [bx]
  562. and cx, 03h
  563. jnz NotAnAtom
  564. ; Now walk down the atom table and check each entry against the
  565. ; given object
  566. mov dx, bx ; save the near pointer to the object
  567. mov bx, ds:[8] ; Get the pointer to the atom table pAtomTable
  568. mov cx, [bx].at_prime ; Get the number of entries
  569. ; Skip to the first entry in the atom table
  570. errnz <at_hashtable - 2>
  571. AtomLoop2:
  572. errnz <SIZE at_hashtable - 2>
  573. add bx, 2 ;
  574. errnz <a_chain>
  575. mov si, [bx] ; Pointer to the next string
  576. AtomLoop:
  577. or si, si
  578. jz NextBucket ; Goto NextBucket
  579. ;Check the new atom matches the given object
  580. cmp si, dx
  581. jz FoundObjType ; AX already has ST_ATOMS in it
  582. mov si, [si].a_chain
  583. jmps AtomLoop
  584. NextBucket:
  585. loop AtomLoop2
  586. mov bx, dx ; Make bx point to the first byte of the object
  587. NotAnAtom:
  588. ; bx points to the tag byte of the object
  589. xor ah, ah
  590. mov al, byte ptr [bx]
  591. FoundObjType:
  592. ; ax already contains the proper return value
  593. cEnd
  594. endif
  595. endif ;WOW
  596. ;*--------------------------------------------------------------------------*
  597. ;* *
  598. ;* mouse_event() - *
  599. ;* *
  600. ;*--------------------------------------------------------------------------*
  601. ; Mouse interrupt event routine
  602. ;
  603. ; Entry: (ax) = flags:
  604. ; 01h = mouse move
  605. ; 02h = left button down
  606. ; 04h = left button up
  607. ; 08h = right button down
  608. ; 10h = right button up
  609. ; 20h = middle button down
  610. ; 40h = middle button up
  611. ; 8000h = absolute move
  612. ; (bx) = dX
  613. ; (cx) = dY
  614. ; (dx) = # of buttons, which is assumed to be 2.
  615. ; (si) = extra info loword (should be null if none)
  616. ; (di) = extra info hiword (should be null if none)
  617. ;
  618. ; Exit: None
  619. ;
  620. ; Uses: All registers
  621. ;
  622. ExternFP <MouseEvent> ; Thunk in user4.asm
  623. LabelFP <PUBLIC, mouse_event>
  624. push si ; Preserve the same regs as Win3.1
  625. regptr disi,di,si
  626. cCall <FAR PTR MouseEvent>, <ax,bx,cx,dx,disi>
  627. pop si
  628. retf
  629. LabelFP <PUBLIC, GetMouseEventProc>
  630. mov dx,cs
  631. mov ax,offset mouse_event
  632. retf
  633. ;*--------------------------------------------------------------------------*
  634. ;* *
  635. ;* keybd_event() - *
  636. ;* *
  637. ;*--------------------------------------------------------------------------*
  638. ; Keyboard interrupt handler.
  639. ;
  640. ; ENTRY: AL = Virtual Key Code, AH = 80 (up), 00 (down)
  641. ; BL = Scan Code
  642. ; BH = 0th bit is set if it is an enhanced key(Additional return etc.,).
  643. ; SI = LOWORD of ExtraInfo for the message
  644. ; DI = HIWORD of ExtraInfo for the message
  645. ;
  646. ; NOTES: This routine must preserve all registers.
  647. ExternFP <KeybdEvent> ; Thunk in user4.asm
  648. LabelFP <PUBLIC, keybd_event>
  649. push es ; Preserve the registers
  650. push dx
  651. push cx
  652. push bx
  653. push ax
  654. regptr disi,di,si
  655. cCall <FAR PTR KeybdEvent>, <ax,bx,disi>
  656. pop ax
  657. pop bx
  658. pop cx
  659. pop dx
  660. pop es
  661. retf
  662. sEnd %SEGNAME
  663. end