page ,132 if 0 /*++ Copyright (c) 1991 Microsoft Corporation Module Name: resident.asm Abstract: This module contains the resident code part of the stub redir TSR for NT VDM net support. The routines contained herein are the 2f handler and the API support routines: MultHandler ReturnMode SetMode GetAssignList DefineMacro BreakMacro GetRedirVersion NetGetUserName DefaultServiceError NetGetEnumInfo NetSpoolStuff Author: Richard L Firth (rfirth) 05-Sep-1991 Environment: Dos mode only Revision History: 05-Sep-1991 rfirth Created --*/ endif .xlist ; don't list these include files .xcref ; turn off cross-reference listing include dosmac.inc ; Break macro etc (for following include files only) include dossym.inc ; User_ defines include mult.inc ; MultNET include error.inc ; DOS errors - ERROR_INVALID_FUNCTION include syscall.inc ; DOS system call numbers include rdrint2f.inc ; redirector Int 2f numbers include segorder.inc ; segments include enumapis.inc ; dispatch codes include debugmac.inc ; DbgPrint macro include localmac.inc ; DbgPrint macro include asmmacro.inc ; language extensions include rdrsvc.inc ; BOP and SVC macros/dispatch codes include rdrmisc.inc ; miscellaneous definitions include sf.inc ; SFT definitions/structure include vrdefld.inc ; VDM_LOAD_INFO .cref ; switch cross-reference back on .list ; switch listing back on subttl ; kill subtitling started in include file .286 ; all code in this module 286 compatible ResidentDataStart public LanRootLength, LanRoot LanRootLength dw ? ; can't be >81 bytes anyhow LanRoot db (64+3+1+13) dup (?) ResidentDataEnd ResidentCodeStart extrn DosQnmPipeInfo: near extrn DosQNmpHandState: near extrn DosSetNmpHandState: near extrn DosPeekNmPipe: near extrn DosTransactNmPipe: near extrn DosCallNmPipe: near extrn DosWaitNmPipe: near extrn NetTransactAPI: near extrn NetIRemoteAPI: near extrn NetUseAdd: near extrn NetUseDel: near extrn NetUseEnum: near extrn NetUseGetInfo: near extrn NetServerEnum: near extrn DosMakeMailslot: near extrn DosDeleteMailslot: near extrn DosMailslotInfo: near extrn DosReadMailslot: near extrn DosPeekMailslot: near extrn DosWriteMailslot: near extrn NetNullTransactAPI: near extrn NetServerEnum2: near extrn NetServiceControl: near extrn NetWkstaGetInfo: near extrn NetWkstaSetInfo: near extrn NetMessageBufferSend: near extrn NetHandleGetInfo: near extrn NetHandleSetInfo: near extrn DosReadAsyncNmPipe: near extrn DosWriteAsyncNmPipe: near extrn DosReadAsyncNmPipe2: near extrn DosWriteAsyncNmPipe2: near extrn MessengerDispatch: near ; ; IMPORTANT: This structure MUST be the first thing in the resident code segment ; extrn dwPostRoutineAddress: dword VdmWindowAddr VDM_LOAD_INFO align 4 ; ; Address of previous handler to chain if int 2f not for us ; public OldMultHandler OldMultHandler dd ? ; ; OldFunctionTable is a table of near pointers to handlers for the old 5f ; functions 5f00 through 5f05 ; OldFunctionTable label word dw ReturnMode ; 5f00 dw SetMode ; 5f01 dw GetAssignList ; 5f02 dw DefineMacro ; 5f03 dw BreakMacro ; 5f04 dw GetAssignList2 ; 5f05 ; ; May as well keep this jump table in the code segment - no point in loading ; ds just to get a jump offset ; MultDispatchTable label word dw GetRedirVersion ; 5f30 dw DefaultServiceError ; 5f31 - NetWkstaSetUID dw DosQnmPipeInfo ; 5f32 dw DosQNmpHandState ; 5f33 dw DosSetNmpHandState ; 5f34 dw DosPeekNmPipe ; 5f35 dw DosTransactNmPipe ; 5f36 dw DosCallNmPipe ; 5f37 dw DosWaitNmPipe ; 5f38 dw DefaultServiceError ; 5f39 - DosRawReadNmPipe dw DefaultServiceError ; 5f3a - DosRawWriteNmPipe dw NetHandleSetInfo ; 5f3b dw NetHandleGetInfo ; 5f3c dw NetTransactAPI ; 5f3d dw DefaultServiceError ; 5f3e - NetSpecialSMB dw NetIRemoteAPI ; 5f3f dw NetMessageBufferSend ; 5f40 dw DefaultServiceError ; 5f41 - NetServiceEnum dw NetServiceControl ; 5f42 dw DefaultServiceError ; 5f43 - DosPrintJobGetID dw NetWkstaGetInfo ; 5f44 dw NetWkstaSetInfo ; 5f45 dw NetUseEnum ; 5f46 dw NetUseAdd ; 5f47 dw NetUseDel ; 5f48 dw NetUseGetInfo ; 5f49 dw DefaultServiceError ; 5f4a - NetRemoteCopy dw DefaultServiceError ; 5f4b - NetRemoteMove dw NetServerEnum ; 5f4c dw DosMakeMailslot ; 5f4d dw DosDeleteMailslot ; 5f4e dw DosMailslotInfo ; 5f4f dw DosReadMailslot ; 5f50 dw DosPeekMailslot ; 5f51 dw DosWriteMailslot ; 5f52 dw NetServerEnum2 ; 5f53 dw NetNullTransactAPI ; 5f54 - NullTransaction entrypoint. MAX_TABLE_ENTRIES = (($-MultDispatchTable)/type MultDispatchTable)-1 ; ; this next table dispatches the functions that come in through a direct call ; to int 2f, ah=11, al=function code ; ServiceDispatchTable label word dw NetGetUserName ; 80h - NetGetUserName o dw DefaultServiceError ; 81h - NetSetUserName x dw DefaultServiceError ; 82h - NetServiceNotify x dw DefaultServiceError ; 83h - NetPrintNameEnum x dw NetGetEnumInfo ; 84h - NetGetEnumInfo o dw DefaultServiceError ; 85h - TestDBCSLB x dw DosReadAsyncNmPipe ; 86h - DosReadAsyncNmPipe x dw DefaultServiceError ; 87h - DosUnusedFunction1 x dw DefaultServiceError ; 88h - DosUnusedFunction2 x dw DefaultServiceError ; 89h - NetCalloutNCB x dw DefaultServiceError ; 8Ah - EncrPasswd x dw DefaultServiceError ; 8Bh - NetGetLogonServer o dw DefaultServiceError ; 8Ch - NetSetLogonServer o dw DefaultServiceError ; 8Dh - NetGetDomain o dw DefaultServiceError ; 8Eh - NetSetDomain o dw DosWriteAsyncNmPipe ; 8FH - DosWriteAsyncNmPipe x dw DosReadAsyncNmPipe2 ; 90H - DosReadAsyncNmPipe2 x dw DosWriteAsyncNmPipe2 ; 91H - DosWriteAsyncNmPipe2 x MAX_SERVICE_ENTRIES = (($-ServiceDispatchTable)/type ServiceDispatchTable)-1 page ; *** MultHandler ; * ; * Whenever an INT 2F call is made, sooner or later this function will ; * get control. If the call is actually for the redir, AH will be set ; * to 11h (MultNET). If it is any other value then we just chain it ; * along. Note that since there is no MINSES loaded in the NT DOS network ; * stack, then we need also to fake calls to MINSES. These are made through ; * INT 2F, with ah = 0xB8. We trap calls AX=B800 (network presence test) ; * and AX=B809 (network/redir installation test) ; * ; * ENTRY ax = (MultNET << 8) | net operation code ; * Net operation code can be: ; * Install check 0 ; * Assign operation 30 ; * Anything else is DOS/NET specific. We should raise a gorbachev ; * or rather an error if we receive something else ; * ; * Stack: IP \ ; * CS > From Int 2f ; * Flags / ; * Caller's AX From call to Int 21/ah=5f ; * ; * We need the caller's AX to dispatch the NetAssOper calls, nothing ; * more ; * ; * All the rest of the registers are as per the caller ; * ; * EXIT CF = 0 ; * success ; * CF = 1 ; * AX = error ; * ; * USES all regs ; * ; * ASSUMES Earth is flat ; * ; *** if DEBUG OriginalAx dw ? OriginalBx dw ? endif public MultHandler MultHandler proc far assume cs:ResidentCode assume ds:nothing assume es:nothing assume ss:nothing if DEBUG mov OriginalAx,ax mov OriginalBx,bx endif cmp ah,MultNET ; 11h je @f ; ; test for AH=B8 and return network presence indicators if it is. Here we are ; faking calls to MINSES (minimum session layer) and intercept calls AX=B800 ; and AX=B809. Any other AH=B8 call must be for a different TSR/driver ; cmp ah,0b8h jne check_messenger or al,al jnz try_9 ; ; AX=B800. This is the MinSes installation check. Return the magic numbers ; AL=1 and BX=8 (see doslan\minses\int2f.inc in LANMAN project) ; inc al mov bx,8 do_iret:iret try_9: cmp al,9 jne chain_previous_handler ; AL not 0 or 9, AH=B8 for somebody else ; ; AX=B809 is a network installation test. Return the magic numbers AL=1, AH=2 ; for PC Network version 1.2 (this is what minses does, don't complain to me ; about PC networks, etc, etc) ; mov ax,0201h jmp short do_iret ; ; MESSENGER TSR uses AH=42h ; check_messenger: cmp ah,42h ; multMESSAGE jne chain_previous_handler call MessengerDispatch retf 2 ; return state in flags chain_previous_handler: jmp OldMultHandler ; not for us; pass it along ; ; the 2f call is for us. If it is the installation check, return al == -1 else ; dispatch the byte code at sp+6 ; @@: sti ; re-enable interrupts or al,al jnz @f or al,-1 ; installation check just returns 0xff ret 2 ; 'or' clears carry @@: cld ; auto-increment string operations ; ; this call is something other than an installation check. I really hope that ; its the AssignOper request, because I don't know what to do if it isn't... ; cmp al,_2F_NET_ASSOPER jmpe is_net_request ; yes - we can do something ; ; if its the ResetEnvironment request then we have to kill any net state info ; like mailslot info. Return via iret ; cmp al,_2F_NetResetEnvironment jmpne check_service_call ; ; deferred loading: don't load VDMREDIR.DLL for VrTerminateDosProcess if no NET ; calls have been made ; cmp VdmWindowAddr.VrInitialized,1 je @f iret if 0 DbgPrintString "NetResetEnvironment received. PDB=" push ax ; int 21/51 uses ax,bx push bx endif @@: mov ah,51h int 21h ; get current PDB if 0 DbgPrintHexWord bx ; bx contains PSP of current process pop bx pop ax DbgCrLf endif mov ax,bx SVC SVC_RDRTERMINATE iret ; ; if this is a net service call (ah=11h, al=function code 80h through 91h) then ; dispatch through the service table ; check_service_call: cmp al,_2F_NetSpoolOper ; 25h jne @f call NetSpoolStuff jmp short return_to_dos @@: cmp al,_2F_NetGetUserName ; 80h jmpb trap_it cmp al,_2F_DosWriteAsyncNmPipe2 ; 91h jmpa trap_it if 0 DbgPrintString "Received Service Request: " DbgPrintHexWord ax DbgCrLf endif sub ax,(MultNET shl 8) + _2F_NetGetUserName xchg ax,bx shl bx,1 mov bx,ServiceDispatchTable[bx] xchg ax,bx call ax ; ; all calls that come through here are expected to have originated in DOS ; return_to_dos: ret 2 ; with interrupts enabled ; ; if we get anything else, either from DOS, or some - as yet - unknown source, ; then just pass it along to the next handler. In the debug version, we alert ; someone to the fact that we've got an unrecognized call ; trap_it: DbgPrintString "Received unrecognized Service Request: " DbgPrintHexWord ax DbgCrLf DbgBreakPoint jmp OldMultHandler ; pass it down the chain ; ; get the original dispatch code back off the stack. We no longer require the ; current contents of ax ; is_net_request: push bp mov bp,sp mov ax,[bp + 8] ; ax <- original code (5fxx) pop bp if DEBUG mov OriginalAx,ax endif ; ; quick sanity check to make sure that we're processing the right call. If we ; were called with ax != 5fxx, assume that somebody else is also using the ; same 2F function call, and chain the next handler. Note: this wouldn't be ; a very smart thing to do ; sub ah,AssignOper ; ah => 0 it is AssignOper jz @f DbgBreakPoint mov ax,(MultNET shl 8) + _2F_NET_ASSOPER ; restore ax jmps chain_previous_handler @@: cmp al,5 ; is it 5f00 - 5f05? jnbe @f ; ; if the function is in the range 0 - 5 then its an old function - dispatch ; through the old function table ; shl al,1 xchg ax,bx mov bx,OldFunctionTable[bx] xchg ax,bx call ax ret 2 @@: sub al,Local_API_RedirGetVersion jz @f ; function is GetRedirVersion cmp al,MAX_TABLE_ENTRIES jbe @f ; UNSIGNED comparison!!! ; ; get 32-bit support code to dump registers to debug terminal ; if DEBUG mov ax,OriginalAx DbgUnsupported endif mov ax,ERROR_NOT_SUPPORTED stc ; set error indication jmp short set_ax_exit ; ; the function is within range. Dispatch it. Copy the offset from the dispatch ; table into ax then call through ax. ax was only required to get us this far ; and contains no useful information ; @@: xchg ax,bx ; need base register, ax not good enough in 286 shl bx,1 ; bx is now offset in dispatch table mov bx,MultDispatchTable[bx]; bx is offset of handler routine xchg ax,bx ; restore caller's bx call ax ; go handle it ret 2 ; return without reinstating flags ; ; Return an error in the caller's ax register. To do this we have to ask DOS to ; please give us the address of its copy of the user's registers, which it will ; pass back in DS:SI. We then futz with the copy of the user's reg. Dos will ; restore this before returning control to the user code. Since we know we have ; an error situation set the carry flag ; set_ax_exit: pushf ; error indicator push ax ; return code DosCallBack GET_USER_STACK ; get pointer to caller's context assume ds:nothing ; nuked - actually in DOS somewhere (stack) pop [si].User_Ax ; copy saved return code into user's copy popf ; restore error indicator ret 2 ; clear caller's flags from int 2f call MultHandler endp page ; *** ReturnMode ; * ; * Returns the disk or print redirection flag. Flag is 0 if redirection ; * is paused, else 1 ; * ; * ENTRY BL = 3 ; * Return print redirection ; * ; * BL = 4 ; * Return drive redirection ; * ; * EXIT CF = 0 ; * BX = redirection flag: 0 or 1 ; * ; * CF = 1 ; * error ; * ; * USES bx ; * ; * ASSUMES nothing ; * ; *** PrintRedirection db 0 DriveRedirection db 0 ReturnMode proc near assume cs:ResidentCode assume ds:nothing DbgPrintString <"5f00 called",13,10> DbgUnsupported cmp bl,3 jne @f mov bh,PrintRedirection jmp short set_info @@: cmp bl,4 stc jnz @f mov bh,DriveRedirection set_info: and bh,1 DosCallBack GET_USER_STACK mov [si].User_Bx,bx clc @@: ret ReturnMode endp page ; *** SetMode ; * ; * Pauses or continues drive or printer redirection. Note that we don't ; * support drive/print pause/continuation from DOS ; * ; * ENTRY BL = printer (3) or drive (4) redirection ; * BH = pause (0) or continue (1) ; * ; * EXIT CF = 0 ; * success ; * CF = 1 ; * ax = ERROR_INVALID_PARAMETER ; * ; * USES ax, bx ; * ; * ASSUMES nothing ; * ; *** SetMode proc near assume cs:ResidentCode assume ds:nothing DbgPrintString <"5f01 called",13,10> DbgUnsupported cmp bh,1 jnbe bad_parm_exit dec bh ; convert 0 => ff, 1 => 0 not bh ; convert ff => 0, 0 => ff sub bl,3 jnz try_drive mov PrintRedirection,bh jmp short ok_exit try_drive: dec bl jnz bad_parm_exit mov DriveRedirection,bh ok_exit:clc ret bad_parm_exit: mov ax,ERROR_INVALID_PARAMETER stc ret SetMode endp page ; *** GetAssignList ; * ; * Returns information on enumerated redirections. Old version of ; * NetUseGetInfo ; * ; * ENTRY BX = which item to return (starts @ 0) ; * DS:SI points to local redirection name ; * ES:DI points to remote redirection name ; * AL != 0 means return LSN in BP (GetAssignList2)? ** UNSUPPORTED ** ; * ; * EXIT CF = 0 ; * BL = macro type (3 = printer, 4 = drive) ; * BH = 'interesting' bits: 00 = valid, 01 = invalid ; * CX = user word ; * DS:SI has device type ; * ES:DI has net path ; * CF = 1 ; * AX = ERROR_NO_MORE_FILES ; * ; * USES ; * ; * ASSUMES nothing ; * ; *** GetAssignList proc near assume cs:ResidentCode assume ds:nothing xor al,al jmp short @f GetAssignList2: or al,-1 @@: SVC SVC_RDRGET_ASG_LIST jc @f push bx push cx DosCallBack GET_USER_STACK pop [si].User_Cx pop [si].User_Bx clc @@: ret GetAssignList endp page ; *** DefineMacro ; * ; * Old version of NetUseAdd ; * ; * ENTRY BL = device type ; * 3 = printer ; * 4 = drive ; * bit 7 on means use the wksta password when connecting ; * CX = user word ; * DS:SI = local device ; * Can be NUL device name, indicating UNC use ; * ES:DI = remote name ; * ; * EXIT CF = 0 ; * success ; * ; * CF = 1 ; * AX = ERROR_INVALID_PARAMETER (87) ; * ERROR_INVALID_PASSWORD (86) ; * ERROR_INVALID_DRIVE (15) ; * ERROR_ALREADY_ASSIGNED (85) ; * ERROR_PATH_NOT_FOUND (3) ; * ERROR_ACCESS_DENIED (5) ; * ERROR_NOT_ENOUGH_MEMORY (8) ; * ERROR_NO_MORE_FILES (18) ; * ERROR_REDIR_PAUSED (72) ; * ; * USES ; * ; * ASSUMES nothing ; * ; *** DefineMacro proc near assume cs:ResidentCode assume ds:nothing SVC SVC_RDRDEFINE_MACRO ret DefineMacro endp page ; *** BreakMacro ; * ; * Old version of NetUseDel ; * ; * ENTRY DS:SI = buffer containing device name of redirection to break ; * ; * EXIT ; * ; * USES ; * ; * ASSUMES nothing ; * ; *** BreakMacro proc near assume cs:ResidentCode assume ds:nothing SVC SVC_RDRBREAK_MACRO ret BreakMacro endp page ; *** GetRedirVersion ; * ; * Returns the version number of this redir in ax ; * ; * ENTRY none ; * ; * EXIT ax = version # ; * ; * USES ax, flags ; * ; * ASSUMES nothing ; * ; *** GetRedirVersion proc near assume cs:ResidentCode assume ds:nothing mov ax,300 clc ret GetRedirVersion endp page ; *** NetGetUserName ; * ; * Returns the current logged on user name (if any) ; * ; * ENTRY CX = buffer length ; * ES:DI = buffer ; * ; * EXIT CF = 1 ; * AX = Error code ; * NERR_BufTooSmall ; * Buffer not large enough for user name ; * ; * CF = 0 ; * CX:BX = UID (ignored) ; * ES:DI = user name ; * ; * USES ax, flags ; * ; * ASSUMES nothing ; * ; *** NetGetUserName proc near assume cs:ResidentCode assume ds:nothing mov bx,1 ; bx == 1: check name length against cx call NetGetUserNameSvcCall DbgBreakPoint jc @f ; error ; ; no error: the user name was copied into ES:DI. Set the caller's cx and bx to ; return a UID. We could leave this as a random number since it is not used, ; but we set it to a known value ; DosCallBack GET_USER_STACK xor ax,ax ; clears carry again mov [si].User_Cx,ax inc ax mov [si].User_Bx,ax ; UID = 0x00000001 @@: ret NetGetUserName endp page ; *** DefaultServiceError ; * ; * Default error routine - returns ERROR_INVALID_FUNCTION for any API ; * function which we don't support. Reached exclusively through dispatch ; * table ; * ; * ENTRY none ; * ; * EXIT CF = 1 ; * AX = ERROR_INVALID_FUNCTION ; * ; * USES ax, flags ; * ; * ASSUMES nothing ; * ; *** DefaultServiceError proc near assume cs:ResidentCode assume ds:nothing ; DbgPrintString <"DefaultServiceError Ax=" ; DbgPrintHexWord OriginalAx ; DbgPrintString <" Bx=">,NOBANNER ; DbgPrintHexWord OriginalBx ; DbgCrLf ; ; cause debug output to go to debug port: making invalid BOP will dump registers ; if DEBUG mov ax,OriginalAx mov bx,OriginalBx DbgUnsupported endif mov ax,ERROR_INVALID_FUNCTION stc ret DefaultServiceError endp page ; *** NetGetEnumInfo ; * ; * Routine which returns various internal redir variables based on an ; * index ; * ; * ENTRY BL = index ; * 0 = CDNames ; * 1 = Comment (not supported) ; * 2 = LanRoot ; * 3 = ComputerName ; * 4 = UserName ; * 5 = Primary Domain ; * 6 = Logon Server ; * 7 = Mailslots Yes/No ; * 8 = RIPL Yes/No ; * 9 = Get RIPL UNC ; * 10 = Get RIPL drive ; * 11 = Start marking CON_RIPL ; * 12 = Stop marking CON_RIPL ; * 13 = exchange int17 handlers ; * 14 = primary WrkNet ; * ; * es:di = buffer for returned info ; * ; * EXIT CF = 0 ; * success ; * CF = 1 ; * AX = ERROR_INVALID_FUNCTION ; * ; * USES ax, flags ; * ; * ASSUMES nothing ; * ; *** NetGetEnumInfo proc near or bl,bl jnz @f ; ; CDNames (Computer and Domain Names) ; ; DbgPrintString <"NetGetEnumInfo: return CDNames", 13, 10> SVC SVC_RDRGETCDNAMES ret ; ; Comment - nothing returned by this or the original redir (ax = invalid ; function, but carry clear?) ; @@: dec bl jnz @f DbgPrintString <"NetGetEnumInfo: return Comment", 13, 10> mov ax,ERROR_INVALID_FUNCTION ret ; ; LanRoot ; @@: dec bl jnz check_computername DbgPrintString <"NetGetEnumInfo: return LanRoot", 13, 10> pusha ; save user gp regs push es ; save user seg regs push ds mov si,ResidentData mov ds,si assume ds:ResidentData mov si,offset LanRoot mov cx,LanRootLength shr cx,1 ; cx = number of words to copy, cf=lsb cld rep movsw ; copy words jnc @f ; if not odd number of bytes skip movsb ; copy single byte @@: pop ds ; restore user seg regs pop es popa ; restore user gp regs ret ; ; ComputerName ; check_computername: dec bl jnz @f DbgPrintString <"NetGetEnumInfo: return ComputerName", 13, 10> SVC SVC_RDRGETCOMPUTERNAME ret ; ; Username ; @@: dec bl jnz @f DbgPrintString <"NetGetEnumInfo: return UserName", 13, 10> ; ; This is also the entry point for NetGetUserName, which return some info in ; cx:bx (the (ignored) UID). We could leave this random, but we set it to a ; known value, just in case ; NetGetUserNameSvcCall: SVC SVC_RDRGETUSERNAME ; either 0 if for NetGetEnumInfo or 1 if NetGetUserName ret ; ; Primary domain name ; @@: dec bl jnz @f DbgPrintString <"NetGetEnumInfo: return DomainName", 13, 10> SVC SVC_RDRGETDOMAINNAME ret ; ; Logon server name ; @@: dec bl jnz @f DbgPrintString <"NetGetEnumInfo: return LogonServerName", 13, 10> SVC SVC_RDRGETLOGONSERVER ret ; ; Mailslots YN ; ; Mailslots are always enabled with this redir, so return yes (TRUE, 1) ; @@: dec bl jnz @f DbgPrintString <"NetGetEnumInfo: Mailslot check", 13, 10> mov ax,1 ret ; ; RIPL YN ; ; This redir doesn't know anything about RPL, so return no (FALSE, 0) ; @@: dec bl jnz @f DbgPrintString <"NetGetEnumInfo: RIPL check", 13, 10> xor ax,ax ret ; ; RIPL UNC ; @@: dec bl jnz @f DbgPrintString <"NetGetEnumInfo: return RIPL UNC", 13, 10> jmps DefaultServiceError ; ; RIPL drive ; @@: dec bl jnz @f DbgPrintString <"NetGetEnumInfo: return RIPL drive", 13, 10> jmps DefaultServiceError ; ; Start marking CON_RIPL ; @@: dec bl jnz @f DbgPrintString <"NetGetEnumInfo: Start marking CON_RIPL", 13, 10> jmps DefaultServiceError ; ; Stop marking CON_RIPL ; @@: dec bl jnz @f DbgPrintString <"NetGetEnumInfo: Stop marking CON_RIPL", 13, 10> jmps DefaultServiceError ; ; exchange int 17 handlers ; ; We don't support this so return error ; @@: dec bl jnz @f DbgPrintString <"NetGetEnumInfo: exchange int 17 handlers", 13, 10> jmps DefaultServiceError ; ; primary WrkNet ; ; This is transport-specific so we don't return anything except error ; @@: dec bl jnz @f DbgPrintString <"NetGetEnumInfo: return primary WrkNet", 13, 10> jmps DefaultServiceError ; ; anything else - return an error ; @@: DbgPrintString "NetGetEnumInfo: unknown request: " DbgPrintHexWord bx DbgCrLf jmps DefaultServiceError NetGetEnumInfo endp page ; *** NetSpoolStuff ; * ; * Gets control from INT 2f/ax=1125h. This really has no use in NTVDM, ; * but we supply it because DOS has started making 1125 calls. Spooling ; * in NTVDM has nothing to do with the Redir TSR. Historically, printing ; * over the net was handled by the redir & this call was used (amongst ; * other things) to flush & close all spool files when an app terminated ; * ; * ENTRY AL = 7 Return truncate flag in DL (DH destroyed) ; * AL = 8 Set truncate flag from DL (must be 0 or 1) ; * AL = 9 Close all spool files ; * ; * EXIT CF = 1 ; * AX = ERROR_INVALID_FUNCTION ; * ; * USES ax, dx, si, ds, flags ; * ; * ASSUMES nothing ; * ; *** PrintTruncate db 0 NetSpoolStuff proc near sub al,9 ; most common case first jnz @f net_spool_stuff_good_exit: xor ax,ax ; nothing to do for CloseAllSpool! ret @@: inc al jnz @f ; must be get, or invalid mov ax,ERROR_INVALID_PARAMETER cmp dl,1 ; must be 0 or 1 ja net_spool_stuff_error_exit mov PrintTruncate,dl jmp short net_spool_stuff_good_exit @@: inc al mov ax,ERROR_INVALID_FUNCTION jnz net_spool_stuff_error_exit ; ; return PrintTruncate flag to caller (app) ; DosCallBack GET_USER_STACK mov dl,PrintTruncate xor dh,dh mov [si].User_Dx,dx ret net_spool_stuff_error_exit: stc ret NetSpoolStuff endp page if DEBUG even public Old21Handler Old21Handler dd ? public CheckInt21Function5e CheckInt21Function5e proc far assume cs:ResidentCode assume ds:nothing assume es:nothing assume ss:nothing ; cmp ah,5eh ; jnz @f ; DbgUnsupported @@: jmp Old21Handler ; let DOS handle it. DOS returns to caller CheckInt21Function5e endp endif ResidentCodeEnd end