Flickering when loading pictures into Gui

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
pv007
Posts: 93
Joined: 20 Jul 2020, 23:50

Flickering when loading pictures into Gui

28 Nov 2021, 20:12

While searching for a way to stop the flickering while changing the picture of a control, i have found the function GDI_SetImageX from @SKAN in this topic https://www.autohotkey.com/board/topic/73440-gui-image-flicker/

I did the test function below, to help check if the flickering is really gone, how to use it:
Just replace the WinTitle with your current window, i suggest using a video on youtube or something that forces the window to be refreshed so often.

The function will capture the screen of the given WinTitle and paint it into the Gui picture control.

-Topic:
I was debugging the function GDI_SetImageX and i could see that the value of w and h on w := Numget( bm,4 ), h := Numget( bm,8 ) is 0, it shouldnt be the width and height of the WinTitle?
as the hBitmap passed to the function contains the same dimension as the WinTitle window, there's also something wrong with the WM_SETREDRAW lines.

As the function is from a very old topic i think something need to be updated, i dont understand much about Gdip, would like to request help on it.
Also, i could not understand, but sometimes it rarely flicks, and sometimes as seen in the video above it flickes a lot.

Spoiler


.

Code: Select all

;#include gdip.ahk
pToken := Gdip_Startup()


Gui, +Resize +E0x02000000 +E0x00080000
Gui, Color, 0
Gui, Add, Picture, x0 y0 hwndPic 0xE  ; <=== Need add 0xE to the control.

Gui, Show, w1200 h600, YetFlickering


WinTitle := "Guns N' Roses - Sweet Child O' Mine (Official Music Video) - YouTube - Opera"      ; <== Replace with your window title, i suggest using a browser with a video playing, or any window that refresh very often.
WinGet, Hwnd, Id, %WinTitle%

Loop {
   hBm := Gdip_BitmapFromHWND(Hwnd, 1)
   GDI_SetImageX(hBM, Pic)
   DllCall( "DeleteObject", UInt, hBM )
}
Return


GDI_SetImageX( hBM, hCtrl ) { ; By SKAN Created 10-Nov-2011
 ; SetImage without flicker :       www.autohotkey.com/forum/viewtopic.php?p=488784#488784
 hdcSrc  := DllCall( "CreateCompatibleDC", UInt,0 )
 hdcDst  := DllCall( "GetDC", UInt,hCtrl )
 VarSetCapacity( bm,24,0 ) ; BITMAP Structure
 DllCall( "GetObject", UInt,hbm, UInt,24, UInt,&bm )
 w := Numget( bm,4 ), h := Numget( bm,8 )
 hbmOld  := DllCall( "SelectObject", UInt,hdcSrc, UInt,hBM )
 hbmNew  := DllCall( "CreateBitmap", Int,w, Int,h, UInt,NumGet( bm,16,"UShort" )
                    , UInt,NumGet( bm,18,"UShort" ), Int,0 )
 hbmOld2 := DllCall( "SelectObject", UInt,hdcDst, UInt,hbmNew )
 DllCall( "BitBlt", UInt,hdcDst, Int,0, Int,0, Int,w, Int,h
                  , UInt,hdcSrc, Int,0, Int,0, UInt,0x00CC0020 )
 DllCall( "SelectObject", UInt,hdcSrc, UInt,hbmOld )
 DllCall( "DeleteDC",  UInt,hdcSrc ),   DllCall( "ReleaseDC", UInt,hCtrl, UInt,hdcDst )
 ;DllCall( "SendMessage", UInt,hCtrl, UInt,0x0B, UInt,0, UInt,0 )        ; WM_SETREDRAW OFF
 oBM := DllCall( "SendMessage", UInt,hCtrl, UInt,0x172, UInt,0, UInt,hBM ) ; STM_SETIMAGE
 ;DllCall( "SendMessage", UInt,hCtrl, UInt,0x0B, UInt,1, UInt,0 )        ; WM_SETREDRAW ON
 DllCall( "DeleteObject", UInt,oBM )
}



; ================================================================================
; Adding these two functions in case someone doesn't have it, all other functions can be found in Gdip.Ahk
; ================================================================================



; Function           Gdip_BitmapFromHWND
; Description        Uses PrintWindow to get a handle to the specified window and return a bitmap from it
;
; hwnd               handle to the window to get a bitmap from
; clientOnly         capture only the client area of the window, without title bar and border
;
; return             If the function succeeds, the return value is a pointer to a gdi+ bitmap

Gdip_BitmapFromHWND(hwnd, Return_hBitmap:=0, clientOnly:=0) { 

   ; Restore the window if minimized! Must be visible for capture.
   If DllCall("IsIconic", "ptr", hwnd) 
      DllCall("ShowWindow", "ptr", hwnd, "int", 4) 

   Static Ptr := "UPtr" 
   thisFlag := 0 
   If (clientOnly=1) {
      VarSetCapacity(rc, 16, 0) 
      DllCall("GetClientRect", "ptr", hwnd, "ptr", &rc) 
      Width := NumGet(rc, 8, "int") 
      Height := NumGet(rc, 12, "int") 
      thisFlag := 1 
   } 
   Else 
      GetWindowRect(hwnd, Width, Height) 

   hbm := CreateDIBSection(Width, Height) 
   hdc := CreateCompatibleDC(), obm := SelectObject(hdc, hbm) 
   PrintWindow(hwnd, hdc, 2 + thisFlag) 

   If (Return_hBitmap) {
      SelectObject(hdc, obm)
      ;DeleteObject(hbm)
      DeleteDC(hdc)
      Return hbm
   }

   pBitmap := Gdip_CreateBitmapFromHBITMAP(hbm) 
   SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc) 
   
   return pBitmap

}



; Function           PrintWindow
; Description        The PrintWindow function copies a visual window into the specified device context (DC), typically a printer DC
;
; hwnd               A handle to the window that will be copied
; hdc                A handle to the device context
; Flags              Drawing options
;
; return             If the function succeeds, it returns a nonzero value
;
; PW_CLIENTONLY      = 1

PrintWindow(hwnd, hdc, Flags:=2) {
   ; set Flags to 2, to capture hardware accelerated windows
   ; this only applies on Windows 8.1 and later versions.

   Static Ptr := "UPtr"
return DllCall("PrintWindow", Ptr, hwnd, Ptr, hdc, "uint", Flags)
}
Last edited by pv007 on 29 Nov 2021, 09:59, edited 2 times in total.
User avatar
Hellbent
Posts: 2102
Joined: 23 Sep 2017, 13:34

Re: Flickering when loading pictures into Gui

28 Nov 2021, 20:16

If you can. Use a layered window for your animations and you won't have any flicker.
just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Flickering when loading pictures into Gui

29 Nov 2021, 06:28

SKAN's function is rather old 32-bit code. Do you use AHK 32-bit?
pv007
Posts: 93
Joined: 20 Jul 2020, 23:50

Re: Flickering when loading pictures into Gui

29 Nov 2021, 09:25

@just me No i dont. I'm currently using the latest v1 version x64, I don't know much about gdip, do you mind pointing how to update the function to x64?
fabricio234
Posts: 122
Joined: 06 Mar 2020, 21:48

Re: Flickering when loading pictures into Gui

30 Nov 2021, 17:53

The part about getting the bitmap width and height, you could try:

Code: Select all

   VarSetCapacity(bm, size:=(A_PtrSize=8 ? 32:24), 0)
   DllCall("GetObject", Ptr, hBM, "int",size, Ptr,&bm)
   w:=NumGet(bm,4,"int"), h:=Abs(NumGet(bm,8,"int"))
But i think theres something more that need to be updated.
pv007
Posts: 93
Joined: 20 Jul 2020, 23:50

Re: Flickering when loading pictures into Gui

03 Dec 2021, 20:04

Hey thanks, now it recognize the image width and height correctly, however it still flickering, I've been trying to update the rest of the function unsuccessfully.
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: Flickering when loading pictures into Gui

04 Dec 2021, 00:18

Try another approach:

Code: Select all

targetWindow := "Guns N' Roses - Sweet Child O' Mine (Official Music Video)"
; targetWindow := "ahk_class Chrome_WidgetWin_1 ahk_exe opera.exe" ; this way is preferable
if !hTarget := WinExist(targetWindow)
   throw "window not found"
WinActivate
WinGetPos,,, W, H

Gui, New, +hwndhGui +Resize +AlwaysOnTop
Gui, Show, w900 h600

Thumb := new ThumbnailGui(hGui, W, H, hTarget, 0, 0, W, H)
Return

GuiClose() {
   ExitApp
}

class ThumbnailGui
{
   __New(hWndThumb, thumbW, thumbH, hWndSource, sourceX, sourceY, sourceW, sourceH, clientOnly := false) {
      this.hLib := DllCall("LoadLibrary", "Str", "dwmapi.dll")
      if DllCall("dwmapi\DwmRegisterThumbnail", "Ptr", hWndThumb, "Ptr", hWndSource, "PtrP", hThumbnailId) != 0
         throw "DwmRegisterThumbnail failed"
      this.ThumbnailId := hThumbnailId
      this.SetSourceRegion(sourceX, sourceY, sourceW, sourceH, clientOnly)
      this.SetThumbRegion(thumbW, thumbH)
   }
   __Delete() {
      DllCall("dwmapi\DwmUnregisterThumbnail", "Ptr", this.ThumbnailId)
      DllCall("FreeLibrary", "Ptr", this.hLib)
   }
   SetSourceRegion(X, Y, W, H, clientOnly) {
      this.SetRegion(DWM_TNP_RECTSOURCE := 0x2, X, Y, W, H, clientOnly)
   }
   SetThumbRegion(W, H) {
      this.SetRegion(DWM_TNP_RECTDESTINATION := 0x1, 0, 0, W, H)
   }
   SetRegion(flag, X, Y, W, H, clientOnly := false) {
      static DWM_TNP_SOURCECLIENTAREAONLY := 0x10
           , DWM_TNP_RECTDESTINATION := 0x1
           , DWM_TNP_RECTSOURCE := 0x2
      VarSetCapacity(DWM_THUMBNAIL_PROPERTIES, 48, 0)
      flags := flag | DWM_TNP_SOURCECLIENTAREAONLY*(flag = DWM_TNP_RECTSOURCE)
      NumPut( flags     , DWM_THUMBNAIL_PROPERTIES)
      NumPut( X         , DWM_THUMBNAIL_PROPERTIES,  4 + 16*(flag = DWM_TNP_RECTSOURCE) )
      NumPut( Y         , DWM_THUMBNAIL_PROPERTIES,  8 + 16*(flag = DWM_TNP_RECTSOURCE) )
      NumPut( X + W     , DWM_THUMBNAIL_PROPERTIES, 12 + 16*(flag = DWM_TNP_RECTSOURCE) )
      NumPut( Y + H     , DWM_THUMBNAIL_PROPERTIES, 16 + 16*(flag = DWM_TNP_RECTSOURCE) )
      NumPut( clientOnly, DWM_THUMBNAIL_PROPERTIES, 44, "UInt")
      this.UpdateThumbnailProperties(&DWM_THUMBNAIL_PROPERTIES)
   }
   UpdateThumbnailProperties(pProp) {
      DllCall("dwmapi\DwmUpdateThumbnailProperties", "Ptr", this.ThumbnailId, "Ptr", pProp)
   }
}
pv007
Posts: 93
Joined: 20 Jul 2020, 23:50

Re: Flickering when loading pictures into Gui

04 Dec 2021, 11:28

@teadrinker do you know how to draw something over the thumbnail in the GUI?
i mean any other possible GUI control, it always get hidden by the thumbnail.
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: Flickering when loading pictures into Gui

04 Dec 2021, 11:46

You could create the new GUI and place it above the thumbnail GUI.
pv007
Posts: 93
Joined: 20 Jul 2020, 23:50

Re: Flickering when loading pictures into Gui

04 Dec 2021, 11:50

@teadrinker is possible to temporarily hide the thumbnail? or do i need to delete it and create again
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: Flickering when loading pictures into Gui

04 Dec 2021, 12:00

That's what you can do:

Code: Select all

targetWindow := "ahk_class Progman"
if !hTarget := WinExist(targetWindow)
   throw "window not found"
WinActivate
WinGetPos,,, W, H

Gui, New, +hwndhGui +Resize +AlwaysOnTop
Gui, Add, Button, w150 h24, My Button
Gui, Show, w900 h600

Thumb := new ThumbnailGui(hGui, W, H, hTarget, 0, 0, W, H)
Thumb.SetRegion(DWM_TNP_RECTDESTINATION := 0x1, 0, 100, W, H)

Sleep, 1000
Thumb := ""
Sleep, 1000

Thumb := new ThumbnailGui(hGui, W, H, hTarget, 0, 0, W, H)
Thumb.SetRegion(DWM_TNP_RECTDESTINATION := 0x1, 0, 100, W, H)
Return

GuiClose() {
   ExitApp
}

class ThumbnailGui
{
   __New(hWndThumb, thumbW, thumbH, hWndSource, sourceX, sourceY, sourceW, sourceH, clientOnly := false) {
      this.hLib := DllCall("LoadLibrary", "Str", "dwmapi.dll")
      if DllCall("dwmapi\DwmRegisterThumbnail", "Ptr", hWndThumb, "Ptr", hWndSource, "PtrP", hThumbnailId) != 0
         throw "DwmRegisterThumbnail failed"
      this.ThumbnailId := hThumbnailId
      this.SetSourceRegion(sourceX, sourceY, sourceW, sourceH, clientOnly)
      this.SetThumbRegion(thumbW, thumbH)
   }
   __Delete() {
      DllCall("dwmapi\DwmUnregisterThumbnail", "Ptr", this.ThumbnailId)
      DllCall("FreeLibrary", "Ptr", this.hLib)
   }
   SetSourceRegion(X, Y, W, H, clientOnly) {
      this.SetRegion(DWM_TNP_RECTSOURCE := 0x2, X, Y, W, H, clientOnly)
   }
   SetThumbRegion(W, H) {
      this.SetRegion(DWM_TNP_RECTDESTINATION := 0x1, 0, 0, W, H)
   }
   SetRegion(flag, X, Y, W, H, clientOnly := false) {
      static DWM_TNP_SOURCECLIENTAREAONLY := 0x10
           , DWM_TNP_RECTDESTINATION := 0x1
           , DWM_TNP_RECTSOURCE := 0x2
      VarSetCapacity(DWM_THUMBNAIL_PROPERTIES, 48, 0)
      flags := flag | DWM_TNP_SOURCECLIENTAREAONLY*(flag = DWM_TNP_RECTSOURCE)
      NumPut( flags     , DWM_THUMBNAIL_PROPERTIES)
      NumPut( X         , DWM_THUMBNAIL_PROPERTIES,  4 + 16*(flag = DWM_TNP_RECTSOURCE) )
      NumPut( Y         , DWM_THUMBNAIL_PROPERTIES,  8 + 16*(flag = DWM_TNP_RECTSOURCE) )
      NumPut( X + W     , DWM_THUMBNAIL_PROPERTIES, 12 + 16*(flag = DWM_TNP_RECTSOURCE) )
      NumPut( Y + H     , DWM_THUMBNAIL_PROPERTIES, 16 + 16*(flag = DWM_TNP_RECTSOURCE) )
      NumPut( clientOnly, DWM_THUMBNAIL_PROPERTIES, 44, "UInt")
      this.UpdateThumbnailProperties(&DWM_THUMBNAIL_PROPERTIES)
   }
   UpdateThumbnailProperties(pProp) {
      DllCall("dwmapi\DwmUpdateThumbnailProperties", "Ptr", this.ThumbnailId, "Ptr", pProp)
   }
}

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Google [Bot], wilkster and 128 guests