Can't get a window handle? - c#

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

Related

WinAPI FindWindow not working for Unreal engine games

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;
}
}

How to read dll from specific path in C#

I need to import SglW32.dll to my solution.
But I get:
AccessViolation exeption : Attempted to read or write protected
memory. This is often an indication that other memory is corrupt.
I could not use just DllImport. In that case dll is not found.
This is whole example.
using System;
using System.Runtime.InteropServices;
namespace TestDllimport
{
class Program
{
static void Main(string[] args)
{
var a = new MyClass();
var result = a.getValue();
}
}
class FunctionLoader
{
[DllImport("Kernel32.dll")]
private static extern IntPtr LoadLibrary(string path);
[DllImport("Kernel32.dll")]
private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
public static Delegate LoadFunction<T>(string dllPath, string functionName)
{
var hModule = LoadLibrary(dllPath);
var functionAddress = GetProcAddress(hModule, functionName);
return Marshal.GetDelegateForFunctionPointer(functionAddress, typeof(T));
}
}
public class MyClass
{
//Define your path to dll.
//Get dll from: http://www.sg-lock.com/download/sglw32_v2_28.zip
private const string DLL_Path = #"C:\Users\admin123\Desktop\MyDlls\SglW32.dll";
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate ulong SglAuthentA(IntPtr AuthentCode);
static MyClass()
{
sglAuthentA = (SglAuthentA)FunctionLoader.LoadFunction<SglAuthentA>(DLL_Path, "SglAuthentA");
}
static private SglAuthentA sglAuthentA;
unsafe public ulong getValue()
{
IntPtr d = new IntPtr(5);
var a1 = sglAuthentA(d); // Exception IS HERE !!!!!
return a1;
}
}
}
I am using load function to get dll from any path. After that I crate delegate from required function. In my case function is SglAuthentA.
This solution in working with one other dll, but not for SglW32.dll.
Product: http://www.sg-lock.com/us/
Required dll : http://www.sg-lock.com/download/sglw32_v2_28.zip
Manual: http://www.sg-lock.com/download/SG-Lock_Manual_Eng.pdf
Source 1: https://stackoverflow.com/a/8836228/2451446
EDIT: Solution thanks to Hans Passant answer and ja72 comment
See How to import dll
using System.Runtime.InteropServices;
namespace TestDllimport
{
class Program
{
static void Main(string[] args)
{
var testA = DllImportClass.SglAuthentA(new uint[] { 5, 6, 7 }, new uint[] { 5, 6, 7 }, new uint[] { 5, 6, 7 });
var testB = DllImportClass.SglAuthentB(new uint[] { 5, 6, 7 });
}
}
static class DllImportClass
{
[DllImport("SglW32.dll")]
public static extern uint SglAuthentA(uint[] AuthentCode0, uint[] AuthentCode1, uint[] AuthentCode2);
[DllImport("SglW32.dll")]
public static extern uint SglAuthentB(uint[] AuthentCode);
}
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate ulong SglAuthentA(IntPtr AuthentCode);
The delegate declaration is not correct and does not match the api function signature. An ULONG in C is an uint in C#. An ULONG* in C is ambiguous, could be a ref uint or it could be a uint[]. Since you are supposed to pass a 48 byte authentication code, you know it is an array. Fix:
private delegate uint SglAuthentA(uint[] authentCode);
Be sure to pass the proper authentication code. It is not 5, the array must have 12 elements. If you don't have one then call the manufacturer to acquire one.
private const string DLL_Path = #"C:\Users\admin123\Desktop\MyDlls\SglW32.dll";
Do beware that this is not a workaround for not being able to use [DllImport]. Hardcoding the path is a problem, the file is not going to be present in that directory on the user's machine. The DLL itself does not have any dependencies that prevents it from loading, the only plausible reason for having trouble is you just forgetting to copy the DLL into the proper place. There is only one such place, the same directory as your EXE.
Fix this the right way, use Project > Add Existing Item > select the DLL. Select the added file in the Solution Explorer window. In the Properties window, change the Copy to Output Directory setting to "Copy if newer". Rebuild your project and note that you'll now get the DLL in your project's bin\Debug directory. Now [DllImport] will work.
A caution about the manual, it lists code samples in Visual Basic. Which is in general what you'd normally use as a guide on learning how to use the api. The code is however not VB.NET code, it is VB6 code. Where ever you see Long in the sample code, you should use uint or int instead.
Very sloppy, it casts a big question mark on the quality of the product. Something else they don't seem to address at all is how to get your own code secure. Very important when you use a dongle. Beware it is very trivial for anybody to reverse-engineer your authentication code. And worse, to decompile your program and remove the authentication check. You need to use an obfuscator.

Need help resolving AccessViolationException with C#/C interop

I need some help fixing a persistent AccessViolationException.
Given a c signature like this
struct message {
char *topic;
void *payload;
int payloadlen;
};
__declspec(dllexport) void callback_set(struct data *dat, void (*on_publish)(struct data *, void *, const struct message *));
I have this C#
public struct message
{
public string topic;
public IntPtr payload;
public int payloadlen;
};
/* INTEROP ACCESS */
public delegate void on_publish(IntPtr dat, IntPtr usrData, IntPtr messageData);
[DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
public extern static void callback_set(IntPtr dat, IntPtr callback);
/* IMPLEMENTATION OF OUR on_publish*/
public static void MessageHandler(IntPtr dat, IntPtr usrData, IntPtr messageData)
{
var instance = (message)Marshal.PtrToStructure(messageData, typeof(message));
string test = instance.topic; // <-- this is successfully received
Console.WriteLine("message rec " + test);
} //<-- as soon as I exit, the dll blows up with access violation
/* REGISTERING MESSAGEHANDLER AS ON_PUBLISH */
public static void RegisterMessageHandler(IntPtr dat) //<-- I promise, the pointer I send here is valid and not modified
{
messageHandler = new on_publish(MessageHandler);
messageHandlerPtr = Marshal.GetFunctionPointerForDelegate(messageHandler);
callback_set(dat, messageHandlerPtr); //<-- if I do not call this, everything works, no ADE
Console.WriteLine("message handler registered");
}
//just tried to move to scope in order to retain their managed memory loc
private static IntPtr messageHandlerPtr;
private static on_publish messageHandler;
When running, and making sure a message should be received - I get the correct string for the topic but as soon as MessageHandler returns, I get the dreaded exception.
Things I've tried:
Change CallingConvention
Use on_publish instead of IntPtr in managed callback_set definition
Probably more things in desperation that should not have an impact
Any help much appreciated!
I can share a zip of the project if anyone can help - it will be BSD licensed just like Mosquitto which I'm trying to interop with.
I ended up creating a C++/CLI project to wrap the C project to .NET.
I found it much easier to manage the unmanaged code using C++, and I ended up with a nice interop to C# as my class became .NET accessible.
I would recommend this path, and will do it myself - the next time I need to integrate C# with a C lib.

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.

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