[comp.sys.ibm.pc] HELP! Using DOS print

jillj@brspyr1.BRS.Com (Jill Jacomine) (11/29/89)

I  am  trying to execute the DOS (version 3.1) print command from within
an executable (compliled using MSC 5.1).  The command I am using is:

	spawnvp(P_WAIT,"print.com",args);

The  value  of  args  is  "print /D:prn filename".  Now, this works well
enough to print the file out, the problem seems to be setting the device
within the program eats up about 200k of memory, and never lets  it  go.
(I  tried  setting the device before executing the program, and it seems
to work fine, therefore I am relativly sure  the  problem  is  with  the
/D:prn  option).  A chkdsk before running the program shows 655360 bytes
total memory and 594256 bytes free, after execution it is  426720  bytes
total memory and 356616 bytes free.

I  have  tried  using  the  SYSTEM  function, as well as different SPAWN
functions, but they all yield the same results.  Has  anyone  else  come
across  this  problem,  or  can  anyone offer information as to why this
happens and how it can be corrected.

Thanks in advance.

Jill Jacomine
------------------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////////
------------------------------------------------------------------------------
Jill Jacomine (jill@brspyr1.BRS.COM)
UUCP:
BRS Information Technologies
Latham, NY

gs940971@longs.LANCE.ColoState.Edu (glen sunada f84) (11/29/89)

In article <6534@brspyr1.BRS.Com>, jillj@brspyr1.BRS.Com (Jill Jacomine)
writes:
> I  am  trying to execute the DOS (version 3.1) print command from within
> an executable (compliled using MSC 5.1).  The command I am using is:
> 
> 	spawnvp(P_WAIT,"print.com",args);
             [deleted stuff]
> within the program eats up about 200k of memory, and never lets  it  go.
> (I  tried  setting the device before executing the program, and it seems
> to work fine, therefore I am relativly sure  the  problem  is  with  the
> /D:prn  option).  A chkdsk before running the program shows 655360 bytes
                   [deleted stuff]
> I  have  tried  using  the  SYSTEM  function, as well as different SPAWN
> functions, but they all yield the same results.  Has  anyone  else  come
> across  this  problem,  or  can  anyone offer information as to why this
> happens and how it can be corrected.

The problem is that the DOS print command is not just a file printer but
also a siak based print sppooler and scheduler (sp?).  To correctly
spool and schedule jobs print needs to make part of its code resident. 
Print uses some mechanism to detect if it is already resident to prevent
multiple copies of the resident code.  I do not know how this is done
but one way may be to check trough the interrupt linkages and see if
print is there (I think i saw somewhere that print preempts one of the
user interrupts for communication to the resedent code but I can no
prove this).  The best solution is to write your own printout routine in
your program.  If the progam is to be used in house only then just make
sure that the print command has always been installed before running
your program.

Glen U. Sunada
gs940971@longs.LANCE.ColoState.EDU   ARPA Internet (preferred)
...!ncar!boulder!ccncsu!longs.LANCE.ColoState.EDU!gs940971 UUCP

We have only ignorence to fear

swh@hpcupt1.HP.COM (Steve Harrold) (11/30/89)

Re: Using PRINT from within a program

I haven't tried your particular program setup, but I suspect you may be
overlooking the fact that, although PRINT is not a TSR in the usual sense,
it does grab memory for its buffers and some code, and never ever again
lets go of it.  This is necessary because PRINT operates in the background
while you do additional work.  When control comes back from PRINT, it has
not yet completed its operation.  Since the memory is not freed, you end
up with fragmented memory; DOS does not handle this well, satisfying all
of subsequent memory requests from only one free memory hole.

The only thing you can do to get around this is to start PRINT once BEFORE
to run your program.  In this way, the PRINT memory is assigned at the top
of memory (or is it at the bottom? At any rate, memory fragmentation is
avoided). 

A good place to do this is in your AUTOEXEC.BAT file.

Hope this helps.

gs940971@longs.LANCE.ColoState.Edu (glen sunada f84) (11/30/89)

In my article I expressed ignorence to the mechanism used to communicate
with print
I recieved a mail message from Raymond Chen at Berkley that set me on
the correct path
to locateing that method.  I then looked up the specifics in the Waite Group's
_MS-DOS Developers Guide_ Second editions.

What follows is my reply to him:

>>Print uses some mechanism to detect if it is already resident to prevent
>>multiple copies of the resident code.  I do not know how this is done
>
>It installs itself into the DOS multiplex interrupt (Int 21, ah = 2f,
>I think).  This is a quasi-standard way of checking for multiple
>installations, once you get an official multiplex ID number.

I found my DOS reference and print does install itself on the DOS
Multiplex interrupts.
That is interruipt 2f.  The calling parameters for interrupt 2f are as follows.

    AH = program code (supplied DOS codes as folows)
          01 - print
          02 - assign
          10 - share
          b7 - append
   
    AL = requested function code
          00 - get installed state (all)
          01 - submit file to print
               DS:DX = pointer to submit packet
                       0 + DWORD pointer to ASCIIZ filespec
          02 - cancel file in print queue
               DS:DX = pointer to fully qualified (no wild card) ASCIIZ
filespec
                       to cancel
          03 - Cancel all files in print queue
          04 - pause print and return status
               (I don't know the return codes here)
          05 - end of print status
               (I don't know these reutrns either)

    Gaurenteed return codes
    if CF = 1 AX = error code
    if AL = 0FF a program with your identifier is installed
    if AL =   0 no program with your identifer installed ok to install
    if AL =   1 no program with your identifer installed not ok to install

Glen Sunada
gs940971@longs.LANCE.ColoState.EDU    ARPA Internet (preferred)
...ncar!boulder!ccncsu!longs.LANCE.ColoState.EDU!gs940971 UUCP

Money is the root of all evil.  Men need roots. - Lazerus Long

cramer@optilink.UUCP (Clayton Cramer) (11/30/89)

In article <6534@brspyr1.BRS.Com>, jillj@brspyr1.BRS.Com (Jill Jacomine) writes:
> I  am  trying to execute the DOS (version 3.1) print command from within
> an executable (compliled using MSC 5.1).  The command I am using is:
> 
> 	spawnvp(P_WAIT,"print.com",args);
> 
> The  value  of  args  is  "print /D:prn filename".  Now, this works well
> enough to print the file out, the problem seems to be setting the device
> within the program eats up about 200k of memory, and never lets  it  go.
> (I  tried  setting the device before executing the program, and it seems
> to work fine, therefore I am relativly sure  the  problem  is  with  the
> /D:prn  option).  A chkdsk before running the program shows 655360 bytes
> total memory and 594256 bytes free, after execution it is  426720  bytes
> total memory and 356616 bytes free.
> 
> I  have  tried  using  the  SYSTEM  function, as well as different SPAWN
> functions, but they all yield the same results.  Has  anyone  else  come
> across  this  problem,  or  can  anyone offer information as to why this
> happens and how it can be corrected.
> 
> Jill Jacomine

Yes, it gobbles up memory doing it this way, but I've never seen it
grab so much memory, and keep it gobbled.  I solved the problem by
writing some C to call the BIOS routines.  (Thanks to the several
people on the net who helped me find a bug).

Here's some code that you may find useful, and doesn't require 
bringing up another copy of DOS, or burning any unnecessary RAM 
to do print spooling.

/*============================================================================
OMSPOOL.C: Print Spooling functions.
	This module contains print spooling functions for use by OMAPS.

Glossary:
	abbr		- abbreviation
============================================================================*/

#include <dos.h>
#include <stdlib.h>
#include <process.h>
#define TRUE 1
#define FALSE 0
typedef int bool;
typedef struct tSub
        {
        char    ByteLevel;
        char*   FileName;
        } tSub;
/*===Entries================================================================*/
int			SpoolFile(char*);		/* add a file to the print queue */
bool		SpoolInstall(void);		/* install the print spooler */
bool		SpoolInstalled(void);	/* is the print spooler installed? */
int			SpoolRemoveFile(char*);	/* remove a spooled file from queue */
int			SpoolTerminate(void);	/* terminate the spool queue */
int			TestDiagT1Admin(void);	/* testing & diagnostics T1 */

/*===Functions=============================================================*/
/*==========================================================================*/


/*----------------------------------------------------------------------------
SpoolFile: Add a file to the print queue.

	Adds a file to the print spool queue.

RETURN:
	int				print spool error code (0 = no error)

GLOBALS:
	none
----------------------------------------------------------------------------*/

int SpoolFile(FileName)

char*           FileName;		/* IN: ptr to filename to add to queue */

    {
    union REGS      InRegs;
    union REGS      OutRegs;
    struct SREGS    SegRegs;
    int             ErrCode;
	tSub			SubmitFile;
	tSub*			pSubmitFile;
	
	pSubmitFile = &SubmitFile;
    InRegs.x.ax = 0x101;
    SubmitFile.ByteLevel = 0;
    SubmitFile.FileName = FileName;
    InRegs.x.dx = FP_OFF(pSubmitFile);
    SegRegs.ds = FP_SEG(pSubmitFile);
    int86x(0x2f, &InRegs, &OutRegs, &SegRegs);
    if(OutRegs.x.cflag)
        ErrCode = OutRegs.x.ax;
    else
        ErrCode = 0;
    return(ErrCode);
    }

/*----------------------------------------------------------------------------
SpoolInstall: Install the print spooler.

	Installs the print spooler.

RETURN:
	bool			TRUE: successfully installed
					FALSE: failed to install

GLOBALS:
	none
----------------------------------------------------------------------------*/

bool SpoolInstall()

    {
    return(0 == system("PRINT"));
    }

/*----------------------------------------------------------------------------
SpoolInstalled: Is the print spooler installed?

	Checks to see if the print spooler is already installed.

RETURN:
	bool				TRUE: already installed
						FALSE: not yet

GLOBALS:
	none
----------------------------------------------------------------------------*/

bool SpoolInstalled()

    {
    union REGS          InRegs;
    union REGS          OutRegs;
    struct SREGS        SegRegs;
    int                 ErrCode;
    
    InRegs.x.ax = 0x100;
    int86x(0x2f, &InRegs, &OutRegs, &SegRegs);
    return(OutRegs.h.al == 0xff);
    }

/*----------------------------------------------------------------------------
SpoolRemoveFile: Remove a file from the print queue.

	Removes the specified file from the print spooler queue.

RETURN:
	int					print spooler error code

GLOBALS:
	none
----------------------------------------------------------------------------*/

int SpoolRemoveFile(FileName)

char*           FileName;		/* IN: ptr to filename to remove from queue */

    {
    union REGS          InRegs;
    union REGS          OutRegs;
    struct SREGS        SegRegs;
    int                 ErrCode;

    InRegs.x.ax = 0x102;
    InRegs.x.dx = FP_OFF(FileName);
    SegRegs.ds = FP_SEG(FileName);
    int86x(0x2f, &InRegs, &OutRegs, &SegRegs);
    if(OutRegs.x.cflag)
        ErrCode = OutRegs.x.ax;
    else
        ErrCode = 0;
    return(ErrCode);
    }

/*----------------------------------------------------------------------------
SpoolTerminate: Clear the queue.

	Removes all current jobs from the print spooler queue.

RETURN:
	int					print spooler error code (0 = no error)

GLOBALS:
	none
----------------------------------------------------------------------------*/

int SpoolTerminate()

    {
    union REGS          InRegs;
    union REGS          OutRegs;
    struct SREGS        SegRegs;
    int                 ErrCode;
    
    InRegs.x.ax = 0x103;
    int86x(0x2f, &InRegs, &OutRegs, &SegRegs);
    if(OutRegs.x.cflag)
        ErrCode = OutRegs.x.ax;
    else
        ErrCode = 0;
    return(ErrCode);
    }
-- 
Clayton E. Cramer {pyramid,pixar,tekbspa}!optilink!cramer
My definition of social justice: those who refuse to work deserve to go hungry.
===============================================================================
Disclaimer?  You must be kidding!  No company would hold opinions like mine!

pipkins@qmsseq.imagen.com (Jeff Pipkins) (12/01/89)

In article <6534@brspyr1.BRS.Com> jillj@brspyr1.BRS.Com (Jill Jacomine) writes:
>I  am  trying to execute the DOS (version 3.1) print command from within
>an executable (compliled using MSC 5.1).  The command I am using is:
>
>	spawnvp(P_WAIT,"print.com",args);
>
>The  value  of  args  is  "print /D:prn filename".  Now, this works well
>enough to print the file out, the problem seems to be setting the device
>within the program eats up about 200k of memory, and never lets  it  go.
>(I  tried  setting the device before executing the program, and it seems
>to work fine, therefore I am relativly sure  the  problem  is  with  the
>/D:prn  option).  A chkdsk before running the program shows 655360 bytes
>total memory and 594256 bytes free, after execution it is  426720  bytes
>total memory and 356616 bytes free.

PRINT is a "TSR" program.  The first time you run it, it installs
itself into your precious memory.  If your program loads it, realize
that chances are very high that it will be loaded RIGHT AFTER your
program in memory.  After your program terminates, PRINT STAYS THERE --
and you have irrecoverable memory fragmentation.  DOS usually loads
new programs in the first hole that it will fit in, so a program
may use that hole, but if it tries to use the DOS SETBLOCK function
to increase its size, it will most likely fail.

This problem occurs any time a nonresident program loads a resident
program.  I have only thought of two possible work-arounds, and I
don't like either of them:

1) Reserve enough memory below your program so that you can load
the TSR there.

2) Modify DOSs memory control blocks to allocate just the right
size block high in memory; then use the overlay option of DOSs
EXEC function to load the program into that memory.

I would be very interested in hearing other possible solutions
from anyone else!

/*=======================================================================*\
   Jeff Pipkins: pipkins@imagen.com  My views are not necessarily shared
   by my employer or the IRS.  That explains a lot about my paycheck.

   "Why is it that unpitted dates have pits and pitted dates do not?"
\*=======================================================================*/

miller@b-mrda.boeing.com (Mark Miller) (12/02/89)

Jill:
	From the print options you specified, it doesn't sound like you're
looking for the PRINT command to do anything more than dump a file to
the printer. The only advantage to using PRINT is that PRINT uses a spooler
to do the trick. The disadvantage is that PRINT does load a memory-resident
segment that doesn't go away. I have two suggestions:

	1. If you don't need a spooler and you're not in a hurry, simply
open the file for reading and send it to stdprn (defaults to lpt1:) via
fprintf.

	2. If you're in a hurry, write a small custom spooler hanging
off the INT8 (timer tick) interrupt for your application. 

Either of these returns full control of the memory to you.

Good luck. Let me know how it works out.

				Mark Miller
				miller@b-mrda.boeing.com

john@wsl.UUCP (John Allen on wsl) (12/05/89)

Minor correction -- PRINT.COM is a TSR, in fact it is the original TSR.
Print should never be loaded from within an application unless it has been
previously loaded from either the command line or a BATCH file. Your suggestion
to load it from autoexec is absolutely correct.

-- 
People that don't know want to know from the people that do know and if the 
poeple that do know don't tell the people that don't know then the people
that don't know still won't know.
				   "Don't quote me on any issue whatsoever."