Programming with the DWF Express Viewer Control, Part 214 Mar, 2005 By: Mike Tuersley Cadalyst
Now that you've created all those multipage DWF files, let's discuss how to print them
So, if you read last month's column, have you tried experimenting with the DWF Express Viewer control? If so, have you figured out how to print the DWF file once you have it opened?
If you have been playing around, I'm sure you figured out that you could print the DWF file by issuing the command:
Private Sub cmdPan_Click() dwfViewer.ExecuteCommand ("PLOT") End Sub
And, you've been able to get the EV plot dialog box to pop up and print the file:
Figure 1. Using the Express Viewer plot dialog box, you can print a DWF file.
I, personally, have no problems with the Express Viewer dialog box. It is, however, quite daunting for some -- or so I've heard from my clients. Whether that's true or not, I'll leave to your discretion. What is true is that plenty of clients just want a print button that sends the printout to the right printer, at the right size, and so forth. Given this request, the dialog box is definitely a hindrance unless you're dying to practice your SendKeys programming, because that is the only way to automate your way past it. There has to be a better way!
Luckily, there are two backdoor methods to automate printing the DWF file loaded into the EV control. You can use either the SimplePrint or PrintEx method. Let's look at each one.
The simplest method of printing the loaded DWF file is obviously the SimplePrint method. (Was that a little redundant for you?) SimplePrint requires only two parameters:
|bFullPage As Boolean||True = full page; False = current view|
|bWhiteBackground As Boolean||True = white; False = black*|
|*Assuming the background is white; flip-flop results if background is black.|
From there, I can plug this code into my button click event for Simple Printing:
Private Sub cmdSimplePrint_Click() Dim dwfFile As IAdEPlotDocument dwfViewer.SimplePrint True, True End Sub
Remembering that in the example project last month, dwfViewer was a global variable declared as type IAdPageViewer2. Really easy, wasn't it?
Well, there's one problem: To which printer and paper size is this going to print? Answer: To whichever defaults are currently set for the end user. That may work for 10% of you, but not for the majority. In automating the "one-print solution," most of you would want the proper printer/paper size combination to be selected. So how do we do that?
Setting the Printer/Paper Size for SimplePrint Printing
Depending on your development environment, this can be fairly easy to accomplish. If you are using VB6, then access the Printer object and set the options you want. If you are using a Microsoft .NET environment, you can access the PrintDocument object. There are plenty of examples available on the Internet for accomplishing the printer tasks in these environments, so I am not going to delve into them.
If you are using VBA, boy, are you stuck!
In VBA, there is no access to the Windows printing environment. Yes, you can access AutoCAD's printing, but remember that this DWF file is loaded into the EV control on our form and AutoCAD can't open a DWF file.
Over the years, I have looked into all the Windows API programming methods available to try to control Windows printing. Somewhere along the way, I decided it would be faster and easier to create a VB6 ActiveX DLL that wrapped the VB6's Printer object for VBA to use. You can find this in the sample code's ZIP file for this month. To use it, please refer to the README.TXT file included.
So now that you have my DLL installed, here's how you can totally automate the SimplePrint code:
Private Sub cmdSimplePrint_Click() Dim oPrinter as vbaPrinter Dim dwfFile As IAdEPlotDocument oPrinter.SetDefault "HP DesignJet 755" oprinter.SetPaperSize "ANSI B: 9 x 12 in." dwfViewer.SimplePrint True, True End Sub
Now, the default Windows printer will be my HP DesignJet 755 with the ANSI B paper size. This is abbreviated as there is a method in my DLL to get all the supported media sizes for a given printer so you don't have to type in the full name of the paper size you want to use.
Concluding the SimplePrint method is easy and fast. With the addition of my DLL, the only reason to use PrintEx in VBA is if you want to scale the DWF print larger or smaller. If you are using VB6, PrintEx handles a lot of the printer settings for you. If you are using a .NET language, you're in the VBA-SimplePrint group -- more on that later!
The PrintEx command requires a few more parameters than the SimplePrint method:
|nDc As Long||handle to the printer's device context|
|rLeft As Double||value for the left of the image to print|
|rBottom As Double||value for the bottom of the image to print|
|rRight As Double||value for the right of the image to print|
|rTop As Double||value for the top of the image to print|
|valign=top bWhiteBackground as Boolean||whether to print with a white background or not|
Without getting too deep into this method, the values for the box simply define the "window" to print and the WhiteBackground setting should be self-explanatory. The oddball in this group is the nDC parameter for the target printer's device context. The device context is roughly the memory address for the printer so that the DWF image can be sent to it for processing.
The drawback to providing the DC in VBA is actually accessing it because, as I hope you've learned by now, VBA doesn't have direct access to the Windows printing environment. Luckily for you, my DLL also returns the device context. Those VB6ers reading this can easily access the Printer object and return its hDC property. For either programming group, it is also relatively easy to do through the Windows API:
Private Declare Function OpenPrinter Lib "winspool.drv" _ Alias "OpenPrinterA" (ByVal pPrinterName As String, phPrinter As Long, pDefault As Any) As Long Private Declare Function ClosePrinter Lib "winspool.drv" _ (ByVal hPrinter As Long) As Long Public Function getPrinterDC(sPrinterName As String) As Long Dim hPrinter As Long 'establish connection with the printer to retrieve 'its device content handle OpenPrinter sPrinterName, hPrinter, ByVal 0& 'hPrinter is set so close the printer connection ClosePrinter hPrinter getPrinterDC = hPrinter End Function
In the code above, using the API call OpenPrinter to establish a connection to the printer supplies the device context to the variable parameter hPrinter. Then ClosePrinter is called to close the connection to the printer.
If you are using a .NET language, however, there is no way to retrieve the device context of the printer thanks to Microsoft's revamping of the printer API. Don't get me wrong, the printer API was the worst of the bunch and the .NET approach is far better once you are used to it. Unfortunately, there are still a lot of VB6 COM-based controls out there that require the old approach. I know of three options for retrieving the device context:
- Try to use the VB6 code above with the VB Compatibility assembly, which works most of the time.
- Learn C++ and generate your own interface wrapper.
- Download PrintUtil from the Autodesk newsgroups. One of Autodesk's programmers wrote this utility to overcome this obstacle and it's freely available to use. Note that this is not supported.
Public Sub PrintEXAPI() 'Set desired Printer Dim lHDC As Long lHDC = ReturnPrinterHDC("Apollo P2200") 'Print With dwfViewer .ExecuteCommand ("FITTOWINDOW") .PrintEx lHDC, dwfViewer.Page.View.Left, _ dwfViewer.Page.View.bottom, _ dwfViewer.Page.View.Right, _ dwfViewer.Page.View.top, True End With End Sub
To use the PrintEX method with a multi-page DWF, simply iterate through the pages. See the accompanying sample project for an example.
Kick It Up A Notch!
Well, there's not much more I can write about the DWF Viewer Control from inside a desktop application. There are more things possible if you have access to Autodesk's DWF Composer and more and more methods/properties are available with each new release. Please keep up to speed with these releases by visiting the Autodesk Web site periodically and checking. If you come across any programming issues when trying to manipulate DWF files, look to the Autodesk Discussion groups Customization.VBA and DWF for help.
In next month's issue, I'll look at using the control inside a web page. Until then, have a great time playing with DWFs!