Page 1 of 3 123 LastLast
Results 1 to 40 of 102

Thread: Problems getting a window capture with Bitblt and PrintWindow.

  1. #1

    Thread Starter
    Member
    Join Date
    Oct 2020
    Posts
    63

    Unhappy Problems getting a window capture with Bitblt and PrintWindow.

    Hello, I'm trying to get a window capture through the bitblt capture method and printWindow api, but in both I have the problem with some processes (Mostly games) where it only captures the window showing the white or black content (depending on the computer).

    Here I can show how they are observed in each one.

    Name:  Bitblt.jpg
Views: 3610
Size:  31.9 KB
    [Using Bitblt]

    Name:  PrintWindow.jpg
Views: 3292
Size:  35.3 KB
    [Using PrintWindow]

    I have noticed that OBS has Bitblt as a capture method, where it also presents the same problem.
    Name:  Bitblt OBS.jpg
Views: 3346
Size:  28.5 KB

    But if "Windows 10" capture mode is used, it is solved. Is this mode available to use in vb6?

    Name:  WIN10 Mode.jpg
Views: 3370
Size:  31.4 KB

    Thank you very much, this has me worried and it would be good to have information!.

  2. #2
    Hyperactive Member -Franky-'s Avatar
    Join Date
    Dec 2022
    Location
    Bremen Germany
    Posts
    476

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    Hi
    From Windows 10 you can also use the UWP/WinRT namespace Windows.Graphics.Capture (https://learn.microsoft.com/en-us/uw...ew=winrt-22621) in VB6 . Try if you can make a screenshot with this. https://www.activevb.de/cgi-bin/uplo...oad.pl?id=3904

  3. #3
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    6,167

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    @Franky: A clever piece of code although painful to watch Invoke-ing all those calls without a typelib. I'll hoist RoGetActivationFactory and RoActivateInstance API declares immediately to test WinRT JSON classes :-))

    Also note that the link to your ZIP upload will be removed by these forums in a short time. All your previous back-links are removed too which is a shame as the code is solid.

    Can you please link *and* paste relevant code in the thread so it becomes searchable in google and with forum's advanced search?

    cheers,
    </wqw>

  4. #4
    Fanatic Member
    Join Date
    Aug 2016
    Posts
    733

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    This is a difficult problem. Games and videos are difficult to capture images.
    But in games or videos, DX or Opengl is used to draw pictures, which naturally cannot be cut off

  5. #5
    Hyperactive Member -Franky-'s Avatar
    Join Date
    Dec 2022
    Location
    Bremen Germany
    Posts
    476

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    @wqweto Sorry for the links to the ZIP download. I will revise my code again briefly and then upload a new ZIP here.

    Edit: In the ActiveVB Up/Downlod I also have a code for WinRT JSON. Find the VBC_UwpJson.zip there.
    Attached Files Attached Files
    Last edited by -Franky-; Jan 9th, 2023 at 04:21 AM.

  6. #6
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,619

    Post Re: Problems getting a window capture with Bitblt and PrintWindow.

    For some games you can BitBlt from their window hDC and for others you can't, even though they obviously all use DirectX. I don't know what makes the difference. On the other hand you can always BitBlt from the desktop hDC so just calculate the coordinates of the game window.

  7. #7
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    6,167

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    Quote Originally Posted by -Franky- View Post
    Edit: In the ActiveVB Up/Downlod I also have a code for WinRT JSON. Find the VBC_UwpJson.zip there.
    Thanks! Looking at it now.

    Btw, in ToString impl is there WindowsDeleteString call missing on the output hString?

    cheers,
    </wqw>

  8. #8
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,619

    Thumbs up Re: Problems getting a window capture with Bitblt and PrintWindow.

    To answer the initial post, it seems that "PrintWindow" has been modified (since Windows 8.1) to work with DirectX surfaces. Now it has an undocumented parameter (PW_RENDERFULLCONTENT):

    Code:
    Public Const PW_CLIENTONLY = 1, PW_RENDERFULLCONTENT = 2
    
    PrintWindow SourceWindow_hWnd, Destination_hDC, PW_CLIENTONLY Or PW_RENDERFULLCONTENT
    Just tested this and it seems to be working correctly.

  9. #9

    Thread Starter
    Member
    Join Date
    Oct 2020
    Posts
    63

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    Thank you very much!! -Franky-, VanGoghGaming. The solutions are excellent for this problem.!
    VBC_UwpCapturePicker.zip and PrintWindow has surprised me, They got me out of big trouble!

  10. #10
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,619

    Question Re: Problems getting a window capture with Bitblt and PrintWindow.

    Quote Originally Posted by wqweto View Post
    A clever piece of code although painful to watch Invoke-ing all those calls without a typelib.
    Is it even possible to include all those objects and their methods in a typelib? So far all the VB6 typelibs I've seen include only DLL function declarations and basic types (long, integer, byte)...

    I tried to take a look at Franky's code and got dizzy from all the invoking of "DispCallFunc"!

  11. #11
    Hyperactive Member -Franky-'s Avatar
    Join Date
    Dec 2022
    Location
    Bremen Germany
    Posts
    476

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    Quote Originally Posted by wqweto View Post
    Btw, in ToString impl is there WindowsDeleteString call missing on the output hString?
    </wqw>
    If I read that correctly in the MS Docs, hString must be deleted via WindowsDeleteString if it was created with WindowsCreateString. Otherwise not.

  12. #12
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    6,167

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    Quote Originally Posted by -Franky- View Post
    If I read that correctly in the MS Docs, hString must be deleted via WindowsDeleteString if it was created with WindowsCreateString. Otherwise not.
    Pretty sure that for every [out] HSTRING *value parameter you have to call WindowsDeleteString when done working with the HSTRING. This is what WinRT/C++ wrappers do when returning HSTRING with return { value, take_ownership_from_abi } which ensures Close method is called on the handle (the method which wraps native WindowsDeleteString).

    You already do this in GetInspectable_GetRuntimeClassName which is correct but in most other cases where VarPtr(hString) is populated as an output parameter the HSTRING is leaking (e.g. ToString, GetStringAt, Stringify, GetString in clsJsonArray)

    Another possible source of leaks is when missing calling (manually) Release on the raw pointers in Long variables. These could be declared as IUnknown and let VB6 automagically call Release at correct places with no leaks possible.

    Otherwise the proof of concept is great, this is something I wanted to research for a long time and will probably invest some time wrapping base WinRT interfaces in a typelib for performance reasons (Invoke-ing is expensive).

    cheers,
    </wqw>

  13. #13
    Hyperactive Member -Franky-'s Avatar
    Join Date
    Dec 2022
    Location
    Bremen Germany
    Posts
    476

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    Quote Originally Posted by wqweto View Post
    Pretty sure that for every [out] HSTRING *value parameter you have to call WindowsDeleteString when done working with the HSTRING. This is what WinRT/C++ wrappers do when returning HSTRING with return { value, take_ownership_from_abi } which ensures Close method is called on the handle (the method which wraps native WindowsDeleteString).

    You already do this in GetInspectable_GetRuntimeClassName which is correct but in most other cases where VarPtr(hString) is populated as an output parameter the HSTRING is leaking (e.g. ToString, GetStringAt, Stringify, GetString in clsJsonArray)

    Another possible source of leaks is when missing calling (manually) Release on the raw pointers in Long variables. These could be declared as IUnknown and let VB6 automagically call Release at correct places with no leaks possible.

    Otherwise the proof of concept is great, this is something I wanted to research for a long time and will probably invest some time wrapping base WinRT interfaces in a typelib for performance reasons (Invoke-ing is expensive).

    cheers,
    </wqw>
    OK. then I misunderstood the MS Docs. Thank you for your explanation.

  14. #14
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,619

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    @Franky is it possible to start the capture directly from a supplied window hWnd instead of displaying that "CapturePicker" window every time?

  15. #15
    Hyperactive Member -Franky-'s Avatar
    Join Date
    Dec 2022
    Location
    Bremen Germany
    Posts
    476

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    Hi
    In the windows.graphics.capture.interop.h there is a function CreateForWindow.
    Code:
    HRESULT CreateForWindow(
      HWND   window,
      REFIID riid,
      void   **result
    );
    REFIID = IID_IGraphicsCaptureItem

    Edit: add the following
    Code:
    Private Const WindowsGraphicsCaptureGraphicsCaptureItem As String = "Windows.Graphics.Capture.GraphicsCaptureItem"
    Private Const IID_IGraphicsCaptureItemInterop As String = "{3628e81b-3cac-4c60-b7f4-23ce0e0c3356}"
    Private Const IID_IGraphicsCaptureItem As String = "{79c3f95b-31f7-4ec2-a464-632ef5d30760}"
    
    
    
    Private Enum vtb_Interfaces
    
        ' ...
    
    
    
        ' IGraphicsCaptureItemInterop
        IGraphicsCaptureItemInterop_CreateForWindow = 3
        IGraphicsCaptureItemInterop_CreateForMonitor = 4
    End Enum
    
    Private m_pIGraphicsCaptureItemInterop As Long
    
    
    Private Sub Class_Initialize()
    
    
        If GetActivationFactory(WindowsGraphicsCaptureGraphicsCaptureItem, _
                                IID_IGraphicsCaptureItemInterop, _
                                m_pIGraphicsCaptureItemInterop) Then
    
        ' ....
    End Sub
    
    Public Function CaptureHwnd(ByVal hwnd As Long) As Boolean
        If m_pIGraphicsCaptureItemInterop <> 0& And hwnd <> 0& Then
            Dim pIGraphicsCaptureItem As Long
            If Invoke(m_pIGraphicsCaptureItemInterop, _
                      IGraphicsCaptureItemInterop_CreateForWindow, _
                      hwnd, _
                      VarPtr(Str2Guid(IID_IGraphicsCaptureItem)), _
                      VarPtr(pIGraphicsCaptureItem)) = S_OK Then
            
                ' etc.
                ' CaptureHwnd = True
            
                Call Release(pIGraphicsCaptureItem)
            End If
        End If
    End Function
    Last edited by -Franky-; Jan 11th, 2023 at 02:53 AM.

  16. #16
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,619

    Thumbs up Re: Problems getting a window capture with Bitblt and PrintWindow.

    Hey Franky, thanks for the code sample! I think I got the hang of it now, it's not really difficult once you step through the code in the debugger. I really wish you could do something like CreateObject("Windows.Graphics.Capture") though... Invoking all those methods without instantiating their classes is terribly slow:

    Taking a screenshot with this code sample: 92ms
    Taking the same screenshot with "PrintWindow" with the "PW_RENDERFULLCONTENT" flag (which probably does the same thing under the hood): 19ms
    Taking the same screenshot with "BitBlt" (for comparison purposes): 0.7 ms


    All measurements done inside the IDE.

    Incidentally I have stumbled upon this piece of code which does exactly the same thing as yours, only using the AutoHotkey scripting language:

    https://www.autohotkey.com/boards/vi...yle=17&t=96161

    The similarities are uncanny, almost as if it's the same code translated in VB6!

  17. #17
    Hyperactive Member -Franky-'s Avatar
    Join Date
    Dec 2022
    Location
    Bremen Germany
    Posts
    476

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    Quote Originally Posted by VanGoghGaming View Post
    Hey Franky, thanks for the code sample! I think I got the hang of it now, it's not really difficult once you step through the code in the debugger. I really wish you could do something like CreateObject("Windows.Graphics.Capture") though... Invoking all those methods without instantiating their classes is terribly slow:

    Taking a screenshot with this code sample: 92ms
    Taking the same screenshot with "PrintWindow" with the "PW_RENDERFULLCONTENT" flag (which probably does the same thing under the hood): 19ms
    Taking the same screenshot with "BitBlt" (for comparison purposes): 0.7 ms


    All measurements done inside the IDE.

    Incidentally I have stumbled upon this piece of code which does exactly the same thing as yours, only using the AutoHotkey scripting language:

    https://www.autohotkey.com/boards/vi...yle=17&t=96161

    The similarities are uncanny, almost as if it's the same code translated in VB6!
    Caught. Let's put it that way. I copied a few things from this AutoHotKey Script and some comes directly from Microsoft examples.


    I think the code is correspondingly slow because of the invoking. BitBlt has the disadvantage that the window has to be in the foreground. Not via the WinRT.

  18. #18
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,619

    Thumbs up Re: Problems getting a window capture with Bitblt and PrintWindow.

    Hey no worries, you did a fine job nevertheless. I did some reading on this WinRT stuff, apparently it's not so easy to instantiate WinRT objects in VB6 (if even possible at all) compared to the rest of COM objects.

    BitBlt does work with background windows even if they are completely covered by other windows as long as they are not minimized. It just fails on some windows that use "special" DirectX techniques to draw their content (because it can also work fine with other DirectX windows)...

  19. #19
    Fanatic Member
    Join Date
    Aug 2016
    Posts
    733

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    The code should be sent to codebank

    BitBlt cannot work with background windows!

  20. #20
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,619

    Cool Re: Problems getting a window capture with Bitblt and PrintWindow.

    Quote Originally Posted by xxdoc123 View Post
    BitBlt cannot work with background windows!
    While that may have been true in previous versions of Windows, somewhere along the way Microsoft woke up and got their act together. Anyway it's pretty easy to test it yourself, just make a new project with two forms and a timer on each. "Form2" has a "Label" starting with "1" and the timer keeps incrementing it each second. In "Form1" the timer performs "BitBlt" from "Form2.hDC" each second, like this:

    Name:  BitBltTest.jpg
Views: 3153
Size:  11.6 KB

    Form1:
    Code:
    Option Explicit
    
    Private Sub Form_Load()
        Form2.Show
    End Sub
    
    Private Sub Form_Unload(Cancel As Integer)
        Unload Form2
    End Sub
    
    Private Sub Timer1_Timer()
        BitBlt Me.hDC, 0, 0, Form2.ScaleWidth, Form2.ScaleHeight, Form2.hDC, 0, 0, vbSrcCopy
    End Sub
    Form2:
    Code:
    Option Explicit
    
    Private Sub Timer1_Timer()
        Label1 = Val(Label1) + 1
    End Sub
    Now try to hide "Form2" somewhere in the dark recesses of your desktop, behind a browser window for example. "BitBlt" will continue to work just fine on "Form1", hell it even works if both windows are in the background.

  21. #21
    Hyperactive Member -Franky-'s Avatar
    Join Date
    Dec 2022
    Location
    Bremen Germany
    Posts
    476

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    Quote Originally Posted by xxdoc123 View Post
    The code should be sent to codebank
    You can do whatever you want with the WinRT code. I make no claim to it. I'm just playing around with WinRT to explore some possibilities for VB6.

  22. #22
    Fanatic Member
    Join Date
    Aug 2016
    Posts
    733

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    Quote Originally Posted by VanGoghGaming View Post
    While that may have been true in previous versions of Windows, somewhere along the way Microsoft woke up and got their act together. Anyway it's pretty easy to test it yourself, just make a new project with two forms and a timer on each. "Form2" has a "Label" starting with "1" and the timer keeps incrementing it each second. In "Form1" the timer performs "BitBlt" from "Form2.hDC" each second, like this:

    Name:  BitBltTest.jpg
Views: 3153
Size:  11.6 KB

    Form1:
    Code:
    Option Explicit
    
    Private Sub Form_Load()
        Form2.Show
    End Sub
    
    Private Sub Form_Unload(Cancel As Integer)
        Unload Form2
    End Sub
    
    Private Sub Timer1_Timer()
        BitBlt Me.hDC, 0, 0, Form2.ScaleWidth, Form2.ScaleHeight, Form2.hDC, 0, 0, vbSrcCopy
    End Sub
    Form2:
    Code:
    Option Explicit
    
    Private Sub Timer1_Timer()
        Label1 = Val(Label1) + 1
    End Sub
    Now try to hide "Form2" somewhere in the dark recesses of your desktop, behind a browser window for example. "BitBlt" will continue to work just fine on "Form1", hell it even works if both windows are in the background.
    from1 and from2 in the same exe .

    if you test form2 in other exe ,you will see different

  23. #23
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,619

    Wink Re: Problems getting a window capture with Bitblt and PrintWindow.

    Quote Originally Posted by xxdoc123 View Post
    if you test form2 in other exe ,you will see different
    Generally it doesn't bode well to make such bold, blanket statements without at least bothering to write 4 simple lines of code... In this example the actual game is running in the background behind the VB6 IDE window:

    Name:  BitBltTest1.jpg
Views: 3035
Size:  24.5 KB

    And the full screenshot (which for some reason is too small to read the text when uploaded):

    Name:  BitBltTest.jpg
Views: 3101
Size:  31.1 KB

  24. #24
    Fanatic Member
    Join Date
    Aug 2016
    Posts
    733

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    thanks ,In my memory, I can't take screenshots in the background used bitblt if some form out of the range of the display . So I used printwindow instead~

    some hacker can hook dx and screenshot.but can not find any code ~

  25. #25
    Fanatic Member
    Join Date
    Aug 2016
    Posts
    733

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    Quote Originally Posted by -Franky- View Post
    Hi
    In the windows.graphics.capture.interop.h there is a function CreateForWindow.
    Code:
    HRESULT CreateForWindow(
      HWND   window,
      REFIID riid,
      void   **result
    );
    REFIID = IID_IGraphicsCaptureItem

    Edit: add the following
    Code:
    Private Const WindowsGraphicsCaptureGraphicsCaptureItem As String = "Windows.Graphics.Capture.GraphicsCaptureItem"
    Private Const IID_IGraphicsCaptureItemInterop As String = "{3628e81b-3cac-4c60-b7f4-23ce0e0c3356}"
    Private Const IID_IGraphicsCaptureItem As String = "{79c3f95b-31f7-4ec2-a464-632ef5d30760}"
    
    
    
    Private Enum vtb_Interfaces
    
        ' ...
    
    
    
        ' IGraphicsCaptureItemInterop
        IGraphicsCaptureItemInterop_CreateForWindow = 3
        IGraphicsCaptureItemInterop_CreateForMonitor = 4
    End Enum
    
    Private m_pIGraphicsCaptureItemInterop As Long
    
    
    Private Sub Class_Initialize()
    
    
        If GetActivationFactory(WindowsGraphicsCaptureGraphicsCaptureItem, _
                                IID_IGraphicsCaptureItemInterop, _
                                m_pIGraphicsCaptureItemInterop) Then
    
        ' ....
    End Sub
    
    Public Function CaptureHwnd(ByVal hwnd As Long) As Boolean
        If m_pIGraphicsCaptureItemInterop <> 0& And hwnd <> 0& Then
            Dim pIGraphicsCaptureItem As Long
            If Invoke(m_pIGraphicsCaptureItemInterop, _
                      IGraphicsCaptureItemInterop_CreateForWindow, _
                      hwnd, _
                      VarPtr(Str2Guid(IID_IGraphicsCaptureItem)), _
                      VarPtr(pIGraphicsCaptureItem)) = S_OK Then
            
                ' etc.
                ' CaptureHwnd = True
            
                Call Release(pIGraphicsCaptureItem)
            End If
        End If
    End Function
    thank you but how can add it to the cls?

    If GetActivationFactory(WindowsGraphicsCaptureGraphicsCaptureItem, IID_IGraphicsCaptureItemInterop, m_pIGraphicsCaptureItemInterop) Then

    Dim bolIsSupported As Boolean

    If Invoke(pIGraphicsCaptureSessionStatics, IGraphicsCaptureSessionStatics_IsSupported, VarPtr(bolIsSupported)) = S_OK Then may be not return S_OK

    thanks .

  26. #26
    New Member
    Join Date
    Jan 2023
    Posts
    1

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    Thank you very much!! -Franky-, VanGoghGaming. The solutions are excellent for this problem.!

  27. #27
    Hyperactive Member -Franky-'s Avatar
    Join Date
    Dec 2022
    Location
    Bremen Germany
    Posts
    476

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    Quote Originally Posted by xxdoc123 View Post
    thank you but how can add it to the cls?

    If GetActivationFactory(WindowsGraphicsCaptureGraphicsCaptureItem, IID_IGraphicsCaptureItemInterop, m_pIGraphicsCaptureItemInterop) Then

    Dim bolIsSupported As Boolean

    If Invoke(pIGraphicsCaptureSessionStatics, IGraphicsCaptureSessionStatics_IsSupported, VarPtr(bolIsSupported)) = S_OK Then may be not return S_OK

    thanks .
    First: The WinRT code works on Windows 10 and higher. What does the Debug.Print "0x" & Hex$(varRet) return in the OleInvoke function when you call IGraphicsCaptureSessionStatics.IsSupported?


    The call GetActivationFactory(WindowsGraphicsCaptureGraphicsCaptureItem.... goes after IGraphicsCaptureSessionStatics.IsSupported. If IGraphicsCaptureSessionStatics.IsSupported already fails, then the rest won't work either.

  28. #28
    Fanatic Member
    Join Date
    Aug 2016
    Posts
    733

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    thanks。i have modiy the cls and work fine

    Code:
    ......
    Private Const WindowsGraphicsCaptureGraphicsCaptureItem As String = "Windows.Graphics.Capture.GraphicsCaptureItem"
    Private Const IID_IGraphicsCaptureItemInterop As String = "{3628e81b-3cac-4c60-b7f4-23ce0e0c3356}"
    Private Const IID_IGraphicsCaptureItem As String = "{79c3f95b-31f7-4ec2-a464-632ef5d30760}"
    
    
    ' ----==== Enums ====----
    Private Enum vtb_Interfaces
       ....
         ' IGraphicsCaptureItemInterop
        IGraphicsCaptureItemInterop_CreateForWindow = 3
        IGraphicsCaptureItemInterop_CreateForMonitor = 4
    End Enum
    
    
    Private m_pIGraphicsCaptureItemInterop As Long
    
    ' ----==== Events ====----
    ' Variable to hold 'ChoseCaptureFormHwnd' property value
    Private m_bChoseCaptureFormHwnd As Boolean
    
    Public Property Get ChoseCaptureFormHwnd() As Boolean
        ChoseCaptureFormHwnd = m_bChoseCaptureFormHwnd
    End Property
    
    Public Property Let ChoseCaptureFormHwnd(ByVal bValue As Boolean)
        m_bChoseCaptureFormHwnd = bValue
    End Property
    
    ' ----==== Class ====----
    Private Sub Class_Initialize()
    
        m_bolIsInitialized = False
        m_bolIsCapturePickerCreated = False
        
        m_bChoseCaptureFormHwnd = False
    
    End Sub
    
    Public Function Init()
        Dim tGdipStartupInput  As GDIPlusStartupInput
        Dim tGdipStartupOutput As GdiplusStartupOutput
    
        If m_bChoseCaptureFormHwnd = False Then
            Dim pIGraphicsCaptureSessionStatics As Long
    
            If GetActivationFactory(WindowsGraphicsCaptureGraphicsCaptureSession, IID_IGraphicsCaptureSessionStatics, pIGraphicsCaptureSessionStatics) Then
                Dim bolIsSupported As Boolean
    
                If Invoke(pIGraphicsCaptureSessionStatics, IGraphicsCaptureSessionStatics_IsSupported, VarPtr(bolIsSupported)) = S_OK Then
    
                    If bolIsSupported Then
                        If GetActivateInstance(WindowsGraphicsCaptureGraphicsCapturePicker, IID_IGraphicsCapturePicker, m_pIGraphicsCapturePicker) Then
                            
                            If m_bolIsInitialized = False Then
    
                                tGdipStartupInput.GdiPlusVersion = GdiPlusVersion
    
                                If GdiplusStartup(m_lngGdipToken, tGdipStartupInput, tGdipStartupOutput) = OK Then
                                    m_bolIsInitialized = True
    
                                End If
                            
                            End If
                        End If
                    End If
                End If
    
                Call Release(pIGraphicsCaptureSessionStatics)
            End If
    
        Else
    
            
    
            If GetActivationFactory(WindowsGraphicsCaptureGraphicsCaptureItem, IID_IGraphicsCaptureItemInterop, m_pIGraphicsCaptureItemInterop) Then
                '        Dim bolIsSupported As Boolean
                '        If Invoke(m_pIGraphicsCaptureItemInterop, _
                '                  IGraphicsCaptureSessionStatics_IsSupported, _
                '                  VarPtr(bolIsSupported)) = S_OK Then
                '            If bolIsSupported Then
                ''                If GetActivateInstance(WindowsGraphicsCaptureGraphicsCapturePicker, _
                ''                                       IID_IGraphicsCapturePicker, _
                ''                                       m_pIGraphicsCapturePicker) Then
                
                If m_bolIsInitialized = False Then
                    tGdipStartupInput.GdiPlusVersion = GdiPlusVersion
    
                    If GdiplusStartup(m_lngGdipToken, tGdipStartupInput, tGdipStartupOutput) = OK Then
                        m_bolIsInitialized = True
                        '
                    End If
                
                End If
    
                '                End If
                '            End If
                '        End If
                'Call Release(m_pIGraphicsCaptureItemInterop)
            End If
        End If
        
    End Function
    
    Public Function CaptureHwnd(ByVal hwnd As Long) As Boolean
    
        If m_pIGraphicsCaptureItemInterop <> 0& And hwnd <> 0& Then
            Dim pIGraphicsCaptureItem As Long
    
            If Invoke(m_pIGraphicsCaptureItemInterop, IGraphicsCaptureItemInterop_CreateForWindow, hwnd, VarPtr(Str2Guid(IID_IGraphicsCaptureItem)), VarPtr(pIGraphicsCaptureItem)) = S_OK Then
            
                Call StartCapture(pIGraphicsCaptureItem)
                 CaptureHwnd = True
            
                Call Release(pIGraphicsCaptureItem)
            End If
        End If
    End Function

    Code:
    VERSION 5.00
    Begin VB.Form frmMain 
       Caption         =   "Form1"
       ClientHeight    =   7320
       ClientLeft      =   60
       ClientTop       =   408
       ClientWidth     =   9180
       LinkTopic       =   "Form1"
       ScaleHeight     =   610
       ScaleMode       =   3  'Pixel
       ScaleWidth      =   765
       StartUpPosition =   3  '窗口缺省
       Begin VB.TextBox txtHwnd 
          Height          =   372
          Left            =   7080
          TabIndex        =   3
          Top             =   240
          Width           =   732
       End
       Begin VB.CommandButton Command2 
          Caption         =   "capture hwnd"
          Height          =   552
          Left            =   4200
          TabIndex        =   2
          Top             =   120
          Width           =   2628
       End
       Begin VB.PictureBox Picture1 
          Height          =   6375
          Left            =   120
          ScaleHeight     =   6324
          ScaleWidth      =   8820
          TabIndex        =   1
          Top             =   720
          Width           =   8865
       End
       Begin VB.CommandButton Command1 
          Caption         =   "Show CapturePicker"
          Height          =   555
          Left            =   150
          TabIndex        =   0
          Top             =   120
          Width           =   3945
       End
    End
    Attribute VB_Name = "frmMain"
    Attribute VB_GlobalNameSpace = False
    Attribute VB_Creatable = False
    Attribute VB_PredeclaredId = True
    Attribute VB_Exposed = False
    ' Autor: F. Sch黮er ([email protected])
    ' Datum: 08/2022
    
    Option Explicit
    
    Private cCapturePicker As clsCapturePicker
    
    Private Sub Command2_Click()
        cCapturePicker.ChoseCaptureFormHwnd = True
        cCapturePicker.Init
        If cCapturePicker.CaptureHwnd(Val(txtHwnd.Text)) Then
            If Not cCapturePicker.CapturePicture Is Nothing Then
                Picture1.Picture = cCapturePicker.CapturePicture
            Else
                Picture1.Picture = LoadPicture()
            End If
    
        Else
            Picture1.Picture = LoadPicture()
        End If
    
    End Sub
    
    Private Sub Form_Load()
        Command1.Enabled = False
        Set cCapturePicker = New clsCapturePicker
        cCapturePicker.ChoseCaptureFormHwnd = False
        cCapturePicker.Init
    
        If cCapturePicker.IsInitialized Then
            If cCapturePicker.CreateCapturePicker(Me.hwnd) Then
                Command1.Enabled = True
            End If
        End If
        txtHwnd.Text = Me.hwnd
        
    End Sub
    
    Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
        Set cCapturePicker = Nothing
    End Sub
    
    Private Sub Command1_Click()
        If cCapturePicker.PickSingleItemAsync Then
            If Not cCapturePicker.CapturePicture Is Nothing Then
                Picture1.Picture = cCapturePicker.CapturePicture
            Else
                Picture1.Picture = LoadPicture()
            End If
        Else
            Picture1.Picture = LoadPicture()
        End If
    End Sub

  29. #29
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,619

    Question Re: Problems getting a window capture with Bitblt and PrintWindow.

    Quote Originally Posted by -Franky- View Post
    Hi
    From Windows 10 you can also use the UWP/WinRT namespace Windows.Graphics.Capture (https://learn.microsoft.com/en-us/uw...ew=winrt-22621) in VB6 . Try if you can make a screenshot with this. https://www.activevb.de/cgi-bin/uplo...oad.pl?id=3904
    I am trying to replace these two GDI+ functions with standard GDI alternatives (mainly for didactic purposes):

    Code:
    GdipCreateBitmapFromScan0 tD3D11_TEXTURE2D_DESC.Width, tD3D11_TEXTURE2D_DESC.Height, tD3D11_MAPPED_SUBRESOURCE.RowPitch, PixelFormats.PixelFormat32bppARGB,  tD3D11_MAPPED_SUBRESOURCE.pData, pBitmap
    
    GdipCreateHBITMAPFromBitmap pBitmap, hBitmap, &HFFFFFFFF
    These function calls create a GDI "hBitmap" from the pixel data provided by "tD3D11_MAPPED_SUBRESOURCE.pData". I have tried to replace them by:

    Code:
    Dim hDC As Long, hBitmap As Long, bmiBitmapInfo As BITMAPINFO, lRet As Long
         hDC = GetDC(0)
         hBitmap = CreateCompatibleBitmap(hDC, tD3D11_TEXTURE2D_DESC.Width, tD3D11_TEXTURE2D_DESC.Height)
         hDC = ReleaseDC(0, hDC)
         With bmiBitmapInfo.bmiHeader
              .biSize = LenB(bmiBitmapInfo.bmiHeader): .biPlanes = 1: .biBitCount = 32: .biCompression = BI_RGB
              .biWidth = tD3D11_TEXTURE2D_DESC.Width: .biHeight = -tD3D11_TEXTURE2D_DESC.Height
              .biSizeImage = (((.biWidth * .biBitCount) + 31) \ 32) * 4 * tD3D11_TEXTURE2D_DESC.Height
         End With
         lRet = SetDIBits(0, hBitmap, 0, tD3D11_TEXTURE2D_DESC.Height, ByVal tD3D11_MAPPED_SUBRESOURCE.pData, bmiBitmapInfo, DIB_RGB_COLORS)
    This works to some extent, as in I do end up with a "hBitmap" containing the source pixels, however the image is all garbled as if the pixels are somehow misaligned in memory.

    I have a feeling that the parameter "tD3D11_MAPPED_SUBRESOURCE.RowPitch" might have something to do with this but I don't see how I can incorporate that into the call to "SetDIBits". I have read the "Pitch" remarks from the documentation on D3D11_MAPPED_SUBRESOURCE but I still don't understand what's really going on under the covers.

    Maybe someone with more experience in GDI Bitmaps can chime in with some advice?

  30. #30
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    7,653

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    I've been working on making a WinRT typelib/tB interface package... The stumbling block isn't HSTRING; that's straightforward. The issue I have is some of these insane things that look like dynamically defined interface templates.

  31. #31
    Hyperactive Member -Franky-'s Avatar
    Join Date
    Dec 2022
    Location
    Bremen Germany
    Posts
    476

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    Quote Originally Posted by fafalone View Post
    The issue I have is some of these insane things that look like dynamically defined interface templates.
    I can understand you well that this is not easy to implement. I also sometimes have problems with various WinRT interfaces and don't know how to approach them. Unfortunately, what is very easy in .Net cannot always be replicated in VB6.

  32. #32
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,619

    Question Re: Problems getting a window capture with Bitblt and PrintWindow.

    This is what I mean. The code captures the whole window (Form1.hWnd) and puts the screenshot in the Picturebox below the two buttons. The first "hBitmap" (made with GDI+) is displayed correctly and the second one (made with SetDIBits) is displayed all warped. I'll be damned if I know what's causing it, the code above looks spot-on whichever way I look at it...

    Name:  CaptureWnd.jpg
Views: 2885
Size:  63.1 KB

  33. #33
    PowerPoster
    Join Date
    Jan 2020
    Posts
    5,538

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    try dxgi?

  34. #34
    Hyperactive Member -Franky-'s Avatar
    Join Date
    Dec 2022
    Location
    Bremen Germany
    Posts
    476

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    Quote Originally Posted by VanGoghGaming View Post
    The first "hBitmap" (made with GDI+) is displayed correctly and the second one (made with SetDIBits) is displayed all warped
    tD3D11_MAPPED_SUBRESOURCE.RowPitch gives you back the stride value. For 32bpp this would typically be = Width * 4. The D3D11_MAPPED_SUBRESOURCE documentation says:
    For D3D_FEATURE_LEVEL_10_0 and higher, the pointer is aligned to 16 bytes. For lower than D3D_FEATURE_LEVEL_10_0, the pointer is aligned to 4 bytes.
    You calculate the stride value yourself here:
    .biSizeImage = (((.biWidth * .biBitCount) + 31) \ 32) * 4 * tD3D11_TEXTURE2D_DESC.Height
    Try the following:
    .biSizeImage = tD3D11_MAPPED_SUBRESOURCE.RowPitch * tD3D11_TEXTURE2D_DESC.Height

  35. #35
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,619

    Post Re: Problems getting a window capture with Bitblt and PrintWindow.

    Quote Originally Posted by -Franky- View Post
    tD3D11_MAPPED_SUBRESOURCE.RowPitch gives you back the stride value. For 32bpp this would typically be = Width * 4. The D3D11_MAPPED_SUBRESOURCE documentation says:
    For D3D_FEATURE_LEVEL_10_0 and higher, the pointer is aligned to 16 bytes. For lower than D3D_FEATURE_LEVEL_10_0, the pointer is aligned to 4 bytes.
    Yeah I've already read that paragraph in MSDN 3 times and it still doesn't make much sense. I have no idea what's a "stride". Also tD3D11_TEXTURE2D_DESC.Width is 621 for this screenshot and 621*4=2484 while tD3D11_MAPPED_SUBRESOURCE.RowPitch=2560 so I don't know where is this difference coming from, maybe some sort of padding? If so then how can you remove it?

    You calculate the stride value yourself here:
    .biSizeImage = (((.biWidth * .biBitCount) + 31) \ 32) * 4 * tD3D11_TEXTURE2D_DESC.Height
    Try the following:
    .biSizeImage = tD3D11_MAPPED_SUBRESOURCE.RowPitch * tD3D11_TEXTURE2D_DESC.Height
    Unfortunately this also doesn't work (it would have been too easy if it did, haha)! Furthermore the documentation about BITMAPINFOHEADER says that:

    Code:
    biSizeImage
    
    Specifies the size, in bytes, of the image. This can be set to 0 for uncompressed RGB bitmaps.
    And that seems to be correct, setting "biSizeImage" to zero makes absolutely no difference...

    I have a feeling the solution to this issue should be rather easy and it's still eluding us...

  36. #36
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,454

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    Quote Originally Posted by VanGoghGaming View Post
    ...I have no idea what's a "stride".
    It's an info-attribute, related to making "looped copies".
    (representing the pointer-offset to add, before you start your next loop over zerobased x-Values in the current row)

    When it is larger than the ImageWidth (or in case of "RowPitch" larger than Width*BytesPerPixel),
    then you have to make a copy in a loop (Row-by-Row).

    Either via CopyMemory (into a truly consecutive DIB-allocation first, before you Blit-Out your DIB) -
    or (in case you want to avoid an intermediate DIB-allocation) by Blitting directly in that loop (defining your DIB to be only "one Row in Height").

    Olaf
    Last edited by Schmidt; Apr 22nd, 2023 at 01:27 PM.

  37. #37
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,619

    Cool Re: Problems getting a window capture with Bitblt and PrintWindow.

    Thanks for explaining how stuff works, Olaf. You rock as usual! I've finally managed to get it right with the following code using CopyMemory to an intermediate array:

    Code:
    Dim bytePixelData() As Byte
    ReDim bytePixelData(0 To tD3D11_TEXTURE2D_DESC.Width * tD3D11_TEXTURE2D_DESC.Height * 4 - 1)
    With bmiBitmapInfo.bmiHeader
        .biSize = LenB(bmiBitmapInfo.bmiHeader): .biPlanes = 1: .biBitCount = 32: .biCompression = BI_RGB
        .biWidth = tD3D11_TEXTURE2D_DESC.Width: .biHeight = -tD3D11_TEXTURE2D_DESC.Height
    End With
    For i = 0 To tD3D11_TEXTURE2D_DESC.Height - 1
        CopyMemory bytePixelData(i * tD3D11_TEXTURE2D_DESC.Width * 4), ByVal tD3D11_MAPPED_SUBRESOURCE.pData + i * tD3D11_MAPPED_SUBRESOURCE.RowPitch, tD3D11_TEXTURE2D_DESC.Width * 4
    Next i
    SetDIBits 0, hBitmap, 0, tD3D11_TEXTURE2D_DESC.Height, bytePixelData(0), bmiBitmapInfo, DIB_RGB_COLORS
    However the following code doesn't work as expected:

    Code:
    For i = 0 To tD3D11_TEXTURE2D_DESC.Height - 1
        SetDIBits 0, hBitmap, i, 1, ByVal tD3D11_MAPPED_SUBRESOURCE.pData + i * tD3D11_MAPPED_SUBRESOURCE.RowPitch, bmiBitmapInfo, DIB_RGB_COLORS
    Next i
    Is it not possible to blit one row at a time in a "hBitmap" with "SetDIBits"?

  38. #38
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,454

    Re: Problems getting a window capture with Bitblt and PrintWindow.

    Quote Originally Posted by VanGoghGaming View Post
    Is it not possible to blit one row at a time in a "hBitmap" with "SetDIBits"?
    It isn't, ... but you get similar performance when you use StretchDIBits instead:
    - without Stretching anything
    - but with RowIndex i in the DstY-Param
    - the number of Rows set to 1
    - and BIHeader.biHeight Member also at 1 (or -1)

    Olaf

  39. #39
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,619

    Wink Re: Problems getting a window capture with Bitblt and PrintWindow.

    Actually it seems "SetDIBits" does work with one row at a time, but blitting needed to start in reversed order. This took a LOT of "trial and error" but the following code works perfectly:

    Code:
    For i = 0 To tD3D11_TEXTURE2D_DESC.Height - 1
        SetDIBits 0, hBitmap, tD3D11_TEXTURE2D_DESC.Height - i - 1, 1, ByVal tD3D11_MAPPED_SUBRESOURCE.pData + i * tD3D11_MAPPED_SUBRESOURCE.RowPitch, bmiBitmapInfo, DIB_RGB_COLORS
    Next i
    CopyMemory to an intermediate array no longer needed!

  40. #40
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,619

    Red face Re: Problems getting a window capture with Bitblt and PrintWindow.

    Looks like I spoke too soon... CopyMemory is noticeably faster than calling SetDIBits in a loop, so yeah, speed is king!

Page 1 of 3 123 LastLast

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width