Category : Alternate Operating Systems - Quarterdeck DesqView, CP/M, etc
Archive   : PCCAPP.ZIP
Filename : VPCA.H

 
Output of file : VPCA.H contained in archive : PCCAPP.ZIP
#ifndef VirtualPCArgs_h
#define VirtualPCArgs_h

#include "VirtualPCRegisters.h"
#include "String.h"

// Names of 16-bit registers that can be written and read.
enum I86Register {rAX, rBX, rCX, rDX, rDS, rES, rBP, rSI, rDI, rFlags};
struct VirtualPCBuffer
{
/* A VirtualPCBuffer is a registerpair-buffer association. It keeps track
* of the register-pairs that are supposed to point to buffers.
*/
I86Register segment; // Register to store the segment address.
I86Register offset; // Register to store the offset address.
char *buffer; // 32-bit address of the buffer.
int bufferSize; // Size of the buffer.
enum {Regular, Const, Uninit} bufferType; // How the buffer should be
// copied: Regular: copy before and after call, Const: copy before call,
// Uninit: copy after call.
};

class VirtualPCArgs
{
/* A VirtualPCArgs object is used to declare the arguments for a VirtualPC
* vector call (eg. DOS and BIOS functions). This object stores the values
* of registers to be used when making the call, and contains the resulting
* values of registers after making the call. The set() and get() method
* may be used to set and retrieve the values of registers. There are cases
* where the registers cannot be assigned values directly - for example,
* when a DOS function expects a register pair to point at a buffer located in
* a 16-bit address space. The setBuffer methods are provided for setting
* register pairs so that they point to buffers located in the 32-bit
* address space used by PC-Choices. You select the most appropriate
* setBuffer method so that copying of buffers is minimized done when making
* the VirtualPC call. A VirtualPCArgs object also optionally declares the
* DTA argument for certain DOS calls that require a DTA.
*
* More details on setBuffer methods: suppose a DOS function requires DS:DX
* to point to a buffer in 16-bit address space, and you want DS:DX to
* point to your buffer (call it buf) which resides in 32-bit address space.
* Then you should set up your VirtualPCArgs like this:
* char buf [100];
* VirtualPCArgs args;
* args.setBuffer (rDS, rDX, buf, 100);
* (...set other registers, like AX...)
* virtualPC -> executeVector (DOSVector, &args);
* (...read registers like Flags to determine success of call...)
* where 100 is the size of your buffer. setBuffer() will add a registerpair-
* buffer association to args. When executeVector() is called, the VirtualPC
* will handle all registerpair-buffer associations by allocating new buffers
* in 16-bit space and then setting the indicated register-pairs to the
* addresses of the new buffers. Your buffer in 32-bit space will be copied
* to the new buffer in 16-bit space before the DOS function call starts,
* so that DOS can make use of the information in your buffer. After the
* DOS call exits, the buffer in 16-bit space will be copied back to your
* buffer in 32-bit space, so that all changes to the buffer made by DOS
* will be visible to you.
*
* In many cases, this double copying is unnecessary, and you may choose to
* have your buffers copied only once by calling setConstBuffer() or
* setUninitBuffer() instead of setBuffer(). If you are not interested in
* looking at the contents of the 16-bit buffer after the call, use
* setConstBuffer(). If the buffer you're passing does not initially contain
* any data that will be used by the VirtualPC call, then you should use
* setUninitBuffer(). For example, when you want DOS to write a buffer
* to a file, you should use setConstBuffer() because the final contents
* of the buffer is not needed. And when you want DOS to read a buffer
* from the file, you should use setUninitBuffer() because DOS will not
* use any information from the uninitialized buffer.
*
* When you call setDTA to set the DTA buffer, the VirtualPC will similarly
* allocate a DTA buffer in 16-bit space, copy it, make the DOS call, and
* copy it back. In addition, the VirtualPC will inform DOS about the
* location of the DTA before making the requested DOS call.
*/
public:
/* Method VirtualPCArgs:
* Initialize the arguments - set all registerpair-buffer associations
* to null and set DTA to null.
*/
VirtualPCArgs ();

/* Method set:
* Set register reg to the specified 16-bit value. Should not be used
* for setting registers to point at buffers - use setBuffer instead.
* See definition of I86Register above for valid register names.
*/
void set (I86Register reg, unsigned short value);

/* Method setBuffer:
* Set register-pair to a 32-bit buffer address. The register-pair is
* specified in "segment" and "offset". buffer is a 32-bit address.
* buffer[0] through buffer[bufferSize-1] are assumed to contain
* data to be passed to the call and passed back. Since there are
* only 4 register-pairs, all the set*Buffer methods should not be
* called more than 4 times altogether on a particular VirtualPCArgs
* without calling reset().
*/
void setBuffer (I86Register segment, I86Register offset, char *buffer,
int bufferSize);

/* Method setConstBuffer:
* Set register-pair to a 32-bit buffer address. The register-pair is
* specified in "segment" and "offset". buffer is a 32-bit address.
* buffer[0] through buffer[bufferSize-1] are assumed to contain
* data to be passed to the call. The buffer will not be passed back.
* If bufferSize is absent, buffer is assumed to contain a null-
* terminated string and the string will be passed to the call.
*/
void setConstBuffer (I86Register segment, I86Register offset, const char
*buffer, int bufferSize = -1);

/* Method setUninitBuffer:
* Set register-pair to a 32-bit buffer address. The register-pair is
* specified in "segment" and "offset". buffer is a 32-bit address.
* Upon return from a VirtualPC call, buffer[0] through
* buffer[bufferSize-1] will be written with data returned from the call.
* The buffer will not be passed before the call.
*/
void setUninitBuffer (I86Register segment, I86Register offset, char
*buffer, int bufferSize);

/* Method setDTA:
* Set the DTA address to be used for a VirtualPC call. dta is a
* 32-bit DTA buffer address and dtaSize is the size of the DTA buffer.
* The DTA will be passed to the call and will also be passed back.
* (DTA = disk transfer area, used by old DOS functions and for the
* new directory-scanning DOS functions.)
*/
void setDTA (char *dta, int dtaSize);

/* Method get:
* Return the value of 16-bit register "reg". See definition of
* I86Register above for valid register names.
*/
unsigned short get (I86Register reg);

/* Method reset:
* Erase all registerpair-buffer associations and set the DTA address
* to null.
*/
void reset ();
private:
friend class VirtualPCInterface;
VirtualPCRegisters regs; // Registers passed and returned from call.
int nextBuffer; // Index into bufferList for first unused association.
VirtualPCBuffer bufferList [4]; // Registerpair-buffer associations.
char *dta; // 32-bit address of DTA.
int dtaSize; // Size of DTA.
};

inline VirtualPCArgs :: VirtualPCArgs () { nextBuffer = 0; dta = 0; }
inline void VirtualPCArgs :: reset () { nextBuffer = 0; dta = 0; }

inline void VirtualPCArgs :: set (I86Register reg, unsigned short value)
{
switch (reg)
{
case rAX: regs.ax = value; break;
case rBX: regs.bx = value; break;
case rCX: regs.cx = value; break;
case rDX: regs.dx = value; break;
case rDS: regs.ds = value; break;
case rES: regs.es = value; break;
case rBP: regs.bp = value; break;
case rSI: regs.si = value; break;
case rDI: regs.di = value; break;
case rFlags: regs.flags = value; break;
}
}

inline unsigned short VirtualPCArgs :: get (I86Register reg)
{
switch (reg)
{
case rAX: return regs.ax;
case rBX: return regs.bx;
case rCX: return regs.cx;
case rDX: return regs.dx;
case rDS: return regs.ds;
case rES: return regs.es;
case rBP: return regs.bp;
case rSI: return regs.si;
case rDI: return regs.di;
case rFlags: return regs.flags;
}
}

inline void VirtualPCArgs :: setBuffer (I86Register segment, I86Register
offset, char *buffer, int bufferSize)
{
if (bufferSize < 0) bufferSize = strlen (buffer) + 1;
if (nextBuffer > 3) return; // Not possible - too many registers used.
bufferList [nextBuffer].segment = segment;
bufferList [nextBuffer].offset = offset;
bufferList [nextBuffer].buffer = buffer;
bufferList [nextBuffer].bufferSize = bufferSize;
bufferList [nextBuffer].bufferType = VirtualPCBuffer::Regular;
nextBuffer++;
}

inline void VirtualPCArgs :: setConstBuffer (I86Register segment, I86Register
offset, const char *buffer, int bufferSize)
{
if (bufferSize < 0) bufferSize = strlen (buffer) + 1;
if (nextBuffer > 3) return; // Not possible - too many registers used.
bufferList [nextBuffer].segment = segment;
bufferList [nextBuffer].offset = offset;
bufferList [nextBuffer].buffer = (char *) buffer;
bufferList [nextBuffer].bufferSize = bufferSize;
bufferList [nextBuffer].bufferType = VirtualPCBuffer::Const;
nextBuffer++;
}

inline void VirtualPCArgs :: setUninitBuffer (I86Register segment, I86Register
offset, char *buffer, int bufferSize)
{
if (bufferSize < 0) bufferSize = strlen (buffer) + 1;
if (nextBuffer > 3) return; // Not possible - too many registers used.
bufferList [nextBuffer].segment = segment;
bufferList [nextBuffer].offset = offset;
bufferList [nextBuffer].buffer = buffer;
bufferList [nextBuffer].bufferSize = bufferSize;
bufferList [nextBuffer].bufferType = VirtualPCBuffer::Uninit;
nextBuffer++;
}

inline void VirtualPCArgs :: setDTA (char *dta2, int dtaSize2)
{
dta = dta2;
dtaSize = dtaSize2;
}

#endif


  3 Responses to “Category : Alternate Operating Systems - Quarterdeck DesqView, CP/M, etc
Archive   : PCCAPP.ZIP
Filename : VPCA.H

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/