Option Explicit
Implements IPrintWatcher
Private WithEvents ExcelAppEvents As Excel.Application
Private WithEvents WordAppEvents As Word.Application
#If VBA7 Then
#If Win64 Then
Private Declare PtrSafe Function SetWindowLong Lib "user32" Alias "SetWindowLongPtrA" (ByVal hwnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As LongPtr) As LongPtr
#Else
Private Declare PtrSafe Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As LongPtr) As LongPtr
#End If
Private Declare PtrSafe Function IUnknown_GetWindow Lib "shlwapi" Alias "#172" (ByVal pIUnk As IUnknown, ByVal hwnd As LongPtr) As Long
Private Declare PtrSafe Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As LongPtr, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare PtrSafe Function GetForegroundWindow Lib "user32" () As LongPtr
Private Declare PtrSafe Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, ByVal lpsz1 As String, ByVal lpsz2 As String) As LongPtr
Private Declare PtrSafe Function AccessibleObjectFromWindow Lib "oleacc" (ByVal hwnd As LongPtr, ByVal dwId As Long, ByVal riid As LongPtr, ByVal ppvObject As LongPtr) As Long
Private Declare PtrSafe Function IIDFromString Lib "ole32.dll" (ByVal lpsz As LongPtr, ByVal lpiid As LongPtr) As LongPtr
Private Declare PtrSafe Function GetDefaultPrinter Lib "winspool.drv" Alias "GetDefaultPrinterA" (ByVal pszBuffer As String, pcchBuffer As Long) As Long
#Else
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function IUnknown_GetWindow Lib "shlwapi" Alias "#172" (ByVal pIUnk As IUnknown, ByVal hwnd As Long) As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function GetForegroundWindow Lib "user32" () As Long
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function AccessibleObjectFromWindow Lib "oleacc" (ByVal hwnd As Long, ByVal dwId As Long, ByVal riid As Long, ByVal ppvObject As Long) As Long
Private Declare Function IIDFromString Lib "ole32.dll" (ByVal lpsz As Long, ByVal lpiid As Long) As Long
Private Declare Function GetDefaultPrinter Lib "winspool.drv" Alias "GetDefaultPrinterA" (ByVal pszBuffer As String, pcchBuffer As Long) As Long
#End If
Private oFileListRange As Range
'IPrinterWatcher Interface Functions.
Private Property Set IPrintWatcher_FileListRange(ByVal FileList As Range)
Set oFileListRange = FileList
End Property
Private Sub IPrintWatcher_StartWatching()
Call StartTimer
End Sub
Private Sub IPrintWatcher_StopWatching()
Call StopTimer
Set WordAppEvents = Nothing
Unload Me
End Sub
'UPrinterWatcher UserForm Open\Close\Hide.
Private Sub UserForm_Initialize()
Me.Tag = "PrintWatcher"
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = 0 Then
Cancel = True
Me.Hide
Else
Cancel = False
End If
End Sub
Private Sub CommandButton1_Click()
Me.Hide
End Sub
'EXCEL\WORD BeforePrint Events.
Private Sub ExcelAppEvents_WorkbookBeforePrint(ByVal Wb As Workbook, Cancel As Boolean)
Cancel = CancelPrinting(Wb)
End Sub
Private Sub WordAppEvents_DocumentBeforePrint(ByVal Doc As Word.Document, Cancel As Boolean)
Cancel = CancelPrinting(Doc)
End Sub
'Supporting Routines.
Private Function CancelPrinting(ByVal oObj As Object) As Boolean
Const GWL_HWNDPARENT = (-8)
#If Win64 Then
Dim hwnd As LongLong
#Else
Dim hwnd As Long
#End If
Dim vFilesList() As Variant
If Evaluate("CountA(" & oFileListRange.Address & ")") Then
vFilesList() = Application.Transpose(oFileListRange)
If Not IsError(Application.Match(oObj.FullName, vFilesList, 0)) Then
'A file in the list (oFileListRange) is about to be printed, so abort the printing now.
CancelPrinting = True
Call IUnknown_GetWindow(Me, VarPtr(hwnd))
Call SetWindowLong(hwnd, GWL_HWNDPARENT, GetForegroundWindow)
With Me
.Caption = GetPrinterName
.Label1.Caption = "Sorry, printing is disabled for the following file :"
.Label2.Caption = Chr(149) & " " & oObj.FullName
.Show vbModeless
End With
End If
End If
End Function
#If Win64 Then
Private Function GetObjectRef(ByVal hwnd As LongLong, ByVal sClassName As String) As Object
#Else
Private Function GetObjectRef(ByVal hwnd As Long, ByVal sClassName As String) As Object
#End If
Const IID_DISPATCH = "{00020400-0000-0000-C000-000000000046}"
Const OBJID_NATIVEOM = &HFFFFFFF0
Const S_OK = 0&
Dim tDisp(0 To 3) As Long
Dim oWnd As Object
If IIDFromString(StrPtr(IID_DISPATCH), VarPtr(tDisp(0))) = S_OK Then
Select Case sClassName
Case "OpusApp" 'Word App
hwnd = FindWindowEx(hwnd, 0&, "_WwF", vbNullString)
hwnd = FindWindowEx(hwnd, 0&, "_WwB", vbNullString)
hwnd = FindWindowEx(hwnd, 0&, "_WwG", vbNullString)
Case "XLMAIN" 'Excel App
hwnd = FindWindowEx(hwnd, 0&, "XLDESK", vbNullString)
hwnd = FindWindowEx(hwnd, 0&, "EXCEL7", vbNullString)
End Select
If hwnd Then
If AccessibleObjectFromWindow(hwnd, OBJID_NATIVEOM, VarPtr(tDisp(0)), VarPtr(oWnd)) = S_OK Then
Set GetObjectRef = oWnd.Application
End If
End If
End If
End Function
Private Function GetPrinterName() As String
Dim sBuffer As String, lSize As Long
Call GetDefaultPrinter(vbNullString, lSize)
sBuffer = Space(lSize)
Call GetDefaultPrinter(sBuffer, lSize)
GetPrinterName = Left(sBuffer, Len(sBuffer) - 1)
End Function
Public Function TimerProc()
#If Win64 Then
Dim hwnd As LongLong
#Else
Dim hwnd As Long
#End If
Dim sBuffer As String * 256, lRet As Long
On Error Resume Next
hwnd = GetForegroundWindow
lRet = GetClassName(hwnd, sBuffer, 256)
Select Case True
Case Left(sBuffer, lRet) = "XLMAIN"
Set ExcelAppEvents = GetObjectRef(hwnd, "XLMAIN")
Case Left(sBuffer, lRet) = "OpusApp"
Set WordAppEvents = GetObjectRef(hwnd, "OpusApp")
End Select
On Error GoTo 0
End Function