Kbase P185384: Extended example calling EnumPrinters from ABL / 4GL
Autor |
  Progress Software Corporation - Progress |
Acesso |
  Público |
Publicação |
  4/6/2011 |
|
Status: Unverified
GOAL:
Extended example calling EnumPrinters from ABL / 4GL
GOAL:
How to access printer information for local, remote, or connected printers using the Windows Print Spooler API
FACT(s) (Environment):
Windows
Progress 9.x
OpenEdge 10.x
FIX:
The following code uses the EnumPrinters function of the Windows Print Spooler API to obtain information about the various categories of printers that are enumerated in this interface. It extends examples in solutions 19311 and P107640. Note that PRINTER_ENUM_CONNECTIONS does not work on Windows 7.
/*------------------------------------------------------------------------
File: printerinfo.p
Description: Displays printer information from the Windows Print
SpoolerAPI. Uses the EnumPrintersA (ANSI) version of the
EnumPrintersfunction. Displays detailed printer information from the
PRINTER_INFO_2 structure for print object types PRINTER_ENUM_LOCAL,
PRINTER_ENUM_CONNECTIONS, and PRINTER_ENUM_NAME where a server name
is provided. Displays general printer information from PRINTER_INFO_1
structure for print object type PRINTER_ENUM_REMOTE.
Input Parameters:
<none>
Output Parameters:
<none>
Author: romiller
Created: 2011-03-23
------------------------------------------------------------------------*/
/* *************************** Definitions ************************** */
/* Preprocessor Definitions --- */
&Scoped-define WINDOW-NAME wPrinterOpt
&Scoped-define FRAME-NAME DEFAULT-FRAME
&GLOBAL-DEFINE PRINTER_ENUM_LOCAL 2
&GLOBAL-DEFINE PRINTER_ENUM_CONNECTIONS 4
&GLOBAL-DEFINE PRINTER_ENUM_REMOTE 16
&GLOBAL-DEFINE PRINTER_ENUM_NAME 8
&GLOBAL-DEFINE PRINTER_INFO_1 1
&GLOBAL-DEFINE PRINTER_INFO_2 2
/* Local Variable Definitions --- */
DEFINE VARIABLE iFlags AS INTEGER NO-UNDO.
DEFINE VARIABLE cName AS CHARACTER NO-UNDO.
DEFINE VARIABLE iLevel AS INTEGER NO-UNDO.
DEFINE VARIABLE mpPrinterEnum AS MEMPTR NO-UNDO.
DEFINE VARIABLE ipcbNeeded AS INTEGER NO-UNDO.
DEFINE VARIABLE ipcReturned AS INTEGER NO-UNDO.
DEFINE VARIABLE iResult AS INTEGER NO-UNDO.
DEFINE VARIABLE cTest AS CHARACTER NO-UNDO.
/* *********************** Control Definitions ********************** */
/* Define the widget handle for the window */
DEFINE VARIABLE wPrinterOpt AS HANDLE NO-UNDO.
/* Definitions of the field level widgets&nb.sp; */
DEFINE BUTTON bDisplay
LABEL "Display Printers"
SIZE 19 BY 1.14.
DEFINE BUTTON bExit
LABEL "Exit"
SIZE 19 BY 1.14.
DEFINE VARIABLE lConnections AS LOGICAL INITIAL no
LABEL "Connected printers"
VIEW-AS TOGGLE-BOX
SIZE 50 BY .81 NO-UNDO.
DEFINE VARIABLE lLocal AS LOGICAL INITIAL no
LABEL "Local printers"
VIEW-AS TOGGLE-BOX
SIZE 50 BY .81 NO-UNDO.
DEFINE VARIABLE lRemote AS LOGICAL INITIAL no
LABEL "Remote printers and print servers in your domain"
VIEW-AS TOGGLE-BOX
SIZE 50 BY .81 NO-UNDO.
DEFINE VARIABLE cServer AS CHARACTER INITIAL ""
LABEL "All printers on server:"
VIEW-AS FILL-IN
SIZE 28 BY 1 NO-UNDO.
/* ************************ Frame Definitions *********************** */
DEFINE FRAME DEFAULT-FRAME
lLocal AT ROW 2 COL 10 WIDGET-ID 2
lConnections AT ROW 3 COL 10 WIDGET-ID 4
lRemote AT ROW 4 COL 10 WIDGET-ID 6
cServer AT ROW 6 COL 10 WIDGET-ID 12
bDisplay AT ROW 9 COL 20 WIDGET-ID 8
bExit AT ROW 9 COL 40 WIDGET-ID 10
WITH 1 DOWN NO-BOX KEEP-TAB-ORDER OVERLAY
SIDE-LABELS NO-UNDERLINE THREE-D
AT COL 1 ROW 1
SIZE 75 BY 12 WIDGET-ID 100.
/* Create an unnamed pool to store all the widgets created
by this procedure. This is a good default which assures
that this procedure's triggers and internal procedures
will execute in this procedure's storage, and that proper
cleanup will occur on deletion of the procedure. */
CREATE WIDGET-POOL.
/* ************************* Create Window ************************** */
IF SESSION:DISPLAY-TYPE = "GUI":U THEN
CREATE WINDOW wPrinterOpt ASSIGN
HIDDEN = YES
TITLE = "Printer Information"
HEIGHT = 12
WIDTH = 75
MAX-HEIGHT = 16
MAX-WIDTH = 80
VIRTUAL-HEIGHT = 16
VIRTUAL-WIDTH = 80
RESIZE = yes
SCROLL-BARS = no
STATUS-AREA &.nbsp; = no
BGCOLOR = ?
FGCOLOR = ?
KEEP-FRAME-Z-ORDER = yes
THREE-D = yes
MESSAGE-AREA = no
SENSITIVE = yes.
ELSE {&WINDOW-NAME} = CURRENT-WINDOW.
&IF '{&WINDOW-SYSTEM}' NE 'TTY' &THEN
IF NOT wPrinterOpt:LOAD-ICON("adeicon/progress.ico":U) THEN
MESSAGE "Unable to load icon: adeicon/progress.ico"
VIEW-AS ALERT-BOX WARNING BUTTONS OK.
&ENDIF
IF SESSION:DISPLAY-TYPE = "GUI":U AND VALID-HANDLE(wPrinterOpt)
THEN wPrinterOpt:HIDDEN = no.
/* ************************ Control Triggers ************************ */
ON END-ERROR OF wPrinterOpt /* Printer Information */
OR ENDKEY OF {&WINDOW-NAME} ANYWHERE DO:
/* This case occurs when the user presses the "Esc" key.
In a persistently run window, just ignore this. If we did not, the
application would exit. */
IF THIS-PROCEDURE:PERSISTENT THEN RETURN NO-APPLY.
END.
ON WINDOW-CLOSE OF wPrinterOpt /* Printer Information */
DO:
/* This event will close the window and terminate the procedure. */
APPLY "CLOSE":U TO THIS-PROCEDURE.
RETURN NO-APPLY.
END.
ON CHOOSE OF bDisplay IN FRAME DEFAULT-FRAME /* Display Printers */
DO:
IF NOT cServer = "" THEN
DO:
IF NOT iFlags = 0 THEN
MESSAGE
'Displaying all printers on server' cServer
SKIP
'Check boxes will be ignored ...'
VIEW-AS ALERT-BOX.
iFlags = 8.
END.
CASE iFlags:
WHEN 2 THEN
RUN setAllLevel2.
WHEN 4 THEN
RUN setAllLevel2.
WHEN 6 THEN
RUN setAllLevel2.
WHEN 8 THEN
RUN setServerLevel2.
WHEN 16 THEN
RUN setAllLevel1.
WHEN 0 THEN
DO:
MESSAGE 'Please choose the printers to display' VIEW-AS ALERT-BOX.
LEAVE.
END.
&nb.sp; OTHERWISE
DO:
MESSAGE
'Incompatible or invalid choices'
SKIP
'Displaying all remote printers in domain ...'
VIEW-AS ALERT-BOX.
iFlags = 16.
RUN setAllLevel1.
END.
END CASE.
RUN enumeratePrinters.
RUN initializeParameters.
END.
ON CHOOSE OF bExit IN FRAME DEFAULT-FRAME /* Exit */
DO:
APPLY "WINDOW-CLOSE" TO wPrinterOpt.
END.
ON VALUE-CHANGED OF cServer IN FRAME DEFAULT-FRAME /* Server Name */
DO:
IF SUBSTRING(cServer:SCREEN-VALUE, 1, 2) = '\\' THEN
cServer = cServer:SCREEN-VALUE.
ELSE
cServer = '\\' + cServer:SCREEN-VALUE.
END.
ON VALUE-CHANGED OF lConnections IN FRAME DEFAULT-FRAME /* Connected Printers */
DO:
iFlags = iFlags + {&PRINTER_ENUM_CONNECTIONS}.
END.
ON VALUE-CHANGED OF lLocal IN FRAME DEFAULT-FRAME /* Local printers */
DO:
iFlags = iFlags + {&PRINTER_ENUM_LOCAL}.
END.
ON VALUE-CHANGED OF lRemote IN FRAME DEFAULT-FRAME /* Remote Printers */
DO:
iFlags = iFlags + {&PRINTER_ENUM_REMOTE}.
END.
/* *************************** Main Block *************************** */
/* May be helpful if this sample is developed further */
SESSION:DEBUG-ALERT = TRUE.
/* Set CURRENT-WINDOW: this will parent dialog-boxes and frames. */
ASSIGN CURRENT-WINDOW = {&WINDOW-NAME}
THIS-PROCEDURE:CURRENT-WINDOW = {&WINDOW-NAME}.
/* The CLOSE event can be used from inside or outside the procedure to */
/* terminate it. */
ON CLOSE OF THIS-PROCEDURE
RUN disable_UI.
/* Best default for GUI applications is... */
PAUSE 0 BEFORE-HIDE.
/* Now enable the interface and wait for the exit condition. */
/* (NOTE: handle ERROR and END-KEY so cleanup code will always fire. */
MAIN-BLOCK:
DO ON ERROR UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK
ON END-KEY UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK:
RUN initializeParameters.
RUN enable_UI.
IF NOT THIS-PROCEDURE:PERSISTENT THEN
WAIT-FOR CLOSE OF THIS-PROCEDURE.
END.
/* ********************** Internal Procedures *********************** */
.PROCEDURE disable_UI :
/*------------------------------------------------------------------------------
Purpose: DISABLE the User Interface
Parameters: <none>
Notes: Here we clean-up the user-interface by deleting
dynamic widgets we have created and/or hide
frames. This procedure is usually called when
we are ready to "clean-up" after running.
------------------------------------------------------------------------------*/
/* Delete the WINDOW we created */
IF SESSION:DISPLAY-TYPE = "GUI":U AND VALID-HANDLE(wPrinterOpt)
THEN DELETE WIDGET wPrinterOpt.
IF THIS-PROCEDURE:PERSISTENT THEN DELETE PROCEDURE THIS-PROCEDURE.
END PROCEDURE.
PROCEDURE display_PRINTER_INFO_1 :
/*------------------------------------------------------------------------------
Purpose: Display general printer information
Parameters: <none>
Notes:
------------------------------------------------------------------------------*/
DEFINE VARIABLE iCounter AS INTEGER NO-UNDO.
DEFINE VARIABLE mpPrinterInfo2 AS MEMPTR NO-UNDO.
DEFINE VARIABLE mBuffer AS MEMPTR NO-UNDO.
DEFINE VARIABLE cDescription AS CHARACTER NO-UNDO.
DEFINE VARIABLE cName AS CHARACTER NO-UNDO.
DEFINE VARIABLE cComment AS CHARACTER NO-UNDO.
DO iCounter = 0 TO ipcReturned - 1:
SET-POINTER-VALUE(mpPrinterInfo2) = GET-POINTER-VALUE(mpPrinterEnum) +
(iCounter * 16 ).
SET-POINTER-VALUE(mBuffer) = GET-LONG(mpPrinterInfo2,5) NO-ERROR.
cDescription = GET-STRING(mBuffer,1).
SET-POINTER-VALUE(mBuffer) = GET-LONG(mpPrinterInfo2,9) NO-ERROR.
cName = GET-STRING(mBuffer,1).
SET-POINTER-VALUE(mBuffer) = GET-LONG(mpPrinterInfo2,13)NO-ERROR.
cComment = GET-STRING(mBuffer,1).
MESSAGE
"Description:" "~t" cDescription "~n"
"Server or Printer Name" "~t" cName "~n"
"Comment:" "~t" cComment "~n"
VIEW-AS ALERT-BOX INFO BUTTONS OK.
END.
END PROCEDURE.
PROCEDURE display_PRINTER_INFO_2 :
/*------------------------------------------------------------------------------
Purpose: Display detailed printer information
Parameters: <none>
&.nbsp; Notes:
------------------------------------------------------------------------------*/
DEFINE VARIABLE iCounter AS INTEGER NO-UNDO.
DEFINE VARIABLE mpPrinterInfo2 AS MEMPTR NO-UNDO.
DEFINE VARIABLE mBuffer AS MEMPTR NO-UNDO.
DEFINE VARIABLE cServerName AS CHARACTER NO-UNDO.
DEFINE VARIABLE cPrinterName AS CHARACTER NO-UNDO.
DEFINE VARIABLE cShareName AS CHARACTER NO-UNDO.
DEFINE VARIABLE cPortName AS CHARACTER NO-UNDO.
DEFINE VARIABLE cDriverName AS CHARACTER NO-UNDO.
DEFINE VARIABLE cComment AS CHARACTER NO-UNDO.
DEFINE VARIABLE cLocation AS CHARACTER NO-UNDO.
DO iCounter = 0 TO ipcReturned - 1:
SET-POINTER-VALUE(mpPrinterInfo2) = GET-POINTER-VALUE(mpPrinterEnum) +
(iCounter * 84 ).
SET-POINTER-VALUE(mBuffer) = GET-LONG(mpPrinterInfo2,1).
cServerName = GET-STRING(mBuffer,1) NO-ERROR.
SET-POINTER-VALUE(mBuffer) = GET-LONG(mpPrinterInfo2,5).
cPrinterName = GET-STRING(mBuffer,1) NO-ERROR.
SET-POINTER-VALUE(mBuffer) = GET-LONG(mpPrinterInfo2,9).
cShareName = GET-STRING(mBuffer,1) NO-ERROR.
SET-POINTER-VALUE(mBuffer) = GET-LONG(mpPrinterInfo2,13).
cPortName = GET-STRING(mBuffer,1) NO-ERROR.
SET-POINTER-VALUE(mBuffer) = GET-LONG(mpPrinterInfo2,17).
cDriverName = GET-STRING(mBuffer,1) NO-ERROR.
SET-POINTER-VALUE(mBuffer) = GET-LONG(mpPrinterInfo2,21).
cComment = GET-STRING(mBuffer,1) NO-ERROR.
SET-POINTER-VALUE(mBuffer) = GET-LONG(mpPrinterInfo2,25).
cLocation = GET-STRING(mBuffer,1) NO-ERROR.
MESSAGE
"Server Name:" "~t" cServerName "~n"
"Printer Name:" "~t" cPrinterName "~n"
"Share Name:" "~t" cShareName "~n"
"Port Name:" "~t" cPortName "~n"
"Driver Name:" "~t" cDriverNAME "~n"
"Comment:" "~t" cComment "~n"
"Location:" "~t" cLocation "~n"
VIEW-AS ALERT-BOX INFO BUTTONS OK.
END.
END PROCEDURE.
PROCEDURE enable_UI :
/*-----------------------------------------.-------------------------------------
Purpose: ENABLE the User Interface
Parameters: <none>
Notes: Here we display/view/enable the widgets in the
user-interface. In addition, OPEN all queries
associated with each FRAME and BROWSE.
These statements here are based on the "Other
Settings" section of the widget Property Sheets.
------------------------------------------------------------------------------*/
DISPLAY lLocal lConnections lRemote cServer
WITH FRAME DEFAULT-FRAME IN WINDOW wPrinterOpt.
ENABLE lLocal lConnections lRemote cServer bDisplay bExit
WITH FRAME DEFAULT-FRAME IN WINDOW wPrinterOpt.
{&OPEN-BROWSERS-IN-QUERY-DEFAULT-FRAME}
VIEW wPrinterOpt.
END PROCEDURE.
PROCEDURE enumeratePrinters :
/*------------------------------------------------------------------------------
Purpose:
Parameters: <none>
Notes:
------------------------------------------------------------------------------*/
/* Get the correct size of the mpPrinterEnum buffer needed */
SET-SIZE(mpPrinterEnum)= 1.
RUN EnumPrintersA(
INPUT iFlags,
INPUT cName,
INPUT iLevel,
INPUT-OUTPUT mpPrinterEnum,
INPUT GET-SIZE(mpPrinterEnum),
OUTPUT ipcbNeeded,
OUTPUT ipcReturned,
OUTPUT iResult).
IF ipcbNeeded > 0 THEN
DO:
/* Set the correct size of the mpPrinterEnum buffer as needed */
SET-SIZE(mpPrinterEnum)= 0.
SET-SIZE(mpPrinterEnum)= ipcbNeeded.
/* Get printer information into the mpPrinterEnum buffer */
RUN EnumPrintersA(
INPUT iFlags,
INPUT cName,
INPUT iLevel,
INPUT-OUTPUT mpPrinterEnum,
INPUT GET-SIZE(mpPrinterEnum),
OUTPUT ipcbNeeded,
OUTPUT ipcReturned,
OUTPUT iResult).
END.
ELSE
MESSAGE 'There are no printers or servers of this type to display'
VIEW-AS ALERT-BOX.
/* Display printer information from the structure that was returned. */
IF iLevel = 2 THEN
RUN display_PRINTER_INFO_2.
ELSE
RUN display_PRINTER_INFO_1.
END PROCEDURE.
PROCEDURE EnumPrintersA EXTERNAL "winspool.drv":
/*------------------------------------------------------------------------------
Purpose: External call to Windows Print Spooler API
Parameters: <none>
Notes:
------------------------------------------------------------------------------*/
DEFINE INPUT PARAMETER Flags AS LONG.
DEFINE INPUT PARAMETER Name AS CHARACTER.
DEFINE INPUT PARAMETER Level AS LONG.
&n.bsp; DEFINE INPUT-OUTPUT PARAMETER pPrinterEnum AS MEMPTR.
DEFINE INPUT PARAMETER cdBuf AS LONG.
DEFINE OUTPUT PARAMETER pcbNeeded AS LONG.
DEFINE OUTPUT PARAMETER pcReturned AS LONG.
DEFINE RETURN PARAMETER iResult AS LONG.
END PROCEDURE.
PROCEDURE initializeParameters :
/*------------------------------------------------------------------------------
Purpose: Reset printer objects requested after each display.
Parameters: <none>
Notes:
------------------------------------------------------------------------------*/
lLocal:CHECKED IN FRAME {&FRAME-NAME} = FALSE.
lConnections:CHECKED IN FRAME {&FRAME-NAME} = FALSE.
lRemote:CHECKED IN FRAME {&FRAME-NAME} = FALSE.
ASSIGN
iFlags = 0
cName = ""
iLevel = 1
.
END PROCEDURE.
PROCEDURE setAllLevel1 :
/*------------------------------------------------------------------------------
Purpose: Request general information for all printers or servers.
Parameters: <none>
Notes:
------------------------------------------------------------------------------*/
cName = "".
iLevel = 1.
END PROCEDURE.
PROCEDURE setAllLevel2 :
/*------------------------------------------------------------------------------
Purpose: Request detailed information for all printers.
Parameters: <none>
Notes:
------------------------------------------------------------------------------*/
cName = "".
iLevel = 2.
END PROCEDURE.
PROCEDURE setServerLevel2 :
/*------------------------------------------------------------------------------
Purpose: Request detailed information for printers on a particular server.
Parameters: <none>
Notes:
------------------------------------------------------------------------------*/
cName = cServer.
iLevel = 2.
END PROCEDURE..