home *** CD-ROM | disk | FTP | other *** search
- '─ 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$ = "<Command Shell>"
- 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
-
-