;Author: Kanashius@autoitscript.com, Kanashius@autoit.de, https://www.kanashius.com ; General code idea: https://github.com/o5x/DesktopIntegration/blob/master/DesktopIntegration/Source.cpp ; Detailed information, what changed at windows 8: https://www.codeproject.com/Articles/856020/Draw-Behind-Desktop-Icons-in-Windows-plus?fid=1875575&df=90&mpp=25&prof=True&sort=Position&view=Normal&spc=Relaxed&fr=26 ; Useful tool for finding window information: spy++ from visual studio code ; This UDF works only with Win8+ #include-once #include #include #include #include Global $__Wallpaper_bRunning = True, $__Wallpaper_bExit = False, $__Wallpaper_bClear = False, $__Wallpaper_idTrayPauseResume = -1, $__Wallpaper_iSleepTimer = 0, $__Wallpaper_iSleepTime = 0 ;=============================================================================== ; ; Function Name: __Wallpaper_InitDefaultTray() ; Description: Create a simple tray menu, replacing the default AutoIt tray menu, allowing to pause/resume, clear and exit ; Parameter(s): none. ; Requirement(s): none. ; Return Value(s): none/ ; Author(s): Kanashius ; ;=============================================================================== Func __Wallpaper_InitDefaultTray() Opt("TrayOnEventMode", 1) Opt("TrayMenuMode", 3) Local $__Wallpaper_idTrayClear = TrayCreateItem("Clear") TrayItemSetOnEvent($__Wallpaper_idTrayClear, "__Wallpaper_Clear") $__Wallpaper_idTrayPauseResume = TrayCreateItem("Pause") TrayItemSetOnEvent($__Wallpaper_idTrayPauseResume, "__Wallpaper_PauseResume") TrayCreateItem("") Local $__Wallpaper_idTrayExit = TrayCreateItem("Exit") TrayItemSetOnEvent($__Wallpaper_idTrayExit, "__Wallpaper_Exit") EndFunc ;=============================================================================== ; ; Function Name: __Wallpaper_IsPause() ; Description: Check if the drawing loop is paused. ; Parameter(s): none. ; Requirement(s): none. ; Return Value(s): True if the drawing loop is paused. ; Author(s): Kanashius ; ;=============================================================================== Func __Wallpaper_IsPause() return Not $__Wallpaper_bRunning EndFunc ;=============================================================================== ; ; Function Name: __Wallpaper_PauseResume() ; Description: Pauses or Resume the drawing loop. ; Parameter(s): none. ; Requirement(s): none. ; Return Value(s): none. ; Author(s): Kanashius ; ;=============================================================================== Func __Wallpaper_PauseResume() $__Wallpaper_bRunning = Not $__Wallpaper_bRunning If $__Wallpaper_idTrayPauseResume>0 and $__Wallpaper_bRunning Then TrayItemSetText($__Wallpaper_idTrayPauseResume, "Pause") If $__Wallpaper_idTrayPauseResume>0 and Not $__Wallpaper_bRunning Then TrayItemSetText($__Wallpaper_idTrayPauseResume, "Resume") EndFunc ;=============================================================================== ; ; Function Name: __Wallpaper_Clear() ; Description: Remove all drawings and clear the background to the default one. Pauses the drawing loop. ; Parameter(s): none. ; Requirement(s): none. ; Return Value(s): none. ; Author(s): Kanashius ; ;=============================================================================== Func __Wallpaper_Clear() $__Wallpaper_bRunning = False $__Wallpaper_bClear = True If $__Wallpaper_idTrayPauseResume>0 Then TrayItemSetText($__Wallpaper_idTrayPauseResume, "Resume") EndFunc ;=============================================================================== ; ; Function Name: __Wallpaper_Exit() ; Description: Stop the drawing loop and exit the program ; Parameter(s): none. ; Requirement(s): none. ; Return Value(s): none. ; Author(s): Kanashius ; ;=============================================================================== Func __Wallpaper_Exit() $__Wallpaper_bExit = True EndFunc ;=============================================================================== ; ; Function Name: __Wallpaper_Start() ; Description: Register Callbacks for the functions and start the loop ; Parameter(s): $fCallbackDraw : Callback that is called to draw at the wallpaper-image. ; Parameter(s): $hGraphics = GDI+ graphics context to draw at ; $iWidth = The width of the wallpaper ; $iHeight = The height of the wallpaper ; $arScreenInfo = A 2D-Array with the position and size of all screens at the wallpaper-image. The primary screen is always the first one. ; [0] - $iScreenPosX ; [1] - $iScreenPosY ; [2] - $iScreenWidth ; [3] - $iScreenHeight ; [4] - $iScreenIsPrimary ; Return Value(s): A 2D-Array of Areas to redraw. ; [0][0] - $iScreenPosX ; [0][1] - $iScreenPosY ; [0][2] - $iScreenWidth ; [0][3] - $iScreenHeight ; The SetExtended (@extended) can be used to add a sleep time in between draw calls. ; ... ; $fCallbackInit : Callback that is called after the startup to allow initialization. ; Parameter(s): $iWidth = The width of the wallpaper ; $iHeight = The height of the wallpaper ; $arScreenInfo = A 2D-Array with the position and size of all screens at the wallpaper-image. The primary screen is always the first one. ; [0] - $iScreenPosX ; [1] - $iScreenPosY ; [2] - $iScreenWidth ; [3] - $iScreenHeight ; [4] - $iScreenIsPrimary ; $fCallbackShutdown : Callback that is called before everything is shutdown to allow cleanup at the user side. ; $fCallbackProcess : Callback that is independently from the $fCallbackDraw and is not affected by pausing. Can be used to process own events like GuiGetMsg. ; Requirement(s): none. ; Return Value(s): none. ; Author(s): Kanashius ; ;=============================================================================== Func __Wallpaper_Start($fCallbackDraw, $fCallbackInit = Default, $fCallbackShutdown = Default, $fCallbackProcess = Default) $arObjects = __Wallpaper_Startup() If IsFunc($fCallbackInit) Then $fCallbackInit($arObjects[0], $arObjects[1], $arObjects[2]) Local $arAreas[0], $iWaitTime Do If IsFunc($fCallbackProcess) Then $fCallbackProcess() If TimerDiff($__Wallpaper_iSleepTimer) > $__Wallpaper_iSleepTime Then $__Wallpaper_iSleepTimer = TimerInit() If $__Wallpaper_bRunning Then For $i=0 To UBound($arAreas)-1 Step 1 _WinAPI_BitBlt($arObjects[7], $arAreas[$i][0], $arAreas[$i][1], $arAreas[$i][2], $arAreas[$i][3], $arObjects[5], $arAreas[$i][0], $arAreas[$i][1], $SRCCOPY) Next $arAreas = $fCallbackDraw($arObjects[9], $arObjects[0], $arObjects[1], $arObjects[2]) $__Wallpaper_iSleepTime = @extended For $i=0 To UBound($arAreas)-1 Step 1 _WinAPI_BitBlt($arObjects[4], $arAreas[$i][0], $arAreas[$i][1], $arAreas[$i][2], $arAreas[$i][3], $arObjects[7], $arAreas[$i][0], $arAreas[$i][1], $SRCCOPY) Next ElseIf $__Wallpaper_bClear Then $__Wallpaper_bClear = False __Wallpaper_ClearInternal($arObjects) EndIf EndIf If $__Wallpaper_iSleepTime>10 Then Sleep(10) EndIf Until $__Wallpaper_bExit If IsFunc($fCallbackShutdown) Then $fCallbackShutdown() __Wallpaper_Shutdown($arObjects) EndFunc ;=============================================================================== ; ; Function Name: __Wallpaper_GetWallpaperFile() ; Description: Get the current file used as wallpaper. ; Parameter(s): none. ; Requirement(s): none. ; Return Value(s): The path to the wallpaper file ; Error(s): 1 - No path could be found, return value is "" ; Author(s): Kanashius ; ;=============================================================================== Func __Wallpaper_GetWallpaperFile() Local $SPI_GETDESKWALLPAPER = 0x0073 $tWallpaper = DllStructCreate("char[261]") DllStructSetData($tWallpaper, 1, 0) DllCall("user32.dll", "int", "SystemParametersInfo", "int", $SPI_GETDESKWALLPAPER, "int", 260, "ptr", DllStructGetPtr($tWallpaper), "int", 0) $sPath = DllStructGetData($tWallpaper, 1) If $sPath <> "" and FileExists($sPath) Then return $sPath $sPath = RegRead("HKEY_CURRENT_USER\Control Panel\Desktop", "WallPaper") If $sPath <> "" and FileExists($sPath) Then return $sPath $sPath = @AppDataDir&"\Microsoft\Windows\Themes\TranscodedWallpaper" If $sPath <> "" and FileExists($sPath) Then return $sPath return SetError(1, 0, "") EndFunc ;=============================================================================== ; ; Function Name: __Wallpaper_SetWallpaper() ; Description: Set the current wallpaper from a file ; Parameter(s): $sFile : The path to the new wallpaper. ; Requirement(s): none. ; Return Value(s): True for success, otherwise False ; Error(s): 1 - The path is empty or the file does not exist ; Author(s): Kanashius ; ;=============================================================================== Func __Wallpaper_SetWallpaper($sFile) If $sFile = "" or Not FileExists($sFile) Then SetError(1, 0, 0) Local $SPI_SETDESKWALLPAPER = 0x0014 Local $SPIF_UPDATEINIFILE = 0x0001 Local $SPIF_SENDCHANGE = 0x0002 if $sFile <> "" Then DllCall("user32.dll", "int", "SystemParametersInfo", "int", $SPI_SETDESKWALLPAPER, "int", 0, "str", $sFile, "int", BitOR(1, 2)) return True EndIf return False EndFunc ;======Internel Use Only====================================================== ; ; Function Name: __Wallpaper_Startup ; Description: Initializes everything. Will be called by __Wallpaper_Start automatically. ; Parameter(s): none. ; Requirement(s): none. ; Return Value(s): Array with needed Objects. ; [0] - $iWidth: Width of the wallpaper ; [1] - $iHeight: Height of the wallpaper ; [2] - $arMonitorInfo: 2D-Array containing posX, posY, width, height, isPrimaryDisplay of all screens ; [3] - $hWorkerW: The window to draw at ; [4] - $hDC: The device context to draw at ; [5] - $hDC_Backup: The backup device context to restore the wallpaper ; [6] - $hBitmapBackup: The bitmap for the backup ; [7] - $hDC_Backbuffer: The buffer device context to draw at ; [8] - $hBitmapBuffer: The bitmap for the buffer ; [9] - $hGfxCtxt: The graphics context of the buffer to draw at ; Error(s): 1 - Progman window not found ; 2 - WorkerW window not found ; 3 - WorkerW DC window not found ; 4 - Some GDI+ error ; Author(s): Kanashius ; ;=============================================================================== Func __Wallpaper_Startup() _GDIPlus_Startup() ; Create window between background and desktop icons to draw at Local $hProgman = __Wallpaper_FindWindowByClass("Progman") If @error Then return SetError(1, @error, 0) _WinAPI_SendMessageTimeout($hProgman, 0x052C, 0, 0, 1000, 0) ; Get the WorkerW window between wallpaper and icons Local $hWorkerW = __Wallpaper_GetWorkerW() If @error Then return SetError(2, @error, 0) Local $hDC = _WinAPI_GetDCEx($hWorkerW, 0, 0x403) If not $hDC Then return SetError(3, @error, 0) ; Get size of background Local $ptrHBitmap = _WinAPI_GetCurrentObject($hDC, $OBJ_BITMAP) If @error Then return SetError(4, @error, 0) Local $tBitmap = DllStructCreate($tagBITMAP) _WinAPI_GetObject($ptrHBitmap, DllStructGetSize($tBitmap), DllStructGetPtr($tBitmap)) If @error Then return SetError(4, @error, 0) Local $iWidth = DllStructGetData($tBitmap, "bmWidth") Local $iHeight = DllStructGetData($tBitmap, "bmHeight") $tBitmap = 0 _WinAPI_DeleteObject($ptrHBitmap) If @error Then return SetError(4, @error, 0) Local $arMonitorInfo = __Wallpaper_GetScreenInfo() ; init backup buffer Local $hDC_Backup = _WinAPI_CreateCompatibleDC($hDC) If @error Then return SetError(4, @error, 0) Local $hBitmapBackup = _WinAPI_CreateCompatibleBitmap($hDC, $iWidth, $iHeight) If @error Then return SetError(4, @error, 0) _WinAPI_SelectObject($hDC_Backup, $hBitmapBackup) If @error Then return SetError(4, @error, 0) ; init drawing buffer Local $hDC_Backbuffer = _WinAPI_CreateCompatibleDC($hDC) If @error Then return SetError(4, @error, 0) Local $hBitmapBuffer = _WinAPI_CreateCompatibleBitmap($hDC, $iWidth, $iHeight) If @error Then return SetError(4, @error, 0) _WinAPI_SelectObject($hDC_Backbuffer, $hBitmapBuffer) If @error Then return SetError(4, @error, 0) ; load backup buffer _WinAPI_BitBlt($hDC_Backup, 0, 0, $iWidth, $iHeight, $hDC, 0, 0, $SRCCOPY) If @error Then return SetError(4, @error, 0) ; initialize drawing buffer graphics object Local $hGfxCtxt = _GDIPlus_GraphicsCreateFromHDC($hDC_Backbuffer) If @error Then return SetError(4, @error, 0) _GDIPlus_GraphicsSetSmoothingMode($hGfxCtxt, $GDIP_SMOOTHINGMODE_HIGHQUALITY) If @error Then return SetError(4, @error, 0) _GDIPlus_GraphicsSetPixelOffsetMode($hGfxCtxt, $GDIP_PIXELOFFSETMODE_HIGHQUALITY) If @error Then return SetError(4, @error, 0) $__Wallpaper_iSleepTimer = TimerInit() Local $arObjects = [$iWidth, $iHeight, $arMonitorInfo, $hWorkerW, $hDC, $hDC_Backup, $hBitmapBackup, $hDC_Backbuffer, $hBitmapBuffer, $hGfxCtxt] return $arObjects EndFunc ;======Internel Use Only====================================================== ; ; Function Name: __Wallpaper_ClearInternal ; Description: Clear the background and restore the original wallpaper ; Parameter(s): $arObjects: Array with needed Objects, created by __Wallpaper_Startup. ; Requirement(s): none. ; Return Value(s): none. ; Author(s): Kanashius ; ;=============================================================================== Func __Wallpaper_ClearInternal(Byref $arObjects) _WinAPI_BitBlt($arObjects[4], 0, 0, $arObjects[0], $arObjects[1], $arObjects[5], 0, 0, $SRCCOPY) __Wallpaper_SetWallpaper(__Wallpaper_GetWallpaperFile()) EndFunc ;======Internel Use Only====================================================== ; ; Function Name: __Wallpaper_Shutdown ; Description: Clear the wallpaper and shutdown of the UDF, required when the __Wallpaper_Start or __Wallpaper_Startup was called. Exits the program. Will be called by __Wallpaper_Start, when the loop is done. ; Parameter(s): $arObjects: Array with needed Objects, created by __Wallpaper_Startup. ; Requirement(s): none. ; Return Value(s): none. ; Author(s): Kanashius ; ;=============================================================================== Func __Wallpaper_Shutdown(Byref $arObjects) __Wallpaper_ClearInternal($arObjects) _GDIPlus_GraphicsDispose($arObjects[9]) _WinAPI_DeleteObject($arObjects[8]) _WinAPI_DeleteObject($arObjects[7]) _WinAPI_DeleteObject($arObjects[6]) _WinAPI_DeleteObject($arObjects[5]) _WinAPI_ReleaseDC($arObjects[3], $arObjects[4]) _GDIPlus_Shutdown() _WinAPI_RedrawWindow($arObjects[3],"","",BitOR($RDW_ERASE,$RDW_INVALIDATE,$RDW_UPDATENOW,$RDW_FRAME,$RDW_ALLCHILDREN)) Exit EndFunc ;======Internel Use Only====================================================== ; ; Function Name: __Wallpaper_GetScreenInfo ; Description: Get the information of all screens ; Parameter(s): none. ; Requirement(s): none. ; Return Value(s): 2D-Array with Monitor Information. ; [0][0] - X-Screen position ; [0][1] - Y-Screen position ; [0][2] - Screen width ; [0][3] - Screen height ; [0][4] - True if the screen is the primary screen ; ... ; Author(s): Kanashius ; ;=============================================================================== Func __Wallpaper_GetScreenInfo() Local $arMonitors = _WinAPI_EnumDisplayMonitors() Local $arMonitorResult[UBound($arMonitors)][5], $iCount = 0 For $i = 1 To UBound($arMonitors)-1 Step 1 $arMonitorInfo=_WinAPI_GetMonitorInfo($arMonitors[$i][0]) If Not @error Then $arData = _WinAPI_EnumDisplaySettings($arMonitorInfo[3], $ENUM_CURRENT_SETTINGS) If Not @error Then $arMonitorResult[$i-1][0] = DllStructGetData($arMonitorInfo[0], 1) $arMonitorResult[$i-1][1] = DllStructGetData($arMonitorInfo[0], 2) $arMonitorResult[$i-1][2] = $arMonitorResult[$i][0] + $arData[0] $arMonitorResult[$i-1][3] = $arMonitorResult[$i][1] + $arData[1] $arMonitorResult[$i-1][4] = $arMonitorInfo[2] <> 0 $iCount+=1 EndIf EndIf Next ReDim $arMonitorResult[$iCount][5] _ArraySort($arMonitorResult, 1, 0, 0, 4) If UBound($arMonitorResult)>0 Then Local $iYMin=$arMonitorResult[0][0], $iXMin=$arMonitorResult[0][1] For $i = 0 To UBound($arMonitorResult)-1 Step 1 If $arMonitorResult[$i][0]<$iYMin Then $iYMin=$arMonitorResult[$i][0] If $arMonitorResult[$i][1]<$iXMin Then $iXMin=$arMonitorResult[$i][1] Next $iYMin = $iYMin*-1 $iXMin = $iXMin*-1 For $i = 0 To UBound($arMonitorResult)-1 Step 1 $arMonitorResult[$i][0] += $iYMin $arMonitorResult[$i][1] += $iXMin Next EndIf return $arMonitorResult EndFunc ;======Internel Use Only====================================================== ; ; Function Name: __Wallpaper_GetWorkerW ; Description: Get the window to draw at. ; Parameter(s): none. ; Requirement(s): none. ; Return Value(s): HWND of the worker window ; Error(s): 1 - WorkerW window not found ; 2 - Error calling __Wallpaper_FindWindowByClass ; Author(s): Kanashius ; ;=============================================================================== Func __Wallpaper_GetWorkerW() Local $arWorkerWhwnd = __Wallpaper_FindWindowByClass("WorkerW", Default, True) if @error then return SetError(2, 0, 0) Local $iPos = -1 For $i = 0 To UBound($arWorkerWhwnd)-1 Step 1 If __Wallpaper_FindWindowByClass("SHELLDLL_DefView", $arWorkerWhwnd[$i], False, True) Then $iPos = $i+1 ExitLoop EndIf Next If $iPos