Xác định máy in có thể in bằng VBA Excel

Liên hệ QC

phamduylong

-
Thành viên đã mất
Tham gia
30/12/06
Bài viết
918
Được thích
2,370
Nghề nghiệp
Giáo viên
Trong danh sách máy in, có thể có nhiều máy in.Tất cả các máy in trên đều liệt kê trong combobox Name của form Print :
Print-1.jpg


- Máy in sằn sàng hoạt động : có nối với PC, cấp điện và sẳn sàng in.
- Máy in không hoạt động : không có máy in hoặc chưa nối với PC.
- Máy in trong mạng.

Người dùng có thể chọn 1 máy in trong danh sách để in, nhưng không thể biết được máy in nào sẳn sàng để in.
Nếu chọn trúng máy in không hoạt động, Excel vẫn ra lệnh in và một thời gian mới báo lỗi, phải thoát máy in. Rất bất tiện.
Để mở rộng các chức năng in trong bài In trang chẳn, lẻ trong Excel
nhờ các bạn giúp các lệnh VBA Excel để :
- Liệt kê tất cả máy in có trong Windows.
- Biết được máy in nào sẳn sàng hoạt động.
- Thay đổi máy in khi ra lệnh in.
 
Lần chỉnh sửa cuối:
Không biết bài bên dưới có giúp ích gì cho Thầy không, nhưng em cũng mạo muội post lên để anh em cùng chia sẻ và thảo luận.
1. Đầu tiên ta phải khai báo một số thông số sau:
PHP:
Type FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type
''--------------------------------
Declare Function RegOpenKeyEx _
   Lib "advapi32.dll" _
   Alias "RegOpenKeyExA" _
   ( _
   ByVal hKey As Long, _
   ByVal lpSubKey As String, _
   ByVal ulOptions As Long, _
   ByVal samDesired As Long, _
   phkResult As Long _
   ) _
   As Long
''--------------------------------'
Declare Function RegEnumKeyEx _
   Lib "advapi32.dll" _
   Alias "RegEnumKeyExA" _
   ( _
   ByVal hKey As Long, _
   ByVal dwIndex As Long, _
   ByVal lpName As String, _
   lpcbName As Long, ByVal _
   lpReserved As Long, _
   ByVal lpClass As String, _
   lpcbClass As Long, _
   lpftLastWriteTime As FILETIME _
   ) _
   As Long
''--------------------------------'
Declare Function RegCloseKey _
   Lib "advapi32.dll" _
   ( _
   ByVal hKey As Long _
   ) _
   As Long
Sau đó là một Public Function:
PHP:
Public Function fncEnumInstalledPrintersReg() As Collection
   Dim tmpFunctionResult As Boolean
   Dim aFileTimeStruc As FILETIME
   Dim AddressofOpenKey As Long, aPrinterName As String
   Dim aPrinterIndex As Integer, aPrinterNameLen As Long
   Const KEY_ENUMERATE_SUB_KEYS = &H8
   Const HKEY_LOCAL_MACHINE = &H80000002
   Set fncEnumInstalledPrintersReg = New Collection
   aPrinterIndex = 0
   tmpFunctionResult = Not CBool _
      ( _
      RegOpenKeyEx _
      ( _
      hKey:=HKEY_LOCAL_MACHINE, _
      lpSubKey:="SYSTEM\CURRENTCONTROLSET\CONTROL\PRINT\PRINTERS", _
      ulOptions:=0, _
      samDesired:=KEY_ENUMERATE_SUB_KEYS, _
      phkResult:=AddressofOpenKey _
      ) _
      )
   If tmpFunctionResult = False Then GoTo ExitFunction
   Do
      aPrinterNameLen = 255
      aPrinterName = String(aPrinterNameLen, CStr(0))
      tmpFunctionResult = Not CBool _
         ( _
         RegEnumKeyEx _
         ( _
         hKey:=AddressofOpenKey, _
         dwIndex:=aPrinterIndex, _
         lpName:=aPrinterName, _
         lpcbName:=aPrinterNameLen, _
         lpReserved:=0, _
         lpClass:=vbNullString, _
         lpcbClass:=0, _
         lpftLastWriteTime:=aFileTimeStruc _
         ) _
         )
      aPrinterIndex = aPrinterIndex + 1
      If tmpFunctionResult = False Then Exit Do
      aPrinterName = Left(aPrinterName, aPrinterNameLen)
      On Error Resume Next
      fncEnumInstalledPrintersReg.Add aPrinterName
      On Error GoTo 0
   Loop
   Call RegCloseKey(AddressofOpenKey)
   '
   Exit Function
ExitFunction:
   If Not AddressofOpenKey = 0 Then _
      Call RegCloseKey(AddressofOpenKey)
   Set fncEnumInstalledPrintersReg = Nothing
End Function
2. Tiếp đến là tạo một UserForm với 1 Combobox và 1 nút In:
attachment.php


Và code cho UserForm này như sau:
PHP:
Private Sub UserForm_Activate()
Dim aPrinter As Variant, iRow As Long
cboPrintList.ColumnCount = 2
cboPrintList.ColumnHeads = False
iRow = 0
'-------------------------------------------------------'
For Each aPrinter In fncEnumInstalledPrintersReg
      cboPrintList.AddItem aPrinter
      lenPrinter = Len(aPrinter)
      If aPrinter <> Left(Application.ActivePrinter, lenPrinter) Then
      cboPrintList.List(iRow, 1) = "Not Active"
      Else
      cboPrintList.List(iRow, 1) = "Active"
      End If
      iRow = iRow + 1
Next aPrinter
End Sub
''//-----------------------------------------------------'
Private Sub cmdPrint_Click()
ActiveWindow.SelectedSheets.PrintOut Copies:=1, _
             ActivePrinter:=Me.cboPrintList.Value, Collate:=True
End Sub
Thầy xem thêm file đính kèm xem sao.

Tham khảo thêm tại đây:
http://www.mrexcel.com/forum/showthread.php?t=362766
http://www.vbaexpress.com/kb/getarticle.php?kb_id=528
 

File đính kèm

  • Book1.xls
    Book1.xls
    38.5 KB · Đọc: 150
  • 5.jpg
    5.jpg
    12.9 KB · Đọc: 237
Lần chỉnh sửa cuối:
Upvote 0
Code hay quá, cảm ơn anh vì đã chia sẻ.

Khi chay thử em thấy vẫn còn thiếu báo lỗi tí : Em cố tình tắt máy in đi, khi bấm print thì nó vẫn chạy bình thường.

Ý em là làm sao khi bấm Print, nếu không thể in được bằng máy in ta vừa chọn thì ra thông báo yêu cầu chọn máy in khác.
 
Upvote 0
Khi chay thử em thấy vẫn còn thiếu báo lỗi tí : Em cố tình tắt máy in đi, khi bấm print thì nó vẫn chạy bình thường.

Ý em là làm sao khi bấm Print, nếu không thể in được bằng máy in ta vừa chọn thì ra thông báo yêu cầu chọn máy in khác.
Mình đi theo hướng khác được không? Nghĩa là như thế này:
Search tìm những máy in nào có kết nối với máy tính của mình trong danh sách máy in của windows, sau đó mới đưa vào combobox. Như vậy Combobox sẽ chỉ chứa danh sách các máy in đã kết nối với máy tính.

Hoàng Danh tham khảo code sau (test lại vì ca_dafi không có máy in bên cạnh nhé)

[highlight=vb]
Option Explicit
Const PRINTER_ENUM_CONNECTIONS = &H4
Const PRINTER_ENUM_LOCAL = &H2
Private Declare Function EnumPrinters Lib "winspool.drv" Alias "EnumPrintersA" _
(ByVal flags As Long, ByVal name As String, ByVal Level As Long, _
pPrinterEnum As Long, ByVal cdBuf As Long, pcbNeeded As Long, _
pcReturned As Long) As Long
Private Declare Function PtrToStr Lib "kernel32" Alias "lstrcpyA" _
(ByVal RetVal As String, ByVal Ptr As Long) As Long
Private Declare Function StrLen Lib "kernel32" Alias "lstrlenA" _
(ByVal Ptr As Long) As Long
'\\------------------------------------------------------------------------------------
Public Function ListPrinters() As Variant
Dim bSuccess As Boolean
Dim iBufferRequired As Long
Dim iBufferSize As Long
Dim iBuffer() As Long
Dim iEntries As Long
Dim iIndex As Long
Dim strPrinterName As String
Dim iDummy As Long
Dim iDriverBuffer() As Long
Dim StrPrinters() As String
iBufferSize = 3072
ReDim iBuffer((iBufferSize \ 4) - 1) As Long
'EnumPrinters will return a value False if the buffer is not big enough
bSuccess = EnumPrinters(PRINTER_ENUM_CONNECTIONS Or _
PRINTER_ENUM_LOCAL, vbNullString, _
1, iBuffer(0), iBufferSize, iBufferRequired, iEntries)
If Not bSuccess Then
If iBufferRequired > iBufferSize Then
iBufferSize = iBufferRequired
Debug.Print "iBuffer too small. Trying again with "; _
iBufferSize & " bytes."
ReDim iBuffer(iBufferSize \ 4) As Long
End If
'Try again with new buffer
bSuccess = EnumPrinters(PRINTER_ENUM_CONNECTIONS Or _
PRINTER_ENUM_LOCAL, vbNullString, _
1, iBuffer(0), iBufferSize, iBufferRequired, iEntries)
End If

If Not bSuccess Then
'Enumprinters returned False
MsgBox "Error enumerating printers."
Exit Function
Else
'Enumprinters returned True, use found printers to fill the array
ReDim StrPrinters(iEntries - 1)
For iIndex = 0 To iEntries - 1
'Get the printername
strPrinterName = Space$(StrLen(iBuffer(iIndex * 4 + 2)))
iDummy = PtrToStr(strPrinterName, iBuffer(iIndex * 4 + 2))
StrPrinters(iIndex) = strPrinterName
Next iIndex
End If
ListPrinters = StrPrinters
End Function
'\\------------------------------------------------------------------------------------
''You could call the function as follows:
Public Function IsBounded(vArray As Variant) As Boolean
''If the variant passed to this function is an array, the function will return True;
''otherwise it will return False
On Error Resume Next
IsBounded = IsNumeric(UBound(vArray))
End Function[/highlight]Và Code cho Form:
[highlight=vb]
Private Sub cmdPrint_Click()
ActiveWindow.SelectedSheets.PrintOut Copies:=1, ActivePrinter:=Me.cboPrintList.Value, Collate:=True
End Sub
Private Sub UserForm_Activate()
cboPrintList.ColumnCount = 1
cboPrintList.ColumnHeads = False
Dim StrPrinters As Variant, iRow As Long
StrPrinters = ListPrinters
If IsBounded(StrPrinters) Then
For iRow = LBound(StrPrinters) To UBound(StrPrinters)
cboPrintList.AddItem StrPrinters(iRow)
Next iRow
End If
End Sub
[/highlight]Tham khảo thêm tại đây:
http://word.mvps.org/FAQs/MacrosVBA/AvailablePrinters.htm

Và tại đây:
http://pubs.logicalexpressions.com/pub0009/LPMArticle.asp?ID=183
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Nếu được như anh nói thì quá hay.
Em đã thử file 2, mặc dù máy in của em đã tắt, Trong list của Combobox vẫn xuất hiện máy in này và như thế khi in sẽ gặp lỗi ngay.
 
Upvote 0
Cả 2 file a_dafi gởi lên cũng không phân biệt được máy in nào sẳn sàng. Có hay không có máy in nó cũng cho in tuốt.
Mà có cái combobox này giúp cho người dùng chọn máy in là quá tốt rồi.Việc xác định máy in sẳn sàng chắc không đơn giản vì các Form Print ngay của Office cũng chả xác định được !
 
Upvote 0
Em cũng đã từng thử nhiều cách mà cũng không thành công. em có ý kiến là :

Khi bấm Print xong sẽ chạy thủ tục in. Nếu sau vài giây mà vẫn chưa thực hiện xong thủ tục in thì sẽ báo lỗi và thoát khỏi thủ tục, sau đó gọi lại form chọn máy in.
 
Upvote 0
Em cũng đã từng thử nhiều cách mà cũng không thành công. em có ý kiến là :

Khi bấm Print xong sẽ chạy thủ tục in. Nếu sau vài giây mà vẫn chưa thực hiện xong thủ tục in thì sẽ báo lỗi và thoát khỏi thủ tục, sau đó gọi lại form chọn máy in.

Danh xem thử code theo cách 1. Khi sổ combobox xuống, cột thứ hai của combobox nó có thể hiện status là Active hay Not Active.

Bây giờ:
- Bật máy in lên, rồi cho form chạy, xem cái status là gì?
- Sau đó tắt máy in đi, cho form chạy, xem cái status là gì?
 
Upvote 0
Danh xem thử code theo cách 1. Khi sổ combobox xuống, cột thứ hai của combobox nó có thể hiện status là Active hay Not Active.

Bây giờ:
- Bật máy in lên, rồi cho form chạy, xem cái status là gì?
- Sau đó tắt máy in đi, cho form chạy, xem cái status là gì?

Chữ Active hay Not Active chỉ cho biết là máy in nào đang được chọn để in thôi. VD trong list có 3 máy in, máy in nào có chữ Active thì máy in đó đang được chọn, và nó thường lấy lại cái Recent Active. Và trong list chỉ có duy nhất 1 máy in có ghi chú Active thôi.
 
Upvote 0
ở nhà lại không có máy in thật cài tạm một cái, rồi cho nó trạng thái offline để test thì thấy đúng là nhận ra nó offline thật (TRUE)
PrinterOffline.JPG


PHP:
Sub PrinterOffline()
    Dim strWhere As String
    Dim objWMI As Object
    Dim objPrinters As Object
    Dim objPrinter As Object
 
    Set objWMI = GetObject("winmgmts:\\.\root\CIMV2")
 
    k = 0
For Each n In Range("A1:A4")
    strWhere = "Name = '" & n.Value & "'"
    Set objPrinters = objWMI.ExecQuery("SELECT * FROM Win32_Printer WHERE " & strWhere)
    For Each objPrinter In objPrinters
    k = k + 1
    Cells(k, 2).Value = objPrinter.WorkOffline
    Next
Next
    Set objPrinter = Nothing
    Set objPrinters = Nothing
    Set objWMI = Nothing
End Sub
Tiện thể giới thiệu cho bà con site up ảnh tốt phết, nó up lên google nên không sợ mất mà lại nhanh http://www.up2store.com/filelist.aspx
Chứ up tại diễn đàn khôgn đăng nhập không nhìn thấy hình

Hôm nay đến cơ quan có máy in thật thêm cái hàm kiểm tra máy in online vào cách 2 phía trên là hoàn thiện
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Upvote 0
Trong danh sách máy in, có thể có nhiều máy in.Tất cả các máy in trên đều liệt kê trong combobox Name của form Print :
Print-1.jpg


- Máy in sằn sàng hoạt động : có nối với PC, cấp điện và sẳn sàng in.
- Máy in không hoạt động : không có máy in hoặc chưa nối với PC.
- Máy in trong mạng.

Người dùng có thể chọn 1 máy in trong danh sách để in, nhưng không thể biết được máy in nào sẳn sàng để in.
Nếu chọn trúng máy in không hoạt động, Excel vẫn ra lệnh in và một thời gian mới báo lỗi, phải thoát máy in. Rất bất tiện.
Để mở rộng các chức năng in trong bài In trang chẳn, lẻ trong Excel
nhờ các bạn giúp các lệnh VBA Excel để :
- Liệt kê tất cả máy in có trong Windows.
- Biết được máy in nào sẳn sàng hoạt động.
- Thay đổi máy in khi ra lệnh in.

cho mình hỏi, đã gội được Printer thì có code nào gọi được Scaner không?
Ví dụ mình có 1 Nút lệnh trong Excel tên là "Scan" khi bấm vào nó nó sẽ tự tạo 1 file Word và mở file Word lên sau đó gọi Scaner để scan vào Word (IsertImageScan)
 
Upvote 0
Các anh/chị cho em hỏi chút. Nếu em muốn kiểm tra xem máy in đã in xong 1 lệnh dc truyền từ file pdf hay excel hay chưa thì dùng code gì ạ
 
Upvote 0
Web KT

Bài viết mới nhất

Back
Top Bottom