Controle Printer setting using vb.net

Abanoub Zak 36 Reputation points
2022-02-23T23:05:32.137+00:00

I was Introduced to "winspool.drv" not long ago and I was able to use it to change the default printer on windows but can I do more than that like adding or changing the printer setting it self. for example the following pic has a printer that have 3 papers' sizes, can I change the manual feed from 80(72.1)*297 to 80(72.1)*3276.
177353-screenshot-2022-02-24-004648.png
example two: add new paper size and orientations.
177354-screenshot-2022-02-24-004821.png

VB
VB
An object-oriented programming language developed by Microsoft that is implemented on the .NET Framework. Previously known as Visual Basic .NET.
2,625 questions
{count} votes

Accepted answer
  1. Castorix31 82,316 Reputation points
    2022-02-24T21:37:07.56+00:00

    Global Printers Settings are changed with DocumentProperties

    For example, this test gets the default paper size (DM_PAPERSIZE) for the selected printer and changes it on Button click
    You can also change the orientation with DM_ORIENTATION (DMORIENT_PORTRAIT = 1 and DMORIENT_LANDSCAPE = 2)

    Add 2 ComboBoxes and 1 Button for the Button click =>

    177665-documentproperties.jpg

    Imports System.Drawing.Printing  
    Imports System.Runtime.InteropServices  
      
    Public Class Form1  
        <DllImport("Winspool.drv", SetLastError:=True, CharSet:=CharSet.Unicode)>  
        Public Shared Function DeviceCapabilities(lpDeviceName As String, lpPort As String, iIndex As Integer, lpOutput As IntPtr, lpDevMode As IntPtr) As Integer  
        End Function  
      
        <DllImport("Winspool.drv", SetLastError:=True, CharSet:=CharSet.Unicode)>  
        Public Shared Function OpenPrinter(pPrinterName As String, ByRef hPrinter As IntPtr, ByRef pDefault As PRINTER_DEFAULTS) As Boolean  
        End Function  
      
        <DllImport("Winspool.drv", SetLastError:=True, CharSet:=CharSet.Unicode)>  
        Public Shared Function ClosePrinter(hPrinter As IntPtr) As Boolean  
        End Function  
      
        <DllImport("Winspool.drv", SetLastError:=True, CharSet:=CharSet.Unicode)>  
        Public Shared Function GetPrinter(hPrinter As IntPtr, Level As Integer, pPrinter As IntPtr, cbBuf As Integer, ByRef pcbNeeded As Integer) As Boolean  
        End Function  
      
        <DllImport("Winspool.drv", SetLastError:=True, CharSet:=CharSet.Unicode)>  
        Private Shared Function SetPrinter(hPrinter As IntPtr, Level As Integer, pPrinter As IntPtr, Command As Integer) As Boolean  
        End Function  
      
        Public Const ERROR_INSUFFICIENT_BUFFER = 122  
      
        <StructLayout(LayoutKind.Sequential)>  
        Public Structure PRINTER_INFO_2  
            <MarshalAs(UnmanagedType.LPTStr)> Public pServerName As String  
            <MarshalAs(UnmanagedType.LPTStr)> Public pPrinterName As String  
            <MarshalAs(UnmanagedType.LPTStr)> Public pShareName As String  
            <MarshalAs(UnmanagedType.LPTStr)> Public pPortName As String  
            <MarshalAs(UnmanagedType.LPTStr)> Public pDriverName As String  
            <MarshalAs(UnmanagedType.LPTStr)> Public pComment As String  
            <MarshalAs(UnmanagedType.LPTStr)> Public pLocation As String  
      
            Public pDevMode As IntPtr  
      
            <MarshalAs(UnmanagedType.LPTStr)> Public pSepFile As String  
            <MarshalAs(UnmanagedType.LPTStr)> Public pPrintProcessor As String  
            <MarshalAs(UnmanagedType.LPTStr)> Public pDatatype As String  
            <MarshalAs(UnmanagedType.LPTStr)> Public pParameters As String  
      
            Public pSecurityDescriptor As IntPtr  
            Public Attributes As Integer  
            Public Priority As Integer  
            Public DefaultPriority As Integer  
            Public StartTime As Integer  
            Public UntilTime As Integer  
            Public Status As Integer  
            Public cJobs As Integer  
            Public AveragePPM As Integer  
        End Structure  
      
        <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)>  
        Public Structure DEVMODE  
            <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)> Public pDeviceName 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  
            <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)> Public dmFormName As String  
            Public dmUnusedPadding As Short  
            Public dmBitsPerPel As Integer  
            Public dmPelsWidth As Integer  
            Public dmPelsHeight As Integer  
            Public dmNup As Integer  
            Public dmDisplayFrequency As Integer  
            Public dmICMMethod As Integer  
            Public dmICMIntent As Integer  
            Public dmMediaType As Integer  
            Public dmDitherType As Integer  
            Public dmReserved1 As Integer  
            Public dmReserved2 As Integer  
            Public dmPanningWidth As Integer  
            Public dmPanningHeight As Integer  
        End Structure  
      
        <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)>  
        Public Structure PRINTER_DEFAULTS  
            Public pDatatype As IntPtr  
            Public pDevMode As IntPtr  
            Public DesiredAccess As Integer  
        End Structure  
        Dim STANDARD_RIGHTS_REQUIRED As Integer = &HF0000  
        Dim PRINTER_ACCESS_ADMINISTER As Integer = &H4  
        Dim PRINTER_ACCESS_USE As Integer = &H8  
        Dim PRINTER_ALL_ACCESS As Integer = (STANDARD_RIGHTS_REQUIRED Or (PRINTER_ACCESS_ADMINISTER Or PRINTER_ACCESS_USE))  
      
        Public Const DC_PAPERS = 2  
        Public Const DC_PAPERSIZE = 3  
        Public Const DC_PAPERNAMES = 16  
        Public Const DC_BINNAMES = 12  
        Public Const DC_BINS = 6  
        Public Const DEFAULT_VALUES = 0  
      
        Public Const DM_ORIENTATION = &H1  
        Public Const DM_PAPERSIZE = &H2  
      
        <DllImport("Winspool.drv", SetLastError:=True, CharSet:=CharSet.Unicode)>  
        Public Shared Function DocumentProperties(hwnd As IntPtr, hPrinter As IntPtr, pDeviceName As String, pDevModeOutput As IntPtr, pDevModeInput As IntPtr, fMode As Integer) As Integer  
        End Function  
      
        Public Const DM_UPDATE = 1  
        Public Const DM_COPY = 2  
        Public Const DM_PROMPT = 4  
        Public Const DM_MODIFY = 8  
      
        Public Const DM_IN_BUFFER = DM_MODIFY  
        Public Const DM_IN_PROMPT = DM_PROMPT  
        Public Const DM_OUT_BUFFER = DM_COPY  
        Public Const DM_OUT_DEFAULT = DM_UPDATE  
      
        Public Const HWND_BROADCAST As Integer = (&HFFFF)  
        Public Const WM_DEVMODECHANGE As Integer = &H1B  
      
        Public Const SMTO_NORMAL As Integer = &H0  
        Public Const SMTO_BLOCK As Integer = &H1  
        Public Const SMTO_ABORTIFHUNG As Integer = &H2  
        Public Const SMTO_NOTIMEOUTIFNOTHUNG As Integer = &H8  
        Public Const SMTO_ERRORONEXIT As Integer = &H20  
      
        <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>  
        Public Shared Function SendMessageTimeout(hWnd As IntPtr, Msg As Integer, wParam As IntPtr, lParam As String, fuFlags As UInteger, uTimeout As UInteger, lpdwResult As IntPtr) As IntPtr  
        End Function  
      
      
        Private WithEvents PrintDocument1 As PrintDocument = New PrintDocument  
      
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load  
            For i As Integer = 0 To PrinterSettings.InstalledPrinters.Count - 1  
                ComboBox1.Items.Add(PrinterSettings.InstalledPrinters(i).ToString)  
                If PrintDocument1.PrinterSettings.PrinterName = PrinterSettings.InstalledPrinters(i).ToString Then  
                    ComboBox1.SelectedIndex = i  
                End If  
            Next  
        End Sub  
      
        Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged  
            Cursor = Cursors.WaitCursor  
            With PrintDocument1  
                .PrinterSettings.PrinterName = PrinterSettings.InstalledPrinters(ComboBox1.SelectedIndex)  
                If ComboBox2.Items.Count > 0 Then ComboBox2.Items.Clear()  
      
                Dim hPrinter As IntPtr  
                Dim pDefaults As New PRINTER_DEFAULTS()  
                Dim sPrinterName = PrinterSettings.InstalledPrinters(ComboBox1.SelectedIndex)  
                Dim sPrinterPort As String = Nothing  
                Dim nPrinterPaperSize As Integer = 0  
                pDefaults.DesiredAccess = PRINTER_ACCESS_USE  
                Dim bResult As Boolean = OpenPrinter(sPrinterName, hPrinter, pDefaults)  
                If (bResult = True) Then  
                    Dim nBytesNeeded As Integer = -1  
                    Dim nSize As Integer = -1  
                    Dim pPrinterInfo As IntPtr = IntPtr.Zero  
                    GetPrinter(hPrinter, 2, IntPtr.Zero, 0, nBytesNeeded)  
                    pPrinterInfo = Marshal.AllocHGlobal(nBytesNeeded)  
                    nSize = nBytesNeeded  
                    If (Not GetPrinter(hPrinter, 2, pPrinterInfo, nSize, nBytesNeeded)) Then  
                        Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error())  
                    End If  
                    Dim PrinterInfo As PRINTER_INFO_2 = CType(Marshal.PtrToStructure(pPrinterInfo, GetType(PRINTER_INFO_2)), PRINTER_INFO_2)  
                    sPrinterPort = PrinterInfo.pPortName  
                    Dim pDevMode As IntPtr = PrinterInfo.pDevMode  
                    Dim DevMode As DEVMODE = CType(Marshal.PtrToStructure(pDevMode, GetType(DEVMODE)), DEVMODE)  
                    nPrinterPaperSize = DevMode.dmPaperSize  
                    Marshal.FreeHGlobal(pPrinterInfo)  
                    ClosePrinter(hPrinter)  
                End If  
      
                Dim nNumber As Integer  
                nNumber = DeviceCapabilities(sPrinterName, sPrinterPort, DC_PAPERNAMES, IntPtr.Zero, IntPtr.Zero)  
                Dim nStringSize As Integer = Marshal.SystemDefaultCharSize * 64  
                Dim pNamesBuffer As IntPtr = Marshal.AllocHGlobal(nStringSize * nNumber)  
                nNumber = DeviceCapabilities(sPrinterName, sPrinterPort, DC_PAPERNAMES, pNamesBuffer, IntPtr.Zero)  
      
                nNumber = DeviceCapabilities(sPrinterName, sPrinterPort, DC_PAPERS, IntPtr.Zero, IntPtr.Zero)  
                Dim pPapersBuffer As IntPtr = Marshal.AllocHGlobal(2 * nNumber)  
                nNumber = DeviceCapabilities(sPrinterName, sPrinterPort, DC_PAPERS, pPapersBuffer, IntPtr.Zero)  
      
                For nCurrent = 0 To nNumber - 1  
                    Dim sName As String = Marshal.PtrToStringAuto(CType((CType(pNamesBuffer, Long) + (nStringSize * nCurrent)), IntPtr), 64)  
                    Dim nIndex As Integer = sName.IndexOf(vbNullChar)  
                    If (nIndex > -1) Then  
                        sName = sName.Substring(0, nIndex)  
                        Dim nPaper As Short = Marshal.ReadInt16(((pPapersBuffer + nCurrent * 2)))  
                        Dim item As ComboboxItem = New ComboboxItem()  
                        item.PaperName = sName  
                        item.PaperSize = nPaper  
                        ComboBox2.Items.Add(item)  
                        If (nPaper = nPrinterPaperSize) Then  
                            ComboBox2.SelectedIndex = nCurrent  
                        End If  
                    End If  
                Next  
                Marshal.FreeHGlobal(pNamesBuffer)  
                Marshal.FreeHGlobal(pPapersBuffer)  
            End With  
            Cursor = Cursors.Default  
        End Sub  
      
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click  
            Dim hPrinter As IntPtr  
            Dim pDefaults As New PRINTER_DEFAULTS()  
            Dim sPrinterName = PrinterSettings.InstalledPrinters(ComboBox1.SelectedIndex)  
            Dim bResult As Boolean = OpenPrinter(sPrinterName, hPrinter, pDefaults)  
            If (bResult = True) Then  
                Dim nBytesNeeded As Integer = -1  
                Dim nSize As Integer = -1  
                Dim pPrinterInfo As IntPtr = IntPtr.Zero  
                GetPrinter(hPrinter, 2, IntPtr.Zero, 0, nBytesNeeded)  
                pPrinterInfo = Marshal.AllocHGlobal(nBytesNeeded)  
                nSize = nBytesNeeded  
                If (Not GetPrinter(hPrinter, 2, pPrinterInfo, nSize, nBytesNeeded)) Then  
                    Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error())  
                End If  
                Dim PrinterInfo As PRINTER_INFO_2 = CType(Marshal.PtrToStructure(pPrinterInfo, GetType(PRINTER_INFO_2)), PRINTER_INFO_2)  
                Dim pDevMode As IntPtr = PrinterInfo.pDevMode  
                Dim DevMode As DEVMODE = CType(Marshal.PtrToStructure(pDevMode, GetType(DEVMODE)), DEVMODE)  
                DevMode.dmFields = DM_PAPERSIZE  
                DevMode.dmPaperSize = TryCast(ComboBox2.SelectedItem, ComboboxItem).PaperSize  
                Marshal.StructureToPtr(DevMode, pDevMode, False)  
                Marshal.StructureToPtr(PrinterInfo, pPrinterInfo, False)  
                Dim nReturn = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, pDevMode, pDevMode, DM_IN_BUFFER Or DM_OUT_BUFFER)  
                nReturn = Convert.ToInt32(SetPrinter(hPrinter, 2, pPrinterInfo, 2))  
                SendMessageTimeout(New IntPtr(HWND_BROADCAST), WM_DEVMODECHANGE, IntPtr.Zero, sPrinterName, SMTO_NORMAL, 1000, IntPtr.Zero)  
                Marshal.FreeHGlobal(pPrinterInfo)  
                ClosePrinter(hPrinter)  
            End If  
        End Sub  
      
        Public Class ComboboxItem  
            Public Property PaperName As String  
            Public Property PaperSize As Short  
            Public Overrides Function ToString() As String  
                Return PaperName  
            End Function  
        End Class  
    End Class  
      
    

0 additional answers

Sort by: Most helpful