Symptom
At an operating system level, is it possible to define the settings for a specific tray/paper format for a given printer?
When invoking the SelectPrinter method, the settings for the printer will be default ones so any customization at the Control Panel level is lost.
Cause
The behaviour is normal.
Resolution
When the customized settings for the printer need to be retained, the workaround is to write a routine which
- retrieves the settings for the required printer (in COM invoking the WINSPOOL API)
- changes the printer settings for the CRViewer object.
The codes returned from the API vary from printer to printer and are not the same as the constants used by Crystal Reports so another function will be needed to to translate the codes returned by WINSPOOL onto the Crystal Reports constants.
Below is sample code in Visual Basic, which demonstrates a possible solution, when you need to print using the paper tray defined on the printer settings in the control panel.
' #### START OF CODE ############
' THIS PART OF CODE GOES IN A MODULE
Private Declare Function GetProfileString Lib "kernel32" Alias _
"GetProfileStringA" (ByVal lpAppName As String, _
ByVal lpKeyName As String, ByVal lpDefault As String, _
ByVal lpReturnedString As String, _
ByVal nSize As Long) As Long
Private Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" (ByVal pPrinterName As String, phPrinter As Long, pDefault As PRINTER_DEFAULTS) As Long
Private Declare Function GetPrinter Lib "winspool.drv" Alias "GetPrinterA" (ByVal hPrinter As Long, ByVal Level As Long, buffer As Long, ByVal pbSize As Long, pbSizeNeeded As Long) As Long
Private Declare Function ClosePrinter Lib "winspool.drv" (ByVal hPrinter As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
'---------------------------------------------------------------
' Retrieve the vb object "printer" corresponding to the window's
' default printer.
'---------------------------------------------------------------
Public Function GetDefaultPrinter() As Printer
Dim strBuffer As String * 254
Dim iRetValue As Long
Dim strDefaultPrinterInfo As String
Dim tblDefaultPrinterInfo() As String
Dim objPrinter As Printer
' Retreive current default printer information
iRetValue = GetProfileString("windows", "device", ",,,", _
strBuffer, 254)
strDefaultPrinterInfo = Left(strBuffer, InStr(strBuffer, Chr(0)) - 1)
tblDefaultPrinterInfo = Split(strDefaultPrinterInfo, ",")
For Each objPrinter In Printers
If objPrinter.DeviceName = tblDefaultPrinterInfo(0) Then
' Default printer found !
Exit For
End If
Next
' If not found, return nothing
If objPrinter.DeviceName <> tblDefaultPrinterInfo(0) Then
Set objPrinter = Nothing
End If
Set GetDefaultPrinter = objPrinter
End Function
Public Function setDefaultPrinter(strPrinterName As String)
Dim myPrinter As Printer
For Each myPrinter In Printers
If myPrinter.DeviceName = strPrinterName Then
Set Printer = myPrinter
Exit For
End If
Next
End Function
' ----------------------
' --- THE FOLLOWING CODE GOES BETWEEN THE SELECTPRINTER AND PRINTOUT METHODS
Dim iDefSourceWin as integer ' this variable will store the value returned from Windows for the papersource set for the printer
Dim P as Printer
P = GetDefaultPrinter
iDefSourceWin = GetPrinterPaperBin(P.Devicename, P.HDC)
' now we need to convert the windows value to the one for crystal
iDefsourceCR = ConvertPaperBinCodeWtoCR(iDefSourceWin, P.DeviceName)
crxReport.PaperSource = iDefSourceCR
' THIS IS THE FUNCTION GetPrinterPaperBin WHICH RETURNS THE TRAY
' THE TRAY IS RETURNED AS A INTEGER,
Function GetPrinterPaperBin(szPrinterName As String, hdc As Long) As Integer
Dim hPrinter As Long
Dim nSize As Long
Dim pDevMode As DEVMODE
Dim aDevMode() As Byte
Dim TempStr As String
If OpenPrinter(szPrinterName, hPrinter, NULLPTR) <> 0 Then
nSize = DocumentProperties(NULLPTR, hPrinter, szPrinterName, _
NULLPTR, NULLPTR, 0)
If nSize < 1 Then
GetPrinterPaperBin = 0
Exit Function
End If
ReDim aDevMode(1 To nSize)
nSize = DocumentProperties(NULLPTR, hPrinter, szPrinterName, _
aDevMode(1), NULLPTR, DM_OUT_BUFFER)
If nSize < 0 Then
GetPrinterPaperBin = 0
Exit Function
End If
Call CopyMemory(pDevMode, aDevMode(1), Len(pDevMode))
GetPrinterPaperBin = pDevMode.dmDefaultSource
Call ClosePrinter(hPrinter)
Else
GetPrinterPaperBin = 0
End If
End Function
' THIS IS THE FUNCTION ConvertPaperBinCodeWtoCR which translates the value from Windows to CR coding
' WIN CODES MAY BE SPECIFIC TO PRINTER MODELS, SO YOU NEED TO CREATE YOUR OWN CONVERSION TABLE
' SOME VALUES ARE THE SAME FOR ALL PRINTERS
Public Function ConvertPaperBinCodeWtoCR(iWinCode as integer, strPrinter as string ) as Integer
' this routine converts an integer value, corresponding to the paperbin value returned by the winspool api for a given printer.
' below the list of constants for the bin selection used by crystal reports
' constant value
' ------------------------
' crPRBinAuto 8
' crPRBinCassette 14
' crPRBinEnvelope 5
' crPRBinManual 6
' crPRBinFormSource 15
' crPRBinLargeCapacity 11
' crPRBinLargeFmt 10
' crPRBinLower 2
' crPRBinManual 4
' crPRBinMiddle 3
' crPRBinSmallFmt 9
' crPRBinTractor 8
' crPRBinUpper 1
' ------------------------
Dim iResult
iResult = 8 ' if no value is returned, will set to automatic
Select Case strPrinter
Case "HP laserjet 4000"
Select Case iWinCode
Case 15 ' automatic
iResult = 8
Case 257 ' cassette
iResult = 14
End Select
Case "Fujitsu DL 1100"
Select Case iWinCode
Case 15,8 ' automatic - tractor
iResult = 8
End Select
End Select
' returning the converted value.
ConvertPaperBinCodeWtoCR = iResult
End Function
' #### END OF CODE #######
Keywords
selectprinter, crystal, sdk, rdc, default printer settings lost , 1869514 , KBA , BI-RA-CR , Crystal Reports designer or Business View Manager , How To