Jump to content

_shellExecuteHidden (allow no windows to become visible)


Bluesmaster
 Share

Recommended Posts

Run a process and surpress any windows created by that process that may become visible.
Main purpose is to automate gui-applications on a hidden desktop so that the user cannot disturb the process.
Its my first attempt to write a UDF so please be patient. Advices, bug reports and recommendations are welcome.
.

#Include <WinAPIEx.au3>



; #FUNCTION# ====================================================================================================================
; Name ..........: ShellExecuteHidden
;
; Description ...: runs a process on another winApi-desktop, so that none of its windows ever get visible, but can be automated by window messages and other technologies.
;                  The difference to shellExecute( ... , ... , @SW_HIDE ) is, that no just the first, but any windows from the created process will stay totaly isolated from user input and graphics
;
; Syntax ........: ShellExecuteHidden($filepath[, $parameters = "" [, $returnType = 1 [, $waitingOption = -1 ]]])
;
; Parameters ....: $filepath       - the file to run
;
;                  $returnType     =           0  >>  returns window handle of toplevel window of the started process
;                                                     even if its window is "hidden" (would not be visible on normal desktop)
;                                  =           1  >>  returns window handle of toplevel window of the started process
;                                  =           2  >>  returns process id (PID) of the started process
;
;
;                  $waitingOption  =          -2  >> dont wait (not recommended for window handles, as they need some time to appear even if the program is loading fast)
;                                  =          -1  >> wait 1000 milliseconds for windows to "appear" but dont wait for processes to finish (compromise)
;                                  =           0  >> wait for the process to finish or the window to appear
;                                  =         <x>  >> wait <x> milliseconds for the process to finish or the window to appear (see "$returnType" )
;
; Return values .: windowHandle or ProcessID
; Author ........: Bluesmaster
; Modified ......: 2013 - 11 - 09
; Remarks .......:
; Related .......: ShellExecute, _WinAPI_CreateDesktop
; Link ..........: http://msdn.microsoft.com/en-us/library/windows/desktop/ms687098(v=vs.85).aspx
; Example .......: Yes
; ===============================================================================================================================
Func _shellExecuteHidden( $filepath , $parameters = "" , $returnType = 1 , $waitingOption = -1 )


    ; 1 - Create Desktop
    ;Global Const $GENERIC_ALL = 0x10000000
    $hNewDesktop     = _WinAPI_CreateDesktop( "ShellExecuteHidden_Desktop" , $GENERIC_ALL )


    ; 2 - Start Process
    $tProcess = DllStructCreate( $tagPROCESS_INFORMATION )
    $tStartup = DllStructCreate( $tagSTARTUPINFO )
    DllStructSetData( $tStartup , 'Size', DllStructGetSize( $tStartup) )
    DllStructSetData( $tStartup , 'Desktop', _WinAPI_CreateString(  "ShellExecuteHidden_Desktop" ) )

    Local $pid
    If _WinAPI_CreateProcess( $filepath , $parameters , 0, 0, 0, 0x00000200 , 0, 0, DllStructGetPtr($tStartup), DllStructGetPtr($tProcess)) Then
        $pid =  DllStructGetData( $tProcess , 'ProcessID' )
    Else
        Return -1
    EndIf


    ; 3 - Return Process
    if $returnType = 2 Then
        if $waitingOption > -1 Then ProcessWaitClose( $pid  , $waitingOption  )
        Return $pid
    EndIf



    ; 4 - Return WindowHandle
    if $waitingOption =  -1  Then
        Sleep( 1000  )
    ElseIf $waitingOption >  0 Then
        Sleep( $waitingOption  )
    EndIf

    While True  ; keep searching for the window

        $aWindows = _WinAPI_EnumDesktopWindows( $hNewDesktop , $returnType ) ; $returnType = 0 >> means also list hidden windows

        if IsArray( $aWindows ) Then

            for $i = 1 to $aWindows[0][0]

                ;~      MsgBox( 0 , '' , $curPID  & " " & $pid & "      "  & $hWnd & " " & $aWindows[$i][0] )

                $hWnd = $aWindows[$i][0]
                if $pid = WinGetProcess( $hWnd ) Then ; same process?

                    do ; searching through parent windows ...
                        $hLast = $hWnd ; cache it for not loosing it when desktop is reached
                        $hWnd  = _WinAPI_GetParent( $hLast )
                    Until $hWnd = 0    ; ... until root/ desktop is reached
                    $hWnd = $hLast

                    Return $hWnd  ; return the toplevel-window of the process

                EndIf

            Next

        EndIf

        if $waitingOption = 0 Then ; keep searching for the window until it appears ( in worst case endless )
            Sleep( 200 )
        Else
            Return -1
        EndIf

    WEnd


EndFunc

.
Examples: (also included as comment in download file)


; EXAMPLE 1 ( principle ):

; 1 - open a programm with @SW_HIDE
ShellExecute( @ComSpec , "/c start notepad.exe" , "" , "" ,  @SW_HIDE )
WinWaitActive(  "[CLASS:Notepad]" )
ControlSend( "[CLASS:Notepad]" ,   "" , "Edit1" , "As you can see, you cannot prevent an hidden started application " & @LF & "from opening another window that gets visible...")
MsgBox( 0 , '' , "I understand. show me the version with appstart on hidden desktop" )
WinKill(  "[CLASS:Notepad]"  )

; 2 - do the same routine with "_shellExecuteHidden"
$hWinHiddenApp = _shellExecuteHidden( @ComSpec , "/c start notepad.exe"  )
ShellExecute( "taskmgr.exe" )
MsgBox( 0 , '' ,  "...´ok look in your taskmanager now. There should be a new notepad.exe entry but no window is visible." )

; 3 - close  hidden application
WinKill( $hWinHiddenApp )



; EXAMPLE 2 ( interaction ):

; 1 - start  hidden application
MsgBox( 0 , '' ,  "Now we start an editor on the hidden desktop and interact with it programmaticly" )
$hWinHiddenApp = _shellExecuteHidden( @SystemDir & "\notepad.exe" )

; 2 - send to hidden application
ControlSend( $hWinHiddenApp  ,  "" , "Edit1" , "di{BS}eb{BS}mk{BS}os{BS}" )

; 3 - receive information from hidden application
MsgBox( 0 , '' , "Text in the editor on hidden desktop: " & @LF & @LF &  ControlGetText( $hWinHiddenApp  , "" , "Edit1" ) )

; 4 - close  hidden application
WinKill( $hWinHiddenApp )

.
_shellExecuteHidden.au3
winapiex   (needed)

Edited by Bluesmaster

My UDF: [topic='156155']_shellExecuteHidden[/topic]

Link to comment
Share on other sites

I thought about that. But as the main purpose of the fcn is to automate the startet application,

the udf would split in 2 parts which decreases the UDFs usability. So deskop just stays open until next reboot.

AFAIK it does not comsume relevant ressources or interfere with other processes

regards

Blues

My UDF: [topic='156155']_shellExecuteHidden[/topic]

Link to comment
Share on other sites

So deskop just stays open until next reboot.

Just a bit of advice is all.

After looking I see you do not even return the new desktop handle.

It's entirely up to you of course, but leaving it hanging around is quite lazy, and my advice to anyone who might need such a function is to modify this UDF to return desktop handle, as well as any window handles created in it.

AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt   ipify 

Monkey's are, like, natures humans.

Link to comment
Share on other sites

  • 1 month later...

Hi Bluesmaster

 Thanks for sharing. I can be very useful.

I have an application that starts a webcam and capture things in it´s screen (PixelSearch).

The webcam window is pointed to a specific area and is not to be seen.

Now is we need to setup in windows7 a desktop extension where the notebook screen is the main one and another screen is  the extension, where the webcam window is.

Questions:

1- If I execute the webcam pgm with your udf on a new desktop, probably the coordinate system will be another than main screen .

    I think that at PixelSearch I need do specify the winhandle, correct? And the coordinates obtained would be relative to webcam application?

2- I suppose that functions like MouseGetPos, mouseMove, etc., would e able to operate just on main screen, correct?

Thanks

Jose

Link to comment
Share on other sites

@Jose

I am not an expert but I think you should not imagine this desktop as a kind of hidden desktop but as an organisation unit for security purposes.

Mouse and keyboard ( user-input in general ) can only be processed by the current active desktop. There is also a  desktop for the windows logon-screen

which can by purpose (!) not be automated. (The screensaver also got one). The next higher organisation unit is the so  called "window station" which is  used

for remote desktop connections for example. This then does also separates the clipboard. You can read further here:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms681928%28v=vs.85%29.aspx

I am also not sure if graphics is processed ( if pixelsearch works ) untit the desktop is  active but I would encourage you to share your experiences with us :)

 

@d4arkon3

I will update it later with cleaner code. I also want to add the oportunity to change the desktop after loading. But I am a bit rare of time at the moment :)

My UDF: [topic='156155']_shellExecuteHidden[/topic]

Link to comment
Share on other sites

Thank you very much for your reply. I start my autoit script from a hidden desktop, then it starts IE browser then it tries to send mouse clicks , but unfortunately it doesnt work there. (I checked the result with _IEDocReadHTML($oIE) and also checked with iniwrite)- Btw it really does many things on that hidden desktop- it opens browser, navigates to certain web pages, but when it comes to mouse clicking and sending anything- it doesnt respond. I know, you would advise controlclick, controlsend in this case, but there are many unreachable places overthere. Would it be really more effective to try to create Window station though?- As far as I understood, Window station may allow to interact in an insolated way with the second created station and with desktop on it?

Thanx again!!!!

Link to comment
Share on other sites

I am really rare of time and cannot solve the problem for you. But I can give some small tips.

At first ensure that your automations is 100% robust working when it is visible.

Use only controlsend and control click! ( if you got no control use x y coordinates on the main window )

Ensure all handles are valid ( consolewrite... )

Ensure window sizes are equal ( wingetpos ... )

Yes you are blind on this desktop and yes this is  a big problem :)

But take it as challenge. If you dont understand why something isnt working:

Build small test guis ( which you can better get informations from than from internet explorer ). Make experiments...

Dont give up and please share your experiences :)

good luck

Blues

My UDF: [topic='156155']_shellExecuteHidden[/topic]

Link to comment
Share on other sites

Glad that I could help.

By the way I found out through some experiments, that the windows on such a  hidden desktop will not render their DCs ( device context )

so for automation with image regognition unfortunately you will have to switch to that desktop or get the window to the current desktop which I will describe another time.

regards

Blues

My UDF: [topic='156155']_shellExecuteHidden[/topic]

Link to comment
Share on other sites

So I made some other experiments. It turns out, that neither pixelGetColor  pixelSearce or any other device context operation can gather

graphical information from the hidden desktop even if you manually send paint messages :(

So unfortunately my udf is not appropriate for graphical operations and image regognition. I would recommend for that

- virtual machines

- out of monitor region ( manual repaint )

So far.

best regards

My UDF: [topic='156155']_shellExecuteHidden[/topic]

Link to comment
Share on other sites

I mean if you want to automate your window while the user can continue working you can place it outside your Monitor reach

Lets say you place it on x = 4000 y=4000

But if you Need graphical Information ( lets say you must click on a Point that is in a certain color ) then you must

send a "wm_paint" message to the window manually because Windows does not repaint Windows outside the Monitor reach

 

regards

Blues

My UDF: [topic='156155']_shellExecuteHidden[/topic]

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...