How to retrieve PRINTER-NAME in Progress Session

Chris Kelleher

Administrator
Staff member
Dear API gurus;

I am using Progress V8.0, it does not have PRINTER-NAME attribute on SESSION
handle. I want to one of followings:

a) Use SYSTEM-DIALOG PRINTER-SETUP statement and pass the printer name to a
DLL I made
b) EnumPrinters to list all printer configured on my Windows then pass
selected printer to the DLL
c) PrintDLG in the DLL to select a printer configured.

All of my trial was failed.


- NT 4.0/SP3
- Our company has more than hundreds of printers on network and I have
configuration with 2 remote printer (EnumPrinters(PRINTER_ENUM_REMOTE, ...)
returns hundreds of printer and does not return port-number, so not useful.
- Most of them including thunking is from Jurjen Dijkstra's sample

1) Isn't there any way to get the printer name which set by the PRINTER-SETUP
(in Progress or in C) ?

2) My printers are not attached to Local Printer port. Is it the reason why
EnumPrinters(PRINTER_ENUM_LOCAL) returns nothing

3) If it is not possible, then can I make Printer Dialog in the DLL?

The DLL prints on default printer and I just insert SetPrinter() to see if I
can put Printer Dialog before finding default printer, it did not have compile
error, no run-time complaint and no-screen shown on the screen.

*** I just started C programming ***
<BLOCKQUOTE><font size="1" face="Arial, Verdana">code:</font><HR><pre>

int StartDocument( void )
{
char DeviceName[128], DeviceSpecs[255];
int FirstPos;

DEVMODE DefaultDevMode, DevMode;
DOCINFO DocInfo;

memset( DeviceSpecs, '\0', 255 );
memset( DeviceName, '\0', 128 );

SetPrinter();

GetProfileString( "windows",
"device",
"-unknown-",
DeviceSpecs,
sizeof( DeviceSpecs )
);
FirstPos = strcspn( DeviceSpecs, "," );
strncpy( DeviceName, DeviceSpecs, FirstPos-- );

if ( strcmp( DeviceName, "-unknown-" ) == 0 )
{
// Error on getting default printer
return 2;
}


DocumentProperties( 0,
0,
DeviceName,
&DefaultDevMode,
0,
DM_OUT_BUFFER
);

DefaultDevMode.dmOrientation = DM_ORIENTATION;
DefaultDevMode.dmPaperSize = DMORIENT_PORTRAIT;

DocumentProperties( 0,
0,
DeviceName,
&DevMode,
&DefaultDevMode,
DM_IN_BUFFER + DM_OUT_BUFFER
);

hPrinterDC = CreateDC( "WINSPOOL",
DeviceName,
0,
&DevMode
);
if ( hPrinterDC == 0 )
{
// Error on CreateDC
return 3;
}

DocInfo.cbSize = sizeof( DOCINFO );
DocInfo.lpszDocName = "Bar Code";
DocInfo.lpszOutput = (LPTSTR) NULL;
DocInfo.lpszDatatype = (LPTSTR) NULL;
DocInfo.fwType = 0;

if ( StartDoc( hPrinterDC, &DocInfo ) < 1 )
{
// Error on StartDoc
return 2;
}

return 0;
}

void SetPrinter( void )
{
PRINTDLG pd;
HWND hwnd;

// Initialize PRINTDLG
ZeroMemory(&pd, sizeof(PRINTDLG));
pd.lStructSize = sizeof(PRINTDLG);
pd.hwndOwner = hwnd;
pd.hDevMode = NULL; // Don't forget to free or store hDevMode.
pd.hDevNames = NULL; // Don't forget to free or store hDevNames.
pd.Flags = PD_USEDEVMODECOPIESANDCOLLATE | PD_RETURNDC;
pd.nCopies = 1;
pd.nFromPage = 0xFFFF;
pd.nToPage = 0xFFFF;
pd.nMinPage = 1;
pd.nMaxPage = 0xFFFF;

if (PrintDlg(&pd)==TRUE) {

// GDI calls to render output.

// Delete DC when done.
DeleteDC(pd.hDC);
}

}
[/code]

Thanks in advance

Simon Kim


____________________________________________________________________
Get your own FREE, personal Netscape WebMail account today at http://webmail.netscape.com.
 

Chris Kelleher

Administrator
Staff member
Are you using struct PRINTER_INFO2? It passes back the port in the
pLocation variable I believe. We used EnumPrinters here to create
a vb front end to change the default printer in a progress session.
 

Chris Kelleher

Administrator
Staff member
Simon,

I believe that the below program will achieve what you are trying to do. It
could easily be converted over to C/C++ if necessary. This was written
under 8.2 so if your using 8.0, you will have to change the offsets
accordingly.

Todd G. Nist
tnist@netcarrier.com

<--------- Snip Code here ---------->
<BLOCKQUOTE><font size="1" face="Arial, Verdana">code:</font><HR><pre>

/*------------------------------------------------------------------------

File: PrintDlg.p

Description: Provides and interface to the common Print Dialog box.

Input Parameters:
< none >

Output Parameters:
pcPrinterName - Name of printer selected
piHDC - Device Context
piNumCopies - Number of copies selected

Author: Todd G. Nist

------------------------------------------------------------------------*/

/* parameters */
define output parameter pcPrinterName as char no-undo.
define output parameter piHDC as int no-undo.
define output parameter piNumCopies as int no-undo.

&GLOB PD_ALLPAGES 0
&GLOB PD_SELECTION 1
&GLOB PD_PAGENUMS 2
&GLOB PD_NOSELECTION 4
&GLOB PD_NOPAGENUMS 8
&GLOB PD_COLLATE 16
&GLOB PD_PRINTTOFILE 32 /* should the PrintToFile
toggle box show */
&GLOB PD_PRINTSETUP 64 /* display PrintSetup dialog
vs Printer Dialog */
&GLOB PD_NOWARNING 128
&GLOB PD_RETURNDC 256 /* return the Device Context
for the selected printer */
&GLOB PD_RETURNIC 512
&GLOB PD_RETURNDEFAULT 1024 /* returns hDevMod and
hDevName without displaying dialog */
&GLOB PD_SHOWHELP 2048 /* should help button show
up */
&GLOB PD_ENABLEPRINTHOOK 4096
&GLOB PD_ENABLESETUPHOOK 8192
&GLOB PD_ENABLEPRINTTEMPLATE 16384
&GLOB PD_ENABLESETUPTEMPLATE 32768
&GLOB PD_ENABLEPRINTTEMPLATEHANDLE 65536
&GLOB PD_ENABLESETUPTEMPLATEHANDLE 131072
&GLOB PD_USEDEVMODECOPIES 262144
&GLOB PD_USEDEVMODECOPIESANDCOLLATE 524288
&GLOB PD_DISABLEPRINTTOFILE 524288
&GLOB PD_HIDEPRINTTOFILE 1048576
&GLOB PD_NONETWORKBUTTON 2097152

&GLOB DEVMOD_NUMCOPIESOFFSET 23
&GLOB CCHDEVICENAME 32

&GLOB DM_COPIES 256

/* {winapi/winapi.i} */

FUNCTION LogicalAnd RETURNS INTEGER
( INPUT pi1 AS INTEGER,
INPUT pi2 AS INTEGER ):

def var i1 as int extent 32 initial [ 0 ] no-undo.
def var i2 as int extent 32 initial [ 0 ] no-undo.
def var iIdx as int no-undo.
def var iResult as int no-undo.

repeat iIdx = 1 to extent( i1 ):
assign i1[ iIdx ] = pi1 MOD 2
pi1 = truncate( pi1 / 2, 0 ).
end.

repeat iIdx = 1 to extent( i2 ):
assign i2[ iIdx ] = pi2 MOD 2
pi2 = truncate( pi2 / 2, 0 ).
end.

repeat iIdx = 1 to extent( i1 ):
if i1[ iIdx ] = 1 and
i2[ iIdx ] = 1 then
iResult = iResult + exp( 2, iIdx - 1 ).
end.

RETURN iResult.

END FUNCTION. /* LogicalAnd */


define var lpPrintDlg as memptr no-undo.
define var lpDevMod as memptr no-undo.
define var lpDevNames as memptr no-undo.
define var iRetCode as int no-undo.


/* set up PRINTDLG Structure */
assign
/* allocate memory */
set-size(lpPrintDlg) = 66
put-long(lpPrintDlg,1) = get-size(lpPrintDlg) /* structure
size */
put-long(lpPrintDlg,5) = current-window:hwnd /* hwndOwner
*/
put-long(lpPrintDlg,9) = 0 /* hDevMod
*/
put-long(lpPrintDlg,13) = 0 /* hDevNames
*/
put-long(lpPrintDlg,17) = 0 /* hDC
*/
put-long(lpPrintDlg,21) = {&PD_RETURNDC} /*
{&PD_USEDEVMODECOPIESANDCOLLATE} */ /* + /* {&PD_RETURNDEFAULT} + */
{&PD_RETURNDC} /* flags */ */
put-short(lpPrintDlg,25) = 1 /* nFromPage
*/
put-short(lpPrintDlg,27) = 1 /* nToPage
*/
put-short(lpPrintDlg,29) = 0 /* nMinPage
*/
put-short(lpPrintDlg,31) = 0 /* nMaxPage
*/
put-short(lpPrintDlg,33) = 0 /* nCopies
*/
put-long(lpPrintDlg,35) = 0
put-long(lpPrintDlg,39) = 0
put-long(lpPrintDlg,43) = 0
put-long(lpPrintDlg,47) = 0
put-long(lpPrintDlg,51) = 0
put-long(lpPrintDlg,55) = 0
put-long(lpPrintDlg,59) = 0
put-long(lpPrintDlg,63) = 0
.

RUN PrintDlgA (input get-pointer-value(lpPrintDlg),
output iRetCode).

/* ok pressed */
if iRetCode > 0 then
do:
RUN GlobalLock(INPUT get-long(lpPrintDlg,9),
OUTPUT iRetCode).
set-pointer-value(lpDevMod) = iRetCode. /* pointer to DEVMOD structure */

RUN GlobalLock(INPUT get-long(lpPrintDlg,13),
OUTPUT iRetCode).

if iRetCode > 0 then
do:
set-pointer-value(lpDevNames) = iRetCode.

pcPrinterName = get-string(lpDevNames, get-short(lpDevNames,3) + 1).
/* num copies is stored on DEVMOD structure */
if LogicalAnd({&DM_COPIES}, get-long(lpDevMod,41)) > 0 then
piNumCopies = get-short(lpDevMod,
{&CCHDEVICENAME} +
{&DEVMOD_NUMCOPIESOFFSET}).
/* Device does not support copies, stored in PrintDlg structure */
else
piNumCopies = get-short(lpPrintDlg, 33).

/* obtain the Device Context associated with Printer */
piHDC = get-long(lpPrintDlg,17).

/* unlock memory and return it to OS control */
RUN GlobalUnlock(INPUT get-long(lpPrintDlg,9)).
RUN GlobalUnlock(INPUT get-long(lpPrintDlg,13)).
end.

end.

/* either cancel was pressed or an Error occured */
else
assign
pcPrinterName = ''
piHDC = 0
piNumCopies = 0.

/* deallocate memory */
set-size(lpPrintDlg) = 0.

PROCEDURE PrintDlgA EXTERNAL "comdlg32.dll":U:
DEFINE INPUT PARAMETER lpStructure AS LONG.
DEFINE RETURN PARAMETER iRetCode AS LONG.
END.

PROCEDURE GlobalLock EXTERNAL "Kernel32":U:
DEFINE INPUT PARAMETER hDevMod AS LONG.
DEFINE RETURN PARAMETER lpDevMod AS LONG.
END.

PROCEDURE GlobalUnlock EXTERNAL "Kernel32":U:
DEFINE INPUT PARAMETER hDevMod AS LONG.
END.
[/code]
 

Chris Kelleher

Administrator
Staff member
Thanks Todd,

You inspired me that I need to initialize hwnd variable.
Basically, your progress program is same as my c program and I was wondering
what was wrong.

I defined HWND hwnd; and it did not display anything and no error.
After change it to HWND hwnd = 0; no problem.... Great!!!

Simon Kim,
 

Chris Kelleher

Administrator
Staff member
Yes, I am using PRINTER_INFO_2.
It was unfortunate it returns pcReturned 0.
Do you get all printers on Start->Settings->Printers?

When I use EnumPrinters with PRINTER_ENUM_REMOTE or NETWORK,
I am getting 387 printers in PRINTER_INFO_1.

Simon Kim,
 

Chris Kelleher

Administrator
Staff member
I used PRINTER_ENUM_NAME.

What we did was this:

we had an Ini file as follows:

[ServerLst]
SrvLst="Server1,Server2,Server3,....,Server(N)"
DefaultPrn="PrinterName"
DefaultSrv="ServerName"

[Server1]
prn1="Some Name"
prn2="Some Name"


prn(N)="Some Name"

[Server2]
prn1=""

etc....

[Server3]

etc....

******************
You get the idea.

We read the Ini File, loaded a combo box, eventually the user would
select a printer from a combo box having format "\\ServerName\Printer"

I then passes the ServerStr, and the PrinterStr to a function
which I have included only a snippet of what was contained

<BLOCKQUOTE><font size="1" face="Arial, Verdana">code:</font><HR><pre>

WritePrinterProperties (ServerStr, PrinterStr) as Boolean
Level = 2 /* PRINTER_INFO STRUCT2 */
lBuffer() as Long
pINFO() as PRINTER_INFO_2
nPrinters as Long

nBytes = 32768 /* I assumed 3K would be plenty large enough */

retVal = EnumPrinters(PRINTER_ENUM_NAME, "\\" + ServerStr, Level,
lBuffer(0), nBytes, nReqd, nPrinters)

/* This should return all Printers on the Server you passed in */

For i = 0 to nPrinters -1
'Level 2 Structure 21 = number of elements in structure

Fill the pINFO structure using lBuffer
Next i

j = -1

For i = 0 to nPrinters -1
If pINFO(i).pShareName = PrinterStr then
j = i /* j points to the printer you want */
i = nPrinters /* no need to search further */
endif
next i

if j = -1 then PRINTER NOT FOUND

X = AddPrinterConnection(pINFO(j).pPrinterName)
X = WritePrivateProfileString("windows", "device",
pINFO(j).pPrinterName +
",winspool," + pINFO(j).pPortName)

/* The above creates the registry settng for the default printer*/

/* Need to alert to OS to use the change */

X = SendMessage(HWND_BROADCAST, WM_INICHANGE, 0, 0)

[/code]

If you require further info

email to marmstrong@utramax.com
 

Chris Kelleher

Administrator
Staff member
Hi, Michael.

No luch on PRINTER_ENUM_NAME.
So, I tried PRNTER_ENUM_LOCAL, PRINTER_ENUM_NAME, PRINTER_ENUM_SHARED,
PRINTER_ENUM_DEFAULT and pcReturned = 0.

PRINTER_ENUM_CONNECTIONS returned all of my two network printers what I have.
Why?

And pPortName is weird. It is 160.43.159.138:INT_SYS_2.
Isn't it supposed be like LPT1: LPT3:? What do I send to DocumentProperties(
pDeviceName )?

msdn says;
PRINTER_ENUM_CONNECTIONS

Windows NT/2000: The function enumerates the list of printers to which the
user has made previous connections.

My english does not tell me this is what I want. Because what if the
connections will be made when I tried to print out.

Simon Kim,
 

ashwathnp

New Member
Hi all,

Using the same API call as above can you please tell us how to get the port number of the printer. Because while setting the value of activeprinter method/property of MS word 2007 it requires "printer name" on "port number".

Thanks,
Ashwath
 
Top