'Ä Area: F-QUICKBASIC ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ' Msg#: 364 Date: 17 Apr 94 17:19:00 ' From: Saul Ansbacher Read: Yes Replied: No ' To: Larry Thacker Mark: ' Subj: PSP, EXE name and thi 1/3 'ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ 'Well here is a programme call PSP (that's the bit of memory you were 'talking about it's the Programme Segment Prefix) Compile this little 'programme and run it (give it a case SENSITIVE command line for fun) and 'then have a look at the display. There should be every thing you need 'here. Also there are some other nice things like case sensitive command 'lines, and the C$ function is a REALLY good idea check it out. ALso 'there are the dox, called psp.doc, I hope all this helps... as for you 'question there are lots of DIR$ routines out there, if you don't find 'one or someone else doesn't post on then let me know and I'll post one 'of the bunch I have... Oh, PSP.BAS needs QB.LIB or QBX.LIB... ' ' PSP.BAS by Brent Ashley, needs QB.LIB (QB4n) or QBX.LIB (PDS) ' DECLARE FUNCTION C$ (Fore%, Back%) DECLARE FUNCTION CurPspSegment% () DECLARE FUNCTION Hex2$ (Num%) DECLARE FUNCTION Hex4$ (Num%) DECLARE FUNCTION ProgramSpec$ (PSP AS ANY) DECLARE SUB LoadPSPVar (PSPSeg%, PSPVar AS ANY) DECLARE SUB MemCopy (FSeg%, FOfs%, FCnt%, TSeg%, TOfs%, TCnt%) DECLARE SUB ShowFCB (FCB AS ANY) DECLARE SUB ShowPSP (PSP AS ANY) 'Uncomment for compiled version and delete MemCopy SUB: 'DECLARE SUB MemCopy ALIAS "B$ASSN" (BYVAL FSeg%, BYVAL FOfs%, BYVAL FCnt%,_ ' BYVAL TSeg%, BYVAL TOfs%, BYVAL TCnt%) 'this is a routine internal to BCOM45.LIB - using it will 'result in a smaller program and speed up the memory copies DEFINT A-Z '$INCLUDE: 'qb.bi' ' user-defined types TYPE UnopenedFCBType DriveNum AS STRING * 1 FileName AS STRING * 8 Ext AS STRING * 3 CurBlk AS INTEGER RecSize AS INTEGER END TYPE TYPE PSPType Int20 AS STRING * 2 TopOfMemory AS INTEGER Junk1 AS STRING * 6 TermIP AS INTEGER TermCS AS INTEGER BreakIP AS INTEGER BreakCS AS INTEGER CritErrIP AS INTEGER CritErrCS AS INTEGER ParentPSPSeg AS INTEGER HandleTable AS STRING * 20 EnvSeg AS INTEGER Junk3 AS STRING * 4 HandleCnt AS INTEGER HdlTblOfs AS INTEGER HdlTblSeg AS INTEGER Junk4 AS STRING * 36 FCB1 AS UnopenedFCBType FCB2 AS UnopenedFCBType Junk5 AS STRING * 4 CmdLen AS STRING * 1 CmdLine AS STRING * 127 END TYPE ' declare variables: DIM SHARED Regs AS RegType, Fg, Bg, Hi DIM PSP AS PSPType, ParentPSP AS PSPType ' set up colors DEF SEG = 0 IF PEEK(&H449) = 7 THEN ' monochrome Fg = 7: Bg = 0: Hi = 15 ELSE ' colour Fg = 11: Bg = 1: Hi = 14 END IF ' Do that funky PSP thang! ' fill PSP variable with current PSP data LoadPSPVar CurPspSegment, PSP COLOR Fg, Bg: CLS PRINT C(Hi, Bg); "----------- Program Segment Prefix Breakdown -----------" PRINT C(Hi, Bg); "This Program: "; C(Fg, Bg); ProgramSpec(PSP); " "; PRINT C(Hi, Bg); "Current PSP at: "; C(Fg, Bg); Hex4$(CurPspSegment) ShowPSP PSP ' fill ParentPSP variable with data LoadPSPVar PSP.ParentPSPSeg, ParentPSP PRINT C(Hi, Bg); "Parent Program: "; C(Fg, Bg); ProgramSpec(ParentPSP) PRINT C(Hi, Bg); "Parent Command Line: "; C(Fg, Bg); CHR$(16); PRINT LEFT$(ParentPSP.CmdLine, ASC(ParentPSP.CmdLen)); CHR$(17) FUNCTION C$ (Fore, Back) 'You can change colors in the middle of a print 'statement with this little gem! (only if you 'use ; or , to separate the printed elements - 'don't concatenate strings with + in a print statement COLOR Fore, Back C$ = "" END FUNCTION FUNCTION CurPspSegment ' return current PSP segment address Regs.AX = &H6200 Interrupt &H21, Regs, Regs CurPspSegment = Regs.BX END FUNCTION FUNCTION Hex2$ (Num) Hex2$ = RIGHT$("0" + HEX$(Num), 2) END FUNCTION FUNCTION Hex4$ (Num) Hex4$ = RIGHT$("000" + HEX$(Num), 4) END FUNCTION SUB LoadPSPVar (PSPSeg, PSPVar AS PSPType) ' use memory block ciopy to fill PSP variable with data MemCopy PSPSeg, 0, 256, VARSEG(PSPVar), VARPTR(PSPVar), 256 END SUB SUB MemCopy (FSeg, FOfs, FCnt, TSeg, TOfs, TCnt) STATIC i, Temp$ ' copy a block of memory ' TCnt should be same as FCnt (it's there for B$ASSN compatibility) ' * use B$ASSN alias instead for compiled programs * ' go to source segment DEF SEG = FSeg ' peek temporary string Temp$ = SPACE$(FCnt) FOR i = 0 TO FCnt - 1 MID$(Temp$, i + 1, 1) = CHR$(PEEK(FOfs + i)) NEXT ' go to destination segment DEF SEG = TSeg ' poke temp string FOR i = 0 TO TCnt - 1 POKE TOfs + i, ASC(MID$(Temp$, i + 1, 1)) NEXT ' restore BASIC seg DEF SEG END SUB FUNCTION ProgramSpec$ (PSP AS PSPType) STATIC i, Temp$ ' Returns full pathspec for program whose PSP is passed ' look at environment block DEF SEG = PSP.EnvSeg i = 0 ' find first occurrence of 00 00 DO WHILE PEEK(i) OR PEEK(i + 1) i = i + 1 LOOP ' if user program, then 01 00 follows IF (PEEK(i + 2) = 1) AND (PEEK(i + 3) = 0) THEN ' jump past user program signature i = i + 4 Temp$ = "" ' build string until 00 byte DO WHILE PEEK(i) Temp$ = Temp$ + CHR$(PEEK(i)) i = i + 1 LOOP ProgramSpec$ = Temp$ ELSE ProgramSpec$ = "" END IF END FUNCTION SUB ShowFCB (FCB AS UnopenedFCBType) PRINT C(Hi, Bg); " Drive :"; C(Fg, Bg); ASC(FCB.DriveNum) PRINT C(Hi, Bg); " Name : "; C(Fg, Bg); FCB.FileName PRINT C(Hi, Bg); " Ext : "; C(Fg, Bg); FCB.Ext PRINT C(Hi, Bg); " CurBlk :"; C(Fg, Bg); FCB.CurBlk PRINT C(Hi, Bg); " RecSize:"; C(Fg, Bg); FCB.RecSize END SUB SUB ShowPSP (PSP AS PSPType) PRINT C(Hi, Bg); "Top of memory: "; PRINT C(Fg, Bg); Hex4$(PSP.TopOfMemory); " " PRINT C(Hi, Bg); "Term: "; PRINT C(Fg, Bg); Hex4$(PSP.TermCS); ":"; Hex4$(PSP.TermIP); " "; PRINT C(Hi, Bg); "Break: "; PRINT C(Fg, Bg); Hex4$(PSP.BreakCS); ":"; Hex4$(PSP.BreakIP); " "; PRINT C(Hi, Bg); "CritErr: "; PRINT C(Fg, Bg); Hex4$(PSP.CritErrCS); ":"; Hex4$(PSP.CritErrIP) PRINT C(Hi, Bg); "Parent PSP Seg: "; C(Fg, Bg); Hex4$(PSP.ParentPSPSeg); " " PRINT C(Hi, Bg); "Environment Seg: "; C(Fg, Bg); Hex4$(PSP.EnvSeg) PRINT C(Hi, Bg); "Handle Table: " PRINT C(Fg, Bg); " "; FOR i = 1 TO 20 PRINT Hex2$(ASC(MID$(PSP.HandleTable, i, 1))); " "; NEXT PRINT PRINT C(Hi, Bg); "Handle Count:"; C(Fg, Bg); HandleCnt; " "; PRINT C(Hi, Bg); "Handle Table Address: "; C(Fg, Bg); PRINT Hex4$(PSP.HdlTblSeg); ":"; C(Fg, Bg); Hex4$(PSP.HdlTblOfs) PRINT C(Hi, Bg); "FCB #1" ShowFCB PSP.FCB1 PRINT C(Hi, Bg); "FCB #2" ShowFCB PSP.FCB2 PRINT C(Hi, Bg); "Cmd Line Length:"; PRINT C(Fg, Bg); ASC(PSP.CmdLen); " "; PRINT C(Hi, Bg); "Command Line: "; C(Fg, Bg); PRINT CHR$(16); LEFT$(PSP.CmdLine, ASC(PSP.CmdLen)); PRINT CHR$(17) END SUB ' PSP.DOC ' ======== Exploring the PSP - by Brent Ashley ========= ' DOS maintains various data structures to help it to organize 'a running machine's memory. One of these structures is the 'Program Segment Prefix, which is a collection of information DOS 'builds for an executing program. The following discussion and the 'accompanying program will give you all you need to access and 'interpret the information stored in your program's PSP. ' The PSP is a 256-byte area which is reserved in memory 'immediately before your program is loaded and run by the command 'shell (usually COMMAND.COM). Its structure follows, along with 'typical uses of the information it contains. Offsets are in hex, 'byte counts in decimal, and remember that intel processors store 'numbers with lowest bytes first, ie 1234:5678 is stored as 78 56 '34 12. 'OFFSET 0 - 2 Bytes ' There will always be the bytes CD 20 here - this is an INT 20h ' call (terminate program). It's here so programs can jump to ' this location to terminate - not recommended, but it makes sense ' that programs which jump to an uninitialised (zero) address ' should be made to terminate in this way. 'OFFSET 2 - 2 Bytes ' This is the segment address of the last paragraph of memory ' allocated to the program. 'OFFSET 5 - 5 Bytes ' There is a far call to the DOS function dispatcher here. This ' is here only for CP/M compatibility and is never used. 'OFFSET A - 4 Bytes 'OFFSET E - 4 Bytes 'OFFSET 12 - 4 Bytes ' These are the Segment:Offset Addresses to which control is ' passed: ' - upon termination of the program. ' - when Control-Break is pressed. ' - when a critical error is encountered. 'OFFSET 16 - 2 Bytes ' The segment address of this program's parent program's PSP is ' stored here. 'OFFSET 18 - 20 Bytes ' A table of 20 file handles is stored here. Any program needing ' more than the default 20 file handles will need to use INT 21h ' function 67h to set the handle count to a number more than 20 ' (but no more than FILES= in CONFIG.SYS). This will cause DOS ' to allocate a new file handle table of the size requested. See ' Offsets 2E, 30 also. 'OFFSET 2C - 2 Bytes ' DOS provides each executable program with its own copy of the ' active Environment Strings at program load time. This is the ' segment address of this program's copy. The environment strings ' block contains a list of strings, each terminated by a 00 byte, ' with a further 00 byte at the end of the list. At the end of the ' environment strings, there is a 2-byte User Program signature ' which, when set to 1 (01 00), signifies the program's full path ' specification can be found in the following bytes, teminated ' with a null (00) byte. 'OFFSET 2E - 2 Bytes ' This is the number of file handles in the current handle table. 'OFFSET 30 - 4 Bytes ' Segment:Offset address of the file handle table, either the one ' here in the PSP, or the one allocated with INT 21h svc 67h. 'OFFSET 5C - 16 Bytes 'OFFSET 6C - 16 Bytes ' There are two unopened File Control Blocks constructed here as ' part of the program load process, based on the command line ' entered when the current progam was invoked. It's interesting ' to note that DOS has already parsed the drive, filename and ' extension and placed it here, but only if there is no path ' information included, since FCBs are a throwback from when DOS ' didn't have a heirarchical directory structure. 'OFFSET 80 - 1 Byte 'OFFSET 81 - 127 Bytes ' The length of the command line entered after the program name ' when the program was invoked is stored here, followed by the ' command line itself. The default Disk Transfer Area for this ' program is also here, so unless your program sets its own ' (which most do), the command line information could be ' overwritten. You might want to get the command line information ' from here because QB uppercases it and trims it before passing ' it to you via COMMAND$. ' The accompanying program, PSP.BAS, shows how you can access and 'interpret the PSP. Remember that when using it in the QB 'development environment, the PSP it will be looking at is that of 'the environment. A good test for the program will be to invoke it 'as follows: 'PSP A:FILENAME.EXT B:OUTFILE.TST