Get the Titles of All Open Windows

get the titles of all open windows

Something like this:

using System.Diagnostics;

Process[] processlist = Process.GetProcesses();

foreach (Process process in processlist)
{
if (!String.IsNullOrEmpty(process.MainWindowTitle))
{
Console.WriteLine("Process: {0} ID: {1} Window title: {2}", process.ProcessName, process.Id, process.MainWindowTitle);
}
}

Get ALL open windows

This should do it. It will return a list of integer pointers to each open window of the given application name:

public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam);

[DllImport("user32.dll")]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

[DllImport("user32.Dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam);

static void Main(string[] args)
{
Process[] processes = Process.GetProcessesByName("MyApp");

var windows = new List<IntPtr>();

foreach (Process p in processes)
{
IEnumerable<IntPtr> w = GetRootWindowsOfProcess(p.Id);
windows.AddRange(w);
}
}

private static IEnumerable<IntPtr> GetRootWindowsOfProcess(int pid)
{
IEnumerable<IntPtr> rootWindows = GetChildWindows(IntPtr.Zero);
var dsProcRootWindows = new List<IntPtr>();
foreach (IntPtr hWnd in rootWindows)
{
uint lpdwProcessId;
GetWindowThreadProcessId(hWnd, out lpdwProcessId);
if (lpdwProcessId == pid)
dsProcRootWindows.Add(hWnd);
}
return dsProcRootWindows;
}

private static IEnumerable<IntPtr> GetChildWindows(IntPtr parent)
{
var result = new List<IntPtr>();
GCHandle listHandle = GCHandle.Alloc(result);
try
{
var childProc = new Win32Callback(EnumWindow);
EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
}
finally
{
if (listHandle.IsAllocated)
listHandle.Free();
}
return result;
}

private static bool EnumWindow(IntPtr handle, IntPtr pointer)
{
GCHandle gch = GCHandle.FromIntPtr(pointer);
var list = gch.Target as List<IntPtr>;
if (list == null)
{
throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
}
list.Add(handle);
// You can modify this to check to see if you want to cancel the operation, then return a null here
return true;
}

Now as one of the commenter's mentioned, you shouldn't have multiple threads doing GUI work. One thread should be doing the GUI drawing while other threads do the actual other work.

Get a list of all open windows using AutoIt

You can get a list of all open windows using WinList:

$aWindows = WinList()
For $i=1 To $aWindows[0][0]

; skip windows without a title
If $aWindows[$i][0] = '' Then ContinueLoop

;use the HWND to get the state of the window
$iWndState = WinGetState($aWindows[$i][1])

; here you could filter out the windows you don't want to modify
ConsoleWrite($aWindows[$i][0] & ': ')
If BitAND($iWndState,1) = 1 Then ConsoleWrite(' exists')
If BitAND($iWndState,2) = 2 Then ConsoleWrite(' visible')
If BitAND($iWndState,4) = 4 Then ConsoleWrite(' enabled')
If BitAND($iWndState,8) = 8 Then ConsoleWrite(' active')
If BitAND($iWndState,16) = 16 Then ConsoleWrite(' minimised')
If BitAND($iWndState,32) = 32 Then ConsoleWrite(' maximised')
ConsoleWrite(@CRLF)
Next

Getting a list of all open windows in c++ and storing them

The second parameter (lParam) to EnumWindows is documented as:

An application-defined value to be passed to the callback function.

Just pass your container to the API call:

int main() {
std::vector<std::wstring> titles;
EnumWindows(speichereFenster, reinterpret_cast<LPARAM>(&titles));
// At this point, titles if fully populated and could be displayed, e.g.:
for ( const auto& title : titles )
std::wcout << L"Title: " << title << std::endl;
cin.get();
return 0;
}

And use it in your callback:

BOOL CALLBACK speichereFenster(HWND hwnd, LPARAM lParam){
const DWORD TITLE_SIZE = 1024;
WCHAR windowTitle[TITLE_SIZE];

GetWindowTextW(hwnd, windowTitle, TITLE_SIZE);

int length = ::GetWindowTextLength(hwnd);
wstring title(&windowTitle[0]);
if (!IsWindowVisible(hwnd) || length == 0 || title == L"Program Manager") {
return TRUE;
}

// Retrieve the pointer passed into this callback, and re-'type' it.
// The only way for a C API to pass arbitrary data is by means of a void*.
std::vector<std::wstring>& titles =
*reinterpret_cast<std::vector<std::wstring>*>(lParam);
titles.push_back(title);

return TRUE;
}

Notes:

  • The code presented uses a std::wstring in place of std::string. This is necessary so that the entire character set can be represented.
  • As written, the code isn't correct. There are (invisible) code paths, that have no well-defined meaning. The Windows API is strictly exposed as a C interface. As such, it doesn't understand C++ exceptions. Particularly with callbacks it is vital to never let C++ exceptions travel across unknown stack frames. To fix the code apply the following changes:

    • [C++11 only] Mark the callback noexcept.
    • Wrap the entire callback inside a try-catch block, and handle any exceptions appropriately.
    • [C++11 only] With C++11 you can pass C++ exceptions across unknown stack frames, by passing a std::exception_ptr, and calling std::rethrow_exception at the call site.

Get list of all open windows in .Net Core running on macOS (via NSApplication?)

In the link you refer to, there is an important note:

... as Xamarin.Mac.dll does not run under the .NET Core runtime, it only runs with the Mono runtime.

Because you try to run Xamarin.Mac.dll under .net-core, you get this dlopen error.

No System-wide List via NSApplication

The linked answer with NSApplication.shared.windows is incorrect if you want to read a system-wide list of open windows. It can only be used to determine all currently existing windows for the application from which the call is made, see Apple's documentation.

Alternative solution

Nevertheless, there are several ways to access the Window information in macOS. One of them could be a small unmanaged C-lib that gets the necessary information via CoreFoundation and CoreGraphics and returns it to C# via Platform Invoke (P/Invoke).

Native Code

Here is example code for a C-Lib that determines and returns the names of the window owners.

WindowsListLib.h

extern char const **windowList(void);
extern void freeWindowList(char const **list);

The interface of the library consists of only two functions. The first function called windowList returns a list with the names of the window owners. The last element of the list must be NULL so that you can detect where the list ends on the managed C# side. Since the memory for the string list is allocated dynamically, you must use the freeWindowList function to free the associated memory after processing.

WindowsListLib.c

#include "WindowListLib.h"
#include <CoreFoundation/CoreFoundation.h>
#include <CoreGraphics/CoreGraphics.h>

static void errorExit(char *msg) {
fprintf(stderr, "%s\n", msg);
exit(1);
}

static char *copyUTF8String(CFStringRef string) {
CFIndex length = CFStringGetLength(string);
CFIndex size = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
char *buf = malloc(size);
if(!buf) {
errorExit("malloc failed");
}
if(!CFStringGetCString(string, buf, size, kCFStringEncodingUTF8)) {
errorExit("copyUTF8String with utf8 encoding failed");
}
return buf;
}

char const **windowList(void) {
CFArrayRef cfWindowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
CFIndex count = CFArrayGetCount(cfWindowList);
char const **list = malloc(sizeof(char *) * (count + 1));
if(!list) {
errorExit("malloc failed");
}
list[count] = NULL;
for(CFIndex i = 0; i < count; i++) {
CFDictionaryRef windowInfo = CFArrayGetValueAtIndex(cfWindowList, i);
CFStringRef name = CFDictionaryGetValue(windowInfo, kCGWindowOwnerName);
if(name) {
list[i] = copyUTF8String(name);
} else {
list[i] = strdup("unknown");
}
}
CFRelease(cfWindowList);
return list;
}

void freeWindowList(char const **list) {
const char **ptr = list;
while(*ptr++) {
free((void *)*ptr);
}
free(list);
}

CGWindowListCopyWindowInfo is the actual function that gets the window information. It returns a list of dictionaries containing the details. From this we extract kCGWindowOwnerName. This CFStringRef is converted to a dynamically allocated UTF-8 string by the function copyUTF8String.

By convention, calls like CGWindowListCopyWindowInfo that contain the word copy (or create) must be released after use with CFRelease to avoid creating memory leaks.

C# Code

The whole thing can then be called on the C# side something like this:

using System.Runtime.InteropServices;

namespace WindowList
{
public static class Program
{
[DllImport("WindowListLib", EntryPoint = "windowList")]
private static extern IntPtr WindowList();

[DllImport("WindowListLib", EntryPoint = "freeWindowList")]
private static extern void FreeWindowList(IntPtr list);

private static List<string> GetWindows()
{
var nativeWindowList = WindowList();
var windows = new List<string>();
var nativeWindowPtr = nativeWindowList;
string? windowName;
do
{
var strPtr = Marshal.ReadIntPtr(nativeWindowPtr);
windowName = Marshal.PtrToStringUTF8(strPtr);
if (windowName == null) continue;
windows.Add(windowName);
nativeWindowPtr += Marshal.SizeOf(typeof(IntPtr));
} while (windowName != null);

FreeWindowList(nativeWindowList);
return windows;
}

static void Main()
{
foreach (var winName in GetWindows())
{
Console.WriteLine(winName);
}
}
}
}

The GetWindows method fetches the data via a native call to WindowList and converts the C strings to managed strings, then releases the native resources via a call to FreeWindowList.

This function returns only the owner names, such as Finder, Xcode, Safari, etc. If there are multiple windows, the owners will also be returned multiple times, etc. The exact logic of what should be determined will probably have to be changed according to your requirements. However, the code above should at least show a possible approach to how this can be done.

Screenshot

demo



Related Topics



Leave a reply



Submit