Changing WIN.INI Printer Settings from VB using Windows API

Last reviewed: January 12, 1996
Article ID: Q142388
The information in this article applies to:

- Professional and Enterprise Editions of Microsoft Visual Basic,

  16-bit only, for Windows, version 4.0

SUMMARY

From Visual Basic, you can call Windows API routines to change the default printer settings stored in the Windows WIN.INI file. You can also broadcast a message to all applications currently loaded in Windows to try to force them to use this WIN.INI change. However, most Windows version 3.0 and 3.1 applications are not designed to act on this broadcast message.

Applications that are started after you change WIN.INI will reflect your WIN.INI changes, as will applications that are currently loaded, if the user did not change Printer Setup in the application. But if the user changed Printer Setup in a currently loaded application, the application will ignore any changes to WIN.INI during that application's session.

There are only two ways to ensure that an application will take the changes made to the printer settings stored in WIN.INI. Either method will work:

  • Exit and restart the application, or restart Windows.
  • Choose options in the application Printer-Setup dialog box.

This article also describes how to add a Printer Setup dialog box to a Visual Basic application that optionally changes WIN.INI, and it gives example code showing how to change the default printer in Windows.

MORE INFORMATION

The following steps change the printer settings in the WIN.INI file, and then broadcast a message to all programs currently loaded in Windows to make the change take effect:

  1. Call the Windows API functions GetProfileString and WriteProfileString to change the printer setting device= in the [windows] section of the WIN.INI file to one of the printers listed in the [devices] section.

    For example, a WIN.INI file would contain the following settings to make an HP LaserJet the default printer:

          [windows]
          device=HP LaserJet IIISi PostScript,pscript,LPT1:
    

          [devices]
          Generic / Text Only=TTY,FILE:
          HP LaserJet IIISi PostScript=pscript,LPT1:
    

    For a detailed article that discusses how to change WIN.INI, please see the following article(s) in the Microsoft Knowledge Base:

    ARTICLE-ID: Q75639

       TITLE     :How to Access Windows Initialization Files Within Visual
                  Basic
    
    

  2. Call the Windows API WriteProfileString function using all NULL pointer parameters to force Windows to reload the WIN.INI file into memory. (WIN.INI is normally cached in memory and not reloaded until you restart Windows.) Pass all parameters By Value as type Long with value 0.

  3. Call the SendMessage API function with hWnd% parameter set to HWND_BROADCAST (&hffff) to broadcast a message to all pop-up windows currently loaded in the system. Setting the wMsg% parameter to WM_WININICHANGE notifies all top-level windows of a WIN.INI change, and WM_DEVMODECHANGE notifies them of a device-mode change.

However, if you changed settings in the Printer-Setup dialog box of a loaded application earlier in this session of Windows, most applications ignore the SendMessage broadcast. By design, most Windows-based applications ignore this message, as explained in the Notepad example given below.

Example of How Notepad Uses WIN.INI Printer Settings

Under Windows, you can change default printer settings in the Printers section of the Control Panel program. This writes changes to the WIN.INI file on disk and in memory. Many other applications, such as Microsoft Word, also write changes to the WIN.INI file.

When Notepad starts, a global variable of type PRINTDLG provides the structure to initialize the Print dialog box. One of the members of that structure is hDevNames. It contains three strings that specify the driver name, printer name, and output port name. When Notepad starts, these three strings start with a NULL value. This tells Notepad to get its printer device context (DC) from the WIN.INI file.

If you choose Print Setup from within NotePad and make changes, NotePad will continue using those changes for the remaining NotePad session, and the three strings in hDevNames will no longer all be NULL. That session of NotePad will no longer look in the WIN.INI file, so it will ignore any WM_WININICHANGE and WM_DEVMODECHANGE messages. Many Windows-based applications work in this manner. Internally, they process only certain messages, and they pass all unrecognized messages to the default API DefWindowProc function, which does nothing.

Because you cannot rely on an application processing WM_WININICHANGE and WM_DEVMODECHANGE messages, an application such as Visual Basic cannot force the updated WIN.INI modifications onto another loaded application by sending Windows messages. To change printer parameters to those changed in the WIN.INI file, you must use one of these two techniques:

  • Exit and restart the application, or restart Windows.
  • Use the application's Printer-Setup dialog box to set the parameters.

Adding Printer Setup to a Visual Basic Application

To add a Printer-Setup dialog to a Visual Basic application, use the Common Dialog printer control provided with the following products:

  • Visual Basic version 1.0 Professional Toolkit for Windows
  • Professional Edition of Visual Basic version 2.0 for Windows
  • Standard or Professional Edition of Visual Basic version 3.0 for Windows
  • Standard, Professional and Enterprise Editions of Microsoft Visual Basic for Windows, version 4.0

Setting the PrinterDefault property to True writes any Printer Setup changes to the WIN.INI file:

   CMDialog1.PrinterDefault = True

You can use the Flags property of the Common Dialog printer control to specify various options, as described on page 208 of "Visual Basic 3.0: Language Reference." For example, you can have a print dialog with a button for Printer Setup. Or, you can give the Printer Setup its own dialog box by setting the Flags property to PD_PRINTSETUP as follows:

   CMDialog1.Flags = PD_PRINTSETUP  ' PD_PRINTSETUP = &H40&
   CMDialog1.Action = 5     ' Displays Printer Dialog for Printer Setup

To change printer settings from a Visual Basic application without user interaction, call a DLL written in C that calls the Windows API ExtDeviceMode function. Because Visual Basic does not support function pointers, you cannot call the ExtDeviceMode function directly from Visual Basic. A Windows-compatible C compiler is required to create a Windows DLL.

Code Example to Change Windows Default Printer in WIN.INI

The following program demonstrates how to change the default printer in the WIN.INI file by using Visual Basic code:

  1. In Visual Basic, place a list box (List1) and a command button (Command1) on Form1.

  2. Set the Caption property of Command1 to Set Default Printer.

  3. Add the following code and three subprograms to the General Declarations section of Form1:

    Option Explicit

       ' Enter each Declare statement on one, single line:
       Private Declare Function GetProfileString Lib "Kernel"
          (ByVal lpAppName As String, ByVal lpKeyName As Any,
          ByVal lpDefault As String, ByVal lpReturnedString As String,
          ByVal nSize As Integer) As Integer
       Private Declare Function WriteProfileString Lib "Kernel"
          (ByVal lpApplicationName As String, ByVal lpKeyName As Any,
          ByVal lpString As Any) As Integer
       Private Declare Function SendMessage Lib "User" (ByVal hWnd As Integer,
          ByVal wMsg As Integer, ByVal wParam As Integer,
          lParam As Any) As Long
       Private Const WM_WININICHANGE = &H1A
       Private Const HWND_BROADCAST = &HFFFF
    
       ' Enter the following two lines as one, single line:
       Sub GetDriverAndPort (ByVal Buffer As String, DriverName As String,
          PrinterPort As String)
          Dim r As Integer
          Dim iDriver As Integer
          Dim iPort As Integer
          DriverName = ""
          PrinterPort = ""
    
          'The driver name is first in the string terminated by a comma
          iDriver = InStr(Buffer, ",")
          If iDriver > 0 Then
    
             'Strip out the driver name
             DriverName = Left(Buffer, iDriver - 1)
    
             'The port name is the second entry after the driver name
             'separated by commas.
             iPort = InStr(iDriver + 1, Buffer, ",")
    
             If iPort > 0 Then
                'Strip out the port name
                PrinterPort = Mid(Buffer, iDriver + 1, iPort - iDriver - 1)
             End If
          End If
       End Sub
    
       Sub ParseList (lstCtl As Control, ByVal Buffer As String)
          Dim i As Integer
          Do
             i = InStr(Buffer, Chr(0))
             If i > 0 Then
                lstCtl.AddItem Left(Buffer, i - 1)
                Buffer = Mid(Buffer, i + 1)
             Else
                lstCtl.AddItem Buffer
                Buffer = ""
             End If
          Loop While i > 0
       End Sub
    
       ' Enter the following two lines as one, single line:
       Sub SetDefaultPrinter (ByVal PrinterName As String,
          ByVal DriverName As String, ByVal PrinterPort As String)
          Dim DeviceLine As String
          Dim r As Integer
          Dim l As Long
          DeviceLine = PrinterName & "," & DriverName & "," & PrinterPort
          ' Store the new printer information in the [WINDOWS] section of
          ' the WIN.INI file for the DEVICE= item
          r = WriteProfileString("windows", "Device", DeviceLine)
          ' Cause all applications to reload the INI file:
          l = SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, ByVal "windows")
       End Sub
    
    

  4. Add the following code to the Command1_Click event procedure:

    Dim r As Integer Dim Buffer As String Dim DeviceName As String Dim DriverName As String Dim PrinterPort As String Dim PrinterName As String If List1.ListIndex > -1 Then

          'Get the printer information for the currently selected printer
          'in the list. The information is taken from the WIN.INI file.
          Buffer = Space(1024)
          PrinterName = List1.Text
          r=GetProfileString("PrinterPorts",PrinterName,"",Buffer,Len(Buffer))
    

          'Parse the driver name and port name out of the buffer
          GetDriverAndPort Buffer, DriverName, PrinterPort
    

          If DriverName <> "" And PrinterPort <> "" Then
    
             SetDefaultPrinter List1.Text, DriverName, PrinterPort
          End If
       End If
    
    

  5. Add the following code to Form_Load event procedure:

    Dim r As Integer Dim Buffer As String

       'Get the list of available printers from WIN.INI
       Buffer = Space(8192)
       r = GetProfileString("PrinterPorts",ByVal 0&,"",Buffer,Len(Buffer))
    
       'Display the list of printer in the list box List1
       ParseList List1, Buffer
    
    

  6. Run the program. The list box will display the printer choices from the WIN.INI file. By clicking the command button, you will set the default printer in the WIN.INI file.

REFERENCES

"Microsoft Windows Programmer's Reference," Chapters 4 and 6, Microsoft Press, 1990.


Additional reference words: 2.00 3.00 4.00 vb4win vb416
KBCategory: kbprint kbprg kbcode
KBSubcategory: APrgPrint


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: January 12, 1996
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.