;       SCCSID = @(#)smgsgstr.asm       6.10 92/03/24
;       SCCSID @(#)smgsgstr.asm 6.10 92/03/24
PAGE 60,132                             ;
; ****************************************************************************
; *                                                                          *
; *                       IBM/Microsoft Confidential                         *
; *                                                                          *
; *                 Copyright (c) IBM Corporation  1987, 1990                *
; *                 Copyright (c) Microsoft Corp.  1987, 1990                *
; *                           All Rights Reserved                            *
; *                                                                          *
; ****************************************************************************

;**************************************************************************
;
; Source File Name:     SMGSGSTR.ASM
;
; Subroutine Name:      DOSSMSGSTART
;
; Descriptive Name:     Start a new screen group
;
; Function:     Add a new screen group to the active queue. For
;               a foreground start, save the state of the current
;               foreground screen group and switch the new screen
;               group to the foreground and start the requested
;               program in the new screen group. For a background
;               start, just start the specified program in the
;               new screen group.
;
; Notes:
;       Dependencies:   None
;
;       Restrictions:   PgmName and PgmInputs may not exceed 384
;                       characters including the ASCIIZ 0.
;
; Change History:
;   @@AB   03/02/90  PTR B711695 - Trap D when VDM can't be started
;   @CJ4   03/05/90  PTR B788158 Pass the program name offst to RqstrProgOff
;                                for DosCreateVDM.
;   @@AD   03/09/90  PTR B711862 Call DosSGDDNotify for pgm_type 0, AND 1.
;   @TL7   04/05/90  PTR B712376 - Enable for MMIO
;   @D1088 07/07/90  DCR 1088 Add support for special needs.
;   @MHW   09/13/90  PTR B715818 In-Line performance (MMIO) hooks
;   CJ27   05/14/91  PTR B722693 Reset SGCB_Flags after DosExecPgm fails.
;   CJ28   05/30/91  PTR J200265 Fix to allow DBCS monitor installation.
;   CJ41   01/11/92  PTR B732600 Set SGCB_Flags so ChildExit won't get called
;                                twice.
;   CJ53   01/13/92  PTR AA03977 Free up memory from DosGetSegs.
;   D1573  02/21/92  DCR 1573 Common Win-OS/2 Seamless VDMs
;   CJ61   03/24/92  PTR SM11410 Don't GetSeg if already have access.
;   VLR    08/19/92  def 53036   Add progtypes for win 31
;   58348  02/22/93  CJJ Pass current directory to a VDM started VDM session.
;   74851  11/06/93  LEW TOP_BY_DELETION should be reset for TopMost not
;                        Local_TopMost
;   MDLL   01/10/94  BJN Page Tune segments for Merged DLL.
;
; Entry Point:
;       Linkage:  EXTRN DOSSMSGSTART:FAR
;                       PUSH    WORD   Action     ; Save/Nosave action flag
;                       PUSH    WORD   StartMode  ; Fore/Background start
;                       PUSH    WORD   AsyncOpt   ; Asynchronous option
;                       PUSH    WORD   PgmType    ; Program Type
;                       PUSH@   ASCIIZ Pgmtitle   ; Address of Title
;                       PUSH@   ASCIIZ PgmName    ; Address of Program Name
;                       PUSH@   ASCIIZ PgmInputs  ; Address of Program
;                                                 ;    Input Arguments
;                       PUSH    WORD   ParentID   ; Parent Session ID
;                       PUSH@   WORD   NewSgID    ; New Screen Group ID
;                       PUSH@   WORD   NewProcess ; New Process ID
;                       PUSH    WORD   EnvironOpt ; Environment Option
;                       PUSH@   OTHER  ReqBlock   ; @ of request block
;                       PUSH@   OTHER  PMStruc    ; @ of PM structure
;                       PUSH    WORD   DebugSID   ; Debugger's Session ID
;                       PUSH    WORD   DebugPID   ; Debugger's Process ID
;                       PUSH    DWORD  Reserved   ; Reserved for future use
;                       CALL    DOSSMSGSTART
;
; Inputs:
;       WORD    Action     Value = 0, Save state of Shell
;                          Value = 1, Don't save state of Shell
;       WORD    StartMode  Value = 0, Start session in foreground
;                          Value = 1, Start session in background
;       WORD    AsyncOpt   Value = 3, Asynchronous trace exec
;                          Value = 5, Asynchronous frozen exec
;       WORD    ProgType   Value = 1, Fullscreen start
;                          Value = 2, Windowed VIO start
;                          Value = 3, PM start
; |                        Value = 4, VDM start
; |                        Value = 7, Windowed VDM start
;       ASCIIZ  PgmTitle   ASCIIZ string containing the program
;                          title
;       ASCIIZ  PgmName    ASCIIZ string containing the drive
;                          path,and file name of the program to
;                          be loaded.
;       ASCIIZ  PgmInputs  ASCIIZ string containing the input
;                          arguments to be passed to the program
;       WORD    ParentID   Session ID of the parent session
;       WORD    NewScrGrp  Screen Group ID of the new program
;       WORD    NewProcess New process ID program started in.
;       WORD    EnvironOpt Value = 0, Use Shell's Environment
;                          Value = 1, Use calling Pgms. Environment
;                          NOTE:  This parm is ignored if called by
;                                 the shell.
;       OTHER   ReqBlock   Session Manager request block data
;       OTHER   PMStruc    Structure to be filled in for the PM
;       WORD    DebugSID   Debugger's Session ID
;       WORD    DebugPID   Debugger's Process ID
;       DWORD   Reserved   Reserved double word of zeros
;
; Exit Normal:
;       AX      ReturnCode Value = 0, group start successful
;
; Exit Errors:
;       AX      ReturnCode error_smg_bad_action
;                          error_smg_bad_reserve
;                          error_smg_invalid_program_Type
;                          error_smg_invalid_start_mode
;                          error_smg_not_baseshell
;
;                          DOSEXECPGM      errors
;                          DOSSGDDNOTIFY   errors
;                          DOSSMADDSGQUEUE errors
;                          DOSSMBASESHELL  errors
;                          DOSSMGSWITCH    errors
;                          VIORESTORE      errors
;
; Effects:      All other registers preserved.
;
; Internal References:
;          Routines:    DOSSMBASESHELL
;                       DOSSMPARSEPATH
;                       DOSSMADDSGQUEUE
;                       DOSSMGSWITCH
;                       DOSSMCHILDEXIT
;
; External References:
;          Routines:    DOSSEMREQUEST
;                       DOSSGDDNOTIFY
;                       DOSSGSWITCHME
;                       DOSSETPRTY
;                       DOSEXECPGM
;                       DOSSLEEP
;                       DOSSEMCLEAR
;                       DOSSEMWAIT
;                       DOSGETSEG
;**************************************************************************
ifdef I1
;
;  DOSSMBASESHELL (Verify caller is Shell)
;  IF (No error)
;    DOSSMGETNAMES (Get program name and title)
;      IF (No Error)
;        DOSSMADDSGCB (Create a new sgcb and setup pointer to it)
;        IF (No error)
;          IF (Request block exists)
;            IF (Async e 2)
;              Reset Async to 6
;              Setup request block and new sgcb to show relationship
;            ELSE
;              IF (we are under debugger)
;                Reset Async variable on stack and in req block to 6
;                Store Debugger SID and PID in new sgcb
;              ENDIF
;            ENDIF
;          ELSE
;            PUSH No debugger SID
;          ENDIF
;        ENDIF
;        IF (No error from DOSSMADDSGQUEUE)
;          IF (Title not specified) AND
;          IF (PM NOT present)
;            Get session title
;          ENDIF
;          DOSSMNOTIFYDD (Notify registered device drivers of sg creation)
;          DOSSMSTARTSWITCH (Switch to new sg if necessary)
;          IF (No error)
;            IF (NOT VDM) AND
;            IF (NOT Windowed_VDM)
;              Get program name
;            ENDIF
;            IF (Input parameters) AND
;            IF (Program name address ne zero) AND
;            IF (Room available in program parameters)
;              Get parameters
;            ELSE
;              Force string to ASCIIZ
;            ENDIF
;            IF (Name exceeds maximum)
;              Make string ASCIIZ
;            ENDIF
;            IF (Inherited)
;              Load request block with program name and parameter addresses
;              IF (VDM) OR
;              IF (Windowed_VDM)
;                Point to program name argument (Do not concatenate with args.)
;              ENDIF
;              DOSSEMCLEAR (Clear sem to wake Appsendrequest)
;            ELSE
;              Save address of req block in local variables
;              IF (No request block)
;                Set object buffer to 0
;              ELSE
;                DOSGETSET (Get access to selector Obj. Name)
;                IF (No error)
;                  Point to object name
;                ELSE
;                  PUSH 0's
;                ENDIF
;              ENDIF
;
;              IF (NOT VDM) AND
;              IF (NOT Windowed_VDM)
;                PUSH Async option
;              ELSE
;                Pad object buf len
;              ENDIF
;              IF (Request block exists)
;                DOSGETSEG (Get acccess to environment selector)
;                IF (No error)
;                  Restore selector
;                ELSE
;                  Clear stack of bad selector
;                ENDIF
;              ELSE (No request block)
;                Set buffer address to 0
;              ENDIF
;              IF (NOT VDM) AND
;              IF (NOT Windowed_VDM)
;                DOSEXECPGM
;              ELSE
;                DOSCREATEVDM (Start a VDM)
;              ENDIF
;              IF (No error)
;                DOSSETPRTY (Lower priority of new session)
;              ENDIF
;            ENDIF
;            Put PID in sgcb pidarray
;          ELSE (Switch failed)
;            IF (Request block exists)
;              Set RC into request block
;            ENDIF
;          ENDIF
;          IF (PM call back routine exists)
;            IF (No error from DosExecPgm or DosCreateVDM)
;              Push PID and SID
;            ELSE
;              PUSH zeros
;            ENDIF
;            WinPreThaw
;          ENDIF
;          IF (No error from DosExecPgm or DosCreateVDM)
;            IF (Inherited)
;              DOSSYSTEMSERVICE (Adopt)
;            ENDIF
;            IF (NOT VDM) AND
;            IF (NOT Windowed_VDM)
;              Convert Program Type to Local Infoseg Process Type)
;              DOSSGSWITCHPROC2 (Switch processes)
;            ENDIF
;            IF (NOT being traced)
;              DOSSYSTEMSERVICE  (Thaw the new session)
;            ENDIF
;            DOSSEMCLEAR
;            DOSSETFGND (Boost new SG priority)
;            IF (Shell is foreground)
;              IF (PM is present)
;                WINQUERYEXTIDFOCUS (Find extended sgid)
;                DOSSMGETSGCB (Get sgcb)
;              ELSE (PM NOT present
;                Set a fake error
;              ENDIF
;            ELSE (Shell NOT foreground)
;              Get sgid and pid
;            ENDIF
;            IF (No error)
;              DOSSETFGND (Boost topmost SG priority)
;              DOSSETFGND (Boost topmost PID priority)
;            ENDIF
;          ELSE (Exec or Switch failed)
;            DOSSMGETSGCB   (Get sgcb)
;            DOSSMCHILDEXIT (Free SGID)
;            IF (Foreground start)
;              IF (NOT Error_SMG_Session_Not_Found)
;                Set parms to force a switch
;                IF (Full screen session) OR
;                IF (VDM)
;                  Set parm to switch to old fgnd screen group
;                ENDIF
;                DOSSMGSWITCH
;              ENDIF
;            ENDIF
;          ENDIF
;        ELSE
;        IF (Request block exists)
;          Set RC in request block
;        ENDIF
;        IF (PM call back routine exists)
;          Notify shell through prethaw of error)
;        ENDIF
;      ENDIF
;    ENDIF
;
;
;
;**************************************************************************
else

.386P                                                                   ;CJ61
    EXTRN BaseShell               : DWORD ; @ of Shell's SGCB
    EXTRN CmdArgs                 : DWORD ; Offset to default arguments
    EXTRN CmdInputLen             : WORD  ; Input parms buffer to CMD.EXE
    EXTRN CmdInputs               : BYTE  ; Input parms buffer to CMD.EXE
    EXTRN CmdName                 : DWORD ; Address to command processor name
    EXTRN GlobalSelector          : WORD  ; Global information seg. sel.
    EXTRN IncomingDebugger        : WORD
    EXTRN PM_Present              : BYTE  ; PM Present indicator
    EXTRN SGCB_PIDArray           : DWORD
    EXTRN SGCB_QueueRamSem        : DWORD
    EXTRN StartActionPacket       : WORD  ; Freeze/Thaw action packet
    EXTRN StartRamSem             : DWORD
    EXTRN TitleSelector           : WORD
    EXTRN TopMost                 : DWORD
    EXTRN VDMName                 : BYTE  ; Name of untitled VDM session
    EXTRN WinCreateConsole        : DWORD ; PMVIOP routine
    EXTRN WinQueryExtIDFocus      : DWORD ; PM routine
    EXTRN NotDD_DosDev_Data_Len   : WORD  ; Data for DosSMNotifyDD      ;@D1088
    EXTRN NotDD_Notification_Type : WORD                                ;@D1088
    EXTRN NotDD_InSG_or_OutType   : WORD                                ;@D1088
    EXTRN NotDD_InType_or_OutSG   : WORD                                ;@D1088
    EXTRN NotDD_OutSG             : WORD                                ;@D1088
    EXTRN NotDD_OutType           : WORD                                ;@D1088
    EXTRN Registered_DLLs         : WORD  ; Flag for registered DLLS    ;CJ28
    EXTRN VDMCurDir               : DWORD ; Current VDM directory       ;58348

    EXTRN DOSCREATEVDM     : FAR        ; Start a DOS Mode Session
    EXTRN DOSEXECPGM       : FAR        ; Load and execute program
    EXTRN DOSGETSEG        : FAR        ; Allow access to selector
    EXTRN DOSFREESEG       : FAR        ; Free access to selector       ;CJ53
    EXTRN DOSSEMCLEAR      : FAR        ; Clear semaphore
    EXTRN DOSSEMREQUEST    : FAR        ; Request a semaphore
    EXTRN DOSSEMWAIT       : FAR        ; Wait on semaphore
    EXTRN DOSSETFGND       : FAR        ; Give foregrnd priority
    EXTRN DOSSETPRTY       : FAR        ; Set priority of new child
    EXTRN DOSSGDDNOTIFY    : FAR        ; Screen switch SGCB initialize
    EXTRN DOSSGSWITCHPROC2 : FAR        ; Switch process SG
    EXTRN DOSSLEEP         : FAR        ; Give up time slice
    EXTRN DOSSMADDSGCB     : NEAR       ; Add new screen group queue element
    EXTRN DOSSMBASESHELL   : NEAR       ; Verify Base Shell is calling
    EXTRN DOSSMCHILDEXIT   : NEAR       ; Free specified screen group
    EXTRN DOSSMGETSGCB     : FAR
    EXTRN DOSSMGSWITCH     : NEAR       ; Change foreground screen group
    EXTRN DOSSMNOTIFYDD    : FAR        ; Notify Registered Device Drivers
    EXTRN DOSSMPARSEPATH   : NEAR       ; Parse path out of pgmname
    EXTRN DOSSYSTEMSERVICE : FAR        ; Thaw new process in SG
    EXTRN VIORESTORE       : FAR        ; Clear the display
.xlist
    INCLUDE SMRREQB.INC
    INCLUDE SMRRDATA.INC
    INCLUDE SMRSGCB.INC
    INCLUDE SMGSGSTR.INC
    INCLUDE INFOSEG.INC
    INCLUDE SMMMPHA.INC                 ; Performance hook macros       ;MHW
    INCLUDE DEMSMG.INC                  ; VDM STRUC                     ;58348
.xcref
    INCLUDE ERROR.INC                   ; Error code equate for ERROR_INTERRUPT
    INCLUDE ERROR2.INC
    INCLUDE STRUC.INC
.cref
.list

CODE_TUNE1 SEGMENT WORD PUBLIC 'CODE' USE16                             ;MDLL
    ASSUME CS:CODE_TUNE1,DS:RDATA,SS:NOTHING,ES:NOTHING                 ;MDLL

    PUBLIC DOSSMSGSTART
    PUBLIC DOSSMSGSTART_POSTDT
DOSSMSGSTART PROC FAR

    Local_Bytes   EQU 18
    Local_Var1    EQU SS:[BP][-2]       ; Local variable on stack
    Local_Var2    EQU SS:[BP][-4]       ; Local variable on stack
    Local_DS      EQU SS:[BP][-6]       ; Local variable on stack
    Local_SI      EQU SS:[BP][-8]       ; Local variable on stack
    Local_SGID    EQU SS:[BP][-10]      ; Local variable on stack
    Local_PIDRC   EQU SS:[BP][-14]      ; DosExecPgm stores a DWORD here
    Local_TopMost EQU SS:[BP][-18]      ; DosExecPgm stores a DWORD here

    ENTER Local_Bytes,0                 ; Get a word for a local variable
    PUSHA                               ; Save registers
    PUSH DS
    PUSH ES
    PUSH FS

    MOV  BX, RDATA                      ; Addressability to global data
    MOV  DS, BX
    MOV  FS, BX

    MMPHPreDOSSMSGStart                 ; Performance Hook (8002h)      ;MHW

;   *************************************
;   * Verify the Base Shell is calling. *
;   *************************************
    CALL DOSSMBASESHELL                 ; GS --> Local InfoSeg
    .IF  < zero AX > NEAR                                               ;@CJ10
      CALL DOSSMGETNAMES                ; Get Program name and Title
;     ********************************************************************
;     *      Get a screen group ID and add queue element                 *
;     *                                                                  *
;     *      CX      PID         Parent process ID for the screen group  *
;     *      BX      ParentSGID  Parent process screen group ID          *
;     *      DX      ProgramType                                         *
;     *      ES:DI   PgmTitle    @ of the program title                  *
;     *      DS      RDATA                                               *
;     *                                                                  *
;     *  Exit Normal:                                                    *
;     *      AX      ReturnCode Value = 0, Screen group added to queue   *
;     *      DX      SGID       Screen group number added                *
;     *      ES:DI   Newqueue   Address of queue element added           *
;     ********************************************************************
      MOV  BX, SS:[BP].SGStrParentSGID  ; Parent SGID
      MOV  DX, SS:[BP].SGStrPgmType     ; Program type

      CALL DOSSMADDSGCB                 ; DX = SGID ES:DI = New SGCB

      MOV  Local_SGID, CX               ; Clear Local Storage
      MOV  Local_SGID, DL               ; Store truncated sgid on stack

;     Shouldn't get an error from DosSMAddSGQueue
      PUSH ES
      POP  FS                           ; FS:DI --> New SGCB

      PUSH SI                           ; Title existence flag
      LGS  SI, SS:[BP].SGStrNewSGID
      MOV  GS:[SI], DX                  ; Return SG # to the caller

;     *****************************************************
;     *  We get access to the request block to get the    *
;     *  requestor's SID and the trace option. NOTE: We   *
;     *  follow this path if a debugger starts us with    *
;     *  the special trace option. If the app being       *
;     *  started in turn starts an app, the code will     *
;     *  take care of that too.                           *
;     *****************************************************
      .IF  < zero AX >                                                  ;@CJ10
        MOV  Local_Var1, AX             ; Init ReqFlags                 ;D1545
        LGS  SI, SS:[BP].SGStrReqBlock  ; Req block address
        MOV  AX, GS

        .IF  < nonzero AX >                   ; If there is a reqblock  ;@CJ10
          MOV  AX, GS:[SI].ReqFlags     ; Get ReqFlags                  ;D1545
          MOV  Local_Var1, AX           ; Save it for DOSSMSTARTSWITCH  ;D1545
          .IF  < GS:[SI].RqstrAsyncInd eq 2 >
            MOV  SS:[BP].SGStrAsyncInd, 6
            MOV  AX, GS:[SI].ReqSessionID     ; Parent's SID from Requst Blk
            MOV  ES:[DI].SGCB_DebuggerSID, AX ; Store in SGCB
            PUSH AX                           ; Save Debugger's SID on stack
            MOV  AX, GS:[SI].ReqProcesSID     ; Parent's PID
            MOV  ES:[DI].SGCB_DebuggerPID, AX ; Store in sgcb

          .ELSE
            PUSH SS:[BP].SGStrDebuggerSID
            .IF < SS:[BP].SGStrDebuggerSID ne Null > ; Under debugger
;             ****************************************************
;             *  If this session is being started along a chain  *
;             *  of apps being debugged then we should be        *
;             *  started with trace option = 6 (and we need to   *
;             *  tell APPSENDREQUEST for an inherited start)     *
;             ****************************************************
              MOV  SS:[BP].SGStrAsyncInd, 6      ; and stack
              MOV  GS:[SI].RqstrAsyncInd, 6      ; For inheritance  (2 to 6)
              MOV  AX, SS:[BP].SGStrDebuggerSID
              MOV  ES:[DI].SGCB_DebuggerSID, AX  ; Store in SGCB
              MOV  AX, SS:[BP].SGStrDebuggerPID
              MOV  ES:[DI].SGCB_DebuggerPID, AX  ; Store in SGCB
            .ENDIF                      ; Debugger Existence Test
          .ENDIF
        .ELSE                           ; No request block
          PUSH Null                     ; No Debugger's SID
        .ENDIF                          ; Async Test
        POP  IncomingDebugger           ; Save SID in SGCB header
        XOR  AX, AX                     ; Set good return code
      .ENDIF

      POP  SI                           ; Restore title existance flag
      .IF  < zero AX > NEAR             ; If DOSSMADDSGQUEUE ok         ;@CJ10
        .IF  < zero SI > AND            ; Title not specified           ;CJ10
        .IF < PM_Present e No >         ; If PM not present, then
          MOV  SI, ES:[DI].SGCB_Title   ; Get session title offset
          MOV  GS, TitleSelector        ; Get title selector
          MOV  BYTE PTR GS:[SI], Null   ; Stuff Null to signify No Title
        .ENDIF

;       ********************************************************************
;       *  If we have any registered DLLs, we need to do the dummy         *
;       *  VioRestore before the Create notification.  This is because     *
;       *  DBCS does a DosExecPgm during the Create notification which     *
;       *  causes VioInitProcess to call down to BVScalls.  The VioRestore *
;       *  has to be done 1st, otherwise the BVS per session selectors     *
;       *  are allocated under the new SG during VioInitProcess instead    *
;       *  of under the Shell during VioRestore.                           *
;       *  Note: The dummy restore for normal conditions (not DBCS) is     *
;       *        still done at bottom cause for Foreground starts, 2       *
;       *        restores have to be done and we don't want to affect      *
;       *        performance.                                          CJ28*
;       ********************************************************************

        .IF  < DS:Registered_DLLs ne 0 >  AND      ; Any reg'd Dlls?    ;CJ28
        .IF  < ES:[DI].SGCB_Type be Window_Type >  ; If FS or VIO       ;CJ28
            PUSH ES:[DI].SGCB_ID                   ; New SGID           ;CJ28
            PUSH 4                                 ; Dummy Restore      ;CJ28
            CALL VIORESTORE                                             ;CJ28
                                                                        ;CJ28
            .IF  < AX ne Error_VIO_Internal_Resource >                  ;CJ28
              XOR  AX, AX                          ; Set AX to no error ;CJ28
            .ENDIF                                                      ;CJ28
        .ENDIF                                                          ;CJ28

;       ******************************
;       *  Notify Registered Device  *
;       *  Drivers of SG creation.   *
;       ******************************

        MOV  NotDD_DosDev_Data_Len, Version_1_2_Len         ;data length ;@D1088
        MOV  NotDD_Notification_Type, Creation_Notification ;notify type ;@D1088
        MOV  AX, ES:[DI].SGCB_ID        ; New SG                         ;@D1088
        XOR  AH,AH                      ; Zero out type byte             ;@D1088,VR2
        MOV  NotDD_InSG_or_OutType, AX                                   ;@D1088
        MOV  AX,ES:[DI].SGCB_Type       ; New SG type                    ;@D1088
        MOV  NotDD_InType_or_OutSG, AX                                   ;@D1088
        PUSH DS                         ;Address of NotifyDD data        ;@D1088
        PUSH OFFSET NotDD_DosDev_Data_Len                                ;@D1088
        CALL DOSSMNOTIFYDD

        CALL DOSSMSTARTSWITCH           ; Switch to new SG if necessary

;       ***********************************************
;       *  Convert program name and input parameters  *
;       *  into a single input string for CMD.EXE     *
;       ***********************************************
        PUSH ES                         ; Save pointer to SGCB
        PUSH DI

        .IF  < zero AX > NEAR           ; Switch successful?            ;@CJ10
          CALL DOSSMCOPYNAMES           ; Copy pgm name & inputs to CMDINPUTS

          .IF  < SS:[BP].SGStrEnvironOpt eq Inherited >
;           *******************************************
;           * Since this is an inherited start, we    *
;           * need to pass the addresses of the       *
;           * program name, and the command line      *
;           * arguments to the application side, so   *
;           * it can do the DOSEXECPGM.               *
;           *******************************************
            LDS  SI, SS:[BP].SGStrReqBlock ; @ of Req Blk
            MOV  [SI].RqstrArgSel, ES                ; Arguments Sel
            MOV  [SI].RqstrArgOff, OFFSET CmdInputs  ; /C parms offset

;           *******************************************
;           * When starting a VDM, the program name   *
;           * and the program inputs MUST not be      *
;           * concatenated. Therefore, we will pass   *
;           * the program name argument independently *
;           * to DosCreateVDM.                        *
;           *******************************************
            .IF  < DH e VDM_Type > OR       ; If VDM
            .IF  < DH e Windowed_VDM_Type >
              LES  DI, SS:[BP].SGStrPgmName ; Pgm name string
              MOV  [SI].RqstrProgOff, DI    ; Prog offset                  ;@CJ4
            .ELSE                                                          ;@CJ4
              MOV  [SI].RqstrProgOff, OFFSET CmdInputs ; Prog offset       ;@CJ4
            .ENDIF                          ;

            MOV  [SI].RqstrProgSel, ES               ; Prog selector

;           ********************************************
;           * Clear the semaphore that will wake up    *
;           * APPSENDREQUEST.  Then we will wait on    *
;           * another semaphore (located in the        *
;           * request block of course).  APPSENDREQUEST*
;           * will EXEC the program, then clear our    *
;           * semaphore, waking us up, and then wait   *
;           * on a semaphore again.                    *
;           ********************************************
;CJ10       MOV  CX, SI
            LEA  CX, [SI].ReqBlockSem                                   ;CJ10
            PUSH DS                     ; Selector of sem to wake
            PUSH CX
            CALL DOSSEMCLEAR            ; Wake up APPSENDREQUEST

            LEA  CX, [SI].ReqBlockSem2                                  ;CJ10
            .REPEAT                     ; Make sure sem is cleared
;CJ10         MOV  CX, SI               ; Get address of semaphore
;CJ10         ADD  CX, OFFSET ReqBlockSem2
              PUSH DS
              PUSH CX
              PUSH DWORD PTR -1         ; Wait on the semaphore         ;@CJ10
              CALL DOSSEMWAIT
            .UNTIL < AX ne Error_Interrupt >

            MOV  AX, DS:[SI].ReqReturnCode ; Get RC
            MOV  BX, DS:[SI].RQStrChildPID ; Get PID

            POP  DI                     ; Restore @ to new SGCB
            POP  ES
            MOV  ES:[DI].SGCB_PID, BX   ; Save PID in SGCB
          .ELSE NEAR                    ; Not inherited

;           **********************************************************  ;CJ61
;           *  NOTE:  Don't change CX until after DosFreeSegs.       *  ;CJ61
;           *         Use CX to indicate if DosGetSegs were used.    *  ;CJ61
;           **********************************************************  ;CJ61
            XOR  CX, CX                 ; Zero out CX (no DosGetSegs)   ;CJ61

;           **********************************************************
;           *  We can't push DS:SI onto stack because we will be     *
;           *  needing them real soon, and there will be DosExecPgm  *
;           *  parms on the stack by the time we need them.  So use  *
;           *  local parameters on the stack to save them.           *
;           **********************************************************
            LDS  SI, SS:[BP].SGStrReqBlock ; @ of RB

;           *****************************************
;           *  If we come in from the shell, then   *
;           *  we don't have a request block, so    *
;           *  check the selector to see if it's 0. *
;           *****************************************
            MOV  AX, DS                      ; See if sel. is valid
            .IF  < zero AX >                 ; If we don't have a request block ;@D1088
              CWDE                           ; 0 = Object Buffer        ;CJ10
              PUSH EAX                                                  ;CJ10
              PUSH AX                        ;  0 = Object Buffer Length
            .ELSE                            ;  We have a request block

              MOV  AX, DS:[SI].RqStrObjName[2] ; Selector to Obj. Name   ;CJ61
              VERW AX                          ; Do we have access?      ;CJ61
              .IF  < nz >                      ; no, get access to it    ;CJ61
                MOV  CL, 1                     ; Indicate RqStr GetSeg done;CJ61
                PUSH AX                                                  ;CJ61
                CALL DOSGETSEG                 ;  Get access to selector ;CJ61
              .ELSE                                                      ;CJ61
                XOR  AX, AX                                              ;CJ61
              .ENDIF                                                     ;CJ61

              .IF < zero AX >                ; If we got the selector    ;@CJ10
;CJ10           PUSH DS:[SI].RqStrObjName[2] ; Selector to Obj. Name
                PUSH DWORD PTR DS:[SI].RqStrObjName ; Sel:Off to Obj Name ;CJ10
                PUSH DS:[SI].RqStrObjBufLen  ; Object Name Bufer Len
              .ELSE                          ; DosGetSeg Failed
                SUB  EAX,EAX                 ; PUSH AX 1 Byte, PUSH 0 2 Bytes
                PUSH EAX                     ; Can't use caller's buffer;CJ10
;CJ10           PUSH AX
                PUSH AX
              .ENDIF
            .ENDIF                           ; Test for request block

            .IF  < DH ne VDM_Type > AND      ; If Not a VDM
            .IF  < DH ne Windowed_VDM_Type >
              PUSH SS:[BP].SGStrAsyncInd     ; Async option
            .ELSE                            ; Else if a VDM
              POP  AX
              PUSH 0                         ; Pad object buf len to dword
              PUSH AX
            .ENDIF                           ; Test for VDM

            MOV  AX, DS                      ; See if sel. is valid
            .IF  < nonzero AX >              ; If we have a request block ;@CJ10
              MOV  AX, DS:[SI].RqEnvironment[2] ; Selector
              MOV  BX, DS:[SI].RqEnvironment    ; Offset

;             *******************************************************
;             *  Issue DosGetSeg to gain access to the Environment  *
;             *  selector we allocated over on the app side.        *
;             *******************************************************
              PUSH AX                   ; Save selector

              VERW AX                          ; Do we have access?      ;CJ61
              .IF  < nz >                      ; no, get access to it    ;CJ61
                MOV  CH, 1                     ; Indicate Env GetSeg done;CJ61
                PUSH AX                                                  ;CJ61
                CALL DOSGETSEG                 ;  Get access to selector ;CJ61
              .ELSE                                                      ;CJ61
                XOR  AX, AX                                              ;CJ61
              .ENDIF                                                     ;CJ61

              .IF < zero AX >           ; DosGetSeg Worked              ;@CJ10
                POP  AX                 ; Restore selector
              .ELSE                     ; DosGetSeg Failed
                POP  AX                 ; Get bad selector off stack
                XOR  AX, AX             ; Can't use caller's environment
                XOR  BX, BX             ; AX:BX = 0 = Environment buffer @
              .ENDIF

            .ELSE                       ; No Request Block
              XOR  BX, BX               ; AX:BX = 0 = Environment buffer @
            .ENDIF

            PUSH ES                     ; Input argument string address
            PUSH DI                     ; '/C PgmName PgmInputs',0

            PUSH AX                     ; Environment
            PUSH BX

            PUSH DWORD PTR SS:[BP].SGStrNewPID  ; Process ID            ;CJ10
;CJ10       PUSH ES
;CJ10       PUSH DI

            PUSH DWORD PTR SS:[BP].SGStrPgmName ; Program addr          ;CJ10
;CJ10       PUSH ES
;CJ10       PUSH DI

ifdef gsproblem
            PUSH 0
            POP  GS
endif
            .IF  < DH ne VDM_Type > AND      ; If not VDM
            .IF  < DH ne Windowed_VDM_Type > ; If not Windowed VDM
              CALL DOSEXECPGM
            .ELSE                            ; It is a VDM
              PUSH 0                         ; Pad to a DWORD
              PUSH Local_SGID

;             ********************************************************  ;58348
;             *  If this came from our VDM start session, then pass  *  ;58348
;             *  it's current directory to the DosCreateVDM else     *  ;58348
;             *  just pass 0.                                        *  ;58348
;             ********************************************************  ;58348
              TEST WORD PTR Local_Var1, VDMStartedSession               ;58348
              .IF  < nz >                                               ;58348
                MOV  AX, RDATA                                          ;58348
                MOV  ES, AX                                             ;58348
                PUSH ES:VDMCurDir       ; Current VDM directory         ;58348
              .ELSE                                                     ;58348
                PUSH DWORD PTR 0        ; No current directory          ;58348
              .ENDIF                                                    ;58348

              CALL DOSCREATEVDM              ; Start A VDM
            .ENDIF

;           *************
;           *  Get PID  *
;           *************
            LES  DI, SS:[BP].SGStrNewPID  ; Process ID
            MOV  BX, ES:[DI]              ; Get it into BX

;           ********************************************
;           *  Restore SGCB address & put Pid in SGCB  *
;           ********************************************
            POP  DI                     ; Restore new SGCB @
            POP  ES
            MOV  ES:[DI].SGCB_PID, BX   ; Put PID in SGCB

;           *******************************************
;           *  LOWER THE PRIORITY OF THE NEW SESSION  *
;           *******************************************
            .IF  < zero AX >            ; Good start?                   ;@CJ10
;CJ10         PUSH 1                    ; Process and descendants
              PUSH DWORD PTR 10002H     ; Regular class                 ;CJ10
              PUSH AX                   ; Default delta priority (0)    ;CJ10
              PUSH BX                   ; Process ID
              CALL DOSSETPRTY           ; Lower priority
            .ENDIF

            PUSH AX                     ; PD/RP
            MOV  AX,DS                  ; PD/RP
            .IF  < nonzero AX >         ; Good selector   ; PD/RP
              .IF  < nonzero CL >       ; If RqStr GetSeg done          ;CJ61
                PUSH DS:[SI].RqStrObjName[2]   ; Free Sel to Obj. Name  ;CJ53
                CALL DOSFREESEG                                         ;CJ53
              .ENDIF                                                    ;CJ61

              .IF  < nonzero CH >       ; If Env GetSeg done            ;CJ61
                PUSH DS:[SI].RqEnvironment[2]  ; Free Selector to Env.  ;CJ53
                CALL DOSFREESEG                                         ;CJ53
              .ENDIF                                                    ;CJ61
            .ENDIF                           ; PD/RP
            POP  AX                          ; PD/RP

          .ENDIF                        ; End Inherited or not inherited test

;         *********************************************************   ;CJ41
;         *  EXEC/CREATEVDM failed so set SGCB_Flag ASAP in       *   ;CJ41
;         *  case ChildWait wakes up.  ChildWait will check       *   ;CJ41
;         *  this flag so ChildExit isn't called >1 for same SG.  *   ;CJ41
;         *********************************************************   ;CJ41
          .IF  < nonzero AX >                                         ;CJ41
            OR   ES:[DI].SGCB_Flags, Start_Failed    ; Exec failure   ;CJ41
          .ENDIF                                                      ;CJ41

;         ******************************
;         *  Put Pid in SGCB_PIDArray  *
;         ******************************
          PUSH ES                       ; Save @ of Request Block
          PUSH DI

          MOV  CX, RDATA                ; Get DS back to RDATA
          MOV  DS, CX
          MOV  CX, BX                   ; Save PID
          MOV  BX, DX                   ; Get SGID
          XOR  BH, BH                   ; Use only lower byte
          SHL  BX, 1                    ; Offset into PID_Array
          LES  DI, SGCB_PIDArray        ; ES:[DI] --> SGCB_PIDArray (@ of array)
          LES  DI, ES:[DI]              ; ES:[DI] --> 1st element in array
          MOV  ES:[DI][BX][2], CX       ; PID in PID_Array(past reserved word)
          MOV  BX, CX                   ; Restore PID in BX

        .ELSE                            ; Switch failed
          LDS  SI, SS:[BP].SGStrReqBlock ; @ of Req Blk
          MOV  DI, DS                    ; Check for NULL selector DX 2 DI @@AB

          .IF  < nonzero DI >            ; Use DI instead of DX    @@AB, @CJ10
            MOV  DS:[SI].ReqReturnCode, AX ; Put RC in RB
          .ENDIF
        .ENDIF

        POP  DI                         ; Restore new SGCB @
        POP  ES

;       ************************
;       *  ES:DI --> New SGCB  *
;       ************************
;       ***************************************************
;       *  Lower new childs priority to the default       *
;       *  regular class. Clear RAM semaphore to unblock  *
;       *  termination monitoring thread (4)              *
;       ***************************************************

;       **********************************************
;       *  If there is a PM call back routine, call  *
;       *  it now - before we thaw the new session.  *
;       **********************************************
        .IF  < <WORD PTR SS:[BP].SGStrPMRoutine[2]> ne Null > ; If Selector exists
          MOV  CX, AX                   ; Save RC from DosExecPgm or DosCreateVDM
          .IF  < cxz >                  ; Exec was successful           ;CJ10
            PUSH BX                     ; PID
            PUSH DX                     ; SGID
          .ELSE
            PUSH DWORD PTR 0                                            ;@CJ10
          .ENDIF

          CALL SS:[BP].SGStrPMRoutine   ; Call WinPreThaw
          MOV  AX, CX                   ; Get previous error, if any
        .ENDIF                          ; Check to see if @ passed

        PUSH AX                         ; Save return code
        .IF  < zero AX > NEAR           ; If exec worked                ;@CJ10
;         ***********************************************
;         *  If this is an inherited start, adopt it.   *
;         ***********************************************
          .IF  < SS:[BP].SGStrEnvironOpt eq Inherited >
;           **********************************************
;           *  Get the new PID out of the request block  *
;           **********************************************
            LDS  SI, SS:[BP].SGStrReqBlock ; @ of Req Blk
            MOV  AX, DS:[SI].RqStrChildPID ; Pid to Adopt

            PUSH RDATA                  ; Address shared data
            POP  DS                     ; Selector of action packet
            MOV  StartActionPacket, 4        ; Adopt process
            MOV  StartActionPacket[2], AX    ; PID to adopt

            PUSH 0                      ; Session Manager request
            PUSH DS                     ; Action packet
            PUSH OFFSET StartActionPacket
            PUSH DWORD PTR 0            ; Null response packet          ;@CJ10
            CALL DOSSYSTEMSERVICE

            MOV  StartActionPacket, 1   ; Reset Back Default
          .ENDIF                        ; End Inheritance test

          MOV  AX, DX                   ; Save full SGID
          XOR  DH, DH                   ; Clear upper byte
;         ***************************
;         *  SWITCH TO NEW SESSION  *
;         ***************************
          .IF  < AH ne VDM_Type > AND
          .IF  < AH ne Windowed_VDM_Type >
;           *********************************
;           *  Convert Program Type to      *
;           *  Local InfoSeg Process Type   *
;           *  and put it in the InfoSeg    *
;           *********************************
            PUSH BX                     ; New PID
            PUSH DX                     ; New SG

            .IF < AH e FS_Type >
              PUSH LIS_PT_FULLSCRN
            .ELSEIF < AH e Window_Type >
              PUSH LIS_PT_VIOWIN
            .ELSEIF < AH e PM_Type >
              PUSH LIS_PT_PRESMGR
            .ELSE
              PUSH LIS_PT_FULLSCRN      ; Default type
            .ENDIF

            CALL DOSSGSWITCHPROC2       ; Switch proc.
          .ENDIF

;         **************************
;         *  THAW THE NEW SESSION  *
;         **************************
          .IF  < SS:[BP].SGStrAsyncInd ne 3 > ; Not trace
            MOV  StartActionPacket[2], 3      ; Thaw SG
            MOV  StartActionPacket[4], DX
            PUSH 0                      ; Session Manager request
            PUSH DS                     ; Action packet
            PUSH OFFSET StartActionPacket
            PUSH DWORD PTR 0            ; Null response packet          ;@CJ10
            CALL DOSSYSTEMSERVICE
          .ENDIF                        ;

          PUSH DS                       ; Start screen group semaphore
          PUSH OFFSET StartRamSem
          CALL DOSSEMCLEAR

;         *****************************************
;         *  Give foreground boost to new process *
;         *****************************************
          PUSH 3                        ; Boost new SG priority only
          PUSH DX                       ; Foreground boost
          CALL DOSSETFGND

          PUSH 0                        ; Boost new PID priority only
          PUSH ES:[DI].SGCB_PID         ; Foreground boost
          CALL DOSSETFGND

;         ************************
;         *  Get topmost process *
;         ************************
          PUSH DX                       ; Save new SGID <use for SGID>
          PUSH BX                       ; Save old foreground SGID
          LFS  SI, TopMost              ; Get topmost addressability

;         ***********************
;         *  Find Extended SGID *
;         ***********************
          .IF  < <BYTE PTR FS:[SI].SGCB_ID> eq Shell_SG > ; Shell Foreground?
            .IF  < PM_Present e Yes >          ; If PM is in the System
              LEA  DX, Local_Var1

              PUSH SS
              PUSH DX
              CALL WINQUERYEXTIDFOCUS   ; Ignore any errors

              MOV  DX, Local_Var1       ; Extended SG
              LEA  SI, Local_Var2
              PUSH SS
              PUSH SI
              PUSH DX
              PUSH SGID_Lookup + 8000H  ; Look up SGID not PID and      ;CJ10
              CALL DOSSMGETSGCB         ;   don't serialize QueueRamSem

              .IF < zero AX >           ; If we found the SGCB          ;@CJ10
                LGS  SI, Local_Var2
              .ELSE                     ; We didn't find the SGCB
                LGS  SI, BaseShell      ; So just go to the Shell's SG
              .ENDIF

              MOV  BX, GS:[SI].SGCB_PID ; Get extended PID

            .ELSE                       ; PM not present
              MOV  AX, Not No_Error     ; Fake error - Win not present
            .ENDIF                      ; PM here test
          .ELSE                         ; Shell not foreground
            MOV  DX, FS:[SI].SGCB_ID    ; Get SGID
            MOV  BX, FS:[SI].SGCB_PID   ; Get PID
          .ENDIF

;         **********************************
;         *  Always boost topmost process. *
;         **********************************
          .IF  < zero AX >                                              ;@CJ10
            PUSH 3                      ; Boost SG priority only
            PUSH DX                     ; Foreground boost
            CALL DOSSETFGND

            PUSH 0                      ; Boost PID priority only
            PUSH BX                     ; Foreground boost
            CALL DOSSETFGND
          .ENDIF

          POP  BX                       ; Restore new SGID
          POP  DX                       ; Restore old foreground SGID

        .ELSE                           ; Exec or Switch failed
;         **************************************************
;         *  Exec or switch failed, free screen group ID.  *
;         **************************************************
          LEA  SI, Local_Var2
          PUSH SS
          PUSH SI
          PUSH DX
          PUSH SGID_Lookup + 8000H      ; Look up SGID not PID and      ;CJ10
          CALL DOSSMGETSGCB             ;   don't serialize QueueRamSem

;         ********************************
;         *  Save address of calling SG  *
;         ********************************
          MOV  AX, RDATA                ; Setup DS for DosSMChildExit      @@AB
          MOV  DS, AX                   ;                                  @@AB
          LGS  SI, Local_Var2           ; GS:[SI] --> SGCB
          OR   GS:[SI].SGCB_Flags, 2    ; Exec failure
          CALL DOSSMCHILDEXIT

          .IF  < DX ne -1 > AND         ; If we need to do the switch
          .IF  < AX ne Error_SMG_Session_Not_Found >
            XOR  AX, AX                 ; Force switch to occur
            XOR  BX, BX                 ; Save old fgnd SG

            .IF  < DH e FS_Type > OR    ; Are we presently in a FS session?
            .IF  < DH e VDM_Type >
              MOV  BX, 0100H            ; Switch to old Fgnd screen group
            .ENDIF

;           ***********************************************
;           *  Set up ES:SI, and DX.                      *
;           *  ES:SI --> SG that did the Dos_____Session  *
;           ***********************************************
            LES  SI, Local_TopMost
            MOV  EAX, TopMost
;           *******************************************************        @@AB
;           *  Don't switch if we're already on top, UNLESS       *        @@AB
;           *  TopMost was set to Local_TopMost in DosSMDelSGCB.  *        @@AB
;           *******************************************************        @@AB
            .IF  < EAX ne Local_TopMost > OR ; Don't switch if already on top
            TEST ES:[SI].SGCB_Flags, 4       ; Unless TopMost By Deletion  @@AB
            .IF nz                           ; TopMost=EAX from DelSGCB    @@AB
              MOV  DX, ES:[SI].SGCB_ID
              LES  SI, TopMost                            ; 74851 Flag should be
              AND  ES:[SI].SGCB_Flags, NOT 4 ; Reset flag ; reset for TopMost!!
              CALL DOSSMGSWITCH
            .ENDIF
          .ENDIF
        .ENDIF
        POP  AX                         ; Restore return code

      .ELSE                             ; DOSSMADDSGCB failed
        PUSH DS                         ; Save DS
        PUSH SI                         ; Save SI
        LDS  SI, SS:[BP].SGStrReqBlock  ; @ of Req Blk
        PUSH DX
        MOV  DX, DS                     ; Check for NULL selector

        .IF  < nonzero DX >                                             ;@CJ10
          MOV  DS:[SI].ReqReturnCode, AX ; Put RC in Req. Blk
        .ENDIF

        .IF  < <WORD PTR SS:[BP].SGStrPMRoutine[2]> ne Null >
          PUSH AX                       ; Save return code
          PUSH DWORD PTR 0              ; Notify Shell thru PreThaw     ;@CJ10
          CALL SS:[BP].SGStrPMRoutine   ;   of error
          POP  AX                       ; Restore return code
        .ENDIF

        POP  DX
        POP  SI                         ; Restore SI
        POP  DS                         ; Restore DS
      .ENDIF                            ; DOSSMADDQUEUE test
    .ENDIF

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

    MMPHPostDOSSMSGStart                ; Performance Hook (8082h)      ;MHW

    POP  FS                             ; Restore registers
    POP  ES
    POP  DS
    POPA

    LEAVE
    DOSSMSGSTART_POSTDT LABEL FAR
    RET  SGStrFrmLen                    ; Return to caller

DOSSMSGSTART ENDP
;****************************************************************************


;****************************************************************************
PUBLIC  DOSSMGETNAMES
DOSSMGETNAMES  PROC NEAR
;     ********************************************
;     *  This code used to be inline above, but  *
;     *  was broken out to modularize the code.  *
;     ********************************************
      LES  DI, SS:[BP].SGStrPgmName     ; Program name
      MOV  AX, ES

      .IF  < SS:[BP].SGStrPgmType ne VDM_Type > AND   ; If not VDM
      .IF  < SS:[BP].SGStrPgmType ne Windowed_VDM_Type > AND
      .IF  < zero AX > OR                        ; Program name not specified ;@CJ10
      .IF  < <ES:BYTE PTR [DI]> eq Null >        ; or points to a null
;       **************************************************
;       *  PUT PROTSHELL PROGRAM ON STACK IF NONE GIVEN  *
;       **************************************************
        MOV  EAX, CmdName                                               ;CJ10
;CJ10   MOV  SS:WORD PTR [BP].SGStrPgmName[2], ES
        MOV  DWORD PTR SS:[BP].SGStrPgmName, EAX                        ;CJ10
        LES  DI, SS:[BP].SGStrPgmInputs          ; Program inputs
        MOV  AX, ES

        .IF  < zero AX > OR                      ; Program inputs not specified ;@CJ10
        .IF  < <ES:BYTE PTR [DI]> eq Null >
;         ****************************************************
;         *  PUT PROTSHELL ARGUMENTS ON STACK IF NONE GIVEN  *
;         ****************************************************
          MOV  EAX, CmdArgs                                             ;CJ10
;CJ10     MOV  SS:WORD PTR [BP].SGStrPgmInputs[2], ES
          MOV  DWORD PTR SS:[BP].SGStrPgmInputs, EAX                    ;CJ10
        .ENDIF
      .ENDIF

      MOV  SI, Yes                      ; Assume title specified
      LES  DI, SS:[BP].SGStrPgmTitle    ; Shell specified title
      MOV  AX, ES

      .IF  < zero AX > OR                 ; Program title not specified ;@CJ10
      .IF  < <ES:BYTE PTR [DI]> eq Null > ; or pointing to a null
        SUB  SI, SI                       ; Title not specified         ;CJ10
        .IF  < SS:[BP].SGStrPgmType e VDM_Type > OR
        .IF  < SS:[BP].SGStrPgmType e Windowed_VDM_Type >
          MOV  ES, BX
          MOV  DI, OFFSET VDMName
        .ELSE
          LES  DI, SS:[BP].SGStrPgmName ; Use prog. name as title
          CALL DOSSMPARSEPATH           ; Strip off path
        .ENDIF
      .ENDIF
      CWDE                                                              ;CJ10
      RET
DOSSMGETNAMES  ENDP
;****************************************************************************


PUBLIC   DOSSMCOPYNAMES
DOSSMCOPYNAMES   PROC  NEAR
;     ********************************************
;     *  This code used to be inline above, but  *
;     *  was broken out to modularize the code.  *
;     ********************************************

      MOV  BX, RDATA
      MOV  ES, BX                       ; ES = global data segment
      MOV  DI, OFFSET CmdInputs         ; CMD.EXE input string
      CLD                               ; Clear direction flag

      PUSH DI                           ; Save offset of Program Name
      MOV  CX, CmdInputLen              ; Maximum length of input parms
      .IF  < DH ne VDM_Type > AND       ; If not VDM
      .IF  < DH ne Windowed_VDM_Type >
        LDS  SI, SS:[BP].SGStrPgmName   ; Program name addr

        .REPEAT                         ; cmdinputs = '/Cpgmname'
          LODSB
          STOSB
        .LEAVE < AL eq 0 >
        .LOOP

        .IF  < AL ne 0 >                ; Name exceeds max
          XOR  AL, AL                   ; Make string ASCIIZ
          STOSB
        .ENDIF
      .ENDIF

      LDS  SI, SS:[BP].SGStrPgmInputs   ; Pgm input string
      MOV  AX, DS
      .IF  < nonzero AX > AND           ; Inputs specified?             ;@CJ10
      .IF  < <DS:BYTE PTR [SI]> ne 0 > AND
      .IF  < NCXZ >                     ; If we still have room in Pgm Parms ;@CJ10

        .REPEAT                         ; cmdinputs = '/Cpgmname'
          LODSB
          STOSB
        .LEAVE < AL eq 0 >
        .LOOP

      .ELSE
        MOV  AL, 1                      ; Force string to ASCIIZ
      .ENDIF

      .IF  < AL ne 0 >                  ; Name exceeds max
        XOR  AL, AL                     ; Make string ASCIIZ
        STOSB
      .ENDIF
      MOV  ES:BYTE PTR [DI], 0          ; ASCIIZ parm
      POP  DI                           ; Restore @ of Pgm name/inputs

      RET

DOSSMCOPYNAMES   ENDP
;****************************************************************************


PUBLIC   DOSSMSTARTSWITCH
DOSSMSTARTSWITCH  PROC  NEAR
;     ********************************************
;     *  This code used to be inline above, but  *
;     *  was broken out to modularize the code.  *
;     ********************************************
;       ************************************************************
;       *  Determine whether to save the foreground screen group.  *
;       ************************************************************
        MOV  BX, SS:[BP].SGStrStartMode ; Fore/background
        LGS  SI, TopMost
        MOV  AX, GS:[SI].SGCB_ID        ; Topmost screen group

        MOV  Local_TopMost[2], GS       ; Remember who's on top now
        MOV  Local_TopMost, SI

        .IF  < BX eq ForeGround > AND   ; Foreground start?
        .IF  < ES:[DI].SGCB_Type eq FS_Type >   OR ; Standard session?
        .IF  < ES:[DI].SGCB_Type eq VDM_Type >  OR ; FS VDM session?
        .IF  < AL ne Shell_SG >                    ; Shell SG not on top
          MOV  BH, BYTE PTR SS:[BP].SGStrAction    ; Action
          MOV  BL, SG_Start_Switch      ; Start switch action

;         ********************************************************
;         *  Make new screen group the foreground screen group.  *
;         ********************************************************
          .IF  < ES:[DI].SGCB_Type ne FS_Type> AND  ; Ext. session?
          .IF  < ES:[DI].SGCB_Type ne VDM_Type >    ; VDM session?
            PUSH DX                     ; Save Real Session ID
            MOV  DX, Shell_SG           ; Bring Shell to foreground
            XOR  BX, BX
            CALL DOSSMGSWITCH

            POP  DX                     ; Get real session id
          .ELSE                         ; We're switching to non-windowed SG
            CALL DOSSMGSWITCH           ; Call without modifying DX
          .ENDIF

        .ELSE                           ; We don't have to switch SGs
          XOR  AX, AX                   ; Initialize return code
          .IF  < ES:[DI].SGCB_Type eq FS_Type > OR   ; FS OR               @@AD
          .IF  < ES:[DI].SGCB_Type eq Default_Type > ; Standard session?
            PUSH Local_SGID             ; New screen group ID
;CJ10       PUSH -1                     ; Flag to create new SGCB
            PUSH DWORD PTR 0FFFF0000H   ; No Debugger                   ;CJ10
            CALL DOSSGDDNOTIFY
          .ENDIF
        .ENDIF                          ; To switch or not to switch, test

;       ************************************************
;       *  Allocate BVSCB and LVB prior to DOSEXECPGM  *
;       ************************************************
        .IF  < zero AX > NEAR                                           ;@CJ10;val
          .IF  < ES:[DI].SGCB_Type be Window_Type >  ; If FS or VIO

;           *********************************************               ;CJ28
;           *  If no registered DLLs, do dummy restore  *               ;CJ28
;           *********************************************               ;CJ28
            .IF  < DS:Registered_DLLs eq 0 >                            ;CJ28
              PUSH ES:[DI].SGCB_ID                   ; New SGID
              PUSH 4                                 ; Dummy Restore
              CALL VIORESTORE
;           *********************************************               ;CJ28
;           *  Else do regular restore for Foreground   *               ;CJ28
;           *  starts only since the dummy restore was  *               ;CJ28
;           *  done before create notification.         *               ;CJ28
;           *********************************************               ;CJ28
            .ELSEIF  <SS:[BP].SGStrStartMode eq ForeGround>             ;CJ28
              PUSH ES:[DI].SGCB_ID                   ; New SGID         ;CJ28
              PUSH 0                                 ; Normal Restore   ;CJ28
              CALL VIORESTORE                                           ;CJ28
            .ENDIF                                                      ;CJ28

            .IF  < AX ne Error_VIO_Internal_Resource >
              XOR  AX, AX               ; Set AX to no error            ;@CJ10
            .ENDIF

          .ELSEIF < ES:[DI].SGCB_Type e VDM_Type > OR        ; If VDM
          .IF     < ES:[DI].SGCB_Type e Windowed_VDM_Type >
            MOV  AX, WORD PTR WinCreateConsole
            OR   AX, WORD PTR WinCreateConsole+2

            .IF < nz >
              PUSH CX                   ; trashable by call
              PUSH DX                   ; trashable by call
              PUSH ES                   ; trashable by call

;             **************************************************        ;D1573
;             *  Reset session type if Seamless.  Seamless     *        ;D1573
;             *  sessions are changed to WindowedVDM sessions  *        ;D1573
;             *  in DosStartSession but the sheild needs to    *        ;D1573
;             *  know when a VDM session is Seamless.          *        ;D1573
;             **************************************************        ;D1573
              MOV  AX, WORD PTR Local_Var1                              ;D1573
              AND  AX, Seamless_Start + Seamless_Common + \
                       STDSeamless_Start + STDSeamless_Common + \
                       ENHSeamless_Start + ENHSeamless_Common

              .IF < nz >                                                ;D1545
                .IF <AX eq Seamless_Start>                              ;D1573
                  MOV  DH, PROG_SEAMLESSVDM                             ;D1545
                .ELSEIF <AX eq Seamless_Common>                         ;VLR
                  MOV  DH, PROG_SEAMLESSCOMMON                          ;VLR
                .ELSEIF <AX eq STDSeamless_Start>                       ;VLR
                  MOV  DH,  PROG_31_STDSEAMLESSVDM                      ;VLR
                .ELSEIF <AX eq STDSeamless_Common>                      ;VLR
                  MOV  DH,  PROG_31_STDSEAMLESSCOMMON                   ;VLR
                .ELSEIF <AX eq ENHSeamless_Start>                       ;VLR
                  MOV  DH,  PROG_31_ENHSEAMLESSVDM                      ;VLR
                .ELSEIF <AX eq ENHSeamless_Common>                      ;VLR
                  MOV  DH,  PROG_31_ENHSEAMLESSCOMMON                   ;VLR
                .ENDIF
              .ENDIF

              PUSH DX                   ; SGID in low byte, type in high
              SUB  EAX, EAX                                             ;@D1088
              PUSH EAX                  ; NULL pointer to presentation space ;@D1088
              PUSH EAX                  ; NULL pointer to kbd/mou parms      ;@D1088
              PUSH EAX                  ; NULL pointer for console handle    ;@D1088
              CALL WinCreateConsole     ; begin VDM window creation

              POP  ES
              POP  DX
              POP  CX
            .ENDIF
          .ENDIF
        .ENDIF

        RET
DOSSMSTARTSWITCH  ENDP
;****************************************************************************

CODE_TUNE1  ENDS                                                        ;MDLL
endif
    END
