Option Explicit
Private Type GUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(0 To 7) As Byte
End Type
Private Type CLIP_INFO
RangeAddr As String
CutCopyMode As Long
End Type
#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 Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
#End If
Private Declare PtrSafe Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As LongPtr, ByVal hwnd As LongPtr, ByVal Msg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr
Private Declare PtrSafe Function RegisterWindowMessage Lib "user32" Alias "RegisterWindowMessageA" (ByVal lpString As String) As Long
Private Declare PtrSafe Function CreateWindowEx Lib "user32" Alias "CreateWindowExA" (ByVal dwExStyle As Long, ByVal lpClassName As String, ByVal lpWindowName As String, ByVal dwStyle As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hWndParent As LongPtr, ByVal hMenu As LongPtr, ByVal hInstance As LongPtr, lpParam As Any) As LongPtr
Private Declare PtrSafe Function DestroyWindow Lib "user32" (ByVal hwnd As LongPtr) As Long
Private Declare PtrSafe Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" (ByVal lpModuleName As String) As LongPtr
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) 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 GetForegroundWindow Lib "user32" () As LongPtr
Private Declare PtrSafe Function SetProp Lib "user32" Alias "SetPropA" (ByVal hwnd As LongPtr, ByVal lpString As String, ByVal hData As LongPtr) As Long
Private Declare PtrSafe Function GetProp Lib "user32" Alias "GetPropA" (ByVal hwnd As LongPtr, ByVal lpString As String) As LongPtr
Private Declare PtrSafe Function RemoveProp Lib "user32" Alias "RemovePropA" (ByVal hwnd As LongPtr, ByVal lpString As String) As LongPtr
Private Declare PtrSafe Function AccessibleObjectFromWindow Lib "OLEACC.DLL" (ByVal hwnd As LongPtr, ByVal dwId As Long, ByVal riid As LongPtr, ppvObject As Any) As Long
Private Declare PtrSafe Function IIDFromString Lib "ole32.dll" (ByVal lpsz As LongPtr, ByVal lpiid As LongPtr) As LongPtr
#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 CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function RegisterWindowMessage Lib "user32" Alias "RegisterWindowMessageA" (ByVal lpString As String) As Long
Private Declare Function CreateWindowEx Lib "user32" Alias "CreateWindowExA" (ByVal dwExStyle As Long, ByVal lpClassName As String, ByVal lpWindowName As String, ByVal dwStyle As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hWndParent As Long, ByVal hMenu As Long, ByVal hInstance As Long, lpParam As Any) As Long
Private Declare Function DestroyWindow Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" (ByVal lpModuleName As String) As Long
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) 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 GetForegroundWindow Lib "user32" () As Long
Private Declare Function SetProp Lib "user32" Alias "SetPropA" (ByVal hwnd As Long, ByVal lpString As String, ByVal hData As Long) As Long
Private Declare Function GetProp Lib "user32" Alias "GetPropA" (ByVal hwnd As Long, ByVal lpString As String) As Long
Private Declare Function RemoveProp Lib "user32" Alias "RemovePropA" (ByVal hwnd As Long, ByVal lpString As String) As Long
Private Declare Function AccessibleObjectFromWindow Lib "OLEACC.DLL" (ByVal hwnd As Long, ByVal dwId As Long, ByVal riid As Long, ppvObject As Any) As Long
Private Declare Function IIDFromString Lib "ole32.dll" (ByVal lpsz As Long, ByVal lpiid As Long) As Long
#End If
Private sRangAddr As String
Private lCCMode As Long
Private WM_MSO_BROADCASTCHANGE As Long
Sub Test()
Dim uInfo As CLIP_INFO
Dim sMsg As String
uInfo = GetInfo
With uInfo
If Len(.RangeAddr) Then
sMsg = "Clipboard Operation : "
sMsg = sMsg & IIf(.CutCopyMode = 1, "COPY", "CUT") & vbNewLine
sMsg = sMsg & "Range in question : " & .RangeAddr
MsgBox sMsg
End If
End With
End Sub
'__________________________________________PUBLIC ROUTINES________________________________________________
Public Property Let EnableClipBoardMonitor(ByVal bEnable As Boolean)
Const WS_POPUP = &H80000000
Const GWL_WNDPROC = -4
#If Win64 Then
Dim hClipMonitor As LongLong, lPrevProc As LongLong
#Else
Dim hClipMonitor As Long, lPrevProc As Long
#End If
If bEnable Then
If GetProp(hClipMonitor, "hClipMonitor") = 0 Then
hClipMonitor = CreateWindowEx(0, "Static", "MyClipMonitor", WS_POPUP, 0, 0, 0, 0, 0, 0, GetModuleHandle(vbNullString), 0)
WM_MSO_BROADCASTCHANGE = RegisterWindowMessage("WM_MSO_BROADCASTCHANGE")
lPrevProc = SetWindowLong(hClipMonitor, GWL_WNDPROC, AddressOf WinProc)
Call SetProp(hClipMonitor, "hClipMonitor", hClipMonitor)
Call SetProp(hClipMonitor, "PrevProc", lPrevProc)
End If
Else
Call CleanUp
End If
End Property
Public Function GetInfo() As CLIP_INFO
If Len(sRangAddr) Then
With GetInfo
.RangeAddr = sRangAddr
.CutCopyMode = lCCMode
End With
ElseIf FindWindow("Static", "MyClipMonitor") And GetApp.CutCopyMode = 0 Then
MsgBox "Either there is no range currently being cut or copied OR" & vbNewLine & _
"the Cut\Copy operation was performed before enabling the ClipboardMonitor routine."
Else
MsgBox "The ClipBoardMonitor is not enabled."
End If
End Function
'__________________________________________PRIVATE ROUTINES________________________________________________
Private Sub CleanUp()
Const GWL_WNDPROC = -4
#If Win64 Then
Dim hClipMonitor As LongLong
#Else
Dim hClipMonitor As Long
#End If
hClipMonitor = FindWindowEx(0, hClipMonitor, "Static", "MyClipMonitor")
Do
hClipMonitor = FindWindowEx(0, 0, "Static", "MyClipMonitor")
If hClipMonitor = 0 Then
Exit Do
Else
Call SetWindowLong(hClipMonitor, GWL_WNDPROC, GetProp(GetProp(hClipMonitor, "HWND"), "PrevProc"))
Call RemoveProp(hClipMonitor, "PrevProc")
Call RemoveProp(hClipMonitor, "HWND")
Call DestroyWindow(hClipMonitor)
End If
Loop
sRangAddr = vbNullString
lCCMode = 0
End Sub
Private Function GetApp() As Application
Const S_OK = &H0&
Const IID_DISPATCH = "{00020400-0000-0000-C000-000000000046}"
Const OBJID_NATIVEOM = &HFFFFFFF0
#If Win64 Then
Dim hXl As LongLong, hDsk As LongLong, hWb As LongLong
#Else
Dim hXl As Long, hDsk As Long, hWb As Long
#End If
Dim oWB As Object
Dim tGUID(0 To 3) As Long
If Application.CutCopyMode <> False Then
Set GetApp = Application
Exit Function
End If
Do
hXl = FindWindowEx(0, hXl, "XLMAIN", vbNullString)
If hXl = 0 Then
Exit Do
ElseIf hXl = GetForegroundWindow Then
hDsk = FindWindowEx(hXl, 0&, "XLDESK", vbNullString)
hWb = FindWindowEx(hDsk, 0&, "EXCEL7", vbNullString)
If hWb Then
If IIDFromString(strPtr(IID_DISPATCH), VarPtr(tGUID(0))) = S_OK Then
Call AccessibleObjectFromWindow _
(hWb, OBJID_NATIVEOM, VarPtr(tGUID(0)), oWB)
Set GetApp = oWB.Application
Exit Do
End If
End If
End If
Loop
Set oWB = Nothing
End Function
#If Win64 Then
Private Function WinProc(ByVal hwnd As LongLong, ByVal Msg As Long, ByVal wParam As LongLong, ByVal lParam As LongLong) As LongLong
#Else
Private Function WinProc(ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
#End If
Const GWL_WNDPROC = -4
Const WM_DESTROY = &H2
Dim sRngAddr As String
Dim oXL As Application
On Error Resume Next
Select Case Msg
Case WM_MSO_BROADCASTCHANGE
Set oXL = GetApp
If oXL.CutCopyMode = 0 Then
sRangAddr = vbNullString
lCCMode = 0
Else
sRngAddr = oXL.ActiveWindow.RangeSelection.Address(, , , True)
If Len(sRngAddr) Then
sRangAddr = sRngAddr
lCCMode = oXL.CutCopyMode
End If
End If
Case WM_DESTROY
Call SetWindowLong(hwnd, GWL_WNDPROC, GetProp(hwnd, "PrevProc"))
End Select
WinProc = CallWindowProc(GetProp(hwnd, "PrevProc"), hwnd, Msg, wParam, ByVal lParam)
End Function
Private Sub Auto_Close()
EnableClipBoardMonitor = False
End Sub