Select Posted July 17, 2013 Share Posted July 17, 2013 Hello, I'm trying to communicate with a GUI over a secondary desktop thread, but It doesn't seem to pick up any commands sent to the GUI even though it responds perfectly on the main desktop. Any ideas as to how I can go about this? Link to comment Share on other sites More sharing options...
0xdefea7 Posted July 17, 2013 Share Posted July 17, 2013 Can you post your code please? I am sure I can help you get it sorted out. Link to comment Share on other sites More sharing options...
Decipher Posted July 17, 2013 Share Posted July 17, 2013 (edited) Select, Nice username Right off the top of my head, I'd say that the simplest approach would be change desktop threads and set the X,Y to something offscreen until you've finished then reset everything back to normal. When you say communicate do you mean sending commands via ControlSend or what? I'd rather read code then chit chat expandcollapse popup#include "WinAPIEx.au3" ; Get WinAPIEx from -> http://www.autoitscript.com/forum/topic/98712-winapiex-udf/ #include "APIConstants.au3" ; Included with WinAPIEx #include <Array.au3> ; Included with AutoIt3 Opt("WinTitleMatchMode", 2) ; 2 = Match any substring in the windows title, 3 = Exact title match Global Enum $nStation, $nDesktop, $nWIndow ; Used for array index identification Global $aWindow = _GetWindowHwndEx("Firefox") If IsArray($aWindow) Then ConsoleWrite(">Station: " & $aWindow[$nStation] & @CRLF) ; Low level station handle ConsoleWrite(">Desktop: " & $aWindow[$nDesktop] & @CRLF) ; This is not the handle to the desktop window. ConsoleWrite(">Window: " & $aWindow[$nWIndow] & @CRLF) ; The window handle as returned by WinGetHandle If _WinAPI_SwitchDesktop($aWindow[$nDesktop]) Then ConsoleWrite("-->Switched Desktop Successfully!" & @CRLF) Dim $aPos = WinGetPos($aWindow[$nWIndow]) WinMove($aWindow[$nWIndow], "", -5000, -5000) Sleep(3000) ; Send Commands WinMove($aWindow[$nWIndow], "", $aPos[0], $aPos[1]) ; Reset to original position EndIf Else ConsoleWrite("!>Failed to find the specified window!" & @CRLF) EndIf Func _GetWindowHwndEx($sTitle, $sText = "") ; Author: Decipher Local $aStations = _WinAPI_EnumWindowStations(), $aDesktops, $hStation, $hDesktop, $aWindows, $hWindow = WinGetHandle($sTitle, $sText) If Not $hWindow Then Return SetError(1, 0, "") For $n = 1 To $aStations[0] Step 1 $hStation = _WinAPI_OpenWindowStation($aStations[$n], $WINSTA_ENUMDESKTOPS) If $hStation Then $aDesktops = _WinAPI_EnumDesktops($hStation) For $i = 1 To $aDesktops[0] Step 1 $hDesktop = _WinAPI_OpenDesktop($aDesktops[$i], BitOR($DESKTOP_SWITCHDESKTOP, $DESKTOP_READOBJECTS)) If $hDesktop Then $aWindows = _WinAPI_EnumDesktopWindows($hDesktop, True) ; Change the boolean to false to search through hidden windows For $d = 1 To $aWindows[0][0] Step 1 If $aWindows[$d][0] = $hWindow Then Local $aRet[3] = [$hStation, $hDesktop, $hWindow] Return SetError(0, 0, $aRet) EndIf Next EndIf Next EndIf Next Return SetError(2, 0, "") EndFunc Edit - Added comment on EnumDesktopWindows line. Anonymous Edited July 17, 2013 by Decipher Spoiler Link to comment Share on other sites More sharing options...
Select Posted July 17, 2013 Author Share Posted July 17, 2013 Good morning, Thanks for the reply. I'm using this example snippet from the WinAPI, here it is. #Include <APIConstants.au3> #Include <WinAPIEx.au3> Opt('MustDeclareVars', 1) Global $hDesktop, $hPrev, $pText, $tProcess, $tStartup ; Retrieve a handle to the current desktop and create a new desktop named "MyDesktop" $hPrev = _WinAPI_GetThreadDesktop(_WinAPI_GetCurrentThreadID()) $hDesktop = _WinAPI_CreateDesktop('MyDesktop', BitOR($DESKTOP_CREATEWINDOW, $DESKTOP_SWITCHDESKTOP)) If Not $hDesktop Then MsgBox(16, 'Error', 'Unable to create desktop.') Exit EndIf ; Switch to the newly created desktop _WinAPI_SwitchDesktop($hDesktop) ; Run "calc.exe" on "MyDesktop" and wait until a process will not be closed by user $pText = _WinAPI_CreateString('MyDesktop') $tProcess = DllStructCreate($tagPROCESS_INFORMATION) $tStartup = DllStructCreate($tagSTARTUPINFO) DllStructSetData($tStartup, 'Size', DllStructGetSize($tStartup)) DllStructSetData($tStartup, 'Desktop', $pText) If _WinAPI_CreateProcess('', @SystemDir & '\calc.exe', 0, 0, 0, $CREATE_NEW_PROCESS_GROUP, 0, 0, DllStructGetPtr($tStartup), DllStructGetPtr($tProcess)) Then ProcessWaitClose(DllStructGetData($tProcess, 'ProcessID')) EndIf ; Switch to previous desktop and close "MyDesktop" _WinAPI_SwitchDesktop($hPrev) _WinAPI_CloseDesktop($hDesktop) ; Free memory allocated for a string _WinAPI_FreeMemory($pText) The desktop gets created successfully, I can switch over, etc. However the tricky part is that I'm automating an installation package, and so I want it to be as non-influencing to the users current desktop experience. I have multiple packages being simultaneously being installed. I realize i made a mistake with the topic title, it was ControlSend that I'm using to automate key presses to the GUI. I'm not sure if it's possible to do this without interrupting the users experience, unless there is another way of making the window hidden before WM_Create gets initiated, I'm guessing through SetWindowsHookEx, however anti-viruses tend to pick this up as malicious I find. Forgive me, as I'm a beginner programmer. Cheers guys. Link to comment Share on other sites More sharing options...
0xdefea7 Posted July 17, 2013 Share Posted July 17, 2013 (edited) @Decipher, Very nice work with that code @Select, It seems that what Decipher posted should do what you need. Use his code to get the window handle. Use ControlGetHandle with the handle that you just got using Decipher's code, ControlSend or SendMessage (likely the latter, look in the helpfile under "my script does not work on a locked workstation - same concept here) I don't have time to code it right now, but I'll do it later when I get home if there is no solution yet Edited July 17, 2013 by 0xdefea7 Link to comment Share on other sites More sharing options...
Decipher Posted July 17, 2013 Share Posted July 17, 2013 (edited) When testing my code earlier I noticed that the desktop handle returned by _GetWindowHwndEx was different than what is returned by this line of code: $hPrev = _WinAPI_GetThreadDesktop(_WinAPI_GetCurrentThreadID()) I was going to compare the two and if they were different then switch back to the original desktop like your doing now. Although the desktops(Just one) are the same, the handles aren't matching on my system.... It appears as if the desktop thread handle and standard desktop handle are interchangable but I don't know how to compare the two! Select, You mentioned SetWindowsHookEx, how would you use it? 0xdefea7, Any ideas on how to move an already existent process onto another desktop? Edit - Perfectionist Anonymous Edited July 17, 2013 by Decipher Spoiler Link to comment Share on other sites More sharing options...
0xdefea7 Posted July 17, 2013 Share Posted July 17, 2013 (edited) Are you on the same desktop when you are testing this code? Or are your running firefox on another desktop, then running your function? For the second question, I have no idea. The desktop name is passed in the startupinfo struct. I could imagine that if there was a way to change that dynamically, it might be possible. Thanks for giving me something to pass my free time today To Google! Edited July 17, 2013 by 0xdefea7 Link to comment Share on other sites More sharing options...
Decipher Posted July 17, 2013 Share Posted July 17, 2013 0xdefea7, I'm testing this code with the default desktop(Winsta0) only but seeing how enumerate the stations and so forth it should work as advertised with multiple stations, desktop, etc. Are you on the same desktop when you are testing this code? Or are your running firefox on another desktop, then running your function? For the second question, I have no idea. The desktop name is passed in the startupinfo struct. I could imagine that if there was a way to change that dynamically, it might be possible. Thanks for giving me something to pass my free time today To Google! http://msdn.microsoft.com/en-us/library/ms686232(VS.85).aspx - SetProcessWindowStation Let's get something working. Ready? Go. Your Welcome! Anonymous Spoiler Link to comment Share on other sites More sharing options...
Select Posted July 17, 2013 Author Share Posted July 17, 2013 Thanks a lot for the help guys, when I get home I'll do some testing @ Decipher - You mentioned how I would use SetWindowsHookEx. I've never tried this, specially to hook a window before it's created, but my guess would be to use WH_CBT and then HCBT_CREATEWND to then change the properties before it's created. Cheers! Link to comment Share on other sites More sharing options...
Zooovel2 Posted July 21, 2013 Share Posted July 21, 2013 Anyone got it working ? Link to comment Share on other sites More sharing options...
Decipher Posted July 21, 2013 Share Posted July 21, 2013 Zooovel2, If your concerned with window manipulation on another desktop besides the default desktop then I would recommend that you use the code above. I've only ever tried ControlSend or other methods in the context of the default desktop. I'd think that you'd have to switch to the desktop that of which the application is currently running on before sending commands to it's interface based on the problems the OP is experiencing. Use the UDF above to get the window, desktop, and station handles and then switch to that desktop using its handle before utilizing ControlSend or other methods. I don't know of a way around this. If you can't figure it out then show some code and I'd be glad to assit. Note: Software like VirtualWin only virtualize multiple desktops, meaning they don't use Windows API to create their desktops. This topic is concerned with Microsoft's user interactive work stations(desktops created using native API) and their properties. If your using such software then this topic is irrevelant to your question(s). Anonymous Spoiler Link to comment Share on other sites More sharing options...
Ascend4nt Posted July 22, 2013 Share Posted July 22, 2013 I'm tempted to test the Desktop switch code to see what the difference is between desktops and secondary logons or sessions.. but once I'm switched over to a new desktop, how do I switch back.. what exactly changes? And is there something in windows I can use to manually switch? Thx My contributions: Performance Counters in Windows - Measure CPU, Disk, Network etc Performance | Network Interface Info, Statistics, and Traffic | CPU Multi-Processor Usage w/o Performance Counters | Disk and Device Read/Write Statistics | Atom Table Functions | Process, Thread, & DLL Functions UDFs | Process CPU Usage Trackers | PE File Overlay Extraction | A3X Script Extract | File + Process Imports/Exports Information | Windows Desktop Dimmer Shade | Spotlight + Focus GUI - Highlight and Dim for Eyestrain Relief | CrossHairs (FullScreen) | Rubber-Band Boxes using GUI's (_GUIBox) | GUI Fun! | IE Embedded Control Versioning (use IE9+ and HTML5 in a GUI) | Magnifier (Vista+) Functions UDF | _DLLStructDisplay (Debug!) | _EnumChildWindows (controls etc) | _FileFindEx | _ClipGetHTML | _ClipPutHTML + ClipPutHyperlink | _FileGetShortcutEx | _FilePropertiesDialog | I/O Port Functions | File(s) Drag & Drop | _RunWithReducedPrivileges | _ShellExecuteWithReducedPrivileges | _WinAPI_GetSystemInfo | dotNETGetVersions | Drive(s) Power Status | _WinGetDesktopHandle | _StringParseParameters | Screensaver, Sleep, Desktop Lock Disable | Full-Screen Crash Recovery Wrappers/Modifications of others' contributions: _DOSWildcardsToPCRegEx (original code: RobSaunder's) | WinGetAltTabWinList (original: Authenticity) UDF's added support/programming to: _ExplorerWinGetSelectedItems | MIDIEx UDF (original code: eynstyne) (All personal code/wrappers centrally located at Ascend4nt's AutoIT Code) Link to comment Share on other sites More sharing options...
Decipher Posted July 22, 2013 Share Posted July 22, 2013 (edited) Ascend4nt, There is no way to switch desktops using the WIndows Interface that I know of because there isn't anything to switch, only one interactive desktop is created on the "Winsta0" station at login. I edited the example code above to hopefully elaborate how to create a desktop, switch desktops, and switch back to the previous desktop. Just run the code. expandcollapse popup#Include <APIConstants.au3> #Include <WinAPIEx.au3> Opt('MustDeclareVars', 1) ; Retrieve a handle to the current desktop and create a new desktop Global $hDefaultDesktop = _WinAPI_GetThreadDesktop(_WinAPI_GetCurrentThreadID()) Global $hNewDesktop = _CreateDesktop("SecondDesktop") If Not $hNewDesktop Then MsgBox(16, 'Error', 'Unable to create desktop.') Exit EndIf ; Switch to the newly created desktop _WinAPI_SwitchDesktop($hNewDesktop) Dim $nPID = _LaunchProcessOnDesktop("SecondDesktop", @SystemDir & '\calc.exe') Sleep(2000) ProcessClose($nPID) ; Switch to previous desktop _WinAPI_SwitchDesktop($hDefaultDesktop) _WinAPI_CloseDesktop($hNewDesktop) ; Close the other one Func _CreateDesktop($sName) Return _WinAPI_CreateDesktop($sName, BitOR($DESKTOP_CREATEWINDOW, $DESKTOP_SWITCHDESKTOP)) EndFunc Func _LaunchProcessOnDesktop($sDesktopName, $sAppName, $sCommandLine = "") Local $pText = _WinAPI_CreateString($sDesktopName) Local $tProcess = DllStructCreate($tagPROCESS_INFORMATION) Local $tStartup = DllStructCreate($tagSTARTUPINFO) DllStructSetData($tStartup, 'Size', DllStructGetSize($tStartup)) DllStructSetData($tStartup, 'Desktop', $pText) If _WinAPI_CreateProcess($sAppName, $sCommandLine, 0, 0, 0, $CREATE_NEW_PROCESS_GROUP, 0, 0, DllStructGetPtr($tStartup), DllStructGetPtr($tProcess)) Then Return DllStructGetData($tProcess, 'ProcessID') EndIf _WinAPI_FreeMemory($pText) EndFunc I'd think of stations as objects with properties such as interactive or non-interactive. Desktops inherit their properties from stations. When you switch desktops its like changing an environment variable so when an applications attempts to create a window it expands that variable to mean the current desktop and inherits its privileges and etc from that desktop before creating any GUI. If the inheritted properties don't contain the interactive dwflag then the process dosen't have privileges to interact with the user furthermore if the current desktop thread doesn't belong to that application then its operations are hidden the same. Thats the basics of it anyway. One more thing which ya probably already know is that processes inherit their access rights and etc. from the parent process. They inherit the window station and desktop of their parent aswell. So if a service process created on a non-interactive station starts a child process than that process won't have access to the desktop either. You can distinguish between service processes and standard process I quess but they work very similar when it comes to stations and desktops prior to Vista. I think theres more restrictions imposed on services now but if you use WinAPI to create a process on a seperate station even services should be able to bypass this, dunno. Anonymous Edited July 22, 2013 by Decipher Spoiler Link to comment Share on other sites More sharing options...
Ascend4nt Posted July 22, 2013 Share Posted July 22, 2013 decipher, that's a pretty cool effect. I'm sorta confused with what exactly is happening.. I read what you said but still need time to digest it. Dang there's always some feature I didn't know existed in Windows... My contributions: Performance Counters in Windows - Measure CPU, Disk, Network etc Performance | Network Interface Info, Statistics, and Traffic | CPU Multi-Processor Usage w/o Performance Counters | Disk and Device Read/Write Statistics | Atom Table Functions | Process, Thread, & DLL Functions UDFs | Process CPU Usage Trackers | PE File Overlay Extraction | A3X Script Extract | File + Process Imports/Exports Information | Windows Desktop Dimmer Shade | Spotlight + Focus GUI - Highlight and Dim for Eyestrain Relief | CrossHairs (FullScreen) | Rubber-Band Boxes using GUI's (_GUIBox) | GUI Fun! | IE Embedded Control Versioning (use IE9+ and HTML5 in a GUI) | Magnifier (Vista+) Functions UDF | _DLLStructDisplay (Debug!) | _EnumChildWindows (controls etc) | _FileFindEx | _ClipGetHTML | _ClipPutHTML + ClipPutHyperlink | _FileGetShortcutEx | _FilePropertiesDialog | I/O Port Functions | File(s) Drag & Drop | _RunWithReducedPrivileges | _ShellExecuteWithReducedPrivileges | _WinAPI_GetSystemInfo | dotNETGetVersions | Drive(s) Power Status | _WinGetDesktopHandle | _StringParseParameters | Screensaver, Sleep, Desktop Lock Disable | Full-Screen Crash Recovery Wrappers/Modifications of others' contributions: _DOSWildcardsToPCRegEx (original code: RobSaunder's) | WinGetAltTabWinList (original: Authenticity) UDF's added support/programming to: _ExplorerWinGetSelectedItems | MIDIEx UDF (original code: eynstyne) (All personal code/wrappers centrally located at Ascend4nt's AutoIT Code) Link to comment Share on other sites More sharing options...
topten Posted January 8, 2014 Share Posted January 8, 2014 Hi Everyone! Has anything changed since that time? I mean is it really possible somehow to send comands to inactive desktop. Thanx in advance!!! Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now