WinAPI FindWindow not working for Unreal engine games - c#

I am making a Unity app that will run in Windows in a custom arcade cabinet and will load and stop games.
I have been abusing winAPI to do this.
Eg. I start the game process, then use findwindow to wait until a window of the correct name exists and also get an IntPtr for that window which I can send to the SetForegroundWindow winAPI function to make sure the game is in front and focused for inputs.
This all works fine.
Except for some unreal games I was using to test. Eg. this game 'Peekaboo', despite calling findwindow every frame in my Unity app a window called Peekaboo is never found, though when I look in Windows it is clearly there.
Its the same story for another Unreal engine game 'Mechwarrior 5 mercenaries'
I think it might have something to do with the fact that unreal games seems to launch several nested processes like in the image below.
(Eg. To stop non-unreal games I can just stop the process using the reference I got when I started it. But this did not work with Unreal games, the exe I started is gone and I needed to find that Win64-Shipping process and stop that.)
Here is the code I am using to call findwindow and also setforground
using UnityEngine;
using System.Collections;
using System;
using System.Runtime.InteropServices;
public static class WinAPIGetWindowIfExists
{
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
public static IntPtr DoesWindowExist(string windowName)
{
Debug.Log("looking for window: " + windowName);
return FindWindow(null, #windowName);
}
}
public static class WinAPISetForegroundWindow
{
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr handle);
public static void SetForeground(IntPtr windowHandle)
{
SetForegroundWindow(windowHandle);
}
}
So how can I get a reference to an unreal game window so I can set it to the forground?
UPDATE:
I am super confused now, as I have called EnumWindows, and called GetWindowText for every window returned by it, and I have found a window called Peekaboo.. If I pass that window's handle to SetForeground the correct game window is set to foreground, also if I sendmessage with this message 0x000D; I get the text peekboo back. Yet, findwindow still finds no window named peekaboo...
So I can use this EnumWindows to solve my issue.. but this utterly sucks. Why does iterating through every window, calling get windowtext, then checking if the text contains the window title work, whereas findwindow doesnt work?

So here is the code for using enumwindows. This code does work for Unreal engine games. I found this somewhere on the internet. It's a good thing too cus figuring out how to make these functions work with interop from just MS documentation is not trivial imo. It was really not clear to me from the MS documentation that after calling the enumwindows function it would call the callback function over and over for every single window returned. It seems like a kind of ridiculous pattern to me, just to avoid having any unsafe code.
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
public delegate bool WNDENUMPROC(
UInt32 hWnd,
IntPtr lParam
);
internal static class WinAPI
{
[DllImport("user32.dll")]
internal static extern bool EnumWindows(
WNDENUMPROC cb, // WNDENUMPROC lpEnumFiunc
IntPtr manageObject // LPARAM lParam (the managed object))
);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern bool GetWindowText(
UInt32 hWnd,
StringBuilder title,
int size
);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam,
StringBuilder lParam);
}
public class WindowEnumerator
{
private const uint WM_GETTEXT = 0x000D;
public static IntPtr FindWindowWithThisTitle(string findthis)
{
List<UInt32> hWnds = new List<UInt32>();
//
// Prevent the managed object (hWnds) from being collected
// by the garbage collector:
//
GCHandle objHandle = GCHandle.Alloc(hWnds);
//
// Create an instance of a delegate in order to
// provide a «callback» for EnumWindows:
//
WNDENUMPROC enumProc = new WNDENUMPROC(callback);
//
// Get an internal representation for the gc handle
// so as to be able to pass it to the second parameter
// of EnumWindows:
//
IntPtr objHandlePtr = GCHandle.ToIntPtr(objHandle);
WinAPI.EnumWindows( // Let Windows iterate over each window and
enumProc, // call enumProc (which is «initialized» for the method callback)
objHandlePtr // and pass this pointer to the method
);
//
// Free the handle of the object so that
// the object can be collected and
// thus to prevent memory leaks:
//
objHandle.Free();
StringBuilder title = new StringBuilder(256);
foreach (UInt32 hWnd in hWnds)
{
WinAPI.GetWindowText(hWnd, title, 256);
if (title.ToString().Contains(findthis))
{
return (IntPtr)hWnd;
}
//UnityEngine.Debug.Log(" "+ hWnd+" "+ title);
}
return IntPtr.Zero;
}
private static bool callback(
//
// After calling WinAPI.EnumWindows, Windows calls
// this method for each Window and passes it
// the hWnd of the respective Window and
// the value that was given as second parameter
// to EnumWindows (objHandlePtr);
//
UInt32 hWnd,
IntPtr objHandlePtr
)
{
//
// Get the handle to the object from the pointer:
//
GCHandle objHandle = GCHandle.FromIntPtr(objHandlePtr);
//
// and cast the handle's target into the underlying
// managed object:
//
List<UInt32> obj = (List<UInt32>)objHandle.Target;
obj.Add(hWnd);
return true;
}
}

Related

Handle external app and populate input fields

I have a C# Windows Desktop app that needs to handle a given external app, - unmanaged code - and populate it's input fields.
Note that this must be done programatically, so the use of SPY++ to get windows names is out of discussion, I just can get windows classes using SPY++.
Looking and reading over there I'found that it can be accomplished with the following steps (pseducode):
Get or start the external app process.
Get the main window using FindWindow();
Get the childWindows, which are the input fields, using FindWindowEx.
Send messages using Sendmessage().
I've tested populating a notepad, however dealing with my given app has been a PITA. Can't populate anything.
here is my actual code:
/*
List of references, which includes System.Diagnostics,
System.Runtime.InteropServices,...
*/
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
private void click_test(object sender, RoutedEventArgs e)
{
Process[] apps = Process.GetProcessesByName("givenApp");
if (apps.Length == 0) return;
if (apps[0] != null)
{
IntPtr mainWindow = FindWindow("class name", null);
IntPtr child = FindWindowEx(apps[0].MainWindowHandle, new IntPtr(0), "Class Name", null);
SendMessage(child, 0x000C, 0, input_test.Text);
}
}
With this code I can populate notepad. However populating notepad is a test stage. I need to populate other app.
What is missing, what is wrong?
I found what the error was, simply:
When instantiating a child, instead of calling the generic MainWindowHadle, call the App Window handle, which is previously defined in a variable called MainWindow which invokes the FindWindow() Class.
This is wrong:
IntPtr child = FindWindowEx(apps[0].MainWindowHandle, new IntPtr(0), "Class Name", null);
This is Correct:
IntPtr child = FindWindowEx(mainWindow, new IntPtr(0), "Class Name", null);

Can't get a window handle?

I've searched all over to try and find an answer to my predicament but cannot seem to find a valid answer. I'm trying to write some equivalent user32.dll code with Xlib instead so I can support Linux users. I'm of course running Linux, so I'm using Mono. Problem comes along when I cannot even grab a window handle from the Process class because it was never even implemented:
[MonoTODO]
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
[MonitoringDescription ("The handle of the main window of the process.")]
public IntPtr MainWindowHandle {
get {
return((IntPtr)0);
}
}
(Source)
This is especially frustrating because there is seemingly no alternative. I'm trying to grab a window handle like so:
[DllImport("libX11")]
private static extern IntPtr XOpenDisplay(IntPtr display);
[DllImport("libX11")]
private static extern int XRaiseWindow(IntPtr display, IntPtr window);
private IntPtr ApplicationHandle;
private IntPtr Display;
private void TestXlib() {
Process process = Process.GetProcessById(myPid);
ApplicationHandle = process.MainWindowHandle;
Display = XOpenDisplay(IntPtr.Zero);
XRaiseWindow(Display, ApplicationHandle);
}
NOTE: In place of "myPid" is a proper process ID. Replace "myPid" with a valid process ID. Yes, I did make sure the replaced "myPid" was a valid process ID and my code didn't throw any errors indicating any process IDs I used as invalid.
This doesn't crash my application, but almost every time I call XRaiseWindow it prints:
X11 Error encountered:
Error: BadWindow (invalid Window parameter)
Request: 12 (0)
Resource ID: 0x0
Serial: 121
Hwnd: <null>
Control: <null>
This obviously occurs because Process.MainWindowHandle returns IntPtr.Zero. Is there no other way to get a window handle? Thanks in advance!
Yes, I know this was forever ago that I asked this, but I'm answering it now because I kept forgetting to answer it after I found the solution myself. I originally used #SushiHangover's solution but didn't really like it because I felt relying on an external program(xwininfo) was a hotfix and ultimately just added another dependency. Hopefully this helps other C# developers using Mono. This code was originally written for .NET Framework 2.0. It's not fancy and isn't really documented well. My solution was just to natively enumerate the windows using Xlib myself and return all windows whose title's match the described title.
In X11Wrapper.cs:
using System;
using System.Runtime.InteropServices;
namespace Program.PInvoke.Xlib {
public static class X11Wrapper {
public const string SOName = "libX11.so";
[DllImport(SOName)]
// See: https://tronche.com/gui/x/xlib/display/display-macros.html#DefaultRootWindow
public static extern IntPtr XDefaultRootWindow(IntPtr display);
[DllImport(SOName)]
// See: https://tronche.com/gui/x/xlib/window-information/XQueryTree.html
public static extern int XQueryTree(IntPtr display, IntPtr w,
out IntPtr root_return, out IntPtr parent_return,
out IntPtr[] children_return, out int nchildren_return);
[DllImport(SOName)]
// See: https://tronche.com/gui/x/xlib/ICC/client-to-window-manager/XFetchName.html
public static extern int XFetchName(IntPtr display, IntPtr w,
out string window_name_return);
}
}
In Linux.Utilities.cs:
using Program.PInvoke.Xlib;
namespace Program {
public static partial class Utilities {
public static bool IsUnix {
get {
return Environment.OSVersion.
Platform == PlatformID.Unix;
}
}
private static IntPtr[] FindChildWindows(IntPtr display, IntPtr window,
string title, ref List<IntPtr> windows) {
IntPtr rootWindow;
IntPtr parentWindow;
IntPtr[] childWindows = new IntPtr[0];
int childWindowsLength;
X11Wrapper.XQueryTree(display, window,
out rootWindow, out parentWindow,
out childWindows, out childWindowsLength);
childWindows = new IntPtr[childWindowsLength];
X11Wrapper.XQueryTree(display, window,
out rootWindow, out parentWindow,
out childWindows, out childWindowsLength);
string windowFetchedTitle;
X11Wrapper.XFetchName(display, window, out windowFetchedTitle);
if(title == windowFetchedTitle &&
!windows.Contains(window)) {
windows.Add(window);
}
for(int childWindowsIndexer = 0;
childWindowsIndexer < childWindows.Length;
childWindowsIndexer++) {
IntPtr childWindow = childWindows[childWindowsIndexer];
string childWindowFetchedTitle;
X11Wrapper.XFetchName(display, childWindow,
out childWindowFetchedTitle);
if(title == childWindowFetchedTitle &&
!windows.Contains(childWindow)) {
windows.Add(childWindow);
}
FindChildWindows(display, childWindow, title, ref windows);
}
windows.TrimExcess();
return windows.ToArray();
}
public static IntPtr[] FindWindows(IntPtr display, string title) {
List<IntPtr> windows = new List<IntPtr>();
return FindChildWindows(display,
X11Wrapper.XDefaultRootWindow(display),
title,
ref windows);
}
}
}
Footnote: I initially stated I wasn't a C developer(Things have changed since then and I've learned C) so I was hesitant to implement the functionality myself using interop. If you do end up using Xlib a lot more like I did then consider using tronche as an Xlib API reference. It is in C but I found it was pretty easy to translate to PInvokable functions and marshable structs in C#. Has some good notes to take into account too. Another good resource to help translation is directly using the source to find the definitions of the low level types to help find C# equivalents. Something like this should greatly aid you: http://refspecs.linuxbase.org/LSB_4.0.0/LSB-Desktop-generic/LSB-Desktop-generic/libx11-ddefs.html

Bring a window to foreground without window handle

I have a Windows CE embedded 6.0 application that opens another app in the background, and I want to bring the other app to the front. I first tried SetParent with the third party app's MainWindowHandle and it didnt work. I then tried SetActiveWindow on the same MainWindowHandle again and it didnt work. This led me to believe that the MainWindowHandle was messed up, and when I print it on the console, its always 0. This brings me to my first question: Is it possible that the dev for the app forgot to mention what the MainWindow is? Or is it assigned automatically in .NET?
Secondly, now that that approach failed, I tried to EnumWindows, then get the ID for each window and match it to the process Id I knew for my required program. This gave me an exception 0x80131515 saying "EnumWindows" is not supported. I have imported EnumWindows from CoreDll just fine. Second question: what could be the cause of this error? What am I doing wrong?
Sorry! Here's some code (Assume VCProcess has already been started):
[DllImport("coredll.dll")]
static extern int EnumWindows(CallbackDef callback, int lParam);
[DllImport("coredll.dll")]
static extern int GetWindowThreadProcessId(IntPtr hWnd, int pid);
static void Main()
{
callBackPtr = new CallBackPtr(Report);
EnumWindows(callBackPtr, 0);
}
public static bool Report(int hwnd, int lParam)
{
int pid = 0;
GetWindowThreadProcessId(hWnd, pid);
if (pid == VCProcessId)
{
SetForegroundWindow(hWnd);
}
MessageBox.show("Window handle is "+hwnd);
return true;
}
Your OEM must not have included support for EnumWindows. You could try FindWindow instead.
I would probably P/Invoke SetForegroundWindow to do this. SetActiveWindow does not work if the application is in the background.
-PaulH
Edit
P/Invoking EnumWindows can't throw a System.NotSupportedException (unless you throw it in your code) and GetLastError() wouldn't return an HRESULT COR_E_NOTSUPPORTED. There's something fishy in your code.
I am answering this question after having the same issue and having it resolved.
While it is true that OEMs may not include certain portions of the OS as part of WindowsCE (being the nature of its modular architecture), it is also true that a call like EnumWindows, or most other low level calls for that matter, are intrinsically part of the OS and it would be crazy to remove them.
I actually received a message back from a Microsoft engineer (!) which pointed out that the issue is the way the callback is defined. While I tried different approaches (delegates, intPtr vs int, and others) he gave the following answer that actually works well in WindowsCE 5/6 for different devices:
"[The “EnumWindows call from .Net/C# Application results in NotSupportedException 0x80131515” error because it ONLY supports Integer return types: I2, I4 etc. This applies to all callback methods and may vary depending on the call being used]"
So INSTEAD OF defining your callback as you did (I tried delegates, WinProcs and others unsuccessfully as well), define it as:
[DllImport("coredll.dll")]
[return: MarshalAs(UnmanagedType.I4)]
private static extern int EnumWindows(IntPtr callPtr, int param);
which works perfectly!!
The following is my working code implementing this approach and works flawlessly in different devices running PocketPC/WindowsCE etc:
public delegate int CallBackPtr(int hwnd, int param);
[DllImport("coredll.dll")]
[return: MarshalAs(UnmanagedType.I4)]
private static extern int EnumWindows(IntPtr callPtr, int param);
private static List<IntPtr> windows = new List<IntPtr>();
private static int CallBackMethod(int hwnd, int param)
{
windows.Add(new IntPtr(hwnd));
return 1;
}
private static void GetAllWindowsHandles()
{
// using a delegate does NOT work.
//EnumWindows(delegate(IntPtr wnd, IntPtr param)
//{
// windows.Add(wnd);
// return true;
//}, IntPtr.Zero);
CallBackPtr callbackPtr = CallBackMethod;
IntPtr cb = Marshal.GetFunctionPointerForDelegate(callbackPtr);
EnumWindows(cb, 0);
}
CJ.

C# - Capturing Windows Messages from a specific application

I'm writing a C# application which needs to intercept Window Messages that another applications is sending out. The company who wrote the application I'm monitoring sent me some example code, however it's in C++ which I don't really know.
In the C++ example code I've got they use the following code:
UINT uMsg = RegisterWindowMessage(SHOCK_MESSAGE_BROADCAST);
ON_REGISTERED_MESSAGE(WM_SHOCK_BROADCAST_MESSAGE, OnShockStatusMessage)
LRESULT OnShockStatusMessage(WPARAM wParam, LPARAM lParam);
As I understand it this retrieves an Id from Windows for the specific message we want to listen for. Then we're asking C++ to call OnShockStatusMessage whenever an message matching the Id is intercepted.
After a bit of research I've put together the following in C#
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint RegisterWindowMessage(string lpString);
private IntPtr _hWnd; // APS-50 class reference
private List<IntPtr> _windowsMessages = new List<IntPtr>(); // APS-50 messages
private const string _className = "www.AuPix.com/SHOCK/MessageWindowClass";
// Windows Messages events
private const string _messageBroadcast = "www.AuPix.com/SHOCK/BROADCAST";
private const string _messageCallEvents = "www.AuPix.com/SHOCK/CallEvents";
private const string _messageRegistrationEvents = "www.AuPix.com/SHOCK/RegistrationEvents";
private const string _messageActions = "www.AuPix.com/SHOCK/Actions";
private void DemoProblem()
{
// Find hidden window handle
_hWnd = FindWindow(_className, null);
// Register for events
_windowsMessages.Add( new IntPtr( RegisterWindowMessage( _messageActions ) ) );
_windowsMessages.Add( new IntPtr( RegisterWindowMessage( _messageBroadcast ) ) );
_windowsMessages.Add( new IntPtr( RegisterWindowMessage( _messageCallEvents ) ) );
_windowsMessages.Add( new IntPtr( RegisterWindowMessage( _messageRegistrationEvents ) ) );
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
// Are they registered Windows Messages for the APS-50 application?
foreach (IntPtr message in _windowsMessages)
{
if ((IntPtr)m.Msg == message)
{
Debug.WriteLine("Message from specified application found!");
}
}
// Are they coming from the APS-50 application?
if ( m.HWnd == shock.WindowsHandle)
{
Debug.WriteLine("Message from specified application found!");
}
}
As I understand this should do the same basic thing, in that it:
Finds the application I wish to monitor
Registers the Window Messages I wish to intercept
Watches for all Window Messages - then strips out the ones I need
However in my override of the WndProc() method neither of my checks intercept any of the specific messages or any message from the application I'm monitoring.
If I Debug.WriteLine for all messages that come through it, I can see that it's monitoring them. However it never filters out the messages that I want.
By running the example monitoring application written in C++ I can see that Window Messages are being sent and picked up - it's just my C# implemention doesn't do the same.
Turns out I also needed to send the other application a PostMessage asking it to send my application the Window Messages.
PostMessage((int)_hWnd, _windowsMessages[0], SHOCK_REQUEST_ACTIVE_CALLINFO, (int)_thisHandle);
PostMessage((int)_hWnd, _windowsMessages[0], SHOCK_REQUEST_ALL_REGISTRATIONINFO, (int)_thisHandle);
PostMessage((int)_hWnd, _windowsMessages[0], SHOCK_REQUEST_CALL_EVENTS, (int)_thisHandle);
PostMessage((int)_hWnd, _windowsMessages[0], SHOCK_REQUEST_REGISTRATION_EVENTS, (int)_thisHandle);
Not pretty code, but good enough to prove it works which is all I need for now :)
I think the problem is with your P/Invoke definition for RegisterWindowMessage(). pinvoke.net suggests using the following:
[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
static extern uint RegisterWindowMessage(string lpString);
Using uint as the return value instead of IntPtr should make the difference. Typically you want to use IntPtr when the return value is a handle (such as an HWND or HANDLE), but when the return value can be directly converted to a C# type it is better to use that type.

Find out programmatically if a process is demanding user input

How can I programmatically (in C#) determine, if ANOTHER foreign application (native, java, .NET or whatever...) is currently demanding user input? Can this be done fully in Managed code?
What I'm looking for is the implementation of:
static Boolean IsWaitingForUserInput(String processName)
{
???
}
By demanding user input I mean when an application asks the user to enter some data or quit an error message (Modal dialogs) and is not able to perform its normal tasks anymore. A drawing application that is waiting for the user to draw something is not meant here.
PS: After edits to reflect the comments at the bottom and make the concern clearer, some comments and answers may not be 100% consistent with the question. Take this into account when evaluating the answers and remarks.
It's in general impossible. Take for instance a common kind of application, a word processor. Nowadays that will be running spellchecks in the background, it periodically auto-saves your document, etcetera. Yet from a users perspective it's waiting for input all the time.
Another common case would be a slideshow viewer. At any moment in time you could press a key to advance a slide. Yet your typical user would not view this as "waiting for input".
To summarize: "waiting for input" is a subjective state and therefore cannot be determined programmatically.
How do you like this?
I worked out a solution that seems to work, please notify me in case of problems with this code so I also gain benefit of improvements. It works for Excel as far as I tested. The only issue I dislike is that I had to use unmanaged calls. It also handles the case when an application is based on a dialog like for MFC, derived from CDialog.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using System.Diagnostics;
namespace Util
{
public class ModalChecker
{
public static Boolean IsWaitingForUserInput(String processName)
{
Process[] processes = Process.GetProcessesByName(processName);
if (processes.Length == 0)
throw new Exception("No process found matching the search criteria");
if (processes.Length > 1)
throw new Exception("More than one process found matching the search criteria");
// for thread safety
ModalChecker checker = new ModalChecker(processes[0]);
return checker.WaitingForUserInput;
}
#region Native Windows Stuff
private const int WS_EX_DLGMODALFRAME = 0x00000001;
private const int GWL_EXSTYLE = (-20);
private delegate int EnumWindowsProc(IntPtr hWnd, int lParam);
[DllImport("user32")]
private extern static int EnumWindows(EnumWindowsProc lpEnumFunc, int lParam);
[DllImport("user32", CharSet = CharSet.Auto)]
private extern static uint GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32")]
private extern static uint GetWindowThreadProcessId(IntPtr hWnd, out IntPtr lpdwProcessId);
#endregion
// The process we want the info from
private Process _process;
private Boolean _waiting;
private ModalChecker(Process process)
{
_process = process;
_waiting = false; //default
}
private Boolean WaitingForUserInput
{
get
{
EnumWindows(new EnumWindowsProc(this.WindowEnum), 0);
return _waiting;
}
}
private int WindowEnum(IntPtr hWnd, int lParam)
{
if (hWnd == _process.MainWindowHandle)
return 1;
IntPtr processId;
GetWindowThreadProcessId(hWnd, out processId);
if (processId.ToInt32() != _process.Id)
return 1;
uint style = GetWindowLong(hWnd, GWL_EXSTYLE);
if ((style & WS_EX_DLGMODALFRAME) != 0)
{
_waiting = true;
return 0; // stop searching further
}
return 1;
}
}
}
If I understand you well, you may try to enumerate the process's threads and check their states. Windows Task Manager does something similar. This however will require Win32 functions - Thread32First and Thread32Next among others - but you can achieve this by the simplest use of P/Invoke in C#:
[DllImport("Executor.dll")]
public static extern bool Thread32First(IntPtr handle, IntPtr threadEntry32);
(Precise signature may differ).
EDIT: Ok, there are corresponding functions in the .NET library.
If possible, rewrite the other code to be a concurrent input processor (similar to the algorithm for a concurrent web server):
Wait for input
Fork process
Parent: Repeat
Child: (Worker) handle input
Of course, you could still have your function:
static Boolean IsWaitingForUserInput(String processName) {
return true;
}

Categories