Re: vb6 print dialog problem



Mike,

Thanks for that. It is a lot of code to rewrite to use the API. I will try your changing the default printer idea.

If you do find the article it would be good.

Jack Russell


Mike Williams wrote:

"Jack Russell" <jackr@xxxxxxxxxxxxxxxxxxxx> wrote in message news:43838433@xxxxxxxxxxxxxxxxxxxx

If I select a printer it prints to that (and seems to make it the
default). If I do the same again without restarting the program
and select the other printer it prints to the one I selected the
previous time and will continue to do so until I restart the
program. In other words it only seems to change the printer
selection within the program the first time that I do it.


Somewhere in the back of my mind I seem to recall reading a Knowledge Base article about such behaviour under certain conditions, but I've searched and searched and I can't seem to out my finger on it now.

My refernce to using the API calls is that , using a similar (same
but in a different routine) selection dialog the program prints via
API calls using the hdc returned by the common dialog. That
does select the right printer each time.


Yep. I'm afraid that's what I do all the time now when writing code to reliably select printers. I have almost (but not quite) given up on the VB printer object! Printing to the CommonDialog returned hDC has always worked for me. I'll continue to look for this "half remembered" thing about the printer object "hanging onto" the selected printer until you restart your VB program, but I'm not sure whether I will find it or not. Why don't you just ditch the VB printer object altogether, and do all your printing to the CommonDialog returned hDC? I think that's the route I would take in your position.

Alternatively, how about changing the system wide "default printer" ujsing the API and then using the VB printer object to print to it. You can always save the original default and restore it after your print job if you wish. Here is some code that should change the default printer for you. I don't know whether it is any good for your own specific purposes, but it might be worth looking at taking that route. Paste the example code into a VB Form containing a List Box and a Command Button:

Mike

Option Explicit
Private Const HWND_BROADCAST = &HFFFF
Private Const WM_WININICHANGE = &H1A
Private Const CCHDEVICENAME = 32
Private Const CCHFORMNAME = 32
Private Const STANDARD_RIGHTS_REQUIRED = &HF0000
Private Const PRINTER_ACCESS_ADMINISTER = &H4
Private Const PRINTER_ACCESS_USE = &H8
Private Const PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or _
PRINTER_ACCESS_ADMINISTER Or PRINTER_ACCESS_USE)
Private Const PRINTER_ATTRIBUTE_DEFAULT = 4
Private Const VER_PLATFORM_WIN32_WINDOWS = 1
Private Type OSVERSIONINFO
 dwOSVersionInfoSize As Long
 dwMajorVersion As Long
 dwMinorVersion As Long
 dwBuildNumber As Long
 dwPlatformId As Long
 szCSDVersion As String * 128
End Type
Private Type DEVMODE
 dmDeviceName As String * CCHDEVICENAME
 dmSpecVersion As Integer
 dmDriverVersion As Integer
 dmSize As Integer
 dmDriverExtra As Integer
 dmFields As Long
 dmOrientation As Integer
 dmPaperSize As Integer
 dmPaperLength As Integer
 dmPaperWidth As Integer
 dmScale As Integer
 dmCopies As Integer
 dmDefaultSource As Integer
 dmPrintQuality As Integer
 dmColor As Integer
 dmDuplex As Integer
 dmYResolution As Integer
 dmTTOption As Integer
 dmCollate As Integer
 dmFormName As String * CCHFORMNAME
 dmLogPixels As Integer
 dmBitsPerPel As Long
 dmPelsWidth As Long
 dmPelsHeight As Long
 dmDisplayFlags As Long
 dmDisplayFrequency As Long
 dmICMMethod As Long
 dmICMIntent As Long
 dmMediaType As Long
 dmDitherType As Long
 dmReserved1 As Long
 dmReserved2 As Long
End Type
Private Type PRINTER_INFO_5
 pPrinterName As String
 pPortName As String
 Attributes As Long
 DeviceNotSelectedTimeout As Long
 TransmissionRetryTimeout As Long
End Type
Private Type PRINTER_DEFAULTS
 pDatatype As Long
 pDevMode As Long
 DesiredAccess As Long
End Type
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 WriteProfileString _
 Lib "kernel32" Alias "WriteProfileStringA" _
 (ByVal lpszSection As String, _
 ByVal lpszKeyName As String, _
 ByVal lpszString As String) As Long
Private Declare Function SendMessage Lib "user32" _
 Alias "SendMessageA" (ByVal hwnd As Long, _
 ByVal wMsg As Long, _
 ByVal wParam As Long, _
 lparam As String) As Long
Private Declare Function GetVersionExA Lib "kernel32" _
 (lpVersionInformation As OSVERSIONINFO) As Integer
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 SetPrinter Lib "winspool.drv" _
 Alias "SetPrinterA" _
 (ByVal hPrinter As Long, _
 ByVal Level As Long, _
 pPrinter As Any, _
 ByVal Command As Long) As Long
Private Declare Function GetPrinter Lib "winspool.drv" _
 Alias "GetPrinterA" _
 (ByVal hPrinter As Long, _
 ByVal Level As Long, _
 pPrinter As Any, _
 ByVal cbBuf As Long, _
 pcbNeeded As Long) As Long
Private Declare Function lstrcpy Lib "kernel32" _
 Alias "lstrcpyA" _
 (ByVal lpString1 As String, _
 ByVal lpString2 As Any) As Long
Private Declare Function ClosePrinter Lib "winspool.drv" _
 (ByVal hPrinter As Long) As Long

Private Sub SelectPrinter(NewPrinter As String)
Dim Prt As Printer
 For Each Prt In Printers
 If Prt.DeviceName = NewPrinter Then
   Set Printer = Prt
   Exit For
 End If
Next
End Sub

Private Function PtrCtoVbString(Add As Long) As String
Dim sTemp As String * 512, x As Long
x = lstrcpy(sTemp, Add)
If (InStr(1, sTemp, Chr(0)) = 0) Then
 PtrCtoVbString = ""
Else
 PtrCtoVbString = Left(sTemp, InStr(1, sTemp, Chr(0)) - 1)
End If
End Function

Private Sub SetDefaultPrinter(ByVal PrinterName As String, _
 ByVal DriverName As String, ByVal PrinterPort As String)
Dim DeviceLine As String
Dim r As Long
Dim l As Long
DeviceLine = PrinterName & "," & DriverName & "," & PrinterPort
r = WriteProfileString("windows", "Device", DeviceLine)
l = SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, "windows")
End Sub

Private Sub Win95SetDefaultPrinter()
Dim Handle As Long
Dim PrinterName As String
Dim pd As PRINTER_DEFAULTS
Dim x As Long
Dim need As Long
Dim pi5 As PRINTER_INFO_5
Dim LastError As Long
PrinterName = List1.List(List1.ListIndex)
If PrinterName = "" Then
 Exit Sub
End If
pd.pDatatype = 0&
pd.DesiredAccess = PRINTER_ALL_ACCESS Or pd.DesiredAccess
x = OpenPrinter(PrinterName, Handle, pd)
If x = False Then
 ' handle errors here
Exit Sub
End If
x = GetPrinter(Handle, 5, ByVal 0&, 0, need)
ReDim t((need \ 4)) As Long
x = GetPrinter(Handle, 5, t(0), need, need)
If x = False Then
 '  handle errors here
Exit Sub
End If
pi5.pPrinterName = PtrCtoVbString(t(0))
pi5.pPortName = PtrCtoVbString(t(1))
pi5.Attributes = t(2)
pi5.DeviceNotSelectedTimeout = t(3)
pi5.TransmissionRetryTimeout = t(4)
pi5.Attributes = PRINTER_ATTRIBUTE_DEFAULT
x = SetPrinter(Handle, 5, pi5, 0)
If x = False Then
 MsgBox "SetPrinter Failed. Error code: " & Err.LastDllError
 Exit Sub
Else
 If Printer.DeviceName <> List1.Text Then
   SelectPrinter (List1.Text)
 End If
End If
ClosePrinter (Handle)
End Sub

Private Sub GetDriverAndPort(ByVal Buffer As String, DriverName As _
 String, PrinterPort As String)
Dim iDriver As Integer
Dim iPort As Integer
DriverName = ""
PrinterPort = ""
iDriver = InStr(Buffer, ",")
If iDriver > 0 Then
 DriverName = Left(Buffer, iDriver - 1)
 iPort = InStr(iDriver + 1, Buffer, ",")
 If iPort > 0 Then
   PrinterPort = Mid(Buffer, iDriver + 1, _
   iPort - iDriver - 1)
 End If
End If
End Sub

Private Sub ParseList(lstCtl As Control, ByVal Buffer As String)
Dim i As Integer
Dim s As String
Do
 i = InStr(Buffer, Chr(0))
 If i > 0 Then
   s = Left(Buffer, i - 1)
   If Len(Trim(s)) Then lstCtl.AddItem s
   Buffer = Mid(Buffer, i + 1)
 Else
   If Len(Trim(Buffer)) Then lstCtl.AddItem Buffer
   Buffer = ""
 End If
Loop While i > 0
End Sub

Private Sub WinNTSetDefaultPrinter()
Dim Buffer As String
Dim DeviceName As String
Dim DriverName As String
Dim PrinterPort As String
Dim PrinterName As String
Dim r As Long
If List1.ListIndex > -1 Then
 Buffer = Space(1024)
 PrinterName = List1.Text
 r = GetProfileString("PrinterPorts", PrinterName, "", _
   Buffer, Len(Buffer))
 GetDriverAndPort Buffer, DriverName, PrinterPort
 If DriverName <> "" And PrinterPort <> "" Then
   SetDefaultPrinter List1.Text, DriverName, PrinterPort
   If Printer.DeviceName <> List1.Text Then
     SelectPrinter (List1.Text)
   End If
 End If
End If
End Sub

Private Sub Form_Load()
Dim r As Long
Dim Buffer As String
Buffer = Space(8192)
r = GetProfileString("PrinterPorts", vbNullString, "", _
 Buffer, Len(Buffer))
ParseList List1, Buffer
End Sub

Private Sub Command1_Click()
Dim osinfo As OSVERSIONINFO
Dim retvalue As Integer
osinfo.dwOSVersionInfoSize = 148
osinfo.szCSDVersion = Space$(128)
retvalue = GetVersionExA(osinfo)
If osinfo.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS Then
 Call Win95SetDefaultPrinter
Else
 Call WinNTSetDefaultPrinter
End If
End Sub



.