I want to write my own program that lets me select one Window of ALL open windows and set the state of this window to TOP, so that this selected window will always show on top!
The problem... since Windows 8 there are APPs and actually the process comes up in the process explorer but my selection of my tool doesn't list it. (Its like there is no app)
My source looks like:
private void refreshWindowList(object sender, EventArgs e)
{
windowList.Items.Clear();
foreach (Process p in Process.GetProcesses().Where(pp => pp.MainWindowHandle != IntPtr.Zero && pp.ProcessName != "explorer"))
{
windowList.Items.Add(p.ProcessName);
}
}
This function is called when I open my combobox and actually refresh the Items every time when I view the list.
I find normal programs, but is there a way to find Win 8/10 apps ?
EDIT to clarify: Normal processes like notepad can be found. But Windows Universal apps like e.g. netflix can't. At least I don't know how to find them.
Some applications, e.g. Netflix, are written using HTML and JavaScript. These apps are hosted by WWAHost:
[...] Microsoft explains WWAHost as “an Internet Explorer-based rendering platform.”
You can check if this is the case for an app by right clicking it in the Task Manager and choosing Go to details:
To find out which app is being hosted, you can use MainWindowTitle
Console.WriteLine(p.ProcessName); // WWAHost
Console.WriteLine(p.MainWindowTitle); // Netflix
Related
We have a simple launcher.cmd script that sets up some prerequisites (network shares, configuration files etc.), depending on command-line arguments, and then starts a third-party application.
It also launches a custom splash screen (Windows Forms application), but that doesn't have any functionality beyond the splash screen. The external application also contains a plugin that we have written.
Imagine something like this:
set appEnvironment=%1
MyCustomSplashScreen\MyCustomSplashScreen.exe %appEnvironment%
net use X: /delete /yes
net use X: \\someserver\%appEnvironment%
copy Configuration\%appEnvironment%.config ExternalApp\ExternalApp.MyPlugin.config
start ExternalApp\ExternalApp.exe
It is invoked like this:
launcher.cmd Production
The challenge we are facing is that some users pin ExternalApp.exe (the actual application, after launcher.cmd and the splash screen have terminated) to the taskbar. The taskbar shortcut then launches ExternalApp.exe directly and not our launcher script - so all kinds of strange things can happen.
As we have control over the plugin, it would be possible to move some of the logic directly into ExternalApp.exe, but that wouldn't solve the issue of losing the environment parameter. The best solution I can come up with would be different ways of making sure the application can only be launched via the launcher script, essentially making it useless for the user to pin the application to the taskbar.
However, I have thought about being a little more creative. I am planning to do the following:
Move the launcher.cmd logic into MyCustomSplashScreen.exe
In MyCustomSplashScreen.exe, start ExternalApp.exe and make it a docked child window (cf. Docking Window inside another Window ).
Instead of using a parameter, create copies (or links) of MyCustomSplashScreen.exe that reflect the environment, e.g. Launch_Production.exe, Launch_Staging.exe etc.
The consequence would be that only MyCustomSplashScreen would appear on the taskbar and be pinnable. Pinning the application would result in the application specific to that environment (e.g. Launch_Staging.exe) being pinned, just what the user expects.
I am quite confident that this would work. But maybe there is a simpler solution? What I'm looking for is some way to make only my launcher application on the taskbar and not the application it launches.
I found similar questions here and here where it was suggested to manipulate the pinning process itself. Maybe that's a better solution? I'm just not sure if my plugin has enough control over ExternalApp.exe to implement this, so would need to test it.
The solution from Control path to pinned exe in Windows taskbar and start menu works just fine.
I put something like this into my plugin and it does exactly what I want:
private static void SetTaskbarRelaunchCommand(string environment)
{
// WARNING, once RelaunchCommand has been set it can't be changed for any given appID.
// Workaround: delete all links here related to our app.
// %AppData%\Microsoft\Internet Explorer\Quick Launch\User Pinned\ImplicitAppShortcuts
// %AppData%\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar
// Source: https://stackoverflow.com/a/28388958/33236
const string appID = "MyAppID";
string path = $#"C:\Launcher.exe {environment}";
IntPtr windowHandle = Process.GetCurrentProcess().MainWindowHandle;
var propGuid = new Guid("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}");
var id = new PropertyKey(propGuid, 5); // System.AppUserModel.ID
var relaunchCommand = new PropertyKey(propGuid, 2); // System.AppUserModel.RelaunchCommand
var relaunchDisplayNameResource = new PropertyKey(propGuid, 4); // System.AppUserModel.RelaunchDisplayNameResource
WindowProperties.SetWindowProperty(windowHandle, id, appID);
WindowProperties.SetWindowProperty(windowHandle, relaunchCommand, path);
WindowProperties.SetWindowProperty(windowHandle, relaunchDisplayNameResource, $"My App {environment}");
}
It seems like the original version of the Windows API CodePack published by Microsoft in 2009 is no longer officially available. Instead there are a dozen inofficial NuGet packages that (claim to) contain the original library, as well as some where bugs have been fixed.
I ended up using this NuGet package as it seems to be actively maintained.
Of course I am in the fortunate situation that I could manipulate the behavior of the external application through my plugin. Without this, there probably is no other solution than running the application as a docked child window.
UPDATE: It seems like there is another way to achieve thisn when you cannot control the application you're launching. You simply set the System.AppUserModel.Id for the launched application's window. More details here.
I wasn't successful in setting the RelaunchCommand and the RelaunchDisplayNameResource on the newest Windows 10 update. But i have found another possibility to set that the Launcher is pinned to the taskbar: Pinning to the taskbar a "chained process"
I want know can i use TestStack to doing an automate process on an application. so i wrote a simple code to count all windows of the target application.
First i tested it on a sample application (WinForm (.net)) and it worked well (Return 1 as Forms Count).
Second i tested it on my target application but it dos not return any window (Return 0 as Forms Count).
My Code under the Button:
TestStack.White.Application application = TestStack.White.Application.Launch(#"C:\target.exe");
var windows = application.GetWindows();
foreach (var window in windows)
{
MessageBox.Show(window.Title);
}
....................................
Additional info:
When i click on the Button, it can lunch my target application
successfully.
I did not know my application programming technology, i guess it is
c++ and QT but maybe it is different!
I watched application variable. Result is:
Questions:
Which reasons can cause this problem?
Should i switch to another way else TestStack to do automate proccess on this kind of application (for example use low level windows APIs and messages or....)?
I'm a bigginer in TestStack, have i any mistake?
What are your suggestions???
Thanks...
EDIT 1
The target Application window ClassName: "Qt5QWindowIcon" (i used SpyUI to get this)
I found the problem base on #Mikez notice in the comments.
Reason of the problem was >>
When i run the target application it changes itself process with a new process and i lost it?
Solution:
Now i changed my code to this and it works well ;)
var myFirstTargetApp =TestStack.White.Application.Launch(#"c:\target.exe");
myFirstTargetApp.Process.WaitForExit();
TestStack.White.Application application = TestStack.White.Application.Attach("target");
var windows = application.GetWindows();
MessageBox.Show(windows.Count.ToString()); // << now my messagebox show: 1
Have you tried:
TestStack.White.Application application = TestStack.White.Application.AttachOrLaunch("target");
Saves some lines of code.
bit of a strange one... when my app is running I add a custom control to a StackPanel on the click of a button like so...
void btnAddPlayer_Click(object sender, EventArgs e)
{
PlayerControl sbItem = new PlayerControl();
ctlPanel.Children.Add(sbItem);
}
(ctlPanel is a StackPanel PlayerControl is a standard Control inherited from UserControl)
So I add one or two, not a problem... if I multi-task on the phone to a different app, then multi-task back to my app, not a problem... however, if I multi-task away (or hit the windows phone button) and then instead of multi-tasking back, I just click on the icon (as if Im running the app again) it reloads my app but without any PlayerControl's in the StackPanel ... and while debugging, it doesnt hit the InitializeComponents() method in the pages constructor (of course this could be because it might not debug it when you run it straight from the menu)
Anyone know if theres a way to only allow an app to be run once (and dont restart it if the user runs the app again)????
It does not work that way. You can save the "state" of your app and load that when you start the application. Look at "Tombstoning" for windows phones. Example, you can save in the local storage the current screen id and any other necessary data and when you launch the app, if you have something in local storage you load that screen, else you start with your homepage.
I want to write a C# program which will launch an .exe (this is an easy job, I know how to do it.) but now I want to add some more functionality to it.
I want to take user inputs to my program and want to pass them to running .exe as a input.Also I want to click on a particular button available on the exe window. Important thing is, I want to do it programatically without user knowledge that we are actually running that exe in background.
Please let me know if it is possible. It is very urgent.
Yes it is possible with Windows API. You need to send a message to that Window. At first use Spy++ to get IDs of all buttons you want to click. Spy++ is a Visual Studio tool and it shows you what messages are being sent to the application when you press those buttons. Then use PostMessage() function (Windows API) to send the same message programatically.
You can also for example look at Winamp (a music player for windows), there is documentation on how to press its buttons from external app. You can do it the same way for other apps, you just need to know IDs of all controls and names of windows or their classes.
here is code to click on Winamp's pause button:
#define AMP_PAUSE 40046
HWND hwnd = FindWindow("Winamp v1.x", 0);
if(hwnd) SendMessage(hwnd, WM_COMMAND, AMP_PAUSE, 0);
This is written in C++. If you do it in C#, use PInvoke to get access to Windows API. I assume you know how to do this. In the first step FindWindow gets a handle to the window, it identifies it by the name of its class. Then we use SendMessage or PostMessage to send the message. There are four parameters: window to send the message to, message id, and two parameters.
In Spy++ you can find those parameters you need for FindWindow and SendMessage. Please start it and play with it a little bit to see what it can do.
If you want to avoid directly use of WIN API, there's a small library that can help you with this, WindowScrape.
You can use it directly from C#.
Some of the features:
Search for windows and child controls registered in memory.
Change the titles of windows
Change the text of UI elements (permissions/privacy permitting)
Click on UI elements
Read the Titles of windows
Read the text from UI elements
Navigate through object hierarchies
Set object locations
Set object sizes
There might be other similar libraries, but at this point this is the only one that i'm aware.
Edited
Sample Usage:
using System.Windows.Forms;
//WindowScrape
using WindowScrape.Types;
namespace WindowsFormsTestApplication
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var npad = HwndObject.GetWindowByTitle("Untitled - Notepad");
}
}
}
If it is a WPF application you could have a look at AutomationPeers
I'm trying to find a way to get the open tasks in C#. I've been searching on google and can only find how to get a list of the processes. I want the only the tasks that would show up on the taskbar.
Also, along with that, it would be cool if I could get the process the task is associated with. And if possible get the thumbnail images that Vista uses for the ALT-TAB menu, like in this image:
I assume that I will have to use pinvokes because it really doesn't look like there are any libraries to do this already. Any ideas?
This article should pretty much tell you exactly what to do, it shows how to build your own task switch and includes the code needed to enumerate all windows and determine if they are "tasks" and it shows you how to use PrintWindow api to get the previews on XP.
http://msdn.microsoft.com/en-us/library/ms997649.aspx
Also, here is a blog post that talks about the algorithm used to determine what shows up in the Alt+Tab view. Basically you need to check the WS_EX_APPWINDOW and WS_EX_TOOLWINDOW along with if the window has an owner.
From an API (Win32) perspective there is no such thing as Tasks (at least not the one that Windows Task Manager/Alt-Tab shows).
Those "Tasks" are actually top level windows.
So in order to get a list of those, you need to enumerate the windows (here is the PInvoke for it).
Then look at the style of the windows to determine if they are actually top level windows.
I haven't tried it, but I suspect something like this:
using System.Diagnostics;
static void MyFunc()
{
Process[] processes = Process.GetProcesses();
foreach(Process p in processes)
{
if (p.MainWindowHandle != 0)
{ // This is a GUI process
}
else
{ // this is a non-GUI / invisible process
}
}
}
The point is to check each process for a WindowHandle.
#abelenky17
I suspect that this will not cover all cases, for example there are processes who have several top level windows (that all appear in the task manager).
Consider for example: FireFox, Windows Explorer, IE, etc... those applications can have multiple windows on the desktop.
Also, it will not handle Terminal Sessions scenario's properly (because you enumerate all the processes running in the system).
#Dan C.
Doing something like this:
p.ProcessName != "explorer"
seems ok to you? It smells, bad.