Find windows on application from another desktop - windows

I have same user logged in into windows 7 station with several simultaneous sessions (like Concurrent RDP or log in at station and then via RDP).
UPDATE:
Ok, my research in this question has been stuck at this point (python example to write less complicated code):
#!/usr/bin/env python
import ctypes
import ctypes.wintypes as wintypes
def enum_desktops():
GetProcessWindowStation = user32.GetProcessWindowStation
EnumDesktops = user32.EnumDesktopsW
EnumDesktopsProc = ctypes.WINFUNCTYPE(wintypes.BOOL, wintypes.LPWSTR, wintypes.LPARAM)
hwinsta = GetProcessWindowStation()
def foreach_desktop(desk_name, lparam):
print("Desktop %s"%desk_name)
return True
EnumDesktops(hwinsta, EnumDesktopsProc(foreach_desktop), desk_lparam)
This function prints information about "Default" and "Winlogon" dektops. If we try to enumerate window stations, we'll get only "WinSta0", while I can see potentially target process started on different logon session.
So, what should I use to find window for target Desktop?
daemon is not an option at this point at all.

Have a background app or task tray applet that gets launched with every desktop session. (Easily installed by adding an EXE path to the following registry key: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\Current Version\Run).
The code that lives in that installed application will do two things:
All the desktop windows enumeration and manipulation that you need to do that can only interact with the local desktop.
Acts as a "Client" to your "server" app that runs on another desktop session. Your server app is what triggers the clients to do the window scanning. You can use almost any interprocess communication mechanism you want for this.

Already some time passed from the time the question was posted, but in case someone needs it, I will post an answer.
What you have to do is set a desktop for your current thread, which is calling FindWindow. In this way, your calling thread will operate in other desktop and will find a window. For this to achieve, you have to use SetThreadDesktop WinAPI function.
For more info, check MSDN documentation on SetThreadDesktop.

Related

What is the Windows "WorkerW" windows and what creates them?

On some Windows 10 computers (and possibly older versions) there are sometimes "WorkerW" windows that show up in the list from a call to EnumWindows. This is not on all computers - just some. What are these windows and what creates them?
It is basically created by calling Shell API function SHCreateWorkerWindowW. W stands for widechar (unicode) version of the window vs. SHCreateWorkerWindowA for ascii version. Any application that needs to listen to window messages call this Api to create a worker window. The API is basically a wrapper around CreateWindowEx but with window class name that is hardcoded to "WorkerW" or "WorkerA".
Comment requested to provide supporting documentation. Unfortunately, there is no documentation on MSDN because this is an undocumented function. If you look at the disassembly of SHCreateWorkerWindowA in shlwapi.dll you can verify this easily. Alternatively, you can do a GetProcAddress() for SHCreateWorkerWindowA and call the function to create the worker window.

Check visibility or status change of a window

I have to enumerate all process running on my machine and notify if some changement will happen (for example: change of visibility of windows, open a new window, close a window).
To enumerate all processes I can use this function provided by MSDN: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682623(v=vs.85).aspxI thought that I need to save a list of running processes and check (how without polling?) if it changes. Can I do it without saving current running processes?
For the visibility changes here https://msdn.microsoft.com/it-it/library/windows/desktop/ms646274(v=vs.85).aspx I found that VM_ACTIVATE message is sent to both windows. How can I catch it? Can I do it in another way?
For whom is interested in this topic, I found that to check if a window is created or destroyed I've to use SetWinEventHook(), like in the example of its MSDN page. I simply check if event value is EVENT_OBJECT_CREATE or EVENT_OBJECT_DESTROY. For other events, check the event constants list.

Understanding SystemParametersInfo SPI_SETFOREGROUNDLOCKTIMEOUT

My App needs to get the focus when it get's called by an external tool (via an API), i know that the default is, that it should just flash in the Taskbar, but in this case this is absolutely not the behaviour that i want. In this case i try to get the focus by "this.Activate()" (C#).
This is where the ForeGroundLockTimeOut comes into play.
However, I got a little problem understanding the SystemParameterInfo SPI_SETFOREGROUNDLOCKTIMEOUT.
I know that it's used to set the ForeGroundLockTimeOut which defines how long your app has to wait until it gets the focus it requested.
(for further information the variable "val" is an IntPtr that is set to 0)
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,0,val,SPIF_SENDWININICHANGE + SPIF_UPDATEINIFILE);
this one will change the Registry key that that handles the timeout (HKEY_CURRENT_USER\Control Panel\Desktop\ForeGroundLockTimout)
Since this will change the behaviour of all apps, it's really the last resort to use.
Now i thought what if i don't update the registry key. So i tried this:
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, val, 0);
However it doesn't change the behavior of my app in any way, but
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,0,val,SPIF_SENDWININICHANGE);
does.
What i do not understand is why this only works for my app, which is absolutely what i want, but i do not understandit .Why do i have to broadcast a change, that only works for my app, when there has been no change made to any registry key or whatsoever, and why does this work only for my app.
Note: If you want to test this behavior, test it when Visual Studio is not running, while it's running (even if this Solution is not loaded) it changes the behavior of the App into getting focus in any case.
This is not a per-app setting, it is a global system setting. There's no way to set it for just your application, so when you call SystemParametersInfo with 0 for the last parameter, nothing happens.
On the other hand, when you use SPIF_SENDWININICHANGE, the new setting gets broadcast in the form of a WM_SETTINGCHANGE message. (Which is why manually editing the registry is the wrong thing to do; always call the documented API.)
Aside from that, this code is wrong:
SPIF_SENDWININICHANGE + SPIF_UPDATEINIFILE
To concatenate two flags, you must use the boolean OR operator (|), not the addition operator (+). In this particular case, because 0x1 + 0x2 and 0x1 | 0x2 are both equal to 3, it seems to work, but that's just an accident.
The real solution to this problem needs not involve manipulating global settings (because you surely don't want to do that on client machines, even if you're OK with it on your own). You need to work with the system, rather than trying to work against it. In the system's model, the process that currently has the focus is the one with the privilege of setting/changing the focus. So there are basically three options:
Just have the external tool call SetForegroundWindow itself and pass your application's window as the parameter. This altogether avoids your app having to activate itself.
Use the AllowSetForegroundWindow function to delegate the external tool's foreground-window-setting privileges to your application. It should call this function, passing the ID of your app's process as the parameter. That way, when your app calls SetForegroundWindow, it will work as expected.
Depending on how your tool and application are designed, you could just have the external tool launch the application. Like the documentation says, if a process is launched by the foreground process, it is allowed to set the foreground window.
SPIF_UPDATEINIFILE--Writes the new system-wide parameter setting to the user profile.
SPIF_SENDCHANGE--Broadcasts the WM_SETTINGCHANGE message after updating the user profile.

Start Internet Explorer 8 in a separate process using vbscript

Due to the recently added "feature" in IE8 where new windows are automatically associated with a single session, some of our code is behaving erratically.
This is because a separate app would launch a new IE window when it was activated, and once the user was finished, close the window. This worked fine in IE7 because the session information in the windows stayed separate. However in IE8, since the session is shared among IE windows, we find that the "pop up" app would corrupt the session on the first app.
I have read about the nomerge switch, so that is a workaround, but I was wondering if there was a way of working the solution into the "CreateObject" of vbscript; i.e:
Dim ieWin As Object
Set ieWin = CreateObject("InternetExplorer.Application")
Is there a way of sending parameters when calling the CreateObject function?
No, there's no way to use COM to create an IE instance that specifies this behavior (or any of the others, e.g. InPrivate, No Add-ons, etc). The only thing you can do is create an automation instance that defaults to MediumIL using the CLSID provided for that purpose. http://blogs.msdn.com/b/ieinternals/archive/2011/08/03/internet-explorer-automation-protected-mode-lcie-default-integrity-level-medium.aspx
If you have control over the web application you are loading with your IE window you can set it's session to "cookieless" (http://msdn.microsoft.com/en-us/library/aa479314.aspx) which will avoid the issues you're having with multiple instances.
The solution we ended up going with, although it's more a work around than anything else - was assigning a new url to the popped up window.
Previously, it worked as follows:
Call centre agents would be using our internal app for other duties
e.g. "http://internalsite/somepage.faces" on a day to day basis.
When they got a phone call, a third party app would fire up
"http://internalsite/customerdetails.faces". This caused the issues mentioned above.
The solution we went with:
We assigned "http://internalsite/customerdetails.faces" it's own url e.g."http://customerdetailminisite/customer.faces".
This way the call center agent could keep their main window open for other stuff and still be able to handle calls when they came in.

Subscribe to Vista Events in .NET (e.g. Window Opened)

I am trying to build my own little toolbox for Vista.
One of the features is a "window placeing tool" which places the windows at saved position. Another tool I could imagine are extensions to firefox or thunderbird...
For these tools to work, I need them to be able to capture "Events" in Vista.
To give you a concrete example:
Explorer Opened New Window
User started Firefox
Mouse moved
For the mouse case, there are some examples for C#.
I also know about the directory watcher, nice little helper.
Want I now need is the "new window opened event"
Any idea how to monitor this, without iterating the current window list every 5 seconds (I already know how to get Windows using the DLLImports, and getting Processes using managed code. But I have no Event when the explorer process opens a new windows)
Thanks for your help,
Chris
What you're talking about doing is not simple by any stretch.
You're going to need to register a hook, and you're going to have to build a callback procedure that gets called within another process's execution context -- this is not going to be .NET code (probably C instead), and will have to be in a DLL. That callback procedure will get called every time a certain class of events happens. It will examine the events it receives and filter out the ones you're interested, then send your application the notifications you want (probably via PostMessage). You'll then tap in to your application's main message loop to intercept those messages, and from there you can fire a .NET Event, or whatever you want.
Writing hook callbacks is tricky stuff because the code gets run within another process, not your own, and the memory management and concurrency issues take a bit of forethought. For that same reason, it's not going to be done in C#. Ideally, though, this callback code will be very small and very fast, since it's going to get called so often.
Also note that while perfectly "legal" in Win32, these system hooks have an immense amount of power and are commonly used by malware to change the way your system works. For that reason, you may run afoul of antivirus software if you attempt to do this sort of thing on a customer's computer.
Also note that the far-reaching effects of system hooks also means that simple programming mistakes can take down your whole system, which you will probably discover for yourself at some point while debugging; so save everything before you hit "run".
Good luck!
EDIT
Did a bit more search to see if there's any way to write the hook proc in C#, and came up with this:
How to set a Windows hook in Visual C# .NET
This is almost what you're looking for, but not quite. Hook procedures can either be global (which means that they run on every application) or thread (only runs within your application). The document states that:
Global hooks are not supported in the .NET Framework
Except for the
WH_KEYBOARD_LL low-level hook and the
WH_MOUSE_LL low-level hook, you cannot
implement global hooks in the
Microsoft .NET Framework. To install a
global hook, a hook must have a native
DLL export to inject itself in another
process that requires a valid,
consistent function to call into. This
behavior requires a DLL export. The
.NET Framework does not support DLL
exports. Managed code has no concept
of a consistent value for a function
pointer because these function
pointers are proxies that are built
dynamically.
Which means, again, to monitor things that go on outside your application's view, you need to set a global hook, which can't be written in .NET.
I have exactly the same issue as this, and I think I have a workable solution. Initially I looked into a similar option to the one mentioned by 'tylerl'. In my case however, instead of using 'SetWindowsHookEx', I attempted to use the similar function 'RegisterShellHookWindows'.
Unfortunately, this only succeeded in providing me with notifications of when a subset of windows are created/destroyed. The only windows which it provided notifications for are those shown on the taskbar.
Since I didn't fancy hacking into other processes, or writing the native code which would be required for SetWindowHookEx, I tried digging into the .NET automation APIs introduced in .NET 4.0, and I think this has the answer to your problem (at least as far as detecting when windows are opened / closed).
Here's a code snippet for using this API to detect windows being opened/closed:
using System.Windows.Automation;
private void StartMonitoringForWindowEvents()
{
Task.Factory.StartNew(() =>
{
AutomationEventHandler windowOpenedHandler = new AutomationEventHandler(OnWindowOpened);
System.Windows.Automation.Automation.AddAutomationEventHandler(
WindowPattern.WindowOpenedEvent, AutomationElement.RootElement,
TreeScope.Descendants, windowOpenedHandler);
});
}
private void OnWindowOpened(object source, AutomationEventArgs eventArgs)
{
try
{
AutomationElement sourceElement = (AutomationElement)source;
string message = string.Format(
"Automation.WindowOpened PID: {0}, Handle: {1}, Name:{2}",
sourceElement.Current.ProcessId,
sourceElement.Current.NativeWindowHandle,
sourceElement.Current.Name);
Debug.WriteLine(message);
// for each created window, register to watch for it being closed
RegisterForClosedWindowEvent(sourceElement);
}
catch
{
}
}
private void RegisterForClosedWindowEvent(AutomationElement element)
{
try
{
string elementName = element.Current.Name;
int processId = element.Current.ProcessId;
int nativeHandle = element.Current.NativeWindowHandle;
AutomationEventHandler windowClosedHandler = new AutomationEventHandler(
(ignoreSource, ignoreArgs) => OnWindowClosed(nativeHandle, processId, elementName));
System.Windows.Automation.Automation.AddAutomationEventHandler(
WindowPattern.WindowClosedEvent, element,
TreeScope.Element, windowClosedHandler);
}
catch
{
}
}
private void OnWindowClosed(int nativeHandle, int processId, string elementName)
{
string message = string.Format(
"Automation.WindowClosed PID: {0}, Handle: {1}, Name:{2}",
processId,
nativeHandle,
elementName);
Debug.WriteLine(message);
}
You will need to add a reference to the assemblies 'UIAutomationClient' and 'UIAutomationClientTypes'.
Here's a link to the MSDN documentation (you'll probably particularly want to take a look at the information on events):
http://msdn.microsoft.com/en-us/library/ms747327.aspx
Important implementation Notes:
1.) Notice that in the sample, I used a task factory to register for reception of the automation events. It's particularly important to avoid using the UI thread when registering for automation events or generally interacting with the automation APIs. Doing so can (and usually quickly does) result in a deadlock. Therefore, I use the task factory to ensure registration is done via the thread pool.
This also means, that the events will be received on the thread pool... So, if you need to perform any UI updates, you will have to marshal these across to the UI thread.
2.) You'll also note, that I capture any needed information on the element which may be closed, at the time of registration (using a closure). This is because, once the element is closed, we will no longer have access to this information - since the element has been destroyed.
Phil
The answer is not C# (or .Net) specific. You'll need to call SetWindowsHookEx( WH_CBT, ... ). This will allows to know when a window is created, destroyed, moved, sized, etc. You'll also need to get the relevant information from the window to identify if its one you need to do something about. Perhaps GetClassInfo, GetWindowLong, and GetWindowText.
The problem with the SetWindowsHookEx is that in order to get events from every window you need to have a separate win32 dll with the function in question exported. Although you might have success with the procedure outlined here.
To expand upon Joel Lucsy's answer, you need to use the Win32 API. However, there's a nice library, the Managed Windows API, that provides an object-oriented wrapper over common APIs. It may have what you need.

Resources