;       SCCSID = @(#)smrqstat.asm	6.3 92/02/21
PAGE 60,132                             ;
;***************************************************************************
;
; Source File Name:     SMRQSTAT.ASM
;
; Subroutine Name:      DOSSMGETSTATUS
;
; Descriptive Name:     Active screen group queue status
;
; Function:     Return the number of active screen groups and the
;               screen group ID for each active screen group.
;               Optionally, the screen group type, the program type,
;               program title, relatives, and bond information may be
;               returned depending on the size of the screen group
;               data element requested.
;
;               The screen group data is returned in order from
;               the topmost to the bottommost screen group or from
;               the Shell to the last screen group started.
;
; Notes:
;       Dependencies:   None
;
;       Restrictions:   Only the Shell can call this procedure.
;                       It is the Shell's responsibility to
;                       ensure that the ActiveSG segment is
;                       allocated large enough to hold the
;                       maximum amount of information prior to
;                       making this call.
;
;     Change History:
;       @@AE - 03/09/90 - PTR B788388 - Put DosSMGetStatus back in
;       @TL7 - 04/05/90 - PTR B712376 - Enable for MMIO
;       @MHW - 09/13/90 - PTR B715818 - In-line performance (MMIO) hooks
;       @GDW   08/26/91   PTR B725436 Fix to allow semaphore loop on INTERUPT
;
; Entry Point:
;       Linkage:  EXTRN DOSSMGETSTATUS:FAR
;                       PUSH    WORD   StatusReq  ; Status Options
;                       PUSH@   Other  ActiveSG   ; Addr. to return data
;                       CALL    DOSSMGETSTATUS
;
; Inputs:
;       WORD    StatusReq  Value = 0, Return all data (Top to Bottom)
;                          Value = 1, Return all data (Shell to Last)
;                          Value = 2, Return number of screen groups
;                                     in use and next active SG only
;                          Value = 3, Return all data for specified
;                                     screen group.
;
;       Other   ActiveSG   Structure where the active screen group
;                          data will be returned. The structure
;                          contains the following information:
;
;       WORD    HdrLength  The length of the header (8)
;       WORD    NumberSG   Number of active screen groups
;       WORD    NextSG     Number of the next active screen group
;                          after the topmost screen group
;       WORD    EntryLen   The length allowed for each screen groups data
;
;       Some or all of the following information is returned
;       for each active screen group:
;
;       WORD    SGID       Screen group ID number
;       ASCII   SGTitle    32 byte screen group title padded
;                          with blanks
;       WORD    SGSelect   Select status
; ============  SHELL.EXE doesn't require anything below this  ===============
;       WORD    SGBound    Child screen group bound to the parent
;       WORD    SGType     Parent/Child/Independent
;       WORD    SGChild    Parent screen groups first child
;       WORD    SGRelative Next child or parent screen group
;       WORD    SGParent   Parent screen group ID
;       WORD    SGClass    Fullscreen/windowed VIO/PM specific
;
; Exit Normal:
;       AX      ReturnCode Value = 0, screen group status
;                                     returned
;
; Exit Errors:
;       AX      ReturnCode error_smg_not_baseshell
;                          error_smg_bad_statusreq
;
;                          DOSSMBASESHELL errors
;
; Effects:      All other registers are preserved.
;
; Internal References:
;          Routines:    DOSSMBASESHELL
;
; External References:
;          Routines:    DOSFSRAMSEMREQUEST
;                       DOSFSRAMSEMCLEAR
;
;***************************************************************************
ifdef I1
;
;   IF (StatusReq < 4)
;      DOSSMBASESHELL (Verify caller is Shell)
;      IF (No_Error)
;         DOSSEMREQUEST (Wait on the queue semaphore)
;         Locate topmost queue element
;
;         REPEAT
;            next queue element
;         UNTIL (queue elemet found) OR
;         UNTIL (end of queue)
;
;         WHILE (Room left buffer)
;           Return active screen group information
;         ENDWHILE
;
;         IF (Entry length is sufficient) AND
;         IF (Full status requested) AND
;         IF (StatusReq <> 2)
;            Get EntryLen allowed for each entry
;            Calculate beginning of session data based on HeaderLength
;            StartSG = Base Shell queue element
;
;            IF (Start with topmost SG)
;               Setup offset to topmost queue element
;            ELSE
;               Setup offset to Shell queue element
;            ENDIF
;
;            REPEAT
;               IF (Enough room left in buffer)
;                  Copy screen group data to ActiveSG
;               ENDIF
;               Calculate next entry offset based on EntryLen
;               Get next active screen group queue element
;            UNTIL (SGID e StartSG)
;
;         ENDIF
;         DOSFSRAMSEMCLEAR(Release queue semaphore
;      ENDIF
;   ELSE
;      RC = Error_SMG_Bad_StatusReq
;   ENDIF
;
;***************************************************************************
else

.386C
    EXTRN PM_Present       : BYTE       ; Check for presence of PM
    EXTRN SGCB_QueueRamSem : DWORD      ; Queue access ram semaphore
    EXTRN TopMost          : DWORD      ; @ of TopMost SGCB
    EXTRN BaseShell        : DWORD      ; @ of Shell's SGCB
    EXTRN TitleSelector    : WORD
    EXTRN UsedScrnGrps     : WORD

    EXTRN DOSSMBASESHELL      : NEAR    ; Verify Base Shell is calling
    EXTRN DOSFSRAMSEMREQUEST  : FAR     ; Request semaphore ownership
    EXTRN DOSFSRAMSEMCLEAR    : FAR     ; Clear semaphore ownership
.xlist
    INCLUDE SMRSGCB.INC                 ; SGCB definition
    INCLUDE SMRREQB.INC                 ; Request block definitions
    INCLUDE SMRQSTAT.INC                ; Stack template
    INCLUDE SMRRDATA.INC
    INCLUDE INFOSEG.INC                 ; needed by smmmpha.inc         ;MHW
    INCLUDE SMMMPHA.INC                 ; Performance hook macros       ;MHW
.xcref
    INCLUDE STRUC.INC
    INCLUDE ERROR2.INC
.cref
.list

CODE SEGMENT WORD PUBLIC 'CODE' USE16
    ASSUME CS:CODE,DS:RDATA,SS:NOTHING,ES:NOTHING,FS:NOTHING,GS:NOTHING

    PUBLIC DOSSMGETSTATUS
    PUBLIC DOSSMGETSTATUS_POSTDT
DOSSMGETSTATUS PROC FAR

    Local_Bytes  EQU  2                 ; 1 WORD of local storage
    Specific_SG  EQU  SS:[BP][-2]       ; Used as local variable

    ENTER Local_Bytes,0
    PUSHA                               ; Save registers
    PUSH DS
    PUSH ES
    PUSH FS

    MMPHPreDOSSMGetStatus               ; Performance Hook (8017h)      ;MHW

    MOV  AX, RDATA                      ; Get addressability to shared data
    MOV  FS, AX
    MOV  DS, AX

    .IF  < <SS:[BP].QStatStatusReq> b 4 > near ; Valid req?
;     *****************************************
;     *  Verify the caller is the Base Shell  *
;     *****************************************
      CALL DOSSMBASESHELL
      .IF  < zero AX > NEAR                                             ;CJ10

;       *****************************************
;       *  Block other Session Manager threads  *
;       *  from accessing the queue segment     *
;       *****************************************
        .repeat                                                         ;@GDW
;CJ10     LES  DI, SGCB_QueueRamSem     ; Queue access semaphore
          PUSH SGCB_QueueRamSem                                         ;CJ10
;CJ10     PUSH DI
          PUSH DWORD PTR -1             ; Wait until queue available    ;CJ10
;CJ10     PUSH -1
          CALL DOSFSRAMSEMREQUEST
        .until  <ax ne ERROR_INTERRUPT>                                 ;@GDW

;       *****************************************************************
;       *  Copy the input parameter for a specific screen group status  *
;       *  into the local variable provided on the stack.  We must do   *
;       *  this now since we're about to overwrite it with the number   *
;       *  of active sessions.                                          *
;       *****************************************************************
        LES  DI, SS:[BP].QueueStatusPacket
        MOV  BX, ES:[DI].QStatSpecificSG ; Input/Output variable
        MOV  Specific_SG, BX             ; Save for later testing on stack

;       *****************************************
;       *  Locate next active screen group and  *
;       *  number of active screen groups       *
;       *****************************************
        PUSH DI
        LDS  SI, FS:TopMost             ; Topmost SG
        MOV  BX, DS:[SI].SGCB_ID        ; Get TopMost ID into BX

        .REPEAT                         ; Locate next selectable SGID
          LDS  SI, DS:[SI].SGCB_Next    ; @ of Next SG
        .UNTIL < DS:[SI].SGCB_SelectStatus eq 0 > OR   ; Found one thats selectable
        .UNTIL < DS:[SI].SGCB_ID eq BX >               ; Back to TopMost's Next SG

        MOV  BX, SP                     ; Save stack offset
        MOV  CX, DS:[SI].SGCB_ID        ; Next selectable SGID
        XOR  CH, CH                     ; Strip off high byte
        PUSH CX
        PUSH FS:UsedScrnGrps            ; Number used SGs

;       *****************************************
;       *  Return next active screen group and  *
;       *  number of active screen groups       *
;       *****************************************
        MOV  CX, ES:[DI].QStatHeaderLen ; Header length
        SUB  CX, 2                      ; Subtract header length word
        ADD  DI, 2                      ; Place to return used SGs
        CLD

        .WHILE < CX ae 2 > AND          ; Room in header to return
        .WHILE < BX ne SP >             ; data or all data returned?
          POP  AX                       ; Return header data
          STOSW
          SUB  CX, 2                    ; Decrement header length
        .ENDWHILE

        MOV  SP, BX                     ; Reset stack offset
        POP  DI                         ; Reset offset to header

;       *********************************************
;       *  Get length of screen group data desired  *
;       *********************************************
        XOR  AX, AX                     ; Set AX to No_Error
        MOV  BX, SS:[BP].QStatStatusReq

        .IF  < CX ae 2 > AND NEAR         ; Entry length provided
        .IF  < BX ne 2 > NEAR             ; Not status only request
          MOV  CX, ES:[DI].QStatEntryLen  ; Entry length
          ADD  DI, ES:[DI].QStatHeaderLen ; First entry

          .IF  < CX ae 2 > NEAR         ; Verify room for SGID
;           ******************************************
;           *  Get offset to first queue element to  *
;           *  return data for (Shell or Topmost)    *
;           ******************************************
            .IF  < zero BX >            ; Start with topmost SG         ;CJ10
              LDS  SI, FS:TopMost
            .ELSE                       ; Start with Base Shell
              LDS  SI, FS:BaseShell
            .ENDIF

            MOV  BX, DS:[SI].SGCB_ID    ; Save first SG
;           *********************************
;           *  Copy data from active queue  *
;           *********************************
            .REPEAT NEAR
              MOV  AX, DS:[SI].SGCB_ID  ; Get SG ID
              .IF  < SS:[BP].QStatStatusReq ne 3 > OR ; SG Specific status
              .IF  < AX e Specific_SG > ; This is the specific SG
                PUSH CX                 ; Save entry length
                PUSH DI                 ; Save entry offset
                PUSH DS                 ; Save address to SG data
                PUSH SI
                SUB  CX, 2              ; SGID returned
                XOR  AH, AH             ; Clear off high byte           ;CJ10,VR9
                STOSW                   ; Store SGID

                .IF  < nonzero CX >     ; Room for more data?           ;CJ10
                  MOV  DX, SP           ; Save stack offset
                  PUSH DS:[SI].SGCB_DebuggerPID
                  PUSH DS:[SI].SGCB_DebuggerSID
                  PUSH DS:[SI].SGCB_Type
                  PUSH DS:[SI].SGCB_ParentSID
                  PUSH DS:[SI].SGCB_Bound
                  PUSH DS:[SI].SGCB_Relative
                  PUSH DS:[SI].SGCB_FirstChild
                  PUSH DS:[SI].SGCB_FamilyType
                  PUSH DS:[SI].SGCB_SelectStatus

                  MOV  SI, DS:[SI].SGCB_Title
                  MOV  DS, FS:TitleSelector
                  INC  SI                     ; SG title address
                  .IF < FS:PM_Present e No >  ; If PM not present
                    .IF  <CX ae QueueTitleLen>    ; title
                      SUB  CX, QueueTitleLen
                      PUSH CX                     ; Save remaining len
                      MOV  CX, QueueTitleLen
                    .ELSE
                      PUSH 0            ; No additional data
                    .ENDIF

                    .REPEAT             ; Copy all/part of title
                      LODSB
                    .LEAVE <AL eq 0>
                      STOSB
                    .LOOP

                    MOV  AL,' '
                    .IF  <ncxz>         ; Title need padding?           ;CJ10
;CJ10                 .REPEAT           ; Blank fill title
                        REP  STOSB                                      ;CJ10
;CJ10                 .LOOP
                    .ENDIF

                    POP  CX             ; Restore remaining len

                  .ELSE                           ; If PM is present,
                    SUB  CX, QueueTitleLen        ; Bump counter and
                    ADD  SI, QueueTitleLen        ; Pointers
                    ADD  DI, QueueTitleLen        ;
                  .ENDIF

                  .WHILE <CX ae 2> AND  ; More data?
                  .WHILE <DX ne SP>     ; All data ret.?
                    POP  AX             ; data
                    STOSW
                    SUB  CX, 2          ; Adjust length
                  .ENDWHILE

                  MOV  SP, DX           ; Reset stack offset
                .ENDIF

                POP  SI                 ; Restore SG queue element
                POP  DS
                POP  DI                 ; Restore entry offset
                POP  CX                 ; Restore entry length
                ADD  DI, CX             ; Next entry for data
              .ENDIF                    ; Test for specific Screen Group

              LDS  SI, DS:[SI].SGCB_Next           ; Next SG
            .UNTIL < DS:[SI].SGCB_ID eq BX >  NEAR ; All done?

            XOR  AX, AX                 ; Set RC = No_Error
          .ENDIF
        .ENDIF

        PUSH AX                         ; Save possible return code

;CJ10   LES  DI, FS:SGCB_QueueRamSem    ; Queue access semaphore
        PUSH FS:SGCB_QueueRamSem                                        ;CJ10
;CJ10   PUSH DI
        CALL DOSFSRAMSEMCLEAR

        POP  AX                         ; Restore possible return code
      .ENDIF

    .ELSE
      MOV  AX, Error_SMG_Bad_StatusReq
    .ENDIF

    MOV  AX_Reg[-Local_Bytes], AX       ; Put return code on the stack

    POP  FS                             ; Restore registers
    POP  ES
    POP  DS
    POPA

    MMPHPostDOSSMGetStatus              ; Performance Hook (8097h)      ;MHW

    LEAVE

    DOSSMGETSTATUS_POSTDT LABEL FAR
    RET  QStatFrmLen                    ; Return to caller

DOSSMGETSTATUS ENDP

CODE ENDS
endif
    END
