Jump to content

Desktop Class: WorkerW


gsx
 Share

Recommended Posts

On Windows 7 Progman is replaced by WorkerW (akaik).

Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

Link to comment
Share on other sites

I have Windows 7 x64, and it still reports 'Progman' for me.

*edit: According to this thread, it looks like WorkerW may possibly be the more reliable method in Windows 7? Odd, because I believe Internet Explorer used 'WorkerW' class in the past..

Edited by Ascend4nt
Link to comment
Share on other sites

KaFu, do you know the Desktop Window handle's 'children' encompass ALL things on the desktop, all programs, all program's controls, and so on? For me on my basic desktop, thats over 1600 items it has to traverse through. There's gotta be a better way.

If we know its either Progman or WorkerW, maybe we need to just check those and if they are full-screen. We could also possibly further check if they have a listview child (which would result in far fewer checks)..

Edited by Ascend4nt
Link to comment
Share on other sites

Okay, somehow I got my desktop to register as 'WorkerW'. I'm not certain exactly how, but I recall starting up and setting the wallpaper with an external program. I'll have to see if that's replicable.

Anyway, here's a solution I propose that might work the best, since there are actually numerous 'WorkerW' class windows on my Windows 7 window list. So far, it registers perfectly fine. I'd appreciate it if others would give it a try and let me/us know if the result is the same as what you get with the AutoIt Window Info Tool (note that a blank title indicates it found a 'WorkerW' window typically, otherwise the title will be 'Program Manager'):

$hDeskWin=WinGetHandle("[CLASS:Progman]")
$hListView=ControlGetHandle($hDeskWin,'','[CLASS:SysListView32; INSTANCE:1]')
If $hDeskWin='' Or $hListView='' Then
    ConsoleWrite("Looking through WorkerW windows.."&@CRLF)
    $aWinList=WinList("[CLASS:WorkerW]")
    For $i=1 To $aWinList[0][0]
        $hListView=ControlGetHandle($aWinList[$i][1],'','[CLASS:SysListView32; INSTANCE:1]')
        If $hListView<>'' Then ExitLoop
    Next
    If $i<=$aWinList[0][0] Then $hDeskWin=$aWinList[$i][1]
EndIf
If $hListView='' Then Exit
MsgBox(0,"Desktop handle (with ListView) found","Handle to desktop: "&$hDeskWin&", Title: '"&WinGetTitle($hDeskWin)&"',"&@CRLF&"Handle to Listview: "&$hListView)
ConsoleWrite("Handle to desktop: "&$hDeskWin&", Title: '"&WinGetTitle($hDeskWin)&"', Handle to Listview: "&$hListView&@CRLF)

*edit: Added check for cases where $i>window count

Edited by Ascend4nt
Link to comment
Share on other sites

Okay, just found a way to force 'Progman' to be the desktop window: Disable 'Desktop Composition' (turn off Windows Aero). The above code works for me in both scenarios, and is much faster than KaFu's method, so I have faith that this method is the one to use:P

The only issue that *could* occur is if some old program that used older Internet Explorer 'WorkerW' windows might cause this to get incorrect info (its possible with some virtualization packages to run Internet Explorer 6 etc on all O/S's).

I think, to be *absolutely* sure, we can add the control ID check that KaFu uses like this (in the For-Next loop):

If $hListView<>'' And _WinAPI_GetWindowLong($hListView,-12)=1 Then ExitLoop
Link to comment
Share on other sites

Okay, just found a way to force 'Progman' to be the desktop window: Disable 'Desktop Composition' (turn off Windows Aero).

Good find ;), I always wondered what might be the difference, but as usual DWM kicks in an me of my feet :)...

KaFu, do you know the Desktop Window handle's 'children' encompass ALL things on the desktop, all programs, all program's controls, and so on? For me on my basic desktop, thats over 1600 items it has to traverse through.

You're right, some 1300 controls for me which are processed on my box in ~100ms. BUT it seems to be save for any OS config AND only needs to be run once on program start (desktop handle won't change, thus it seems save to use a global var for that), so imho the 100ms overhead still is acceptable ;)...
Link to comment
Share on other sites

KaFu, no doubt if its not done that often it won't be a problem. However, are you certain that only one window with a 'SysListView32' control with an ID of 1 will always be explorer?

I'm not sure if its possible myself... a simple check using '_ArrayDisplay' for example seems to always set the SysListView32 control to a control ID of 3, but I wonder about other types of program's window setups (which will also display in the children list for the main desktop handle)..

My code example above seems to work on all the O/S's I've tried it on, so it seems pretty reliable. Since these are the only two types of classes we've seen in O/S's so far, it solves both scenarios fairly easily. We shall see when Windows 8 comes out what revisions will need to be made hehe ;)

*edit: I just checked using my _EnumChildWindows on the main desktop window and there is a second 'SysListView32' with an ID of 1. (title='FolderView', parent = 'ShellView', parent class= 'SHELLDLL_DefView', explorer.exe). I get 133 items for this one, yikes. This may pose an issue for your code unless the last window enumerated is always the main window handle. (it works that way for me right now, but how can we be certain it always will?)

Edited by Ascend4nt
Link to comment
Share on other sites

  • 6 months later...

I'm resurrecting this thread because I found it via Google and it indirectly helped with my problem.

My problem was a program I wrote that looks for the SysListView32 control inside SHELLDLL_DefView. On Windows 7 this had previously been inside WorkerW (Aero enabled). My script suddenly stopped working. Debugging the problem I noticed that for some reason SHELLDLL_DefView and SysListView32 were suddenly under Progman. Searching Google for "WorkerW" brought me to this thread (It's the 3rd result). I saw the comment about Desktop Composition and checked (not that I needed to) - it was enabled. I've had Aero enabled the entire time. While trying to locate the setting I noticed that Windows said I was using an unsaved theme instead of the custom theme I have saved. The only difference is that my theme uses a slideshow for the background where-as the unsaved theme was using a single image (Presumably the image whenever this theme became active). I had a clue where this unsaved theme may be coming from and it seems I was correct. I use TightVNC and have the option set to use a black background when a VNC viewer is connected. This causes TightVNC to change my theme. It seems TightVNC is also changing some setting I can't locate but the end result is that when Explorer is restarted it puts the Desktop under Progrman instead of WorkerW even though Aero is enabled. If I select my normal theme (with slideshow) then restart Explorer it's back under WorkerW where it belongs. I saved both themes and opened them up to compare them and the only difference is the slideshow stuff. There's no obvious setting that is different between the two.

I resurrect this thread to provide a simple warning: Always check both locations when trying to find the Desktop. I'm going to modify my code to check first for Progman -> SHELLDLL_DefView -> SysListView32 and if that fails then I will go into the current code which iterates all WorkerW windows looking for it. This should prevent the issue from happening in the future. It seems there's more than one way for Progman to be the parent window on Windows 7 other than just Desktop Composition. I am rather curious as to what TightVNC is changing that causes this shift in Explorer behavior. I'm already launching TightVNC via a script so if I can figure out what it's doing I can probably script a way to fix it so I don't have some stray odd setting that shouldn't be toggled.

Link to comment
Share on other sites

  • 2 months later...

I guess I'm resurrecting this thread now haha, but I just reworked the code I had posted previously. Thanks to Valik, the code is even shorter and faster, with no need for _WinAPI* functions:

; ===============================================================================================================================
; <_WinGetDesktopHandle.au3>
;
; Function to get the Windows' Desktop Handle.
;   Since this is no longer a simple '[CLASS:Progman]' on Aero-enabled desktops, this method uses a slightly
;   more involved method to find the correct Desktop Handle.
;
; Author: Ascend4nt, credits to Valik for pointing out the Parent->Child relationship: Desktop->'SHELLDLL_DefView'
; ===============================================================================================================================

Func _WinGetDesktopHandle()
    Local $i,$hDeskWin,$hSHELLDLL_DefView,$hListView
    ; The traditional Windows Classname for the Desktop, not always so on newer O/S's
    $hDeskWin=WinGetHandle("[CLASS:Progman]")
    ; Parent->Child relationship: Desktop->SHELLDLL_DefView
    $hSHELLDLL_DefView=ControlGetHandle($hDeskWin,'','[CLASS:SHELLDLL_DefView; INSTANCE:1]')
    ; No luck with finding the Desktop and/or child?
    If $hDeskWin='' Or $hSHELLDLL_DefView='' Then
        ; Look through a list of WorkerW windows - one will be the Desktop on Windows 7+ O/S's
        $aWinList=WinList("[CLASS:WorkerW]")
        For $i=1 To $aWinList[0][0]
            $hSHELLDLL_DefView=ControlGetHandle($aWinList[$i][1],'','[CLASS:SHELLDLL_DefView; INSTANCE:1]')
            If $hSHELLDLL_DefView<>'' Then
                $hDeskWin=$aWinList[$i][1]
                ExitLoop
            EndIf
        Next
    EndIf
    ; Parent->Child relationship: Desktop->SHELDLL_DefView->SysListView32
    $hListView=ControlGetHandle($hSHELLDLL_DefView,'','[CLASS:SysListView32; INSTANCE:1]')
    If $hListView='' Then Return SetError(-1,0,'')
    Return SetExtended($hListView,$hDeskWin)
EndFunc

; Example use:

#cs
#include <GuiListView.au3>
$iTimer=TimerInit()
$hDeskWin=_WinGetDesktopHandle()
$hListView=HWnd(@extended)
ConsoleWrite("Time elapsed:"&TimerDiff($iTimer)&" ms"&@CRLF)
$iDeskItems=_GUICtrlListView_GetItemCount($hListView)
ConsoleWrite("Handle to desktop: "&$hDeskWin&", Title: '"&WinGetTitle($hDeskWin)&"', Handle to Listview: "&$hListView&", # Items:"&$iDeskItems&", Title: "&WinGetTitle($hListView)&@CRLF)
MsgBox(0,"Desktop handle (with ListView) found","Handle to desktop: "&$hDeskWin&", Title: '"&WinGetTitle($hDeskWin)&"',"&@CRLF&"Handle to Listview: "&$hListView&@CRLF&"# Desktop Items:"&$iDeskItems)
#ce
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...