By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
444,137 Members | 2,199 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 444,137 IT Pros & Developers. It's quick & easy.

How to OPEN native PRINTER DIALOG -- Please HELP !!

P: n/a
I am doing my own PrintDialog, and have placed there a combo with the
printer names, as in the PrintDialog provided by VB.NET.

Here is the question: how do I open the native windows printer dialog
for the current printer, so that my current
PrintDocument.PrinterSettings will be set according to the User choices
?

Thanks
-Pamela
My question in code. Assume you have ceated a MyPrintDialog
form with a combo box "ComboBoxPrinterNames" listing the printers and a
button "ButtonSelectedPrinterProperties"
to set the current printer properties.

---------------------------------------
Private Sub ButtonSelectedPrinterProperties_Click(ByVal sender As
System.Object, ByVal e As System.EventArgs) Handles
ButtonSelectedPrinterProperties.Click

Me.PrintDocument.PrinterSettings.PrinterName =
Me.ComboBoxPrinterNames.SelectedText
If Not Me.PrintDocument.PrinterSettings.IsValid Then
MsgBox("Invalid printer", MsgBoxStyle.Information)
Exit Sub
End If

Me.OpenPrinterPropertiesDialog(PrintDocument)
End Sub

Sub OpenPrinterPropertiesDialog(ByVal PrintDocument As
PrintDocument)

' ???????? my question: how to open the windows dialog for
setting PrintDocument.PrinterSettings

End Sub
--------------------------------------------

Nov 21 '05 #1
Share this Question
Share on Google+
11 Replies


P: n/a
Hi,

<pa***********@libero.it> wrote in message
news:11**********************@o13g2000cwo.googlegr oups.com...
I am doing my own PrintDialog, and have placed there a combo with the
printer names, as in the PrintDialog provided by VB.NET.

Here is the question: how do I open the native windows printer dialog
for the current printer, so that my current
PrintDocument.PrinterSettings will be set according to the User choices
?

Thanks
-Pamela
My question in code. Assume you have ceated a MyPrintDialog
form with a combo box "ComboBoxPrinterNames" listing the printers and a
button "ButtonSelectedPrinterProperties"
to set the current printer properties.

---------------------------------------


Without much guarantee though it should be possible with a few native
functions:

Public Class YourPrinterSettingsDialog
' native functions
Private Declare Auto Function GlobalLock Lib "kernel32.dll" _
(ByVal handle As IntPtr) As IntPtr
Private Declare Auto Function GlobalUnlock Lib "kernel32.dll" _
(ByVal handle As IntPtr) As Integer
Private Declare Auto Function GlobalFree Lib "kernel32.dll" _
(ByVal handle As IntPtr) As IntPtr
Private Declare Auto Function DocumentProperties Lib "winspool.drv" _
(ByVal hWnd As IntPtr, ByVal hPrinter As IntPtr, _
ByVal pDeviceName As String, ByVal pDevModeOutput As IntPtr, _
ByVal pDevModeInput As IntPtr, ByVal fMode As Int32) As Integer
Private Sub ButtonSelectedPrinterProperties_Click( ... )...
' only change PrinterName when it is required, NOT each time the user
presses
' the button, setting a printername resets some of the settings
If (ComboBoxPrinterNames.SelectedIndex <> -1) Then
If (Me.PrintDocument.PrinterSettings.PrinterName <>
ComboBoxPrinterNames.Text) Then
Me.PrintDocument.PrinterSettings.PrinterName =
ComboBoxPrinterNames.Text
End If
If Me.PrintDocument.PrinterSettings.IsValid Then
Me.OpenPrinterPropertiesDialog(PrintDocument.Print erSettings)
Else
MsgBox("Invalid printersettings", MsgBoxStyle.Information)
End If
Else
MsgBox("Choose a printer", MsgBoxStyle.Information)
End If
End Sub

Sub OpenPrinterPropertiesDialog(ByVal Settings As PrinterSettings)
' PrinterSettings+PageSettings -> hDEVMODE
Dim hDevMode As IntPtr = _
Settings.GetHdevmode(Settings.DefaultPageSettings)

' Show Dialog ( [In,Out] pDEVMODE )
Dim pDevMode As IntPtr = GlobalLock(hDevMode)
DocumentProperties(Me.Handle, IntPtr.Zero, _
Settings.PrinterName, pDevMode, pDevMode, 14)
GlobalUnlock(hDevMode)

' hDEVMODE -> PrinterSettings+PageSettings
Settings.SetHdevmode(hDevMode)
Settings.DefaultPageSettings.SetHdevmode(hDevMode)

' cleanup
GlobalFree(hDevMode)
End Sub

End Class

HTH,
Greetings
Nov 21 '05 #2

P: n/a
Dear Bart,

Really THANK YOU VERY MUCH !!! for your contribution.

You also provide some additional advice. Let me study and try to
implement it.

This one is very important for my work. Infact the PrintDialog provided
with .NET is too primitive
to be useful in real programs, and once one rewrite one cannot escape
the task to manually call the printer setup.

I will work on it and will probably poput later with some question, in
case I have problems.

I am very grateful,

-Pamela

Nov 21 '05 #3

P: n/a
Dear Burt,

I have tried your code (on XP). Actually it is quite complete. You
have practically
done the all job. I also appreciated your correction about setting
the printer name.
You are really an angel!

I have not tried yet to print because now its night here and I am
not at my office,
but the printer properties dialog pops up fine. In case of problems
I will tell you.

If I may, I would need some further info for some refinements.
I am loading the printer names in a combo (or perhaps I will use a
treeview):
with something like:

-------------------------------------
Private Sub YourPrinterSettingsDialog_Load(ByVal sender...) Handles
MyBase.Load

Dim PrinterNames As New ArrayList
For Each PrinterName As String In
PrinterSettings.InstalledPrinters
Try
PrinterNames.Add(PrinterName)
Catch
End Try
Next PrinterName
Me.ComboBoxPrinterNames.Items.AddRange(PrinterName s.ToArray)

End Sub
------------------------------------

I need to recognize: 1. the Default Printer, 2. Network printers, to
change the appearance
of their icons. So, I guess, I need 2 boolean functions:

function IsDefaulPrinter(PrinterName as string) as boolean
function IsNetworkPrinter(PrinterName as string) as boolean
(others assumed local, I guess)

Do you know how to make these functions?
Any suggestion is very welcome. Thanks,

-Pamela

Nov 21 '05 #4

P: n/a
Hi,

<pa***********@libero.it> wrote in message
news:11**********************@g49g2000cwa.googlegr oups.com...
Dear Burt,

I have tried your code (on XP). Actually it is quite complete. You
have practically
done the all job. I also appreciated your correction about setting
the printer name.
You are really an angel!

I have not tried yet to print because now its night here and I am
not at my office,
but the printer properties dialog pops up fine. In case of problems
I will tell you.

If I may, I would need some further info for some refinements.
I am loading the printer names in a combo (or perhaps I will use a
treeview):
with something like:

-------------------------------------
Private Sub YourPrinterSettingsDialog_Load(ByVal sender...) Handles
MyBase.Load

Dim PrinterNames As New ArrayList
For Each PrinterName As String In
PrinterSettings.InstalledPrinters
Try
PrinterNames.Add(PrinterName)
Catch
End Try
Next PrinterName
Me.ComboBoxPrinterNames.Items.AddRange(PrinterName s.ToArray)

End Sub
------------------------------------

I need to recognize: 1. the Default Printer, 2. Network printers, to
change the appearance
of their icons. So, I guess, I need 2 boolean functions:

function IsDefaulPrinter(PrinterName as string) as boolean
function IsNetworkPrinter(PrinterName as string) as boolean
(others assumed local, I guess)
I understand you want to customize the PrintDialog, is there anything in
particular that you want to change or add, it is possible to create your
own, but it will involve a lot of pinvoke.

About default and network printers, it's not that simple, if you want to do
this for all printers then you need to think about speed. You can use the
native function EnumPrinters(see MSDN) but it gets complicated because a
different level is needed for wxp/2000 or w9x/me.

The example shows you how you can do it using 2 additional classes:
PrinterInfo (name, isdefault, isnetwork)
PrinterApi (thin wrapper around w32 native Printer Functions)

YourPrintDialog.vb
------------------
Public Class YourPrintDialog
' ....
Private Sub LoadPrinters()
ComboBoxPrinterNames.Clear()

For Each pi As PrinterInfo In PrinterInfo.InstalledPrinters
Console.WriteLine("Name={0} Def={1} Network={2}", _
pi.Name, pi.IsDefault, pi.IsNetwork)

ComboBoxPrinterNames.Items.Add(pi.Name)
If (pi.IsDefault) Then ComboBoxPrinterNames.Text = pi.Name
Next
End Sub
' ....
End Class
PrinterInfo.vb
--------------
Public Class PrinterInfo

Public Name As String
Public IsDefault As Boolean
Public IsNetwork As Boolean

Public Shared ReadOnly Property InstalledPrinters() As PrinterInfo()
Get
Dim infos As New ArrayList
If (Environment.OSVersion.Platform = PlatformID.Win32NT) Then
' window xp,2000
Dim DefName As String = PrinterApi.GetDefPrinter()

For Each pi4 As PrinterApi.PRINTER_INFO_4 In _
PrinterApi.EnumInfo4( _
PrinterApi.PRINTER_ENUM_LOCAL Or _
PrinterApi.PRINTER_ENUM_CONNECTIONS)

Dim pi As New PrinterInfo
pi.Name = pi4.PrinterName
pi.IsDefault = Equals(pi4.PrinterName, DefName)
pi.IsNetwork = (pi4.Attributes And
PrinterApi.PRINTER_ATTRIBUTE_NETWORK) > 0
infos.Add(pi)
Next
Else
' windows 95,98,me
For Each pi5 As PrinterApi.PRINTER_INFO_5 In _
PrinterApi.EnumInfo5(PrinterApi.PRINTER_ENUM_LOCAL )
Dim pi As New PrinterInfo
pi.Name = pi5.PrinterName
pi.IsDefault = (pi5.Attributes And
PrinterApi.PRINTER_ATTRIBUTE_DEFAULT) > 0
pi.IsNetwork = (pi5.Attributes And
PrinterApi.PRINTER_ATTRIBUTE_NETWORK) > 0
infos.Add(pi)
Next
End If
Return infos.ToArray(GetType(PrinterInfo))
End Get
End Property
End Class
PrinterApi.vb
--------------
Imports System.Runtime.InteropServices
Imports System.Text

Public Class PrinterApi

Private Declare Auto Function EnumPrinters Lib "winspool.drv" ( _
ByVal flags As Int32, ByVal name As String, ByVal level As Int32, _
ByVal pPrinterEnum As IntPtr, ByVal cbBuf As Int32, _
ByRef pcbNeeded As Int32, ByRef pcReturned As Int32) As Int32

Private Declare Auto Function GetDefaultPrinter Lib "winspool.drv" ( _
ByVal szBuffer As StringBuilder, _
ByRef cchBuffer As Int32) As Int32

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
Public Class PRINTER_INFO_4
Public PrinterName As String
Public ServerName As String
Public Attributes As Integer
End Class

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
Public Class PRINTER_INFO_5
Public PrinterName As String
Public PortName As String
Public Attributes As Integer
Public DeviceNotSelectedTimeout As Integer
Public TransmissionRetryTimeout As Integer
End Class

Public Const PRINTER_ATTRIBUTE_NETWORK As Int32 = &H10
Public Const PRINTER_ENUM_CONNECTIONS As Int32 = &H4
Public Const PRINTER_ENUM_LOCAL As Int32 = &H2
Public Const PRINTER_ATTRIBUTE_DEFAULT As Int32 = &H4

Public Shared Function GetDefPrinter() As String
Dim sbName As New StringBuilder(32)
GetDefaultPrinter( sbName, 32 )
return sbName.ToString()

End Function

Public Shared Function EnumInfo4(ByVal Flags As Int32) As PRINTER_INFO_4()
' level 4 enum
Return DirectCast( _
EnumInfo(4, Flags, GetType(PRINTER_INFO_4)), _
PRINTER_INFO_4())

End Function

Public Shared Function EnumInfo5(ByVal Flags As Int32) As PRINTER_INFO_5()
' level 5 enum
Return DirectCast( _
EnumInfo(5, Flags, GetType(PRINTER_INFO_5)), _
PRINTER_INFO_5())

End Function

Private Shared Function EnumInfo(ByVal Level As Int32, _
ByVal Flags As Int32, ByVal InfoType As Type) As Object()

Dim cbNeeded As Int32, cReturned As Int32
Dim pBuffer As IntPtr, pBuf As IntPtr
Dim pi As Object
Dim infos As New ArrayList

' enumerate printers
EnumPrinters(Flags, Nothing, Level, IntPtr.Zero, 0, cbNeeded, cReturned)
pBuffer = Marshal.AllocHGlobal(cbNeeded)

EnumPrinters(Flags, Nothing, Level, pBuffer, cbNeeded, cbNeeded,
cReturned)

pBuf = pBuffer
For i As Int32 = 0 To cReturned - 1
pi = Marshal.PtrToStructure(pBuf, InfoType)
infos.Add(pi)

pBuf = New IntPtr(pBuf.ToInt64() + Marshal.SizeOf(InfoType))
Next
Marshal.FreeHGlobal(pBuffer)
Return infos.ToArray(InfoType)

End Function
End Class

HTH,
Greetings


Do you know how to make these functions?
Any suggestion is very welcome. Thanks,

-Pamela

Nov 21 '05 #5

P: n/a
Dear Burt,

I don't now what to say.

I should probably take a flight and come to kiss you. Or send Microsoft
a petition to have you appointed MVP.
Thanks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

I * do have to * make my own PrintDialog. I have abolutely no choice
because the application is such that there is no way to use the one
provided with the language.

So the help you are so kindly and generously providing is very crucial
for me.

Let me digest all the material you have provided. I will be back later
with possible
questions.

A presto,

-Pamela

Nov 21 '05 #6

P: n/a
Dear Bart,

I have tried it on XP Professional with a unique default local printer.

It seems it fail to recognize the a default printer. This is the
result:

Name=Microsoft Office Document Image Writer Def=False Network=False

The function:
Public Shared Function GetDefPrinter() As String
returns an empty string.
GetDefaultPrinter is returning an empty stringbuilder.

In particular

Public Class PrinterInfo
.....

For Each pi4 As PrinterApi.PRINTER_INFO_4 In
PrinterApi.EnumInfo4(PrinterApi.PRINTER_ENUM_LOCAL Or
PrinterApi.PRINTER_ENUM_CONNECTIONS)
Dim pi As New PrinterInfo
pi.Name = pi4.PrinterName
pi.IsDefault = Equals(pi4.PrinterName, DefName)

'------------------------------------------------
when executed on XP with a unique, default, printer I have:

pi4.PrinterName = "Microsoft Office Document Image Writer"
DefName = ""

hence it does not recognize the default printer as such.
PrinterApi.GetDefPrinter is returning empty string

--------------------------------------------------

pi.IsNetwork = (pi4.Attributes And
PrinterApi.PRINTER_ATTRIBUTE_NETWORK) > 0
infos.Add(pi)
Next

This is strange it is like the native function GetDefaultPrinter it is
not doing its job (?)

-Pamela

Nov 21 '05 #7

P: n/a
Hi,

<pa***********@libero.it> wrote in message
news:11*********************@g47g2000cwa.googlegro ups.com...
Dear Bart,

I have tried it on XP Professional with a unique default local printer.

It seems it fail to recognize the a default printer. This is the
result:

Name=Microsoft Office Document Image Writer Def=False Network=False

The function:
Public Shared Function GetDefPrinter() As String
returns an empty string.
GetDefaultPrinter is returning an empty stringbuilder.
I think it is caused because the Name is longer then 32 characters (which is
currently the limit inside GetDefPrinter() but also in PRINTER_INFO_4/5), if
you can try it with a printer that has a shorter name, i will look how to
deal with this and get back to you later.

HTH,
Greetings

In particular

Public Class PrinterInfo
....

For Each pi4 As PrinterApi.PRINTER_INFO_4 In
PrinterApi.EnumInfo4(PrinterApi.PRINTER_ENUM_LOCAL Or
PrinterApi.PRINTER_ENUM_CONNECTIONS)
Dim pi As New PrinterInfo
pi.Name = pi4.PrinterName
pi.IsDefault = Equals(pi4.PrinterName, DefName)

'------------------------------------------------
when executed on XP with a unique, default, printer I have:

pi4.PrinterName = "Microsoft Office Document Image Writer"
DefName = ""

hence it does not recognize the default printer as such.
PrinterApi.GetDefPrinter is returning empty string

--------------------------------------------------

pi.IsNetwork = (pi4.Attributes And
PrinterApi.PRINTER_ATTRIBUTE_NETWORK) > 0
infos.Add(pi)
Next

This is strange it is like the native function GetDefaultPrinter it is
not doing its job (?)

-Pamela

Nov 21 '05 #8

P: n/a
Hi,

"Bart Mermuys" <bm*************@hotmail.com> wrote in message
news:eJ**************@TK2MSFTNGP12.phx.gbl...
Hi,

<pa***********@libero.it> wrote in message
news:11*********************@g47g2000cwa.googlegro ups.com...
Dear Bart,

I have tried it on XP Professional with a unique default local printer.

It seems it fail to recognize the a default printer. This is the
result:

Name=Microsoft Office Document Image Writer Def=False Network=False

The function:
Public Shared Function GetDefPrinter() As String
returns an empty string.
GetDefaultPrinter is returning an empty stringbuilder.
I think it is caused because the Name is longer then 32 characters (which
is currently the limit inside GetDefPrinter() but also in
PRINTER_INFO_4/5), if you can try it with a printer that has a shorter
name, i will look how to deal with this and get back to you later.


Oh, PRINTER_INFO4/5.PrinterName isn't limited to 32 character, so i
shouldn't have limited GetDefPrinter, my mistake.

Corrected code for GetDefPrinter inside PrinterApi:

Public Shared Function GetDefPrinter() As String
Dim len As Integer
Dim sbName As StringBuilder

GetDefaultPrinter(Nothing, len)
sbName = New StringBuilder(len)

GetDefaultPrinter(sbName, len)
Return sbName.ToString()
End Function

HTH,
Greetings


HTH,
Greetings

In particular

Public Class PrinterInfo
....

For Each pi4 As PrinterApi.PRINTER_INFO_4 In
PrinterApi.EnumInfo4(PrinterApi.PRINTER_ENUM_LOCAL Or
PrinterApi.PRINTER_ENUM_CONNECTIONS)
Dim pi As New PrinterInfo
pi.Name = pi4.PrinterName
pi.IsDefault = Equals(pi4.PrinterName, DefName)

'------------------------------------------------
when executed on XP with a unique, default, printer I have:

pi4.PrinterName = "Microsoft Office Document Image Writer"
DefName = ""

hence it does not recognize the default printer as such.
PrinterApi.GetDefPrinter is returning empty string

--------------------------------------------------

pi.IsNetwork = (pi4.Attributes And
PrinterApi.PRINTER_ATTRIBUTE_NETWORK) > 0
infos.Add(pi)
Next

This is strange it is like the native function GetDefaultPrinter it is
not doing its job (?)

-Pamela


Nov 21 '05 #9

P: n/a
Bart,

very good. Now it works. Tomorrow morning I will be able to do more
extensive testing on a networked environment. I will let you know the
result.

Congratulation for your knowledge. I envy you.

Where did you get all that know how? After one reads your code and the
gdi documentation everything seems even obvious, but if I should have
done it only reading the documentation, I would have probably struggled
for months to put things together. How can one become like you? :-)

-Pamela

Nov 21 '05 #10

P: n/a
Hi,

<pa***********@libero.it> wrote in message
news:11**********************@g14g2000cwa.googlegr oups.com...
Bart,

very good. Now it works. Tomorrow morning I will be able to do more
extensive testing on a networked environment. I will let you know the
result.
Hope it goes well.

Congratulation for your knowledge. I envy you.

Where did you get all that know how? After one reads your code and the
gdi documentation everything seems even obvious, but if I should have
done it only reading the documentation, I would have probably struggled
for months to put things together. How can one become like you? :-)
:-) Like all things the beginning is hard, but after a while things begin to
make more sense. I have done lots of pinvoke and it is a lot easier if you
have used api's in unmanaged code (like c/c++) before, you really need to
know about pointers and memory allocation. When you know enough about
pointers and the like then there is enough information inside .net framework
sdk doc to get you started with pinvoke, the rest you'll need to learn from
practice, examples or other sources.

Greetings

-Pamela

Nov 21 '05 #11

P: n/a
Dear Bart

I am going to go sleep. Just a few thoughs.
I am really fashinated by this kind of specific knowledge.

In my programs I have always tried to stick as much as possible
to the functionalities provided by the language, to avoid, using native
things,
that if Microsoft changes something than my program could no more work
or run into errors. So say mainly maintenance reason. On the other hand
its really exciting to put hands on that native stuff.

In this case I am forced to use them because strangey Microsoft does
not provided them in the framework. But at the same time I am afraid
that with maybe next version of windows my program would run into
errors.
Actually the class you made up PrinterInfo is very useful in general
and I don't
see why Microsoft does not include it (or something similar) in the
framework.

I am sure that a large number of programmers will have this basic need
to have control
on printing process, and your class is absolutely indispensable.

Looking at your code I have a couple of doubts. Can we rely this work
on any framework
and os (win 2003, ...)? Also about the function Equal. Is it safe to
use it or it would be more
prudent to use a case insensitive (and perhaps even trimmed) version,
just in case... ?

See you later,

-Pamela

Nov 21 '05 #12

This discussion thread is closed

Replies have been disabled for this discussion.