I have been trying to change printer settings thru SetPrinter API and it
works successfully for local printers, but with network printers i don't get
neither an error message or anything else.
Here is my code.
'Class DevMode
' Used to get data from PrintDialog thru a pointer using Marshal .NET
functionality.
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
Friend Class DevMode
<VBFixedString(32), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)>
Public dmDeviceName As String
Public dmSpecVersion As Short
Public dmDriverVersion As Short
Public dmSize As Short
Public dmDriverExtra As Short
Public dmFields As Integer
Public dmOrientation As Short
Public dmPaperSize As Short
Public dmPaperLength As Short
Public dmPaperWidth As Short
Public dmScale As Short
Public dmCopies As Short
Public dmDefaultSource As Short
Public dmPrintQuality As Short
Public dmColor As Short
Public dmDuplex As Short
Public dmYResolution As Short
Public dmTTOption As Short
Public dmCollate As Short
<VBFixedString(32), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)>
Public dmFormName As String
Public dmUnusedPadding As Short
Public dmBitsPerPel As Short
Public dmPelsWidth As Integer
Public dmPelsHeight As Integer
Public dmDisplayFlags As Integer
Public dmDisplayFrequency As Integer
End Class
<Serializable(), StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)>
_
Friend Structure PRINTER_INFO_2
Public pServerName As String
Public pPrinterName As String
Public pShareName As String
Public pPortName As String
Public pDriverName As String
Public pComment As String
Public pLocation As String
Public pDevMode As IntPtr
Public pSepFile As String
Public pPrintProcessor As String
Public pDatatype As String
Public pParameters As String
Public pSecurityDescriptor As IntPtr
Public Attributes As System.UInt32
Public Priority As System.UInt32
Public DefaultPriority As System.UInt32
Public StartTime As System.UInt32
Public UntilTime As System.UInt32
Public Status As System.UInt32
Public cJobs As System.UInt32
Public AveragePPM As System.UInt32
End Structure
<StructLayout(LayoutKind.Sequential)> _
Private Structure PRINTER_DEFAULTS
Public pDatatype As IntPtr
Public pDevMode As IntPtr
Public DesiredAccess As Integer
End Structure
Private Enum PrinterAccessRights
PRINTER_ACCESS_ADMINISTER = &H4
PRINTER_ACCESS_USE = &H8
PRINTER_ALL_ACCESS = &HF000C
End Enum
'* DEVMODE collation selections
Private Const DMCOLLATE_FALSE As Short = 0
Private Const DMCOLLATE_TRUE As Short = 1
<DllImport("winspool.drv", EntryPoint:="OpenPrinterW", _
CharSet:=CharSet.Auto, SetLastError:=True, ExactSpelling:=True, _
CallingConvention:=CallingConvention.StdCall)> _
Private Shared Function OpenPrinter( _
ByVal pPrinterName As String, ByRef hPrinter As IntPtr, _
ByVal pDefault As IntPtr) As Boolean
End Function
<DllImport("winspool.drv", EntryPoint:="OpenPrinterW", _
CharSet:=CharSet.Auto, SetLastError:=True, ExactSpelling:=True, _
CallingConvention:=CallingConvention.StdCall)> _
Private Shared Function OpenPrinter( _
ByVal pPrinterName As String, ByRef hPrinter As IntPtr, _
ByRef pDefault As PRINTER_DEFAULTS) As Boolean
End Function
<DllImport("winspool.drv", CharSet:=CharSet.Auto, _
SetLastError:=True, ExactSpelling:=True, _
CallingConvention:=CallingConvention.StdCall)> _
Private Shared Function ClosePrinter( _
ByVal hPrinter As IntPtr) As Boolean
End Function
<DllImport("winspool.drv", EntryPoint:="GetPrinterW", _
CharSet:=CharSet.Auto, SetLastError:=True, ExactSpelling:=True, _
CallingConvention:=CallingConvention.StdCall)> _
Private Shared Function GetPrinter( _
ByVal hPrinter As IntPtr, ByVal dwLevel As Integer, _
ByVal pPrinter As IntPtr, ByVal cbBuf As Integer, _
ByRef pcbNeeded As Integer) As Boolean
End Function
<DllImport("winspool.drv", entrypoint:="SetPrinterW", _
CharSet:=CharSet.Auto, SetLastError:=True, ExactSpelling:=True, _
CallingConvention:=CallingConvention.StdCall)> _
Private Shared Function SetPrinter( _
ByVal hPrinter As IntPtr, ByVal dwLevel As Integer, _
ByVal pPrinter As IntPtr, ByVal Command As Integer) As Boolean
End Function
Public Sub ChangeSettings()
Dim hPrinter As IntPtr
Dim pPrinterInfo As IntPtr
Dim PrinterInfo As PRINTER_INFO_2
Dim PrinterName As String
Dim MyPrintDialog As New PrintDialog
If MyPrintDialog.ShowDialog() = DialogResult.OK Then
PrinterName = MyPrintDialog.PrinterSettings.PrinterName
hPrinter = OpenPrinter(PrinterName)
pPrinterInfo = IntPtr.Zero
Try
Dim needed As Integer
GetPrinter(hPrinter, 2, IntPtr.Zero, 0, needed)
If needed <= 0 Then
Throw New Exception("It failed getting printer settings.")
End If
pPrinterInfo = Marshal.AllocHGlobal(needed)
Dim temp As Integer
If Not GetPrinter(hPrinter, 2, pPrinterInfo, needed, temp) Then
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
'* Marshalling it does in type
PrinterInfo = CType(Marshal.PtrToStructure(pPrinterInfo,
GetType(PRINTER_INFO_2)), PRINTER_INFO_2)
Dim Copies As Short = CType(New Random(Minute(Now) + Second(Now)).Next(1,
9999), Short)
Dim m_dvmode As New DevMode
m_dvmode = CType(Marshal.PtrToStructure(PrinterInfo.pDevMode,
GetType(DevMode)), DevMode)
With m_dvmode
..dmCopies = Copies
..dmCollate = CType(IIf(Copies Mod 2 = 0, DMCOLLATE_TRUE, DMCOLLATE_FALSE),
Short)
..dmOrientation = CType(IIf(Copies Mod 2 = 0, EOrientation.eoLandscape,
EOrientation.eoPortrait), Short)
End With
Marshal.StructureToPtr(m_dvmode, PrinterInfo.pDevMode, True)
If Not SetPrinter(hPrinter, 2, pPrinterInfo, 0) Then
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
Finally
Marshal.FreeHGlobal(pPrinterInfo)
End Try
'''Serialization.SaveObjectToFile("c:\temp\test.be fore.txt", pinfo)
ClosePrinter(hPrinter)
End If
End Sub
Private Function OpenPrinter(ByVal PrinterName As String) As IntPtr
Dim hPrinter As IntPtr
Dim pd As New PRINTER_DEFAULTS
Dim pPrinterDefaults As IntPtr = IntPtr.Zero
With pd
..DesiredAccess = PrinterAccessRights.PRINTER_ALL_ACCESS
..pDevMode = GetPrinterInfo(PrinterName).pDevMode
..pDatatype = IntPtr.Zero
End With
'Marshal.StructureToPtr(pd, pPrinterDefaults, True)
If Not OpenPrinter(PrinterName, hPrinter, pd) Then 'IntPtr.Zero) Then
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
Return hPrinter
End Function
Private Function GetPrinterInfo(ByVal PrinterName As String) As
PRINTER_INFO_2
Dim hPrinter As IntPtr
If Not OpenPrinter(PrinterName, hPrinter, IntPtr.Zero) Then
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
Dim pPrinterInfo As IntPtr = IntPtr.Zero
Try
Dim needed As Integer
GetPrinter(hPrinter, 2, IntPtr.Zero, 0, needed)
If needed <= 0 Then
Throw New Exception("It failed getting printer settings.")
End If
pPrinterInfo = Marshal.AllocHGlobal(needed)
Dim temp As Integer
If Not GetPrinter(hPrinter, 2, pPrinterInfo, needed, temp) Then
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
'* Marshalling it does in type
Dim printerInfo As PRINTER_INFO_2 = _
CType(Marshal.PtrToStructure( _
pPrinterInfo, GetType(PRINTER_INFO_2)), PRINTER_INFO_2)
Return printerInfo
Finally
ClosePrinter(hPrinter)
Marshal.FreeHGlobal(pPrinterInfo)
End Try
End Function