Solved

Printer Selection from combo box

Posted on 2007-11-22
12
742 Views
Last Modified: 2008-02-01
Hi

I have a annoying problem I have a form with a combo box that lists printers on a PC. in properties are the following
Data
Row Source Type        FillPrinterList    (Function call)

Format
Column Count = 4
ColumnWidth     =  ;0cm;0cm;0cm

pName = me!cboPrinter.Column(1)

Problem it works and other times I get Null Value in pName

with the pName = Me!cboPrinter.Column(1)
I have tried on exit, on focus etc

I must be doing something wrong. If some one can see the problem help would be most apprciated

chestera
0
Comment
Question by:chestera
  • 4
  • 3
  • 2
  • +2
12 Comments
 
LVL 75

Expert Comment

by:DatabaseMX (Joe Anderson - Access MVP)
Comment Utility
Hi Alan ...

Seems it would be an issue with the List fill function.  Can you post the code for that?

mx
0
 
LVL 10

Expert Comment

by:LennyGray
Comment Utility
You specify 4 columns but you define the width for only 3.

If the first column is the name of the printer, then pName = me!cboPrinter.Column(1)
 is incorrect.

It can be stated in either of two ways:

pName = me!cboPrinter.Column(0)

or

pName = me!cboPrinter


Comboboxes are zero-based numbering (satrts at zero) for reference but the boundccolumn property starts at 1 not zero.

I hope that this helps.
0
 
LVL 75

Expert Comment

by:DatabaseMX (Joe Anderson - Access MVP)
Comment Utility
"You specify 4 columns but you define the width for only 3"
The 4th column will be the defined by the Width of the combo box ... and the 4th column is probably a description of the printer.

Also, sounds like the printer name is in physical column 2, thus Column(1) would be correct.

mx
0
 

Author Comment

by:chestera
Comment Utility
databasemax

I have tried (0) and (1) it seems (1) it the right column but it's erratic Works then spits the dummy and doesn't work. The complet code is quite large. I will post the FillPrinterList portion.

chestera
0
 

Author Comment

by:chestera
Comment Utility
databasemx

Here it the FillPrintList code

' Code from:
' Microsoft Access 95 How-To
' (c) 1998 Ken Getz and Paul Litwin
' All rights reserved.

' You may only use this code as part of an application
' that requires its use. You must including this
' notice intact. You may not distribute the code
' as your own work, nor can you distribute the
' code on its own.

Function ahtGetDefaultPrinter(dr As aht_tagDeviceRec) As Boolean

   ' Retrieve the default printer information. Though
   ' the function dutifully returns True if the
   ' values were available, and False otherwise, Windows
   ' really isn't happy without a default printer, and
   ' this situation rarely comes up.

   ' In:
   '     dr: a aht_tagDeviceRec structure to fill in
   ' Out:
   '     Return Value: True if info available, False otherwise.
   '     dr: filled in with default printer information,
   '        if it was available (check the function's return
   '        value).
   '
   ' Comments:
   '     Requires the ahtGetToken() function from basGetToken
   '     Requires the ahtGetINIString() function from basINIFile
   '     Requires type definitions from basPrintTypes
   
   Dim strBuffer As String

   strBuffer = ahtGetINIString("Windows", "Device")
   If Len(strBuffer) > 0 Then
      With dr
         .drDeviceName = ahtGetToken(strBuffer, ",", 1)
         .drDriverName = ahtGetToken(strBuffer, ",", 2)
         .drPort = ahtGetToken(strBuffer, ",", 3)
      End With
      ahtGetDefaultPrinter = True
   Else
      ahtGetDefaultPrinter = False
   End If
End Function

Function ahtSetDefaultPrinter(dr As aht_tagDeviceRec) As Boolean

   ' Set the default printer device in Win.INI

   ' In:
   '     dr: a aht_tagDeviceRec structure to use as
   '        the source of information.
   ' Out:
   '     Return Value: True if set correctly, False otherwise.
   '     If successful, writes a string in the form:
   '        device=HP LaserJet 4,HPPCL5E,LPT1:
   '     to your Win.INI file.
   '
   ' Comments:
   '     Requires the aht_apiWriteProfileString() declaration from basINIFile
   '     Requires type definitions from basPrintTypes

   Dim strBuffer As String

   ' Build up the appropriate string.
   strBuffer = dr.drDeviceName & ","
   strBuffer = strBuffer & dr.drDriverName & ","
   strBuffer = strBuffer & dr.drPort

   ' Now write that string out to WIN.INI.
   ahtSetDefaultPrinter = (aht_apiWriteProfileString("Windows", _
    "Device", strBuffer) <> 0)
End Function

Private Sub TestDefaultPrinter()
   
   ' Test the ahtDefaultPrinter() function.
   ' Fill in a DeviceRec structure with
   ' the pieces of the default printer info,
   ' and then print them out.

   Dim dr As aht_tagDeviceRec
   
   If ahtGetDefaultPrinter(dr) Then
      Debug.Print "Device: "; dr.drDeviceName
      Debug.Print "Driver: "; dr.drDriverName
      Debug.Print "Port  : "; dr.drPort
   End If
End Sub
0
 
LVL 84
Comment Utility
Albert Kallal provides a code module that helps with switching printers, and part of that code shows how to get a listing of the available printers:

http://www.members.shaw.ca/AlbertKallal/msaccess/msaccess.html
0
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 
LVL 10

Expert Comment

by:LennyGray
Comment Utility
you can easily add the printers on a custom menu and it would take literally seconds to so.

Are you trying to add a way to select printers?

I will be away for the next two days, so I would hope that one of the experts could direct this person in the method to make a custom menubar from the GUI for the printer.  




Good Luck !!
0
 
LVL 84

Accepted Solution

by:
Scott McDaniel (Microsoft Access MVP - EE MVE ) earned 500 total points
Comment Utility
You can also use code like this fill your combo. Simply copy/paste this code into a standard code module (name it something like basPrinters or such), then set your Combo's RowSourceType to "Value List" and the ColumnCount=3 and ColumnWidths=1;0;0. Call the EnumPrintersWinNT in your form's Load event, like this:

Private Sub Form_Load()
  EnumPrintersWinNT Me.cboPrinters
End Sub

Of course, replace "Me.cboPrinters" with the name of your combo. To "get" the name of the printer after your user selects one, use the AfterUpdate event of your combo:

Private Sub cboPrinters_AfterUpdate()
  MsgBox "You picked " & Me.cboPrinters.Column(0)
End Sub

Again, change the name to match the combo in your project.
Option Explicit
 

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

' Copyright ©1996-2006 VBnet, Randy Birch, All Rights Reserved.

' Some pages may also contain other copyrights by the author.

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

' Distribution: You can freely use this code in your own

'               applications, but you may not reproduce

'               or publish this code on any web site,

'               online service, or distribute as source

'               on any media without express permission.

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
 

Public Type PRINTER_INFO_1

   Flags As Long

   pDescription As Long

   Pane As Long

   Comment As Long

End Type
 

Public Type PRINTER_INFO_4

   pPrinterName As Long

   pServerName As Long

   Attributes As Long

End Type
 

'SIZEOFxxx are non-windows constants defined for this method

Public Const SIZEOFPRINTER_INFO_1 = 16

Public Const SIZEOFPRINTER_INFO_4 = 12
 

Public Const PRINTER_LEVEL1 = &H1

Public Const PRINTER_LEVEL4 = &H4
 

'EnumPrinters enumerates available printers,

'print servers, domains, or print providers.

Public Declare Function EnumPrinters Lib "winspool.drv" _

   Alias "EnumPrintersA" _

  (ByVal Flags As Long, _

   ByVal Name As String, _

   ByVal Level As Long, _

   pPrinterEnum As Any, _

   ByVal cbBuffer As Long, _

   pcbNeeded As Long, _

   pcReturned As Long) As Long
 

'EnumPrinters Parameters:

'Flags - Specifies the types of print objects that the function should enumerate.

Public Const PRINTER_ENUM_DEFAULT = &H1     'Windows 95: The function returns

                                            'information about the default printer.

Public Const PRINTER_ENUM_LOCAL = &H2       'function ignores the Name parameter,

                                            'and enumerates the locally installed

                                            'printers. Windows 95: The function will

                                            'also enumerate network printers because

                                            'they are handled by the local print provider

Public Const PRINTER_ENUM_CONNECTIONS = &H4 'Windows NT/2000: The function enumerates the

                                            'list of printers to which the user has made

                                            'previous connections

Public Const PRINTER_ENUM_NAME = &H8        'enumerates the printer identified by Name.

                                            'This can be a server, a domain, or a print

                                            'provider. If Name is NULL, the function

                                            'enumerates available print providers

Public Const PRINTER_ENUM_REMOTE = &H10     'Windows NT/2000: The function enumerates network

                                            'printers and print servers in the computer's domain.

                                            'This value is valid only if Level is 1

Public Const PRINTER_ENUM_SHARED = &H20     'enumerates printers that have the shared attribute.

                                            'Cannot be used in isolation; use an OR operation

                                            'to combine with another PRINTER_ENUM type

Public Const PRINTER_ENUM_NETWORK = &H40    'Windows NT/2000: The function enumerates network

                                            'printers in the computer's domain. This value is

                                            'valid only if Level is 1.
 

'''''''''''''''''''''''

'Name:

'If Level is 1, Flags contains PRINTER_ENUM_NAME, and Name is non-NULL,

'then Name is a pointer to a null-terminated string that specifies the

'name of the object to enumerate. This string can be the name of a server,

'a domain, or a print provider.

'

'If Level is 1, Flags contains PRINTER_ENUM_NAME, and Name is NULL, then

'the function enumerates the available print providers.

'

'If Level is 1, Flags contains PRINTER_ENUM_REMOTE, and Name is NULL, then

'the function enumerates the printers in the user's domain.

'

'If Level is 2 or 5, Name is a pointer to a null-terminated string that

'specifies the name of a server whose printers are to be enumerated. If

'this string is NULL, then the function enumerates the printers installed

'on the local machine.

'

'If Level is 4, Name should be NULL. The function always queries on

'the local machine.
 

'When Name is NULL, it enumerates printers that are installed on the

'local machine. These printers include those that are physically attached

'to the local machine as well as remote printers to which it has a

'network connection.
 

'''''''''''''''''''''''

'Level:

'Specifies the type of data structures pointed to by pPrinterEnum.

'Valid values are 1, 2, 4, and 5, which correspond to the

'PRINTER_INFO_1, PRINTER_INFO_2, PRINTER_INFO_4, and PRINTER_INFO_5

'data structures.

'

'Windows 95: The value can be 1, 2, or 5.

'

'Windows NT/Windows 2000: This value can be 1, 2, 4, or 5.
 

'''''''''''''''''''''''

'pPrinterEnum:

'Pointer to a buffer that receives an array of PRINTER_INFO_1,

'PRINTER_INFO_2, PRINTER_INFO_4, or PRINTER_INFO_5 structures.

'Each structure contains data that describes an available print object.

'

'If Level is 1, the array contains PRINTER_INFO_1 structures.

'If Level is 2, the array contains PRINTER_INFO_2 structures.

'If Level is 4, the array contains PRINTER_INFO_4 structures.

'If Level is 5, the array contains PRINTER_INFO_5 structures.

'

'The buffer must be large enough to receive the array of data

'structures and any strings or other data to which the structure

'members point. If the buffer is too small, the pcbNeeded parameter

'returns the required buffer size.

'

'Windows 95: The buffer cannot receive PRINTER_INFO_4 structures.

'It can receive any of the other types.
 

'''''''''''''''''''''''

'cbBuf

'Specifies the size, in bytes, of the buffer pointed to by pPrinterEnum.

'''''''''''''''''''''''

'pcbNeeded

'Pointer to a value that receives the number of bytes copied if the

'function succeeds or the number of bytes required if cbBuffer is too small.

'''''''''''''''''''''''

'pcReturned

'Pointer to a value that receives the number of PRINTER_INFO_1,

'PRINTER_INFO_2, PRINTER_INFO_4, or PRINTER_INFO_5 structures that

'the function returns in the array to which pPrinterEnum points.
 
 

'PRINTER_INFO_4 returned Attribute values

Public Const PRINTER_ATTRIBUTE_DEFAULT = &H4

Public Const PRINTER_ATTRIBUTE_DIRECT = &H2

Public Const PRINTER_ATTRIBUTE_ENABLE_BIDI = &H800&

Public Const PRINTER_ATTRIBUTE_LOCAL = &H40

Public Const PRINTER_ATTRIBUTE_NETWORK = &H10

Public Const PRINTER_ATTRIBUTE_QUEUED = &H1

Public Const PRINTER_ATTRIBUTE_SHARED = &H8

Public Const PRINTER_ATTRIBUTE_WORK_OFFLINE = &H400
 

'PRINTER_INFO_1 returned Flag values

Public Const PRINTER_ENUM_CONTAINER = &H8000&

Public Const PRINTER_ENUM_EXPAND = &H4000

Public Const PRINTER_ENUM_ICON1 = &H10000

Public Const PRINTER_ENUM_ICON2 = &H20000

Public Const PRINTER_ENUM_ICON3 = &H40000

Public Const PRINTER_ENUM_ICON4 = &H80000

Public Const PRINTER_ENUM_ICON5 = &H100000

Public Const PRINTER_ENUM_ICON6 = &H200000

Public Const PRINTER_ENUM_ICON7 = &H400000

Public Const PRINTER_ENUM_ICON8 = &H800000
 

Public Const LB_SETTABSTOPS As Long = &H192
 

Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" _

  (ByVal hwnd As Long, _

   ByVal wMsg As Long, _

   ByVal wParam As Long, _

   lParam As Any) As Long

   

Public Declare Function lstrcpyA Lib "kernel32" _

  (ByVal RetVal As String, ByVal ptr As Long) As Long

                        

Public Declare Function lstrlenA Lib "kernel32" _

  (ByVal ptr As Any) As Long

  

Private Declare Function SetDefaultWindowsPrinter Lib "winspool.drv" _

   Alias "SetDefaultPrinterA" _

  (ByVal pszPrinter As String) As Long
 

Function GetStrFromPtrA(ByVal lpszA As Long) As String
 

   GetStrFromPtrA = String$(lstrlenA(ByVal lpszA), 0)

   Call lstrcpyA(ByVal GetStrFromPtrA, ByVal lpszA)

   

End Function

 

 

Public Function SetAsDefaultPrinter(PrinterName As String) As Boolean

'/Purpose:

'/Parameters:

'/    PrinterName

'/Returns: Boolean

'/Created: 3/6/2007

'/Created By: Scott
 
 

  Dim i       As Integer

  Dim blnSet  As Boolean
 

On Error GoTo Err_SetAsDefaultPrinter
 

    For i = 0 To Application.Printers.Count - 1

        If Application.Printers(i).DeviceName = PrinterName Then

          Set Application.Printer = Application.Printers(i)

          blnSet = True

          Exit For

        End If 'If Application.Printers(i).DeviceName = PrinterName

    Next i
 

  SetAsDefaultPrinter = blnSet
 

Exit_SetAsDefaultPrinter:

  On Error Resume Next

  Exit Function
 

Err_SetAsDefaultPrinter:

  Select Case Err

    'case

    'case

    Case Else

     MsgBox Err & ":" & Error$, vbCritical, "basPrinters" & ": " & "SetAsDefaultPrinter"

  End Select

  

  Resume Exit_SetAsDefaultPrinter
 

End Function
 

 

Public Function IsPrinterAvailable(PrinterName As String) As Boolean

  '/Purpose:

  '/Parameters:

  '/    PrinterName

  '/Returns: Boolean

  '/Created: 3/5/2007

  '/Created By: Scott
 

  Dim cbRequired  As Long

  Dim cbBuffer    As Long

  Dim ptr()       As PRINTER_INFO_4

  Dim nEntries    As Long

  Dim cnt         As Long
 

  On Error GoTo Err_IsPrinterAvailable
 

  Call EnumPrinters(PRINTER_ENUM_CONNECTIONS Or PRINTER_ENUM_LOCAL, _

  vbNullString, PRINTER_LEVEL4, _

  0, 0, cbRequired, nEntries)

   

  ReDim ptr((cbRequired \ SIZEOFPRINTER_INFO_4))

  cbBuffer = cbRequired

    

  'Enumerate the printers. If the function succeeds,

  'the return value is nonzero. If the function fails,

  'the return value is zero.

    If EnumPrinters(PRINTER_ENUM_CONNECTIONS Or PRINTER_ENUM_LOCAL, _

      vbNullString, PRINTER_LEVEL4, _

      ptr(0), cbBuffer, _

      cbRequired, nEntries) Then

              

        For cnt = 0 To nEntries - 1

           

            With ptr(cnt)

              '/If GetStrFromPtrA(.pPrinterName) = "hp LaserJet 1000" Then Stop

                If PrinterName = GetStrFromPtrA(.pPrinterName) Then

                  IsPrinterAvailable = True

                  Exit For

                End If 'If PrinterName = GetStrFromPtrA(.pPrinterName)

            End With

              

        Next cnt

    End If 'If EnumPrinters(PRINTER_ENUM_CONNECTIONS Or PRINTER_ENUM_LOCAL,vbNullString, PRINTER_LEVEL4,ptr(0), cbBuffer,cbRequired, nEntries)
 

Exit_IsPrinterAvailable:

  On Error Resume Next

  Erase ptr

  Exit Function
 

Err_IsPrinterAvailable:

    Select Case Err

      'case

      'case

      Case Else

        MsgBox Err & ":" & Error$, vbCritical, "basPrinters" & ": " & "IsPrinterAvailable"

    End Select

  

  

  Resume Exit_IsPrinterAvailable
 

End Function

 

 Function EnumPrintersWinNT(ctl As ComboBox) As Long

    

   Dim Success As Boolean

   Dim cbRequired As Long

   Dim cbBuffer As Long

   Dim ptr() As PRINTER_INFO_4

   Dim nEntries As Long

   Dim cnt As Long

   Dim sAttr As String

   

   ctl.RowSource = ""

   

  'To determine the required buffer size, call EnumPrinters with

  'cbBuffer set to zero. EnumPrinters fails, and Err.LastDLLError

  'returns ERROR_INSUFFICIENT_BUFFER, filling in the cbRequired

  'parameter with the size, in bytes, of the buffer required to

  'hold the array of structures and their data.

   

   Call EnumPrinters(PRINTER_ENUM_CONNECTIONS Or PRINTER_ENUM_LOCAL, _

                     vbNullString, PRINTER_LEVEL4, _

                     0, 0, cbRequired, nEntries)

            

   

  'The strings pointed to by each PRINTER_INFO_4 struct's members

  'reside in memory after the end of the array of structs. So we're

  'not only allocating memory for the structs themselves, but all the

  'strings pointed to by each struct's member as well.

   ReDim ptr((cbRequired \ SIZEOFPRINTER_INFO_4))

       

  'Set cbBuffer equal to the size of the buffer

   cbBuffer = cbRequired

    

  'Enumerate the printers. If the function succeeds,

  'the return value is nonzero. If the function fails,

  'the return value is zero.

   If EnumPrinters(PRINTER_ENUM_CONNECTIONS Or PRINTER_ENUM_LOCAL, _

                   vbNullString, PRINTER_LEVEL4, _

                   ptr(0), cbBuffer, _

                   cbRequired, nEntries) Then

              

      For cnt = 0 To nEntries - 1

           

         With ptr(cnt)

            

            '/If GetStrFromPtrA(.pPrinterName) = "hp LaserJet 1000" Then Stop

            

            sAttr = ""

               

            If (.Attributes And PRINTER_ATTRIBUTE_DEFAULT) Then sAttr = "default "

            If (.Attributes And PRINTER_ATTRIBUTE_DIRECT) Then sAttr = sAttr & "direct "

            If (.Attributes And PRINTER_ATTRIBUTE_ENABLE_BIDI) Then sAttr = sAttr & "bidirectional "

            If (.Attributes And PRINTER_ATTRIBUTE_LOCAL) Then sAttr = sAttr & "local "

            If (.Attributes And PRINTER_ATTRIBUTE_NETWORK) Then sAttr = sAttr & "net "

            If (.Attributes And PRINTER_ATTRIBUTE_QUEUED) Then sAttr = sAttr & "queued "

            If (.Attributes And PRINTER_ATTRIBUTE_SHARED) Then sAttr = sAttr & "shared "

            If (.Attributes And PRINTER_ATTRIBUTE_WORK_OFFLINE) Then sAttr = sAttr & "offline "

            

            ctl.AddItem GetStrFromPtrA(.pPrinterName) & ";" & _

                        GetStrFromPtrA(.pServerName) & ";" & _

                        sAttr
 

         End With

              

      Next cnt

        

   Else

      ctl.AddItem "Error enumerating printers."

   End If  'EnumPrinters

   

   EnumPrintersWinNT = nEntries

    

End Function

Open in new window

0
 
LVL 75

Expert Comment

by:DatabaseMX (Joe Anderson - Access MVP)
Comment Utility
Actually, I've never seen the need for the various code over the years for selecting printers.  If you bring up any report in print preview, you can right click (or use the File menu) and you have available (built in) the Print ... and Page Setup menus. From these dialogs, the use can select any printer that is installed and set other properties for either the printer and/or the page. In addition, you can create your own right click menu with further added functionality.  

I suppose the code might be necessary if ... you were not using print preview and needed to go directly to a specific printer.  I alway use print preview ... before shooting a load of paper out to a printer blindly.

mx
0
 

Author Comment

by:chestera
Comment Utility
databasemx

Office 2003 no longer supports Print dialog box in mail merge sendto printer. I need to select printer Number of copies and tray so I designed a smiple dialog box

 WordDoc.Application.ActivePrinter = pName
   WordDoc.Application.PrintOut Copies:=nCopies
   With Options
        .DefaultTray = "Tray" & nTray
   End With

I have since found via lsmconsulting I don't need this massive code I am currently using.

chestera




0
 

Author Comment

by:chestera
Comment Utility
lmsconsulting

I modified using your code now working 100%. problem with my code it wouldn't always populate variable pName from the combo box from time to time I would get invalid use of null. I think it might be how the combo box was set up. Anyway thanks for that code

chestera
0
 

Expert Comment

by:mytfein
Comment Utility
Hi Gentlemen,

If you have a few minutes,

Just posted a related question here:
     http://www.experts-exchange.com/Microsoft/Development/MS_Access/Q_25135122.html

Would LSM's solution work for my situation?
If so your help would be appreciated, bec. i do not know how to use the code.
tx, sandra
0

Featured Post

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

In the previous article, Using a Critera Form to Filter Records (http://www.experts-exchange.com/A_6069.html), the form was basically a data container storing user input, which queries and other database objects could read. The form had to remain op…
Regardless of which version on MS Access you are using, one of the harder data-entry forms to create is one where most data from previous entries needs to be appended to new records, especially when there are numerous fields and records involved.  W…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…
Familiarize people with the process of retrieving data from SQL Server using an Access pass-thru query. Microsoft Access is a very powerful client/server development tool. One of the ways that you can retrieve data from a SQL Server is by using a pa…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now