Microsoft KB Archive/105839

From BetaArchive Wiki

PSS ID Number: 105839

Article Last Modified on 12/9/2003



The information in this article applies to:

  • Microsoft Visual Basic Standard Edition for Windows 2.0
  • Microsoft Visual Basic Standard Edition for Windows 3.0
  • Microsoft Visual Basic Professional Edition for Windows 2.0
  • Microsoft Visual Basic Professional Edition for Windows 3.0



This article was previously published under Q105839

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 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, search for the following words in the Microsoft Knowledge Base:

    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

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:
       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
       Declare Function WriteProfileString Lib "Kernel"
          (ByVal lpApplicationName As String, ByVal lpKeyName As Any,
          ByVal lpString As Any) As Integer
       Declare Function SendMessage Lib "User" (ByVal hWnd As Integer,
          ByVal wMsg As Integer, ByVal wParam As Integer,
          lParam As Any) As Long
       Const WM_WININICHANGE = &H1A
       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 query words: 2.00 3.00

Keywords: kbcode kbprint KB105839
Technology: kbAudDeveloper kbVB200 kbVB300 kbVB300Search kbVBSearch kbZNotKeyword2 kbZNotKeyword6