Option Explicit
Private Const IMAGE_BITMAP As Long = 0
Private Const LR_COPYRETURNORG As Long = &H4
Private Const CF_BITMAP As Long = 2
Private Const S_OK As Long = 0
Private Type GUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(0 To 7) As Byte
End Type
Private Type GdiplusStartupInput
GdiplusVersion As Long
#If VBA7 Then
DebugEventCallback As LongPtr
SuppressBackgroundThread As LongPtr
#Else
DebugEventCallback As Long
SuppressBackgroundThread As Long
#End If
SuppressExternalCodecs As Long
End Type
Private Type EncoderParameter
GUID As GUID
NumberOfValues As Long
Type As Long
#If VBA7 Then
Value As LongPtr
#Else
Value As Long
#End If
End Type
Private Type EncoderParameters
Count As Long
Parameter As EncoderParameter
End Type
#If VBA7 Then
Private Declare PtrSafe Function IUnknown_GetWindow Lib "shlwapi" Alias "#172" (ByVal pIUnk As IUnknown, ByVal hUf As LongPtr) As Long
Private Declare PtrSafe Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)
Private Declare PtrSafe Function CopyImage Lib "user32" (ByVal handle As LongPtr, ByVal un1 As Long, ByVal n1 As Long, ByVal n2 As Long, ByVal un2 As Long) As LongPtr
Private Declare PtrSafe Function OpenClipboard Lib "user32" (ByVal hWnd As LongPtr) As Long
Private Declare PtrSafe Function CloseClipboard Lib "user32" () As Long
Private Declare PtrSafe Function EmptyClipboard Lib "user32" () As Long
Private Declare PtrSafe Function GetClipboardData Lib "user32" (ByVal wFormat As Long) As LongPtr
Private Declare PtrSafe Function GdiplusStartup Lib "GDIPlus" (token As LongPtr, inputbuf As GdiplusStartupInput, Optional ByVal outputbuf As Long = 0) As Long
Private Declare PtrSafe Function GdiplusShutdown Lib "GDIPlus" (ByVal token As LongPtr) As Long
Private Declare PtrSafe Function GdipCreateBitmapFromHBITMAP Lib "GDIPlus" (ByVal hbm As LongPtr, ByVal hPal As LongPtr, Bitmap As LongPtr) As Long
Private Declare PtrSafe Function GdipDisposeImage Lib "GDIPlus" (ByVal Image As LongPtr) As LongPtr
Private Declare PtrSafe Function GdipSaveImageToFile Lib "GDIPlus" (ByVal Image As LongPtr, ByVal Filename As LongPtr, clsidEncoder As GUID, encoderParams As Any) As Long
Private Declare PtrSafe Function CLSIDFromString Lib "ole32" (ByVal str As LongPtr, id As GUID) As Long
Private Declare PtrSafe Function SetForegroundWindow Lib "user32" (ByVal hWnd As LongPtr) As Long
Private Declare PtrSafe Function SetFocus Lib "user32" (ByVal hWnd As LongPtr) As LongPtr
Private Declare PtrSafe Function DeleteObject Lib "gdi32" (ByVal hObject As LongPtr) As Long
Private Declare PtrSafe Function ShowCursor Lib "user32" (ByVal bShow As Long) As Long
Dim GDIPToken As LongPtr, hBitmap As LongPtr, hCopy As LongPtr, hPtr As LongPtr, hWnd As LongPtr
#Else
Private Declare Function IUnknown_GetWindow Lib "shlwapi" Alias "#172" (ByVal pIUnk As IUnknown, ByVal hUf As Long) As Long
Private Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)
Private Declare Function CopyImage Lib "user32" (ByVal handle As Long, ByVal un1 As Long, ByVal n1 As Long, ByVal n2 As Long, ByVal un2 As Long) As Long
Private Declare Function OpenClipboard Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function CloseClipboard Lib "user32" () As Long
Private Declare Function EmptyClipboard Lib "user32" () As Long
Private Declare Function GetClipboardData Lib "user32" (ByVal wFormat As Long) As Long
Private Declare Function GdiplusStartup Lib "GDIPlus" (token As Long, inputbuf As GdiplusStartupInput, Optional ByVal outputbuf As Long = 0) As Long
Private Declare Function GdiplusShutdown Lib "GDIPlus" (ByVal token As Long) As Long
Private Declare Function GdipCreateBitmapFromHBITMAP Lib "GDIPlus" (ByVal hbm As Long, ByVal hPal As Long, Bitmap As Long) As Long
Private Declare Function GdipDisposeImage Lib "GDIPlus" (ByVal Image As Long) As Long
Private Declare Function GdipSaveImageToFile Lib "GDIPlus" (ByVal Image As Long, ByVal Filename As Long, clsidEncoder As GUID, encoderParams As Any) As Long
Private Declare Function CLSIDFromString Lib "ole32" (ByVal str As Long, id As GUID) As Long
Private Declare Function SetForegroundWindow Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function SetFocus Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function ShowCursor Lib "user32" (ByVal bShow As Long) As Long
Dim GDIPToken As Long, hBitmap As Long, hCopy As Long, hPtr As Long, hWnd As Long
#End If
Public Sub UserFormSnapshot(ByVal UForm As Object, ByVal Filename As String, Optional ByVal HideMouse As Boolean = True, Optional ByVal TimerDelay As Long)
Call IUnknown_GetWindow(UForm, VarPtr(hWnd))
If Not hWnd = 0 Then
CaptureWindow HideMouse, TimerDelay
Dim tSI As GdiplusStartupInput, Result As Long
Dim tEncoder As GUID, TParams As EncoderParameters
OpenClipboard 0
hPtr = GetClipboardData(CF_BITMAP)
hCopy = CopyImage(hPtr, IMAGE_BITMAP, 0, 0, LR_COPYRETURNORG)
tSI.GdiplusVersion = 1
Result = GdiplusStartup(GDIPToken, tSI)
If Result = 0 Then
Result = GdipCreateBitmapFromHBITMAP(hCopy, 0, hBitmap)
If Result = 0 Then
CLSIDFromString StrPtr("{557CF406-1A04-11D3-9A73-0000F81EF32E}"), tEncoder
TParams.Count = 1
Result = GdipSaveImageToFile(hBitmap, StrPtr(Filename), tEncoder, TParams)
GdipDisposeImage hBitmap
End If
GdiplusShutdown GDIPToken
End If
End If
errHandler:
EmptyClipboard
CloseClipboard
DeleteObject hCopy
If Result Then Err.Raise 5, , "Cannot save the image. GDI+ Error:" & Result
End Sub
Private Sub CaptureWindow(Optional ByVal HideMouse As Boolean = True, Optional ByVal TimerDelay As Long)
If HideMouse Then Call ShowMouse(False)
SetForegroundWindow hWnd
SetFocus hWnd
If TimerDelay Then Call Pause(TimerDelay)
keybd_event &H12, 0, 0, 0
keybd_event &H2C, 0, 0, 0
keybd_event &H2C, 0, &H2, 0
keybd_event &H12, 0, &H2, 0
Call Pause(2)
Call ShowMouse(True)
End Sub
Private Sub Pause(ByVal Period As Single)
Dim StartTimer As Single
StartTimer = Timer
Do
DoEvents
Loop Until StartTimer + Period < Timer
End Sub
Private Sub ShowMouse(ByVal Value As Boolean)
ShowCursor CLng(Value)
End Sub