Hello all!

I'm trying to create a macro which will automatically capture the screen when shortcut is pressed.
What is really important, I need to have taskbar visible on the screenshot.

I really found helpful code provided by Zack Barresse on this website (cannot post URL).

However, in my case I have users with 2-3 monitors setup. I tried to work with WinAPI and combining different solutions found in internet got a solution.

Option Explicit

Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type

Private Type MONITORINFO
cbSize As Long
rcMonitor As RECT
rcWork As RECT
dwFlags As Long
End Type

Private Declare PtrSafe Function GetForegroundWindow Lib "user32" () As Long
Private Declare PtrSafe Function GetMonitorInfo Lib "user32" Alias "GetMonitorInfoA" (ByVal hMonitor As Long, ByRef lpmi As MONITORINFO) As Long
Private Declare PtrSafe Function MonitorFromWindow Lib "user32" (ByVal hwnd As Long, ByVal dwFlags As Long) As Long
Private Declare PtrSafe Function EnumDisplayMonitors Lib "user32" (ByVal hdc As Long, ByVal lprcClip As Long, ByVal lpfnEnum As Long, ByVal dwData As Long) As Boolean
Private Declare PtrSafe Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare PtrSafe Function CreateCompatibleBitmap Lib "gdi32" (ByVal hdc As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long
Private Declare PtrSafe Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare PtrSafe Function BitBlt Lib "gdi32" (ByVal hdcDest As Long, ByVal nXDest As Long, ByVal nYDest As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hdcSrc As Long, ByVal nXSrc As Long, ByVal nYSrc As Long, ByVal dwRop As Long) As Long
Private Declare PtrSafe Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare PtrSafe Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare PtrSafe Function CreateDC Lib "gdi32" Alias "CreateDCA" (ByVal lpDriverName As String, ByVal lpDeviceName As String, ByVal lpOutput As String, ByVal lpInitData As Long) As Long
Private Declare PtrSafe Function OpenClipboard Lib "user32" (ByVal hwnd As Long) As Long
Private Declare PtrSafe Function EmptyClipboard Lib "user32" () As Long
Private Declare PtrSafe Function SetClipboardData Lib "user32" (ByVal wFormat As Long, ByVal hMem As Long) As Long
Private Declare PtrSafe Function CloseClipboard Lib "user32" () As Long
Private Declare PtrSafe Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long
Private Declare PtrSafe Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare PtrSafe Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function GetObject Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long

Private Const MONITOR_DEFAULTTOPRIMARY = &H1
Private Const MONITOR_DEFAULTTONEAREST = &H2
Private Const CF_BITMAP = 2

Sub GetActiveWindowMonitorBitmap()
    Dim hwnd As Long
    Dim hMonitor As Long
    Dim mi As MONITORINFO
    Dim hDCScreen As Long
    Dim hDCMem As Long
    Dim hBitmap As Long
    Dim hPrevBitmap As Long
    Dim ret As Long
    Dim hData As Long
    
    ' Get the handle of the active window
    hwnd = GetForegroundWindow()
    
    ' Get the handle of the monitor containing the active window
    hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST)
    
    ' Initialize the structure's size
    mi.cbSize = Len(mi)
    
    ' Get monitor information
    ret = GetMonitorInfo(hMonitor, mi)
    
    ' Check if successful
    If ret <> 0 Then
        ' Create a compatible DC for the screen
        hDCScreen = CreateDC("DISPLAY", vbNullString, vbNullString, ByVal 0&)
        If hDCScreen <> 0 Then
            ' Create a compatible DC for the bitmap
            hDCMem = CreateCompatibleDC(hDCScreen)
            If hDCMem <> 0 Then
                ' Create a compatible bitmap
                hBitmap = CreateCompatibleBitmap(hDCScreen, mi.rcMonitor.Right - mi.rcMonitor.Left, mi.rcMonitor.Bottom - mi.rcMonitor.Top)
                If hBitmap <> 0 Then
                    ' Select the bitmap into the memory DC
                    hPrevBitmap = SelectObject(hDCMem, hBitmap)
                    ' Copy the screen to the bitmap
                    ret = BitBlt(hDCMem, 0, 0, mi.rcMonitor.Right - mi.rcMonitor.Left, mi.rcMonitor.Bottom - mi.rcMonitor.Top, hDCScreen, mi.rcMonitor.Left, mi.rcMonitor.Top, &HCC0020)
                    ' Open the clipboard
                    ret = OpenClipboard(0)
                    If ret <> 0 Then
                        ' Empty the clipboard
                        EmptyClipboard
                        ' Set the bitmap data to clipboard
                        ret = SetClipboardData(CF_BITMAP, hBitmap)
                        ' Close the clipboard
                        ret = CloseClipboard
                    End If
                    ' Clean up
                    DeleteObject hBitmap
                Else
                    MsgBox "Failed to create bitmap."
                End If
                ' Clean up
                DeleteDC hDCMem
            Else
                MsgBox "Failed to create compatible DC for bitmap."
            End If
            ' Clean up
            DeleteDC hDCScreen
        Else
            MsgBox "Failed to create DC for the screen."
        End If
    Else
        MsgBox "Failed to get monitor information."
    End If
End Sub

Sub CaptureScreens()
    ' Loop through each monitor
    EnumDisplayMonitors 0, 0, AddressOf EnumMonitorsProc, 0
End Sub

Function EnumMonitorsProc(ByVal hMonitor As Long, ByVal hdcMonitor As Long, ByVal lprcMonitor As Long, ByVal dwData As Long) As Boolean
    Dim mi As MONITORINFO
    Dim hDCScreen As Long
    Dim hDCMem As Long
    Dim hBitmap As Long
    Dim hPrevBitmap As Long
    Dim ret As Long
    ' Initialize the structure's size
    mi.cbSize = Len(mi)
    ' Get monitor information
    ret = GetMonitorInfo(hMonitor, mi)
    ' Check if successful
    If ret <> 0 Then
        ' Create a compatible DC for the screen
        hDCScreen = CreateDC("DISPLAY", vbNullString, vbNullString, ByVal 0&)
        If hDCScreen <> 0 Then
            ' Create a compatible DC for the bitmap
            hDCMem = CreateCompatibleDC(hDCScreen)
            If hDCMem <> 0 Then
                ' Create a compatible bitmap
                hBitmap = CreateCompatibleBitmap(hDCScreen, mi.rcMonitor.Right - mi.rcMonitor.Left, mi.rcMonitor.Bottom - mi.rcMonitor.Top)
                If hBitmap <> 0 Then
                    ' Select the bitmap into the memory DC
                    hPrevBitmap = SelectObject(hDCMem, hBitmap)
                    ' Copy the screen to the bitmap
                    ret = BitBlt(hDCMem, 0, 0, mi.rcMonitor.Right - mi.rcMonitor.Left, mi.rcMonitor.Bottom - mi.rcMonitor.Top, hDCScreen, mi.rcMonitor.Left, mi.rcMonitor.Top, &HCC0020)
                    ' Open the clipboard
                    ret = OpenClipboard(0)
                    If ret <> 0 Then
                        ' Empty the clipboard
                        EmptyClipboard
                        ' Set the bitmap data to clipboard
                        ret = SetClipboardData(CF_BITMAP, hBitmap)
                        ' Close the clipboard
                        ret = CloseClipboard
                    End If
                    ' Clean up
                    DeleteObject hBitmap
                Else
                    MsgBox "Failed to create bitmap."
                End If
                ' Clean up
                DeleteDC hDCMem
            Else
                MsgBox "Failed to create compatible DC for bitmap."
            End If
            ' Clean up
            DeleteDC hDCScreen
        Else
            MsgBox "Failed to create DC for the screen."
        End If
    Else
        MsgBox "Failed to get monitor information."
    End If
    ' Continue enumeration
    EnumMonitorsProc = True
End Function
The problem appears when I use laptop+monitor setup: screenshot from laptop monitor is perfect, but screenshot from secondary monitor is larger than the screen and has black areas around the screenshot.

Do you guys any thoughts on this? Cool if you have a ready solution, but i'll be thankful for just any ideas in what direction I should think or for a proper algorithm.