Subject Re: Printing only A4
From Akshat Kapoor <akshat.kapoor@kapoorsons.in>
Date Mon, 26 Apr 2021 20:16:53 +0530
Newsgroups dbase.getting-started
Attachment(s) getBINinfo.ccgetbininfo.prgpaperbin.prgpapersize.prg

Good Evening Cornelius,

> Hi there, I have clients with new printers and refusing to print if paper is set to anything but A4.
> You can change if with every print but i was hoping for all my printing to always go out as A4 for that printer

The printer object of the report has a papersize property. Set it to A4.

BUT the paper size property can vary from 1 computer to another.
Try the attached files.

Updated versions could be there on the newsgroup.


IF these fails (just 0.01% chances) then will provide code that I use to
set the paper size and printer once and then use it in every report.

Regards
Akshat



version = "$VERSION 1.04 {06/14/2011 02:43:04 PM} VERSION$"
clear

// 06/14/2011 - REM - Added abilities to return the default bin info.

// 05/24/2007 - REM - Added abilities to return paper source info.
// 03/02/2006 - REM - Generally just cleaned it up.
// 03/09/2006 - REM = Increased buffer size, lpszOutput. I'd rather have too
//big a buffer than too small.
                // I noticed a buffer too small error in Funcky where he most likely use
//the standardize
      // buffer size when calling a HP printer. Our problem seems to be also
//isolated to a HP printer.

// http://msdn2.microsoft.com/en-us/library/ms535506.aspx


/* device capabilities indices */
#define DC_FIELDS             1
#define DC_PAPERS             2
#define DC_PAPERSIZE          3
#define DC_MINEXTENT          4
#define DC_MAXEXTENT          5
#define DC_BINS               6
#define DC_DUPLEX             7
#define DC_SIZE               8
#define DC_EXTRA              9
#define DC_VERSION           10
#define DC_DRIVER            11
#define DC_BINNAMES          12
#define DC_ENUMRESOLUTIONS   13
#define DC_FILEDEPENDENCIES  14
#define DC_TRUETYPE          15
#define DC_PAPERNAMES        16
#define DC_ORIENTATION       17
#define DC_COPIES            18

/* bin selections */
#define DMBIN_FIRST         DMBIN_UPPER
#define DMBIN_UPPER         1
#define DMBIN_ONLYONE       1
#define DMBIN_LOWER         2
#define DMBIN_MIDDLE        3
#define DMBIN_MANUAL        4
#define DMBIN_ENVELOPE      5
#define DMBIN_ENVMANUAL     6
#define DMBIN_AUTO          7
#define DMBIN_TRACTOR       8
#define DMBIN_SMALLFMT      9
#define DMBIN_LARGEFMT      10
#define DMBIN_LARGECAPACITY 11
#define DMBIN_CASSETTE      14
#define DMBIN_FORMSOURCE    15
#define DMBIN_LAST          DMBIN_FORMSOURCE
#define DMBIN_USER          256     /* device specific bins start at 256 */

/* paper selections */
#define DMPAPER_FIRST                DMPAPER_LETTER
#define DMPAPER_LETTER               1  /* Letter 8 1/2 x 11 in
*/
#define DMPAPER_LETTERSMALL          2  /* Letter Small 8 1/2 x 11 in
*/
#define DMPAPER_TABLOID              3  /* Tabloid 11 x 17 in
*/
#define DMPAPER_LEDGER               4  /* Ledger 17 x 11 in
*/
#define DMPAPER_LEGAL                5  /* Legal 8 1/2 x 14 in
*/
#define DMPAPER_STATEMENT            6  /* Statement 5 1/2 x 8 1/2 in
*/
#define DMPAPER_EXECUTIVE            7  /* Executive 7 1/4 x 10 1/2 in
*/
#define DMPAPER_A3                   8  /* A3 297 x 420 mm
*/
#define DMPAPER_A4                   9  /* A4 210 x 297 mm
*/
#define DMPAPER_A4SMALL             10  /* A4 Small 210 x 297 mm
*/
#define DMPAPER_A5                  11  /* A5 148 x 210 mm
*/
#define DMPAPER_B4                  12  /* B4 (JIS) 250 x 354
*/
#define DMPAPER_B5                  13  /* B5 (JIS) 182 x 257 mm
*/
#define DMPAPER_FOLIO               14  /* Folio 8 1/2 x 13 in
*/
#define DMPAPER_QUARTO              15  /* Quarto 215 x 275 mm
*/
#define DMPAPER_10X14               16  /* 10x14 in
*/
#define DMPAPER_11X17               17  /* 11x17 in
*/
#define DMPAPER_NOTE                18  /* Note 8 1/2 x 11 in
*/
#define DMPAPER_ENV_9               19  /* Envelope #9 3 7/8 x 8 7/8
*/
#define DMPAPER_ENV_10              20  /* Envelope #10 4 1/8 x 9 1/2
*/
#define DMPAPER_ENV_11              21  /* Envelope #11 4 1/2 x 10 3/8
*/
#define DMPAPER_ENV_12              22  /* Envelope #12 4 \276 x 11
*/
#define DMPAPER_ENV_14              23  /* Envelope #14 5 x 11 1/2
*/
#define DMPAPER_CSHEET              24  /* C size sheet
*/
#define DMPAPER_DSHEET              25  /* D size sheet
*/
#define DMPAPER_ESHEET              26  /* E size sheet
*/
#define DMPAPER_ENV_DL              27  /* Envelope DL 110 x 220mm
*/
#define DMPAPER_ENV_C5              28  /* Envelope C5 162 x 229 mm
*/
#define DMPAPER_ENV_C3              29  /* Envelope C3  324 x 458 mm
*/
#define DMPAPER_ENV_C4              30  /* Envelope C4  229 x 324 mm
*/
#define DMPAPER_ENV_C6              31  /* Envelope C6  114 x 162 mm
*/
#define DMPAPER_ENV_C65             32  /* Envelope C65 114 x 229 mm
*/
#define DMPAPER_ENV_B4              33  /* Envelope B4  250 x 353 mm
*/
#define DMPAPER_ENV_B5              34  /* Envelope B5  176 x 250 mm
*/
#define DMPAPER_ENV_B6              35  /* Envelope B6  176 x 125 mm
*/
#define DMPAPER_ENV_ITALY           36  /* Envelope 110 x 230 mm
*/
#define DMPAPER_ENV_MONARCH         37  /* Envelope Monarch 3.875 x 7.5 in
*/
#define DMPAPER_ENV_PERSONAL        38  /* 6 3/4 Envelope 3 5/8 x 6 1/2 in
*/
#define DMPAPER_FANFOLD_US          39  /* US Std Fanfold 14 7/8 x 11 in
*/
#define DMPAPER_FANFOLD_STD_GERMAN  40  /* German Std Fanfold 8 1/2 x 12 in
*/
#define DMPAPER_FANFOLD_LGL_GERMAN  41  /* German Legal Fanfold 8 1/2 x 13
in */
//#if(WINVER >= 0x0400)
#define DMPAPER_ISO_B4              42  /* B4 (ISO) 250 x 353 mm
*/
#define DMPAPER_JAPANESE_POSTCARD   43  /* Japanese Postcard 100 x 148 mm
*/
#define DMPAPER_9X11                44  /* 9 x 11 in
*/
#define DMPAPER_10X11               45  /* 10 x 11 in
*/
#define DMPAPER_15X11               46  /* 15 x 11 in
*/
#define DMPAPER_ENV_INVITE          47  /* Envelope Invite 220 x 220 mm
*/
#define DMPAPER_RESERVED_48         48  /* RESERVED--DO NOT USE
*/
#define DMPAPER_RESERVED_49         49  /* RESERVED--DO NOT USE
*/
#define DMPAPER_LETTER_EXTRA        50  /* Letter Extra 9 \275 x 12 in
*/
#define DMPAPER_LEGAL_EXTRA         51  /* Legal Extra 9 \275 x 15 in
*/
#define DMPAPER_TABLOID_EXTRA       52  /* Tabloid Extra 11.69 x 18 in
*/
#define DMPAPER_A4_EXTRA            53  /* A4 Extra 9.27 x 12.69 in
*/
#define DMPAPER_LETTER_TRANSVERSE   54  /* Letter Transverse 8 \275 x 11 in
*/
#define DMPAPER_A4_TRANSVERSE       55  /* A4 Transverse 210 x 297 mm
*/
#define DMPAPER_LETTER_EXTRA_TRANSVERSE 56 /* Letter Extra Transverse 9\275
x 12 in */
#define DMPAPER_A_PLUS              57  /* SuperA/SuperA/A4 227 x 356 mm
*/
#define DMPAPER_B_PLUS              58  /* SuperB/SuperB/A3 305 x 487 mm
*/
#define DMPAPER_LETTER_PLUS         59  /* Letter Plus 8.5 x 12.69 in
*/
#define DMPAPER_A4_PLUS             60  /* A4 Plus 210 x 330 mm
*/
#define DMPAPER_A5_TRANSVERSE       61  /* A5 Transverse 148 x 210 mm
*/
#define DMPAPER_B5_TRANSVERSE       62  /* B5 (JIS) Transverse 182 x 257 mm
*/
#define DMPAPER_A3_EXTRA            63  /* A3 Extra 322 x 445 mm
*/
#define DMPAPER_A5_EXTRA            64  /* A5 Extra 174 x 235 mm
*/
#define DMPAPER_B5_EXTRA            65  /* B5 (ISO) Extra 201 x 276 mm
*/
#define DMPAPER_A2                  66  /* A2 420 x 594 mm
*/
#define DMPAPER_A3_TRANSVERSE       67  /* A3 Transverse 297 x 420 mm
*/
#define DMPAPER_A3_EXTRA_TRANSVERSE 68  /* A3 Extra Transverse 322 x 445 mm
*/
//#endif /* WINVER >= 0x0400 */

//#if(WINVER >= 0x0500)
#define DMPAPER_DBL_JAPANESE_POSTCARD 69 /* Japanese Double Postcard 200 x
148 mm */
#define DMPAPER_A6                  70  /* A6 105 x 148 mm
*/
#define DMPAPER_JENV_KAKU2          71  /* Japanese Envelope Kaku #2
*/
#define DMPAPER_JENV_KAKU3          72  /* Japanese Envelope Kaku #3
*/
#define DMPAPER_JENV_CHOU3          73  /* Japanese Envelope Chou #3
*/
#define DMPAPER_JENV_CHOU4          74  /* Japanese Envelope Chou #4
*/
#define DMPAPER_LETTER_ROTATED      75  /* Letter Rotated 11 x 8 1/2 11 in
*/
#define DMPAPER_A3_ROTATED          76  /* A3 Rotated 420 x 297 mm
*/
#define DMPAPER_A4_ROTATED          77  /* A4 Rotated 297 x 210 mm
*/
#define DMPAPER_A5_ROTATED          78  /* A5 Rotated 210 x 148 mm
*/
#define DMPAPER_B4_JIS_ROTATED      79  /* B4 (JIS) Rotated 364 x 257 mm
*/
#define DMPAPER_B5_JIS_ROTATED      80  /* B5 (JIS) Rotated 257 x 182 mm
*/
#define DMPAPER_JAPANESE_POSTCARD_ROTATED 81 /* Japanese Postcard Rotated
148 x 100 mm */
#define DMPAPER_DBL_JAPANESE_POSTCARD_ROTATED 82 /* Double Japanese Postcard
Rotated 148 x 200 mm */
#define DMPAPER_A6_ROTATED          83  /* A6 Rotated 148 x 105 mm
*/
#define DMPAPER_JENV_KAKU2_ROTATED  84  /* Japanese Envelope Kaku #2 Rotated
*/
#define DMPAPER_JENV_KAKU3_ROTATED  85  /* Japanese Envelope Kaku #3 Rotated
*/
#define DMPAPER_JENV_CHOU3_ROTATED  86  /* Japanese Envelope Chou #3 Rotated
*/
#define DMPAPER_JENV_CHOU4_ROTATED  87  /* Japanese Envelope Chou #4 Rotated
*/
#define DMPAPER_B6_JIS              88  /* B6 (JIS) 128 x 182 mm
*/
#define DMPAPER_B6_JIS_ROTATED      89  /* B6 (JIS) Rotated 182 x 128 mm
*/
#define DMPAPER_12X11               90  /* 12 x 11 in
*/
#define DMPAPER_JENV_YOU4           91  /* Japanese Envelope You #4
*/
#define DMPAPER_JENV_YOU4_ROTATED   92  /* Japanese Envelope You #4
Rotated*/
#define DMPAPER_P16K                93  /* PRC 16K 146 x 215 mm
*/
#define DMPAPER_P32K                94  /* PRC 32K 97 x 151 mm
*/
#define DMPAPER_P32KBIG             95  /* PRC 32K(Big) 97 x 151 mm
*/
#define DMPAPER_PENV_1              96  /* PRC Envelope #1 102 x 165 mm
*/
#define DMPAPER_PENV_2              97  /* PRC Envelope #2 102 x 176 mm
*/
#define DMPAPER_PENV_3              98  /* PRC Envelope #3 125 x 176 mm
*/
#define DMPAPER_PENV_4              99  /* PRC Envelope #4 110 x 208 mm
*/
#define DMPAPER_PENV_5              100 /* PRC Envelope #5 110 x 220 mm
*/
#define DMPAPER_PENV_6              101 /* PRC Envelope #6 120 x 230 mm
*/
#define DMPAPER_PENV_7              102 /* PRC Envelope #7 160 x 230 mm
*/
#define DMPAPER_PENV_8              103 /* PRC Envelope #8 120 x 309 mm
*/
#define DMPAPER_PENV_9              104 /* PRC Envelope #9 229 x 324 mm
*/
#define DMPAPER_PENV_10             105 /* PRC Envelope #10 324 x 458 mm
*/
#define DMPAPER_P16K_ROTATED        106 /* PRC 16K Rotated
*/
#define DMPAPER_P32K_ROTATED        107 /* PRC 32K Rotated
*/
#define DMPAPER_P32KBIG_ROTATED     108 /* PRC 32K(Big) Rotated
*/
#define DMPAPER_PENV_1_ROTATED      109 /* PRC Envelope #1 Rotated 165 x 102
mm */
#define DMPAPER_PENV_2_ROTATED      110 /* PRC Envelope #2 Rotated 176 x 102
mm */
#define DMPAPER_PENV_3_ROTATED      111 /* PRC Envelope #3 Rotated 176 x 125
mm */
#define DMPAPER_PENV_4_ROTATED      112 /* PRC Envelope #4 Rotated 208 x 110
mm */
#define DMPAPER_PENV_5_ROTATED      113 /* PRC Envelope #5 Rotated 220 x 110
mm */
#define DMPAPER_PENV_6_ROTATED      114 /* PRC Envelope #6 Rotated 230 x 120
mm */
#define DMPAPER_PENV_7_ROTATED      115 /* PRC Envelope #7 Rotated 230 x 160
mm */
#define DMPAPER_PENV_8_ROTATED      116 /* PRC Envelope #8 Rotated 309 x 120
mm */
#define DMPAPER_PENV_9_ROTATED      117 /* PRC Envelope #9 Rotated 324 x 229
mm */
#define DMPAPER_PENV_10_ROTATED     118 /* PRC Envelope #10 Rotated 458 x
324 mm */
//#endif /* WINVER >= 0x0500 */

//#if (WINVER >= 0x0500)
#define DMPAPER_LAST                DMPAPER_PENV_10_ROTATED
//#elif (WINVER >= 0x0400)
//#define DMPAPER_LAST                DMPAPER_A3_EXTRA_TRANSVERSE
//#else
//#define DMPAPER_LAST                DMPAPER_FANFOLD_LGL_GERMAN
//#endif

#define DMPAPER_USER                256
#define Chr_Zeros(nZ)  replicate(chr(0), nZ)

/*  Rich - www.autotraker.com
        Returns paper tray and paper source information for a printer.

   Parameters:
   cDevice = "Printer name"
   cPort = "Printer Port"

   2 parallel arrays are returned. aBinNames is the actual bin names used for display and
   aBins are the bin codes used for setting the printer to the proper paper tray.
   Also
   2 parallel arrays are returned. aSourceNames is the actual source names used for display and
   aSources are the Source codes used for setting the printer to the proper paper source.

        Examples:
   Printer cDevice is as it appears in printer configureation and you can use
   either the path to the printer or the port as cPort. Local printers normally
   use "LPT1:" or NT machines may use virtual ports such as "Ne00:" but you can also
   use actual path such as "\\TOWER66\HP895se" as returned by WSH or WMI functions.
   (See sample WSH and WMI code at end of this document)

//   x = new getBinInfo("Auto HP DeskJet 895Cse on TOWER66", "Ne00:")

   x = new getBinInfo("Auto HP DeskJet 895Cse on TOWER66","\\TOWER66\HP895se")
   for i = 1 to x.aBinNames.size
      ? x.aBinNames[i]
      ?? " " + x.aBins[i]
   endfor

   for i = 1 to x.aSourceNames.size
      ? x.aSourceNames[i]
      ?? " " + x.aSources[i]
   endfor


*/




class getBinInfo(cDevice, cPort)

//        #include <WINDEF.H>
//   extern CINT REM_DeviceCapabilities(LPCSTR, LPCSTR, WORD, ;
                   LPSTR, LPSTRUCTURE) winspool.drv ;
                   from "DeviceCapabilitiesA"

   if not type("REM_DeviceCapabilities") == "FP"
      extern cint REM_DeviceCapabilities( ;
      cstring, cstring, cword, cptr, cptr);
      winspool.drv from 'DeviceCapabilitiesA'
   endif

   this.nDefaultBin  = 7 // Auto
   this.cDefaultBin  = ""

   this.nMax                         = 64 // max buffer size
   this.cDevice                 = cDevice
   this.cPort                         = cPort
   this.aBinNames         = class::getBinNames()
   this.aBins                         = class::getBinCodes()
   this.aSourceNames = class::getSourceNames()
   this.aSources                 = class::getSourceCodes()

   function getSourceNames
      Local lpdm,lpszOutput,nSourceMax,nSize,aSourceNames,nSource

      // init the API to recover the number of sources to setup lpszOutput buffer
      lpdm = NULL
      lpszOutput = NULL
      nSourceMax = REM_DeviceCapabilities(this.cDevice,this.cPort,DC_PAPERNAMES,lpszOutput,lpdm)
      if nSourceMax == -1
         return new array()
      endif

      nSize = 64/2 // each source name, 64 bytes wide, but returned as single byte string

      // create the buffers
      lpdm = 0
      lpszOutput = Chr_Zeros(nSourceMax * this.nMax) // * nSize

                // get the source names loading them into the buffer
      nSourceMax = REM_DeviceCapabilities(this.cDevice,this.cPort,DC_PAPERNAMES,lpszOutput,lpdm)
      if nSourceMax == -1
         return new array()
      endif

      aSourceNames = new array(nSourceMax)
      for nSource = 1 to nSourceMax
         // convert single wide buffer string to double wide and put into array
              aSourceNames[nSource] = class::A_SBCSZToDBCS(substr(lpszOutput,(nSource*nSize) - (nSize-1), nSize))
              //? aSourceNames[nSource]
      endfor
      release lpszOutput
      return aSourceNames


   function getBinNames
      Local lpdm,lpszOutput,nBinMax,nSize,aBinNames,nSource

      // init the API to recover the number of bins to setup lpszOutput buffer
      lpdm = NULL
      lpszOutput = NULL
      nBinMax = REM_DeviceCapabilities(this.cDevice,this.cPort,DC_BINNAMES,lpszOutput,lpdm)
      if nBinMax == -1
         return new array()
      endif

      nSize = 24/2 // each bin name, 24 bytes wide, but returned as single byte string

      // create the buffers
     lpdm = 0
     lpszOutput = Chr_Zeros(nBinMax * this.nMax) // * nSize

                // get the bin names loading them into the buffer
      nBinMax = REM_DeviceCapabilities(this.cDevice,this.cPort,DC_BINNAMES,lpszOutput,lpdm)
      if nBinMax == -1
         return new array()
      endif

      aBinNames = new array(nBinMax)
      for nSource = 1 to nBinMax
         // convert single wide buffer string to double wide and put into array
              aBinNames[nSource] = class::A_SBCSZToDBCS(substr(lpszOutput, (nSource*nSize) - (nSize-1), nSize))
              //? aBinNames[nSource]

                        if "auto" $ aBinNames[nSource]
                 this.nDefaultBin  = nSource
                 this.cDefaultBin  = aBinNames[nSource]
         endif

      endfor
      release lpszOutput
      return aBinNames

   function getSourceCodes
      Local lpdm,lpszOutput,nMaxSources,aSources,nSource

      // init the API to recover the number of sources to setup lpszOutput buffer
      lpdm = NULL
      lpszOutput = NULL
      nMaxSources = REM_DeviceCapabilities(this.cDevice,this.cPort,DC_PAPERS,lpszOutput,lpdm)
      if nMaxSources == -1
              return new array()
      endif

      // create the buffers
      lpdm = 0
      lpszOutput = Chr_Zeros(nMaxSources * this.nMax)

      // load bin codes into buffer
      nMaxSources = REM_DeviceCapabilities(this.cDevice,this.cPort,DC_PAPERS,lpszOutput,lpdm)
      if nMaxSources == -1
         return new array()
      endif

      aSources = new array(nMaxSources)
      for nSource = 1 to nMaxSources
         // read buffer converting each 16bit 'C' number into a numeric and store in array
              aSources[nSource] = class::A_Chr2Num16(substr(lpszOutput,(nSource*1), 1), 0)
              //? aSources[nSource]
      endfor
      release lpszOutput
      return aSources

   function getBinCodes
      Local lpdm,lpszOutput,nMaxBins,aBins,nSource

      // init the API to recover the number of bins to setup lpszOutput buffer
      lpdm = NULL
      lpszOutput = NULL
      nMaxBins = REM_DeviceCapabilities(this.cDevice,this.cPort,DC_BINS,lpszOutput,lpdm)
      if nMaxBins == -1
              return new array()
      endif

      // create the buffers
      lpdm = 0
      lpszOutput = Chr_Zeros(nMaxBins * this.nMax)

      // load bin codes into buffers
      nMaxBins = REM_DeviceCapabilities(this.cDevice,this.cPort,DC_BINS,lpszOutput,lpdm)
      if nMaxBins == -1
         return new array()
      endif

      aBins = new array(nMaxBins)
      for nSource = 1 to nMaxBins
         // read buffer converting each 16bit 'C' number into a numeric and store in array
              aBins[nSource] = class::A_Chr2Num16(substr(lpszOutput, (nSource*1),1), 0)
              //? aBins[i]
      endfor
      release lpszOutput
      return aBins

   function A_Chr2Num16(cBuff, nIndex)
      // Converts 16bit 'C' to number
      local b1, b2, w16
      b1 = cBuff.GetByte(nIndex)
      b2 = cBuff.GetByte(nIndex+1)
      w16 = b1+;
          b2*256
      return w16

   function A_SBCSZToDBCS(cStr)
           // convert single byte string into double byte
      // 16bit 'C' string to double
      local cTemp, nChar, nLen, cChar
      nLen = (len(cStr)*2)-1
      cTemp = ''
      for nChar = 0 to nLen
         cChar = chr(cStr.getByte(nChar))
         if cChar == chr(0)
            // replace the 'C' null string terminator with a space
            // since terminators may exist within the string
                                cChar = " "
         endif
         cTemp += cChar
      endfor
      return cTemp.rightTrim() // trim spaces at end of string

endclass


/* Sample WSH and WMI code

      objLocator = new OleAutoClient("WbemScripting.SWbemLocator")
      objWMI=objLocator.ConnectServer(".", "root\cimv2")
      objWMI.Security_.ImpersonationLevel=3 // Impersonate
      oItems = objWMI.ExecQuery("Select * from Win32_Printer")
                for i = 1 to oItems.count()
              ? oItems[i-1].name
              ? oItems[i-1].portName
              ? oItems[i-1].default
                endfor
      release object objWMI
      release object objLocator


      x = new OleAutoClient("WScript.Network")
      // Get list of printers
      oPrinters = x.EnumPrinterConnections()
      // assign printers to array
      for i = 0 to oPrinters.count() -1 step 2
          ? oPrinters.Item(i+1) // name
          ? oPrinters.Item(i) // port
                endfor

*/



clear
set procedure to getBINinfo.cc
r = new report()
r.printer.chooseprinter()
cPrinter = r.printer.printername
x = new getBINinfo(cPrinter,'0')
?cPrinter
?
?'Paper bins'
for i = 1 to x.aBinNames.size
      ? x.aBins[i]
      ?? '    '+ x.aBinNames[i]
   endfor
?
?'Paper sizes'
for i = 1 to x.aSourceNames.size
   ? x.aSources[i]
   ?? "     " + x.aSourceNames[i]
endfor

/*
   PaperBin.prg
  
   This a direct copy of PapeSize.prg posted by Rick Miller with the necessary
   changes so as to be able to identify the available paper sources.
  
   2020-08-09   Mervyn Bick
  
   This program will return the binName and PapeBin information
   for the default printer. The number returned for each option
   could then be used for a report. This is really not a production
   program, but meant to be used by a developer to help as needed.
   Output is to the output pane of the Command Window.
  
   Usage:
      do :dUFLP:PapeBin
      
      or to use a printer other than the default, you would need
      to know the name of the printer:
      
      cPrinter = "HP LaserJet 1020"
      do :dUFLP:PapeBin with cPrinter
      
      Includes:
         getBins()
         getPrinterDefault()
*/

   #define  DC_PAPERNAMES     16
   #define  DC_PAPERS         2
   #define  DC_BINNAMES       12
   #define  DC_BINS           6
   #define  ZEROS(n)          replicate(chr(0), n)
   parameters cDevice

   initExterns()
   if not type("argVector(1)") == "C"
       cDevice  := getPrinterDefault()
//       ? cDevice  // moved out of if...endif  MB 2020-08-10
   endif
    ? cDevice
   local a, i
   a  =  getBins( cDevice, "")
   for i = 1 to int((a.size + 1) / 2)
       ?     a[i, 2]
       ??    " - "
       ??    a[i, 1]
   endfor

return

//------------------------------------------------------------//
// return a 2 column array of paper bins for a printerName.
// column 1 = binName <char>,
// column 2 = PapeBin <int>.
function getBins(cDevice, cPort)
    local    aRet, cName, i, ii, lpDevMode, nPair, nWord,;
             sPaperName, sPapeBin
    lpDevMode   =  0
    // get the number of PapeBin/paperName pairs.
    nPair =  RMM_DeviceCapability(;
             cDevice,;
             cPort,;
             DC_BINS,;
             null,;
             lpDevMode)
    if nPair > 0
       // create empty PapeBin buffer of proper length.
       sPapeBin  =  ZEROS(nPair * 2)
       // fill the PapeBin buffer.
       RMM_DeviceCapability(;
                cDevice,;
                cPort,;
                DC_BINS,;
                sPapeBin,;
                lpDevMode)
       // create empty paperName buffer of proper length.
       sPaperName  =  ZEROS(nPair * 24)
       // fill the paperName buffer.
       RMM_DeviceCapability(;
                cDevice,;
                cPort,;
                DC_BINNAMES,;
                sPaperName,;
                lpDevMode)
       // create the return array.
       aRet  =  new array(nPair, 2)
       for i = 0 to nPair - 1
          // loop through and assign the array values.
          // store the PapeBin number into nX.
          nWord =  getWord(sPapeBin, i * 2)
          cName =  ""
          for ii = 0 to 23 //63
             // loop through reading the paperName buffer.
             if sPaperName.getByte((i * 24) + ii) == 0
                // ran into a string terminator.
                // assign ii to exit the loop.
                ii := 24
             else
                // add the character to c.
                cName += chr(sPaperName.getByte( ;
                         (i * 24) + ii))
             endif
          endfor
          // assign the pair to a row in the array.
          aRet[i + 1, 1] =  cName    // paperName.
          aRet[i + 1, 2] =  nWord    // PapeBin.
       endfor
    else
       aRet  =  new array()
    endif
return   aRet

//------------------------------------------------------------//
// return the windows default printer as a string.
function getPrinterDefault
    Local sBuff, cRet, nLen
    sBuff =  ZEROS(250)
    nLen  =  RMM_GetWinIniString( ;
             "windows", "device", ;
             ",,,", sBuff, sBuff.length)
    cRet  =  sBuff.left(sBuff.indexOf(","))
return   cRet.rightTrim()

//------------------------------------------------------------//
// return a WORD from the string sValu starting at nByte.
function getWord(sValu, nByte)
return   int(sValu.getByte(nByte) + ;
          bitlshift(sValu.getByte(nByte + 1), 8))

//------------------------------------------------------------//
function initExterns
    if not type("RMM_DeviceCapability") == "FP"
       extern CINT RMM_DeviceCapability( ;
                CSTRING, CSTRING, CWORD, CPTR, CPTR);
                winspool.drv from 'DeviceCapabilitiesA'
    endif
    if not type("RMM_GetWinIniString") == "FP"
       extern CULONG RMM_GetWinIniString( ;
                CSTRING, CSTRING, CSTRING, CSTRING, CULONG);
                kernel32 from "GetProfileStringA"
    endif
return

// end of file: PapeBin.prg


/*
   PaperSize.prg
   Posted by Rick Miller (and more recently by Lyndon Sidelinger)
   in the dBASE newsgroups, originally written by Jim Sare.
  
   October 11, 2017
  
   This program will return the paperName and paperSize information
   for the default printer. The number returned for each option
   could then be used for a report. This is really not a production
   program, but meant to be used by a developer to help as needed.
   Output is to the output pane of the Command Window.
  
   Usage:
      do :dUFLP:PaperSize
      
      or to use a printer other than the default, you would need
      to know the name of the printer:
      
      cPrinter = "HP LaserJet 1020"
      do :dUFLP:PaperSize with cPrinter
      
      Includes:
         getPapers()
         getPrinterDefault()
*/

   #define  DC_PAPERNAMES     16
   #define  DC_PAPERS         2
   #define  ZEROS(n)          replicate(chr(0), n)
   parameters cDevice

   initExterns()
   if not type("argVector(1)") == "C"
       cDevice  := getPrinterDefault()
       ? cDevice
   endif
   local a, i
   a  =  getPapers( cDevice, "")
   for i = 1 to int((a.size + 1) / 2)
       ?     a[i, 2]
       ??    " - "
       ??    a[i, 1]
   endfor

return

//------------------------------------------------------------//
// return a 2 column array of paper sizes for a printerName.
// column 1 = paperName <char>,
// column 2 = paperSize <int>.
function getPapers(cDevice, cPort)
    local    aRet, cName, i, ii, lpDevMode, nPair, nWord,;
             sPaperName, sPaperSize
    lpDevMode   =  0
    // get the number of paperSize/paperName pairs.
    nPair =  RMM_DeviceCapability(;
             cDevice,;
             cPort,;
             DC_PAPERS,;
             null,;
             lpDevMode)
    if nPair > 0
       // create empty paperSize buffer of proper length.
       sPaperSize  =  ZEROS(nPair * 2)
       // fill the paperSize buffer.
       RMM_DeviceCapability(;
                cDevice,;
                cPort,;
                DC_PAPERS,;
                sPaperSize,;
                lpDevMode)
       // create empty paperName buffer of proper length.
       sPaperName  =  ZEROS(nPair * 64)
       // fill the paperName buffer.
       RMM_DeviceCapability(;
                cDevice,;
                cPort,;
                DC_PAPERNAMES,;
                sPaperName,;
                lpDevMode)
       // create the return array.
       aRet  =  new array(nPair, 2)
       for i = 0 to nPair - 1
          // loop through and assign the array values.
          // store the paperSize number into nX.
          nWord =  getWord(sPaperSize, i * 2)
          cName =  ""
          for ii = 0 to 63
             // loop through reading the paperName buffer.
             if sPaperName.getByte((i * 64) + ii) == 0
                // ran into a string terminator.
                // assign ii to exit the loop.
                ii := 64
             else
                // add the character to c.
                cName += chr(sPaperName.getByte( ;
                         (i * 64) + ii))
             endif
          endfor
          // assign the pair to a row in the array.
          aRet[i + 1, 1] =  cName    // paperName.
          aRet[i + 1, 2] =  nWord    // paperSize.
       endfor
    else
       aRet  =  new array()
    endif
return   aRet

//------------------------------------------------------------//
// return the windows default printer as a string.
function getPrinterDefault
    Local sBuff, cRet, nLen
    sBuff =  ZEROS(250)
    nLen  =  RMM_GetWinIniString( ;
             "windows", "device", ;
             ",,,", sBuff, sBuff.length)
    cRet  =  sBuff.left(sBuff.indexOf(","))
return   cRet.rightTrim()

//------------------------------------------------------------//
// return a WORD from the string sValu starting at nByte.
function getWord(sValu, nByte)
return   int(sValu.getByte(nByte) + ;
          bitlshift(sValu.getByte(nByte + 1), 8))

//------------------------------------------------------------//
function initExterns
    if not type("RMM_DeviceCapability") == "FP"
       extern CINT RMM_DeviceCapability( ;
                CSTRING, CSTRING, CWORD, CPTR, CPTR);
                winspool.drv from 'DeviceCapabilitiesA'
    endif
    if not type("RMM_GetWinIniString") == "FP"
       extern CULONG RMM_GetWinIniString( ;
                CSTRING, CSTRING, CSTRING, CSTRING, CULONG);
                kernel32 from "GetProfileStringA"
    endif
return

// end of file: PaperSize.prg