Monday, January 28, 2008

Excel VBA printing and NE numbers

Anyone who has dealt with printing in VBA for Excel knows the plight of the NE00-NE99 ports/numbers that need to be appended to the printer name when passing it into the Application.ActivePrinter.

There are many ways to do this. I have found little bits and pieces here and there on the web and have come up with numerous ways of doing it myself. So I hope to guide you through the easier ways to do this as there seems to be little on the web about working around this problem.

The key:

HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\PrinterPorts

holds the values of the printers and NE port numbers. You could use these registry entries to figure out the NE port number for your printer. It requires some knowledge of using vba to access the registry for reading and using string functions to make a match.

I have also seem some people loop through all the NE numbers....from 00 to 99 to print out. It is possible but I think bad programming and I just don't like it.

The easiest way I've found is using the windows API via VBA.

How it works....

1. You need to declare the API function as below,

Private Declare Function SetDefaultPrinter Lib "winspool.drv" Alias "SetDefaultPrinterA"(ByVal pszPrinter As String) As Long

Note: Don't try to be smart and change the function name or alias or whatever just copy the lines...seriously it won't work if you mess with it.

2. Call the Function: SetDefaultPrinter strPrinter where strPrinter is the name of the print queue..if local the PrinterName and if located on a print server then \\server\queue_name

3. Print Something like the selected sheets or whatever floats your boat.

ActiveWindow.SelectedSheets.PrintOut Copies:=1, Collate:=True

So now you are asking well but now my default printer changed even though it printer correctly...I can't live without my default printer...So here is what I implemented for my specific situation and should get you moving in the right direction. This was a module in Excel and I called it from Workbook_Open by using:

Call PrintModule.Print_Selected_Sheets("C:\Printer.txt")

where PrintModule is the name of my Module if you are creating a new module and copying/pasting the code your module will be Module1 most likely if it is a new workbook.

Also the way this code works is it prints the Selected Sheets so I added the following line prior to calling my PrintModule function.

Sheets(Array("Sheet1","Sheet2")).Select

You could obviously edit Sheet1 and Sheet2 with the sheets you want to print out. You could specify only Sheet1 or add more Sheets to print out....

Please post comments and I will do my best to reply. If you think there is a much better way then please post. I have seen lots of dead end posts with no real answer in my searches so hopefully this one will help out at least a few people. Also I apologize for the formatting as this is my first attempt at using Blogger.

3 comments:

Simon Superstar said...

Thanks for your post, it really helped me resolve an issue I have had for quite some time.

Dave said...

I received the following as a comment from Benno. I only glanced at the code and am posting it but would like to point out it works only for one printer not a list of them from file as in my post. I think the registry parsing makes it a little less readable but not to anyone that will likely need to be editing macros. Not sure I understand the line "If Workbooks.Count <= 1 Then" , this will fail if there is only one workbook open not sure why you would want it to fail, it is likely that only one workbook will be open. Also, this check becomes fairly useless as the macro needs to run from within a workbook so there will always be a workbook available for printing. This might meet your needs in simple instances but lacks support for multiple printers. It does however show you another way to get NE numbers. You will also need to use something like
Sheets(Array("Sheet1","Sheet2")).Select
to select sheets that you want to print otherwise the below will only print the active sheet.
-----------------------------------
Function GetNewPrinter(Printer As String) As String
'
' Get EXCEL printer name from windows printer name
' Input: printer name like "HP Laserjet"
' Output: printer name like "HP Laserjet at Ne02:"
'
Dim ws As Object
On Error GoTo ErrHandler

Set ws = CreateObject("WScript.Shell")
np = ws.RegRead("HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Devices\" & Printer)
If Len(np) >= 5 Then GetNewPrinter = Printer & " auf " & Right(np, 5) Else GetNewPrinter = ""
Exit Function

ErrHandler:
GetNewPrinter = ""
End Function

Sub PrintMacro_HP()
'
' Changes standard printer to specific device and resets after printing
'
If Workbooks.Count <= 1 Then
Res = MsgBox("No document for printing available.", vbOKOnly)
Else
NewPrinter = GetNewPrinter("HP Laserjet") ' or any other installed printer
If NewPrinter = "" Then
Res = MsgBox("Printer is not defined.", vbOKOnly)
Exit Sub
End If
OldPrinter = Application.ActivePrinter
Application.ActivePrinter = NewPrinter
ActiveWindow.SelectedSheets.PrintOut Copies:=1, ActivePrinter:=NewPrinter, Collate:=True
Application.ActivePrinter = OldPrinter
End If
End Sub
-----------------------------------

Benno said...

Hi Dave,

the reason for "If Workbooks.Count <= 1 Then" is:
I put the macro in the PERSONL.XLS for general use. So workbook number 1 is always PERSONL.XLS and the second (if any) is my "normal" sheet.

The general reason for not using switching the default system printer to "my" printer and back after printing was:
Some printer drivers like "Adobe PDF" and "PDFCreator" fail sometimes during this procedure.
So I use the "EXCEL switching" without any problems.

Regards

Benno