Category : C Source Code
Archive   : DPMIXM.ZIP
Filename : ENDSPOOL.C
Output of file : ENDSPOOL.C contained in archive : DPMIXM.ZIP
* *
* WENDSPOOL - Execute Banyan Vines EndSpool API call *
* *
* This program is provided to illustrate how to examine the real mode *
* interrupt table, grab a vector and examine the real mode memory area *
* pointed to by the vector. In addition, it illustrates the use of the *
* GlobalDosAlloc call and the DPMI interface to talk to the BANYAN API. *
* *
* The Banyan API requires that you pass the address of a command block *
* in DS:DX. This program maintains this as a local structure, then copies *
* the structure to a memory area that the real mode Vines API can access. *
* *
******************************************************************************
* *
* Written on 03/09/91 By Mike Flynn - Compuserve ID 76376,2273 *
* *
* Special Thanks to Peter Gofton for the DPMI and GlobalDosAlloc stuff and *
* to Steve Goulet for the selector manipulation help. *
* *
******************************************************************************
* *
* EXCUSE: Please excuse the primitive nature of this program as it is my *
* very first C program, and my first Windows program! The ASM code *
* for copying the data should be cleaned up..... *
* *
******************************************************************************
* *
* NOTE: This code does not support real-mode. However, it would be easy *
* to add if desired. *
* *
*****************************************************************************/
#include
#include
#define VSP_SUCCESS 1
#define VSP_NONETWORK 2
#define VSP_NOPRINTJOBS 3
#define VSP_DPMIERROR 4
#define VSP_ERROR 5
#define ABSADDR(seg, ofs) ((((unsigned long) seg) << 4) + (ofs & 0xffff))
struct VINESPARMBLOCK
{
unsigned nCommand;
unsigned nActive;
unsigned long nParm1;
};
BYTE GetVinesVector(void);
unsigned char VinesEndSpool(struct VINESPARMBLOCK *);
VOID FAR PASCAL SetSelectorBase(WORD, DWORD );
VOID FAR PASCAL SetSelectorLimit(WORD, DWORD);
DWORD FAR PASCAL GlobalDosAlloc( DWORD );
int CallDPMI (BYTE nVector);
typedef struct tagSIMRINT
{
DWORD EDI;
DWORD ESI;
DWORD EBP;
DWORD Reserved;
DWORD EBX;
DWORD EDX;
DWORD ECX;
DWORD EAX;
WORD Flags;
WORD ES;
WORD DS;
WORD FS;
WORD GS;
WORD IP;
WORD CS;
WORD SP;
WORD SS;
} SIMRINT ;
SIMRINT sRealModeIntRegs = {0L,0L,0L,0L,0L,0L,0L,0L,0,0,0,0,0,0,0,0,0};
unsigned int dos_buf_seg,wSharedSelector;
static DWORD dwParmBlock;
BOOL protected_mode = FALSE;
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
struct VINESPARMBLOCK sParmBlock={0x201,0,0L};
unsigned nSpoolResult;
char szStatusBuf[36],szAppName[]="Banyan EndSpool";
if (hPrevInstance) // Other instances of app running?
{
MessageBox (NULL, "A copy of EndSpool is already running!",
szAppName, MB_OK | MB_SYSTEMMODAL);
return FALSE;
}
dwParmBlock = GlobalDosAlloc(sizeof(sParmBlock)); //Allocate shared mem
if (dwParmBlock == NULL) // If no mem, report it and xit
{
MessageBox (NULL, "Unable to allocate memory for VINES command.",
szAppName, MB_OK | MB_ICONSTOP);
return FALSE;
}
dos_buf_seg = HIWORD(dwParmBlock); // Get real mode segment
wSharedSelector = LOWORD(dwParmBlock); // Get prot mode selector
if (GetWinFlags() & WF_PMODE)
protected_mode = TRUE;
nSpoolResult = VinesEndSpool(&sParmBlock); // do the VINES call
switch (nSpoolResult)
{
case VSP_SUCCESS:
wsprintf (szStatusBuf,"Print job has been spooled to LPT%d:",sParmBlock);
MessageBox (NULL, szStatusBuf,szAppName, MB_OK );
break;
case VSP_NONETWORK:
MessageBox (NULL, "No VINES software Loaded",
szAppName, MB_OK | MB_ICONSTOP);
break;
case VSP_NOPRINTJOBS:
MessageBox (NULL, "No jobs to EndSpool",
szAppName, MB_OK | MB_ICONSTOP);
break;
case VSP_ERROR:
MessageBox (NULL, "Vines Network ERROR!",
szAppName, MB_OK | MB_ICONSTOP);
break;
case VSP_DPMIERROR:
MessageBox (NULL, "DPMI real mode error",
szAppName, MB_OK | MB_ICONSTOP);
break;
}
return FALSE;
}
unsigned char VinesEndSpool(struct VINESPARMBLOCK *parmblock)
{
BYTE nVinesVector;
unsigned nCount;
if (! (nVinesVector=GetVinesVector())) //Then go find it
return VSP_NONETWORK; //Couldn't find it
parmblock->nCommand = 0x0205; // Get spooled printer
// This peice of ASM stuff copies my VINES API data block
// into the shared memory as returned from GlobalDosAlloc
_asm
{
push es ;save ES
mov es,wSharedSelector ;get shared selector
mov di,0 ;offset is zip
mov si,parmblock ;point to my data structure
mov cx,4 ;4 words to copy (this should be calced)
cld ;dir is forward
rep movsw ;copy the data
pop es ;restore ES
}
if (!CallDPMI(nVinesVector)) // do the VINES API call
return VSP_DPMIERROR;
// This peice of ASM stuff copies the shared memory block back
// into the local data area.
_asm
{
push ds ;save ES
push es ;save ES
push ds ;save ES
pop es
mov di,parmblock ;point to my data structure
mov ds,wSharedSelector ;point to shared data area as source
mov si,0
mov cx,4 ;4 words to copy (this should be calced)
cld ;dir is forward
rep movsw ;copy the data
pop es ;restore ES
pop ds ;restore ES
}
if (!parmblock->nActive)
return VSP_NOPRINTJOBS;
parmblock->nCommand = 0x0201; // Endspool Command
// This peice of ASM stuff copies my VINES API data block
// into the shared memory as returned from GlobalDosAlloc
_asm
{
push es ;save ES
mov es,wSharedSelector ;get shared selector
mov di,0 ;offset is zip
mov si,parmblock ;point to my data structure
mov cx,4 ;4 words to copy (this should be calced)
cld ;dir is forward
rep movsw ;copy the data
pop es ;restore ES
}
if (!CallDPMI(nVinesVector)) // do the VINES API call
return VSP_DPMIERROR;
if (sRealModeIntRegs.EAX) // If VINES API returned non 0 then error
return VSP_ERROR;
return VSP_SUCCESS; // Return success!!!
}
BYTE GetVinesVector()
{
WORD wLocalDataSelector,wRealAddrSelector,wCurrentSegment,wCurrentOffset;
WORD nBase = (0x60*4); // Start with int 60H
unsigned char status = FALSE;
_asm
{
mov ax,ds
mov wRealAddrSelector,ax ;use my ds as prototype
}
/*
Allocate a new selector using the current DS as a template
(for granularity, privlidge et. al.). Set it's limit to 64K.
*/
wLocalDataSelector = AllocSelector(wRealAddrSelector);
SetSelectorLimit(wLocalDataSelector, 0xffff);
while (!status && nBase < (0x68 * 4))
{
SetSelectorBase(wLocalDataSelector, ABSADDR(0x0000,0)); //Set to seg 0
_asm
{
push es ;save ES
push di ;and DI
mov es,wLocalDataSelector ;get selector for INT vector table seg
mov di,nBase ;get offset
mov ax, word ptr es:[di] ;get int offset
mov wCurrentOffset,ax ;and save it
mov ax, word ptr es:[di+2] ;get int seg
mov wCurrentSegment,ax ;save it also
pop di ;restore regs
pop es
}
// point my selector to segment that INT vector pointed to
SetSelectorBase(wLocalDataSelector, ABSADDR(wCurrentSegment,0));
_asm
{
push es ;save ES
push di ;save DS
mov es,wLocalDataSelector ;get selector
mov di,wCurrentOffset ;and offset that INT pointed to
cmp word ptr es:[di-4],0x4142 ;look for VINES signature
jne gbnext ;not found then try next vector
cmp word ptr es:[di-2],0x564e ;look for VINES signature
jne gbnext ;not found then try next vector
mov al,TRUE ;Else, found it, indicate success
mov status,al
gbnext:
pop di ;restore regs
pop es
}
if (!status)
nBase += 4; // point to next vector if status = FALSE
}
FreeSelector(wLocalDataSelector); // Free up the selector
return (status ? nBase/4 : FALSE); //return result or FALSE
}
int CallDPMI (BYTE nVector)
{
char far *d = (char far *) &sRealModeIntRegs;
unsigned p_seg = FP_SEG(d);
unsigned p_off = FP_OFF(d);
sRealModeIntRegs.SS = 0 ; // Let DPMI deal with stack
sRealModeIntRegs.SP = 0 ;
sRealModeIntRegs.DS = dos_buf_seg; //Point DS to my memory seg
sRealModeIntRegs.EDX = 0L; //Segment Offset is 0
sRealModeIntRegs.EAX = 5L; //VINES API requires a 5 in AX
_asm
{
mov bh, 00h
mov bl, nVector ; Interrupt to call (Vines API)
xor cx, cx ; Nothing to copy to stack
mov es, p_seg ; Make es:di point to sRealModeIntRegs structure
mov di, p_off
mov ax, 0300h ; DPMI simulate real mode interrupt
int 31h ; DPMI interrupt
jnc EndDP ; DPMI sets carry flag if error
}
return FALSE;
EndDP: /* DPMI worked ok */
return TRUE;
}
/*
Here is the excerpt from the DPMI spec that describes the previous function:
11.1 Simulate Real Mode Interrupt
This function simulates an interrupt in real mode. It
will invoke the CS:IP specified by the real mode
interrupt vector and the handler must return by
executing an iret.
To Call
AX = 0300h
BL = Interrupt number
BH = Flags
Bit 0 = 1 resets the interrupt controller and A20
line
Other flags reserved and must be 0
CX = Number of words to copy from protected mode to
real mode stack
ES:(E)DI = Selector:Offset of real mode call structure
Returns
If function was successful:
Carry flag is clear.
ES:(E)DI = Selector:Offset of modified real mode call
structure
If function was not successful:
Carry flag is set.
Programmer's Notes
o The CS:IP in the real mode call structure is
ignored by this service. The appropriate
interrupt handler will be called based on the
value passed in BL.
o If the SS:SP fields are zero then a real mode
stack will be provided by the DPMI host.
Otherwise, the real mode SS:SP will be set to the
specified values before the interrupt handler is
called.
o The flags specified in the real mode call
structure will be pushed on the real mode stack
iret frame. The interrupt handler will be called
with the interrupt and trace flags clear.
o When the Int 31h returns, the real mode call
register structure will contain the values that
were returned by the real mode interrupt handler.
o It is up to the caller to remove any parameters
that were pushed on the protected mode stack.
o 32-bit programs must use ES:EDI to point to the
real mode call structure. 16-bit programs should
use ES:DI.
o The flag to reset the interrupt controller and A20
line is ignored by DPMI implementations that run
in Virtual 8086 mode. It causes DPMI
implementations that return to real mode to set
the interrupt controller and A20 address line
hardware to its normal real mode state.
*/
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
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/