Migrating from VB6 and Printer object

J

J.B. Moreno

Hello,

I'm migrating a program from VB6 that uses the Printer object to get
the name, driver and port of a printer and then passes it along to a
Crystal 8.0 viewer (this allows printing to non-default printers).

But I can't figure out how to get the port (a string like "ne04:").

The VB6 code looks like:

Dim PrinterLoop As Printer

For Each PrinterLoop In Printers

If PrinterLoop.DeviceName = "namefromconfigfile" Then
crv.PrinterName = PrinterLoop.DeviceName
crv.PrinterPort = PrinterLoop.Port
crv.PrinterDriver = PrinterLoop.DriverName
End If

Next

If I hard code the values from VB6 into VB.Net, the Crystal works as
expected. But while the printname and drivername are easy to obtain. I
have no idea where to find the port, and I really don't want to the
port to the config file, particularly since I don't know how it's
determined.

I tried win32_print and WMI, but that didn't have it. Anyone know the
answer? Or even a good suggestion?
 
D

Dick Grier

Hi,

I "think" that you should be able to use WMI (System.Management). For
example, take this fragment:

Dim pReturn As Management.ManagementObjectCollection

Dim pSearch As Management.ManagementObjectSearcher

Dim pObject As Management.ManagementObject

Dim sStatus As String = ""

pSearch = New Management.ManagementObjectSearcher("Select *from
Win32_PnPEntity")

pReturn = pSearch.Get

Try

For Each pObject In pReturn

'look for a specific device name

Debug.Print(pObject("Name").ToString)



Next

See if it lists the printer you are looking for.

Dick
--
Richard Grier, MVP
Hard & Software
Author of Visual Basic Programmer's Guide to Serial Communications, Fourth
Edition,
ISBN 1-890422-28-2 (391 pages, includes CD-ROM). July 2004, Revised March
2006.
See www.hardandsoftware.net for details and contact information.
 
J

J.B. Moreno

Dick Grier said:
Hi,

I "think" that you should be able to use WMI (System.Management). For
example, take this fragment: -snip-
pSearch = New Management.ManagementObjectSearcher("Select * from Win32_PnPEntity") -snip-
See if it lists the printer you are looking for.

It doesn't list any of the printers (they are all network printers).

I'm not adverse to WMI (I'd already tried it, and failed, but it's
certainly possible, even likely< that is due to my ignorance).

(Crossposting this to microsoft.public.win32.programmer.wmi, so recap:
I'm looking for the printer port such as "ne04" of a specific printer,
to be accessed from within a .net application).
 
U

urkec

J.B. Moreno said:
It doesn't list any of the printers (they are all network printers).


Win32_Printer class has a property named PortName. I can't test this for
network printers right now, but for local printers it seems to return the
right printer port values.
 
J

J.B. Moreno

urkec said:
Win32_Printer class has a property named PortName. I can't test this for
network printers right now, but for local printers it seems to return the
right printer port values.

Win32_Printer was what I used for my first attempt. The PortName
property gives me the printer name, not the "ne04:" that the VB6
printer object gives.

I tried using it, hoping that it would work anyway, but it doesn't work
(Crystal still prints to the default printer).
 
U

urkec

J.B. Moreno said:
Win32_Printer was what I used for my first attempt. The PortName
property gives me the printer name, not the "ne04:" that the VB6
printer object gives.

I couldn't replicate this. I tested Win32_Printer with network printers and
PortName contained port name, not printer name. Can you test your code on a
machine with a local printer?
 
J

J.B. Moreno

J.B. Moreno said:
Hello,

I'm migrating a program from VB6 that uses the Printer object to get
the name, driver and port of a printer and then passes it along to a
Crystal 8.0 viewer (this allows printing to non-default printers).

But I can't figure out how to get the port (a string like "ne04:").

The VB6 code looks like:

Dim PrinterLoop As Printer

For Each PrinterLoop In Printers

If PrinterLoop.DeviceName = "namefromconfigfile" Then
crv.PrinterName = PrinterLoop.DeviceName
crv.PrinterPort = PrinterLoop.Port
crv.PrinterDriver = PrinterLoop.DriverName
End If

Next -snip-
I tried win32_print and WMI, but that didn't have it. Anyone know the
answer? Or even a good suggestion?

Possibly not the most perfect solution, but I found it in the
Registry...

[HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Devices]

This has an entry with the printer name and driver port as
"driver,port". I'll have to split that out, but that's no big deal.
I'd have been more comfortable with something that didn't require
stepping outside of the framework, but if that's what it takes...
 
D

Duncan Jones

You can use the GetPrinter API call to get all the information (such as Port
name) - e.g.
(Code snippet extracted from http://www.codeplex.com/PUMA in case I miss any
references or declarations)

'- -
8< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
<DllImport("winspool.drv", EntryPoint:="OpenPrinter", _
SetLastError:=True, CharSet:=CharSet.Ansi, _
ExactSpelling:=False, _
CallingConvention:=CallingConvention.StdCall)> _
Public Function OpenPrinter(<InAttribute()> ByVal pPrinterName As String, _
<OutAttribute()> ByRef phPrinter As Int32, _
<InAttribute(),
MarshalAs(UnmanagedType.LPStruct)> ByVal pDefault As PRINTER_DEFAULTS _
) As Boolean

End Function

<DllImport("winspool.drv", EntryPoint:="GetPrinter", _
SetLastError:=True, CharSet:=CharSet.Ansi, _
ExactSpelling:=False, _
CallingConvention:=CallingConvention.StdCall)> _
Public Function GetPrinter _
(<InAttribute()> ByVal hPrinter As IntPtr, _
<InAttribute()> ByVal Level As Int32, _
<OutAttribute()> ByVal lpPrinter As IntPtr, _
<InAttribute()> ByVal cbBuf As Int32, _
<OutAttribute()> ByRef lpbSizeNeeded As Int32) As Boolean

End Function

#Region "PRINTER_INFO_2 STRUCTURE"
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi),
System.Security.SuppressUnmanagedCodeSecurity()> _
Friend Class PRINTER_INFO_2
<MarshalAs(UnmanagedType.LPStr)> Public pServerName As String
<MarshalAs(UnmanagedType.LPStr)> Public pPrinterName As String
<MarshalAs(UnmanagedType.LPStr)> Public pShareName As String
<MarshalAs(UnmanagedType.LPStr)> Public pPortName As String
<MarshalAs(UnmanagedType.LPStr)> Public pDriverName As String
<MarshalAs(UnmanagedType.LPStr)> Public pComment As String
<MarshalAs(UnmanagedType.LPStr)> Public pLocation As String
<MarshalAs(UnmanagedType.U4)> Public lpDeviceMode As Int32
<MarshalAs(UnmanagedType.LPStr)> Public pSeperatorFilename As String
<MarshalAs(UnmanagedType.LPStr)> Public pPrintProcessor As String
<MarshalAs(UnmanagedType.LPStr)> Public pDataType As String
<MarshalAs(UnmanagedType.LPStr)> Public pParameters As String
<MarshalAs(UnmanagedType.U4)> Public lpSecurityDescriptor As Int32
Public Attributes As Int32
Public Priority As Int32
Public DefaultPriority As Int32
Public StartTime As Int32
Public UntilTime As Int32
Public Status As Int32
Public JobCount As Int32
Public AveragePPM As Int32

#Region "Private member variables"
Dim dmOut As New DEVMODE
#End Region

#Region "Public constructors"
Public Sub New(ByVal hPrinter As IntPtr)

Dim BytesWritten As Int32 = 0
Dim ptBuf As IntPtr

ptBuf = Marshal.AllocHGlobal(1)

If Not GetPrinter(hPrinter, 2, ptBuf, 1, BytesWritten) Then
If BytesWritten > 0 Then
'\\ Free the buffer allocated
Marshal.FreeHGlobal(ptBuf)
ptBuf = Marshal.AllocHGlobal(BytesWritten)
If GetPrinter(hPrinter, 2, ptBuf, BytesWritten,
BytesWritten) Then
Marshal.PtrToStructure(ptBuf, Me)
'\\ Fill any missing members
If pServerName Is Nothing Then
pServerName = ""
End If
'\\ If the devicemode is available, get it
If lpDeviceMode > 0 Then
Dim ptrDevMode As New IntPtr(lpDeviceMode)
Marshal.PtrToStructure(ptrDevMode, dmOut)
End If
End If
'\\ Free this buffer again
Marshal.FreeHGlobal(ptBuf)
Else
End If
End If

End Sub

Public ReadOnly Property DeviceMode() As DEVMODE
Get
Return dmOut
End Get
End Property

Public Sub New()

End Sub
#End Region

End Class

#End Region

''' -----------------------------------------------------------------------------
''' Project : PrinterQueueWatch
''' Class : PrinterInformation
'''
''' -----------------------------------------------------------------------------
''' <summary>
''' Class which holds the settings for a printer
''' </summary>
''' <remarks>
''' These settings can apply to physical printers and also to virtual print
devices
''' </remarks>
''' <history>
''' [Duncan] 20/11/2005 Created
''' </history>
''' -----------------------------------------------------------------------------
<System.Security.SuppressUnmanagedCodeSecurity()> _
<System.Runtime.InteropServices.ComVisible(False)> _
Public Class PrinterInformation
Implements IDisposable

Private mhPrinter As IntPtr

'\\ PRINTER_INFO_ structures
Private mPrinter_Info_2 As New PRINTER_INFO_2

#Region "PortName"
''' -----------------------------------------------------------------------------
''' <summary>
''' The name of the port the printer is connected to
''' </summary>
''' <value></value>
''' <remarks>
''' </remarks>
''' <example>Prints the name of the port that the named printer is
installed on
''' <code>
''' Dim pi As New PrinterInformation("Microsoft Office Document Image
Writer",
SpoolerApiConstantEnumerations.PrinterAccessRights.PRINTER_ALL_ACCESS, True)
''' Trace.WriteLine(pi.PortName)
''' </code>
''' </example>
''' <history>
''' [Duncan] 20/11/2005 Created
''' </history>
''' -----------------------------------------------------------------------------
<Diagnostics.MonitoringDescription("The name of the port the printer is
connected to")> _
Public Overridable ReadOnly Property PortName() As String
Get
RefreshPrinterInformation(PrinterInfoLevels.PrinterInfoLevel2)
If mPrinter_Info_2.pPortName Is Nothing Then
Return ""
Else
Return mPrinter_Info_2.pPortName
End If
End Get
End Property
#End Region

''' -----------------------------------------------------------------------------
''' <summary>
''' Creates a new printer information class for the named printer
''' </summary>
''' <param name="DeviceName">The name of the print device</param>
''' <param name="DesiredAccess">The required access rights for that
printer</param>
''' <param name="GetSecurityInfo"></param>
''' <param name="GetJobs">True to return the collection of print jobs
''' queued against this print device
''' </param>
''' <remarks>
'''
''' </remarks>
''' <history>
''' [Duncan] 20/11/2005 Created
''' </history>
''' -----------------------------------------------------------------------------
Public Sub New(ByVal DeviceName As String, ByVal DesiredAccess As
SpoolerApiConstantEnumerations.PrinterAccessRights, ByVal GetSecurityInfo As
Boolean, ByVal GetJobs As Boolean)
Dim hPrinter As Integer = 0
If OpenPrinter(DeviceName, hPrinter, New
PRINTER_DEFAULTS(DesiredAccess)) Then
mhPrinter = New IntPtr(hPrinter)
mPrinter_Info_2 = New PRINTER_INFO_2(mhPrinter)
Else
Throw New Win32Exception
End If
End Sub

'- -
8< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -

Hope this helps,
Duncan Jones
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top