Have you ever needed to change the default printer from an application? VB.Net lets you change the PrinterName property of the PrinterSettings class without a problem but you will very soon discover that the scope of this modification is limited to the current application only! What if you need to change the default printer as it appears into the Printer and Faxes panel? Read on, you’ll finally find how here!
What inspires me today to write this column is a very recent problem I had at a client site. I have an application written in VB.Net running each morning for over a year that retrieves reports in rtf format from providers and prints them locally. All this runs on the client’s server and was printed on a printer attached to this server. One morning that the job status sent to me by e-mail was indicating that everything went well, the client phoned me asking where her reports where! I first thought she was joking. Then I thought that somebody else had grabbed the reports on the printer for her. We checked the printers’ settings to discover that the default printer was set to “Fax” and that all my reports were queued there! So I have set the default printer back to the HP Laserjet. The next day, she called again. Same story! After some research, I found that each time I was connecting using Terminal Services, the printers’ settings was changing. That was a test made by the sysadmin testing some Terminal Services settings.
Discovering printers
The first class you need to know in the .Net framework when you need to handle printers is the PrinterSettings class from the System.Drawing.Printing namespace.
Typically, you access a PrinterSettings through PrintDocument.PrinterSettings or PageSettings.PrinterSettings properties to modify printer settings. The most common printer setting is PrinterName, which specifies the printer to print to.
This first code snippet lists all available printers to a listbox control (the same devices you see when you open the “Printers and Faxes” panel). This method ends by selecting the current default printer simply by using the PrinterName property from the DefaultPageSettings class.
Private Sub ListAvailablePrinters() For Each strPrinterName As String In PrinterSettings.InstalledPrinters ListBox1.Items.Add(strPrinterName) Next 'Find the Default printer Dim PD As New PrintDocument ListBox1.SelectedItem = PD.DefaultPageSettings.PrinterSettings.PrinterName End Sub
Setting the default printer for the current application
In some circumstances, you will only want to set a printer of particular settings (like paper orientation) for the current application without changing the default values in Windows. To do that, you create an instance of the PrintDocument class, set the properties that describe how to print, and call the Print method to start the printing process.
This is what this code snippet is doing (set a printer and the orientation to landscape):
Dim pd As New PrintDocument AddHandler pd.PrintPage, AddressOf pd_PrintPage ' Specify the printer to use pd.PrinterSettings.PrinterName = ListBox1.SelectedItem ' Set the page orientation to landscape. pd.DefaultPageSettings.Landscape = True pd.Print()
Setting the default printer like this does not affect the default printer in Windows. Only documents printed using the PrintDocument class are affected. That method didn’t help me in my story (in which I had a couple a rtf files, some Crystal Reports, and a couple of htm files).
Setting the default printer for Windows
Because the previous method didn’t fix my problem, I have “Googled” to find 3 methods of setting the default printer in Windows from my application. Sadly, none of these 3 methods is 100% pure managed code.
The first method uses Wscript.Network. The second method uses System.Management and InvokeMethod. The third method uses the WriteProfileString API call.
The downloadable demo contains the 3 methods but here, I will only show one method here.
Dim strOldPrinter As String Dim WshNetwork As Object Dim pd As New PrintDocument Try strOldPrinter = pd.PrinterSettings.PrinterName WshNetwork = Microsoft.VisualBasic.CreateObject("WScript.Network") WshNetwork.SetDefaultPrinter(strPrinterName) pd.PrinterSettings.PrinterName = strPrinterName If pd.PrinterSettings.IsValid Then Return True Else WshNetwork.SetDefaultPrinter(strOldPrinter) Return False End If Catch exptd As Exception WshNetwork.SetDefaultPrinter(strOldPrinter) Return False Finally WshNetwork = Nothing pd = Nothing End Try
Figure 1: The test application
Conclusion
Sometime we cannot rely on .Net alone to fulfill our requirements. This does not mean that the task cannot be done. It simply means that we have to dig deeper and use the methods we used long time ago!
Do you care about the sysadmin from the introduction story? Don’t worry form him. He is still one of my friends! He just made my application more robust and gave me a subject to write about.
I hope you appreciated the topic and see you next month.