InstalledPrinters and Windows Server 2003 R2

M

Marc

I am using VB 2005 to get the printers that have been installed on a Windows
Server 2003 R2 box. I would like to write these printers into a table in SQL
Server. The problem is when I run the code using:
System.Drawing.Printing.PrinterSettings.InstalledPrinters and count and
item no printers are found. Printers are installed on the server and when I
run the same code on a Win XP box all installed printers are listed. Anyone
have any idea why the 2003 R2 box does not return the installed printers?
Any help would be greatly appreciated.
Marc
 
D

Duncan Jones

Hi

I found that InstalledPrinters had problems when one or more printers had
different permissions to the others
I had to fall back on the EnumPrinters API. Maybe make sure that the user
running the code has the same permissions on all the printers?

Hope this helps,
Duncan
 
M

Marc

Thanks for your help Duncan. I decided to try what you have suggested using
the EnumPrinters API but I am having problems getting this API to work on the
Server 2003 R2 box. It works fine on XP. When the following code gets to
the EnumPrinters line it just stops and does not return an error. Am I using
the wrong lib for 2003 R2?

Private Declare Function EnumPrinters Lib "winspool.drv" Alias
"EnumPrintersA" (ByVal flags As Integer, ByVal name As String, ByVal Level As
Integer, ByRef pPrinterEnum As Integer, ByVal cdBuf As Integer, ByRef
pcbNeeded As Integer, ByRef pcReturned As Integer) As Integer

Private Structure PRINTER_INFO_4
Dim pPrinterName As String
Dim pServerName As String
Dim Attributes As Integer
End Structure

Dim PrinterEnum() As PRINTER_INFO_4, FNLoop As Integer = 0,
PRINTER_ENUM_LOCAL = &H2, pPrinterEnum() As Integer, cdBuf As Integer =
10000, pcbNeeded As Integer, pcReturned As Integer, ReturnValue As Integer
ReDim pPrinterEnum(0 To cdBuf / 4)

ReturnValue = EnumPrinters(PRINTER_ENUM_LOCAL, "", 4, pPrinterEnum(0),
cdBuf, pcbNeeded, pcReturned)

Thanks,
Marc
 
D

Duncan Jones

I can't see anything wrong with what you have there - however just in case
it is of use, my code is as follows:-

#Region "EnumPrinters"
<DllImport("winspool.drv", EntryPoint:="EnumPrinters", _
SetLastError:=True, CharSet:=CharSet.Auto, _
ExactSpelling:=False, _
CallingConvention:=CallingConvention.StdCall)> _
Public Function EnumPrinters(<InAttribute()> ByVal Flags As
EnumPrinterFlags, _
<InAttribute()> ByVal Name As String, _
<InAttribute()> ByVal Level As Int32, _
<OutAttribute()> ByVal lpBuf As IntPtr, _
<InAttribute()> ByVal cbBuf As Int32, _
<OutAttribute()> ByRef pcbNeeded As Int32,
_
<OutAttribute()> ByRef pcbReturned As
Int32) As Boolean

End Function

<DllImport("winspool.drv", EntryPoint:="EnumPrinters", _
SetLastError:=True, CharSet:=CharSet.Auto, _
ExactSpelling:=False, _
CallingConvention:=CallingConvention.StdCall)> _
Public Function EnumPrinters(<InAttribute()> ByVal Flags As
EnumPrinterFlags, _
<InAttribute()> ByVal Name As IntPtr, _
<InAttribute()> ByVal Level As Int32, _
<OutAttribute()> ByVal lpBuf As IntPtr, _
<InAttribute()> ByVal cbBuf As Int32, _
<OutAttribute()> ByRef pcbNeeded As Int32, _
<OutAttribute()> ByRef pcbReturned As Int32) As
Boolean

End Function

#End Region

and is used thus:-
Public Sub New()
Dim pcbNeeded As Int32 '\\ Holds the requires size of the output
buffer (in bytes)
Dim pcReturned As Int32 '\\ Holds the returned size of the output
buffer
Dim pPrinters As IntPtr
Dim pcbProvided As Int32 = 0

If Not EnumPrinters(EnumPrinterFlags.PRINTER_ENUM_NAME,
String.Empty, 1, pPrinters, 0, pcbNeeded, pcReturned) Then
If pcbNeeded > 0 Then
pPrinters = Marshal.AllocHGlobal(pcbNeeded)
pcbProvided = pcbNeeded
If Not EnumPrinters(EnumPrinterFlags.PRINTER_ENUM_NAME,
String.Empty, 1, pPrinters, pcbProvided, pcbNeeded, pcReturned) Then
Throw New Win32Exception
End If
End If
End If

If pcReturned > 0 Then
'\\ Get all the monitors for the given server
Dim ptNext As IntPtr = pPrinters
While pcReturned > 0
Dim pi1 As New PRINTER_INFO_1
Marshal.PtrToStructure(ptNext, pi1)
If Not pi1.pName Is Nothing Then
Me.Add(New PrinterInformation(pi1.pName,
PrinterAccessRights.PRINTER_ACCESS_USE, False)) ', pi2.pLocation,
pi2.pComment, pi2.pServerName, 1))
End If
ptNext = New IntPtr(ptNext.ToInt32 +
Marshal.SizeOf(GetType(PRINTER_INFO_1)))
pcReturned -= 1
End While
End If

'\\ Free the allocated buffer memory
If pPrinters.ToInt32 > 0 Then
Marshal.FreeHGlobal(pPrinters)
End If

End Sub

(The full code is in CodePlex : http://www.codeplex.com/PrintQueueWatch in
case I have missed anything in this cut-and-paste)

Hope this helps,
Duncan
 

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