Retrieving the Names of Installed Printers

Using Drag-and-Drop on Multiple Items in a List Box Control

Sending Data to the Printer in Landscape or Portrait Mode

 

Retrieving the Names of Installed Printers

Source: MSDN 98

Abstract

The Windows® initialization file, WIN.INI, contains a list of all printers attached to the computer system. This article contains an example program that retrieves the name of each printer stored in the WIN.INI initialization file.

Using GetProfileString and GetPrivateProfileString

The Devices section of the WIN.INI initialization file contains the names of all printers attached to your computer system. You can retrieve this list of printer names by using two Windows® application programming interface (API) functions.

The Windows API GetProfileString and GetPrivateProfileString functions can be used to retrieve the name of a printer as stored in the WIN.INI file. For a complete discussion of these functions, see the articles listed in the "Additional References" section of this article.

Example Program

This program retrieves the names of all installed printers from the WIN.INI initialization file. The printer names are displayed in a List Box control.

  1. Create a new project in Visual Basic. Form1 is created by default.

  2. Add the following Constant, Declare, and Type statements to the General Declarations section of Form1 (note that each Declare statement must be typed as a single line of text):
    Option Explicit
    Private Type WindowsDevice
       WindowsDeviceUserName As String
       WindowsDeviceShortName As String
       WindowsDevicePortName As String
    End Type
    Private Declare Function GetProfileString Lib "Kernel" (ByVal lpAppName 
       As String, ByVal lpKeyName As String, ByVal lpDefault As String, ByVal 
       lpReturnedString As String, ByVal nSize As Integer) As Integer
    Private Declare Function GetPrivateProfileString Lib "Kernel" (ByVal lpAppName 
       As String, ByVal lpKeyName As String, ByVal lpDefault As String, ByVal 
       lpReturnedString As String, ByVal nSize As Integer, ByVal lpFileName As 
       String) As Integer
    Private Declare Function GetProfileKeys Lib "Kernel" Alias "GetProfileString" 
       (ByVal lpAppName As String, ByVal lpKeyName As Long, ByVal lpDefault As 
        String, ByVal lpReturnedString As String, ByVal nSize As Integer) As Integer
    Private Declare Function GetPrivateProfileKeys Lib "Kernel" Alias 
       "GetPrivateProfileString" (ByVal lpAppName As String, ByVal lpKeyName As 
       Long, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal 
       nSize As Integer, ByVal lpFileName As String) As Integer
    Const WINDOWS_SECTION_NAME = "windows"
    Const DEVICES_SECTION_NAME = "devices"
    Const DEVICE_KEY_NAME = "device"
    Const NO_PRINTER = "(none)"
    
  3. Add a Text Box control to Form1. Text1 is created by default.

  4. Add a Command Button control to Form1. Command1 is created by default.

  5. Add the following code to the Click event for Command1 (note that the List1.AddItem statement must be typed as a single line of code):
    Private Sub Command1_Click()
    Dim OrgPrinter As WindowsDevice
    Call GetDefaultPrinter(OrgPrinter)
    Text1.Text = OrgPrinter.WindowsDeviceUserName
    
    Dim NumPrinters As Integer
    ReDim InstalledPrinters(0) As WindowsDevice
    Call GetInstalledPrinters(InstalledPrinters())
    For NumPrinters = 1 To UBound(InstalledPrinters)
    List1.AddItem InstalledPrinters(NumPrinters).WindowsDeviceUserName + " 
    on " + InstalledPrinters(NumPrinters).WindowsDevicePortName
    Next
    List1.AddItem NO_PRINTER, 0
    End Sub
    
  6. Create a new function called GetDefaultPrinter. Add the following code to this function:
    Private Sub GetDefaultPrinter(recDefaultPrinter As WindowsDevice)
    Dim StrPos As Integer
    Dim DefaultPrinter As String
    Dim RC As Integer
    DefaultPrinter = GetString(WINDOWS_SECTION_NAME, DEVICE_KEY_NAME, "", "")
    StrPos = InStr(DefaultPrinter, ",")
    recDefaultPrinter.WindowsDeviceUserName = Left$(DefaultPrinter, StrPos - 1)
    DefaultPrinter = Mid$(DefaultPrinter, StrPos + 1)
    StrPos = InStr(DefaultPrinter, ",")
    recDefaultPrinter.WindowsDeviceShortName = Left$(DefaultPrinter, StrPos - 1)
    recDefaultPrinter.WindowsDevicePortName = Mid$(DefaultPrinter, StrPos + 1)
    End Sub
    
  7. Create a new function called GetInstalledPrinter. Add the following code to this function (note that the InstalledPrinter lines must be typed as a single line of code):
    Private Sub GetInstalledPrinters(recInstalledPrinters() As WindowsDevice)
    Dim StrPos As Integer
    Dim PrtSub As Integer
    Dim InstalledPrinter As String
    ReDim PrinterNames(0) As String
    Call GetKeyNames(DEVICES_SECTION_NAME, PrinterNames(), "")
    ReDim recInstalledPrinters(UBound(PrinterNames))
    For PrtSub = 1 To UBound(PrinterNames)
    InstalledPrinter = GetString(DEVICES_SECTION_NAME, PrinterNames(PrtSub), 
    "", "")
    StrPos = InStr(InstalledPrinter, ",")
    recInstalledPrinters(PrtSub).WindowsDeviceUserName = 
    PrinterNames(PrtSub)
    recInstalledPrinters(PrtSub).WindowsDeviceShortName = 
    Left$(InstalledPrinter, StrPos - 1)
    InstalledPrinter = Mid$(InstalledPrinter, StrPos + 1)
    StrPos = InStr(InstalledPrinter, ",")
    If StrPos > 0 Then
    recInstalledPrinters(PrtSub).WindowsDevicePortName = 
    Left$(InstalledPrinter, StrPos - 1)
    Else
    recInstalledPrinters(PrtSub).WindowsDevicePortName = 
    InstalledPrinter
    End If
    Next
    End Sub
    
  8. Create a new function called GetString. Add the following code to this function (note that the Function and KeyValueLength lines must each be typed as a single line of code):
    Function GetString(SectionName As String, KeyName As String, DefaultValue 
    As String, ProfileName As String) As String
    Dim KeyValueLength As Integer
    Dim KeyValue As String
    KeyValue = Space$(256)
    If Trim$(ProfileName) = "" Then
    KeyValueLength = GetProfileString(SectionName, KeyName, DefaultValue, 
    KeyValue, Len(KeyValue))
    Else
    KeyValueLength = GetPrivateProfileString(SectionName, KeyName, 
    DefaultValue, KeyValue, Len(KeyValue), ProfileName)
    End If
    GetString = Left$(KeyValue, KeyValueLength)
    End Function
    
  9. Create a new function called GetKeyName. Add the following code to this function (note that the Sub and KeyNamesLength lines must each be typed as a single line of code):
    Sub GetKeyNames(SectionName As String, KeyNames() As String, ProfileName 
       As String)
        Dim StrPos As Integer
        Dim KeyCount As Integer
        Dim Start As Integer
        Dim KeyNamesLength As Integer
        Dim KeyNameString As String
        KeyNameString = Space$(1024)
        If Trim$(ProfileName) = "" Then
            KeyNamesLength = GetProfileKeys(SectionName, 0, "", KeyNameString, 
                Len(KeyNameString))
        Else
            KeyNamesLength = GetPrivateProfileKeys(SectionName, 0, "", 
                KeyNameString, Len(KeyNameString), ProfileName)
        End If
        KeyCount = 0
        ReDim KeyNames(0)
        If KeyNamesLength > 0 Then
            KeyNameString = Left$(KeyNameString, KeyNamesLength)
            If Right$(KeyNameString, 1) <> Chr$(0) Then
                KeyNameString = KeyNameString + Chr$(0)
            End If
            KeyNamesLength = Len(KeyNameString)
            Start = 1
            Do
                StrPos = InStr(Start, KeyNameString, Chr$(0))
                If StrPos > 0 Then
                    KeyCount = KeyCount + 1
                    ReDim Preserve KeyNames(KeyCount)
                    KeyNames(KeyCount) = Mid$(KeyNameString, Start, StrPos - Start)
                    If StrPos < KeyNamesLength Then
                        Start = StrPos + 1
                    Else
                        Exit Do
                    End If
                Else
                    Exit Do
                End If
            Loop
            End If
    End Sub
    

Run the example program by pressing the F5 function key. Click the Command Button control. The name of the default printer is displayed in the Text Box control, and a list of all installed printers is displayed in the List Box control.

Using Drag-and-Drop on Multiple Items in a List Box Control

Source: MSDN 98

Abstract

The drag-and-drop functionality provided in many Windows®-based applications allows you to copy an item from one program to another or from one control to another control in the same application. This article explains how to use this drag-and-drop technique in Visual Basic® to copy multiple items selected in a List Box control to another List Box control.

Dragging Multiple List Box Items

Many Windows-based applications include drag-and-drop functionality. This means that you can select an item, such as an entry in a List Box control, click on the item, and, while holding the mouse button down, drag that item to another window or control and drop it on its new location.

The example program below shows how you can add this drag-and-drop feature to your Visual Basic® applications. This program allows you to select multiple items in the source List Box control and drag the whole group of selected items to a second List Box control all at one time.

Example Program

This program shows how to drag several items selected in one List Box control to another List Box control. Run the example program by pressing the F5 function key. From the first List Box control, click the mouse on several items to select (highlight) them. While clicking each item, hold down the SHIFT key. When you want to drag the selected items to the second List Box control, click once on the first List Box control and hold the mouse button down while you drag the control to the second List Box. Release the mouse button to drop the selected items onto the second List Box control.

While using this program, you can select the items from the first List Box either by holding the SHIFT key down while you click on each entry, or by simply clicking the mouse on each individual entry. If you hold the SHIFT key down when selecting entries, those entries will remain selected (highlighted) in the first List Box control after the items have been dropped onto the second List Box control. If the SHIFT key is not used, one of the selected items will not retain its selected status after the drag-and-drop operation has finished.

  1. Create a new project in Visual Basic. Form1 is created by default.

  2. Add the following code to the General Declarations section of Form1:
    Option Explicit
    Dim IG As Integer
    Dim LIG(20) As Integer
    Dim LGlobal As Long
    Const VK_SHIFT = &H10
    
  3. Add the following code to the Form_Load event for Form1:
    Private Sub Form_Load()
    Dim X As Integer
    IG = 0
    For X = 0 To 9
    List1.AddItem "Item #" + Str$(X)
    Next X
    List1.DragMode = 0
    LGlobal = 99999
    End Sub
    
  4. Add a List Box control to Form1. List1 is created by default. Set its MultiSelect property to 1-Simple.

  5. Add the following code to the MouseDown event for List1 (note that the Private line must be typed as a single line of code):
    Private Sub List1_MouseDown(Button As Integer, Shift As Integer, X As Single, 
    Y As Single)
    LGlobal = List1.ListIndex
    For X = 1 To IG
    List1.Selected(LIG(X)) = True
    Next X
    List1.Drag
    End Sub
    
  6. Add a second List Box control to Form1. List2 is created by default. Set its MultiSelect property to 1-Simple.

  7. Add the following code to the DragDrop event for List2:
    Private Sub List2_DragDrop(Source As Control, X As Single, Y As Single)
        For X = 0 To List1.ListCount - 1
            If X = LGlobal Then
                List2.AddItem List1.List(X)
            Else
                If List1.Selected(X) Then
                    List2.AddItem List1.List(X)
                End If
            End If
        Next X
        LGlobal = 99999
        IG = 0
    End Sub
    

Sending Data to the Printer in Landscape or Portrait Mode

July 1, 1995

Abstract

In a Microsoft® Visual Basic® application, you can send data to the printer by using the Print method. The printed output appears in the default portrait orientation. This article shows how to change the orientation of the printer from its default portrait mode to landscape mode.

Sending Commands to the Printer

When you create a report in a Microsoft® Visual Basic® application, the output is usually sent to the printer in portrait mode. However, by using two Microsoft Windows® application programming interface (API) functions, you can tell the printer to print the report in landscape mode.

Most printers manufactured today support a number of functions such as changing the print orientation to landscape mode. You tell the printer driver to select landscape printing by sending specific control code commands to the device. In Windows terminology, these control code commands are called Escape operations.

The example program below shows how to use the Windows API Escape function to change the orientation of the printer. When you run this program, notice that a blank piece of paper is not ejected when the setting takes effect.

How do we prevent the blank sheet of paper from being ejected? The AbortDoc function tells Windows to ignore the previous print request. This generates a printer error, which is trapped by the On Error Resume Next statement. Therefore, the printer is set to the new orientation without ejecting a blank piece of paper.

The Escape function can be used to send specific control codes to a printer device. The CONSTANT.TXT file contains a list of the most commonly used escape codes that can be used with printers, display screens, and other devices.

To use the Escape function within your program, include the following Declare statement in the General Declarations section of your form (note that this Declare statement must be typed as a single line of text):

Private Declare Function Escape Lib "GDI" (ByVal hDC As Integer, ByVal nEscape
   As Integer, ByVal nCount As Integer, lpInData As Any, lpOutData As Any) As
   Integer

The Escape function requires five arguments, as follows.

hDC An integer value containing the device context's handle
nEscape An integer value containing the specific escape code to be sent to the device context
nCount An integer value set to the size of the lpInData argument
lpInData Varies—see below
lpOutData Varies—see below

The arguments lpInData and lpOutData are set according to which escape code is being sent to the printer. Because we want to set the printer to either landscape or portrait mode, we specify the nEscape argument as GETSETPRINTORIENT. The GETSETPRINTORIENT operation requires that the arguments lpInData and lpOutData point to a 20-byte structure. To actually set the orientation, the first long value in this structure must be set to the specific orientation you want to use.

After the escape code (landscape or portrait) is sent to the printer, you must use the Windows API AbortDoc function. This function tells the printer to abort the print request. Calling the AbortDoc function sets the printer to the new mode. All subsequent output to the printer will then print in whichever print orientation you selected. This means that you may have to issue another Escape statement to reset the printer to portrait mode to return the printer to its default state.

Example Program

This program shows how to set the printer to landscape (or portrait) mode.

  1. Create a new project in Visual Basic. Form1 is created by default.

  2. Add the following Constant and Declare statements to the General Declarations section of Form1 (note that each Declare statement must be typed as a single line of code):
    Private Declare Function AbortDoc Lib "GDI" (ByVal hDC As Integer) As Integer
    Private Declare Function Escape Lib "GDI" (ByVal hDC As Integer, ByVal
       nEscape As Integer, ByVal nCount As Integer, lpInData As Any, lpOutData As
       Any) As Integer
    Const PORTRAIT = 1
    Const LANDSCAPE = 2
    Const GETSETPAPERORIENT = 30
    Const NULLVALUE = 0&
    
  3. Add a Command Button control to Form1. Command1 is created by default. Set its Caption property to "Landscape".

  4. Add the following code to the Click event for Command1:
    Private Sub Command1_Click()
        PrintOrient LANDSCAPE, "This is landscape printing."
    End Sub
    
  5. Add a second Command Button control to Form1. Command2 is created by default. Set its Caption property to "Portrait".

  6. Add the following code to the Click event for Command2:
    Private Sub Command2_Click()
        PrintOrient PORTRAIT, "This is portrait printing."
    End Sub
    
  7. Create a new procedure called PrintOrient. Add the following code to this procedure:
    Sub PrintOrient(Mode As Integer, PrintThis As String)
        Dim Orient As OrientStructure
        Dim Ret As Integer
        Dim X As Integer
           
        Printer.Print ""
        Orient.Orientation = Mode
        X = Escape(Printer.hDC, GETSETPAPERORIENT, Len(Orient), Orient, NULLVALUE)
        On Error Resume Next
        Ret = AbortDoc(Printer.hDC)
        On Error Resume Next
        
        Printer.EndDoc
        Printer.Print PrintThis
        Printer.EndDoc
    End Sub
    
  8. From the Visual Basic Insert menu, click Module to create a new module. Module1.Bas is created by default.

  9. Add the following Type structure to Module1.Bas:
    Type OrientStructure
        Orientation As Long
        Pad As String * 16
    End Type
    

Run the example program by pressing F5. Click the Landscape command button to print a test sheet in landscape mode. Next, click the Portrait command button to print a test sheet in portrait mode. Notice that each time you change the orientation of the printer, a blank sheet of paper is not ejected needlessly